Skip to content

Commit

Permalink
ISO 8601 calendar
Browse files Browse the repository at this point in the history
This adds an 'iso8601' calendar and changes the polyfill code for
Temporal.Date, Temporal.DateTime, Temporal.YearMonth, and
Temporal.MonthDay so that they gain a CALENDAR slot, and delegate all of
their calendar-sensitive operations to the object in the CALENDAR slot.

Among the changes made to those types:
- Constructors gain a calendar argument of type Temporal.Calendar.
- Types gain a 'calendar' property of type Temporal.Calendar.
- from() accepts a 'calendar' string or Temporal.Calendar.
- Temporal.Date and Temporal.DateTime accept a calendar in with().
- Temporal.MonthDay & Temporal.YearMonth throw on a calendar in with().
- The calendar is returned in getFields() (see #641).
- equals() and compare() take the calendar into account (see #625).

This includes documentation, but leaves out spec changes and all but the
necessary test changes for the time being.
  • Loading branch information
ptomato committed Jun 10, 2020
1 parent 9827fb3 commit 08a997c
Show file tree
Hide file tree
Showing 29 changed files with 904 additions and 294 deletions.
46 changes: 34 additions & 12 deletions docs/date.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,21 @@ A `Temporal.Date` can be converted into a `Temporal.DateTime` by combining it wi

## Constructor

### **new Temporal.Date**(_isoYear_: number, _isoMonth_: number, _isoDay_: number) : Temporal.Date
### **new Temporal.Date**(_isoYear_: number, _isoMonth_: number, _isoDay_: number, _calendar_?: Temporal.Calendar) : Temporal.Date

**Parameters:**
- `isoYear` (number): A year.
- `isoMonth` (number): A month, ranging between 1 and 12 inclusive.
- `isoDay` (number): A day of the month, ranging between 1 and 31 inclusive.
- `calendar` (optional `Temporal.Calendar`): A calendar to project the date into.

**Returns:** a new `Temporal.Date` object.

Use this constructor if you have the correct parameters for the date already as individual number values.
Otherwise, `Temporal.Date.from()`, which accepts more kinds of input and allows disambiguation behaviour, is probably more convenient.
Use this constructor if you have the correct parameters for the date already as individual number values in the ISO 8601 calendar.
Otherwise, `Temporal.Date.from()`, which accepts more kinds of input, allows inputting dates in different calendar reckonings, and allows disambiguation behaviour, is probably more convenient.

All values are given as reckoned in the [ISO 8601 calendar](https://en.wikipedia.org/wiki/ISO_8601#Dates).
Together, `isoYear`, `isoMonth`, and `isoDay` must represent a valid date in that calendar.
Together, `isoYear`, `isoMonth`, and `isoDay` must represent a valid date in that calendar, even if you are passing a different calendar as the `calendar` parameter.

The range of allowed values for this type is exactly enough that calling [`getDate()`](./datetime.html#getDate) on any valid `Temporal.DateTime` will succeed.
If `isoYear`, `isoMonth`, and `isoDay` form a date outside of this range, then `constrain` mode will clamp the values to the limit of the allowed range, while `reject` mode will throw a `RangeError`.
Expand Down Expand Up @@ -58,7 +59,8 @@ date = new Temporal.Date(2020, 3, 14) // => 2020-03-14

This static method creates a new `Temporal.Date` object from another value.
If the value is another `Temporal.Date` object, a new object representing the same date is returned.
If the value is any other object, it must have `year`, `month`, and `day` properties, and a `Temporal.Date` will be constructed from them.
If the value is any other object, it must have `year`, `month`, and `day` properties, and optionally a `calendar` property.
A `Temporal.Date` will be constructed from these properties.

Any non-object value is converted to a string, which is expected to be in ISO 8601 format.
Any time or time zone part is optional and will be ignored.
Expand All @@ -83,6 +85,11 @@ date = Temporal.Date.from({year: 2006, month: 8, day: 24}); // => 2006-08-24
date = Temporal.Date.from(Temporal.DateTime.from('2006-08-24T15:43:27'));
// => same as above; Temporal.DateTime has year, month, and day properties

calendar = Temporal.Calendar.from('islamic');
date = Temporal.Date.from({ year: 1427, month; 8, day: 1, calendar }); // => 2006-08-24[c=islamic]
date = Temporal.Date.from({ year: 1427, month: 8, day: 1, calendar: 'islamic' });
// => same as above

// Different disambiguation modes
date = Temporal.Date.from({ year: 2001, month: 13, day: 1 }, { disambiguation: 'constrain' })
// => 2001-12-01
Expand Down Expand Up @@ -138,10 +145,14 @@ date.month // => 8
date.day // => 24
```

### date.**calendar** : Temporal.Calendar

The `calendar` read-only property gives the calendar that the `year`, `month`, and `day` properties are interpreted in.

### date.**dayOfWeek** : number

The `dayOfWeek` read-only property gives the weekday number that the date falls on.
The weekday number is defined as in the ISO 8601 standard: a value between 1 and 7, inclusive, with Monday being 1, and Sunday 7.
For the ISO 8601 calendar, the weekday number is defined as in the ISO 8601 standard: a value between 1 and 7, inclusive, with Monday being 1, and Sunday 7.
For an overview, see [ISO 8601 on Wikipedia](https://en.wikipedia.org/wiki/ISO_8601#Week_dates).

Usage example:
Expand All @@ -153,7 +164,7 @@ date = Temporal.Date.from('2006-08-24');
### date.**dayOfYear** : number

The `dayOfYear` read-only property gives the ordinal day of the year that the date falls on.
This is a value between 1 and 365, or 366 in a leap year.
For the ISO 8601 calendar, this is a value between 1 and 365, or 366 in a leap year.

Usage example:
```javascript
Expand All @@ -165,7 +176,7 @@ console.log(date.year, date.dayOfYear); // 2006 236
### date.**weekOfYear** : number

The `weekOfYear` read-only property gives the ISO week number of the date.
This is normally a value between 1 and 52, but in a few cases it can be 53 as well.
For the ISO 8601 calendar, this is normally a value between 1 and 52, but in a few cases it can be 53 as well.
ISO week 1 is the week containing the first Thursday of the year.
For more information on ISO week numbers, see for example the Wikipedia article on [ISO week date](https://en.wikipedia.org/wiki/ISO_week_date).

Expand All @@ -179,7 +190,7 @@ console.log(date.year, date.weekOfYear, date.dayOfWeek); // 2006 34 4
### date.**daysInMonth** : number

The `daysInMonth` read-only property gives the number of days in the month that the date falls in.
This is 28, 29, 30, or 31, depending on the month and whether the year is a leap year.
For the ISO 8601 calendar, this is 28, 29, 30, or 31, depending on the month and whether the year is a leap year.

Usage example:
```javascript
Expand All @@ -202,7 +213,7 @@ console.log(poem);
### date.**daysInYear** : number

The `daysInYear` read-only property gives the number of days in the year that the date falls in.
This is 365 or 366, depending on whether the year is a leap year.
For the ISO 8601 calendar, this is 365 or 366, depending on whether the year is a leap year.

Usage example:
```javascript
Expand Down Expand Up @@ -246,6 +257,9 @@ Since `Temporal.Date` objects are immutable, use this method instead of modifyin

> **NOTE**: The allowed values for the `dateLike.month` property start at 1, which is different from legacy `Date` where months are represented by zero-based indices (0 to 11).
> **NOTE**: If a `calendar` property is provided on `dateLike`, the new calendar is applied first, before any of the other properties.
> If you are passing in an object with _only_ a `calendar` property, it is recommended to use the `withCalendar` method instead.
Usage example:
```javascript
date = Temporal.Date.from('2006-01-24');
Expand Down Expand Up @@ -501,7 +515,7 @@ date.getYearMonth() // => 2006-08
date.getMonthDay() // => 08-24
```

### date.**getFields**() : { year: number, month: number, day: number, [propName: string]: unknown }
### date.**getFields**() : { year: number, month: number, day: number, calendar: Temporal.Calendar, [propName: string]: unknown }

**Returns:** a plain object with properties equal to the fields of `date`.

Expand All @@ -525,10 +539,18 @@ Object.assign({}, date.getFields()).day // => 24

This method is mainly useful if you are implementing a custom calendar.
Most code will not need to use it.
Use `date.getFields()` instead.
Use `date.getFields()` instead, or `date.withCalendar('iso8601').getFields()`.

Usage example:
```javascript
date = Temporal.Date.from('2006-08-24');
date.getISOCalendarFields().day // => 24

// Date in other calendar
date = date.withCalendar('hebrew');
date.getFields().day // => 30
date.getISOCalendarFields().day // => 24

// Most likely what you need is this:
date.withCalendar('iso8601').day // => 24
```
47 changes: 35 additions & 12 deletions docs/datetime.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ A `Temporal.DateTime` can also be converted into any of the other `Temporal` obj

## Constructor

### **new Temporal.DateTime**(_isoYear_: number, _isoMonth_: number, _isoDay_: number, _hour_: number = 0, _minute_: number = 0, _second_: number = 0, _millisecond_: number = 0, _microsecond_: number = 0, _nanosecond_: number = 0) : Temporal.DateTime
### **new Temporal.DateTime**(_isoYear_: number, _isoMonth_: number, _isoDay_: number, _hour_: number = 0, _minute_: number = 0, _second_: number = 0, _millisecond_: number = 0, _microsecond_: number = 0, _nanosecond_: number = 0, _calendar_?: Temporal.Calendar) : Temporal.DateTime

**Parameters:**
- `isoYear` (number): A year.
Expand All @@ -33,14 +33,15 @@ A `Temporal.DateTime` can also be converted into any of the other `Temporal` obj
- `millisecond` (optional number): A number of milliseconds, ranging between 0 and 999 inclusive.
- `microsecond` (optional number): A number of microseconds, ranging between 0 and 999 inclusive.
- `nanosecond` (optional number): A number of nanoseconds, ranging between 0 and 999 inclusive.
- `calendar` (optional `Temporal.Calendar`): A calendar to project the date into.

**Returns:** a new `Temporal.DateTime` object.

Use this constructor if you have the correct parameters for the date already as individual number values.
Otherwise, `Temporal.DateTime.from()`, which accepts more kinds of input and allows disambiguation behaviour, is probably more convenient.
Use this constructor if you have the correct parameters for the date already as individual number values in the ISO 8601 calendar.
Otherwise, `Temporal.DateTime.from()`, which accepts more kinds of input, allows inputting dates in different calendar reckonings, and allows disambiguation behaviour, is probably more convenient.

All values are given as reckoned in the [ISO 8601 calendar](https://en.wikipedia.org/wiki/ISO_8601#Dates).
Together, `isoYear`, `isoMonth`, and `isoDay` must represent a valid date in that calendar, and the time parameters must represent a valid time of day.
Together, `isoYear`, `isoMonth`, and `isoDay` must represent a valid date in that calendar, even if you are passing a different calendar as the `calendar` parameter, and the time parameters must represent a valid time of day.

> **NOTE**: Although Temporal does not deal with leap seconds, dates coming from other software may have a `second` value of 60.
> This value will cause the constructor will throw, so if you have to interoperate with times that may contain leap seconds, use `Temporal.DateTime.from()` instead.
Expand Down Expand Up @@ -72,8 +73,9 @@ datetime = new Temporal.DateTime(2020, 3, 14, 13, 37) // => 2020-03-14T13:37

This static method creates a new `Temporal.DateTime` object from another value.
If the value is another `Temporal.DateTime` object, a new object representing the same date and time is returned.
If the value is any other object, a `Temporal.DateTime` will be constructed from the values of any `year`, `month`, `day`, `hour`, `minute`, `second`, `millisecond`, `microsecond`, and `nanosecond` properties that are present.
If the value is any other object, a `Temporal.DateTime` will be constructed from the values of any `year`, `month`, `day`, `hour`, `minute`, `second`, `millisecond`, `microsecond`, `nanosecond`, and `calendar` properties that are present.
At least the `year`, `month`, and `day` properties must be present.
If `calendar` is missing, it will be assumed to be `Temporal.Calendar.from('iso8601')`.
Any other missing ones will be assumed to be 0.

Any non-object value is converted to a string, which is expected to be in ISO 8601 format.
Expand Down Expand Up @@ -113,6 +115,12 @@ dt = Temporal.DateTime.from({year: 1995, month: 12, day: 7}); // => 1995-12-07T
dt = Temporal.DateTime.from(Temporal.Date.from('1995-12-07T03:24:30'));
// => same as above; Temporal.Date has year, month, and day properties

calendar = Temporal.Calendar.from('hebrew');
dt = Temporal.DateTime.from({ year: 5756, month: 3, day: 14, hour: 3, minute: 24, second: 30, calendar });
// => 1995-12-07T03:24:30[c=hebrew]
dt = Temporal.DateTime.from({ year: 5756, month: 3, day: 14, hour: 3, minute: 24, second: 30, calendar: 'hebrew' });
// => same as above

// Different disambiguation modes
dt = Temporal.DateTime.from({ year: 2001, month: 13, day: 1 }, { disambiguation: 'constrain' })
// => 2001-12-01T00:00
Expand Down Expand Up @@ -197,10 +205,14 @@ dt.microsecond // => 3
dt.nanosecond // => 500
```

### datetime.**calendar** : Temporal.Calendar

The `calendar` read-only property gives the calendar that the `year`, `month`, and `day` properties are interpreted in.

### datetime.**dayOfWeek** : number

The `dayOfWeek` read-only property gives the weekday number that the date falls on.
The weekday number is defined as in the ISO 8601 standard: a value between 1 and 7, inclusive, with Monday being 1, and Sunday 7.
For the ISO 8601 calendar, the weekday number is defined as in the ISO 8601 standard: a value between 1 and 7, inclusive, with Monday being 1, and Sunday 7.
For an overview, see [ISO 8601 on Wikipedia](https://en.wikipedia.org/wiki/ISO_8601#Week_dates).

Usage example:
Expand All @@ -212,7 +224,7 @@ dt = new Temporal.DateTime(1995, 12, 7, 3, 24, 30, 0, 3, 500);
### datetime.**dayOfYear** : number

The `dayOfYear` read-only property gives the ordinal day of the year that the date falls on.
This is a value between 1 and 365, or 366 in a leap year.
For the ISO 8601 calendar, this is a value between 1 and 365, or 366 in a leap year.

Usage example:
```javascript
Expand All @@ -224,7 +236,7 @@ console.log(dt.year, dt.dayOfYear); // => 1995 341
### datetime.**weekOfYear** : number

The `weekOfYear` read-only property gives the ISO week number of the date.
This is normally a value between 1 and 52, but in a few cases it can be 53 as well.
For the ISO 8601 calendar, this is normally a value between 1 and 52, but in a few cases it can be 53 as well.
ISO week 1 is the week containing the first Thursday of the year.
For more information on ISO week numbers, see for example the Wikipedia article on [ISO week date](https://en.wikipedia.org/wiki/ISO_week_date).

Expand All @@ -238,7 +250,7 @@ console.log(dt.year, dt.weekOfYear, dt.dayOfWeek); // => 1995 49 4
### datetime.**daysInMonth** : number

The `daysInMonth` read-only property gives the number of days in the month that the date falls in.
This is 28, 29, 30, or 31, depending on the month and whether the year is a leap year.
For the ISO 8601 calendar, this is 28, 29, 30, or 31, depending on the month and whether the year is a leap year.

Usage example:
```javascript
Expand All @@ -261,7 +273,7 @@ console.log(poem);
### datetime.**daysInYear** : number

The `daysInYear` read-only property gives the number of days in the year that the date falls in.
This is 365 or 366, depending on whether the year is a leap year.
For the ISO 8601 calendar, this is 365 or 366, depending on whether the year is a leap year.

Usage example:
```javascript
Expand Down Expand Up @@ -305,6 +317,9 @@ Since `Temporal.DateTime` objects are immutable, use this method instead of modi

> **NOTE**: The allowed values for the `dateTimeLike.month` property start at 1, which is different from legacy `Date` where months are represented by zero-based indices (0 to 11).
> **NOTE**: If a `calendar` property is provided on `dateTimeLike`, the new calendar is applied first, before any of the other properties.
> If you are passing in an object with _only_ a `calendar` property, it is recommended to use the `withCalendar` method instead.
Usage example:
```javascript
dt = new Temporal.DateTime(1995, 12, 7, 3, 24, 30, 0, 3, 500);
Expand Down Expand Up @@ -574,7 +589,7 @@ dt.getMonthDay() // => 12-07
dt.getTime() // => 03:24:30.000003500
```

### datetime.**getFields**() : { year: number, month: number, day: number, hour: number, minute: number, second: number, millisecond: number, microsecond: number, nanosecond: number, [propName: string]: unknown }
### datetime.**getFields**() : { year: number, month: number, day: number, hour: number, minute: number, second: number, millisecond: number, microsecond: number, nanosecond: number, calendar: Temporal.Calendar, [propName: string]: unknown }

**Returns:** a plain object with properties equal to the fields of `datetime`.

Expand All @@ -598,10 +613,18 @@ Object.assign({}, dt.getFields()).day // => 7

This method is mainly useful if you are implementing a custom calendar.
Most code will not need to use it.
Use `datetime.getFields()` instead.
Use `datetime.getFields()` instead, or `datetime.withCalendar('iso8601').getFields()`.

Usage example:
```javascript
dt = Temporal.Date.from('1995-12-07T03:24:30.000003500');
date.getISOCalendarFields().day // => 7

// Date in other calendar
dt = dt.withCalendar('hebrew');
dt.getFields().day // => 14
dt.getISOCalendarFields().day // => 7

// Most likely what you need is this:
dt.withCalendar('iso8601').day // => 7
```
Loading

0 comments on commit 08a997c

Please sign in to comment.