Java 运行中的JVM是否检测到计算机的更改';什么时区?
我找不到任何具体的文档来回答这个问题 我编写了一些简单的测试代码,以了解在OS X 10.12上的Java 1.8上实际发生了什么:Java 运行中的JVM是否检测到计算机的更改';什么时区?,java,jvm,Java,Jvm,我找不到任何具体的文档来回答这个问题 我编写了一些简单的测试代码,以了解在OS X 10.12上的Java 1.8上实际发生了什么: public static void main(String[] _args) throws InterruptedException { while (true) { int calendarTimezoneOffset = Calendar.getInstance().get(Calendar.ZONE_OFFSET);
public static void main(String[] _args) throws InterruptedException {
while (true) {
int calendarTimezoneOffset = Calendar.getInstance().get(Calendar.ZONE_OFFSET);
System.out.println("calendarTimezoneOffset = " + calendarTimezoneOffset);
ZoneOffset offset = ZonedDateTime.now().getOffset();
System.out.println("offset = " + offset);
Thread.sleep(1000);
}
}
旧方式(日历)和新方式(Java8的日期和时间库)在JVM运行时都没有检测到我对操作系统时区所做的任何更改。我需要停止并启动代码以获取更改的时区
这是故意的吗?跨JVM实现和操作系统的这种行为可靠吗?规范非常清楚它是如何获得时区的:
获取Java虚拟机的默认时区。如果缓存的
默认时区可用,将返回其克隆。否则
方法采取以下步骤来确定默认时区
- 使用user.timezone属性值作为默认时区ID(如果可用)
- 检测平台时区ID。平台时区的来源和ID映射可能因实现而异
- 如果给定或检测到的时区ID未知,则使用GMT作为最后手段
TimeZone.setDefault(null)
清除时区缓存李>
system.clearProperty(“user.timezone”);清除user.timezone
system属性代码>
while (true) {
TimeZone.setDefault(null);
System.clearProperty("user.timezone");
System.out.println("Offset = " + TimeZone.getDefault().getRawOffset() / 3600);
System.out.println("Zone ID = " + System.getProperty("user.timezone"));
Thread.sleep(1000);
}
我搜索了一些与此问题相关的JVM文档,但没有任何内容提到对底层操作系统的更改会传播到JVM 我认为
TimeZone
类持有答案。如果查看它,您将看到有一个名为defaultTimeZone
的私有变量,它保存日期/日历实例默认使用的时区。此变量在方法setDefaultZone
和setDefault
中设置
setDefaultZone
方法是私有的,仅从从日期/日历构造函数调用的getDefaultRef
调用。下面是它的代码:
static TimeZone getDefaultRef() {
TimeZone defaultZone = defaultTimeZone;
if (defaultZone == null) {
// Need to initialize the default time zone.
defaultZone = setDefaultZone();
assert defaultZone != null;
}
// Don't clone here.
return defaultZone;
}
从这个方法可以明显看出,日期/日历的任何新实例都将使用已设置的日历实例,并且不会检查它是否与操作系统使用的相同
setDefault
方法非常简单,它只是将defaultTimeZone
变量设置为一个新值
public static void setDefault(TimeZone zone) {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(new PropertyPermission("user.timezone", write"));
}
defaultTimeZone = zone;
}
阅读此方法的文档时,您将阅读以下语句:如果zone为null,则缓存的默认时区将被清除
。这意味着以后对getDefault
或getDefaultRef
的调用将首先从user.timezone
属性读取最新的OS时区。如果此属性为空,它将读取系统的实际时区
知道了这一点,我认为可以安全地假设对OS时区的更改不会传播到默认时区,因为该值是缓存的,并且永远不会更新,除非客户端希望这样做。在我看来,有两种可能的方法:
TimeZone.setDefault
方法,同时将所需时区传递为新的默认时区System.setProperty(“user.timezone”,”);
TimeZone.setDefault(空)代码>
哇,另一种方式,时区可以刺伤我们的背部…我认为这是一种假设,即计算机在单个程序运行期间不会在时区之间移动。虽然这已经不符合要求了。。。我认为当操作系统改变时区时,当前的JVM不会改变时区。(不是JVM,但可能值得检查Android是如何做到这一点的…)我认为这可以归类为JVM错误。JVM对时区一无所知(规范从未提及它们,VM也不需要这些信息),与时区有关的一切都是平台API的一部分,也就是说,它是在类中实现的,如
java.util.Timezone
,java.util.Calendar
或java.time
-packages`。但是我没有发现定义这些类在更改时区时的行为的任何东西,因此,虽然在VM运行时不更改默认时区似乎是当前Java实现的行为,但这是无法保证的。有人知道时区缓存的位置吗?@Laurent.B在静态字段中,好的,仅此而已,不在磁盘上?我可以看到你在时区来源中所说的,但我在时区中面临着奇怪的行为,这就是为什么我怀疑,但你一定是对的。非常感谢。