This fixes all failing Date.UTC test262 tests, which failed due to not
handling invalid input and evaluating inputs out of order. But this also
avoids using timegm(), which doesn't work on macOS for years before 1900
(they simply return -1 for those years).
Partially addresses #4651. Date.parse.js still fails.
When searching for the locale-specific flexible day period for a given
hour, we were neglecting to handle cases where the period crosses 00:00.
For example, the en locale defines a day period range of [21:00, 06:00).
When given the hour of 05:00, we were checking if (21 <= 5 && 5 < 6),
thus not recognizing that the hour falls in that period.
As noted in the prototype comments, this implementation becomes less
accurate as the precision approaches the limit of 100. For example:
(3).toPrecision(100)
Should result in "3." followed by 99 "0"s. However, due to the loss of
accuracy in the floating point computations, we currently result in
"2.9999999...".
Since years don't have a constant amount of seconds because they can be
leap years no constant will work in all cases. We now test a timezone in
both the positive and negative direction and check that at least one
worked. Assuming years are at least 2 days long this will always pass
at least one test.
Some locales do not define morning, night, etc. day period ranges.
TR-35 states they should fall back to the fixed day periods AM and PM.
Add a test case for the "as" locale, which is one such locale, to ensure
its AM/PM symbols are used.
For the test cases changed here, we now recognize "morning2" and
"afternoon2" from the CLDR, so the expected results now match the specs
and other engines.
There are a few FIXMEs that will need to be addressed, but this
implements most of the prototype method. The FIXMEs are mostly related
to range formatting, which has been entirely ignored so far. But other
than that, the following will need to be addressed:
* Determining flexible day periods must be made locale-aware.
* DST will need to be determined and acted upon.
* Time zones other than UTC and calendars other than Gregorian are
ignored.
* Some of our results differ from other engines as they have some
format patterns we do not. For example, they seem to have a lonely
{dayPeriod} pattern, whereas our closest pattern is
"{hour} {dayPeriod}".
This was an oversight in e42d954743.
These fields should always follow the locale preference in the CLDR.
Overriding these fields would permit formats like "h:mm:ss" to result in
strings like "1:2:3" instead of "1:02:03".
TR-35's Matching Skeleton algorithm dictates how user requests including
fractional second digits should be handled when the CLDR format pattern
does not include that field. When the format pattern contains {second},
but does not contain {fractionalSecondDigits}, generate a second pattern
which appends "{decimal}{fractionalSecondDigits}" to the {second} field.
This is not a calendar supported by ECMA-402, so let's not waste space
with its data.
Further, don't generate "gregorian" as a valid Unicode locale extension
keyword. It's an invalid type identifier, thus cannot be used in locales
such as "en-u-ca-gregorian".
This adds plumbing for the Intl.DateTimeFormat object, constructor, and
prototype.
Note that unlike other Intl objects, the Intl.DateTimeFormat object has
a LibUnicode structure as a base. This is to prevent wild amounts of
code duplication between LibUnicode, Intl.DateTimeFormat, and other
not-yet-defined Intl structures, because there's 12 fields shared
between them.