java.time.Clock.systemDefaultZone().getZone() 与 java.util.TimeZone.getDefault().toZoneId() 之间有什么区别?

Any difference between java.time.Clock.systemDefaultZone().getZone() vs java.util.TimeZone.getDefault().toZoneId()?

鉴于java.time.Clock.systemDefaultZone().getZone()java.util.TimeZone.getDefault().toZoneId()return输出相同,两者之间有什么区别吗?

比如这段代码

import java.time.Clock;
import java.util.TimeZone;

public class Main {

  public static void main(String[] args) {
    System.out.println("Clock.systemDefaultZone().getZone() : " 
        + Clock.systemDefaultZone().getZone());
    System.out.println("TimeZone.getDefault().toZoneId() : " 
        + TimeZone.getDefault().toZoneId());
  }

}

returns 这个输出

Clock.systemDefaultZone().getZone() : Europe/Paris
TimeZone.getDefault().toZoneId() : Europe/Paris

查看 grepcode 上的源代码,他们最终执行完全相同的方法,导致相同的结果。 Clock.systemDefaultZone() 调用 ZoneId.systemDefault(),其中 returns TimeZone.getDefault().toZoneId():

http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8u40-b25/java/time/ZoneId.java#ZoneId.systemDefault%28%29

两者 return 都是 JVM 的默认时区(最后,Clock 调用 TimeZone.getDefault(),如 中所述),但不能保证所有调用总是 return 相同的值每次

那是因为可以更改默认时区:

  • JVM 所在的系统 运行ning 可以更改其配置。例如,在 Windows 机器中,这个 information is read from the registry,而在 Linux 中,它从 /etc/localtime(通常是 link 到 [=14= 中的特定文件) ]) 或另一个类似的文件夹(每个 version/distribution 可能有所不同),或者通过设置 TZ 环境变量。如果此系统配置更改并重新启动 JVM,您的代码突然开始 returning 不同的值
  • JVM can be configured to use a different timezone,无论 OS 的配置如何。一个例子是 maintanance/infrastructure 团队更改了此配置(有意或无意,通常没有告诉开发人员...),然后您的代码不再 return 相同的值(以及所有内容这取决于时区会突然中断)
  • 您的应用程序(或另一个应用程序 运行使用相同的 JVM)调用 TimeZone.setDefault() method。这将影响 运行 在同一 JVM 中 在 运行 时间 的所有应用程序,因此如果您 运行 此代码:

    TimeZone.setDefault(TimeZone.getTimeZone("Europe/London"));
    System.out.println(ZoneId.systemDefault());
    
    TimeZone.setDefault(TimeZone.getTimeZone("America/New_York"));
    System.out.println(ZoneId.systemDefault());
    
    TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
    System.out.println(ZoneId.systemDefault());
    

输出将是:

Europe/London
America/New_York
UTC

请注意默认时区在 运行 时是多么容易更改,所有后续获取它的调用都会受到影响。如果您调用 Clock.systemDefaultZone().getZone()TimeZone.getDefault().toZoneId(),也会发生同样的情况,因为两者都使用默认时区。

由于这会更改 JVM 的默认时区,因此 运行 同一 JVM 中的所有应用程序都将受其影响。这可能会导致难以调试的意外错误。

虽然使用默认时区的方法很方便,但您必须检查您的代码如何依赖它以及如果时区更改会如何影响它。

如果你不想依赖于默认值,理想的是使用特定的时区,例如ZoneId.of("Europe/Paris")。始终首选 IANA timezones names(始终采用 Region/City 格式,例如 America/New_YorkEurope/Paris)。 避免使用短缩写(如 CETCEST),因为它们是 ambiguous and not standard.

您可以通过调用 ZoneId.getAvailableZoneIds().

获取可用时区列表(并选择最适合您的系统的时区)