test262 icon indicating copy to clipboard operation
test262 copied to clipboard

Missing tests forbidding Date.parse output with fractional part

Open gibson042 opened this issue 3 years ago • 4 comments
trafficstars

The algorithm at https://tc39.es/ecma262/multipage/numbers-and-dates.html#sec-date.parse requires returning a time value—"either a finite integral Number representing an instant in time to millisecond precision or NaN representing no specific instant". This should be covered by tests, to avoid violations as seen in JavaScriptCore:

$ eshost -se '
  [
    "1970-01-01T00:00:00.000500001Z",
    "1969-12-31T23:59:59.999515625Z",
    "1969-12-31T23:59:59.999015625Z",
  ]
  .map(str => {
    const tv = Date.parse(str);
    return `${str} => ${(new Date(str)).toISOString()} (${Object.is(tv, -0) ? "-0" : tv} ms from epoch)`;
  })
  .join("\n")
'
#### ChakraCore, engine262, GraalJS, Hermes, SpiderMonkey, V8
1970-01-01T00:00:00.000500001Z => 1970-01-01T00:00:00.000Z (0 ms from epoch)
1969-12-31T23:59:59.999515625Z => 1969-12-31T23:59:59.999Z (-1 ms from epoch)
1969-12-31T23:59:59.999015625Z => 1969-12-31T23:59:59.999Z (-1 ms from epoch)

#### JavaScriptCore
1970-01-01T00:00:00.000500001Z => 1970-01-01T00:00:00.000Z (0.500001 ms from epoch)
1969-12-31T23:59:59.999515625Z => 1970-01-01T00:00:00.000Z (-0.484375 ms from epoch)
1969-12-31T23:59:59.999015625Z => 1970-01-01T00:00:00.000Z (-0.984375 ms from epoch)

#### Moddable XS
1970-01-01T00:00:00.000500001Z => 1970-01-01T00:00:00.001Z (1 ms from epoch)
1969-12-31T23:59:59.999515625Z => 1970-01-01T00:00:00.000Z (0 ms from epoch)
1969-12-31T23:59:59.999015625Z => 1969-12-31T23:59:59.999Z (-1 ms from epoch)

Every engine except JavaScriptCore seems to get this right, and a bug has now been reported there: https://bugs.webkit.org/show_bug.cgi?id=238050

gibson042 avatar Mar 17 '22 22:03 gibson042

I think 0 ms for all three inputs is reasonable since TimeClip is trunc https://tc39.es/ecma262/multipage/numbers-and-dates.html#sec-timeclip

new Date(0.500001).valueOf();  // 0
new Date(-0.484375).valueOf();  // 0
new Date(-0.984375).valueOf();  // 0

Constellation avatar Mar 21 '22 20:03 Constellation

To copy from https://bugs.webkit.org/show_bug.cgi?id=238050#c5 , Date.parse doesn't depend upon TimeClip, and couldn't even use that operation until first parsing a number from input. The above expressions bypass Date.parse, and are instead subject only to the usual treatment of non-integer input in JavaScript where integers are needed. Truncating numbers towards zero is expected, while rounding datetimes towards the start of 1970 is surprising, especially when it results in rollover of coarser unit components due to arithmetic carry (e.g., when input like "1969-…" gets mapped to 1970).

But regardless, https://tc39.es/ecma262/multipage/numbers-and-dates.html#sec-date.parse is underspecified and it is not the proper place of test262 to correct that. Enforcement here should be limited to verifying the absence of fractional data.

gibson042 avatar Mar 23 '22 17:03 gibson042

It looks inconsistent to me. TimeClip is designed to be used only to produce time value. It means that, ECMAScript behaves differently only when passing sub-millisecond epoch double value to Date constructor. If floor behavior is expected for sub-millisecond time values, then I think we should also do so in TimeClip to align to that expectation.

Constellation avatar Mar 23 '22 18:03 Constellation

I responded at https://bugs.webkit.org/show_bug.cgi?id=238050#c7 , but the summary is that the only cases where input to TimeClip can have a nonempty fractional component correspond with source text providing a single number to a date function (Date(nonDateNumberable) and dateInstance.setTime(numberable)), where usual JavaScript conventions for deriving integers from inputs using truncation inside ToNumber are expected. So while I do think the truncation towards zero of e.g. Date(-0.9) is expected and analogous to e.g. "foo".slice(-0.9)==="foo", I don't think it is relevant to the expected behavior of Date.parse(overlyPreciseString), in which the more logical origin to which truncation should be directed is not 1970 but rather the start of time itself (i.e., towards negative infinity).

But with that, I am done with this thread. As I said above, enforcement within test262 should be limited to verifying the absence of fractional data output from Date.parse and should not be opinionated about how overly-precise input is rounded to integer (because that behavior is not specified in ECMA-262).

gibson042 avatar Mar 23 '22 20:03 gibson042