This document is an initial user guide for the ThreeTen project and JSR 310.
The primary goal of this project, via JSR-310, is to develop a new API to replace the
Date
and
Calendar
classes in the current Java SE platform. A key part of this is providing a new API that is dramatically easier to use and less error prone. As such, all the key public classes are immuatble and thread-safe.
A secondary goal is to define terminology and behaviour that other areas in computing can adopt.
A time-line is a way of defining time progressing from the past to the future. The machine time-line is a mechanism of describing that is intended for machines to use. This is normally defined as a single incrementing number. For example, the millisecond count from 1970-01-01 in the
Date
class.
ThreeTen defines two core classes in this area.
The
Instant
class represents an instant in time to an accuracy of nanoseconds. It should be viewed as a replacement for java.util.Date. Operations on an Instant include comparison to another Instant and adding or subtracting a duration. The
Duration
class represents a duration of time to an accuracy of nanoseconds. There is no current JDK class representing this concept. Operations on a Duration include comparison to another Duration and mathematical operations like addition, subtraction, multiplication and division.
Time scales
The
Instant
class operates on a simplified time-line model that avoids dealing with leap seconds. It does this using the UTC-SLS convention which smooths leap seconds ensuring that there are always 60 seconds in a minute. These simplifications are useful because most applications do not take into account the existence of leap seconds. If your application needs to take them into account then an alternate class is needed. The
UTCInstant
class represents an instant taking into account the correct definition of UTC with leap seconds. The
TAIInstant
class represents a pure scientific time-scale.
The human time-line is a mechanism of describing that is intended for humans to use. This is defined as date-time fields, such as year month, day, hour, minute and second.
ThreeTen defines many classes in this area.
The
LocalDate
class represents a date. There is no representation of a time or time-zone. Methods are provided to get the year, month, day-of-month, day-of-week and day-of-year, and to return a new instance with any of these altered. Further methods allow a period of time measured in years, months or days to be added/subtracted.
LocalDate date = LocalDate.of(2010, MonthOfYear.FEBRUARY, 26); date = date.plusDays(3); String str = date.toString(); // 2010-03-01
The
LocalTime
class represents a time. There is no representation of a date or time-zone. Methods are provided to get the hour, minute, second and nanosecond, and to return a new instance with any of these altered. Further methods allow a period of time measured in hours, minutes, seconds or nanoseconds to be added/subtracted.
LocalTime time = LocalTime.of(12, 30); time = time.plusHours(3); String str = time.toString(); // 15:30
The
LocalDateTime
class represents a date-time. There is no representation of a time-zone. This is a combination of a
LocalDate
and a
LocalTime
and has similar methods.
LocalDateTime dt = LocalDate.of(2010, MonthOfYear.FEBRUARY, 26, 12, 30); dt = dt.plusDays(3).plusHours(3); String str = dt.toString(); // 2010-03-01T15:30
The
OffsetDate
,
OffsetTime
and
OffsetDateTime
classes represents a date, time or date-time with a time-zone offset, such as +02:00
. There is no representation of time-zone, as in Europe/Paris
. These classes are built around the matching "Local" class and store the additional ZoneOffset instance.
OffsetDateTime
can be converted to and from an
Instant
with no loss of accuracy. The
ZonedDateTime
class represents a date-time with full time-zone rule, such as Europe/Paris
. The addition of time-zone rules makes the class significantly more complex than
OffsetDateTime
as there are points on the local time-line that don't exist or exist twice (due to daylight savings time changes). This class handles those gaps and overlaps using the
ZoneResolver
class, with standard implementations in
ZoneResolvers
. Other representations of date and time include
Year
, representing a year,
YearMonth
, representing the combination of a year and a month,
MonthDay
, representing the combination of a month and a day, and
DateTimeFields
, representing any combination of date-time fields.
The period classes represent durations measured in human-scale units.
The
Period
class allows a period in years, months, days, hours, minutes and seconds to be stored. This is the most commonly used period class. There are two more advanced classes. The
PeriodField
class represents a period in a single unit, such as "6 Months". The
PeriodFields
class represents a compound period built of a collection of fields. Methods are provided to allow conversion between the different units where the conversions are fixed.
The current Java SE platform uses int constants for months, day-of-week, era and am-pm. ThreeTen uses the Java 5 Enum for these concepts to create a better API. The int values are retained internally, and may be used externally for months, where 1 is January and 12 is December.
MonthOfYear month = date.getMonthOfYear(); DayOfWeek dow = date.getDayOfWeek(); if (month.isFebruary() and dow.isFriday()) ...
What is the result when you add one month to the 31st of March? Is it the 30th of April? The 1st of May? An exception?
ThreeTen addresses this problem using the
DateResolver
strategy interface. Standard implementations are provided in
DateResolvers
.
LocalDate date = LocalDate.of(2010, MonthOfYear.JANUARY, 31); LocalDate oneMonthLater = date.plusMonths(1, DateResolvers.previousValid()); // 28th Feb LocalDate oneMonthLater = date.plusMonths(1, DateResolvers.nextValid()); // 1st Mar
How do you find the last day of the month? Or the next working day? Or a week on Tuesday?
ThreeTen addresses this problem using the
DateAdjuster
strategy interface. Standard implementations are provided in
DateAdjusters
.
LocalDate date = LocalDate.of(2010, MonthOfYear.FEBRUARY, 26); LocalDate endOfMonth = date.with(DateAdjusters.lastDayOfMonth()); LocalDate nextTue = date.with(DateAdjusters.next(DayOfWeek.TUESDAY));
The builder pattern allows the object you want to be built up using individual parts. This is achieved using the methods prefixed by "at".
// builder pattern OffsetDateTime dt = Year.of(2010).atMonth(MonthOfYear.FEBRUARY).atDay(26) .atTime(12, 30).atOffset(ZoneOffset.of("+03:00")); // normal shorthand OffsetDateTime dt = OffsetDateTime.of(2010, 2, 26, 12, 30, ZoneOffset.of("+03:00"));
In ThreeTen, the current time is no longer obtained via
System.currentTimeMillis()
. Instead, the
TimeSource
class is used. This returns an instant based on the current time, or an altered instant suitable for testing. For the human-scale classes, the
Clock
class should used. This has methods to obtain all different kinds of date-time object, based on a time-source and a time-zone.
@Inject private Clock clock public void process() { if (clock.today().getDayOfWeek().isMonday()) ... }
In ThreeTen, time zones are represented by three co-operating classes.
The
ZoneOffset
class represents a fixed offset from UTC in seconds. This is normally represented as a string of the format "±hh:mm". Using a zone-offset is easier and safer than using a full time-zone as there are no gaps or overlaps in the local time-line when just using an offset. The
TimeZone
class represents the identifier for a region of the planet where time zone rules are defined and who has collated the data. The identifier consists of three parts:
The full identifier has the format {groupID}:{regionID}#{versionID}
where the version id can be omitted (see below) and the group ID can be implied (as the standard TZDB used in java SE today).
The
ZoneRules
are the actual set of rules that define when the zone-offset changes. Each set of rules contains two parts - a list of historical transitions where the zone-offset has changed in the past, and a formula for calculating future changes. The rule information is fully accessible via the API. The
ZonedDateTime
class stores a
TimeZone
reference, rather than a
ZoneRules
. The time-zone must contain a group and a region, but the version may be blank, which indicates a "floating version". A "floating version" simply means that the
ZonedDateTime
class will use the latest available zone-rules. By comparison, if the date-time stores a time-zone with a specific version, then only that version of the rules can be used. This approach allows the time zone rules to be updated in a background thread while the application is running. The date-time object will pick up the changes on the next calculation is the version is floating or not at all if the version is specified.
The code to support background thread zone rules updates is not included in this JSR as it is more appropriate at the Java EE level.
In ThreeTen, the standard civil calendar is considered to be the default and most classes are built around it. This calendar system is defined as the
ISOChronology
and models the time-line using the current rules for leap years over all time. It includes year 0 but omits leap seconds. To handle alternate calendar systems, a package of additional chronology and date classes is provided. Thus, to use the coptic date you should use the
CopticDate
class. Low level code can use the
Calendrical
interface to interoperate between different calendars. The ISO calendar system does not model historical dates accurately. The rules of the ISO calendar system were first introduced in 1582 and adopted by some European countries. However, some other countries did not adopt the system until into the 1900s. As such, it is always essential to check the software requirements when dealing with historical dates. ThreeTen provides the
HistoricDate
class to assist, which requires the cutover from the older Julian calendar system to the newer ISO/Gregorian system to be passed in.
All standard ThreeTen have meaningful
toString
methods. The formatting package is there should more control be required. The formatting package supplies a set of standard formatters in
DateTimeFormatters
and a builder for complex formats in
DateTimeFormatterBuilder
. The end result is an instance of
DateTimeFormatter
which can be used to print to or parse from a string. Printing is based on an
Appendable
to allow direct output to a stream. The formatter is independent of the older Java SE Format class. However, a method
asFormat
allows a compatible formatter to be obtained.
OldWiki: Early_Draft_Review
OldWiki: Main_Page
OldWiki: Old_home_page