java时区和夏天 - 冬天

时间:2013-02-20 11:57:39

标签: java timezone

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

-Duser.timezone = “CET”

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

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

谢谢和问候, 亚历

编辑:java可能通过调用使用日期的函数来确定正确的时区。但是,启动时java也可能确定正确的时区。

3 个答案:

答案 0 :(得分:2)

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

当您格式化输出的日期/时间或从字符串解析日期/时间时,时区开始起作用。您将通过-Duser.timezone设置的时区信息将在当时使用。

所以它应该工作,一点点测试也显示它:

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=GMT它将打印:(无开关)

Sat Mar 30 23:00:00 GMT 2013
Sun Mar 31 00:00:00 GMT 2013
Sun Mar 31 01:00:00 GMT 2013
Sun Mar 31 02:00:00 GMT 2013
Sun Mar 31 03:00:00 GMT 2013

使用-Duser.timezone=CET它将打印:(凌晨2点切换)

Sat Mar 30 23:00:00 CET 2013
Sun Mar 31 00:00:00 CET 2013
Sun Mar 31 01:00:00 CET 2013
Sun Mar 31 03:00:00 CEST 2013
Sun Mar 31 04:00:00 CEST 2013

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

Sat Mar 30 23:00:00 EET 2013
Sun Mar 31 00:00:00 EET 2013
Sun Mar 31 01:00:00 EET 2013
Sun Mar 31 02:00:00 EET 2013
Sun Mar 31 04:00:00 EEST 2013

答案 1 :(得分:0)

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

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

答案 2 :(得分:0)

CET是伪区域

请勿使用2-4个字母的缩写,例如ESTIST,因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!)。

Continent/Region

Continent/Region的格式指定proper time zone name,例如America/MontrealAfrica/CasablancaPacific/Auckland

也许CET实际上是指一个时区,例如Europe/LuxembourgEurope/Gibraltar

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

TimeZone类现在已成为旧版,它是与最早的Java版本捆绑在一起的可怕的日期时间类的一部分。只能使用现代的 java.time 类。

专有名称针对DST进行调整

由于该程序没有定期重新启动(它是服务器),所以我想知道当我们从冬季切换到夏季时会发生什么情况?

如果使用上面显示的专有名称,并且在JVM安装中保持 tzdata 数据文件为最新,则将自动处理夏令时(DST)转换,用于ZonedDateTime时使用您。

ZonedDateTime zdt = ZonedDateTime.now() ;  // Omitting the optional `ZoneId` argument means the JVM’s current default time zone is implicitly applied, looking up the current offset in use at this moment for the JVM's current default time zone.

让我们看看3月29日凌晨2点在2020年春季DST转换期间发生了什么。我们将时间定在凌晨2点一分钟。然后我们添加一分钟。请注意,由于DST时钟的提前调整,一天中的时间从1:59 AM跳到3 AM ,而不是2 AM。

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 ) ;

请参阅此code run live at IdeOne.com

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

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

不要依赖默认值

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

前面显示的代码行(ZonedDateTime.now())不是我建议的 。该行省略了可选的ZoneId参数。相反,我建议始终通过您希望的/预期的时区。

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