[LEAPSECS] Java: ThreeTen/JSR-310
scolebourne at joda.org
Thu Jan 27 19:43:50 EST 2011
I note that there has been some previous discussion about JSR-310 on
this list. I thought I'd provide an update on the status wrt leap
seconds (as spec lead) given Java is perhaps the most important
enterprise programming language.
The relevant classes for leap seconds are in this package:
Instant is the class that will typically be used, and has 86400
seconds in a day using the UTC-SLS definition. The Javadoc has the
UTCInstant supports leap seconds based on a pluggable UTCRules class:
TAIInstant represents the TAI scale:
TimeSource allows an implementation to provide an accurate UTC/TAI
clock if one is available:
Note that the UTC definition used states "The modern UTC time-scale
was introduced in 1972, introducing the concept of whole leap-seconds.
Between 1958 and 1972, the definition of UTC was complex, with minor
sub-second leaps and alterations to the length of seconds. The default
rules only implement UTC from 1972. Prior to that date, the default
rules fix the UTC-TAI offset at 10 seconds. While not historically
accurate, it is a simple, easy definition, suitable for this library.
Given the acrimony on this list, I'm sure there will be opinions on
these design decisions (which differ from those last discussed here
AFAICT). I'm looking for (constructive) feedback of all kinds,
remembering that my goal is practical usage, not scientific purity.
Also bear in mind that wide-adoption of this in Java may (or at least
should) influence the future direction of standards.
Interestingly, I started the process of looking into the topic with a
strong dislike of leap-seconds, and a desire to remove them. I ended
it with the strong desire to retain them exactly as at present, but
with UTC-SLS for most users and separate UTC support for those that
need it. This balanced the needs of most developers and business users
to not care about leap seconds, with the reality that they exist.
For reference, here is the explanation I previously sent to the
ThreeTen mailing list:
There are four key elements of date/time that vary:
- month lengths
- leap years
- leap seconds
The API handles each of these, but in different ways. Month lengths
and leap years can be managed by DateResolver. DST by ZonedDateTime
and ZoneResolver. Leap seconds by UTCInstant and UTCRules.
However, the general prinicple of the API is that users care about
these four elements in decreasing order. And specifically, almost
no-one cares about leap seconds.
The impact of the last statement is that the API only permits the
second-of-minute to be from 0 to 59 inclusive. 60 is never a valid
value. This is in accordance with most users expectations and makes a
large API actually usable.
(Without this simplification, every single user would need to take
account of leap seconds. Trying to hide them in special methods like
plusLeapSecond doesn't help. As a receiver of an object you don't know
what state the class has been left in. In our initial approach, I
indicated that simple Javadoc was a key goal. If the Javadoc is
compex, then its a sign of multiple classes.)
So, this lead to the question of how a date/time class, like
OffsetDateTime, maps to the real time-line. With this change, the
mapping is defined as UTC-SLS. This has the advantage that time always
progresses forwards, given an accurate clock. Thus, OffsetDateTime is
not 'just' a label, it also has a well-defined physical point for all
moments prior to the next leap-second.
Instant is an alternative view of OffsetDateTime. The two are always
convertible exactly, however an Instant is always in the equivalent of
UTCInstant exposes leap seconds accurately. UTCRules are applied in
all instant conversions, and you need to convert a TAIInstnat to an
Instant before converting to OffsetDateTime.
As you say, TAIInstant is the only true "machine time".
For most users that don't care about the subtleties of sub-second
accuracy around leap seconds and just want to ignore them, they want
something that they /believe/ is a "machine time". This is currently
thought of as System.currentTimeMillis(). Instant is the replacement
for that concept. Its "machine time" for most users that need a it,
typically for an event time-stamp of some kind. InstantProvider is
simply an interface to access this definition of Instant.
TAIInstant (the correct "machine time") is theoretically a better
choice, but is difficult to obtain, and not easily processed by ther
systems, such as DB and XML. So, we have it for those specialist users
that need it, but it is a low-importance class.
So, the whole purpose of the design is to construct a successful
mirage for our users so they don't ever have to deal with
leap-seconds. UTC-SLS provides a clear definition for those that want
to deal with higher accuracy time-sources. TAIInstant and UTCInstant
deal with those that want to keep everything truly correct.
On durations, the current code copes nicely with the differences
between the UTC, TAI and 86400 definitions. A duration can be obtained
as the difference between two points on any of the three scales. But
it is not linked to any scale. They are effective seconds not SI
seconds. Those that care about the difference should use TAIInstant
throughout, and they will get SI seconds.
In summary, if we were being truly honest in the API, then TAIInstant
would be called Instant, and UTCInstant and Instant would disappear
into the other human focussed classes. But our users don't want the
truth - at least not around leap seconds - they want something in line
with their conceptual model of time.
Project lead ThreeTen
Co-spec lead JSR-310
More information about the LEAPSECS