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

DO NOT MERGE: Proof-of-concept for ZonedDateTime (Instant + TimeZone + Calendar) #700

Closed
wants to merge 47 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
eb73e5f
LocalDateTime PoC
justingrant Jun 28, 2020
eaefb3f
Stop using ?? operator (to fix CI)
justingrant Jun 28, 2020
d3a26c0
Fix meetingPlanner cookbook sample
justingrant Jul 1, 2020
7261d02
Fix meeting planner and storage tank samples
justingrant Jul 1, 2020
8ae4ad2
Update PoC-only lint step to use poc.d.ts
justingrant Jul 1, 2020
fa36734
Update localTimeForFutureEvents cookbook sample
justingrant Jul 2, 2020
4fc4300
Limit math disambiguation to `dateTime` durations
justingrant Jul 6, 2020
8f767b3
Update with new toXxx method names
justingrant Jul 8, 2020
14d6162
Simplify `from`, `with`, and offset handling
justingrant Jul 9, 2020
371200a
Remove `durationKind` options in math methods
justingrant Aug 1, 2020
b41414e
Remove `absolute` field
justingrant Aug 10, 2020
636733c
Accept bigint (not Absolute) in constructor.
justingrant Aug 10, 2020
1ca1978
Use default order-of-operations for subtraction
justingrant Aug 11, 2020
ac45253
Fixes for toLocalDateTime in Date and Time types
justingrant Aug 12, 2020
c09eea2
Add startOfDay prop; fix DST-related props + tests
justingrant Aug 12, 2020
9b307ff
Improved string parsing and added parsing tests
justingrant Aug 30, 2020
514c891
Change offset option default to 'reject' in from()
justingrant Sep 2, 2020
29ccefe
Catch up with recently-landed PRs
justingrant Sep 14, 2020
0d5daec
Mop-up fixes for .d.ts
justingrant Sep 14, 2020
108bcb8
Fix bug that broke arithmetic with years unit
justingrant Sep 15, 2020
15e7aea
Add daysInWeek and monthsInYear property getters
justingrant Sep 15, 2020
1ccad6f
Fix bug in `with` if param is a Temporal instance
justingrant Sep 15, 2020
cb2d5f2
Update offset errors, compare, and equals
justingrant Sep 17, 2020
edef775
Added rounding (part 1)
justingrant Sep 18, 2020
8c75a58
Rename Absolute->Instant in cookbook
justingrant Sep 26, 2020
d48d277
Rename Absolute->Instant (non-cookbook files)
justingrant Sep 26, 2020
e1ad085
Finalize plus and minus
justingrant Sep 28, 2020
55c5eed
update dependencies
justingrant Oct 7, 2020
53b1dc6
Fix tests for Japanese locale outputting era
justingrant Oct 11, 2020
d040603
Add epochXXX convenience properties
justingrant Oct 11, 2020
fb39305
Interim code for rounded difference()
justingrant Oct 11, 2020
c8d6a03
Fix JSDoc typo
justingrant Oct 11, 2020
c0a54e8
Rename timeZoneOffsetXxx properties to offsetXxx
justingrant Oct 11, 2020
55e6dfb
Rename [plus, mius] => [add, subtract]
justingrant Oct 11, 2020
d14c45f
Rename LocalDateTime=>ZonedDateTime
justingrant Oct 11, 2020
c838929
Mop-up fixes for LDT=>ZDT rename
justingrant Oct 11, 2020
cdded19
plus => add for usage of non-ZDT types
justingrant Oct 16, 2020
e962ae3
Default calendar changes
justingrant Oct 16, 2020
4793cdd
Minor edits
justingrant Oct 17, 2020
ffb2fd9
Add withTimeZone method
justingrant Oct 19, 2020
70f054d
Rename offsetString => offset and make it a field
justingrant Oct 19, 2020
710661f
Update to use Instant.epochXxx properties
justingrant Oct 19, 2020
8ab7459
Largest-units-first subtraction and addition
justingrant Oct 20, 2020
7085495
Fix add/subtract DST behavior if date units are 0
justingrant Oct 21, 2020
8777de8
Update `difference()` to fully support rounding
justingrant Oct 21, 2020
5511474
Enable parsing of strings without offsets per #933
justingrant Oct 21, 2020
d6f7f36
Add a few basic tests for rounding
justingrant Oct 21, 2020
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
2 changes: 2 additions & 0 deletions .eslintrc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ ignorePatterns:
- /polyfill/coverage/
# Specific generated files
- /polyfill/script.js
- /docs/playground.js
- /polyfill/index.js
rules:
array-element-newline:
- error
Expand Down
104 changes: 46 additions & 58 deletions docs/cookbook/getBusinessOpenStateText.mjs
Original file line number Diff line number Diff line change
@@ -1,76 +1,50 @@
// ZonedDateTime POC notes
// - This sample's original implementation had a DST bug #698 that would have
// been easier to prevent using `ZonedDateTime`.
// - The result will be easier to work with because it has its time zone already
// baked in.

/**
* Compare the given exact time to the business hours of a business located in
* a particular time zone, and return a string indicating whether the business
* 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
* @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
* opens
* @param {Temporal.Time} businessHours[].close - Time at which the business
* closes
* @param {Temporal.Duration} soonWindow - Length of time before the opening
* or closing time during which the business should be considered "opening
* soon" or "closing soon"
* closes. If this time is smaller than the `open` time, it means that the
* business hours wrap around midnight, so this time represents the closing
* time on the next day.
* @param {Temporal.Duration} soonWindow - Length of time before the opening or
* closing time during which the business should be considered "opening soon"
* or "closing soon"
* @returns {string} "open", "closed", "opening soon", or "closing soon"
*/
function getBusinessOpenStateText(now, timeZone, 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 weekday = dateTime.dayOfWeek % 7; // convert to 0-based, for array indexing
function getBusinessOpenStateText(now, businessHours, soonWindow) {
const inRange = (zonedDateTime, start, end) =>
Temporal.ZonedDateTime.compare(zonedDateTime, start) >= 0 && Temporal.ZonedDateTime.compare(zonedDateTime, end) < 0;

// Because of times wrapping around at midnight, we may need to consider
// yesterday's and tomorrow's hours as well
const today = dateTime.toDate();
const yesterday = today.subtract({ days: 1 });
const tomorrow = today.add({ days: 1 });

// Push any of the businessHours that overlap today's date into an array,
// that we will subsequently check. Convert the businessHours Times into
// DateTimes so that they no longer wrap around.
const businessHoursOverlappingToday = [];
const yesterdayHours = businessHours[(weekday + 6) % 7];
if (yesterdayHours) {
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)
});
for (const delta of [-1, 0, 1]) {
const index = (now.dayOfWeek + 7 + delta) % 7; // convert to 0-based, for array indexing
if (!businessHours[index]) continue;
const openDate = now.toDate().add({ days: delta });
const { open: openTime, close: closeTime } = businessHours[index];
const open = now.with({ ...openDate.getFields(), ...openTime.getFields() });
const isWrap = Temporal.Time.compare(closeTime, openTime) < 0;
const closeDate = isWrap ? openDate.add({ days: 1 }) : openDate;
const close = now.with({ ...closeDate.getFields(), ...closeTime.getFields() });
if (inRange(now, open, close)) {
return Temporal.ZonedDateTime.compare(now, close.subtract(soonWindow)) >= 0 ? 'closing soon' : 'open';
}
if (inRange(now.add(soonWindow), open, close)) return 'opening soon';
}
const todayHours = businessHours[weekday];
if (todayHours) {
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)
});
}

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

if (openNow) {
if (!openSoon) return 'closing soon';
return 'open';
}
if (openSoon) return 'opening soon';
return 'closed';
}

Expand All @@ -86,8 +60,22 @@ 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');
// This ISO string is intentionally conflicting, because the real TZ offset for
// that date is +02:00. The default behavior of from() on ISO strings is to
// throw if the offset isn't valid for the time zone, e.g. if the time zone
// definition has changed since the time was stored. (The user can force use of
// the ISO offset in this case via the 'use' option.)
const now = Temporal.ZonedDateTime.from('2019-04-07T00:00+01:00[Europe/Berlin]', { offset: 'use' });
assert.equal(now.toString(), '2019-04-07T01:00+02: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');

const lastCall = now.add({ minutes: 50 });
assert.equal(lastCall.toString(), '2019-04-07T01:50+02:00[Europe/Berlin]');
const lastCallState = getBusinessOpenStateText(lastCall, businessHours, soonWindow);
assert.equal(lastCallState, 'closing soon');

const tuesdayEarly = now.add({ days: 2, hours: 6 });
const tuesdayEarlyState = getBusinessOpenStateText(tuesdayEarly, businessHours, soonWindow);
assert.equal(tuesdayEarlyState, 'closed');
8 changes: 4 additions & 4 deletions docs/cookbook/getInstantBeforeOldRecord.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,23 @@
* Retrieve an exact time at which to give advance notice of a record that
* is potentially about to be broken.
*
* @param {Temporal.Instant} start - Starting exact time of the event
* @param {Temporal.ZonedDateTime} start - Start of the event
* @param {Temporal.Duration} previousRecord - Existing record to be broken
* @param {Temporal.Duration} noticeWindow - Advance notice time
* @returns {Temporal.Instant} Exact time at which to give advance notice of
* @returns {Temporal.ZonedDateTime} Time at which to give advance notice of
* breaking the record
*/
function getInstantBeforeOldRecord(start, previousRecord, noticeWindow) {
return start.add(previousRecord).subtract(noticeWindow);
}

// Start of the men's 10000 meters at the Rio de Janeiro 2016 Olympic Games
const raceStart = Temporal.Instant.from('2016-08-13T21:27-03:00[America/Sao_Paulo]');
const raceStart = Temporal.ZonedDateTime.from('2016-08-13T21:27-03:00[America/Sao_Paulo]');
// Kenenisa Bekele's world record set in 2005
const record = Temporal.Duration.from({ minutes: 26, seconds: 17, milliseconds: 530 });
const noticeWindow = Temporal.Duration.from({ minutes: 1 });
// Time to send a "hurry up, can you finish the race in 1 minute?" push
// notification to all the runners
const reminderAt = getInstantBeforeOldRecord(raceStart, record, noticeWindow);

assert.equal(reminderAt.toString(), '2016-08-14T00:52:17.530Z');
assert.equal(reminderAt.toString(), '2016-08-13T21:52:17.530-03:00[America/Sao_Paulo]');
6 changes: 3 additions & 3 deletions docs/cookbook/getInstantWithLocalTimeInZone.mjs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/**
* Get an exact time corresponding with a calendar date / wall-clock time in a
* particular time zone, the same as Temporal.TimeZone.getInstantFor() or
* Get an instant corresponding with a calendar date / wall-clock time in
* a particular time zone, the same as Temporal.TimeZone.getInstantFor() or
* Temporal.DateTime.toInstant(), but with more disambiguation options.
*
* As well as the default Temporal disambiguation options 'compatible',
Expand All @@ -17,7 +17,7 @@
* @param {Temporal.TimeZone} timeZone - Time zone in which to consider the
* wall-clock time
* @param {string} [disambiguation='earlier'] - Disambiguation mode, see description.
* @returns {Temporal.Instant} Absolute time in timeZone at the time of the
* @returns {Temporal.Instant} Instant time in timeZone at the time of the
* calendar date and wall-clock time from dateTime
*/
function getInstantWithLocalTimeInZone(dateTime, timeZone, disambiguation = 'earlier') {
Expand Down
18 changes: 12 additions & 6 deletions docs/cookbook/getLocalizedArrival.mjs
Original file line number Diff line number Diff line change
@@ -1,18 +1,24 @@
// ZonedDateTime POC notes
// - Existing code is fine-- no DST issues.
// - This function will break around DST transitions if the caller passes a
justingrant marked this conversation as resolved.
Show resolved Hide resolved
// date/time duration instead of the expected instant duration.
// - The result will be easier to work with because it has its time zone already
// baked in.

/**
* 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
* @param {Temporal.Duration} flightTime - Duration of the flight
* @param {Temporal.Duration} flightTime - Instant 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
* @returns {Temporal.ZonedDateTime} 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);
const departure = Temporal.ZonedDateTime.from(parseableDeparture);
return departure.toInstant().add(flightTime).toZonedDateTime(destinationTimeZone, calendar);
}

const arrival = getLocalizedArrival(
Expand All @@ -21,4 +27,4 @@ const arrival = getLocalizedArrival(
'America/Los_Angeles',
'iso8601'
);
assert.equal(arrival.toString(), '2020-03-08T09:50');
assert.equal(arrival.toString(), '2020-03-08T09:50-07:00[America/Los_Angeles]');
9 changes: 9 additions & 0 deletions docs/cookbook/getParseableZonedStringAtInstant.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,24 @@ const result = instant.toString('Europe/Paris');
assert.equal(result, '2020-01-03T11:41:51+01:00[Europe/Paris]');
assert(instant.equals(Temporal.Instant.from(result)));

const zdt = instant.toZonedDateTime('Europe/Paris', 'iso8601');
assert.equal(zdt.toString(), '2020-01-03T11:41:51+01:00[Europe/Paris]');
assert.equal(Temporal.Instant.compare(instant, zdt.toInstant()), 0);
assert.equal(zdt.toDateTime().toString(), '2020-01-03T11:41:51');

// With an offset:

const result2 = instant.toString('-07:00');
const zdt2 = instant.toZonedDateTime('-07:00', 'iso8601');

assert.equal(result2, '2020-01-03T03:41:51-07:00');
assert.equal(zdt2.toString(), '2020-01-03T03:41:51-07:00[-07:00]');

// With a Temporal.TimeZone object:

const timeZone = Temporal.TimeZone.from('Asia/Seoul');
const result3 = instant.toString(timeZone);
const zdt3 = instant.toZonedDateTime('Asia/Seoul', 'iso8601');

assert.equal(result3, '2020-01-03T19:41:51+09:00[Asia/Seoul]');
assert.equal(zdt3.toString(), '2020-01-03T19:41:51+09:00[Asia/Seoul]');
24 changes: 4 additions & 20 deletions docs/cookbook/getParseableZonedStringWithLocalTimeInOtherZone.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -3,33 +3,17 @@
* expressing the local date and time in another time zone at the same exact
* time.
*
* If `sourceDateTime` doesn't exist in `sourceTimeZone`, or exists twice, then
* an error will be thrown by default.
* Usually this is what you want. (FIXME: but is it?)
* Use `sourceDisambiguationPolicy` to change this behaviour.
*
* @param {Temporal.DateTime} sourceDateTime - The local date and time
* @param {Temporal.TimeZone} sourceTimeZone - The time zone for
* `sourceDateTime`
* @param {Temporal.ZonedDateTime} source - The local date and time
* @param {Temporal.TimeZone} targetTimeZone - The time zone for the
* return value
* @param {string} [sourceDisambiguationPolicy=reject] - what to do when
* `sourceDateTime` is ambiguous
* @returns {string} String indicating the time with time zone designation
*/
function getParseableZonedStringWithLocalTimeInOtherZone(
sourceDateTime,
sourceTimeZone,
targetTimeZone,
sourceDisambiguationPolicy = 'reject'
) {
let instant = sourceDateTime.toInstant(sourceTimeZone, { disambiguation: sourceDisambiguationPolicy });
return instant.toString(targetTimeZone);
function getParseableZonedStringWithLocalTimeInOtherZone(source, targetTimeZone) {
return source.with({ timeZone: targetTimeZone }).toString();
}

const result = getParseableZonedStringWithLocalTimeInOtherZone(
Temporal.DateTime.from('2020-01-09T00:00'),
Temporal.TimeZone.from('America/Chicago'),
Temporal.ZonedDateTime.from('2020-01-09T00:00-06:00[America/Chicago]'),
Temporal.TimeZone.from('America/Los_Angeles')
);
// On this date, when it's midnight in Chicago, it's 10 PM the previous night in LA
Expand Down
6 changes: 3 additions & 3 deletions docs/cookbook/getSortedLocalDateTimes.mjs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
/**
* getSortedLocalDateTimes will sort an array of zoneless Temporal.DateTime instances by the
* getSortedZonedDateTimes will sort an array of zoneless Temporal.DateTime instances by the
* corresponding local date and time of day (e.g., for building a conference schedule).
*
*
* @param {Temporal.DateTime[]} dateTimes - This is a DateTime instance
* @param {boolean} [reverse=false] - Return in reversed order
* @returns {Temporal.DateTime[]} the array from dateTimes, sorted
*/
function getSortedLocalDateTimes(dateTimes, reverse = false) {
function getSortedZonedDateTimes(dateTimes, reverse = false) {
let newDateTimes = Array.from(dateTimes).sort(Temporal.DateTime.compare);

return reverse ? newDateTimes.reverse() : newDateTimes;
Expand Down Expand Up @@ -35,7 +35,7 @@ let c = Temporal.DateTime.from({
hour: 15,
minute: 30
}); // Coffee Break
const results = getSortedLocalDateTimes([a, b, c]);
const results = getSortedZonedDateTimes([a, b, c]);
assert.deepEqual(
results.map((x) => x.toString()),
['2020-02-20T08:45', '2020-02-20T15:30', '2020-02-21T13:10']
Expand Down
4 changes: 2 additions & 2 deletions docs/cookbook/getTripDurationInHrMinSec.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
* @returns {Temporal.Duration} A duration with units no larger than hours
*/
function getTripDurationInHrMinSec(parseableDeparture, parseableArrival) {
const departure = Temporal.Instant.from(parseableDeparture);
const arrival = Temporal.Instant.from(parseableArrival);
const departure = Temporal.ZonedDateTime.from(parseableDeparture);
const arrival = Temporal.ZonedDateTime.from(parseableArrival);
return arrival.difference(departure, { largestUnit: 'hours' });
}

Expand Down
17 changes: 8 additions & 9 deletions docs/cookbook/getUtcOffsetDifferenceSecondsAtInstant.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,20 @@
* Returns the number of seconds' difference between the UTC offsets of two
* time zones, at an exact time
*
* @param {Temporal.Instant} instant - An exact time
* @param {Temporal.TimeZone} sourceTimeZone - A time zone to examine
* @param {Temporal.ZonedDateTime} source - Am exact time in the source time zone
* @param {Temporal.TimeZone} targetTimeZone - A second time zone to examine
* @returns {number} The number of seconds difference between the time zones'
* UTC offsets
* UTC offsets at that moment.
*/
function getUtcOffsetDifferenceSecondsAtInstant(instant, sourceTimeZone, targetTimeZone) {
const sourceOffsetNs = sourceTimeZone.getOffsetNanosecondsFor(instant);
const targetOffsetNs = targetTimeZone.getOffsetNanosecondsFor(instant);
return (targetOffsetNs - sourceOffsetNs) / 1e9;
function getUtcOffsetDifferenceSecondsAtInstant(source, targetTimeZone) {
const target = source.with({ timeZone: targetTimeZone });
return (target.offsetNanoseconds - source.offsetNanoseconds) / 1e9;
}

const instant = Temporal.Instant.from('2020-01-09T00:00Z');
const nyc = Temporal.TimeZone.from('America/New_York');
const zdtNyc = instant.toZonedDateTime(nyc, 'iso8601');
const chicago = Temporal.TimeZone.from('America/Chicago');

// At this exact time, Chicago is 3600 seconds earlier than New York
assert.equal(getUtcOffsetDifferenceSecondsAtInstant(instant, nyc, chicago), -3600);
// At this instant, Chicago's local time is 3600 seconds earlier than New York
assert.equal(getUtcOffsetDifferenceSecondsAtInstant(zdtNyc, chicago), -3600);
7 changes: 4 additions & 3 deletions docs/cookbook/getUtcOffsetSecondsAtInstant.mjs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const instant = Temporal.Instant.from('2020-01-09T00:00Z');
const nyc = Temporal.TimeZone.from('America/New_York');
const zdt = Temporal.Instant.from('2020-01-09T00:00Z').toZonedDateTime('America/New_York', 'iso8601');

nyc.getOffsetNanosecondsFor(instant) / 1e9; // => -18000
zdt.offsetNanoseconds / 1e9; // => -18000

assert.equal(zdt.offsetNanoseconds / 1e9, '-18000');
5 changes: 4 additions & 1 deletion docs/cookbook/getUtcOffsetStringAtInstant.mjs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
const instant = Temporal.Instant.from('2020-01-09T00:00Z');
const nyc = Temporal.TimeZone.from('America/New_York');
const zdt = instant.toZonedDateTime(nyc, 'iso8601');

nyc.getOffsetStringFor(instant); // => -05:00
zdt.offset; // => '-05:00'

assert.equal(zdt.offset, '-05:00');
17 changes: 8 additions & 9 deletions docs/cookbook/localTimeForFutureEvents.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -28,21 +28,20 @@ const tc39meetings = [

// To follow the meetings remotely from Tokyo, calculate the times you would
// need to join:
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' })
.with({ timeZone: 'Asia/Tokyo' }, { disambiguation: 'reject' });
});

assert.deepEqual(
localTimes.map((dt) => dt.toString()),
[
'2019-01-29T02:00',
'2019-03-26T23:00',
'2019-06-04T17:00',
'2019-07-24T02:00',
'2019-10-01T23:00',
'2019-12-04T03:00'
'2019-01-29T02:00+09:00[Asia/Tokyo]',
'2019-03-26T23:00+09:00[Asia/Tokyo]',
'2019-06-04T17:00+09:00[Asia/Tokyo]',
'2019-07-24T02:00+09:00[Asia/Tokyo]',
'2019-10-01T23:00+09:00[Asia/Tokyo]',
'2019-12-04T03:00+09:00[Asia/Tokyo]'
]
);
Loading