java.text.ParseException:无法解析的日期

时间:2011-08-31 08:17:18

标签: java android date parseexception

我收到以下错误: 'java.text.ParseException:Unparseable date:“Aug 31 09:53:19 2011”'使用以下格式:new SimpleDateFormat("MMM dd HH:mm:ss yyyy");

有没有人看到这个问题?

3 个答案:

答案 0 :(得分:26)

确保使用正确的区域设置。 (SimpleDateFormat(String)构造函数使用系统默认区域设置,这可能不是您要使用的区域设置。)

这在我的机器上工作正常:

String input = "Aug 31 09:53:19 2011";
DateFormat df = new SimpleDateFormat("MMM dd HH:mm:ss yyyy", Locale.US);
System.out.println(df.parseObject(input));

(例如,在使用Locale.FRENCH时,会产生ParseException。)

答案 1 :(得分:6)

格式本身对于您提供的输入是可以的。但是,如果您的默认语言环境设置为“Aug”不是月份名称的有效缩写,则可能会出现此错误。尝试使用例如Locale.US,你会发现它会起作用:

DateFormat df = new SimpleDateFormat("MMM dd HH:mm:ss yyyy", Locale.US);
Date date = df.parse("Aug 31 09:53:19 2011");

答案 2 :(得分:5)

TL;博士

  • 指定Locale ,以确定翻译月份名称时使用的人类语言和文化规范。
  • 使用现代 java.time 类而不是那些麻烦的遗留类。

受挫的例子:

LocalDateTime.parse(                                       // Parse input text as a `LocalDateTime` lacking any concept of time zone or offset-from-UTC.
    "Aug 31 09:53:19 2011" , 
    DateTimeFormatter.ofPattern( "MMM dd HH:mm:ss yyyy" )  // Specify formatting pattern to match input string.
                     .withLocale( Locale.US )              // The `Locale` determines the human language and cultural norms used in translating the input text.
)                                                          // Returns a `LocalDateTime` object.

详细

另外两个答案by aioobeby Jesper都是正确的:隐式使用Locale,其中的人类语言与输入文字的语言不匹配。

本答案解释了一种新的工作方式。此外,其他答案没有解决时区的关键问题。

java.time

几年后从这篇文章快进,我们现在将新的java.time package内置到Java 8及更高版本中。这些新类取代了旧的java.util.Date/.Calendar& SimpleDateFormat类。事实证明,那些旧班级很麻烦,令人困惑,也有缺陷。

格式化程序模式

定义要解析的数据及其格式。

String input = "Aug 31 09:53:19 2011";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern( "MMM dd HH:mm:ss uuuu" );

如果未指定,则为DateTimeFormatter分配当前在JVM中默认的Locale。即使在运行时(!),该默认值也可随时更改。因此,请始终指定所需/预期的Locale

formatter = formatter.withLocale( Locale.US );  // Or Locale.UK, Locale.CANADA_FRENCH, etc.

鉴于输入缺少任何时区或偏离 - UTC信息,请解析为LocalDateTime

LocalDateTime ldt = LocalDateTime.parse( input , formatter );

如果从上下文中您知道该日期 - 时间值的预期偏离UTC或时区,请指定它。

如果是UTC,请使用ZoneOffset.UTC常量来获取OffsetDateTime对象。

OffsetDateTime odt = ldt.atOffset( ZoneOffset.UTC );

时区是与UTC 的偏移量加上用于处理夏令时(DST)等异常的一组规则。使用proper time zone names,而不是3-4 letter abbreviations

ZoneId zoneId_Montreal = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = ldt.atZone( zoneId_Montreal );

指定时区

这个人类语言元素是回答问题的关键缺失部分。为符合输入字符串语言的人类语言指定正确的Locale可以解决该问题。

但请注意,时区也很重要;其他答案忽略了此问题,从而隐式使用JVM的当前默认时区。这是不可取的,因为它取决于主机操作系统作为初始默认值(因此可能会有所不同),而且JVM中任何应用程序的任何线程中的任何代码都可以在 em>运行时。最好指定期望/预期的时区,而不是隐含地依赖默认值。

不可变对象

请注意语法。这些类设计为immutable。因此,不是修改(变异)对象,而是基于旧对象的值创建新的新对象。这意味着我们影响上面定义的DateTimeFormatter对象并保存在formatter变量(对象引用)中。我们在这行代码中创建,使用和丢弃一个新的DateTimeFormatter对象(实际上是两个新对象)。

方法参考

文档建议另一种解析字符串的方法是调用parse方法,在那里从所需类型的类中传递method reference(Java 8中的新增内容)(如TemporalQuery):ZonedDateTime::fromLocalDateTime::fromLocalDate::from等。

ZonedDateTime zdt = formatter.withZone( zoneId_Montreal ).withLocale( Locale.ENGLISH ).parse( input, ZonedDateTime :: from );

为了演示,让我们转而创建一个ZonedDateTime值的字符串表示形式,但在QuébécoisFrench中。

String output = formatter.withLocale( Locale.CANADA_FRENCH ).format( zdt );

更好的是,让我们本地化而不是硬编码特定的格式。

String outputLocalized = DateTimeFormatter.ofLocalizedDateTime( FormatStyle.FULL ).withLocale( Locale.CANADA_FRENCH ).format( zdt );

转储到控制台。

System.out.println( "input: " + input );
System.out.println( "formatter: " + formatter );
System.out.println( "zdt: " + zdt );
System.out.println( "output: " + output );
System.out.println( "outputLocalized: " + outputLocalized );

跑步时。

input: Aug 31 09:53:19 2011
formatter: Text(MonthOfYear,SHORT)' 'Value(DayOfMonth,2)' 'Value(HourOfDay,2)':'Value(MinuteOfHour,2)':'Value(SecondOfMinute,2)' 'Value(YearOfEra,4,19,EXCEEDS_PAD)
zdt: 2011-08-31T09:53:19-04:00[America/Montreal]
output: août 31 09:53:19 2011
outputLocalized: mercredi 31 août 2011 9 h 53 EDT

关于 java.time

java.time框架内置于Java 8及更高版本中。这些类取代了麻烦的旧legacy日期时间类,例如java.util.DateCalendar和& SimpleDateFormat

现在位于Joda-Timemaintenance mode项目建议迁移到java.time类。

要了解详情,请参阅Oracle Tutorial。并搜索Stack Overflow以获取许多示例和解释。规范是JSR 310

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

从哪里获取java.time类?