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

Normative: Use Number arithmetic for constructing dates and times #1564

Open
wants to merge 9 commits into
base: master
from

Conversation

@gibson042
Copy link
Contributor

commented May 31, 2019

Fixes #1087

Also differentiates the range for time value vs. [[DateValue]], cleans up the text for date and time operations (particularly LocalTZA), and consolidates them where possible.

Can be reviewed commit-by-commit if the merged view is overwhelming.

@spectranaut
Copy link

left a comment

This is awesome! These changes make the spec way more clear.

spec.html Outdated
<p>The exact moment of midnight at the beginning of 01 January, 1970 UTC is represented by the time value *+0*.</p>
<emu-note>
<p>The 400 year cycle of the Gregorian calendar contains 97 leap years. This yields an average of 365.2425 days per year, or an average of 31,556,952,000 milliseconds per year under the Gregorian calendar. ECMAScript applies a proleptic Gregorian calendar for all time computations.</p>
<p>As specified by this section, the maximum year range a Number can represent exactly with millisecond precision is approximately -285,426 to 285,426 years relative to midnight at the beginning of 01 January, 1970 UTC.</p>
<p>As specified by this section, the maximum year range a time value can represent is approximately -273,790 to 273,790 years relative to midnight at the beginning of 01 January, 1970 UTC.</p>
<p>As specified by this section, the maximum year range a [[DateValue]] can represent is approximately -273,790 to 273,790 years relative to midnight at the beginning of 01 January, 1970 UTC.</p>

This comment has been minimized.

Copy link
@spectranaut

spectranaut Aug 8, 2019

I'm not sure why time value was changed to [[DateValue]] here -- it seems to me that a "time value" is only a valid "time value" if it is within this range? This makes it seem like that value of [[DateValue]] must be in this range but "time value" can be outside of it.

This comment has been minimized.

Copy link
@gibson042

gibson042 Aug 15, 2019

Author Contributor

Right, and it's actually a critically important aspect here that some time values fall outside the valid range of the [[DateValue]] internal slot of Date instances.

For a simple example, consider LocalTime, which returns a time value with UTC date and time of day equal to the local date and time of day at the instant in time specified by its time value argument. This is equivalent to returning the the sum of its argument and the local UTC offset at that instant, which can exceed the maximum valid [[DateValue]] if the argument is already close to it (e.g., if the local UTC offset at the maximum [[DateValue]] of +275760-09-13T00:00Z is +10:00 [+275760-09-13T10:00+10:00], then LocalTime(8_640_000_000_000_000) returns 8_640_000_036_000_000 [corresponding with +275760-09-13T10:00Z, which is not a valid [[DateValue]] but is nonetheless a well-defined time value]). And similar effects apply with negative UTC offsets near the minimum [[DateValue]] boundary of -8_640_000_000_000_000.

This comment has been minimized.

Copy link
@ljharb

ljharb Aug 29, 2019

Member

In that case perhaps we should define, alongside a "time value", a "date value", and indicate that [[DateValue]] can only hold a "date value"?

This comment has been minimized.

Copy link
@gibson042

gibson042 Aug 31, 2019

Author Contributor

I think that would confuse rather than illuminate. There really is just one concept, but the full range of safe integers is only available for internal operations to avoid rounding errors where the spec calls for UTC offset conversion/DST calculation/etc. The bounds are enforced by TimeClip, which is introduced as the last operation in this overview section. Perhaps the range aspects of "Time Values and Time Range" should be pulled into an explicit subsection and TimeClip should be moved there, making it the first operation rather than the last?

This comment has been minimized.

Copy link
@spectranaut

spectranaut Sep 3, 2019

I like that suggestion, @gibson042.

This comment has been minimized.

Copy link
@gibson042

gibson042 Sep 4, 2019

Author Contributor

Done.

spec.html Outdated
<emu-eqn id="eqn-Day" aoid="Day">Day(_t_) = floor(_t_ / msPerDay)</emu-eqn>
<p>where the number of milliseconds per day is</p>
<emu-eqn id="eqn-msPerDay" aoid="msPerDay">msPerDay = 86400000</emu-eqn>

This comment has been minimized.

Copy link
@spectranaut

spectranaut Aug 8, 2019

If we remove this, there is no definition for msPerDay in the spec. It seems like this should be specified.

This comment has been minimized.

Copy link
@gibson042

gibson042 Aug 15, 2019

Author Contributor

It got moved to line 26781.

spec.html Outdated
<p>where</p>
<emu-eqn id="eqn-DayWithinYear" aoid="DayWithinYear">DayWithinYear(_t_) = Day(_t_) - DayFromYear(YearFromTime(_t_))</emu-eqn>
<p>A month value of 0 specifies January; 1 specifies February; 2 specifies March; 3 specifies April; 4 specifies May; 5 specifies June; 6 specifies July; 7 specifies August; 8 specifies September; 9 specifies October; 10 specifies November; and 11 specifies December. Note that <emu-eqn>MonthFromTime(0) = 0</emu-eqn>, corresponding to Thursday, 01 January, 1970.</p>
<p>Note that <emu-eqn>MonthFromTime(0) = 0</emu-eqn>, corresponding to Thursday, 01 January, 1970.</p>

This comment has been minimized.

Copy link
@spectranaut

spectranaut Aug 8, 2019

Maybe use <emu-note>? If so, then change the "note" in the Week Day definition to the <emu-note> format, too.

This comment has been minimized.

Copy link
@gibson042

gibson042 Aug 15, 2019

Author Contributor

I think this renders better as-is, but will change to <emu-note> if there are strong feelings about it.

@gibson042 gibson042 force-pushed the gibson042:gh-1087-time-arithmetic-precision branch from e5c9eb0 to d6b339c Sep 4, 2019

spec.html Show resolved Hide resolved
1. If _wholeYears_ is not finite, return *NaN*.
1. Let _monthWithinYear_ be _m_ modulo 12.
1. Let _inLeapYear_ be InLeapYear(TimeFromYear(_wholeYears_)).
1. Let _day_ be DayFromYear(_wholeYears_) `+` DaysWithinYearBeforeMonth(_monthWithinYear_, _inLeapYear_) `+` _d_ `-` 1, performing the arithmetic according to IEEE 754-2008 rules (that is, as if using the ECMAScript operators `+` and `-`).

This comment has been minimized.

Copy link
@ljharb

ljharb Sep 4, 2019

Member

if you use the subscript 𝔽, i don't think you need the "performing …" prose, since that makes them Numbers?

This comment has been minimized.

Copy link
@jmdyck

jmdyck Sep 4, 2019

Collaborator

You don't even need the subscript, since it's optional when the operands are Number values, which they presumably are, according to 5.2.5. And the operators don't need backticks either.

This comment has been minimized.

Copy link
@ljharb

ljharb Sep 4, 2019

Member

even better

This comment has been minimized.

Copy link
@gibson042

gibson042 Sep 4, 2019

Author Contributor

Cool; I'll update that. Should multiplication of Number values use * or ×?

@ljharb ljharb force-pushed the gibson042:gh-1087-time-arithmetic-precision branch from a754929 to c5b118b Sep 5, 2019

gibson042 added 9 commits May 25, 2019
Editorial: Clarify time value comparison and conversion
Differentiate time values representing instants in (absolute) time from
those representing (civil) date and time of day.
Editorial: Only restrict time values more tightly than safe integers …
…in [[DateValue]]

UTC/local time calculations near the [[DateValue]] limits can yield
integers that exceed them.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
4 participants
You can’t perform that action at this time.