Java: ver 1.7 update 71 DB: MySQL ver 5.6.x
We are having multiple applications running accessing same DB. Two applications are running on Tomcat 7 (ver 7.0.52) and
tzdata
Time zone data is nearly always defined by the tz database, formerly known as the Olson Database, now handled by IANA. This database has a history of past, present, and future changes in offset-by-UTC used by the people of each region (time zone) around the globe.
This databases changes frequently, as politicians around the world are inexplicably drawn to making frequent changes. The changes are often made with little forewarning, as little as several weeks ahead.
When the restless politicians make their changes, if you care about the affected zones, you need to update the “tzdata” of both your operating system (for native apps) and your Java implementation (for Java apps). Oracle provides the Timezone Updater Tool to install a fresh tzdata to their implementation. Updated versions from Oracle usually include the latest tzdata, but not always, so you should read the release notes for such details. With the new planned quarterly release cadence for Oracle & OpenJDK implementations, the need for manual installs of tzdata may decrease if you choose stay up-to-date with the Java releases.
So when a time zone that you care about has its definition changed, you’ll likely need to change the tzdata
in at least three places:
The Java using time zone details of the underlying OS.
No. The source of time zone details comes is an implementation-detail for each Java implementation.
In the JVM implementations I know of, the JVM determines the current default time zone by asking the host OS as part of the JVM launching. As a part of launching, a default time zone may have been passed as a startup parameter to the JVM. Thirdly, any code in in any thread of any app at any moment during runtime may change the default time zone (this is almost never a good idea).
But in all these cases, the definition of the zones is stored within the JVM itself. So you need to keep the JVM’s tzdata
up-to-date if any zones of interest have have changed.
ones running on Netty continued to run one hour behind …
Once restarted, they started showing the right time.
Without seeing the programming for your apps, and without seeing the programming of Netty, we can only guess as to the specific problem. I suspect the app may be failing to handle date-times properly.
The proper way to capture a moment is to do so in UTC. In Java, that means the Instant
class. The Instant class represents a moment on the timeline in UTC with a resolution of nanoseconds (up to nine (9) digits of a decimal fraction).
Instant instant = Instant.now() ; // Capture current moment in UTC.
Alternatively, you could capture the moment for a particular time zone.
ZoneId z = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = ZonedDateTime.now( z );
Your app may be using a mere offset-from-UTC cached when the app launched.
ZoneOffset offset = ZoneOffset.systemDefault() ; // Do NOT cache this, as it will be invalid after a DST cut-over.
A time zone is always preferable to a mere offset-from-UTC. An offset is simply a number of hours, minutes, and seconds – nothing less, nothing more. In contrast, a time zone is a history of past, present, and future changes in offset used by the people of a particular region.
If an app detected the offset currently in use when launched, and cached that offset indefinitely, its use would no longer be correct after a Daylight Saving Time (DST) cut-over.
For example, currently in America/Los_Angeles
zone, the offset-from-UTC is eight hours behind UTC, -08:00
. But in several days, on the second Sunday in March, the DST nonsense takes effect, when everyone sets their clocks ahead an hour, thereby changing the offset-from-UTC in use to seven hours behind UTC, -07:00
. If that -08:00
had been inappropriately cached, the attempts at capturing the current moment will be incorrect.
OffsetDateTime odt = OffsetDateTime.now( inappropriatelyCachedOffset ) ; // Capturing the wrong wall-clock time.
Again, the prophylactic is simple… Use time zone, not offset-from-UTC.
Specify a proper time zone name in the format of continent/region
, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland
. Never use the 3-4 letter abbreviation such as EST
or IST
as they are not true time zones, not standardized, and not even unique(!).
tzdata
not updatedAnother possible cause of your apparent behavior might be your app getting the current zoned date-time from a database server where the database’s own tzdata
is now outdated, not yet updated to reflect changes in that zone’s definition.
As discussed up above, some sophisticated databases such as Postgres have their own internally-stored tzdata
information. The prophylactic is to either keep the database server up-to-date with its version updates, or manually install an updated tzdata
.
This is also yet another reason to think, work, log, store, and exchange date-time values in UTC. Throughout this discussion of problems, the clock may have been set correctly to the current time. It is the interpretation of that time through a zone where things may have gone wrong. If the current had been captured in UTC, there would be no adjustment into a time zone, and therefore no problem.
So learn to think in UTC. While on the job as a programmer or administrator, forget about your own parochial time zone. Keep a second clock on your desk set to UTC. Do all your logging and note-taking in UTC. Think of UTC as the One True Time, with all other zoned times being but mere variations.
Again, Instant.now()
is your friend.
When you need to serialize a date-time value, use the standard ISO 8601 formats only. This standard was cleverly designed to be practical and sensible. The formats are easy to parse by machine yet also easy to read by humans across cultures.
For a moment in UTC, the format is YYYY-MM-DDTHH:MM:SS.SZ. The T
in the middle separates year-month-day from hour-minute-second. The Z
on the end is short for Zulu
and means UTC.
2018-01-23T12:34:56.123456789Z
The java.time classes use ISO 8601 formats by default when parsing/generating strings.
String output = instant.toString() ;
…and…
Instant instant = Instant.parse( "2018-01-23T12:34:56.123456789Z" ) ;
Another important point: Never use the troublesome old date-time classes bundled with the earliest versions of Java. They are a terrible wretched mess, to be avoided. They are now legacy, supplanted entirely by the java.time classes. All the code seen above usese the modern java.time classes.
Is there some patch that needs to be applied to Java 1.7?
Not that I am aware of. But you may need to update your tzdata
as discussed above, both in your JVM and in your database server.
Is there anything explicitly needs to be done in the application to recognize change in DST?
No. You need not do anything during a DST cut-over IF your tzdata
is up-to-date (a) in your JVM and (b) in your database, AND you use time zones rather than mere offsets.
How is Tomcat taking care of this?
No. Apache Tomcat has nothing to do with your date-time issues. Tomcat knows nothing about time zones and offsets. That is the business of your JVM, not Tomcat.
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.*
classes.
Where to obtain the java.time classes?
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.