我们有一个java程序,它在启动时使用-Duser.timezone参数:
-Duser.timezone = “CET”
这是必要的,因为我们不能依赖服务器内部时钟(管理员玩游戏,设置错误的时区等等,不要问:-()并且重要的是前端的时区与后端匹配
由于这个程序没有定期重启(它是服务器),我想知道当我们从冬季到夏季时会发生什么?它会自动切换还是我们必须重新启动服务器?
谢谢和问候, 亚历
编辑:java可能通过调用使用日期的函数来确定正确的时区。但是,启动时java也可能确定正确的时区。
答案 0 :(得分:2)
Java中的时间只是一个简单的长值(自1970年以来的毫秒),没有任何关于时区的信息。 java.util.Date
和java.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个字母的缩写,例如EST
或IST
,因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!)。
Continent/Region
以Continent/Region
的格式指定proper time zone name,例如America/Montreal
,Africa/Casablanca
或Pacific/Auckland
。
也许CET
实际上是指一个时区,例如Europe/Luxembourg
或Europe/Gibraltar
。
ZoneId zoneId = ZoneId.of( "Europe/Gibralter" ) ;
TimeZone
类现在已成为旧版,它是与最早的Java版本捆绑在一起的可怕的日期时间类的一部分。只能使用现代的 java.time 类。
由于该程序没有定期重新启动(它是服务器),所以我想知道当我们从冬季切换到夏季时会发生什么情况?
如果使用上面显示的专有名称,并且在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 ) ;