An abstract implementation of Chronology
.
An abstract implementation of Chronology
.
This class must be implemented with care to ensure other classes operate correctly. All implementations that can be instantiated must be final, immutable and thread-safe. Subclasses should be Serializable wherever possible.
A date expressed in terms of a standard year-month-day calendar system.
A date expressed in terms of a standard year-month-day calendar system.
This class is used by applications seeking to handle dates in non-ISO calendar systems. For example, the Japanese, Minguo, Thai Buddhist and others.
ChronoLocalDate
is built on the generic concepts of year, month and day.
The calendar system, represented by a Chronology
, expresses the relationship between
the fields and this class allows the resulting date to be manipulated.
Note that not all calendar systems are suitable for use with this class. For example, the Mayan calendar uses a system that bears no relation to years, months and days.
The API design encourages the use of LocalDate
for the majority of the application.
This includes code to read and write from a persistent data store, such as a database,
and to send dates and times across a network. The ChronoLocalDate
instance is then used
at the user interface level to deal with localized input/output.
Example:
System.out.printf("Example()%n"); // Enumerate the list of available calendars and print today for each Set<Chrono> chronos = Chrono.getAvailableChronologies(); for (Chrono chrono : chronos) { ChronoLocalDate date = chrono.dateNow(); System.out.printf(" %20s: %s%n", chrono.getID(), date.toString()); } // Print the Hijrah date and calendar ChronoLocalDate date = Chrono.of("Hijrah").dateNow(); int day = date.get(ChronoField.DAY_OF_MONTH); int dow = date.get(ChronoField.DAY_OF_WEEK); int month = date.get(ChronoField.MONTH_OF_YEAR); int year = date.get(ChronoField.YEAR); System.out.printf(" Today is %s %s %d-%s-%d%n", date.getChrono().getID(), dow, day, month, year); // Print today's date and the last day of the year ChronoLocalDate now1 = Chrono.of("Hijrah").dateNow(); ChronoLocalDate first = now1.with(ChronoField.DAY_OF_MONTH, 1) .with(ChronoField.MONTH_OF_YEAR, 1); ChronoLocalDate last = first.plus(1, ChronoUnit.YEARS) .minus(1, ChronoUnit.DAYS); System.out.printf(" Today is %s: start: %s; end: %s%n", last.getChrono().getID(), first, last);
The set of calendars is extensible by defining a subclass of ChronoLocalDate
to represent a date instance and an implementation of Chronology
to be the factory for the ChronoLocalDate subclass.
To permit the discovery of the additional calendar types the implementation of
Chronology
must be registered as a Service implementing the Chronology
interface
in the META-INF/Services
file as per the specification of java.util.ServiceLoader
.
The subclass must function according to the Chronology
class description and must provide its
calendar name
and
calendar type
.
This abstract class must be implemented with care to ensure other classes operate correctly. All implementations that can be instantiated must be final, immutable and thread-safe. Subclasses should be Serializable wherever possible.
the date type
A date without time-of-day or time-zone in an arbitrary chronology, intended for advanced globalization use cases.
A date without time-of-day or time-zone in an arbitrary chronology, intended for advanced globalization use cases.
Most applications should declare method signatures, fields and variables as `[[LocalDate]]`, not this interface.
A ChronoLocalDate
is the abstract representation of a date where the
Chronology chronology
, or calendar system, is pluggable.
The date is defined in terms of fields expressed by TemporalField
,
where most common implementations are defined in ChronoField
.
The chronology defines how the calendar system operates and the meaning of
the standard fields.
The design of the API encourages the use of LocalDate
rather than this
interface, even in the case where the application needs to deal with multiple
calendar systems. The rationale for this is explored in the following documentation.
The primary use case where this interface should be used is where the generic
type parameter
is fully defined as a specific chronology.
In that case, the assumptions of that chronology are known at development
time and specified in the code.
When the chronology is defined in the generic type parameter as ? or otherwise
unknown at development time, the rest of the discussion below applies.
To emphasize the point, declaring a method signature, field or variable as this
interface type can initially seem like the sensible way to globalize an application,
however it is usually the wrong approach.
As such, it should be considered an application-wide architectural decision to choose
to use this interface as opposed to LocalDate
.
==== Architectural issues to consider ====
These are some of the points that must be considered before using this interface
throughout an application.
1) Applications using this interface, as opposed to using just LocalDate
,
face a significantly higher probability of bugs. This is because the calendar system
in use is not known at development time. A key cause of bugs is where the developer
applies assumptions from their day-to-day knowledge of the ISO calendar system
to code that is intended to deal with any arbitrary calendar system.
The section below outlines how those assumptions can cause problems
The primary mechanism for reducing this increased risk of bugs is a strong code review process.
This should also be considered a extra cost in maintenance for the lifetime of the code.
2) This interface does not enforce immutability of implementations.
While the implementation notes indicate that all implementations must be immutable
there is nothing in the code or type system to enforce this. Any method declared
to accept a ChronoLocalDate
could therefore be passed a poorly or
maliciously written mutable implementation.
3) Applications using this interface must consider the impact of eras.
LocalDate
shields users from the concept of eras, by ensuring that getYear()
returns the proleptic year. That decision ensures that developers can think of
LocalDate
instances as consisting of three fields - year, month-of-year and day-of-month.
By contrast, users of this interface must think of dates as consisting of four fields -
era, year-of-era, month-of-year and day-of-month. The extra era field is frequently
forgotten, yet it is of vital importance to dates in an arbitrary calendar system.
For example, in the Japanese calendar system, the era represents the reign of an Emperor.
Whenever one reign ends and another starts, the year-of-era is reset to one.
4) The only agreed international standard for passing a date between two systems
is the ISO-8601 standard which requires the ISO calendar system. Using this interface
throughout the application will inevitably lead to the requirement to pass the date
across a network or component boundary, requiring an application specific protocol or format.
5) Long term persistence, such as a database, will almost always only accept dates in the
ISO-8601 calendar system (or the related Julian-Gregorian). Passing around dates in other
calendar systems increases the complications of interacting with persistence.
6) Most of the time, passing a ChronoLocalDate
throughout an application
is unnecessary, as discussed in the last section below.
==== False assumptions causing bugs in multi-calendar system code ====
As indicated above, there are many issues to consider when try to use and manipulate a
date in an arbitrary calendar system. These are some of the key issues.
Code that queries the day-of-month and assumes that the value will never be more than
31 is invalid. Some calendar systems have more than 31 days in some months.
Code that adds 12 months to a date and assumes that a year has been added is invalid.
Some calendar systems have a different number of months, such as 13 in the Coptic or Ethiopic.
Code that adds one month to a date and assumes that the month-of-year value will increase
by one or wrap to the next year is invalid. Some calendar systems have a variable number
of months in a year, such as the Hebrew.
Code that adds one month, then adds a second one month and assumes that the day-of-month
will remain close to its original value is invalid. Some calendar systems have a large difference
between the length of the longest month and the length of the shortest month.
For example, the Coptic or Ethiopic have 12 months of 30 days and 1 month of 5 days.
Code that adds seven days and assumes that a week has been added is invalid.
Some calendar systems have weeks of other than seven days, such as the French Revolutionary.
Code that assumes that because the year of date1
is greater than the year of date2
then date1
is after date2
is invalid. This is invalid for all calendar systems
when referring to the year-of-era, and especially untrue of the Japanese calendar system
where the year-of-era restarts with the reign of every new Emperor.
Code that treats month-of-year one and day-of-month one as the start of the year is invalid.
Not all calendar systems start the year when the month value is one.
In general, manipulating a date, and even querying a date, is wide open to bugs when the
calendar system is unknown at development time. This is why it is essential that code using
this interface is subjected to additional code reviews. It is also why an architectural
decision to avoid this interface type is usually the correct one.
==== Using LocalDate instead ====
The primary alternative to using this interface throughout your application is as follows.
- Declare all method signatures referring to dates in terms of LocalDate
.
- Either store the chronology (calendar system) in the user profile or lookup
the chronology from the user locale
- Convert the ISO LocalDate
to and from the user's preferred calendar system during
printing and parsing
This approach treats the problem of globalized calendar systems as a localization issue
and confines it to the UI layer. This approach is in keeping with other localization
issues in the java platform.
As discussed above, performing calculations on a date where the rules of the calendar system
are pluggable requires skill and is not recommended.
Fortunately, the need to perform calculations on a date in an arbitrary calendar system
is extremely rare. For example, it is highly unlikely that the business rules of a library
book rental scheme will allow rentals to be for one month, where meaning of the month
is dependent on the user's preferred calendar system.
A key use case for calculations on a date in an arbitrary calendar system is producing
a month-by-month calendar for display and user interaction. Again, this is a UI issue,
and use of this interface solely within a few methods of the UI layer may be justified.
In any other part of the system, where a date must be manipulated in a calendar system
other than ISO, the use case will generally specify the calendar system to use.
For example, an application may need to calculate the next Islamic or Hebrew holiday
which may require manipulating the date.
This kind of use case can be handled as follows:
- start from the ISO LocalDate
being passed to the method
- convert the date to the alternate calendar system, which for this use case is known
rather than arbitrary
- perform the calculation
- convert back to LocalDate
Developers writing low-level frameworks or libraries should also avoid this interface.
Instead, one of the two general purpose access interfaces should be used.
Use `[[TemporalAccessor]]` if read-only access is required, or use `[[Temporal]]`
if read-write access is required.
=== Specification for implementors ===
This interface must be implemented with care to ensure other classes operate correctly.
All implementations that can be instantiated must be final, immutable and thread-safe.
Subclasses should be Serializable wherever possible.
Additional calendar systems may be added to the system.
See `[[Chronology]]` for more details.
A date-time without a time-zone for the calendar neutral API.
A date-time without a time-zone for the calendar neutral API.
ChronoLocalDateTime
is an immutable date-time object that represents a date-time, often
viewed as year-month-day-hour-minute-second. This object can also access other
fields such as day-of-year, day-of-week and week-of-year.
This class stores all date and time fields, to a precision of nanoseconds.
It does not store or represent a time-zone. For example, the value
"2nd October 2007 at 13:45.30.123456789" can be stored in an ChronoLocalDateTime
.
This class is immutable and thread-safe.
the date type
A date-based amount of time, such as '3 years, 4 months and 5 days' in an arbitrary chronology, intended for advanced globalization use cases.
A date-based amount of time, such as '3 years, 4 months and 5 days' in an arbitrary chronology, intended for advanced globalization use cases.
This interface models a date-based amount of time in a calendar system.
While most calendar systems use years, months and days, some do not.
Therefore, this interface operates solely in terms of a set of supported
units that are defined by the Chronology
.
The set of supported units is fixed for a given chronology.
The amount of a supported unit may be set to zero.
The period is modeled as a directed amount of time, meaning that individual parts of the period may be negative.
This abstract class must be implemented with care to ensure other classes operate correctly. All implementations that can be instantiated must be final, immutable and thread-safe. Subclasses should be Serializable wherever possible.
An implementation of ChronoPeriod
.
An implementation of ChronoPeriod
.
A date-time with a time-zone in an arbitrary chronology, intended for advanced globalization use cases.
A date-time with a time-zone in an arbitrary chronology, intended for advanced globalization use cases.
Most applications should declare method signatures, fields and variables as `[[ZonedDateTime]]`, not this interface.
A ChronoZonedDateTime
is the abstract representation of an offset date-time
where the Chronology chronology
, or calendar system, is pluggable.
The date-time is defined in terms of fields expressed by TemporalField
,
where most common implementations are defined in ChronoField
.
The chronology defines how the calendar system operates and the meaning of
the standard fields.
The design of the API encourages the use of ZonedDateTime
rather than this
interface, even in the case where the application needs to deal with multiple
calendar systems. The rationale for this is explored in detail in ChronoLocalDate
.
Ensure that the discussion in ChronoLocalDate
has been read and understood
before using this interface.
This interface must be implemented with care to ensure other classes operate correctly. All implementations that can be instantiated must be final, immutable and thread-safe. Subclasses should be Serializable wherever possible.
the date type
A date-time with a time-zone in the calendar neutral API.
A date-time with a time-zone in the calendar neutral API.
ZoneChronoDateTime
is an immutable representation of a date-time with a time-zone.
This class stores all date and time fields, to a precision of nanoseconds,
as well as a time-zone and zone offset.
The purpose of storing the time-zone is to distinguish the ambiguous case where the local time-line overlaps, typically as a result of the end of daylight time. Information about the local-time can be obtained using methods on the time-zone.
This class is immutable and thread-safe.
the date type
A calendar system, used to organize and identify dates.
A calendar system, used to organize and identify dates.
The main date and time API is built on the ISO calendar system. This class operates behind the scenes to represent the general concept of a calendar system. For example, the Japanese, Minguo, Thai Buddhist and others.
Most other calendar systems also operate on the shared concepts of year, month and day,
linked to the cycles of the Earth around the Sun, and the Moon around the Earth.
These shared concepts are defined by ChronoField
and are availalbe
for use by any Chronology
implementation:
val isoDate: LocalDate = ... val thaiDate: ChronoLocalDate[ThaiBuddhistChrono] = ... val isoYear: Int = isoDate.get(ChronoField.YEAR); val thaiYear: Int = thaiDate.get(ChronoField.YEAR);
As shown, although the date objects are in different calendar systems, represented by different
Chronology
instances, both can be queried using the same constant on ChronoField
.
For a full discussion of the implications of this, see ChronoLocalDate
.
In general, the advice is to use the known ISO-based LocalDate
, rather than
ChronoLocalDate
.
While a Chronology
object typically uses ChronoField
and is based on
an era, year-of-era, month-of-year, day-of-month model of a date, this is not required.
A Chronology
instance may represent a totally different kind of calendar system,
such as the Mayan.
In practical terms, the Chronology
instance also acts as a factory.
The #of(String)
method allows an instance to be looked up by identifier,
while the #ofLocale(Locale)
method allows lookup by locale.
The Chronology
instance provides a set of methods to create ChronoLocalDate
instances.
The date classes are used to manipulate specific dates.
dateNow()
dateNow(clock)
dateNow(zone)
int, int) date(yearProleptic, month, day)
int, int, int) date(era, yearOfEra, month, day)
int) dateYearDay(yearProleptic, dayOfYear)
int, int) dateYearDay(era, yearOfEra, dayOfYear)
date(TemporalAccessor)
Adding New Calendars
The set of available chronologies can be extended by applications.
Adding a new calendar system requires the writing of an implementation of
Chronology
, ChronoLocalDate
and Era
.
The majority of the logic specific to the calendar system will be in
ChronoLocalDate
. The Chronology
subclass acts as a factory.
To permit the discovery of additional chronologies, the ServiceLoader
is used. A file must be added to the META-INF/services
directory with the
name 'org.threeten.bp.chrono.Chrono' listing the implementation classes.
See the ServiceLoader for more details on service loading.
For lookup by id or calendarType, the system provided calendars are found
first followed by application provided calendars.
Each chronology must define a chronology ID that is unique within the system. If the chronology represents a calendar system defined by the Unicode Locale Data Markup Language (LDML) specification then that calendar type should also be specified.
This class must be implemented with care to ensure other classes operate correctly. All implementations that can be instantiated must be final, immutable and thread-safe. Subclasses should be Serializable wherever possible.
An era of the time-line.
An era of the time-line.
Most calendar systems have a single epoch dividing the time-line into two eras.
However, some calendar systems, have multiple eras, such as one for the reign
of each leader.
In all cases, the era is conceptually the largest division of the time-line.
Each chronology defines the Era's that are known Eras and a
Chrono.eras
to get the valid eras.
For example, the Thai Buddhist calendar system divides time into two eras, before and after a single date. By contrast, the Japanese calendar system has one era for the reign of each Emperor.
Instances of Era
may be compared using the ==
operator.
This interface must be implemented with care to ensure other classes operate correctly. All implementations must be singletons - final, immutable and thread-safe. It is recommended to use an enum whenever possible.
The Hijrah calendar system.
The Hijrah calendar system.
This chronology defines the rules of the Hijrah calendar system.
The implementation follows the Freeman-Grenville algorithm (*1) and has following features.
The table shows the features described above.
(*1) The algorithm is taken from the book, The Muslim and Christian Calendars by G.S.P. Freeman-Grenville. === Specification for implementors === This class is immutable and thread-safe.
# of month Name of month Number of days 1 Muharram 30 2 Safar 29 3 Rabi'al-Awwal 30 4 Rabi'ath-Thani 29 5 Jumada l-Ula 30 6 Jumada t-Tania 29 7 Rajab 30 8 Sha`ban 29 9 Ramadan 30 10 Shawwal 29 11 Dhu 'l-Qa`da 30 12 Dhu 'l-Hijja 29, but 30 days in years 2, 5, 7, 10,
13, 16, 18, 21, 24, 26, and 29
A date in the Hijrah calendar system.
A date in the Hijrah calendar system.
This implements ChronoLocalDate
for the Hijrah calendar
.
The Hijrah calendar has a different total of days in a year than Gregorian calendar, and a month is based on the period of a complete revolution of the moon around the earth (as between successive new moons). The calendar cycles becomes longer and unstable, and sometimes a manual adjustment (for entering deviation) is necessary for correctness because of the complex algorithm.
HijrahDate supports the manual adjustment feature by providing a configuration file. The configuration file contains the adjustment (deviation) data with following format.
StartYear/StartMonth(0-based)-EndYear/EndMonth(0-based):Deviation day (1, 2, -1, or -2) Line separator or ";" is used for the separator of each deviation data.Here is the example.
1429/0-1429/1:1 1429/2-1429/7:1;1429/6-1429/11:1 1429/11-9999/11:1The default location of the configuration file is:
$CLASSPATH/org/threeten/bp/chronoAnd the default file name is:
hijrah_deviation.cfgThe default location and file name can be overriden by setting following two Java's system property.
Location: org.threeten.bp.i18n.HijrahDate.deviationConfigDir File name: org.threeten.bp.i18n.HijrahDate.deviationConfigFile
This class is immutable and thread-safe.
An era in the Hijrah calendar system.
An era in the Hijrah calendar system.
The Hijrah calendar system has two eras.
The date 0001-01-01 (Hijrah)
is 622-06-19 (ISO)
.
Do not use ordinal()
to obtain the numeric representation of HijrahEra
.
Use getValue()
instead.
This is an immutable and thread-safe enum.
The ISO calendar system.
The ISO calendar system.
This chronology defines the rules of the ISO calendar system. This calendar system is based on the ISO-8601 standard, which is the de facto world calendar.
The fields are defined as follows:
This class is immutable and thread-safe.
An era in the ISO calendar system.
An era in the ISO calendar system.
The ISO-8601 standard does not define eras. A definition has therefore been created with two eras - 'Current era' (CE) for years from 0001-01-01 (ISO) and 'Before current era' (BCE) for years before that.
Do not use ordinal()
to obtain the numeric representation of IsoEra
.
Use getValue()
instead.
This is an immutable and thread-safe enum.
The Japanese Imperial calendar system.
The Japanese Imperial calendar system.
This chronology defines the rules of the Japanese Imperial calendar system. This calendar system is primarily used in Japan. The Japanese Imperial calendar system is the same as the ISO calendar system apart from the era-based year numbering.
Japan introduced the Gregorian calendar starting with Meiji 6. Only Meiji and later eras are supported; dates before Meiji 6, January 1 are not supported.
The supported ChronoField
instances are:
DAY_OF_WEEK
DAY_OF_MONTH
DAY_OF_YEAR
EPOCH_DAY
MONTH_OF_YEAR
PROLEPTIC_MONTH
YEAR_OF_ERA
YEAR
ERA
This class is immutable and thread-safe.
A date in the Japanese Imperial calendar system.
A date in the Japanese Imperial calendar system.
This date operates using the Japanese Imperial calendar. This calendar system is primarily used in Japan.
The Japanese Imperial calendar system is the same as the ISO calendar system apart from the era-based year numbering. The proleptic-year is defined to be equal to the ISO proleptic-year.
Japan introduced the Gregorian calendar starting with Meiji 6. Only Meiji and later eras are supported.
For example, the Japanese year "Heisei 24" corresponds to ISO year "2012".
Calling japaneseDate.get(YEAR_OF_ERA)
will return 24.
Calling japaneseDate.get(YEAR)
will return 2012.
Calling japaneseDate.get(ERA)
will return 2, corresponding to
JapaneseChEra.HEISEI
.
This class is immutable and thread-safe.
An era in the Japanese Imperial calendar system.
An era in the Japanese Imperial calendar system.
This class defines the valid eras for the Japanese chronology. Japan introduced the Gregorian calendar starting with Meiji 6. Only Meiji and later eras are supported; dates before Meiji 6, January 1 are not supported.
The four supported eras are hard-coded.
A single additional era may be registered using String)
.
This class is immutable and thread-safe.
The Minguo calendar system.
The Minguo calendar system.
This chronology defines the rules of the Minguo calendar system.
This calendar system is primarily used in the Republic of China, often known as Taiwan.
Dates are aligned such that 0001-01-01 (Minguo)
is 1912-01-01 (ISO)
.
The fields are defined as follows:
This class is immutable and thread-safe.
A date in the Minguo calendar system.
A date in the Minguo calendar system.
This date operates using the Minguo calendar.
This calendar system is primarily used in the Republic of China, often known as Taiwan.
Dates are aligned such that 0001-01-01 (Minguo)
is 1912-01-01 (ISO)
.
This class is immutable and thread-safe.
An era in the Minguo calendar system.
An era in the Minguo calendar system.
The Minguo calendar system has two eras.
The date 0001-01-01 (Minguo)
is equal to 1912-01-01 (ISO)
.
Do not use ordinal()
to obtain the numeric representation of MinguoEra
.
Use getValue()
instead.
This is an immutable and thread-safe enum.
The Thai Buddhist calendar system.
The Thai Buddhist calendar system.
This chronology defines the rules of the Thai Buddhist calendar system.
This calendar system is primarily used in Thailand.
Dates are aligned such that 2484-01-01 (Buddhist)
is 1941-01-01 (ISO)
.
The fields are defined as follows:
This class is immutable and thread-safe.
A date in the Thai Buddhist calendar system.
A date in the Thai Buddhist calendar system.
This date operates using the Thai Buddhist calendar.
This calendar system is primarily used in Thailand.
Dates are aligned such that 2484-01-01 (Buddhist)
is 1941-01-01 (ISO)
.
This class is immutable and thread-safe.
An era in the Thai Buddhist calendar system.
An era in the Thai Buddhist calendar system.
The Thai Buddhist calendar system has two eras.
Do not use ordinal() to obtain the numeric representation of a ThaiBuddhistEra instance. Use getValue() instead.
This is an immutable and thread-safe enum.
Support for calendar systems other than the default ISO.
The main API is based around the calendar system defined in ISO-8601. This package provides support for alternate systems.
The supported calendar systems includes:
-Hijrah calendar -Japanese calendar -Minguo calendar -Thai Buddhist calendar
It is intended that applications use the main API whenever possible, including code to read and write from a persistent data store, such as a database, and to send dates and times across a network. This package is then used at the user interface level to deal with localized input/output. See
ChronoLocalDate
for a full discussion of the issues.Example
This example creates and uses a date in a non-ISO calendar system.