Environment: Java 7 on Amazon Linux AMI (patched). Note that NTP is used in this environment.
A portion of our code executes scheduled tasks periodically. Generally, the exact time of the execution is not particularly important. However, we have similar logic that is used to calculate intervals for reporting. The reporting periods are expected to fall on exact hour boundaries.
Sample code:
protected Calendar increment(ScheduledPeriodEnum scheduledPeriod, Calendar date) {
Calendar next = CalendarUtils.getCalendar();
next.setTimeInMillis(date.getTimeInMillis());
switch (scheduledPeriod) {
case ONE_DAY:
next.add(Calendar.DAY_OF_MONTH, 1);
break;
case ONE_HOUR:
next.add(Calendar.HOUR_OF_DAY, 1);
break;
case FIFTEEN_MINUTE:
next.add(Calendar.MINUTE, 15);
break;
case ONE_MONTH:
next.add(Calendar.MONTH, 1);
break;
default:
throw new RuntimeException("Unhandled case: " + scheduledPeriod);
}
return next;
}
We persist the time as a unix timestamp (long) value. The Calendar
instances all are in the UTC timezone.
It is our understanding that Java 7's Calendar implementation does not account for leap seconds. We also believe that NTP will update the OS clock.
We are aware of Amazon's 2012 leap second debacle. We are communicating directly with them to understand their operational preparations.
Specific questions:
If we are increment
a Calendar that is on an hour boundary before the leap second, will it be on an hour boundary after the leap second? Or one second before the hour?
How should we test/validate how this code will operate across the leap second boundary? Is a hacked NIST leapfile a good way to go?
Is there a more appropriate pattern/implementation that would sidestep the leap-second issue?
I would not worry so much about the next leap second in 2015 and assume that the Linux-team has done a lot in the meantime to fix any issues with leap-second-handling code, see also this interesting interview with Linus Torvalds. If the linux software is wrong again then you cannot do much more than just restart your Java program (here Java is just the backend)
Now let's consider what might happen else. About code which is totally unaware of any leap seconds like the stuff of java.util.Date
and java.util.Calendar
, please keep in mind that such code only sees what the OS-clock delivers. Most OS just deliver UNIX-timestamps. If they are in sync with NTP, so keep also in mind that NTP-timestamps don't count leap seconds as specified in NTP-protocol. They just repeat the same timestamp. Windows might then trigger a clock jump any time later while a Linux kernel tries to be more precise, applies some leap-second-handling code and immediately manipulates the system clock. Anyway, both OS only delivers POSIX-like timestamps. And Java just sees ... nothing.
This also answers your first specific question: A GregorianCalendar
-object will remain on an hour boundary after adding one hour.
About your second question:
It is just one single second here in question. But what is probably more troublesome is the fact that local clocks can be wrong even by minutes (and then suddenly make jumps after synchronization with NTP-clocks). Latter behaviour can happen anytime, not just at the end of 2015-06-30. So I assume your real issue is rather monotonicity of clocks. This shows in general that any testing should use something like an injectable clock mechanism. For example, you can write a TimeSource
-interface which yields any unix timestamp via a method public long currentTime()
(maybe even making simulated jumps created by a timer) and then use this interface in JUnit-test classes to supply a (fake) time and observe the behaviour of your code.
ad 3.) Most people will just use a library which is not aware of any leap seconds because POSIX is simple to understand and to calculate (although it is not correct when it comes to these special seconds). Without leap-second-handling code there can hardly be a problem rooted directly in such standard libraries. Otherwise, if you are willing not to hide leap seconds from the user then you can also consult my answer in this SO-post.
Whatever your decision is, leap seconds are really not important enough to choose an appropriate library/implementation (other subjects like thread-safety, internationalization etc. are far more important). Regarding these criteria, the old Calendar
-stuff is pretty bad.