更改操作系统时区不会更改JVM默认时区

时间:2017-10-24 10:58:18

标签: java linux date timezone

我在Linux计算机上运行Java程序,但是当我使用System.out.println(new Date())时,它总是打印相同的时区(EAT),即使我更改了链接/etc/localtime到不同的时区,date命令显示正确的时区(由/etc/localtime引用的时区)。 我知道Date.toString()使用java默认时区,该时区必须与主机操作系统时区相同,但在我的情况下,这不会发生,因为JVM默认时区永远不会更改。 我的问题是:Java从哪里获取默认时区;即哪个文件或环境变量?

我正在使用红帽企业Linux服务器版本6.5(圣地亚哥)和openjdk 1.7

1 个答案:

答案 0 :(得分:4)

这已经在Stack Overflow上多次被覆盖,因此请搜索更多信息。

...简言之

不,java.util.Date 有时区。始终为UTC。不幸的是,它的toString方法在生成String时动态地应用JVM的当前默认时区,这是一个善意但不明智的反特征。更令人困惑的是:实际上埋藏在java.util.Date类中的时区,但与此讨论无关。混乱?确实。这些旧的日期时间类是糟糕的设计混乱。

避免使用这些麻烦的旧日期时间课程。它们现在已经遗留下来,取而代之的是java.time类。而不是Date在UTC中暂时使用java.time.Instant。对于其他区域,请应用ZoneId获取ZonedDateTime

  

我的问题是:Java从哪里获取

的默认时区

取决于Java的实现。

通常,默认设置是检测主机操作系统的当前默认时区,并将其复制为JVM的当前默认时区。启动JVM后,两者将分开。主机OS可以在不影响JVM的情况下更改其默认时区。反之亦然,JVM可能会更改其当前的默认时区而不会影响主机操作系统。但是,据我所知,这种行为依赖于实现,而不是JVM specification中的强制要求。

在启动期间传递给JVM的参数可以设置初始默认时区,以覆盖主机操作系统默认的检测。

注意:在运行时不可预测 - JVM中任何应用程序的任何线程中的任何代码都可能随时更改JVM的当前默认时区,从而立即影响该JVM的所有应用程序的所有代码。

因此,出于所有这些原因,您可以看到取决于默认时区是不明智的。最好总是传递可选的ZoneId参数,以明确指定所需/预期的时区。

通常,最佳做法是以UTC格式工作,思考,存储数据和交换数据。

Instant instant = Instant.now() ;  // Always in UTC. 

仅在需要时应用其他时区,例如向用户演示。

ZoneId z = ZoneId.of( "Africa/Casablanca" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;

生成或解析字符串时,java.time类使用标准的ISO 8601格式。对于其他格式,请使用DateTimeFormatter类。您可以选择在生成String期间动态应用格式化程序上设置时区。