[threeten-dev] [threeten-develop] Package structure for Threeten in JDK
Roger Riggs
Roger.Riggs at oracle.com
Thu Dec 13 07:08:49 PST 2012
Hi Chris,
It is refreshing to get comprehensive comments with a fresh point of view.
We've been looking at this API for so long it all seems very familiar.
By way of explanation, some comments below.
On 12/12/2012 5:35 PM, Christopher Schultz wrote:
> Roger,
>
> On 12/12/12 3:56 PM, Roger Riggs wrote:
>> After some discussion within Oracle and with the JDK architects and
>> incorporating
>> the discussion of issue#149 Design split between embedded core and
>> general JDK<https://github.com/ThreeTen/threeten/issues/149>
>> I propose the following package structure for Threeten.
>>
>> * java.time - basic human and machine time (ISO)
>> o Clock, Duration, Instant
>> o LocalTime, LocalDate, LocalDateTime
>> o ZonedDateTime, ZoneId, ZoneOffset
>> o Period
> So, these are the "basics". When someone asks me "so, what am I supposed
> to use, now, instead of Date or Calendar", what do I say?
>
> Just from the names shown above, it's totally unclear even which one to
> look at, first. The names Clock, Instant, Local*, and ZonedDateTime all
> seem plausible.
>
> I realize one of the aims of this API is to finally get a clean
> separation between the simple notion of time (e.g. a number that
> represents True Time) and all the cultural and political ideas that
> confuse everyone (time zones, DST, etc.) and so there is no true
> "replacement" for java.util.Date (which handles time zone offset but not
> in a manageable way, no DST support) or java.util.Calendar (which
> handles time zone via TimeZone *and/or* zone offset and DST via offset
> and possible TimeZone). But, there should be at least one class that you
> can point to and say "start there", and its name shouldn't be totally
> off the wall.
If there were just one it would be ZonedDateTime but one of the problems
with
the current Calendar is that a single type does a bad job of handling
the different
needs of developer. So, depending on the use case the developer might
choose better from LocalTime, LocalDate, LocalDateTime, etc.
That will need to be part of the documentation and education about the
DateTime
API and taken into account on the learning curve.
The basic APIs have concrete types with methods to access and manipulate
the values that are easy to use and easy to program.
>
>> * java.time.chrono - the date-time framework and advanced functions
>> o DateTime, DateTimeAccessor, DateTimeField, PeriodUnit
> So, ZonedDateTime is a "basic" class but "DateTime" is an "advanced"
> interface? Just the naming makes it seem like DateTime is the base class
> and ZonedDateTime adds something to it... that would seem to imply that
> DateTime is more basic than ZonedDateTime, yet the packages they are in
> are opposite to that implication. DateTime being an interface was --
> honestly -- a surprise to me even when I got to the end of this message
> and had to go back to adjust this comment. I had thought it was a class
> the whole time. I guess I just like my interfaces to be adjectives.
Because the Threeten API has different types to properly handle multiple
kinds of time and date data, there needed to be a common interface that
provides access to any of the types. That has gone through many iterations
of function and naming but DateTime seemed like best name for its
inclusive nature. BTW, DateTime by itself would not convey any information
about whether it had a timezone or what calendar it was part of, etc.
From that perspective it is too generic to represent a concrete type.
>
>> o ChronoField, ChronoUnit, DateTimeValueRange
>> o DateTimeAdjusters
>> o Julian Day field
>> o WeekDefinition, ISOWeeks
>> o Chrono, ISOChrono, ChronoLocalDate, ChronoLocalDateTime,
>> ChronoZoneDateTime, Era
>> o YearMonth, MonthDay, Yea
>> o OffsetTime, OffsetDateTime, OffsetDate
>> * java.time.format - formatting
>> * java.time.zone - timezone
>> * java.time.global - global calendars
>> o Japanese, ThaiBuddhist, Minguo, Hijrah
>>
>> All of the packages except java.time.global are tightly integrated and
>> would form a module to be included with all Java Runtimes.
>> The global calendars should be (a module) and decoupled from the base.
>>
>> For reference the current javadoc is:
>> http://cr.openjdk.java.net/~rriggs/threeten-javadoc/
> I have to admit that I've been neither following every discussion nor
> participating in everything but that does give me a somewhat fresh
> perspective -- one that 99% of Java developers are going to have when
> seeing this for the first time.
>
> I've been reading the API Javadoc and I have to say that I'm dumbfounded
> by my initial overview. A comment by a friend and long-time Java
> programmer was "Waa? This whole thing seems intentionally ill-conceived.
> Did some deep-Python lovers infiltrate the working group to scuttle the
> project?".
I'll leave the history to Stephen, I've only be at this for a year.
>
> Some specifics -- and I've only looked in java.time and not the
> sub-packages, yet.
>
> Clock: creates Clock objects. Great. What can they do? They can produce
> other Clock objects -- ones in different time zones. Why? Well, to
> produce Instants, of course. So, Instants have time zones? Sadly, no.
>
> Instant: okay, I get this one: it's a point on a universal time line.
> There is a total ordering of these things across all of time. What can
> you do with an Instant? Well, one of the (alphabetically) first things
> you can do is "doWithAdjustment(DateTime). Do /what/ with adjustment?
> The javadoc description is nonsense: "Implementation of the strategy to
> make an adjustment to the specified date-time object." At least that
> tells me that the argument is the object being modified -- or is it?
> That method returns a DateTime object. Does it return an adjusted
> DateTime object, leaving the original argument in-tact? Or does it
> modify the argument *and* return it? What adjustment is even being made?
> Well, it turns out that it doesn't matter, because the next sentence in
> the javadoc says "This method is not intended to be called by
> application code directly.". Fantastic: this is a method that is
> intentionally useless to me.
Some folks blame this on the Java language, some on the javadoc
(alphabetical),
some on the IDE's completion methods.
A big part of Threeten is a framework for defining how date-time objects
inter-operate.
And along with that framework is a best-practice for using the API.
Personally, I'd rather not make a distinction between framework methods
and not but some found it to be an important distinction.
Feel free to call any public method, but there is a preferred way to use
the API.
The 'do' prefix identifies framework methods.
>
> LocalDate: looking at the name I just *know* it's going to be a classic
> "date" object (like year-month-day) plus some local information -- like
> time zone which includes DST info, right? Oooh, sorry: it's the exact
> /opposite/ -- a date with *no* local information. Thank god there's a
> ZonedDate, right? Wrong. It's called OffsetDate, and it doesn't have a
> Time Zone. Nope, instead it's got a bunch of offsets -- the bane of
> anyone who's ever tried to use java.util.Date and java.util.Calendar.
A fine point here, though maybe not in your use case, Timezones are used
and expected to do adjustments related to daylight savings time and that
implies
that they can only be evaluated at a particular time. OffsetDate does
not have a
time...
The use of "Local" is from a local observer point of view. If I put you
in a room
with a clock and calendar on the wall, that's all you know; nothing
about where
in the world you are; just time and date and they are only useful to use
relative
to the local context and anyone else who shares that context.
>
> Back to LocalDate. The class docs say "However, any application that
> makes use of historical dates and requires them to be accurate will find
> the ISO-8601 rules unsuitable. In this case, the application code should
> use HistoricDate and define an explicit cutover date between the Julian
> and Gregorian calendar systems.". There's no indication of what the
> cutoff between "recent" and "historical" dates should be. 2000 (Y2K)?
> 1970 (epoch)? 1900 (2-byte BCD problems)? 1583? 1582? 0? It doesn't
> matter because there is no HistoricalDate class, anyway.
Sorry, a gap in the spec and a out of date javadoc.
>
> Year/YearMonth/Month/MonthDay -- these classes are clearly junk that I
> can ignore -- at least until I need to something weird. Probably never.
> Actually, I take that back: Year.isLeap has some promise, but this stuff
> is mostly useful for people writing calendar widgets. Does it need to be
> in the top-level package?
>
> ZoneId: yay, another TimeZone class!
>
> ZoneOffset extends ZoneId? Weird.
>
> Okay, forget just browsing the API. Let's try to actually get something
> done. Let's see... what do I do on a regular basis with Java's date/time
> APIs?
>
> Exercise 1: get the current date and time, in my time zone.
>
> Let's assume that I always have this around:
> String zoneId = "America/New_York";
>
> Old way:
> Calendar now = Calendar.getInstance(TimeZone.getTimeZone(zoneId));
>
> New way:
> ZoneDateTime now = ZoneDateTime.now(ZoneId.of(zoneId));
>
> That wasn't too bad.
>
> Exercise 2: find the start of this quarter (Q1=Jan 1, Q2=Apr 1, etc.).
>
> Old way:
> Calendar quarter = Calendar.getInstance(TimeZone.getTimeZone(zoneId));
> int month = quarter.get(Calendar.MONTH);
> quarter.set(Calendar.DAY_OF_MONTH, 1);
> quarter.set(Calendar.MONTH, 3 * (month / 3));
> quarter.getTime();
>
> New way:
> ZoneDateTime now = ZoneDateTime.now(ZoneId.of(zoneId));
>
> Hmm... I'm a little lost. I'm fairly sure the best option is to use a
> "WithAdjuster", but I'm not sure if I should be writing my own or if
> there is one already that will meet my needs. This seems like it would
> be a good candidate for adding to the standard API, since getting
> quarterly information is essential to businesses.
An earlier draft contained support for Quarters but it got classified as
you did with
YearMonth and got sidelined.
I don't see the leap to an Adjuster unless its some you want to do often.
The same logic used above can be used with Threeten.
now.withDay(1);withMonth((now.getMonth()-1)/3 * 3) + 1);
I myself looked twice to see if Month had help here.
Dealing with quarters is domain specific...
>
> Exercise 3: find out how many days between two dates
> (Let's just assume there aren't any complexities like calendar
> discontinuities, etc. between the dates)
>
> Old way:
> Calendar now = Calendar.getInstance(TimeZone.getTimeZone(zoneId));
> Calendar then = ...;
> long l_now = now.getTimeInMillis();
> long l_then = then.getTimeInMillis();
> long delta = l_now - l_then; // Assume 'then' is in the past
> long days = delta / (1000 * 60 * 60 * 24);
>
> New way:
> ZoneDateTime now = ZoneDateTime.now(ZoneId.of(zoneId));
> ZoneDateTime then = ...;
>
> long days = then.periodUntil(now, ChronoUnit.DAYS);
>
> That's nice. It will probably deal with all the discontinuities that I
> wiped-away above, too.
>
> It's odd that I can't do that with LocalDate -- 'cause I don't care
> about time zone, etc... I'm looking for gross-estimates, here -- because
> LocalDate.periodUntil() takes a DateTime.
ok, but all the Threeten types are a DateTime; so it works with LocalDate.
> So, the API seems to be a lot more useful than it appears at first
> glance: you can still (probably) get everything done, but there is just
> so much cruft it's hard to see what you're really looking for.
>
> My first reading was absolutely confusing, and I think the same will be
> true of many Java developers out there.
Good point, we've spec a lot of time on the API and making it robust and
extensible
and will need to put more time into the presentation and documentation.
>
> If some of these distracting classes could be placed into sub-packages,
> that would certainly help. If some classes could be re-named (always a
> matter of subjectivity, I know), I'm sure confusion could be reduced (cf
> LocalDate that's not local to anything, etc.).
>
> Just my naïve thoughts on the whole thing.
Naming has been difficult and choices of names depend on the reader's
point view, use cases and what's important making it harder to settle on
universally good names and concepts.
Thank you very much, keep the comments coming. The more detailed the
better.
We are more at the stage of explaining what's been done than changing it
(due
to the schedule) but will make improvements where possible.
Roger
>
> -chris
>
>
More information about the threeten-dev
mailing list