I can't find any specific docs to answer this question.
I wrote some simple test code to work out what actually happens on Java 1.8 on OS X 10.12:
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);
}
}
Both the old way (Calendar) and the new way (Java 8's Date and Time library) do not detect any change I make to the OS's timezone while the JVM is running. I need to stop and start the code to get the changed timezone.
Is this by design? Is this reliable behaviour across JVM implementations and operating systems?
TimeZone.getDefault()
specification is pretty clear about how it gets the time zone:
Gets the default TimeZone of the Java virtual machine. If the cached default TimeZone is available, its clone is returned. Otherwise, the method takes the following steps to determine the default time zone.
- Use the user.timezone property value as the default time zone ID if it's available.
- Detect the platform time zone ID. The source of the platform time zone and ID mapping may vary with implementation.
- Use GMT as the last resort if the given or detected time zone ID is unknown.
The default TimeZone created from the ID is cached, and its clone is returned. The user.timezone property value is set to the ID upon return.
The documentation states that the zone is cached; this method is affected by user.timezone system property and vice versa.
The specification also says that the cache is cleared by TimeZone.setDefault(null)
:
If zone is null, the cached default TimeZone is cleared.
That is, in order to re-read the system time zone, you have to
TimeZone.setDefault(null)
;user.timezone
system property by calling System.clearProperty("user.timezone");
Try the following test:
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);
}
I search for some of the JVM documentation related to this issue, but there isn't a thing which mentions that changes to the underlying OS are propagated to the JVM.
I think the TimeZone
class holds the answer. If you look in it, you will see that there is a private variable called defaultTimeZone
which holds the timezone which is used by default by the Date/Calendar instances. This variable is set in the methods setDefaultZone
and setDefault
.
The setDefaultZone
method is private and called only from the getDefaultRef
which is called from the Date/Calendar constructors. Here is the code from it:
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;
}
From this method, is obvious that any new instances of Date/Calendar will use an already set calendar instance and won't check if it's the same as the one the OS uses.
The setDefault
method is pretty straighforward, it just sets the defaultTimeZone
variable to a new value.
public static void setDefault(TimeZone zone) {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(new PropertyPermission("user.timezone", write"));
}
defaultTimeZone = zone;
}
Reading the documentation for this method you will read this statement: If zone is null, the cached default TimeZone is cleared
. This means that future calls to the getDefault
or getDefaultRef
will retrieve the latest OS timezone from reading it first from the user.timezone
property. If this property is empty, it will read the actual TimeZone of the system.
Knowing this things, I think it's safe to assume that changes to the OS timezone aren't propagated to the default TimeZone since that value is cached and never updated unless the client wishes to do it. The way I see it, there are two possible ways to do it:
TimeZone.setDefault
method while passing a desired timezone as the new default timezoneUse the following code to set it to the value your system uses:
System.setProperty("user.timezone", "");
TimeZone.setDefault(null);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With