我正在尝试解析看起来像这样的日期:
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上使用以获得预期的输出,但我不认为这是必要的。有什么我想念的吗?是否有替代日期解析器?
答案 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)
Instant.parse ( "2010-04-05T17:16:00Z" )
您的字符串符合ISO 8601标准(其中提到的RFC 3339是个人资料)。
与Java捆绑在一起的java.util.Date和.Calendar类非常麻烦。避免它们。
而是使用Java中的Joda-Time库或新的java.time包。两者都使用ISO 8601作为解析和生成日期时间值的字符串表示的默认值。
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)
X时区ISO 8601时区-08; -0800; -08:00
对于ISO 8601时区,您应该使用:
所以解析你的" 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类。
尽管如此,您可能只想在解析之前将“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();
}
这是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
答案 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")