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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7254307/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 19:18:22  来源:igfitidea点击:

java.text.ParseException: Unparseable date

javaandroiddateparseexception

提问by Stijn.V

I get the following error: ′java.text.ParseException: Unparseable date: "Aug 31 09:53:19 2011"′ with this format: new SimpleDateFormat("MMM dd HH:mm:ss yyyy");

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

Does anyone see the problem?

有没有人看到问题?

回答by aioobe

Make sure you're using the correct locale. (The SimpleDateFormat(String)constructor uses the system default locale, which may not be the one you want to use.)

确保您使用正确的语言环境。(SimpleDateFormat(String)构造函数使用 系统默认 locale,这可能不是您想要使用的那个。)

This works fine on my machine:

这在我的机器上运行良好:

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));

(While using Locale.FRENCHfor instance, results in a ParseException.)

Locale.FRENCH例如,在使用时,结果为ParseException.)

回答by Jesper

The format itself is OK for the input you gave. But you might get this error if your default locale is set to something where "Aug" is not a valid abbreviation of a month name. Try using for example to Locale.USand you'll see that it will work:

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

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

回答by Basil Bourque

tl;dr

tl;博士

  • Specify the Locale, to determine human language and cultural norms used in translating the name of month.
  • Use modern java.timeclasses rather that troublesome legacy classes.
  • 指定Locale, 以确定用于翻译月份名称的人类语言和文化规范。
  • 使用现代java.time类而不是麻烦的遗留类。

Contrived example:

人为的例子:

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.

Details

细节

The other two answers by aioobeand by Jesperare both correct: Implicitly using a Localewith a human language that does not match the language of your input text.

aioobeJesper的另外两个答案都是正确的:隐式使用Locale与输入文本语言不匹配的人类语言。

This Answer explains a new way of doing the job. Also, the other Answers do not address the crucial issue of time zone.

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

java.time

时间

Fast forward a few years later from this posting, and we now have the new java.time packagebuilt into Java 8 and later. These new classes supplant the old java.util.Date/.Calendar & SimpleDateFormat classes. Those old classes have proven to be troublesome, confusing, and flawed.

几年后从这篇文章中快进,我们现在在Java 8 及更高版本中内置了新的java.time 包。这些新类取代了旧的 java.util.Date/.Calendar 和 SimpleDateFormat 类。那些旧的类已被证明是麻烦、混乱和有缺陷的。

Formatter Pattern

格式化程序模式

Define the data to be parsed and its format.

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

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

If not specified, the DateTimeFormatteris assigned the Localethat is currently the default in the JVM. That default can change at any moment, even during runtime(!). So always specify the desired/expected Locale.

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

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

Given that the input lacks any time zone or offset-from-UTCinformation, parse as a LocalDateTime.

鉴于输入缺少任何时区或UTC偏移量信息,解析为LocalDateTime.

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

If from the context you know the intended offset-from-UTC or a time zone for this date-time value, assign it.

如果从上下文中您知道此日期时间值的预期偏移量或时区,请分配它。

If UTC, use the ZoneOffset.UTCconstant to get a OffsetDateTimeobject.

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

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

A time zone is an offset-from-UTC plusa set of rules for handling anomalies such as Daylight Saving Time (DST). Use proper time zone names, never the 3-4 letter abbreviations.

时区是 UTC 的偏移量加上一组用于处理夏令时 (DST) 等异常的规则。使用正确的时区名称,不要使用3-4 个字母的缩写

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

Specify Time Zone

指定时区

This human language element was the key missing piece to answer the Question. Specifying the correct Localefor the human language matching the language of your input string solves that problem.

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

But note that the time zone is also critical; the other answers ignored this issue thereby implicitly using the JVM's current default time zone. That is not advisable, as it depends on the host operating system as an initial default value (so may vary) and furthermore any code in any thread of any app within the JVM can change the JVM's current default time zone duringruntime. Better to specify the desired/expected time zone than rely implicitly on default.

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

Immutable Objects

不可变对象

Note the syntax. These classes are designed to be immutable. So rather than modifying (mutating) an object, a fresh new object is created based on the old object's values. This means we are notaffecting the DateTimeFormatterobject defined above and held in the formattervariable (object reference). We are creating, using, and discarding a new DateTimeFormatter object (actually, twonew objects) within this line of code.

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

Method Reference

方法参考

The documentation suggests an alternative way to parse a string is to call the parsemethod where you pass a method reference(new in Java 8) from the class of the kind of result you desire (as the TemporalQuery): ZonedDateTime::from, LocalDateTime::from, LocalDate::from, and so on.

该文档建议另一种解析字符串的parse方法是调用传递方法引用(Java 8 中的新功能)的方法,该方法从您想要的结果类型的类(如TemporalQuery):ZonedDateTime::fromLocalDateTime::fromLocalDate::from等。

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

For demonstration, let's turn around and create a String representation of that ZonedDateTimevalue but in Québécois French.

为了演示,让我们转过身来创建该ZonedDateTime值的字符串表示形式,但使用魁北克法语。

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

Even better, let's localize rather than hard-code a particular format.

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

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

Dump to console.

转储到控制台。

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 );

When run.

跑的时候。

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


About java.time

关于java.time

The java.timeframework is built into Java 8 and later. These classes supplant the troublesome old legacydate-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

java.time框架是建立在Java 8和更高版本。这些类取代了麻烦的旧的遗留日期时间类,例如java.util.Date, Calendar, & SimpleDateFormat

The Joda-Timeproject, now in maintenance mode, advises migration to the java.timeclasses.

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

To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.

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

You may exchange java.timeobjects directly with your database. Use a JDBC drivercompliant with JDBC 4.2or later. No need for strings, no need for java.sql.*classes.

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

Where to obtain the java.time classes?

从哪里获得 java.time 类?