This post is an extract of a Code Kata presentation I had hosted back in November 2015. Java 8 Date Time API was relatively new to many of the attendees.
This Kata-based style of teaching includes sharing a set of failing / non-functional JUnit tests with TODO comments indicating actions that need to be taken to resolve/pass the JUnit tests. Solving the JUnit tests repeatedly helps developers gain muscle-memory into using the feature (similar to the karate kata).
Link to the code kata is on Github, located at the bottom of the post.
Background: Why a new API
First, some background on why there was a need to create a new API.
Issues with java.util.Date
java.util.Date:
- is mutable-only – Date instances are not immutable.
- has concurrency problems – Date instances are not thread-safe.
- has incorrect naming – Date is not a “date” but a “timestamp”.
- lacks convention – Days start with 1, months with 0 and years with 1900.
- lacks fluency – Cannot create durations (a quarter, 5 minutes) OR combos(year+month, date without seconds) etc.
Additional observations about the pre-Java 8 Date API
System.currentTimeInMillis()
is not accurate and can return same value for multiple sequential calls.java.util.Date
vs.java.sql.Date
– SQL flavor is only a DATE with no time.java.sql.Timestamp
– SQL flavor replicatingjava.util.Date
but additionally storing nanoseconds.
Issues with java.util.Calendar
java.util.Calendar:
- lacks clarity – Mix of dates and times.
- has confusing timezone support – Not very easy to switch timezones, offsets etc.
- has severe formatting hurdles –
SimpleDateFormat
andCalendar
do not interoperate well. - presents extension hardships – New calendar systems are created by extending
Calendar
(therefore all it’s problems).
“Calendar is the Ravenous Bugblatter Beast of Traal for Date APIs” – Chandra Guntur (circa 2000).
What was proposed to fix this?
JSR-310: Date and Time API
Excerpts from JSR-310 (https://jcp.org/en/jsr/detail?id=310)
- “The main goal is to build upon the lessons learned from the first two APIs (Date and Calendar) in Java SE, providing a more advanced and comprehensive model for date and time manipulation.”
- “The new API will be targeted at all applications needing a data model for dates and times. This model will go beyond classes to replace Date and Calendar, to include representations of date without time, time without date, durations and intervals.“
- “The new API will also tackle related date and time issues. These include formatting and parsing, taking into account the ISO8601 standard and its implementations, such as XML.”
- “The final goal of the new API is to be simple to use. The API will need to contain some powerful features, but these must not be allowed to obscure the standard use cases. Part of being easy to use includes interaction with the existing Date and Calendar classes …”
Origins of the JSR-310
- JSR-310 is “inspired from” the very popular Joda-Time library by Stephen Colebourne, who is also the lead on JSR-310.
- JSR-310 was a means to both overcome the shortcomings as well as refactor portions of the Joda-Time. http://blog.joda.org/2009/11/why-jsr-310-isn-joda-time_4941.html.
- Check out the cheatsheet from converting from Joda-Time to java.time apis: http://blog.joda.org/2014/11/convertingfrom-joda-time-to-javatime.html
- Also check out Meno Hochschild’s (author of the Time4J library) response at stack overflow: http://stackoverflow.com/questions/24631909/differences-between-java-8-date-time-apijava-time-and-joda-time
Java 8 Date Time API
The Java classes in lavender below are all linked to the JDK 8 API. Please feel free to click.
Date Time Classes
Dates and Times: Simple Date and Time ‘containers’
Instant
stores a numeric timestamp from Java epoch, + nanoseconds.LocalDate
stores a date without a time portion (calendar date).LocalTime
stores a time without a date portion (wall clock).LocalDateTime
stores a date and time (LocalDate + Local Time).ZonedDateTime
stores a date and time with a time-zone.OffsetTime
stores a time and offset from UTC without a date.OffsetDateTime
stores a date with time and offset from UTC.
Ranges and Partials: Spans and ranges of temporality
Duration
models time in nanoseconds for time intervals. (e.g. 5 mins)Period
models amount of time in years, months and/or days. (e.g. 2 Days)Month
stores a month on its own. (e.g. MARCH)MonthDay
stores a month and day without a year or time (e.g. date of birth)Year
stores a year on its own. (e.g. 2015)YearMonth
stores a year and month without a day or time. (e.g. credit card expiry)DayOfWeek
stores a day-of-week on its own. (e.g. WEDNESDAY)
Chronology: A calendar system to organize and identify dates
Chronology
is a factory to create or fetch pre-built calendar systems.
Default isIsoChronology
(e.g.ThaiBuddhistChronology
).ChronoLocalDate
stores a date without a time in an arbitrary chronology.ChronoLocalDateTime
stores a date and time in an arbitrary chronology.ChronoZonedDateTime
stores a date, time and timezone in an arbitrary chronology.ChronoPeriod
models a span on days/time for use in an arbitrary chronology.Era
stores a timeline [typically two perChronology
, but some have more eras].
Date Time Common API – Reference Table
Date and Time
Type | Y | M | D | H | m | S(n) | Z | ZId | toString |
---|---|---|---|---|---|---|---|---|---|
Instant |
1999-01-12T12:00:00.747Z | ||||||||
LocalDate |
1999-01-12 | ||||||||
LocalTime |
12:00:00.747 | ||||||||
LocalDateTime |
1999-01-12T12:00:00.747 | ||||||||
ZonedDateTime |
1999-01-12T12:00:00.747-05:00 [America/New_York] | ||||||||
OffsetTime |
12:00:00.747-05:00 | ||||||||
OffsetDateTime |
1999-01-12T12:00:00.747-05:00 |
Ranges
Type | Y | M | D | H | m | S(n) | Z | ZId | toString |
---|---|---|---|---|---|---|---|---|---|
Duration |
P22H | ||||||||
Period |
P15D |
Partials
Type | Y | M | D | H | m | S(n) | Z | ZId | toString |
---|---|---|---|---|---|---|---|---|---|
Month |
* | JANUARY | |||||||
MonthDay |
-01-12 | ||||||||
Year |
1999 | ||||||||
YearMonth |
1999-01 | ||||||||
DayOfWeek |
* | TUESDAY |
Fluency and Symmetry in the new Date Time API
The Java 8 Date Time API introduces a certain symmetry in operations that make for a pleasant developer experience. Below is a list of prefixes for methods across the API that perform in a similar pattern where encountered.
- of {static factory method prefix} – Factory method to obtain an instance with provided parameters – validates and builds with no conversion.example usage:
LocalDate.of(...)
orInstant.ofEpochSecond(...)
“ - from {static factory method prefix} – Factory method to obtain an instance with provided parameters – validates, converts and builds.example usage:
LocalDateTime.from(...)
orOffsetTime.from(...)
- parse {static factory method prefix} – Factory method to obtain an instance with provided CharSequence parameters, by parsing the content.example usage:
LocalDate.parse(...)
orOffsetDateTime.parse(...)
- format {instance method prefix} – Formats the instance with provided formatter.example usage:
localDate.format(formatter)
- get {instance method prefix} – Return part of the state of the target temporal object.example usage:
localDate.getDayOfWeek()
- is {instance method prefix} – Queries a part of the state of the target temporal objectexample usage:
localTime.isAfter(...)
- with {instance method prefix} – Returns a copy of the immutable temporal object with a portion altered. Alternate for a set operation.example usage:
offsetTime.withHour(...)
- plus {instance method prefix} – Return a copy of the temporal object with an added time.example usage:
localDate.plusWeeks(...)
- minus {instance method prefix} – Return a copy of the temporal object with subtracted time.example usage:
localTime.minusSeconds(...)
- to {instance method prefix} – Convert the temporal object into a new temporal object of another type.example usage:
localDateTime.toLocalDate(...)
- at {instance method prefix} – Combine the temporal object into a new temporal object with supplied parameters.example usage:
localDate.atTime(...)
KATA TIME !!!
The Code for the Kata is located at: https://github.com/c-guntur/javasig-datetime
Your mission, should you choose to accept it, is to:
- setup the kata using your favorite IDE
- launch each JUnit test (Exercise1Test through Exercise5Test) and fix the tests, so all execute as instructed in the TODO above any commented lines.
- repeat as often as necessary to build muscle memory of using the awesome Date Time API
There are solutions, but looking at solutions may limit your learning different ways of solving the same problem.
Link to solutions: https://github.com/c-guntur/javasig-datetime-solutions
I hope you found this post fun!
Happy coding!
Excellent One. Very clean and neat. Easy to learn as well. Loved reading this.
LikeLike