Goal of this example
It sounds like a typical interview question :
“How many ways Java has to represent a Date or Time?”
With the arrival of the new Date-Time API in Java 8 the answer becomes more difficult. Let’s see the options…
- Java 8
- JUnit 4.8.1
Pre Java 8 options
1. Gregorian Calendar with constructor parameters
GregorianCalendar gregorianCalendar = new GregorianCalendar(1978, Calendar.DECEMBER, 31);
- Pro: Dead simple
- Cons :
- According to Clean Code “Functions that take three arguments are significantly harder to understand”
- the month parameter is represented with 0 based index (December being 11). The above code without using a constant for the month field would be quite confusing
2. Gregorian calendar with setters
GregorianCalendar gregorianCalendar = new GregorianCalendar(); gregorianCalendar.set(Calendar.YEAR,1978); gregorianCalendar.set(Calendar.MONTH,Calendar.DECEMBER); gregorianCalendar.set(Calendar.DAY_OF_MONTH,31); gregorianCalendar.set(Calendar.MINUTE,0); gregorianCalendar.set(Calendar.SECOND, 0); gregorianCalendar.set(Calendar.MILLISECOND, 0);
- Pro : more readable,
- Cons : quite lengthy
Calendar calendar = Calendar.getInstance(); calendar.set(Calendar.YEAR,1978); calendar.set(Calendar.MONTH,Calendar.DECEMBER); calendar.set(Calendar.DAY_OF_MONTH,31); calendar.set(Calendar.MINUTE,0); calendar.set(Calendar.SECOND, 0); calendar.set(Calendar.MILLISECOND, 0);
Same as the previous solution, but based on the computer’s locale, calendar can be instance of one of the following :
Java 8 options
With the arrival of Java 8 the builder pattern was introduced everywhere, calendar is not an exception.
4. Calendar.Builder() with setters
Calendar calendar = new Calendar.Builder() .set(Calendar.YEAR, 1978) .set(Calendar.DAY_OF_MONTH, 31) .set(Calendar.MONTH, Calendar.DECEMBER) .build();
- Pro : a bit more condense
- Cons : not a lot of improvement
5. Calendar.Builder() with setFields
Calendar calendar = new Calendar.Builder() .setFields(Calendar.YEAR, 1978, Calendar.DAY_OF_MONTH, 31, Calendar.MONTH, Calendar.DECEMBER) .build();
- Pro : Best of both, condense, yet readable
- Cons : ?
Looks like we have a good solution, we could finish here, but the Java API designers were on a different opinion.
Java 8 Date-time API
It always required extra care to represent a Date without Time or a time without Date in Java, not to mention thread safety and pre java 5 API design of java.util.Calendar. To address this issue, the author of Joda time and Oracle partnered and as part of JSR 310 created the Date-time API under java.time
LocalDate localDate = LocalDate.of(1978, Month.DECEMBER, 31);
- Pro :
- LocalDate classes don’t have Timezone and Local properties. For simple use cases it makes life much easier
- LocalDate classes are immutable therefore thread-safe
- Month is finally represented by an enum
- Month can be used as a number but in a more human readable 1 based index instead of the old 0 based index.
- Cons : We are back to square one, having methods with up to 7 parameters! Sometimes I wonder if Java API designers talk to each other at all…
It also worth mentioning that the Date-Time API introduced other useful classes as well :
- The Instant class provides a machine view of the timeline.
- The LocalDate, LocalTime, and LocalDateTime classes provide a human view of date and time without any reference to time zone.
- The ZoneId, ZoneRules, and ZoneOffset classes describe time zones, time zone offsets, and time zone rules.
- The ZonedDateTime class represents date and time with a time zone. The OffsetDateTime and OffsetTime classes represent date and time, or time, respectively. These classes take a time zone offset into account.
- The Duration class measures an amount of time in seconds and nanoseconds.
- The Period class measures an amount of time using years, months, and days.
The complete list is on the official Oracle Java Tutorial page
I trust the reader to answer the original question and count all possible options to represent date or time in Java, but it is certainly more than six.