Add comprehensive installation and setup documentation

- Add GETTING_STARTED.md with quick start guide and development modes
- Add INSTALL.sh automated installation script
- Add INSTALLATION_CHECKLIST.md, INSTALLATION_SUCCESS.md, and INSTALLATION_SUMMARY.md
- Add QUICK_REFERENCE.md for common commands
- Add SETUP_GUIDE.md with detailed setup instructions
- Update README.md with improved project overview
- Add did-wallet app dependencies and node_modules
This commit is contained in:
Dorian
2026-01-27 17:18:21 +00:00
parent a81f655133
commit 0d073fa89e
22658 changed files with 4494151 additions and 6 deletions
+386
View File
@@ -0,0 +1,386 @@
# 0.4.4
Breaking changes:
- `Temporal.ZonedDateTime` objects are no longer supported as parameters to `Intl.DateTimeFormat` formatting methods. ([12071fb0], see also [Upstream PR](https://github.com/tc39/proposal-temporal/pull/2479), [Upstream PR 2](https://github.com/tc39/proposal-temporal/pull/2522))
- To format using `Temporal.ZonedDateTime`'s time zone, use `Temporal.ZonedDateTime.prototype.toLocaleString`. This method:
1. Creates a new `Intl.DateTimeFormat` instance in the same time zone and calendar as the `Temporal.ZonedDateTime` instance
1. Creates a `Temporal.Instant` from the `Temporal.ZonedDateTime` instance.
1. Formats that `Temporal.Instant` instance using the created `Intl.DateTimeFormat` instance.
- To format in a time zone that does not match the time zone of the `Temporal.ZonedDateTime` instance:
1. Create a new `Temporal.ZonedDateTime` instance in the right time zone using `Temporal.ZonedDateTime.prototype.withTimeZone`.
- To get the current system time zone, use `Temporal.Now.timeZoneId()`.
Be careful when caching the current system time zone (or an `Intl.DateTimeFormat` instance using that time zone), because the system time zone can change during the lifetime of your program (e.g. when a user on a mobile device crosses a time zone boundary or when a user manually edits time zone settings).
1. Follow the steps above.
- Generally, try to always include the `timeZone` property when creating an `Intl.DateTimeFormat` instance to avoid an ambiguity about which time zone the formatted results will be in.
- `Intl.DateTimeFormat` instances can be expensive to create. For performance-sensitive code where the same calendar and time zone are used repeatedly for formatting, we recommend creating and reusing an `Intl.DateTimeFormat` instance with the desired `timeZone` and `calendar` options, and then formatting using the value of `Temporal.ZonedDateTime.prototype.epochMilliseconds`.
`Intl.DateTimeFormat` instances may also require a lot of RAM, so indefinitely caching large numbers of them is not recommended for memory-constrained environments.
- The `.calendar` property on Temporal types has been replaced with a `.calendarId` property that returns the string calendar identifier and a `.getCalendar()` method that returns an object that implements `Temporal.CalendarProtocol`.
- `getCalendar()` will always return a new object if the containing instance was constructed using a built-in calendar identifier string. However, if the containing instance was constructed using a calendar object (either a built-in calendar or custom calendar), then the same object is returned. ([cc701b45], see also [Upstream issue](https://github.com/tc39/proposal-temporal/issues/1808))
- Temporal will compare calendars by testing for string equality between calendar identifiers.
When a calendar is an object, its `id` property will be used for comparison. ([3916e547], see also [Upstream issue](https://github.com/tc39/proposal-temporal/issues/1808))
- The `.calendar` property has been entirely removed from `Temporal.PlainTime`. ([0727d86e], see also [Issue 1](https://github.com/tc39/proposal-temporal/issues/1808), [Issue 2](https://github.com/tc39/proposal-temporal/issues/1588))
- The `.timeZone` property on `Temporal.ZonedDateTime` has been replaced with a `.timeZoneId` property that returns the string time zone identifier and a `.getTimeZone()` method that returns an object that implements `Temporal.TimeZoneProtocol`. ([d3263f0], see also Upstream issue)
- `getTimeZone()` will always return a new object if the `Temporal.ZonedDateTime` instance was constructed using a built-in time zone identifier string.
However, if the instance was constructed using a time zone object (either a built-in time zone or custom time zone), then the same object is returned.
- `Termporal.Now.timeZone()` is replaced by `Temporal.Now.timeZoneId()`, which returns a time zone identifier string, not a `Temporal.TimeZone` instance. ([600f0cc7], see also [Upstream issue](https://github.com/tc39/proposal-temporal/issues/1808))
- Temporal will compare time zones by testing for string equality between calendar identifiers.
When a calendar is an object, its `id` property will be used for comparison. ([d6cb2862], see also [Upstream issue](https://github.com/tc39/proposal-temporal/issues/1808))
- Require the `id` property and make overriding `toString` optional (but recommended!) for `Temporal.TimeZoneProtocol`. ([97637bbc])
- Remove support for nested time zone and calendar property bags. ([9b7f61ae], [0c38267b], see also [Discussion](https://github.com/tc39/proposal-temporal/issues/2104#issuecomment-140))
- Require the remainder returned by the `NanosecondsToDays` internal operation to be less than the length of one calendar day.
This could happen due to shenanigans in a custom time zone's `getOffsetNanosecondsFor` or `getPossibleInstantsFor` methods, or a custom calendar's `dateAdd` method.
([44b00a38], see also [Upstream issue](https://github.com/tc39/proposal-temporal/issues/2357)
- Set an upper limit of 1e9 on rounding increments. ([5d78c815])
- Require `fields` and `mergeFields` methods for `Temporal.CalendarProtocol` (custom calendar) objects. ([5ad63274])
- Reject Z designators when parsing `Temporal.PlainTime` strings.
Bug fixes:
- Read field identifiers from a calendar's `fields()` method during `dateFromFields()`, `yearMonthFromFields()`, and `monthDayFromFields()`.
Previously, these methods only referenced hardcoded `'era'` and `'eraYear'` field identifiers. ([375a4ad9])
- Avoid precision loss in AddDuration operations. ([c0f7349a])
- Fix an infinite-loop bug and a RangeError during non-ISO calendar calculations. ([d94c1cd9], see also [proposal-temporal PR](https://github.com/tc39/proposal-temporal/pull/2539), [Issue 1](https://github.com/tc39/proposal-temporal/issues/2383), [Issue 2](https://github.com/tc39/proposal-temporal/issues/2537))
- Avoid rounding errors in `BalanceTime` operations. ([9260a8a0])
- Avoid precision loss in `NanosecondsToDays` operations. ([e02f0626])
- Require that results from `NanosecondsToDays` calls don't flip sign. ([0b238ccf])
- Fix bugs introduced while restricting the creation of `Temporal.Duration` using non-numeric inputs. ([46c4132d], see also [Upstream issue](https://github.com/tc39/proposal-temporal/issues/2112))
- Fix bugs when passing fractional numbers to `CreateTemporalDuration`. ([856a5460], see also [Upstream issue](https://github.com/tc39/proposal-temporal/issues/2246))
- Always return a Number of nanoseconds from `RoundDuration`. ([8d3c1f1b])
- Use BigInt math in `RoundDuration` to avoid problems when the values are larger than `Number.MAX_SAFE_INTEGER`. ([955323f8])
- Always start at the end of 1972 when computing a `Temporal.PlainMonthDay` from fields, preventing the reference year from accidentally being in 1971. ([ef4a0c4b])
- Apply the overflow behaviour to year/month/day values in `monthDayFromFields`. ([7ebd0f96])
- Preserve the day of month when constraining a nonexistent leap month, instead of defaulting to the end of the closest corresponding regular month. ([996f8fa1])
- Allow month codes `'M01L'` and `'M12L'` in the Chinese calendar. ([696f2c7e])
- Avoid overflows in `GetNamedTimeZoneOffsetNanoseconds`. ([c42570b8])
- Fix calendar validation in various ToTemporal\_\_\_ operations. ([e3913974], see also [Upstream issue](https://github.com/tc39/proposal-temporal/issues/2546))
- Don't call `GetMethod` on a string calendar. ([fe698d8d], see also [Upstream issue](https://github.com/tc39/proposal-temporal/pull/2547))
- Avoid rounding errors in `BalanceDurationRelative` and `UnbalanceDurationRelative`. ([a907acf0])
- Check for negative day length in `Temporal.ZonedDateTime.prototype.round`. ([0d2d60ec], see also [Spec PR](https://github.com/tc39/proposal-temporal/pull/2261))
This change avoids a common bug where a UTC timestamp is accidentally interpreted as if it were a local time in a real time zone.
If you do want to parse the time portion of a UTC timestamp string, use: `Temporal.Instant.from(s).toZonedDateTimeISO('UTC').toPlainTime()`. ([a7a50eac])
- Reject 0-value components when parsing `Temporal.Duration` strings, and avoid rounding errors when nanoseconds components are present. ([58b5601a])
- Reject `relativeTo` string options that are neither valid `Temporal.PlainDate` nor `Temporal.ZonedDateTime` strings, such as `'2022-08-18T17:01Z'`. ([4db15c41])
- Add validation for the return values from calendar operations. ([d88cfa4d])
- Validate required methods of `Temporal.TimeZoneProtocol` and `Temporal.CalendarProtocol`. ([84563cea], [755c7620], see also [Discussion](https://github.com/tc39/proposal-temporal/issues/2104#issuecomment-140))
- Throw earlier when users might mix up positional `Temporal.TimeZone` and `Temporal.Calendar` arguments with each other, to prevent bugs like `new Temporal.ZonedDateTime(0n, cal, tz)` where the switched calendar and time zone arguments would cause exceptions to be thrown later. ([7922f1f9])
Non-breaking changes:
- Implement `yearOfWeek` methods that complement existing `weekOfYear` methods.
The new method returns the year associated with `weekOfYear`, which may (see https://en.wikipedia.org/wiki/ISO_week_date) vary from `year` in some calendars like `'iso8601'`.
This new method can be useful for formatting IS0 8601 strings using the year-week-day format like `1981-W53-7`. ([bf08ca56])
- Support new Internet Extended Date-Time (IXDTF) Annotations
- See the [Temporal + IXDTF tracking issue](https://github.com/tc39/proposal-temporal/issues/1450).
- Align ISO 8601 grammar with annotations from IXDTF specification.
Calendar and time zone annotations are now allowed to contain a "critical" flag (`'!'`) prefix.
Critical flags have no effect when parsing input strings because Temporal already treats unknown or inconsistent inputs as errors by default. ([e8b2e71c])
- There can be multiple types of annotations in an IXDTF string.
Temporal only recognizes time zone and calendar annotations.
Unrecognized non-critical annotations will be ignored.
Unrecognized critical annotations will cause the parsing method to throw an exception.
- Allow `toString()` methods for `Temporal.PlainDate`, `Temporal.PlainDateTime`, `Temporal.PlainYearMonth`, `Temporal.PlainMonthDay`, and `Temporal.ZonedDateTime` to emit critical IXDTF annotations using the `'critical'` option.
Use this option with care, because the platform that you're communicating with may not understand this syntax.
`calendarName: 'critical'` behaves like `calendarName: 'always'` and `timeZoneName: 'critical'` behaves like `timeZoneName: 'always'`, but they also output a `'!'` prefix in the corresponding annotation. ([50a64f16])
Critical flags are never used by Temporal, but could be consumed by other programs.
- Ignore calendar annotations when parsing `Temporal.Instant` strings. ([b86b87f0])
- Allow calendar and/or time zone annotations after strings without a time part: YYYY-MM-DD, YYYY-MM, and MM-DD. ([acd6464f])
- Disallow UTC offsets in YYYY-MM and MM-DD strings because they could cause ambiguity between an offset and the day of a YYYY-MM-DD string. ([acd6464f])
- Reject ambiguous time strings even with calendar annotations. ([af875275])
- Implement the full set of rounding modes.
New modes include `'expand'`, `'halfCeil'`, `'halfFloor'`, `'halfTrunc'`, and `'halfEven'`.
([eb5404d1])
- Treat calendar names as case-insensitive. ([9e730d68])
- Improve cross-binary compatibility of polyfill objects by storing internals on `globalThis`. ([73a0bf36], see also [GitHub Issue](https://github.com/js-temporal/temporal-polyfill/issues/164))
- Allow various `Temporal.Calendar` methods to return 0. ([8a49023b])
- Improve error messages when converting fields to a `Temporal.PlainMonthDay`. ([e1cd4170])
- Round towards the Big Bang in epoch time getters. ([6d124a56], see also [Upstream issue](https://github.com/tc39/proposal-temporal/issues/2423), [Spec change](https://github.com/tc39/proposal-temporal/issues/2424))
- Improve performance when operating on large numbers in `BalanceISODate`. ([d2a23dd5])
- Optimize `Temporal.TimeZone.prototype.getNextTransition()` for dates that predate 1847, which is the earliest data in the IANA time zone database. ([9591af3b])
- Improve performance when out-of-range finding transition points for named time zones. ([3b61abfe])
- Special-case zones with precomputed DST transition points in `GetPreviousTransition`. ([5922bdf1])
Other:
- Bump required dependency versions. ([c65455a5])
- Fix sourcemaps so they point directly to TS source files. ([6b462d49], see also [GitHub PR](https://github.com/js-temporal/temporal-polyfill/pull/194))
# 0.4.3
Bug fixes:
- Fix an off-by-one error when dates in the Hebrew calendar were created using
`monthCode`, the year was a leap year, and the month was after the leap
month ([f3d0ca9f])
- Fix addition of months and years for lunisolar calendars ([4f8b04c1])
- Fix the ISO8601 representation of years between 1 BCE and 999 BCE ([b251dc0e]).
- Fix a bug causing time to appear to go backwards for a small number of
milliseconds ([bb59ca97])
- Always validate ISO8601 time components as well as date components
([34662a05])
- Fix comparison of dates that might have a differing number of hours in their
respective days ([a4c60241])
- Include calendar reference information when `calendarName='always'` is passed
to various Temporal toString method's options bags ([54fcc4f3])
- Fix a nonconformant use of the `relativeTo` property bag ([9992f9b1])
- Fix ZonedDateTime.prototype.withPlainTime(null) to throw a TypeError, instead
of treating it as midnight ([ec2b0546])
- Fix parsing of some valid Instant strings when they would be out of range
before considering the UTC offset ([d9de9e74])
- Bail out early in non-ISO calendar implementations to avoid an infinte loop
when calculating the duration between two identical dates. ([6f3c42c9])
- Fix type resolution when using TypeScript Node16 and transpiling to CJS ([9bab0eb5], see
also the [relevant TypeScript issue](https://github.com/microsoft/TypeScript/issues/49160))
Non-breaking changes:
- Consistently call observable operations with undefined options arguments,
instead of empty objects ([297b8f38])
# 0.4.2
This version is a patch version enabling TypeScript Node16 support for this
package.
Bug Fixes:
- Add types to exports/./import to support Typescript Node16 ([304c86dd])
# 0.4.1
This version is a patch version enabling polyfill compatibility with Safari
versions <15.1 (October 2021 and earlier).
Bug fixes:
- Remove erroneous options from Safari's Intl.DateTimeFormat resolvedOptions
bag. The underlying bug in Safari was fixed in Safari 15.1.
# 0.4.0
This version roughly corresponds with all the changes made to the Temporal polyfill as of the January 2022 TC39 Plenary meeting.
Breaking changes:
- Use JSBI instead of big-integer for Big Integer math operations. If your codebase does not need to polyfill BigInt, consider using [the JSBI Babel plugin](https://github.com/GoogleChromeLabs/babel-plugin-transform-jsbi-to-bigint) to transpile these operations to native BigInt.
- Reject plain date-only strings ([b733c213], see also [Spec PR](https://github.com/tc39/proposal-temporal/pull/1952), [proposal-temporal polyfill PR](https://github.com/tc39/proposal-temporal/pull/1986))
- Reject '-000000' as an extended year value ([670cda6b], see also [Spec PR](https://github.com/tc39/proposal-temporal/pull/1992))
- Add missing branding checks for Calendar and Timezone classes to match spec changes ([670cda6b], see also [Spec PR](https://github.com/tc39/proposal-temporal/pull/1995))
Bug fixes:
- Temporal class prototypes are no longer writeable ([871d28dc], see also [proposal-temporal polyfill PR](https://github.com/tc39/proposal-temporal/pull/1974))
- Throw a RangeError for invalid offset strings ([d5ada8b0], see also [proposal-temporal polyfill PR](https://github.com/tc39/proposal-temporal/pull/1976))
- Pad fractional second values correctly in Duration.prototype.toString() ([e046ccdf], see also [Spec PR](https://github.com/tc39/proposal-temporal/pull/1956))
- Support the numberless output of Hebrew months from Intl.DateTimeFormat ([b06ac47f], see also [proposal-temporal polyfill PR](https://github.com/tc39/proposal-temporal/pull/2034))
- Workaround FireFox bug with Gregory era names ([30c4d4d8], see also [proposal-temporal polyfill PR](https://github.com/tc39/proposal-temporal/pull/2033))
Non-breaking changes:
- Rename public ...FromFields types ([3554d7f1])
- Add validation for hard-coded Era data in Calendar.ts ([08e84c9f])
- Improve code in Calendar.ts to handle calendar with a constant era but a variable number of months in a year ([ef8c588b])
- Add an optional calendar to PlainTime, PlainDateTime, and PlainMonthDay ([f8837367], see also [Spec PR](https://github.com/tc39/proposal-temporal/pull/1950))
- Only require a year in Gregorian calendar implementations, not a full date ([02aec1c3])
- Include `valueOf` in the Temporal.Duration type ([b1dd7eb3])
- Expand the types allowed to be used as TimezoneLike and CalendarLike to match the spec ([9d54c646])
- Improve worse-case performance when finding Timezone transition points by over 1000X! ([e70d6324])
- Change Calendar.fields to return an `Array`, not an `Iterable` ([3145c6c4], see also [Spec PR](https://github.com/tc39/proposal-temporal/pull/2056))
Other:
- Update build dependencies ([500b4c97])
- Run tests against Node 17 on CI ([db63e22a])
# 0.3.0
This version roughly corresponds with all the changes made to the Temporal polyfill as of the October 2021 TC39 Plenary meeting.
Breaking changes:
- Timezones now require a `getOffsetNanosecondsFor` method, and no longer fall back to the intrinsic definition (previously provided by `Temporal.Timezone#getOffsetNanosecondsFor`) if not provided. ([08346dc5], see also [proposal-temporal polyfill PR](https://github.com/tc39/proposal-temporal/pull/1929))
- Disallow Z designators when parsing strings for Plain Temporal types ([f3f8a994], see also [Spec PR](https://github.com/tc39/proposal-temporal/pull/1874))
- Allow ISO strings with "Z" + a bracketed IANA name ([70bd9898], see also [Spec PR](https://github.com/tc39/proposal-temporal/pull/1749))
- Emit ES2020 builds for newer browsers, and emit ES5 for older browsers. ([2331468d], [9e95c62b])
- Temporal.Duration constructor will now throw if given a non-integer ([9df5d068], see also [Spec PR](https://github.com/tc39/proposal-temporal/pull/1872))
- Remove support for sub-minute offsets in ISO strings ([766e5037], see also [Spec PR](https://github.com/tc39/proposal-temporal/pull/1871), [Spec PR](https://github.com/tc39/proposal-temporal/pull/1862))
- Throw TypeError on missing options from Duration.total ([4ec075f0], see also [Spec PR](https://github.com/tc39/proposal-temporal/pull/1720))
- Reject non-integer Duration fields in Duration.with() ([e6b2488d], see also [Spec PR](https://github.com/tc39/proposal-temporal/pull/1735))
- Ensure an Object is returned from calendar.mergeFields() ([4e63f25f], see also [Spec PR](https://github.com/tc39/proposal-temporal/pull/1719))
Bug fixes:
- Fix GetFormatterParts for Firefox Nightly ([47f9132f])
- Fix TS types of RoundTo and TotalOf ([3008a670])
- Fix crash setting `day` outside current JPN era ([6d3588c3], see also [proposal-temporal polyfill PR](https://github.com/tc39/proposal-temporal/pull/1807))
- Copy options object for PlainYearMonth.{add,subtract} and InterpretTemporalDateTimeFields to prevent user-modified objects from interfering with later operations. ([bafa1bdf], see also [Spec PR](https://github.com/tc39/proposal-temporal/pull/1748))
- Validate input to Calendar.prototype.fields ([7ebc700e], see also [Spec PR](https://github.com/tc39/proposal-temporal/pull/1750))
- Stop observably calling into `getPossibleInstantsFor` in `InterpretISODateTimeOffset` ([5448e59f], see also [Spec PR](https://github.com/tc39/proposal-temporal/pull/1688))
- Call `CalendarEquals` correctly ([07ea694e], see also [proposal-temporal polyfill PR](https://github.com/tc39/proposal-temporal/pull/1858))
- Fix arithmetic issues when using non-ISO months ([079a3325], see also [proposal-temporal polyfill PR](https://github.com/tc39/proposal-temporal/pull/1761))
- Regex: tighten matching of month and day values in datesplit ([b5736546], see also [proposal-temporal polyfill PR](https://github.com/tc39/proposal-temporal/pull/1836))
- Fix TS types for required CalendarProtocol methods ([0ee4581f], see also [proposal-temporal polyfill PR](https://github.com/tc39/proposal-temporal/pull/1964))
Non-breaking changes:
- Various `#round` and `#total` methods now accept string parameters or options bags. Strings are interpreted as the `smallestUnit` option (or `unit` for `Temporal.Duration#total`). ([068e801f], see also [Spec PR](https://github.com/tc39/proposal-temporal/pull/1875))
- Add @@toStringTag to TS types ([41ab6bc0])
- Accept string Calendar names in PlainMonthDay and PlainYearMonth constructors ([27b4c7e8])
- Make options optional in Calendar method TS types ([3a09d00d])
- Align implementation of RoundDuration with adjusted spec text ([4a0d0264], see also [Spec PR](https://github.com/tc39/proposal-temporal/pull/1968/files))
Other:
- Bump various dependencies ([47701107], [f5427de9], [310d9d8b])
- Allow launching and debugging tests (both Demitasse and Test262 suites) from the VSCode debug panel ([960d9b76], [7f7c19a1], [4ec6568e], [edcc668b])
- Run the Test262 test suite against this polyfill, for various configurations of the resulting build artifact ([2331468d], [666c69da], [429273ec], [ff937782], [f885253f])
- Remove various pieces of unused code, and add CI testing to detect unused code in PR review ([67f9f6bb], [63bdfcd1])
- Drop the dependency on es-abstract ([d24575f2], [ad7e2e3a], [5b1bc5e2])
- The polyfill's source was ported to TypeScript ([12e4d529], [ac78fd9d], [53f32e0f], [06b806c9], [66fdc765], [50b1c34b], [4724b017], [947a8a5e], [fdbf7e01], [fa60af6a], [da753f2f], [f4db8b0b], [4a38420d])
- Document the release process for this polyfill ([c55818b6])
[12071fb0]: https://github.com/js-temporal/temporal-polyfill/commit/12071fb08903bdf8f73bae4b628ca91e469e8085
[cc701b45]: https://github.com/js-temporal/temporal-polyfill/commit/cc701b45afc2438f76cbbafe30c29a4485ad556c
[3916e547]: https://github.com/js-temporal/temporal-polyfill/commit/3916e547fa33eed8342f7845146135aae30696fd
[0727d86e]: https://github.com/js-temporal/temporal-polyfill/commit/0727d86ec364749f36cb7e5fb53f10db9b404da2
[600f0cc7]: https://github.com/js-temporal/temporal-polyfill/commit/600f0cc7cdd540bb55d738ed7c934bb7a7e01e17
[d6cb2862]: https://github.com/js-temporal/temporal-polyfill/commit/d6cb2862d624580f6210d849bdd424f3e9cebb4d
[97637bbc]: https://github.com/js-temporal/temporal-polyfill/commit/97637bbc3d7d1546ea67586534efc87b84c12359
[9b7f61ae]: https://github.com/js-temporal/temporal-polyfill/commit/9b7f61ae616c512df3c681d00cd59f86718d6a02
[0c38267b]: https://github.com/js-temporal/temporal-polyfill/commit/0c38267bfe56b5215ddaa14765a6a77275285569
[44b00a38]: https://github.com/js-temporal/temporal-polyfill/commit/44b00a38525a0e9607856d64909475c083476999
[5d78c815]: https://github.com/js-temporal/temporal-polyfill/commit/5d78c815bb561218c262714a6becc879cc9d66af
[5ad63274]: https://github.com/js-temporal/temporal-polyfill/commit/5ad63274fed03f9606bb827a5ccb49fcbfe33d3e
[375a4ad9]: https://github.com/js-temporal/temporal-polyfill/commit/375a4ad9bd527e002a0aa499b09c539ad8ded35b
[c0f7349a]: https://github.com/js-temporal/temporal-polyfill/commit/c0f7349a327b68543797d38e045b1fd8c1e0949b
[d94c1cd9]: https://github.com/js-temporal/temporal-polyfill/commit/d94c1cd9a853a6c9cd1212de9db46d4c4b695957
[9260a8a0]: https://github.com/js-temporal/temporal-polyfill/commit/9260a8a0f58db2c4606a09ae54b711f0c4a1d892
[e02f0626]: https://github.com/js-temporal/temporal-polyfill/commit/e02f0626ce89945c791ad4443f502738e0de3779
[0b238ccf]: https://github.com/js-temporal/temporal-polyfill/commit/0b238ccf338cd9b185d4df87433d7f65debc6347
[46c4132d]: https://github.com/js-temporal/temporal-polyfill/commit/46c4132d4cdcb923ec09eb0674873ce0a875fdd8
[856a5460]: https://github.com/js-temporal/temporal-polyfill/commit/856a54605b542a7d049bc1da58dee570367d7c6a
[8d3c1f1b]: https://github.com/js-temporal/temporal-polyfill/commit/8d3c1f1bd2533e69ef42368e8dbd4a097433dfbb
[955323f8]: https://github.com/js-temporal/temporal-polyfill/commit/955323f8e863f18c6691427bb1c3bbfc7c6a1403
[ef4a0c4b]: https://github.com/js-temporal/temporal-polyfill/commit/ef4a0c4bc143f3c8b28a19aec2a6ea5e588f4b9c
[7ebd0f96]: https://github.com/js-temporal/temporal-polyfill/commit/7ebd0f962589fe9885f7eaa35fd0a001a5075499
[996f8fa1]: https://github.com/js-temporal/temporal-polyfill/commit/996f8fa1084175f7c6fa11af393f5974d3364f26
[696f2c7e]: https://github.com/js-temporal/temporal-polyfill/commit/696f2c7eb1c37b6fe4a4696fbe6073e182cfa4a4
[c42570b8]: https://github.com/js-temporal/temporal-polyfill/commit/c42570b8aee0482e84f061afd75379c03cd11c8e
[e3913974]: https://github.com/js-temporal/temporal-polyfill/commit/e39139743a43a6fb5702036fa7e2989f8a91ad02
[fe698d8d]: https://github.com/js-temporal/temporal-polyfill/commit/fe698d8d9357633520e3b22c5a48d84db84bb400
[a907acf0]: https://github.com/js-temporal/temporal-polyfill/commit/a907acf0031e3ce80a3e9b2897240a61b6c34b23
[0d2d60ec]: https://github.com/js-temporal/temporal-polyfill/commit/0d2d60eca7a0293a4c3c4e4741e1674a2d24c7f7
[a7a50eac]: https://github.com/js-temporal/temporal-polyfill/commit/a7a50eac6d0413b8b222d8cecef00dcc949a58b7
[58b5601a]: https://github.com/js-temporal/temporal-polyfill/commit/58b5601a921296754c402aaf01c81fcf5418235b
[4db15c41]: https://github.com/js-temporal/temporal-polyfill/commit/4db15c41bde82f14416daf9a1990d4e82b4104af
[d88cfa4d]: https://github.com/js-temporal/temporal-polyfill/commit/d88cfa4d4968dde600f0a99fe79496d65109589f
[84563cea]: https://github.com/js-temporal/temporal-polyfill/commit/84563cea6f1b380ea6dd8366bab65023756161c2
[755c7620]: https://github.com/js-temporal/temporal-polyfill/commit/755c762014b196c8c3ff16325bc8a6df836ec69e
[7922f1f9]: https://github.com/js-temporal/temporal-polyfill/commit/7922f1f9f4eb154573f695d19f980d66401e4d82
[e8b2e71c]: https://github.com/js-temporal/temporal-polyfill/commit/e8b2e71c8c558a849b487f43785e46337ef3e837
[50a64f16]: https://github.com/js-temporal/temporal-polyfill/commit/50a64f163cb3abefdf7ef956c10f0197f4e46faf
[b86b87f0]: https://github.com/js-temporal/temporal-polyfill/commit/b86b87f048937caee6d00243af69eb6604d853f0
[acd6464f]: https://github.com/js-temporal/temporal-polyfill/commit/acd6464fac951c13cd1f0ad268c2d485be76b872
[af875275]: https://github.com/js-temporal/temporal-polyfill/commit/af875275902e18eb6a230c5f5541ed9c286eb955
[eb5404d1]: https://github.com/js-temporal/temporal-polyfill/commit/eb5404d182a94574c4aa183fcbf6907c54874657
[9e730d68]: https://github.com/js-temporal/temporal-polyfill/commit/9e730d68ef2e7d2bf9a568a67ac1f22aa91a1d6d
[bf08ca56]: https://github.com/js-temporal/temporal-polyfill/commit/bf08ca5606a9392635e70cd888f5686f6ecf4aa0
[73a0bf36]: https://github.com/js-temporal/temporal-polyfill/commit/73a0bf36b6d8aa4feb31d91c14688ca43c5822db
[8a49023b]: https://github.com/js-temporal/temporal-polyfill/commit/8a49023b1b8857c01aadbe71dc8d53481dd4c10b
[e1cd4170]: https://github.com/js-temporal/temporal-polyfill/commit/e1cd4170f12da0790faf3adcb99848e6cb6789c4
[6d124a56]: https://github.com/js-temporal/temporal-polyfill/commit/6d124a5676f608f3ff6b971588325ae134ff507b
[d2a23dd5]: https://github.com/js-temporal/temporal-polyfill/commit/d2a23dd500d97b37364d0e655d2408a88a35d424
[9591af3b]: https://github.com/js-temporal/temporal-polyfill/commit/9591af3b160b5db53d3d56fe60bc59aaf023eec1
[3b61abfe]: https://github.com/js-temporal/temporal-polyfill/commit/3b61abfee69a0c41dee334e901c43fb6829108b6
[5922bdf1]: https://github.com/js-temporal/temporal-polyfill/commit/5922bdf16c1af1209020ab20f60d5f525308e16d
[c65455a5]: https://github.com/js-temporal/temporal-polyfill/commit/c65455a531bdeceedca1aaa0372747263b799942
[6b462d49]: https://github.com/js-temporal/temporal-polyfill/commit/6b462d498634f3641bd5fdafe894b536413aa3bb
[f3d0ca9f]: https://github.com/js-temporal/temporal-polyfill/commit/f3d0ca9f2f32beb071a7d25c9732bd38784b3e6d
[4f8b04c1]: https://github.com/js-temporal/temporal-polyfill/commit/4f8b04c1caba0360a527cbe8c8d95e2a8642ab6e
[b251dc0e]: https://github.com/js-temporal/temporal-polyfill/commit/b251dc0ef48cd7b2edee2f6541ce0cfb6d019e08
[bb59ca97]: https://github.com/js-temporal/temporal-polyfill/commit/bb59ca970b1c0cb70bdafd2896814076c11edd07
[34662a05]: https://github.com/js-temporal/temporal-polyfill/commit/34662a05cfe50e17a02356cbc55ff0ca2365e888
[a4c60241]: https://github.com/js-temporal/temporal-polyfill/commit/a4c602410bb5b711683918cd414568e19c594499
[54fcc4f3]: https://github.com/js-temporal/temporal-polyfill/commit/54fcc4f34b6ce87d15d3df9359bb538766c562ef
[9992f9b1]: https://github.com/js-temporal/temporal-polyfill/commit/9992f9b1137ff52cc427bc0c96504dca387d267b
[ec2b0546]: https://github.com/js-temporal/temporal-polyfill/commit/ec2b0546dd68718c6645713512753570eccf0ba6
[d9de9e74]: https://github.com/js-temporal/temporal-polyfill/commit/d9de9e74d0cba630b3480b31964362f82c435992
[6f3c42c9]: https://github.com/js-temporal/temporal-polyfill/commit/6f3c42c90460fa0917e228b5724d7b462c052fd8
[9bab0eb5]: https://github.com/js-temporal/temporal-polyfill/commit/9bab0eb586a8db13081a51e81fd0f6f2518d041a
[297b8f38]: https://github.com/js-temporal/temporal-polyfill/commit/297b8f385e5a146ad9c97ce3a9865a654999a713
[304c86dd]: https://github.com/js-temporal/temporal-polyfill/commit/304c86dd61e7107095ed42149e85d919e3a6cac8
[b733c213]: https://github.com/js-temporal/temporal-polyfill/commit/b733c213cba462f79eb9ee3a084661ea5344d9ea
[670cda6b]: https://github.com/js-temporal/temporal-polyfill/commit/670cda6bd269db66c8ce97eb73f941b20abb92ec
[670cda6b]: https://github.com/js-temporal/temporal-polyfill/commit/670cda6bd269db66c8ce97eb73f941b20abb92ec
[871d28dc]: https://github.com/js-temporal/temporal-polyfill/commit/871d28dc16674b650bd2161e168bae4549ec2bd2
[d5ada8b0]: https://github.com/js-temporal/temporal-polyfill/commit/d5ada8b01f6ebc96cac46b6fda888ee6fc64e457
[e046ccdf]: https://github.com/js-temporal/temporal-polyfill/commit/e046ccdfd5ff4a2f048195894e279aefc64e565c
[b06ac47f]: https://github.com/js-temporal/temporal-polyfill/commit/b06ac47f2d580f7079f13b4f82a90ebce2e469bb
[30c4d4d8]: https://github.com/js-temporal/temporal-polyfill/commit/30c4d4d8584267989423cb09124ea175e08e9c04
[3554d7f1]: https://github.com/js-temporal/temporal-polyfill/commit/3554d7f119d275749507dc0943f9b0823a0a3dd2
[08e84c9f]: https://github.com/js-temporal/temporal-polyfill/commit/08e84c9f2478dc9e62bbe43737bacba762dbc9f7
[ef8c588b]: https://github.com/js-temporal/temporal-polyfill/commit/ef8c588bc54204d584ff5f3f582f9075e7e1abf7
[f8837367]: https://github.com/js-temporal/temporal-polyfill/commit/f88373671662b5d108311804c26f56df8df2f32c
[02aec1c3]: https://github.com/js-temporal/temporal-polyfill/commit/02aec1c319b9081e394232ec264d515549ed2a51
[b1dd7eb3]: https://github.com/js-temporal/temporal-polyfill/commit/b1dd7eb348d001008240102a154e94eb141f8d7d
[9d54c646]: https://github.com/js-temporal/temporal-polyfill/commit/9d54c6464b31a71b9f28d94cc8cfae60c5765067
[e70d6324]: https://github.com/js-temporal/temporal-polyfill/commit/e70d6324b876888c5b46e46523e1a3ef47a067ba
[3145c6c4]: https://github.com/js-temporal/temporal-polyfill/commit/3145c6c411a36e69985419a84d4bbf9a573383c0
[500b4c97]: https://github.com/js-temporal/temporal-polyfill/commit/500b4c97e05b225472ae61007da579a7548bfb78
[db63e22a]: https://github.com/js-temporal/temporal-polyfill/commit/db63e22a238c3546d8c1082847ae6a19c7bc9570
[08346dc5]: https://github.com/js-temporal/temporal-polyfill/commit/08346dc5bc809e7575eacde3200f9775fe19c378
[f3f8a994]: https://github.com/js-temporal/temporal-polyfill/commit/f3f8a994c05603ddf1f4ebad09f191a8e847566e
[70bd9898]: https://github.com/js-temporal/temporal-polyfill/commit/70bd98989d79da847c479b1a3ff05a6a4dc045b2
[2331468d]: https://github.com/js-temporal/temporal-polyfill/commit/2331468dc809b1abefab5d3c6d0901baf298f9fa
[9e95c62b]: https://github.com/js-temporal/temporal-polyfill/commit/9e95c62b4346f89b79a8be66a8767bf120230cf8
[9df5d068]: https://github.com/js-temporal/temporal-polyfill/commit/9df5d068165cce79cbdf5b047674e4156a3acb28
[766e5037]: https://github.com/js-temporal/temporal-polyfill/commit/766e5037a7943ed30f4e7d106bd74fb68509008e
[4ec075f0]: https://github.com/js-temporal/temporal-polyfill/commit/4ec075f0b8d3e58cc1a6632157696dc76901835a
[e6b2488d]: https://github.com/js-temporal/temporal-polyfill/commit/e6b2488d668c72e73f2d0052439bca4eca48536c
[4e63f25f]: https://github.com/js-temporal/temporal-polyfill/commit/4e63f25f4adcb3230ae18d75aca878eadff7ab91
[47f9132f]: https://github.com/js-temporal/temporal-polyfill/commit/47f9132f1c56658e40bb1f268a9ac542a897a9ca
[3008a670]: https://github.com/js-temporal/temporal-polyfill/commit/3008a670b3758abe1b2341d54da4217b251bc234
[6d3588c3]: https://github.com/js-temporal/temporal-polyfill/commit/6d3588c33fec99d18c403229cff19375a7726dea
[bafa1bdf]: https://github.com/js-temporal/temporal-polyfill/commit/bafa1bdf2dbfc28513d7e39b0c0d1c3d075d9db5
[7ebc700e]: https://github.com/js-temporal/temporal-polyfill/commit/7ebc700ea92d660f42b6397f7e400122630c2e76
[5448e59f]: https://github.com/js-temporal/temporal-polyfill/commit/5448e59f461e7a56f8d5af4eb5353b2284cbab93
[07ea694e]: https://github.com/js-temporal/temporal-polyfill/commit/07ea694e0e44bffae021b537facf80def78d94cf
[079a3325]: https://github.com/js-temporal/temporal-polyfill/commit/079a33254af4e6610b409e33a3cc7fa22d116796
[b5736546]: https://github.com/js-temporal/temporal-polyfill/commit/b5736546a193478cd4b8f491f8a7c7d9763c322a
[0ee4581f]: https://github.com/js-temporal/temporal-polyfill/commit/0ee4581f8068fdd433040b17c7a2580733c55039
[068e801f]: https://github.com/js-temporal/temporal-polyfill/commit/068e801ff507aa1176dba2283e526900cdc6d0c1
[41ab6bc0]: https://github.com/js-temporal/temporal-polyfill/commit/41ab6bc01dc66b6f20ba7bc39f681aeebb64068a
[27b4c7e8]: https://github.com/js-temporal/temporal-polyfill/commit/27b4c7e89d617434bddf9b4240c57ab732233dba
[3a09d00d]: https://github.com/js-temporal/temporal-polyfill/commit/3a09d00de02918362b1530cc4121047c9e7495bb
[4a0d0264]: https://github.com/js-temporal/temporal-polyfill/commit/4a0d02648592439840345820b80f6d6f45e773aa
[47701107]: https://github.com/js-temporal/temporal-polyfill/commit/477011079f6e69e4d6fb18127d9cb0db2ee29ea6
[f5427de9]: https://github.com/js-temporal/temporal-polyfill/commit/f5427de92d4e4f015ea1374368b6594295597af3
[310d9d8b]: https://github.com/js-temporal/temporal-polyfill/commit/310d9d8b329de46e83fb2de75b997c7d28ac65f6
[960d9b76]: https://github.com/js-temporal/temporal-polyfill/commit/960d9b76d7acb24f017eb6ad58c72cb89905f804
[7f7c19a1]: https://github.com/js-temporal/temporal-polyfill/commit/7f7c19a11fc16bdd8aed52cd9e074d06be14c1ae
[4ec6568e]: https://github.com/js-temporal/temporal-polyfill/commit/4ec6568e1dc64f219b8b9aeddc9655f2728157b5
[edcc668b]: https://github.com/js-temporal/temporal-polyfill/commit/edcc668b680321aea0ceb20f041e7831cbb3b041
[2331468d]: https://github.com/js-temporal/temporal-polyfill/commit/2331468dc809b1abefab5d3c6d0901baf298f9fa
[666c69da]: https://github.com/js-temporal/temporal-polyfill/commit/666c69dab69655940ed712ca40d1ea7b1a6f3a4c
[429273ec]: https://github.com/js-temporal/temporal-polyfill/commit/429273ec7ced0eb85bfd736d07c01e7c31d871e8
[ff937782]: https://github.com/js-temporal/temporal-polyfill/commit/ff9377829f27895ee5d31f02d2b442fea827e399
[f885253f]: https://github.com/js-temporal/temporal-polyfill/commit/f885253fdc0d16115b0a9d986a47e3fa35e50878
[67f9f6bb]: https://github.com/js-temporal/temporal-polyfill/commit/67f9f6bbb7c3252144d6267cd1cf25f53e253d56
[63bdfcd1]: https://github.com/js-temporal/temporal-polyfill/commit/63bdfcd11f62d85796761c6397369b900db35a84
[d24575f2]: https://github.com/js-temporal/temporal-polyfill/commit/d24575f21b127c7889f1fa49ce41fc2f5e100618
[ad7e2e3a]: https://github.com/js-temporal/temporal-polyfill/commit/ad7e2e3a5b7a9f136c0ef551753b7381a5d16301
[5b1bc5e2]: https://github.com/js-temporal/temporal-polyfill/commit/5b1bc5e2e8635626993a65dadfecab45125f4f96
[12e4d529]: https://github.com/js-temporal/temporal-polyfill/commit/12e4d5294ffe6c847ca0a98e752fbf25a68b973d
[ac78fd9d]: https://github.com/js-temporal/temporal-polyfill/commit/ac78fd9ddff96dd792703a4948d11196d52fbbed
[53f32e0f]: https://github.com/js-temporal/temporal-polyfill/commit/53f32e0f868d2ddcaf09643c87a09df2ed158b78
[06b806c9]: https://github.com/js-temporal/temporal-polyfill/commit/06b806c9c1831eca649d5398399f862ea539a5ed
[66fdc765]: https://github.com/js-temporal/temporal-polyfill/commit/66fdc76589578b349ae2df63d9c79972f311ff0f
[50b1c34b]: https://github.com/js-temporal/temporal-polyfill/commit/50b1c34b3f54073fe50ce56998767a3bb0f4c763
[4724b017]: https://github.com/js-temporal/temporal-polyfill/commit/4724b017f86ef8c7b51d6291594604bff24a81f3
[947a8a5e]: https://github.com/js-temporal/temporal-polyfill/commit/947a8a5e0bfbfaf534fb943d8bd46d676dd5b5e6
[fdbf7e01]: https://github.com/js-temporal/temporal-polyfill/commit/fdbf7e0167be4413b39d3ea9c1e41c5323ab97c1
[fa60af6a]: https://github.com/js-temporal/temporal-polyfill/commit/fa60af6af015dbefba11de488e7f6be707c953a7
[da753f2f]: https://github.com/js-temporal/temporal-polyfill/commit/da753f2fedd80f4894ab5d1d9522b2820eb39f56
[f4db8b0b]: https://github.com/js-temporal/temporal-polyfill/commit/f4db8b0bb47584da0ecf5ab138242836924f052f
[4a38420d]: https://github.com/js-temporal/temporal-polyfill/commit/4a38420de406f35439c937eafbdc5783cda9c2b9
[c55818b6]: https://github.com/js-temporal/temporal-polyfill/commit/c55818b6458cfd4ea0efd7259f593fc2ec8dcda9
+13
View File
@@ -0,0 +1,13 @@
Copyright 2017, 2018, 2019, 2020 ECMA International
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
+82
View File
@@ -0,0 +1,82 @@
# Temporal Polyfill
## Polyfill for [TC39 Proposal: Temporal](https://github.com/tc39/proposal-temporal)
This polyfill was kicked off by some of the champions of the [Temporal proposal](https://github.com/tc39/proposal-temporal).
The goal is to be ready for production use when the Temporal proposal reaches Stage 4, although like with all OSS work progress is dependent on contributors.
We're eagerly welcoming to contributors who want to help build and maintain this polyfill.
PRs are always welcome!
Note that this polyfill is not affiliated with TC39. Links to other polyfills can be found [here](https://github.com/tc39/proposal-temporal/tree/main/#polyfills).
This polyfill is compatible with Node.js 14 or later.
## Roadmap
- [x] Fork non-production polyfill from [tc39/proposal-temporal repo](https://github.com/tc39/proposal-temporal/tree/main/polyfill)
- [x] Release initial pre-alpha to NPM at [@js-temporal/polyfill](https://www.npmjs.com/package/@js-temporal/polyfill)
- [x] Sync the code in this repo with the handful of polyfill changes that have recently been made in the [tc39/proposal-temporal](https://github.com/tc39/proposal-temporal) repo
- [x] Release alpha version to NPM
- [x] Deprecate all other earlier Temporal polyfills
- [x] Optimize slow operations by reducing calls to Intl.DateTimeFormat constructor (see #7, #8, #10, #12)
- [x] Convert to TypeScript for better maintainability
- [x] Improve typing of sources for better maintainability
- [x] Migrate to JSBI for improved compile-time safety around BigInt operations.
- [ ] Optimize performance of other slow operations
- [ ] Release production version to NPM
## Bug Reports and Feedback
If you think you've found a bug in the Temporal API itself (not the implementation in this polyfill), please file an issue in the [tc39/proposal-temporal issue tracker](https://github.com/tc39/proposal-temporal/issues) issue tracker.
If you've found a bug in this polyfill&mdash;meaning that the implementation here doesn't match the [Temporal spec](https://tc39.es/proposal-temporal/)&mdash;please file an issue in this repo's [issue tracker](https://github.com/js-temporal/temporal-polyfill/issues).
## Documentation
Reference documentation and examples for the Temporal API can be found [here](https://tc39.es/proposal-temporal/docs/index.html).
A cookbook to help you get started and learn the ins and outs of Temporal is available [here](https://tc39.es/proposal-temporal/docs/index.html)
If you find a bug in the documentation, please file a bug over in the [tc39/proposal-temporal issue tracker](https://github.com/tc39/proposal-temporal/issues) issue tracker.
Note that the Temporal documentation is in the process of being migrated to [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript).
You can track the progress of the MDN migration [here](https://github.com/tc39/proposal-temporal/issues/1449).
## Usage
To install:
```bash
$ npm install @js-temporal/polyfill
```
CJS Usage:
```javascript
const { Temporal, Intl, toTemporalInstant } = require('@js-temporal/polyfill');
Date.prototype.toTemporalInstant = toTemporalInstant;
```
Import the polyfill as an ES6 module:
```javascript
import { Temporal, Intl, toTemporalInstant } from '@js-temporal/polyfill';
Date.prototype.toTemporalInstant = toTemporalInstant;
```
Note that this polyfill currently does not install a global `Temporal` object like a real implementation will.
This behavior avoids hiding the global Temporal object in environments where a real Temporal implementation is present.
See [this issue](https://github.com/tc39/proposal-temporal/issues/778) for more background on this decision.
Once JS engines start shipping with Temporal, we may decide to change this behavior to match built-in behavior more closely.
See [#2](https://github.com/js-temporal/temporal-polyfill/issues/2) to provide feedback or track this issue.
This polyfill ships ES2020 code for both CJS and ESM bundles - if your
environment does not support ES2020, then please make sure to transpile the
content of this package along with the rest of your code.
This polyfill uses [JSBI](https://github.com/GoogleChromeLabs/jsbi) to enable backwards-compatibility for environments that don't support native bigints. If your project only ever runs in environments that do support native bigints (see [caniuse data](https://caniuse.com/bigint)), we highly recommend configuring the [JSBI Babel plugin](https://github.com/GoogleChromeLabs/babel-plugin-transform-jsbi-to-bigint) that translates JSBI calls to their native bigint equivalent, improving code-size and performance. We are exploring ways to provide separate builds for these use-cases in [#155](https://github.com/js-temporal/temporal-polyfill/issues/155).
## Contributing / Help Wanted
We're eagerly welcoming to contributors who want to help build and maintain this polyfill.
PRs are always welcome!
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+5
View File
@@ -0,0 +1,5 @@
interface GlobalDebugInfo {
__debug__?: boolean;
}
export const DEBUG = !!(globalThis as GlobalDebugInfo).__debug__;
+483
View File
@@ -0,0 +1,483 @@
import { DEBUG } from './debug';
import * as ES from './ecmascript';
import { MakeIntrinsicClass } from './intrinsicclass';
import {
YEARS,
MONTHS,
WEEKS,
DAYS,
HOURS,
MINUTES,
SECONDS,
MILLISECONDS,
MICROSECONDS,
NANOSECONDS,
CreateSlots,
GetSlot,
SetSlot
} from './slots';
import type { Temporal } from '..';
import type { DurationParams as Params, DurationReturn as Return } from './internaltypes';
import JSBI from 'jsbi';
export class Duration implements Temporal.Duration {
constructor(
yearsParam: Params['constructor'][0] = 0,
monthsParam: Params['constructor'][1] = 0,
weeksParam: Params['constructor'][2] = 0,
daysParam: Params['constructor'][3] = 0,
hoursParam: Params['constructor'][4] = 0,
minutesParam: Params['constructor'][5] = 0,
secondsParam: Params['constructor'][6] = 0,
millisecondsParam: Params['constructor'][7] = 0,
microsecondsParam: Params['constructor'][8] = 0,
nanosecondsParam: Params['constructor'][9] = 0
) {
const years = yearsParam === undefined ? 0 : ES.ToIntegerIfIntegral(yearsParam);
const months = monthsParam === undefined ? 0 : ES.ToIntegerIfIntegral(monthsParam);
const weeks = weeksParam === undefined ? 0 : ES.ToIntegerIfIntegral(weeksParam);
const days = daysParam === undefined ? 0 : ES.ToIntegerIfIntegral(daysParam);
const hours = hoursParam === undefined ? 0 : ES.ToIntegerIfIntegral(hoursParam);
const minutes = minutesParam === undefined ? 0 : ES.ToIntegerIfIntegral(minutesParam);
const seconds = secondsParam === undefined ? 0 : ES.ToIntegerIfIntegral(secondsParam);
const milliseconds = millisecondsParam === undefined ? 0 : ES.ToIntegerIfIntegral(millisecondsParam);
const microseconds = microsecondsParam === undefined ? 0 : ES.ToIntegerIfIntegral(microsecondsParam);
const nanoseconds = nanosecondsParam === undefined ? 0 : ES.ToIntegerIfIntegral(nanosecondsParam);
ES.RejectDuration(years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds);
CreateSlots(this);
SetSlot(this, YEARS, years);
SetSlot(this, MONTHS, months);
SetSlot(this, WEEKS, weeks);
SetSlot(this, DAYS, days);
SetSlot(this, HOURS, hours);
SetSlot(this, MINUTES, minutes);
SetSlot(this, SECONDS, seconds);
SetSlot(this, MILLISECONDS, milliseconds);
SetSlot(this, MICROSECONDS, microseconds);
SetSlot(this, NANOSECONDS, nanoseconds);
if (DEBUG) {
Object.defineProperty(this, '_repr_', {
value: `${this[Symbol.toStringTag]} <${ES.TemporalDurationToString(this)}>`,
writable: false,
enumerable: false,
configurable: false
});
}
}
get years(): Return['years'] {
if (!ES.IsTemporalDuration(this)) throw new TypeError('invalid receiver');
return GetSlot(this, YEARS);
}
get months(): Return['months'] {
if (!ES.IsTemporalDuration(this)) throw new TypeError('invalid receiver');
return GetSlot(this, MONTHS);
}
get weeks(): Return['weeks'] {
if (!ES.IsTemporalDuration(this)) throw new TypeError('invalid receiver');
return GetSlot(this, WEEKS);
}
get days(): Return['days'] {
if (!ES.IsTemporalDuration(this)) throw new TypeError('invalid receiver');
return GetSlot(this, DAYS);
}
get hours(): Return['hours'] {
if (!ES.IsTemporalDuration(this)) throw new TypeError('invalid receiver');
return GetSlot(this, HOURS);
}
get minutes(): Return['minutes'] {
if (!ES.IsTemporalDuration(this)) throw new TypeError('invalid receiver');
return GetSlot(this, MINUTES);
}
get seconds(): Return['seconds'] {
if (!ES.IsTemporalDuration(this)) throw new TypeError('invalid receiver');
return GetSlot(this, SECONDS);
}
get milliseconds(): Return['milliseconds'] {
if (!ES.IsTemporalDuration(this)) throw new TypeError('invalid receiver');
return GetSlot(this, MILLISECONDS);
}
get microseconds(): Return['microseconds'] {
if (!ES.IsTemporalDuration(this)) throw new TypeError('invalid receiver');
return GetSlot(this, MICROSECONDS);
}
get nanoseconds(): Return['nanoseconds'] {
if (!ES.IsTemporalDuration(this)) throw new TypeError('invalid receiver');
return GetSlot(this, NANOSECONDS);
}
get sign(): Return['sign'] {
if (!ES.IsTemporalDuration(this)) throw new TypeError('invalid receiver');
return ES.DurationSign(
GetSlot(this, YEARS),
GetSlot(this, MONTHS),
GetSlot(this, WEEKS),
GetSlot(this, DAYS),
GetSlot(this, HOURS),
GetSlot(this, MINUTES),
GetSlot(this, SECONDS),
GetSlot(this, MILLISECONDS),
GetSlot(this, MICROSECONDS),
GetSlot(this, NANOSECONDS)
);
}
get blank(): Return['blank'] {
if (!ES.IsTemporalDuration(this)) throw new TypeError('invalid receiver');
return (
ES.DurationSign(
GetSlot(this, YEARS),
GetSlot(this, MONTHS),
GetSlot(this, WEEKS),
GetSlot(this, DAYS),
GetSlot(this, HOURS),
GetSlot(this, MINUTES),
GetSlot(this, SECONDS),
GetSlot(this, MILLISECONDS),
GetSlot(this, MICROSECONDS),
GetSlot(this, NANOSECONDS)
) === 0
);
}
with(durationLike: Params['with'][0]): Return['with'] {
if (!ES.IsTemporalDuration(this)) throw new TypeError('invalid receiver');
const partialDuration = ES.PrepareTemporalFields(
durationLike,
// NOTE: Field order here is important.
[
'days',
'hours',
'microseconds',
'milliseconds',
'minutes',
'months',
'nanoseconds',
'seconds',
'weeks',
'years'
],
'partial'
);
const {
years = GetSlot(this, YEARS),
months = GetSlot(this, MONTHS),
weeks = GetSlot(this, WEEKS),
days = GetSlot(this, DAYS),
hours = GetSlot(this, HOURS),
minutes = GetSlot(this, MINUTES),
seconds = GetSlot(this, SECONDS),
milliseconds = GetSlot(this, MILLISECONDS),
microseconds = GetSlot(this, MICROSECONDS),
nanoseconds = GetSlot(this, NANOSECONDS)
} = partialDuration;
return new Duration(years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds);
}
negated(): Return['negated'] {
if (!ES.IsTemporalDuration(this)) throw new TypeError('invalid receiver');
return ES.CreateNegatedTemporalDuration(this);
}
abs(): Return['abs'] {
if (!ES.IsTemporalDuration(this)) throw new TypeError('invalid receiver');
return new Duration(
Math.abs(GetSlot(this, YEARS)),
Math.abs(GetSlot(this, MONTHS)),
Math.abs(GetSlot(this, WEEKS)),
Math.abs(GetSlot(this, DAYS)),
Math.abs(GetSlot(this, HOURS)),
Math.abs(GetSlot(this, MINUTES)),
Math.abs(GetSlot(this, SECONDS)),
Math.abs(GetSlot(this, MILLISECONDS)),
Math.abs(GetSlot(this, MICROSECONDS)),
Math.abs(GetSlot(this, NANOSECONDS))
);
}
add(other: Params['add'][0], options: Params['add'][1] = undefined): Return['add'] {
if (!ES.IsTemporalDuration(this)) throw new TypeError('invalid receiver');
return ES.AddDurationToOrSubtractDurationFromDuration('add', this, other, options);
}
subtract(other: Params['subtract'][0], options: Params['subtract'][1] = undefined): Return['subtract'] {
if (!ES.IsTemporalDuration(this)) throw new TypeError('invalid receiver');
return ES.AddDurationToOrSubtractDurationFromDuration('subtract', this, other, options);
}
round(roundToParam: Params['round'][0]): Return['round'] {
if (!ES.IsTemporalDuration(this)) throw new TypeError('invalid receiver');
if (roundToParam === undefined) throw new TypeError('options parameter is required');
let years = GetSlot(this, YEARS);
let months = GetSlot(this, MONTHS);
let weeks = GetSlot(this, WEEKS);
let days = GetSlot(this, DAYS);
let hours = GetSlot(this, HOURS);
let minutes = GetSlot(this, MINUTES);
let seconds = GetSlot(this, SECONDS);
let milliseconds = GetSlot(this, MILLISECONDS);
let microseconds = GetSlot(this, MICROSECONDS);
let nanoseconds = GetSlot(this, NANOSECONDS);
let defaultLargestUnit = ES.DefaultTemporalLargestUnit(
years,
months,
weeks,
days,
hours,
minutes,
seconds,
milliseconds,
microseconds,
nanoseconds
);
const roundTo =
typeof roundToParam === 'string'
? (ES.CreateOnePropObject('smallestUnit', roundToParam) as Exclude<typeof roundToParam, string>)
: ES.GetOptionsObject(roundToParam);
let largestUnit = ES.GetTemporalUnit(roundTo, 'largestUnit', 'datetime', undefined, ['auto']);
let relativeTo = ES.ToRelativeTemporalObject(roundTo);
const roundingIncrement = ES.ToTemporalRoundingIncrement(roundTo);
const roundingMode = ES.ToTemporalRoundingMode(roundTo, 'halfExpand');
let smallestUnit = ES.GetTemporalUnit(roundTo, 'smallestUnit', 'datetime', undefined);
let smallestUnitPresent = true;
if (!smallestUnit) {
smallestUnitPresent = false;
smallestUnit = 'nanosecond';
}
defaultLargestUnit = ES.LargerOfTwoTemporalUnits(defaultLargestUnit, smallestUnit);
let largestUnitPresent = true;
if (!largestUnit) {
largestUnitPresent = false;
largestUnit = defaultLargestUnit;
}
if (largestUnit === 'auto') largestUnit = defaultLargestUnit;
if (!smallestUnitPresent && !largestUnitPresent) {
throw new RangeError('at least one of smallestUnit or largestUnit is required');
}
if (ES.LargerOfTwoTemporalUnits(largestUnit, smallestUnit) !== largestUnit) {
throw new RangeError(`largestUnit ${largestUnit} cannot be smaller than smallestUnit ${smallestUnit}`);
}
const maximumIncrements = {
hour: 24,
minute: 60,
second: 60,
millisecond: 1000,
microsecond: 1000,
nanosecond: 1000
} as { [k in Temporal.DateTimeUnit]?: number };
const maximum = maximumIncrements[smallestUnit];
if (maximum !== undefined) ES.ValidateTemporalRoundingIncrement(roundingIncrement, maximum, false);
({ years, months, weeks, days } = ES.UnbalanceDurationRelative(
years,
months,
weeks,
days,
largestUnit,
relativeTo
));
({ years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds } =
ES.RoundDuration(
years,
months,
weeks,
days,
hours,
minutes,
seconds,
milliseconds,
microseconds,
nanoseconds,
roundingIncrement,
smallestUnit,
roundingMode,
relativeTo
));
({ years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds } =
ES.AdjustRoundedDurationDays(
years,
months,
weeks,
days,
hours,
minutes,
seconds,
milliseconds,
microseconds,
nanoseconds,
roundingIncrement,
smallestUnit,
roundingMode,
relativeTo
));
({ days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds } = ES.BalanceDuration(
days,
hours,
minutes,
seconds,
milliseconds,
microseconds,
nanoseconds,
largestUnit,
relativeTo
));
({ years, months, weeks, days } = ES.BalanceDurationRelative(years, months, weeks, days, largestUnit, relativeTo));
return new Duration(years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds);
}
total(optionsParam: Params['total'][0]): Return['total'] {
if (!ES.IsTemporalDuration(this)) throw new TypeError('invalid receiver');
let years = GetSlot(this, YEARS);
let months = GetSlot(this, MONTHS);
let weeks = GetSlot(this, WEEKS);
let days = GetSlot(this, DAYS);
let hours = GetSlot(this, HOURS);
let minutes = GetSlot(this, MINUTES);
let seconds = GetSlot(this, SECONDS);
let milliseconds = GetSlot(this, MILLISECONDS);
let microseconds = GetSlot(this, MICROSECONDS);
let nanoseconds = GetSlot(this, NANOSECONDS);
if (optionsParam === undefined) throw new TypeError('options argument is required');
const options =
typeof optionsParam === 'string'
? (ES.CreateOnePropObject('unit', optionsParam) as Exclude<typeof optionsParam, string>)
: ES.GetOptionsObject(optionsParam);
const relativeTo = ES.ToRelativeTemporalObject(options);
const unit = ES.GetTemporalUnit(options, 'unit', 'datetime', ES.REQUIRED);
// Convert larger units down to days
({ years, months, weeks, days } = ES.UnbalanceDurationRelative(years, months, weeks, days, unit, relativeTo));
// If the unit we're totalling is smaller than `days`, convert days down to that unit.
let intermediate;
if (ES.IsTemporalZonedDateTime(relativeTo)) {
intermediate = ES.MoveRelativeZonedDateTime(relativeTo, years, months, weeks, 0);
}
let balanceResult = ES.BalancePossiblyInfiniteDuration(
days,
hours,
minutes,
seconds,
milliseconds,
microseconds,
nanoseconds,
unit,
intermediate
);
if (balanceResult === 'positive overflow') {
return Infinity;
} else if (balanceResult === 'negative overflow') {
return -Infinity;
}
({ days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds } = balanceResult);
// Finally, truncate to the correct unit and calculate remainder
const { total } = ES.RoundDuration(
years,
months,
weeks,
days,
hours,
minutes,
seconds,
milliseconds,
microseconds,
nanoseconds,
1,
unit,
'trunc',
relativeTo
);
return total;
}
toString(optionsParam: Params['toString'][0] = undefined): string {
if (!ES.IsTemporalDuration(this)) throw new TypeError('invalid receiver');
const options = ES.GetOptionsObject(optionsParam);
const digits = ES.ToFractionalSecondDigits(options);
const roundingMode = ES.ToTemporalRoundingMode(options, 'trunc');
const smallestUnit = ES.GetTemporalUnit(options, 'smallestUnit', 'time', undefined);
if (smallestUnit === 'hour' || smallestUnit === 'minute') {
throw new RangeError('smallestUnit must be a time unit other than "hours" or "minutes"');
}
const { precision, unit, increment } = ES.ToSecondsStringPrecisionRecord(smallestUnit, digits);
ES.uncheckedAssertNarrowedType<Exclude<typeof precision, 'minute'>>(
precision,
'Precision cannot be "minute" because of RangeError above'
);
return ES.TemporalDurationToString(this, precision, { unit, increment, roundingMode });
}
toJSON(): Return['toJSON'] {
if (!ES.IsTemporalDuration(this)) throw new TypeError('invalid receiver');
return ES.TemporalDurationToString(this);
}
toLocaleString(
locales: Params['toLocaleString'][0] = undefined,
options: Params['toLocaleString'][1] = undefined
): string {
if (!ES.IsTemporalDuration(this)) throw new TypeError('invalid receiver');
if (typeof Intl !== 'undefined' && typeof (Intl as any).DurationFormat !== 'undefined') {
return new (Intl as any).DurationFormat(locales, options).format(this);
}
console.warn('Temporal.Duration.prototype.toLocaleString() requires Intl.DurationFormat.');
return ES.TemporalDurationToString(this);
}
valueOf(): never {
throw new TypeError('use compare() to compare Temporal.Duration');
}
static from(item: Params['from'][0]): Return['from'] {
if (ES.IsTemporalDuration(item)) {
return new Duration(
GetSlot(item, YEARS),
GetSlot(item, MONTHS),
GetSlot(item, WEEKS),
GetSlot(item, DAYS),
GetSlot(item, HOURS),
GetSlot(item, MINUTES),
GetSlot(item, SECONDS),
GetSlot(item, MILLISECONDS),
GetSlot(item, MICROSECONDS),
GetSlot(item, NANOSECONDS)
);
}
return ES.ToTemporalDuration(item);
}
static compare(
oneParam: Params['compare'][0],
twoParam: Params['compare'][1],
optionsParam: Params['compare'][2] = undefined
) {
const one = ES.ToTemporalDuration(oneParam);
const two = ES.ToTemporalDuration(twoParam);
const options = ES.GetOptionsObject(optionsParam);
const relativeTo = ES.ToRelativeTemporalObject(options);
const y1 = GetSlot(one, YEARS);
const mon1 = GetSlot(one, MONTHS);
const w1 = GetSlot(one, WEEKS);
let d1 = GetSlot(one, DAYS);
const h1 = GetSlot(one, HOURS);
const min1 = GetSlot(one, MINUTES);
const s1 = GetSlot(one, SECONDS);
const ms1 = GetSlot(one, MILLISECONDS);
const µs1 = GetSlot(one, MICROSECONDS);
let ns1 = GetSlot(one, NANOSECONDS);
const y2 = GetSlot(two, YEARS);
const mon2 = GetSlot(two, MONTHS);
const w2 = GetSlot(two, WEEKS);
let d2 = GetSlot(two, DAYS);
const h2 = GetSlot(two, HOURS);
const min2 = GetSlot(two, MINUTES);
const s2 = GetSlot(two, SECONDS);
const ms2 = GetSlot(two, MILLISECONDS);
const µs2 = GetSlot(two, MICROSECONDS);
let ns2 = GetSlot(two, NANOSECONDS);
const shift1 = ES.CalculateOffsetShift(relativeTo, y1, mon1, w1, d1);
const shift2 = ES.CalculateOffsetShift(relativeTo, y2, mon2, w2, d2);
if (y1 !== 0 || y2 !== 0 || mon1 !== 0 || mon2 !== 0 || w1 !== 0 || w2 !== 0) {
({ days: d1 } = ES.UnbalanceDurationRelative(y1, mon1, w1, d1, 'day', relativeTo));
({ days: d2 } = ES.UnbalanceDurationRelative(y2, mon2, w2, d2, 'day', relativeTo));
}
const totalNs1 = ES.TotalDurationNanoseconds(d1, h1, min1, s1, ms1, µs1, ns1, shift1);
const totalNs2 = ES.TotalDurationNanoseconds(d2, h2, min2, s2, ms2, µs2, ns2, shift2);
return ES.ComparisonResult(JSBI.toNumber(JSBI.subtract(totalNs1, totalNs2)));
}
[Symbol.toStringTag]!: 'Temporal.Duration';
}
MakeIntrinsicClass(Duration, 'Temporal.Duration');
File diff suppressed because it is too large Load Diff
+36
View File
@@ -0,0 +1,36 @@
// This entry point treats Temporal as a library, and does not polyfill it onto
// the global object.
// This is in order to avoid breaking the web in the future, if the polyfill
// gains wide adoption before the API is finalized. We do not want checks such
// as `if (typeof Temporal === 'undefined')` in the wild, until browsers start
// shipping the finalized API.
import * as Temporal from './temporal';
import * as Intl from './intl';
import { toTemporalInstant } from './legacydate';
// Work around https://github.com/babel/babel/issues/2025.
const types = [
Temporal.Instant,
Temporal.Calendar,
Temporal.PlainDate,
Temporal.PlainDateTime,
Temporal.Duration,
Temporal.PlainMonthDay,
// Temporal.Now, // plain object (not a constructor), so no `prototype`
Temporal.PlainTime,
Temporal.TimeZone,
Temporal.PlainYearMonth,
Temporal.ZonedDateTime
];
for (const type of types) {
const descriptor = Object.getOwnPropertyDescriptor(type, 'prototype') as PropertyDescriptor;
if (descriptor.configurable || descriptor.enumerable || descriptor.writable) {
descriptor.configurable = false;
descriptor.enumerable = false;
descriptor.writable = false;
Object.defineProperty(type, 'prototype', descriptor);
}
}
export { Temporal, Intl, toTemporalInstant };
+43
View File
@@ -0,0 +1,43 @@
// This is an alternate entry point that polyfills Temporal onto the global
// object. This is used only for the browser playground and the test262 tests.
// See the note in index.mjs.
import * as Temporal from './temporal';
import * as Intl from './intl';
import { toTemporalInstant } from './legacydate';
Object.defineProperty(globalThis, 'Temporal', {
value: {},
writable: true,
enumerable: false,
configurable: true
});
const globalTemporal = (globalThis as unknown as { Temporal: typeof Temporal }).Temporal;
copy(globalTemporal, Temporal);
Object.defineProperty(globalTemporal, Symbol.toStringTag, {
value: 'Temporal',
writable: false,
enumerable: false,
configurable: true
});
copy(globalTemporal.Now, Temporal.Now);
copy(globalThis.Intl, Intl);
Object.defineProperty(globalThis.Date.prototype, 'toTemporalInstant', {
value: toTemporalInstant,
writable: true,
enumerable: false,
configurable: true
});
function copy(target: Record<string | number | symbol, unknown>, source: Record<string | number | symbol, unknown>) {
for (const prop of Object.getOwnPropertyNames(source)) {
Object.defineProperty(target, prop, {
value: source[prop],
writable: true,
enumerable: false,
configurable: true
});
}
}
export { Temporal, Intl, toTemporalInstant };
+201
View File
@@ -0,0 +1,201 @@
import { DEBUG } from './debug';
import * as ES from './ecmascript';
import { MakeIntrinsicClass } from './intrinsicclass';
import { EPOCHNANOSECONDS, CreateSlots, GetSlot, SetSlot } from './slots';
import type { Temporal } from '..';
import { DateTimeFormat } from './intl';
import type { InstantParams as Params, InstantReturn as Return } from './internaltypes';
import JSBI from 'jsbi';
import { BILLION, MILLION, THOUSAND } from './ecmascript';
export class Instant implements Temporal.Instant {
constructor(epochNanoseconds: bigint | JSBI) {
// Note: if the argument is not passed, ToBigInt(undefined) will throw. This check exists only
// to improve the error message.
if (arguments.length < 1) {
throw new TypeError('missing argument: epochNanoseconds is required');
}
const ns = ES.ToBigInt(epochNanoseconds);
ES.ValidateEpochNanoseconds(ns);
CreateSlots(this);
SetSlot(this, EPOCHNANOSECONDS, ns);
if (DEBUG) {
const repr = ES.TemporalInstantToString(this, undefined, 'auto');
Object.defineProperty(this, '_repr_', {
value: `${this[Symbol.toStringTag]} <${repr}>`,
writable: false,
enumerable: false,
configurable: false
});
}
}
get epochSeconds(): Return['epochSeconds'] {
if (!ES.IsTemporalInstant(this)) throw new TypeError('invalid receiver');
const value = GetSlot(this, EPOCHNANOSECONDS);
return JSBI.toNumber(ES.BigIntFloorDiv(value, BILLION));
}
get epochMilliseconds(): Return['epochMilliseconds'] {
if (!ES.IsTemporalInstant(this)) throw new TypeError('invalid receiver');
const value = JSBI.BigInt(GetSlot(this, EPOCHNANOSECONDS));
return JSBI.toNumber(ES.BigIntFloorDiv(value, MILLION));
}
get epochMicroseconds(): Return['epochMicroseconds'] {
if (!ES.IsTemporalInstant(this)) throw new TypeError('invalid receiver');
const value = JSBI.BigInt(GetSlot(this, EPOCHNANOSECONDS));
return ES.ToBigIntExternal(ES.BigIntFloorDiv(value, THOUSAND));
}
get epochNanoseconds(): Return['epochNanoseconds'] {
if (!ES.IsTemporalInstant(this)) throw new TypeError('invalid receiver');
return ES.ToBigIntExternal(JSBI.BigInt(GetSlot(this, EPOCHNANOSECONDS)));
}
add(temporalDurationLike: Params['add'][0]): Return['add'] {
if (!ES.IsTemporalInstant(this)) throw new TypeError('invalid receiver');
return ES.AddDurationToOrSubtractDurationFromInstant('add', this, temporalDurationLike);
}
subtract(temporalDurationLike: Params['subtract'][0]): Return['subtract'] {
if (!ES.IsTemporalInstant(this)) throw new TypeError('invalid receiver');
return ES.AddDurationToOrSubtractDurationFromInstant('subtract', this, temporalDurationLike);
}
until(other: Params['until'][0], options: Params['until'][1] = undefined): Return['until'] {
if (!ES.IsTemporalInstant(this)) throw new TypeError('invalid receiver');
return ES.DifferenceTemporalInstant('until', this, other, options);
}
since(other: Params['since'][0], options: Params['since'][1] = undefined): Return['since'] {
if (!ES.IsTemporalInstant(this)) throw new TypeError('invalid receiver');
return ES.DifferenceTemporalInstant('since', this, other, options);
}
round(roundToParam: Params['round'][0]): Return['round'] {
if (!ES.IsTemporalInstant(this)) throw new TypeError('invalid receiver');
if (roundToParam === undefined) throw new TypeError('options parameter is required');
const roundTo =
typeof roundToParam === 'string'
? (ES.CreateOnePropObject('smallestUnit', roundToParam) as Exclude<typeof roundToParam, string>)
: ES.GetOptionsObject(roundToParam);
const roundingIncrement = ES.ToTemporalRoundingIncrement(roundTo);
const roundingMode = ES.ToTemporalRoundingMode(roundTo, 'halfExpand');
const smallestUnit = ES.GetTemporalUnit(roundTo, 'smallestUnit', 'time', ES.REQUIRED);
const maximumIncrements = {
hour: 24,
minute: 1440,
second: 86400,
millisecond: 86400e3,
microsecond: 86400e6,
nanosecond: 86400e9
};
ES.ValidateTemporalRoundingIncrement(roundingIncrement, maximumIncrements[smallestUnit], true);
const ns = GetSlot(this, EPOCHNANOSECONDS);
const roundedNs = ES.RoundInstant(ns, roundingIncrement, smallestUnit, roundingMode);
return new Instant(roundedNs);
}
equals(otherParam: Params['equals'][0]): Return['equals'] {
if (!ES.IsTemporalInstant(this)) throw new TypeError('invalid receiver');
const other = ES.ToTemporalInstant(otherParam);
const one = GetSlot(this, EPOCHNANOSECONDS);
const two = GetSlot(other, EPOCHNANOSECONDS);
return JSBI.equal(JSBI.BigInt(one), JSBI.BigInt(two));
}
toString(optionsParam: Params['toString'][0] = undefined): string {
if (!ES.IsTemporalInstant(this)) throw new TypeError('invalid receiver');
const options = ES.GetOptionsObject(optionsParam);
const digits = ES.ToFractionalSecondDigits(options);
const roundingMode = ES.ToTemporalRoundingMode(options, 'trunc');
const smallestUnit = ES.GetTemporalUnit(options, 'smallestUnit', 'time', undefined);
if (smallestUnit === 'hour') throw new RangeError('smallestUnit must be a time unit other than "hour"');
let timeZone = options.timeZone;
if (timeZone !== undefined) timeZone = ES.ToTemporalTimeZoneSlotValue(timeZone);
const { precision, unit, increment } = ES.ToSecondsStringPrecisionRecord(smallestUnit, digits);
const ns = GetSlot(this, EPOCHNANOSECONDS);
const roundedNs = ES.RoundInstant(ns, increment, unit, roundingMode);
const roundedInstant = new Instant(roundedNs);
return ES.TemporalInstantToString(roundedInstant, timeZone as Temporal.TimeZoneProtocol, precision);
}
toJSON(): string {
if (!ES.IsTemporalInstant(this)) throw new TypeError('invalid receiver');
return ES.TemporalInstantToString(this, undefined, 'auto');
}
toLocaleString(
locales: Params['toLocaleString'][0] = undefined,
options: Params['toLocaleString'][1] = undefined
): string {
if (!ES.IsTemporalInstant(this)) throw new TypeError('invalid receiver');
return new DateTimeFormat(locales, options).format(this);
}
valueOf(): never {
throw new TypeError('use compare() or equals() to compare Temporal.Instant');
}
toZonedDateTime(item: Params['toZonedDateTime'][0]): Return['toZonedDateTime'] {
if (!ES.IsTemporalInstant(this)) throw new TypeError('invalid receiver');
if (!ES.IsObject(item)) {
throw new TypeError('invalid argument in toZonedDateTime');
}
const calendarLike = item.calendar;
if (calendarLike === undefined) {
throw new TypeError('missing calendar property in toZonedDateTime');
}
const calendar = ES.ToTemporalCalendarSlotValue(calendarLike);
const temporalTimeZoneLike = item.timeZone;
if (temporalTimeZoneLike === undefined) {
throw new TypeError('missing timeZone property in toZonedDateTime');
}
const timeZone = ES.ToTemporalTimeZoneSlotValue(temporalTimeZoneLike);
return ES.CreateTemporalZonedDateTime(GetSlot(this, EPOCHNANOSECONDS), timeZone, calendar);
}
toZonedDateTimeISO(timeZoneParam: Params['toZonedDateTimeISO'][0]): Return['toZonedDateTimeISO'] {
if (!ES.IsTemporalInstant(this)) throw new TypeError('invalid receiver');
const timeZone = ES.ToTemporalTimeZoneSlotValue(timeZoneParam);
return ES.CreateTemporalZonedDateTime(GetSlot(this, EPOCHNANOSECONDS), timeZone, 'iso8601');
}
static fromEpochSeconds(epochSecondsParam: Params['fromEpochSeconds'][0]): Return['fromEpochSeconds'] {
const epochSeconds = ES.ToNumber(epochSecondsParam);
const epochNanoseconds = JSBI.multiply(JSBI.BigInt(epochSeconds), BILLION);
ES.ValidateEpochNanoseconds(epochNanoseconds);
return new Instant(epochNanoseconds);
}
static fromEpochMilliseconds(
epochMillisecondsParam: Params['fromEpochMilliseconds'][0]
): Return['fromEpochMilliseconds'] {
const epochMilliseconds = ES.ToNumber(epochMillisecondsParam);
const epochNanoseconds = JSBI.multiply(JSBI.BigInt(epochMilliseconds), MILLION);
ES.ValidateEpochNanoseconds(epochNanoseconds);
return new Instant(epochNanoseconds);
}
static fromEpochMicroseconds(
epochMicrosecondsParam: Params['fromEpochMicroseconds'][0]
): Return['fromEpochMicroseconds'] {
const epochMicroseconds = ES.ToBigInt(epochMicrosecondsParam);
const epochNanoseconds = JSBI.multiply(epochMicroseconds, THOUSAND);
ES.ValidateEpochNanoseconds(epochNanoseconds);
return new Instant(epochNanoseconds);
}
static fromEpochNanoseconds(
epochNanosecondsParam: Params['fromEpochNanoseconds'][0]
): Return['fromEpochNanoseconds'] {
const epochNanoseconds = ES.ToBigInt(epochNanosecondsParam);
ES.ValidateEpochNanoseconds(epochNanoseconds);
return new Instant(epochNanoseconds);
}
static from(item: Params['from'][0]): Return['from'] {
if (ES.IsTemporalInstant(item)) {
return new Instant(GetSlot(item, EPOCHNANOSECONDS));
}
return ES.ToTemporalInstant(item);
}
static compare(oneParam: Params['compare'][0], twoParam: Params['compare'][1]): Return['compare'] {
const one = ES.ToTemporalInstant(oneParam);
const two = ES.ToTemporalInstant(twoParam);
const oneNs = GetSlot(one, EPOCHNANOSECONDS);
const twoNs = GetSlot(two, EPOCHNANOSECONDS);
if (JSBI.lessThan(oneNs, twoNs)) return -1;
if (JSBI.greaterThan(oneNs, twoNs)) return 1;
return 0;
}
[Symbol.toStringTag]!: 'Temporal.Instant';
}
MakeIntrinsicClass(Instant, 'Temporal.Instant');
@@ -0,0 +1,205 @@
import type { Intl, Temporal } from '..';
export type BuiltinCalendarId =
| 'iso8601'
| 'hebrew'
| 'islamic'
| 'islamic-umalqura'
| 'islamic-tbla'
| 'islamic-civil'
| 'islamic-rgsa'
| 'islamicc'
| 'persian'
| 'ethiopic'
| 'ethioaa'
| 'coptic'
| 'chinese'
| 'dangi'
| 'roc'
| 'indian'
| 'buddhist'
| 'japanese'
| 'gregory';
export type AnyTemporalType =
| Temporal.Calendar
| Temporal.Duration
| Temporal.Instant
| Temporal.PlainDate
| Temporal.PlainDateTime
| Temporal.PlainMonthDay
| Temporal.PlainTime
| Temporal.PlainYearMonth
| Temporal.TimeZone
| Temporal.ZonedDateTime;
/*
// unused, but uncomment if this is needed later
export type AnyTemporalConstructor =
| typeof Temporal.Calendar
| typeof Temporal.Duration
| typeof Temporal.Instant
| typeof Temporal.PlainDate
| typeof Temporal.PlainDateTime
| typeof Temporal.PlainMonthDay
| typeof Temporal.PlainTime
| typeof Temporal.PlainYearMonth
| typeof Temporal.TimeZone
| typeof Temporal.ZonedDateTime;
*/
export type CalendarSlot = string | Temporal.CalendarProtocol;
export type TimeZoneSlot = string | Temporal.TimeZoneProtocol;
// Used in AnyTemporalLikeType
// ts-prune-ignore-next
type AllTemporalLikeTypes = [
Temporal.DurationLike,
Temporal.PlainDateLike,
Temporal.PlainDateTimeLike,
Temporal.PlainMonthDayLike,
Temporal.PlainTimeLike,
Temporal.PlainYearMonthLike,
Temporal.ZonedDateTimeLike
];
export type AnyTemporalLikeType = AllTemporalLikeTypes[number];
// Keys is a conditionally-mapped version of keyof
export type Keys<T> = T extends Record<string, unknown> ? keyof T : never;
export type AnyTemporalKey = Exclude<Keys<AnyTemporalLikeType>, symbol>;
// The properties below are all the names of Temporal properties that can be set with `with`.
// `timeZone` and `calendar` are not on the list because they have special methods to set them.
// Used in PrimitiveFieldsOf
// ts-prune-ignore-next
type PrimitivePropertyNames =
| 'year'
| 'month'
| 'monthCode'
| 'day'
| 'hour'
| 'minute'
| 'second'
| 'millisecond'
| 'microsecond'
| 'nanosecond'
| 'years'
| 'months'
| 'weeks'
| 'days'
| 'hours'
| 'minutes'
| 'seconds'
| 'milliseconds'
| 'microseconds'
| 'nanoseconds'
| 'era'
| 'eraYear'
| 'offset';
export type PrimitiveFieldsOf<T extends AnyTemporalLikeType> = Pick<T, keyof T & PrimitivePropertyNames>;
export type UnitSmallerThanOrEqualTo<T extends Temporal.DateTimeUnit> = T extends 'year'
? Temporal.DateTimeUnit
: T extends 'month'
? Exclude<Temporal.DateTimeUnit, 'year'>
: T extends 'week'
? Exclude<Temporal.DateTimeUnit, 'year' | 'month'>
: T extends 'day'
? Exclude<Temporal.DateTimeUnit, 'year' | 'month' | 'week'>
: T extends 'hour'
? Temporal.TimeUnit
: T extends 'minute'
? Exclude<Temporal.TimeUnit, 'hour'>
: T extends 'second'
? Exclude<Temporal.TimeUnit, 'hour' | 'minute'>
: T extends 'millisecond'
? Exclude<Temporal.TimeUnit, 'hour' | 'minute' | 'second'>
: T extends 'microsecond'
? 'nanosecond'
: never;
// ts-prune complains about the type definitions below, even though they're used
// by exported types Not sure why and don't have time to investigate, so just
// disabling the warnings for now.
// ts-prune-ignore-next
type Method = (...args: any) => any;
// ts-prune-ignore-next
type NonObjectKeys<T> = Exclude<keyof T, 'toString' | 'toLocaleString' | 'prototype'>;
// ts-prune-ignore-next
type MethodParams<Type extends new (...args: any) => any> = {
// constructor parameters
constructor: ConstructorParameters<Type>;
} & {
// static method parameters
[Key in NonObjectKeys<Type>]: Type[Key] extends Method ? Parameters<Type[Key]> : never;
} & {
// prototype method parameters
[Key in keyof InstanceType<Type>]: InstanceType<Type>[Key] extends Method
? Parameters<InstanceType<Type>[Key]>
: never;
};
// ts-prune-ignore-next
type MethodReturn<Type extends new (...args: any) => any> = {
constructor: InstanceType<Type>;
} & {
[Key in NonObjectKeys<Type>]: Type[Key] extends Method ? ReturnType<Type[Key]> : Type[Key];
} & {
[Key in keyof InstanceType<Type>]: InstanceType<Type>[Key] extends Method
? ReturnType<InstanceType<Type>[Key]>
: InstanceType<Type>[Key];
};
/* Currently unused, but may use later
type InterfaceReturn<Type> = {
[Key in keyof Type]: Type[Key] extends Method ? ReturnType<Type[Key]> : Type[Key];
};
*/
// ts-prune-ignore-next
type InterfaceParams<Type> = {
[Key in keyof Type]: Type[Key] extends Method ? Parameters<Type[Key]> : never;
};
// Parameters of each Temporal type. Examples:
// * InstantParams['compare'][1] - static methods
// * PlainDateParams['since'][0] - prototype methods
// * DurationParams['constructor'][3] - constructors
export interface ZonedDateTimeParams extends MethodParams<typeof Temporal.ZonedDateTime> {}
export interface CalendarParams extends MethodParams<typeof Temporal.Calendar> {}
export interface DurationParams extends MethodParams<typeof Temporal.Duration> {}
export interface InstantParams extends MethodParams<typeof Temporal.Instant> {}
export interface PlainDateParams extends MethodParams<typeof Temporal.PlainDate> {}
export interface PlainDateTimeParams extends MethodParams<typeof Temporal.PlainDateTime> {}
export interface PlainMonthDayParams extends MethodParams<typeof Temporal.PlainMonthDay> {}
export interface PlainTimeParams extends MethodParams<typeof Temporal.PlainTime> {}
export interface PlainYearMonthParams extends MethodParams<typeof Temporal.PlainYearMonth> {}
export interface TimeZoneParams extends MethodParams<typeof Temporal.TimeZone> {}
export interface ZonedDateTimeParams extends MethodParams<typeof Temporal.ZonedDateTime> {}
// Return types of static or instance methods
export interface ZonedDateTimeReturn extends MethodReturn<typeof Temporal.ZonedDateTime> {}
export interface CalendarReturn extends MethodReturn<typeof Temporal.Calendar> {}
export interface DurationReturn extends MethodReturn<typeof Temporal.Duration> {}
export interface InstantReturn extends MethodReturn<typeof Temporal.Instant> {}
export interface PlainDateReturn extends MethodReturn<typeof Temporal.PlainDate> {}
export interface PlainDateTimeReturn extends MethodReturn<typeof Temporal.PlainDateTime> {}
export interface PlainMonthDayReturn extends MethodReturn<typeof Temporal.PlainMonthDay> {}
export interface PlainTimeReturn extends MethodReturn<typeof Temporal.PlainTime> {}
export interface PlainYearMonthReturn extends MethodReturn<typeof Temporal.PlainYearMonth> {}
export interface TimeZoneReturn extends MethodReturn<typeof Temporal.TimeZone> {}
export interface ZonedDateTimeReturn extends MethodReturn<typeof Temporal.ZonedDateTime> {}
export interface CalendarProtocolParams extends InterfaceParams<Temporal.CalendarProtocol> {}
export interface TimeZoneProtocolParams extends InterfaceParams<Temporal.TimeZoneProtocol> {}
// UNUSED, BUT MAY USE LATER
// export interface TimeZoneProtocolReturn extends InterfaceReturn<Temporal.TimeZoneProtocol> {}
// export interface CalendarProtocolReturn extends InterfaceReturn<Temporal.CalendarProtocol> {}
export interface DateTimeFormatParams extends MethodParams<typeof Intl.DateTimeFormat> {}
export interface DateTimeFormatReturn extends MethodReturn<typeof Intl.DateTimeFormat> {}
+558
View File
@@ -0,0 +1,558 @@
import * as ES from './ecmascript';
import { GetIntrinsic } from './intrinsicclass';
import {
GetSlot,
ISO_YEAR,
ISO_MONTH,
ISO_DAY,
ISO_HOUR,
ISO_MINUTE,
ISO_SECOND,
ISO_MILLISECOND,
ISO_MICROSECOND,
ISO_NANOSECOND,
CALENDAR
} from './slots';
import type { Temporal, Intl } from '..';
import type { DateTimeFormatParams as Params, DateTimeFormatReturn as Return } from './internaltypes';
const DATE = Symbol('date');
const YM = Symbol('ym');
const MD = Symbol('md');
const TIME = Symbol('time');
const DATETIME = Symbol('datetime');
const INST = Symbol('instant');
const ORIGINAL = Symbol('original');
const TZ_RESOLVED = Symbol('timezone');
const CAL_ID = Symbol('calendar-id');
const LOCALE = Symbol('locale');
const OPTIONS = Symbol('options');
const descriptor = <T extends (...args: any[]) => any>(value: T) => {
return {
value,
enumerable: true,
writable: false,
configurable: true
};
};
const IntlDateTimeFormat = globalThis.Intl.DateTimeFormat;
const ObjectAssign = Object.assign;
const ObjectHasOwnProperty = Object.prototype.hasOwnProperty;
const ReflectApply = Reflect.apply;
interface CustomFormatters {
[DATE]: typeof dateAmend | globalThis.Intl.DateTimeFormat;
[YM]: typeof yearMonthAmend | typeof globalThis.Intl.DateTimeFormat;
[MD]: typeof monthDayAmend | typeof globalThis.Intl.DateTimeFormat;
[TIME]: typeof timeAmend | typeof globalThis.Intl.DateTimeFormat;
[DATETIME]: typeof datetimeAmend | typeof globalThis.Intl.DateTimeFormat;
[INST]: typeof instantAmend | typeof globalThis.Intl.DateTimeFormat;
}
interface PrivateProps extends CustomFormatters {
[ORIGINAL]: globalThis.Intl.DateTimeFormat;
[TZ_RESOLVED]: string | Temporal.TimeZoneProtocol;
[CAL_ID]: globalThis.Intl.ResolvedDateTimeFormatOptions['calendar'];
[LOCALE]: globalThis.Intl.ResolvedDateTimeFormatOptions['locale'];
[OPTIONS]: Intl.DateTimeFormatOptions;
}
type OptionsAmenderFunction = (options: Intl.DateTimeFormatOptions) => globalThis.Intl.DateTimeFormatOptions;
type FormatterOrAmender = globalThis.Intl.DateTimeFormat | OptionsAmenderFunction;
// Construction of built-in Intl.DateTimeFormat objects is sloooooow,
// so we'll only create those instances when we need them.
// See https://bugs.chromium.org/p/v8/issues/detail?id=6528
function getPropLazy<T extends PrivateProps, P extends keyof CustomFormatters>(
obj: T,
prop: P
): globalThis.Intl.DateTimeFormat {
let val = obj[prop] as FormatterOrAmender;
if (typeof val === 'function') {
// If we get here, `val` is an "amender function". It will take the user's
// options and transform them into suitable options to be passed into the
// built-in (non-polyfill) Intl.DateTimeFormat constructor. These options
// will vary depending on the Temporal type, so that's why we store separate
// formatters in separate props on the polyfill's DateTimeFormat instances.
// The efficiency happens because we don't create an (expensive) formatter
// until the user calls toLocaleString for that Temporal type.
val = new IntlDateTimeFormat(obj[LOCALE], val(obj[OPTIONS]));
// TODO: can this be typed more cleanly?
(obj[prop] as globalThis.Intl.DateTimeFormat) = val;
}
return val;
}
type DateTimeFormatImpl = Intl.DateTimeFormat & PrivateProps;
function DateTimeFormatImpl(
this: Intl.DateTimeFormat & PrivateProps,
locale: Params['constructor'][0] = undefined,
optionsParam: Params['constructor'][1] = {}
) {
if (!(this instanceof DateTimeFormatImpl)) {
type Construct = new (
locale: Params['constructor'][0],
optionsParam: Params['constructor'][1]
) => Intl.DateTimeFormat;
return new (DateTimeFormatImpl as unknown as Construct)(locale, optionsParam);
}
const hasOptions = typeof optionsParam !== 'undefined';
const options = hasOptions ? ObjectAssign({}, optionsParam) : {};
// TODO: remove type assertion after Temporal types land in TS lib types
const original = new IntlDateTimeFormat(locale, options as globalThis.Intl.DateTimeFormatOptions);
const ro = original.resolvedOptions();
// DateTimeFormat instances are very expensive to create. Therefore, they will
// be lazily created only when needed, using the locale and options provided.
// But it's possible for callers to mutate those inputs before lazy creation
// happens. For this reason, we clone the inputs instead of caching the
// original objects. To avoid the complexity of deep cloning any inputs that
// are themselves objects (e.g. the locales array, or options property values
// that will be coerced to strings), we rely on `resolvedOptions()` to do the
// coercion and cloning for us. Unfortunately, we can't just use the resolved
// options as-is because our options-amending logic adds additional fields if
// the user doesn't supply any unit fields like year, month, day, hour, etc.
// Therefore, we limit the properties in the clone to properties that were
// present in the original input.
if (hasOptions) {
const clonedResolved = ObjectAssign({}, ro);
for (const prop in clonedResolved) {
if (!ReflectApply(ObjectHasOwnProperty, options, [prop])) {
delete clonedResolved[prop as keyof typeof clonedResolved];
}
}
this[OPTIONS] = clonedResolved as Intl.DateTimeFormatOptions;
} else {
this[OPTIONS] = options;
}
this[LOCALE] = ro.locale;
this[ORIGINAL] = original;
this[TZ_RESOLVED] = ro.timeZone;
this[CAL_ID] = ro.calendar;
this[DATE] = dateAmend;
this[YM] = yearMonthAmend;
this[MD] = monthDayAmend;
this[TIME] = timeAmend;
this[DATETIME] = datetimeAmend;
this[INST] = instantAmend;
return undefined; // TODO: I couldn't satisfy TS without adding this. Is there another way?
}
Object.defineProperty(DateTimeFormatImpl, 'name', {
writable: true,
value: 'DateTimeFormat'
});
DateTimeFormatImpl.supportedLocalesOf = function (
locales: Params['supportedLocalesOf'][0],
options: Params['supportedLocalesOf'][1]
) {
return IntlDateTimeFormat.supportedLocalesOf(locales, options as globalThis.Intl.DateTimeFormatOptions);
};
const propertyDescriptors: Partial<Record<keyof Intl.DateTimeFormat, PropertyDescriptor>> = {
resolvedOptions: descriptor(resolvedOptions),
format: descriptor(format),
formatRange: descriptor(formatRange)
};
if ('formatToParts' in IntlDateTimeFormat.prototype) {
propertyDescriptors.formatToParts = descriptor(formatToParts);
}
if ('formatRangeToParts' in IntlDateTimeFormat.prototype) {
propertyDescriptors.formatRangeToParts = descriptor(formatRangeToParts);
}
DateTimeFormatImpl.prototype = Object.create(IntlDateTimeFormat.prototype, propertyDescriptors);
// Ensure that the prototype isn't writeable.
Object.defineProperty(DateTimeFormatImpl, 'prototype', {
writable: false,
enumerable: false,
configurable: false
});
export const DateTimeFormat = DateTimeFormatImpl as unknown as typeof Intl.DateTimeFormat;
function resolvedOptions(this: DateTimeFormatImpl): Return['resolvedOptions'] {
return this[ORIGINAL].resolvedOptions();
}
// TODO: investigate why there's a rest parameter here. Does this function really need to accept extra params?
// And if so, why doesn't formatRange also accept extra params?
function format<P extends readonly unknown[]>(
this: DateTimeFormatImpl,
datetime: Params['format'][0],
...rest: P
): Return['format'] {
let { instant, formatter } = extractOverrides(datetime, this);
if (instant && formatter) {
return formatter.format(instant.epochMilliseconds);
}
// Support spreading additional args for future expansion of this Intl method
type AllowExtraParams = (datetime: Parameters<Intl.DateTimeFormat['format']>[0], ...rest: P) => Return['format'];
return (this[ORIGINAL].format as unknown as AllowExtraParams)(datetime, ...rest);
}
function formatToParts<P extends readonly unknown[]>(
this: DateTimeFormatImpl,
datetime: Params['formatToParts'][0],
...rest: P
): Return['formatToParts'] {
let { instant, formatter } = extractOverrides(datetime, this);
if (instant && formatter) {
return formatter.formatToParts(instant.epochMilliseconds);
}
// Support spreading additional args for future expansion of this Intl method
type AllowExtraParams = (
datetime: Parameters<Intl.DateTimeFormat['formatToParts']>[0],
...rest: P
) => Return['formatToParts'];
return (this[ORIGINAL].formatToParts as unknown as AllowExtraParams)(datetime, ...rest);
}
function formatRange(this: DateTimeFormatImpl, a: Params['formatRange'][0], b: Params['formatRange'][1]) {
if (isTemporalObject(a) || isTemporalObject(b)) {
if (!sameTemporalType(a, b)) {
throw new TypeError('Intl.DateTimeFormat.formatRange accepts two values of the same type');
}
const { instant: aa, formatter: aformatter } = extractOverrides(a as unknown as TypesWithToLocaleString, this);
const { instant: bb, formatter: bformatter } = extractOverrides(b as unknown as TypesWithToLocaleString, this);
if (aa && bb && aformatter && bformatter && aformatter === bformatter) {
// TODO: Remove type assertion after this method lands in TS lib types
return (aformatter as Intl.DateTimeFormat).formatRange(aa.epochMilliseconds, bb.epochMilliseconds);
}
}
// TODO: Remove type assertion after this method lands in TS lib types
return (this[ORIGINAL] as Intl.DateTimeFormat).formatRange(a, b);
}
function formatRangeToParts(
this: DateTimeFormatImpl,
a: Params['formatRangeToParts'][0],
b: Params['formatRangeToParts'][1]
) {
if (isTemporalObject(a) || isTemporalObject(b)) {
if (!sameTemporalType(a, b)) {
throw new TypeError('Intl.DateTimeFormat.formatRangeToParts accepts two values of the same type');
}
const { instant: aa, formatter: aformatter } = extractOverrides(a, this);
const { instant: bb, formatter: bformatter } = extractOverrides(b, this);
if (aa && bb && aformatter && bformatter && aformatter === bformatter) {
// TODO: Remove type assertion after this method lands in TS lib types
return (aformatter as Intl.DateTimeFormat).formatRangeToParts(aa.epochMilliseconds, bb.epochMilliseconds);
}
}
// TODO: Remove type assertion after this method lands in TS lib types
return (this[ORIGINAL] as Intl.DateTimeFormat).formatRangeToParts(a, b);
}
// "false" is a signal to delete this option
type MaybeFalseOptions = {
[K in keyof Intl.DateTimeFormatOptions]?: Intl.DateTimeFormatOptions[K] | false;
};
function amend(optionsParam: Intl.DateTimeFormatOptions = {}, amended: MaybeFalseOptions = {}) {
const options = ObjectAssign({}, optionsParam);
for (const opt of [
'year',
'month',
'day',
'hour',
'minute',
'second',
'weekday',
'dayPeriod',
'timeZoneName',
'dateStyle',
'timeStyle'
] as const) {
// TODO: can this be typed more cleanly?
type OptionMaybeFalse = typeof options[typeof opt] | false;
(options[opt] as OptionMaybeFalse) = opt in amended ? amended[opt] : options[opt];
if ((options[opt] as OptionMaybeFalse) === false || options[opt] === undefined) delete options[opt];
}
return options as globalThis.Intl.DateTimeFormatOptions;
}
type OptionsType<T extends TypesWithToLocaleString> = NonNullable<Parameters<T['toLocaleString']>[1]>;
function timeAmend(optionsParam: OptionsType<Temporal.PlainTime>) {
let options = amend(optionsParam, {
year: false,
month: false,
day: false,
weekday: false,
timeZoneName: false,
dateStyle: false
});
if (!hasTimeOptions(options)) {
options = ObjectAssign({}, options, {
hour: 'numeric',
minute: 'numeric',
second: 'numeric'
});
}
return options;
}
function yearMonthAmend(optionsParam: OptionsType<Temporal.PlainYearMonth>) {
let options = amend(optionsParam, {
day: false,
hour: false,
minute: false,
second: false,
weekday: false,
dayPeriod: false,
timeZoneName: false,
dateStyle: false,
timeStyle: false
});
if (!('year' in options || 'month' in options)) {
options = ObjectAssign(options, { year: 'numeric', month: 'numeric' });
}
return options;
}
function monthDayAmend(optionsParam: OptionsType<Temporal.PlainMonthDay>) {
let options = amend(optionsParam, {
year: false,
hour: false,
minute: false,
second: false,
weekday: false,
dayPeriod: false,
timeZoneName: false,
dateStyle: false,
timeStyle: false
});
if (!('month' in options || 'day' in options)) {
options = ObjectAssign({}, options, { month: 'numeric', day: 'numeric' });
}
return options;
}
function dateAmend(optionsParam: OptionsType<Temporal.PlainDate>) {
let options = amend(optionsParam, {
hour: false,
minute: false,
second: false,
dayPeriod: false,
timeZoneName: false,
timeStyle: false
});
if (!hasDateOptions(options)) {
options = ObjectAssign({}, options, {
year: 'numeric',
month: 'numeric',
day: 'numeric'
});
}
return options;
}
function datetimeAmend(optionsParam: OptionsType<Temporal.PlainDateTime>) {
let options = amend(optionsParam, { timeZoneName: false });
if (!hasTimeOptions(options) && !hasDateOptions(options)) {
options = ObjectAssign({}, options, {
year: 'numeric',
month: 'numeric',
day: 'numeric',
hour: 'numeric',
minute: 'numeric',
second: 'numeric'
});
}
return options;
}
function instantAmend(optionsParam: OptionsType<Temporal.Instant>) {
let options = optionsParam;
if (!hasTimeOptions(options) && !hasDateOptions(options)) {
options = ObjectAssign({}, options, {
year: 'numeric',
month: 'numeric',
day: 'numeric',
hour: 'numeric',
minute: 'numeric',
second: 'numeric'
});
}
return options;
}
function hasDateOptions(options: OptionsType<TypesWithToLocaleString>) {
return 'year' in options || 'month' in options || 'day' in options || 'weekday' in options || 'dateStyle' in options;
}
function hasTimeOptions(options: OptionsType<TypesWithToLocaleString>) {
return (
'hour' in options || 'minute' in options || 'second' in options || 'timeStyle' in options || 'dayPeriod' in options
);
}
function isTemporalObject(
obj: unknown
): obj is
| Temporal.PlainDate
| Temporal.PlainTime
| Temporal.PlainDateTime
| Temporal.ZonedDateTime
| Temporal.PlainYearMonth
| Temporal.PlainMonthDay
| Temporal.Instant {
return (
ES.IsTemporalDate(obj) ||
ES.IsTemporalTime(obj) ||
ES.IsTemporalDateTime(obj) ||
ES.IsTemporalZonedDateTime(obj) ||
ES.IsTemporalYearMonth(obj) ||
ES.IsTemporalMonthDay(obj) ||
ES.IsTemporalInstant(obj)
);
}
function sameTemporalType(x: unknown, y: unknown) {
if (!isTemporalObject(x) || !isTemporalObject(y)) return false;
if (ES.IsTemporalTime(x) && !ES.IsTemporalTime(y)) return false;
if (ES.IsTemporalDate(x) && !ES.IsTemporalDate(y)) return false;
if (ES.IsTemporalDateTime(x) && !ES.IsTemporalDateTime(y)) return false;
if (ES.IsTemporalZonedDateTime(x) && !ES.IsTemporalZonedDateTime(y)) return false;
if (ES.IsTemporalYearMonth(x) && !ES.IsTemporalYearMonth(y)) return false;
if (ES.IsTemporalMonthDay(x) && !ES.IsTemporalMonthDay(y)) return false;
if (ES.IsTemporalInstant(x) && !ES.IsTemporalInstant(y)) return false;
return true;
}
type TypesWithToLocaleString =
| Temporal.PlainDateTime
| Temporal.PlainDate
| Temporal.PlainTime
| Temporal.PlainYearMonth
| Temporal.PlainMonthDay
| Temporal.ZonedDateTime
| Temporal.Instant;
function extractOverrides(temporalObj: Params['format'][0], main: DateTimeFormatImpl) {
const DateTime = GetIntrinsic('%Temporal.PlainDateTime%');
if (ES.IsTemporalTime(temporalObj)) {
const hour = GetSlot(temporalObj, ISO_HOUR);
const minute = GetSlot(temporalObj, ISO_MINUTE);
const second = GetSlot(temporalObj, ISO_SECOND);
const millisecond = GetSlot(temporalObj, ISO_MILLISECOND);
const microsecond = GetSlot(temporalObj, ISO_MICROSECOND);
const nanosecond = GetSlot(temporalObj, ISO_NANOSECOND);
const datetime = new DateTime(1970, 1, 1, hour, minute, second, millisecond, microsecond, nanosecond, main[CAL_ID]);
return {
instant: ES.GetInstantFor(main[TZ_RESOLVED], datetime, 'compatible'),
formatter: getPropLazy(main, TIME)
};
}
if (ES.IsTemporalYearMonth(temporalObj)) {
const isoYear = GetSlot(temporalObj, ISO_YEAR);
const isoMonth = GetSlot(temporalObj, ISO_MONTH);
const referenceISODay = GetSlot(temporalObj, ISO_DAY);
const calendar = ES.ToTemporalCalendarIdentifier(GetSlot(temporalObj, CALENDAR));
if (calendar !== main[CAL_ID]) {
throw new RangeError(
`cannot format PlainYearMonth with calendar ${calendar} in locale with calendar ${main[CAL_ID]}`
);
}
const datetime = new DateTime(isoYear, isoMonth, referenceISODay, 12, 0, 0, 0, 0, 0, calendar);
return {
instant: ES.GetInstantFor(main[TZ_RESOLVED], datetime, 'compatible'),
formatter: getPropLazy(main, YM)
};
}
if (ES.IsTemporalMonthDay(temporalObj)) {
const referenceISOYear = GetSlot(temporalObj, ISO_YEAR);
const isoMonth = GetSlot(temporalObj, ISO_MONTH);
const isoDay = GetSlot(temporalObj, ISO_DAY);
const calendar = ES.ToTemporalCalendarIdentifier(GetSlot(temporalObj, CALENDAR));
if (calendar !== main[CAL_ID]) {
throw new RangeError(
`cannot format PlainMonthDay with calendar ${calendar} in locale with calendar ${main[CAL_ID]}`
);
}
const datetime = new DateTime(referenceISOYear, isoMonth, isoDay, 12, 0, 0, 0, 0, 0, calendar);
return {
instant: ES.GetInstantFor(main[TZ_RESOLVED], datetime, 'compatible'),
formatter: getPropLazy(main, MD)
};
}
if (ES.IsTemporalDate(temporalObj)) {
const isoYear = GetSlot(temporalObj, ISO_YEAR);
const isoMonth = GetSlot(temporalObj, ISO_MONTH);
const isoDay = GetSlot(temporalObj, ISO_DAY);
const calendar = ES.ToTemporalCalendarIdentifier(GetSlot(temporalObj, CALENDAR));
if (calendar !== 'iso8601' && calendar !== main[CAL_ID]) {
throw new RangeError(`cannot format PlainDate with calendar ${calendar} in locale with calendar ${main[CAL_ID]}`);
}
const datetime = new DateTime(isoYear, isoMonth, isoDay, 12, 0, 0, 0, 0, 0, main[CAL_ID]);
return {
instant: ES.GetInstantFor(main[TZ_RESOLVED], datetime, 'compatible'),
formatter: getPropLazy(main, DATE)
};
}
if (ES.IsTemporalDateTime(temporalObj)) {
const isoYear = GetSlot(temporalObj, ISO_YEAR);
const isoMonth = GetSlot(temporalObj, ISO_MONTH);
const isoDay = GetSlot(temporalObj, ISO_DAY);
const hour = GetSlot(temporalObj, ISO_HOUR);
const minute = GetSlot(temporalObj, ISO_MINUTE);
const second = GetSlot(temporalObj, ISO_SECOND);
const millisecond = GetSlot(temporalObj, ISO_MILLISECOND);
const microsecond = GetSlot(temporalObj, ISO_MICROSECOND);
const nanosecond = GetSlot(temporalObj, ISO_NANOSECOND);
const calendar = ES.ToTemporalCalendarIdentifier(GetSlot(temporalObj, CALENDAR));
if (calendar !== 'iso8601' && calendar !== main[CAL_ID]) {
throw new RangeError(
`cannot format PlainDateTime with calendar ${calendar} in locale with calendar ${main[CAL_ID]}`
);
}
let datetime = temporalObj;
if (calendar === 'iso8601') {
datetime = new DateTime(
isoYear,
isoMonth,
isoDay,
hour,
minute,
second,
millisecond,
microsecond,
nanosecond,
main[CAL_ID]
);
}
return {
instant: ES.GetInstantFor(main[TZ_RESOLVED], datetime, 'compatible'),
formatter: getPropLazy(main, DATETIME)
};
}
if (ES.IsTemporalZonedDateTime(temporalObj)) {
throw new TypeError(
'Temporal.ZonedDateTime not supported in DateTimeFormat methods. Use toLocaleString() instead.'
);
}
if (ES.IsTemporalInstant(temporalObj)) {
return {
instant: temporalObj,
formatter: getPropLazy(main, INST)
};
}
return {};
}
@@ -0,0 +1,165 @@
import type JSBI from 'jsbi';
import type { Temporal } from '..';
import { DEBUG } from './debug';
type OmitConstructor<T> = { [P in keyof T as T[P] extends new (...args: any[]) => any ? P : never]: T[P] };
type TemporalIntrinsics = Omit<typeof Temporal, 'Now' | 'Instant' | 'ZonedDateTime'> & {
Instant: OmitConstructor<Temporal.Instant> &
(new (epochNanoseconds: JSBI) => Temporal.Instant) & { prototype: typeof Temporal.Instant.prototype };
ZonedDateTime: OmitConstructor<Temporal.ZonedDateTime> &
(new (
epochNanoseconds: JSBI,
timeZone: string | Temporal.TimeZoneProtocol,
calendar?: string | Temporal.CalendarProtocol
) => Temporal.ZonedDateTime) & {
prototype: typeof Temporal.ZonedDateTime.prototype;
from: typeof Temporal.ZonedDateTime.from;
compare: typeof Temporal.ZonedDateTime.compare;
};
};
type TemporalIntrinsicRegistrations = {
[key in keyof TemporalIntrinsics as `Temporal.${key}`]: TemporalIntrinsics[key];
};
type TemporalIntrinsicPrototypeRegistrations = {
[key in keyof TemporalIntrinsics as `Temporal.${key}.prototype`]: TemporalIntrinsics[key]['prototype'];
};
type TemporalIntrinsicRegisteredKeys = {
[key in keyof TemporalIntrinsicRegistrations as `%${key}%`]: TemporalIntrinsicRegistrations[key];
};
type TemporalIntrinsicPrototypeRegisteredKeys = {
[key in keyof TemporalIntrinsicPrototypeRegistrations as `%${key}%`]: TemporalIntrinsicPrototypeRegistrations[key];
};
type CalendarPrototypeKeys = keyof Omit<Temporal.Calendar, typeof Symbol.toStringTag>;
type TemporalCalendarIntrinsicRegistrations = {
[key in CalendarPrototypeKeys as `Temporal.Calendar.prototype.${key}`]: Temporal.Calendar[key];
} & {
'Temporal.Calendar.from': typeof Temporal.Calendar.from;
};
type TemporalCalendarIntrinsicRegisteredKeys = {
[key in keyof TemporalCalendarIntrinsicRegistrations as `%${key}%`]: TemporalCalendarIntrinsicRegistrations[key];
};
type TimeZonePrototypeKeys = 'getOffsetNanosecondsFor' | 'getPossibleInstantsFor';
type TemporalTimeZoneIntrinsicRegistrations = {
[key in TimeZonePrototypeKeys as `Temporal.TimeZone.prototype.${key}`]: Temporal.TimeZone[key];
} & {
'Temporal.TimeZone.from': typeof Temporal.TimeZone.from;
};
type TemporalTimeZoneIntrinsicRegisteredKeys = {
[key in keyof TemporalTimeZoneIntrinsicRegistrations as `%${key}%`]: TemporalTimeZoneIntrinsicRegistrations[key];
};
const INTRINSICS = {} as TemporalIntrinsicRegisteredKeys &
TemporalIntrinsicPrototypeRegisteredKeys &
TemporalTimeZoneIntrinsicRegisteredKeys &
TemporalCalendarIntrinsicRegisteredKeys;
type customFormatFunction<T> = (
this: T,
depth: number,
options: { stylize: (value: unknown, type: 'number' | 'special') => string }
) => string;
const customUtilInspectFormatters: Partial<{
[key in keyof TemporalIntrinsicRegistrations]: customFormatFunction<
InstanceType<TemporalIntrinsicRegistrations[key]>
>;
}> = {
['Temporal.Duration'](depth, options) {
const descr = options.stylize(`${this[Symbol.toStringTag]} <${this}>`, 'special');
if (depth < 1) return descr;
const entries = [];
for (const prop of [
'years',
'months',
'weeks',
'days',
'hours',
'minutes',
'seconds',
'milliseconds',
'microseconds',
'nanoseconds'
] as const) {
if (this[prop] !== 0) entries.push(` ${prop}: ${options.stylize(this[prop], 'number')}`);
}
return descr + ' {\n' + entries.join(',\n') + '\n}';
}
};
type InspectFormatterOptions = { stylize: (str: string, styleType: string) => string };
function defaultUtilInspectFormatter(this: any, depth: number, options: InspectFormatterOptions) {
return options.stylize(`${this[Symbol.toStringTag]} <${this}>`, 'special');
}
export function MakeIntrinsicClass(
Class: TemporalIntrinsicRegistrations[typeof name],
name: keyof TemporalIntrinsicRegistrations
) {
Object.defineProperty(Class.prototype, Symbol.toStringTag, {
value: name,
writable: false,
enumerable: false,
configurable: true
});
if (DEBUG) {
Object.defineProperty(Class.prototype, Symbol.for('nodejs.util.inspect.custom'), {
value: customUtilInspectFormatters[name] || defaultUtilInspectFormatter,
writable: false,
enumerable: false,
configurable: true
});
}
for (const prop of Object.getOwnPropertyNames(Class)) {
// we know that `prop` is present, so the descriptor is never undefined
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const desc = Object.getOwnPropertyDescriptor(Class, prop)!;
if (!desc.configurable || !desc.enumerable) continue;
desc.enumerable = false;
Object.defineProperty(Class, prop, desc);
}
for (const prop of Object.getOwnPropertyNames(Class.prototype)) {
// we know that `prop` is present, so the descriptor is never undefined
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const desc = Object.getOwnPropertyDescriptor(Class.prototype, prop)!;
if (!desc.configurable || !desc.enumerable) continue;
desc.enumerable = false;
Object.defineProperty(Class.prototype, prop, desc);
}
DefineIntrinsic(name, Class);
DefineIntrinsic(`${name}.prototype`, Class.prototype);
}
type IntrinsicDefinitionKeys =
| keyof TemporalIntrinsicRegistrations
| keyof TemporalIntrinsicPrototypeRegistrations
| keyof TemporalCalendarIntrinsicRegistrations
| keyof TemporalTimeZoneIntrinsicRegistrations;
export function DefineIntrinsic<KeyT extends keyof TemporalIntrinsicRegistrations>(
name: KeyT,
value: TemporalIntrinsicRegistrations[KeyT]
): void;
export function DefineIntrinsic<KeyT extends keyof TemporalIntrinsicPrototypeRegistrations>(
name: KeyT,
value: TemporalIntrinsicPrototypeRegistrations[KeyT]
): void;
export function DefineIntrinsic<KeyT extends keyof TemporalCalendarIntrinsicRegistrations>(
name: KeyT,
value: TemporalCalendarIntrinsicRegistrations[KeyT]
): void;
export function DefineIntrinsic<KeyT extends keyof TemporalTimeZoneIntrinsicRegistrations>(
name: KeyT,
value: TemporalTimeZoneIntrinsicRegistrations[KeyT]
): void;
export function DefineIntrinsic<KeyT>(name: KeyT, value: never): void;
export function DefineIntrinsic<KeyT extends IntrinsicDefinitionKeys>(name: KeyT, value: unknown): void {
const key: `%${IntrinsicDefinitionKeys}%` = `%${name}%`;
if (INTRINSICS[key] !== undefined) throw new Error(`intrinsic ${name} already exists`);
INTRINSICS[key] = value;
}
export function GetIntrinsic<KeyT extends keyof typeof INTRINSICS>(intrinsic: KeyT): typeof INTRINSICS[KeyT] {
return INTRINSICS[intrinsic];
}
+10
View File
@@ -0,0 +1,10 @@
import { Instant } from './instant';
import JSBI from 'jsbi';
import { MILLION } from './ecmascript';
export function toTemporalInstant(this: Date) {
// Observable access to valueOf is not correct here, but unavoidable
const epochNanoseconds = JSBI.multiply(JSBI.BigInt(+this), MILLION);
return new Instant(epochNanoseconds);
}
+64
View File
@@ -0,0 +1,64 @@
import * as ES from './ecmascript';
import { GetIntrinsic } from './intrinsicclass';
import type { Temporal } from '..';
const instant: typeof Temporal.Now['instant'] = () => {
const Instant = GetIntrinsic('%Temporal.Instant%');
return new Instant(ES.SystemUTCEpochNanoSeconds());
};
const plainDateTime: typeof Temporal.Now['plainDateTime'] = (
calendarLike,
temporalTimeZoneLike = ES.DefaultTimeZone()
) => {
const tZ = ES.ToTemporalTimeZoneSlotValue(temporalTimeZoneLike);
const calendar = ES.ToTemporalCalendarSlotValue(calendarLike);
const inst = instant();
return ES.GetPlainDateTimeFor(tZ, inst, calendar);
};
const plainDateTimeISO: typeof Temporal.Now['plainDateTimeISO'] = (temporalTimeZoneLike = ES.DefaultTimeZone()) => {
const tZ = ES.ToTemporalTimeZoneSlotValue(temporalTimeZoneLike);
const inst = instant();
return ES.GetPlainDateTimeFor(tZ, inst, 'iso8601');
};
const zonedDateTime: typeof Temporal.Now['zonedDateTime'] = (
calendarLike,
temporalTimeZoneLike = ES.DefaultTimeZone()
) => {
const tZ = ES.ToTemporalTimeZoneSlotValue(temporalTimeZoneLike);
const calendar = ES.ToTemporalCalendarSlotValue(calendarLike);
return ES.CreateTemporalZonedDateTime(ES.SystemUTCEpochNanoSeconds(), tZ, calendar);
};
const zonedDateTimeISO: typeof Temporal.Now['zonedDateTimeISO'] = (temporalTimeZoneLike = ES.DefaultTimeZone()) => {
return zonedDateTime('iso8601', temporalTimeZoneLike);
};
const plainDate: typeof Temporal.Now['plainDate'] = (calendarLike, temporalTimeZoneLike = ES.DefaultTimeZone()) => {
return ES.TemporalDateTimeToDate(plainDateTime(calendarLike, temporalTimeZoneLike));
};
const plainDateISO: typeof Temporal.Now['plainDateISO'] = (temporalTimeZoneLike = ES.DefaultTimeZone()) => {
return ES.TemporalDateTimeToDate(plainDateTimeISO(temporalTimeZoneLike));
};
const plainTimeISO: typeof Temporal.Now['plainTimeISO'] = (temporalTimeZoneLike = ES.DefaultTimeZone()) => {
return ES.TemporalDateTimeToTime(plainDateTimeISO(temporalTimeZoneLike));
};
const timeZoneId: typeof Temporal.Now['timeZoneId'] = () => {
return ES.DefaultTimeZone();
};
export const Now: typeof Temporal.Now = {
instant,
plainDateTime,
plainDateTimeISO,
plainDate,
plainDateISO,
plainTimeISO,
timeZoneId,
zonedDateTime,
zonedDateTimeISO,
[Symbol.toStringTag]: 'Temporal.Now'
};
Object.defineProperty(Now, Symbol.toStringTag, {
value: 'Temporal.Now',
writable: false,
enumerable: false,
configurable: true
});
+333
View File
@@ -0,0 +1,333 @@
import * as ES from './ecmascript';
import { MakeIntrinsicClass } from './intrinsicclass';
import {
ISO_YEAR,
ISO_MONTH,
ISO_DAY,
ISO_HOUR,
ISO_MINUTE,
ISO_SECOND,
ISO_MILLISECOND,
ISO_MICROSECOND,
ISO_NANOSECOND,
CALENDAR,
EPOCHNANOSECONDS,
GetSlot
} from './slots';
import type { Temporal } from '..';
import { DateTimeFormat } from './intl';
import type { PlainDateParams as Params, PlainDateReturn as Return } from './internaltypes';
export class PlainDate implements Temporal.PlainDate {
constructor(
isoYearParam: Params['constructor'][0],
isoMonthParam: Params['constructor'][1],
isoDayParam: Params['constructor'][2],
calendarParam: Params['constructor'][3] = 'iso8601'
) {
const isoYear = ES.ToIntegerWithTruncation(isoYearParam);
const isoMonth = ES.ToIntegerWithTruncation(isoMonthParam);
const isoDay = ES.ToIntegerWithTruncation(isoDayParam);
const calendar = ES.ToTemporalCalendarSlotValue(calendarParam);
ES.CreateTemporalDateSlots(this, isoYear, isoMonth, isoDay, calendar);
}
get calendarId(): Return['calendarId'] {
if (!ES.IsTemporalDate(this)) throw new TypeError('invalid receiver');
return ES.ToTemporalCalendarIdentifier(GetSlot(this, CALENDAR));
}
get era(): Return['era'] {
if (!ES.IsTemporalDate(this)) throw new TypeError('invalid receiver');
return ES.CalendarEra(GetSlot(this, CALENDAR), this);
}
get eraYear(): Return['eraYear'] {
if (!ES.IsTemporalDate(this)) throw new TypeError('invalid receiver');
return ES.CalendarEraYear(GetSlot(this, CALENDAR), this);
}
get year(): Return['year'] {
if (!ES.IsTemporalDate(this)) throw new TypeError('invalid receiver');
return ES.CalendarYear(GetSlot(this, CALENDAR), this);
}
get month(): Return['month'] {
if (!ES.IsTemporalDate(this)) throw new TypeError('invalid receiver');
return ES.CalendarMonth(GetSlot(this, CALENDAR), this);
}
get monthCode(): Return['monthCode'] {
if (!ES.IsTemporalDate(this)) throw new TypeError('invalid receiver');
return ES.CalendarMonthCode(GetSlot(this, CALENDAR), this);
}
get day(): Return['day'] {
if (!ES.IsTemporalDate(this)) throw new TypeError('invalid receiver');
return ES.CalendarDay(GetSlot(this, CALENDAR), this);
}
get dayOfWeek(): Return['dayOfWeek'] {
if (!ES.IsTemporalDate(this)) throw new TypeError('invalid receiver');
return ES.CalendarDayOfWeek(GetSlot(this, CALENDAR), this);
}
get dayOfYear(): Return['dayOfYear'] {
if (!ES.IsTemporalDate(this)) throw new TypeError('invalid receiver');
return ES.CalendarDayOfYear(GetSlot(this, CALENDAR), this);
}
get weekOfYear(): Return['weekOfYear'] {
if (!ES.IsTemporalDate(this)) throw new TypeError('invalid receiver');
return ES.CalendarWeekOfYear(GetSlot(this, CALENDAR), this);
}
get yearOfWeek(): Return['weekOfYear'] {
if (!ES.IsTemporalDate(this)) throw new TypeError('invalid receiver');
return ES.CalendarYearOfWeek(GetSlot(this, CALENDAR), this);
}
get daysInWeek(): Return['daysInWeek'] {
if (!ES.IsTemporalDate(this)) throw new TypeError('invalid receiver');
return ES.CalendarDaysInWeek(GetSlot(this, CALENDAR), this);
}
get daysInMonth(): Return['daysInMonth'] {
if (!ES.IsTemporalDate(this)) throw new TypeError('invalid receiver');
return ES.CalendarDaysInMonth(GetSlot(this, CALENDAR), this);
}
get daysInYear(): Return['daysInYear'] {
if (!ES.IsTemporalDate(this)) throw new TypeError('invalid receiver');
return ES.CalendarDaysInYear(GetSlot(this, CALENDAR), this);
}
get monthsInYear(): Return['monthsInYear'] {
if (!ES.IsTemporalDate(this)) throw new TypeError('invalid receiver');
return ES.CalendarMonthsInYear(GetSlot(this, CALENDAR), this);
}
get inLeapYear(): Return['inLeapYear'] {
if (!ES.IsTemporalDate(this)) throw new TypeError('invalid receiver');
return ES.CalendarInLeapYear(GetSlot(this, CALENDAR), this);
}
with(temporalDateLike: Params['with'][0], optionsParam: Params['with'][1] = undefined): Return['with'] {
if (!ES.IsTemporalDate(this)) throw new TypeError('invalid receiver');
if (!ES.IsObject(temporalDateLike)) {
throw new TypeError('invalid argument');
}
ES.RejectTemporalLikeObject(temporalDateLike);
const options = ES.GetOptionsObject(optionsParam);
const calendar = GetSlot(this, CALENDAR);
const fieldNames = ES.CalendarFields(calendar, ['day', 'month', 'monthCode', 'year'] as const);
let fields = ES.PrepareTemporalFields(this, fieldNames, []);
const partialDate = ES.PrepareTemporalFields(temporalDateLike, fieldNames, 'partial');
fields = ES.CalendarMergeFields(calendar, fields, partialDate);
fields = ES.PrepareTemporalFields(fields, fieldNames, []);
return ES.CalendarDateFromFields(calendar, fields, options);
}
withCalendar(calendarParam: Params['withCalendar'][0]): Return['withCalendar'] {
if (!ES.IsTemporalDate(this)) throw new TypeError('invalid receiver');
const calendar = ES.ToTemporalCalendarSlotValue(calendarParam);
return new PlainDate(GetSlot(this, ISO_YEAR), GetSlot(this, ISO_MONTH), GetSlot(this, ISO_DAY), calendar);
}
add(temporalDurationLike: Params['add'][0], optionsParam: Params['add'][1] = undefined): Return['add'] {
if (!ES.IsTemporalDate(this)) throw new TypeError('invalid receiver');
const duration = ES.ToTemporalDuration(temporalDurationLike);
const options = ES.GetOptionsObject(optionsParam);
return ES.CalendarDateAdd(GetSlot(this, CALENDAR), this, duration, options);
}
subtract(
temporalDurationLike: Params['subtract'][0],
optionsParam: Params['subtract'][1] = undefined
): Return['subtract'] {
if (!ES.IsTemporalDate(this)) throw new TypeError('invalid receiver');
const duration = ES.CreateNegatedTemporalDuration(ES.ToTemporalDuration(temporalDurationLike));
const options = ES.GetOptionsObject(optionsParam);
return ES.CalendarDateAdd(GetSlot(this, CALENDAR), this, duration, options);
}
until(other: Params['until'][0], options: Params['until'][1] = undefined): Return['until'] {
if (!ES.IsTemporalDate(this)) throw new TypeError('invalid receiver');
return ES.DifferenceTemporalPlainDate('until', this, other, options);
}
since(other: Params['since'][0], options: Params['since'][1] = undefined): Return['since'] {
if (!ES.IsTemporalDate(this)) throw new TypeError('invalid receiver');
return ES.DifferenceTemporalPlainDate('since', this, other, options);
}
equals(otherParam: Params['equals'][0]): Return['equals'] {
if (!ES.IsTemporalDate(this)) throw new TypeError('invalid receiver');
const other = ES.ToTemporalDate(otherParam);
for (const slot of [ISO_YEAR, ISO_MONTH, ISO_DAY]) {
const val1 = GetSlot(this, slot);
const val2 = GetSlot(other, slot);
if (val1 !== val2) return false;
}
return ES.CalendarEquals(GetSlot(this, CALENDAR), GetSlot(other, CALENDAR));
}
toString(optionsParam: Params['toString'][0] = undefined): string {
if (!ES.IsTemporalDate(this)) throw new TypeError('invalid receiver');
const options = ES.GetOptionsObject(optionsParam);
const showCalendar = ES.ToCalendarNameOption(options);
return ES.TemporalDateToString(this, showCalendar);
}
toJSON(): Return['toJSON'] {
if (!ES.IsTemporalDate(this)) throw new TypeError('invalid receiver');
return ES.TemporalDateToString(this);
}
toLocaleString(
locales: Params['toLocaleString'][0] = undefined,
options: Params['toLocaleString'][1] = undefined
): string {
if (!ES.IsTemporalDate(this)) throw new TypeError('invalid receiver');
return new DateTimeFormat(locales, options).format(this);
}
valueOf(): never {
throw new TypeError('use compare() or equals() to compare Temporal.PlainDate');
}
toPlainDateTime(temporalTimeParam: Params['toPlainDateTime'][0] = undefined): Return['toPlainDateTime'] {
if (!ES.IsTemporalDate(this)) throw new TypeError('invalid receiver');
const year = GetSlot(this, ISO_YEAR);
const month = GetSlot(this, ISO_MONTH);
const day = GetSlot(this, ISO_DAY);
const calendar = GetSlot(this, CALENDAR);
if (temporalTimeParam === undefined) return ES.CreateTemporalDateTime(year, month, day, 0, 0, 0, 0, 0, 0, calendar);
const temporalTime = ES.ToTemporalTime(temporalTimeParam);
const hour = GetSlot(temporalTime, ISO_HOUR);
const minute = GetSlot(temporalTime, ISO_MINUTE);
const second = GetSlot(temporalTime, ISO_SECOND);
const millisecond = GetSlot(temporalTime, ISO_MILLISECOND);
const microsecond = GetSlot(temporalTime, ISO_MICROSECOND);
const nanosecond = GetSlot(temporalTime, ISO_NANOSECOND);
return ES.CreateTemporalDateTime(
year,
month,
day,
hour,
minute,
second,
millisecond,
microsecond,
nanosecond,
calendar
);
}
toZonedDateTime(item: Params['toZonedDateTime'][0]): Return['toZonedDateTime'] {
if (!ES.IsTemporalDate(this)) throw new TypeError('invalid receiver');
type TimeZoneAndPlainTimeProps = Exclude<typeof item, string | Temporal.TimeZoneProtocol>;
let timeZone: Temporal.TimeZoneLike, temporalTime: TimeZoneAndPlainTimeProps['plainTime'];
if (ES.IsObject(item)) {
if (ES.IsTemporalTimeZone(item)) {
timeZone = item;
} else {
const timeZoneLike = (item as TimeZoneAndPlainTimeProps).timeZone;
if (timeZoneLike === undefined) {
ES.uncheckedAssertNarrowedType<Temporal.TimeZoneProtocol>(
item,
"if no timeZone property, then assume it's a custom time zone object"
);
timeZone = ES.ToTemporalTimeZoneSlotValue(item);
} else {
timeZone = ES.ToTemporalTimeZoneSlotValue(timeZoneLike);
ES.uncheckedAssertNarrowedType<TimeZoneAndPlainTimeProps>(
item,
"it's a property bag with a timeZone and optional plainTime"
);
temporalTime = item.plainTime;
}
}
} else {
timeZone = ES.ToTemporalTimeZoneSlotValue(item);
}
const year = GetSlot(this, ISO_YEAR);
const month = GetSlot(this, ISO_MONTH);
const day = GetSlot(this, ISO_DAY);
const calendar = GetSlot(this, CALENDAR);
let hour = 0,
minute = 0,
second = 0,
millisecond = 0,
microsecond = 0,
nanosecond = 0;
if (temporalTime !== undefined) {
temporalTime = ES.ToTemporalTime(temporalTime);
ES.uncheckedAssertNarrowedType<Temporal.PlainTime>(
temporalTime,
'ToTemporalTime above always returns a PlainTime'
);
hour = GetSlot(temporalTime, ISO_HOUR);
minute = GetSlot(temporalTime, ISO_MINUTE);
second = GetSlot(temporalTime, ISO_SECOND);
millisecond = GetSlot(temporalTime, ISO_MILLISECOND);
microsecond = GetSlot(temporalTime, ISO_MICROSECOND);
nanosecond = GetSlot(temporalTime, ISO_NANOSECOND);
}
const dt = ES.CreateTemporalDateTime(
year,
month,
day,
hour,
minute,
second,
millisecond,
microsecond,
nanosecond,
calendar
);
const instant = ES.GetInstantFor(timeZone, dt, 'compatible');
return ES.CreateTemporalZonedDateTime(GetSlot(instant, EPOCHNANOSECONDS), timeZone, calendar);
}
toPlainYearMonth(): Return['toPlainYearMonth'] {
if (!ES.IsTemporalDate(this)) throw new TypeError('invalid receiver');
const calendar = GetSlot(this, CALENDAR);
const fieldNames = ES.CalendarFields(calendar, ['monthCode', 'year'] as const);
const fields = ES.PrepareTemporalFields(this, fieldNames, []);
return ES.CalendarYearMonthFromFields(calendar, fields);
}
toPlainMonthDay(): Return['toPlainMonthDay'] {
if (!ES.IsTemporalDate(this)) throw new TypeError('invalid receiver');
const calendar = GetSlot(this, CALENDAR);
const fieldNames = ES.CalendarFields(calendar, ['day', 'monthCode'] as const);
const fields = ES.PrepareTemporalFields(this, fieldNames, []);
return ES.CalendarMonthDayFromFields(calendar, fields);
}
getISOFields(): Return['getISOFields'] {
if (!ES.IsTemporalDate(this)) throw new TypeError('invalid receiver');
return {
calendar: GetSlot(this, CALENDAR),
isoDay: GetSlot(this, ISO_DAY),
isoMonth: GetSlot(this, ISO_MONTH),
isoYear: GetSlot(this, ISO_YEAR)
};
}
getCalendar(): Return['getCalendar'] {
if (!ES.IsTemporalDate(this)) throw new TypeError('invalid receiver');
return ES.ToTemporalCalendarObject(GetSlot(this, CALENDAR));
}
static from(item: Params['from'][0], optionsParam: Params['from'][1] = undefined): Return['from'] {
const options = ES.GetOptionsObject(optionsParam);
if (ES.IsTemporalDate(item)) {
ES.ToTemporalOverflow(options); // validate and ignore
return ES.CreateTemporalDate(
GetSlot(item, ISO_YEAR),
GetSlot(item, ISO_MONTH),
GetSlot(item, ISO_DAY),
GetSlot(item, CALENDAR)
);
}
return ES.ToTemporalDate(item, options);
}
static compare(oneParam: Params['compare'][0], twoParam: Params['compare'][1]): Return['compare'] {
const one = ES.ToTemporalDate(oneParam);
const two = ES.ToTemporalDate(twoParam);
return ES.CompareISODate(
GetSlot(one, ISO_YEAR),
GetSlot(one, ISO_MONTH),
GetSlot(one, ISO_DAY),
GetSlot(two, ISO_YEAR),
GetSlot(two, ISO_MONTH),
GetSlot(two, ISO_DAY)
);
}
[Symbol.toStringTag]!: 'Temporal.PlainDate';
}
MakeIntrinsicClass(PlainDate, 'Temporal.PlainDate');
+485
View File
@@ -0,0 +1,485 @@
import * as ES from './ecmascript';
import { MakeIntrinsicClass } from './intrinsicclass';
import {
ISO_YEAR,
ISO_MONTH,
ISO_DAY,
ISO_HOUR,
ISO_MINUTE,
ISO_SECOND,
ISO_MILLISECOND,
ISO_MICROSECOND,
ISO_NANOSECOND,
CALENDAR,
EPOCHNANOSECONDS,
GetSlot
} from './slots';
import type { Temporal } from '..';
import { DateTimeFormat } from './intl';
import type { PlainDateTimeParams as Params, PlainDateTimeReturn as Return } from './internaltypes';
export class PlainDateTime implements Temporal.PlainDateTime {
constructor(
isoYearParam: Params['constructor'][0],
isoMonthParam: Params['constructor'][1],
isoDayParam: Params['constructor'][2],
hourParam: Params['constructor'][3] = 0,
minuteParam: Params['constructor'][4] = 0,
secondParam: Params['constructor'][5] = 0,
millisecondParam: Params['constructor'][6] = 0,
microsecondParam: Params['constructor'][7] = 0,
nanosecondParam: Params['constructor'][8] = 0,
calendarParam: Params['constructor'][9] = 'iso8601'
) {
const isoYear = ES.ToIntegerWithTruncation(isoYearParam);
const isoMonth = ES.ToIntegerWithTruncation(isoMonthParam);
const isoDay = ES.ToIntegerWithTruncation(isoDayParam);
const hour = hourParam === undefined ? 0 : ES.ToIntegerWithTruncation(hourParam);
const minute = minuteParam === undefined ? 0 : ES.ToIntegerWithTruncation(minuteParam);
const second = secondParam === undefined ? 0 : ES.ToIntegerWithTruncation(secondParam);
const millisecond = millisecondParam === undefined ? 0 : ES.ToIntegerWithTruncation(millisecondParam);
const microsecond = microsecondParam === undefined ? 0 : ES.ToIntegerWithTruncation(microsecondParam);
const nanosecond = nanosecondParam === undefined ? 0 : ES.ToIntegerWithTruncation(nanosecondParam);
const calendar = ES.ToTemporalCalendarSlotValue(calendarParam);
ES.CreateTemporalDateTimeSlots(
this,
isoYear,
isoMonth,
isoDay,
hour,
minute,
second,
millisecond,
microsecond,
nanosecond,
calendar
);
}
get calendarId(): Return['calendarId'] {
if (!ES.IsTemporalDateTime(this)) throw new TypeError('invalid receiver');
return ES.ToTemporalCalendarIdentifier(GetSlot(this, CALENDAR));
}
get year(): Return['year'] {
if (!ES.IsTemporalDateTime(this)) throw new TypeError('invalid receiver');
return ES.CalendarYear(GetSlot(this, CALENDAR), this);
}
get month(): Return['month'] {
if (!ES.IsTemporalDateTime(this)) throw new TypeError('invalid receiver');
return ES.CalendarMonth(GetSlot(this, CALENDAR), this);
}
get monthCode(): Return['monthCode'] {
if (!ES.IsTemporalDateTime(this)) throw new TypeError('invalid receiver');
return ES.CalendarMonthCode(GetSlot(this, CALENDAR), this);
}
get day(): Return['day'] {
if (!ES.IsTemporalDateTime(this)) throw new TypeError('invalid receiver');
return ES.CalendarDay(GetSlot(this, CALENDAR), this);
}
get hour(): Return['hour'] {
if (!ES.IsTemporalDateTime(this)) throw new TypeError('invalid receiver');
return GetSlot(this, ISO_HOUR);
}
get minute(): Return['minute'] {
if (!ES.IsTemporalDateTime(this)) throw new TypeError('invalid receiver');
return GetSlot(this, ISO_MINUTE);
}
get second(): Return['second'] {
if (!ES.IsTemporalDateTime(this)) throw new TypeError('invalid receiver');
return GetSlot(this, ISO_SECOND);
}
get millisecond(): Return['millisecond'] {
if (!ES.IsTemporalDateTime(this)) throw new TypeError('invalid receiver');
return GetSlot(this, ISO_MILLISECOND);
}
get microsecond(): Return['microsecond'] {
if (!ES.IsTemporalDateTime(this)) throw new TypeError('invalid receiver');
return GetSlot(this, ISO_MICROSECOND);
}
get nanosecond(): Return['nanosecond'] {
if (!ES.IsTemporalDateTime(this)) throw new TypeError('invalid receiver');
return GetSlot(this, ISO_NANOSECOND);
}
get era(): Return['era'] {
if (!ES.IsTemporalDateTime(this)) throw new TypeError('invalid receiver');
return ES.CalendarEra(GetSlot(this, CALENDAR), this);
}
get eraYear(): Return['eraYear'] {
if (!ES.IsTemporalDateTime(this)) throw new TypeError('invalid receiver');
return ES.CalendarEraYear(GetSlot(this, CALENDAR), this);
}
get dayOfWeek(): Return['dayOfWeek'] {
if (!ES.IsTemporalDateTime(this)) throw new TypeError('invalid receiver');
return ES.CalendarDayOfWeek(GetSlot(this, CALENDAR), this);
}
get dayOfYear(): Return['dayOfYear'] {
if (!ES.IsTemporalDateTime(this)) throw new TypeError('invalid receiver');
return ES.CalendarDayOfYear(GetSlot(this, CALENDAR), this);
}
get weekOfYear(): Return['weekOfYear'] {
if (!ES.IsTemporalDateTime(this)) throw new TypeError('invalid receiver');
return ES.CalendarWeekOfYear(GetSlot(this, CALENDAR), this);
}
get yearOfWeek(): Return['yearOfWeek'] {
if (!ES.IsTemporalDateTime(this)) throw new TypeError('invalid receiver');
return ES.CalendarYearOfWeek(GetSlot(this, CALENDAR), this);
}
get daysInWeek(): Return['daysInWeek'] {
if (!ES.IsTemporalDateTime(this)) throw new TypeError('invalid receiver');
return ES.CalendarDaysInWeek(GetSlot(this, CALENDAR), this);
}
get daysInYear(): Return['daysInYear'] {
if (!ES.IsTemporalDateTime(this)) throw new TypeError('invalid receiver');
return ES.CalendarDaysInYear(GetSlot(this, CALENDAR), this);
}
get daysInMonth(): Return['daysInMonth'] {
if (!ES.IsTemporalDateTime(this)) throw new TypeError('invalid receiver');
return ES.CalendarDaysInMonth(GetSlot(this, CALENDAR), this);
}
get monthsInYear(): Return['monthsInYear'] {
if (!ES.IsTemporalDateTime(this)) throw new TypeError('invalid receiver');
return ES.CalendarMonthsInYear(GetSlot(this, CALENDAR), this);
}
get inLeapYear(): Return['inLeapYear'] {
if (!ES.IsTemporalDateTime(this)) throw new TypeError('invalid receiver');
return ES.CalendarInLeapYear(GetSlot(this, CALENDAR), this);
}
with(temporalDateTimeLike: Params['with'][0], optionsParam: Params['with'][1] = undefined): Return['with'] {
if (!ES.IsTemporalDateTime(this)) throw new TypeError('invalid receiver');
if (!ES.IsObject(temporalDateTimeLike)) {
throw new TypeError('invalid argument');
}
ES.RejectTemporalLikeObject(temporalDateTimeLike);
const options = ES.GetOptionsObject(optionsParam);
const calendar = GetSlot(this, CALENDAR);
const fieldNames = ES.CalendarFields(calendar, [
'day',
'hour',
'microsecond',
'millisecond',
'minute',
'month',
'monthCode',
'nanosecond',
'second',
'year'
] as const);
let fields = ES.PrepareTemporalFields(this, fieldNames, []);
const partialDateTime = ES.PrepareTemporalFields(temporalDateTimeLike, fieldNames, 'partial');
fields = ES.CalendarMergeFields(calendar, fields, partialDateTime);
fields = ES.PrepareTemporalFields(fields, fieldNames, []);
const { year, month, day, hour, minute, second, millisecond, microsecond, nanosecond } =
ES.InterpretTemporalDateTimeFields(calendar, fields, options);
return ES.CreateTemporalDateTime(
year,
month,
day,
hour,
minute,
second,
millisecond,
microsecond,
nanosecond,
calendar
);
}
withPlainTime(temporalTimeParam: Params['withPlainTime'][0] = undefined): Return['withPlainTime'] {
if (!ES.IsTemporalDateTime(this)) throw new TypeError('invalid receiver');
const year = GetSlot(this, ISO_YEAR);
const month = GetSlot(this, ISO_MONTH);
const day = GetSlot(this, ISO_DAY);
const calendar = GetSlot(this, CALENDAR);
if (temporalTimeParam === undefined) return ES.CreateTemporalDateTime(year, month, day, 0, 0, 0, 0, 0, 0, calendar);
const temporalTime = ES.ToTemporalTime(temporalTimeParam);
const hour = GetSlot(temporalTime, ISO_HOUR);
const minute = GetSlot(temporalTime, ISO_MINUTE);
const second = GetSlot(temporalTime, ISO_SECOND);
const millisecond = GetSlot(temporalTime, ISO_MILLISECOND);
const microsecond = GetSlot(temporalTime, ISO_MICROSECOND);
const nanosecond = GetSlot(temporalTime, ISO_NANOSECOND);
return ES.CreateTemporalDateTime(
year,
month,
day,
hour,
minute,
second,
millisecond,
microsecond,
nanosecond,
calendar
);
}
withPlainDate(temporalDateParam: Params['withPlainDate'][0]): Return['withPlainDate'] {
if (!ES.IsTemporalDateTime(this)) throw new TypeError('invalid receiver');
const temporalDate = ES.ToTemporalDate(temporalDateParam);
const year = GetSlot(temporalDate, ISO_YEAR);
const month = GetSlot(temporalDate, ISO_MONTH);
const day = GetSlot(temporalDate, ISO_DAY);
let calendar = GetSlot(temporalDate, CALENDAR);
const hour = GetSlot(this, ISO_HOUR);
const minute = GetSlot(this, ISO_MINUTE);
const second = GetSlot(this, ISO_SECOND);
const millisecond = GetSlot(this, ISO_MILLISECOND);
const microsecond = GetSlot(this, ISO_MICROSECOND);
const nanosecond = GetSlot(this, ISO_NANOSECOND);
calendar = ES.ConsolidateCalendars(GetSlot(this, CALENDAR), calendar);
return ES.CreateTemporalDateTime(
year,
month,
day,
hour,
minute,
second,
millisecond,
microsecond,
nanosecond,
calendar
);
}
withCalendar(calendarParam: Params['withCalendar'][0]): Return['withCalendar'] {
if (!ES.IsTemporalDateTime(this)) throw new TypeError('invalid receiver');
const calendar = ES.ToTemporalCalendarSlotValue(calendarParam);
return new PlainDateTime(
GetSlot(this, ISO_YEAR),
GetSlot(this, ISO_MONTH),
GetSlot(this, ISO_DAY),
GetSlot(this, ISO_HOUR),
GetSlot(this, ISO_MINUTE),
GetSlot(this, ISO_SECOND),
GetSlot(this, ISO_MILLISECOND),
GetSlot(this, ISO_MICROSECOND),
GetSlot(this, ISO_NANOSECOND),
calendar
);
}
add(temporalDurationLike: Params['add'][0], options: Params['add'][1] = undefined): Return['add'] {
if (!ES.IsTemporalDateTime(this)) throw new TypeError('invalid receiver');
return ES.AddDurationToOrSubtractDurationFromPlainDateTime('add', this, temporalDurationLike, options);
}
subtract(
temporalDurationLike: Params['subtract'][0],
options: Params['subtract'][1] = undefined
): Return['subtract'] {
if (!ES.IsTemporalDateTime(this)) throw new TypeError('invalid receiver');
return ES.AddDurationToOrSubtractDurationFromPlainDateTime('subtract', this, temporalDurationLike, options);
}
until(other: Params['until'][0], options: Params['until'][1] = undefined): Return['until'] {
if (!ES.IsTemporalDateTime(this)) throw new TypeError('invalid receiver');
return ES.DifferenceTemporalPlainDateTime('until', this, other, options);
}
since(other: Params['since'][0], options: Params['since'][1] = undefined): Return['since'] {
if (!ES.IsTemporalDateTime(this)) throw new TypeError('invalid receiver');
return ES.DifferenceTemporalPlainDateTime('since', this, other, options);
}
round(roundToParam: Params['round'][0]): Return['round'] {
if (!ES.IsTemporalDateTime(this)) throw new TypeError('invalid receiver');
if (roundToParam === undefined) throw new TypeError('options parameter is required');
const roundTo =
typeof roundToParam === 'string'
? (ES.CreateOnePropObject('smallestUnit', roundToParam) as Exclude<typeof roundToParam, string>)
: ES.GetOptionsObject(roundToParam);
const roundingIncrement = ES.ToTemporalRoundingIncrement(roundTo);
const roundingMode = ES.ToTemporalRoundingMode(roundTo, 'halfExpand');
const smallestUnit = ES.GetTemporalUnit(roundTo, 'smallestUnit', 'time', ES.REQUIRED, ['day']);
const maximumIncrements = {
day: 1,
hour: 24,
minute: 60,
second: 60,
millisecond: 1000,
microsecond: 1000,
nanosecond: 1000
};
const maximum = maximumIncrements[smallestUnit];
const inclusive = maximum === 1;
ES.ValidateTemporalRoundingIncrement(roundingIncrement, maximum, inclusive);
let year = GetSlot(this, ISO_YEAR);
let month = GetSlot(this, ISO_MONTH);
let day = GetSlot(this, ISO_DAY);
let hour = GetSlot(this, ISO_HOUR);
let minute = GetSlot(this, ISO_MINUTE);
let second = GetSlot(this, ISO_SECOND);
let millisecond = GetSlot(this, ISO_MILLISECOND);
let microsecond = GetSlot(this, ISO_MICROSECOND);
let nanosecond = GetSlot(this, ISO_NANOSECOND);
({ year, month, day, hour, minute, second, millisecond, microsecond, nanosecond } = ES.RoundISODateTime(
year,
month,
day,
hour,
minute,
second,
millisecond,
microsecond,
nanosecond,
roundingIncrement,
smallestUnit,
roundingMode
));
return ES.CreateTemporalDateTime(
year,
month,
day,
hour,
minute,
second,
millisecond,
microsecond,
nanosecond,
GetSlot(this, CALENDAR)
);
}
equals(otherParam: Params['equals'][0]): Return['equals'] {
if (!ES.IsTemporalDateTime(this)) throw new TypeError('invalid receiver');
const other = ES.ToTemporalDateTime(otherParam);
for (const slot of [
ISO_YEAR,
ISO_MONTH,
ISO_DAY,
ISO_HOUR,
ISO_MINUTE,
ISO_SECOND,
ISO_MILLISECOND,
ISO_MICROSECOND,
ISO_NANOSECOND
]) {
const val1 = GetSlot(this, slot);
const val2 = GetSlot(other, slot);
if (val1 !== val2) return false;
}
return ES.CalendarEquals(GetSlot(this, CALENDAR), GetSlot(other, CALENDAR));
}
toString(optionsParam: Params['toString'][0] = undefined): string {
if (!ES.IsTemporalDateTime(this)) throw new TypeError('invalid receiver');
const options = ES.GetOptionsObject(optionsParam);
const showCalendar = ES.ToCalendarNameOption(options);
const digits = ES.ToFractionalSecondDigits(options);
const roundingMode = ES.ToTemporalRoundingMode(options, 'trunc');
const smallestUnit = ES.GetTemporalUnit(options, 'smallestUnit', 'time', undefined);
if (smallestUnit === 'hour') throw new RangeError('smallestUnit must be a time unit other than "hour"');
const { precision, unit, increment } = ES.ToSecondsStringPrecisionRecord(smallestUnit, digits);
return ES.TemporalDateTimeToString(this, precision, showCalendar, { unit, increment, roundingMode });
}
toJSON(): Return['toJSON'] {
if (!ES.IsTemporalDateTime(this)) throw new TypeError('invalid receiver');
return ES.TemporalDateTimeToString(this, 'auto');
}
toLocaleString(
locales: Params['toLocaleString'][0] = undefined,
options: Params['toLocaleString'][1] = undefined
): string {
if (!ES.IsTemporalDateTime(this)) throw new TypeError('invalid receiver');
return new DateTimeFormat(locales, options).format(this);
}
valueOf(): never {
throw new TypeError('use compare() or equals() to compare Temporal.PlainDateTime');
}
toZonedDateTime(
temporalTimeZoneLike: Params['toZonedDateTime'][0],
optionsParam: Params['toZonedDateTime'][1] = undefined
): Return['toZonedDateTime'] {
if (!ES.IsTemporalDateTime(this)) throw new TypeError('invalid receiver');
const timeZone = ES.ToTemporalTimeZoneSlotValue(temporalTimeZoneLike);
const options = ES.GetOptionsObject(optionsParam);
const disambiguation = ES.ToTemporalDisambiguation(options);
const instant = ES.GetInstantFor(timeZone, this, disambiguation);
return ES.CreateTemporalZonedDateTime(GetSlot(instant, EPOCHNANOSECONDS), timeZone, GetSlot(this, CALENDAR));
}
toPlainDate(): Return['toPlainDate'] {
if (!ES.IsTemporalDateTime(this)) throw new TypeError('invalid receiver');
return ES.TemporalDateTimeToDate(this);
}
toPlainYearMonth(): Return['toPlainYearMonth'] {
if (!ES.IsTemporalDateTime(this)) throw new TypeError('invalid receiver');
const calendar = GetSlot(this, CALENDAR);
const fieldNames = ES.CalendarFields(calendar, ['monthCode', 'year'] as const);
const fields = ES.PrepareTemporalFields(this, fieldNames, []);
return ES.CalendarYearMonthFromFields(calendar, fields);
}
toPlainMonthDay(): Return['toPlainMonthDay'] {
if (!ES.IsTemporalDateTime(this)) throw new TypeError('invalid receiver');
const calendar = GetSlot(this, CALENDAR);
const fieldNames = ES.CalendarFields(calendar, ['day', 'monthCode'] as const);
const fields = ES.PrepareTemporalFields(this, fieldNames, []);
return ES.CalendarMonthDayFromFields(calendar, fields);
}
toPlainTime(): Return['toPlainTime'] {
if (!ES.IsTemporalDateTime(this)) throw new TypeError('invalid receiver');
return ES.TemporalDateTimeToTime(this);
}
getISOFields(): Return['getISOFields'] {
if (!ES.IsTemporalDateTime(this)) throw new TypeError('invalid receiver');
return {
calendar: GetSlot(this, CALENDAR),
isoDay: GetSlot(this, ISO_DAY),
isoHour: GetSlot(this, ISO_HOUR),
isoMicrosecond: GetSlot(this, ISO_MICROSECOND),
isoMillisecond: GetSlot(this, ISO_MILLISECOND),
isoMinute: GetSlot(this, ISO_MINUTE),
isoMonth: GetSlot(this, ISO_MONTH),
isoNanosecond: GetSlot(this, ISO_NANOSECOND),
isoSecond: GetSlot(this, ISO_SECOND),
isoYear: GetSlot(this, ISO_YEAR)
};
}
getCalendar(): Return['getCalendar'] {
if (!ES.IsTemporalDateTime(this)) throw new TypeError('invalid receiver');
return ES.ToTemporalCalendarObject(GetSlot(this, CALENDAR));
}
static from(item: Params['from'][0], optionsParam: Params['from'][1] = undefined): Return['from'] {
const options = ES.GetOptionsObject(optionsParam);
if (ES.IsTemporalDateTime(item)) {
ES.ToTemporalOverflow(options); // validate and ignore
return ES.CreateTemporalDateTime(
GetSlot(item, ISO_YEAR),
GetSlot(item, ISO_MONTH),
GetSlot(item, ISO_DAY),
GetSlot(item, ISO_HOUR),
GetSlot(item, ISO_MINUTE),
GetSlot(item, ISO_SECOND),
GetSlot(item, ISO_MILLISECOND),
GetSlot(item, ISO_MICROSECOND),
GetSlot(item, ISO_NANOSECOND),
GetSlot(item, CALENDAR)
);
}
return ES.ToTemporalDateTime(item, options);
}
static compare(oneParam: Params['compare'][0], twoParam: Params['compare'][1]): Return['compare'] {
const one = ES.ToTemporalDateTime(oneParam);
const two = ES.ToTemporalDateTime(twoParam);
for (const slot of [
ISO_YEAR,
ISO_MONTH,
ISO_DAY,
ISO_HOUR,
ISO_MINUTE,
ISO_SECOND,
ISO_MILLISECOND,
ISO_MICROSECOND,
ISO_NANOSECOND
] as const) {
const val1 = GetSlot(one, slot);
const val2 = GetSlot(two, slot);
if (val1 !== val2) return ES.ComparisonResult(val1 - val2);
}
return 0;
}
[Symbol.toStringTag]!: 'Temporal.PlainDateTime';
}
MakeIntrinsicClass(PlainDateTime, 'Temporal.PlainDateTime');
+134
View File
@@ -0,0 +1,134 @@
import * as ES from './ecmascript';
import { MakeIntrinsicClass } from './intrinsicclass';
import { ISO_MONTH, ISO_DAY, ISO_YEAR, CALENDAR, GetSlot } from './slots';
import type { Temporal } from '..';
import { DateTimeFormat } from './intl';
import type { PlainMonthDayParams as Params, PlainMonthDayReturn as Return } from './internaltypes';
const ObjectCreate = Object.create;
export class PlainMonthDay implements Temporal.PlainMonthDay {
constructor(
isoMonthParam: Params['constructor'][0],
isoDayParam: Params['constructor'][0],
calendarParam: string | Temporal.CalendarProtocol = 'iso8601',
referenceISOYearParam = 1972
) {
const isoMonth = ES.ToIntegerWithTruncation(isoMonthParam);
const isoDay = ES.ToIntegerWithTruncation(isoDayParam);
const calendar = ES.ToTemporalCalendarSlotValue(calendarParam);
const referenceISOYear = ES.ToIntegerWithTruncation(referenceISOYearParam);
ES.CreateTemporalMonthDaySlots(this, isoMonth, isoDay, calendar, referenceISOYear);
}
get monthCode(): Return['monthCode'] {
if (!ES.IsTemporalMonthDay(this)) throw new TypeError('invalid receiver');
return ES.CalendarMonthCode(GetSlot(this, CALENDAR), this);
}
get day(): Return['day'] {
if (!ES.IsTemporalMonthDay(this)) throw new TypeError('invalid receiver');
return ES.CalendarDay(GetSlot(this, CALENDAR), this);
}
get calendarId(): Return['calendarId'] {
if (!ES.IsTemporalMonthDay(this)) throw new TypeError('invalid receiver');
return ES.ToTemporalCalendarIdentifier(GetSlot(this, CALENDAR));
}
with(temporalMonthDayLike: Params['with'][0], optionsParam: Params['with'][1] = undefined): Return['with'] {
if (!ES.IsTemporalMonthDay(this)) throw new TypeError('invalid receiver');
if (!ES.IsObject(temporalMonthDayLike)) {
throw new TypeError('invalid argument');
}
ES.RejectTemporalLikeObject(temporalMonthDayLike);
const options = ES.GetOptionsObject(optionsParam);
const calendar = GetSlot(this, CALENDAR);
const fieldNames = ES.CalendarFields(calendar, ['day', 'month', 'monthCode', 'year'] as const);
let fields = ES.PrepareTemporalFields(this, fieldNames, []);
const partialMonthDay = ES.PrepareTemporalFields(temporalMonthDayLike, fieldNames, 'partial');
fields = ES.CalendarMergeFields(calendar, fields, partialMonthDay);
fields = ES.PrepareTemporalFields(fields, fieldNames, []);
return ES.CalendarMonthDayFromFields(calendar, fields, options);
}
equals(otherParam: Params['equals'][0]): Return['equals'] {
if (!ES.IsTemporalMonthDay(this)) throw new TypeError('invalid receiver');
const other = ES.ToTemporalMonthDay(otherParam);
for (const slot of [ISO_MONTH, ISO_DAY, ISO_YEAR]) {
const val1 = GetSlot(this, slot);
const val2 = GetSlot(other, slot);
if (val1 !== val2) return false;
}
return ES.CalendarEquals(GetSlot(this, CALENDAR), GetSlot(other, CALENDAR));
}
toString(optionsParam: Params['toString'][0] = undefined): string {
if (!ES.IsTemporalMonthDay(this)) throw new TypeError('invalid receiver');
const options = ES.GetOptionsObject(optionsParam);
const showCalendar = ES.ToCalendarNameOption(options);
return ES.TemporalMonthDayToString(this, showCalendar);
}
toJSON(): Return['toJSON'] {
if (!ES.IsTemporalMonthDay(this)) throw new TypeError('invalid receiver');
return ES.TemporalMonthDayToString(this);
}
toLocaleString(
locales: Params['toLocaleString'][0] = undefined,
options: Params['toLocaleString'][1] = undefined
): string {
if (!ES.IsTemporalMonthDay(this)) throw new TypeError('invalid receiver');
return new DateTimeFormat(locales, options).format(this);
}
valueOf(): never {
throw new TypeError('use equals() to compare Temporal.PlainMonthDay');
}
toPlainDate(item: Params['toPlainDate'][0]): Return['toPlainDate'] {
if (!ES.IsTemporalMonthDay(this)) throw new TypeError('invalid receiver');
if (!ES.IsObject(item)) throw new TypeError('argument should be an object');
const calendar = GetSlot(this, CALENDAR);
const receiverFieldNames = ES.CalendarFields(calendar, ['day', 'monthCode'] as const);
const fields = ES.PrepareTemporalFields(this, receiverFieldNames, []);
const inputFieldNames = ES.CalendarFields(calendar, ['year'] as const);
const inputFields = ES.PrepareTemporalFields(item, inputFieldNames, []);
let mergedFields = ES.CalendarMergeFields(calendar, fields, inputFields);
// TODO: Use MergeLists abstract operation.
const mergedFieldNames = [...new Set([...receiverFieldNames, ...inputFieldNames])];
mergedFields = ES.PrepareTemporalFields(mergedFields, mergedFieldNames, []);
const options = ObjectCreate(null);
options.overflow = 'reject';
return ES.CalendarDateFromFields(calendar, mergedFields, options);
}
getISOFields(): Return['getISOFields'] {
if (!ES.IsTemporalMonthDay(this)) throw new TypeError('invalid receiver');
return {
calendar: GetSlot(this, CALENDAR),
isoDay: GetSlot(this, ISO_DAY),
isoMonth: GetSlot(this, ISO_MONTH),
isoYear: GetSlot(this, ISO_YEAR)
};
}
getCalendar(): Return['getCalendar'] {
if (!ES.IsTemporalMonthDay(this)) throw new TypeError('invalid receiver');
return ES.ToTemporalCalendarObject(GetSlot(this, CALENDAR));
}
static from(item: Params['from'][0], optionsParam: Params['from'][1] = undefined): Return['from'] {
const options = ES.GetOptionsObject(optionsParam);
if (ES.IsTemporalMonthDay(item)) {
ES.ToTemporalOverflow(options); // validate and ignore
return ES.CreateTemporalMonthDay(
GetSlot(item, ISO_MONTH),
GetSlot(item, ISO_DAY),
GetSlot(item, CALENDAR),
GetSlot(item, ISO_YEAR)
);
}
return ES.ToTemporalMonthDay(item, options);
}
[Symbol.toStringTag]!: 'Temporal.PlainMonthDay';
}
MakeIntrinsicClass(PlainMonthDay, 'Temporal.PlainMonthDay');
+357
View File
@@ -0,0 +1,357 @@
import { DEBUG } from './debug';
import * as ES from './ecmascript';
import { GetIntrinsic, MakeIntrinsicClass } from './intrinsicclass';
import {
ISO_YEAR,
ISO_MONTH,
ISO_DAY,
ISO_HOUR,
ISO_MINUTE,
ISO_SECOND,
ISO_MILLISECOND,
ISO_MICROSECOND,
ISO_NANOSECOND,
CALENDAR,
EPOCHNANOSECONDS,
CreateSlots,
GetSlot,
SetSlot
} from './slots';
import type { Temporal } from '..';
import { DateTimeFormat } from './intl';
import type { PlainTimeParams as Params, PlainTimeReturn as Return } from './internaltypes';
const ObjectAssign = Object.assign;
type TemporalTimeToStringOptions = {
unit: ReturnType<typeof ES.ToSecondsStringPrecisionRecord>['unit'];
increment: ReturnType<typeof ES.ToSecondsStringPrecisionRecord>['increment'];
roundingMode: Temporal.RoundingMode;
};
function TemporalTimeToString(
time: Temporal.PlainTime,
precision: ReturnType<typeof ES.ToSecondsStringPrecisionRecord>['precision'],
options: TemporalTimeToStringOptions | undefined = undefined
) {
let hour = GetSlot(time, ISO_HOUR);
let minute = GetSlot(time, ISO_MINUTE);
let second = GetSlot(time, ISO_SECOND);
let millisecond = GetSlot(time, ISO_MILLISECOND);
let microsecond = GetSlot(time, ISO_MICROSECOND);
let nanosecond = GetSlot(time, ISO_NANOSECOND);
if (options) {
const { unit, increment, roundingMode } = options;
({ hour, minute, second, millisecond, microsecond, nanosecond } = ES.RoundTime(
hour,
minute,
second,
millisecond,
microsecond,
nanosecond,
increment,
unit,
roundingMode
));
}
const hourString = ES.ISODateTimePartString(hour);
const minuteString = ES.ISODateTimePartString(minute);
const seconds = ES.FormatSecondsStringPart(second, millisecond, microsecond, nanosecond, precision);
return `${hourString}:${minuteString}${seconds}`;
}
export class PlainTime implements Temporal.PlainTime {
constructor(
isoHourParam = 0,
isoMinuteParam = 0,
isoSecondParam = 0,
isoMillisecondParam = 0,
isoMicrosecondParam = 0,
isoNanosecondParam = 0
) {
const isoHour = isoHourParam === undefined ? 0 : ES.ToIntegerWithTruncation(isoHourParam);
const isoMinute = isoMinuteParam === undefined ? 0 : ES.ToIntegerWithTruncation(isoMinuteParam);
const isoSecond = isoSecondParam === undefined ? 0 : ES.ToIntegerWithTruncation(isoSecondParam);
const isoMillisecond = isoMillisecondParam === undefined ? 0 : ES.ToIntegerWithTruncation(isoMillisecondParam);
const isoMicrosecond = isoMicrosecondParam === undefined ? 0 : ES.ToIntegerWithTruncation(isoMicrosecondParam);
const isoNanosecond = isoNanosecondParam === undefined ? 0 : ES.ToIntegerWithTruncation(isoNanosecondParam);
ES.RejectTime(isoHour, isoMinute, isoSecond, isoMillisecond, isoMicrosecond, isoNanosecond);
CreateSlots(this);
SetSlot(this, ISO_HOUR, isoHour);
SetSlot(this, ISO_MINUTE, isoMinute);
SetSlot(this, ISO_SECOND, isoSecond);
SetSlot(this, ISO_MILLISECOND, isoMillisecond);
SetSlot(this, ISO_MICROSECOND, isoMicrosecond);
SetSlot(this, ISO_NANOSECOND, isoNanosecond);
if (DEBUG) {
Object.defineProperty(this, '_repr_', {
value: `${this[Symbol.toStringTag]} <${TemporalTimeToString(this, 'auto')}>`,
writable: false,
enumerable: false,
configurable: false
});
}
}
get hour(): Return['hour'] {
if (!ES.IsTemporalTime(this)) throw new TypeError('invalid receiver');
return GetSlot(this, ISO_HOUR);
}
get minute(): Return['minute'] {
if (!ES.IsTemporalTime(this)) throw new TypeError('invalid receiver');
return GetSlot(this, ISO_MINUTE);
}
get second(): Return['second'] {
if (!ES.IsTemporalTime(this)) throw new TypeError('invalid receiver');
return GetSlot(this, ISO_SECOND);
}
get millisecond(): Return['millisecond'] {
if (!ES.IsTemporalTime(this)) throw new TypeError('invalid receiver');
return GetSlot(this, ISO_MILLISECOND);
}
get microsecond(): Return['microsecond'] {
if (!ES.IsTemporalTime(this)) throw new TypeError('invalid receiver');
return GetSlot(this, ISO_MICROSECOND);
}
get nanosecond(): Return['nanosecond'] {
if (!ES.IsTemporalTime(this)) throw new TypeError('invalid receiver');
return GetSlot(this, ISO_NANOSECOND);
}
with(temporalTimeLike: Params['with'][0], optionsParam: Params['with'][1] = undefined): Return['with'] {
if (!ES.IsTemporalTime(this)) throw new TypeError('invalid receiver');
if (!ES.IsObject(temporalTimeLike)) {
throw new TypeError('invalid argument');
}
ES.RejectTemporalLikeObject(temporalTimeLike);
const options = ES.GetOptionsObject(optionsParam);
const overflow = ES.ToTemporalOverflow(options);
const partialTime = ES.ToTemporalTimeRecord(temporalTimeLike, 'partial');
const fields = ES.ToTemporalTimeRecord(this);
let { hour, minute, second, millisecond, microsecond, nanosecond } = ObjectAssign(fields, partialTime);
({ hour, minute, second, millisecond, microsecond, nanosecond } = ES.RegulateTime(
hour,
minute,
second,
millisecond,
microsecond,
nanosecond,
overflow
));
return new PlainTime(hour, minute, second, millisecond, microsecond, nanosecond);
}
add(temporalDurationLike: Params['add'][0]): Return['add'] {
if (!ES.IsTemporalTime(this)) throw new TypeError('invalid receiver');
return ES.AddDurationToOrSubtractDurationFromPlainTime('add', this, temporalDurationLike);
}
subtract(temporalDurationLike: Params['subtract'][0]): Return['subtract'] {
if (!ES.IsTemporalTime(this)) throw new TypeError('invalid receiver');
return ES.AddDurationToOrSubtractDurationFromPlainTime('subtract', this, temporalDurationLike);
}
until(other: Params['until'][0], options: Params['until'][1] = undefined): Return['until'] {
if (!ES.IsTemporalTime(this)) throw new TypeError('invalid receiver');
return ES.DifferenceTemporalPlainTime('until', this, other, options);
}
since(other: Params['since'][0], options: Params['since'][1] = undefined): Return['since'] {
if (!ES.IsTemporalTime(this)) throw new TypeError('invalid receiver');
return ES.DifferenceTemporalPlainTime('since', this, other, options);
}
round(roundToParam: Params['round'][0]): Return['round'] {
if (!ES.IsTemporalTime(this)) throw new TypeError('invalid receiver');
if (roundToParam === undefined) throw new TypeError('options parameter is required');
const roundTo =
typeof roundToParam === 'string'
? (ES.CreateOnePropObject('smallestUnit', roundToParam) as Exclude<typeof roundToParam, string>)
: ES.GetOptionsObject(roundToParam);
const roundingIncrement = ES.ToTemporalRoundingIncrement(roundTo);
const roundingMode = ES.ToTemporalRoundingMode(roundTo, 'halfExpand');
const smallestUnit = ES.GetTemporalUnit(roundTo, 'smallestUnit', 'time', ES.REQUIRED);
const MAX_INCREMENTS = {
hour: 24,
minute: 60,
second: 60,
millisecond: 1000,
microsecond: 1000,
nanosecond: 1000
};
ES.ValidateTemporalRoundingIncrement(roundingIncrement, MAX_INCREMENTS[smallestUnit], false);
let hour = GetSlot(this, ISO_HOUR);
let minute = GetSlot(this, ISO_MINUTE);
let second = GetSlot(this, ISO_SECOND);
let millisecond = GetSlot(this, ISO_MILLISECOND);
let microsecond = GetSlot(this, ISO_MICROSECOND);
let nanosecond = GetSlot(this, ISO_NANOSECOND);
({ hour, minute, second, millisecond, microsecond, nanosecond } = ES.RoundTime(
hour,
minute,
second,
millisecond,
microsecond,
nanosecond,
roundingIncrement,
smallestUnit,
roundingMode
));
return new PlainTime(hour, minute, second, millisecond, microsecond, nanosecond);
}
equals(otherParam: Params['equals'][0]): Return['equals'] {
if (!ES.IsTemporalTime(this)) throw new TypeError('invalid receiver');
const other = ES.ToTemporalTime(otherParam);
for (const slot of [ISO_HOUR, ISO_MINUTE, ISO_SECOND, ISO_MILLISECOND, ISO_MICROSECOND, ISO_NANOSECOND]) {
const val1 = GetSlot(this, slot);
const val2 = GetSlot(other, slot);
if (val1 !== val2) return false;
}
return true;
}
toString(optionsParam: Params['toString'][0] = undefined): string {
if (!ES.IsTemporalTime(this)) throw new TypeError('invalid receiver');
const options = ES.GetOptionsObject(optionsParam);
const digits = ES.ToFractionalSecondDigits(options);
const roundingMode = ES.ToTemporalRoundingMode(options, 'trunc');
const smallestUnit = ES.GetTemporalUnit(options, 'smallestUnit', 'time', undefined);
if (smallestUnit === 'hour') throw new RangeError('smallestUnit must be a time unit other than "hour"');
const { precision, unit, increment } = ES.ToSecondsStringPrecisionRecord(smallestUnit, digits);
return TemporalTimeToString(this, precision, { unit, increment, roundingMode });
}
toJSON(): Return['toJSON'] {
if (!ES.IsTemporalTime(this)) throw new TypeError('invalid receiver');
return TemporalTimeToString(this, 'auto');
}
toLocaleString(
locales: Params['toLocaleString'][0] = undefined,
options: Params['toLocaleString'][1] = undefined
): string {
if (!ES.IsTemporalTime(this)) throw new TypeError('invalid receiver');
return new DateTimeFormat(locales, options).format(this);
}
valueOf(): never {
throw new TypeError('use compare() or equals() to compare Temporal.PlainTime');
}
toPlainDateTime(temporalDateParam: Params['toPlainDateTime'][0]): Return['toPlainDateTime'] {
if (!ES.IsTemporalTime(this)) throw new TypeError('invalid receiver');
const temporalDate = ES.ToTemporalDate(temporalDateParam);
const year = GetSlot(temporalDate, ISO_YEAR);
const month = GetSlot(temporalDate, ISO_MONTH);
const day = GetSlot(temporalDate, ISO_DAY);
const calendar = GetSlot(temporalDate, CALENDAR);
const hour = GetSlot(this, ISO_HOUR);
const minute = GetSlot(this, ISO_MINUTE);
const second = GetSlot(this, ISO_SECOND);
const millisecond = GetSlot(this, ISO_MILLISECOND);
const microsecond = GetSlot(this, ISO_MICROSECOND);
const nanosecond = GetSlot(this, ISO_NANOSECOND);
return ES.CreateTemporalDateTime(
year,
month,
day,
hour,
minute,
second,
millisecond,
microsecond,
nanosecond,
calendar
);
}
toZonedDateTime(item: Params['toZonedDateTime'][0]): Return['toZonedDateTime'] {
if (!ES.IsTemporalTime(this)) throw new TypeError('invalid receiver');
if (!ES.IsObject(item)) {
throw new TypeError('invalid argument');
}
const dateLike = item.plainDate;
if (dateLike === undefined) {
throw new TypeError('missing date property');
}
const temporalDate = ES.ToTemporalDate(dateLike);
const timeZoneLike = item.timeZone;
if (timeZoneLike === undefined) {
throw new TypeError('missing timeZone property');
}
const timeZone = ES.ToTemporalTimeZoneSlotValue(timeZoneLike);
const year = GetSlot(temporalDate, ISO_YEAR);
const month = GetSlot(temporalDate, ISO_MONTH);
const day = GetSlot(temporalDate, ISO_DAY);
const calendar = GetSlot(temporalDate, CALENDAR);
const hour = GetSlot(this, ISO_HOUR);
const minute = GetSlot(this, ISO_MINUTE);
const second = GetSlot(this, ISO_SECOND);
const millisecond = GetSlot(this, ISO_MILLISECOND);
const microsecond = GetSlot(this, ISO_MICROSECOND);
const nanosecond = GetSlot(this, ISO_NANOSECOND);
const PlainDateTime = GetIntrinsic('%Temporal.PlainDateTime%');
const dt = new PlainDateTime(
year,
month,
day,
hour,
minute,
second,
millisecond,
microsecond,
nanosecond,
calendar
);
const instant = ES.GetInstantFor(timeZone, dt, 'compatible');
return ES.CreateTemporalZonedDateTime(GetSlot(instant, EPOCHNANOSECONDS), timeZone, calendar);
}
getISOFields(): Return['getISOFields'] {
if (!ES.IsTemporalTime(this)) throw new TypeError('invalid receiver');
return {
isoHour: GetSlot(this, ISO_HOUR),
isoMicrosecond: GetSlot(this, ISO_MICROSECOND),
isoMillisecond: GetSlot(this, ISO_MILLISECOND),
isoMinute: GetSlot(this, ISO_MINUTE),
isoNanosecond: GetSlot(this, ISO_NANOSECOND),
isoSecond: GetSlot(this, ISO_SECOND)
};
}
static from(item: Params['from'][0], optionsParam: Params['from'][1] = undefined): Return['from'] {
const options = ES.GetOptionsObject(optionsParam);
const overflow = ES.ToTemporalOverflow(options);
if (ES.IsTemporalTime(item)) {
return new PlainTime(
GetSlot(item, ISO_HOUR),
GetSlot(item, ISO_MINUTE),
GetSlot(item, ISO_SECOND),
GetSlot(item, ISO_MILLISECOND),
GetSlot(item, ISO_MICROSECOND),
GetSlot(item, ISO_NANOSECOND)
);
}
return ES.ToTemporalTime(item, overflow);
}
static compare(oneParam: Params['compare'][0], twoParam: Params['compare'][1]): Return['compare'] {
const one = ES.ToTemporalTime(oneParam);
const two = ES.ToTemporalTime(twoParam);
for (const slot of [ISO_HOUR, ISO_MINUTE, ISO_SECOND, ISO_MILLISECOND, ISO_MICROSECOND, ISO_NANOSECOND] as const) {
const val1 = GetSlot(one, slot);
const val2 = GetSlot(two, slot);
if (val1 !== val2) return ES.ComparisonResult(val1 - val2);
}
return 0;
}
[Symbol.toStringTag]!: 'Temporal.PlainTime';
}
MakeIntrinsicClass(PlainTime, 'Temporal.PlainTime');
@@ -0,0 +1,191 @@
import * as ES from './ecmascript';
import { MakeIntrinsicClass } from './intrinsicclass';
import { ISO_YEAR, ISO_MONTH, ISO_DAY, CALENDAR, GetSlot } from './slots';
import type { Temporal } from '..';
import { DateTimeFormat } from './intl';
import type { PlainYearMonthParams as Params, PlainYearMonthReturn as Return } from './internaltypes';
const ObjectCreate = Object.create;
export class PlainYearMonth implements Temporal.PlainYearMonth {
constructor(
isoYearParam: Params['constructor'][0],
isoMonthParam: Params['constructor'][1],
calendarParam: Params['constructor'][2] = 'iso8601',
referenceISODayParam: Params['constructor'][3] = 1
) {
const isoYear = ES.ToIntegerWithTruncation(isoYearParam);
const isoMonth = ES.ToIntegerWithTruncation(isoMonthParam);
const calendar = ES.ToTemporalCalendarSlotValue(calendarParam);
const referenceISODay = ES.ToIntegerWithTruncation(referenceISODayParam);
ES.CreateTemporalYearMonthSlots(this, isoYear, isoMonth, calendar, referenceISODay);
}
get year(): Return['year'] {
if (!ES.IsTemporalYearMonth(this)) throw new TypeError('invalid receiver');
return ES.CalendarYear(GetSlot(this, CALENDAR), this);
}
get month(): Return['month'] {
if (!ES.IsTemporalYearMonth(this)) throw new TypeError('invalid receiver');
return ES.CalendarMonth(GetSlot(this, CALENDAR), this);
}
get monthCode(): Return['monthCode'] {
if (!ES.IsTemporalYearMonth(this)) throw new TypeError('invalid receiver');
return ES.CalendarMonthCode(GetSlot(this, CALENDAR), this);
}
get calendarId(): Return['calendarId'] {
if (!ES.IsTemporalYearMonth(this)) throw new TypeError('invalid receiver');
return ES.ToTemporalCalendarIdentifier(GetSlot(this, CALENDAR));
}
get era(): Return['era'] {
if (!ES.IsTemporalYearMonth(this)) throw new TypeError('invalid receiver');
return ES.CalendarEra(GetSlot(this, CALENDAR), this);
}
get eraYear(): Return['eraYear'] {
if (!ES.IsTemporalYearMonth(this)) throw new TypeError('invalid receiver');
return ES.CalendarEraYear(GetSlot(this, CALENDAR), this);
}
get daysInMonth(): Return['daysInMonth'] {
if (!ES.IsTemporalYearMonth(this)) throw new TypeError('invalid receiver');
return ES.CalendarDaysInMonth(GetSlot(this, CALENDAR), this);
}
get daysInYear(): Return['daysInYear'] {
if (!ES.IsTemporalYearMonth(this)) throw new TypeError('invalid receiver');
return ES.CalendarDaysInYear(GetSlot(this, CALENDAR), this);
}
get monthsInYear(): Return['monthsInYear'] {
if (!ES.IsTemporalYearMonth(this)) throw new TypeError('invalid receiver');
return ES.CalendarMonthsInYear(GetSlot(this, CALENDAR), this);
}
get inLeapYear(): Return['inLeapYear'] {
if (!ES.IsTemporalYearMonth(this)) throw new TypeError('invalid receiver');
return ES.CalendarInLeapYear(GetSlot(this, CALENDAR), this);
}
with(temporalYearMonthLike: Params['with'][0], optionsParam: Params['with'][1] = undefined): Return['with'] {
if (!ES.IsTemporalYearMonth(this)) throw new TypeError('invalid receiver');
if (!ES.IsObject(temporalYearMonthLike)) {
throw new TypeError('invalid argument');
}
ES.RejectTemporalLikeObject(temporalYearMonthLike);
const options = ES.GetOptionsObject(optionsParam);
const calendar = GetSlot(this, CALENDAR);
const fieldNames = ES.CalendarFields(calendar, ['month', 'monthCode', 'year'] as const);
let fields = ES.PrepareTemporalFields(this, fieldNames, []);
const partialYearMonth = ES.PrepareTemporalFields(temporalYearMonthLike, fieldNames, 'partial');
fields = ES.CalendarMergeFields(calendar, fields, partialYearMonth);
fields = ES.PrepareTemporalFields(fields, fieldNames, []);
return ES.CalendarYearMonthFromFields(calendar, fields, options);
}
add(temporalDurationLike: Params['add'][0], options: Params['add'][1] = undefined): Return['add'] {
if (!ES.IsTemporalYearMonth(this)) throw new TypeError('invalid receiver');
return ES.AddDurationToOrSubtractDurationFromPlainYearMonth('add', this, temporalDurationLike, options);
}
subtract(
temporalDurationLike: Params['subtract'][0],
options: Params['subtract'][1] = undefined
): Return['subtract'] {
if (!ES.IsTemporalYearMonth(this)) throw new TypeError('invalid receiver');
return ES.AddDurationToOrSubtractDurationFromPlainYearMonth('subtract', this, temporalDurationLike, options);
}
until(other: Params['until'][0], options: Params['until'][1] = undefined): Return['until'] {
if (!ES.IsTemporalYearMonth(this)) throw new TypeError('invalid receiver');
return ES.DifferenceTemporalPlainYearMonth('until', this, other, options);
}
since(other: Params['since'][0], options: Params['since'][1] = undefined): Return['since'] {
if (!ES.IsTemporalYearMonth(this)) throw new TypeError('invalid receiver');
return ES.DifferenceTemporalPlainYearMonth('since', this, other, options);
}
equals(otherParam: Params['equals'][0]): Return['equals'] {
if (!ES.IsTemporalYearMonth(this)) throw new TypeError('invalid receiver');
const other = ES.ToTemporalYearMonth(otherParam);
for (const slot of [ISO_YEAR, ISO_MONTH, ISO_DAY]) {
const val1 = GetSlot(this, slot);
const val2 = GetSlot(other, slot);
if (val1 !== val2) return false;
}
return ES.CalendarEquals(GetSlot(this, CALENDAR), GetSlot(other, CALENDAR));
}
toString(optionsParam: Params['toString'][0] = undefined): string {
if (!ES.IsTemporalYearMonth(this)) throw new TypeError('invalid receiver');
const options = ES.GetOptionsObject(optionsParam);
const showCalendar = ES.ToCalendarNameOption(options);
return ES.TemporalYearMonthToString(this, showCalendar);
}
toJSON(): Return['toJSON'] {
if (!ES.IsTemporalYearMonth(this)) throw new TypeError('invalid receiver');
return ES.TemporalYearMonthToString(this);
}
toLocaleString(
locales: Params['toLocaleString'][0] = undefined,
options: Params['toLocaleString'][1] = undefined
): string {
if (!ES.IsTemporalYearMonth(this)) throw new TypeError('invalid receiver');
return new DateTimeFormat(locales, options).format(this);
}
valueOf(): never {
throw new TypeError('use compare() or equals() to compare Temporal.PlainYearMonth');
}
toPlainDate(item: Params['toPlainDate'][0]): Return['toPlainDate'] {
if (!ES.IsTemporalYearMonth(this)) throw new TypeError('invalid receiver');
if (!ES.IsObject(item)) throw new TypeError('argument should be an object');
const calendar = GetSlot(this, CALENDAR);
const receiverFieldNames = ES.CalendarFields(calendar, ['monthCode', 'year'] as const);
const fields = ES.PrepareTemporalFields(this, receiverFieldNames, []);
const inputFieldNames = ES.CalendarFields(calendar, ['day'] as const);
const inputFields = ES.PrepareTemporalFields(item, inputFieldNames, []);
let mergedFields = ES.CalendarMergeFields(calendar, fields, inputFields);
// TODO: Use MergeLists abstract operation.
const mergedFieldNames = [...new Set([...receiverFieldNames, ...inputFieldNames])];
mergedFields = ES.PrepareTemporalFields(mergedFields, mergedFieldNames, []);
const options = ObjectCreate(null);
options.overflow = 'reject';
return ES.CalendarDateFromFields(calendar, mergedFields, options);
}
getISOFields(): Return['getISOFields'] {
if (!ES.IsTemporalYearMonth(this)) throw new TypeError('invalid receiver');
return {
calendar: GetSlot(this, CALENDAR),
isoDay: GetSlot(this, ISO_DAY),
isoMonth: GetSlot(this, ISO_MONTH),
isoYear: GetSlot(this, ISO_YEAR)
};
}
getCalendar(): Return['getCalendar'] {
if (!ES.IsTemporalYearMonth(this)) throw new TypeError('invalid receiver');
return ES.ToTemporalCalendarObject(GetSlot(this, CALENDAR));
}
static from(item: Params['from'][0], optionsParam: Params['from'][1] = undefined): Return['from'] {
const options = ES.GetOptionsObject(optionsParam);
if (ES.IsTemporalYearMonth(item)) {
ES.ToTemporalOverflow(options); // validate and ignore
return ES.CreateTemporalYearMonth(
GetSlot(item, ISO_YEAR),
GetSlot(item, ISO_MONTH),
GetSlot(item, CALENDAR),
GetSlot(item, ISO_DAY)
);
}
return ES.ToTemporalYearMonth(item, options);
}
static compare(oneParam: Params['compare'][0], twoParam: Params['compare'][1]): Return['compare'] {
const one = ES.ToTemporalYearMonth(oneParam);
const two = ES.ToTemporalYearMonth(twoParam);
return ES.CompareISODate(
GetSlot(one, ISO_YEAR),
GetSlot(one, ISO_MONTH),
GetSlot(one, ISO_DAY),
GetSlot(two, ISO_YEAR),
GetSlot(two, ISO_MONTH),
GetSlot(two, ISO_DAY)
);
}
[Symbol.toStringTag]!: 'Temporal.PlainYearMonth';
}
MakeIntrinsicClass(PlainYearMonth, 'Temporal.PlainYearMonth');
+70
View File
@@ -0,0 +1,70 @@
const tzComponent = /\.[-A-Za-z_]|\.\.[-A-Za-z._]{1,12}|\.[-A-Za-z_][-A-Za-z._]{0,12}|[A-Za-z_][-A-Za-z._]{0,13}/;
const offsetNoCapture = /(?:[+\u2212-][0-2][0-9](?::?[0-5][0-9](?::?[0-5][0-9](?:[.,]\d{1,9})?)?)?)/;
export const timeZoneID = new RegExp(
'(?:' +
[
`(?:${tzComponent.source})(?:\\/(?:${tzComponent.source}))*`,
'Etc/GMT(?:0|[-+]\\d{1,2})',
'GMT[-+]?0',
'EST5EDT',
'CST6CDT',
'MST7MDT',
'PST8PDT',
offsetNoCapture.source
].join('|') +
')'
);
const yearpart = /(?:[+\u2212-]\d{6}|\d{4})/;
const monthpart = /(?:0[1-9]|1[0-2])/;
const daypart = /(?:0[1-9]|[12]\d|3[01])/;
const datesplit = new RegExp(
`(${yearpart.source})(?:-(${monthpart.source})-(${daypart.source})|(${monthpart.source})(${daypart.source}))`
);
const timesplit = /(\d{2})(?::(\d{2})(?::(\d{2})(?:[.,](\d{1,9}))?)?|(\d{2})(?:(\d{2})(?:[.,](\d{1,9}))?)?)?/;
export const offset = /([+\u2212-])([01][0-9]|2[0-3])(?::?([0-5][0-9])(?::?([0-5][0-9])(?:[.,](\d{1,9}))?)?)?/;
const offsetpart = new RegExp(`([zZ])|${offset.source}?`);
export const annotation = /\[(!)?([a-z_][a-z0-9_-]*)=([A-Za-z0-9]+(?:-[A-Za-z0-9]+)*)\]/g;
export const zoneddatetime = new RegExp(
[
`^${datesplit.source}`,
`(?:(?:T|\\s+)${timesplit.source}(?:${offsetpart.source})?)?`,
`(?:\\[!?(${timeZoneID.source})\\])?`,
`((?:${annotation.source})*)$`
].join(''),
'i'
);
export const time = new RegExp(
[
`^T?${timesplit.source}`,
`(?:${offsetpart.source})?`,
`(?:\\[!?${timeZoneID.source}\\])?`,
`((?:${annotation.source})*)$`
].join(''),
'i'
);
// The short forms of YearMonth and MonthDay are only for the ISO calendar, but
// annotations are still allowed, and will throw if the calendar annotation is
// not ISO.
// Non-ISO calendar YearMonth and MonthDay have to parse as a Temporal.PlainDate,
// with the reference fields.
// YYYYMM forbidden by ISO 8601 because ambiguous with YYMMDD, but allowed by
// RFC 3339 and we don't allow 2-digit years, so we allow it.
// Not ambiguous with HHMMSS because that requires a 'T' prefix
// UTC offsets are not allowed, because they are not allowed with any date-only
// format; also, YYYY-MM-UU is ambiguous with YYYY-MM-DD
export const yearmonth = new RegExp(
`^(${yearpart.source})-?(${monthpart.source})(?:\\[!?${timeZoneID.source}\\])?((?:${annotation.source})*)$`
);
export const monthday = new RegExp(
`^(?:--)?(${monthpart.source})-?(${daypart.source})(?:\\[!?${timeZoneID.source}\\])?((?:${annotation.source})*)$`
);
const fraction = /(\d+)(?:[.,](\d{1,9}))?/;
const durationDate = /(?:(\d+)Y)?(?:(\d+)M)?(?:(\d+)W)?(?:(\d+)D)?/;
const durationTime = new RegExp(`(?:${fraction.source}H)?(?:${fraction.source}M)?(?:${fraction.source}S)?`);
export const duration = new RegExp(`^([+\u2212-])?P${durationDate.source}(?:T(?!$)${durationTime.source})?$`, 'i');
+315
View File
@@ -0,0 +1,315 @@
import type JSBI from 'jsbi';
import type { Temporal } from '..';
import type { BuiltinCalendarId, AnyTemporalType, CalendarSlot, TimeZoneSlot } from './internaltypes';
// Instant
export const EPOCHNANOSECONDS = 'slot-epochNanoSeconds';
// TimeZone
export const TIMEZONE_ID = 'slot-timezone-identifier';
// DateTime, Date, Time, YearMonth, MonthDay
export const ISO_YEAR = 'slot-year';
export const ISO_MONTH = 'slot-month';
export const ISO_DAY = 'slot-day';
export const ISO_HOUR = 'slot-hour';
export const ISO_MINUTE = 'slot-minute';
export const ISO_SECOND = 'slot-second';
export const ISO_MILLISECOND = 'slot-millisecond';
export const ISO_MICROSECOND = 'slot-microsecond';
export const ISO_NANOSECOND = 'slot-nanosecond';
export const CALENDAR = 'slot-calendar';
// Date, YearMonth, and MonthDay all have the same slots, disambiguation needed:
export const DATE_BRAND = 'slot-date-brand';
export const YEAR_MONTH_BRAND = 'slot-year-month-brand';
export const MONTH_DAY_BRAND = 'slot-month-day-brand';
// ZonedDateTime
export const INSTANT = 'slot-cached-instant';
export const TIME_ZONE = 'slot-time-zone';
// Duration
export const YEARS = 'slot-years';
export const MONTHS = 'slot-months';
export const WEEKS = 'slot-weeks';
export const DAYS = 'slot-days';
export const HOURS = 'slot-hours';
export const MINUTES = 'slot-minutes';
export const SECONDS = 'slot-seconds';
export const MILLISECONDS = 'slot-milliseconds';
export const MICROSECONDS = 'slot-microseconds';
export const NANOSECONDS = 'slot-nanoseconds';
// Calendar
export const CALENDAR_ID = 'slot-calendar-identifier';
interface SlotInfo<ValueType, UsedByType extends AnyTemporalType> {
value: ValueType;
usedBy: UsedByType;
}
interface SlotInfoRecord {
[k: string]: SlotInfo<unknown, AnyTemporalType>;
}
interface Slots extends SlotInfoRecord {
// Instant
[EPOCHNANOSECONDS]: SlotInfo<JSBI, Temporal.Instant | Temporal.ZonedDateTime>; // number? JSBI?
// TimeZone
[TIMEZONE_ID]: SlotInfo<string, Temporal.TimeZone>;
// DateTime, Date, Time, YearMonth, MonthDay
[ISO_YEAR]: SlotInfo<number, TypesWithCalendarUnits>;
[ISO_MONTH]: SlotInfo<number, TypesWithCalendarUnits>;
[ISO_DAY]: SlotInfo<number, TypesWithCalendarUnits>;
[ISO_HOUR]: SlotInfo<number, TypesWithCalendarUnits>;
[ISO_MINUTE]: SlotInfo<number, TypesWithCalendarUnits>;
[ISO_SECOND]: SlotInfo<number, TypesWithCalendarUnits>;
[ISO_MILLISECOND]: SlotInfo<number, TypesWithCalendarUnits>;
[ISO_MICROSECOND]: SlotInfo<number, TypesWithCalendarUnits>;
[ISO_NANOSECOND]: SlotInfo<number, TypesWithCalendarUnits>;
[CALENDAR]: SlotInfo<CalendarSlot, TypesWithCalendarUnits>;
// Date, YearMonth, MonthDay common slots
[DATE_BRAND]: SlotInfo<true, Temporal.PlainDate>;
[YEAR_MONTH_BRAND]: SlotInfo<true, Temporal.PlainYearMonth>;
[MONTH_DAY_BRAND]: SlotInfo<true, Temporal.PlainMonthDay>;
// ZonedDateTime
[INSTANT]: SlotInfo<Temporal.Instant, Temporal.ZonedDateTime>;
[TIME_ZONE]: SlotInfo<TimeZoneSlot, Temporal.ZonedDateTime>;
// Duration
[YEARS]: SlotInfo<number, Temporal.Duration>;
[MONTHS]: SlotInfo<number, Temporal.Duration>;
[WEEKS]: SlotInfo<number, Temporal.Duration>;
[DAYS]: SlotInfo<number, Temporal.Duration>;
[HOURS]: SlotInfo<number, Temporal.Duration>;
[MINUTES]: SlotInfo<number, Temporal.Duration>;
[SECONDS]: SlotInfo<number, Temporal.Duration>;
[MILLISECONDS]: SlotInfo<number, Temporal.Duration>;
[MICROSECONDS]: SlotInfo<number, Temporal.Duration>;
[NANOSECONDS]: SlotInfo<number, Temporal.Duration>;
// Calendar
[CALENDAR_ID]: SlotInfo<BuiltinCalendarId, Temporal.Calendar>;
}
type TypesWithCalendarUnits =
| Temporal.PlainDateTime
| Temporal.PlainDate
| Temporal.PlainTime
| Temporal.PlainYearMonth
| Temporal.PlainMonthDay
| Temporal.ZonedDateTime;
interface SlotsToTypes {
// Instant
[EPOCHNANOSECONDS]: Temporal.Instant;
// TimeZone
[TIMEZONE_ID]: Temporal.TimeZone;
// DateTime, Date, Time, YearMonth, MonthDay
[ISO_YEAR]: TypesWithCalendarUnits;
[ISO_MONTH]: TypesWithCalendarUnits;
[ISO_DAY]: TypesWithCalendarUnits;
[ISO_HOUR]: TypesWithCalendarUnits;
[ISO_MINUTE]: TypesWithCalendarUnits;
[ISO_SECOND]: TypesWithCalendarUnits;
[ISO_MILLISECOND]: TypesWithCalendarUnits;
[ISO_MICROSECOND]: TypesWithCalendarUnits;
[ISO_NANOSECOND]: TypesWithCalendarUnits;
[CALENDAR]: TypesWithCalendarUnits;
// Date, YearMonth, MonthDay common slots
[DATE_BRAND]: Temporal.PlainDate;
[YEAR_MONTH_BRAND]: Temporal.PlainYearMonth;
[MONTH_DAY_BRAND]: Temporal.PlainMonthDay;
// ZonedDateTime
[INSTANT]: Temporal.ZonedDateTime;
[TIME_ZONE]: Temporal.ZonedDateTime;
// Duration
[YEARS]: Temporal.Duration;
[MONTHS]: Temporal.Duration;
[WEEKS]: Temporal.Duration;
[DAYS]: Temporal.Duration;
[HOURS]: Temporal.Duration;
[MINUTES]: Temporal.Duration;
[SECONDS]: Temporal.Duration;
[MILLISECONDS]: Temporal.Duration;
[MICROSECONDS]: Temporal.Duration;
[NANOSECONDS]: Temporal.Duration;
// Calendar
[CALENDAR_ID]: Temporal.Calendar;
}
type SlotKey = keyof SlotsToTypes;
const globalSlots = new WeakMap<Slots[keyof Slots]['usedBy'], Record<keyof Slots, Slots[keyof Slots]['value']>>();
function _GetSlots(container: Slots[keyof Slots]['usedBy']) {
return globalSlots.get(container);
}
const GetSlotsSymbol = Symbol.for('@@Temporal__GetSlots');
// expose GetSlots to avoid dual package hazards
(globalThis as any)[GetSlotsSymbol] ||= _GetSlots;
const GetSlots = (globalThis as any)[GetSlotsSymbol] as typeof _GetSlots;
function _CreateSlots(container: Slots[keyof Slots]['usedBy']): void {
globalSlots.set(container, Object.create(null));
}
const CreateSlotsSymbol = Symbol.for('@@Temporal__CreateSlots');
// expose CreateSlots to avoid dual package hazards
(globalThis as any)[CreateSlotsSymbol] ||= _CreateSlots;
export const CreateSlots = (globalThis as any)[CreateSlotsSymbol] as typeof _CreateSlots;
// TODO: is there a better way than 9 overloads to make HasSlot into a type
// guard that takes a variable number of parameters?
export function HasSlot<ID1 extends SlotKey>(container: unknown, id1: ID1): container is Slots[ID1]['usedBy'];
export function HasSlot<ID1 extends SlotKey, ID2 extends SlotKey>(
container: unknown,
id1: ID1,
id2: ID2
): container is Slots[ID1]['usedBy'] | Slots[ID2]['usedBy'];
export function HasSlot<ID1 extends SlotKey, ID2 extends SlotKey, ID3 extends SlotKey>(
container: unknown,
id1: ID1,
id2: ID2,
id3: ID3
): container is Slots[ID1]['usedBy'] | Slots[ID2]['usedBy'] | Slots[ID3]['usedBy'];
export function HasSlot<ID1 extends SlotKey, ID2 extends SlotKey, ID3 extends SlotKey, ID4 extends SlotKey>(
container: unknown,
id1: ID1,
id2: ID2,
id3: ID3,
id4: ID4
): container is Slots[ID1 | ID2 | ID3 | ID4]['usedBy'];
export function HasSlot<
ID1 extends SlotKey,
ID2 extends SlotKey,
ID3 extends SlotKey,
ID4 extends SlotKey,
ID5 extends SlotKey
>(
container: unknown,
id1: ID1,
id2: ID2,
id3: ID3,
id4: ID4,
id5: ID5
): container is Slots[ID1 | ID2 | ID3 | ID4 | ID5]['usedBy'];
export function HasSlot<
ID1 extends SlotKey,
ID2 extends SlotKey,
ID3 extends SlotKey,
ID4 extends SlotKey,
ID5 extends SlotKey,
ID6 extends SlotKey
>(
container: unknown,
id1: ID1,
id2: ID2,
id3: ID3,
id4: ID4,
id5: ID5,
id6: ID6
): container is Slots[ID1 | ID2 | ID3 | ID4 | ID5 | ID6]['usedBy'];
export function HasSlot<
ID1 extends SlotKey,
ID2 extends SlotKey,
ID3 extends SlotKey,
ID4 extends SlotKey,
ID5 extends SlotKey,
ID6 extends SlotKey,
ID7 extends SlotKey
>(
container: unknown,
id1: ID1,
id2: ID2,
id3: ID3,
id4: ID4,
id5: ID5,
id6: ID6,
id7: ID7
): container is Slots[ID1 | ID2 | ID3 | ID4 | ID5 | ID6 | ID7]['usedBy'];
export function HasSlot<
ID1 extends SlotKey,
ID2 extends SlotKey,
ID3 extends SlotKey,
ID4 extends SlotKey,
ID5 extends SlotKey,
ID6 extends SlotKey,
ID7 extends SlotKey,
ID8 extends SlotKey
>(
container: unknown,
id1: ID1,
id2: ID2,
id3: ID3,
id4: ID4,
id5: ID5,
id6: ID6,
id7: ID7,
id8: ID8
): container is Slots[ID1 | ID2 | ID3 | ID4 | ID5 | ID6 | ID7 | ID8]['usedBy'];
export function HasSlot<
ID1 extends SlotKey,
ID2 extends SlotKey,
ID3 extends SlotKey,
ID4 extends SlotKey,
ID5 extends SlotKey,
ID6 extends SlotKey,
ID7 extends SlotKey,
ID8 extends SlotKey,
ID9 extends SlotKey
>(
container: unknown,
id1: ID1,
id2: ID2,
id3: ID3,
id4: ID4,
id5: ID5,
id6: ID6,
id7: ID7,
id8: ID8,
id9: ID9
): container is Slots[ID1 | ID2 | ID3 | ID4 | ID5 | ID6 | ID7 | ID8 | ID9]['usedBy'];
export function HasSlot(container: unknown, ...ids: (keyof Slots)[]): boolean {
if (!container || 'object' !== typeof container) return false;
const myslots = GetSlots(container as AnyTemporalType);
return !!myslots && ids.every((id) => id in myslots);
}
export function GetSlot<KeyT extends keyof Slots>(
container: Slots[typeof id]['usedBy'],
id: KeyT
): Slots[KeyT]['value'] {
const value = GetSlots(container)?.[id];
if (value === undefined) throw new TypeError(`Missing internal slot ${id}`);
return value;
}
export function SetSlot<KeyT extends SlotKey>(
container: Slots[KeyT]['usedBy'],
id: KeyT,
value: Slots[KeyT]['value']
): void {
const slots = GetSlots(container);
if (slots === undefined) throw new TypeError('Missing slots for the given container');
const existingSlot = slots[id];
if (existingSlot) throw new TypeError(`${id} already has set`);
slots[id] = value;
}
+11
View File
@@ -0,0 +1,11 @@
export { Instant } from './instant';
export { Calendar } from './calendar';
export { PlainDate } from './plaindate';
export { PlainDateTime } from './plaindatetime';
export { Duration } from './duration';
export { PlainMonthDay } from './plainmonthday';
export { Now } from './now';
export { PlainTime } from './plaintime';
export { TimeZone } from './timezone';
export { PlainYearMonth } from './plainyearmonth';
export { ZonedDateTime } from './zoneddatetime';
+168
View File
@@ -0,0 +1,168 @@
import { DEBUG } from './debug';
import * as ES from './ecmascript';
import { DefineIntrinsic, GetIntrinsic, MakeIntrinsicClass } from './intrinsicclass';
import {
TIMEZONE_ID,
EPOCHNANOSECONDS,
ISO_YEAR,
ISO_MONTH,
ISO_DAY,
ISO_HOUR,
ISO_MINUTE,
ISO_SECOND,
ISO_MILLISECOND,
ISO_MICROSECOND,
ISO_NANOSECOND,
CreateSlots,
GetSlot,
SetSlot
} from './slots';
import JSBI from 'jsbi';
import type { Temporal } from '..';
import type { TimeZoneParams as Params, TimeZoneReturn as Return } from './internaltypes';
export class TimeZone implements Temporal.TimeZone {
constructor(timeZoneIdentifierParam: string) {
// Note: if the argument is not passed, GetCanonicalTimeZoneIdentifier(undefined) will throw.
// This check exists only to improve the error message.
if (arguments.length < 1) {
throw new RangeError('missing argument: identifier is required');
}
const timeZoneIdentifier = ES.GetCanonicalTimeZoneIdentifier(timeZoneIdentifierParam);
CreateSlots(this);
SetSlot(this, TIMEZONE_ID, timeZoneIdentifier);
if (DEBUG) {
Object.defineProperty(this, '_repr_', {
value: `${this[Symbol.toStringTag]} <${timeZoneIdentifier}>`,
writable: false,
enumerable: false,
configurable: false
});
}
}
get id(): Return['id'] {
if (!ES.IsTemporalTimeZone(this)) throw new TypeError('invalid receiver');
return GetSlot(this, TIMEZONE_ID);
}
getOffsetNanosecondsFor(instantParam: Params['getOffsetNanosecondsFor'][0]): Return['getOffsetNanosecondsFor'] {
if (!ES.IsTemporalTimeZone(this)) throw new TypeError('invalid receiver');
const instant = ES.ToTemporalInstant(instantParam);
const id = GetSlot(this, TIMEZONE_ID);
if (ES.IsTimeZoneOffsetString(id)) {
return ES.ParseTimeZoneOffsetString(id);
}
return ES.GetNamedTimeZoneOffsetNanoseconds(id, GetSlot(instant, EPOCHNANOSECONDS));
}
getOffsetStringFor(instantParam: Params['getOffsetStringFor'][0]): Return['getOffsetStringFor'] {
if (!ES.IsTemporalTimeZone(this)) throw new TypeError('invalid receiver');
const instant = ES.ToTemporalInstant(instantParam);
return ES.GetOffsetStringFor(this, instant);
}
getPlainDateTimeFor(
instantParam: Params['getPlainDateTimeFor'][0],
calendarParam: Params['getPlainDateTimeFor'][1] = 'iso8601'
): Return['getPlainDateTimeFor'] {
if (!ES.IsTemporalTimeZone(this)) throw new TypeError('invalid receiver');
const instant = ES.ToTemporalInstant(instantParam);
const calendar = ES.ToTemporalCalendarSlotValue(calendarParam);
return ES.GetPlainDateTimeFor(this, instant, calendar);
}
getInstantFor(
dateTimeParam: Params['getInstantFor'][0],
optionsParam: Params['getInstantFor'][1] = undefined
): Return['getInstantFor'] {
if (!ES.IsTemporalTimeZone(this)) throw new TypeError('invalid receiver');
const dateTime = ES.ToTemporalDateTime(dateTimeParam);
const options = ES.GetOptionsObject(optionsParam);
const disambiguation = ES.ToTemporalDisambiguation(options);
return ES.GetInstantFor(this, dateTime, disambiguation);
}
getPossibleInstantsFor(dateTimeParam: Params['getPossibleInstantsFor'][0]): Return['getPossibleInstantsFor'] {
if (!ES.IsTemporalTimeZone(this)) throw new TypeError('invalid receiver');
const dateTime = ES.ToTemporalDateTime(dateTimeParam);
const Instant = GetIntrinsic('%Temporal.Instant%');
const id = GetSlot(this, TIMEZONE_ID);
if (ES.IsTimeZoneOffsetString(id)) {
const epochNs = ES.GetUTCEpochNanoseconds(
GetSlot(dateTime, ISO_YEAR),
GetSlot(dateTime, ISO_MONTH),
GetSlot(dateTime, ISO_DAY),
GetSlot(dateTime, ISO_HOUR),
GetSlot(dateTime, ISO_MINUTE),
GetSlot(dateTime, ISO_SECOND),
GetSlot(dateTime, ISO_MILLISECOND),
GetSlot(dateTime, ISO_MICROSECOND),
GetSlot(dateTime, ISO_NANOSECOND)
);
if (epochNs === null) throw new RangeError('DateTime outside of supported range');
const offsetNs = ES.ParseTimeZoneOffsetString(id);
return [new Instant(JSBI.subtract(epochNs, JSBI.BigInt(offsetNs)))];
}
const possibleEpochNs = ES.GetNamedTimeZoneEpochNanoseconds(
id,
GetSlot(dateTime, ISO_YEAR),
GetSlot(dateTime, ISO_MONTH),
GetSlot(dateTime, ISO_DAY),
GetSlot(dateTime, ISO_HOUR),
GetSlot(dateTime, ISO_MINUTE),
GetSlot(dateTime, ISO_SECOND),
GetSlot(dateTime, ISO_MILLISECOND),
GetSlot(dateTime, ISO_MICROSECOND),
GetSlot(dateTime, ISO_NANOSECOND)
);
return possibleEpochNs.map((ns) => new Instant(ns));
}
getNextTransition(startingPointParam: Params['getNextTransition'][0]): Return['getNextTransition'] {
if (!ES.IsTemporalTimeZone(this)) throw new TypeError('invalid receiver');
const startingPoint = ES.ToTemporalInstant(startingPointParam);
const id = GetSlot(this, TIMEZONE_ID);
// Offset time zones or UTC have no transitions
if (ES.IsTimeZoneOffsetString(id) || id === 'UTC') {
return null;
}
let epochNanoseconds: JSBI | null = GetSlot(startingPoint, EPOCHNANOSECONDS);
const Instant = GetIntrinsic('%Temporal.Instant%');
epochNanoseconds = ES.GetNamedTimeZoneNextTransition(id, epochNanoseconds);
return epochNanoseconds === null ? null : new Instant(epochNanoseconds);
}
getPreviousTransition(startingPointParam: Params['getPreviousTransition'][0]): Return['getPreviousTransition'] {
if (!ES.IsTemporalTimeZone(this)) throw new TypeError('invalid receiver');
const startingPoint = ES.ToTemporalInstant(startingPointParam);
const id = GetSlot(this, TIMEZONE_ID);
// Offset time zones or UTC have no transitions
if (ES.IsTimeZoneOffsetString(id) || id === 'UTC') {
return null;
}
let epochNanoseconds: JSBI | null = GetSlot(startingPoint, EPOCHNANOSECONDS);
const Instant = GetIntrinsic('%Temporal.Instant%');
epochNanoseconds = ES.GetNamedTimeZonePreviousTransition(id, epochNanoseconds);
return epochNanoseconds === null ? null : new Instant(epochNanoseconds);
}
toString(): string {
if (!ES.IsTemporalTimeZone(this)) throw new TypeError('invalid receiver');
return GetSlot(this, TIMEZONE_ID);
}
toJSON(): Return['toJSON'] {
if (!ES.IsTemporalTimeZone(this)) throw new TypeError('invalid receiver');
return GetSlot(this, TIMEZONE_ID);
}
static from(item: Params['from'][0]): Return['from'] {
const timeZoneSlotValue = ES.ToTemporalTimeZoneSlotValue(item);
return ES.ToTemporalTimeZoneObject(timeZoneSlotValue);
}
[Symbol.toStringTag]!: 'Temporal.TimeZone';
}
MakeIntrinsicClass(TimeZone, 'Temporal.TimeZone');
DefineIntrinsic('Temporal.TimeZone.prototype.getOffsetNanosecondsFor', TimeZone.prototype.getOffsetNanosecondsFor);
DefineIntrinsic('Temporal.TimeZone.prototype.getPossibleInstantsFor', TimeZone.prototype.getPossibleInstantsFor);
+627
View File
@@ -0,0 +1,627 @@
import * as ES from './ecmascript';
import { GetIntrinsic, MakeIntrinsicClass } from './intrinsicclass';
import {
CALENDAR,
EPOCHNANOSECONDS,
ISO_HOUR,
INSTANT,
ISO_DAY,
ISO_MONTH,
ISO_YEAR,
ISO_MICROSECOND,
ISO_MILLISECOND,
ISO_MINUTE,
ISO_NANOSECOND,
ISO_SECOND,
TIME_ZONE,
GetSlot
} from './slots';
import type { Temporal } from '..';
import { DateTimeFormat } from './intl';
import type { ZonedDateTimeParams as Params, ZonedDateTimeReturn as Return } from './internaltypes';
import JSBI from 'jsbi';
import { BILLION, MILLION, THOUSAND, ZERO, HOUR_NANOS } from './ecmascript';
const customResolvedOptions = DateTimeFormat.prototype.resolvedOptions as Intl.DateTimeFormat['resolvedOptions'];
const ObjectCreate = Object.create;
export class ZonedDateTime implements Temporal.ZonedDateTime {
constructor(
epochNanosecondsParam: bigint | JSBI,
timeZoneParam: string | Temporal.TimeZoneProtocol,
calendarParam: string | Temporal.CalendarProtocol = 'iso8601'
) {
// Note: if the argument is not passed, ToBigInt(undefined) will throw. This check exists only
// to improve the error message.
// ToTemporalTimeZoneSlotValue(undefined) has a clear enough message.
if (arguments.length < 1) {
throw new TypeError('missing argument: epochNanoseconds is required');
}
const epochNanoseconds = ES.ToBigInt(epochNanosecondsParam);
const timeZone = ES.ToTemporalTimeZoneSlotValue(timeZoneParam);
const calendar = ES.ToTemporalCalendarSlotValue(calendarParam);
ES.CreateTemporalZonedDateTimeSlots(this, epochNanoseconds, timeZone, calendar);
}
get calendarId(): Return['calendarId'] {
if (!ES.IsTemporalZonedDateTime(this)) throw new TypeError('invalid receiver');
return ES.ToTemporalCalendarIdentifier(GetSlot(this, CALENDAR));
}
get timeZoneId(): Return['timeZoneId'] {
if (!ES.IsTemporalZonedDateTime(this)) throw new TypeError('invalid receiver');
return ES.ToTemporalTimeZoneIdentifier(GetSlot(this, TIME_ZONE));
}
get year(): Return['year'] {
if (!ES.IsTemporalZonedDateTime(this)) throw new TypeError('invalid receiver');
return ES.CalendarYear(GetSlot(this, CALENDAR), dateTime(this));
}
get month(): Return['month'] {
if (!ES.IsTemporalZonedDateTime(this)) throw new TypeError('invalid receiver');
return ES.CalendarMonth(GetSlot(this, CALENDAR), dateTime(this));
}
get monthCode(): Return['monthCode'] {
if (!ES.IsTemporalZonedDateTime(this)) throw new TypeError('invalid receiver');
return ES.CalendarMonthCode(GetSlot(this, CALENDAR), dateTime(this));
}
get day(): Return['day'] {
if (!ES.IsTemporalZonedDateTime(this)) throw new TypeError('invalid receiver');
return ES.CalendarDay(GetSlot(this, CALENDAR), dateTime(this));
}
get hour(): Return['hour'] {
if (!ES.IsTemporalZonedDateTime(this)) throw new TypeError('invalid receiver');
return GetSlot(dateTime(this), ISO_HOUR);
}
get minute(): Return['minute'] {
if (!ES.IsTemporalZonedDateTime(this)) throw new TypeError('invalid receiver');
return GetSlot(dateTime(this), ISO_MINUTE);
}
get second(): Return['second'] {
if (!ES.IsTemporalZonedDateTime(this)) throw new TypeError('invalid receiver');
return GetSlot(dateTime(this), ISO_SECOND);
}
get millisecond(): Return['millisecond'] {
if (!ES.IsTemporalZonedDateTime(this)) throw new TypeError('invalid receiver');
return GetSlot(dateTime(this), ISO_MILLISECOND);
}
get microsecond(): Return['microsecond'] {
if (!ES.IsTemporalZonedDateTime(this)) throw new TypeError('invalid receiver');
return GetSlot(dateTime(this), ISO_MICROSECOND);
}
get nanosecond(): Return['nanosecond'] {
if (!ES.IsTemporalZonedDateTime(this)) throw new TypeError('invalid receiver');
return GetSlot(dateTime(this), ISO_NANOSECOND);
}
get era(): Return['era'] {
if (!ES.IsTemporalZonedDateTime(this)) throw new TypeError('invalid receiver');
return ES.CalendarEra(GetSlot(this, CALENDAR), dateTime(this));
}
get eraYear(): Return['eraYear'] {
if (!ES.IsTemporalZonedDateTime(this)) throw new TypeError('invalid receiver');
return ES.CalendarEraYear(GetSlot(this, CALENDAR), dateTime(this));
}
get epochSeconds(): Return['epochSeconds'] {
if (!ES.IsTemporalZonedDateTime(this)) throw new TypeError('invalid receiver');
const value = GetSlot(this, EPOCHNANOSECONDS);
return JSBI.toNumber(ES.BigIntFloorDiv(value, BILLION));
}
get epochMilliseconds(): Return['epochMilliseconds'] {
if (!ES.IsTemporalZonedDateTime(this)) throw new TypeError('invalid receiver');
const value = GetSlot(this, EPOCHNANOSECONDS);
return JSBI.toNumber(ES.BigIntFloorDiv(value, MILLION));
}
get epochMicroseconds(): Return['epochMicroseconds'] {
if (!ES.IsTemporalZonedDateTime(this)) throw new TypeError('invalid receiver');
const value = GetSlot(this, EPOCHNANOSECONDS);
return ES.ToBigIntExternal(ES.BigIntFloorDiv(value, THOUSAND));
}
get epochNanoseconds(): Return['epochNanoseconds'] {
if (!ES.IsTemporalZonedDateTime(this)) throw new TypeError('invalid receiver');
return ES.ToBigIntExternal(GetSlot(this, EPOCHNANOSECONDS));
}
get dayOfWeek(): Return['dayOfWeek'] {
if (!ES.IsTemporalZonedDateTime(this)) throw new TypeError('invalid receiver');
return ES.CalendarDayOfWeek(GetSlot(this, CALENDAR), dateTime(this));
}
get dayOfYear(): Return['dayOfYear'] {
if (!ES.IsTemporalZonedDateTime(this)) throw new TypeError('invalid receiver');
return ES.CalendarDayOfYear(GetSlot(this, CALENDAR), dateTime(this));
}
get weekOfYear(): Return['weekOfYear'] {
if (!ES.IsTemporalZonedDateTime(this)) throw new TypeError('invalid receiver');
return ES.CalendarWeekOfYear(GetSlot(this, CALENDAR), dateTime(this));
}
get yearOfWeek(): Return['yearOfWeek'] {
if (!ES.IsTemporalZonedDateTime(this)) throw new TypeError('invalid receiver');
return ES.CalendarYearOfWeek(GetSlot(this, CALENDAR), dateTime(this));
}
get hoursInDay(): Return['hoursInDay'] {
if (!ES.IsTemporalZonedDateTime(this)) throw new TypeError('invalid receiver');
const dt = dateTime(this);
const DateTime = GetIntrinsic('%Temporal.PlainDateTime%');
const year = GetSlot(dt, ISO_YEAR);
const month = GetSlot(dt, ISO_MONTH);
const day = GetSlot(dt, ISO_DAY);
const today = new DateTime(year, month, day, 0, 0, 0, 0, 0, 0);
const tomorrowFields = ES.AddISODate(year, month, day, 0, 0, 0, 1, 'reject');
const tomorrow = new DateTime(tomorrowFields.year, tomorrowFields.month, tomorrowFields.day, 0, 0, 0, 0, 0, 0);
const timeZone = GetSlot(this, TIME_ZONE);
const todayNs = GetSlot(ES.GetInstantFor(timeZone, today, 'compatible'), EPOCHNANOSECONDS);
const tomorrowNs = GetSlot(ES.GetInstantFor(timeZone, tomorrow, 'compatible'), EPOCHNANOSECONDS);
const diffNs = JSBI.subtract(tomorrowNs, todayNs);
return ES.BigIntDivideToNumber(diffNs, HOUR_NANOS);
}
get daysInWeek(): Return['daysInWeek'] {
if (!ES.IsTemporalZonedDateTime(this)) throw new TypeError('invalid receiver');
return ES.CalendarDaysInWeek(GetSlot(this, CALENDAR), dateTime(this));
}
get daysInMonth(): Return['daysInMonth'] {
if (!ES.IsTemporalZonedDateTime(this)) throw new TypeError('invalid receiver');
return ES.CalendarDaysInMonth(GetSlot(this, CALENDAR), dateTime(this));
}
get daysInYear(): Return['daysInYear'] {
if (!ES.IsTemporalZonedDateTime(this)) throw new TypeError('invalid receiver');
return ES.CalendarDaysInYear(GetSlot(this, CALENDAR), dateTime(this));
}
get monthsInYear(): Return['monthsInYear'] {
if (!ES.IsTemporalZonedDateTime(this)) throw new TypeError('invalid receiver');
return ES.CalendarMonthsInYear(GetSlot(this, CALENDAR), dateTime(this));
}
get inLeapYear(): Return['inLeapYear'] {
if (!ES.IsTemporalZonedDateTime(this)) throw new TypeError('invalid receiver');
return ES.CalendarInLeapYear(GetSlot(this, CALENDAR), dateTime(this));
}
get offset(): Return['offset'] {
if (!ES.IsTemporalZonedDateTime(this)) throw new TypeError('invalid receiver');
return ES.GetOffsetStringFor(GetSlot(this, TIME_ZONE), GetSlot(this, INSTANT));
}
get offsetNanoseconds(): Return['offsetNanoseconds'] {
if (!ES.IsTemporalZonedDateTime(this)) throw new TypeError('invalid receiver');
return ES.GetOffsetNanosecondsFor(GetSlot(this, TIME_ZONE), GetSlot(this, INSTANT));
}
with(temporalZonedDateTimeLike: Params['with'][0], optionsParam: Params['with'][1] = undefined): Return['with'] {
if (!ES.IsTemporalZonedDateTime(this)) throw new TypeError('invalid receiver');
if (!ES.IsObject(temporalZonedDateTimeLike)) {
throw new TypeError('invalid zoned-date-time-like');
}
ES.RejectTemporalLikeObject(temporalZonedDateTimeLike);
const options = ES.GetOptionsObject(optionsParam);
const calendar = GetSlot(this, CALENDAR);
let fieldNames: (keyof Temporal.ZonedDateTimeLike)[] = ES.CalendarFields(calendar, [
'day',
'hour',
'microsecond',
'millisecond',
'minute',
'month',
'monthCode',
'nanosecond',
'second',
'year'
] as const);
fieldNames.push('offset');
let fields = ES.PrepareTemporalFields(this, fieldNames, ['offset']);
const partialZonedDateTime = ES.PrepareTemporalFields(temporalZonedDateTimeLike, fieldNames, 'partial');
fields = ES.CalendarMergeFields(calendar, fields, partialZonedDateTime);
fields = ES.PrepareTemporalFields(fields, fieldNames, ['offset']);
const disambiguation = ES.ToTemporalDisambiguation(options);
const offset = ES.ToTemporalOffset(options, 'prefer');
let { year, month, day, hour, minute, second, millisecond, microsecond, nanosecond } =
ES.InterpretTemporalDateTimeFields(calendar, fields, options);
const offsetNs = ES.ParseTimeZoneOffsetString(fields.offset);
const timeZone = GetSlot(this, TIME_ZONE);
const epochNanoseconds = ES.InterpretISODateTimeOffset(
year,
month,
day,
hour,
minute,
second,
millisecond,
microsecond,
nanosecond,
'option',
offsetNs,
timeZone,
disambiguation,
offset,
/* matchMinute = */ false
);
return ES.CreateTemporalZonedDateTime(epochNanoseconds, timeZone, calendar);
}
withPlainDate(temporalDateParam: Params['withPlainDate'][0]): Return['withPlainDate'] {
if (!ES.IsTemporalZonedDateTime(this)) throw new TypeError('invalid receiver');
const temporalDate = ES.ToTemporalDate(temporalDateParam);
const year = GetSlot(temporalDate, ISO_YEAR);
const month = GetSlot(temporalDate, ISO_MONTH);
const day = GetSlot(temporalDate, ISO_DAY);
let calendar = GetSlot(temporalDate, CALENDAR);
const thisDt = dateTime(this);
const hour = GetSlot(thisDt, ISO_HOUR);
const minute = GetSlot(thisDt, ISO_MINUTE);
const second = GetSlot(thisDt, ISO_SECOND);
const millisecond = GetSlot(thisDt, ISO_MILLISECOND);
const microsecond = GetSlot(thisDt, ISO_MICROSECOND);
const nanosecond = GetSlot(thisDt, ISO_NANOSECOND);
calendar = ES.ConsolidateCalendars(GetSlot(this, CALENDAR), calendar);
const timeZone = GetSlot(this, TIME_ZONE);
const PlainDateTime = GetIntrinsic('%Temporal.PlainDateTime%');
const dt = new PlainDateTime(
year,
month,
day,
hour,
minute,
second,
millisecond,
microsecond,
nanosecond,
calendar
);
const instant = ES.GetInstantFor(timeZone, dt, 'compatible');
return ES.CreateTemporalZonedDateTime(GetSlot(instant, EPOCHNANOSECONDS), timeZone, calendar);
}
withPlainTime(temporalTimeParam: Params['withPlainTime'][0] = undefined): Return['withPlainTime'] {
if (!ES.IsTemporalZonedDateTime(this)) throw new TypeError('invalid receiver');
const PlainTime = GetIntrinsic('%Temporal.PlainTime%');
const temporalTime = temporalTimeParam === undefined ? new PlainTime() : ES.ToTemporalTime(temporalTimeParam);
const thisDt = dateTime(this);
const year = GetSlot(thisDt, ISO_YEAR);
const month = GetSlot(thisDt, ISO_MONTH);
const day = GetSlot(thisDt, ISO_DAY);
const calendar = GetSlot(this, CALENDAR);
const hour = GetSlot(temporalTime, ISO_HOUR);
const minute = GetSlot(temporalTime, ISO_MINUTE);
const second = GetSlot(temporalTime, ISO_SECOND);
const millisecond = GetSlot(temporalTime, ISO_MILLISECOND);
const microsecond = GetSlot(temporalTime, ISO_MICROSECOND);
const nanosecond = GetSlot(temporalTime, ISO_NANOSECOND);
const timeZone = GetSlot(this, TIME_ZONE);
const PlainDateTime = GetIntrinsic('%Temporal.PlainDateTime%');
const dt = new PlainDateTime(
year,
month,
day,
hour,
minute,
second,
millisecond,
microsecond,
nanosecond,
calendar
);
const instant = ES.GetInstantFor(timeZone, dt, 'compatible');
return ES.CreateTemporalZonedDateTime(GetSlot(instant, EPOCHNANOSECONDS), timeZone, calendar);
}
withTimeZone(timeZoneParam: Params['withTimeZone'][0]): Return['withTimeZone'] {
if (!ES.IsTemporalZonedDateTime(this)) throw new TypeError('invalid receiver');
const timeZone = ES.ToTemporalTimeZoneSlotValue(timeZoneParam);
return ES.CreateTemporalZonedDateTime(GetSlot(this, EPOCHNANOSECONDS), timeZone, GetSlot(this, CALENDAR));
}
withCalendar(calendarParam: Params['withCalendar'][0]): Return['withCalendar'] {
if (!ES.IsTemporalZonedDateTime(this)) throw new TypeError('invalid receiver');
const calendar = ES.ToTemporalCalendarSlotValue(calendarParam);
return ES.CreateTemporalZonedDateTime(GetSlot(this, EPOCHNANOSECONDS), GetSlot(this, TIME_ZONE), calendar);
}
add(temporalDurationLike: Params['add'][0], options: Params['add'][1] = undefined): Return['add'] {
if (!ES.IsTemporalZonedDateTime(this)) throw new TypeError('invalid receiver');
return ES.AddDurationToOrSubtractDurationFromZonedDateTime('add', this, temporalDurationLike, options);
}
subtract(
temporalDurationLike: Params['subtract'][0],
options: Params['subtract'][1] = undefined
): Return['subtract'] {
if (!ES.IsTemporalZonedDateTime(this)) throw new TypeError('invalid receiver');
return ES.AddDurationToOrSubtractDurationFromZonedDateTime('subtract', this, temporalDurationLike, options);
}
until(other: Params['until'][0], options: Params['until'][1] = undefined): Return['until'] {
if (!ES.IsTemporalZonedDateTime(this)) throw new TypeError('invalid receiver');
return ES.DifferenceTemporalZonedDateTime('until', this, other, options);
}
since(other: Params['since'][0], options: Params['since'][1] = undefined): Return['since'] {
if (!ES.IsTemporalZonedDateTime(this)) throw new TypeError('invalid receiver');
return ES.DifferenceTemporalZonedDateTime('since', this, other, options);
}
round(roundToParam: Params['round'][0]): Return['round'] {
if (!ES.IsTemporalZonedDateTime(this)) throw new TypeError('invalid receiver');
if (roundToParam === undefined) throw new TypeError('options parameter is required');
const roundTo =
typeof roundToParam === 'string'
? (ES.CreateOnePropObject('smallestUnit', roundToParam) as Exclude<typeof roundToParam, string>)
: ES.GetOptionsObject(roundToParam);
const roundingIncrement = ES.ToTemporalRoundingIncrement(roundTo);
const roundingMode = ES.ToTemporalRoundingMode(roundTo, 'halfExpand');
const smallestUnit = ES.GetTemporalUnit(roundTo, 'smallestUnit', 'time', ES.REQUIRED, ['day']);
const maximumIncrements = {
day: 1,
hour: 24,
minute: 60,
second: 60,
millisecond: 1000,
microsecond: 1000,
nanosecond: 1000
};
const maximum = maximumIncrements[smallestUnit];
const inclusive = maximum === 1;
ES.ValidateTemporalRoundingIncrement(roundingIncrement, maximum, inclusive);
// first, round the underlying DateTime fields
const dt = dateTime(this);
let year = GetSlot(dt, ISO_YEAR);
let month = GetSlot(dt, ISO_MONTH);
let day = GetSlot(dt, ISO_DAY);
let hour = GetSlot(dt, ISO_HOUR);
let minute = GetSlot(dt, ISO_MINUTE);
let second = GetSlot(dt, ISO_SECOND);
let millisecond = GetSlot(dt, ISO_MILLISECOND);
let microsecond = GetSlot(dt, ISO_MICROSECOND);
let nanosecond = GetSlot(dt, ISO_NANOSECOND);
const DateTime = GetIntrinsic('%Temporal.PlainDateTime%');
const timeZone = GetSlot(this, TIME_ZONE);
const calendar = GetSlot(this, CALENDAR);
const dtStart = new DateTime(GetSlot(dt, ISO_YEAR), GetSlot(dt, ISO_MONTH), GetSlot(dt, ISO_DAY), 0, 0, 0, 0, 0, 0);
const instantStart = ES.GetInstantFor(timeZone, dtStart, 'compatible');
const endNs = ES.AddZonedDateTime(instantStart, timeZone, calendar, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0);
const dayLengthNs = JSBI.subtract(endNs, JSBI.BigInt(GetSlot(instantStart, EPOCHNANOSECONDS)));
if (JSBI.lessThanOrEqual(dayLengthNs, ZERO)) {
throw new RangeError('cannot round a ZonedDateTime in a calendar with zero or negative length days');
}
({ year, month, day, hour, minute, second, millisecond, microsecond, nanosecond } = ES.RoundISODateTime(
year,
month,
day,
hour,
minute,
second,
millisecond,
microsecond,
nanosecond,
roundingIncrement,
smallestUnit,
roundingMode,
// Days are guaranteed to be shorter than Number.MAX_SAFE_INTEGER
// (which can hold up to 104 days in nanoseconds)
JSBI.toNumber(dayLengthNs)
));
// Now reset all DateTime fields but leave the TimeZone. The offset will
// also be retained if the new date/time values are still OK with the old
// offset. Otherwise the offset will be changed to be compatible with the
// new date/time values. If DST disambiguation is required, the `compatible`
// disambiguation algorithm will be used.
const offsetNs = ES.GetOffsetNanosecondsFor(timeZone, GetSlot(this, INSTANT));
const epochNanoseconds = ES.InterpretISODateTimeOffset(
year,
month,
day,
hour,
minute,
second,
millisecond,
microsecond,
nanosecond,
'option',
offsetNs,
timeZone,
'compatible',
'prefer',
/* matchMinute = */ false
);
return ES.CreateTemporalZonedDateTime(epochNanoseconds, timeZone, GetSlot(this, CALENDAR));
}
equals(otherParam: Params['equals'][0]): Return['equals'] {
if (!ES.IsTemporalZonedDateTime(this)) throw new TypeError('invalid receiver');
const other = ES.ToTemporalZonedDateTime(otherParam);
const one = GetSlot(this, EPOCHNANOSECONDS);
const two = GetSlot(other, EPOCHNANOSECONDS);
if (!JSBI.equal(JSBI.BigInt(one), JSBI.BigInt(two))) return false;
if (!ES.TimeZoneEquals(GetSlot(this, TIME_ZONE), GetSlot(other, TIME_ZONE))) return false;
return ES.CalendarEquals(GetSlot(this, CALENDAR), GetSlot(other, CALENDAR));
}
toString(optionsParam: Params['toString'][0] = undefined): string {
if (!ES.IsTemporalZonedDateTime(this)) throw new TypeError('invalid receiver');
const options = ES.GetOptionsObject(optionsParam);
const showCalendar = ES.ToCalendarNameOption(options);
const digits = ES.ToFractionalSecondDigits(options);
const showOffset = ES.ToShowOffsetOption(options);
const roundingMode = ES.ToTemporalRoundingMode(options, 'trunc');
const smallestUnit = ES.GetTemporalUnit(options, 'smallestUnit', 'time', undefined);
if (smallestUnit === 'hour') throw new RangeError('smallestUnit must be a time unit other than "hour"');
const showTimeZone = ES.ToTimeZoneNameOption(options);
const { precision, unit, increment } = ES.ToSecondsStringPrecisionRecord(smallestUnit, digits);
return ES.TemporalZonedDateTimeToString(this, precision, showCalendar, showTimeZone, showOffset, {
unit,
increment,
roundingMode
});
}
toLocaleString(
locales: Params['toLocaleString'][0] = undefined,
optionsParam: Params['toLocaleString'][1] = undefined
): string {
if (!ES.IsTemporalZonedDateTime(this)) throw new TypeError('invalid receiver');
const options = ES.GetOptionsObject(optionsParam);
const optionsCopy = ObjectCreate(null);
// This is not quite per specification, but this polyfill's DateTimeFormat
// already doesn't match the InitializeDateTimeFormat operation, and the
// access order might change anyway;
// see https://github.com/tc39/ecma402/issues/747
ES.CopyDataProperties(optionsCopy, options, ['timeZone']);
if (options.timeZone !== undefined) {
throw new TypeError('ZonedDateTime toLocaleString does not accept a timeZone option');
}
if (
optionsCopy.year === undefined &&
optionsCopy.month === undefined &&
optionsCopy.day === undefined &&
optionsCopy.weekday === undefined &&
optionsCopy.dateStyle === undefined &&
optionsCopy.hour === undefined &&
optionsCopy.minute === undefined &&
optionsCopy.second === undefined &&
optionsCopy.timeStyle === undefined &&
optionsCopy.dayPeriod === undefined &&
optionsCopy.timeZoneName === undefined
) {
optionsCopy.timeZoneName = 'short';
// The rest of the defaults will be filled in by formatting the Instant
}
let timeZone = ES.ToTemporalTimeZoneIdentifier(GetSlot(this, TIME_ZONE));
if (ES.IsTimeZoneOffsetString(timeZone)) {
// Note: https://github.com/tc39/ecma402/issues/683 will remove this
throw new RangeError('toLocaleString does not support offset string time zones');
}
timeZone = ES.GetCanonicalTimeZoneIdentifier(timeZone);
optionsCopy.timeZone = timeZone;
const formatter = new DateTimeFormat(locales, optionsCopy);
const localeCalendarIdentifier = ES.Call(customResolvedOptions, formatter, []).calendar;
const calendarIdentifier = ES.ToTemporalCalendarIdentifier(GetSlot(this, CALENDAR));
if (
calendarIdentifier !== 'iso8601' &&
localeCalendarIdentifier !== 'iso8601' &&
localeCalendarIdentifier !== calendarIdentifier
) {
throw new RangeError(
`cannot format ZonedDateTime with calendar ${calendarIdentifier}` +
` in locale with calendar ${localeCalendarIdentifier}`
);
}
return formatter.format(GetSlot(this, INSTANT));
}
toJSON(): Return['toJSON'] {
if (!ES.IsTemporalZonedDateTime(this)) throw new TypeError('invalid receiver');
return ES.TemporalZonedDateTimeToString(this, 'auto');
}
valueOf(): never {
throw new TypeError('use compare() or equals() to compare Temporal.ZonedDateTime');
}
startOfDay(): Return['startOfDay'] {
if (!ES.IsTemporalZonedDateTime(this)) throw new TypeError('invalid receiver');
const dt = dateTime(this);
const DateTime = GetIntrinsic('%Temporal.PlainDateTime%');
const calendar = GetSlot(this, CALENDAR);
const dtStart = new DateTime(
GetSlot(dt, ISO_YEAR),
GetSlot(dt, ISO_MONTH),
GetSlot(dt, ISO_DAY),
0,
0,
0,
0,
0,
0,
calendar
);
const timeZone = GetSlot(this, TIME_ZONE);
const instant = ES.GetInstantFor(timeZone, dtStart, 'compatible');
return ES.CreateTemporalZonedDateTime(GetSlot(instant, EPOCHNANOSECONDS), timeZone, calendar);
}
toInstant(): Return['toInstant'] {
if (!ES.IsTemporalZonedDateTime(this)) throw new TypeError('invalid receiver');
const TemporalInstant = GetIntrinsic('%Temporal.Instant%');
return new TemporalInstant(GetSlot(this, EPOCHNANOSECONDS));
}
toPlainDate(): Return['toPlainDate'] {
if (!ES.IsTemporalZonedDateTime(this)) throw new TypeError('invalid receiver');
return ES.TemporalDateTimeToDate(dateTime(this));
}
toPlainTime(): Return['toPlainTime'] {
if (!ES.IsTemporalZonedDateTime(this)) throw new TypeError('invalid receiver');
return ES.TemporalDateTimeToTime(dateTime(this));
}
toPlainDateTime(): Return['toPlainDateTime'] {
if (!ES.IsTemporalZonedDateTime(this)) throw new TypeError('invalid receiver');
return dateTime(this);
}
toPlainYearMonth(): Return['toPlainYearMonth'] {
if (!ES.IsTemporalZonedDateTime(this)) throw new TypeError('invalid receiver');
const calendar = GetSlot(this, CALENDAR);
const fieldNames = ES.CalendarFields(calendar, ['monthCode', 'year'] as const);
const fields = ES.PrepareTemporalFields(this, fieldNames, []);
return ES.CalendarYearMonthFromFields(calendar, fields);
}
toPlainMonthDay(): Return['toPlainMonthDay'] {
if (!ES.IsTemporalZonedDateTime(this)) throw new TypeError('invalid receiver');
const calendar = GetSlot(this, CALENDAR);
const fieldNames = ES.CalendarFields(calendar, ['day', 'monthCode'] as const);
const fields = ES.PrepareTemporalFields(this, fieldNames, []);
return ES.CalendarMonthDayFromFields(calendar, fields);
}
getISOFields(): Return['getISOFields'] {
if (!ES.IsTemporalZonedDateTime(this)) throw new TypeError('invalid receiver');
const dt = dateTime(this);
const tz = GetSlot(this, TIME_ZONE);
return {
calendar: GetSlot(this, CALENDAR),
isoDay: GetSlot(dt, ISO_DAY),
isoHour: GetSlot(dt, ISO_HOUR),
isoMicrosecond: GetSlot(dt, ISO_MICROSECOND),
isoMillisecond: GetSlot(dt, ISO_MILLISECOND),
isoMinute: GetSlot(dt, ISO_MINUTE),
isoMonth: GetSlot(dt, ISO_MONTH),
isoNanosecond: GetSlot(dt, ISO_NANOSECOND),
isoSecond: GetSlot(dt, ISO_SECOND),
isoYear: GetSlot(dt, ISO_YEAR),
offset: ES.GetOffsetStringFor(tz, GetSlot(this, INSTANT)),
timeZone: tz
};
}
getCalendar(): Return['getCalendar'] {
if (!ES.IsTemporalZonedDateTime(this)) throw new TypeError('invalid receiver');
return ES.ToTemporalCalendarObject(GetSlot(this, CALENDAR));
}
getTimeZone(): Return['getTimeZone'] {
if (!ES.IsTemporalZonedDateTime(this)) throw new TypeError('invalid receiver');
return ES.ToTemporalTimeZoneObject(GetSlot(this, TIME_ZONE));
}
static from(item: Params['from'][0], optionsParam: Params['from'][1] = undefined): Return['from'] {
const options = ES.GetOptionsObject(optionsParam);
if (ES.IsTemporalZonedDateTime(item)) {
ES.ToTemporalDisambiguation(options); // validate and ignore
ES.ToTemporalOffset(options, 'reject');
ES.ToTemporalOverflow(options);
return ES.CreateTemporalZonedDateTime(
GetSlot(item, EPOCHNANOSECONDS),
GetSlot(item, TIME_ZONE),
GetSlot(item, CALENDAR)
);
}
return ES.ToTemporalZonedDateTime(item, options);
}
static compare(oneParam: Params['compare'][0], twoParam: Params['compare'][1]): Return['compare'] {
const one = ES.ToTemporalZonedDateTime(oneParam);
const two = ES.ToTemporalZonedDateTime(twoParam);
const ns1 = GetSlot(one, EPOCHNANOSECONDS);
const ns2 = GetSlot(two, EPOCHNANOSECONDS);
if (JSBI.lessThan(JSBI.BigInt(ns1), JSBI.BigInt(ns2))) return -1;
if (JSBI.greaterThan(JSBI.BigInt(ns1), JSBI.BigInt(ns2))) return 1;
return 0;
}
[Symbol.toStringTag]!: 'Temporal.ZonedDateTime';
}
MakeIntrinsicClass(ZonedDateTime, 'Temporal.ZonedDateTime');
function dateTime(zdt: Temporal.ZonedDateTime) {
return ES.GetPlainDateTimeFor(GetSlot(zdt, TIME_ZONE), GetSlot(zdt, INSTANT), GetSlot(zdt, CALENDAR));
}
+141
View File
@@ -0,0 +1,141 @@
{
"name": "@js-temporal/polyfill",
"version": "0.4.4",
"description": "Polyfill for Tc39 Stage 3 proposal Temporal (https://github.com/tc39/proposal-temporal)",
"type": "module",
"main": "./dist/index.cjs",
"module": "./dist/index.esm.js",
"browser": "./dist/index.umd.js",
"exports": {
".": [
{
"import": {
"types": "./index.d.ts",
"default": "./dist/index.esm.js"
},
"require": {
"types": "./index.d.cts",
"default": "./dist/index.cjs"
},
"default": "./dist/index.cjs"
},
"./dist/index.cjs"
]
},
"types": "./index.d.ts",
"scripts": {
"test": "npm run build && node --no-warnings --experimental-modules --experimental-specifier-resolution=node --icu-data-dir node_modules/full-icu --loader ./test/resolve.source.mjs ./test/all.mjs",
"test262": "TEST262=1 npm run build && node runtest262.mjs \"$@\"",
"testValidStrings": "npm run build && node --experimental-modules --experimental-specifier-resolution=node --no-warnings --icu-data-dir ./node_modules/full-icu/ --loader ./test/resolve.source.mjs test/validStrings.mjs",
"build": "rm -rf dist/* tsc-out/* && tsc && rollup -c rollup.config.js --bundleConfigAsCjs",
"prepare": "npm run build",
"prepublishOnly": "node copy-types.mjs && npm run build",
"update": "npx npm-check-updates -u -x @pipobscure/demitasse && npm install",
"playground": "TEMPORAL_PLAYGROUND=1 npm run build && node --experimental-modules --no-warnings --icu-data-dir node_modules/full-icu -r ./dist/playground.cjs",
"lint": "eslint . --ext ts,js,mjs,.d.ts --max-warnings 0 --cache \"$@\" && npm run prettier",
"postlint": "npm run tscheck",
"prune": "ts-prune -e -i test/tc39 -i \"(lib/index|lib/init|index.d).ts\"",
"prettier": "prettier lib/* ./test/*.mjs ./*.md ./*.json ./*.d.ts ./*.js ./.*.yml --check",
"prettierfix": "prettier lib/* ./test/*.mjs ./*.md ./*.json ./*.d.ts ./*.js ./.*.yml --check --write",
"eslintfix": "eslint . --ext ts,js,mjs,.d.ts --fix",
"fix": "npm run eslintfix && npm run prettierfix",
"tscheck": "tsc index.d.ts --noEmit --strict --lib ESNext"
},
"keywords": [
"Calendar",
"Date",
"DateTime",
"Duration",
"Instant",
"MonthDay",
"Polyfill",
"Temporal",
"Time",
"Timestamp",
"TimeZone",
"YearMonth"
],
"author": "Philipp Dunkel <pip@pipobscure.com>",
"contributors": [
"Daniel Ehrenberg",
"Jason Williams",
"Justin Grant",
"James Wright",
"Maggie Johnson-Pint",
"Matt Johnson-Pint",
"Ms2ger",
"Philip Chimento",
"Philipp Dunkel",
"Sasha Pierson",
"Shane F. Carr",
"Ujjwal Sharma"
],
"license": "ISC",
"files": [
"index.d.ts",
"index.d.cts",
"dist",
"lib",
"CHANGELOG.md"
],
"overrides": {
"@rollup/pluginutils": "^5.0.2"
},
"dependencies": {
"jsbi": "^4.3.0",
"tslib": "^2.4.1"
},
"devDependencies": {
"@babel/core": "^7.20.5",
"@babel/preset-env": "^7.20.2",
"@js-temporal/temporal-test262-runner": "^0.9.0",
"@pipobscure/demitasse": "^1.0.10",
"@pipobscure/demitasse-pretty": "^1.0.10",
"@pipobscure/demitasse-run": "^1.0.10",
"@rollup/plugin-babel": "^6.0.3",
"@rollup/plugin-commonjs": "^23.0.4",
"@rollup/plugin-node-resolve": "^15.0.1",
"@rollup/plugin-replace": "^5.0.1",
"@rollup/plugin-terser": "^0.2.0",
"@rollup/plugin-typescript": "^10.0.1",
"@typescript-eslint/eslint-plugin": "^5.46.0",
"@typescript-eslint/parser": "^5.46.0",
"eslint": "^8.29.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-prettier": "^4.2.1",
"full-icu": "^1.5.0",
"prettier": "^2.8.1",
"rollup": "^3.7.1",
"rollup-plugin-dts": "^5.0.0",
"rollup-plugin-sourcemaps": "^0.6.3",
"test262-harness": "^10.0.0",
"timezones.json": "^1.6.1",
"ts-prune": "^0.10.3",
"typescript": "^4.9.4",
"yargs": "^17.6.2"
},
"engines": {
"node": ">=12"
},
"prettier": {
"printWidth": 120,
"trailingComma": "none",
"tabWidth": 2,
"semi": true,
"singleQuote": true,
"bracketSpacing": true,
"arrowParens": "always"
},
"directories": {
"lib": "lib",
"test": "test"
},
"repository": {
"type": "git",
"url": "git+https://github.com/js-temporal/temporal-polyfill.git"
},
"bugs": {
"url": "https://github.com/js-temporal/temporal-polyfill/issues"
},
"homepage": "https://github.com/js-temporal/temporal-polyfill#readme"
}