Recently I created a VM on Google Cloud Platform to run my .jar 24/7, and a part of my code is like:
if (LocalTime.now().getHour() == 0)
whenDateChanged();
I noticed that it runs at 12 am UTC+0, but I want it to run at 12 am UTC+8, so I use this command in terminal to change the time zone of my server:
sudo timedatectl set-timezone "Asia/Taipei"
After I reboot my server, the whenDateChanged()
stills runs at 8 am UTC+8, why did this happened?
Java version: 21.0.3
OS: Debian GNU/Linux, 12 (bookworm)
2
Answers
Certainly! Here’s a revised explanation in a more conversational tone:
The reason
LocalTime.now()
still returns the same value even after changing the server’s time zone is becauseLocalTime
doesn’t actually consider time zones. It simply reflects the current time according to the system clock, regardless of the time zone setting on your server.To ensure your code respects the new time zone (
Asia/Taipei
), you need to useZonedDateTime
instead ofLocalTime
. Here’s how you can adjust your code:In this updated code:
ZonedDateTime.now(ZoneId.of("Asia/Taipei"))
gives you the current date and time in theAsia/Taipei
time zone..getHour()
retrieves the hour part of the current time in Taipei time.whenDateChanged()
method is triggered correctly at midnight (00:00) in Taipei time (UTC+8).By using
ZonedDateTime
, you’re explicitly telling Java to consider the specified time zone (Asia/Taipei
), which will reflect the change you made usingtimedatectl
on your server.This approach should resolve the issue and align with your requirement to run
whenDateChanged()
at midnight in UTC+8 (Taipei time) after changing the server’s time zone setting.Hope this helps clarify things for you!
tl;dr
Specify time zone in Java
You omitted the time zone argument to that method call. So Java implicitly applied the JVM’s current default time zone.
Depending on such a default pits the success of your app against the whims of a system administrator who mach change that default.
I suggest you instead specify explicitly your desired/expected time zone.
First, get the name of your desired time zone. Real time zones have a name in the format of
Continent/Region
.Since you mentioned an interest in an offset of eight hours ahead of UTC, I arbitrarily chose
Asia/Singapore
. That zone is currently using an offset of +08:00.No, no, no.
Just ignore the time zone of your server. Write your Java code to always specify your desired/expected time zone, as shown above.
And, by the way, servers should generally be set to UTC (an offset of zero hours-minutes-seconds). Programmers and sysadmins should both learn to think of UTC (an offset of zero) to be the One True Time. All time zones are but a variation.
Generally, all your logging, data exchange, data storage, and business logic should be in UTC unless there is a clear and present reason otherwise. I suggest programmers & sysadmins keep a clock on their desk set to UTC. Trying to work, and convert to/from, your parochial time zone is confusing, error-prone, and distracting. While on the job, think in UTC.
Since your current code implicitly relies upon the JVM’s current default time zone, your need to examine the JVM’s current default time zone, not the host operating system’s current default time zone.
Some JVM implementations may set their current default time zone to be that of the host OS, as detected at launch. But this is not necessarily the case. For example, the admin launching the JVM at deployment may be specifying a time zone for the JVM to use as its default. I have no idea what Google Cloud Platform may be doing.
👉🏽 The real solution is to not depend on the host OS’s current default time zone, nor the JVM’s current default time zone. Instead, specify a time zone.