From cd616a11793a37b14b0fca23973c78ce2c40b4ba Mon Sep 17 00:00:00 2001 From: Ms2ger Date: Mon, 28 Jun 2021 14:48:50 +0200 Subject: [PATCH] Editorial: Avoid dividing by zero in ZonedDateTime#round. Ref. #1502. --- polyfill/lib/zoneddatetime.mjs | 3 +++ .../ZonedDateTime/prototype/round/div-zero.js | 23 +++++++++++++++++++ spec/zoneddatetime.html | 2 ++ 3 files changed, 28 insertions(+) create mode 100644 polyfill/test/ZonedDateTime/prototype/round/div-zero.js diff --git a/polyfill/lib/zoneddatetime.mjs b/polyfill/lib/zoneddatetime.mjs index f001f78db1..e344afd96c 100644 --- a/polyfill/lib/zoneddatetime.mjs +++ b/polyfill/lib/zoneddatetime.mjs @@ -644,6 +644,9 @@ export class ZonedDateTime { const instantStart = ES.BuiltinTimeZoneGetInstantFor(timeZone, dtStart, 'compatible'); const endNs = ES.AddZonedDateTime(instantStart, timeZone, calendar, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0); const dayLengthNs = endNs.subtract(GetSlot(instantStart, EPOCHNANOSECONDS)); + if (dayLengthNs.isZero()) { + throw new RangeError('can not round a ZonedDateTime in a calendar with zero-length days'); + } ({ year, month, day, hour, minute, second, millisecond, microsecond, nanosecond } = ES.RoundISODateTime( year, month, diff --git a/polyfill/test/ZonedDateTime/prototype/round/div-zero.js b/polyfill/test/ZonedDateTime/prototype/round/div-zero.js new file mode 100644 index 0000000000..e56300836b --- /dev/null +++ b/polyfill/test/ZonedDateTime/prototype/round/div-zero.js @@ -0,0 +1,23 @@ +// Copyright (C) 2021 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.zoneddatetime.prototype.round +features: [Temporal] +---*/ + +class Calendar extends Temporal.Calendar { + constructor() { + super("iso8601") + } + dateAdd(d) { + return d; + } +}; + +const zdt = new Temporal.ZonedDateTime(0n, "UTC", new Calendar()); + +const units = ["day", "hour", "minute", "second", "millisecond", "microsecond", "nanosecond"]; +for (const smallestUnit of units) { + assert.throws(RangeError, () => zdt.round({ smallestUnit })); +} diff --git a/spec/zoneddatetime.html b/spec/zoneddatetime.html index 4e669de321..c227694020 100644 --- a/spec/zoneddatetime.html +++ b/spec/zoneddatetime.html @@ -789,6 +789,8 @@

Temporal.ZonedDateTime.prototype.round ( _options_ )

1. Let _startNs_ be _instantStart_.[[Nanoseconds]]. 1. Let _endNs_ be ? AddZonedDateTime(_startNs_, _timeZone_, _zonedDateTime_.[[Calendar]], 0, 0, 0, 1, 0, 0, 0, 0, 0, 0). 1. Let _dayLengthNs_ be _endNs_ − _startNs_. + 1. If _dayLengthNs_ is 0, then + 1. Throw a *RangeError* exception. 1. Let _roundResult_ be ? RoundISODateTime(_temporalDateTime_.[[ISOYear]], _temporalDateTime_.[[ISOMonth]], _temporalDateTime_.[[ISODay]], _temporalDateTime_.[[ISOHour]], _temporalDateTime_.[[ISOMinute]], _temporalDateTime_.[[ISOSecond]], _temporalDateTime_.[[ISOMillisecond]], _temporalDateTime_.[[ISOMicrosecond]], _temporalDateTime_.[[ISONanosecond]], _roundingIncrement_, _smallestUnit_, _roundingMode_, _dayLengthNs_). 1. Let _offsetNanoseconds_ be ? GetOffsetNanosecondsFor(_timeZone_, _instant_). 1. Let _epochNanoseconds_ be ? InterpretISODateTimeOffset(_roundResult_.[[Year]], _roundResult_.[[Month]], _roundResult_.[[Day]], _roundResult_.[[Hour]], _roundResult_.[[Minute]], _roundResult_.[[Second]], _roundResult_.[[Millisecond]], _roundResult_.[[Microsecond]], _roundResult_.[[Nanosecond]], _offsetNanoseconds_, _timeZone_, *"compatible"*, *"prefer"*).