How does the (Oracle) Java JVM know a leap second is occurring?

7.8k views Asked by At

A leap second will occur on June 30, 2015. Different Operating Systems seem to handle this situation differently. In my particular case, we are running a Red Hat 6.4 system with custom Java (JDK 1.7) software that is heavily time-dependent. According to some recent Red Hat released information I found, our system's NTP daemon will ensure the OS automatically handle the leap second by repeating 23:59:59 twice.

My question is: if I have a long running JDK 1.7 process, how does it know that a leap second is occurring? What I mean is, how does Java ultimately know the IERS people have decided to insert a leap second? The Date documentation seems to indicate is aware of leap seconds, but seems unhelpfully vague. Can I assume the JDK, when the appropriate Date object is constructed or Calendar.getInstance() is invoked, it is a pass through to the underlying OS's date-time handling to get the appropriate "real" time value? (Which, in my case, sounds like it would repeat second 23:59:59, because that's how the OS will handle it).

4

There are 4 answers

6
assylias On BEST ANSWER

It depends on your jdk version. If for example you are running update 80, you can check the release notes:

JDK 7u80 contains IANA time zone data version 2015a. For more information, refer to Timezone Data Versions in the JRE Software.

Then follow the link to the timezone data versions and find 2015a. Then follow the link to TZ Updater version1.4.11:

New leap second 2015-06-30 23:59:60 UTC as per IERS Bulletin C 49. (Thanks to Tim Parenti.)

It does not seem to have been included before so if you are running an older version of JDK 7 you will probably not get the adjustment. More information about how it works internally is available here.

To be honest I have never tested to see how it works in practice.

6
Basil Bourque On

The Answer by assylias is correct. This Answer adds some thoughts triggered by a comment on that Answer. The comment referred to calculating elapsed time over the midnight when a Leap Second is scheduled.

This Answer does address the original Question as well by pointing out that for practical usage, the issue of Leap Second is moot, ignored by the date-time frameworks.

Leap Seconds Ignored

All the common Java date-time frameworks ignore leap seconds, as I understand it. These include:

  • java.time
  • Joda-Time
  • java.util.Date/.Calendar (now outmoded by java.time & Joda-Time)

Doc

Here are excerpts from each frameworks documentation showing they effectively ignore Leap Seconds. The emphasis in bold is mine.

The java.time doc for Instant class:

… Given the complexity of accurate timekeeping described above, this Java API defines its own time-scale, the Java Time-Scale.

The Java Time-Scale divides each calendar day into exactly 86400 subdivisions, known as seconds. These seconds may differ from the SI second. It closely matches the de facto international civil time scale, the definition of which changes from time to time.

The Java Time-Scale has slightly different definitions for different segments of the time-line, each based on the consensus international time scale that is used as the basis for civil time. Whenever the internationally-agreed time scale is modified or replaced, a new segment of the Java Time-Scale must be defined for it. Each segment must meet these requirements:

  • the Java Time-Scale shall closely match the underlying international civil time scale;
  • the Java Time-Scale shall exactly match the international civil time scale at noon each day;
  • the Java Time-Scale shall have a precisely-defined relationship to the international civil time scale.

There are currently, as of 2013, two segments in the Java time-scale.

For the segment from 1972-11-03 (exact boundary discussed below) until further notice, the consensus international time scale is UTC (with leap seconds). In this segment, the Java Time-Scale is identical to UTC-SLS. This is identical to UTC on days that do not have a leap second. On days that do have a leap second, the leap second is spread equally over the last 1000 seconds of the day, maintaining the appearance of exactly 86400 seconds per day.

For the segment prior to 1972-11-03, extending back arbitrarily far, the consensus international time scale is defined to be UT1, applied proleptically, which is equivalent to the (mean) solar time on the prime meridian (Greenwich). In this segment, the Java Time-Scale is identical to the consensus international time scale. The exact boundary between the two segments is the instant where UT1 = UTC between 1972-11-03T00:00 and 1972-11-04T12:00.

Implementations of the Java time-scale using the JSR-310 API are not required to provide any clock that is sub-second accurate, or that progresses monotonically or smoothly. Implementations are therefore not required to actually perform the UTC-SLS slew or to otherwise be aware of leap seconds. JSR-310 does, however, require that implementations must document the approach they use when defining a clock representing the current instant. See Clock for details on the available clocks.

The Java time-scale is used for all date-time classes. This includes Instant, LocalDate, LocalTime, OffsetDateTime, ZonedDateTime and Duration.

Joda-Time FAQ:

Joda-Time does not support leap seconds. Leap seconds can be supported by writing a new, specialized chronology, or by making a few enhancements to the existing ZonedChronology class. In either case, future versions of Joda-Time will not enable leap seconds by default. Most applications have no need for it, and it might have additional performance costs.

The java.util.Date class doc:

A second is represented by an integer from 0 to 61; the values 60 and 61 occur only for leap seconds and even then only in Java implementations that actually track leap seconds correctly.

As far as I know, the OpenJDK and Oracle-provided implementations do not track leap seconds. Please post such documentation if you find it.

No Leap Second When Calculating Elapsed Time

Accordingly, these frameworks will not report the extra leap second when calculating elapsed time.

Here is some example code calculating elapsed time from minute before midnight to minute after, on June 30 to July 1, 2015 when a Leap Second is scheduled. This code tests Joda-Time 2.8.1 and java-time in java version "1.8.0_45". I ignored java.util.Date/.Calendar as I avoid those classes whenever possible; feel free to add code here for that case if desired.

First Joda-Time.

// Joda-Time 2.8.1
DateTime startJoda = new DateTime( 2015, 06, 30, 23, 59, 00, DateTimeZone.UTC );
DateTime stopJoda = new DateTime( 2015, 07, 01, 00, 01, 00, DateTimeZone.UTC );
long elapsedMillisJoda = ( stopJoda.getMillis( ) - startJoda.getMillis( ) );

System.out.println( "startJoda: " + startJoda + " stopJoda: " + stopJoda + " = elapsedMillisJoda: " + elapsedMillisJoda );

… and java.time

// java.time
ZonedDateTime startZdt = ZonedDateTime.of( 2015, 06, 30, 23, 59, 00, 00, ZoneOffset.UTC );
ZonedDateTime stopZdt = ZonedDateTime.of( 2015, 07, 01, 00, 01, 00, 00, ZoneOffset.UTC );
long elapsedMillisZdt = startZdt.until( stopZdt, ChronoUnit.MILLIS );

System.out.println( "startZdt: " + startZdt + " stopZdt: " + stopZdt + " = elapsedMillisZdt: " + elapsedMillisZdt );

When run, we see a result of even numbers, exactly two minutes, 120 seconds, or 120,000 milliseconds.

startJoda: 2015-06-30T23:59:00.000Z stopJoda: 2015-07-01T00:01:00.000Z = elapsedMillisJoda: 120000
startZdt: 2015-06-30T23:59Z stopZdt: 2015-07-01T00:01Z = elapsedMillisZdt: 120000

About java.time

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.

Using a JDBC driver compliant with JDBC 4.2 or later, you may exchange java.time objects directly with your database. No need for strings nor 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.

8
Ogre Psalm33 On

These are my actual obervations, running a real-time system on RHEL 6.3, with Oracle Java JDK 1.7.0_55-b13 (I.e.: an out-of-date JDK). I added debugging code that kicked on, logging a new DateTime() every 0.5 seconds a minute prior to the leap second at June 30, 2015 23:59 UTC, and then kicked off after the leap second was over. Log follows (for the curious, the double number printed is the number of seconds since the J2000 epoch)

2015-06-30 23:59:59.316 18349217 [main] INFO  - Leaper's time is 488980799.316000 (Tue Jun 30 23:59:59 GMT-00:00 2015)
2015-06-30 23:59:59.817 18349718 [main] INFO  - Leaper's time is 488980799.816000 (Tue Jun 30 23:59:59 GMT-00:00 2015)
2015-07-01 00:00:00.317 18350218 [main] INFO  - Leaper's time is 488980800.317000 (Wed Jul 01 00:00:00 GMT-00:00 2015)
2015-07-01 00:00:00.817 18350718 [main] INFO  - Leaper's time is 488980800.817000 (Wed Jul 01 00:00:00 GMT-00:00 2015)
2015-07-01 00:00:01.318 18351219 [main] INFO  - Leaper's time is 488980801.318000 (Wed Jul 01 00:00:01 GMT-00:00 2015)

Unfortunately, that doesn't tell me much, except that it did not insert the canonical leap second at 23:59:60 (as both assylias's and Basil Bourque's answers indicate would happen). My hope was that 'new Date()' would reach down to the underlying OS (RHEL 6.3, which supposedly accounts for the leap seconds properly) to ask the current time. That did not seem to be the case.

I did not have the resources to run any other combinations of JDK version and RHEL version to test out the effects. My current best guess is that the documentation Basil Bourque found about spreading the leap second over the last 1000 seconds of the day applies to JDK 1.8 and newer (as it is part of the Instant documentation, which is a Java 8 feature). For my particular case, since my older JDK 1.7.0_55 did not have the leap second adjustment for 2015, I think assylias's observation applies. Namely, that our real-time processes are now running 1 second ahead, oblivious to the leap second.

Lesson learned here? Make sure your real-time systems are fully patched with the latest updates, if you want to be sure they account for upcoming leap seconds. I'll have to do some observations and log analysis, but our particular system is now likely running 1 second ahead of real time, and we'll need to restart our services to fall-back in line.

2
JohnM On

Don't forget that the leap second occurs at 23:59:59 in UT0 this is applied at the same instant at all time zones across the world so if you are in zone time plus 8 it will occur at 23:59:59 - 8 = 15:59:59.

Any local time changes due to 'daylight saving' are ignored.

The following second is 23:59:60 then 00:00:00.

Note the specification for leap seconds allows for + - 1 or 2 seconds to be inserted at the end of December or June.