14

The java function System.currentTimeMillis() apparently returns the number of seconds since 1st January 1970. However, according to wikipedia.org/wiki/Leap_second, since 1972 there have been 25 leap seconds. This means the actual number of seconds since 1st January 1970 has been 25 more than a naive calculation would suggest. Does System.currentTimeMillis() do the naive calculation and ignore the leap seconds?

Stochastically
  • 7,616
  • 5
  • 30
  • 58

5 Answers5

10

Officially, it's up to the OS and implementation - at least for Date. From the docs of java.util.Date:

Although the Date class is intended to reflect coordinated universal time (UTC), it may not do so exactly, depending on the host environment of the Java Virtual Machine. Nearly all modern operating systems assume that 1 day = 24 × 60 × 60 = 86400 seconds in all cases. In UTC, however, about once every year or two there is an extra second, called a "leap second." The leap second is always added as the last second of the day, and always on December 31 or June 30. For example, the last minute of the year 1995 was 61 seconds long, thanks to an added leap second. Most computer clocks are not accurate enough to be able to reflect the leap-second distinction.

I suspect you'll find that although your computer clock is roughly aligned to UTC, that's done via NTP or the like correcting the clock periodically, rather than the OS really implementing leap seconds.

I believe the JRE libraries typically do assume the 86400-second day. It makes life so much simpler, and if you're going to correct for an inaccurate system clock anyway, you might as well correct for leap seconds that way too.

You really want to work out what you're interested in. If you need a way of representing dates and times which use leap seconds, the standard Java libraries may not work well for you. Even JSR-310 no longer supports leap seconds as far as I can tell (which is a very sensible decision for most developers).

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 2
    I did some tests on Android 4.2 and Windows 7, and the System.currentTimeMillis() was indeed the number of milliseconds since 1-Jan-1970 on the assumption that each day has exactly 86400 seconds. So indeed, leap seconds are ignored, but as you say computers show the right time (incorporating leap seconds) because their clocks are periodically corrected :-). – Stochastically Apr 16 '13 at 07:50
  • @Stochastically: the test is too weak. It won't show how the system supports leap seconds (POSIX, Mills, smear, ntp, TAI (if input is 1970TAI in the latter case)). – jfs Sep 15 '14 at 02:22
  • 1
    As someone trying to implement "`delay_length_in_nanoseconds = (end_time - now) * scale`" you can't underestimate how much I hate people who think leap seconds can be ignored. – Brendan Jul 21 '19 at 15:31
8

POSIX requires that the system clock not admit the existence of leap seconds. MS Windows cannot guarantee the quality (nor existence) of the system clock hardware, and it has eschewed guarantee of 1-second accuracy. Java cannot easily do anything that the underlying system refuses to do. The operating systems are hamstrung by the history of the international regulations that result in one IEEE standard (PTP) that requires leap seconds and another (POSIX) that denies them.

Steve Allen
  • 326
  • 1
  • 3
3

One easy way to check if leap seconds are accounted for or not is to compute the number of seconds elapsed since the Epoch for 00:00 on any given day in the current year.

If that number of seconds is congruent to 00 modulo 60, then the leap seconds are not accounted for as in 2013 you should have a modulus of 25 (to account for the past 25 leap seconds).

herberts
  • 304
  • 1
  • 4
3

I did a small experiment on javarepl:

java> new Date(1000L * 86400 * (365 * 4 + 1) * 12)
java.util.Date res0 = Mon Jan 01 00:00:00 UTC 2018

As you can see, a simple "naive" arithmetics that just regards leap year, but not leap seconds, is used. No extra seconds are added or subtracted.

Update:

Same for the new Instant class:

java> Instant.ofEpochMilli(1000L * 86400 * (365 * 4 + 1) * 12)
java.time.Instant res0 = 2018-01-01T00:00:00Z
Alexey
  • 9,197
  • 5
  • 64
  • 76
  • FYI, the `Date` class is now legacy, supplanted by the java.time classes built into Java 8 and later. Specifically, the `Instant` class replaces `Date`. – Basil Bourque Dec 31 '17 at 17:17
  • 1
    @BasilBourque, thank you! Is it somehow related to the leap seconds issue in question? – Alexey Jan 01 '18 at 20:42
1

Looking at the Javadoc for currentTimeMillis(), it referes to the documentation of the Date class, which has this to say:

Although the Date class is intended to reflect coordinated universal time (UTC), it may not do so exactly, depending on the host environment of the Java Virtual Machine. Nearly all modern operating systems assume that 1 day = 24 × 60 × 60 = 86400 seconds in all cases. In UTC, however, about once every year or two there is an extra second, called a "leap second." The leap second is always added as the last second of the day, and always on December 31 or June 30. For example, the last minute of the year 1995 was 61 seconds long, thanks to an added leap second. Most computer clocks are not accurate enough to be able to reflect the leap-second distinction.

So to answer your question: Yes, leap seconds are accounted for.

0xCAFEBABE
  • 5,576
  • 5
  • 34
  • 59
  • But I think that means the conclusion should be that "leap seconds are NOT accounted for", i.e. ignored, because operating systems assume 86400 seconds per day. – Stochastically Apr 16 '13 at 07:46
  • The way I understand it: UTC accounts for the leap seconds. Linking a timezone in a modern OS just accounts for the time difference between UTC and local time (and maybe DST, depending on use). The alternative would be that everyone has drifted 35 seconds (Source: Wikipedia) away from UTC since Unix time beginning. – 0xCAFEBABE Apr 16 '13 at 08:07
  • 1
    I think you're right, UTC does account for leap seconds. However, my conclusion is that those leap seconds are NOT included in System.currentTimeMillis(), as I describe in my comment to the answer that I've marked as "the answer". – Stochastically Apr 16 '13 at 09:46