tl;博士
LocalDateTime.parse( // Parse a string lacking any indicator of time zone or offset-from-UTC into a `LocalDateTime` object.
"201710010200" , // Parse string in “basic” ISO 8601 format.
DateTimeFormatter.ofPattern( "uuuuMMddHHmm" ) // Define a formatting pattern to match the input. If you used expanded ISO 8601 format instead of “basic” you would not need to bother with this step.
).atZone( // Place the inexact unzoned value (`LocalDateTime` object) into the context of a time zone. Produces a `ZonedDateTime` object.
ZoneId.of( "Australia/Sydney" )
).toString() // Generate a string in standard expanded ISO 8601 format. This class extends the standard to wisely append the name of the zone in square brackets.
2017-10-01T03:00+11:00[澳大利亚/悉尼]
如果那个日期的那个时间在那个区域是无效的,ZonedDateTime 类会调整。
如果您担心输入错误,请捕获DateTimeParseException。
详情
Answer by Jon Skeet 是正确的。根据他的评论:没有时间是 2017 年 10 月 1 日悉尼当地时间凌晨 2 点。
java.time
现代解决方案是 java.time 类,它取代了麻烦的旧旧日期时间类。
解析
定义格式模式以匹配您的输入。
String input = "201710010200" ;
DateTimeFormatter f = DateTimeFormatter.ofPattern( "uuuuMMddHHmm" ) ;
LocalDateTime
您的输入缺少与 UTC 或时区偏移的指示符。所以解析为LocalDateTime。
LocalDateTime ldt = LocalDateTime.parse( input , f ) ;
ldt.toString(): 2017-10-01T02:00
如果没有时区上下文或与 UTC 的偏移,此值没有实际意义。它确实不代表一个时刻,时间轴上的一个点。对于大约 26-27 小时范围内的可能时刻,这只是一个模糊的概念。
要确定时刻,我们需要将此值放在时区或偏移的上下文中。
您声称知道该值旨在表示Australia/Sydney 时区中的时刻。
ZoneId z = ZoneId.of( "Australia/Sydney" ) ;
2017-10-01T03:00+11:00[澳大利亚/悉尼]
结果是 凌晨 3 点。当时那个地区的人们使用的offset-from-UTC在那个日期发生了变化,这是Daylight Saving Time (DST)愚蠢的一个切入点。当澳大利亚那个地区的时钟即将敲响凌晨 2 点时,时钟跳到了凌晨 3 点。凌晨 2 点在这片土地上从未存在过。 ZonedDateTime 类具有自动调整此类无效时刻的策略。请务必阅读文档,看看您是否理解enter link description here并同意其算法。
因为这个挂钟时间从未存在过,我怀疑你对代表Australia/Sydney 区域中的时刻的日志数据是不正确的。
UTC
这里更大的解决方案是学习在 UTC 中思考、工作、记录和交换数据。将 UTC 视为 One True Time,而所有其他时区只是该主题的变体。在工作编程/管理时忘记您自己的狭隘时区。
在java.time 中,UTC 值的基本类是Instant。 Instant 类代表UTC 时间线上的时刻,分辨率为nanoseconds(最多九 (9) 位小数)。
这个类可以捕捉UTC中的当前时刻。
Instant instant = Instant.now() ; // Capture the current moment in UTC.
ISO 8601
Instant 类还可以解析/生成标准ISO 8601 格式的字符串。
String output = Instant.now().toString() ;
“2018-01-23T12:34:56.734591Z”
末尾的Z 是Zulu 的缩写,表示UTC。这是您最初问题的症结所在:您存储的日期时间值没有这样的区域/偏移指标。
解析:
Instant instant = Instant.parse( "2018-01-23T12:34:56.734591Z" )
我强烈建议使用 ISO 8601 格式来存储/交换文本日期时间值。请务必:
-
在存储/交换时刻时包括偏移量/区域,时间轴上的精确点。
-
使用扩展格式,而不是这些“基本”格式,最大限度地减少分隔符的使用。这些很难被人类阅读,信息类型不太明显,并且默认情况下在 java.time 中不使用。 java.time 类默认使用扩展格式。
关于java.time
java.time 框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧 legacy 日期时间类,例如 java.util.Date、Calendar 和 SimpleDateFormat。
Joda-Time 项目现在位于maintenance mode,建议迁移到java.time 类。
要了解更多信息,请参阅Oracle Tutorial。并在 Stack Overflow 上搜索许多示例和解释。规格为JSR 310。
使用符合JDBC 4.2 或更高版本的JDBC driver,您可以直接与您的数据库交换java.time 对象。不需要字符串也不需要 java.sql.* 类。
从哪里获得 java.time 类?
ThreeTen-Extra 项目通过附加类扩展了 java.time。该项目是未来可能添加到 java.time 的试验场。您可以在这里找到一些有用的类,例如Interval、YearWeek、YearQuarter 和more。