diff --git a/polyfill/lib/plaindate.mjs b/polyfill/lib/plaindate.mjs index 62ecdd3849..69f2449d3e 100644 --- a/polyfill/lib/plaindate.mjs +++ b/polyfill/lib/plaindate.mjs @@ -329,17 +329,26 @@ export class PlainDate { const calendar = ES.ConsolidateCalendars(dateCalendar, timeCalendar); return new DateTime(year, month, day, hour, minute, second, millisecond, microsecond, nanosecond, calendar); } - toZonedDateTime(timeZoneLike, temporalTime = undefined, options = undefined) { + toZonedDateTime(item) { if (!ES.IsTemporalDate(this)) throw new TypeError('invalid receiver'); - const timeZone = ES.ToTemporalTimeZone(timeZoneLike); - options = ES.NormalizeOptionsObject(options); - const disambiguation = ES.ToTemporalDisambiguation(options); + + let timeZone, temporalTime; + if (ES.Type(item) === 'Object') { + let timeZoneLike = item.timeZone; + if (timeZoneLike === undefined) { + timeZone = ES.ToTemporalTimeZone(item); + } else { + timeZone = ES.ToTemporalTimeZone(timeZoneLike); + temporalTime = item.time; + } + } else { + timeZone = ES.ToTemporalTimeZone(item); + } const year = GetSlot(this, ISO_YEAR); const month = GetSlot(this, ISO_MONTH); const day = GetSlot(this, ISO_DAY); const calendar = GetSlot(this, CALENDAR); - const DateTime = GetIntrinsic('%Temporal.PlainDateTime%'); let hour = 0, minute = 0, @@ -357,8 +366,20 @@ export class PlainDate { nanosecond = GetSlot(temporalTime, ISO_NANOSECOND); } - const dt = new DateTime(year, month, day, hour, minute, second, millisecond, microsecond, nanosecond, calendar); - const instant = ES.GetTemporalInstantFor(timeZone, dt, disambiguation); + const PlainDateTime = GetIntrinsic('%Temporal.PlainDateTime%'); + const dt = new PlainDateTime( + year, + month, + day, + hour, + minute, + second, + millisecond, + microsecond, + nanosecond, + calendar + ); + const instant = ES.GetTemporalInstantFor(timeZone, dt, 'compatible'); const ZonedDateTime = GetIntrinsic('%Temporal.ZonedDateTime%'); return new ZonedDateTime(GetSlot(instant, EPOCHNANOSECONDS), timeZone, calendar); } diff --git a/polyfill/lib/plaintime.mjs b/polyfill/lib/plaintime.mjs index 503c6adcaf..a77f46480e 100644 --- a/polyfill/lib/plaintime.mjs +++ b/polyfill/lib/plaintime.mjs @@ -399,12 +399,24 @@ export class PlainTime { const DateTime = GetIntrinsic('%Temporal.PlainDateTime%'); return new DateTime(year, month, day, hour, minute, second, millisecond, microsecond, nanosecond, calendar); } - toZonedDateTime(timeZoneLike, temporalDate, options = undefined) { + toZonedDateTime(item) { if (!ES.IsTemporalTime(this)) throw new TypeError('invalid receiver'); + + if (ES.Type(item) !== 'Object') { + throw new TypeError('invalid argument'); + } + + const dateLike = item.date; + if (dateLike === undefined) { + throw new TypeError('missing date property'); + } + const temporalDate = ES.ToTemporalDate(dateLike, GetIntrinsic('%Temporal.PlainDate%')); + + const timeZoneLike = item.timeZone; + if (timeZoneLike === undefined) { + throw new TypeError('missing timeZone property'); + } const timeZone = ES.ToTemporalTimeZone(timeZoneLike); - temporalDate = ES.ToTemporalDate(temporalDate, GetIntrinsic('%Temporal.PlainDate%')); - options = ES.NormalizeOptionsObject(options); - const disambiguation = ES.ToTemporalDisambiguation(options); const year = GetSlot(temporalDate, ISO_YEAR); const month = GetSlot(temporalDate, ISO_MONTH); @@ -416,10 +428,21 @@ export class PlainTime { const millisecond = GetSlot(this, ISO_MILLISECOND); const microsecond = GetSlot(this, ISO_MICROSECOND); const nanosecond = GetSlot(this, ISO_NANOSECOND); - const DateTime = GetIntrinsic('%Temporal.PlainDateTime%'); - const dt = new DateTime(year, month, day, hour, minute, second, millisecond, microsecond, nanosecond, calendar); - const instant = ES.GetTemporalInstantFor(timeZone, dt, disambiguation); + const PlainDateTime = GetIntrinsic('%Temporal.PlainDateTime%'); + const dt = new PlainDateTime( + year, + month, + day, + hour, + minute, + second, + millisecond, + microsecond, + nanosecond, + calendar + ); + const instant = ES.GetTemporalInstantFor(timeZone, dt, 'compatible'); const ZonedDateTime = GetIntrinsic('%Temporal.ZonedDateTime%'); return new ZonedDateTime(GetSlot(instant, EPOCHNANOSECONDS), timeZone, calendar); } diff --git a/polyfill/test/plaindate.mjs b/polyfill/test/plaindate.mjs index bbcfb75901..b45a1c4e5c 100644 --- a/polyfill/test/plaindate.mjs +++ b/polyfill/test/plaindate.mjs @@ -208,49 +208,33 @@ describe('Date', () => { const date = PlainDate.from('2020-01-01'); const time = Temporal.PlainTime.from('12:00'); const tz = Temporal.TimeZone.from('America/Los_Angeles'); - equal(`${date.toZonedDateTime(tz, time)}`, '2020-01-01T12:00:00-08:00[America/Los_Angeles]'); + const zdt = date.toZonedDateTime({ timeZone: tz, time }); + equal(`${zdt}`, '2020-01-01T12:00:00-08:00[America/Los_Angeles]'); }); - it('works with time omitted', () => { + it('works with time omitted (timeZone argument)', () => { const date = PlainDate.from('2020-01-01'); const tz = Temporal.TimeZone.from('America/Los_Angeles'); - equal(`${date.toZonedDateTime(tz)}`, '2020-01-01T00:00:00-08:00[America/Los_Angeles]'); + const zdt = date.toZonedDateTime(tz); + equal(`${zdt}`, '2020-01-01T00:00:00-08:00[America/Los_Angeles]'); }); - it('works with disambiguation option', () => { - const date = PlainDate.from('2020-03-08'); - const time = Temporal.PlainTime.from('02:00'); + it('works with time omitted (timeZone property)', () => { + const date = PlainDate.from('2020-01-01'); const tz = Temporal.TimeZone.from('America/Los_Angeles'); - const zdt = date.toZonedDateTime(tz, time, { disambiguation: 'earlier' }); - equal(`${zdt}`, '2020-03-08T01:00:00-08:00[America/Los_Angeles]'); + const zdt = date.toZonedDateTime({ timeZone: tz }); + equal(`${zdt}`, '2020-01-01T00:00:00-08:00[America/Los_Angeles]'); }); - it('casts first argument', () => { + it('casts timeZone property', () => { const date = PlainDate.from('2020-07-08'); const time = Temporal.PlainTime.from('12:00'); - const zdt = date.toZonedDateTime('America/Los_Angeles', time); + const zdt = date.toZonedDateTime({ timeZone: 'America/Los_Angeles', time }); equal(`${zdt}`, '2020-07-08T12:00:00-07:00[America/Los_Angeles]'); }); - it('casts second argument', () => { + it('casts time property', () => { const date = PlainDate.from('2020-07-08'); const tz = Temporal.TimeZone.from('America/Los_Angeles'); - const zdt = date.toZonedDateTime(tz, '12:00'); + const zdt = date.toZonedDateTime({ timeZone: tz, time: '12:00' }); equal(`${zdt}`, '2020-07-08T12:00:00-07:00[America/Los_Angeles]'); }); - it('throws on bad disambiguation', () => { - ['', 'EARLIER', 'xyz', 3, null].forEach((disambiguation) => - throws(() => PlainDate.from('2019-10-29').toZonedDateTime('UTC', '12:00', { disambiguation }), RangeError) - ); - }); - it('options may only be an object or undefined', () => { - const date = PlainDate.from('2019-10-29'); - [null, 1, 'hello', true, Symbol('foo'), 1n].forEach((badOptions) => - throws(() => date.toZonedDateTime('America/Sao_Paulo', '10:46:38', badOptions), TypeError) - ); - [{}, () => {}, undefined].forEach((options) => - equal( - `${date.toZonedDateTime('America/Sao_Paulo', '10:46:38', options)}`, - '2019-10-29T10:46:38-03:00[America/Sao_Paulo]' - ) - ); - }); }); describe('date.until() works', () => { const date = new PlainDate(1969, 7, 24); diff --git a/polyfill/test/plaintime.mjs b/polyfill/test/plaintime.mjs index 5c653303ad..a0bc772af2 100644 --- a/polyfill/test/plaintime.mjs +++ b/polyfill/test/plaintime.mjs @@ -268,44 +268,21 @@ describe('Time', () => { const time = PlainTime.from('12:00'); const date = Temporal.PlainDate.from('2020-01-01'); const tz = Temporal.TimeZone.from('America/Los_Angeles'); - equal(`${time.toZonedDateTime(tz, date)}`, '2020-01-01T12:00:00-08:00[America/Los_Angeles]'); + const zdt = time.toZonedDateTime({ timeZone: tz, date }); + equal(`${zdt}`, '2020-01-01T12:00:00-08:00[America/Los_Angeles]'); }); - it('works with disambiguation option', () => { - const time = PlainTime.from('02:00'); - const date = Temporal.PlainDate.from('2020-03-08'); - const tz = Temporal.TimeZone.from('America/Los_Angeles'); - const zdt = time.toZonedDateTime(tz, date, { disambiguation: 'earlier' }); - equal(`${zdt}`, '2020-03-08T01:00:00-08:00[America/Los_Angeles]'); - }); - it('casts first argument', () => { + it('casts timeZone property', () => { const time = PlainTime.from('12:00'); const date = Temporal.PlainDate.from('2020-07-08'); - const zdt = time.toZonedDateTime('America/Los_Angeles', date); + const zdt = time.toZonedDateTime({ timeZone: 'America/Los_Angeles', date }); equal(`${zdt}`, '2020-07-08T12:00:00-07:00[America/Los_Angeles]'); }); - it('casts second argument', () => { + it('casts date property', () => { const time = PlainTime.from('12:00'); const tz = Temporal.TimeZone.from('America/Los_Angeles'); - const zdt = time.toZonedDateTime(tz, '2020-07-08'); + const zdt = time.toZonedDateTime({ timeZone: tz, date: '2020-07-08' }); equal(`${zdt}`, '2020-07-08T12:00:00-07:00[America/Los_Angeles]'); }); - it('throws on bad disambiguation', () => { - ['', 'EARLIER', 'xyz', 3, null].forEach((disambiguation) => - throws(() => PlainTime.from('12:00').toZonedDateTime('UTC', '2019-10-29', { disambiguation }), RangeError) - ); - }); - it('options may only be an object or undefined', () => { - const time = PlainTime.from('10:46:38'); - [null, 1, 'hello', true, Symbol('foo'), 1n].forEach((badOptions) => - throws(() => time.toZonedDateTime('America/Sao_Paulo', '2019-10-29', badOptions), TypeError) - ); - [{}, () => {}, undefined].forEach((options) => - equal( - `${time.toZonedDateTime('America/Sao_Paulo', '2019-10-29', options)}`, - '2019-10-29T10:46:38-03:00[America/Sao_Paulo]' - ) - ); - }); }); describe('time.until() works', () => { const time = new PlainTime(15, 23, 30, 123, 456, 789); diff --git a/spec/plaindate.html b/spec/plaindate.html index c4647f67d0..7e8155c97c 100644 --- a/spec/plaindate.html +++ b/spec/plaindate.html @@ -523,23 +523,33 @@

Temporal.PlainDate.prototype.toPlainDateTime ( [ _temporalTime_ ] )

-

Temporal.PlainDate.prototype.toZonedDateTime ( _timeZoneLike_ [ , _temporalTime_ [ , _options_ ] ] )

+

Temporal.PlainDate.prototype.toZonedDateTime ( _item_ )

- The `toZonedDateTime` method takes three arguments, _timeZoneLike_, _temporalTime_, and _options_. + The `toZonedDateTime` method takes one argument _item_. The following steps are taken:

1. Let _temporalDate_ be the *this* value. 1. Perform ? RequireInternalSlot(_temporalDate_, [[InitializedTemporalDate]]). - 1. Let _timeZone_ be ? ToTemporalTimeZone(_temporalTimeZoneLike_). - 1. Set _options_ to ? NormalizeOptionsObject(_options_). - 1. Let _disambiguation_ be ? ToTemporalDisambiguation(_options_). + 1. If Type(_item_) is Object, then + 1. Let _timeZoneLike_ be ? Get(_item_, *"timeZone"*). + 1. If _timeZoneLike_ is *undefined*, then + + 1. Let _timeZone_ be ? ToTemporalTimeZone(_item_). + 1. Let _temporalTime_ be *undefined*. + 1. Else, + + 1. Let _timeZone_ be ? ToTemporalTimeZone(_timeZoneLike_). + 1. Let _temporalTime_ be ? Get(_item_, *"time"*). + 1. Else, + 1. Let _timeZone_ be ? ToTemporalTimeZone(_item_). + 1. Let _temporalTime_ be *undefined*. 1. If _temporalTime_ is *undefined*, then 1. Let _temporalDateTime_ be ? CreateTemporalDateTime(_temporalDate_.[[ISOYear]], _temporalDate_.[[ISOMonth]], _temporalDate_.[[ISODay]], 0, 0, 0, 0, 0, 0, _temporalDate_.[[Calendar]]). 1. Else, 1. Set _temporalTime_ to ? ToTemporalTime(_temporalTime_). 1. Let _temporalDateTime_ be ? CreateTemporalDateTime(_temporalDate_.[[ISOYear]], _temporalDate_.[[ISOMonth]], _temporalDate_.[[ISODay]], _temporalTime_.[[Hour]], _temporalTime_.[[Minute]], _temporalTime_.[[Second]], _temporalTime_.[[Millisecond]], _temporalTime_.[[Microsecond]], _temporalTime_.[[Nanosecond]], _temporalDate_.[[Calendar]]). - 1. Let _instant_ be ? GetTemporalInstantFor(_timeZone_, _temporalDateTime_, _disambiguation_). + 1. Let _instant_ be ? GetTemporalInstantFor(_timeZone_, _temporalDateTime_, *"compatible"*). 1. Return ? CreateTemporalZonedDateTime(_instant_.[[Nanoseconds]], _timeZone_, _temporalDate_.[[Calendar]]).
diff --git a/spec/plaintime.html b/spec/plaintime.html index c647307427..822466d2b9 100644 --- a/spec/plaintime.html +++ b/spec/plaintime.html @@ -404,20 +404,24 @@

Temporal.PlainTime.prototype.toPlainDateTime ( _temporalDate_ )

-

Temporal.PlainTime.prototype.toZonedDateTime ( _timeZoneLike_, _temporalDate_ [ , _options_ ] )

+

Temporal.PlainTime.prototype.toZonedDateTime ( _item_ )

- The `toZonedDateTime` method takes three arguments, _timeZoneLike_, _temporalDate_, and _options_. + The `toZonedDateTime` method takes one argument _item_. The following steps are taken:

1. Let _temporalTime_ be the *this* value. 1. Perform ? RequireInternalSlot(_temporalTime_, [[InitializedTemporalTime]]). + 1. Let _temporalDateLike_ be ? Get(_item_, *"date"*). + 1. If _temporalDateLike_ is *undefined*, then + 1. Throw a *TypeError* exception. + 1. Let _temporalDate_ to ? ToTemporalTime(_temporalDateLike_). + 1. Let _temporalTimeZoneLike_ be ? Get(_item_, *"timeZone"*). + 1. If _temporalTimeZoneLike_ is *undefined*, then + 1. Throw a *TypeError* exception. 1. Let _timeZone_ be ? ToTemporalTimeZone(_temporalTimeZoneLike_). - 1. Set _temporalDate_ to ? ToTemporalTime(_temporalDate_). - 1. Set _options_ to ? NormalizeOptionsObject(_options_). - 1. Let _disambiguation_ be ? ToTemporalDisambiguation(_options_). 1. Let _temporalDateTime_ be ? CreateTemporalDateTime(_temporalDate_.[[ISOYear]], _temporalDate_.[[ISOMonth]], _temporalDate_.[[ISODay]], _temporalTime_.[[Hour]], _temporalTime_.[[Minute]], _temporalTime_.[[Second]], _temporalTime_.[[Millisecond]], _temporalTime_.[[Microsecond]], _temporalTime_.[[Nanosecond]], _temporalDate_.[[Calendar]]). - 1. Let _instant_ be ? GetTemporalInstantFor(_timeZone_, _temporalDateTime_, _disambiguation_). + 1. Let _instant_ be ? GetTemporalInstantFor(_timeZone_, _temporalDateTime_, *"compatible"*). 1. Return ? CreateTemporalZonedDateTime(_instant_.[[Nanoseconds]], _timeZone_, _temporalDate_.[[Calendar]]).