您不能使用预定义的格式化程序,但可以使用以下模式构造自己的格式化程序(并将其分配给静态常量):
static final DateTimeFormatter DATE_TIME_OPTIONAL_OFFSET =
DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss[xxx]");
注意力:如果您解析仅包含日期和时间但没有偏移量(并且没有任何偏移量/区域默认值)的输入,那么结果只能是LocalDateTime
,不是全局时间戳。
另请注意方法的不同行为withZone(...)
.
乔达时间
When parsing, this zone will be set on the parsed datetime.
A null zone means of no-override. If both an override chronology
and an override zone are set, the override zone will take precedence
over the zone in the chronology.
Java-8 (JSR-310)
When parsing, there are two distinct cases to consider.
If a zone has been parsed directly from the text, perhaps because
DateTimeFormatterBuilder.appendZoneId() was used, then this override Zone
has no effect. If no zone has been parsed, then this override zone will
be included in the result of the parse where it can be used to build
instants and date-times.
旁注:Joda 时间方法withOffsetParsed()
更接近 Java-8 行为。
Update:我现在已经做了自己的测试。查看有时令人惊讶的结果。
System.out.println(System.getProperty("java.version")); // 1.8.0_31
// parsing s1 with offset = UTC
String s1 = "2015-01-01T12:29:22+00:00";
OffsetDateTime odt1 = DATE_TIME_OPTIONAL_OFFSET.parse(s1, OffsetDateTime::from);
System.out.println(odt1); // 2015-01-01T12:29:22Z --- OK
LocalDateTime ldt1 = DATE_TIME_OPTIONAL_OFFSET.parse(s1, LocalDateTime::from);
System.out.println(ldt1); // 2015-01-01T12:29:22 --- OK
ZonedDateTime zdt1 = DATE_TIME_OPTIONAL_OFFSET.withZone(ZoneId.of("America/New_York")).parse(s1, ZonedDateTime::from);
System.out.println(zdt1); // 2015-01-01T12:29:22-05:00[America/New_York] --- seems to be a bug compared with the spec above, the parsed offset was overridden!!!
// now parsing s2 without offset
String s2 = "2015-01-01T12:29:22";
OffsetDateTime odt2 = DATE_TIME_OPTIONAL_OFFSET.parse(s2, OffsetDateTime::from);
System.out.println(odt2); // 2015-01-01T12:29:22Z --- questionable, the offset Z is invented/guessed here
LocalDateTime ldt2 = DATE_TIME_OPTIONAL_OFFSET.parse(s2, LocalDateTime::from);
System.out.println(ldt2); // 2015-01-01T12:29:22 --- OK
DATE_TIME_OPTIONAL_OFFSET.withZone(ZoneId.of("America/New_York")).parse(s2, ZonedDateTime::from);
// throws an exception --- seems to be a bug compared with the spec above, the zone set was not accepted
结论:
迁移时我会小心。细节决定成败。也许较新的 Java 版本 8u40 同时纠正了一些显示的问题(至少是withZone()
可能已更正 - 请参阅JDK 问题 8033662 https://bugs.openjdk.java.net/browse/JDK-8033662,但对于 8u31,向后移植修复似乎丢失了?!)。您还应该注意,在我的测试中,标记为“EST”的“时区”已被“America/New_York”替换,因为“EST”不是可识别的时区 ID(它是美国本地化的时区名称缩写)。
更新-最终解决方案
经过额外测试后,此代码似乎可以在 Java 8u31 中工作(假设 UTC 作为默认值,以防输入中缺少偏移量):
static final DateTimeFormatter DATE_TIME_OPTIONAL_OFFSET =
DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss[xxx]");
OffsetDateTime odt =
DATE_TIME_OPTIONAL_OFFSET.withZone(ZoneOffset.UTC).parse(input, OffsetDateTime::from);
ZonedDateTime zdt = odt.toZonedDateTime(); // containing a fixed offset