There are two types of field under discussion - calendar and duration.
Such as years or minutes.
It is desirable to be able to represent this information in a type-safe way, so that you cannot confuse seconds with minutes and so on. There are three potential parts to any field:
The options for duration fields are:
The simple option is to use an int to represent the duration field. This option is not unit-safe, as only javadoc tells the user whether a given value is seconds or hours. This is a potential source of bugs.
int timeout = 6; // seconds
public abstract int phoneCallDuration(); // what does this return?
Duration d = ...;
int seconds = d.getSeconds();
The most type-safe option is a wrapper class for each field.
This option is unit-safe, and makes it much harder for different fields to be confused. The downside is that one class must be written and used for each field, which makes the javadoc API appear complex. In reality, the API only consists of the concept of a field, there just happen to be a lot of implementations.
Seconds timeout = seconds(6);
public abstract Seconds phoneCallDuration();
Duration d = ...;
Seconds seconds = d.getSeconds();
The generics option is a single field class with a generic parameter.
This option is unit-safe (assuming generics are used corrrectly), making it much harder for different fields to be confused. The main API only has one class for the field, however the generic parameter still needs to be a class. As a result, the classes for Seconds, Days etc from option 2 still need to be present, however in this case they do not serve any real purpose. The danger is that a user will define a method to take in Days, which will be confusing and pointless as the class is only designed for use as a generic parameter.
DurationField<Seconds> timeout = seconds(6);
public abstract DurationField<Seconds> phoneCallDuration();
Duration d = ...;
DurationField<Seconds> seconds = d.getSeconds();
This option is to use the classes in JSR-275.
This option is unit-safe, but not unit-explicit. The API that the user works with is in terms of the JSR-275 duration. The unit (seconds) can be queried from the API, but is not part of the code that a user writes. If I understand correctly, auto conversion occurs between units when required.
Measure<Integer, Duration> timeout = seconds(6);
public abstract Measure<Integer, Duration> phoneCallDuration();
Duration d = ...;
Measure<Integer, Duration> seconds = d.getSeconds();
or
Measurable<Duration> timeout = Measure.value(6, SECOND);
public abstract Measurable<Duration> phoneCallDuration();
Measurable<Duration> d = phoneCallDuration();
int seconds = d.intValue(SECOND);
Such as dayOfWeek or hourOfDay.
The options are similar to duration but complicated by having two possible fields. It is desirable to be able to represent this information in a type-safe way, so that you cannot confuse secondOfMinute with minuteOfHour and so on. There are three potential parts to any field:
The options for calendar fields are:
The simple option is to use an int to represent the calendar field. This option is not field-safe, as only javadoc tells the user whether a given value is secondOfMinute or hourOfDay. This is a potential source of bugs, and particularly annoying when passing fields into methods (as Java has no named parameters).
int dayOfMonth = 6; // day of month
public void createDate(int year, int month, int day); // very easy to pass fields in wrong order
CalendarDate d = ...;
int dayOfMonth = d.getDayOfMonth();
Some fields are well suited to Enums, like !MonthOfYear and !DayOfWeek. Option 1B is to use Enum where appropriate and int elsewhere.
int dayOfMonth = d.getDayOfMonth();
MonthOfYear month = d.getMonthOfYear();
The most type-safe option is a wrapper class for each field.
This option is field-safe, and makes it much harder for different fields to be confused. The downside is that one class must be written and used for each field, which makes the javadoc API appear complex. In reality, the API only consists of the concept of a field, there just happen to be a lot of implementations.
DayOfMonth dom = dayOfMonth(6);
public void createDate(Year year, MonthOfYear month, DayOfMonth day);
CalendarDate d = ...;
DayOfMonth dayOfMonth = d.getDayOfMonth();
The generics option is a single field class with generic parameters.
This option is field-safe (assuming generics are used corrrectly), making it much harder for different fields to be confused. The main API only has one class for the field, however the generic parameters still needs to be classes. The generic parameters are one for each concept (shared with duration fields), which are combined to represent the unit and range of the field. The generics add significantly to the complexity of the field. They can also be misused, as you could enter the generic parameters the wrong way around (range before unit).
CalendarField<Day, Month> timeout = seconds(6);
public void createDate(CalendarField<Year, Forever> year, CalendarField<Month, Year> month, CalendarField<Day, Month> day);
CalendarDate d = ...;
CalendarField<Day, Month> dayOfMonth = d.getDayOfMonth();
It should be noted that certain calendar fields are well suited to Enums:
OldWiki: DateTimeCalendarClasses
OldWiki: Historic_Fields
OldWiki: Historic_choices
OldWiki: ThreeTen