42

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).

Ogre Psalm33
  • 21,366
  • 16
  • 74
  • 92
  • see also [java.time.Instant](https://docs.oracle.com/javase/8/docs/api/java/time/Instant.html) – ZhongYu Jun 22 '15 at 16:37
  • well, cmiiw as I'm not really remember where I read this. But, I'm sure it's about UT1 and UTC, if the distance between those two timezone is more than 0.6 second (or so) then the leap second would be added. – kucing_terbang Jun 22 '15 at 16:57
  • @bayou.io: Interesting, so for Java 8 at least, it seems Oracle decided to take matters into their own hands with the gradual second-stretching over the final 1000 seconds of the day (which appears to be different from both RHEL and Windows approaches, at least). – Ogre Psalm33 Jun 22 '15 at 17:00
  • Well, if no one has a definitive answer before then, I'll probably add some extra debug logging to our Java 1.7 processes and report back my findings in about 9 days. – Ogre Psalm33 Jun 22 '15 at 17:02

4 Answers4

34

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.

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
  • This is a very good general analysis, particularly applicable to newer (version 8+) JDKs. – Ogre Psalm33 Jul 01 '15 at 13:03
  • Is it correct to assume that the "spreading out" of leap seconds also extend to milliseconds and nanoseconds? – Harald Apr 11 '18 at 10:21
  • @Harald Sorry, I don’t follow your question. A leap second is declared when some scientific body measures enough drift between out current UTC time-tracking and astronomical time-tracking, once the delta has grown to a full second. So the leap is always a full second, never a fraction. Maybe you refer to the practice of some people such as the Google company to “smear” the leap as a series of tiny fractional second leaps made over minutes rather than in one full second stop-the-clock moment. – Basil Bourque Apr 11 '18 at 16:20
  • yes: "the leap second is spread equally over the last 1000 seconds" is what I was wondering. These seconds probably don't have more milliseconds, so the millis and nanos must be spread out too. I was wondering if there is some tricky code with time deltas that can provoke showing that there was a leap second. – Harald Apr 12 '18 at 16:52
  • @Harald I still don’t follow, sorry. Maybe you don’t understand that we are trying to absorb/swallow/ignore the extra second. We are pausing our clocks for one second to let them catch up with the slowing rotation of the earth and other astronomical positioning. One way is to have a 61st second on some arbitrarily chosen minute. Another way is to add an extra millisecond to each of a thousand seconds. – Basil Bourque Apr 12 '18 at 17:45
  • No the answer of assylias is not correct, see my comment there. And the documentation part in class `java.time.Instant` related to leap seconds is also rubbish because the designers want users to interprete that class partially as related to the outdated proposal UTC-SLS (sic!) but we can be very sure that most users handle it like POSIX in real coding practice. – Meno Hochschild Apr 20 '20 at 03:10
13

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.

assylias
  • 321,522
  • 82
  • 660
  • 783
  • I believe our production system is running jdk-7u55, so it might be a good guess that, if the JRE is doing its own time-keeping internally, jdk 7u55 will ignore the 2015-06-30 leap second. – Ogre Psalm33 Jun 22 '15 at 17:11
  • 2
    @OgrePsalm33 It looks like it yes - according to the last link I gave: "*The Java SE platform's timezone data is not read from the local or host operating system (OS), so OS timezone patches will not update the JRE software's timezone data*". But then if you create a `new Date()` after midnight it will probably pick up the clock adjustment performed by the OS - but a date calculation, of say `date2.getMillis() - date1.getMillis()` over the leap second will probably give results wrong by one second. Actually that last thing is easy to check. – assylias Jun 22 '15 at 17:13
  • 1
    This answer most closely matches my observations of what happened. – Ogre Psalm33 Jul 01 '15 at 13:01
  • The update would have to be done manually by using the TZupdater tool (if you don't want to update the JRE) but even that requires you to stop it "You must stop any running instances of the JDK/JRE software to be operated upon before you run the TZUpdater tool on that installed JDK/JRE software image." – fidudidu Sep 25 '19 at 08:45
  • 1
    Wrong answer. The Oracle JVM can never know it, not even in the most modern distributions because the leap second table in the original tz data has not been imported. The only thing which was imported was the NEWS-section in the documentation of tz distribution which sometimes contains infos about leap seconds. But Oracle just copies the documentation to the tz updater tool without any consequences for the JVM code. – Meno Hochschild Apr 20 '20 at 03:05
  • @MenoHochschild feel free to amend my answer if that makes sense, or post a separate answer if mine is not fixable. – assylias Apr 21 '20 at 19:16
6

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.

Ogre Psalm33
  • 21,366
  • 16
  • 74
  • 92
  • 1
    Are you sure that is the case? Assuming 'new DateTime()' is referencing joda time, or that you meant 'new Date()', both of these use System.currentTimeMillis(), which uses the OS's clock: https://blogs.oracle.com/dholmes/entry/inside_the_hotspot_vm_clocks – Andy Tolbert Dec 30 '16 at 12:33
  • For my own benefit, I created a docker image that when ran demonstrates that when a leap second is inserted java responds accordingly (https://hub.docker.com/r/tolbertam/leap-java-demo/). Used Instant.of in this case, but should apply to any constructor using System.currentTimeMillis() – Andy Tolbert Dec 30 '16 at 14:46
  • 1
    Ahh! I understand what happened here. I just tried this on an older JDK and had the same experience. The reason is because older versions of the JDK < 7u60 used CLOCK_REALTIME for scheduling instead of CLOCK_MONOTONIC, so during a a leap second any scheduling (i.e. Thread.sleep) will be delayed at least by 1 second, which is what I observed when I ran my test. – Andy Tolbert Dec 30 '16 at 15:05
  • See: http://mail.openjdk.java.net/pipermail/hotspot-runtime-dev/2015-April/014775.html for more info on that. – Andy Tolbert Dec 30 '16 at 15:06
  • Sorry for the comment spam, but I think even when this happens, your java dates will not become 1 second ahead, its just that scheduling during the leap second will be delayed for 1 second, so any tasks that use a higher reoslution will be impacted. – Andy Tolbert Dec 30 '16 at 15:10
  • Output demonstrating that behavior: https://gist.github.com/tolbertam/203ef0aab9a5fa60c92b2112b67496c4 (1st column is the elapsed time, after leap second inserted, Thread.sleep(200) takes 1200ms) – Andy Tolbert Dec 30 '16 at 15:17
  • 1
    @AndyTolbert I should clarify, new DateTime() is our own class that wraps Java Date(), not the Joda Time class (our specific implementation is based off of J2000 for dates, which is a requirement for our system). So you're saying the actual Thread.sleep() accounts for the leap second, even if System.currentTimeMillis() does not? – Ogre Psalm33 Jan 06 '17 at 14:58
  • 1
    Prior to 7u60, there was a bug such that when a leap second happened (or the clock is sent back in general), it throws off timers in the JVM, so if you do a Thread.sleep(10); during a leap second, instead of sleeping 10ms, the code would end up sleeping for the duration of the leap second + 10ms. Which is why if you print the date, sleep and then print the date, you would not see the leap second printed with an older JVM, but the leap second is indeed regarded by the JVM since new Date/System.currentTimeMillis uses the clock from the OS. – Andy Tolbert Jan 06 '17 at 21:47
-2

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.

JohnM
  • 1
  • 1
    Hi, and welcome to StackOverflow! We certainly appreciate contributions from new users like you. Unfortunately, the answer you just posted does not really answer the question directly. If you feel additional information like this is important, leave a comment. You will need to earn just a few more reputation points to post comments, so get started by asking questions or answering some in a meaningful way. Good luck! – MarioDS Jan 22 '18 at 12:58
  • 2 seconds??? No a "double" leap second is not permitted because UTC is defined such that it must never deviate from UT by more than 0.9 secs. See also [Wikipedia](https://en.wikipedia.org/wiki/ΔT) So the logical consequence is at maximum one leap second at end of quarter (preferrably at end of June or December). – Meno Hochschild Apr 16 '20 at 19:53