Menu

DateTimeCalendarClasses

Stephen Colebourne

This choice is about what calendar classes should be provided. This especially covers the issues of variable precision.

Precision refers to the level to which the calendar class defines the date and time. The JDK only permits precision at the millisecond level, whereas often we might need year, month, date, hour, minute, second or subsecond precision.

Option 1 - One class per precision

This option would see the JSR supply one class per precision:

  • CalendarYear / Year - year
  • CalendarMonth - all fields month or larger
  • CalendarDate - all fields day or larger
  • CalendarHour - all fields hour or larger
  • CalendarMinute - all fields minute or larger
  • CalendarSecond - all fields second or larger
  • CalendarPoint - all fields nanosecond or larger
  • HourMin / TimeToMinute - all fields from minute to day
  • HourMinSec / TimeToSecond - all fields from second to day
  • TimeOfDay - all fields from nanosecond to day

The advantage is clarity in that each class is clear via its name and compilation check as to the fields it makes available. The user cannot get minutes from CalendarDate because there is no such method.

The disadvantage is that there are lots of classes. This results in the potential to have to convert between them to call methods in your application. (Javadoc is also large, but the conceptual weight is light as the classes are very similar.)

 /** Add PandP delay */
 public CalendarDate addPostAndPackageDelay(CalendarDate dt);

 CalendarDate date = yearMonthDay(2007, 2, 15);
 CalendarMinute dateTime = calendarMinute(2007, 2, 15, 12, 30);

Option 2 - Two classes, variable precision

This option would see the JSR supply just two classes which can have any precision. When constructing the instance, you pass in parameters that indicate how precise the instance will be.

  • TimePoint - the time point at year, month, date, hour, minute, second or nanosecond precision
  • TimeOfDay - the time of day at nanosecond, second, minute or hour precision

The advantage is a small API (two classes). Each class can easily be passed around without needing to call conversion methods

The disadvantage is that there is much less compile time checking. For example, you could call the method to get hours and get an exception due to insufficient precision.

A method in application code will take in a TimePoint, but it can't say that it only actually wants or expects a date. As such, the user could pass in a full date and time (overkill) or just a year (error). Only the javadoc specifies the information (contrast the example to that above).

 /** Add PandP delay - input date must be a date, output date is a date */
 public TimePoint addPostAndPackageDelay(TimePoint dt);

 TimePoint date = yearMonthDay(2007, 2, 15);  // precise to day
 TimePoint dateTime = calendarMinute(2007, 2, 15, 12, 30);  // precise to minute

Option 3 - Two classes with generics, variable precision

This option would see the JSR supply just two generified classes which can have any precision. When constructing the instance, you pass in parameters that indicate how precise the instance will be together with a generic parameter.

  • TimePoint<Day> - the time point at year, month, date, hour, minute, second or nanosecond precision
  • TimeOfDay<Minute> - the time of day at nanosecond, second, minute or hour precision

The advantage is a small API (two classes), although it is reliant on [[DateTimeFields][using generics]] for calendar fields. The API is reasonably type-safe at one level, as the different precisions can't be confused

The disadvantage is that the generics don't help with the methods available to the user to call. Thus, you could still call a method to get minutes, even if the precision generic parameter says you can't. This is probably more confusing than not having generics at all.

/** Add PandP delay */
public TimePoint<Day> addPostAndPackageDelay(TimePoint<Day> dt);

TimePoint<Day> date = yearMonthDay(2007, 2, 15);
TimePoint<Minute> dateTime = calendarMinute(2007, 2, 15, 12, 30);

Option 4 - Mixed - One class per precision for dates, and variable precision for times

This option would see the JSR supply classes as follows:

  • CalendarYear / Year - year
  • CalendarMonth - all fields month or larger
  • CalendarDate - all fields day or larger
  • CalendarDateTime - date plus variable precision time from nanosecond to day
  • TimeOfDay - variable precision time from nanosecond to day

The advantage is that the date classes are the ones that benefit the most from option 1 style classes with compile time safety. Time classes can thus be reduced to two classes (one with and one without a date).

The user cannot get minutes from CalendarDate because there is no such method. However, the user might get an exception from get minutes on CalendarDateTime due to lack of precision. The user will never get an exception from get day / month / year on CalendarDateTime however as those fields are guaranteed to be present.

The disadvantage is that the design is inconsistent and potentially more difficult to learn. In addition there is the ability to get an exception which didn't exist before.

As there are less classes, there is less likelihood of a user needing to convert between different types. This is especially true as a user will tend to have a reference to a date field at a given precision for a good reason.

 /** Add PandP delay */
 public CalendarDate addPostAndPackageDelay(CalendarDate dt);

 CalendarDate date = yearMonthDay(2007, 2, 15);
 CalendarDateTime dateTime = calendarMinute(2007, 2, 15, 12, 30);  // precise to minute

Option 5 - One class per date precision, generified for time precision

This option would see the JSR supply one class per date precision plus a time precision controlled by generics:

  • CalendarYear / Year - year
  • CalendarMonth - all fields month or larger
  • CalendarDate - all fields day or larger
  • CalendarTime<TimeToHour> - all fields hour or larger
  • CalendarTime<TimeToMinute> - all fields minute or larger
  • CalendarTime<TimeToSecond> - all fields second or larger
  • CalendarTime<TimeToNano> - all fields nanosecond or larger
  • TimeToHour - all fields from minute to day
  • TimeToMinute - all fields from minute to day
  • TimeToSecond - all fields from second to day
  • TimeToNano - all fields from nanosecond to day

The advantage is a type-safe solution that uses generics to limit precision. The user cannot get minutes from !CalendarDate because there is no such method. In addition, the user cannot get the seconds from CalendarTime<TimeToMinute> as there is no such method (because getTime() returns an instance of the generified type):

 CalendarTime<TimeToMinute> dt = new CalendarTime<TimeToMinute>();
 Year year = dt.getYear();
 DayOfMonth dom = dt.getDayOfMonth();
 HourOfDay hour = dt.getTime().getHourofDay();
 dt.getTime().getSecondOfDay()  // does not compile, no such method

The disadvantage is that there are still quite a lot of classes. This results in the potential to have to convert between them to call methods in your application. Compared to option 1, where all the classes are supplied, this option has a higher conceptual weight.

 /** Add PandP delay */
 public CalendarDate addPostAndPackageDelay(CalendarDate dt);

 CalendarDate date = yearMonthDay(2007, 2, 15);
 CalendarTime<TimeToMinute> dateTime = calendarMinute(2007, 2, 15, 12, 30);

Option 6 - One class per precision for dates, one class to nanoseconds for time

This option would see the JSR supply classes as follows:

  • CalendarYear / Year - year
  • CalendarMonth / YearMonth - all fields month or larger
  • CalendarDate - all fields day or larger
  • CalendarDateTime - date-time with nanosecond precision
  • TimeOfDay - time with nanosecond precision

The advantage is that the number of classes is controlled in the area where they are less useful - times. Date classes are the ones that benefit the most from the compile time safety. For example, the user cannot get minutes from CalendarDate because there is no such method. Time classes are reduced to two classes (one with and one without a date).

The disadvantage is that the design is slightly inconsistent, as the user might expect to find classes of different precision for times as well as dates.

As there are less classes, there is less likelihood of a user needing to convert between different types. This is especially true as a user will tend to have a reference to a date field at a given precision for a good reason.

 /** Add PandP delay */
 public CalendarDate addPostAndPackageDelay(CalendarDate dt);

 CalendarDate date = yearMonthDay(2007, 2, 15);
 CalendarDateTime dateTime = calendarDateTime(2007, 2, 15, 12, 30);  // second/nano set to zero


Related

OldWiki: DateTimeFields
OldWiki: Historic_choices
OldWiki: ThreeTen

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.