Java日历在MS Windows中返回的'America/Santiago'区域的时间错误
我有一个桌面应用程序(必须在Windows中运行),在执行特定操作时需要记录时间戳,但调用日历时得到的时间带有错误的小时和正确的时区。 运行我发现的一些测试时,如果我取消选中windows时区设置上的“自动调整夏令时时钟”复选框,日历将提供正确的小时数。Linux上不存在此问题。不幸的是,我不允许在windows计算机上进行任何更改 更多信息:Java日历在MS Windows中返回的'America/Santiago'区域的时间错误,java,date,time,calendar,timezone,Java,Date,Time,Calendar,Timezone,我有一个桌面应用程序(必须在Windows中运行),在执行特定操作时需要记录时间戳,但调用日历时得到的时间带有错误的小时和正确的时区。 运行我发现的一些测试时,如果我取消选中windows时区设置上的“自动调整夏令时时钟”复选框,日历将提供正确的小时数。Linux上不存在此问题。不幸的是,我不允许在windows计算机上进行任何更改 更多信息: 在windows时钟中设置时区:“美国/圣地亚哥”(-4:00) 测试代码: public class Test2 { public sta
- 在windows时钟中设置时区:“美国/圣地亚哥”(-4:00)
- 测试代码:
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); } }
tz
数据库尚未更新
详情如下
java.time
您正在使用与早期Java捆绑在一起的旧日期时间类,这些类已被证明很麻烦。在Java8和更高版本中,这些类被Java.time框架(受Joda时间库启发)取代。避免上旧课
关注UTC
程序员应该首先考虑问题。始终确保计算机的时间正确。翻转时区和变化会让你的大脑受伤,UTC是你的阿司匹林
在Java8及更高版本中,该类以UTC表示时间线上的一个时刻,分辨率为纳秒
Instant now = Instant.now();
System.out.println( "Instant.now(): " + now );
始终在诸如此问题的帖子中包含UTC值
主机操作系统的时区并不重要
JVM拥有自己的当前默认时区表示。默认情况下,在大多数实现中,该区域是从主机操作系统的时区设置中选取的。但是Java启动配置可以覆盖默认设置。JVM中任何应用程序的任何线程中的任何Java代码都可以在运行时通过调用更改JVM的当前默认时区
因此,主机操作系统的当前时区设置是不相关的。重要的是JVM中的当前设置
主机操作系统的重要部分在于其硬件时钟是否正确地知道当前时刻。在大多数JVM实现中,当前时刻由主机硬件时钟确定,然后JVM应用其自己的当前默认时区
2016年初智利重新定义时区
政客们喜欢摆弄时区和时间。智利也不例外。请参阅维基百科文章
据我所知……去年,即2015年,智利在-03:00
永久停留在DST上,并决定永远不再回到-04:00
的标准时间。然后他们又改变了主意,他们将重新引入冬天的标准时间(南半球,现在是冬天,5月底,6月,7月)。2016年5月15日午夜(几周前),旧的标准偏移量-04:00
开始生效。标准/冬季时间将持续到2016年8月14日(或直到他们再次改变主意)。[对所有这些都不屑一顾。请证实我的事实是正确的。]
这些频繁的变化对计算机造成了巨大的破坏,计算机需要更新其文件以反映最新的变化
您的操作系统有自己的时区定义副本。Java有自己的副本。和其他软件,如您的数据库引擎,可能有自己的副本
当前的Java8更新92缺少最近的更改
因此,让我们在Java8Update92中运行一个测试,看看tz
的Java副本是否是最新的
long millis = 1464645007120L;
Instant instant = Instant.ofEpochMilli ( millis ); // UTC, always.
ZoneId zoneId = ZoneId.of ( "America/Santiago" );
ZonedDateTime zdt = ZonedDateTime.ofInstant ( instant , zoneId );
转储到控制台
System.out.println ( "millis: " + millis + " | instant: " + instant + " | zoneId: " + zoneId + " | zdt: " + zdt );
米利斯:1464645007120 |即时:2016-05-30T21:50:07.120Z |地区:美洲/圣地亚哥| zdt:2016-05-30T18:50:07.120-03:00[美洲/圣地亚哥]
您可以看到最后一部分中的偏移量是-03:00
。因此,在我看来,不幸的是,该计划没有跟上智利3月份宣布的变化
从我的读数来看,今天(2016-05-30)美国/圣地亚哥的正确偏移量应该是-04:00
,如图所示
通常我会建议使用。但是这个标签上有单词2015
,所以我认为它也不是最新的
我建议在Oracle的Java团队提交一份bug报告
变通办法
您可能需要一段时间才能获得tz
数据库的正确版本(尽管您可能需要修改自己的更新,我不知道)。在此之前,作为一种解决方法,您可能可以使用类在Java代码中指定自己的偏移量,该类是的一个子类,只表示与UTC的偏移量,而不需要任何规则来调整异常,例如DST。我还没有想清楚其中的含义;小心点
ZoneOffset zoneOffset = ZoneOffset.of( -4 ); // Negative four hours for '-04:00'.
提供您的代码。第一个实例名为“calen”,而日期是从“calendar”读取的。两个实例可能使用不同的配置。或者你需要更新到真实的代码。getInstance是一个函数调用,我甚至看不到这段代码是如何通过编译器的,忘记了其中固有的运行时错误。我将为测试用例和
System.out.println ( "millis: " + millis + " | instant: " + instant + " | zoneId: " + zoneId + " | zdt: " + zdt );
ZoneOffset zoneOffset = ZoneOffset.of( -4 ); // Negative four hours for '-04:00'.