tur*_*tia 3 java time timezone calendar date
我有一个桌面应用程序(必须在 Windows 中运行),它需要在执行特定操作时记录时间戳,但是我在调用日历时获得的时间带有错误的时间和正确的时区。运行一些测试,我发现如果我取消选中 Windows 时区设置上的“自动调整夏令时时钟”复选框,日历会提供正确的小时。Linux 上不存在此问题。不幸的是,我不允许在 Windows 机器上进行任何更改。
更多信息:
测试代码:
public class Test2 {
public static void main(String[] args) {
SimpleDateFormat sdfBase = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
long milisBase = Calendar.getInstance().getTimeInMillis();
Calendar calenBase = Calendar.getInstance();
Date fechaBase = calenBase.getTime();
String fechaStringBase = sdfBase.format(fechaBase);
TimeZone tzBase = Calendar.getInstance().getTimeZone();
System.out.println("Time (in mill): " + milisBase);
System.out.println("TimeZone: " + tzBase.getDisplayName() + " - " + tzBase.getID() + " -Offset: " + tzBase.getRawOffset());
System.out.println("Date Calendar: " + fechaBase);
System.out.println("Fecha StringBase: " + fechaStringBase);
}
}
Run Code Online (Sandbox Code Playgroud)获得以下结果:
选中“自动调整夏令时时钟”(Windows 时钟:17:50:07)
Time (in mill): 1464645007120
TimeZone: Chile Time - America/Santiago -Offset: -10800000
Date Calendar: Mon May 30 18:50:07 CLT 2016
Fecha StringBase: 30-05-2016 18:50:07
Run Code Online (Sandbox Code Playgroud)
取消选中“自动调整夏令时时钟”(Windows 时钟:17:50:37)
Time (in mill): 1464645037914
TimeZone: GMT-04:00 - GMT-04:00 -Offset: -14400000
Date Calendar: Mon May 30 17:50:37 GMT-04:00 2016
Fecha StringBase: 30-05-2016 17:50:37
Run Code Online (Sandbox Code Playgroud)
示例:当 windows 时钟读取 13:00:00(美国/圣地亚哥 -4:00)时执行该操作,但时间戳将时间标记为 14:00:00(美国/圣地亚哥 -3:00)。我取消选中Windows“自动调整夏令时时钟”,由于它不是 DST,Windows 时钟保持不变,我再次执行该操作,时间戳现在读取与 Windows 时钟相同的小时。
我发现了有关该时区的时区和 DST 变化的先前问题,但其中大部分是指 2015 年智利未更改为 DST 的问题。
有什么方法可以在不干预 Windows 机器的情况下解决这个问题?
智利当局在最后一刻更改了今年(2016 年)的时区规则。tzJava 中的数据库尚未更新。
详情如下。
您正在使用与早期 Java 捆绑在一起的旧日期时间类,这些类已被证明很麻烦。在 Java 8 及更高版本中,这些类被 java.time 框架(受 Joda-Time 库的启发)所取代。避免使用旧类。
程序员应该首先考虑UTC。始终验证 UTC 中的当前时间,以确保计算机甚至具有正确的时间。翻转时区和夏令时 (DST)更改会让您的大脑受到伤害,而 UTC 就是您的阿司匹林。
在 Java 8 及更高版本中,Instant该类以 UTC 时间表示时间轴上的一个时刻,分辨率为纳秒。
Instant now = Instant.now();
System.out.println( "Instant.now(): " + now );
Run Code Online (Sandbox Code Playgroud)
始终在诸如此问题的帖子中包含 UTC 值。
JVM 拥有自己的当前默认时区表示。默认情况下,在大多数实现中,该区域是从主机操作系统的时区设置中选取的。但是 Java 启动配置可以覆盖该默认值。并且 JVM 中任何应用程序的任何线程中的任何 Java 代码都可以在运行时通过调用TimeZone.setDefault.
所以主机操作系统的当前时区设置无关紧要。重要的是 JVM 中的当前设置。
您的主机操作系统的一部分做事情是,如果它的硬件时钟正确认识当前时刻。在大多数 JVM 实现中,当前时刻由主机硬件时钟确定,然后 JVM 应用其自己的当前默认时区。
政客们喜欢摆弄时区和夏令时 (DST)。智利也不例外。请参阅维基百科文章智利时间。
据我所知......去年,2015 年,智利将夏令时永久停留在 2015 年,-03:00并决定永远不会恢复到-04:00. 然后他们再次改变主意,在 2016 年 3 月宣布他们将重新引入冬季标准时间(南半球,现在是冬季,5 月下旬、6 月、7 月)。2016 年 5 月 15 日午夜(几周前),旧标准偏移量-04:00开始生效。该标准/冬季时间将持续到2016 年 8 月 14日(或直到他们再次改变主意)。[用一粒盐把这一切都带走。请确认我的事实是正确的。]
这些频繁的更改对需要更新tz时区数据库文件以反映最新版本的计算机造成了严重破坏。
您的操作系统有自己的时区定义副本。Java 有自己的副本。其他软件(例如您的数据库引擎)可能有自己的副本。
因此,让我们在 Java 8 Update 92 中运行一个测试,看看 的 Java 副本是否tz是最新的。
long millis = 1464645007120L;
Instant instant = Instant.ofEpochMilli ( millis ); // UTC, always.
ZoneId zoneId = ZoneId.of ( "America/Santiago" );
ZonedDateTime zdt = ZonedDateTime.ofInstant ( instant , zoneId );
Run Code Online (Sandbox Code Playgroud)
转储到控制台。
System.out.println ( "millis: " + millis + " | instant: " + instant + " | zoneId: " + zoneId + " | zdt: " + zdt );
Run Code Online (Sandbox Code Playgroud)
毫秒:1464645007120 | 即时:2016-05-30T21:50:07.120Z | zoneId:美国/圣地亚哥 | zdt: 2016-05-30T18:50:07.120-03:00[美国/圣地亚哥]
您可以看到最后一部分的偏移量为-03:00。因此,在我看来,不幸的是,4 月中旬发布的当前 Java 版本与 3 月宣布的智利更改不同步。
从我的阅读来看,今天(2016 年 5月30 日)的正确偏移量America/Santiago应该-04:00在time.is/Santiago上看到。
通常我会建议使用Javatzupdater工具。但是当前的下载标有这个词,2015所以我认为它也不是最新的。
我建议向 Oracle 的 Java 团队提交错误报告。
您可能需要一段时间才能获得tz数据库的更正版本(尽管您可能会破解自己的更新——我不知道)。在此之前,作为一种变通方法,也许您可以使用ZoneOffset该类在 Java 代码中指定您自己的偏移量,该类的子类ZoneId仅表示从 UTC 开始的偏移量,而没有任何针对 DST 等异常进行调整的规则。我没有考虑过其中的含义;警惕。
ZoneOffset zoneOffset = ZoneOffset.of( -4 ); // Negative four hours for '-04:00'.
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1431 次 |
| 最近记录: |