I have a Java program that runs on a linux virtual machine as a cron job. Currently there's an issue, the following line is used as part of logging to store the current date and time:
String date = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss").format(new Date());
After daylight savings today, it was determined the system date was not set up correctly as it did not update. After fixing this using the following command, and restarting the linux environment the date is now correct and updated for daylight savings time.
ln -s /usr/share/zoneinfo/America/New_York /etc/localtime
However, when the Java program executes as part of the cron job, the date is still an hour behind. This causes timing issues internally as new Date()
is used to get the current system time, which causes later problems in the process. For example at 5:00 PM, the Java program outputs 4:00 PM. Is there an additional consideration to this implementation? Shouldn't new Date()
always return the current system date?
Adding debugging lines to the cron job, this executes with the expected correct time.
Instant.now()
Date
classShouldn't new Date() always return the current system date?
Yes, the Date
class always captures the current moment in UTC. Let me repeat that: Date
captures the moment in UTC.
The trouble comes from a well-intentioned but unfortunate “feature” of that class’ toString
method where the JVM’s current default time zone is applied in generating that string. One of many reasons to avoid this outmoded and troublesome class.
I suspect that your “tzdata” time zone data file is outdated and not recognizing the new date for DST cutover.
Java implementations typically pick up their current default time zone from the host OS when launching. After the JVM, changing the host OS’ time zone has no effect on the JVM.
Restart the JVM to pick up a new zone setting in host OS.
Best practice is usually to set your servers to UTC. Then you do not need to worry about Daylight Saving Time nonsense.
The bulk of your programming, logging, cron jobs, data exchange, and data serialization should be in UTC.
Note, for example, how Stack Overflow uses UTC in reporting your activity for "today" and "yesterday". Learn to think of UTC as The One True Time; all zones are a variation on that theme.
Apply a time zone only where critical, such as in presentation to a user expecting a certain zone.
Remember that your problem was not due to the bending of space-time. The seconds, minutes, and hours continued to increment normally, tick-tock tick-tock, in terms of UTC. Your problem was in the mistranslation into a time zone with outdated time zone rule change data.
Your Java apps should always specify their desired/intended time zone explicitly. If omitted, the JVM’s current default time zone is implicitly applied.
That JVM default can be changed at any time by any code in any thread of any app within the JVM and immediately affect all other code in that JVM. So never depend on that current default for anything important. Confirm with the user, and specify explicitly in your code.
The old date time classes including Date
and Calendar
are a bloody mess. Avoid them. They are now legacy, supplanted by the java.time classes.
Instant
class is a moment on the time line with a resolution in nanoseconds, always in UTC.
Instant instant = Instant.now() ;
To generate a standard ISO 8601 formatted string, call toString
. The Z
on the end is short for Zulu and means UTC.
String output = instant.toString() ;
2017-01-23T12:34:56.123456789Z
Using those two simple lines of code would avoid your entire problem.
But you should be routinely updating the tzdata in: