simpledateformat使用'Z'文字解析日期

时间:2010-04-05 20:17:09

标签: java datetime parsing timezone simpledateformat

我正在尝试解析看起来像这样的日期:

2010-04-05T17:16:00Z

这是http://www.ietf.org/rfc/rfc3339.txt的有效日期。 'Z'字面意思“暗示UTC    是指定时间的首选参考点。“

如果我尝试使用SimpleDateFormat和这种模式解析它:

yyyy-MM-dd'T'HH:mm:ss

它将被解析为2010年4月5日17:16:00美国东部时间2010

SimpleDateFormat无法使用这些模式解析字符串:

yyyy-MM-dd'T'HH:mm:ssz
yyyy-MM-dd'T'HH:mm:ssZ

我可以显式设置TimeZone在SimpleDateFormat上使用以获得预期的输出,但我不认为这是必要的。有什么我想念的吗?是否有替代日期解析器?

12 个答案:

答案 0 :(得分:49)

Java无法正确解析ISO日期。

与McKenzie的回答相似。

在解析之前修复Z

代码

String string = "2013-03-05T18:05:05.000Z";
String defaultTimezone = TimeZone.getDefault().getID();
Date date = (new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ")).parse(string.replaceAll("Z$", "+0000"));

System.out.println("string: " + string);
System.out.println("defaultTimezone: " + defaultTimezone);
System.out.println("date: " + (new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ")).format(date));

结果

string: 2013-03-05T18:05:05.000Z
defaultTimezone: America/New_York
date: 2013-03-05T13:05:05.000-0500

答案 1 :(得分:37)

您要解析的日期是ISO8601格式。

在java 7中,读取和应用时区后缀的模式应为yyyy-MM-dd'T'HH:mm:ssX

答案 2 :(得分:30)

在模式中,包含'z'日期时间组件表示时区格式需要符合General time zone“标准”,其示例为Pacific Standard Time; PST; GMT-08:00

'Z'表示时区符合RFC 822 time zone标准,例如-0800

我认为你需要一个DatatypeConverter ......

@Test
public void testTimezoneIsGreenwichMeanTime() throws ParseException {
    final Calendar calendar = javax.xml.bind.DatatypeConverter.parseDateTime("2010-04-05T17:16:00Z");
    TestCase.assertEquals("gotten timezone", "GMT+00:00", calendar.getTimeZone().getID());
}

答案 3 :(得分:19)

TL;博士

Instant.parse ( "2010-04-05T17:16:00Z" )

ISO 8601标准

您的字符串符合ISO 8601标准(其中提到的RFC 3339是个人资料)。

避免使用j.u.Date

与Java捆绑在一起的java.util.Date和.Calendar类非常麻烦。避免它们。

而是使用Java中的Joda-Time库或新的java.time包。两者都使用ISO 8601作为解析和生成日期时间值的字符串表示的默认值。

java.time

Java 8及更高版本中内置的java.time框架取代了棘手的旧java.util.Date/.Calendar类。新课程的灵感来自非常成功的Joda-Time框架,旨在作为其继承者,在概念上类似但重新设计。由JSR 310定义。由ThreeTen-Extra项目扩展。请参阅Tutorial

java.time中的Instant类表示UTC时区中时间轴上的一个时刻。

输入字符串末尾的Z表示Zulu,代表UTC。这样的字符串可以由Instant类直接解析,无需指定格式化程序。

String input = "2010-04-05T17:16:00Z";
Instant instant = Instant.parse ( input );

转储到控制台。

System.out.println ( "instant: " + instant );
  

时刻:2010-04-05T17:16:00Z

您可以在此处应用时区(ZoneId)将此Instant调整为ZonedDateTime。搜索Stack Overflow以供讨论和举例。

如果必须使用java.util.Date对象,则可以通过调用添加到旧类的新转换方法(例如静态方法java.util.Date.from( Instant ))进行转换。

java.util.Date date = java.util.Date.from( instant );

约达时间

Joda-Time 2.5中的示例。

DateTimeZone timeZone = DateTimeZone.forID( "Europe/Paris" ):
DateTime dateTime = new DateTime( "2010-04-05T17:16:00Z", timeZone );

转换为UTC。

DateTime dateTimeUtc = dateTime.withZone( DateTimeZone.UTC );

如有必要,转换为java.util.Date。

java.util.Date date = dateTime.toDate();

答案 4 :(得分:15)

根据Date and Time Patterns

Java 7 API 表中的最后一行

X时区ISO 8601时区-08; -0800; -08:00

对于ISO 8601时区,您应该使用:

  • X代表(-08或Z),
  • XX代表(-0800或Z),
  • XXX for(-08:00或Z);

所以解析你的" 2010-04-05T17:16:00Z"你也可以使用  的 " YYYY-MM-DD' T' HH:MM:SSX"或" yyyy-MM-dd' HH:mm:ssXX"或" yyyy-MM-dd' H&H:mm:ssXXX"

    System.out.println(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX").parse("2010-04-05T17:16:00Z"));
    System.out.println(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXX").parse("2010-04-05T17:16:00Z"));
    System.out.println(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX").parse("2010-04-05T17:16:00Z"));

将正确打印出' Mon Apr 05 13:16:00 EDT 2010'

答案 5 :(得分:6)

'X'仅在部分秒不存在时才有效:即SimpleDateFormat模式

“YYYY-MM-dd'T'HH:MM:SSX”

将正确解析

“2008-01-31T00:00:00Z”

“YYYY-MM-dd'T'HH:MM:ss.SX”

不会解析

“2008-01-31T00:00:00.000Z”

可悲但真实,带有部分秒数的日期时间似乎不是有效的ISO日期:http://en.wikipedia.org/wiki/ISO_8601

答案 6 :(得分:3)

时区应该是“GMT + 00:00”或0000,以便SimpleDateFormat正确解析 - 您可以用这种结构替换Z.

答案 7 :(得分:2)

restlet项目包含一个可以解析RFC 3339日期的InternetDateFormat类。

Restlet InternetDateFormat

尽管如此,您可能只想在解析之前将“Z”替换为“UTC”。

答案 8 :(得分:2)

我提供了另一个答案,我在api-client-library由Google找到了

try {
    DateTime dateTime = DateTime.parseRfc3339(date);
    dateTime = new DateTime(new Date(dateTime.getValue()), TimeZone.getDefault());
    long timestamp = dateTime.getValue();  // get date in timestamp
    int timeZone = dateTime.getTimeZoneShift();  // get timezone offset
} catch (NumberFormatException e) {
    e.printStackTrace();
}

安装指南,
enter image description here

这是API参考,
https://developers.google.com/api-client-library/java/google-api-java-client/setup#download

DateTime类的来源代码,
https://developers.google.com/api-client-library/java/google-http-java-client/reference/1.20.0/com/google/api/client/util/DateTime

DateTime单元测试,
https://github.com/google/google-http-java-client/blob/master/google-http-client/src/main/java/com/google/api/client/util/DateTime.java

答案 9 :(得分:2)

关于JSR-310,另一个感兴趣的项目可能是threetenbp

  

JSR-310为Java SE 8提供了一个新的日期和时间库。该项目是Java SE 6和7的后端。

如果您正在处理 Android 项目,可能需要查看ThreeTenABP library

compile "com.jakewharton.threetenabp:threetenabp:${version}"
  

JSR-310作为java.time。*包被包含在Java 8中。它完全取代了Java和Android中令人生畏的Date和Calendar API。 JSR-310由其创建者Stephen Colebourne向后移植到Java 6,该库适用于该库。

答案 10 :(得分:1)

在Java 8下,使用预定义的DateTimeFormatter.ISO_DATE_TIME

 DateTimeFormatter formatter = DateTimeFormatter.ISO_DATE_TIME;
 ZonedDateTime result = ZonedDateTime.parse("2010-04-05T17:16:00Z", formatter);

我猜这是最简单的方法

答案 11 :(得分:0)

因为java 8只使用ZonedDateTime.parse("2010-04-05T17:16:00Z")