Date and Time API
Many Java applications require logic to store and manipulate dates and times. At present, Java SE provides a number of disparate APIs for this purpose, including Date, Calendar, SQL Date/Time/Timestamp and XML Duration/XMLGregorianCalendar. Unfortunately, these APIs are not all particularly well-designed and they do not cover many use cases needed by developers.
As an example, Java developers currently have no standard Java SE class to represent the concept of a date without a time, a time without a date or a duration. The result of these missing features has been widespread abuse of the facilities which are provided, such as using the Date or Calendar class with the time set to midnight to represent a date without a time. Such an approach is very error-prone - there are certain time zones where midnight does not exist once a year due to the daylight saving time cutover!
JSR-310 tackles this by providing a comprehensive set of date and time classes suitable for Java SE today. The specification includes:
The domain of dates, times and other temporal concepts is large and complex - much more complex than is often apparent. A key aim of the JSR is to allow the API to explain this complexity simply by the way that the features are exposed. In this way, the user of the API is guided to make the correct choice, minimising the potential for bugs.
Part of this process is determining and using a consistent terminology. For this purpose, JSR-310 is building upon the excellent work of the ISO-8601 standard. However, we have changed a few terms, thus the entire terminology is defined here for clarity:
The single line or axis of time from the past to the future.
A single instantaneous point on the time line.
A quantity of time equal to the directed difference between any two instants on the time line.
A known, well-defined, instant that can be used as a reference point to measure other instants from.
A system of assigning meaningful values to instants in relation to a known epoch.
Continuous time scale
A time scale fundamentally based on a single incrementing number. This is usually defined as a duration relative to an epoch.
International Atomic Time (TAI)
The primary continuous time scale intended for scientific and technical purposes, defined by international standard. It is agreed internationally based on atomic clocks and is completely continuous.
Coordinated Universal Time (True UTC)
The standard "continuous" time scale intended for civil purposes, defined by international standard. It follows TAI except for the insertion or removal of an integral number of leap seconds which are intended to keep UTC closer to the real and variable length of a solar day. These leap seconds are a discontinuity in the time scale, meaning that it is not truly "continuous".
The "continuous" time scale based on UTC actually implemented by most computer systems. Most computer systems choose to ignore leap seconds wherever possible, even going so far as to refer to the time scale as "UTC". The simplified UTC scale treats all days as having exactly the same number of seconds.
Calendar system (Chronology)
A way of defining time that is meaningful to humans and used in everyday life. It uses individual fields, such as year, month, day, hour minute and second. There are many calendar systems, each defining fields in different ways.
A quantity of time, expressed in terms of the fields of a particular calendar system, such as "five years" or "three hours and twenty minutes."
A period, usually between +14 and -12 hours, that a given location differs from UTC at any given instant. The offset used for a particular location is controlled by government. The value used originally aimed to ensure that the calendar system time of midday (12:00) was equivalent to the solar midday. Today, the offset is influenced by many other factors.
Daylight Saving Time (DST)
A change to the zone offset that typically occurs each summer. The standard approach is to move clocks forward in the Spring and back in the Autumn/Fall. The two periods are generally known as Summer and Winter time. Whether a given location does this, and on what dates is controlled by government.
An area of the planet that uses the same zone offset and observes the same rules for changing it due to daylight savings time. A time zone is controlled by government. Some countries have multiple time zones, others share a time zone with their neighbours.
Time zone rules
A set of rules, for each time zone, that determine how the zone offset varies. A simple set of rules consist solely of a fixed, year round, offset. More complex rules include annual daylight savings changes, historical data and predicted future changes. There are multiple sources of time zone rule data.
Local date / time
A date or time defined solely using calendar system fields. A local date or time does not represent a fixed instant, or range of instants. For example the local date of 3rd December 2009 will start at one instant in Australia, a later instant in the UK, and an even later instant in the USA. In all cases however, the same local date is referred to.
Offset date / time
A date or time defined using calendar system fields and a zone offset. Unlike a local date or time, an offset date or time can be converted to and from an instant. For example the local date of 3rd December 2009 refers to a specific instant once the zone offset of 1 hour ahead of UTC is specified.
A date-time defined using calendar system fields, zone offset and time zone. As with an offset date or time, a zoned date-time can be converted to and from an instant. In addition, the presence of a time zone allows accurate calculations of related date-times, such as adding 6 months (which may cause the zone offset to alter).
The JSR-310 classes should be immutable wherever possible. Experience over time has shown that APIs at this level should consist of simple immutable objects. These are simple to use, can be easily shared, are inherently thread-safe, friendly to the garbage collector and tend to have fewer bugs due to the limited state-space.
The API strives to be fluent within the standard patterns of Java SE. A fluent API has methods that are easy to read and understand, specifically when chained together. The key goal here is to simplify the use and enhance the readability of the API.
Clear, explicit and expected
Each method in the API should be well-defined and clear in what it does. This is not just a question of good Javadoc, but also of ensuring that the method can be called in isolation successfully and meaningfully.
The API should be extensible in well defined ways by application developers, not just JSR authors. The reasoning is simple - there are just far too many weird and wonderful ways to manipulate time. A JSR cannot capture all of them, but an extensible JSR design can allow for them to be added as required by application developers or open source projects.
We classify dates and times into two basic use cases - machine-scale and human-scale.
Machine-scale time represents the passage of time using a single, continually incrementing number. The rules that determine how the scale is measured and communicated are typically defined by international scientific standards organisations.
Two key classes are defined to represent machine-scale time:
These classes use nanosecond precision. The classes have sufficient accuracy to represent any nanosecond instant within the current age of the universe. The epoch used is 1970-01-01T00:00:00Z (midnight at the start of 1 January 1970 UTC), as per the current Java SE date and time classes.
Instant defines the instant in terms of the simplified UTC time scale, which ignores leap seconds. This choice simplifies the API and should follow what most users expect.
To handle leap seconds and other time-scales, additional classes are defined:
Three time-scales are supplied - Simplified UTC, True UTC and TAI. Conversion between values in these time-scales is supported, although clearly conversion to a regular Instant is lossy. The intention is that only those applications that specifically need to handle leap seconds will use these classes.
Human-scale time represents the passage of time using a number of named fields, such as year, month, day, hour, minute and second. The rules that determine how the fields work together are defined in a calendar system.
The design adopted splits the classes into a high-level API suitable for general use and a low-level API designed for advanced use and frameworks.
The high level API contains the following key classes:
Each of these date-time classes represent time in the ISO calendar system, defined by ISO-8601. This is also known as the proleptic Gregorian calendar system, and is the civil calendar system used today in the vast majority of the world.
Other calendar systems are supported with their own dedicated date classes. However the other calendar systems do not have the breadth and depth of the main ISO calendar system API.
Each date-time field can be represented as an int. However, some fields are primarily represented using an enum for code clarity and safety. These include month, day of week, am/pm, quarter and era.
Although there are lots of classes and each class has lots of methods, the "conceptual weight" of the API is greatly reduced through consistent use of method name prefixes. Some of these prefixes differ from JavaBean conventions simply because the classes are immutable:
The high level API includes a number of strategy interface plug-in points:
The low level API provides access to both fields and entire objects, such as the date, time or offset. Each item that can be accessed has a rule - either a CalendricalRule or its subclass a DateTimeFieldRule. The former is designed to represent the rules for combination classes like dates, times and time zones, whereas the latter represents a single field.
Each rule is a singleton defining what the associated calendar component represents. The date-time field rules include the minimum and maximum valid values.
The rule is frequently used as a key, for example to extract data from an object or to store data in a hash map.
The division in the API between machine-scale and human-scale is deliberate and necessary, as the two time scales represent different ways of looking at time.
The machine-scale approach is very time-line focussed. For example, Instant simply represents an instant on the time-line. The only meaningful operations on the class are to check whether the instant is before or after another instant. These classes will be of most use for recording event timestamps and logging.
The human-scale approach is very focussed on what the time means to a human, through the use of the fields. In addition to getting and setting the field values, methods are provided to perform mathematical operations, such as adding three days to a date. These classes will be of most use in business logic, such as representing the departure time of a train or a customer's birthday.
The design adopted is notably different to the Java SE Calendar API and the Joda-Time API.
The Java SE Calendar API has a single base class that represents both the date-time and the calendar system. Different calendar systems are implemented as subclasses. This design is flawed as calendar systems are too different to be properly treated as subclasses.
The Joda-Time API has simple date-time classes with a plug-in calendar system (chronology). This design, while better than Calendar, is also flawed because each method on the API is unable to properly define its result. For example, the getMonthOfYear() method normally returns a value from 1 to 12, however if the Coptic calendar system has been "plugged in" then the method will return results from 1 to 13.
The JSR-310 design ensures that each method on the core API is able to fully define its input and output by focussing the entire class on a single calendar system. The problems of the Java SE API are avoided by not having a common superclass. Instead, users with advanced requirements have to study the API a little more closely and use the low-level calendrical classes.
The purpose of an Early Draft Review (EDR) is to gain feedback on an early version of the JSR. This is no different for JSR-310.
The contents of the EDR are this specification and the Javadoc. The reference implementation with source code is available at https://jsr-310.dev.java.net/source/browse/jsr-310/ where trunk contains the latest code, and there is a tag for the EDR.
JSR-310 needs feedback! We need reviewers to read the specification and Javadoc, and where possible, try out the code (its still Alpha).
Specifically, we need to know if
Remember - Java SE already has two poor quality date/time APIs. We need to ensure that the third one works well!
Feedback can be sent by email to firstname.lastname@example.org which is a public mailing list (so comments will be publicly archived).