Hi Stephen,
Aside from others' concerns, I am a little worried about the nonfunctional
nature of your API. The user might appreciate documentation about which
expressions may vary across calls to registerSystemLeapSecond(), and which
member functions are well-defined functions of the object and arguments
only. (And maybe some example test cases about the correct answer.)
For example, if you make Instant a = ofEpochSeconds( 1325375990 ) and
Instant b = ofEpochSeconds( 1325375991 ), and then take long d = between(
a, b ).toMillisLong(), what do you get?
It seems to me if I read your documentation correctly, that right now you
would get d = 1000. Then in a few months the IERS emails everybody to add
in a leap second, somebody calls registerSystemLeapSecond(), and suddenly
the *same code* will yield a different result -- d = 1001.
Do I understand correctly? If so, I think you are being a little glib to
tell the user that duration calculations with Instant "ignore leap
seconds." To the contrary: by using UTC-SLS, you are acknowledging the
existence of leap seconds, and you are making user-visible changes in
response to new information received about them, and your date-and-time
routines are no longer functions of the inputs -- they have side effects
based on ancillary calls to registerSystemLeapSecond(). I don't see how
you are ignoring them at all.
E.g., you say that "Instant uses the UTC-SLS time-scale which always has
86400 seconds in a day." But do you "always" have 86400000 milliseconds in
the day?
Another question I couldn't figure out from the documentation is whether
ofEpochMillis(x).toEpochMillisLong() is supposed to be an identity. It
seems like it might not be -- if a call to registerSystemLeapSecond()
happens in between, then this could yield a different output than what was
put in. Code could easily make this assumption so if it's rarely not true,
you should warn the user.
Another question is whether your notion of UTC-SLS EpochMillis will be
compatible with the operating system's POSIX epoch time_t (which often
just pauses on a leap second). I'm guessing it probably won't be, and
users may get in trouble here too without warning. E.g., the Python
time.time() function will give different results than your new definition
of "epoch" time.
Also it's not clear to me how you plan to distribute these historical leap
seconds. There is no historical leap second table in the GPS navigation
message that I am aware of, and no way to get one within the POSIX API
either. So it is a little tricky...
I raised these same issues when the Haskell people came on here five years
ago so I am not trying to pick on Java. :-) But I do think the issues are
probably subtle, and since UTC-SLS has never been implemented in any
widespread software, we do not really know what the issues are very well.
Being the very first implementation of UTC-SLS anywhere may put you on the
untested bleeding edge -- whether that's appropriate for this API is up to
you I guess.
Best,
Keith
On Fri, 28 Jan 2011, Stephen Colebourne wrote:
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:
http://threeten.sourceforge.net/apidocs/javax/time/package-summary.html
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
full explanation:
http://threeten.sourceforge.net/apidocs/javax/time/Instant.html
UTCInstant supports leap seconds based on a pluggable UTCRules class:
http://threeten.sourceforge.net/apidocs/javax/time/UTCInstant.html
TAIInstant represents the TAI scale:
http://threeten.sourceforge.net/apidocs/javax/time/TAIInstant.html
TimeSource allows an implementation to provide an accurate UTC/TAI
clock if one is available:
http://threeten.sourceforge.net/apidocs/javax/time/TimeSource.html
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
- DST
- 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
+00:00 offset.
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".
However...
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.
"
Feedback welcome.
Stephen Colebourne
Project lead ThreeTen
Co-spec lead JSR-310
https://sourceforge.net/apps/mediawiki/threeten/index.php?title=ThreeTen
_______________________________________________
LEAPSECS mailing list
[email protected]
http://six.pairlist.net/mailman/listinfo/leapsecs
_______________________________________________
LEAPSECS mailing list
[email protected]
http://six.pairlist.net/mailman/listinfo/leapsecs