2016-09-12 50 views
5

我对java时间的时间处理感到困惑。我这么长时间的工作假设,如果一个时间戳被指定为祖鲁时间,java会照顾当地时间的偏移量。与Java时间解析混淆UTC

举例说明。我目前在BST中有UTC +1的偏移量。考虑到这一点,我希望这个祖鲁时间:

2016-09-12T13:15:17.309Z 

2016-09-12T14:15:17.309 

LocalDateTime解析之后。这是因为我的默认系统时间设置为BST,而上述时间戳(祖鲁时间)指定它是UTC时间。

而是然而考虑这个示例:

 String ts = "2016-09-12T13:15:17.309Z"; 
     LocalDateTime parse = LocalDateTime.parse(ts, DateTimeFormatter.ISO_DATE_TIME); 
     System.out.println(parse); 

这将打印:

2016-09-12T13:15:17.309 

所以时间戳,解析为一个LocalDateTime,不被识别为UTC时间,而不是为本地时间直接进行处理。 所以我想,也许我需要将其解析为ZonedDateTime并专门将其转换为LocalDateTime以获得正确的本地时间。有了这个测试:

 String ts = "2016-09-12T13:15:17.309Z"; 
     ZonedDateTime parse = ZonedDateTime.parse(ts, DateTimeFormatter.ISO_DATE_TIME); 
     System.out.println(parse); 
     System.out.println(parse.toLocalDateTime()); 

我得到的输出:

2016-09-12T13:15:17.309Z 
2016-09-12T13:15:17.309 

两个日期相同的输出。

正确解析这是我能找到的唯一方法,就是:

String ts = "2016-09-12T13:15:17.309Z"; 
    Instant instant = Instant.parse(ts); // parses UTC 
    LocalDateTime ofInstant = LocalDateTime.ofInstant(instant, ZoneId.systemDefault()); 
    System.out.println(instant); 
    System.out.println(ofInstant); 

此打印:

2016-09-12T13:15:17.309Z 
2016-09-12T14:15:17.309 

这是正确的。

所以问题(S)是:

  • 应该不是Java的时间认识一个UTC时间戳,并将其解析到正确的系统默认?
  • 如何使用LocalDateTime#parse方法获得正确的结果?
  • 现在我应该使用Instant来放弃所有的解析吗?

的问题是,jersey/jackson的Java模块时使用解析ISO格式和定期LocalDateTime#parse方法的时间戳。我意识到我的时代没有关闭,因为他们被视为LocalTime,而事实上他们在祖鲁时间。

回答

5

您误解了LocalDateTime的用途。

引述类文档:

甲日期 - 时间而不在​​ISO-8601的日历系统,时区,例如{@code 2007-12-03T10:15:30}。

...

此课程不存储或表示时区。相反,它是用于生日的日期的描述,结合在挂钟上看到的当地时间。如果没有附加信息(如偏移量或时区),它不能表示时间线上的瞬间。

所以它明确的目的只是代表日期和时间没有时区。它的作用是而不是表示日期和时间在当地时区

因此,每次转换只会剥去时区。

因此,为了您的目的,您需要一个ZonedDateTimeZoneId.systemDefault(),因为您已经在第三个示例中使用过。

你的第二个例子,这可能是:

String ts = "2016-09-12T13:15:17.309Z"; 
ZonedDateTime parse = 
    ZonedDateTime.parse(ts, DateTimeFormatter.ISO_DATE_TIME) 
     .withZoneSameInstant(ZoneId.systemDefault()); 
System.out.println(parse); 
System.out.println(parse.toLocalDateTime()); 
+0

你的例子看起来像它会做我的例子3的即时对话。你是对的,我误解了什么LocalDateTime代表。呃.. timezones :)谢谢 – pandaadb

+0

啊,所以ZonedDateTime将时区识别为“Z”,它自动解释为UTC(正是我想要的) - 是吗? – pandaadb

+0

@pandaadb是的,这可能只是写这个的另一种方式。 –

3

TL;博士

实施例:

Instant.parse("2016-09-12T13:15:17.309Z") 
     .atZone(ZoneId.of("Europe/London")) 
     .toString(); 

2016-09-12T14:15:17.309 + 01:00 [欧洲/伦敦]

Run in IdeOne.com

详细

Answer by Krüske是正确的。你误解了课堂上的意义。它确实是而不是代表特定地点的日期时间。恰恰相反,它不是而是代表一个实际的时刻。

我建议你想把Instant作为你在java.time中的基本构建块类。 Instant类表示UTC中时间轴上的一个时刻,分辨率为nanoseconds(小数点后最多九(9)位数字)。

输入字符串符合Instant类中默认使用的ISO 8601格式,用于解析和生成字符串表示。 Z最后是Zulu的缩写,意思是UTC。不需要指定格式化模式。

Instant instant = Instant.parse("2016-09-12T13:15:17.309Z"); 

作为一名程序员,您应该学会以UTC为主要思想和工作。忘记你自己的时区。将UTC视为一个真实的时间。将时区应用为变体,并且只根据需要进行。

continent/region的格式指定一个proper time zone name,如America/MontrealAfrica/Casablanca,或Pacific/Auckland。切勿使用3-4字母缩写,如BSTESTIST,因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!)。如果按BST您的意思是英国夏令时,那么实际的时区名称将是Europe/London。 java.time类将决定如何针对任何异常(包括夏令时(DST))进行调整。

ZoneId z = ZoneId.of("Europe/London"); 
ZonedDateTime zdt = instant.atZone(z); 

关于java.time

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

Joda-Time项目现在位于maintenance mode,建议迁移到java.time。请参阅Oracle Tutorial。并搜索堆栈溢出了很多例子和解释。规格是JSR 310

从何处获取java.time类?

ThreeTen-Extra项目与其他类扩展java.time。这个项目是未来可能增加java.time的一个试验场。您可以在这里找到一些有用的类,如Interval,YearWeek,YearQuartermore