如何确保java系统属性"user.timezone"被明确指定



我想确保我的Java程序始终通过显式指定的user.timezone属性运行。我将-Duser.timezone=XXX作为命令行设置传递。

但是,当我完全省略该系统属性,然后在程序中检查System.getProperty("user.timezone")的值时,它不是null,而是包含系统时区。因此,我不能终止我的程序,因为该属性的值永远不会为空。

我知道我可以使用自定义的系统属性名称(比如tz(来接受时区ID,然后在代码中执行TimeZone.setDefault(System.getProperty("tz")),但我更喜欢使用系统属性user.timezone,正是出于这个原因。

有什么方法可以使用user.timezone系统属性来实现我所需要的吗?

显式指定时区作为方法调用的参数

依赖JVM当前的默认时区本质上是不可靠的。JVM中任何应用程序的任何线程中的任何代码都可以随时通过调用TimeZone.setDefault来更改默认值。这样的调用会立即影响依赖该默认值的所有其他代码。

相反,请始终明确指定您希望/期望的时区。

此外,TimeZone已经过时,几年前被JSR310中定义的现代java.time类所取代。具体为ZoneIdZoneOffset。您可以将这些类的对象作为可选参数传递给所有相关方法。

ZoneId z = ZoneId.of( "Africa/Casablanca" ) ;
ZonedDateTime now = ZonedDateTime.now( z ) ;

UTC是唯一的真实时间

在服务器上,通常最佳做法是将主机操作系统和JVM的默认时区都设置为UTC(与UTC的偏移量为零(。

您的大部分业务逻辑、日志记录和调试也应该都在UTC中。

只需要一个时区:

  • 将显示本地化到用户时
  • 根据特定业务规则的要求

顺便说一句,属性user.timezone没有被列为Java 11中的标准默认属性之一。

我非常同意Basil Bourque的回答:您的解决方案是编写代码,使其独立于JVM默认时区。同样如注释中所述,当通过JDBC 4.2(或更高版本(在SQL数据库中使用java.time类型时,没有默认时区会干扰。

此外,据我所知,驱动程序倾向于使用数据库会话时区,而不是JVM默认时区。您可能需要搜索数据库文档和JDBC驱动程序文档,以找到控制会话时区的方法。

然而,按照要求回答您的问题:

String userTimezoneProp = System.getProperty("user.timezone");
boolean timezonePropertyEmpty = userTimezoneProp == null || userTimezoneProp.isEmpty();
if (timezonePropertyEmpty) {
System.err.println("You must set the user.timezone property to the same time zone as the database time zone.");
System.exit(-1);
}

只有您必须在执行任何使用默认时区的操作之前执行此操作。一旦执行了这样的操作,JVM将向操作系统查询默认时区,并相应地设置系统属性(如果成功(。

根据文档,对于尚未设置的系统属性,System.getProperty()应返回null。在本例中,我的Java返回了一个空字符串。所以我把这两种可能性都考虑在内。这可能是user.timezone的特别之处。我没有发现任何文档提到它。我仍然不能保证这个方法是防弹的。

最新更新