A timestamp expressed in milliseconds since 1.1.1970 UTC is a common way to store timestamps, e.g in Java.
e.g:
long timestampUtc = System.currentTimeMillis();
Such a timestamp can be formated in human readle time format, e.g using this code
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US);
df.setTimeZone(TimeZone.getTimeZone("UTC"));
String humanTimeUtc = df.format(new Date(timestampUtc));
System.out.println(humanTimeUtc);
which gives output: 2014-02-14 14:58:05
Now imagine that today at midnight the time administration introduces a new UTC leap second. If I run the code above tommorow, the java JRE on my system cannot know that leap second introduction, and would format the time wrongly (by one second).
Is my asumption correct?
How to correctly format the time (e.g in a log file) in systems that cannot always use an up to date JRE?.
Background info:
This is used in an embedded device, which synchronizes its system clock via GPS, having the GPS number of leap seconds offset to UTC.
Java and the Unix "epoch" (number of seconds since Jan 1, 1970 00:00:00 UTC) both ignore leap seconds entirely. They both assume every day (measured in UTC) has had exactly 86400 seconds. A simple block of code to verify:
Calendar c = Calendar.getInstance();
c.setTimeZone(TimeZone.getTimeZone("UTC"));
c.set(2014, 0, 1, 0, 0, 0);
c.set(Calendar.MILLISECOND, 0);
System.out.println(c.getTimeInMillis());
You will see that the number of seconds from 1/1/1970 to 1/1/2014 is an exact multiple of 86400 (it's actually exactly 44 years * 365.25 days/year * 86400 seconds/day); it shouldn't be, because there have been 25 leap seconds introduced in that interval.
If you need to take leap seconds into account, you need to find a library that will do so, or come up with your own adjustment.
Leap second handling is hard and Java is not particularly bad in this respect.
The NTP Timescale and Leap Seconds explains just some of the weirdness:
The insertion of leap seconds in UTC and subsequently into NTP and POSIX affect the system clock, and thus the conversion between system clock time and conventional civil time in hours, minutes and seconds. However, since the only institutional memory available to determine the conversion are the UTC national broadcast services, the conversion is in effect reset to UTC as each broadcast timecode is received. Thus, when a leap second is inserted in UTC and subsequently in NTP or POSIX, knowledge of all previous leap seconds is lost.
Another way to describe this is to say there are as many NTP or POSIX timescales as historic leap seconds. In effect, a new timescale is reestablished after each new leap second. Thus, all previous leap seconds, not to mention the apparent origin of the timescale itself, lurch backward one second as each new timescale is established. For instance, if a clock synchronized to UTC in 2005 was used to establish the UTC epoch of an event that occurred in early 1972 without correction, the event would appear 22 seconds late. As a result, for the most precise determination of epoch relative to the historic Gregorian calendar and UTC timescale, the user must subtract from the apparent NTP or POSIX epoch the relevant offset provided by the IERS. This is a feature of almost all present day time distribution mechanisms.
Leap seconds are almost never relevant unless you're doing astronomical calculations or something else that depends on the position of the Earth and Sun.
Usually people who think they need leap seconds really need either
I prefer (2). The scalar representation is better for scientific calculations, and the tuple representation is better for business and casual applications.
The answer by dcsohl and the answer by Mike Samuel are correct.
The other comments about the time database of Java being updated are incorrect. Yes, the database is updated, but not for leap seconds. Leap seconds are entirely ignored by Java, by Joda-Time, and by other Unix-oriented timekeeping systems.
Your question assumes a problem where none exists.
The physical clock on nearly all computers are not very precise. Drifting a second or more per month is common. That's why virtually all Operating Systems default to connecting to time servers either locally or over the internet. So, in practical terms, your computer is regularly tweaking its own current time. Because of this you may already find anomalies in the time sequences recorded in your logs if you looked carefully.
Inserting a leap second has the same effect as your clock’s imprecision. Your computer is off by a second, and will soon be corrected by a check-in with a time server.
In terms of your data, both the bundled java.util.Date class and the popular replacement, Joda-Time, ignore the leap second. So think of a leap second as just stretching out that 59th second on the last hour of the day of a leap-second event. In terms of our calendar and call clocks, nothing happened. For all business-related apps and most practical purposes of most software, ignoring leap seconds has no detrimental effects.
Yes, technically speaking, the milliseconds-since-epoch used by java.util.Date and Joda-Time are incorrect. Right now is reported 1392442622998 since the beginning of the year 1970, while actually with 25 leap-seconds having been inserted since 1972, that number "should" be 1,392,442,647,998 (25,000 more). Yes, calculating the elapsed time between two timepoints over years will be short by a few seconds. But for most purposes, who cares? We have adjusted our calendars to act as if there was no extra second.
If you have a precision-oriented mind as I do, it takes a while to wrap your head around the fact that ignoring leap seconds has no practical effect on tracking the calendar. The basic problem:
The only real practical problem is that reportedly some systems generate an actual 60th second, a time of 23:59:60. That time value wreaks havoc with some software written while ignorant of leap seconds. Such software incorrectly assumes that value is impossible, and may throw errors or otherwise fail. Properly informed software should know that (a) we can have extra seconds so 23:59:60 and 23:59:61 are legal values, and (b) the leap can be negative. (While so far we've had only single positive leap seconds, I recall reading that more than one is possible but not expected. I cannot find a source on that.) Remember, this problem only occurs if an OS or provider of time values is actually tracking those leap second events – few do, so they never see a second numbered 60.
Wikipedia page has more info on Leap Second.
My new library Time4J is able to handle leap seconds so this is one of several unique features of this library. I don't know any other library which can do formatting of leap seconds. Concretely about your question in detail:
Your example code using standard Java
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US);
df.setTimeZone(TimeZone.getTimeZone("UTC"));
String humanTimeUtc = df.format(new Date(timestampUtc));
System.out.println(humanTimeUtc);
looks in Time4J like:
ChronoFormatter<Moment> formatter =
ChronoFormatter.setUp(Moment.class, Locale.US)
.addPattern("uuuu-MM-dd HH:mm:ss", PatternType.CLDR)
.build();
Moment timestampUTC = SystemClock.INSTANCE.currentTime();
System.out.println(formatter.format(timestampUTC));
// output: 2014-02-20 14:16:25
a) The time source SystemClock
is based on System.currentTimeMillis()
. This source never counts leap seconds and can also never yield a leap second timestamp - assuming that the underlying OS is leapsecond-unaware. So the output in this example will never display a leap second value of 60.
b) Internally an object of type Moment
both holds a posix-timestamp AND a leapsecond-bit in its state. So by help of an external leapsecond table (which is actually hold in a small file in classpath) every Moment
will correctly display the exact same time even when a system administrator will later update the leapsecond file and insert a new one. This does not affect any Moment
outside of leap seconds hence there is no one-second-off-error. => If you rerun the code after insertion of new leap second then the timestamp of stored moment is still the same. The formatted output does not change which is a good thing.
c) You can construct a Moment
which represent a leap second either by choosing a specialized time source (in the future I deliver a SNTP-client which might be able to track a leap second), or by applying a suitable number of SI-seconds added to a normal Moment
. The formatted output for such a timestamp will indeed display a second value of 60, provided that the leap second table is up-to-date. If you transfer this leapsecond-moment to another JVM by serialization where the leapsecond-table is not up-to-date then it will be handled there as one second off (and if you serialize it back to a properly updated JVM or if the receiver-JVM is properly updated later then the leapsecond will be shown again).
d) Time4J also supports GPS time scale. You can construct a Moment
by giving the elapsed seconds since GPS epoch (1980-01-06 midnight at start) and specifying the GPS time scale. Internally the Moment
converts the data to UTC state which is not lossy provided the leapsecond-table is up-to-date. Of course, if your configuration is not up-to-date and the GPS source emits a number of elapsed seconds representing a leapsecond event then there will be an error one-second-off. In order to avoid such tiny and rare errors because of not properly managed leapsecond tables in client JVMs it might be a good idea to install another mechanism for configuration. Time4J defines a SPI-interface for this purpose.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With