Java 爪哇时区和夏季-冬季

Java 爪哇时区和夏季-冬季,java,timezone,Java,Timezone,我们有一个java程序,它在启动时使用-Duser.timezone参数: -Duser.timezone=“CET” 这是必要的,因为我们不能依赖服务器的内部时钟(管理员到处玩,设置错误的时区等等,不要问:-(),前端的时区与后端匹配很重要 由于这个程序没有定期重新启动(它是一个服务器),我想知道当我们从冬季切换到夏季时会发生什么?它是自动切换还是我们必须重新启动服务器 感谢和问候, 亚历克斯 编辑:java可能通过对使用日期的函数的服务器调用来确定正确的时区。但也可能java在启动时确定正确

我们有一个java程序,它在启动时使用-Duser.timezone参数:

-Duser.timezone=“CET”

这是必要的,因为我们不能依赖服务器的内部时钟(管理员到处玩,设置错误的时区等等,不要问:-(),前端的时区与后端匹配很重要

由于这个程序没有定期重新启动(它是一个服务器),我想知道当我们从冬季切换到夏季时会发生什么?它是自动切换还是我们必须重新启动服务器

感谢和问候, 亚历克斯


编辑:java可能通过对使用日期的函数的服务器调用来确定正确的时区。但也可能java在启动时确定正确的时区。

我很确定设置
user.timezone
设置默认时区就像
timezone.setDefault()
。因此,它不会因夏令时或其他更改而更新


如果您真的必须这样做,我的建议是向您的服务器创建一个自定义请求,该请求可以通过调用
TimeZone.setDefault()来更改时区
。这样,您可以在需要时更改它,而无需重新启动服务器。显然,此请求需要得到保护,以便只有管理员可以执行它。

Java中的时间只是一个简单的长值(自1970年以来的毫秒)没有关于时区的任何信息。
java.util.Date
java.sql.Date
也将日期/时间存储为1970年以来的毫秒,但使用UTC时区

ZoneId zoneId = ZoneId.of( "Europe/Gibralter" ) ;
ZonedDateTime zdtGibralter = ZonedDateTime.now( zoneId ) ;
当您为输出设置日期/时间格式或从字符串解析日期/时间时,时区将发挥作用。您通过
-Duser设置的时区信息。此时将使用时区

因此,它应该可以工作,一个小测试也表明了这一点:

public static void main(String[] args) {
    Calendar c = Calendar.getInstance();
    c.set(2013, 2, 30, 23, 0, 0);
    long start = c.getTimeInMillis();
    long oneHour = 1000 * 60 * 60;
    long t = start;
    for (long i = 0; i < 5; i++) {
        System.out.println(new Date(t));            
        t = t + oneHour;
    }
}
使用
-Duser.timezone=CET
它将打印:(凌晨2点切换)

使用
-Duser.timezone=EET
它将打印:(东欧时间,CET后一小时)

CET
是一个虚拟区域 切勿使用2-4个字母的缩写,如
EST
IST
,因为它们不是真正的时区,也不是标准化的,甚至不是唯一的(!)

大陆/地区
大陆/地区
的格式指定,例如
美国/蒙特利尔
非洲/卡萨布兰卡
,或
太平洋/奥克兰

也许你所说的
CET
实际上指的是一个时区,例如
欧洲/卢森堡
欧洲/直布罗陀

ZoneId zoneId = ZoneId.of( "Europe/Gibralter" ) ;
TimeZone
类现在是遗留类,是与最早版本的Java捆绑在一起的糟糕的日期时间类的一部分。请只使用现代的Java.time类

为DST调整专有名称 由于这个程序没有定期重新启动(它是一个服务器),我想知道当我们从冬季切换到夏季时会发生什么

如果您使用如上所示的正确名称,并且在JVM安装中保持tzdata数据文件的最新状态,则在使用时会自动为您处理夏时制(DST)切换

让我们看看2020年春季DST切换期间发生的情况,即3月29日凌晨2点。我们在凌晨2点前一分钟获得时间。然后我们添加一分钟。请注意,由于DST在挂钟时间上的“提前春天”调整,一天中的时间从凌晨1:59跳到凌晨3点而不是凌晨2点

ZoneId z = ZoneId.of( "Europe/Gibraltar" ) ;
ZonedDateTime zdt = ZonedDateTime.of( 2020 , 3 , 29 , 1 , 59 , 0 , 0 , z ) ;
ZonedDateTime zdtMinuteLater = zdt.plusMinutes( 1 ) ;  // Notice how the time-of-day jumps to 3 AM rather than 2 AM.
转储到控制台

System.out.println( "zdt.toString(): " + zdt ) ;
System.out.println( "zdtMinuteLater.toString(): " + zdtMinuteLater ) ;
看这个

zdt.toString():2020-03-29T01:59+01:00[欧洲/直布罗陀]

zdtMinuteLater.toString():2020-03-29T03:00+02:00[欧洲/直布罗陀]

不要依赖违约 您可以编写不依赖JVM当前默认时区的代码

ZoneId zoneId = ZoneId.of( "Europe/Gibralter" ) ;
ZonedDateTime zdtGibralter = ZonedDateTime.now( zoneId ) ;
前面显示的代码行(
ZonedDateTime.now()
)不是我所建议的。该行省略了可选的
ZoneId
参数。相反,我建议始终传递所需/预期的时区

ZoneId zoneId = ZoneId.of( "Europe/Gibralter" ) ;
ZonedDateTime zdtGibralter = ZonedDateTime.now( zoneId ) ;

非常感谢您的详细回答和我问题的解决方案。
System.out.println( "zdt.toString(): " + zdt ) ;
System.out.println( "zdtMinuteLater.toString(): " + zdtMinuteLater ) ;
ZoneId zoneId = ZoneId.of( "Europe/Gibralter" ) ;
ZonedDateTime zdtGibralter = ZonedDateTime.now( zoneId ) ;