Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove Instant.toDateTime{,ISO}(), DateTime.toInstant() #1088

Merged
merged 3 commits into from
Nov 2, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .eslintrc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ overrides:
- polyfill/test/Time/**/*.js
- polyfill/test/TimeZone/**/*.js
- polyfill/test/YearMonth/**/*.js
- polyfill/test/ZonedDateTime/**/*.js
- polyfill/test/now/**/*.js
globals:
Temporal: readonly
Expand Down
2 changes: 1 addition & 1 deletion docs/cookbook.md
Original file line number Diff line number Diff line change
Expand Up @@ -362,7 +362,7 @@ Map localized trip departure and arrival times into trip duration in units no la
{{cookbook/getTripDurationInHrMinSec.mjs}}
```

Map localized departure time and duration into localized arrival time.
Given a departure time with time zone and a flight duration, get an arrival time in the destination time zone, using time zone-aware math.

```javascript
{{cookbook/getLocalizedArrival.mjs}}
Expand Down
2 changes: 1 addition & 1 deletion docs/cookbook/calculateDailyOccurrence.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
*/
function* calculateDailyOccurrence(startDate, time, timeZone) {
for (let date = startDate; ; date = date.add({ days: 1 })) {
yield date.toDateTime(time).toInstant(timeZone);
yield date.toDateTime(time).toZonedDateTime(timeZone);
}
}

Expand Down
31 changes: 16 additions & 15 deletions docs/cookbook/getBusinessOpenStateText.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@
* is open, closed, opening soon, or closing soon. The length of "soon" can be
* controlled using the `soonWindow` parameter.
*
* @param {Temporal.Instant} now - Exact time at which to consider whether the
* business is open
* @param {Temporal.TimeZone} timeZone - Time zone in which the business is
* located
* FIXME: This example should stop using TimeZone.getInstantFor as soon as the
* ZonedDateTime.with(), add(), and subtract() methods get implemented.
*
* @param {Temporal.ZonedDateTime} now - Date and Time at which to consider
* whether the business is open
* @param {(Object|null)[]} businessHours - Array of length 7 indicating
* business hours during the week
* @param {Temporal.Time} businessHours[].open - Time at which the business
Expand All @@ -19,12 +20,12 @@
* soon" or "closing soon"
* @returns {string} "open", "closed", "opening soon", or "closing soon"
*/
function getBusinessOpenStateText(now, timeZone, businessHours, soonWindow) {
function getBusinessOpenStateText(now, businessHours, soonWindow) {
function inRange(i, start, end) {
return Temporal.Instant.compare(i, start) >= 0 && Temporal.Instant.compare(i, end) < 0;
}

const dateTime = now.toDateTimeISO(timeZone);
const dateTime = now.toDateTime();
const weekday = dateTime.dayOfWeek % 7; // convert to 0-based, for array indexing

// Because of times wrapping around at midnight, we may need to consider
Expand All @@ -42,8 +43,8 @@ function getBusinessOpenStateText(now, timeZone, businessHours, soonWindow) {
const { open, close } = yesterdayHours;
if (Temporal.Time.compare(close, open) < 0) {
businessHoursOverlappingToday.push({
open: yesterday.toDateTime(open).toInstant(timeZone),
close: today.toDateTime(close).toInstant(timeZone)
open: now.timeZone.getInstantFor(yesterday.toDateTime(open)),
close: now.timeZone.getInstantFor(today.toDateTime(close))
});
}
}
Expand All @@ -52,17 +53,18 @@ function getBusinessOpenStateText(now, timeZone, businessHours, soonWindow) {
const { open, close } = todayHours;
const todayOrTomorrow = Temporal.Time.compare(close, open) >= 0 ? today : tomorrow;
businessHoursOverlappingToday.push({
open: today.toDateTime(open).toInstant(timeZone),
close: todayOrTomorrow.toDateTime(close).toInstant(timeZone)
open: now.timeZone.getInstantFor(today.toDateTime(open)),
Ms2ger marked this conversation as resolved.
Show resolved Hide resolved
close: now.timeZone.getInstantFor(todayOrTomorrow.toDateTime(close))
});
}

// Check if any of the candidate business hours include the given time
const soon = now.add(soonWindow);
const nowInstant = now.toInstant();
const soon = nowInstant.add(soonWindow);
let openNow = false;
let openSoon = false;
for (const { open, close } of businessHoursOverlappingToday) {
openNow = openNow || inRange(now, open, close);
openNow = openNow || inRange(nowInstant, open, close);
openSoon = openSoon || inRange(soon, open, close);
}

Expand All @@ -86,8 +88,7 @@ const businessHours = [
/* Sat */ { open: Temporal.Time.from('11:00'), close: Temporal.Time.from('02:00') }
];

const now = Temporal.Instant.from('2019-04-07T00:00+01:00[Europe/Berlin]');
const tz = Temporal.TimeZone.from('Europe/Berlin');
const now = Temporal.ZonedDateTime.from('2019-04-07T00:00+01:00[Europe/Berlin]');
const soonWindow = Temporal.Duration.from({ minutes: 30 });
const saturdayNightState = getBusinessOpenStateText(now, tz, businessHours, soonWindow);
const saturdayNightState = getBusinessOpenStateText(now, businessHours, soonWindow);
assert.equal(saturdayNightState, 'open');
4 changes: 2 additions & 2 deletions docs/cookbook/getInstantWithLocalTimeInZone.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,13 @@ function getInstantWithLocalTimeInZone(dateTime, timeZone, disambiguation = 'ear
switch (disambiguation) {
case 'clipEarlier':
if (possible.length === 0) {
const before = dateTime.toInstant(timeZone, { disambiguation: 'earlier' });
const before = timeZone.getInstantFor(dateTime, { disambiguation: 'earlier' });
return timeZone.getNextTransition(before).subtract({ nanoseconds: 1 });
}
return possible[0];
case 'clipLater':
if (possible.length === 0) {
const before = dateTime.toInstant(timeZone, { disambiguation: 'earlier' });
const before = timeZone.getInstantFor(dateTime, { disambiguation: 'earlier' });
return timeZone.getNextTransition(before);
}
return possible[possible.length - 1];
Expand Down
17 changes: 10 additions & 7 deletions docs/cookbook/getLocalizedArrival.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,26 @@
* Given a localized departure time and a flight duration, get a local arrival
* time in the destination time zone.
*
* @param {string} parseableDeparture - Departure time with time zone
* FIXME: This becomes a one-liner when Temporal.ZonedDateTime.add() is
* implemented.
*
* @param {string} departure - Departure time with time zone
* @param {Temporal.Duration} flightTime - Duration of the flight
* @param {Temporal.TimeZone} destinationTimeZone - Time zone in which the
* flight's destination is located
* @param {Temporal.Calendar|string} calendar - Calendar system used for output
* @returns {Temporal.DateTime} Local arrival time
*/
function getLocalizedArrival(parseableDeparture, flightTime, destinationTimeZone, calendar) {
const departure = Temporal.Instant.from(parseableDeparture);
const arrival = departure.add(flightTime);
return arrival.toDateTime(destinationTimeZone, calendar);
function getLocalizedArrival(departure, flightTime, destinationTimeZone, calendar) {
const instant = departure.toInstant();
const arrival = instant.add(flightTime);
return destinationTimeZone.getDateTimeFor(arrival, calendar);
}

const arrival = getLocalizedArrival(
'2020-03-08T11:55:00+08:00[Asia/Hong_Kong]',
Temporal.ZonedDateTime.from('2020-03-08T11:55:00+08:00[Asia/Hong_Kong]'),
Temporal.Duration.from({ minutes: 775 }),
'America/Los_Angeles',
Temporal.TimeZone.from('America/Los_Angeles'),
'iso8601'
);
assert.equal(arrival.toString(), '2020-03-08T09:50:00');
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,10 @@ function getParseableZonedStringWithLocalTimeInOtherZone(
targetTimeZone,
sourceDisambiguationPolicy = 'reject'
) {
let instant = sourceDateTime.toInstant(sourceTimeZone, { disambiguation: sourceDisambiguationPolicy });
return instant.toString(targetTimeZone);
return sourceDateTime
.toZonedDateTime(sourceTimeZone, { disambiguation: sourceDisambiguationPolicy })
.withTimeZone(targetTimeZone)
.toString();
}

const result = getParseableZonedStringWithLocalTimeInOtherZone(
Expand Down
5 changes: 3 additions & 2 deletions docs/cookbook/localTimeForFutureEvents.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,9 @@ const tc39meetings = [
const localTimeZone = Temporal.TimeZone.from('Asia/Tokyo');
const localTimes = tc39meetings.map(({ dateTime, timeZone }) => {
return Temporal.DateTime.from(dateTime)
.toInstant(timeZone, { disambiguation: 'reject' })
.toDateTimeISO(localTimeZone);
.toZonedDateTime(timeZone, { disambiguation: 'reject' })
.withTimeZone(localTimeZone)
.toDateTime();
});

assert.deepEqual(
Expand Down
21 changes: 11 additions & 10 deletions docs/cookbook/nextWeeklyOccurrence.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,17 @@
* Returns the local date and time for the next occurrence of a weekly occurring
* event.
*
* @param {Temporal.Instant} now - Starting point
* @param {Temporal.TimeZone} localTimeZone - Time zone for return value
* FIXME: This should use ZonedDateTime arithmetic once ZonedDateTime.add() and
* subtract() are implemented.
*
* @param {Temporal.ZonedDateTime} now - Starting point
* @param {number} weekday - Weekday event occurs on (Monday=1, Sunday=7)
* @param {Temporal.Time} eventTime - Time event occurs at
* @param {Temporal.TimeZone} eventTimeZone - Time zone where event is planned
* @returns {Temporal.DateTime} Local date and time of next occurrence
*/
function nextWeeklyOccurrence(now, localTimeZone, weekday, eventTime, eventTimeZone) {
const dateTime = now.toDateTimeISO(eventTimeZone);
function nextWeeklyOccurrence(now, weekday, eventTime, eventTimeZone) {
const dateTime = now.withTimeZone(eventTimeZone).toDateTime();
const nextDate = dateTime.toDate().add({ days: (weekday + 7 - dateTime.dayOfWeek) % 7 });
let nextOccurrence = nextDate.toDateTime(eventTime);

Expand All @@ -19,19 +21,18 @@ function nextWeeklyOccurrence(now, localTimeZone, weekday, eventTime, eventTimeZ
nextOccurrence = nextOccurrence.add({ days: 7 });
}

return nextOccurrence.toInstant(eventTimeZone).toDateTimeISO(localTimeZone);
return eventTimeZone.getInstantFor(nextOccurrence).toZonedDateTime(now.timeZone, now.calendar).toDateTime();
}

// "Weekly on Thursdays at 08:45 California time":
const weekday = 4;
const eventTime = Temporal.Time.from('08:45');
const eventTimeZone = Temporal.TimeZone.from('America/Los_Angeles');

const rightBefore = Temporal.Instant.from('2020-03-26T08:30-07:00[America/Los_Angeles]');
const localTimeZone = Temporal.TimeZone.from('Europe/London');
let next = nextWeeklyOccurrence(rightBefore, localTimeZone, weekday, eventTime, eventTimeZone);
const rightBefore = Temporal.ZonedDateTime.from('2020-03-26T15:30+00:00[Europe/London]');
let next = nextWeeklyOccurrence(rightBefore, weekday, eventTime, eventTimeZone);
assert.equal(next.toString(), '2020-03-26T15:45:00');

const rightAfter = Temporal.Instant.from('2020-03-26T09:00-07:00[America/Los_Angeles]');
next = nextWeeklyOccurrence(rightAfter, localTimeZone, weekday, eventTime, eventTimeZone);
const rightAfter = Temporal.ZonedDateTime.from('2020-03-26T16:00+00:00[Europe/London]');
next = nextWeeklyOccurrence(rightAfter, weekday, eventTime, eventTimeZone);
assert.equal(next.toString(), '2020-04-02T16:45:00');
33 changes: 0 additions & 33 deletions docs/datetime.md
Original file line number Diff line number Diff line change
Expand Up @@ -850,39 +850,6 @@ For usage examples and a more complete explanation of how this disambiguation wo

If the result is earlier or later than the range that `Temporal.ZonedDateTime` can represent (approximately half a million years centered on the [Unix epoch](https://en.wikipedia.org/wiki/Unix_time)), then a `RangeError` will be thrown, no matter the value of `disambiguation`.

### datetime.**toInstant**(_timeZone_ : object | string, _options_?: object) : Temporal.Instant

**Parameters:**

- `timeZone` (optional string or object): The time zone in which to interpret `dateTime`, as a `Temporal.TimeZone` object, an object implementing the [time zone protocol](./timezone.md#protocol), or a string.
- `options` (optional object): An object with properties representing options for the operation.
The following options are recognized:
- `disambiguation` (string): How to disambiguate if the date and time given by `dateTime` does not exist in the time zone, or exists more than once.
Allowed values are `'compatible'`, `'earlier'`, `'later'`, and `'reject'`.
The default is `'compatible'`.

**Returns:** A `Temporal.Instant` object indicating the exact time in `timeZone` at the time of the calendar date and wall-clock time from `dateTime`.

This method is one way to convert a `Temporal.DateTime` to a `Temporal.Instant`.
It is identical to [`(Temporal.TimeZone.from(timeZone || 'UTC')).getInstantFor(dateTime, disambiguation)`](./timezone.html#getInstantFor).

In the case of ambiguity, the `disambiguation` option controls what exact time to return:

- `'compatible'` (the default): Acts like `'earlier'` for backward transitions and `'later'` for forward transitions.
- `'earlier'`: The earlier of two possible exact times.
- `'later'`: The later of two possible exact times.
- `'reject'`: Throw a `RangeError` instead.

When interoperating with existing code or services, `'compatible'` mode matches the behavior of legacy `Date` as well as libraries like moment.js, Luxon, and date-fns.
This mode also matches the behavior of cross-platform standards like [RFC 5545 (iCalendar)](https://tools.ietf.org/html/rfc5545).

During "skipped" clock time like the hour after DST starts in the Spring, this method interprets invalid times using the pre-transition time zone offset if `'compatible'` or `'later'` is used or the post-transition time zone offset if `'earlier'` is used.
This behavior avoids exceptions when converting non-existent `Temporal.DateTime` values to `Temporal.Instant`, but it also means that values during these periods will result in a different `Temporal.DateTime` in "round-trip" conversions to `Temporal.Instant` and back again.

For usage examples and a more complete explanation of how this disambiguation works and why it is necessary, see [Resolving ambiguity](./ambiguity.md).

If the result is earlier or later than the range that `Temporal.Instant` can represent (approximately half a million years centered on the [Unix epoch](https://en.wikipedia.org/wiki/Unix_time)), then a `RangeError` will be thrown, no matter the value of `disambiguation`.

### datetime.**toDate**() : Temporal.Date

**Returns:** a `Temporal.Date` object that is the same as the date portion of `datetime`.
Expand Down
63 changes: 0 additions & 63 deletions docs/instant.md
Original file line number Diff line number Diff line change
Expand Up @@ -284,69 +284,6 @@ console.log(zdt.year, zdt.era);
```
<!-- prettier-ignore-end -->

### instant.**toDateTimeISO**(_timeZone_: object | string) : Temporal.DateTime

**Parameters:**

- `timeZone` (object or string): A `Temporal.TimeZone` object, or an object implementing the [time zone protocol](./timezone.md#protocol), or a string description of the time zone; either its IANA name or UTC offset.

**Returns:** a `Temporal.DateTime` object representing the calendar date, wall-clock time in `timeZone`, according to the reckoning of the ISO 8601 calendar, at the exact time indicated by `instant`.

For a list of IANA time zone names, see the current version of the [IANA time zone database](https://www.iana.org/time-zones).
A convenient list is also available [on Wikipedia](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones), although it might not reflect the latest official status.

This method is one way to convert a `Temporal.Instant` to a `Temporal.DateTime`.
It is the same as `toDateTime()`, but always uses the ISO 8601 calendar.
Use this method if you are not doing computations in other calendars.

Example usage:

```js
// Converting an exact time to a calendar date / wall-clock time
timestamp = Temporal.Instant.fromEpochSeconds(1553993100);
timestamp.toDateTime('Europe/Berlin'); // => 2019-03-31T01:45
timestamp.toDateTime('UTC'); // => 2019-03-31T00:45
timestamp.toDateTime('-08:00'); // => 2019-03-30T16:45
```

### instant.**toDateTime**(_timeZone_: object | string, _calendar_: object | string) : Temporal.DateTime

**Parameters:**

- `timeZone` (object or string): A `Temporal.TimeZone` object, or an object implementing the [time zone protocol](./timezone.md#protocol), or a string description of the time zone; either its IANA name or UTC offset.
- `calendar` (object or string): A `Temporal.Calendar` object, or a plain object, or a calendar identifier.

**Returns:** a `Temporal.DateTime` object indicating the calendar date and wall-clock time in `timeZone`, according to the reckoning of `calendar`, at the instant time indicated by `instant`.

For a list of IANA time zone names, see the current version of the [IANA time zone database](https://www.iana.org/time-zones).
A convenient list is also available [on Wikipedia](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones), although it might not reflect the latest official status.

For a list of calendar identifiers, see the documentation for [Intl.DateTimeFormat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/DateTimeFormat#Parameters).

This method is one way to convert a `Temporal.Instant` to a `Temporal.DateTime`.

If you only want to use the ISO 8601 calendar, use `toDateTimeISO()`.

Example usage:

<!-- prettier-ignore-start -->
```js
// What time was the Unix epoch (timestamp 0) in Bell Labs (Murray Hill, New Jersey, USA) in the Gregorian calendar?
epoch = Temporal.Instant.fromEpochSeconds(0);
tz = Temporal.TimeZone.from('America/New_York');
epoch.toDateTime(tz, 'gregory');
// => 1969-12-31T19:00[c=gregory]

// What time was the Unix epoch in Tokyo in the Japanese calendar?
tz = Temporal.TimeZone.from('Asia/Tokyo');
cal = Temporal.Calendar.from('japanese');
dt = epoch.toDateTime(tz, cal);
// => 1970-01-01T09:00[c=japanese]
console.log(dt.year, dt.era);
// => 45 showa
```
<!-- prettier-ignore-end -->

### instant.**add**(_duration_: Temporal.Duration | object | string) : Temporal.Instant

**Parameters:**
Expand Down
3 changes: 0 additions & 3 deletions polyfill/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -550,8 +550,6 @@ export namespace Temporal {
| /** @deprecated */ 'nanoseconds'
>
): Temporal.Instant;
toDateTime(tzLike: TimeZoneProtocol | string, calendar: CalendarProtocol | string): Temporal.DateTime;
toDateTimeISO(tzLike: TimeZoneProtocol | string): Temporal.DateTime;
toZonedDateTime(tzLike: TimeZoneProtocol | string, calendar: CalendarProtocol | string): Temporal.ZonedDateTime;
toZonedDateTimeISO(tzLike: TimeZoneProtocol | string): Temporal.ZonedDateTime;
toLocaleString(locales?: string | string[], options?: Intl.DateTimeFormatOptions): string;
Expand Down Expand Up @@ -934,7 +932,6 @@ export namespace Temporal {
| /** @deprecated */ 'nanoseconds'
>
): Temporal.DateTime;
toInstant(tzLike: TimeZoneProtocol | string, options?: ToInstantOptions): Temporal.Instant;
toZonedDateTime(tzLike: TimeZoneProtocol | string, options?: ToInstantOptions): Temporal.ZonedDateTime;
toDate(): Temporal.Date;
toYearMonth(): Temporal.YearMonth;
Expand Down
7 changes: 0 additions & 7 deletions polyfill/lib/datetime.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -714,13 +714,6 @@ export class DateTime {
throw new TypeError('use compare() or equals() to compare Temporal.DateTime');
}

toInstant(temporalTimeZoneLike, options = undefined) {
if (!ES.IsTemporalDateTime(this)) throw new TypeError('invalid receiver');
const timeZone = ES.ToTemporalTimeZone(temporalTimeZoneLike);
options = ES.NormalizeOptionsObject(options);
const disambiguation = ES.ToTemporalDisambiguation(options);
return ES.GetTemporalInstantFor(timeZone, this, disambiguation);
}
toZonedDateTime(temporalTimeZoneLike, options = undefined) {
if (!ES.IsTemporalDateTime(this)) throw new TypeError('invalid receiver');
const timeZone = ES.ToTemporalTimeZone(temporalTimeZoneLike);
Expand Down
12 changes: 0 additions & 12 deletions polyfill/lib/instant.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -240,18 +240,6 @@ export class Instant {
valueOf() {
throw new TypeError('use compare() or equals() to compare Temporal.Instant');
}
toDateTime(temporalTimeZoneLike, calendarLike) {
if (!ES.IsTemporalInstant(this)) throw new TypeError('invalid receiver');
const timeZone = ES.ToTemporalTimeZone(temporalTimeZoneLike);
const calendar = ES.ToTemporalCalendar(calendarLike);
return ES.GetTemporalDateTimeFor(timeZone, this, calendar);
}
toDateTimeISO(temporalTimeZoneLike) {
if (!ES.IsTemporalInstant(this)) throw new TypeError('invalid receiver');
const timeZone = ES.ToTemporalTimeZone(temporalTimeZoneLike);
const calendar = GetISO8601Calendar();
return ES.GetTemporalDateTimeFor(timeZone, this, calendar);
}
toZonedDateTime(temporalTimeZoneLike, calendarLike) {
if (!ES.IsTemporalInstant(this)) throw new TypeError('invalid receiver');
const timeZone = ES.ToTemporalTimeZone(temporalTimeZoneLike);
Expand Down
Loading