繁体   English   中英

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

[英]java.text.ParseException: Unparseable date

我收到以下错误:´java.text.ParseException:无法解析的日期:“ 2011年8月31日09:53:19”´,格式为: new SimpleDateFormat("MMM dd HH:mm:ss yyyy");

有人看到这个问题吗?

确保您使用的语言环境正确。 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 。)

输入的格式本身可以。 但是,如果您的默认语言环境设置为“ 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");

tl; dr

  • 指定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.

细节

其他两个答案通过aioobe通过加斯帕都是正确的:隐式使用Locale与人类的语言不匹配你的输入文本的语言。

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

java.time

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

格式化程序模式

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

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

如果未指定,则为DateTimeFormatter分配Locale ,该Locale当前是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)。 请使用正确的时区名称 ,不要使用3-4个字母的缩写

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

指定时区

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

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

不变的对象

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

方法参考

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

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

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

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及更高版本中。 这些类取代了麻烦的旧的旧式日期时间类,例如java.util.DateCalendarSimpleDateFormat

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

要了解更多信息,请参见Oracle教程 并在Stack Overflow中搜索许多示例和说明。 规格为JSR 310

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

在哪里获取java.time类?

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM