-
Notifications
You must be signed in to change notification settings - Fork 1.3k
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
Editorial: Better relate ECMAScript time values to POSIX and UTC #1325
Editorial: Better relate ECMAScript time values to POSIX and UTC #1325
Conversation
spec.html
Outdated
<p>A Date object contains a Number representing an instant in time with millisecond precision. Such a Number is called a <dfn>time value</dfn>. A time value may also be *NaN*, indicating that the Date object does not represent a specific instant in time.</p> | ||
<p>Time is measured in ECMAScript as milliseconds since midnight at the beginning of 01 January, 1970 UTC. Time in ECMAScript does not observe leap seconds; they are ignored. Time calculations assume each and every day contains exactly <emu-eqn>60 × 60 × 24 × 1000 = 86,400,000</emu-eqn> milliseconds, to align with the POSIX specification of each and every day containing exactly 86,400 seconds.</p> | ||
<p>A Number can exactly represent all integers from -9,007,199,254,740,992 to 9,007,199,254,740,992 (<emu-xref href="#sec-number.min_safe_integer"></emu-xref> and <emu-xref href="#sec-number.max_safe_integer"></emu-xref>). A time value supports a slightly smaller range of exactly -100,000,000 days to 100,000,000 days measured relative to midnight at the beginning of 01 January, 1970 UTC. This yields an exact supported time value range of -8,640,000,000,000,000 to 8,640,000,000,000,000 milliseconds relative to midnight at the beginning of 01 January, 1970 UTC.</p> | ||
<p>Time measurement in ECMAScript is analogous to time measurement in POSIX, in particular sharing an epoch of midnight at the beginning of 01 January, 1970 UTC, use of the proleptic Gregorian calendar, and an accounting of every day as comprising exactly 86,400 seconds (each of which is itself 1000 milliseconds). An ECMAScript <dfn>time value</dfn> is a Number representing an instant in time with millisecond precision as a signed count of such milliseconds since the epoch, or *NaN* representing no specific instant. Alignment of time values to UTC values (deviating by no more than 1000 milliseconds) is maintained by equating every multiple of 86,400,000 with the start of a UTC day, ignoring leap seconds and the duration variance they entail.</p> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you ignore UTC's leap seconds, then you're not aligning to UTC.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed, but I want to make clear that every UTC day is a fresh start. How would you feel about "approximate alignment to UTC"?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that "equating every multiple of 86,400,000 with the start of a UTC day" does make it clear that every UTC day is a fresh start, but that raises the question of exactly what happens to ES time on a day when UTC has a leap second. Wikipedia indicates that a strictly conforming implementation of POSIX time would have a discontinuity (typically negative) at the end of the leap second. But your phrase "duration variance" suggests instead that each second of ES time on that day is slightly longer (typically) than a UTC (SI) second, so that at the end of the leap second (86,401th SI second), only 86,400 ES seconds have elapsed.
It's possible that TC39 doesn't want to be specific about what happens, but:
- If so, it should maybe explicitly say that the behavior is implemenation-defined.
- It may at least want to specify whether ES time is monotonically increasing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, I think "equating every multiple of 86,400,000 with the start of a UTC day" is a requirement that the current spec does not make, so I'm not sure this change qualifies as editorial.
E.g., I think one possible interpretation of the current spec is that each ES day is exactly 86,400 SI seconds long, so (due to UTC's leap seconds) each ES start-of-day currently occurs 27 seconds before the UTC start-of-day.
Mind you, I wouldn't be surprised if all real implementations do have ES and UTC start-of-day coincide, in which case this might as well be editorial.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, ECMAScript matches POSIX in its use of SI seconds with discontinuities for daily alignment with UTC. Both behaviors can be derived from the abstract operations of 20.3.1 such as TimeWithinDay and MakeDate, but I'm trying to make them explicit in the introduction (though I'm open to ideas on how to do so).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe that assumption is the TC39 consensus, and if so it'd be great to see that documented somewhere
It is not clear to me what consensus you're seeking. The relevant algorithms already require implementations to equate a negative leap second YYYY-MM-DDT23:59:59Z (which is not part of the UTC timeline) as 86_400_000 × n + 86_399_000 where n is an integer, and more importantly require a one-to-one correspondence between every integer in the range [86_400_000 × n, 86_400_000 × (n + 1) − 1] with a distinct YYYY-MM-DDTHH:mm:ss.sssZ (where YYYY-MM-DD is fixed by n) for every integer n in [−100_000_000, 99_999_999].
Note that the second requirement maps the full range of every ECMAScript time value into a distinct UTC value, but leaves no room for positive leap seconds T23:59:60Z—they simply don't exist in the ECMAScript timeline, just as they don't exist in the POSIX timeline.
I'm not sure if that means you think an ES implementation that uses leap smears can be conformant.
What could "uses leap smears" possibly mean in the context of these abstract operations on discrete values? ECMAScript time value 86_400_000 × (n + 1) − 1 is necessarily equated with UTC value YYYY-MM-DDT23:59:59.999Z, whether or not YYYY-MM-DDT23:59:60Z is part of the UTC timeline. An implementation could add functionality to convert between ECMAScript time values or Dates and some other time scale (such as Hebrew, Julian, TAI, or even actual leap-second-inclusive UTC), but that has no bearing on the required behavior of time values and Dates in and of theirselves that I'm addressing here.
What exactly is it that you would have changed in the text of this PR?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is not clear to me what consensus you're seeking.
Yes, I realize that, but I'm not sure I can make it any clearer. I'll try though.
What could "uses leap smears" possibly mean in the context of these abstract operations on discrete values?
That isn't the context in which it means something.
Instead, I'll go way back to "the question of exactly what happens to ES time on a day when UTC has a leap second." Say you call Date.now() every 200 milliseconds for a few seconds around the time that UTC experiences a leap second. What behavior does the ES spec require of a conforming implementation?
- steadily increasing values, each about 200 more than the previous;
- mostly as above, but with one additional jump of 1000 (up or down, depending on the sign of the leap second); or
- implementation-defined/implementation-dependent.
(The first is what I'd expect from an implementation that uses a time source that implements leap smears. The second is supposedly what you'd get from an implementation that uses a time source that implements POSIX.1 time.)
ECMAScript time value 86_400_000 × (n + 1) - 1 is necessarily equated with UTC value YYYY-MM-DDT23:59:59.999Z
It's necessarily mapped to such a date-string, but:
- whether that date-string represents a UTC time is, in the general case, unknown; and
- in the case that it does represent a UTC time, whether the ES time value "is equated to" that UTC time is unclear (I claim).
An implementation could add functionality to convert between ECMAScript time values and [...] actual leap-second-inclusive UTC ...
The latter phrase is telling, in that it acknowledges that the "UTC" that ES time values supposedly convert to is not "actual UTC". If one excludes leap-seconds from UTC, the result is not UTC, and shouldn't be called UTC.
What exactly is it that you would have changed in the text of this PR?
I'd like 20.3.1.1 to say whether there is any required relation between ES time and "external" time, and if so, what. (And then, depending on that, maybe other things.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Say you call Date.now() every 200 milliseconds for a few seconds around the time that UTC experiences a leap second. What behavior does the ES spec require of a conforming implementation?
That question is unrelated to the content of this PR, but i don't believe that the spec requires implementations to even have access to an accurate clock, let alone one with any particular behavior around leap seconds. It only requires Date.now to always return a Number that is a valid time value.
whether the ES time value "is equated to" that UTC time is unclear (I claim).
Date.now
, Date.parse
, Date.UTC
, and the abstract operation UTC(t) all include language like "the time value designating the UTC date and time" and use the abstract operations I've been referencing to convert between time values and ISO 8601 (which is based upon UTC) calendar date and time of day. The intention is clearly to map them directly, even though each timeline includes values that the other lacks (hence the discontinuities). It's exactly the same compromise made by POSIX, and for exactly the same reasons—static deterministic date-time arithmetic without access to a necessarily-dynamic table of leap seconds. That is what I'm trying to convey here.
I'd like 20.3.1.1 to say whether there is any required relation between ES time and "external" time, and if so, what.
Like POSIX time values, ES time values have a piecewise linear relationship with UTC. The specifics of that relationship are detailed in abstract operations, but summarized as an accounting of every UTC day having exactly 86400000 milliseconds. Do you dispute that? Do you believe it is not sufficiently clear in thr proposed text?
I am not covering implementation use of any clock in this PR, but believe that there is no requirement to even have one (e.g., a Date.now
could always return NaN
and still be conforming).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Say you call Date.now() every 200 milliseconds for a few seconds around the time that UTC experiences a leap second. What behavior does the ES spec require of a conforming implementation?
That question is unrelated to the content of this PR,
The blurb for Date.now() says: The *now* function returns a Number value that is the time value designating the UTC date and time of the occurrence of the call to *now*.
So the above question appears to be about how ES time values relate to UTC, and so would seem to be covered by the title of this PR. Which is not to say that this PR is obliged to answer it, just that it's not unreasonable to expect that it would. (And I hope some PR does answer it.)
but i don't believe that the spec requires implementations to even have access to an accurate clock, let alone one with any particular behavior around leap seconds. It only requires Date.now to always return a Number that is a valid time value.
It could be that that's the intent of TC39, but a phrase like the UTC date and time of the occurrence of the call
seems, on the face of it, to require the implementation to have access to an accurate UTC clock (or to a clock that it can convert to an accurate UTC clock). So I think it's a point that could stand some clarification.
whether the ES time value "is equated to" that UTC time is unclear (I claim).
Date.now, Date.parse, Date.UTC, and the abstract operation UTC(t) all include language like "the time value designating the UTC date and time"
-
Date.parse says
it returns a Number, the UTC time value corresponding to the date and time [extracted from the string argument]
, which is clearly a misuse of the term UTC: ES time values are not UTC. (Similarly: algorithm references tothe time value (UTC) identifying the current time
.) -
Date.UTC says (in a Note) that it
interprets the arguments in UTC rather than as local time
. -
UTC(t) says it
converts t from local time to UTC
.
For all of these, I get the impression that "UTC" is only used to mean (roughly) the zero-offset timezone, not the real-world time-scale.
and use the abstract operations I've been referencing to convert between time values and ISO 8601 (which is based upon UTC) calendar date and time of day. The intention is clearly to map them directly, even though each timeline includes values that the other lacks (hence the discontinuities).
In my opinion, the current spec is sufficiently muddled concerning UTC that I can't agree that its intention is clear.
But if this PR makes it clear, that'll be great.
I'd like 20.3.1.1 to say whether there is any required relation between ES time and "external" time, and if so, what.
Like POSIX time values, ES time values have a piecewise linear relationship with UTC.
Sorry, I didn't mean a relation between two time systems, but rather a relation between ES's idea of current time and an external current time. I.e., wording that would answer my question above involving Date.now().
The specifics of that relationship are detailed in abstract operations, but summarized as an accounting of every UTC day having exactly 86400000 milliseconds. Do you dispute that? Do you believe it is not sufficiently clear in thr proposed text?
I think saying "every UTC day having exactly 86400000 milliseconds" would confuse/annoy people who understand leap seconds, but the actual proposed text is better.
However, when the text says An ECMAScript <dfn>time value</dfn> is a Number representing an instant in time with millisecond precision as a signed count of such milliseconds since the epoch
, that implies a time-scale that's monotonic in the real world, which contradicts what you want to convey. So that sentence needs to be toned down.
Note that POSIX says "Seconds Since the Epoch" is merely "a value that approximates the number of seconds that have elapsed since the Epoch" (emphasis mine). (Moreover, it doesn't explicitly tie the Epoch to a particular real-world time-point.)
I am not covering implementation use of any clock in this PR, but believe that there is no requirement to even have one (e.g., a Date.now could always return NaN and still be conforming).
Okay, but in that case, the other text (that doesn't talk about a clock) shouldn't mislead the reader into thinking that an accurate clock is required. (See above re "the UTC date and time of the occurrence of the call".)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Your points about clarifying the requirement (or lack thereof) for implementations to have access clocks with certain characteristics are valid, but out of scope for this PR (which merely attempts to clarify the relationship between ECMAScript time values and points on the UTC timeline).
I have updated the text to define time value as a linear sum of "day number" and "time within the day" rather than a pure count of milliseconds, corresponding with treatment in the immediately following operations. It's certainly more complex than before, but should resolve some misunderstandings. We can tackle requirements relating to "current time" next.
I've been following gibson042/ecma262-proposal-uniform-interchange-date-parsing and after reading this PR exchange I wanted to say thanks to both of you for your hard work 👍 |
@ljharb et al.: This PR appears to have stalled, but I'd really like to see it land. My goal with it is just to clarify the piecewise-discontinuous relationship between ECMAScript time values and the UTC timeline, and I believe that goal has been met (with the changes marked Editorial because that relationship is already inherent in the algorithms of section 20.3, I'm just trying to better express it in prose). @jmdyck seems to agree that I have met that goal, but is also concerned with the relationship between ECMAScript time values and external time on Earth, in particular pertaining to the requirement (or lack thereof) for implementations to have access to clocks with certain characteristics (accuracy being most notable among them). I think those concerns are valid, but out of scope for this PR, since it is limited to abstract rather than physical relationships. So where do we go from here? Should this be tagged "needs consensus" and discussed in plenary? |
@gibson042 sorry for the oversight. if you wouldn't mind rebasing this PR, we'll take a look at it this week. |
a2ce907
to
9b5c4be
Compare
Done. |
…9#1325) - Be more precise about UTC alignment discontinuities - Define time values as linear sums rather than pure counts - Make the distinction between finite and NaN time values more explicit - Clarify that every time value is a Number - Explicitly describe the relationship between time values and leap seconds - Confine time value interpretation to the same day as its referent - Improve grammar
9b5c4be
to
a91a674
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is good. I've made a few minor suggestions.
<p>Time is measured in ECMAScript as milliseconds since midnight at the beginning of 01 January, 1970 UTC. Time in ECMAScript does not observe leap seconds; they are ignored. Time calculations assume each and every day contains exactly <emu-eqn>60 × 60 × 24 × 1000 = 86,400,000</emu-eqn> milliseconds, to align with the POSIX specification of each and every day containing exactly 86,400 seconds.</p> | ||
<p>A Number can exactly represent all integers from -9,007,199,254,740,992 to 9,007,199,254,740,992 (<emu-xref href="#sec-number.min_safe_integer"></emu-xref> and <emu-xref href="#sec-number.max_safe_integer"></emu-xref>). A time value supports a slightly smaller range of exactly -100,000,000 days to 100,000,000 days measured relative to midnight at the beginning of 01 January, 1970 UTC. This yields an exact supported time value range of -8,640,000,000,000,000 to 8,640,000,000,000,000 milliseconds relative to midnight at the beginning of 01 January, 1970 UTC.</p> | ||
<p>Time measurement in ECMAScript is analogous to time measurement in POSIX, in particular sharing definition in terms of the proleptic Gregorian calendar, an epoch of midnight at the beginning of 01 January, 1970 UTC, and an accounting of every day as comprising exactly 86,400 seconds (each of which is 1000 milliseconds long).</p> | ||
<p>An ECMAScript <dfn>time value</dfn> is a Number, either a finite integer representing an instant in time to millisecond precision or *NaN* representing no specific instant. A time value that is a multiple of <emu-eqn>24 × 60 × 60 × 1000 = 86,400,000</emu-eqn> (i.e., is equal to 86,400,000 × _d_ for some integer _d_) represents the instant at the start of the UTC day that follows the epoch by _d_ whole UTC days (preceding the epoch for negative _d_). Every other finite time value _t_ is defined relative to the greatest preceding time value _s_ that is such a multiple, and represents the instant that occurs within the same UTC day as _s_ but follows it by _t_ − _s_ milliseconds.</p> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After "finite integer", maybe insert something like "(within a specific range defined below)", so it's clearer that the range-limitation is part of the definition. (But I agree it's better to define the range separately.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since the more restrictive range limitation only applies to the [[DateValue]] slot rather than to all time values, I'm going to leave this as-is and improve things further with #1564.
spec.html
Outdated
<p>Time measurement in ECMAScript is analogous to time measurement in POSIX, in particular sharing definition in terms of the proleptic Gregorian calendar, an epoch of midnight at the beginning of 01 January, 1970 UTC, and an accounting of every day as comprising exactly 86,400 seconds (each of which is 1000 milliseconds long).</p> | ||
<p>An ECMAScript <dfn>time value</dfn> is a Number, either a finite integer representing an instant in time to millisecond precision or *NaN* representing no specific instant. A time value that is a multiple of <emu-eqn>24 × 60 × 60 × 1000 = 86,400,000</emu-eqn> (i.e., is equal to 86,400,000 × _d_ for some integer _d_) represents the instant at the start of the UTC day that follows the epoch by _d_ whole UTC days (preceding the epoch for negative _d_). Every other finite time value _t_ is defined relative to the greatest preceding time value _s_ that is such a multiple, and represents the instant that occurs within the same UTC day as _s_ but follows it by _t_ − _s_ milliseconds.</p> | ||
<p>Time values do not account for UTC leap seconds—there are no time values representing instants within positive leap seconds, but there are time values representing instants removed from the UTC timeline by negative leap seconds. However, the definition of time values nonetheless yields piecewise alignment with UTC, discontinuities only at leap second boundaries, and zero difference outside of leap seconds.</p> | ||
<p>A Number can exactly represent all integers from -9,007,199,254,740,992 to 9,007,199,254,740,992 (<emu-xref href="#sec-number.min_safe_integer"></emu-xref> and <emu-xref href="#sec-number.max_safe_integer"></emu-xref>). A time value supports a slightly smaller range of -8,640,000,000,000,000 to 8,640,000,000,000,000 milliseconds. This yields a supported time value range of exactly -100,000,000 days to 100,000,000 days relative to midnight at the beginning of 01 January, 1970 UTC.</p> | ||
<p>The exact moment of midnight at the beginning of 01 January, 1970 UTC is represented by the time value *+0*.</p> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would be slightly better to put this para (epoch = *+0*
) right after the para that defines "time value", because it basically follows from the second sentence there. Also, that would bring together the Note and the para that it's talking about.
Also, it might be better in the active voice ("The time value +0 represents..."), since that's how the definition of time value is expressed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll leave this and let #1564 do the rearranging.
…9#1325) - Be more precise about UTC alignment discontinuities - Define time values as linear sums rather than pure counts - Make the distinction between finite and NaN time values more explicit - Clarify that every time value is a Number - Explicitly describe the relationship between time values and leap seconds - Confine time value interpretation to the same day as its referent - Improve grammar - Accept some review suggestions. Thanks @jmdyck!
feee055
to
df54f35
Compare
This should be the last of my editorial Date changes in advance of proposing normative updates for https://github.com/gibson042/ecma262-proposal-uniform-interchange-date-parsing .