tl;博士
LocalDateTime
.parse(
"20190310022817" ,
DateTimeFormatter.ofPattern( "uuuuMMddHHmmss" )
)
.atZone(
ZoneId.of( "America/Montreal" )
)
结果是凌晨 3 点而不是凌晨 2 点。针对 DST 进行调整的功能,而不是错误。
2019-03-10T03:28:17-04:00[美国/蒙特利尔]
如果您的目标是拒绝此类无效输入而不是调整它们,请参阅my Answer 另一个解释ResolverStyle 枚举的问题:LENIENT, SMART,&STRICT。
避免使用旧的日期时间类
您正在使用糟糕的日期时间类,这些类在几年前已被现代 java.time 类所取代。
夏令时 (DST)
正如Answer by rgettman 中所指出的,一些疯狂到可以参与Daylight Saving Time (DST) 的司法管辖区正在您给定日期 3 月 10 日凌晨 2 点进行“提前”跳跃。这种情况发生在美国和加拿大的大部分地区,也许还有其他地方。请参阅有关 DST in the United States 的维基百科。
在这些地点,没有凌晨 2 点。当时钟敲响凌晨 2 点时,时钟立即跳到凌晨 3 点。两点钟的时间从未存在过。
顺便说一下,DST 并不是时钟更改的唯一方案。世界各地的政客都表现出在他们的管辖范围内搞乱UTC偏移量的倾向。例如,参见近年来的朝鲜、委内瑞拉、土耳其和俄罗斯。现在美国的一些州正在选择停止 DST 废话,尽管有些州正在考虑永久保留 DST。关键是,为了稳健地处理日期时间,无论当前的做法如何,您都应该始终假设政治家将在未来的某个时候做出改变,并相应地进行编码。
您的输入无效(可能)
你使用的遗留类可能会拒绝你的输入,因为你的 JVM 当前默认时区中的 DST 跳转是由于你没有指明时区而隐式应用的。这种解析有效值的严格协议并没有错,只是处理无效输入的一种方法。
ZonedDateTime 类默认使用另一种方法,根据需要进行调整。
ZonedDateTime
java.time.ZonedDateTime 类知道时区过去、现在和未来对特定地区人们使用的偏移量的变化的历史。这样该类将自动调整。请务必阅读课程文档,以便了解并同意其调整协议。
LocalDateTime
这是一些示例代码。首先,我们将您的输入解析为LocalDateTime,因为您的输入缺少任何时区指示或与UTC 的偏移量。因此,LocalDateTime 确实 不 代表一个时刻,不是时间轴上的一个点。因此,如果已知时区是针对该日期和时间的,我们可以应用ZoneId 来获得ZonedDateTime。
在此示例中,我们任意选择两个区域来应用,因此您可以看到不同的结果。在美国,3 月 10 日是夏令时跳跃的日子。在法国等欧洲大部分地区,跳跃计划在三月的最后一天晚些时候进行。所以凌晨 2 点在法国是有效时间,但在美国却不是。
String input = "20190310022817";
DateTimeFormatter f = DateTimeFormatter.ofPattern( "uuuuMMddHHmmss" ) ;
LocalDateTime ldt = LocalDateTime.parse( input , f ) ;
ZoneId zParis = ZoneId.of( "Europe/Paris" ) ;
ZonedDateTime zdtParis = ldt.atZone( zParis ) ;
ZoneId zNewYork = ZoneId.of( "America/New_York" ) ;
ZonedDateTime zdtNewYork = ldt.atZone( zNewYork ) ;
转储到控制台。
System.out.println( "ldt.toString(): " + ldt ) ;
System.out.println( "zdtParis.toString(): " + zdtParis ) ;
System.out.println( "zdtNewYork.toString(): " + zdtNewYork ) ;
运行时。请参阅此code run live at IdeOne.com。注意这三个输出中每一个的小时数:
ldt.toString(): 2019-03-10T02:28:17
zdtParis.toString(): 2019-03-10T02:28:17+01:00[欧洲/巴黎]
zdtNewYork.toString(): 2019-03-10T03:28:17-04:00[America/New_York]
关于java.time
java.time 框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧 legacy 日期时间类,例如 java.util.Date、Calendar 和 SimpleDateFormat。
要了解更多信息,请参阅Oracle Tutorial。并在 Stack Overflow 上搜索许多示例和解释。规格为JSR 310。
Joda-Time 项目现在位于maintenance mode,建议迁移到java.time 类。
您可以直接与您的数据库交换 java.time 对象。使用符合JDBC 4.2 或更高版本的JDBC driver。不需要字符串,不需要java.sql.* 类。
从哪里获得 java.time 类?
ThreeTen-Extra 项目通过附加类扩展了 java.time。该项目是未来可能添加到 java.time 的试验场。您可以在这里找到一些有用的类,例如Interval、YearWeek、YearQuarter 和more。