Java - 日期格式无法解析

20

我正在尝试解析一个日期,但是出现了异常。

这是代码:

import java.util.Date;

String strDate = "Wed, 09 Feb 2011 12:34:27";
Date date;
SimpleDateFormat FORMATTER =  new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss");
try {
  date = FORMATTER.parse(strDate.trim());
  System.out.println(date);
} catch (ParseException e) {
  e.printStackTrace();
}
异常是:

java.text.ParseException: 无法解析的日期:"Wed, 09 Feb 2011 12:34:27" at java.text.DateFormat.parse(DateFormat.java:337) at DateTest.main(DateTest.java:17)

我已经阅读了文档,并且认为我的格式是正确的。所以我不明白为什么会出现这种情况...
你有什么想法吗?
谢谢!

3
请注意,令人头疼的旧日期时间类(如 java.util.Datejava.util.Calendarjava.text.SimpleTextFormat)现在已被认定为遗留系统,并已被 java.time 类所取代。请参阅 Oracle 教程 - Basil Bourque
3个回答

42

可能是因为您计算机的默认语言环境不是英语导致的。

您应该使用:

new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss", Locale.ENGLISH);

改为使用“instead”。


7

简短概述

java.util.Date.from (

    LocalDateTime.parse( 
        "Wed, 09 Feb 2011 12:34:27" , 
        DateTimeFormatter.ofPattern( "EEE, dd MMM uuuu HH:mm:ss" , Locale.US )
    ).atZone( ZoneId.of( "America/Montreal" ) )
     .toInstant()

)

详情

问题和其他答案都使用过时的、麻烦的旧日期时间类,这些类现在已经被 java.time 类所取代。

使用 java.time

输入字符串缺乏任何关于时区或UTC偏移量的指示。因此我们将其解析为 OffsetDateTime

指定一个 Locale 来确定 (a) 用于翻译星期几、月份名称等人类语言,以及 (b) 决定缩写、大写、标点符号、分隔符等文化规范。

String input = "Wed, 09 Feb 2011 12:34:27" ;
Locale l = Locale.US ; 
DateTimeFormatter f = DateTimeFormatter.ofPattern( "EEE, dd MMM uuuu HH:mm:ss" , l ) ;
LocalDateTime ldt = LocalDateTime.parse( input , f ) ;

ldt.toString(): 2011-02-09T12:34:27

时区

问题和其他答案都忽略了关键的时区问题。

输入字符串缺少时区或偏移量。我们解析为一个LocalDateTime,它不是时间线上的瞬间,只是可能瞬间的模糊概念。就像说“圣诞节在2017年12月25日午夜开始”,这在没有放置在特定时区的上下文中是没有意义的。在奥克兰新西兰,圣诞节比在巴黎法国早得多,在蒙特利尔魁北克则更晚。

如果您知道所需的时区,请分配一个ZoneId以生成一个ZonedDateTime

ZoneId z = ZoneId.of( "America/Montreal" ) ;
ZonedDateTime zdt = ldt.atZone( z ); // Assigning a time zone to determine an actual moment on the timeline.

转换

最好避免使用麻烦的旧日期时间类。但是如果您必须与尚未更新为java.time类型的旧代码交互,您可以在旧类中查找新方法并在旧类和java.time之间进行转换。

java.util.Date是UTC时间轴上的一个时刻。因此,我们需要从ZonedDateTime中提取一个InstantInstant类表示UTC时间轴上的一个时刻,具有纳秒的分辨率(最多九(9)位小数)。

Instant instant = zdt.toInstant() ;
java.util.Date d = java.util.Date.from( instant ) ;  // Convert from java.time to legacy class.

朝另一个方向。

Instant instant = d.toInstant() ;  // Convert from legacy class to java.time class.
ZonedDateTime zdt = instant.atZone( z ) ;  // Adjust from UTC into a particular time zone.

关于java.time

java.time框架已内置于Java 8及更高版本中。这些类替代了旧的legacy日期时间类,例如java.util.Date, Calendar, 和 SimpleDateFormat

Joda-Time项目现在处于维护模式,建议迁移到java.time类。

要了解更多信息,请参阅Oracle教程。并搜索Stack Overflow以获取许多示例和解释。规范为JSR 310

您可以直接与数据库交换java.time对象。使用符合JDBC 4.2或更高版本的JDBC驱动程序。无需字符串,无需java.sql.*类。

如何获取java.time类?

ThreeTen-Extra项目扩展了java.time的附加类。该项目是java.time可能未来新增的一个实验场。您可能会在这里找到一些有用的类,例如Interval, YearWeek, YearQuarter更多


1

不要在使用SimpleDateFormatDateTimeFormatter时忘记指定Locale

由于给定的日期时间是英文格式,因此您应该使用Locale.ENGLISH与您的日期时间解析器一起使用;否则,在使用非英语类型区域设置的系统(计算机、手机等)中,解析将会失败。

此外,请注意,java.util的日期时间API及其格式化APISimpleDateFormat已经过时且容易出错。建议完全停止使用它们并切换到现代日期时间API

演示:

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;

public class Main {
    public static void main(String[] args) {
        final String strDateTime = "Wed, 09 Feb 2011 12:34:27";
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("EEE, dd MMM uuuu HH:mm:ss", Locale.ENGLISH);
        LocalDateTime ldt = LocalDateTime.parse(strDateTime, dtf);
        System.out.println(ldt);
    }
}

输出:

2011-02-09T12:34:27

默认情况下,DateTimeFormatter#ofPattern 使用JVM在启动时基于主机环境设置的默认格式区域设置SimpleDateFormat也是如此。我已经尝试通过以下演示来说明问题:
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;

public class Main {
    public static void main(String[] args) {
        final String strDateTime = "Wed, 09 Feb 2011 12:34:27";
        DateTimeFormatter dtfWithDefaultLocale = null;

        System.out.println("JVM's Locale: " + Locale.getDefault());
        // Using DateTimeFormatter with the default Locale
        dtfWithDefaultLocale = DateTimeFormatter.ofPattern("EEE, dd MMM uuuu HH:mm:ss");
        System.out.println("DateTimeFormatter's Locale: " + dtfWithDefaultLocale.getLocale());
        System.out
                .println("Parsed with JVM's default locale: " + LocalDateTime.parse(strDateTime, dtfWithDefaultLocale));

        // Setting the JVM's default locale to Locale.FRANCE
        Locale.setDefault(Locale.FRANCE);

        // Using DateTimeFormatter with Locale.ENGLISH explicitly (recommended)
        DateTimeFormatter dtfWithEnglishLocale = DateTimeFormatter.ofPattern("EEE, dd MMM uuuu HH:mm:ss",
                Locale.ENGLISH);
        System.out.println("JVM's Locale: " + Locale.getDefault());
        System.out.println("DateTimeFormatter's Locale: " + dtfWithEnglishLocale.getLocale());
        LocalDateTime zdt = LocalDateTime.parse(strDateTime, dtfWithEnglishLocale);
        System.out.println("Parsed with Locale.ENGLISH: " + zdt);

        System.out.println("JVM's Locale: " + Locale.getDefault());
        // Using DateTimeFormatter with the default Locale
        dtfWithDefaultLocale = DateTimeFormatter.ofPattern("EEE, dd MMM uuuu HH:mm:ss");
        System.out.println("DateTimeFormatter's Locale: " + dtfWithDefaultLocale.getLocale());
        System.out
                .println("Parsed with JVM's default locale: " + LocalDateTime.parse(strDateTime, dtfWithDefaultLocale));
    }
}

输出:

JVM's Locale: en_GB
DateTimeFormatter's Locale: en_GB
Parsed with JVM's default locale: 2011-02-09T12:34:27
JVM's Locale: fr_FR
DateTimeFormatter's Locale: en
Parsed with Locale.ENGLISH: 2011-02-09T12:34:27
JVM's Locale: fr_FR
DateTimeFormatter's Locale: fr_FR
Exception in thread "main" java.time.format.DateTimeParseException: Text 'Wed, 09 Feb 2011 12:34:27' could not be parsed at index 0
    at java.base/java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:2046)
    at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1948)
    at java.base/java.time.LocalDateTime.parse(LocalDateTime.java:492)
    at Main.main(Main.java:33)

下面的演示代码,使用SimpleDateFormat,仅是为了完整起见:
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

public class Main {
    public static void main(String[] args) throws ParseException {
        final String strDateTime = "Wed, 09 Feb 2011 12:34:27";
        SimpleDateFormat sdf = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss", Locale.ENGLISH);
        Date date = sdf.parse(strDateTime);
        System.out.println(date);
    }
}

输出:

Wed Feb 09 12:34:27 GMT 2011

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接