Canada/Yukon timezone no longer observe DST (source https://www.timeanddate.com/time/change/canada/yukon) and is now permanently GMT-7. But when I tried this:
ZonedDateTime nowZoned = LocalDateTime.parse("2021-02-03T08:04:00").atZone(ZoneOffset.UTC).toInstant().atZone(ZoneId.of("Canada/Yukon"));
nowZoned is shown as 2021-02-03T00:04-08:00[Canada/Yukon].
Does it mean that java.time library does not update when some timezones have decided not to observe DST or decided to move ahead of the clock permanently? What are some ways to work around this issues? I thought about manually checking for these but there are simply way too many timezones to handle them manually. Thanks!
Yes indeed, the Yukon time zone rules changed in early 2020. The politicians there decided to stay on Daylight Saving Time (DST) indefinitely, using an offset of -07:00 year-round. So the sun will never again be overhead at noon.
Staying on DST year-round is the new fad among politicians around the world. Countries such as Morocco and Turkey have gone that way. Others are headed that way, such as Washington State in the United States.
Your code:
ZonedDateTime nowZoned = LocalDateTime.parse("2021-02-03T08:04:00").atZone(ZoneOffset.UTC).toInstant().atZone(ZoneId.of("Canada/Yukon"));
… is overwrought. Simply put a Z at the end of your input string if that date and time is intended to be a moment as seen in UTC.
ZonedDateTime zdt =
Inatant
.parse("2021-02-03T08:04:00Z")
.atZone(
ZoneId.of( "Canada/Yukon" )
)
;
You asked:
Does it mean that java.time library does not update when some timezones have decided not to observe DST or decided to move ahead of the clock permanently?
Politicians around the world have shown a predilection towards changing the rules of the time zones in their jurisdiction. They do so with surprising frequency. And some do so with astonishingly little forewarning.
The rules are stored in a tzdata file. When politicians change the rules, ICANN/IANA publishes a new updated version of the tzdata. This typically happens a few times a year.
And, no, there is no automatic immediate updating on your computer. As a SysAdmin or DBA, you are responsible for these updates. Of course, you need not update unless a time zone of interest to your company changes.
You will find at least two or three of these on your machines.
Your JVM has one embedded. Updates to the JVM will typically include the latest tzdata. But that Java update may not come soon enough. So you may need to manually obtain a tzdata file, ad replace the one in your JVM. Oracle provides a tool to assist. But I’m not aware of its current licensing terms, so study their terms. Or check with the vendor of your JVM such as Azul Systems, Adoptium, SAP, Amazon, Microsoft, BellSoft, Red Hat/IBM, etc.
Your host operating system such as macOS, BSD, Linux, Windows, etc. has a copy of the tzdata. While updating this tzdata does not affect your Java apps, you’ll want to update it for other apps.
Sophisticated database servers such as Postgres also keep their own internal copy of tzdata. Update as needed by either manual replacement or through an updated version of the DBMS.
Every SysAdmin & DBA should consider subscribing to the tzdata announcement mailing list.
Related
I would like to measure elapsed time in a Java. However differences in System.currentTimeMillis() and (I believe) System.nanoTime() can be changed by external changes eg someone (or the system) altering the system clock.
Using network calls is not an option as it's possible very frequent and fast returns are required.
Is there a common solution for this?
EDIT
Sorry, I should have elaborated about the reason. It isn't to stop malicious users - it's things like client initiated logout for being idle and routine client events.
This doesn't really answer your question, but bug #6458294 implies that where possible, Sun's implementation of nanoTime() will use mechanisms which are truly monotonic (CLOCK_MONOTONIC on Linux, QueryPerformanceFrequency/QueryPerformanceCounter on Windows). Only if these are unavailable will it fall back to a mechanism which is susceptible to system clock changes.
If you have control (or at least knowledge) of the hardware you're running on, and can ensure that these clock mechanisms will be available, you might be in luck and nanoTime() will do fine.
You may also like to read this blog post, which discusses the HotSpot-on-Windows case in more detail.
I don't think there is a way to do this.
There is certainly no way to do this that cannot be subverted. Fundamentally, you are at the mercy of the operating system and the JVM as to what is reported to the Java app as the current time. Either or both of these could be patched so that the Java code ends up getting a bogus timestamp value. You could try to defend against this, but then all the hacker needs to do is to patch your app to disable license checking entirely.
For the record, this "vulnerability" applies whether or not you are using Java.
If you're trying to stop people from subverting a license scheme by setting the clock back, you need to store the highest time you've seen so far in some sort of encrypted and secure storage, and then disable the program if either the time goes less than the highest you've seen (with some allowance for NTP clock adjustments and DST changes of course), or if they somehow tamper with or delete the secure store.
I don't know if nanoTime() is likely to change if the system clock changes, but I suppose it's possible. Also nanoTime() may not be accurate.
If you really need to guard against clock changes, you could monitor the clock in a thread. Sleep for 100ms or 1000ms, then call currentTimeMillis(). If clock advanced more then 1000 + x or has gone backwards then likely the clock changed (or the thread got hung up on something, which is possible).
In the event of a disjunction, you could actually make the network call to check. Of course, it's possible that network time might change due to the insertion of leap seconds. I once read a Slashdot comment by some scientists who was coordinating astronomical data from lots of different sources. A leap second was added during his experiment, and it basically ruined it because some sites inserted it and others didn't.
Another possibility might be to use a low level native API to get some other system timers. Such as system or network uptime to calibrate the API. Windows has the getTickCount() function that returns the number of milliseconds since boot. On unix systems you can use the uptime command to get a rough estimate. You can periodically check these values to see if the system clock has changed.
If you don't mind adding a bit of native code to your Java app, use:
QueryPerformanceCounter() and QueryPerformanceFrequency() on Windows; or
POSIX clock_gettime() function with CLOCK_MONOTONIC clock ID.
Note that the use of the x86 TSC register is discouraged on multiprocessor systems, so you better use the above APIs.
I know that is required because of changes that occurs after the release of the jdk/jre, but why don't get those informations from the server?
As "from the server" i mean from OS. The question is: "Why doesn't Java use the time zone system from the operating system instead of having its own copy of the time zone database"?
Here is my rough understanding. I believe it should at least give you the main reasons.
When Java was designed in the 1990s, a main design goal was that your Java program should be write once run anywhere, popularly abbreviated WORA. At that time cross-platform programs were not that commonplace. Porting your Windows program to a Mac or vice versa required quite some effort. Sun, the company that developed Java, was selling an operating system called Solaris, a Unix variant that not that many wanted to port to or from.
Different operating systems have different time zone data: different structure, different names for the time zones, different amounts of detail. Windows, for example, hasn’t got the full history of offsets for all time zones. What Mac and Unix had in the 1990s I don’t know. There were many Unix variants back then, and I am not even sure whether they all had built-in time zone information.
So relying on the operating system would mean that a program doing for example TimeZone.getTimeZone("America/Sao_Paulo") (using the time zone class from back then, now long outdated) would not be portable because on another operating system the time zone would not be called that. The write once run anywhere idea would be seriously harmed.
I suppose that this was the main reason for choosing that Java needed to have its own built-in time zone database, the same on all operating systems. I also believe that the choice of the Olson database, also known as tzdata, the zoneinfo database or IANA time zone database, was rather obvious. And from this choice came also the need for being able to update the timezone data, since the database is constantly evolving, especially since politicians around the globe are constantly (and eagerly, it would appear) deciding on new time zone rules.
Links for comparison:
List of tz database time zones
Windows Default Time Zones
Please notice that the former uses time zone IDs like America/Sao_Paulo, that is the region/city format, while the latter instead uses names like E. South America Standard Time.
I am running Three Quartz servers(as java wrapper services) from one Linux Virtual Server machine. My requirement is to run these servers in different time zone in one machine. e.g. Say there are three servers name A, B and C then A should schedule job based on Central Time zone, B should schedule jobs based on Eastern Time zone and so on. Is there any way we could achieve this?
Time zones are but concepts in Unix land. Each system clock should run with UTC, calculating displayed times based on the timezone you configure within the system.
Depending on which software should deal with that, it might be totally sufficient to set the TZ environment variable correctly.
I created three users for three different servers and set the desired time zones in .bashrc file. Say user name is user1 then do the following:
Open file /home/user1/.bashrc usinf any editor.
Modify and enter this line:
export TZ="/usr/share/zoneinfo/{TIMEZONE-DIRECTORY}/{TIMEZONE_FILE}"
Save the file.
Timezone is set for the user now.
If run this code in windows machine, its works properly:
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println(sdf.format(new Date()));
It shows date & time same as clock, but the same code if I run on Windows Server it's showing -2hrs of clock time.
I tried by the setting the timezone as,
TimeZone timeZone = TimeZone.getTimeZone("Europe/Vienna");
sdf.setTimeZone(timeZone);
Then, it shows same as clock time.
My doubt is why is it not taking the clock time zone by default in Windows Server.
It should always take the time zone of the running machine but in some case it fails as reported here and here. If you are sure that your server time zone is correct but Java uses a different one, you can force a default time zone of your choice from the command line:
-Duser.timezone="YOUR_TIME_ZONE_HERE"
or by code. You can also try with the Timezone Updater Tool by Oracle.
To see the time zone used by Java:
System.out.println(TimeZone.getDefault());
Time zone settings have no effect on a time value as the computer sees it. See my answer here for details. So long as the system time is set properly (regardless of time zone) and you don't need to display the time as text or parse the time from text, java will have no trouble and its calculations will be correct. If you do need to display/parse a time value, setting the default time zone is safe and it won't effect how times are stored, except of course Java will use that time zone to parse text representations of time that don't explicitly specify the time zone (like if you used the SimpleDateFormat in your example to parse, since the format string doesn't include the time zone).
As for why Java has this problem on your server box but not your desktop box, what version of Windows Server is it, and what version Java is running on the server? My guess is that the JVM can't unambiguously identify the OS version and therefore can't know for sure how to get the local time zone, so uses UTC as a fallback. Try updating your java version to the latest.
Another possibly is that the time zone on the server is set on a per-user basis. Verify that the time zone for the user/process that is running the app on the server is set properly.
There is a bug open at Oracle about that problem: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7044727. Basically it's because Java pulls the timezone out of the registry. And Windows saves it in HKLocalMachine, which is not the Client time but the time of the machine.
I had this issue after upgrading from 2003 server to 2008 server. Java keeps using GMT timezone instead of Windows Timezone setting. The solution is simple, go to Windows control panel and change to a different Timezone(whatever timezone is fine), then change it back. Took me hours to figure it out but it worked as charm.
My thought: the change triggerred something in Java, which correct the issue.
I would like to measure elapsed time in a Java. However differences in System.currentTimeMillis() and (I believe) System.nanoTime() can be changed by external changes eg someone (or the system) altering the system clock.
Using network calls is not an option as it's possible very frequent and fast returns are required.
Is there a common solution for this?
EDIT
Sorry, I should have elaborated about the reason. It isn't to stop malicious users - it's things like client initiated logout for being idle and routine client events.
This doesn't really answer your question, but bug #6458294 implies that where possible, Sun's implementation of nanoTime() will use mechanisms which are truly monotonic (CLOCK_MONOTONIC on Linux, QueryPerformanceFrequency/QueryPerformanceCounter on Windows). Only if these are unavailable will it fall back to a mechanism which is susceptible to system clock changes.
If you have control (or at least knowledge) of the hardware you're running on, and can ensure that these clock mechanisms will be available, you might be in luck and nanoTime() will do fine.
You may also like to read this blog post, which discusses the HotSpot-on-Windows case in more detail.
I don't think there is a way to do this.
There is certainly no way to do this that cannot be subverted. Fundamentally, you are at the mercy of the operating system and the JVM as to what is reported to the Java app as the current time. Either or both of these could be patched so that the Java code ends up getting a bogus timestamp value. You could try to defend against this, but then all the hacker needs to do is to patch your app to disable license checking entirely.
For the record, this "vulnerability" applies whether or not you are using Java.
If you're trying to stop people from subverting a license scheme by setting the clock back, you need to store the highest time you've seen so far in some sort of encrypted and secure storage, and then disable the program if either the time goes less than the highest you've seen (with some allowance for NTP clock adjustments and DST changes of course), or if they somehow tamper with or delete the secure store.
I don't know if nanoTime() is likely to change if the system clock changes, but I suppose it's possible. Also nanoTime() may not be accurate.
If you really need to guard against clock changes, you could monitor the clock in a thread. Sleep for 100ms or 1000ms, then call currentTimeMillis(). If clock advanced more then 1000 + x or has gone backwards then likely the clock changed (or the thread got hung up on something, which is possible).
In the event of a disjunction, you could actually make the network call to check. Of course, it's possible that network time might change due to the insertion of leap seconds. I once read a Slashdot comment by some scientists who was coordinating astronomical data from lots of different sources. A leap second was added during his experiment, and it basically ruined it because some sites inserted it and others didn't.
Another possibility might be to use a low level native API to get some other system timers. Such as system or network uptime to calibrate the API. Windows has the getTickCount() function that returns the number of milliseconds since boot. On unix systems you can use the uptime command to get a rough estimate. You can periodically check these values to see if the system clock has changed.
If you don't mind adding a bit of native code to your Java app, use:
QueryPerformanceCounter() and QueryPerformanceFrequency() on Windows; or
POSIX clock_gettime() function with CLOCK_MONOTONIC clock ID.
Note that the use of the x86 TSC register is discouraged on multiprocessor systems, so you better use the above APIs.