From 5af743c737b556725c899ad271d78324c36bab00 Mon Sep 17 00:00:00 2001 From: nodejs-github-bot <18269663+nodejs-github-bot@users.noreply.github.com> Date: Sun, 30 Nov 2025 00:41:36 +0000 Subject: [PATCH] deps: update temporal to 0.1.2 --- deps/temporal/CHANGELOG.md | 42 +- deps/temporal/Cargo.lock | 94 ++- deps/temporal/Cargo.toml | 37 +- deps/temporal/docs/architecture.md | 2 +- deps/temporal/provider/Cargo.toml | 4 +- .../src/data/debug/iana_normalizer.json | 424 ------------- .../provider/src/data/iana_normalizer.rs.data | 2 +- .../provider/src/experimental_tzif/posix.rs | 10 +- deps/temporal/provider/src/provider.rs | 137 +++++ deps/temporal/provider/src/tzdb/datagen.rs | 27 +- deps/temporal/provider/src/tzif.rs | 2 +- .../src/builtins/compiled/duration/tests.rs | 21 +- deps/temporal/src/builtins/core/calendar.rs | 358 ++++++----- .../src/builtins/core/calendar/era.rs | 159 ----- .../src/builtins/core/calendar/fields.rs | 38 +- .../src/builtins/core/calendar/types.rs | 570 +++--------------- deps/temporal/src/builtins/core/duration.rs | 21 +- .../src/builtins/core/duration/normalized.rs | 135 +++-- .../src/builtins/core/duration/tests.rs | 72 ++- deps/temporal/src/builtins/core/instant.rs | 6 +- deps/temporal/src/builtins/core/now.rs | 17 +- deps/temporal/src/builtins/core/plain_date.rs | 14 +- .../src/builtins/core/plain_date_time.rs | 25 +- .../src/builtins/core/plain_month_day.rs | 52 +- .../src/builtins/core/plain_year_month.rs | 11 +- deps/temporal/src/builtins/core/time_zone.rs | 28 +- .../src/builtins/core/zoned_date_time.rs | 101 ++-- .../builtins/core/zoned_date_time/tests.rs | 72 ++- deps/temporal/src/error.rs | 67 +- deps/temporal/src/host.rs | 12 +- deps/temporal/src/lib.rs | 2 +- deps/temporal/src/options/relative_to.rs | 2 +- deps/temporal/src/parsed_intermediates.rs | 5 +- deps/temporal/src/parsers.rs | 21 +- deps/temporal/src/parsers/time_zone.rs | 2 +- deps/temporal/src/primitive.rs | 44 ++ deps/temporal/src/sys.rs | 15 +- deps/temporal/temporal_capi/Cargo.toml | 6 +- .../bindings/c/AnyCalendarKind.d.h | 31 +- .../bindings/c/ArithmeticOverflow.h | 2 +- .../bindings/c/DifferenceSettings.h | 2 +- .../temporal_capi/bindings/c/Disambiguation.h | 2 +- .../bindings/c/DisplayCalendar.h | 2 +- .../temporal_capi/bindings/c/DisplayOffset.h | 2 +- .../bindings/c/DisplayTimeZone.h | 2 +- .../temporal_capi/bindings/c/ErrorKind.h | 2 +- .../bindings/c/OffsetDisambiguation.h | 2 +- .../temporal_capi/bindings/c/PartialDate.h | 2 +- .../bindings/c/PartialDateTime.h | 2 +- .../temporal_capi/bindings/c/PartialTime.h | 2 +- .../bindings/c/PartialZonedDateTime.h | 2 +- .../temporal_capi/bindings/c/Precision.h | 2 +- .../temporal_capi/bindings/c/RelativeTo.h | 2 +- .../temporal_capi/bindings/c/RoundingMode.h | 2 +- .../bindings/c/RoundingOptions.h | 2 +- deps/temporal/temporal_capi/bindings/c/Sign.h | 2 +- .../temporal_capi/bindings/c/TemporalError.h | 2 +- .../bindings/c/ToStringRoundingOptions.h | 2 +- .../bindings/c/TransitionDirection.h | 2 +- deps/temporal/temporal_capi/bindings/c/Unit.h | 2 +- .../bindings/c/UnsignedRoundingMode.h | 2 +- .../cpp/temporal_rs/AnyCalendarKind.d.hpp | 64 +- .../cpp/temporal_rs/AnyCalendarKind.hpp | 3 +- .../cpp/temporal_rs/ArithmeticOverflow.hpp | 2 - .../cpp/temporal_rs/DifferenceSettings.hpp | 2 - .../cpp/temporal_rs/Disambiguation.hpp | 2 - .../cpp/temporal_rs/DisplayCalendar.hpp | 2 - .../cpp/temporal_rs/DisplayOffset.hpp | 2 - .../cpp/temporal_rs/DisplayTimeZone.hpp | 2 - .../bindings/cpp/temporal_rs/ErrorKind.hpp | 2 - .../cpp/temporal_rs/OffsetDisambiguation.hpp | 2 - .../bindings/cpp/temporal_rs/PartialDate.hpp | 2 - .../cpp/temporal_rs/PartialDateTime.hpp | 2 - .../bindings/cpp/temporal_rs/PartialTime.hpp | 2 - .../cpp/temporal_rs/PartialZonedDateTime.hpp | 2 - .../bindings/cpp/temporal_rs/Precision.hpp | 2 - .../bindings/cpp/temporal_rs/RelativeTo.hpp | 2 - .../bindings/cpp/temporal_rs/RoundingMode.hpp | 2 - .../cpp/temporal_rs/RoundingOptions.hpp | 2 - .../bindings/cpp/temporal_rs/Sign.hpp | 2 - .../cpp/temporal_rs/TemporalError.hpp | 2 - .../temporal_rs/ToStringRoundingOptions.hpp | 2 - .../cpp/temporal_rs/TransitionDirection.hpp | 2 - .../bindings/cpp/temporal_rs/Unit.hpp | 2 - .../cpp/temporal_rs/UnsignedRoundingMode.hpp | 2 - .../cpp/temporal_rs/diplomat_runtime.hpp | 7 +- deps/temporal/temporal_capi/src/calendar.rs | 8 +- deps/temporal/tools/bakeddata/Cargo.toml | 2 +- deps/temporal/zoneinfo/Cargo.toml | 2 +- deps/temporal/zoneinfo/src/lib.rs | 34 ++ deps/temporal/zoneinfo/src/parser.rs | 29 +- 91 files changed, 1247 insertions(+), 1678 deletions(-) delete mode 100644 deps/temporal/src/builtins/core/calendar/era.rs diff --git a/deps/temporal/CHANGELOG.md b/deps/temporal/CHANGELOG.md index a56cfdfaaaf900..e7ded7d700b6af 100644 --- a/deps/temporal/CHANGELOG.md +++ b/deps/temporal/CHANGELOG.md @@ -1,3 +1,41 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +## What's Changed in v0.1.2 +* Publish 0.1.2 by @Manishearth in [#625](https://github.com/boa-dev/temporal/pull/625) +* Ignore timezones mentioned in zone.tab when constructing the canonicalization table by @Manishearth in [#624](https://github.com/boa-dev/temporal/pull/624) +* Add logic to Duration::total to handle loss of precision by @nekevss in [#622](https://github.com/boa-dev/temporal/pull/622) +* Add feature to force float64-representable durations by @Manishearth in [#621](https://github.com/boa-dev/temporal/pull/621) +* Updates for ZonedDateTime since / until issue by @Manishearth in [#619](https://github.com/boa-dev/temporal/pull/619) +* Fix returned duration sign for non-ISO date arithmetic by @Manishearth in [#618](https://github.com/boa-dev/temporal/pull/618) +* Constrain durations into a range that will produce valid Temporal dates before passing to ICU4X by @Manishearth in [#615](https://github.com/boa-dev/temporal/pull/615) +* Add smart pointer implementations for TimeZone traits by @jedel1043 in [#614](https://github.com/boa-dev/temporal/pull/614) +* Fix serialization of durations with zero seconds and nonzero subseconds by @ptomato in [#610](https://github.com/boa-dev/temporal/pull/610) +* Remove support for unqualified `islamic` calendar by @Manishearth in [#609](https://github.com/boa-dev/temporal/pull/609) +* Make ISO the default AnyCalendarKind over FFI by @Manishearth in [#608](https://github.com/boa-dev/temporal/pull/608) + +**Full Changelog**: https://github.com/boa-dev/temporal/compare/v0.1.1...v0.1.2 + +## What's Changed in v0.1.1 +* Publish 0.1.1 by @Manishearth in [#605](https://github.com/boa-dev/temporal/pull/605) +* fix: allow passing `&dyn TimeZoneProvider` in arguments by @jedel1043 in [#599](https://github.com/boa-dev/temporal/pull/599) +* Update ICU4X to 2.1 by @Manishearth in [#604](https://github.com/boa-dev/temporal/pull/604) +* Update Diplomat to 0.14.0 by @Manishearth in [#603](https://github.com/boa-dev/temporal/pull/603) +* Update ICU4X by @Manishearth in [#601](https://github.com/boa-dev/temporal/pull/601) +* Move to new ICU4X arithmetic code by @Manishearth in [#595](https://github.com/boa-dev/temporal/pull/595) +* Update to ICU4X main by @Manishearth in [#596](https://github.com/boa-dev/temporal/pull/596) +* Remove HijriSimulatedMecca / islamic-rgsa by @Manishearth in [#597](https://github.com/boa-dev/temporal/pull/597) +* Fix a small typo in errors by @reillysiemens in [#594](https://github.com/boa-dev/temporal/pull/594) +* Update to ICU4X's new Calendar::from_fields by @Manishearth in [#582](https://github.com/boa-dev/temporal/pull/582) +* re-export DefaultHostSystem by @Sharktheone in [#590](https://github.com/boa-dev/temporal/pull/590) + +## New Contributors +* @reillysiemens made their first contribution in [#594](https://github.com/boa-dev/temporal/pull/594) +* @Sharktheone made their first contribution in [#590](https://github.com/boa-dev/temporal/pull/590) + +**Full Changelog**: https://github.com/boa-dev/temporal/compare/v0.1.0...v0.1.1 + ## What's Changed in v0.1.0 * Update Diplomat to 0.13.0 by @Manishearth in [#588](https://github.com/boa-dev/temporal/pull/588) * Add TryFrom for PartialDuration to Duration by @nekevss in [#585](https://github.com/boa-dev/temporal/pull/585) @@ -29,10 +67,6 @@ **Full Changelog**: https://github.com/boa-dev/temporal/compare/v0.0.16...v0.1.0 -# Changelog - -All notable changes to this project will be documented in this file. - ## What's Changed in v0.0.16 * Bump versions to 0.0.16 * Remove extraneous icu_time dependency diff --git a/deps/temporal/Cargo.lock b/deps/temporal/Cargo.lock index 9db20cc27add39..727d3ca67b657b 100644 --- a/deps/temporal/Cargo.lock +++ b/deps/temporal/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "allocator-api2" @@ -117,7 +117,7 @@ checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "bakeddata" -version = "0.1.0" +version = "0.1.2" dependencies = [ "databake", "prettyplease", @@ -157,9 +157,9 @@ checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" [[package]] name = "calendrical_calculations" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53c5d386a9f2c8b97e1a036420bcf937db4e5c9df33eb0232025008ced6104c0" +checksum = "3a0b39595c6ee54a8d0900204ba4c401d0ab4eb45adaf07178e8d017541529e7" dependencies = [ "core_maths", "displaydoc", @@ -285,13 +285,13 @@ dependencies = [ [[package]] name = "depcheck" -version = "0.1.0" +version = "0.1.2" [[package]] name = "diplomat" -version = "0.13.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ece782ffeb426ef0d3074c5623e8f6552cc912e4bbeecfda9583cb01b02b8ba1" +checksum = "9adb46b05e2f53dcf6a7dfc242e4ce9eb60c369b6b6eb10826a01e93167f59c6" dependencies = [ "diplomat_core", "proc-macro2", @@ -301,22 +301,22 @@ dependencies = [ [[package]] name = "diplomat-gen" -version = "0.1.0" +version = "0.1.2" dependencies = [ "diplomat-tool", ] [[package]] name = "diplomat-runtime" -version = "0.13.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa011f69b7f99cd4c4f1545a88cfa5f303abfdd76962843a5e5c88ea7bfe81f4" +checksum = "0569bd3caaf13829da7ee4e83dbf9197a0e1ecd72772da6d08f0b4c9285c8d29" [[package]] name = "diplomat-tool" -version = "0.13.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f88fa2be520ed769c790accb955cc51ebc7ceb1e9d87ce4b7db24357e9378bad" +checksum = "8cff1547f90c8ccb45024e89f9597c1958d54e1374a28e5e33bc278244fc2b25" dependencies = [ "askama", "clap", @@ -336,9 +336,9 @@ dependencies = [ [[package]] name = "diplomat_core" -version = "0.13.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb0f9322e2c506400ac3f374abfcaf9fd841fcdb729bbf008a135b600f99ede7" +checksum = "51731530ed7f2d4495019abc7df3744f53338e69e2863a6a64ae91821c763df1" dependencies = [ "displaydoc", "either", @@ -431,9 +431,9 @@ dependencies = [ [[package]] name = "icu_calendar" -version = "2.0.3" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e239d6422e2fdcea5d9756b48400caabac25aa4ab91b6608bd4bb6f23f0558c" +checksum = "af1012b9ecfa510672c9920645a1247e0ab4037ad149fba52f0daec4c7d07505" dependencies = [ "calendrical_calculations", "displaydoc", @@ -442,21 +442,20 @@ dependencies = [ "icu_locale_core", "icu_provider", "tinystr", - "writeable", "zerovec", ] [[package]] name = "icu_calendar_data" -version = "2.0.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7219c8639ab936713a87b571eed2bc2615aa9137e8af6eb221446ee5644acc18" +checksum = "a5e28bac68c36104316001a16a5a0ce1822dda530e6ee2e30ca566013a62863c" [[package]] name = "icu_collections" -version = "2.0.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" +checksum = "f578a71f2bfaf7ceb30b519a645ae48024b45f9eecbe060a31a004d7b4ba9462" dependencies = [ "displaydoc", "potential_utf", @@ -467,11 +466,10 @@ dependencies = [ [[package]] name = "icu_locale" -version = "2.0.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ae5921528335e91da1b6c695dbf1ec37df5ac13faa3f91e5640be93aa2fbefd" +checksum = "b77d60c94a44c2eb07640e7b9094e6fa052b6cc1b7ad14c309ae346c7108722e" dependencies = [ - "displaydoc", "icu_collections", "icu_locale_core", "icu_locale_data", @@ -483,12 +481,13 @@ dependencies = [ [[package]] name = "icu_locale_core" -version = "2.0.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" +checksum = "4c219b62bf5a06801012446193fdfcbd7970e876823aba4c62def2ce957dcb44" dependencies = [ "displaydoc", "litemap", + "serde", "tinystr", "writeable", "zerovec", @@ -496,20 +495,20 @@ dependencies = [ [[package]] name = "icu_locale_data" -version = "2.0.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fdef0c124749d06a743c69e938350816554eb63ac979166590e2b4ee4252765" +checksum = "c59e4b9cb2fa24a06fd4996f38a18a18ae4d5d27b3d1ed98af83dcbb7ee6e914" [[package]] name = "icu_provider" -version = "2.0.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" +checksum = "f64958e359123591ae1f17a27b5fc9ebdb50c98b04e0401146154de1d8fe3e44" dependencies = [ "displaydoc", "icu_locale_core", + "serde", "stable_deref_trait", - "tinystr", "writeable", "yoke", "zerofrom", @@ -556,12 +555,9 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "ixdtf" -version = "0.6.2" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08b741faae9005d3c809ca4b8566d75745c408171b3c6bbb54d2b00d04910c1c" -dependencies = [ - "displaydoc", -] +checksum = "84de9d95a6d2547d9b77ee3f25fa0ee32e3c3a6484d47a55adebc0439c077992" [[package]] name = "jiff-tzdb" @@ -843,7 +839,7 @@ dependencies = [ [[package]] name = "temporal_capi" -version = "0.1.0" +version = "0.1.2" dependencies = [ "diplomat", "diplomat-runtime", @@ -858,7 +854,7 @@ dependencies = [ [[package]] name = "temporal_rs" -version = "0.1.0" +version = "0.1.2" dependencies = [ "core_maths", "iana-time-zone", @@ -877,7 +873,7 @@ dependencies = [ [[package]] name = "timezone_provider" -version = "0.1.0" +version = "0.1.2" dependencies = [ "combine", "databake", @@ -957,7 +953,7 @@ dependencies = [ [[package]] name = "tzif-inspect" -version = "0.1.0" +version = "0.1.2" dependencies = [ "jiff-tzdb", "temporal_rs", @@ -1200,9 +1196,9 @@ dependencies = [ [[package]] name = "writeable" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" +checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" [[package]] name = "yoke" @@ -1251,14 +1247,14 @@ dependencies = [ [[package]] name = "zerotrie" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" dependencies = [ "databake", "displaydoc", "litemap", - "serde", + "serde_core", "zerovec", ] @@ -1277,9 +1273,9 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.11.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" +checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" dependencies = [ "proc-macro2", "quote", @@ -1288,7 +1284,7 @@ dependencies = [ [[package]] name = "zoneinfo-test-gen" -version = "0.1.0" +version = "0.1.2" dependencies = [ "clap", "serde", @@ -1311,7 +1307,7 @@ dependencies = [ [[package]] name = "zoneinfo_rs" -version = "0.0.17" +version = "0.0.18" dependencies = [ "hashbrown", "indexmap", diff --git a/deps/temporal/Cargo.toml b/deps/temporal/Cargo.toml index f12b83f4ded78c..f45d6a0cf5c18f 100644 --- a/deps/temporal/Cargo.toml +++ b/deps/temporal/Cargo.toml @@ -11,8 +11,8 @@ members = [ [workspace.package] edition = "2021" -version = "0.1.0" -rust-version = "1.82.0" +version = "0.1.2" +rust-version = "1.83.0" authors = ["boa-dev"] license = "MIT OR Apache-2.0" repository = "https://github.com/boa-dev/temporal" @@ -29,30 +29,35 @@ exclude = [ [workspace.dependencies] # Self -temporal_rs = { version = "~0.1.0", path = ".", default-features = false } -timezone_provider = { version = "~0.1.0", path = "./provider" } -zoneinfo_rs = { version = "~0.0.17", path = "./zoneinfo" } +temporal_rs = { version = "0.1.2", path = ".", default-features = false } +timezone_provider = { version = "0.1.2", path = "./provider" } +zoneinfo_rs = { version = "0.0.18", path = "./zoneinfo" } # Dependencies -tinystr = "0.8.1" -icu_calendar = { version = "2.0.3", default-features = false } -icu_locale = "2.0.0" rustc-hash = "2.1.0" num-traits = { version = "0.2.19", default-features = false } -ixdtf = "0.6.0" iana-time-zone = "0.1.64" log = "0.4.28" tzif = "0.4.0" jiff-tzdb = "0.1.4" combine = "4.6.7" web-time = "1.1.0" -zerovec = "0.11.4" + +# ICU4X +tinystr = "0.8.0" +icu_calendar = { version = "2.1.0", default-features = false, features = ["unstable"] } +icu_locale = "2.1.0" +zerovec = "0.11.0" +databake = "0.2.0" +zerotrie = "0.2.0" +writeable = "0.6.0" zoneinfo64 = "0.2.0" +ixdtf = "0.6.4" # Diplomat -diplomat-tool = { version = "0.13.0", default-features = false } -diplomat-runtime = { version = "0.13.0", default-features = false } -diplomat = { version = "0.13.0", default-features = false } +diplomat-tool = { version = "0.14.0", default-features = false } +diplomat-runtime = { version = "0.14.0", default-features = false } +diplomat = { version = "0.14.0", default-features = false } [package] @@ -77,7 +82,7 @@ icu_locale.workspace = true ixdtf = { workspace = true, features = ["duration"] } num-traits.workspace = true tinystr.workspace = true -writeable = "0.6.1" +writeable.workspace = true # log feature log = { workspace = true, optional = true } @@ -104,6 +109,10 @@ tzdb = [ "timezone_provider/tzif", ] std = [] +# https://github.com/boa-dev/temporal/issues/613 +# ECMA-conformant implementations must store durations as float64-representable numbers +# Rust users probably should not enable this, unless they wish to match the quirks of JavaScript +float64_representable_durations = [] [package.metadata.cargo-all-features] denylist = ["default"] diff --git a/deps/temporal/docs/architecture.md b/deps/temporal/docs/architecture.md index 17980052f92a9a..fea6c7601916ef 100644 --- a/deps/temporal/docs/architecture.md +++ b/deps/temporal/docs/architecture.md @@ -51,7 +51,7 @@ A `TimeZoneProvider` API on a core builtin will look like the below. ```rust impl ZonedDateTime { - pub fn day_with_provider(&self, provider: &impl TimeZoneProvider) -> TemporalResult { + pub fn day_with_provider(&self, provider: &(impl TimeZoneProvider + ?Sized)) -> TemporalResult { // Code goes here. } } diff --git a/deps/temporal/provider/Cargo.toml b/deps/temporal/provider/Cargo.toml index 9e40a10233a5f2..0bd9a6b6656363 100644 --- a/deps/temporal/provider/Cargo.toml +++ b/deps/temporal/provider/Cargo.toml @@ -52,7 +52,7 @@ zoneinfo64 = ["dep:zoneinfo64"] [dependencies] # Provider dependency -zerotrie = "0.2.2" +zerotrie.workspace = true zerovec = { workspace = true, features = ["derive", "alloc"] } tinystr = { workspace = true, features = ["zerovec"] } @@ -69,7 +69,7 @@ zoneinfo64 = { workspace = true, optional = true } # Databake dependencies serde = { version = "1.0.225", features = ["derive"], optional = true } -databake = { version = "0.2.0", features = ["derive"], optional = true } +databake = { workspace = true, optional = true, features = ["derive"]} yoke = { version = "0.8.0", features = ["derive"], optional = true } serde_json = { version = "1.0.145", optional = true } diff --git a/deps/temporal/provider/src/data/debug/iana_normalizer.json b/deps/temporal/provider/src/data/debug/iana_normalizer.json index b898f3339ada83..3bc9d9f65dcfa5 100644 --- a/deps/temporal/provider/src/data/debug/iana_normalizer.json +++ b/deps/temporal/provider/src/data/debug/iana_normalizer.json @@ -600,174 +600,22 @@ "zulu": 596 }, "non_canonical_identifiers": [ - [ - 1, - 0 - ], - [ - 2, - 43 - ], - [ - 4, - 43 - ], [ 5, 43 ], - [ - 6, - 0 - ], - [ - 7, - 31 - ], - [ - 8, - 0 - ], - [ - 10, - 38 - ], - [ - 11, - 31 - ], - [ - 12, - 38 - ], - [ - 16, - 0 - ], - [ - 17, - 0 - ], - [ - 18, - 43 - ], - [ - 19, - 43 - ], - [ - 20, - 31 - ], - [ - 22, - 0 - ], - [ - 23, - 38 - ], - [ - 24, - 38 - ], - [ - 27, - 43 - ], - [ - 29, - 38 - ], - [ - 30, - 31 - ], - [ - 32, - 31 - ], - [ - 33, - 0 - ], - [ - 34, - 31 - ], - [ - 35, - 38 - ], - [ - 36, - 38 - ], - [ - 37, - 31 - ], - [ - 39, - 25 - ], - [ - 40, - 25 - ], - [ - 41, - 43 - ], - [ - 45, - 31 - ], - [ - 46, - 0 - ], - [ - 47, - 0 - ], - [ - 48, - 31 - ], [ 50, 0 ], - [ - 56, - 187 - ], - [ - 57, - 187 - ], [ 61, 60 ], - [ - 72, - 187 - ], - [ - 74, - 179 - ], [ 75, 54 ], - [ - 81, - 187 - ], [ 85, 59 @@ -776,10 +624,6 @@ 90, 60 ], - [ - 92, - 179 - ], [ 96, 179 @@ -788,18 +632,6 @@ 97, 62 ], - [ - 100, - 182 - ], - [ - 102, - 187 - ], - [ - 108, - 187 - ], [ 112, 214 @@ -812,14 +644,6 @@ 117, 177 ], - [ - 120, - 187 - ], - [ - 121, - 187 - ], [ 136, 128 @@ -832,22 +656,10 @@ 144, 129 ], - [ - 145, - 187 - ], [ 149, 142 ], - [ - 150, - 187 - ], - [ - 154, - 187 - ], [ 158, 65 @@ -856,14 +668,6 @@ 167, 215 ], - [ - 168, - 187 - ], - [ - 169, - 215 - ], [ 171, 215 @@ -872,10 +676,6 @@ 180, 138 ], - [ - 184, - 187 - ], [ 185, 194 @@ -896,34 +696,10 @@ 202, 106 ], - [ - 204, - 187 - ], - [ - 206, - 187 - ], - [ - 207, - 187 - ], - [ - 208, - 187 - ], - [ - 209, - 187 - ], [ 213, 215 ], - [ - 216, - 187 - ], [ 218, 187 @@ -932,42 +708,14 @@ 222, 109 ], - [ - 225, - 562 - ], - [ - 228, - 530 - ], [ 231, 530 ], - [ - 232, - 307 - ], - [ - 235, - 433 - ], - [ - 236, - 307 - ], [ 243, 242 ], - [ - 246, - 303 - ], - [ - 252, - 287 - ], [ 253, 284 @@ -1004,26 +752,10 @@ 282, 281 ], - [ - 286, - 313 - ], - [ - 288, - 307 - ], [ 289, 290 ], - [ - 294, - 263 - ], - [ - 300, - 248 - ], [ 306, 332 @@ -1048,10 +780,6 @@ 326, 325 ], - [ - 329, - 248 - ], [ 339, 340 @@ -1060,14 +788,6 @@ 341, 433 ], - [ - 343, - 0 - ], - [ - 345, - 0 - ], [ 347, 365 @@ -1240,86 +960,18 @@ 426, 592 ], - [ - 427, - 435 - ], [ 431, 454 ], - [ - 434, - 466 - ], - [ - 438, - 490 - ], - [ - 440, - 433 - ], - [ - 443, - 454 - ], - [ - 445, - 454 - ], - [ - 447, - 454 - ], [ 449, 451 ], - [ - 453, - 432 - ], - [ - 455, - 435 - ], - [ - 458, - 444 - ], - [ - 460, - 464 - ], [ 462, 295 ], - [ - 463, - 433 - ], - [ - 465, - 432 - ], - [ - 470, - 468 - ], - [ - 471, - 432 - ], - [ - 474, - 432 - ], - [ - 476, - 433 - ], [ 479, 439 @@ -1328,18 +980,6 @@ 481, 451 ], - [ - 482, - 490 - ], - [ - 483, - 468 - ], - [ - 488, - 432 - ], [ 489, 451 @@ -1384,38 +1024,6 @@ 500, 0 ], - [ - 501, - 43 - ], - [ - 503, - 248 - ], - [ - 504, - 332 - ], - [ - 505, - 43 - ], - [ - 506, - 508 - ], - [ - 507, - 263 - ], - [ - 510, - 43 - ], - [ - 511, - 263 - ], [ 512, 318 @@ -1484,42 +1092,18 @@ 528, 148 ], - [ - 533, - 562 - ], [ 536, 546 ], - [ - 539, - 567 - ], [ 545, 544 ], - [ - 550, - 567 - ], - [ - 552, - 557 - ], - [ - 560, - 542 - ], [ 561, 542 ], - [ - 564, - 543 - ], [ 565, 557 @@ -1528,14 +1112,6 @@ 569, 562 ], - [ - 570, - 567 - ], - [ - 571, - 567 - ], [ 572, 562 diff --git a/deps/temporal/provider/src/data/iana_normalizer.rs.data b/deps/temporal/provider/src/data/iana_normalizer.rs.data index 40aa9cb95f588c..372c8f4be512e5 100644 --- a/deps/temporal/provider/src/data/iana_normalizer.rs.data +++ b/deps/temporal/provider/src/data/iana_normalizer.rs.data @@ -10,7 +10,7 @@ macro_rules! iana_normalizer_singleton { zerotrie::ZeroAsciiIgnoreCaseTrie { store : unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\xE1sabceghijklmnprstuwz\x0F\x0F\x0F\x13\x13\x13\x13\x13\x13\x13\x14\x14\x16\x16\x16\x16\x16\x16\x03*\xC2\x15>M\xD7\xE6\xF0\xF6*=\x17 *1\xC8\xD3\xE1gfmnrstu\x02\t\t\t\r\x0E\x1A(\xA9\xBC\x83\trica/\xE1rabcdefghjklmnopstw\0\0\0\0\0\0\0\0\0\x01\x01\x01\x01\x01\x01\x01\x01/i\x89\xB1\xBA\xC3\xCC\xD3\xE7\x0C@u\x9C\xA8\xB3\xBC\xD6\xC5bcdls\x06\n\x14\x1Aidjan\x80cra\x81dis_ababa\x82giers\x83m\xC2ae\x03ra\x84ra\x85\xC5ailru\x12\x17\x1E(\xC2mn\x04ako\x86\xC2gj\x03ui\x87ul\x88ssau\x89antyre\x8Aazzaville\x8Bjumbura\x8C\xC3aeo\x0F\x13\xC2is\x03ro\x8Dablanca\x8Euta\x8Fnakry\x90\0\xC3ajo\x14\x1C\xC2kr\x04ar\x90\x01_es_salaam\x90\x02ibouti\x90\x03uala\x90\x04l_aaiun\x90\x05reetown\x90\x06aborone\x90\x07arare\x90\x08\xC2ou\x0Channesburg\x90\tba\x90\n\xC3ahi\x07\x0Fmpala\x90\x0Bartoum\x90\x0C\xC2gn\x05ali\x90\rshasa\x90\x0E\xC4aiou\x05\x0F\x13gos\x90\x0Fbreville\x90\x10me\x90\x11\xC3abs\x05\x0Enda\x90\x12umbashi\x90\x13aka\x90\x14\xC3abo\x15\x1C\xC3lps\x05\nabo\x90\x15uto\x90\x16eru\x90\x17abane\x90\x18\xC2gn\x08adishu\x90\x19rovia\x90\x1A\xC4adio\x07\x0F\x15irobi\x90\x1Bjamena\x90\x1Camey\x90\x1Duakchott\x90\x1Euagadougou\x90\x1Forto-novo\x90 ao_tome\x90!\xC3iru\x08\x0Fmbuktu\x90\"ipoli\x90#nis\x90$indhoek\x90%erica/\xE1vabcdefghijklmnoprstvwy\0\x01\x01\x02\x02\x02\x02\x02\x03\x03\x03\x03\x04\x04\x04\x05\x05\x06\x06\x06\x06\xE7F\xF4-Xv\xD1\xEEg\x7F\xB7\xEC\x92\xEC\xF4g\xB0M\x87\x9A\xB0\xC5dnrst\x04\x1F\xC7\xCFak\x90&\xC3cgt\x08\x0Fhorage\x90'uilla\x90(igua\x90)\xC3agu\x08\x9Eguaina\x90*entina/\xC9bcjlmrstu\r17@HUmuuenos_aires\x90+\xC2ao\ttamarca\x90,\xC2mr\rodrivadavia\x90-doba\x90.ujuy\x90/a_rioja\x900endoza\x901io_gallegos\x902a\xC2ln\x04ta\x903_\xC2jl\x05uan\x904uis\x905ucuman\x906shuaia\x907ba\x908uncion\x909\xC2ik\x07kokan\x90:a\x90;\xC5aelou\x1A&2I\xC2hr\x0Fia\x90<_banderas\x90=bados\x90>l\xC2ei\x03m\x90?ze\x90@anc-sablon\x90A\xC3agi\x08\r_vista\x90Bota\x90Cse\x90Denos_aires\x90E\xC6ahioruCTa\x8C\x93\xC5mnrty\x19\x1E$,\xC2bp\x0Bridge_bay\x90Fo_grande\x90Gcun\x90Hacas\x90Iamarca\x90J\xC2em\x05nne\x90Kan\x90Li\xC2ch\x05ago\x90Muahua\x90Nudad_juarez\x90O\xC3rsy\x14\x1D\xC2ad\x0Bl_harbour\x90Poba\x90Qta_rica\x90Rhaique\x90Seston\x90T\xC2ir\x05aba\x90Uacao\x90V\xC3aeo\x1C+\xC2nw\x0Bmarkshavn\x90Wson\x90X_creek\x90Y\xC2nt\x05ver\x90Zroit\x90[minica\x90\\\xC4diln\x08\x10\x1Bmonton\x90]runepe\x90^_salvador\x90_senada\x90`ort\xC2_a\x11\xC2nw\x07elson\x90aayne\x90bleza\x90c\xC4loru\t\x1B.ace_bay\x90d\xC2do\x06thab\x90ese_bay\x90f\xC2ae\tnd_turk\x90gnada\x90h\xC2ay\x1C\xC3dty\x08\x0Feloupe\x90iemala\x90jaquil\x90kana\x90l\xC2ae\x0F\xC2lv\x06ifax\x90mana\x90nrmosillo\x90o\xC2nqn\xC2dueiana\xC2/pW\xC7ikmptvw\r\x12\x1A%/Andianapolis\x90pnox\x90qarengo\x90retersburg\x90sell_city\x90t\xC2ei\x05vay\x90uncennes\x90vinamac\x90wolis\x90xvik\x90yaluit\x90z\xC2au\x07maica\x90{\xC2jn\x04uy\x90|eau\x90}\xC3enr!(ntucky/\xC2lm\x0Bouisville\x90~onticello\x90\x7Fox_in\x91\0alendijk\x91\x01\xC3aio\x06\n_paz\x91\x02ma\x91\x03\xC3suw\n\x13_angeles\x91\x04isville\x91\x05er_princes\x91\x06\xC4aeio;ks\xC5cnrtz\x05\x11\"*eio\x91\x07a\xC2gu\x04ua\x91\x08s\x91\t\xC2it\x05got\x91\ninique\x91\x0Bamoros\x91\x0Catlan\x91\r\xC4nrtx\x10\x15\x1E\xC2do\x05oza\x91\x0Eminee\x91\x0Fida\x91\x10lakatla\x91\x11ico_city\x91\x12quelon\x91\x13n\xC2ct\x05ton\x91\x14\xC3ers\x0F\x14\xC2rv\x05rey\x91\x15ideo\x91\x16eal\x91\x17errat\x91\x18\xC5aeiou\x06\x0E\x15Lssau\x91\x19w_york\x91\x1Apigon\x91\x1B\xC2mr\x03e\x91\x1C\xC2ot\x05nha\x91\x1Dh_dakota/\xC3bcn\x07\x0Eeulah\x91\x1Eenter\x91\x1Few_salem\x91 uk\x91!jinaga\x91\"\xC4ahou\x1E%R\xC2nr\x11\xC2ag\x04ma\x91#nirtung\x91$amaribo\x91%oenix\x91&rt\xC3-_o\x0B\x15au-prince\x91'of_spain\x91(_\xC2av\x05cre\x91)elho\x91*\xC2en\nrto_rico\x91+ta_arenas\x91,\xC4aeio\x190:\xC2in\nny_river\x91-kin_inlet\x91.\xC3cgs\x05\nife\x91/ina\x910olute\x911o_branco\x912sario\x913\xC6achitw2>FK\x84\xC2no&t\xC3aio\x10\x15\xC2_r\x08isabel\x914em\x915ago\x916_domingo\x917_paulo\x918oresbysund\x919iprock\x91:tka\x91;_\xC6bjkltv\x0B\x11\x17\x1D$arthelemy\x91ucia\x91?homas\x91@incent\x91Aift_current\x91B\xC4ehio\x0B\x1C#gucigalpa\x91Cu\xC2ln\x03e\x91Dder_bay\x91Ejuana\x91Fr\xC2ot\x05nto\x91Gola\x91H\xC2ai\tncouver\x91Irgin\x91J\xC2hi\nitehorse\x91Knnipeg\x91L\xC2ae\x07kutat\x91Mllowknife\x91Ntarctica/\xC8cdmprstv\x06\x1D9@H[aasey\x91O\xC2au\x05vis\x91Pmontdurville\x91Q\xC2ac\x11\xC2cw\x08quarie\x91Rson\x91Smurdo\x91Talmer\x91Uothera\x91V\xC2oy\nuth_pole\x91Wowa\x91Xroll\x91Yostok\x91Zctic/longyearbyen\x91[ia/\xE1uabcdfghijkmnopqrstuvy\0\0\0\0\0\0\x01\x01\x01\x01\x01\x02\x02\x02\x02\x02\x02\x03\x03\x03G\x87\xC1\xF0\xFA\xFF,?]\xD0\xFD\x1F+Miz\xC1\x0BD\\\xC7dlmnqst\x04\n\x0F\x15!3en\x91\\maty\x91]man\x91^adyr\x91_t\xC2ao\x03u\x91`be\x91ah\xC2gk\x06abat\x91bhabad\x91cyrau\x91d\xC4aeir%+2\xC5ghknr\x06\x0C\x0F\x15hdad\x91erain\x91fu\x91ggkok\x91hnaul\x91iirut\x91jshkek\x91kunei\x91l\xC3aho\x08-lcutta\x91m\xC3iou\x04\x17ta\x91n\xC2in\x08balsan\x91ogqing\x91pngking\x91qlombo\x91r\xC4ahiu\x0F\x14\x18\xC2cm\x04ca\x91sascus\x91taka\x91uli\x91v\xC2bs\x04ai\x91whanbe\x91xamagusta\x91yaza\x91z\xC3aeo\x06\x0Crbin\x91{bron\x91|\xC3_nv\n\x12chi_minh\x91}g_kong\x91~d\x91\x7F\xC2rs\x07kutsk\x92\0tanbul\x92\x01\xC2ae\x11\xC2ky\x06arta\x92\x02apura\x92\x03rusalem\x92\x04\xC5ahoru3;BM\xC5bmrst\x04\x0C\x12\x18ul\x92\x05chatka\x92\x06achi\x92\x07hgar\x92\x08\xC2hm\x07mandu\x92\tandu\x92\nandyga\x92\x0Blkata\x92\x0Casnoyarsk\x92\r\xC3acw\x0B\x11la_lumpur\x92\x0Ehing\x92\x0Fait\x92\x10\xC2au#\xC4cgkn\t\x0F\x16a\xC2ou\x02\x92\x11\x92\x12adan\x92\x13assar\x92\x14ila\x92\x15scat\x92\x16\xC2io\x07cosia\x92\x17vo\xC2ks\tuznetsk\x92\x18ibirsk\x92\x19\xC2mr\x04sk\x92\x1Aal\x92\x1B\xC3hoy\n\x13nom_penh\x92\x1Cntianak\x92\x1Dongyang\x92\x1E\xC3aoy\x05\rtar\x92\x1Fstanay\x92 zylorda\x92!\xC2ai\x07ngoon\x92\"yadh\x92#\xC5aehir\x1A\x1F'0\xC3ikm\x05\x0Cgon\x92$halin\x92%arkand\x92&oul\x92'anghai\x92(ngapore\x92)ednekolymsk\x92*\xC5abeho\x10\x17'4\xC2is\x05pei\x92+hkent\x92,ilisi\x92-\xC2hl\x05ran\x92._aviv\x92/im\xC2bp\x03u\x920hu\x921\xC2km\x04yo\x922sk\x923\xC4jlrs\r#)ung_pandang\x924a\xC2an\tnbaatar\x925_bator\x926umqi\x927t-nera\x928\xC2il\tentiane\x929adivostok\x92:\xC2ae\x0F\xC2kn\x06utsk\x92;gon\x92<\xC2kr\x0Caterinburg\x92=evan\x92>lantic/\xC8abcfjmrs\x07\x0F\"0:BLzores\x92?ermuda\x92@a\xC2np\x05ary\x92Ae_verde\x92Ba\xC2er\x05roe\x92Coe\x92Dan_mayen\x92Eadeira\x92Feykjavik\x92G\xC2ot\ruth_georgia\x92H\xC2_a\x08helena\x92Inley\x92Jstralia/\xD0abcdehlmnpqstvwy\x0F%7>DKeo{\x81\x8C\x9B\xA4\xAD\xB2\xC2cd\x03t\x92Kelaide\x92Lr\xC2io\x07sbane\x92Mken_hill\x92N\xC2au\x08nberra\x92Orrie\x92Parwin\x92Qucla\x92Robart\x92S\xC3hio\x03\x0Bi\x92Tndeman\x92Urd_howe\x92Velbourne\x92W\xC2os\x05rth\x92Yw\x92Xerth\x92Zueensland\x92[\xC2oy\x05uth\x92\\dney\x92]asmania\x92^ictoria\x92_est\x92`ancowinna\x92arazil/\xC4adew\x05\x0F\x14cre\x92benoronha\x92cast\x92dest\x92e\xC5aehsu_b\x83\x8Anada/\xC8acemnpsy\t\x11\x19\"/7Dtlantic\x92hentral\x92iastern\x92jountain\x92kewfoundland\x92lacific\x92maskatchewan\x92nukon\x92ot\x92file/\xC2ce\x0Continental\x92pasterisland\x92qt6cdt\x92gba\x92r\xE1fegistu\0\0\0\0\0\x03\x08\x0C\x15\xBFt\x92sypt\x92vre\x92wt\x92t5edt\x92uc/\xC3guz\x88\x9D\xC2mr{t\x92x\xC3+-04p\xCA0123456789\x02\x10\x12\x14\x16\x18\x1A\x1C\x1E\x92y\x92z\xC3012\x02\x04\x92{\x92|\x92}\x92~\x92\x7F\x93\0\x93\x01\x93\x02\x93\x03\x93\x04\x93\x05\xCA0123456789\x02\x18\x1A\x1C\x1E \"$&\x93\x06\x93\x07\xC501234\x02\x04\x06\x08\x93\x08\x93\t\x93\n\x93\x0B\x93\x0C\x93\r\x93\x0E\x93\x0F\x93\x10\x93\x11\x93\x12\x93\x13\x93\x14\x93\x15eenwich\x93\x16\xC3cnt\x03\x0Ct\x93\x17iversal\x93\x19c\x93\x18ulu\x93\x1Arope/\xE1uabcdghijklmnoprstuvwz\0\0\0\0\0\0\0\0\0\x01\x01\x01\x01\x01\x01\x01\x01\x01\x02\x02'u\x8B\x92\xA7\xB0\xC6\xCD\xED\x14DLQkw\xC1\xDA\xEF\x1B\"\xC4mnst\t\x10\x19sterdam\x93\x1Bdorra\x93\x1Ctrakhan\x93\x1Dhens\x93\x1E\xC3eru\x18,\xC2lr\x0F\xC2fg\x05ast\x93\x1Frade\x93 lin\x93!\xC2au\ttislava\x93\"ssels\x93#\xC3cds\x08\x0Fharest\x93$apest\x93%ingen\x93&\xC2ho\x08isinau\x93'penhagen\x93(ublin\x93)\xC2iu\tbraltar\x93*ernsey\x93+elsinki\x93,s\xC2lt\ne_of_man\x93-anbul\x93.ersey\x93/\xC3aiy\x0B\x16liningrad\x930\xC2er\x03v\x931ov\x932iv\x933\xC4ijou\x06\x0F\x15sbon\x934ubljana\x935ndon\x936xembourg\x937\xC3aio\x17\x1C\xC3dlr\x05\trid\x938ta\x939iehamn\x93:nsk\x93;\xC2ns\x05aco\x93slo\x93?\xC3aor\x05\x0Eris\x93@dgorica\x93Aague\x93B\xC2io\x04ga\x93Cme\x93D\xC5aikot\",27\xC3mnr\x05\x0Eara\x93E_marino\x93Fa\xC2jt\x05evo\x93Gov\x93Hmferopol\x93Iopje\x93Jfia\x93Kockholm\x93L\xC2ai\x07llinn\x93Mra\xC2ns\x03e\x93Npol\x93O\xC2lz\tyanovsk\x93Phgorod\x93Q\xC3aio\x0E\x1D\xC2dt\x04uz\x93Rican\x93S\xC2el\x05nna\x93Tnius\x93Ulgograd\x93Varsaw\x93W\xC2au\x12\xC2gp\x05reb\x93Xorozhye\x93Yrich\x93Z\xC3bmr\t\x1A\x93[-eire\x93\\t\x93]\xC3+-0\x03\x060\x93^0\x93_\x93`eenwich\x93a\xC2os\x08ngkong\x93ct\x93b\xC4cnrs\x07x|eland\x93ddian/\xC5ackmr\r/9Zntananarivo\x93e\xC2ho\x11\xC2ar\x05gos\x93fistmas\x93g\xC2cm\x04os\x93horo\x93ierguelen\x93ja\xC4hluy\x03\n\x12e\x93kdives\x93lritius\x93motte\x93neunion\x93oan\x93prael\x93qa\xC2mp\x06aica\x93ran\x93swajalein\x93tibya\x93u\xC2es'\xC2tx\x02\x93vico/\xC2bg\x11aja\xC2ns\x06orte\x93yur\x93zeneral\x93{t\x93w7mdt\x93x\xC2az\x06vajo\x93~\x93|-chat\x93}\xE1daors\x01\x01\x01\xB4\xC4\xC7cific/\xE1qabcefghjkmnprstwy\0\0\0\0\0\0\0\0\0\0\0\x01\x01\x01\x01\x01\x10\x1D,F_\x85\x8E\x97\xBE\xD9\xF71;Ijw\xC2pu\x04ia\x94\x01ckland\x94\x02ougainville\x94\x03h\xC2au\x06tham\x94\x04uk\x94\x05\xC3afn\x06\x0Bster\x94\x06ate\x94\x07derbury\x94\x08\xC3aiu\x07\x0Bkaofo\x94\tji\x94\nnafuti\x94\x0B\xC2au\x12\xC2lm\x08apagos\x94\x0Cbier\x94\ra\xC2dm\talcanal\x94\x0E\x94\x0Fonolulu\x94\x10ohnston\x94\x11\xC4aiow\x06\x10\x16nton\x94\x12ritimati\x94\x13srae\x94\x14ajalein\x94\x15\xC2ai\x11\xC2jr\x05uro\x94\x16quesas\x94\x17dway\x94\x18\xC3aio\x05\turu\x94\x19ue\x94\x1A\xC2ru\x06folk\x94\x1Bmea\x94\x1C\xC3aio\x10\x18\xC2gl\x08o_pago\x94\x1Dau\x94\x1Etcairn\x94\x1F\xC3hnr\x06\x0Bnpei\x94 ape\x94!t_moresby\x94\"arotonga\x94#a\xC2im\x05pan\x94$oa\x94%\xC3aor\x0E\x17\xC2hr\x05iti\x94&awa\x94'ngatapu\x94(uk\x94)a\xC2kl\x03e\x94*lis\x94+ap\x94,\xC2lr\x05and\x94-tugal\x94.c\x93\x7Ft8pdt\x94\0o\xC2ck\x02\x94/\x940ingapore\x941urkey\x942\xC4cnst\x03\x0C\x8Ct\x943iversal\x94A/\xC8acehimps\x1B#7>Mai\xC2lr\x10\xC2ae\x05ska\x944utian\x945izona\x946entral\x947ast\xC2-e\tindiana\x948rn\x949awaii\x94:ndiana-starke\x94;\xC2io\x08chigan\x94amoa\x94?c\x94@\xC2-e\x04su\x94Bt\x94Culu\x94D") }, }, non_canonical_identifiers : unsafe { - zerovec::ZeroVec::from_bytes_unchecked(b"\x01\0\0\0\0\0\0\0\x02\0\0\0+\0\0\0\x04\0\0\0+\0\0\0\x05\0\0\0+\0\0\0\x06\0\0\0\0\0\0\0\x07\0\0\0\x1F\0\0\0\x08\0\0\0\0\0\0\0\n\0\0\0&\0\0\0\x0B\0\0\0\x1F\0\0\0\x0C\0\0\0&\0\0\0\x10\0\0\0\0\0\0\0\x11\0\0\0\0\0\0\0\x12\0\0\0+\0\0\0\x13\0\0\0+\0\0\0\x14\0\0\0\x1F\0\0\0\x16\0\0\0\0\0\0\0\x17\0\0\0&\0\0\0\x18\0\0\0&\0\0\0\x1B\0\0\0+\0\0\0\x1D\0\0\0&\0\0\0\x1E\0\0\0\x1F\0\0\0 \0\0\0\x1F\0\0\0!\0\0\0\0\0\0\0\"\0\0\0\x1F\0\0\0#\0\0\0&\0\0\0$\0\0\0&\0\0\0%\0\0\0\x1F\0\0\0'\0\0\0\x19\0\0\0(\0\0\0\x19\0\0\0)\0\0\0+\0\0\0-\0\0\0\x1F\0\0\0.\0\0\0\0\0\0\0/\0\0\0\0\0\0\x000\0\0\0\x1F\0\0\x002\0\0\0\0\0\0\08\0\0\0\xBB\0\0\09\0\0\0\xBB\0\0\0=\0\0\0<\0\0\0H\0\0\0\xBB\0\0\0J\0\0\0\xB3\0\0\0K\0\0\x006\0\0\0Q\0\0\0\xBB\0\0\0U\0\0\0;\0\0\0Z\0\0\0<\0\0\0\\\0\0\0\xB3\0\0\0`\0\0\0\xB3\0\0\0a\0\0\0>\0\0\0d\0\0\0\xB6\0\0\0f\0\0\0\xBB\0\0\0l\0\0\0\xBB\0\0\0p\0\0\0\xD6\0\0\0r\0\0\0\x80\0\0\0u\0\0\0\xB1\0\0\0x\0\0\0\xBB\0\0\0y\0\0\0\xBB\0\0\0\x88\0\0\0\x80\0\0\0\x8C\0\0\0?\0\0\0\x90\0\0\0\x81\0\0\0\x91\0\0\0\xBB\0\0\0\x95\0\0\0\x8E\0\0\0\x96\0\0\0\xBB\0\0\0\x9A\0\0\0\xBB\0\0\0\x9E\0\0\0A\0\0\0\xA7\0\0\0\xD7\0\0\0\xA8\0\0\0\xBB\0\0\0\xA9\0\0\0\xD7\0\0\0\xAB\0\0\0\xD7\0\0\0\xB4\0\0\0\x8A\0\0\0\xB8\0\0\0\xBB\0\0\0\xB9\0\0\0\xC2\0\0\0\xBD\0\0\0\xDC\0\0\0\xC3\0\0\0>\0\0\0\xC4\0\0\0\xD6\0\0\0\xCA\0\0\0j\0\0\0\xCC\0\0\0\xBB\0\0\0\xCE\0\0\0\xBB\0\0\0\xCF\0\0\0\xBB\0\0\0\xD0\0\0\0\xBB\0\0\0\xD1\0\0\0\xBB\0\0\0\xD5\0\0\0\xD7\0\0\0\xD8\0\0\0\xBB\0\0\0\xDA\0\0\0\xBB\0\0\0\xDE\0\0\0m\0\0\0\xE1\0\0\x002\x02\0\0\xE4\0\0\0\x12\x02\0\0\xE7\0\0\0\x12\x02\0\0\xE8\0\0\x003\x01\0\0\xEB\0\0\0\xB1\x01\0\0\xEC\0\0\x003\x01\0\0\xF3\0\0\0\xF2\0\0\0\xF6\0\0\0/\x01\0\0\xFC\0\0\0\x1F\x01\0\0\xFD\0\0\0\x1C\x01\0\0\xFF\0\0\0E\x01\0\0\0\x01\0\08\x01\0\0\x01\x01\0\08\x01\0\0\x03\x01\0\0\x05\x01\0\0\x0B\x01\0\08\x01\0\0\x11\x01\0\0\xBE\x01\0\0\x18\x01\0\0G\x01\0\0\x1A\x01\0\0\x19\x01\0\0\x1E\x01\0\09\x01\0\0 \x01\0\x003\x01\0\0!\x01\0\0\"\x01\0\0&\x01\0\0\x07\x01\0\0,\x01\0\0\xF8\0\0\x002\x01\0\0L\x01\0\x004\x01\0\0\r\x01\0\0?\x01\0\0\x14\x01\0\0@\x01\0\0A\x01\0\0D\x01\0\0$\x01\0\0F\x01\0\0E\x01\0\0I\x01\0\0\xF8\0\0\0S\x01\0\0T\x01\0\0U\x01\0\0\xB1\x01\0\0W\x01\0\0\0\0\0\0Y\x01\0\0\0\0\0\0[\x01\0\0m\x01\0\0_\x01\0\0m\x01\0\0`\x01\0\0c\x01\0\0d\x01\0\0f\x01\0\0h\x01\0\0m\x01\0\0i\x01\0\0a\x01\0\0k\x01\0\0]\x01\0\0l\x01\0\0\\\x01\0\0n\x01\0\0c\x01\0\0o\x01\0\0g\x01\0\0p\x01\0\0j\x01\0\0q\x01\0\0^\x01\0\0r\x01\0\0\xC2\0\0\0s\x01\0\0\xAD\0\0\0t\x01\0\0\xC8\0\0\0u\x01\0\0\x99\0\0\0v\x01\0\0\xB3\x01\0\0w\x01\0\0]\0\0\0x\x01\0\0}\0\0\0y\x01\0\0\xDC\0\0\0z\x01\0\0\xD7\0\0\0{\x01\0\0m\0\0\0|\x01\0\0\xCD\0\0\0}\x01\0\0\xD9\0\0\0~\x01\0\0\xC0\0\0\0\x7F\x01\0\0\xDB\0\0\0\x80\x01\0\0\xC6\0\0\0\x81\x01\0\0\x16\x02\0\0\x82\x01\0\0~\0\0\0\x83\x01\0\0\xAE\x01\0\0\x84\x01\0\0\xB3\0\0\0\x85\x01\0\0\xAA\0\0\0\x86\x01\0\0\r\0\0\0\x87\x01\0\0\xB9\x01\0\0\x88\x01\0\0P\x02\0\0\x89\x01\0\0P\x02\0\0\x96\x01\0\0P\x02\0\0\xA5\x01\0\0P\x02\0\0\xA6\x01\0\0P\x02\0\0\xA7\x01\0\0P\x02\0\0\xA8\x01\0\0P\x02\0\0\xA9\x01\0\0P\x02\0\0\xAA\x01\0\0P\x02\0\0\xAB\x01\0\0\xB3\x01\0\0\xAF\x01\0\0\xC6\x01\0\0\xB2\x01\0\0\xD2\x01\0\0\xB6\x01\0\0\xEA\x01\0\0\xB8\x01\0\0\xB1\x01\0\0\xBB\x01\0\0\xC6\x01\0\0\xBD\x01\0\0\xC6\x01\0\0\xBF\x01\0\0\xC6\x01\0\0\xC1\x01\0\0\xC3\x01\0\0\xC5\x01\0\0\xB0\x01\0\0\xC7\x01\0\0\xB3\x01\0\0\xCA\x01\0\0\xBC\x01\0\0\xCC\x01\0\0\xD0\x01\0\0\xCE\x01\0\0'\x01\0\0\xCF\x01\0\0\xB1\x01\0\0\xD1\x01\0\0\xB0\x01\0\0\xD6\x01\0\0\xD4\x01\0\0\xD7\x01\0\0\xB0\x01\0\0\xDA\x01\0\0\xB0\x01\0\0\xDC\x01\0\0\xB1\x01\0\0\xDF\x01\0\0\xB7\x01\0\0\xE1\x01\0\0\xC3\x01\0\0\xE2\x01\0\0\xEA\x01\0\0\xE3\x01\0\0\xD4\x01\0\0\xE8\x01\0\0\xB0\x01\0\0\xE9\x01\0\0\xC3\x01\0\0\xEB\x01\0\0\xC6\x01\0\0\xEC\x01\0\0\xC6\x01\0\0\xED\x01\0\0P\x02\0\0\xEE\x01\0\0P\x02\0\0\xEF\x01\0\0P\x02\0\0\xF0\x01\0\0P\x02\0\0\xF1\x01\0\0P\x02\0\0\xF2\x01\0\0 \x02\0\0\xF3\x01\0\0\x0E\x01\0\0\xF4\x01\0\0\0\0\0\0\xF5\x01\0\0+\0\0\0\xF7\x01\0\0\xF8\0\0\0\xF8\x01\0\0L\x01\0\0\xF9\x01\0\0+\0\0\0\xFA\x01\0\0\xFC\x01\0\0\xFB\x01\0\0\x07\x01\0\0\xFE\x01\0\0+\0\0\0\xFF\x01\0\0\x07\x01\0\0\0\x02\0\0>\x01\0\0\x01\x02\0\0\x14\x01\0\0\x02\x02\0\0\x8B\0\0\0\x03\x02\0\0B\x01\0\0\x04\x02\0\0%\x02\0\0\x05\x02\0\x003\0\0\0\x06\x02\0\0\xB3\x01\0\0\x07\x02\0\0\xB6\0\0\0\x08\x02\0\0j\0\0\0\t\x02\0\0\xD6\0\0\0\n\x02\0\0\x9D\0\0\0\x0B\x02\0\0\xA2\0\0\0\x0C\x02\0\0\x12\x02\0\0\r\x02\0\0\x14\x02\0\0\x0E\x02\0\0j\0\0\0\x0F\x02\0\08\x01\0\0\x10\x02\0\0\x94\0\0\0\x15\x02\0\x002\x02\0\0\x18\x02\0\0\"\x02\0\0\x1B\x02\0\x007\x02\0\0!\x02\0\0 \x02\0\0&\x02\0\x007\x02\0\0(\x02\0\0-\x02\0\x000\x02\0\0\x1E\x02\0\x001\x02\0\0\x1E\x02\0\x004\x02\0\0\x1F\x02\0\x005\x02\0\0-\x02\0\09\x02\0\x002\x02\0\0:\x02\0\x007\x02\0\0;\x02\0\x007\x02\0\0<\x02\0\x002\x02\0\0=\x02\0\0\xE7\x01\0\0>\x02\0\0\xC4\x01\0\0?\x02\0\0;\x01\0\0@\x02\0\x007\x01\0\0A\x02\0\09\x01\0\0B\x02\0\0\xBE\x01\0\0C\x02\0\0P\x02\0\0D\x02\0\x007\0\0\0E\x02\0\x006\0\0\0F\x02\0\0\xB6\0\0\0G\x02\0\0]\0\0\0H\x02\0\0\x80\0\0\0I\x02\0\0\xAA\0\0\0J\x02\0\0 \x02\0\0K\x02\0\0\x81\0\0\0L\x02\0\0k\0\0\0M\x02\0\0j\0\0\0N\x02\0\0\x94\0\0\0O\x02\0\0-\x02\0\0Q\x02\0\0P\x02\0\0R\x02\0\0\xCD\x01\0\0S\x02\0\0\xC4\x01\0\0T\x02\0\0P\x02\0\0") + zerovec::ZeroVec::from_bytes_unchecked(b"\x05\0\0\0+\0\0\x002\0\0\0\0\0\0\0=\0\0\0<\0\0\0K\0\0\x006\0\0\0U\0\0\0;\0\0\0Z\0\0\0<\0\0\0`\0\0\0\xB3\0\0\0a\0\0\0>\0\0\0p\0\0\0\xD6\0\0\0r\0\0\0\x80\0\0\0u\0\0\0\xB1\0\0\0\x88\0\0\0\x80\0\0\0\x8C\0\0\0?\0\0\0\x90\0\0\0\x81\0\0\0\x95\0\0\0\x8E\0\0\0\x9E\0\0\0A\0\0\0\xA7\0\0\0\xD7\0\0\0\xAB\0\0\0\xD7\0\0\0\xB4\0\0\0\x8A\0\0\0\xB9\0\0\0\xC2\0\0\0\xBD\0\0\0\xDC\0\0\0\xC3\0\0\0>\0\0\0\xC4\0\0\0\xD6\0\0\0\xCA\0\0\0j\0\0\0\xD5\0\0\0\xD7\0\0\0\xDA\0\0\0\xBB\0\0\0\xDE\0\0\0m\0\0\0\xE7\0\0\0\x12\x02\0\0\xF3\0\0\0\xF2\0\0\0\xFD\0\0\0\x1C\x01\0\0\xFF\0\0\0E\x01\0\0\0\x01\0\08\x01\0\0\x01\x01\0\08\x01\0\0\x03\x01\0\0\x05\x01\0\0\x0B\x01\0\08\x01\0\0\x11\x01\0\0\xBE\x01\0\0\x18\x01\0\0G\x01\0\0\x1A\x01\0\0\x19\x01\0\0!\x01\0\0\"\x01\0\x002\x01\0\0L\x01\0\x004\x01\0\0\r\x01\0\0?\x01\0\0\x14\x01\0\0@\x01\0\0A\x01\0\0D\x01\0\0$\x01\0\0F\x01\0\0E\x01\0\0S\x01\0\0T\x01\0\0U\x01\0\0\xB1\x01\0\0[\x01\0\0m\x01\0\0_\x01\0\0m\x01\0\0`\x01\0\0c\x01\0\0d\x01\0\0f\x01\0\0h\x01\0\0m\x01\0\0i\x01\0\0a\x01\0\0k\x01\0\0]\x01\0\0l\x01\0\0\\\x01\0\0n\x01\0\0c\x01\0\0o\x01\0\0g\x01\0\0p\x01\0\0j\x01\0\0q\x01\0\0^\x01\0\0r\x01\0\0\xC2\0\0\0s\x01\0\0\xAD\0\0\0t\x01\0\0\xC8\0\0\0u\x01\0\0\x99\0\0\0v\x01\0\0\xB3\x01\0\0w\x01\0\0]\0\0\0x\x01\0\0}\0\0\0y\x01\0\0\xDC\0\0\0z\x01\0\0\xD7\0\0\0{\x01\0\0m\0\0\0|\x01\0\0\xCD\0\0\0}\x01\0\0\xD9\0\0\0~\x01\0\0\xC0\0\0\0\x7F\x01\0\0\xDB\0\0\0\x80\x01\0\0\xC6\0\0\0\x81\x01\0\0\x16\x02\0\0\x82\x01\0\0~\0\0\0\x83\x01\0\0\xAE\x01\0\0\x84\x01\0\0\xB3\0\0\0\x85\x01\0\0\xAA\0\0\0\x86\x01\0\0\r\0\0\0\x87\x01\0\0\xB9\x01\0\0\x88\x01\0\0P\x02\0\0\x89\x01\0\0P\x02\0\0\x96\x01\0\0P\x02\0\0\xA5\x01\0\0P\x02\0\0\xA6\x01\0\0P\x02\0\0\xA7\x01\0\0P\x02\0\0\xA8\x01\0\0P\x02\0\0\xA9\x01\0\0P\x02\0\0\xAA\x01\0\0P\x02\0\0\xAF\x01\0\0\xC6\x01\0\0\xC1\x01\0\0\xC3\x01\0\0\xCE\x01\0\0'\x01\0\0\xDF\x01\0\0\xB7\x01\0\0\xE1\x01\0\0\xC3\x01\0\0\xE9\x01\0\0\xC3\x01\0\0\xEB\x01\0\0\xC6\x01\0\0\xEC\x01\0\0\xC6\x01\0\0\xED\x01\0\0P\x02\0\0\xEE\x01\0\0P\x02\0\0\xEF\x01\0\0P\x02\0\0\xF0\x01\0\0P\x02\0\0\xF1\x01\0\0P\x02\0\0\xF2\x01\0\0 \x02\0\0\xF3\x01\0\0\x0E\x01\0\0\xF4\x01\0\0\0\0\0\0\0\x02\0\0>\x01\0\0\x01\x02\0\0\x14\x01\0\0\x02\x02\0\0\x8B\0\0\0\x03\x02\0\0B\x01\0\0\x04\x02\0\0%\x02\0\0\x05\x02\0\x003\0\0\0\x06\x02\0\0\xB3\x01\0\0\x07\x02\0\0\xB6\0\0\0\x08\x02\0\0j\0\0\0\t\x02\0\0\xD6\0\0\0\n\x02\0\0\x9D\0\0\0\x0B\x02\0\0\xA2\0\0\0\x0C\x02\0\0\x12\x02\0\0\r\x02\0\0\x14\x02\0\0\x0E\x02\0\0j\0\0\0\x0F\x02\0\08\x01\0\0\x10\x02\0\0\x94\0\0\0\x18\x02\0\0\"\x02\0\0!\x02\0\0 \x02\0\x001\x02\0\0\x1E\x02\0\x005\x02\0\0-\x02\0\09\x02\0\x002\x02\0\0<\x02\0\x002\x02\0\0=\x02\0\0\xE7\x01\0\0>\x02\0\0\xC4\x01\0\0?\x02\0\0;\x01\0\0@\x02\0\x007\x01\0\0A\x02\0\09\x01\0\0B\x02\0\0\xBE\x01\0\0C\x02\0\0P\x02\0\0D\x02\0\x007\0\0\0E\x02\0\x006\0\0\0F\x02\0\0\xB6\0\0\0G\x02\0\0]\0\0\0H\x02\0\0\x80\0\0\0I\x02\0\0\xAA\0\0\0J\x02\0\0 \x02\0\0K\x02\0\0\x81\0\0\0L\x02\0\0k\0\0\0M\x02\0\0j\0\0\0N\x02\0\0\x94\0\0\0O\x02\0\0-\x02\0\0Q\x02\0\0P\x02\0\0R\x02\0\0\xCD\x01\0\0S\x02\0\0\xC4\x01\0\0T\x02\0\0P\x02\0\0") }, normalized_identifiers : unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"U\x02\x0E\0\x1A\0,\0:\0G\0T\0a\0n\0{\0\x88\0\x97\0\xA9\0\xB9\0\xC5\0\xD6\0\xE2\0\xF0\0\xFC\0\x10\x01\x1F\x01,\x01;\x01J\x01Y\x01f\x01y\x01\x84\x01\x92\x01\xA1\x01\xAE\x01\xBD\x01\xC9\x01\xDA\x01\xE5\x01\xF2\x01\x03\x02\x10\x02\x1D\x02*\x027\x02E\x02U\x02d\x02r\x02\x81\x02\x8E\x02\x9F\x02\xB1\x02\xC2\x02\xD1\x02\xE0\x02\xEE\x02\xFA\x02\t\x03\x15\x03&\x036\x03E\x03V\x03t\x03\x8F\x03\xAF\x03\xC8\x03\xDF\x03\xF9\x03\x12\x040\x04G\x04a\x04{\x04\x94\x04\xAD\x04\xBA\x04\xCA\x04\xDA\x04\xE6\x04\xF3\x04\t\x05\x19\x05&\x054\x05H\x05Y\x05g\x05t\x05\x88\x05\x9D\x05\xB1\x05\xBF\x05\xCE\x05\xDF\x05\xEE\x05\xFC\x05\x0B\x06\x1C\x061\x06F\x06U\x06g\x06x\x06\x87\x06\x95\x06\xA4\x06\xB8\x06\xC6\x06\xDA\x06\xE8\x06\xF7\x06\x07\x07\x17\x07'\x07:\x07J\x07]\x07o\x07\x80\x07\x91\x07\xA0\x07\xB1\x07\xC3\x07\xD2\x07\xE4\x07\xF5\x07\x06\x08\x14\x08#\x081\x08C\x08_\x08s\x08\x8A\x08\xA4\x08\xBD\x08\xD2\x08\xEB\x08\x02\t\x16\t$\t3\tB\tO\t]\tx\t\x93\t\xA2\t\xB4\t\xC2\t\xCE\t\xE1\t\xF3\t\x08\n\x16\n%\n3\nB\nT\ne\nu\n\x84\n\x95\n\xA3\n\xB5\n\xC8\n\xD8\n\xE7\n\xF8\n\n\x0B\x1A\x0B,\x0B:\x0BJ\x0BY\x0Be\x0Bt\x0B\x8F\x0B\xAA\x0B\xC8\x0B\xD4\x0B\xE3\x0B\xF1\x0B\x04\x0C\x16\x0C%\x0C;\x0CP\x0Cb\x0Cu\x0C\x88\x0C\x9C\x0C\xAF\x0C\xC3\x0C\xD1\x0C\xDF\x0C\xEF\x0C\x01\r\x10\r$\r4\rD\rY\rj\r~\r\x8E\r\x9B\r\xB0\r\xC0\r\xD0\r\xE0\r\xF1\r\x03\x0E\x18\x0E+\x0E8\x0EK\x0EZ\x0Ei\x0Ex\x0E\x89\x0E\x97\x0E\xA9\x0E\xB9\x0E\xC8\x0E\xDB\x0E\xEB\x0E\xFB\x0E\x14\x0F(\x0F9\x0FK\x0F\\\x0Fn\x0F\x83\x0F\x93\x0F\xA3\x0F\xB4\x0F\xC7\x0F\xD0\x0F\xDB\x0F\xE5\x0F\xF0\x0F\xFA\x0F\x05\x10\x12\x10 \x10+\x107\x10C\x10L\x10X\x10d\x10o\x10{\x10\x86\x10\x93\x10\x9D\x10\xAC\x10\xBA\x10\xC8\x10\xD4\x10\xDE\x10\xEB\x10\xF5\x10\xFE\x10\x08\x11\x15\x11#\x11,\x117\x11B\x11R\x11`\x11i\x11u\x11\x82\x11\x8E\x11\x9B\x11\xA9\x11\xB3\x11\xC1\x11\xCD\x11\xD9\x11\xE7\x11\xF4\x11\x01\x12\r\x12\x1D\x12.\x12:\x12E\x12O\x12Y\x12e\x12r\x12}\x12\x88\x12\x94\x12\xA5\x12\xB5\x12\xBE\x12\xC7\x12\xD6\x12\xE4\x12\xF2\x12\xFC\x12\t\x13\x17\x13#\x13.\x139\x13F\x13T\x13^\x13k\x13y\x13\x8B\x13\x96\x13\xA3\x13\xAF\x13\xBA\x13\xC7\x13\xD2\x13\xDE\x13\xE8\x13\xF2\x13\x04\x14\x14\x14#\x14.\x14;\x14I\x14Y\x14e\x14p\x14\x82\x14\x8E\x14\x9D\x14\xAD\x14\xBC\x14\xCF\x14\xDE\x14\xEC\x14\xFE\x14\x0E\x15 \x156\x15H\x15X\x15e\x15w\x15\x89\x15\x9E\x15\xB0\x15\xC0\x15\xD0\x15\xDF\x15\xEF\x15\xFC\x15\x0E\x16!\x164\x16A\x16P\x16_\x16s\x16\x82\x16\x92\x16\xA4\x16\xB6\x16\xC4\x16\xD8\x16\xE3\x16\xF3\x16\xFE\x16\t\x17\x0C\x17\x13\x17\"\x170\x17>\x17M\x17`\x17n\x17\x81\x17\x8D\x17\x9E\x17\xB0\x17\xB4\x17\xB7\x17\xBA\x17\xC1\x17\xC6\x17\xCA\x17\xD1\x17\xDA\x17\xE3\x17\xED\x17\xF7\x17\x01\x18\n\x18\x13\x18\x1C\x18%\x18.\x187\x18@\x18I\x18R\x18[\x18e\x18o\x18y\x18\x83\x18\x8D\x18\x96\x18\x9F\x18\xA8\x18\xB1\x18\xBA\x18\xC3\x18\xCC\x18\xD5\x18\xDD\x18\xEA\x18\xF1\x18\xF8\x18\x05\x19\r\x19\x1D\x19+\x19;\x19H\x19V\x19e\x19r\x19\x83\x19\x92\x19\xA2\x19\xB1\x19\xC0\x19\xCF\x19\xE0\x19\xED\x19\xFD\x19\x0C\x1A\x1B\x1A-\x1A<\x1AI\x1A[\x1Af\x1Ar\x1A}\x1A\x8A\x1A\x9A\x1A\xA7\x1A\xB8\x1A\xC5\x1A\xD1\x1A\xE1\x1A\xED\x1A\xFA\x1A\x07\x1B\x15\x1B \x1B,\x1B<\x1BI\x1BT\x1B_\x1Bl\x1B}\x1B\x8C\x1B\x9A\x1B\xAB\x1B\xB8\x1B\xC4\x1B\xD4\x1B\xE2\x1B\xEF\x1B\xFE\x1B\x0E\x1C\x1D\x1C)\x1C7\x1CD\x1CR\x1Cb\x1Co\x1C|\x1C\x8D\x1C\x9A\x1C\x9C\x1C\xA3\x1C\xA6\x1C\xAB\x1C\xB0\x1C\xB4\x1C\xBD\x1C\xC0\x1C\xC8\x1C\xCF\x1C\xE2\x1C\xEF\x1C\xFF\x1C\x0B\x1D\x18\x1D(\x1D3\x1DB\x1DR\x1D`\x1Dn\x1Dr\x1Dx\x1D\x7F\x1D\x84\x1D\x8D\x1D\x92\x1D\x95\x1D\x98\x1D\x9F\x1D\xAF\x1D\xBD\x1D\xCB\x1D\xCD\x1D\xD4\x1D\xDA\x1D\xDD\x1D\xE4\x1D\xF0\x1D\0\x1E\x14\x1E#\x1E0\x1E>\x1EK\x1E\\\x1Ek\x1Ew\x1E\x87\x1E\x98\x1E\xA7\x1E\xBA\x1E\xC6\x1E\xD6\x1E\xE6\x1E\xF4\x1E\x06\x1F\x14\x1F%\x1F3\x1FD\x1FR\x1F_\x1Fk\x1Fz\x1F\x88\x1F\x99\x1F\xA6\x1F\xB6\x1F\xC5\x1F\xD3\x1F\xE7\x1F\xF8\x1F\x06 \x13 ! / @ L X f q w \x7F \x82 \x85 \x8E \x94 \x97 \xA0 \xAB \xB5 \xBF \xCE \xD8 \xE1 \xF2 \xFD \x08!\x12!\x1A!\x1D!&!*!-!Africa/AbidjanAfrica/AccraAfrica/Addis_AbabaAfrica/AlgiersAfrica/AsmaraAfrica/AsmeraAfrica/BamakoAfrica/BanguiAfrica/BanjulAfrica/BissauAfrica/BlantyreAfrica/BrazzavilleAfrica/BujumburaAfrica/CairoAfrica/CasablancaAfrica/CeutaAfrica/ConakryAfrica/DakarAfrica/Dar_es_SalaamAfrica/DjiboutiAfrica/DoualaAfrica/El_AaiunAfrica/FreetownAfrica/GaboroneAfrica/HarareAfrica/JohannesburgAfrica/JubaAfrica/KampalaAfrica/KhartoumAfrica/KigaliAfrica/KinshasaAfrica/LagosAfrica/LibrevilleAfrica/LomeAfrica/LuandaAfrica/LubumbashiAfrica/LusakaAfrica/MalaboAfrica/MaputoAfrica/MaseruAfrica/MbabaneAfrica/MogadishuAfrica/MonroviaAfrica/NairobiAfrica/NdjamenaAfrica/NiameyAfrica/NouakchottAfrica/OuagadougouAfrica/Porto-NovoAfrica/Sao_TomeAfrica/TimbuktuAfrica/TripoliAfrica/TunisAfrica/WindhoekAmerica/AdakAmerica/AnchorageAmerica/AnguillaAmerica/AntiguaAmerica/AraguainaAmerica/Argentina/Buenos_AiresAmerica/Argentina/CatamarcaAmerica/Argentina/ComodRivadaviaAmerica/Argentina/CordobaAmerica/Argentina/JujuyAmerica/Argentina/La_RiojaAmerica/Argentina/MendozaAmerica/Argentina/Rio_GallegosAmerica/Argentina/SaltaAmerica/Argentina/San_JuanAmerica/Argentina/San_LuisAmerica/Argentina/TucumanAmerica/Argentina/UshuaiaAmerica/ArubaAmerica/AsuncionAmerica/AtikokanAmerica/AtkaAmerica/BahiaAmerica/Bahia_BanderasAmerica/BarbadosAmerica/BelemAmerica/BelizeAmerica/Blanc-SablonAmerica/Boa_VistaAmerica/BogotaAmerica/BoiseAmerica/Buenos_AiresAmerica/Cambridge_BayAmerica/Campo_GrandeAmerica/CancunAmerica/CaracasAmerica/CatamarcaAmerica/CayenneAmerica/CaymanAmerica/ChicagoAmerica/ChihuahuaAmerica/Ciudad_JuarezAmerica/Coral_HarbourAmerica/CordobaAmerica/Costa_RicaAmerica/CoyhaiqueAmerica/CrestonAmerica/CuiabaAmerica/CuracaoAmerica/DanmarkshavnAmerica/DawsonAmerica/Dawson_CreekAmerica/DenverAmerica/DetroitAmerica/DominicaAmerica/EdmontonAmerica/EirunepeAmerica/El_SalvadorAmerica/EnsenadaAmerica/Fort_NelsonAmerica/Fort_WayneAmerica/FortalezaAmerica/Glace_BayAmerica/GodthabAmerica/Goose_BayAmerica/Grand_TurkAmerica/GrenadaAmerica/GuadeloupeAmerica/GuatemalaAmerica/GuayaquilAmerica/GuyanaAmerica/HalifaxAmerica/HavanaAmerica/HermosilloAmerica/Indiana/IndianapolisAmerica/Indiana/KnoxAmerica/Indiana/MarengoAmerica/Indiana/PetersburgAmerica/Indiana/Tell_CityAmerica/Indiana/VevayAmerica/Indiana/VincennesAmerica/Indiana/WinamacAmerica/IndianapolisAmerica/InuvikAmerica/IqaluitAmerica/JamaicaAmerica/JujuyAmerica/JuneauAmerica/Kentucky/LouisvilleAmerica/Kentucky/MonticelloAmerica/Knox_INAmerica/KralendijkAmerica/La_PazAmerica/LimaAmerica/Los_AngelesAmerica/LouisvilleAmerica/Lower_PrincesAmerica/MaceioAmerica/ManaguaAmerica/ManausAmerica/MarigotAmerica/MartiniqueAmerica/MatamorosAmerica/MazatlanAmerica/MendozaAmerica/MenomineeAmerica/MeridaAmerica/MetlakatlaAmerica/Mexico_CityAmerica/MiquelonAmerica/MonctonAmerica/MonterreyAmerica/MontevideoAmerica/MontrealAmerica/MontserratAmerica/NassauAmerica/New_YorkAmerica/NipigonAmerica/NomeAmerica/NoronhaAmerica/North_Dakota/BeulahAmerica/North_Dakota/CenterAmerica/North_Dakota/New_SalemAmerica/NuukAmerica/OjinagaAmerica/PanamaAmerica/PangnirtungAmerica/ParamariboAmerica/PhoenixAmerica/Port-au-PrinceAmerica/Port_of_SpainAmerica/Porto_AcreAmerica/Porto_VelhoAmerica/Puerto_RicoAmerica/Punta_ArenasAmerica/Rainy_RiverAmerica/Rankin_InletAmerica/RecifeAmerica/ReginaAmerica/ResoluteAmerica/Rio_BrancoAmerica/RosarioAmerica/Santa_IsabelAmerica/SantaremAmerica/SantiagoAmerica/Santo_DomingoAmerica/Sao_PauloAmerica/ScoresbysundAmerica/ShiprockAmerica/SitkaAmerica/St_BarthelemyAmerica/St_JohnsAmerica/St_KittsAmerica/St_LuciaAmerica/St_ThomasAmerica/St_VincentAmerica/Swift_CurrentAmerica/TegucigalpaAmerica/ThuleAmerica/Thunder_BayAmerica/TijuanaAmerica/TorontoAmerica/TortolaAmerica/VancouverAmerica/VirginAmerica/WhitehorseAmerica/WinnipegAmerica/YakutatAmerica/YellowknifeAntarctica/CaseyAntarctica/DavisAntarctica/DumontDUrvilleAntarctica/MacquarieAntarctica/MawsonAntarctica/McMurdoAntarctica/PalmerAntarctica/RotheraAntarctica/South_PoleAntarctica/SyowaAntarctica/TrollAntarctica/VostokArctic/LongyearbyenAsia/AdenAsia/AlmatyAsia/AmmanAsia/AnadyrAsia/AqtauAsia/AqtobeAsia/AshgabatAsia/AshkhabadAsia/AtyrauAsia/BaghdadAsia/BahrainAsia/BakuAsia/BangkokAsia/BarnaulAsia/BeirutAsia/BishkekAsia/BruneiAsia/CalcuttaAsia/ChitaAsia/ChoibalsanAsia/ChongqingAsia/ChungkingAsia/ColomboAsia/DaccaAsia/DamascusAsia/DhakaAsia/DiliAsia/DubaiAsia/DushanbeAsia/FamagustaAsia/GazaAsia/HarbinAsia/HebronAsia/Ho_Chi_MinhAsia/Hong_KongAsia/HovdAsia/IrkutskAsia/IstanbulAsia/JakartaAsia/JayapuraAsia/JerusalemAsia/KabulAsia/KamchatkaAsia/KarachiAsia/KashgarAsia/KathmanduAsia/KatmanduAsia/KhandygaAsia/KolkataAsia/KrasnoyarskAsia/Kuala_LumpurAsia/KuchingAsia/KuwaitAsia/MacaoAsia/MacauAsia/MagadanAsia/MakassarAsia/ManilaAsia/MuscatAsia/NicosiaAsia/NovokuznetskAsia/NovosibirskAsia/OmskAsia/OralAsia/Phnom_PenhAsia/PontianakAsia/PyongyangAsia/QatarAsia/QostanayAsia/QyzylordaAsia/RangoonAsia/RiyadhAsia/SaigonAsia/SakhalinAsia/SamarkandAsia/SeoulAsia/ShanghaiAsia/SingaporeAsia/SrednekolymskAsia/TaipeiAsia/TashkentAsia/TbilisiAsia/TehranAsia/Tel_AvivAsia/ThimbuAsia/ThimphuAsia/TokyoAsia/TomskAsia/Ujung_PandangAsia/UlaanbaatarAsia/Ulan_BatorAsia/UrumqiAsia/Ust-NeraAsia/VientianeAsia/VladivostokAsia/YakutskAsia/YangonAsia/YekaterinburgAsia/YerevanAtlantic/AzoresAtlantic/BermudaAtlantic/CanaryAtlantic/Cape_VerdeAtlantic/FaeroeAtlantic/FaroeAtlantic/Jan_MayenAtlantic/MadeiraAtlantic/ReykjavikAtlantic/South_GeorgiaAtlantic/St_HelenaAtlantic/StanleyAustralia/ACTAustralia/AdelaideAustralia/BrisbaneAustralia/Broken_HillAustralia/CanberraAustralia/CurrieAustralia/DarwinAustralia/EuclaAustralia/HobartAustralia/LHIAustralia/LindemanAustralia/Lord_HoweAustralia/MelbourneAustralia/NSWAustralia/NorthAustralia/PerthAustralia/QueenslandAustralia/SouthAustralia/SydneyAustralia/TasmaniaAustralia/VictoriaAustralia/WestAustralia/YancowinnaBrazil/AcreBrazil/DeNoronhaBrazil/EastBrazil/WestCETCST6CDTCanada/AtlanticCanada/CentralCanada/EasternCanada/MountainCanada/NewfoundlandCanada/PacificCanada/SaskatchewanCanada/YukonChile/ContinentalChile/EasterIslandCubaEETESTEST5EDTEgyptEireEtc/GMTEtc/GMT+0Etc/GMT+1Etc/GMT+10Etc/GMT+11Etc/GMT+12Etc/GMT+2Etc/GMT+3Etc/GMT+4Etc/GMT+5Etc/GMT+6Etc/GMT+7Etc/GMT+8Etc/GMT+9Etc/GMT-0Etc/GMT-1Etc/GMT-10Etc/GMT-11Etc/GMT-12Etc/GMT-13Etc/GMT-14Etc/GMT-2Etc/GMT-3Etc/GMT-4Etc/GMT-5Etc/GMT-6Etc/GMT-7Etc/GMT-8Etc/GMT-9Etc/GMT0Etc/GreenwichEtc/UCTEtc/UTCEtc/UniversalEtc/ZuluEurope/AmsterdamEurope/AndorraEurope/AstrakhanEurope/AthensEurope/BelfastEurope/BelgradeEurope/BerlinEurope/BratislavaEurope/BrusselsEurope/BucharestEurope/BudapestEurope/BusingenEurope/ChisinauEurope/CopenhagenEurope/DublinEurope/GibraltarEurope/GuernseyEurope/HelsinkiEurope/Isle_of_ManEurope/IstanbulEurope/JerseyEurope/KaliningradEurope/KievEurope/KirovEurope/KyivEurope/LisbonEurope/LjubljanaEurope/LondonEurope/LuxembourgEurope/MadridEurope/MaltaEurope/MariehamnEurope/MinskEurope/MonacoEurope/MoscowEurope/NicosiaEurope/OsloEurope/ParisEurope/PodgoricaEurope/PragueEurope/RigaEurope/RomeEurope/SamaraEurope/San_MarinoEurope/SarajevoEurope/SaratovEurope/SimferopolEurope/SkopjeEurope/SofiaEurope/StockholmEurope/TallinnEurope/TiraneEurope/TiraspolEurope/UlyanovskEurope/UzhgorodEurope/VaduzEurope/VaticanEurope/ViennaEurope/VilniusEurope/VolgogradEurope/WarsawEurope/ZagrebEurope/ZaporozhyeEurope/ZurichGBGB-EireGMTGMT+0GMT-0GMT0GreenwichHSTHongkongIcelandIndian/AntananarivoIndian/ChagosIndian/ChristmasIndian/CocosIndian/ComoroIndian/KerguelenIndian/MaheIndian/MaldivesIndian/MauritiusIndian/MayotteIndian/ReunionIranIsraelJamaicaJapanKwajaleinLibyaMETMSTMST7MDTMexico/BajaNorteMexico/BajaSurMexico/GeneralNZNZ-CHATNavajoPRCPST8PDTPacific/ApiaPacific/AucklandPacific/BougainvillePacific/ChathamPacific/ChuukPacific/EasterPacific/EfatePacific/EnderburyPacific/FakaofoPacific/FijiPacific/FunafutiPacific/GalapagosPacific/GambierPacific/GuadalcanalPacific/GuamPacific/HonoluluPacific/JohnstonPacific/KantonPacific/KiritimatiPacific/KosraePacific/KwajaleinPacific/MajuroPacific/MarquesasPacific/MidwayPacific/NauruPacific/NiuePacific/NorfolkPacific/NoumeaPacific/Pago_PagoPacific/PalauPacific/PitcairnPacific/PohnpeiPacific/PonapePacific/Port_MoresbyPacific/RarotongaPacific/SaipanPacific/SamoaPacific/TahitiPacific/TarawaPacific/TongatapuPacific/TrukPacific/WakePacific/WallisPacific/YapPolandPortugalROCROKSingaporeTurkeyUCTUS/AlaskaUS/AleutianUS/ArizonaUS/CentralUS/East-IndianaUS/EasternUS/HawaiiUS/Indiana-StarkeUS/MichiganUS/MountainUS/PacificUS/SamoaUTCUniversalW-SUWETZulu") }, }; diff --git a/deps/temporal/provider/src/experimental_tzif/posix.rs b/deps/temporal/provider/src/experimental_tzif/posix.rs index 1241bd174c4152..04e67f9c30b9e4 100644 --- a/deps/temporal/provider/src/experimental_tzif/posix.rs +++ b/deps/temporal/provider/src/experimental_tzif/posix.rs @@ -74,9 +74,9 @@ impl From<&PosixTransition> for ZeroPosixTransition { #[cfg_attr(feature = "datagen", databake(path = timezone_provider::experimental_tzif::posix))] pub struct ZeroTransitionDateTime { /// The date at which a transition should occur. - date: ZeroTransitionDate, + pub date: ZeroTransitionDate, /// The time of day in seconds. - time: i64, + pub time: i64, } #[cfg(feature = "datagen")] @@ -97,9 +97,9 @@ impl From<&PosixDateTime> for ZeroTransitionDateTime { )] #[cfg_attr(feature = "datagen", databake(path = timezone_provider::experimental_tzif::posix))] pub struct ZeroTransitionDate { - kind: DateKind, - day: Option, - mwd: Option<(u8, u8, u8)>, + pub kind: DateKind, + pub day: Option, + pub mwd: Option<(u8, u8, u8)>, } #[cfg(feature = "datagen")] diff --git a/deps/temporal/provider/src/provider.rs b/deps/temporal/provider/src/provider.rs index d1fba95f7fb6fd..217c7316f0aefb 100644 --- a/deps/temporal/provider/src/provider.rs +++ b/deps/temporal/provider/src/provider.rs @@ -211,6 +211,65 @@ pub trait TimeZoneProvider { ) -> TimeZoneProviderResult>; } +macro_rules! provider_deref_impl { + ($target:ty) => { + impl

TimeZoneProvider for $target + where + P: TimeZoneProvider + ?Sized, + { + #[inline] + fn get(&self, ident: &[u8]) -> TimeZoneProviderResult { + (**self).get(ident) + } + + #[inline] + fn identifier(&self, id: TimeZoneId) -> TimeZoneProviderResult> { + (**self).identifier(id) + } + + #[inline] + fn canonicalized(&self, id: TimeZoneId) -> TimeZoneProviderResult { + (**self).canonicalized(id) + } + + #[inline] + fn candidate_nanoseconds_for_local_epoch_nanoseconds( + &self, + id: TimeZoneId, + local_datetime: IsoDateTime, + ) -> TimeZoneProviderResult { + (**self).candidate_nanoseconds_for_local_epoch_nanoseconds(id, local_datetime) + } + + #[inline] + fn transition_nanoseconds_for_utc_epoch_nanoseconds( + &self, + id: TimeZoneId, + epoch_nanoseconds: i128, + ) -> TimeZoneProviderResult { + (**self).transition_nanoseconds_for_utc_epoch_nanoseconds(id, epoch_nanoseconds) + } + + #[inline] + fn get_time_zone_transition( + &self, + id: TimeZoneId, + epoch_nanoseconds: i128, + direction: TransitionDirection, + ) -> TimeZoneProviderResult> { + (**self).get_time_zone_transition(id, epoch_nanoseconds, direction) + } + } + }; +} + +provider_deref_impl!(&P); +provider_deref_impl!(&mut P); +provider_deref_impl!(alloc::boxed::Box

); +provider_deref_impl!(alloc::rc::Rc

); +#[cfg(target_has_atomic = "ptr")] +provider_deref_impl!(alloc::sync::Arc

); + /// An id for a resolved timezone, for use with a [`TimeZoneNormalizer`] #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] pub struct NormalizedId(pub usize); @@ -226,6 +285,37 @@ pub trait TimeZoneNormalizer { fn identifier(&self, _: NormalizedId) -> TimeZoneProviderResult<&str>; } +macro_rules! normalizer_deref_impl { + ($target:ty) => { + impl

TimeZoneNormalizer for $target + where + P: TimeZoneNormalizer + ?Sized, + { + #[inline] + fn normalized(&self, name: &[u8]) -> TimeZoneProviderResult { + (**self).normalized(name) + } + + #[inline] + fn canonicalized(&self, id: NormalizedId) -> TimeZoneProviderResult { + (**self).canonicalized(id) + } + + #[inline] + fn identifier(&self, id: NormalizedId) -> TimeZoneProviderResult<&str> { + (**self).identifier(id) + } + } + }; +} + +normalizer_deref_impl!(&P); +normalizer_deref_impl!(&mut P); +normalizer_deref_impl!(alloc::boxed::Box

); +normalizer_deref_impl!(alloc::rc::Rc

); +#[cfg(target_has_atomic = "ptr")] +normalizer_deref_impl!(alloc::sync::Arc

); + /// An id for a resolved timezone, for use with a [`TimeZoneResolver`] #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] pub struct ResolvedId(pub usize); @@ -254,6 +344,53 @@ pub trait TimeZoneResolver { ) -> TimeZoneProviderResult>; } +macro_rules! resolver_deref_impl { + ($target:ty) => { + impl

TimeZoneResolver for $target + where + P: TimeZoneResolver + ?Sized, + { + fn get_id(&self, normalized_identifier: &[u8]) -> TimeZoneProviderResult { + (**self).get_id(normalized_identifier) + } + + fn candidate_nanoseconds_for_local_epoch_nanoseconds( + &self, + identifier: ResolvedId, + local_datetime: IsoDateTime, + ) -> TimeZoneProviderResult { + (**self) + .candidate_nanoseconds_for_local_epoch_nanoseconds(identifier, local_datetime) + } + + fn transition_nanoseconds_for_utc_epoch_nanoseconds( + &self, + identifier: ResolvedId, + epoch_nanoseconds: i128, + ) -> TimeZoneProviderResult { + (**self) + .transition_nanoseconds_for_utc_epoch_nanoseconds(identifier, epoch_nanoseconds) + } + + fn get_time_zone_transition( + &self, + identifier: ResolvedId, + epoch_nanoseconds: i128, + direction: TransitionDirection, + ) -> TimeZoneProviderResult> { + (**self).get_time_zone_transition(identifier, epoch_nanoseconds, direction) + } + } + }; +} + +resolver_deref_impl!(&P); +resolver_deref_impl!(&mut P); +resolver_deref_impl!(alloc::boxed::Box

); +resolver_deref_impl!(alloc::rc::Rc

); +#[cfg(target_has_atomic = "ptr")] +resolver_deref_impl!(alloc::sync::Arc

); + /// A type that can both normalize and resolve, which implements [`TimeZoneProvider`] #[derive(Default, Copy, Clone, Debug)] pub struct NormalizerAndResolver { diff --git a/deps/temporal/provider/src/tzdb/datagen.rs b/deps/temporal/provider/src/tzdb/datagen.rs index 24479c6bef5d59..1b974d9599237d 100644 --- a/deps/temporal/provider/src/tzdb/datagen.rs +++ b/deps/temporal/provider/src/tzdb/datagen.rs @@ -69,6 +69,13 @@ impl IanaIdentifierNormalizer<'_> { pub fn build(tzdata_path: &Path) -> Result { let provider = TzdbDataSource::try_from_zoneinfo_directory(tzdata_path) .map_err(IanaDataError::Provider)?; + + let zonetab_tzs: BTreeSet<_> = provider + .data + .zone_tab + .iter() + .map(|zt| zt.tz.clone()) + .collect(); let mut all_identifiers = BTreeSet::default(); for zone_id in provider.data.zones.keys() { // Add canonical identifiers. @@ -92,14 +99,24 @@ impl IanaIdentifierNormalizer<'_> { }) .collect(); - let mut primary_id_map: BTreeMap = BTreeMap::new(); + // A map from noncanonical identifiers to their canonicalized id + let mut to_primary_id_map: BTreeMap = BTreeMap::new(); // ECMAScript implementations must support an available named time zone with the identifier "UTC", which must be // the primary time zone identifier for the UTC time zone. In addition, implementations may support any number of other available named time zones. let utc_index = norm_vec.binary_search(&"UTC").unwrap(); - primary_id_map.insert(norm_vec.binary_search(&"Etc/UTC").unwrap(), utc_index); - primary_id_map.insert(norm_vec.binary_search(&"Etc/GMT").unwrap(), utc_index); + to_primary_id_map.insert(norm_vec.binary_search(&"Etc/UTC").unwrap(), utc_index); + to_primary_id_map.insert(norm_vec.binary_search(&"Etc/GMT").unwrap(), utc_index); for (link_from, link_to) in &provider.data.links { + if zonetab_tzs.contains(link_from) { + // https://tc39.es/ecma402/#sec-use-of-iana-time-zone-database + // > Any Link name that is present in the “TZ” column of file zone.tab + // > must be a primary time zone identifier. + // + // So we ignore links entries that link from these timezones + // which results in those timezones considered as primary. + continue; + } if link_from == "UTC" { continue; } @@ -109,7 +126,7 @@ impl IanaIdentifierNormalizer<'_> { } else { norm_vec.binary_search(&&**link_to).unwrap() }; - primary_id_map.insert(link_from, index); + to_primary_id_map.insert(link_from, index); } Ok(IanaIdentifierNormalizer { @@ -117,7 +134,7 @@ impl IanaIdentifierNormalizer<'_> { available_id_index: ZeroAsciiIgnoreCaseTrie::try_from(&identifier_map) .map_err(IanaDataError::Build)? .convert_store(), - non_canonical_identifiers: primary_id_map + non_canonical_identifiers: to_primary_id_map .iter() .map(|(x, y)| (u32::try_from(*x).unwrap(), u32::try_from(*y).unwrap())) .collect(), diff --git a/deps/temporal/provider/src/tzif.rs b/deps/temporal/provider/src/tzif.rs index 6bbbf0076b4a8e..98fe7413687ce3 100644 --- a/deps/temporal/provider/src/tzif.rs +++ b/deps/temporal/provider/src/tzif.rs @@ -1917,7 +1917,7 @@ mod tests { id: &str, before_offset: i64, after_offset: i64, - provider: &impl TimeZoneProvider, + provider: &(impl TimeZoneProvider + ?Sized), ) { let id = provider.get(id.as_bytes()).unwrap(); let before_possible = provider diff --git a/deps/temporal/src/builtins/compiled/duration/tests.rs b/deps/temporal/src/builtins/compiled/duration/tests.rs index 72ae0e4a1f67b8..0b6acac85cb186 100644 --- a/deps/temporal/src/builtins/compiled/duration/tests.rs +++ b/deps/temporal/src/builtins/compiled/duration/tests.rs @@ -1,7 +1,8 @@ use crate::{ duration::DateDuration, options::{ - OffsetDisambiguation, RelativeTo, RoundingIncrement, RoundingMode, RoundingOptions, Unit, + OffsetDisambiguation, Overflow, RelativeTo, RoundingIncrement, RoundingMode, + RoundingOptions, Unit, }, partial::PartialDuration, Calendar, PlainDate, TimeZone, ZonedDateTime, @@ -626,6 +627,24 @@ fn add_normalized_time_duration_out_of_range() { assert!(err.is_err()) } +#[test] +fn add_large_durations() { + // Testcases found by fuzzing + let base = PlainDate::new(2000, 1, 1, Calendar::from_str("dangi").unwrap()).unwrap(); + + let test_duration = Duration::from(DateDuration::new(4294901760, 256, 0, 0).unwrap()); + assert!(base.add(&test_duration, Some(Overflow::Constrain)).is_err()); + + let test_duration = Duration::from(DateDuration::new(0, 1281, 0, 8589934592).unwrap()); + assert!(base.add(&test_duration, Some(Overflow::Constrain)).is_err()); + + let test_duration = Duration::from(DateDuration::new(2046820352, 0, 0, 0).unwrap()); + assert!(base.add(&test_duration, Some(Overflow::Constrain)).is_err()); + + let test_duration = Duration::from(DateDuration::new(0, 0, 2516582400, 0).unwrap()); + assert!(base.add(&test_duration, Some(Overflow::Constrain)).is_err()); +} + #[test] fn test_rounding_boundaries() { let relative_to = PlainDate::new(2000, 1, 1, Calendar::default()).unwrap(); diff --git a/deps/temporal/src/builtins/core/calendar.rs b/deps/temporal/src/builtins/core/calendar.rs index e05c3f39c6867b..97ac5a08e0f078 100644 --- a/deps/temporal/src/builtins/core/calendar.rs +++ b/deps/temporal/src/builtins/core/calendar.rs @@ -7,6 +7,7 @@ use crate::{ builtins::core::{ duration::DateDuration, Duration, PlainDate, PlainDateTime, PlainMonthDay, PlainYearMonth, }, + error::ErrorMessage, iso::IsoDate, options::{Overflow, Unit}, parsers::parse_allowed_calendar_formats, @@ -16,23 +17,28 @@ use core::str::FromStr; use icu_calendar::{ cal::{ - Buddhist, Chinese, Coptic, Dangi, Ethiopian, EthiopianEraStyle, Hebrew, HijriSimulated, - HijriTabular, HijriUmmAlQura, Indian, Japanese, JapaneseExtended, Persian, Roc, + Buddhist, ChineseTraditional, Coptic, Ethiopian, EthiopianEraStyle, Hebrew, Hijri, Indian, + Japanese, JapaneseExtended, KoreanTraditional, Persian, Roc, }, AnyCalendar, AnyCalendarKind, Calendar as IcuCalendar, Iso, Ref, }; use icu_calendar::{ cal::{HijriTabularEpoch, HijriTabularLeapYears}, + options::{ + DateAddOptions, DateDifferenceOptions, DateFromFieldsOptions, MissingFieldsStrategy, + Overflow as IcuOverflow, + }, preferences::CalendarAlgorithm, - types::MonthCode as IcuMonthCode, + types::DateDuration as IcuDateDuration, + types::DateDurationUnit as IcuUnit, + types::DateFields, Gregorian, }; use icu_locale::extensions::unicode::Value; -use tinystr::{tinystr, TinyAsciiStr}; +use tinystr::TinyAsciiStr; use super::ZonedDateTime; -mod era; mod fields; mod types; @@ -40,9 +46,7 @@ pub use fields::{CalendarFields, YearMonthCalendarFields}; #[cfg(test)] pub(crate) use types::month_to_month_code; pub(crate) use types::ResolutionType; -pub use types::{MonthCode, ResolvedCalendarFields}; - -use era::EraInfo; +pub use types::{MonthCode, ResolvedIsoFields}; /// The core `Calendar` type for `temporal_rs` /// @@ -90,8 +94,6 @@ impl Calendar { pub const HIJRI_TABULAR_THURSDAY: Self = Self::new(AnyCalendarKind::HijriTabularTypeIIThursday); /// The Hijri Umm al-Qura calendar pub const HIJRI_UMM_AL_QURA: Self = Self::new(AnyCalendarKind::HijriUmmAlQura); - /// The Hijri simulated calendar - pub const HIJRI_SIMULATED: Self = Self::new(AnyCalendarKind::HijriSimulatedMecca); /// The ISO 8601 calendar pub const ISO: Self = Self::new(AnyCalendarKind::Iso); /// The Japanese calendar @@ -106,9 +108,9 @@ impl Calendar { pub const fn new(kind: AnyCalendarKind) -> Self { let cal = match kind { AnyCalendarKind::Buddhist => &AnyCalendar::Buddhist(Buddhist), - AnyCalendarKind::Chinese => const { &AnyCalendar::Chinese(Chinese::new()) }, + AnyCalendarKind::Chinese => const { &AnyCalendar::Chinese(ChineseTraditional::new()) }, AnyCalendarKind::Coptic => &AnyCalendar::Coptic(Coptic), - AnyCalendarKind::Dangi => const { &AnyCalendar::Dangi(Dangi::new()) }, + AnyCalendarKind::Dangi => const { &AnyCalendar::Dangi(KoreanTraditional::new()) }, AnyCalendarKind::Ethiopian => { const { &AnyCalendar::Ethiopian(Ethiopian::new_with_era_style( @@ -128,25 +130,26 @@ impl Calendar { AnyCalendarKind::Indian => &AnyCalendar::Indian(Indian), AnyCalendarKind::HijriTabularTypeIIFriday => { const { - &AnyCalendar::HijriTabular(HijriTabular::new( + &AnyCalendar::HijriTabular(Hijri::new_tabular( HijriTabularLeapYears::TypeII, HijriTabularEpoch::Friday, )) } } AnyCalendarKind::HijriSimulatedMecca => { - const { &AnyCalendar::HijriSimulated(HijriSimulated::new_mecca()) } + // This calendar is currently unsupported by Temporal + &AnyCalendar::Iso(Iso) } AnyCalendarKind::HijriTabularTypeIIThursday => { const { - &AnyCalendar::HijriTabular(HijriTabular::new( + &AnyCalendar::HijriTabular(Hijri::new_tabular( HijriTabularLeapYears::TypeII, HijriTabularEpoch::Thursday, )) } } AnyCalendarKind::HijriUmmAlQura => { - const { &AnyCalendar::HijriUmmAlQura(HijriUmmAlQura::new()) } + const { &AnyCalendar::HijriUmmAlQura(Hijri::new_umm_al_qura()) } } AnyCalendarKind::Iso => &AnyCalendar::Iso(Iso), AnyCalendarKind::Japanese => const { &AnyCalendar::Japanese(Japanese::new()) }, @@ -209,6 +212,81 @@ impl FromStr for Calendar { } } +impl From for IcuOverflow { + fn from(other: Overflow) -> Self { + match other { + Overflow::Reject => Self::Reject, + Overflow::Constrain => Self::Constrain, + } + } +} + +impl TryFrom for IcuUnit { + type Error = TemporalError; + fn try_from(other: Unit) -> TemporalResult { + Ok(match other { + Unit::Day => IcuUnit::Days, + Unit::Week => IcuUnit::Weeks, + Unit::Month => IcuUnit::Months, + Unit::Year => IcuUnit::Years, + _ => { + return Err(TemporalError::r#type() + .with_message("Found time unit when computing CalendarDateUntil.")) + } + }) + } +} + +impl<'a> TryFrom<&'a CalendarFields> for DateFields<'a> { + type Error = TemporalError; + fn try_from(other: &'a CalendarFields) -> TemporalResult { + let mut this = DateFields::default(); + this.era = other.era.as_ref().map(|o| o.as_bytes()); + this.era_year = other.era_year; + this.extended_year = other.year; + this.month_code = other.month_code.as_ref().map(|o| o.0.as_bytes()); + this.ordinal_month = other.month; + this.day = other.day; + Ok(this) + } +} + +/// See +/// +/// We don't want to trigger any pathological or panicky testcases in ICU4X. +/// +/// To aid in that, we early constrain date durations to things that have no hope of producing a datetime +/// that is within Temporal range. +fn early_constrain_date_duration(duration: &IcuDateDuration) -> Result<(), TemporalError> { + // Temporal range is -271821-04-20 to +275760-09-13 + // This is (roughly) the maximum year duration that can exist for ISO + const TEMPORAL_MAX_ISO_YEAR_DURATION: u32 = 275760 + 271821; + // Double it. No calendar has years that are half the size of ISO years. + const YEAR_DURATION: u32 = 2 * TEMPORAL_MAX_ISO_YEAR_DURATION; + // Assume every year is a leap year, calculate a month range + const MONTH_DURATION: u32 = YEAR_DURATION * 13; + // Our longest year is 390 days + const DAY_DURATION: u32 = YEAR_DURATION * 390; + const WEEK_DURATION: u32 = DAY_DURATION / 7; + + let err = Err(TemporalError::range().with_enum(ErrorMessage::IntermediateDateTimeOutOfRange)); + + if duration.years > YEAR_DURATION { + return err; + } + if duration.months > MONTH_DURATION { + return err; + } + if duration.weeks > WEEK_DURATION { + return err; + } + if duration.days > DAY_DURATION.into() { + return err; + } + + Ok(()) +} + // ==== Public `CalendarSlot` methods ==== impl Calendar { @@ -230,26 +308,26 @@ impl Calendar { fields: CalendarFields, overflow: Overflow, ) -> TemporalResult { - let resolved_fields = - ResolvedCalendarFields::try_from_fields(self, &fields, overflow, ResolutionType::Date)?; - if self.is_iso() { + let resolved_fields = + ResolvedIsoFields::try_from_fields(&fields, overflow, ResolutionType::Date)?; + // Resolve month and monthCode; return PlainDate::new_with_overflow( - resolved_fields.era_year.arithmetic_year, - resolved_fields.month_code.to_month_integer(), + resolved_fields.arithmetic_year, + resolved_fields.month, resolved_fields.day, self.clone(), overflow, ); } - let calendar_date = self.0.from_codes( - resolved_fields.era_year.era.as_ref().map(|e| e.0.as_str()), - resolved_fields.era_year.year, - IcuMonthCode(resolved_fields.month_code.0), - resolved_fields.day, - )?; + let fields = DateFields::try_from(&fields)?; + let mut options = DateFromFieldsOptions::default(); + options.overflow = Some(overflow.into()); + options.missing_fields_strategy = Some(MissingFieldsStrategy::Reject); + + let calendar_date = self.0.from_fields(fields, options)?; let iso = self.0.to_iso(&calendar_date); PlainDate::new_with_overflow( Iso.extended_year(&iso), @@ -283,15 +361,11 @@ impl Calendar { let date = self.date_from_fields(fields, overflow)?; fields = CalendarFields::from_date(&date); } - let resolved_fields = ResolvedCalendarFields::try_from_fields( - self, - &fields, - overflow, - ResolutionType::MonthDay, - )?; if self.is_iso() { + let resolved_fields = + ResolvedIsoFields::try_from_fields(&fields, overflow, ResolutionType::MonthDay)?; return PlainMonthDay::new_with_overflow( - resolved_fields.month_code.to_month_integer(), + resolved_fields.month, resolved_fields.day, self.clone(), overflow, @@ -299,13 +373,29 @@ impl Calendar { ); } - // We trust ResolvedCalendarFields to have calculated an appropriate reference year for us - let calendar_date = self.0.from_codes( - resolved_fields.era_year.era.as_ref().map(|e| e.0.as_str()), - resolved_fields.era_year.year, - IcuMonthCode(resolved_fields.month_code.0), - resolved_fields.day, - )?; + let fields = DateFields::try_from(&fields)?; + let mut options = DateFromFieldsOptions::default(); + options.overflow = Some(overflow.into()); + if fields.day.is_none() { + // Otherwise we're liable to hit the YearMonth resolution + return Err(TemporalError::r#type().with_message("Must specify day for MonthDay")); + } + options.missing_fields_strategy = Some(MissingFieldsStrategy::Ecma); + + let mut calendar_date = self.0.from_fields(fields, options)?; + + // The MonthDay algorithm wants us to resolve a date *with* the provided year, + // if one was provided, but then use a reference year afterwards. + // So if a year was provided, we reresolve. + if fields.era_year.is_some() || fields.extended_year.is_some() { + let mut fields2 = DateFields::default(); + fields2.day = Some(self.0.day_of_month(&calendar_date).0); + let code = self.0.month(&calendar_date).standard_code; + fields2.month_code = Some(code.0.as_bytes()); + + calendar_date = self.0.from_fields(fields2, options)?; + } + let iso = self.0.to_iso(&calendar_date); PlainMonthDay::new_with_overflow( Iso.month(&iso).ordinal, @@ -322,30 +412,32 @@ impl Calendar { fields: YearMonthCalendarFields, overflow: Overflow, ) -> TemporalResult { - // TODO: add a from_partial_year_month method on ResolvedCalendarFields - let resolved_fields = ResolvedCalendarFields::try_from_fields( - self, - &CalendarFields::from(fields), - overflow, - ResolutionType::YearMonth, - )?; if self.is_iso() { + // TODO: add a from_partial_year_month method on ResolvedCalendarFields + let resolved_fields = ResolvedIsoFields::try_from_fields( + &CalendarFields::from(fields), + overflow, + ResolutionType::YearMonth, + )?; return PlainYearMonth::new_with_overflow( - resolved_fields.era_year.arithmetic_year, - resolved_fields.month_code.to_month_integer(), + resolved_fields.arithmetic_year, + resolved_fields.month, Some(resolved_fields.day), self.clone(), overflow, ); } - // NOTE: This might preemptively throw as `ICU4X` does not support regulating. - let calendar_date = self.0.from_codes( - resolved_fields.era_year.era.as_ref().map(|e| e.0.as_str()), - resolved_fields.era_year.year, - IcuMonthCode(resolved_fields.month_code.0), - resolved_fields.day, - )?; + let fields = CalendarFields::from(fields); + let fields = DateFields::try_from(&fields)?; + let mut options = DateFromFieldsOptions::default(); + options.overflow = Some(overflow.into()); + if fields.extended_year.is_none() && fields.era_year.is_none() { + // Otherwise we're liable to hit the MonthDay resolution + return Err(TemporalError::r#type().with_message("Must specify year for YearMonth")); + } + options.missing_fields_strategy = Some(MissingFieldsStrategy::Ecma); + let calendar_date = self.0.from_fields(fields, options)?; let iso = self.0.to_iso(&calendar_date); PlainYearMonth::new_with_overflow( Iso.year_info(&iso).year, @@ -370,7 +462,34 @@ impl Calendar { return PlainDate::try_new(result.year, result.month, result.day, self.clone()); } - Err(TemporalError::range().with_message("Not yet implemented.")) + // This should be a valid duration at this point so we can just call .abs() + let invalid = TemporalError::range().with_enum(ErrorMessage::DurationNotValid); + let duration = IcuDateDuration { + is_negative: duration.years < 0 + || duration.months < 0 + || duration.weeks < 0 + || duration.days < 0, + years: u32::try_from(duration.years.abs()).map_err(|_| invalid)?, + months: u32::try_from(duration.months.abs()).map_err(|_| invalid)?, + weeks: u32::try_from(duration.weeks.abs()).map_err(|_| invalid)?, + days: u64::try_from(duration.days.abs()).map_err(|_| invalid)?, + }; + + early_constrain_date_duration(&duration)?; + let mut options = DateAddOptions::default(); + options.overflow = Some(overflow.into()); + let calendar_date = self.0.from_iso(*date.to_icu4x().inner()); + + let added = self.0.add(&calendar_date, duration, options)?; + + let iso = self.0.to_iso(&added); + PlainDate::new_with_overflow( + Iso.extended_year(&iso), + Iso.month(&iso).ordinal, + Iso.day_of_month(&iso).0, + self.clone(), + overflow, + ) } /// `CalendarDateUntil` @@ -384,7 +503,28 @@ impl Calendar { let date_duration = one.diff_iso_date(two, largest_unit)?; return Ok(Duration::from(date_duration)); } - Err(TemporalError::range().with_message("Not yet implemented.")) + let mut options = DateDifferenceOptions::default(); + options.largest_unit = Some(largest_unit.try_into()?); + let calendar_date1 = self.0.from_iso(*one.to_icu4x().inner()); + let calendar_date2 = self.0.from_iso(*two.to_icu4x().inner()); + + let added = self.0.until(&calendar_date1, &calendar_date2, options)?; + + let days = added + .days + .try_into() + .map_err(|_| TemporalError::range().with_enum(ErrorMessage::DurationNotValid))?; + let mut duration = DateDuration::new( + added.years.into(), + added.months.into(), + added.weeks.into(), + days, + )?; + + if added.is_negative { + duration = duration.negated(); + } + Ok(Duration::from(duration)) } /// `CalendarEra` @@ -533,106 +673,6 @@ impl Calendar { } impl Calendar { - pub(crate) fn get_era_info(&self, era_alias: &TinyAsciiStr<19>) -> Option { - match self.0 .0.kind() { - AnyCalendarKind::Buddhist if *era_alias == tinystr!(19, "be") => { - Some(era::BUDDHIST_ERA) - } - AnyCalendarKind::Coptic if *era_alias == tinystr!(19, "am") => Some(era::COPTIC_ERA), - AnyCalendarKind::Ethiopian if era::ETHIOPIC_ERA_IDENTIFIERS.contains(era_alias) => { - Some(era::ETHIOPIC_ERA) - } - AnyCalendarKind::Ethiopian - if era::ETHIOPIC_ETHOPICAA_ERA_IDENTIFIERS.contains(era_alias) => - { - Some(era::ETHIOPIC_ETHIOAA_ERA) - } - AnyCalendarKind::EthiopianAmeteAlem - if era::ETHIOAA_ERA_IDENTIFIERS.contains(era_alias) => - { - Some(era::ETHIOAA_ERA) - } - AnyCalendarKind::Gregorian if era::GREGORY_ERA_IDENTIFIERS.contains(era_alias) => { - Some(era::GREGORY_ERA) - } - AnyCalendarKind::Gregorian - if era::GREGORY_INVERSE_ERA_IDENTIFIERS.contains(era_alias) => - { - Some(era::GREGORY_INVERSE_ERA) - } - AnyCalendarKind::Hebrew if *era_alias == tinystr!(19, "am") => Some(era::HEBREW_ERA), - AnyCalendarKind::Indian if *era_alias == tinystr!(19, "shaka") => Some(era::INDIAN_ERA), - AnyCalendarKind::HijriTabularTypeIIFriday - | AnyCalendarKind::HijriSimulatedMecca - | AnyCalendarKind::HijriTabularTypeIIThursday - | AnyCalendarKind::HijriUmmAlQura - if *era_alias == tinystr!(19, "ah") => - { - Some(era::ISLAMIC_ERA) - } - AnyCalendarKind::HijriTabularTypeIIFriday - | AnyCalendarKind::HijriSimulatedMecca - | AnyCalendarKind::HijriTabularTypeIIThursday - | AnyCalendarKind::HijriUmmAlQura - if *era_alias == tinystr!(19, "bh") => - { - Some(era::ISLAMIC_INVERSE_ERA) - } - AnyCalendarKind::Japanese if *era_alias == tinystr!(19, "heisei") => { - Some(era::HEISEI_ERA) - } - AnyCalendarKind::Japanese if era::JAPANESE_ERA_IDENTIFIERS.contains(era_alias) => { - Some(era::JAPANESE_ERA) - } - AnyCalendarKind::Japanese - if era::JAPANESE_INVERSE_ERA_IDENTIFIERS.contains(era_alias) => - { - Some(era::JAPANESE_INVERSE_ERA) - } - AnyCalendarKind::Japanese if *era_alias == tinystr!(19, "meiji") => { - Some(era::MEIJI_ERA) - } - AnyCalendarKind::Japanese if *era_alias == tinystr!(19, "reiwa") => { - Some(era::REIWA_ERA) - } - AnyCalendarKind::Japanese if *era_alias == tinystr!(19, "showa") => { - Some(era::SHOWA_ERA) - } - AnyCalendarKind::Japanese if *era_alias == tinystr!(19, "taisho") => { - Some(era::TAISHO_ERA) - } - AnyCalendarKind::Persian if *era_alias == tinystr!(19, "ap") => Some(era::PERSIAN_ERA), - AnyCalendarKind::Roc if *era_alias == tinystr!(19, "roc") => Some(era::ROC_ERA), - AnyCalendarKind::Roc if *era_alias == tinystr!(19, "broc") => { - Some(era::ROC_INVERSE_ERA) - } - _ => None, - } - } - - pub(crate) fn get_calendar_default_era(&self) -> Option { - match self.0 .0.kind() { - AnyCalendarKind::Buddhist => Some(era::BUDDHIST_ERA), - AnyCalendarKind::Chinese => None, - AnyCalendarKind::Coptic => Some(era::COPTIC_ERA), - AnyCalendarKind::Dangi => None, - AnyCalendarKind::Ethiopian => Some(era::ETHIOPIC_ERA), - AnyCalendarKind::EthiopianAmeteAlem => Some(era::ETHIOAA_ERA), - AnyCalendarKind::Gregorian => Some(era::GREGORY_ERA), - AnyCalendarKind::Hebrew => Some(era::HEBREW_ERA), - AnyCalendarKind::Indian => Some(era::INDIAN_ERA), - AnyCalendarKind::HijriSimulatedMecca => Some(era::ISLAMIC_ERA), - AnyCalendarKind::HijriTabularTypeIIFriday => Some(era::ISLAMIC_ERA), - AnyCalendarKind::HijriTabularTypeIIThursday => Some(era::ISLAMIC_ERA), - AnyCalendarKind::HijriUmmAlQura => Some(era::ISLAMIC_ERA), - AnyCalendarKind::Iso => None, - AnyCalendarKind::Japanese => Some(era::JAPANESE_ERA), - AnyCalendarKind::Persian => Some(era::PERSIAN_ERA), - AnyCalendarKind::Roc => Some(era::ROC_ERA), - _ => None, - } - } - pub(crate) fn calendar_has_eras(kind: AnyCalendarKind) -> bool { match kind { AnyCalendarKind::Buddhist diff --git a/deps/temporal/src/builtins/core/calendar/era.rs b/deps/temporal/src/builtins/core/calendar/era.rs deleted file mode 100644 index 5b732abc2fd9d2..00000000000000 --- a/deps/temporal/src/builtins/core/calendar/era.rs +++ /dev/null @@ -1,159 +0,0 @@ -//! Calendar Eras constants - -// The general source for this implementation as of 2024-08-28 is the intl-era-monthcode proposal. -// -// As this source is currently a proposal, its content are subject to change, so full era support -// should be viewed as experimental. -// -// Source: https://tc39.es/proposal-intl-era-monthcode/ - -// TODO (0.1.0): Feature flag certain eras as experimental - -use core::ops::RangeInclusive; - -#[cfg(test)] -use icu_calendar::AnyCalendarKind; -use tinystr::{tinystr, TinyAsciiStr}; - -/// Relevant Era info. -pub(crate) struct EraInfo { - pub(crate) name: TinyAsciiStr<16>, - pub(crate) range: RangeInclusive, - pub(crate) arithmetic_year: ArithmeticYear, -} - -/// The way to map an era to an extended year -pub(crate) enum ArithmeticYear { - // This era is the default era, 1 ERA = 1 ArithmeticYear - DefaultEra, - // This era is a non-default era like reiwa, 1 ERA = offset ArithmeticYear - Offset(i32), - // This era is an inverse era like BC, 0 ERA = -1 ArithmeticYear - Inverse, -} - -impl EraInfo { - pub(crate) fn arithmetic_year_for(&self, era_year: i32) -> i32 { - match self.arithmetic_year { - ArithmeticYear::DefaultEra => era_year, - ArithmeticYear::Offset(offset) => offset + era_year - 1, - ArithmeticYear::Inverse => 1 - era_year, - } - } -} - -macro_rules! era_identifier { - ($name:literal) => { - tinystr!(19, $name) - }; -} - -macro_rules! valid_era { - ($name:literal, $range:expr, $ext:expr ) => { - EraInfo { - name: tinystr!(16, $name), - range: $range, - arithmetic_year: $ext, - } - }; - ($name:literal, $range:expr ) => { - valid_era!($name, $range, ArithmeticYear::DefaultEra) - }; -} - -pub(crate) const ETHIOPIC_ERA_IDENTIFIERS: [TinyAsciiStr<19>; 2] = - [era_identifier!("am"), era_identifier!("incar")]; - -pub(crate) const ETHIOPIC_ETHOPICAA_ERA_IDENTIFIERS: [TinyAsciiStr<19>; 2] = - [era_identifier!("aa"), era_identifier!("mundi")]; - -pub(crate) const ETHIOAA_ERA_IDENTIFIERS: [TinyAsciiStr<19>; 2] = - [era_identifier!("aa"), era_identifier!("mundi")]; - -pub(crate) const GREGORY_ERA_IDENTIFIERS: [TinyAsciiStr<19>; 2] = - [era_identifier!("ce"), era_identifier!("ad")]; - -pub(crate) const GREGORY_INVERSE_ERA_IDENTIFIERS: [TinyAsciiStr<19>; 2] = - [era_identifier!("bc"), era_identifier!("bce")]; -pub(crate) const JAPANESE_ERA_IDENTIFIERS: [TinyAsciiStr<19>; 2] = - [era_identifier!("ce"), era_identifier!("ad")]; - -pub(crate) const JAPANESE_INVERSE_ERA_IDENTIFIERS: [TinyAsciiStr<19>; 2] = - [era_identifier!("bc"), era_identifier!("bce")]; - -// NOTE: The below currently might not align 100% with ICU4X. -// TODO: Update to align with ICU4X depending on any Era updates. -pub(crate) const BUDDHIST_ERA: EraInfo = valid_era!("be", i32::MIN..=i32::MAX); -pub(crate) const COPTIC_ERA: EraInfo = valid_era!("am", 1..=i32::MAX); -pub(crate) const ETHIOPIC_ERA: EraInfo = valid_era!("am", 1..=i32::MAX); -pub(crate) const ETHIOPIC_ETHIOAA_ERA: EraInfo = - valid_era!("aa", i32::MIN..=5500, ArithmeticYear::Offset(-5499)); -pub(crate) const ETHIOAA_ERA: EraInfo = valid_era!("aa", i32::MIN..=i32::MAX); -pub(crate) const GREGORY_ERA: EraInfo = valid_era!("ce", 1..=i32::MAX); -pub(crate) const GREGORY_INVERSE_ERA: EraInfo = - valid_era!("bce", 1..=i32::MAX, ArithmeticYear::Inverse); -pub(crate) const HEBREW_ERA: EraInfo = valid_era!("am", i32::MIN..=i32::MAX); -pub(crate) const INDIAN_ERA: EraInfo = valid_era!("shaka", i32::MIN..=i32::MAX); -pub(crate) const ISLAMIC_ERA: EraInfo = valid_era!("ah", i32::MIN..=i32::MAX); -pub(crate) const ISLAMIC_INVERSE_ERA: EraInfo = - valid_era!("bh", i32::MIN..=i32::MAX, ArithmeticYear::Inverse); -pub(crate) const HEISEI_ERA: EraInfo = valid_era!("heisei", 1..=31, ArithmeticYear::Offset(1989)); -pub(crate) const JAPANESE_ERA: EraInfo = valid_era!("ce", 1..=1868); -pub(crate) const JAPANESE_INVERSE_ERA: EraInfo = - valid_era!("bce", 1..=i32::MAX, ArithmeticYear::Inverse); -pub(crate) const MEIJI_ERA: EraInfo = valid_era!("meiji", 1..=45, ArithmeticYear::Offset(1868)); -pub(crate) const REIWA_ERA: EraInfo = - valid_era!("reiwa", 1..=i32::MAX, ArithmeticYear::Offset(2019)); -pub(crate) const SHOWA_ERA: EraInfo = valid_era!("showa", 1..=64, ArithmeticYear::Offset(1926)); -pub(crate) const TAISHO_ERA: EraInfo = valid_era!("taisho", 1..=45, ArithmeticYear::Offset(1912)); -pub(crate) const PERSIAN_ERA: EraInfo = valid_era!("ap", i32::MIN..=i32::MAX); -pub(crate) const ROC_ERA: EraInfo = valid_era!("roc", 1..=i32::MAX); -pub(crate) const ROC_INVERSE_ERA: EraInfo = - valid_era!("broc", 1..=i32::MAX, ArithmeticYear::Inverse); - -#[cfg(test)] -/// https://tc39.es/proposal-intl-era-monthcode/#sec-temporal-calendarsupportsera -pub(crate) const ALL_ALLOWED_ERAS: &[(AnyCalendarKind, &[EraInfo])] = &[ - (AnyCalendarKind::Buddhist, &[BUDDHIST_ERA]), - (AnyCalendarKind::Coptic, &[COPTIC_ERA]), - ( - AnyCalendarKind::Ethiopian, - &[ETHIOPIC_ERA, ETHIOPIC_ETHIOAA_ERA], - ), - (AnyCalendarKind::EthiopianAmeteAlem, &[ETHIOAA_ERA]), - ( - AnyCalendarKind::Gregorian, - &[GREGORY_ERA, GREGORY_INVERSE_ERA], - ), - (AnyCalendarKind::Hebrew, &[HEBREW_ERA]), - (AnyCalendarKind::Indian, &[INDIAN_ERA]), - ( - AnyCalendarKind::HijriSimulatedMecca, - &[ISLAMIC_ERA, ISLAMIC_INVERSE_ERA], - ), - ( - AnyCalendarKind::HijriTabularTypeIIFriday, - &[ISLAMIC_ERA, ISLAMIC_INVERSE_ERA], - ), - ( - AnyCalendarKind::HijriTabularTypeIIThursday, - &[ISLAMIC_ERA, ISLAMIC_INVERSE_ERA], - ), - ( - AnyCalendarKind::HijriUmmAlQura, - &[ISLAMIC_ERA, ISLAMIC_INVERSE_ERA], - ), - ( - AnyCalendarKind::Japanese, - &[ - JAPANESE_ERA, - JAPANESE_INVERSE_ERA, - MEIJI_ERA, - REIWA_ERA, - SHOWA_ERA, - TAISHO_ERA, - ], - ), - (AnyCalendarKind::Persian, &[PERSIAN_ERA]), - (AnyCalendarKind::Roc, &[ROC_ERA, ROC_INVERSE_ERA]), -]; diff --git a/deps/temporal/src/builtins/core/calendar/fields.rs b/deps/temporal/src/builtins/core/calendar/fields.rs index 334693afff11e3..9c19016349e4b3 100644 --- a/deps/temporal/src/builtins/core/calendar/fields.rs +++ b/deps/temporal/src/builtins/core/calendar/fields.rs @@ -1,9 +1,8 @@ use tinystr::TinyAsciiStr; -use super::types::month_to_month_code; use crate::{ - error::ErrorMessage, options::Overflow, Calendar, MonthCode, PlainDate, PlainDateTime, - PlainMonthDay, PlainYearMonth, TemporalError, TemporalResult, + error::ErrorMessage, Calendar, MonthCode, PlainDate, PlainDateTime, PlainMonthDay, + PlainYearMonth, TemporalError, TemporalResult, }; use core::ops::Range; @@ -286,7 +285,7 @@ impl YearMonthCalendarFields { #[macro_export] macro_rules! impl_with_fallback_method { ($method_name:ident, $fields_type:ident, ( $(with_day: $day:ident)? ) $component_type:ty) => { - pub(crate) fn $method_name(&self, fallback: &$component_type, calendar: icu_calendar::AnyCalendarKind, overflow: Overflow) -> TemporalResult { + pub(crate) fn $method_name(&self, fallback: &$component_type, calendar: icu_calendar::AnyCalendarKind) -> TemporalResult { let keys_to_ignore = self.field_keys_to_ignore(calendar); let mut era = self.era; @@ -312,28 +311,15 @@ macro_rules! impl_with_fallback_method { } } - let (month, month_code) = match (self.month, self.month_code) { - (Some(month), Some(mc)) => (Some(month), Some(mc)), - (Some(month), None) => { - let month_maybe_clamped = if overflow == Overflow::Constrain { - // TODO (manishearth) this should be managed by ICU4X - // https://github.com/unicode-org/icu4x/issues/6790 - month.clamp(1, 12) - } else { - month - }; - - (Some(month_maybe_clamped), Some(month_to_month_code(month_maybe_clamped)?)) - } - (None, Some(mc)) => (Some(mc.to_month_integer()).map(Into::into), Some(mc)), - (None, None) if !keys_to_ignore.month => ( - Some(fallback.month()).map(Into::into), - Some(fallback.month_code()), - ), - // This should currently be unreachable, but it may change as CalendarFieldKeysToIgnore - // changes - (None, None) => (None, None) - }; + let month = self.month; + let mut month_code = self.month_code; + + // We only want to fall back if neither a month nor a month code were specified + // and then we only want to fall back with the month code (in case the year is being replaced!) + if month.is_none() && month_code.is_none() && !keys_to_ignore.month { + month_code = Some(fallback.month_code()); + } + #[allow(clippy::needless_update)] { Ok(Self { year, diff --git a/deps/temporal/src/builtins/core/calendar/types.rs b/deps/temporal/src/builtins/core/calendar/types.rs index b396b57230aeb8..ecac06e2f5c1a5 100644 --- a/deps/temporal/src/builtins/core/calendar/types.rs +++ b/deps/temporal/src/builtins/core/calendar/types.rs @@ -6,7 +6,6 @@ use tinystr::TinyAsciiStr; use crate::fields::CalendarFields; use crate::iso::{constrain_iso_day, is_valid_iso_day}; use crate::options::Overflow; -use crate::Calendar; use crate::{TemporalError, TemporalResult}; use icu_calendar::AnyCalendarKind; @@ -20,344 +19,87 @@ pub enum ResolutionType { /// `ResolvedCalendarFields` represents the resolved field values necessary for /// creating a Date from potentially partial values. #[derive(Debug)] -pub struct ResolvedCalendarFields { - pub(crate) era_year: EraYear, - pub(crate) month_code: MonthCode, +pub struct ResolvedIsoFields { + pub(crate) arithmetic_year: i32, + pub(crate) month: u8, pub(crate) day: u8, } -impl ResolvedCalendarFields { +impl ResolvedIsoFields { // TODO: Potentially make a method on `Calendar`. + /// #[inline] pub fn try_from_fields( - calendar: &Calendar, fields: &CalendarFields, overflow: Overflow, resolve_type: ResolutionType, ) -> TemporalResult { fields.check_year_in_safe_arithmetical_range()?; - let era_year = EraYear::try_from_fields(calendar, fields, resolve_type)?; - if calendar.is_iso() { - let month_code = resolve_iso_month(calendar, fields, overflow)?; - let day = resolve_day( - fields.day, - resolve_type == ResolutionType::YearMonth, - &era_year, - month_code, - calendar, - )?; - let day = if overflow == Overflow::Constrain { - constrain_iso_day(era_year.year, month_code.to_month_integer(), day) - } else { - if !is_valid_iso_day(era_year.year, month_code.to_month_integer(), day) { - return Err( - TemporalError::range().with_message("day value is not in a valid range.") - ); - } - day - }; - return Ok(Self { - era_year, - month_code, - day, - }); - } - - let month_code = MonthCode::try_from_fields(calendar, fields)?; - let day = resolve_day( - fields.day, - resolve_type == ResolutionType::YearMonth, - &era_year, - month_code, - calendar, - )?; - - Ok(Self { - era_year, - month_code, - day, - }) - } -} - -fn resolve_day( - day: Option, - is_year_month: bool, - year: &EraYear, - month_code: MonthCode, - calendar: &Calendar, -) -> TemporalResult { - if is_year_month { - if calendar.kind() == AnyCalendarKind::Japanese { - Ok( - match (year.arithmetic_year, month_code.to_month_integer()) { - // Meiji begins Oct 23, 1868 - (1868, 10) => 23, - // Taisho begins Jul 30, 1912 - (1912, 7) => 30, - // Showa begins Dec 12, 1926 - (1926, 12) => 25, - // Heisei begins 8 Jan 1989 - (1989, 1) => 8, - // Reiwa begins 1 May 2019 - (2019, 5) => 1, - _ => 1, - }, - ) + // a. If type is date or year-month and fields.[[Year]] is unset, throw a TypeError exception. + let arithmetic_year = if resolve_type == ResolutionType::MonthDay { + 1972 } else { - // PlainYearMonth construction paths all *require* setting the day to the first day of the month. - // See https://tc39.es/proposal-temporal/#sec-temporal-calendaryearmonthfromfields - Ok(1) - } - } else { - day.ok_or(TemporalError::r#type().with_message("Required day field is empty.")) - } -} - -#[derive(Debug)] -pub struct Era(pub(crate) TinyAsciiStr<16>); - -// TODO(Manishearth) We should just be using arithmetic_year unconditionally. -// so that https://github.com/boa-dev/temporal/issues/448 is handled. -// -// However, ICU4X has some bugs -// (https://github.com/unicode-org/icu4x/pull/6762/, https://github.com/unicode-org/icu4x/pull/6800) -// so for now we store both. -#[derive(Debug)] -pub struct EraYear { - pub(crate) era: Option, - pub(crate) year: i32, - pub(crate) arithmetic_year: i32, -} + // ISO does not look at era/eraYear at all + fields + .year + .ok_or(TemporalError::r#type().with_message("Required year field is empty."))? + }; + // b. If type is date or month-day and fields.[[Day]] is unset, throw a TypeError exception. + let day = if resolve_type == ResolutionType::YearMonth { + 1 + } else { + fields + .day + .ok_or(TemporalError::r#type().with_message("Required day field is empty."))? + }; -impl EraYear { - pub(crate) fn try_from_fields( - calendar: &Calendar, - partial: &CalendarFields, - resolution_type: ResolutionType, - ) -> TemporalResult { - match (partial.year, partial.era, partial.era_year) { - _ if resolution_type == ResolutionType::MonthDay => { - let day = partial - .day - .ok_or(TemporalError::r#type().with_message("MonthDay must specify day"))?; - - let arithmetic_year = Self::reference_arithmetic_year_for_month_day( - calendar, - partial.month_code, - day, - )?; - Ok(Self { - // We should just specify these as arithmetic years, no need - // to muck with eras - era: None, - arithmetic_year, - year: arithmetic_year, - }) - } - (maybe_year, Some(era), Some(era_year)) => { - let Some(era_info) = calendar.get_era_info(&era) else { - return Err(TemporalError::range().with_message("Invalid era provided.")); - }; - if !era_info.range.contains(&era_year) { + let mut month = match (fields.month, fields.month_code) { + (Some(month), None) => month, + (ordinal, Some(code)) => { + code.validate(AnyCalendarKind::Iso)?; + if code.is_leap_month() { return Err(TemporalError::range() - .with_message("Year is not valid for the provided era")); + .with_message("No leap months allowed for ISO calendar")); } - let calculated_arith = era_info.arithmetic_year_for(era_year); - // or a RangeError exception if the fields are sufficient but their values are internally inconsistent - // within the calendar (e.g., when fields such as [[Month]] and [[MonthCode]] have conflicting non-unset values). For example: - if let Some(arith) = maybe_year { - if calculated_arith != arith { + let found_ordinal = code.to_month_integer(); + + if let Some(ordinal) = ordinal { + if ordinal != found_ordinal { return Err( - TemporalError::range().with_message("Conflicting year/eraYear info") + TemporalError::range().with_message("Month does not match monthCode.") ); } } - Ok(Self { - year: era_year, - era: Some(Era(era_info.name)), - arithmetic_year: calculated_arith, - }) + found_ordinal } - (Some(year), None, None) => Ok(Self { - era: calendar.get_calendar_default_era().map(|e| Era(e.name)), - year, - arithmetic_year: year, - }), - _ => Err(TemporalError::r#type() - .with_message("Required fields missing to determine an era and year.")), - } - } - - fn reference_arithmetic_year_for_month_day( - calendar: &Calendar, - month_code: Option, - day: u8, - ) -> TemporalResult { - // For simple calendars without leap days - // (or if leap days have already been handled) - // This needs the date of 1972-12-31 represented in that calendar - fn threshold(month: u8, day: u8, dec_31_1972: (i32, u8, u8)) -> i32 { - // If it's after the day of dec 31 in the primary reference year, - // go one year earlier - if month == dec_31_1972.1 && day > dec_31_1972.2 || month > dec_31_1972.1 { - dec_31_1972.0 - 1 - } else { - // Return the primary reference year - dec_31_1972.0 - } - } - // For simple calendars with a single leap day. - // This needs the date of 1972-12-31 represented in that calendar, the month-day of the leap day, - // and the first reference year where the leap day occurs on or before 1972-12-31 - fn threshold_with_leap_day( - month: u8, - day: u8, - dec_31_1972: (i32, u8, u8), - leap_day: (u8, u8), - leap_year: i32, - ) -> i32 { - // If it's a leap day, just return the leap year - if (month, day) == leap_day { - leap_year - } else { - threshold(month, day, dec_31_1972) - } - } - - let kind = calendar.kind(); - - // This behavior is required by tests, but is not yet specced. - // https://github.com/tc39/proposal-intl-era-monthcode/issues/60 - let Some(month_code) = month_code else { - if kind == AnyCalendarKind::Iso { - return Ok(1972); - } else { + (None, None) => { return Err(TemporalError::r#type() - .with_message("MonthDay must be created with a monthCode for non-ISO")); + .with_message("Required month/monthCode field is empty.")) } }; - // The reference date is the latest ISO 8601 date corresponding to the calendar date, that is also earlier than - // or equal to the ISO 8601 date December 31, 1972. If that calendar date never occurs on or before the ISO 8601 date December 31, 1972, - // then the reference date is the earliest ISO 8601 date corresponding to that calendar date. - // The reference year is almost always 1972 (the first ISO 8601 leap year after the epoch), with exceptions - // for calendars where some dates (e.g. leap days or days in leap months) didn't occur during that ISO 8601 year. - // For example, Hebrew calendar leap month Adar I occurred in calendar years 5730 and 5733 (respectively overlapping - // ISO 8601 February/March 1970 and February/March 1973), but did not occur between them, so the reference year for days of that month is 1970. - - Ok(match calendar.kind() { - AnyCalendarKind::Iso | AnyCalendarKind::Gregorian => 1972, - // These calendars just wrap Gregorian with a different epoch - AnyCalendarKind::Buddhist => 1972 + 543, - AnyCalendarKind::Roc => 1972 - 1911, - - AnyCalendarKind::Indian => { - let month = month_code.to_month_integer(); - threshold_with_leap_day(month, day, (1894, 10, 10), (1, 30), 1984) - } - AnyCalendarKind::Persian => { - let month = month_code.to_month_integer(); - threshold_with_leap_day(month, day, (1351, 10, 10), (12, 30), 1350) - } - AnyCalendarKind::HijriTabularTypeIIFriday => { - let month = month_code.to_month_integer(); - threshold_with_leap_day(month, day, (1392, 11, 25), (12, 30), 1390) - } - AnyCalendarKind::HijriTabularTypeIIThursday => { - let month = month_code.to_month_integer(); - threshold_with_leap_day(month, day, (1392, 11, 26), (12, 30), 1390) - } - AnyCalendarKind::Coptic => { - let month = month_code.to_month_integer(); - threshold_with_leap_day(month, day, (1689, 4, 22), (13, 6), 1687) - } - AnyCalendarKind::Ethiopian => { - let month = month_code.to_month_integer(); - threshold_with_leap_day(month, day, (1965, 4, 22), (13, 6), 1963) - } - AnyCalendarKind::EthiopianAmeteAlem => { - let month = month_code.to_month_integer(); - threshold_with_leap_day(month, day, (7465, 4, 22), (13, 6), 7463) - } - AnyCalendarKind::Hebrew => { - // 1972-12-31 is y=5733 am, m=4, d=26. We must produce year 5732 or lower - if month_code.is_leap_month() { - // 5730 is a leap year - 5730 - } else { - let month = month_code.to_month_integer(); - if (month == 4 && day == 26) || month > 4 { - // 5733 will produce dates after 1972, return 5732 instead - 5732 - } else { - // All months have 29 days - if day <= 29 { - 5733 - // Ḥeshvan/Kislev only have 30 days sometimes - // Fortunately 5732 has 30 days for both - } else if month == 2 || month == 3 { - 5732 - } else { - // Some other month, we don't actually need to check - 5733 - } - } - } + if !(1..=12).contains(&month) { + if overflow == Overflow::Constrain { + month = if month > 12 { 12 } else { 1 }; + } else { + return Err(TemporalError::range().with_message("Month out of range.")); } + } - // TODO(Manishearth) Chinese, Dangi, waiting on https://github.com/unicode-org/icu4x/pull/6762 - - // These lunar calendars are iffier: The ones above are mathematically defined, - // the algorithm for these may change. This data may need to be updated on occasion. - AnyCalendarKind::HijriUmmAlQura => { - let month = month_code.to_month_integer(); - if day < 30 { - threshold(month, day, (1392, 11, 25)) - } else { - match month { - 1 => 1392, - 2 => 1390, - 3 => 1391, - 4 => 1392, - 5 => 1391, - 6 => 1392, - 7 => 1389, - 8 => 1392, - 9 => 1392, - 10 => 1390, - 11 => 1391, - 12 => 1390, - _ => 1392, - } - } - } - AnyCalendarKind::HijriSimulatedMecca => { - let month = month_code.to_month_integer(); - if day < 30 { - threshold(month, day, (1392, 11, 24)) - } else { - match month { - 1 => 1390, - 2 => 1391, - 3 => 1392, - 4 => 1391, - 5 => 1390, - 6 => 1392, - 7 => 1392, - 8 => 1392, - 9 => 1390, - 10 => 1392, - 11 => 1390, - 12 => 1391, - _ => 1392, - } - } - } - _ => { - return Err(TemporalError::range() - .with_message("Do not currently support MonthDay with this calendar")) + let day = if overflow == Overflow::Constrain { + constrain_iso_day(arithmetic_year, month, day) + } else { + if !is_valid_iso_day(arithmetic_year, month, day) { + return Err( + TemporalError::range().with_message("day value is not in a valid range.") + ); } + day + }; + Ok(Self { + arithmetic_year, + month, + day, }) } } @@ -397,7 +139,7 @@ const MONTH_THIRTEEN: TinyAsciiStr<4> = tinystr!(4, "M13"); pub struct MonthCode(pub(crate) TinyAsciiStr<4>); impl MonthCode { - pub(crate) fn validate(&self, calendar: &Calendar) -> TemporalResult<()> { + pub(crate) fn validate(&self, calendar: AnyCalendarKind) -> TemporalResult<()> { const COMMON_MONTH_CODES: [TinyAsciiStr<4>; 12] = [ MONTH_ONE, MONTH_TWO, @@ -432,50 +174,22 @@ impl MonthCode { return Ok(()); } - match calendar.identifier() { - "chinese" | "dangi" if LUNAR_LEAP_MONTHS.contains(&self.0) => Ok(()), - "coptic" | "ethiopic" | "ethiopicaa" if MONTH_THIRTEEN == self.0 => Ok(()), - "hebrew" if MONTH_FIVE_LEAP == self.0 => Ok(()), - _ => Err(TemporalError::range() - .with_message("MonthCode was not valid for the current calendar.")), - } - } - - pub(crate) fn try_from_fields( - calendar: &Calendar, - fields: &CalendarFields, - ) -> TemporalResult { - match fields { - CalendarFields { - month: Some(month), - month_code: None, - .. - } => { - // TODO(manishearth) this is incorrect, - // see https://github.com/unicode-org/icu4x/issues/6790 - let month_code = month_to_month_code(*month)?; - month_code.validate(calendar)?; - Ok(month_code) + match calendar { + AnyCalendarKind::Chinese | AnyCalendarKind::Dangi + if LUNAR_LEAP_MONTHS.contains(&self.0) => + { + Ok(()) } - CalendarFields { - month_code: Some(month_code), - month: None, - .. - } => { - month_code.validate(calendar)?; - Ok(*month_code) + AnyCalendarKind::Coptic + | AnyCalendarKind::Ethiopian + | AnyCalendarKind::EthiopianAmeteAlem + if MONTH_THIRTEEN == self.0 => + { + Ok(()) } - CalendarFields { - month: Some(month), - month_code: Some(month_code), - .. - } => { - are_month_and_month_code_resolvable(*month, month_code)?; - month_code.validate(calendar)?; - Ok(*month_code) - } - _ => Err(TemporalError::r#type() - .with_message("Month or monthCode is required to determine date.")), + AnyCalendarKind::Hebrew if MONTH_FIVE_LEAP == self.0 => Ok(()), + _ => Err(TemporalError::range() + .with_message("MonthCode was not valid for the current calendar.")), } } @@ -542,6 +256,7 @@ impl core::str::FromStr for MonthCode { // NOTE: This is a greedy function, should handle differently for all calendars. #[inline] +#[cfg(test)] pub(crate) fn month_to_month_code(month: u8) -> TemporalResult { if !(1..=13).contains(&month) { return Err(TemporalError::range().with_message("Month not in a valid range.")); @@ -553,13 +268,6 @@ pub(crate) fn month_to_month_code(month: u8) -> TemporalResult { Ok(MonthCode(tinystr)) } -#[inline] -fn are_month_and_month_code_resolvable(_month: u8, _mc: &MonthCode) -> TemporalResult<()> { - // TODO(Manishearth) month is an ordinal month, this check needs year/calendar info - // https://github.com/unicode-org/icu4x/issues/6790 - Ok(()) -} - // Potentially greedy. Need to verify for all calendars that // the month code integer aligns with the month integer, which // may require calendar info @@ -578,54 +286,21 @@ const fn ascii_digit_to_int(ascii_digit: u8) -> u8 { ascii_digit - 48 } -fn resolve_iso_month( - calendar: &Calendar, - fields: &CalendarFields, - overflow: Overflow, -) -> TemporalResult { - let month_code = match (fields.month_code, fields.month) { - (None, None) => { - return Err(TemporalError::r#type().with_message("Month or monthCode must be provided.")) - } - (None, Some(month)) => { - if overflow == Overflow::Constrain { - return month_to_month_code(month.clamp(1, 12)); - } - if !(1..=12).contains(&month) { - return Err( - TemporalError::range().with_message("month value is not in a valid range.") - ); - } - month_to_month_code(month)? - } - (Some(month_code), None) => month_code, - (Some(month_code), Some(month)) => { - if month != month_code.to_month_integer() { - return Err(TemporalError::range() - .with_message("month and monthCode could not be resolved.")); - } - month_code - } - }; - month_code.validate(calendar)?; - Ok(month_code) -} - #[cfg(test)] mod tests { use core::str::FromStr; - use tinystr::{tinystr, TinyAsciiStr}; + use tinystr::tinystr; use crate::{ builtins::{ calendar::{types::ResolutionType, CalendarFields}, - core::{calendar::Calendar, PartialDate, PlainDate}, + core::calendar::Calendar, }, options::Overflow, }; - use super::{month_to_month_code, MonthCode, ResolvedCalendarFields}; + use super::{MonthCode, ResolvedIsoFields}; #[test] fn valid_month_code() { @@ -651,18 +326,6 @@ mod tests { let _ = MonthCode::from_str("M1L").unwrap_err(); } - #[test] - fn month_to_mc() { - let mc = month_to_month_code(1).unwrap(); - assert_eq!(mc.as_str(), "M01"); - - let mc = month_to_month_code(13).unwrap(); - assert_eq!(mc.as_str(), "M13"); - - let _ = month_to_month_code(0).unwrap_err(); - let _ = month_to_month_code(14).unwrap_err(); - } - #[test] fn day_overflow_test() { let bad_fields = CalendarFields { @@ -680,69 +343,6 @@ mod tests { assert!(result.is_ok()); } - #[test] - fn self_consistent_era_year() { - use crate::builtins::core::calendar::era::ALL_ALLOWED_ERAS; - use icu_calendar::AnyCalendarKind; - - for (cal, eras) in ALL_ALLOWED_ERAS { - for era in *eras { - let expect_str = alloc::format!("Trying {cal:?} with era {}", era.name); - let mut calendar_fields = CalendarFields::new(); - - // We want to pick some valid date. year=1 month=1, day=1 is valid for basically - // all calendars except for Japanese, which has mid-year eras. For Japanese we pick December 31 instead - if *cal == AnyCalendarKind::Japanese { - calendar_fields.month = Some(12); - calendar_fields.day = Some(31); - } else { - calendar_fields.month = Some(1); - calendar_fields.day = Some(1); - } - calendar_fields.era = Some(TinyAsciiStr::from_str(&era.name).unwrap()); - calendar_fields.era_year = Some(1); - let partial = PartialDate { - calendar_fields, - calendar: Calendar::new(*cal), - }; - - let plain_date = - PlainDate::from_partial(partial, Some(Overflow::Constrain)).expect(&expect_str); - - assert_eq!( - plain_date.year(), - era.arithmetic_year_for(1), - "Mismatched year/eraYear for {cal:?} and {}", - era.name - ); - - // Get the full partial date. - let full_partial = CalendarFields::default() - .with_fallback_date(&plain_date, *cal, Overflow::Constrain) - .expect(&expect_str); - - let era_year = super::EraYear::try_from_fields( - &Calendar::new(*cal), - &full_partial, - ResolutionType::Date, - ) - .expect(&expect_str); - - assert_eq!( - &*era_year.era.expect("only testing calendars with era").0, - &*era.name, - "Backcalculated era must match" - ); - assert_eq!(era_year.year, 1, "Backcalculated era must match"); - assert_eq!( - era_year.arithmetic_year, - plain_date.year(), - "Backcalculated arithmetic_year must match" - ); - } - } - } - #[test] fn unresolved_month_and_month_code() { let bad_fields = CalendarFields { @@ -753,12 +353,8 @@ mod tests { ..Default::default() }; - let err = ResolvedCalendarFields::try_from_fields( - &Calendar::ISO, - &bad_fields, - Overflow::Reject, - ResolutionType::Date, - ); + let err = + ResolvedIsoFields::try_from_fields(&bad_fields, Overflow::Reject, ResolutionType::Date); assert!(err.is_err()); } @@ -770,21 +366,13 @@ mod tests { ..Default::default() }; - let err = ResolvedCalendarFields::try_from_fields( - &Calendar::ISO, - &bad_fields, - Overflow::Reject, - ResolutionType::Date, - ); + let err = + ResolvedIsoFields::try_from_fields(&bad_fields, Overflow::Reject, ResolutionType::Date); assert!(err.is_err()); let bad_fields = CalendarFields::default(); - let err = ResolvedCalendarFields::try_from_fields( - &Calendar::ISO, - &bad_fields, - Overflow::Reject, - ResolutionType::Date, - ); + let err = + ResolvedIsoFields::try_from_fields(&bad_fields, Overflow::Reject, ResolutionType::Date); assert!(err.is_err()); } } diff --git a/deps/temporal/src/builtins/core/duration.rs b/deps/temporal/src/builtins/core/duration.rs index fc19e7912cfb6c..9062e29dc1a017 100644 --- a/deps/temporal/src/builtins/core/duration.rs +++ b/deps/temporal/src/builtins/core/duration.rs @@ -389,8 +389,21 @@ impl Duration { hours, minutes, seconds, + + // https://github.com/boa-dev/temporal/issues/613 + // With float64_representable_durations enabled, force all smaller units + // to be in the float64-representable range. + #[cfg(feature = "float64_representable_durations")] + milliseconds: milliseconds as f64 as u64, + #[cfg(feature = "float64_representable_durations")] + microseconds: microseconds as f64 as u128, + #[cfg(feature = "float64_representable_durations")] + nanoseconds: nanoseconds as f64 as u128, + #[cfg(not(feature = "float64_representable_durations"))] milliseconds, + #[cfg(not(feature = "float64_representable_durations"))] microseconds, + #[cfg(not(feature = "float64_representable_durations"))] nanoseconds, } } @@ -636,7 +649,7 @@ impl Duration { microseconds, nanoseconds, ) { - return Err(TemporalError::range().with_message("Duration was not valid.")); + return Err(TemporalError::range().with_enum(ErrorMessage::DurationNotValid)); } let sign = duration_sign(&[ years, @@ -830,7 +843,7 @@ impl Duration { &self, other: &Duration, relative_to: Option, - provider: &impl TimeZoneProvider, + provider: &(impl TimeZoneProvider + ?Sized), ) -> TemporalResult { if self == other { return Ok(Ordering::Equal); @@ -1054,7 +1067,7 @@ impl Duration { &self, options: RoundingOptions, relative_to: Option, - provider: &impl TimeZoneProvider, + provider: &(impl TimeZoneProvider + ?Sized), ) -> TemporalResult { // NOTE(HalidOdat): Steps 1-12 are handled before calling the function. // @@ -1286,7 +1299,7 @@ impl Duration { &self, unit: Unit, relative_to: Option, - provider: &impl TimeZoneProvider, + provider: &(impl TimeZoneProvider + ?Sized), // Review question what is the return type of duration.prototye.total? ) -> TemporalResult { match relative_to { diff --git a/deps/temporal/src/builtins/core/duration/normalized.rs b/deps/temporal/src/builtins/core/duration/normalized.rs index fcd2292425c195..26819f99d71dea 100644 --- a/deps/temporal/src/builtins/core/duration/normalized.rs +++ b/deps/temporal/src/builtins/core/duration/normalized.rs @@ -3,15 +3,19 @@ use core::{cmp, num::NonZeroU128, ops::Add}; use num_traits::AsPrimitive; +use timezone_provider::epoch_nanoseconds::EpochNanoseconds; use crate::{ - builtins::core::{time_zone::TimeZone, PlainDate, PlainDateTime}, + builtins::{ + core::{time_zone::TimeZone, PlainDate, PlainDateTime}, + duration::TWO_POWER_FIFTY_THREE, + }, iso::{IsoDate, IsoDateTime}, options::{ Disambiguation, Overflow, ResolvedRoundingOptions, RoundingIncrement, RoundingMode, Unit, UNIT_VALUE_TABLE, }, - primitive::FiniteF64, + primitive::{DoubleDouble, FiniteF64}, provider::TimeZoneProvider, rounding::IncrementRounder, Calendar, TemporalError, TemporalResult, TemporalUnwrap, NS_PER_DAY, NS_PER_DAY_NONZERO, @@ -20,6 +24,7 @@ use crate::{ use super::{DateDuration, Duration, Sign}; const MAX_TIME_DURATION: i128 = 9_007_199_254_740_991_999_999_999; +const MAX_SAFE_INTEGER: i128 = TWO_POWER_FIFTY_THREE - 1; // Nanoseconds constants @@ -170,7 +175,7 @@ impl TimeDuration { // 2. NOTE: The following step cannot be implemented directly using floating-point arithmetic when 𝔽(timeDuration) is not a safe integer. // The division can be implemented in C++ with the __float128 type if the compiler supports it, or with software emulation such as in the SoftFP library. // 3. Return timeDuration / divisor. - DurationTotal::new(time_duration, unit_nanoseconds.get() as u64).to_fractional_total() + Ok(Fraction::new(time_duration, unit_nanoseconds.get() as f64).to_finite_f64()) } pub(crate) fn round_to_fractional_days( @@ -228,29 +233,55 @@ impl Add for TimeDuration { } } -// Struct to handle division steps in `TotalTimeDuration` -struct DurationTotal { - quotient: i128, - remainder: i128, - unit_nanoseconds: u64, +// Struct to fractional division steps in `TotalTimeDuration` +struct Fraction { + numerator: i128, + denominator: f64, } -impl DurationTotal { - pub fn new(time_duration: i128, unit_nanoseconds: u64) -> Self { - let quotient = time_duration.div_euclid(unit_nanoseconds as i128); - let remainder = time_duration.rem_euclid(unit_nanoseconds as i128); - +impl Fraction { + pub fn new(numerator: i128, denominator: f64) -> Self { Self { - quotient, - remainder, - unit_nanoseconds, + numerator, + denominator, + } + } + + // NOTE: Functionally similar to SM and JSC's `fractionToDouble` + // + // For more information on this implementation, see the + // JavaScriptCore's [fractionToDouble.cpp](https://github.com/WebKit/WebKit/blob/main/Source/JavaScriptCore/runtime/FractionToDouble.cpp) + // or SpiderMonkey's [FractionToDouble](https://github.com/mozilla-firefox/firefox/blob/main/js/src/builtin/temporal/Temporal.cpp#L683) + // + // The JavaScriptCore implementation is recommended as it has fairly robust documentation + // on the underlying papers that have informed this approach. + /// Calculate an `f64` from a numerator and denominator that may + /// be beyond the max safe integer range. + pub(crate) fn to_finite_f64(&self) -> FiniteF64 { + if self.denominator == 1. { + return FiniteF64(self.numerator as f64); // This operation is lossy. + } + if self.numerator.abs() < MAX_SAFE_INTEGER { + return FiniteF64(self.numerator as f64 / self.denominator); } + self.to_finite_f64_slow() } - pub(crate) fn to_fractional_total(&self) -> TemporalResult { - let fractional = FiniteF64::try_from(self.remainder)? - .checked_div(&FiniteF64::try_from(self.unit_nanoseconds)?)?; - FiniteF64::try_from(self.quotient)?.checked_add(&fractional) + /// The slow path for calculating a `f64` beyond the max safe integer range. + #[cold] + pub(crate) fn to_finite_f64_slow(&self) -> FiniteF64 { + let dd_numerator = DoubleDouble::from(self.numerator); + // First approx quotient + let q0 = dd_numerator.hi / self.denominator; + // Find remainder + let product = DoubleDouble::mul(q0, self.denominator); + let remainder = DoubleDouble::sum(dd_numerator.hi, -product.hi); + + // Find second approx. quotient + let error = remainder.lo + dd_numerator.lo - product.lo; + let q1 = (remainder.hi + error) / self.denominator; + + FiniteF64(q0 + q1) } } @@ -370,9 +401,10 @@ impl InternalDurationRecord { fn nudge_calendar_unit( &self, sign: Sign, + origin_epoch_ns: EpochNanoseconds, dest_epoch_ns: i128, dt: &PlainDateTime, - time_zone: Option<(&TimeZone, &impl TimeZoneProvider)>, // ??? + time_zone: Option<(&TimeZone, &(impl TimeZoneProvider + ?Sized))>, // ??? options: ResolvedRoundingOptions, ) -> TemporalResult { // NOTE: r2 may never be used...need to test. @@ -570,33 +602,48 @@ impl InternalDurationRecord { } }; - // 7. Let start be ? CalendarDateAdd(calendar, isoDateTime.[[ISODate]], startDuration, constrain). - let start = dt - .calendar() - .date_add(&dt.iso.date, &start_duration, Overflow::Constrain)?; + let start_epoch_ns = if r1 == 0 { + origin_epoch_ns + } else { + // 7. Let start be ? CalendarDateAdd(calendar, isoDateTime.[[ISODate]], startDuration, constrain). + let start = + dt.calendar() + .date_add(&dt.iso.date, &start_duration, Overflow::Constrain)?; + // 9. Let startDateTime be CombineISODateAndTimeRecord(start, isoDateTime.[[Time]]). + let start_date_time = IsoDateTime::new_unchecked(start.iso, dt.iso.time); + if let Some((time_zone, provider)) = time_zone { + time_zone + .get_epoch_nanoseconds_for( + start_date_time, + Disambiguation::Compatible, + provider, + )? + .ns + } else { + start_date_time.as_nanoseconds() + } + }; + // 8. Let end be ? CalendarDateAdd(calendar, isoDateTime.[[ISODate]], endDuration, constrain). let end = dt .calendar() .date_add(&dt.iso.date, &end_duration, Overflow::Constrain)?; - // 9. Let startDateTime be CombineISODateAndTimeRecord(start, isoDateTime.[[Time]]). - let start = IsoDateTime::new_unchecked(start.iso, dt.iso.time); + // 10. Let endDateTime be CombineISODateAndTimeRecord(end, isoDateTime.[[Time]]). let end = IsoDateTime::new_unchecked(end.iso, dt.iso.time); // 12. Else, - let (start_epoch_ns, end_epoch_ns) = if let Some((time_zone, provider)) = time_zone { + let end_epoch_ns = if let Some((time_zone, provider)) = time_zone { // a. Let startEpochNs be ? GetEpochNanosecondsFor(timeZone, startDateTime, compatible). // b. Let endEpochNs be ? GetEpochNanosecondsFor(timeZone, endDateTime, compatible). - let start_epoch_ns = - time_zone.get_epoch_nanoseconds_for(start, Disambiguation::Compatible, provider)?; - let end_epoch_ns = - time_zone.get_epoch_nanoseconds_for(end, Disambiguation::Compatible, provider)?; - (start_epoch_ns.ns, end_epoch_ns.ns) + time_zone + .get_epoch_nanoseconds_for(end, Disambiguation::Compatible, provider)? + .ns // 11. If timeZoneRec is unset, then } else { // a. Let startEpochNs be GetUTCEpochNanoseconds(start.[[Year]], start.[[Month]], start.[[Day]], start.[[Hour]], start.[[Minute]], start.[[Second]], start.[[Millisecond]], start.[[Microsecond]], start.[[Nanosecond]]). // b. Let endEpochNs be GetUTCEpochNanoseconds(end.[[Year]], end.[[Month]], end.[[Day]], end.[[Hour]], end.[[Minute]], end.[[Second]], end.[[Millisecond]], end.[[Microsecond]], end.[[Nanosecond]]). - (start.as_nanoseconds(), end.as_nanoseconds()) + end.as_nanoseconds() }; // TODO: look into handling asserts @@ -660,7 +707,7 @@ impl InternalDurationRecord { dt: &PlainDateTime, time_zone: &TimeZone, options: ResolvedRoundingOptions, - provider: &impl TimeZoneProvider, + provider: &(impl TimeZoneProvider + ?Sized), ) -> TemporalResult { let d = self.date(); // 1.Let start be ? CalendarDateAdd(calendar, isoDateTime.[[ISODate]], duration.[[Date]], constrain). @@ -822,7 +869,7 @@ impl InternalDurationRecord { sign: Sign, nudged_epoch_ns: i128, iso_date_time: &IsoDateTime, - time_zone: Option<(&TimeZone, &impl TimeZoneProvider)>, + time_zone: Option<(&TimeZone, &(impl TimeZoneProvider + ?Sized))>, calendar: &Calendar, largest_unit: Unit, smallest_unit: Unit, @@ -954,9 +1001,10 @@ impl InternalDurationRecord { #[inline] pub(crate) fn round_relative_duration( &self, + origin_epoch_ns: EpochNanoseconds, dest_epoch_ns: i128, dt: &PlainDateTime, - time_zone: Option<(&TimeZone, &impl TimeZoneProvider)>, + time_zone: Option<(&TimeZone, &(impl TimeZoneProvider + ?Sized))>, options: ResolvedRoundingOptions, ) -> TemporalResult { let duration = *self; @@ -974,7 +1022,14 @@ impl InternalDurationRecord { let nudge_result = if irregular_length_unit { // a. Let record be ? NudgeToCalendarUnit(sign, duration, destEpochNs, isoDateTime, timeZone, calendar, increment, smallestUnit, roundingMode). // b. Let nudgeResult be record.[[NudgeResult]]. - duration.nudge_calendar_unit(sign, dest_epoch_ns, dt, time_zone, options)? + duration.nudge_calendar_unit( + sign, + origin_epoch_ns, + dest_epoch_ns, + dt, + time_zone, + options, + )? } else if let Some((time_zone, time_zone_provider)) = time_zone { // 6. Else if timeZone is not unset, then // a. Let nudgeResult be ? NudgeToZonedTime(sign, duration, isoDateTime, timeZone, calendar, increment, smallestUnit, roundingMode). @@ -1012,9 +1067,10 @@ impl InternalDurationRecord { // 7.5.38 TotalRelativeDuration ( duration, destEpochNs, isoDateTime, timeZone, calendar, unit ) pub(crate) fn total_relative_duration( &self, + origin_epoch_ns: EpochNanoseconds, dest_epoch_ns: i128, dt: &PlainDateTime, - time_zone: Option<(&TimeZone, &impl TimeZoneProvider)>, + time_zone: Option<(&TimeZone, &(impl TimeZoneProvider + ?Sized))>, unit: Unit, ) -> TemporalResult { // 1. If IsCalendarUnit(unit) is true, or timeZone is not unset and unit is day, then @@ -1024,6 +1080,7 @@ impl InternalDurationRecord { // b. Let record be ? NudgeToCalendarUnit(sign, duration, destEpochNs, isoDateTime, timeZone, calendar, 1, unit, trunc). let record = self.nudge_calendar_unit( sign, + origin_epoch_ns, dest_epoch_ns, dt, time_zone, diff --git a/deps/temporal/src/builtins/core/duration/tests.rs b/deps/temporal/src/builtins/core/duration/tests.rs index 6ef0453e11792f..c5931d98496a17 100644 --- a/deps/temporal/src/builtins/core/duration/tests.rs +++ b/deps/temporal/src/builtins/core/duration/tests.rs @@ -73,6 +73,12 @@ fn duration_to_string_auto_precision() { .as_temporal_string(ToStringRoundingOptions::default()) .unwrap(); assert_eq!(&result, "P1Y2M3W4DT5H6M7.98765S"); + + let duration = Duration::new(0, 0, 0, 2, 0, 0, 0, 0, 0, 1).unwrap(); + let result = duration + .as_temporal_string(ToStringRoundingOptions::default()) + .unwrap(); + assert_eq!(&result, "P2DT0.000000001S"); } #[test] @@ -153,10 +159,9 @@ fn negative_fields_to_string() { #[test] fn preserve_precision_loss() { - const MAX_SAFE_INT: i64 = 9_007_199_254_740_991; let duration = Duration::from_partial_duration(PartialDuration { - milliseconds: Some(MAX_SAFE_INT), - microseconds: Some(MAX_SAFE_INT as i128), + milliseconds: Some(MAX_SAFE_INTEGER), + microseconds: Some(MAX_SAFE_INTEGER as i128), ..Default::default() }) .unwrap(); @@ -192,8 +197,6 @@ fn duration_from_str() { #[test] fn duration_max_safe() { - const MAX_SAFE_INTEGER: i64 = 9007199254740991; - // From test262 built-ins/Temporal/Duration/prototype/subtract/result-out-of-range-3.js assert!(Duration::new(0, 0, 0, 0, 0, 0, 0, 0, 9_007_199_254_740_991_926_258, 0).is_err()); @@ -398,23 +401,54 @@ fn test_duration_compare() { ) } } -/* -TODO: Uncomment -The below test should fail, but currently doesn't. This has to do with weird -floating point math in IsValidDuration Step 6-8 that defers to C++ std::remquo - -Needs further clarification. +const MAX_SAFE_INTEGER: i64 = 9_007_199_254_740_991; #[test] fn duration_round_out_of_range_norm_conversion() { - const MAX_SAFE_INT: i64 = 9_007_199_254_740_991; - let duration = Duration::new(0, 0, 0, 0, 0, 0, MAX_SAFE_INT, 0, 0, 999_999_999).unwrap(); - let err = duration.round_with_provider( RoundingOptions { - largest_unit: Some(Unit::Nanosecond), - increment: Some(RoundingIncrement::ONE), - ..Default::default() - }, None, &NeverProvider::default()); + let duration = Duration::new(0, 0, 0, 0, 0, 0, MAX_SAFE_INTEGER, 0, 0, 999_999_999).unwrap(); + let err = duration.round_with_provider( + RoundingOptions { + largest_unit: Some(Unit::Nanosecond), + increment: Some(RoundingIncrement::ONE), + ..Default::default() + }, + None, + &NeverProvider::default(), + ); assert!(err.is_err()) } -*/ + +#[test] +#[cfg_attr(not(feature = "float64_representable_durations"), should_panic)] +fn duration_float64_representable() { + // built-ins/Temporal/Duration/prototype/add/float64-representable-integer + let duration = Duration::new(0, 0, 0, 0, 0, 0, 0, 0, MAX_SAFE_INTEGER as i128, 0).unwrap(); + let duration2 = Duration::new(0, 0, 0, 0, 0, 0, 0, 0, MAX_SAFE_INTEGER as i128 - 1, 0).unwrap(); + let added = duration.add(&duration2).unwrap(); + assert_eq!(added.microseconds, 18014398509481980); + assert_eq!( + added.as_temporal_string(Default::default()).unwrap(), + "PT18014398509.48198S" + ); + let one_ms = Duration::new(0, 0, 0, 0, 0, 0, 0, 0, 1, 0).unwrap(); + let added_plus_one = added.add(&one_ms).unwrap(); + assert_eq!( + added, added_plus_one, + "Should not internally use a more accurate representation when adding" + ); +} + +#[test] +#[cfg(feature = "compiled_data")] +fn total_full_numeric_precision() { + // Tests that Duration::total operates without any loss of precision + + // built-ins/Temporal/Duration/prototype/total/precision-exact-mathematical-values-6 + let d = Duration::new(0, 0, 0, 0, 816, 0, 0, 0, 0, 2_049_187_497_660).unwrap(); + assert_eq!(d.total(Unit::Hour, None).unwrap(), 816.56921874935); + + // built-ins/Temporal/Duration/prototype/total/precision-exact-mathematical-values-7 + let d = Duration::new(0, 0, 0, 0, 0, 0, 0, MAX_SAFE_INTEGER + 1, 1999, 0).unwrap(); + assert_eq!(d.total(Unit::Millisecond, None).unwrap(), 9007199254740994.); +} diff --git a/deps/temporal/src/builtins/core/instant.rs b/deps/temporal/src/builtins/core/instant.rs index 3a6a870791ad48..247078fec2f312 100644 --- a/deps/temporal/src/builtins/core/instant.rs +++ b/deps/temporal/src/builtins/core/instant.rs @@ -395,7 +395,7 @@ impl Instant { pub fn to_zoned_date_time_iso_with_provider( &self, time_zone: TimeZone, - provider: &impl TimeZoneProvider, + provider: &(impl TimeZoneProvider + ?Sized), ) -> TemporalResult { ZonedDateTime::new_unchecked_with_provider(*self, time_zone, Calendar::ISO, provider) } @@ -409,7 +409,7 @@ impl Instant { &self, timezone: Option, options: ToStringRoundingOptions, - provider: &impl TimeZoneProvider, + provider: &(impl TimeZoneProvider + ?Sized), ) -> TemporalResult { self.to_ixdtf_writeable_with_provider(timezone, options, provider) .map(|x| x.write_to_string().into()) @@ -420,7 +420,7 @@ impl Instant { &self, timezone: Option, options: ToStringRoundingOptions, - provider: &impl TimeZoneProvider, + provider: &(impl TimeZoneProvider + ?Sized), ) -> TemporalResult { let resolved_options = options.resolve()?; let round = self.round_instant(ResolvedRoundingOptions::from_to_string_options( diff --git a/deps/temporal/src/builtins/core/now.rs b/deps/temporal/src/builtins/core/now.rs index bc640f50f165ec..41a309acd6fc5b 100644 --- a/deps/temporal/src/builtins/core/now.rs +++ b/deps/temporal/src/builtins/core/now.rs @@ -24,7 +24,7 @@ impl Now { pub(crate) fn system_datetime_with_provider( self, time_zone: Option, - provider: &impl TimeZoneProvider, + provider: &(impl TimeZoneProvider + ?Sized), ) -> TemporalResult { let system_nanoseconds = self.host_hooks.get_system_epoch_nanoseconds()?; let time_zone = time_zone.unwrap_or(self.host_hooks.get_system_time_zone(provider)?); @@ -34,7 +34,7 @@ impl Now { /// Converts the current [`Now`] into a [`TimeZone`]. pub fn time_zone_with_provider( self, - provider: &impl TimeZoneProvider, + provider: &(impl TimeZoneProvider + ?Sized), ) -> TemporalResult { self.host_hooks.get_system_time_zone(provider) } @@ -50,7 +50,7 @@ impl Now { pub fn zoned_date_time_iso_with_provider( self, time_zone: Option, - provider: &impl TimeZoneProvider, + provider: &(impl TimeZoneProvider + ?Sized), ) -> TemporalResult { let system_nanoseconds = self.host_hooks.get_system_epoch_nanoseconds()?; let time_zone = time_zone.unwrap_or(self.host_hooks.get_system_time_zone(provider)?); @@ -67,7 +67,7 @@ impl Now { pub fn plain_date_time_iso_with_provider( self, time_zone: Option, - provider: &impl TimeZoneProvider, + provider: &(impl TimeZoneProvider + ?Sized), ) -> TemporalResult { let iso = self.system_datetime_with_provider(time_zone, provider)?; Ok(PlainDateTime::new_unchecked(iso, Calendar::ISO)) @@ -80,7 +80,7 @@ impl Now { pub fn plain_date_iso_with_provider( self, time_zone: Option, - provider: &impl TimeZoneProvider, + provider: &(impl TimeZoneProvider + ?Sized), ) -> TemporalResult { let iso = self.system_datetime_with_provider(time_zone, provider)?; Ok(PlainDate::new_unchecked(iso.date, Calendar::ISO)) @@ -93,7 +93,7 @@ impl Now { pub fn plain_time_with_provider( self, time_zone: Option, - provider: &impl TimeZoneProvider, + provider: &(impl TimeZoneProvider + ?Sized), ) -> TemporalResult { let iso = self.system_datetime_with_provider(time_zone, provider)?; Ok(PlainTime::new_unchecked(iso.time)) @@ -148,7 +148,10 @@ mod tests { } impl HostTimeZone for TestHooks { - fn get_host_time_zone(&self, _: &impl TimeZoneProvider) -> TemporalResult { + fn get_host_time_zone( + &self, + _: &(impl TimeZoneProvider + ?Sized), + ) -> TemporalResult { Ok(self.time_zone) } } diff --git a/deps/temporal/src/builtins/core/plain_date.rs b/deps/temporal/src/builtins/core/plain_date.rs index 90b5c4e4227bc1..31ba19eb5ad74b 100644 --- a/deps/temporal/src/builtins/core/plain_date.rs +++ b/deps/temporal/src/builtins/core/plain_date.rs @@ -279,15 +279,15 @@ impl PlainDate { resolved.smallest_unit == Unit::Day && resolved.increment.get() == 1; // 12. If roundingGranularityIsNoop is false, then if !rounding_granularity_is_noop { + let iso_date_time = IsoDateTime::new_unchecked(self.iso, IsoTime::default()); + let origin_epoch_ns = iso_date_time.as_nanoseconds(); // a. Let destEpochNs be GetUTCEpochNanoseconds(other.[[ISOYear]], other.[[ISOMonth]], other.[[ISODay]], 0, 0, 0, 0, 0, 0). let dest_epoch_ns = other.iso.as_nanoseconds(); // b. Let dateTime be ISO Date-Time Record { [[Year]]: temporalDate.[[ISOYear]], [[Month]]: temporalDate.[[ISOMonth]], [[Day]]: temporalDate.[[ISODay]], [[Hour]]: 0, [[Minute]]: 0, [[Second]]: 0, [[Millisecond]]: 0, [[Microsecond]]: 0, [[Nanosecond]]: 0 }. - let dt = PlainDateTime::new_unchecked( - IsoDateTime::new_unchecked(self.iso, IsoTime::default()), - self.calendar.clone(), - ); + let dt = PlainDateTime::new_unchecked(iso_date_time, self.calendar.clone()); // c. Set duration to ? RoundRelativeDuration(duration, destEpochNs, dateTime, calendarRec, unset, settings.[[LargestUnit]], settings.[[RoundingIncrement]], settings.[[SmallestUnit]], settings.[[RoundingMode]]). duration = duration.round_relative_duration( + origin_epoch_ns, dest_epoch_ns.0, &dt, Option::<(&TimeZone, &NeverProvider)>::None, @@ -446,7 +446,7 @@ impl PlainDate { // 10. Return ? CalendarDateFromFields(calendarRec, fields, resolvedOptions). let overflow = overflow.unwrap_or(Overflow::Constrain); self.calendar.date_from_fields( - fields.with_fallback_date(self, self.calendar.kind(), overflow)?, + fields.with_fallback_date(self, self.calendar.kind())?, overflow, ) } @@ -633,7 +633,7 @@ impl PlainDate { pub fn to_plain_month_day(&self) -> TemporalResult { let overflow = Overflow::Constrain; self.calendar().month_day_from_fields( - CalendarFields::default().with_fallback_date(self, self.calendar.kind(), overflow)?, + CalendarFields::default().with_fallback_date(self, self.calendar.kind())?, overflow, ) } @@ -660,7 +660,7 @@ impl PlainDate { &self, time_zone: TimeZone, plain_time: Option, - provider: &impl TimeZoneProvider, + provider: &(impl TimeZoneProvider + ?Sized), ) -> TemporalResult { // NOTE (nekevss): Steps 1-4 are engine specific let epoch_ns = if let Some(time) = plain_time { diff --git a/deps/temporal/src/builtins/core/plain_date_time.rs b/deps/temporal/src/builtins/core/plain_date_time.rs index 77bdf1b31fd1f5..cfb316ef874337 100644 --- a/deps/temporal/src/builtins/core/plain_date_time.rs +++ b/deps/temporal/src/builtins/core/plain_date_time.rs @@ -311,6 +311,7 @@ impl PlainDateTime { let dest_epoch_ns = other.iso.as_nanoseconds(); // 6. Return ? RoundRelativeDuration(diff, destEpochNs, isoDateTime1, unset, calendar, largestUnit, roundingIncrement, smallestUnit, roundingMode). diff.round_relative_duration( + self.iso.as_nanoseconds(), dest_epoch_ns.0, self, Option::<(&TimeZone, &NeverProvider)>::None, @@ -335,10 +336,12 @@ impl PlainDateTime { if unit == Unit::Nanosecond { return FiniteF64::try_from(diff.normalized_time_duration().0); } + let origin_epoch_ns = self.iso.as_nanoseconds(); // 5. Let destEpochNs be GetUTCEpochNanoseconds(isoDateTime2). let dest_epoch_ns = other.iso.as_nanoseconds(); // 6. Return ? TotalRelativeDuration(diff, destEpochNs, isoDateTime1, unset, calendar, unit). diff.total_relative_duration( + origin_epoch_ns, dest_epoch_ns.0, self, Option::<(&TimeZone, &NeverProvider)>::None, @@ -649,7 +652,7 @@ impl PlainDateTime { let result_date = self.calendar.date_from_fields( fields .calendar_fields - .with_fallback_datetime(self, self.calendar.kind(), overflow)?, + .with_fallback_datetime(self, self.calendar.kind())?, overflow, )?; @@ -892,7 +895,7 @@ impl PlainDateTime { &self, time_zone: TimeZone, disambiguation: Disambiguation, - provider: &impl TimeZoneProvider, + provider: &(impl TimeZoneProvider + ?Sized), ) -> TemporalResult { // 6. Let epochNs be ? GetEpochNanosecondsFor(timeZone, dateTime.[[ISODateTime]], disambiguation). let epoch_ns = time_zone.get_epoch_nanoseconds_for(self.iso, disambiguation, provider)?; @@ -1309,6 +1312,24 @@ mod tests { assert_eq!(result.minutes(), 30); } + #[test] + fn dt_since_conflicting_signs() { + // From intl402/Temporal/PlainDateTime/prototype/since/wrapping-at-end-of-month-gregorian + // Tests that date arithmetic with conflicting signs works + let a = PlainDateTime::try_new(2023, 3, 1, 2, 0, 0, 0, 0, 0, Calendar::GREGORIAN).unwrap(); + let b = PlainDateTime::try_new(2023, 1, 1, 3, 0, 0, 0, 0, 0, Calendar::GREGORIAN).unwrap(); + + let settings = DifferenceSettings { + largest_unit: Some(Unit::Year), + ..Default::default() + }; + let result = a.since(&b, settings).unwrap(); + + assert_eq!(result.months(), 1); + assert_eq!(result.days(), 30); + assert_eq!(result.hours(), 23); + } + #[test] fn dt_round_basic() { let assert_datetime = diff --git a/deps/temporal/src/builtins/core/plain_month_day.rs b/deps/temporal/src/builtins/core/plain_month_day.rs index b60372bce468c6..15cf3e06158272 100644 --- a/deps/temporal/src/builtins/core/plain_month_day.rs +++ b/deps/temporal/src/builtins/core/plain_month_day.rs @@ -353,7 +353,7 @@ impl PlainMonthDay { pub fn epoch_ns_for_with_provider( &self, time_zone: TimeZone, - provider: &impl TimeZoneProvider, + provider: &(impl TimeZoneProvider + ?Sized), ) -> TemporalResult { // 2. Let isoDateTime be CombineISODateAndTimeRecord(temporalYearMonth.[[ISODate]], NoonTimeRecord()). let iso = IsoDateTime::new(self.iso, IsoTime::noon())?; @@ -528,34 +528,30 @@ mod tests { #[test] /// This test is for calendars where we don't wish to hardcode dates; but we do wish to know - /// that monthcodes can be constructed without issue - fn automated_reference_year() { + /// that monthcodes can be constructed without issue (currently only UAQ) + fn automated_uaq_reference_year() { let reference_iso = IsoDate::new_unchecked(1972, 12, 31); - for cal in [ - AnyCalendarKind::HijriSimulatedMecca, - AnyCalendarKind::HijriUmmAlQura, - ] { - let calendar = Calendar::new(cal); - for month in 1..=12 { - for day in [29, 30] { - let month_code = crate::builtins::calendar::month_to_month_code(month).unwrap(); - - let calendar_fields = CalendarFields { - month_code: Some(month_code), - day: Some(day), - ..Default::default() - }; - - let md = calendar - .month_day_from_fields(calendar_fields, Overflow::Reject) - .unwrap(); - - assert!( - md.iso <= reference_iso, - "Reference ISO for {month}-{day} must be before 1972-12-31, found, {:?}", - md.iso, - ); - } + + let calendar = Calendar::new(AnyCalendarKind::HijriUmmAlQura); + for month in 1..=12 { + for day in [29, 30] { + let month_code = crate::builtins::calendar::month_to_month_code(month).unwrap(); + + let calendar_fields = CalendarFields { + month_code: Some(month_code), + day: Some(day), + ..Default::default() + }; + + let md = calendar + .month_day_from_fields(calendar_fields, Overflow::Reject) + .unwrap(); + + assert!( + md.iso <= reference_iso, + "Reference ISO for {month}-{day} must be before 1972-12-31, found, {:?}", + md.iso, + ); } } } diff --git a/deps/temporal/src/builtins/core/plain_year_month.rs b/deps/temporal/src/builtins/core/plain_year_month.rs index 5a9047f82d6876..c61d69ed7f00b4 100644 --- a/deps/temporal/src/builtins/core/plain_year_month.rs +++ b/deps/temporal/src/builtins/core/plain_year_month.rs @@ -329,6 +329,7 @@ impl PlainYearMonth { let dest_epoch_ns = target_iso_date_time.as_nanoseconds(); // d. Set duration to ? RoundRelativeDuration(duration, destEpochNs, isoDateTime, unset, calendar, resolved.[[LargestUnit]], resolved.[[RoundingIncrement]], resolved.[[SmallestUnit]], resolved.[[RoundingMode]]). duration = duration.round_relative_duration( + iso_date_time.as_nanoseconds(), dest_epoch_ns.as_i128(), &PlainDateTime::new_unchecked(iso_date_time, self.calendar.clone()), Option::<(&TimeZone, &NeverProvider)>::None, @@ -548,7 +549,7 @@ impl PlainYearMonth { // 11. Return ! CreateTemporalYearMonth(isoDate, calendar). let overflow = overflow.unwrap_or(Overflow::Constrain); self.calendar.year_month_from_fields( - fields.with_fallback_year_month(self, self.calendar.kind(), overflow)?, + fields.with_fallback_year_month(self, self.calendar.kind())?, overflow, ) } @@ -615,7 +616,7 @@ impl PlainYearMonth { pub fn epoch_ns_for_with_provider( &self, time_zone: TimeZone, - provider: &impl TimeZoneProvider, + provider: &(impl TimeZoneProvider + ?Sized), ) -> TemporalResult { // 2. Let isoDateTime be CombineISODateAndTimeRecord(temporalYearMonth.[[ISODate]], NoonTimeRecord()). let iso = IsoDateTime::new(self.iso, IsoTime::noon())?; @@ -1079,18 +1080,20 @@ mod tests { #[test] fn test_reference_day() { + // Note: Japanese reference days are also day 1 even at era boundaries + // https://github.com/tc39/proposal-temporal/issues/3150 assert_eq!( PlainYearMonth::from_str("1868-10-30[u-ca=japanese]") .unwrap() .reference_day(), - 23 + 1 ); // Still happens for dates that are in the previous era but same month assert_eq!( PlainYearMonth::from_str("1868-10-20[u-ca=japanese]") .unwrap() .reference_day(), - 23 + 1 ); // Won't happen for dates in other months assert_eq!( diff --git a/deps/temporal/src/builtins/core/time_zone.rs b/deps/temporal/src/builtins/core/time_zone.rs index e791f341729261..8a2e40df8af1ab 100644 --- a/deps/temporal/src/builtins/core/time_zone.rs +++ b/deps/temporal/src/builtins/core/time_zone.rs @@ -172,7 +172,7 @@ impl TimeZone { #[inline] pub(crate) fn from_time_zone_record( record: TimeZoneRecord, - provider: &impl TimeZoneProvider, + provider: &(impl TimeZoneProvider + ?Sized), ) -> TemporalResult { let timezone = match record { TimeZoneRecord::Name(name) => TimeZone::IanaIdentifier(provider.get(name)?), @@ -190,7 +190,7 @@ impl TimeZone { /// Parses a `TimeZone` from a provided `&str`. pub fn try_from_identifier_str_with_provider( identifier: &str, - provider: &impl TimeZoneProvider, + provider: &(impl TimeZoneProvider + ?Sized), ) -> TemporalResult { parse_identifier(identifier).map(|tz| match tz { TimeZoneRecord::Name(name) => Ok(TimeZone::IanaIdentifier(provider.get(name)?)), @@ -210,7 +210,7 @@ impl TimeZone { /// This is the equivalent to [`ParseTemporalTimeZoneString`](https://tc39.es/proposal-temporal/#sec-temporal-parsetemporaltimezonestring) pub fn try_from_str_with_provider( src: &str, - provider: &impl TimeZoneProvider, + provider: &(impl TimeZoneProvider + ?Sized), ) -> TemporalResult { if let Ok(timezone) = Self::try_from_identifier_str_with_provider(src, provider) { return Ok(timezone); @@ -227,7 +227,7 @@ impl TimeZone { /// Returns the current `TimeZoneSlot`'s identifier. pub fn identifier_with_provider( &self, - provider: &impl TimeZoneProvider, + provider: &(impl TimeZoneProvider + ?Sized), ) -> TemporalResult { Ok(match self { TimeZone::IanaIdentifier(s) => provider.identifier(*s)?.into(), @@ -244,7 +244,7 @@ impl TimeZone { /// Get the primary identifier for this timezone pub fn primary_identifier_with_provider( &self, - provider: &impl TimeZoneProvider, + provider: &(impl TimeZoneProvider + ?Sized), ) -> TemporalResult { Ok(match self { TimeZone::IanaIdentifier(s) => TimeZone::IanaIdentifier(provider.canonicalized(*s)?), @@ -262,7 +262,7 @@ impl TimeZone { pub(crate) fn time_zone_equals_with_provider( &self, other: &Self, - provider: &impl TimeZoneProvider, + provider: &(impl TimeZoneProvider + ?Sized), ) -> TemporalResult { Ok(match (self, other) { (TimeZone::IanaIdentifier(one), TimeZone::IanaIdentifier(two)) => { @@ -282,7 +282,7 @@ impl TimeZone { } /// Get the primary identifier for this timezone - pub fn utc_with_provider(provider: &impl TimeZoneProvider) -> Self { + pub fn utc_with_provider(provider: &(impl TimeZoneProvider + ?Sized)) -> Self { Self::IanaIdentifier(provider.get(b"UTC").unwrap_or_default()) } } @@ -303,7 +303,7 @@ impl TimeZone { pub(crate) fn get_iso_datetime_for( &self, instant: &Instant, - provider: &impl TimeZoneProvider, + provider: &(impl TimeZoneProvider + ?Sized), ) -> TemporalResult { // 1. Let offsetNanoseconds be GetOffsetNanosecondsFor(timeZone, epochNs). let nanos = self.get_offset_nanos_for(instant.as_i128(), provider)?; @@ -321,7 +321,7 @@ impl TimeZone { pub(crate) fn get_offset_nanos_for( &self, utc_epoch: i128, - provider: &impl TimeZoneProvider, + provider: &(impl TimeZoneProvider + ?Sized), ) -> TemporalResult { // 1. Let parseResult be ! ParseTimeZoneIdentifier(timeZone). match self { @@ -340,7 +340,7 @@ impl TimeZone { pub(crate) fn get_utc_offset_for( &self, utc_epoch: i128, - provider: &impl TimeZoneProvider, + provider: &(impl TimeZoneProvider + ?Sized), ) -> TemporalResult { let offset = self.get_offset_nanos_for(utc_epoch, provider)?; let offset = i64::try_from(offset).ok().temporal_unwrap()?; @@ -351,7 +351,7 @@ impl TimeZone { &self, local_iso: IsoDateTime, disambiguation: Disambiguation, - provider: &impl TimeZoneProvider, + provider: &(impl TimeZoneProvider + ?Sized), ) -> TemporalResult { // 1. Let possibleEpochNs be ? GetPossibleEpochNanoseconds(timeZone, isoDateTime). let possible_nanos = self.get_possible_epoch_ns_for(local_iso, provider)?; @@ -363,7 +363,7 @@ impl TimeZone { pub(crate) fn get_possible_epoch_ns_for( &self, local_iso: IsoDateTime, - provider: &impl TimeZoneProvider, + provider: &(impl TimeZoneProvider + ?Sized), ) -> TemporalResult { // 1.Let parseResult be ! ParseTimeZoneIdentifier(timeZone). let possible_nanoseconds = match self { @@ -442,7 +442,7 @@ impl TimeZone { nanos: CandidateEpochNanoseconds, iso: IsoDateTime, disambiguation: Disambiguation, - provider: &impl TimeZoneProvider, + provider: &(impl TimeZoneProvider + ?Sized), ) -> TemporalResult { // 1. Let n be possibleEpochNs's length. let valid_bounds = match nanos { @@ -556,7 +556,7 @@ impl TimeZone { pub(crate) fn get_start_of_day( &self, iso_date: &IsoDate, - provider: &impl TimeZoneProvider, + provider: &(impl TimeZoneProvider + ?Sized), ) -> TemporalResult { // 1. Let isoDateTime be CombineISODateAndTimeRecord(isoDate, MidnightTimeRecord()). let iso = IsoDateTime::new_unchecked(*iso_date, IsoTime::default()); diff --git a/deps/temporal/src/builtins/core/zoned_date_time.rs b/deps/temporal/src/builtins/core/zoned_date_time.rs index 38cc1fc6aa6197..93fe43724278ac 100644 --- a/deps/temporal/src/builtins/core/zoned_date_time.rs +++ b/deps/temporal/src/builtins/core/zoned_date_time.rs @@ -283,7 +283,7 @@ impl ZonedDateTime { instant: Instant, time_zone: TimeZone, calendar: Calendar, - provider: &impl TimeZoneProvider, + provider: &(impl TimeZoneProvider + ?Sized), ) -> TemporalResult { let offset = time_zone .get_utc_offset_for(instant.epoch_nanoseconds().0, provider) @@ -307,7 +307,7 @@ impl ZonedDateTime { &self, duration: InternalDurationRecord, overflow: Overflow, - provider: &impl TimeZoneProvider, + provider: &(impl TimeZoneProvider + ?Sized), ) -> TemporalResult { // 1. If DateDurationSign(duration.[[Date]]) = 0, then if duration.date().sign() == Sign::Zero { @@ -349,7 +349,7 @@ impl ZonedDateTime { &self, duration: &Duration, overflow: Overflow, - provider: &impl TimeZoneProvider, + provider: &(impl TimeZoneProvider + ?Sized), ) -> TemporalResult { // 1. Let duration be ? ToTemporalDuration(temporalDurationLike). // 2. If operation is subtract, set duration to CreateNegatedTemporalDuration(duration). @@ -375,7 +375,7 @@ impl ZonedDateTime { &self, other: &Instant, resolved_options: ResolvedRoundingOptions, - provider: &impl TimeZoneProvider, + provider: &(impl TimeZoneProvider + ?Sized), ) -> TemporalResult { // 1. If UnitCategory(largestUnit) is time, then if resolved_options.largest_unit.is_time_unit() { @@ -394,6 +394,7 @@ impl ZonedDateTime { let iso = self.get_iso_datetime(); // 5. Return ? RoundRelativeDuration(difference, ns2, dateTime, timeZone, calendar, largestUnit, roundingIncrement, smallestUnit, roundingMode). diff.round_relative_duration( + *self.epoch_nanoseconds(), other.epoch_nanoseconds().as_i128(), &PlainDateTime::new_unchecked(iso, self.calendar().clone()), Some((self.time_zone(), provider)), @@ -406,7 +407,7 @@ impl ZonedDateTime { &self, other: &Instant, unit: Unit, - provider: &impl TimeZoneProvider, + provider: &(impl TimeZoneProvider + ?Sized), ) -> TemporalResult { // 1. If UnitCategory(unit) is time, then if unit.is_time_unit() { @@ -425,6 +426,7 @@ impl ZonedDateTime { let iso = self.get_iso_datetime(); // 4. Return ? TotalRelativeDuration(difference, ns2, dateTime, timeZone, calendar, unit). diff.total_relative_duration( + *self.epoch_nanoseconds(), other.epoch_nanoseconds().as_i128(), &PlainDateTime::new_unchecked(iso, self.calendar().clone()), Some((self.time_zone(), provider)), @@ -436,7 +438,7 @@ impl ZonedDateTime { &self, other: &Instant, largest_unit: Unit, - provider: &impl TimeZoneProvider, + provider: &(impl TimeZoneProvider + ?Sized), ) -> TemporalResult { // 1. If ns1 = ns2, return CombineDateAndTimeDuration(ZeroDateDuration(), 0). if self.epoch_nanoseconds() == other.epoch_nanoseconds() { @@ -446,29 +448,39 @@ impl ZonedDateTime { let start = self.get_iso_datetime(); // 3. Let endDateTime be GetISODateTimeFor(timeZone, ns2). let end = self.time_zone.get_iso_datetime_for(other, provider)?; - // 4. If ns2 - ns1 < 0, let sign be -1; else let sign be 1. + // 4. If CompareISODate(startDateTime.[[ISODate]], endDateTime.[[ISODate]]) = 0, then + if start.date == end.date { + // a. Let timeDuration be TimeDurationFromEpochNanosecondsDifference(ns2, ns1). + let time_duration = TimeDuration::from_nanosecond_difference( + other.epoch_nanoseconds().as_i128(), + self.epoch_nanoseconds().as_i128(), + )?; + // b. Return CombineDateAndTimeDuration(ZeroDateDuration(), timeDuration). + return InternalDurationRecord::new(Default::default(), time_duration); + } + // 5. If ns2 - ns1 < 0, let sign be -1; else let sign be 1. let sign = if other.epoch_nanoseconds().as_i128() - self.epoch_nanoseconds().as_i128() < 0 { Sign::Negative } else { Sign::Positive }; - // 5. If sign = 1, let maxDayCorrection be 2; else let maxDayCorrection be 1. + // 6. If sign = 1, let maxDayCorrection be 2; else let maxDayCorrection be 1. let max_correction = if sign == Sign::Positive { 2 } else { 1 }; - // 6. Let dayCorrection be 0. - // 7. Let timeDuration be DifferenceTime(startDateTime.[[Time]], endDateTime.[[Time]]). + // 7. Let dayCorrection be 0. + // 8. Let timeDuration be DifferenceTime(startDateTime.[[Time]], endDateTime.[[Time]]). let time = start.time.diff(&end.time); - // 8. If TimeDurationSign(timeDuration) = -sign, set dayCorrection to dayCorrection + 1. + // 9. If TimeDurationSign(timeDuration) = -sign, set dayCorrection to dayCorrection + 1. let mut day_correction = if time.sign() as i8 == -(sign as i8) { 1 } else { 0 }; - // 9. Let success be false. + // 10. Let success be false. let mut intermediate_dt = IsoDateTime::default(); let mut time_duration = TimeDuration::default(); let mut is_success = false; - // 10. Repeat, while dayCorrection ≤ maxDayCorrection and success is false, + // 11. Repeat, while dayCorrection ≤ maxDayCorrection and success is false, while day_correction <= max_correction && !is_success { // a. Let intermediateDate be BalanceISODate(endDateTime.[[ISODate]].[[Year]], // endDateTime.[[ISODate]].[[Month]], endDateTime.[[ISODate]].[[Day]] - dayCorrection × sign). @@ -500,14 +512,15 @@ impl ZonedDateTime { // g. Set dayCorrection to dayCorrection + 1. day_correction += 1; } - // 11. Assert: success is true. - // 12. Let dateLargestUnit be LargerOfTwoUnits(largestUnit, day). + // 12. Assert: success is true. + // 13. Let dateLargestUnit be LargerOfTwoUnits(largestUnit, day). let date_largest = largest_unit.max(Unit::Day); - // 13. Let dateDifference be CalendarDateUntil(calendar, startDateTime.[[ISODate]], intermediateDateTime.[[ISODate]], dateLargestUnit). - // 14. Return CombineDateAndTimeDuration(dateDifference, timeDuration). + // 14. Let dateDifference be CalendarDateUntil(calendar, startDateTime.[[ISODate]], intermediateDateTime.[[ISODate]], dateLargestUnit). + // 15. Return CombineDateAndTimeDuration(dateDifference, timeDuration). let date_diff = self.calendar() .date_until(&start.date, &intermediate_dt.date, date_largest)?; + InternalDurationRecord::new(date_diff.date(), time_duration) } @@ -517,7 +530,7 @@ impl ZonedDateTime { op: DifferenceOperation, other: &Self, options: DifferenceSettings, - provider: &impl TimeZoneProvider, + provider: &(impl TimeZoneProvider + ?Sized), ) -> TemporalResult { // NOTE: for order of operations, this should be asserted prior to this point // by any engine implementors, but asserting out of caution. @@ -590,7 +603,7 @@ impl ZonedDateTime { nanos: i128, time_zone: TimeZone, calendar: Calendar, - provider: &impl TimeZoneProvider, + provider: &(impl TimeZoneProvider + ?Sized), ) -> TemporalResult { let instant = Instant::try_new(nanos)?; Self::new_unchecked_with_provider(instant, time_zone, calendar, provider) @@ -618,7 +631,7 @@ impl ZonedDateTime { pub fn try_new_iso_with_provider( nanos: i128, time_zone: TimeZone, - provider: &impl TimeZoneProvider, + provider: &(impl TimeZoneProvider + ?Sized), ) -> TemporalResult { let instant = Instant::try_new(nanos)?; Self::new_unchecked_with_provider(instant, time_zone, Calendar::ISO, provider) @@ -630,7 +643,7 @@ impl ZonedDateTime { instant: Instant, time_zone: TimeZone, calendar: Calendar, - provider: &impl TimeZoneProvider, + provider: &(impl TimeZoneProvider + ?Sized), ) -> TemporalResult { Self::new_unchecked_with_provider(instant, time_zone, calendar, provider) } @@ -640,7 +653,7 @@ impl ZonedDateTime { pub fn try_new_iso_from_instant_with_provider( instant: Instant, time_zone: TimeZone, - provider: &impl TimeZoneProvider, + provider: &(impl TimeZoneProvider + ?Sized), ) -> TemporalResult { Self::new_unchecked_with_provider(instant, time_zone, Calendar::ISO, provider) } @@ -666,7 +679,7 @@ impl ZonedDateTime { overflow: Option, disambiguation: Option, offset_option: Option, - provider: &impl TimeZoneProvider, + provider: &(impl TimeZoneProvider + ?Sized), ) -> TemporalResult { let overflow = overflow.unwrap_or(Overflow::Constrain); let disambiguation = disambiguation.unwrap_or(Disambiguation::Compatible); @@ -729,7 +742,7 @@ impl ZonedDateTime { disambiguation: Option, offset_option: Option, overflow: Option, - provider: &impl TimeZoneProvider, + provider: &(impl TimeZoneProvider + ?Sized), ) -> TemporalResult { let overflow = overflow.unwrap_or_default(); let disambiguation = disambiguation.unwrap_or_default(); @@ -740,11 +753,9 @@ impl ZonedDateTime { // 23. Let dateTimeResult be ? InterpretTemporalDateTimeFields(calendar, fields, overflow). let result_date = self.calendar.date_from_fields( - fields.calendar_fields.with_fallback_datetime( - &plain_date_time, - self.calendar.kind(), - overflow, - )?, + fields + .calendar_fields + .with_fallback_datetime(&plain_date_time, self.calendar.kind())?, overflow, )?; @@ -787,7 +798,7 @@ impl ZonedDateTime { pub fn with_time_zone_with_provider( &self, time_zone: TimeZone, - provider: &impl TimeZoneProvider, + provider: &(impl TimeZoneProvider + ?Sized), ) -> TemporalResult { Self::try_new_with_provider( self.epoch_nanoseconds().as_i128(), @@ -832,7 +843,7 @@ impl ZonedDateTime { pub fn get_time_zone_transition_with_provider( &self, direction: TransitionDirection, - provider: &impl TimeZoneProvider, + provider: &(impl TimeZoneProvider + ?Sized), ) -> TemporalResult> { // 8. If IsOffsetTimeZoneIdentifier(timeZone) is true, return null. let TimeZone::IanaIdentifier(identifier) = self.time_zone else { @@ -874,7 +885,7 @@ impl ZonedDateTime { pub fn hours_in_day_with_provider( &self, - provider: &impl TimeZoneProvider, + provider: &(impl TimeZoneProvider + ?Sized), ) -> TemporalResult { // 1-3. Is engine specific steps // 4. Let isoDateTime be GetISODateTimeFor(timeZone, zonedDateTime.[[EpochNanoseconds]]). @@ -1097,7 +1108,7 @@ impl ZonedDateTime { pub fn with_plain_time_and_provider( &self, time: Option, - provider: &impl TimeZoneProvider, + provider: &(impl TimeZoneProvider + ?Sized), ) -> TemporalResult { let iso = self.get_iso_datetime(); let epoch_ns = if let Some(time) = time { @@ -1123,7 +1134,7 @@ impl ZonedDateTime { &self, duration: &Duration, overflow: Option, - provider: &impl TimeZoneProvider, + provider: &(impl TimeZoneProvider + ?Sized), ) -> TemporalResult { self.add_internal(duration, overflow.unwrap_or(Overflow::Constrain), provider) } @@ -1133,7 +1144,7 @@ impl ZonedDateTime { &self, duration: &Duration, overflow: Option, - provider: &impl TimeZoneProvider, + provider: &(impl TimeZoneProvider + ?Sized), ) -> TemporalResult { self.add_internal( &duration.negated(), @@ -1146,7 +1157,7 @@ impl ZonedDateTime { pub fn equals_with_provider( &self, other: &Self, - provider: &impl TimeZoneProvider, + provider: &(impl TimeZoneProvider + ?Sized), ) -> TemporalResult { // 4. If zonedDateTime.[[EpochNanoseconds]] ≠ other.[[EpochNanoseconds]], return false. if self.instant != other.instant { @@ -1169,7 +1180,7 @@ impl ZonedDateTime { &self, other: &Self, options: DifferenceSettings, - provider: &impl TimeZoneProvider, + provider: &(impl TimeZoneProvider + ?Sized), ) -> TemporalResult { self.diff_internal_with_provider(DifferenceOperation::Since, other, options, provider) } @@ -1179,7 +1190,7 @@ impl ZonedDateTime { &self, other: &Self, options: DifferenceSettings, - provider: &impl TimeZoneProvider, + provider: &(impl TimeZoneProvider + ?Sized), ) -> TemporalResult { self.diff_internal_with_provider(DifferenceOperation::Until, other, options, provider) } @@ -1188,7 +1199,7 @@ impl ZonedDateTime { /// for the current `ZonedDateTime`. pub fn start_of_day_with_provider( &self, - provider: &impl TimeZoneProvider, + provider: &(impl TimeZoneProvider + ?Sized), ) -> TemporalResult { let iso = self.get_iso_datetime(); let epoch_nanos = self.time_zone.get_start_of_day(&iso.date, provider)?; @@ -1221,7 +1232,7 @@ impl ZonedDateTime { /// Creates a default formatted IXDTF (RFC 9557) date/time string for the provided `ZonedDateTime`. pub fn to_string_with_provider( &self, - provider: &impl TimeZoneProvider, + provider: &(impl TimeZoneProvider + ?Sized), ) -> TemporalResult { self.to_ixdtf_string_with_provider( DisplayOffset::Auto, @@ -1236,7 +1247,7 @@ impl ZonedDateTime { pub fn round_with_provider( &self, options: RoundingOptions, - provider: &impl TimeZoneProvider, + provider: &(impl TimeZoneProvider + ?Sized), ) -> TemporalResult { // 1. Let zonedDateTime be the this value. // 2. Perform ? RequireInternalSlot(zonedDateTime, [[InitializedTemporalZonedDateTime]]). @@ -1364,7 +1375,7 @@ impl ZonedDateTime { display_timezone: DisplayTimeZone, display_calendar: DisplayCalendar, options: ToStringRoundingOptions, - provider: &impl TimeZoneProvider, + provider: &(impl TimeZoneProvider + ?Sized), ) -> TemporalResult { let resolved_options = options.resolve()?; let result = @@ -1397,7 +1408,7 @@ impl ZonedDateTime { source: &[u8], disambiguation: Disambiguation, offset_option: OffsetDisambiguation, - provider: &impl TimeZoneProvider, + provider: &(impl TimeZoneProvider + ?Sized), ) -> TemporalResult { let parsed = ParsedZonedDateTime::from_utf8_with_provider(source, provider)?; @@ -1408,7 +1419,7 @@ impl ZonedDateTime { parsed: ParsedZonedDateTime, disambiguation: Disambiguation, offset_option: OffsetDisambiguation, - provider: &impl TimeZoneProvider, + provider: &(impl TimeZoneProvider + ?Sized), ) -> TemporalResult { let date = IsoDate::new_with_overflow( parsed.date.record.year, @@ -1455,7 +1466,7 @@ pub(crate) fn interpret_isodatetime_offset( disambiguation: Disambiguation, offset_option: OffsetDisambiguation, match_minutes: bool, - provider: &impl TimeZoneProvider, + provider: &(impl TimeZoneProvider + ?Sized), ) -> TemporalResult { // 1. If time is start-of-day, then let Some(time) = time else { diff --git a/deps/temporal/src/builtins/core/zoned_date_time/tests.rs b/deps/temporal/src/builtins/core/zoned_date_time/tests.rs index dcb8a3768168a5..26cb8b7a7447cf 100644 --- a/deps/temporal/src/builtins/core/zoned_date_time/tests.rs +++ b/deps/temporal/src/builtins/core/zoned_date_time/tests.rs @@ -488,7 +488,7 @@ fn basic_zdt_add() { fn parse_zdt_with_reject( s: &str, - provider: &impl TimeZoneProvider, + provider: &(impl TimeZoneProvider + ?Sized), ) -> TemporalResult { ZonedDateTime::from_utf8_with_provider( s.as_bytes(), @@ -500,7 +500,7 @@ fn parse_zdt_with_reject( fn parse_zdt_with_compatible( s: &str, - provider: &impl TimeZoneProvider, + provider: &(impl TimeZoneProvider + ?Sized), ) -> TemporalResult { ZonedDateTime::from_utf8_with_provider( s.as_bytes(), @@ -599,7 +599,10 @@ fn test_pacific_niue() { }) } -fn total_seconds_for_one_day(s: &str, provider: &impl TimeZoneProvider) -> TemporalResult { +fn total_seconds_for_one_day( + s: &str, + provider: &(impl TimeZoneProvider + ?Sized), +) -> TemporalResult { Ok(Duration::new(0, 0, 0, 1, 0, 0, 0, 0, 0, 0) .unwrap() .total_with_provider( @@ -645,7 +648,7 @@ fn assert_tr( zdt: &ZonedDateTime, direction: TransitionDirection, s: &str, - provider: &impl TimeZoneProvider, + provider: &(impl TimeZoneProvider + ?Sized), ) { assert_eq!( zdt.get_time_zone_transition_with_provider(direction, provider) @@ -1143,3 +1146,64 @@ fn test_round_to_start_of_day() { assert_eq!(rounded.get_iso_datetime(), known_rounded.get_iso_datetime()); }) } + +#[test] +fn test_same_date_reverse_wallclock() { + // intl402/Temporal/ZonedDateTime/prototype/since/same-date-reverse-wallclock + test_all_providers!(provider: { + let later = + parse_zdt_with_reject("2025-11-02T01:00:00-08:00[America/Vancouver]", provider).unwrap(); + let earlier = + parse_zdt_with_reject("2025-11-02T01:01:00-07:00[America/Vancouver]", provider).unwrap(); + + let diff = DifferenceSettings { + largest_unit: Some(Unit::Year), + smallest_unit: Some(Unit::Millisecond), + ..Default::default() + }; + let duration = later.since_with_provider(&earlier, diff, provider).unwrap(); + assert_eq!(duration.minutes(), 59); + + }) +} + +#[test] +fn test_relativeto_back_transition() { + // intl402/Temporal/Duration/prototype/round/relativeto-dst-back-transition + test_all_providers!(provider: { + let origin = + parse_zdt_with_reject("2025-11-02T01:00:00-08:00[America/Vancouver]", provider).unwrap(); + let duration = Duration::new(0, 0, 0, 0, 11, 39, 0, 0, 0, 0).unwrap(); + + let opts = RoundingOptions { + largest_unit: Some(Unit::Day), + smallest_unit: Some(Unit::Day), + rounding_mode: Some(RoundingMode::HalfExpand), + ..Default::default() + }; + let rounded = duration.round_with_provider(opts, Some(origin.into()), provider).unwrap(); + assert_eq!(rounded.days(), 0); + + }) +} + +#[test] +fn test_canonical_equals() { + // intl402/Temporal/ZonedDateTime/prototype/equals/canonical-not-equal + test_all_providers!(provider: { + let one = parse_zdt_with_compatible("2025-01-01T01:00:00[Africa/Accra]", provider).unwrap(); + let two = parse_zdt_with_compatible("2025-01-01T01:00:00[Africa/Abidjan]", provider).unwrap(); + assert!(!one.equals_with_provider(&two, provider).unwrap()); + + // Spec explicitly lists this case https://tc39.es/ecma402/#sec-use-of-iana-time-zone-database + let one = parse_zdt_with_compatible("2025-01-01T01:00:00[Europe/Prague]", provider).unwrap(); + let two = parse_zdt_with_compatible("2025-01-01T01:00:00[Europe/Bratislava]", provider).unwrap(); + assert!(!one.equals_with_provider(&two, provider).unwrap()); + + + // This should work, though + let one = parse_zdt_with_compatible("2025-01-01T01:00:00[Asia/Kolkata]", provider).unwrap(); + let two = parse_zdt_with_compatible("2025-01-01T01:00:00[Asia/Calcutta]", provider).unwrap(); + assert!(one.equals_with_provider(&two, provider).unwrap()); + }) +} diff --git a/deps/temporal/src/error.rs b/deps/temporal/src/error.rs index e497f368cca262..02eee85e30cf22 100644 --- a/deps/temporal/src/error.rs +++ b/deps/temporal/src/error.rs @@ -4,7 +4,8 @@ use core::fmt; use ixdtf::ParseError; use timezone_provider::TimeZoneProviderError; -use icu_calendar::DateError; +use icu_calendar::cal::AnyCalendarDifferenceError; +use icu_calendar::error::{DateError, DateFromFieldsError, RangeError}; /// `TemporalError`'s error type. #[derive(Debug, Default, Clone, Copy, PartialEq)] @@ -153,6 +154,23 @@ impl From for TemporalError { } } +impl From for TemporalError { + fn from(error: DateFromFieldsError) -> Self { + let kind = if error == DateFromFieldsError::NotEnoughFields { + ErrorKind::Type + } else { + ErrorKind::Range + }; + TemporalError::new(kind).with_enum(ErrorMessage::Icu4xDateFromFields(error)) + } +} + +impl From for TemporalError { + fn from(error: AnyCalendarDifferenceError) -> Self { + TemporalError::range().with_enum(ErrorMessage::Icu4xUntil(error)) + } +} + impl From for TemporalError { fn from(error: ParseError) -> Self { TemporalError::range().with_enum(ErrorMessage::Ixdtf(error)) @@ -168,6 +186,7 @@ pub(crate) enum ErrorMessage { ZDTOutOfDayBounds, LargestUnitCannotBeDateUnit, DateOutOfRange, + DurationNotValid, // Numerical errors NumberNotFinite, @@ -206,6 +225,8 @@ pub(crate) enum ErrorMessage { String(&'static str), Ixdtf(ParseError), Icu4xDate(DateError), + Icu4xDateFromFields(DateFromFieldsError), + Icu4xUntil(AnyCalendarDifferenceError), } impl ErrorMessage { @@ -218,6 +239,7 @@ impl ErrorMessage { Self::ZDTOutOfDayBounds => "ZonedDateTime is outside the expected day bounds", Self::LargestUnitCannotBeDateUnit => "Largest unit cannot be a date unit", Self::DateOutOfRange => "Date is not within ISO date time limits.", + Self::DurationNotValid => "Duration was not valid.", Self::NumberNotFinite => "number value is not a finite value.", Self::NumberNotIntegral => "value must be integral.", Self::NumberNotPositive => "integer must be positive.", @@ -250,15 +272,42 @@ impl ErrorMessage { Self::None => "", Self::String(s) => s, Self::Ixdtf(s) => ixdtf_error_to_static_string(s), - Self::Icu4xDate(DateError::Range { field, .. }) => match field { - "year" => "Year out of range.", - "month" => "Month out of range.", - "day" => "Day out of range.", - _ => "Field out of range.", - }, - Self::Icu4xDate(DateError::UnknownEra) => "Unknown era.", + Self::Icu4xDate(DateError::Range { field, .. }) + | Self::Icu4xDateFromFields(DateFromFieldsError::Range(RangeError { field, .. })) => { + match field { + "year" => "Year out of range.", + "month" => "Month out of range.", + "day" => "Day out of range.", + _ => "Field out of range.", + } + } + Self::Icu4xDate(DateError::UnknownEra) + | Self::Icu4xDateFromFields(DateFromFieldsError::UnknownEra) => "Unknown era.", Self::Icu4xDate(DateError::UnknownMonthCode(..)) => "Unknown month code.", + Self::Icu4xDateFromFields(DateFromFieldsError::MonthCodeInvalidSyntax) => { + "Invalid month code." + } + Self::Icu4xDateFromFields(DateFromFieldsError::MonthCodeNotInCalendar) => { + "Month code not in calendar." + } + Self::Icu4xDateFromFields(DateFromFieldsError::MonthCodeNotInYear) => { + "Month code not in year." + } + Self::Icu4xDateFromFields(DateFromFieldsError::InconsistentYear) => { + "Inconsistent year." + } + Self::Icu4xDateFromFields(DateFromFieldsError::InconsistentMonth) => { + "Inconsistent month/monthCode." + } + Self::Icu4xDateFromFields(DateFromFieldsError::NotEnoughFields) => { + "Insufficient fields." + } Self::Icu4xDate(_) => "Date error.", + Self::Icu4xDateFromFields(_) => "Date error.", + Self::Icu4xUntil(AnyCalendarDifferenceError::MismatchedCalendars) => { + "Mismatched calendars." + } + Self::Icu4xUntil(_) => "Arithmetic error.", } } } @@ -294,7 +343,7 @@ pub fn ixdtf_error_to_static_string(error: ParseError) -> &'static str { ParseError::InvalidDayRange => "Parsed day value not in a valid range.", - ParseError::DateYear => "Invalid chracter while parsing year value.", + ParseError::DateYear => "Invalid character while parsing year value.", ParseError::DateExtendedYear => "Invalid character while parsing extended year value.", diff --git a/deps/temporal/src/host.rs b/deps/temporal/src/host.rs index df090c570d5660..a6f6845277fc64 100644 --- a/deps/temporal/src/host.rs +++ b/deps/temporal/src/host.rs @@ -13,7 +13,10 @@ pub trait HostClock { /// The `HostTimeZone` trait defines the host's time zone. pub trait HostTimeZone { - fn get_host_time_zone(&self, provider: &impl TimeZoneProvider) -> TemporalResult; + fn get_host_time_zone( + &self, + provider: &(impl TimeZoneProvider + ?Sized), + ) -> TemporalResult; } /// `HostHooks` marks whether a trait implements the required host hooks with some @@ -23,7 +26,10 @@ pub trait HostHooks: HostClock + HostTimeZone { self.get_host_epoch_nanoseconds() } - fn get_system_time_zone(&self, provider: &impl TimeZoneProvider) -> TemporalResult { + fn get_system_time_zone( + &self, + provider: &(impl TimeZoneProvider + ?Sized), + ) -> TemporalResult { self.get_host_time_zone(provider) } } @@ -54,7 +60,7 @@ impl HostClock for EmptyHostSystem { } impl HostTimeZone for EmptyHostSystem { - fn get_host_time_zone(&self, _: &impl TimeZoneProvider) -> TemporalResult { + fn get_host_time_zone(&self, _: &(impl TimeZoneProvider + ?Sized)) -> TemporalResult { Ok(TimeZone::from(UtcOffset::default())) } } diff --git a/deps/temporal/src/lib.rs b/deps/temporal/src/lib.rs index 28a9d59b8957ba..49f955cd58f261 100644 --- a/deps/temporal/src/lib.rs +++ b/deps/temporal/src/lib.rs @@ -306,7 +306,7 @@ pub use error::TemporalError; #[cfg(feature = "sys")] #[doc(inline)] -pub use sys::Temporal; +pub use sys::{DefaultHostSystem, Temporal}; pub mod partial { //! Partial date and time component records diff --git a/deps/temporal/src/options/relative_to.rs b/deps/temporal/src/options/relative_to.rs index 2f65fbbf5f0067..771d656aaf5b0d 100644 --- a/deps/temporal/src/options/relative_to.rs +++ b/deps/temporal/src/options/relative_to.rs @@ -38,7 +38,7 @@ impl RelativeTo { /// is invalid, then an error is returned. pub fn try_from_str_with_provider( source: &str, - provider: &impl TimeZoneProvider, + provider: &(impl TimeZoneProvider + ?Sized), ) -> TemporalResult { // b. Let result be ? ParseISODateTime(value, « TemporalDateTimeString[+Zoned], TemporalDateTimeString[~Zoned] »). let bytes = source.as_bytes(); diff --git a/deps/temporal/src/parsed_intermediates.rs b/deps/temporal/src/parsed_intermediates.rs index c4ff2cc0d98fd4..0bab4d8abc0d07 100644 --- a/deps/temporal/src/parsed_intermediates.rs +++ b/deps/temporal/src/parsed_intermediates.rs @@ -24,6 +24,9 @@ use ixdtf::records::UtcOffsetRecordOrZ; fn extract_kind(calendar: Option<&[u8]>) -> TemporalResult { Ok(calendar .map(Calendar::try_kind_from_utf8) + // Note that this will successfully parse AnyCalendarKind::HijriSimulatedMecca + // However, Calendar::new will immediately turn it into an ISO calendar, + // so we don't need to do anything here. .transpose()? .unwrap_or(AnyCalendarKind::Iso)) } @@ -129,7 +132,7 @@ impl ParsedZonedDateTime { /// Converts a UTF-8 encoded string into a `ParsedZonedDateTime`. pub fn from_utf8_with_provider( source: &[u8], - provider: &impl TimeZoneProvider, + provider: &(impl TimeZoneProvider + ?Sized), ) -> TemporalResult { // Steps from the parse bits of of ToZonedDateTime diff --git a/deps/temporal/src/parsers.rs b/deps/temporal/src/parsers.rs index 43a7d778802a5b..20a3d6c796b92f 100644 --- a/deps/temporal/src/parsers.rs +++ b/deps/temporal/src/parsers.rs @@ -594,6 +594,7 @@ impl Writeable for FormattableDuration { let unit_below_minute = self.date.is_none() && hours == 0 && minutes == 0; let write_second = seconds != 0 + || ns != 0 || unit_below_minute || matches!(self.precision, Precision::Digit(_)); @@ -899,11 +900,27 @@ pub fn parse_allowed_calendar_formats(s: &[u8]) -> Option<&[u8]> { #[cfg(test)] mod tests { - use super::{FormattableDate, FormattableOffset}; - use crate::parsers::{FormattableTime, Precision}; + use super::{FormattableDate, FormattableDuration, FormattableOffset}; + use crate::parsers::{FormattableTime, FormattableTimeDuration, Precision}; use alloc::format; use writeable::assert_writeable_eq; + #[test] + fn duration() { + let duration = FormattableDuration { + sign: crate::Sign::Positive, + date: Some(super::FormattableDateDuration { + years: 1, + months: 0, + weeks: 0, + days: 0, + }), + time: Some(FormattableTimeDuration::Seconds(0, 0, 0, Some(1))), + precision: Precision::Auto, + }; + assert_writeable_eq!(duration, "P1YT0.000000001S"); + } + #[test] fn offset_string() { let offset = FormattableOffset { diff --git a/deps/temporal/src/parsers/time_zone.rs b/deps/temporal/src/parsers/time_zone.rs index 51b9d10c434161..248ce0bbb86a2c 100644 --- a/deps/temporal/src/parsers/time_zone.rs +++ b/deps/temporal/src/parsers/time_zone.rs @@ -12,7 +12,7 @@ use super::{parse_ixdtf, ParseVariant}; #[inline] pub(crate) fn parse_allowed_timezone_formats( s: &str, - provider: &impl TimeZoneProvider, + provider: &(impl TimeZoneProvider + ?Sized), ) -> Option { let (offset, annotation) = if let Ok((offset, annotation)) = parse_ixdtf(s.as_bytes(), ParseVariant::DateTime).map(|r| (r.offset, r.tz)) diff --git a/deps/temporal/src/primitive.rs b/deps/temporal/src/primitive.rs index bc7cfe302379df..5066d08798d7ae 100644 --- a/deps/temporal/src/primitive.rs +++ b/deps/temporal/src/primitive.rs @@ -235,6 +235,50 @@ impl Ord for FiniteF64 { } } +/// An intermediate primitive type for calculating +/// double64 results. +#[derive(Debug, Clone, Copy)] +pub(crate) struct DoubleDouble { + pub(crate) hi: f64, + pub(crate) lo: f64, +} + +impl DoubleDouble { + /// Creates a `DoubleDouble` from the product of two `f64` values. + pub(crate) fn mul(a: f64, b: f64) -> Self { + // Mul + let product = a * b; + let error = core_maths::CoreFloat::mul_add(a, b, -product); + Self { + hi: product, + lo: error, + } + } + + /// Creates a `DoubleDouble` from the sum of two `f64` values. + pub(crate) fn sum(one: f64, two: f64) -> Self { + // Sum + let sum = one + two; + + // Calculate error + let calc_one = sum - one; + let calc_two = sum - two; + let two_roundoff = two - calc_one; + let one_roundoff = one - calc_two; + let error = one_roundoff + two_roundoff; + + Self { hi: sum, lo: error } + } +} + +impl From for DoubleDouble { + fn from(value: i128) -> Self { + let hi = value as f64; + let lo = (value - hi as i128) as f64; + Self { hi, lo } + } +} + #[cfg(test)] mod tests { use super::FiniteF64; diff --git a/deps/temporal/src/sys.rs b/deps/temporal/src/sys.rs index a530dc88358fcc..13bd374e25e119 100644 --- a/deps/temporal/src/sys.rs +++ b/deps/temporal/src/sys.rs @@ -7,7 +7,6 @@ use crate::TemporalResult; use crate::unix_time::EpochNanoseconds; use crate::TemporalError; use crate::TimeZone; -#[cfg(feature = "sys")] use timezone_provider::provider::TimeZoneProvider; use web_time::{SystemTime, UNIX_EPOCH}; @@ -22,10 +21,8 @@ use web_time::{SystemTime, UNIX_EPOCH}; // /// The Temporal object for accessing current system time -#[cfg(feature = "sys")] pub struct Temporal; -#[cfg(feature = "sys")] impl Temporal { /// Get a `Now` object for the default host system. pub fn now() -> Now { @@ -36,39 +33,35 @@ impl Temporal { /// A default host system implementation /// /// This implementation is backed by [`SystemTime`] and [`iana_time_zone`] -#[cfg(feature = "sys")] pub struct DefaultHostSystem; -#[cfg(feature = "sys")] impl HostHooks for DefaultHostSystem {} -#[cfg(feature = "sys")] impl HostClock for DefaultHostSystem { fn get_host_epoch_nanoseconds(&self) -> TemporalResult { get_system_nanoseconds() } } -#[cfg(feature = "sys")] impl HostTimeZone for DefaultHostSystem { fn get_host_time_zone( &self, - provider: &impl timezone_provider::provider::TimeZoneProvider, + provider: &(impl TimeZoneProvider + ?Sized), ) -> TemporalResult { get_system_timezone(provider) } } -#[cfg(feature = "sys")] #[inline] -pub(crate) fn get_system_timezone(provider: &impl TimeZoneProvider) -> TemporalResult { +pub(crate) fn get_system_timezone( + provider: &(impl TimeZoneProvider + ?Sized), +) -> TemporalResult { iana_time_zone::get_timezone() .map(|s| TimeZone::try_from_identifier_str_with_provider(&s, provider)) .map_err(|_| TemporalError::general("Error fetching system time"))? } /// Returns the system time in nanoseconds. -#[cfg(feature = "sys")] pub(crate) fn get_system_nanoseconds() -> TemporalResult { use crate::unix_time::EpochNanoseconds; diff --git a/deps/temporal/temporal_capi/Cargo.toml b/deps/temporal/temporal_capi/Cargo.toml index c6201edbf1137d..2b2cc652554490 100644 --- a/deps/temporal/temporal_capi/Cargo.toml +++ b/deps/temporal/temporal_capi/Cargo.toml @@ -23,9 +23,9 @@ diplomat-runtime.workspace = true num-traits.workspace = true temporal_rs = { workspace = true, default-features = false } timezone_provider = { workspace = true, default-features = false } -icu_calendar = { version = "2.0.2", default-features = false } -icu_locale = { version = "2.0.0" } -writeable = "0.6.1" +icu_calendar.workspace = true +icu_locale.workspace = true +writeable.workspace = true zoneinfo64 = { workspace = true, optional = true } [features] diff --git a/deps/temporal/temporal_capi/bindings/c/AnyCalendarKind.d.h b/deps/temporal/temporal_capi/bindings/c/AnyCalendarKind.d.h index 44bed28e18cb5a..23505aa78d7bc3 100644 --- a/deps/temporal/temporal_capi/bindings/c/AnyCalendarKind.d.h +++ b/deps/temporal/temporal_capi/bindings/c/AnyCalendarKind.d.h @@ -12,24 +12,23 @@ typedef enum AnyCalendarKind { - AnyCalendarKind_Buddhist = 0, - AnyCalendarKind_Chinese = 1, - AnyCalendarKind_Coptic = 2, - AnyCalendarKind_Dangi = 3, - AnyCalendarKind_Ethiopian = 4, - AnyCalendarKind_EthiopianAmeteAlem = 5, - AnyCalendarKind_Gregorian = 6, - AnyCalendarKind_Hebrew = 7, - AnyCalendarKind_Indian = 8, - AnyCalendarKind_HijriTabularTypeIIFriday = 9, - AnyCalendarKind_HijriSimulatedMecca = 10, + AnyCalendarKind_Iso = 0, + AnyCalendarKind_Buddhist = 1, + AnyCalendarKind_Chinese = 2, + AnyCalendarKind_Coptic = 3, + AnyCalendarKind_Dangi = 4, + AnyCalendarKind_Ethiopian = 5, + AnyCalendarKind_EthiopianAmeteAlem = 6, + AnyCalendarKind_Gregorian = 7, + AnyCalendarKind_Hebrew = 8, + AnyCalendarKind_Indian = 9, + AnyCalendarKind_HijriTabularTypeIIFriday = 10, AnyCalendarKind_HijriTabularTypeIIThursday = 11, AnyCalendarKind_HijriUmmAlQura = 12, - AnyCalendarKind_Iso = 13, - AnyCalendarKind_Japanese = 14, - AnyCalendarKind_JapaneseExtended = 15, - AnyCalendarKind_Persian = 16, - AnyCalendarKind_Roc = 17, + AnyCalendarKind_Japanese = 13, + AnyCalendarKind_JapaneseExtended = 14, + AnyCalendarKind_Persian = 15, + AnyCalendarKind_Roc = 16, } AnyCalendarKind; typedef struct AnyCalendarKind_option {union { AnyCalendarKind ok; }; bool is_ok; } AnyCalendarKind_option; diff --git a/deps/temporal/temporal_capi/bindings/c/ArithmeticOverflow.h b/deps/temporal/temporal_capi/bindings/c/ArithmeticOverflow.h index 4406c69ff59356..fe0597bf1651b3 100644 --- a/deps/temporal/temporal_capi/bindings/c/ArithmeticOverflow.h +++ b/deps/temporal/temporal_capi/bindings/c/ArithmeticOverflow.h @@ -13,7 +13,7 @@ - +// No Content diff --git a/deps/temporal/temporal_capi/bindings/c/DifferenceSettings.h b/deps/temporal/temporal_capi/bindings/c/DifferenceSettings.h index c43fa6b9d84658..828e089a014bd5 100644 --- a/deps/temporal/temporal_capi/bindings/c/DifferenceSettings.h +++ b/deps/temporal/temporal_capi/bindings/c/DifferenceSettings.h @@ -13,7 +13,7 @@ - +// No Content diff --git a/deps/temporal/temporal_capi/bindings/c/Disambiguation.h b/deps/temporal/temporal_capi/bindings/c/Disambiguation.h index f4aeaa7d58e29d..52f0b66433771e 100644 --- a/deps/temporal/temporal_capi/bindings/c/Disambiguation.h +++ b/deps/temporal/temporal_capi/bindings/c/Disambiguation.h @@ -13,7 +13,7 @@ - +// No Content diff --git a/deps/temporal/temporal_capi/bindings/c/DisplayCalendar.h b/deps/temporal/temporal_capi/bindings/c/DisplayCalendar.h index 1d80f822b2f213..4d7fc470648b90 100644 --- a/deps/temporal/temporal_capi/bindings/c/DisplayCalendar.h +++ b/deps/temporal/temporal_capi/bindings/c/DisplayCalendar.h @@ -13,7 +13,7 @@ - +// No Content diff --git a/deps/temporal/temporal_capi/bindings/c/DisplayOffset.h b/deps/temporal/temporal_capi/bindings/c/DisplayOffset.h index e59ccac16c725d..91343835e72658 100644 --- a/deps/temporal/temporal_capi/bindings/c/DisplayOffset.h +++ b/deps/temporal/temporal_capi/bindings/c/DisplayOffset.h @@ -13,7 +13,7 @@ - +// No Content diff --git a/deps/temporal/temporal_capi/bindings/c/DisplayTimeZone.h b/deps/temporal/temporal_capi/bindings/c/DisplayTimeZone.h index 736cd05c44d302..69642fe4f67f39 100644 --- a/deps/temporal/temporal_capi/bindings/c/DisplayTimeZone.h +++ b/deps/temporal/temporal_capi/bindings/c/DisplayTimeZone.h @@ -13,7 +13,7 @@ - +// No Content diff --git a/deps/temporal/temporal_capi/bindings/c/ErrorKind.h b/deps/temporal/temporal_capi/bindings/c/ErrorKind.h index 113613977f13ba..f4a59170432392 100644 --- a/deps/temporal/temporal_capi/bindings/c/ErrorKind.h +++ b/deps/temporal/temporal_capi/bindings/c/ErrorKind.h @@ -13,7 +13,7 @@ - +// No Content diff --git a/deps/temporal/temporal_capi/bindings/c/OffsetDisambiguation.h b/deps/temporal/temporal_capi/bindings/c/OffsetDisambiguation.h index 8227ec084b5d52..1e4bf0088bcf19 100644 --- a/deps/temporal/temporal_capi/bindings/c/OffsetDisambiguation.h +++ b/deps/temporal/temporal_capi/bindings/c/OffsetDisambiguation.h @@ -13,7 +13,7 @@ - +// No Content diff --git a/deps/temporal/temporal_capi/bindings/c/PartialDate.h b/deps/temporal/temporal_capi/bindings/c/PartialDate.h index 824a8e03422bf1..752468c156f917 100644 --- a/deps/temporal/temporal_capi/bindings/c/PartialDate.h +++ b/deps/temporal/temporal_capi/bindings/c/PartialDate.h @@ -13,7 +13,7 @@ - +// No Content diff --git a/deps/temporal/temporal_capi/bindings/c/PartialDateTime.h b/deps/temporal/temporal_capi/bindings/c/PartialDateTime.h index 11efc7104cfb3c..e43c46138079e5 100644 --- a/deps/temporal/temporal_capi/bindings/c/PartialDateTime.h +++ b/deps/temporal/temporal_capi/bindings/c/PartialDateTime.h @@ -13,7 +13,7 @@ - +// No Content diff --git a/deps/temporal/temporal_capi/bindings/c/PartialTime.h b/deps/temporal/temporal_capi/bindings/c/PartialTime.h index 8662bb27a60ee8..86920b87588be9 100644 --- a/deps/temporal/temporal_capi/bindings/c/PartialTime.h +++ b/deps/temporal/temporal_capi/bindings/c/PartialTime.h @@ -13,7 +13,7 @@ - +// No Content diff --git a/deps/temporal/temporal_capi/bindings/c/PartialZonedDateTime.h b/deps/temporal/temporal_capi/bindings/c/PartialZonedDateTime.h index 2f8305ae3d18c8..eef48b88cef153 100644 --- a/deps/temporal/temporal_capi/bindings/c/PartialZonedDateTime.h +++ b/deps/temporal/temporal_capi/bindings/c/PartialZonedDateTime.h @@ -13,7 +13,7 @@ - +// No Content diff --git a/deps/temporal/temporal_capi/bindings/c/Precision.h b/deps/temporal/temporal_capi/bindings/c/Precision.h index b184fe14192c7c..8ece055c2f56b0 100644 --- a/deps/temporal/temporal_capi/bindings/c/Precision.h +++ b/deps/temporal/temporal_capi/bindings/c/Precision.h @@ -13,7 +13,7 @@ - +// No Content diff --git a/deps/temporal/temporal_capi/bindings/c/RelativeTo.h b/deps/temporal/temporal_capi/bindings/c/RelativeTo.h index d40bc871f08922..e3301f8d9cb6cc 100644 --- a/deps/temporal/temporal_capi/bindings/c/RelativeTo.h +++ b/deps/temporal/temporal_capi/bindings/c/RelativeTo.h @@ -13,7 +13,7 @@ - +// No Content diff --git a/deps/temporal/temporal_capi/bindings/c/RoundingMode.h b/deps/temporal/temporal_capi/bindings/c/RoundingMode.h index 5c028595f86548..428dcc448c798a 100644 --- a/deps/temporal/temporal_capi/bindings/c/RoundingMode.h +++ b/deps/temporal/temporal_capi/bindings/c/RoundingMode.h @@ -13,7 +13,7 @@ - +// No Content diff --git a/deps/temporal/temporal_capi/bindings/c/RoundingOptions.h b/deps/temporal/temporal_capi/bindings/c/RoundingOptions.h index 0d0c4f6cbee25d..57c0fc8cb03307 100644 --- a/deps/temporal/temporal_capi/bindings/c/RoundingOptions.h +++ b/deps/temporal/temporal_capi/bindings/c/RoundingOptions.h @@ -13,7 +13,7 @@ - +// No Content diff --git a/deps/temporal/temporal_capi/bindings/c/Sign.h b/deps/temporal/temporal_capi/bindings/c/Sign.h index 10f470c3427db4..647c28bc68971c 100644 --- a/deps/temporal/temporal_capi/bindings/c/Sign.h +++ b/deps/temporal/temporal_capi/bindings/c/Sign.h @@ -13,7 +13,7 @@ - +// No Content diff --git a/deps/temporal/temporal_capi/bindings/c/TemporalError.h b/deps/temporal/temporal_capi/bindings/c/TemporalError.h index 5386db88391af0..528efa571b287e 100644 --- a/deps/temporal/temporal_capi/bindings/c/TemporalError.h +++ b/deps/temporal/temporal_capi/bindings/c/TemporalError.h @@ -13,7 +13,7 @@ - +// No Content diff --git a/deps/temporal/temporal_capi/bindings/c/ToStringRoundingOptions.h b/deps/temporal/temporal_capi/bindings/c/ToStringRoundingOptions.h index cc43e6f5efc0fc..09455cb7275b75 100644 --- a/deps/temporal/temporal_capi/bindings/c/ToStringRoundingOptions.h +++ b/deps/temporal/temporal_capi/bindings/c/ToStringRoundingOptions.h @@ -13,7 +13,7 @@ - +// No Content diff --git a/deps/temporal/temporal_capi/bindings/c/TransitionDirection.h b/deps/temporal/temporal_capi/bindings/c/TransitionDirection.h index 2bc20dd00d8a4a..e0f22a20bfa276 100644 --- a/deps/temporal/temporal_capi/bindings/c/TransitionDirection.h +++ b/deps/temporal/temporal_capi/bindings/c/TransitionDirection.h @@ -13,7 +13,7 @@ - +// No Content diff --git a/deps/temporal/temporal_capi/bindings/c/Unit.h b/deps/temporal/temporal_capi/bindings/c/Unit.h index 7ad63612212d6e..1035e02a643f6c 100644 --- a/deps/temporal/temporal_capi/bindings/c/Unit.h +++ b/deps/temporal/temporal_capi/bindings/c/Unit.h @@ -13,7 +13,7 @@ - +// No Content diff --git a/deps/temporal/temporal_capi/bindings/c/UnsignedRoundingMode.h b/deps/temporal/temporal_capi/bindings/c/UnsignedRoundingMode.h index 4e68a3ba351f69..b5ff43252859d6 100644 --- a/deps/temporal/temporal_capi/bindings/c/UnsignedRoundingMode.h +++ b/deps/temporal/temporal_capi/bindings/c/UnsignedRoundingMode.h @@ -13,7 +13,7 @@ - +// No Content diff --git a/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/AnyCalendarKind.d.hpp b/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/AnyCalendarKind.d.hpp index d7d93fd3386c8d..fe00577f0b5492 100644 --- a/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/AnyCalendarKind.d.hpp +++ b/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/AnyCalendarKind.d.hpp @@ -19,24 +19,23 @@ class AnyCalendarKind; namespace temporal_rs { namespace capi { enum AnyCalendarKind { - AnyCalendarKind_Buddhist = 0, - AnyCalendarKind_Chinese = 1, - AnyCalendarKind_Coptic = 2, - AnyCalendarKind_Dangi = 3, - AnyCalendarKind_Ethiopian = 4, - AnyCalendarKind_EthiopianAmeteAlem = 5, - AnyCalendarKind_Gregorian = 6, - AnyCalendarKind_Hebrew = 7, - AnyCalendarKind_Indian = 8, - AnyCalendarKind_HijriTabularTypeIIFriday = 9, - AnyCalendarKind_HijriSimulatedMecca = 10, + AnyCalendarKind_Iso = 0, + AnyCalendarKind_Buddhist = 1, + AnyCalendarKind_Chinese = 2, + AnyCalendarKind_Coptic = 3, + AnyCalendarKind_Dangi = 4, + AnyCalendarKind_Ethiopian = 5, + AnyCalendarKind_EthiopianAmeteAlem = 6, + AnyCalendarKind_Gregorian = 7, + AnyCalendarKind_Hebrew = 8, + AnyCalendarKind_Indian = 9, + AnyCalendarKind_HijriTabularTypeIIFriday = 10, AnyCalendarKind_HijriTabularTypeIIThursday = 11, AnyCalendarKind_HijriUmmAlQura = 12, - AnyCalendarKind_Iso = 13, - AnyCalendarKind_Japanese = 14, - AnyCalendarKind_JapaneseExtended = 15, - AnyCalendarKind_Persian = 16, - AnyCalendarKind_Roc = 17, + AnyCalendarKind_Japanese = 13, + AnyCalendarKind_JapaneseExtended = 14, + AnyCalendarKind_Persian = 15, + AnyCalendarKind_Roc = 16, }; typedef struct AnyCalendarKind_option {union { AnyCalendarKind ok; }; bool is_ok; } AnyCalendarKind_option; @@ -47,27 +46,26 @@ namespace temporal_rs { class AnyCalendarKind { public: enum Value { - Buddhist = 0, - Chinese = 1, - Coptic = 2, - Dangi = 3, - Ethiopian = 4, - EthiopianAmeteAlem = 5, - Gregorian = 6, - Hebrew = 7, - Indian = 8, - HijriTabularTypeIIFriday = 9, - HijriSimulatedMecca = 10, + Iso = 0, + Buddhist = 1, + Chinese = 2, + Coptic = 3, + Dangi = 4, + Ethiopian = 5, + EthiopianAmeteAlem = 6, + Gregorian = 7, + Hebrew = 8, + Indian = 9, + HijriTabularTypeIIFriday = 10, HijriTabularTypeIIThursday = 11, HijriUmmAlQura = 12, - Iso = 13, - Japanese = 14, - JapaneseExtended = 15, - Persian = 16, - Roc = 17, + Japanese = 13, + JapaneseExtended = 14, + Persian = 15, + Roc = 16, }; - AnyCalendarKind(): value(Value::Buddhist) {} + AnyCalendarKind(): value(Value::Iso) {} // Implicit conversions between enum and ::Value constexpr AnyCalendarKind(Value v) : value(v) {} diff --git a/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/AnyCalendarKind.hpp b/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/AnyCalendarKind.hpp index 810aae25a504f3..3c5aab6bf8c749 100644 --- a/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/AnyCalendarKind.hpp +++ b/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/AnyCalendarKind.hpp @@ -34,6 +34,7 @@ inline temporal_rs::capi::AnyCalendarKind temporal_rs::AnyCalendarKind::AsFFI() inline temporal_rs::AnyCalendarKind temporal_rs::AnyCalendarKind::FromFFI(temporal_rs::capi::AnyCalendarKind c_enum) { switch (c_enum) { + case temporal_rs::capi::AnyCalendarKind_Iso: case temporal_rs::capi::AnyCalendarKind_Buddhist: case temporal_rs::capi::AnyCalendarKind_Chinese: case temporal_rs::capi::AnyCalendarKind_Coptic: @@ -44,10 +45,8 @@ inline temporal_rs::AnyCalendarKind temporal_rs::AnyCalendarKind::FromFFI(tempor case temporal_rs::capi::AnyCalendarKind_Hebrew: case temporal_rs::capi::AnyCalendarKind_Indian: case temporal_rs::capi::AnyCalendarKind_HijriTabularTypeIIFriday: - case temporal_rs::capi::AnyCalendarKind_HijriSimulatedMecca: case temporal_rs::capi::AnyCalendarKind_HijriTabularTypeIIThursday: case temporal_rs::capi::AnyCalendarKind_HijriUmmAlQura: - case temporal_rs::capi::AnyCalendarKind_Iso: case temporal_rs::capi::AnyCalendarKind_Japanese: case temporal_rs::capi::AnyCalendarKind_JapaneseExtended: case temporal_rs::capi::AnyCalendarKind_Persian: diff --git a/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/ArithmeticOverflow.hpp b/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/ArithmeticOverflow.hpp index 10a1773866e934..905b134649d153 100644 --- a/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/ArithmeticOverflow.hpp +++ b/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/ArithmeticOverflow.hpp @@ -16,9 +16,7 @@ namespace temporal_rs { namespace capi { - extern "C" { - } // extern "C" } // namespace capi } // namespace diff --git a/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/DifferenceSettings.hpp b/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/DifferenceSettings.hpp index d00ab0e5b7590c..2f8267878a9c08 100644 --- a/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/DifferenceSettings.hpp +++ b/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/DifferenceSettings.hpp @@ -18,9 +18,7 @@ namespace temporal_rs { namespace capi { - extern "C" { - } // extern "C" } // namespace capi } // namespace diff --git a/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/Disambiguation.hpp b/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/Disambiguation.hpp index 15476c9ed7512d..857c4a7065e832 100644 --- a/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/Disambiguation.hpp +++ b/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/Disambiguation.hpp @@ -16,9 +16,7 @@ namespace temporal_rs { namespace capi { - extern "C" { - } // extern "C" } // namespace capi } // namespace diff --git a/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/DisplayCalendar.hpp b/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/DisplayCalendar.hpp index 4225d477d4510a..60b274cde6f8f7 100644 --- a/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/DisplayCalendar.hpp +++ b/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/DisplayCalendar.hpp @@ -16,9 +16,7 @@ namespace temporal_rs { namespace capi { - extern "C" { - } // extern "C" } // namespace capi } // namespace diff --git a/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/DisplayOffset.hpp b/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/DisplayOffset.hpp index ab63e3fe1d7d27..198243757473df 100644 --- a/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/DisplayOffset.hpp +++ b/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/DisplayOffset.hpp @@ -16,9 +16,7 @@ namespace temporal_rs { namespace capi { - extern "C" { - } // extern "C" } // namespace capi } // namespace diff --git a/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/DisplayTimeZone.hpp b/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/DisplayTimeZone.hpp index 3341bd73be3c61..35b1e73141b8d1 100644 --- a/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/DisplayTimeZone.hpp +++ b/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/DisplayTimeZone.hpp @@ -16,9 +16,7 @@ namespace temporal_rs { namespace capi { - extern "C" { - } // extern "C" } // namespace capi } // namespace diff --git a/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/ErrorKind.hpp b/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/ErrorKind.hpp index bb6ff87a377f78..04b46353a1a873 100644 --- a/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/ErrorKind.hpp +++ b/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/ErrorKind.hpp @@ -16,9 +16,7 @@ namespace temporal_rs { namespace capi { - extern "C" { - } // extern "C" } // namespace capi } // namespace diff --git a/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/OffsetDisambiguation.hpp b/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/OffsetDisambiguation.hpp index 46313f67c332d5..08ff055e1d06fd 100644 --- a/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/OffsetDisambiguation.hpp +++ b/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/OffsetDisambiguation.hpp @@ -16,9 +16,7 @@ namespace temporal_rs { namespace capi { - extern "C" { - } // extern "C" } // namespace capi } // namespace diff --git a/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/PartialDate.hpp b/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/PartialDate.hpp index b7b9dc43998fc1..77ffc3d8c8fd4f 100644 --- a/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/PartialDate.hpp +++ b/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/PartialDate.hpp @@ -17,9 +17,7 @@ namespace temporal_rs { namespace capi { - extern "C" { - } // extern "C" } // namespace capi } // namespace diff --git a/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/PartialDateTime.hpp b/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/PartialDateTime.hpp index a1f79dc5253982..bd0e0ea8012949 100644 --- a/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/PartialDateTime.hpp +++ b/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/PartialDateTime.hpp @@ -18,9 +18,7 @@ namespace temporal_rs { namespace capi { - extern "C" { - } // extern "C" } // namespace capi } // namespace diff --git a/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/PartialTime.hpp b/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/PartialTime.hpp index 8ac03c53ae11d9..7c056330424444 100644 --- a/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/PartialTime.hpp +++ b/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/PartialTime.hpp @@ -16,9 +16,7 @@ namespace temporal_rs { namespace capi { - extern "C" { - } // extern "C" } // namespace capi } // namespace diff --git a/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/PartialZonedDateTime.hpp b/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/PartialZonedDateTime.hpp index 47bf1d218c6f22..775fa63df28d47 100644 --- a/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/PartialZonedDateTime.hpp +++ b/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/PartialZonedDateTime.hpp @@ -19,9 +19,7 @@ namespace temporal_rs { namespace capi { - extern "C" { - } // extern "C" } // namespace capi } // namespace diff --git a/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/Precision.hpp b/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/Precision.hpp index 798021ca96cb69..2cd58a65b81fa5 100644 --- a/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/Precision.hpp +++ b/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/Precision.hpp @@ -16,9 +16,7 @@ namespace temporal_rs { namespace capi { - extern "C" { - } // extern "C" } // namespace capi } // namespace diff --git a/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/RelativeTo.hpp b/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/RelativeTo.hpp index a5f28a56cdae21..91f4c900896c48 100644 --- a/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/RelativeTo.hpp +++ b/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/RelativeTo.hpp @@ -18,9 +18,7 @@ namespace temporal_rs { namespace capi { - extern "C" { - } // extern "C" } // namespace capi } // namespace diff --git a/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/RoundingMode.hpp b/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/RoundingMode.hpp index 7d5b9253118e99..d86ff9ce1077f4 100644 --- a/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/RoundingMode.hpp +++ b/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/RoundingMode.hpp @@ -16,9 +16,7 @@ namespace temporal_rs { namespace capi { - extern "C" { - } // extern "C" } // namespace capi } // namespace diff --git a/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/RoundingOptions.hpp b/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/RoundingOptions.hpp index 1804f7be41941b..a2b7355184a005 100644 --- a/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/RoundingOptions.hpp +++ b/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/RoundingOptions.hpp @@ -18,9 +18,7 @@ namespace temporal_rs { namespace capi { - extern "C" { - } // extern "C" } // namespace capi } // namespace diff --git a/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/Sign.hpp b/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/Sign.hpp index 131b59507bdb00..4141e32c5fe7a8 100644 --- a/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/Sign.hpp +++ b/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/Sign.hpp @@ -16,9 +16,7 @@ namespace temporal_rs { namespace capi { - extern "C" { - } // extern "C" } // namespace capi } // namespace diff --git a/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/TemporalError.hpp b/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/TemporalError.hpp index aaccd0c1938cc1..c86afc60cc8ced 100644 --- a/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/TemporalError.hpp +++ b/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/TemporalError.hpp @@ -17,9 +17,7 @@ namespace temporal_rs { namespace capi { - extern "C" { - } // extern "C" } // namespace capi } // namespace diff --git a/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/ToStringRoundingOptions.hpp b/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/ToStringRoundingOptions.hpp index e34ebefb8f596f..4cd85fd103f311 100644 --- a/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/ToStringRoundingOptions.hpp +++ b/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/ToStringRoundingOptions.hpp @@ -19,9 +19,7 @@ namespace temporal_rs { namespace capi { - extern "C" { - } // extern "C" } // namespace capi } // namespace diff --git a/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/TransitionDirection.hpp b/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/TransitionDirection.hpp index 1241672350775b..c084ecd90c661a 100644 --- a/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/TransitionDirection.hpp +++ b/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/TransitionDirection.hpp @@ -16,9 +16,7 @@ namespace temporal_rs { namespace capi { - extern "C" { - } // extern "C" } // namespace capi } // namespace diff --git a/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/Unit.hpp b/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/Unit.hpp index 6ab07392ce7c52..b87e67d3563527 100644 --- a/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/Unit.hpp +++ b/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/Unit.hpp @@ -16,9 +16,7 @@ namespace temporal_rs { namespace capi { - extern "C" { - } // extern "C" } // namespace capi } // namespace diff --git a/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/UnsignedRoundingMode.hpp b/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/UnsignedRoundingMode.hpp index 52f543b73934e3..99348e9eb484d5 100644 --- a/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/UnsignedRoundingMode.hpp +++ b/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/UnsignedRoundingMode.hpp @@ -16,9 +16,7 @@ namespace temporal_rs { namespace capi { - extern "C" { - } // extern "C" } // namespace capi } // namespace diff --git a/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/diplomat_runtime.hpp b/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/diplomat_runtime.hpp index 1e32c8929c99cd..a3fd939adf9797 100644 --- a/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/diplomat_runtime.hpp +++ b/deps/temporal/temporal_capi/bindings/cpp/temporal_rs/diplomat_runtime.hpp @@ -512,9 +512,10 @@ template struct fn_traits fn_traits(T) -> fn_traits; -// Trait for extracting inner types from either std::optional or std::unique_ptr. -// These are the two potential types returned by next() functions -template struct inner { using type = T; }; +// Trait for extracting inner types from either T*, std::optional, or std::unique_ptr. +// These are the three potential types returned by next() functions +template struct inner { /* only T*, std::optional, and std::unique_ptr are supported */ }; +template struct inner { using type = T; }; template struct inner> { using type = T; }; template struct inner>{ using type = T; }; diff --git a/deps/temporal/temporal_capi/src/calendar.rs b/deps/temporal/temporal_capi/src/calendar.rs index 5184609e5b67bf..76d9531662415f 100644 --- a/deps/temporal/temporal_capi/src/calendar.rs +++ b/deps/temporal/temporal_capi/src/calendar.rs @@ -8,6 +8,7 @@ pub mod ffi { #[diplomat::enum_convert(icu_calendar::AnyCalendarKind, needs_wildcard)] pub enum AnyCalendarKind { + Iso, Buddhist, Chinese, Coptic, @@ -18,10 +19,8 @@ pub mod ffi { Hebrew, Indian, HijriTabularTypeIIFriday, - HijriSimulatedMecca, HijriTabularTypeIIThursday, HijriUmmAlQura, - Iso, Japanese, JapaneseExtended, Persian, @@ -33,10 +32,9 @@ pub mod ffi { let value = icu_locale::extensions::unicode::Value::try_from_utf8(s).ok()?; let algorithm = CalendarAlgorithm::try_from(&value).ok()?; match icu_calendar::AnyCalendarKind::try_from(algorithm) { + // islamic-rgsa / simulated-mecca is supported by ICU4X but not Temporal + Ok(icu_calendar::AnyCalendarKind::HijriSimulatedMecca) => None, Ok(c) => Some(c.into()), - Err(()) if algorithm == CalendarAlgorithm::Hijri(None) => { - Some(Self::HijriTabularTypeIIFriday) - } Err(()) => None, } } diff --git a/deps/temporal/tools/bakeddata/Cargo.toml b/deps/temporal/tools/bakeddata/Cargo.toml index bd0596cc9405b1..c775393464fd62 100644 --- a/deps/temporal/tools/bakeddata/Cargo.toml +++ b/deps/temporal/tools/bakeddata/Cargo.toml @@ -11,7 +11,7 @@ exclude.workspace = true publish = false [dependencies] -databake = "0.2.0" +databake.workspace = true prettyplease = "0.2.37" serde_json = "1.0.145" syn = "2.0.106" diff --git a/deps/temporal/zoneinfo/Cargo.toml b/deps/temporal/zoneinfo/Cargo.toml index f69398319c07c9..3d441fc9789ff2 100644 --- a/deps/temporal/zoneinfo/Cargo.toml +++ b/deps/temporal/zoneinfo/Cargo.toml @@ -2,7 +2,7 @@ name = "zoneinfo_rs" description = "Zoneinfo parser and compiler" edition.workspace = true -version = "0.0.17" +version = "0.0.18" rust-version.workspace = true authors.workspace = true license.workspace = true diff --git a/deps/temporal/zoneinfo/src/lib.rs b/deps/temporal/zoneinfo/src/lib.rs index 57726bfb4abc06..59934f30481c8e 100644 --- a/deps/temporal/zoneinfo/src/lib.rs +++ b/deps/temporal/zoneinfo/src/lib.rs @@ -36,6 +36,7 @@ extern crate alloc; use alloc::string::String; +use alloc::vec::Vec; use parser::ZoneInfoParseError; use hashbrown::HashMap; @@ -108,6 +109,21 @@ pub struct ZoneInfoData { pub links: HashMap, /// Data parsed from `#PACKRATLIST` lines pub pack_rat: HashMap, + /// Data from zone.tab + /// + /// Will only be parsed if zone.tab is parsed + pub zone_tab: Vec, +} + +#[non_exhaustive] +#[derive(Debug, Clone, Default)] +pub struct ZoneTabEntry { + /// The country code, e.g. "AU" + pub country_code: String, + /// The (unparsed) coordinates, e.g. +5630+08458 + pub coordinates_raw: String, + /// The timezone, e.g. Asia/Tomsk + pub tz: String, } // ==== ZoneInfoData parsing methods ==== @@ -125,6 +141,8 @@ impl ZoneInfoData { let parsed = Self::from_filepath(file_path)?; zoneinfo.extend(parsed); } + let zonetab = Self::zonetab_from_filepath(dir.as_ref().join("zone.tab"))?; + zoneinfo.extend(zonetab); Ok(zoneinfo) } @@ -136,6 +154,14 @@ impl ZoneInfoData { Self::from_zoneinfo_file(&std::fs::read_to_string(path)?) } + /// Parse a zone.tab file from a filepath to a zoneinfo file. + #[cfg(feature = "std")] + pub fn zonetab_from_filepath + core::fmt::Debug>( + path: P, + ) -> Result { + Self::from_zonetab_file(&std::fs::read_to_string(path)?) + } + /// Parses data from a zoneinfo file as a string slice. pub fn from_zoneinfo_file(src: &str) -> Result { ZoneInfoParser::from_zoneinfo_str(src) @@ -143,11 +169,19 @@ impl ZoneInfoData { .map_err(ZoneInfoError::Parse) } + /// Parses data from a zoneinfo file as a string slice. + pub fn from_zonetab_file(src: &str) -> Result { + ZoneInfoParser::from_zoneinfo_str(src) + .parse_zonetab() + .map_err(ZoneInfoError::Parse) + } + /// Extend the current `ZoneInfoCompiler` data from another `ZoneInfoCompiler`. pub fn extend(&mut self, other: Self) { self.rules.extend(other.rules); self.zones.extend(other.zones); self.links.extend(other.links); self.pack_rat.extend(other.pack_rat); + self.zone_tab.extend(other.zone_tab); } } diff --git a/deps/temporal/zoneinfo/src/parser.rs b/deps/temporal/zoneinfo/src/parser.rs index efe7606b6e61f7..6b0186cea12eca 100644 --- a/deps/temporal/zoneinfo/src/parser.rs +++ b/deps/temporal/zoneinfo/src/parser.rs @@ -11,7 +11,7 @@ use alloc::{borrow::ToOwned, string::String, vec, vec::Vec}; use crate::{ rule::{Rule, Rules}, zone::ZoneRecord, - ZoneInfoData, + ZoneInfoData, ZoneTabEntry, }; /// The zoneinfo parsing error @@ -219,4 +219,31 @@ impl<'data> ZoneInfoParser<'data> { } Ok(zoneinfo) } + + /// Parse the provided lines + pub fn parse_zonetab(&mut self) -> Result { + let mut zoneinfo = ZoneInfoData::default(); + let mut context = LineParseContext::default(); + + // The allow clippy is used in favor of for so that `ZoneTable` can + // iterate and parse it's own lines in `Zone::parse_full_table`. + #[allow(clippy::while_let_on_iterator)] + while let Some(line) = self.lines.peek() { + // Check if line is empty or a comment + if !line.is_empty() && !line.starts_with("#") { + let mut splits = line.split_whitespace(); + let country_code = next_split(&mut splits, &context)?; + let coordinates_raw = next_split(&mut splits, &context)?; + let tz = next_split(&mut splits, &context)?; + zoneinfo.zone_tab.push(ZoneTabEntry { + country_code: country_code.into(), + coordinates_raw: coordinates_raw.into(), + tz: tz.into(), + }) + } + self.lines.next(); + context.line_number += 1; + } + Ok(zoneinfo) + } }