packages/core/src/temporal/ChronoField.js
/**
* @copyright (c) 2016, Philipp Thürwächter & Pattrick Hüper
* @copyright (c) 2007-present, Stephen Colebourne & Michael Nascimento Santos
* @license BSD-3-Clause (see LICENSE in the root directory of this source tree)
*/
import { MAX_SAFE_INTEGER, MIN_SAFE_INTEGER } from '../MathUtil';
import { ChronoUnit } from './ChronoUnit';
import { TemporalField } from './TemporalField';
import { ValueRange } from './ValueRange';
import { YearConstants } from '../YearConstants';
/**
* A standard set of fields.
*
* This set of fields provide field-based access to manipulate a date, time or date-time.
* The standard set of fields can be extended by implementing {@link TemporalField}.
*
* These fields are intended to be applicable in multiple calendar systems.
* For example, most non-ISO calendar systems define dates as a year, month and day,
* just with slightly different rules.
* The documentation of each field explains how it operates.
*
* ### Static properties:
*
* - `ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH`: This represents concept of the count of
* days within the period of a week where the weeks are aligned to the start of the month.
* This field is typically used with `ALIGNED_WEEK_OF_MONTH`.
*
* - `ChronoField.ALIGNED_DAY_OF_WEEK_IN_YEAR`: This represents concept of the count of days
* within the period of a week where the weeks are aligned to the start of the year.
* This field is typically used with `ALIGNED_WEEK_OF_YEAR`.
*
* - `ChronoField.ALIGNED_WEEK_OF_MONTH`: This represents concept of the count of weeks within
* the period of a month where the weeks are aligned to the start of the month. This field
* is typically used with `ALIGNED_DAY_OF_WEEK_IN_MONTH`.
*
* - `ChronoField.ALIGNED_WEEK_OF_YEAR`: This represents concept of the count of weeks within
* the period of a year where the weeks are aligned to the start of the year. This field
* is typically used with `ALIGNED_DAY_OF_WEEK_IN_YEAR`.
*
* - `ChronoField.AMPM_OF_DAY`: This counts the AM/PM within the day, from 0 (AM) to 1 (PM).
*
* - `ChronoField.CLOCK_HOUR_OF_AMPM`: This counts the hour within the AM/PM, from 1 to 12.
* This is the hour that would be observed on a standard 12-hour analog wall clock.
*
* - `ChronoField.CLOCK_HOUR_OF_DAY`: This counts the hour within the AM/PM, from 1 to 24.
* This is the hour that would be observed on a 24-hour analog wall clock.
*
* - `ChronoField.DAY_OF_MONTH`: This represents the concept of the day within the month.
* In the default ISO calendar system, this has values from 1 to 31 in most months.
* April, June, September, November have days from 1 to 30, while February has days from
* 1 to 28, or 29 in a leap year.
*
* - `ChronoField.DAY_OF_WEEK`: This represents the standard concept of the day of the week.
* In the default ISO calendar system, this has values from Monday (1) to Sunday (7).
* The {@link DayOfWeek} class can be used to interpret the result.
*
* - `ChronoField.DAY_OF_YEAR`: This represents the concept of the day within the year.
* In the default ISO calendar system, this has values from 1 to 365 in standard years and
* 1 to 366 in leap years.
*
* - `ChronoField.EPOCH_DAY`: This field is the sequential count of days where
* 1970-01-01 (ISO) is zero. Note that this uses the local time-line, ignoring offset and
* time-zone.
*
* - `ChronoField.ERA`: This represents the concept of the era, which is the largest
* division of the time-line. This field is typically used with `YEAR_OF_ERA`.
*
* In the default ISO calendar system, there are two eras defined, 'BCE' and 'CE'. The era
* 'CE' is the one currently in use and year-of-era runs from 1 to the maximum value.
* The era 'BCE' is the previous era, and the year-of-era runs backwards.
*
* - `ChronoField.HOUR_OF_AMPM`: This counts the hour within the AM/PM, from 0 to 11.
* This is the hour that would be observed on a standard 12-hour digital clock.
*
* - `ChronoField.HOUR_OF_DAY`: This counts the hour within the day, from 0 to 23. This is
* the hour that would be observed on a standard 24-hour digital clock.
*
* - `ChronoField.INSTANT_SECONDS`: This represents the concept of the sequential count of
* seconds where 1970-01-01T00:00Z (ISO) is zero. This field may be used with `NANO_OF_DAY`
* to represent the fraction of the day.
*
* An Instant represents an instantaneous point on the time-line. On their own they have
* no elements which allow a local date-time to be obtained. Only when paired with an offset
* or time-zone can the local date or time be found. This field allows the seconds part of
* the instant to be queried.
*
* - `ChronoField.MICRO_OF_DAY`: This counts the microsecond within the day, from 0 to
* (24 * 60 * 60 * 1,000,000) - 1.
*
* This field is used to represent the micro-of-day handling any fraction of the second.
* Implementations of {@link TemporalAccessor} should provide a value for this field if they
* can return a value for `SECOND_OF_DAY` filling unknown precision with zero.
*
* When this field is used for setting a value, it should behave in the same way as
* setting `NANO_OF_DAY` with the value multiplied by 1,000.
*
* - `ChronoField.MICRO_OF_SECOND`: This counts the microsecond within the second, from 0
* to 999,999.
*
* This field is used to represent the micro-of-second handling any fraction of the second.
* Implementations of {@link TemporalAccessor} should provide a value for this field if they
* can return a value for `SECOND_OF_MINUTE`, `SECOND_OF_DAY` or `INSTANT_SECONDS` filling
* unknown precision with zero.
*
* - `ChronoField.MILLI_OF_DAY`: This counts the millisecond within the day, from 0 to
* (24 * 60 * 60 * 1,000) - 1.
*
* This field is used to represent the milli-of-day handling any fraction of the second.
* Implementations of {@link TemporalAccessor} should provide a value for this field if they
* can return a value for `SECOND_OF_DAY` filling unknown precision with zero.
*
* When this field is used for setting a value, it should behave in the same way as
* setting `NANO_OF_DAY` with the value multiplied by 1,000,000.
*
* - `ChronoField.MILLI_OF_SECOND`: This counts the millisecond within the second, from 0 to
* 999.
*
* This field is used to represent the milli-of-second handling any fraction of the second.
* Implementations of {@link TemporalAccessor} should provide a value for this field if they can
* return a value for `SECOND_OF_MINUTE`, `SECOND_OF_DAY` or `INSTANT_SECONDS` filling unknown
* precision with zero.
*
* When this field is used for setting a value, it should behave in the same way as
* setting `NANO_OF_SECOND` with the value multiplied by 1,000,000.
*
* - `ChronoField.MINUTE_OF_DAY`: This counts the minute within the day, from 0 to (24 * 60) - 1.
*
* - `ChronoField.MINUTE_OF_HOUR`: This counts the minute within the hour, from 0 to 59.
*
* - `ChronoField.MONTH_OF_YEAR`: The month-of-year, such as March. This represents the concept
* of the month within the year. In the default ISO calendar system, this has values from
* January (1) to December (12).
*
* - `ChronoField.NANO_OF_DAY`: This counts the nanosecond within the day, from 0 to
* (24 * 60 * 60 * 1,000,000,000) - 1.
*
* This field is used to represent the nano-of-day handling any fraction of the second.
* Implementations of {@link TemporalAccessor} should provide a value for this field if they
* can return a value for `SECOND_OF_DAY` filling unknown precision with zero.
*
* - `ChronoField.NANO_OF_SECOND`: This counts the nanosecond within the second, from 0
* to 999,999,999.
*
* This field is used to represent the nano-of-second handling any fraction of the second.
* Implementations of {@link TemporalAccessor} should provide a value for this field if they
* can return a value for `SECOND_OF_MINUTE`, `SECOND_OF_DAY` or `INSTANT_SECONDS` filling
* unknown precision with zero.
*
* When this field is used for setting a value, it should set as much precision as the
* object stores, using integer division to remove excess precision. For example, if the
* {@link TemporalAccessor} stores time to millisecond precision, then the nano-of-second must
* be divided by 1,000,000 before replacing the milli-of-second.
*
* - `ChronoField.OFFSET_SECONDS`: This represents the concept of the offset in seconds of
* local time from UTC/Greenwich.
*
* A {@link ZoneOffset} represents the period of time that local time differs from
* UTC/Greenwich. This is usually a fixed number of hours and minutes. It is equivalent to
* the total amount of the offset in seconds. For example, during the winter Paris has an
* offset of +01:00, which is 3600 seconds.
*
* - `ChronoField.PROLEPTIC_MONTH`: The proleptic-month, which counts months sequentially
* from year 0.
*
* The first month in year zero has the value zero. The value increase for later months
* and decrease for earlier ones. Note that this uses the local time-line, ignoring offset
* and time-zone.
*
* - `ChronoField.SECOND_OF_DAY`: This counts the second within the day, from 0 to
* (24 * 60 * 60) - 1.
*
* - `ChronoField.SECOND_OF_MINUTE`: This counts the second within the minute, from 0 to 59.
*
* - `ChronoField.YEAR`: The proleptic year, such as 2012. This represents the concept of
* the year, counting sequentially and using negative numbers. The proleptic year is not
* interpreted in terms of the era.
*
* The standard mental model for a date is based on three concepts - year, month and day.
* These map onto the `YEAR`, `MONTH_OF_YEAR` and `DAY_OF_MONTH` fields. Note that there is no
* reference to eras. The full model for a date requires four concepts - era, year, month and
* day. These map onto the `ERA`, `YEAR_OF_ERA`, `MONTH_OF_YEAR` and `DAY_OF_MONTH` fields.
* Whether this field or `YEAR_OF_ERA` is used depends on which mental model is being used.
*
* - `ChronoField.YEAR_OF_ERA`: This represents the concept of the year within the era. This
* field is typically used with `ERA`. The standard mental model for a date is based on three
* concepts - year, month and day. These map onto the `YEAR`, `MONTH_OF_YEAR` and
* `DAY_OF_MONTH` fields. Note that there is no reference to eras. The full model for a date
* requires four concepts - era, year, month and day. These map onto the `ERA`, `YEAR_OF_ERA`,
* `MONTH_OF_YEAR` and `DAY_OF_MONTH` fields. Whether this field or `YEAR` is used depends on
* which mental model is being used.
*
* In the default ISO calendar system, there are two eras defined, 'BCE' and 'CE'.
* The era 'CE' is the one currently in use and year-of-era runs from 1 to the maximum value.
* The era 'BCE' is the previous era, and the year-of-era runs backwards.
*
* For example, subtracting a year each time yield the following:
* - year-proleptic 2 = 'CE' year-of-era 2
* - year-proleptic 1 = 'CE' year-of-era 1
* - year-proleptic 0 = 'BCE' year-of-era 1
* - year-proleptic -1 = 'BCE' year-of-era 2
*
* Note that the ISO-8601 standard does not actually define eras. Note also that the
* ISO eras do not align with the well-known AD/BC eras due to the change between the Julian
* and Gregorian calendar systems.
*/
export class ChronoField extends TemporalField {
/**
* helper function to get one of the static ChronoField defines by name, needed to resolve ChronoField from EnumMap
*
* @param {String} fieldName
* @return {ChronoField | null}
* @private
*/
static byName(fieldName) {
for (const prop in ChronoField) {
if (ChronoField[prop]) {
if ((ChronoField[prop] instanceof ChronoField) && ChronoField[prop].name() === fieldName) {
return ChronoField[prop];
}
}
}
}
/**
*
* @param {!string} name
* @param {!TemporalUnit} baseUnit
* @param {!TemporalUnit} rangeUnit
* @param {!ValueRange} range
* @private
*/
constructor(name, baseUnit, rangeUnit, range) {
super();
this._name = name;
this._baseUnit = baseUnit;
this._rangeUnit = rangeUnit;
this._range = range;
}
/**
* @return {string}
*/
name(){
return this._name;
}
/**
* @return {TemporalUnit} the period unit defining the base unit of the field.
*/
baseUnit(){
return this._baseUnit;
}
/**
* @return {TemporalUnit} the period unit defining the range of the field.
*/
rangeUnit(){
return this._rangeUnit;
}
/**
* @return {ValueRange} the range of valid values for the field.
*/
range(){
return this._range;
}
/**
* @returns {string}
*/
displayName(){
return this.toString();
}
/**
* Checks that the specified value is valid for this field.
*
* This validates that the value is within the outer range of valid values
* returned by {@link range}.
*
* This method checks against the range of the field in the ISO-8601 calendar system.
*
* @param {!number} value the value to check.
* @returns {number} the value that was passed in.
*/
checkValidValue(value) {
return this.range().checkValidValue(value, this);
}
/**
* Checks that the specified value is valid and fits in an `int`.
*
* This validates that the value is within the outer range of valid values
* returned by {@link range}.
* It also checks that all valid values are within the bounds of an `int`.
*
* This method checks against the range of the field in the ISO-8601 calendar system.
*
* @param {number} value the value to check.
* @return {number} the value that was passed in.
*/
checkValidIntValue(value) {
return this.range().checkValidIntValue(value, this);
}
/**
* @return {boolean} `true` if it is a component of a date, `false` otherwise.
*/
isDateBased() {
const dateBased =
this === ChronoField.DAY_OF_WEEK ||
this === ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH ||
this === ChronoField.ALIGNED_DAY_OF_WEEK_IN_YEAR ||
this === ChronoField.DAY_OF_MONTH ||
this === ChronoField.DAY_OF_YEAR ||
this === ChronoField.EPOCH_DAY ||
this === ChronoField.ALIGNED_WEEK_OF_MONTH ||
this === ChronoField.ALIGNED_WEEK_OF_YEAR ||
this === ChronoField.MONTH_OF_YEAR ||
this === ChronoField.PROLEPTIC_MONTH ||
this === ChronoField.YEAR_OF_ERA ||
this === ChronoField.YEAR ||
this === ChronoField.ERA;
return dateBased;
}
/**
* @return {boolean} `true` if it is a component of a time, `false` otherwise.
*/
isTimeBased() {
const timeBased =
this === ChronoField.NANO_OF_SECOND ||
this === ChronoField.NANO_OF_DAY ||
this === ChronoField.MICRO_OF_SECOND ||
this === ChronoField.MICRO_OF_DAY ||
this === ChronoField.MILLI_OF_SECOND ||
this === ChronoField.MILLI_OF_DAY ||
this === ChronoField.SECOND_OF_MINUTE ||
this === ChronoField.SECOND_OF_DAY ||
this === ChronoField.MINUTE_OF_HOUR ||
this === ChronoField.MINUTE_OF_DAY ||
this === ChronoField.HOUR_OF_AMPM ||
this === ChronoField.CLOCK_HOUR_OF_AMPM ||
this === ChronoField.HOUR_OF_DAY ||
this === ChronoField.CLOCK_HOUR_OF_DAY ||
this === ChronoField.AMPM_OF_DAY;
return timeBased;
}
/**
* @param {!TemporalAccessor} temporal the temporal object used to refine the result.
* @return {ValueRange} the range of valid values for this field.
* @throws {DateTimeException} if the range for the field cannot be obtained.
*/
rangeRefinedBy(temporal) {
return temporal.range(this);
}
/**
* @param {!TemporalAccesor} temporal the temporal object to query.
* @return {number} the value of this field.
* @throws {DateTimeException} if a value for the field cannot be obtained.
*/
getFrom(temporal) {
return temporal.getLong(this);
}
/**
* @returns {string}
*/
toString(){
return this.name();
}
/**
* @param {*} other
* @returns {boolean}
*/
equals(other){
return this === other;
}
/**
* @param {!Temporal} temporal the temporal object to adjust.
* @param {!number} newValue the new value of the field.
* @return {Temporal} the adjusted temporal object.
* @throws {DateTimeException} if the field cannot be set.
*/
adjustInto(temporal, newValue) {
return temporal.with(this, newValue);
}
/**
* @param {!TemporalAccesor} temporal the temporal object to query.
* @return {boolean} `true` if the date-time can be queried for this field, `false` if not.
*/
isSupportedBy(temporal) {
return temporal.isSupported(this);
}
}
export function _init() {
ChronoField.NANO_OF_SECOND = new ChronoField('NanoOfSecond', ChronoUnit.NANOS, ChronoUnit.SECONDS, ValueRange.of(0, 999999999));
ChronoField.NANO_OF_DAY = new ChronoField('NanoOfDay', ChronoUnit.NANOS, ChronoUnit.DAYS, ValueRange.of(0, 86400 * 1000000000 - 1));
ChronoField.MICRO_OF_SECOND = new ChronoField('MicroOfSecond', ChronoUnit.MICROS, ChronoUnit.SECONDS, ValueRange.of(0, 999999));
ChronoField.MICRO_OF_DAY = new ChronoField('MicroOfDay', ChronoUnit.MICROS, ChronoUnit.DAYS, ValueRange.of(0, 86400 * 1000000 - 1));
ChronoField.MILLI_OF_SECOND = new ChronoField('MilliOfSecond', ChronoUnit.MILLIS, ChronoUnit.SECONDS, ValueRange.of(0, 999));
ChronoField.MILLI_OF_DAY = new ChronoField('MilliOfDay', ChronoUnit.MILLIS, ChronoUnit.DAYS, ValueRange.of(0, 86400 * 1000 - 1));
ChronoField.SECOND_OF_MINUTE = new ChronoField('SecondOfMinute', ChronoUnit.SECONDS, ChronoUnit.MINUTES, ValueRange.of(0, 59));
ChronoField.SECOND_OF_DAY = new ChronoField('SecondOfDay', ChronoUnit.SECONDS, ChronoUnit.DAYS, ValueRange.of(0, 86400 - 1));
ChronoField.MINUTE_OF_HOUR = new ChronoField('MinuteOfHour', ChronoUnit.MINUTES, ChronoUnit.HOURS, ValueRange.of(0, 59));
ChronoField.MINUTE_OF_DAY = new ChronoField('MinuteOfDay', ChronoUnit.MINUTES, ChronoUnit.DAYS, ValueRange.of(0, (24 * 60) - 1));
ChronoField.HOUR_OF_AMPM = new ChronoField('HourOfAmPm', ChronoUnit.HOURS, ChronoUnit.HALF_DAYS, ValueRange.of(0, 11));
ChronoField.CLOCK_HOUR_OF_AMPM = new ChronoField('ClockHourOfAmPm', ChronoUnit.HOURS, ChronoUnit.HALF_DAYS, ValueRange.of(1, 12));
ChronoField.HOUR_OF_DAY = new ChronoField('HourOfDay', ChronoUnit.HOURS, ChronoUnit.DAYS, ValueRange.of(0, 23));
ChronoField.CLOCK_HOUR_OF_DAY = new ChronoField('ClockHourOfDay', ChronoUnit.HOURS, ChronoUnit.DAYS, ValueRange.of(1, 24));
ChronoField.AMPM_OF_DAY = new ChronoField('AmPmOfDay', ChronoUnit.HALF_DAYS, ChronoUnit.DAYS, ValueRange.of(0, 1));
ChronoField.DAY_OF_WEEK = new ChronoField('DayOfWeek', ChronoUnit.DAYS, ChronoUnit.WEEKS, ValueRange.of(1, 7));
ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH = new ChronoField('AlignedDayOfWeekInMonth', ChronoUnit.DAYS, ChronoUnit.WEEKS, ValueRange.of(1, 7));
ChronoField.ALIGNED_DAY_OF_WEEK_IN_YEAR = new ChronoField('AlignedDayOfWeekInYear', ChronoUnit.DAYS, ChronoUnit.WEEKS, ValueRange.of(1, 7));
ChronoField.DAY_OF_MONTH = new ChronoField('DayOfMonth', ChronoUnit.DAYS, ChronoUnit.MONTHS, ValueRange.of(1, 28, 31), 'day');
ChronoField.DAY_OF_YEAR = new ChronoField('DayOfYear', ChronoUnit.DAYS, ChronoUnit.YEARS, ValueRange.of(1, 365, 366));
ChronoField.EPOCH_DAY = new ChronoField('EpochDay', ChronoUnit.DAYS, ChronoUnit.FOREVER, ValueRange.of(-365961662, 364522971)); // [LocalDate.MIN.toEpochDay() .. LocalDate.MAX.toEpochDay()]
ChronoField.ALIGNED_WEEK_OF_MONTH = new ChronoField('AlignedWeekOfMonth', ChronoUnit.WEEKS, ChronoUnit.MONTHS, ValueRange.of(1, 4, 5));
ChronoField.ALIGNED_WEEK_OF_YEAR = new ChronoField('AlignedWeekOfYear', ChronoUnit.WEEKS, ChronoUnit.YEARS, ValueRange.of(1, 53));
ChronoField.MONTH_OF_YEAR = new ChronoField('MonthOfYear', ChronoUnit.MONTHS, ChronoUnit.YEARS, ValueRange.of(1, 12), 'month');
ChronoField.PROLEPTIC_MONTH = new ChronoField('ProlepticMonth', ChronoUnit.MONTHS, ChronoUnit.FOREVER, ValueRange.of(YearConstants.MIN_VALUE * 12, YearConstants.MAX_VALUE * 12 + 11));
ChronoField.YEAR_OF_ERA = new ChronoField('YearOfEra', ChronoUnit.YEARS, ChronoUnit.FOREVER, ValueRange.of(1, YearConstants.MAX_VALUE, YearConstants.MAX_VALUE + 1));
ChronoField.YEAR = new ChronoField('Year', ChronoUnit.YEARS, ChronoUnit.FOREVER, ValueRange.of(YearConstants.MIN_VALUE, YearConstants.MAX_VALUE), 'year');
ChronoField.ERA = new ChronoField('Era', ChronoUnit.ERAS, ChronoUnit.FOREVER, ValueRange.of(0, 1));
ChronoField.INSTANT_SECONDS = new ChronoField('InstantSeconds', ChronoUnit.SECONDS, ChronoUnit.FOREVER, ValueRange.of(MIN_SAFE_INTEGER, MAX_SAFE_INTEGER));
ChronoField.OFFSET_SECONDS = new ChronoField('OffsetSeconds', ChronoUnit.SECONDS, ChronoUnit.FOREVER, ValueRange.of(-18 * 3600, 18 * 3600));
}