summaryrefslogtreecommitdiff
path: root/vendor/time
diff options
context:
space:
mode:
authormo khan <mo@mokhan.ca>2025-07-02 18:36:06 -0600
committermo khan <mo@mokhan.ca>2025-07-02 18:36:06 -0600
commit8cdfa445d6629ffef4cb84967ff7017654045bc2 (patch)
tree22f0b0907c024c78d26a731e2e1f5219407d8102 /vendor/time
parent4351c74c7c5f97156bc94d3a8549b9940ac80e3f (diff)
chore: add vendor directory
Diffstat (limited to 'vendor/time')
-rw-r--r--vendor/time/.cargo-checksum.json1
-rw-r--r--vendor/time/Cargo.lock926
-rw-r--r--vendor/time/Cargo.toml298
-rw-r--r--vendor/time/LICENSE-Apache177
-rw-r--r--vendor/time/LICENSE-MIT19
-rw-r--r--vendor/time/README.md51
-rw-r--r--vendor/time/src/date.rs1490
-rw-r--r--vendor/time/src/duration.rs1598
-rw-r--r--vendor/time/src/error/component_range.rs114
-rw-r--r--vendor/time/src/error/conversion_range.rs36
-rw-r--r--vendor/time/src/error/different_variant.rs34
-rw-r--r--vendor/time/src/error/format.rs113
-rw-r--r--vendor/time/src/error/indeterminate_offset.rs35
-rw-r--r--vendor/time/src/error/invalid_format_description.rs132
-rw-r--r--vendor/time/src/error/invalid_variant.rs34
-rw-r--r--vendor/time/src/error/mod.rs131
-rw-r--r--vendor/time/src/error/parse.rs109
-rw-r--r--vendor/time/src/error/parse_from_description.rs53
-rw-r--r--vendor/time/src/error/try_from_parsed.rs71
-rw-r--r--vendor/time/src/ext/digit_count.rs26
-rw-r--r--vendor/time/src/ext/instant.rs98
-rw-r--r--vendor/time/src/ext/mod.rs13
-rw-r--r--vendor/time/src/ext/numerical_duration.rs140
-rw-r--r--vendor/time/src/ext/numerical_std_duration.rs192
-rw-r--r--vendor/time/src/format_description/borrowed_format_item.rs106
-rw-r--r--vendor/time/src/format_description/component.rs44
-rw-r--r--vendor/time/src/format_description/mod.rs41
-rw-r--r--vendor/time/src/format_description/modifier.rs434
-rw-r--r--vendor/time/src/format_description/owned_format_item.rs158
-rw-r--r--vendor/time/src/format_description/parse/ast.rs384
-rw-r--r--vendor/time/src/format_description/parse/format_item.rs549
-rw-r--r--vendor/time/src/format_description/parse/lexer.rs284
-rw-r--r--vendor/time/src/format_description/parse/mod.rs262
-rw-r--r--vendor/time/src/format_description/parse/strftime.rs487
-rw-r--r--vendor/time/src/format_description/well_known/iso8601.rs257
-rw-r--r--vendor/time/src/format_description/well_known/iso8601/adt_hack.rs247
-rw-r--r--vendor/time/src/format_description/well_known/rfc2822.rs30
-rw-r--r--vendor/time/src/format_description/well_known/rfc3339.rs30
-rw-r--r--vendor/time/src/formatting/formattable.rs312
-rw-r--r--vendor/time/src/formatting/iso8601.rs142
-rw-r--r--vendor/time/src/formatting/mod.rs517
-rw-r--r--vendor/time/src/hint.rs26
-rw-r--r--vendor/time/src/instant.rs287
-rw-r--r--vendor/time/src/internal_macros.rs209
-rw-r--r--vendor/time/src/interop/js_sys_date_offsetdatetime.rs27
-rw-r--r--vendor/time/src/interop/js_sys_date_utcdatetime.rs26
-rw-r--r--vendor/time/src/interop/mod.rs28
-rw-r--r--vendor/time/src/interop/offsetdatetime_systemtime.rs75
-rw-r--r--vendor/time/src/interop/offsetdatetime_utcdatetime.rs68
-rw-r--r--vendor/time/src/interop/utcdatetime_systemtime.rs75
-rw-r--r--vendor/time/src/lib.rs153
-rw-r--r--vendor/time/src/macros.rs149
-rw-r--r--vendor/time/src/month.rs273
-rw-r--r--vendor/time/src/offset_date_time.rs1511
-rw-r--r--vendor/time/src/parsing/combinator/mod.rs194
-rw-r--r--vendor/time/src/parsing/combinator/rfc/iso8601.rs177
-rw-r--r--vendor/time/src/parsing/combinator/rfc/mod.rs10
-rw-r--r--vendor/time/src/parsing/combinator/rfc/rfc2234.rs13
-rw-r--r--vendor/time/src/parsing/combinator/rfc/rfc2822.rs108
-rw-r--r--vendor/time/src/parsing/component.rs379
-rw-r--r--vendor/time/src/parsing/iso8601.rs332
-rw-r--r--vendor/time/src/parsing/mod.rs57
-rw-r--r--vendor/time/src/parsing/parsable.rs800
-rw-r--r--vendor/time/src/parsing/parsed.rs1118
-rw-r--r--vendor/time/src/parsing/shim.rs50
-rw-r--r--vendor/time/src/primitive_date_time.rs1050
-rw-r--r--vendor/time/src/quickcheck.rs230
-rw-r--r--vendor/time/src/rand.rs90
-rw-r--r--vendor/time/src/serde/iso8601.rs76
-rw-r--r--vendor/time/src/serde/mod.rs535
-rw-r--r--vendor/time/src/serde/rfc2822.rs71
-rw-r--r--vendor/time/src/serde/rfc3339.rs71
-rw-r--r--vendor/time/src/serde/timestamp/microseconds.rs63
-rw-r--r--vendor/time/src/serde/timestamp/milliseconds.rs63
-rw-r--r--vendor/time/src/serde/timestamp/milliseconds_i64.rs66
-rw-r--r--vendor/time/src/serde/timestamp/mod.rs65
-rw-r--r--vendor/time/src/serde/timestamp/nanoseconds.rs61
-rw-r--r--vendor/time/src/serde/visitor.rs355
-rw-r--r--vendor/time/src/sys/local_offset_at/imp.rs8
-rw-r--r--vendor/time/src/sys/local_offset_at/mod.rs23
-rw-r--r--vendor/time/src/sys/local_offset_at/unix.rs101
-rw-r--r--vendor/time/src/sys/local_offset_at/wasm_js.rs16
-rw-r--r--vendor/time/src/sys/local_offset_at/windows.rs113
-rw-r--r--vendor/time/src/sys/mod.rs11
-rw-r--r--vendor/time/src/sys/refresh_tz/imp.rs9
-rw-r--r--vendor/time/src/sys/refresh_tz/mod.rs17
-rw-r--r--vendor/time/src/sys/refresh_tz/unix.rs48
-rw-r--r--vendor/time/src/tests.rs104
-rw-r--r--vendor/time/src/time.rs937
-rw-r--r--vendor/time/src/utc_date_time.rs1223
-rw-r--r--vendor/time/src/utc_offset.rs464
-rw-r--r--vendor/time/src/util.rs105
-rw-r--r--vendor/time/src/weekday.rs220
93 files changed, 22515 insertions, 0 deletions
diff --git a/vendor/time/.cargo-checksum.json b/vendor/time/.cargo-checksum.json
new file mode 100644
index 00000000..96475fc6
--- /dev/null
+++ b/vendor/time/.cargo-checksum.json
@@ -0,0 +1 @@
+{"files":{"Cargo.lock":"54ec18fc70d29545aedf23b042a08cc9362636c69ec2a61c03d6c12b74d93a6b","Cargo.toml":"266015f9745494d625f3ebfd148d72c282a1ec2bb5a34c88012b3c2c31f87f04","LICENSE-Apache":"0d542e0c8804e39aa7f37eb00da5a762149dc682d7829451287e11b938e94594","LICENSE-MIT":"2537228d9a1b44a5dc595241349cae7090b326c8de165aaf89bfddef4a00d0fc","README.md":"28ca0b1f1e88d8d2b2fa7ad2614daa06c301040d6d2980f90508e92283d47daf","src/date.rs":"8fa1c067f62882bf66c2f66b7a84d152f4cc0cd67d88551b37af19aeaf92faa4","src/duration.rs":"4af9d384d1a18653e2214bc79d94fa921725199e57b6241bc785196fc6affde1","src/error/component_range.rs":"f9ad9b0688088e16ec4299348f172ea769bbc85e8fa5c254c91b06c286d2c739","src/error/conversion_range.rs":"972abb765370070de01e2fc2e1bb1e80808a069e6213577d7beaca02e1d707c3","src/error/different_variant.rs":"107bef7b3addd7108b36a2da8389f611d4482f34a5b63429841141e05c8cb30c","src/error/format.rs":"086bfdd271e8b28d59eb07568bc6ad6a6296c2d74786a3e076d74c6140dc46bf","src/error/indeterminate_offset.rs":"1f52f9ea107847fa781399cfcc8046451d70155fb497486c80b2138f82782941","src/error/invalid_format_description.rs":"16eafff868a943877ef6d9f36ae2b32775e30c5a5803ef93731449c02f6f54f6","src/error/invalid_variant.rs":"b653a3e6e902f06cb9f2e0366c4da84b92e8bdb03164c2f8cb15fe66415706e4","src/error/mod.rs":"336265f0a88d01305f749e6382edfe6ebdf61002ff2cb2d6e7f575e03e977398","src/error/parse.rs":"170be4ed1a058342ac07f61330f594512aec30d36e32261766f93a5fa8852122","src/error/parse_from_description.rs":"2de1f5b5af3d9bb358cee1c66a2721a78ee99f0ee5e0c06f159e62de7a294a5f","src/error/try_from_parsed.rs":"8c227be52653a1d33af01a8024c0fc56f1f9803f08ef01487a7eaa5833adbb57","src/ext/digit_count.rs":"d32af3cac57077870f6b31c5bd6e0da3a530a7c713aaebdcd27125d9fd8857a3","src/ext/instant.rs":"96945bc0af1de8eddef110c2d5ec9d5459dde86ba4e3e361fce5927a2388b514","src/ext/mod.rs":"dc70d230a170ddd1bf7798703d9ff7cac419aaadc82b5f8dbf46d5320322e2c5","src/ext/numerical_duration.rs":"92fe416dd1c404d97f06ced3256e664b283b44ecc272aa4307f8a7d84e602cd4","src/ext/numerical_std_duration.rs":"0ada71ca29daa0a8a8d4d7fb477f0eec2114787a345d75a2d4d42534a2a20267","src/format_description/borrowed_format_item.rs":"ac61ff3b6f1e6fa1947669c7bea7ece6d65940731cced34a66db28fdc48ebc10","src/format_description/component.rs":"b65c0ca896ea6ec8dbfc7570c69849c88cbba6031a2847dcfdce06d721a59397","src/format_description/mod.rs":"d6ca12469c42910fd459d2cf5cebf93e694220cf51a6028cca6912fbe92b96ff","src/format_description/modifier.rs":"b7e6c637aa0f149aace9425285df43974b4c7539ee40bc52b777f4107b64dfef","src/format_description/owned_format_item.rs":"bfdf371ebef1125161e364fba745efc5ab3aebe1d0c9570e85cd9396b391f96d","src/format_description/parse/ast.rs":"645e7bce15323529902e9bd22c2a2e06beaa0af934e203e67031b5269a159c46","src/format_description/parse/format_item.rs":"c8ef68b6b0f882e4896033c9761b7f384f09626e8c438aea2e53d2966fb00318","src/format_description/parse/lexer.rs":"8f5bc750f83489e2a5fdc2e5e00ed8f0e5def0a376e9da541fc5fedad709a2c0","src/format_description/parse/mod.rs":"715d5bddfd98f1c1d6b15fe3797b61f2311561c29050fea4497af6f6efae3e99","src/format_description/parse/strftime.rs":"f125b20aefe5ee2eedb32d72cec535cbbce639fccd79e1348c9d0b76bb792377","src/format_description/well_known/iso8601.rs":"30b2f495044ab4e1f3ff6a317a8b4ca2ffb46b7cc23428eca8b685c0f16518cc","src/format_description/well_known/iso8601/adt_hack.rs":"fa099ffded092ce9d875c744891253045a065fa138adf4182c3b2b7e6ca466a4","src/format_description/well_known/rfc2822.rs":"36c23394724ae12250d4193cab26887a6ff8f82ca441ea6b0d03c4f1c928b3dd","src/format_description/well_known/rfc3339.rs":"1a6318dffd3ebb6ac7cf96eae3d9b1eb44b1089cf4284fa6a7e935c6fcf1b43c","src/formatting/formattable.rs":"6c32458f3bf34144ebe7405a568acb0ac85fc71cff6ff71ae72ceff2470ca77f","src/formatting/iso8601.rs":"f99f0d206d88f5360665c18e6119b0001e88fb1a6b7c62bcad06b70021effce9","src/formatting/mod.rs":"3c013d91e54eb4c9bd7661a8a8af92c2ecf6bdc99320c7db9ec588f240bc0e39","src/hint.rs":"7ec8b5320c8e133f0c02942d3e6be83643f84f73053597909ff6a2f06aa7b591","src/instant.rs":"5c0420795708954322b0da7410424ca5b93f5c91b3b799b18e419eb52977c9b0","src/internal_macros.rs":"c1c98ff11424b6f2f05c14bed88cfa146894a4607fd87fae490451f63257e500","src/interop/js_sys_date_offsetdatetime.rs":"f4d60aa1ac398a96a89533d063f9375a7e94021eb9ef8c2ccbcb7caa2c394abf","src/interop/js_sys_date_utcdatetime.rs":"4721b739d6ca06126b236dd9bcfde6b4f35872a7cc232e7026878a383ac63e09","src/interop/mod.rs":"d8c0905e9fea22e4dddab981a020f79a637f849e17f53e5102416dbce1f6dbea","src/interop/offsetdatetime_systemtime.rs":"b59e68dd35e3f47460355a71b2b0be2fb7d239afce2bf1b8ed933abb391b532f","src/interop/offsetdatetime_utcdatetime.rs":"07b1e2d25404fb2f38cf85eb7b27c0e503e6e70bc8107877edfc578eec6323b3","src/interop/utcdatetime_systemtime.rs":"dd0c5f21d77e1cc5909feec22eb20101c9ebdea4089e278e66855159d73daed8","src/lib.rs":"82226f3f9266794e4183759cc6310f0ee541c070eb8adedf57b408e29ad5e650","src/macros.rs":"c35b4f4fbb4781dadf70a952649cedf4f4e29b3b571c8bbfa58e9f6ad4071423","src/month.rs":"aab1a041bb5b69a0c21fa7ef37e3f8a9fe6f3c05bb8432339bbf67d59773fc5d","src/offset_date_time.rs":"f528ec252117159cdf69881de4fd6ec8914b70b3492a380ebbc4a188d5326645","src/parsing/combinator/mod.rs":"e49d14f7d0c38a847d9f5f2e63d466464641d365f1d39c48d1a455ebe6632ec5","src/parsing/combinator/rfc/iso8601.rs":"af40a366ebcdf577e5c16e75331d7e8d4ded26afa88ea9deba0615449fe10fb1","src/parsing/combinator/rfc/mod.rs":"f30b75d248f5ae92c27646d504703f5489185afb76c998cc4375437b3d15c822","src/parsing/combinator/rfc/rfc2234.rs":"08e2813c6d40c0dae881875fe0417ae06886c73679256587e33186e46b3c3bae","src/parsing/combinator/rfc/rfc2822.rs":"6c1f4d2c352aeb79c6d1b49bae6105c472859ce057a030a4cb0aa28b2853cf93","src/parsing/component.rs":"c4d24849e3f8fc14651056996c55f7e5a5ab342f64377c3bb223437c12acb620","src/parsing/iso8601.rs":"38ea74f81388e8beba1f94e01c3b372f566d0a06b9879b21c009aa818c81bbc9","src/parsing/mod.rs":"9f4e580bc88993c7ddefa184bbcb5b34723158d2f303d90b13def2d8f9d808a1","src/parsing/parsable.rs":"9227330b7341b5b76b9beab6aff23b6a1dcb0e91120065a5bec16b3f88d4d0ec","src/parsing/parsed.rs":"17ac85ca457f723ab28719e6a84dc49acc600a4a72cdf86410b187969a5f22db","src/parsing/shim.rs":"46efc374bc3129e28936a850143fff8e42aafe10c69ebbb904195aaeca26adc9","src/primitive_date_time.rs":"d0c4caf3ddb4eca2acd519bf188aab3f58d92249a412aa44ceb34542fc6b23d5","src/quickcheck.rs":"aa7e5417c70d7a99046b6af6974108ebed41c676b80b7f67cf7f3153d4cdd72f","src/rand.rs":"dd7228d1008246d33f2dee3f81e2a66ff12c257d4e89aa468903fe32bc7038c4","src/serde/iso8601.rs":"9c7a856213b95d2d7d7bd6a244aea36de03fca92ebfd2c32dea9a9bb11e1730b","src/serde/mod.rs":"7d8ab3dfb84b3e98f52a428dba0c2542e5b3e76082f551310db0006ef0a4fd64","src/serde/rfc2822.rs":"c3d577f4fcb9b70c5b7127d343bcd4d8449732f68fba333ef2c6013daa6e2ece","src/serde/rfc3339.rs":"4811b3e304ccce4e22803ee7e4a3466d0f3ecc3b4076ca74c9cca2506971eb0d","src/serde/timestamp/microseconds.rs":"7b8a0f6e455ddb6c50ed4a8473ea68cf9aacb31af36ccc058b68fa3bb5f3246d","src/serde/timestamp/milliseconds.rs":"df995f05f340f0429697269aa152a39b0beca45e1b4d8e60f4a6bb27f09a4d88","src/serde/timestamp/milliseconds_i64.rs":"9debcd18cc50bef9c935d25c6edb2827a0f6bb19b426c326349925ae38466e6f","src/serde/timestamp/mod.rs":"8c8349e0e9833480667a3fc7dc31c7b67610467ea36ce0fb24f5a47a2ebb1da5","src/serde/timestamp/nanoseconds.rs":"a46b1e60e8b19792a26ebdab33cba53db95cb13e3c4d9675a17b1491e9fb2940","src/serde/visitor.rs":"0b6bc76b88eb486b783d16c42a8f3af65c610fc8ffa07dd294dbfe0163f6e0b4","src/sys/local_offset_at/imp.rs":"4b6e57f02566364270ac9b7e1540290a5658a296f7e911f988264d103e420326","src/sys/local_offset_at/mod.rs":"0090b833161f0e69dd150bd8fdb599f2a4095475afbd5f7441ae6a363c6a4cea","src/sys/local_offset_at/unix.rs":"bb21dbe063889ceb409f54eee74d54690dc62b8ba840929581d6e827ca291f77","src/sys/local_offset_at/wasm_js.rs":"7cdacf5548a89a00265764ef07c1abb2ea1a3211f1ec720932b066f1d18b2f20","src/sys/local_offset_at/windows.rs":"90c16515d7ac29961bd0b8af92e38c7999f260bfd3438c9935fee65e8c0cc1e9","src/sys/mod.rs":"5e5649775aff43afa68d3ba0ca193273fd412e2de50e532828d7de65a1327f44","src/sys/refresh_tz/imp.rs":"c5265e17bdf1d0e676e7f75ca3a39e84c5d19d24de3d7f37ab0ce0e0f001d3b9","src/sys/refresh_tz/mod.rs":"0399000db309480debdaea9a61f0fad044f6acc4e22f8f7c49d7ea9e2e4877ab","src/sys/refresh_tz/unix.rs":"7a36ccb9efd23d264727fbb4cffcb5de5ed249b8216bbf6389fe10db22a70d30","src/tests.rs":"4cf40de5c6ffd670b9672ead5b3f25137f8214b1a435d298bd16ce467e72b040","src/time.rs":"da5a1bd6ce70547b8351297a0588c460894148b815f5c2008d61ab4102fb963a","src/utc_date_time.rs":"4bf3d0a07de1b5421bbc72cdfe21a297c311672a5618fec92e0a822295224599","src/utc_offset.rs":"3a9cd709e25837362778c550204486d4b4e6b4ff37b30cd87b4084163d06ed26","src/util.rs":"ccbfa06d000c83d8acef73a4576350305e77a547bbc2c67415a46b65f2c8c7da","src/weekday.rs":"daa82e07fa1d5291b7ab13b5dbcc1375f6ba4f8267abfbfea4fab4dae063d324"},"package":"8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40"} \ No newline at end of file
diff --git a/vendor/time/Cargo.lock b/vendor/time/Cargo.lock
new file mode 100644
index 00000000..27fa70c7
--- /dev/null
+++ b/vendor/time/Cargo.lock
@@ -0,0 +1,926 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "aho-corasick"
+version = "1.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "anes"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299"
+
+[[package]]
+name = "anstyle"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87"
+
+[[package]]
+name = "autocfg"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
+
+[[package]]
+name = "bitflags"
+version = "2.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf"
+
+[[package]]
+name = "bumpalo"
+version = "3.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec"
+
+[[package]]
+name = "cast"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
+
+[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
+[[package]]
+name = "ciborium"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e"
+dependencies = [
+ "ciborium-io",
+ "ciborium-ll",
+ "serde",
+]
+
+[[package]]
+name = "ciborium-io"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757"
+
+[[package]]
+name = "ciborium-ll"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9"
+dependencies = [
+ "ciborium-io",
+ "half",
+]
+
+[[package]]
+name = "clap"
+version = "4.4.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e578d6ec4194633722ccf9544794b71b1385c3c027efe0c55db226fc880865c"
+dependencies = [
+ "clap_builder",
+]
+
+[[package]]
+name = "clap_builder"
+version = "4.4.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4df4df40ec50c46000231c914968278b1eb05098cf8f1b3a518a95030e71d1c7"
+dependencies = [
+ "anstyle",
+ "clap_lex",
+]
+
+[[package]]
+name = "clap_lex"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1"
+
+[[package]]
+name = "criterion"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f2b12d017a929603d80db1831cd3a24082f8137ce19c69e6447f54f5fc8d692f"
+dependencies = [
+ "anes",
+ "cast",
+ "ciborium",
+ "clap",
+ "criterion-plot",
+ "is-terminal",
+ "itertools",
+ "num-traits",
+ "once_cell",
+ "oorandom",
+ "regex",
+ "serde",
+ "serde_derive",
+ "serde_json",
+ "tinytemplate",
+ "walkdir",
+]
+
+[[package]]
+name = "criterion-plot"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1"
+dependencies = [
+ "cast",
+ "itertools",
+]
+
+[[package]]
+name = "crunchy"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
+
+[[package]]
+name = "deranged"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "28cfac68e08048ae1883171632c2aef3ebc555621ae56fbccce1cbf22dd7f058"
+dependencies = [
+ "powerfmt",
+ "quickcheck",
+ "rand 0.8.5",
+ "rand 0.9.0",
+ "serde",
+]
+
+[[package]]
+name = "either"
+version = "1.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
+
+[[package]]
+name = "equivalent"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
+
+[[package]]
+name = "errno"
+version = "0.3.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245"
+dependencies = [
+ "libc",
+ "windows-sys",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.2.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "wasi",
+]
+
+[[package]]
+name = "glob"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
+
+[[package]]
+name = "half"
+version = "2.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bc52e53916c08643f1b56ec082790d1e86a32e58dc5268f897f313fbae7b4872"
+dependencies = [
+ "cfg-if",
+ "crunchy",
+]
+
+[[package]]
+name = "hashbrown"
+version = "0.15.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
+
+[[package]]
+name = "hermit-abi"
+version = "0.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5d3d0e0f38255e7fa3cf31335b3a56f05febd18025f4db5ef7a0cfb4f8da651f"
+
+[[package]]
+name = "indexmap"
+version = "2.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652"
+dependencies = [
+ "equivalent",
+ "hashbrown",
+]
+
+[[package]]
+name = "is-terminal"
+version = "0.4.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0bad00257d07be169d870ab665980b06cdb366d792ad690bf2e76876dc503455"
+dependencies = [
+ "hermit-abi",
+ "rustix",
+ "windows-sys",
+]
+
+[[package]]
+name = "itertools"
+version = "0.10.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
+dependencies = [
+ "either",
+]
+
+[[package]]
+name = "itoa"
+version = "1.0.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674"
+
+[[package]]
+name = "js-sys"
+version = "0.3.67"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a1d36f1235bc969acba30b7f5990b864423a6068a10f7c90ae8f0112e3a59d1"
+dependencies = [
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "libc"
+version = "0.2.152"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7"
+
+[[package]]
+name = "linux-raw-sys"
+version = "0.4.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c"
+
+[[package]]
+name = "log"
+version = "0.4.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
+
+[[package]]
+name = "memchr"
+version = "2.7.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
+
+[[package]]
+name = "num-conv"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
+
+[[package]]
+name = "num-traits"
+version = "0.2.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "num_threads"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "once_cell"
+version = "1.19.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
+
+[[package]]
+name = "oorandom"
+version = "11.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575"
+
+[[package]]
+name = "powerfmt"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
+
+[[package]]
+name = "ppv-lite86"
+version = "0.2.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.93"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quickcheck"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "588f6378e4dd99458b60ec275b4477add41ce4fa9f64dcba6f15adccb19b50d6"
+dependencies = [
+ "rand 0.8.5",
+]
+
+[[package]]
+name = "quickcheck_macros"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b22a693222d716a9587786f37ac3f6b4faedb5b80c23914e7303ff5a1d8016e9"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.38"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "rand"
+version = "0.8.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
+dependencies = [
+ "libc",
+ "rand_chacha",
+ "rand_core 0.6.4",
+]
+
+[[package]]
+name = "rand"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94"
+dependencies = [
+ "rand_core 0.9.3",
+ "zerocopy",
+]
+
+[[package]]
+name = "rand_chacha"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
+dependencies = [
+ "ppv-lite86",
+ "rand_core 0.6.4",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
+dependencies = [
+ "getrandom",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38"
+
+[[package]]
+name = "regex"
+version = "1.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-automata",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-automata"
+version = "0.4.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-syntax"
+version = "0.8.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
+
+[[package]]
+name = "relative-path"
+version = "1.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ba39f3699c378cd8970968dcbff9c43159ea4cfbd88d43c00b22f2ef10a435d2"
+
+[[package]]
+name = "rstest"
+version = "0.23.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0a2c585be59b6b5dd66a9d2084aa1d8bd52fbdb806eafdeffb52791147862035"
+dependencies = [
+ "rstest_macros",
+ "rustc_version",
+]
+
+[[package]]
+name = "rstest_macros"
+version = "0.23.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "825ea780781b15345a146be27eaefb05085e337e869bff01b4306a4fd4a9ad5a"
+dependencies = [
+ "cfg-if",
+ "glob",
+ "proc-macro2",
+ "quote",
+ "regex",
+ "relative-path",
+ "rustc_version",
+ "syn 2.0.96",
+ "unicode-ident",
+]
+
+[[package]]
+name = "rstest_reuse"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b3a8fb4672e840a587a66fc577a5491375df51ddb88f2a2c2a792598c326fe14"
+dependencies = [
+ "quote",
+ "rand 0.8.5",
+ "syn 2.0.96",
+]
+
+[[package]]
+name = "rustc_version"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92"
+dependencies = [
+ "semver",
+]
+
+[[package]]
+name = "rustix"
+version = "0.38.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "322394588aaf33c24007e8bb3238ee3e4c5c09c084ab32bc73890b99ff326bca"
+dependencies = [
+ "bitflags",
+ "errno",
+ "libc",
+ "linux-raw-sys",
+ "windows-sys",
+]
+
+[[package]]
+name = "ryu"
+version = "1.0.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
+
+[[package]]
+name = "same-file"
+version = "1.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
+dependencies = [
+ "winapi-util",
+]
+
+[[package]]
+name = "semver"
+version = "1.0.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0"
+
+[[package]]
+name = "serde"
+version = "1.0.217"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.217"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.96",
+]
+
+[[package]]
+name = "serde_json"
+version = "1.0.137"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "930cfb6e6abf99298aaad7d29abbef7a9999a9a8806a40088f55f0dcec03146b"
+dependencies = [
+ "itoa",
+ "memchr",
+ "ryu",
+ "serde",
+]
+
+[[package]]
+name = "serde_spanned"
+version = "0.6.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "serde_test"
+version = "1.0.176"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5a2f49ace1498612d14f7e0b8245519584db8299541dfe31a06374a828d620ab"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "syn"
+version = "1.0.109"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "syn"
+version = "2.0.96"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "target-triple"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "42a4d50cdb458045afc8131fd91b64904da29548bcb63c7236e0844936c13078"
+
+[[package]]
+name = "termcolor"
+version = "1.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755"
+dependencies = [
+ "winapi-util",
+]
+
+[[package]]
+name = "time"
+version = "0.3.41"
+dependencies = [
+ "criterion",
+ "deranged",
+ "itoa",
+ "js-sys",
+ "libc",
+ "num-conv",
+ "num_threads",
+ "powerfmt",
+ "quickcheck",
+ "quickcheck_macros",
+ "rand 0.8.5",
+ "rstest",
+ "rstest_reuse",
+ "serde",
+ "serde_json",
+ "serde_test",
+ "time-core",
+ "time-macros",
+ "trybuild",
+]
+
+[[package]]
+name = "time-core"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c"
+
+[[package]]
+name = "time-macros"
+version = "0.2.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49"
+dependencies = [
+ "num-conv",
+ "time-core",
+]
+
+[[package]]
+name = "tinytemplate"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc"
+dependencies = [
+ "serde",
+ "serde_json",
+]
+
+[[package]]
+name = "toml"
+version = "0.8.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e"
+dependencies = [
+ "serde",
+ "serde_spanned",
+ "toml_datetime",
+ "toml_edit",
+]
+
+[[package]]
+name = "toml_datetime"
+version = "0.6.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "toml_edit"
+version = "0.22.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5"
+dependencies = [
+ "indexmap",
+ "serde",
+ "serde_spanned",
+ "toml_datetime",
+ "winnow",
+]
+
+[[package]]
+name = "trybuild"
+version = "1.0.102"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9f14b5c02a137632f68194ec657ecb92304138948e8957c932127eb1b58c23be"
+dependencies = [
+ "glob",
+ "serde",
+ "serde_derive",
+ "serde_json",
+ "target-triple",
+ "termcolor",
+ "toml",
+]
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83"
+
+[[package]]
+name = "walkdir"
+version = "2.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee"
+dependencies = [
+ "same-file",
+ "winapi-util",
+]
+
+[[package]]
+name = "wasi"
+version = "0.11.0+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
+
+[[package]]
+name = "wasm-bindgen"
+version = "0.2.90"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b1223296a201415c7fad14792dbefaace9bd52b62d33453ade1c5b5f07555406"
+dependencies = [
+ "cfg-if",
+ "wasm-bindgen-macro",
+]
+
+[[package]]
+name = "wasm-bindgen-backend"
+version = "0.2.90"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fcdc935b63408d58a32f8cc9738a0bffd8f05cc7c002086c6ef20b7312ad9dcd"
+dependencies = [
+ "bumpalo",
+ "log",
+ "once_cell",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.96",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-macro"
+version = "0.2.90"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3e4c238561b2d428924c49815533a8b9121c664599558a5d9ec51f8a1740a999"
+dependencies = [
+ "quote",
+ "wasm-bindgen-macro-support",
+]
+
+[[package]]
+name = "wasm-bindgen-macro-support"
+version = "0.2.90"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bae1abb6806dc1ad9e560ed242107c0f6c84335f1749dd4e8ddb012ebd5e25a7"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.96",
+ "wasm-bindgen-backend",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-shared"
+version = "0.2.90"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4d91413b1c31d7539ba5ef2451af3f0b833a005eb27a631cec32bc0635a8602b"
+
+[[package]]
+name = "winapi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+dependencies = [
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+
+[[package]]
+name = "winapi-util"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
+
+[[package]]
+name = "windows-sys"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
+dependencies = [
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd"
+dependencies = [
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc",
+]
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
+
+[[package]]
+name = "winnow"
+version = "0.6.24"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c8d71a593cc5c42ad7876e2c1fda56f314f3754c084128833e64f1345ff8a03a"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "zerocopy"
+version = "0.8.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fd97444d05a4328b90e75e503a34bad781f14e28a823ad3557f0750df1ebcbc6"
+dependencies = [
+ "zerocopy-derive",
+]
+
+[[package]]
+name = "zerocopy-derive"
+version = "0.8.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6352c01d0edd5db859a63e2605f4ea3183ddbd15e2c4a9e7d32184df75e4f154"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.96",
+]
diff --git a/vendor/time/Cargo.toml b/vendor/time/Cargo.toml
new file mode 100644
index 00000000..fdffe750
--- /dev/null
+++ b/vendor/time/Cargo.toml
@@ -0,0 +1,298 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# When uploading crates to the registry Cargo will automatically
+# "normalize" Cargo.toml files for maximal compatibility
+# with all versions of Cargo and also rewrite `path` dependencies
+# to registry (e.g., crates.io) dependencies.
+#
+# If you are reading this file be aware that the original Cargo.toml
+# will likely look very different (and much more reasonable).
+# See Cargo.toml.orig for the original contents.
+
+[package]
+edition = "2021"
+rust-version = "1.67.1"
+name = "time"
+version = "0.3.41"
+authors = [
+ "Jacob Pratt <open-source@jhpratt.dev>",
+ "Time contributors",
+]
+build = false
+include = [
+ "src/**/*",
+ "LICENSE-*",
+ "README.md",
+]
+autolib = false
+autobins = false
+autoexamples = false
+autotests = false
+autobenches = false
+description = "Date and time library. Fully interoperable with the standard library. Mostly compatible with #![no_std]."
+homepage = "https://time-rs.github.io"
+readme = "README.md"
+keywords = [
+ "date",
+ "time",
+ "calendar",
+ "duration",
+]
+categories = [
+ "date-and-time",
+ "no-std",
+ "parser-implementations",
+ "value-formatting",
+]
+license = "MIT OR Apache-2.0"
+repository = "https://github.com/time-rs/time"
+
+[package.metadata.docs.rs]
+all-features = true
+rustdoc-args = ["--generate-link-to-definition"]
+targets = ["x86_64-unknown-linux-gnu"]
+
+[features]
+alloc = ["serde?/alloc"]
+default = ["std"]
+formatting = [
+ "dep:itoa",
+ "std",
+ "time-macros?/formatting",
+]
+large-dates = ["time-macros?/large-dates"]
+local-offset = [
+ "std",
+ "dep:libc",
+ "dep:num_threads",
+]
+macros = ["dep:time-macros"]
+parsing = ["time-macros?/parsing"]
+quickcheck = [
+ "dep:quickcheck",
+ "alloc",
+ "deranged/quickcheck",
+]
+rand = [
+ "dep:rand",
+ "deranged/rand",
+]
+serde = [
+ "dep:serde",
+ "time-macros?/serde",
+ "deranged/serde",
+]
+serde-human-readable = [
+ "serde",
+ "formatting",
+ "parsing",
+]
+serde-well-known = [
+ "serde",
+ "formatting",
+ "parsing",
+]
+std = [
+ "alloc",
+ "deranged/std",
+]
+wasm-bindgen = ["dep:js-sys"]
+
+[lib]
+name = "time"
+path = "src/lib.rs"
+bench = false
+
+[dependencies.deranged]
+version = "0.4.0"
+features = ["powerfmt"]
+default-features = false
+
+[dependencies.itoa]
+version = "1.0.1"
+optional = true
+
+[dependencies.num-conv]
+version = "0.1.0"
+
+[dependencies.powerfmt]
+version = "0.2.0"
+default-features = false
+
+[dependencies.quickcheck]
+version = "1.0.3"
+optional = true
+default-features = false
+
+[dependencies.rand]
+version = "0.8.4"
+optional = true
+default-features = false
+
+[dependencies.serde]
+version = "1.0.184"
+optional = true
+default-features = false
+
+[dependencies.time-core]
+version = "=0.1.4"
+
+[dependencies.time-macros]
+version = "=0.2.22"
+optional = true
+
+[dev-dependencies.num-conv]
+version = "0.1.0"
+
+[dev-dependencies.quickcheck_macros]
+version = "1.0.0"
+
+[dev-dependencies.rand]
+version = "0.8.4"
+default-features = false
+
+[dev-dependencies.rstest]
+version = "0.23.0"
+default-features = false
+
+[dev-dependencies.rstest_reuse]
+version = "0.7.0"
+
+[dev-dependencies.serde]
+version = "1.0.184"
+features = ["derive"]
+default-features = false
+
+[dev-dependencies.serde_json]
+version = "1.0.68"
+
+[dev-dependencies.serde_test]
+version = "1.0.126"
+
+[dev-dependencies.time-macros]
+version = "=0.2.22"
+
+[target."cfg(__ui_tests)".dev-dependencies.trybuild]
+version = "1.0.102"
+
+[target.'cfg(all(target_family = "wasm", not(any(target_os = "emscripten", target_os = "wasi"))))'.dependencies.js-sys]
+version = "0.3.58"
+optional = true
+
+[target."cfg(bench)".dev-dependencies.criterion]
+version = "0.5.1"
+default-features = false
+
+[target.'cfg(target_family = "unix")'.dependencies.libc]
+version = "0.2.98"
+optional = true
+
+[target.'cfg(target_family = "unix")'.dependencies.num_threads]
+version = "0.1.2"
+optional = true
+
+[lints.clippy]
+alloc-instead-of-core = "deny"
+as-underscore = "warn"
+dbg-macro = "warn"
+decimal-literal-representation = "warn"
+explicit-auto-deref = "warn"
+get-unwrap = "warn"
+manual-let-else = "warn"
+missing-docs-in-private-items = "warn"
+missing-enforced-import-renames = "warn"
+obfuscated-if-else = "warn"
+print-stdout = "warn"
+semicolon-outside-block = "warn"
+std-instead-of-core = "deny"
+todo = "warn"
+undocumented-unsafe-blocks = "deny"
+unimplemented = "warn"
+uninlined-format-args = "warn"
+unnested-or-patterns = "warn"
+unwrap-in-result = "warn"
+unwrap-used = "warn"
+use-debug = "warn"
+
+[lints.clippy.all]
+level = "warn"
+priority = -1
+
+[lints.clippy.nursery]
+level = "warn"
+priority = -1
+
+[lints.clippy.option-if-let-else]
+level = "allow"
+priority = 1
+
+[lints.clippy.redundant-pub-crate]
+level = "allow"
+priority = 1
+
+[lints.clippy.uninhabited-references]
+level = "allow"
+priority = 1
+
+[lints.rust]
+ambiguous-glob-reexports = "deny"
+clashing-extern-declarations = "deny"
+const-item-mutation = "deny"
+dangling-pointers-from-temporaries = "deny"
+deref-nullptr = "deny"
+drop-bounds = "deny"
+future-incompatible = "deny"
+hidden-glob-reexports = "deny"
+improper-ctypes = "deny"
+improper-ctypes-definitions = "deny"
+invalid-from-utf8 = "deny"
+invalid-macro-export-arguments = "deny"
+invalid-nan-comparisons = "deny"
+invalid-reference-casting = "deny"
+invalid-value = "deny"
+keyword-idents = "warn"
+let-underscore = "warn"
+macro-use-extern-crate = "warn"
+meta-variable-misuse = "warn"
+missing-abi = "warn"
+missing-copy-implementations = "warn"
+missing-debug-implementations = "warn"
+missing-docs = "warn"
+named-arguments-used-positionally = "deny"
+non-ascii-idents = "deny"
+noop-method-call = "warn"
+opaque-hidden-inferred-bound = "deny"
+overlapping-range-endpoints = "deny"
+single-use-lifetimes = "warn"
+suspicious-double-ref-op = "deny"
+trivial-casts = "warn"
+trivial-numeric-casts = "warn"
+unconditional-recursion = "deny"
+unnameable-test-items = "deny"
+unreachable-pub = "warn"
+unsafe-op-in-unsafe-fn = "deny"
+unstable-syntax-pre-expansion = "deny"
+unused-import-braces = "warn"
+unused-lifetimes = "warn"
+unused-qualifications = "warn"
+variant-size-differences = "warn"
+
+[lints.rust.unexpected_cfgs]
+level = "deny"
+priority = 0
+check-cfg = [
+ "cfg(__ui_tests)",
+ "cfg(bench)",
+]
+
+[lints.rust.unstable-name-collisions]
+level = "allow"
+priority = 1
+
+[lints.rust.unused]
+level = "warn"
+priority = -1
+
+[lints.rustdoc]
+private-doc-tests = "warn"
+unescaped-backticks = "warn"
diff --git a/vendor/time/LICENSE-Apache b/vendor/time/LICENSE-Apache
new file mode 100644
index 00000000..f433b1a5
--- /dev/null
+++ b/vendor/time/LICENSE-Apache
@@ -0,0 +1,177 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
diff --git a/vendor/time/LICENSE-MIT b/vendor/time/LICENSE-MIT
new file mode 100644
index 00000000..663cb2a1
--- /dev/null
+++ b/vendor/time/LICENSE-MIT
@@ -0,0 +1,19 @@
+Copyright (c) Jacob Pratt et al.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/vendor/time/README.md b/vendor/time/README.md
new file mode 100644
index 00000000..22192563
--- /dev/null
+++ b/vendor/time/README.md
@@ -0,0 +1,51 @@
+# time
+
+[![minimum rustc: 1.67.1](https://img.shields.io/badge/minimum%20rustc-1.67.1-yellowgreen?logo=rust&style=flat-square)](https://www.whatrustisit.com)
+[![version](https://img.shields.io/crates/v/time?color=blue&logo=rust&style=flat-square)](https://crates.io/crates/time)
+[![build status](https://img.shields.io/github/actions/workflow/status/time-rs/time/build.yaml?branch=main&style=flat-square)](https://github.com/time-rs/time/actions)
+[![codecov](https://codecov.io/gh/time-rs/time/branch/main/graph/badge.svg?token=yt4XSmQNKQ)](https://codecov.io/gh/time-rs/time)
+
+Documentation:
+
+- [latest release](https://docs.rs/time)
+- [main branch](https://time-rs.github.io/api/time)
+- [book](https://time-rs.github.io/book)
+
+## Minimum Rust version policy
+
+`time` is guaranteed to compile with the latest stable release of Rust in addition to the two prior
+minor releases. For example, if the latest stable Rust release is 1.70, then `time` is guaranteed to
+compile with Rust 1.68, 1.69, and 1.70.
+
+The minimum supported Rust version may be increased to one of the aforementioned versions if doing
+so provides the end user a benefit. However, the minimum supported Rust version may also be bumped
+to a version four minor releases prior to the most recent stable release if doing so improves code
+quality or maintainability.
+
+For interoperability with third-party crates, it is guaranteed that there exists a version of that
+crate that supports the minimum supported Rust version of `time`. This does not mean that the latest
+version of the third-party crate supports the minimum supported Rust version of `time`.
+
+## Contributing
+
+Contributions are always welcome! If you have an idea, it's best to float it by me before working on
+it to ensure no effort is wasted. If there's already an open issue for it, knock yourself out.
+Internal documentation can be viewed [here](https://time-rs.github.io/internal-api/time).
+
+If you have any questions, feel free to use [Discussions]. Don't hesitate to ask questions — that's
+what I'm here for!
+
+[Discussions]: https://github.com/time-rs/time/discussions
+
+## License
+
+This project is licensed under either of
+
+- [Apache License, Version 2.0](https://github.com/time-rs/time/blob/main/LICENSE-Apache)
+- [MIT license](https://github.com/time-rs/time/blob/main/LICENSE-MIT)
+
+at your option.
+
+Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in
+time by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any
+additional terms or conditions.
diff --git a/vendor/time/src/date.rs b/vendor/time/src/date.rs
new file mode 100644
index 00000000..3772c2da
--- /dev/null
+++ b/vendor/time/src/date.rs
@@ -0,0 +1,1490 @@
+//! The [`Date`] struct and its associated `impl`s.
+
+#[cfg(feature = "formatting")]
+use alloc::string::String;
+use core::num::{NonZeroI32, NonZeroU8};
+use core::ops::{Add, Sub};
+use core::time::Duration as StdDuration;
+use core::{cmp, fmt};
+#[cfg(feature = "formatting")]
+use std::io;
+
+use deranged::RangedI32;
+use num_conv::prelude::*;
+use powerfmt::ext::FormatterExt;
+use powerfmt::smart_display::{self, FormatterOptions, Metadata, SmartDisplay};
+
+use crate::convert::*;
+use crate::ext::DigitCount;
+#[cfg(feature = "formatting")]
+use crate::formatting::Formattable;
+use crate::internal_macros::{
+ const_try, const_try_opt, div_floor, ensure_ranged, expect_opt, impl_add_assign,
+ impl_sub_assign,
+};
+#[cfg(feature = "parsing")]
+use crate::parsing::Parsable;
+use crate::util::{days_in_year, is_leap_year, weeks_in_year};
+use crate::{error, Duration, Month, PrimitiveDateTime, Time, Weekday};
+
+type Year = RangedI32<MIN_YEAR, MAX_YEAR>;
+
+/// The minimum valid year.
+pub(crate) const MIN_YEAR: i32 = if cfg!(feature = "large-dates") {
+ -999_999
+} else {
+ -9999
+};
+/// The maximum valid year.
+pub(crate) const MAX_YEAR: i32 = if cfg!(feature = "large-dates") {
+ 999_999
+} else {
+ 9999
+};
+
+/// Date in the proleptic Gregorian calendar.
+///
+/// By default, years between ±9999 inclusive are representable. This can be expanded to ±999,999
+/// inclusive by enabling the `large-dates` crate feature. Doing so has performance implications
+/// and introduces some ambiguities when parsing.
+#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
+pub struct Date {
+ /// Bitpacked field containing the year, ordinal, and whether the year is a leap year.
+ // | x | xxxxxxxxxxxxxxxxxxxxx | x | xxxxxxxxx |
+ // | 1 bit | 21 bits | 1 bit | 9 bits |
+ // | unassigned | year | is leap year? | ordinal |
+ // The year is 15 bits when `large-dates` is not enabled.
+ value: NonZeroI32,
+}
+
+impl Date {
+ /// The minimum valid `Date`.
+ ///
+ /// The value of this may vary depending on the feature flags enabled.
+ // Safety: `ordinal` is not zero.
+ #[allow(clippy::undocumented_unsafe_blocks)]
+ pub const MIN: Self = unsafe { Self::__from_ordinal_date_unchecked(MIN_YEAR, 1) };
+
+ /// The maximum valid `Date`.
+ ///
+ /// The value of this may vary depending on the feature flags enabled.
+ // Safety: `ordinal` is not zero.
+ #[allow(clippy::undocumented_unsafe_blocks)]
+ pub const MAX: Self =
+ unsafe { Self::__from_ordinal_date_unchecked(MAX_YEAR, days_in_year(MAX_YEAR)) };
+
+ /// Construct a `Date` from its internal representation, the validity of which must be
+ /// guaranteed by the caller.
+ ///
+ /// # Safety
+ ///
+ /// - `ordinal` must be non-zero and at most the number of days in `year`
+ /// - `is_leap_year` must be `true` if and only if `year` is a leap year
+ const unsafe fn from_parts(year: i32, is_leap_year: bool, ordinal: u16) -> Self {
+ debug_assert!(year >= MIN_YEAR);
+ debug_assert!(year <= MAX_YEAR);
+ debug_assert!(ordinal != 0);
+ debug_assert!(ordinal <= days_in_year(year));
+ debug_assert!(crate::util::is_leap_year(year) == is_leap_year);
+
+ Self {
+ // Safety: `ordinal` is not zero.
+ value: unsafe {
+ NonZeroI32::new_unchecked(
+ (year << 10) | ((is_leap_year as i32) << 9) | ordinal as i32,
+ )
+ },
+ }
+ }
+
+ /// Construct a `Date` from the year and ordinal values, the validity of which must be
+ /// guaranteed by the caller.
+ ///
+ /// # Safety
+ ///
+ /// `ordinal` must be non-zero and at most the number of days in `year`. `year` should be in the
+ /// range `MIN_YEAR..=MAX_YEAR`, but this is not a safety invariant.
+ #[doc(hidden)]
+ pub const unsafe fn __from_ordinal_date_unchecked(year: i32, ordinal: u16) -> Self {
+ // Safety: The caller must guarantee that `ordinal` is not zero.
+ unsafe { Self::from_parts(year, is_leap_year(year), ordinal) }
+ }
+
+ /// Attempt to create a `Date` from the year, month, and day.
+ ///
+ /// ```rust
+ /// # use time::{Date, Month};
+ /// assert!(Date::from_calendar_date(2019, Month::January, 1).is_ok());
+ /// assert!(Date::from_calendar_date(2019, Month::December, 31).is_ok());
+ /// ```
+ ///
+ /// ```rust
+ /// # use time::{Date, Month};
+ /// assert!(Date::from_calendar_date(2019, Month::February, 29).is_err()); // 2019 isn't a leap year.
+ /// ```
+ pub const fn from_calendar_date(
+ year: i32,
+ month: Month,
+ day: u8,
+ ) -> Result<Self, error::ComponentRange> {
+ /// Cumulative days through the beginning of a month in both common and leap years.
+ const DAYS_CUMULATIVE_COMMON_LEAP: [[u16; 12]; 2] = [
+ [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334],
+ [0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335],
+ ];
+
+ ensure_ranged!(Year: year);
+ match day {
+ 1..=28 => {}
+ 29..=31 if day <= month.length(year) => {}
+ _ => {
+ return Err(error::ComponentRange {
+ name: "day",
+ minimum: 1,
+ maximum: month.length(year) as i64,
+ value: day as i64,
+ conditional_message: Some("for the given month and year"),
+ });
+ }
+ }
+
+ // Safety: `ordinal` is not zero.
+ Ok(unsafe {
+ Self::__from_ordinal_date_unchecked(
+ year,
+ DAYS_CUMULATIVE_COMMON_LEAP[is_leap_year(year) as usize][month as usize - 1]
+ + day as u16,
+ )
+ })
+ }
+
+ /// Attempt to create a `Date` from the year and ordinal day number.
+ ///
+ /// ```rust
+ /// # use time::Date;
+ /// assert!(Date::from_ordinal_date(2019, 1).is_ok());
+ /// assert!(Date::from_ordinal_date(2019, 365).is_ok());
+ /// ```
+ ///
+ /// ```rust
+ /// # use time::Date;
+ /// assert!(Date::from_ordinal_date(2019, 366).is_err()); // 2019 isn't a leap year.
+ /// ```
+ pub const fn from_ordinal_date(year: i32, ordinal: u16) -> Result<Self, error::ComponentRange> {
+ ensure_ranged!(Year: year);
+ match ordinal {
+ 1..=365 => {}
+ 366 if is_leap_year(year) => {}
+ _ => {
+ return Err(error::ComponentRange {
+ name: "ordinal",
+ minimum: 1,
+ maximum: days_in_year(year) as i64,
+ value: ordinal as i64,
+ conditional_message: Some("for the given year"),
+ });
+ }
+ }
+
+ // Safety: `ordinal` is not zero.
+ Ok(unsafe { Self::__from_ordinal_date_unchecked(year, ordinal) })
+ }
+
+ /// Attempt to create a `Date` from the ISO year, week, and weekday.
+ ///
+ /// ```rust
+ /// # use time::{Date, Weekday::*};
+ /// assert!(Date::from_iso_week_date(2019, 1, Monday).is_ok());
+ /// assert!(Date::from_iso_week_date(2019, 1, Tuesday).is_ok());
+ /// assert!(Date::from_iso_week_date(2020, 53, Friday).is_ok());
+ /// ```
+ ///
+ /// ```rust
+ /// # use time::{Date, Weekday::*};
+ /// assert!(Date::from_iso_week_date(2019, 53, Monday).is_err()); // 2019 doesn't have 53 weeks.
+ /// ```
+ pub const fn from_iso_week_date(
+ year: i32,
+ week: u8,
+ weekday: Weekday,
+ ) -> Result<Self, error::ComponentRange> {
+ ensure_ranged!(Year: year);
+ match week {
+ 1..=52 => {}
+ 53 if week <= weeks_in_year(year) => {}
+ _ => {
+ return Err(error::ComponentRange {
+ name: "week",
+ minimum: 1,
+ maximum: weeks_in_year(year) as i64,
+ value: week as i64,
+ conditional_message: Some("for the given year"),
+ });
+ }
+ }
+
+ let adj_year = year - 1;
+ let raw = 365 * adj_year + div_floor!(adj_year, 4) - div_floor!(adj_year, 100)
+ + div_floor!(adj_year, 400);
+ let jan_4 = match (raw % 7) as i8 {
+ -6 | 1 => 8,
+ -5 | 2 => 9,
+ -4 | 3 => 10,
+ -3 | 4 => 4,
+ -2 | 5 => 5,
+ -1 | 6 => 6,
+ _ => 7,
+ };
+ let ordinal = week as i16 * 7 + weekday.number_from_monday() as i16 - jan_4;
+
+ Ok(if ordinal <= 0 {
+ // Safety: `ordinal` is not zero.
+ unsafe {
+ Self::__from_ordinal_date_unchecked(
+ year - 1,
+ (ordinal as u16).wrapping_add(days_in_year(year - 1)),
+ )
+ }
+ } else if ordinal > days_in_year(year) as i16 {
+ // Safety: `ordinal` is not zero.
+ unsafe {
+ Self::__from_ordinal_date_unchecked(year + 1, ordinal as u16 - days_in_year(year))
+ }
+ } else {
+ // Safety: `ordinal` is not zero.
+ unsafe { Self::__from_ordinal_date_unchecked(year, ordinal as u16) }
+ })
+ }
+
+ /// Create a `Date` from the Julian day.
+ ///
+ /// The algorithm to perform this conversion is derived from one provided by Peter Baum; it is
+ /// freely available [here](https://www.researchgate.net/publication/316558298_Date_Algorithms).
+ ///
+ /// ```rust
+ /// # use time::Date;
+ /// # use time_macros::date;
+ /// assert_eq!(Date::from_julian_day(0), Ok(date!(-4713 - 11 - 24)));
+ /// assert_eq!(Date::from_julian_day(2_451_545), Ok(date!(2000-01-01)));
+ /// assert_eq!(Date::from_julian_day(2_458_485), Ok(date!(2019-01-01)));
+ /// assert_eq!(Date::from_julian_day(2_458_849), Ok(date!(2019-12-31)));
+ /// ```
+ #[doc(alias = "from_julian_date")]
+ pub const fn from_julian_day(julian_day: i32) -> Result<Self, error::ComponentRange> {
+ type JulianDay = RangedI32<{ Date::MIN.to_julian_day() }, { Date::MAX.to_julian_day() }>;
+ ensure_ranged!(JulianDay: julian_day);
+ // Safety: The Julian day number is in range.
+ Ok(unsafe { Self::from_julian_day_unchecked(julian_day) })
+ }
+
+ /// Create a `Date` from the Julian day.
+ ///
+ /// # Safety
+ ///
+ /// The provided Julian day number must be between `Date::MIN.to_julian_day()` and
+ /// `Date::MAX.to_julian_day()` inclusive.
+ pub(crate) const unsafe fn from_julian_day_unchecked(julian_day: i32) -> Self {
+ debug_assert!(julian_day >= Self::MIN.to_julian_day());
+ debug_assert!(julian_day <= Self::MAX.to_julian_day());
+
+ const S: i32 = 2_500;
+ const K: i32 = 719_468 + 146_097 * S;
+ const L: i32 = 400 * S;
+
+ let julian_day = julian_day - 2_440_588;
+ let n = (julian_day + K) as u32;
+
+ let n_1 = 4 * n + 3;
+ let c = n_1 / 146_097;
+ let n_c = n_1 % 146_097 / 4;
+
+ let n_2 = 4 * n_c + 3;
+ let p_2 = 2_939_745 * n_2 as u64;
+ let z = (p_2 >> 32) as u32;
+ let n_y = p_2 as u32 / 2_939_745 / 4;
+ let y = 100 * c + z;
+
+ let j = n_y >= 306;
+ let y_g = y as i32 - L + j as i32;
+
+ let is_leap_year = is_leap_year(y_g);
+ let ordinal = if j {
+ n_y - 305
+ } else {
+ n_y + 60 + is_leap_year as u32
+ };
+
+ // Safety: `ordinal` is not zero and `is_leap_year` is correct, so long as the Julian day
+ // number is in range.
+ unsafe { Self::from_parts(y_g, is_leap_year, ordinal as u16) }
+ }
+
+ /// Whether `is_leap_year(self.year())` is `true`.
+ ///
+ /// This method is optimized to take advantage of the fact that the value is pre-computed upon
+ /// construction and stored in the bitpacked struct.
+ const fn is_in_leap_year(self) -> bool {
+ (self.value.get() >> 9) & 1 == 1
+ }
+
+ /// Get the year of the date.
+ ///
+ /// ```rust
+ /// # use time_macros::date;
+ /// assert_eq!(date!(2019-01-01).year(), 2019);
+ /// assert_eq!(date!(2019-12-31).year(), 2019);
+ /// assert_eq!(date!(2020-01-01).year(), 2020);
+ /// ```
+ pub const fn year(self) -> i32 {
+ self.value.get() >> 10
+ }
+
+ /// Get the month.
+ ///
+ /// ```rust
+ /// # use time::Month;
+ /// # use time_macros::date;
+ /// assert_eq!(date!(2019-01-01).month(), Month::January);
+ /// assert_eq!(date!(2019-12-31).month(), Month::December);
+ /// ```
+ pub const fn month(self) -> Month {
+ let ordinal = self.ordinal() as u32;
+ let jan_feb_len = 59 + self.is_in_leap_year() as u32;
+
+ let (month_adj, ordinal_adj) = if ordinal <= jan_feb_len {
+ (0, 0)
+ } else {
+ (2, jan_feb_len)
+ };
+
+ let ordinal = ordinal - ordinal_adj;
+ let month = ((ordinal * 268 + 8031) >> 13) + month_adj;
+
+ // Safety: `month` is guaranteed to be between 1 and 12 inclusive.
+ unsafe {
+ match Month::from_number(NonZeroU8::new_unchecked(month as u8)) {
+ Ok(month) => month,
+ Err(_) => core::hint::unreachable_unchecked(),
+ }
+ }
+ }
+
+ /// Get the day of the month.
+ ///
+ /// The returned value will always be in the range `1..=31`.
+ ///
+ /// ```rust
+ /// # use time_macros::date;
+ /// assert_eq!(date!(2019-01-01).day(), 1);
+ /// assert_eq!(date!(2019-12-31).day(), 31);
+ /// ```
+ pub const fn day(self) -> u8 {
+ let ordinal = self.ordinal() as u32;
+ let jan_feb_len = 59 + self.is_in_leap_year() as u32;
+
+ let ordinal_adj = if ordinal <= jan_feb_len {
+ 0
+ } else {
+ jan_feb_len
+ };
+
+ let ordinal = ordinal - ordinal_adj;
+ let month = (ordinal * 268 + 8031) >> 13;
+ let days_in_preceding_months = (month * 3917 - 3866) >> 7;
+ (ordinal - days_in_preceding_months) as u8
+ }
+
+ /// Get the day of the year.
+ ///
+ /// The returned value will always be in the range `1..=366` (`1..=365` for common years).
+ ///
+ /// ```rust
+ /// # use time_macros::date;
+ /// assert_eq!(date!(2019-01-01).ordinal(), 1);
+ /// assert_eq!(date!(2019-12-31).ordinal(), 365);
+ /// ```
+ pub const fn ordinal(self) -> u16 {
+ (self.value.get() & 0x1FF) as u16
+ }
+
+ /// Get the ISO 8601 year and week number.
+ pub(crate) const fn iso_year_week(self) -> (i32, u8) {
+ let (year, ordinal) = self.to_ordinal_date();
+
+ match ((ordinal + 10 - self.weekday().number_from_monday() as u16) / 7) as u8 {
+ 0 => (year - 1, weeks_in_year(year - 1)),
+ 53 if weeks_in_year(year) == 52 => (year + 1, 1),
+ week => (year, week),
+ }
+ }
+
+ /// Get the ISO week number.
+ ///
+ /// The returned value will always be in the range `1..=53`.
+ ///
+ /// ```rust
+ /// # use time_macros::date;
+ /// assert_eq!(date!(2019-01-01).iso_week(), 1);
+ /// assert_eq!(date!(2019-10-04).iso_week(), 40);
+ /// assert_eq!(date!(2020-01-01).iso_week(), 1);
+ /// assert_eq!(date!(2020-12-31).iso_week(), 53);
+ /// assert_eq!(date!(2021-01-01).iso_week(), 53);
+ /// ```
+ pub const fn iso_week(self) -> u8 {
+ self.iso_year_week().1
+ }
+
+ /// Get the week number where week 1 begins on the first Sunday.
+ ///
+ /// The returned value will always be in the range `0..=53`.
+ ///
+ /// ```rust
+ /// # use time_macros::date;
+ /// assert_eq!(date!(2019-01-01).sunday_based_week(), 0);
+ /// assert_eq!(date!(2020-01-01).sunday_based_week(), 0);
+ /// assert_eq!(date!(2020-12-31).sunday_based_week(), 52);
+ /// assert_eq!(date!(2021-01-01).sunday_based_week(), 0);
+ /// ```
+ pub const fn sunday_based_week(self) -> u8 {
+ ((self.ordinal() as i16 - self.weekday().number_days_from_sunday() as i16 + 6) / 7) as u8
+ }
+
+ /// Get the week number where week 1 begins on the first Monday.
+ ///
+ /// The returned value will always be in the range `0..=53`.
+ ///
+ /// ```rust
+ /// # use time_macros::date;
+ /// assert_eq!(date!(2019-01-01).monday_based_week(), 0);
+ /// assert_eq!(date!(2020-01-01).monday_based_week(), 0);
+ /// assert_eq!(date!(2020-12-31).monday_based_week(), 52);
+ /// assert_eq!(date!(2021-01-01).monday_based_week(), 0);
+ /// ```
+ pub const fn monday_based_week(self) -> u8 {
+ ((self.ordinal() as i16 - self.weekday().number_days_from_monday() as i16 + 6) / 7) as u8
+ }
+
+ /// Get the year, month, and day.
+ ///
+ /// ```rust
+ /// # use time::Month;
+ /// # use time_macros::date;
+ /// assert_eq!(
+ /// date!(2019-01-01).to_calendar_date(),
+ /// (2019, Month::January, 1)
+ /// );
+ /// ```
+ pub const fn to_calendar_date(self) -> (i32, Month, u8) {
+ let (year, ordinal) = self.to_ordinal_date();
+ let ordinal = ordinal as u32;
+ let jan_feb_len = 59 + self.is_in_leap_year() as u32;
+
+ let (month_adj, ordinal_adj) = if ordinal <= jan_feb_len {
+ (0, 0)
+ } else {
+ (2, jan_feb_len)
+ };
+
+ let ordinal = ordinal - ordinal_adj;
+ let month = (ordinal * 268 + 8031) >> 13;
+ let days_in_preceding_months = (month * 3917 - 3866) >> 7;
+ let day = ordinal - days_in_preceding_months;
+ let month = month + month_adj;
+
+ (
+ year,
+ // Safety: `month` is guaranteed to be between 1 and 12 inclusive.
+ unsafe {
+ match Month::from_number(NonZeroU8::new_unchecked(month as u8)) {
+ Ok(month) => month,
+ Err(_) => core::hint::unreachable_unchecked(),
+ }
+ },
+ day as u8,
+ )
+ }
+
+ /// Get the year and ordinal day number.
+ ///
+ /// ```rust
+ /// # use time_macros::date;
+ /// assert_eq!(date!(2019-01-01).to_ordinal_date(), (2019, 1));
+ /// ```
+ pub const fn to_ordinal_date(self) -> (i32, u16) {
+ (self.year(), self.ordinal())
+ }
+
+ /// Get the ISO 8601 year, week number, and weekday.
+ ///
+ /// ```rust
+ /// # use time::Weekday::*;
+ /// # use time_macros::date;
+ /// assert_eq!(date!(2019-01-01).to_iso_week_date(), (2019, 1, Tuesday));
+ /// assert_eq!(date!(2019-10-04).to_iso_week_date(), (2019, 40, Friday));
+ /// assert_eq!(date!(2020-01-01).to_iso_week_date(), (2020, 1, Wednesday));
+ /// assert_eq!(date!(2020-12-31).to_iso_week_date(), (2020, 53, Thursday));
+ /// assert_eq!(date!(2021-01-01).to_iso_week_date(), (2020, 53, Friday));
+ /// ```
+ pub const fn to_iso_week_date(self) -> (i32, u8, Weekday) {
+ let (year, ordinal) = self.to_ordinal_date();
+ let weekday = self.weekday();
+
+ match ((ordinal + 10 - weekday.number_from_monday() as u16) / 7) as u8 {
+ 0 => (year - 1, weeks_in_year(year - 1), weekday),
+ 53 if weeks_in_year(year) == 52 => (year + 1, 1, weekday),
+ week => (year, week, weekday),
+ }
+ }
+
+ /// Get the weekday.
+ ///
+ /// ```rust
+ /// # use time::Weekday::*;
+ /// # use time_macros::date;
+ /// assert_eq!(date!(2019-01-01).weekday(), Tuesday);
+ /// assert_eq!(date!(2019-02-01).weekday(), Friday);
+ /// assert_eq!(date!(2019-03-01).weekday(), Friday);
+ /// assert_eq!(date!(2019-04-01).weekday(), Monday);
+ /// assert_eq!(date!(2019-05-01).weekday(), Wednesday);
+ /// assert_eq!(date!(2019-06-01).weekday(), Saturday);
+ /// assert_eq!(date!(2019-07-01).weekday(), Monday);
+ /// assert_eq!(date!(2019-08-01).weekday(), Thursday);
+ /// assert_eq!(date!(2019-09-01).weekday(), Sunday);
+ /// assert_eq!(date!(2019-10-01).weekday(), Tuesday);
+ /// assert_eq!(date!(2019-11-01).weekday(), Friday);
+ /// assert_eq!(date!(2019-12-01).weekday(), Sunday);
+ /// ```
+ pub const fn weekday(self) -> Weekday {
+ match self.to_julian_day() % 7 {
+ -6 | 1 => Weekday::Tuesday,
+ -5 | 2 => Weekday::Wednesday,
+ -4 | 3 => Weekday::Thursday,
+ -3 | 4 => Weekday::Friday,
+ -2 | 5 => Weekday::Saturday,
+ -1 | 6 => Weekday::Sunday,
+ val => {
+ debug_assert!(val == 0);
+ Weekday::Monday
+ }
+ }
+ }
+
+ /// Get the next calendar date.
+ ///
+ /// ```rust
+ /// # use time::Date;
+ /// # use time_macros::date;
+ /// assert_eq!(date!(2019-01-01).next_day(), Some(date!(2019-01-02)));
+ /// assert_eq!(date!(2019-01-31).next_day(), Some(date!(2019-02-01)));
+ /// assert_eq!(date!(2019-12-31).next_day(), Some(date!(2020-01-01)));
+ /// assert_eq!(Date::MAX.next_day(), None);
+ /// ```
+ pub const fn next_day(self) -> Option<Self> {
+ if self.ordinal() == 366 || (self.ordinal() == 365 && !self.is_in_leap_year()) {
+ if self.value.get() == Self::MAX.value.get() {
+ None
+ } else {
+ // Safety: `ordinal` is not zero.
+ unsafe { Some(Self::__from_ordinal_date_unchecked(self.year() + 1, 1)) }
+ }
+ } else {
+ Some(Self {
+ // Safety: `ordinal` is not zero.
+ value: unsafe { NonZeroI32::new_unchecked(self.value.get() + 1) },
+ })
+ }
+ }
+
+ /// Get the previous calendar date.
+ ///
+ /// ```rust
+ /// # use time::Date;
+ /// # use time_macros::date;
+ /// assert_eq!(date!(2019-01-02).previous_day(), Some(date!(2019-01-01)));
+ /// assert_eq!(date!(2019-02-01).previous_day(), Some(date!(2019-01-31)));
+ /// assert_eq!(date!(2020-01-01).previous_day(), Some(date!(2019-12-31)));
+ /// assert_eq!(Date::MIN.previous_day(), None);
+ /// ```
+ pub const fn previous_day(self) -> Option<Self> {
+ if self.ordinal() != 1 {
+ Some(Self {
+ // Safety: `ordinal` is not zero.
+ value: unsafe { NonZeroI32::new_unchecked(self.value.get() - 1) },
+ })
+ } else if self.value.get() == Self::MIN.value.get() {
+ None
+ } else {
+ // Safety: `ordinal` is not zero.
+ Some(unsafe {
+ Self::__from_ordinal_date_unchecked(self.year() - 1, days_in_year(self.year() - 1))
+ })
+ }
+ }
+
+ /// Calculates the first occurrence of a weekday that is strictly later than a given `Date`.
+ ///
+ /// # Panics
+ /// Panics if an overflow occurred.
+ ///
+ /// # Examples
+ /// ```
+ /// # use time::Weekday;
+ /// # use time_macros::date;
+ /// assert_eq!(
+ /// date!(2023-06-28).next_occurrence(Weekday::Monday),
+ /// date!(2023-07-03)
+ /// );
+ /// assert_eq!(
+ /// date!(2023-06-19).next_occurrence(Weekday::Monday),
+ /// date!(2023-06-26)
+ /// );
+ /// ```
+ pub const fn next_occurrence(self, weekday: Weekday) -> Self {
+ expect_opt!(
+ self.checked_next_occurrence(weekday),
+ "overflow calculating the next occurrence of a weekday"
+ )
+ }
+
+ /// Calculates the first occurrence of a weekday that is strictly earlier than a given `Date`.
+ ///
+ /// # Panics
+ /// Panics if an overflow occurred.
+ ///
+ /// # Examples
+ /// ```
+ /// # use time::Weekday;
+ /// # use time_macros::date;
+ /// assert_eq!(
+ /// date!(2023-06-28).prev_occurrence(Weekday::Monday),
+ /// date!(2023-06-26)
+ /// );
+ /// assert_eq!(
+ /// date!(2023-06-19).prev_occurrence(Weekday::Monday),
+ /// date!(2023-06-12)
+ /// );
+ /// ```
+ pub const fn prev_occurrence(self, weekday: Weekday) -> Self {
+ expect_opt!(
+ self.checked_prev_occurrence(weekday),
+ "overflow calculating the previous occurrence of a weekday"
+ )
+ }
+
+ /// Calculates the `n`th occurrence of a weekday that is strictly later than a given `Date`.
+ ///
+ /// # Panics
+ /// Panics if an overflow occurred or if `n == 0`.
+ ///
+ /// # Examples
+ /// ```
+ /// # use time::Weekday;
+ /// # use time_macros::date;
+ /// assert_eq!(
+ /// date!(2023-06-25).nth_next_occurrence(Weekday::Monday, 5),
+ /// date!(2023-07-24)
+ /// );
+ /// assert_eq!(
+ /// date!(2023-06-26).nth_next_occurrence(Weekday::Monday, 5),
+ /// date!(2023-07-31)
+ /// );
+ /// ```
+ pub const fn nth_next_occurrence(self, weekday: Weekday, n: u8) -> Self {
+ expect_opt!(
+ self.checked_nth_next_occurrence(weekday, n),
+ "overflow calculating the next occurrence of a weekday"
+ )
+ }
+
+ /// Calculates the `n`th occurrence of a weekday that is strictly earlier than a given `Date`.
+ ///
+ /// # Panics
+ /// Panics if an overflow occurred or if `n == 0`.
+ ///
+ /// # Examples
+ /// ```
+ /// # use time::Weekday;
+ /// # use time_macros::date;
+ /// assert_eq!(
+ /// date!(2023-06-27).nth_prev_occurrence(Weekday::Monday, 3),
+ /// date!(2023-06-12)
+ /// );
+ /// assert_eq!(
+ /// date!(2023-06-26).nth_prev_occurrence(Weekday::Monday, 3),
+ /// date!(2023-06-05)
+ /// );
+ /// ```
+ pub const fn nth_prev_occurrence(self, weekday: Weekday, n: u8) -> Self {
+ expect_opt!(
+ self.checked_nth_prev_occurrence(weekday, n),
+ "overflow calculating the previous occurrence of a weekday"
+ )
+ }
+
+ /// Get the Julian day for the date.
+ ///
+ /// ```rust
+ /// # use time_macros::date;
+ /// assert_eq!(date!(-4713 - 11 - 24).to_julian_day(), 0);
+ /// assert_eq!(date!(2000-01-01).to_julian_day(), 2_451_545);
+ /// assert_eq!(date!(2019-01-01).to_julian_day(), 2_458_485);
+ /// assert_eq!(date!(2019-12-31).to_julian_day(), 2_458_849);
+ /// ```
+ pub const fn to_julian_day(self) -> i32 {
+ let (year, ordinal) = self.to_ordinal_date();
+
+ // The algorithm requires a non-negative year. Add the lowest value to make it so. This is
+ // adjusted for at the end with the final subtraction.
+ let adj_year = year + 999_999;
+ let century = adj_year / 100;
+
+ let days_before_year = (1461 * adj_year as i64 / 4) as i32 - century + century / 4;
+ days_before_year + ordinal as i32 - 363_521_075
+ }
+
+ /// Computes `self + duration`, returning `None` if an overflow occurred.
+ ///
+ /// ```rust
+ /// # use time::{Date, ext::NumericalDuration};
+ /// # use time_macros::date;
+ /// assert_eq!(Date::MAX.checked_add(1.days()), None);
+ /// assert_eq!(Date::MIN.checked_add((-2).days()), None);
+ /// assert_eq!(
+ /// date!(2020-12-31).checked_add(2.days()),
+ /// Some(date!(2021-01-02))
+ /// );
+ /// ```
+ ///
+ /// # Note
+ ///
+ /// This function only takes whole days into account.
+ ///
+ /// ```rust
+ /// # use time::{Date, ext::NumericalDuration};
+ /// # use time_macros::date;
+ /// assert_eq!(Date::MAX.checked_add(23.hours()), Some(Date::MAX));
+ /// assert_eq!(Date::MIN.checked_add((-23).hours()), Some(Date::MIN));
+ /// assert_eq!(
+ /// date!(2020-12-31).checked_add(23.hours()),
+ /// Some(date!(2020-12-31))
+ /// );
+ /// assert_eq!(
+ /// date!(2020-12-31).checked_add(47.hours()),
+ /// Some(date!(2021-01-01))
+ /// );
+ /// ```
+ pub const fn checked_add(self, duration: Duration) -> Option<Self> {
+ let whole_days = duration.whole_days();
+ if whole_days < i32::MIN as i64 || whole_days > i32::MAX as i64 {
+ return None;
+ }
+
+ let julian_day = const_try_opt!(self.to_julian_day().checked_add(whole_days as i32));
+ if let Ok(date) = Self::from_julian_day(julian_day) {
+ Some(date)
+ } else {
+ None
+ }
+ }
+
+ /// Computes `self + duration`, returning `None` if an overflow occurred.
+ ///
+ /// ```rust
+ /// # use time::{Date, ext::NumericalStdDuration};
+ /// # use time_macros::date;
+ /// assert_eq!(Date::MAX.checked_add_std(1.std_days()), None);
+ /// assert_eq!(
+ /// date!(2020-12-31).checked_add_std(2.std_days()),
+ /// Some(date!(2021-01-02))
+ /// );
+ /// ```
+ ///
+ /// # Note
+ ///
+ /// This function only takes whole days into account.
+ ///
+ /// ```rust
+ /// # use time::{Date, ext::NumericalStdDuration};
+ /// # use time_macros::date;
+ /// assert_eq!(Date::MAX.checked_add_std(23.std_hours()), Some(Date::MAX));
+ /// assert_eq!(
+ /// date!(2020-12-31).checked_add_std(23.std_hours()),
+ /// Some(date!(2020-12-31))
+ /// );
+ /// assert_eq!(
+ /// date!(2020-12-31).checked_add_std(47.std_hours()),
+ /// Some(date!(2021-01-01))
+ /// );
+ /// ```
+ pub const fn checked_add_std(self, duration: StdDuration) -> Option<Self> {
+ let whole_days = duration.as_secs() / Second::per(Day) as u64;
+ if whole_days > i32::MAX as u64 {
+ return None;
+ }
+
+ let julian_day = const_try_opt!(self.to_julian_day().checked_add(whole_days as i32));
+ if let Ok(date) = Self::from_julian_day(julian_day) {
+ Some(date)
+ } else {
+ None
+ }
+ }
+
+ /// Computes `self - duration`, returning `None` if an overflow occurred.
+ ///
+ /// ```
+ /// # use time::{Date, ext::NumericalDuration};
+ /// # use time_macros::date;
+ /// assert_eq!(Date::MAX.checked_sub((-2).days()), None);
+ /// assert_eq!(Date::MIN.checked_sub(1.days()), None);
+ /// assert_eq!(
+ /// date!(2020-12-31).checked_sub(2.days()),
+ /// Some(date!(2020-12-29))
+ /// );
+ /// ```
+ ///
+ /// # Note
+ ///
+ /// This function only takes whole days into account.
+ ///
+ /// ```
+ /// # use time::{Date, ext::NumericalDuration};
+ /// # use time_macros::date;
+ /// assert_eq!(Date::MAX.checked_sub((-23).hours()), Some(Date::MAX));
+ /// assert_eq!(Date::MIN.checked_sub(23.hours()), Some(Date::MIN));
+ /// assert_eq!(
+ /// date!(2020-12-31).checked_sub(23.hours()),
+ /// Some(date!(2020-12-31))
+ /// );
+ /// assert_eq!(
+ /// date!(2020-12-31).checked_sub(47.hours()),
+ /// Some(date!(2020-12-30))
+ /// );
+ /// ```
+ pub const fn checked_sub(self, duration: Duration) -> Option<Self> {
+ let whole_days = duration.whole_days();
+ if whole_days < i32::MIN as i64 || whole_days > i32::MAX as i64 {
+ return None;
+ }
+
+ let julian_day = const_try_opt!(self.to_julian_day().checked_sub(whole_days as i32));
+ if let Ok(date) = Self::from_julian_day(julian_day) {
+ Some(date)
+ } else {
+ None
+ }
+ }
+
+ /// Computes `self - duration`, returning `None` if an overflow occurred.
+ ///
+ /// ```
+ /// # use time::{Date, ext::NumericalStdDuration};
+ /// # use time_macros::date;
+ /// assert_eq!(Date::MIN.checked_sub_std(1.std_days()), None);
+ /// assert_eq!(
+ /// date!(2020-12-31).checked_sub_std(2.std_days()),
+ /// Some(date!(2020-12-29))
+ /// );
+ /// ```
+ ///
+ /// # Note
+ ///
+ /// This function only takes whole days into account.
+ ///
+ /// ```
+ /// # use time::{Date, ext::NumericalStdDuration};
+ /// # use time_macros::date;
+ /// assert_eq!(Date::MIN.checked_sub_std(23.std_hours()), Some(Date::MIN));
+ /// assert_eq!(
+ /// date!(2020-12-31).checked_sub_std(23.std_hours()),
+ /// Some(date!(2020-12-31))
+ /// );
+ /// assert_eq!(
+ /// date!(2020-12-31).checked_sub_std(47.std_hours()),
+ /// Some(date!(2020-12-30))
+ /// );
+ /// ```
+ pub const fn checked_sub_std(self, duration: StdDuration) -> Option<Self> {
+ let whole_days = duration.as_secs() / Second::per(Day) as u64;
+ if whole_days > i32::MAX as u64 {
+ return None;
+ }
+
+ let julian_day = const_try_opt!(self.to_julian_day().checked_sub(whole_days as i32));
+ if let Ok(date) = Self::from_julian_day(julian_day) {
+ Some(date)
+ } else {
+ None
+ }
+ }
+
+ /// Calculates the first occurrence of a weekday that is strictly later than a given `Date`.
+ /// Returns `None` if an overflow occurred.
+ pub(crate) const fn checked_next_occurrence(self, weekday: Weekday) -> Option<Self> {
+ let day_diff = match weekday as i8 - self.weekday() as i8 {
+ 1 | -6 => 1,
+ 2 | -5 => 2,
+ 3 | -4 => 3,
+ 4 | -3 => 4,
+ 5 | -2 => 5,
+ 6 | -1 => 6,
+ val => {
+ debug_assert!(val == 0);
+ 7
+ }
+ };
+
+ self.checked_add(Duration::days(day_diff))
+ }
+
+ /// Calculates the first occurrence of a weekday that is strictly earlier than a given `Date`.
+ /// Returns `None` if an overflow occurred.
+ pub(crate) const fn checked_prev_occurrence(self, weekday: Weekday) -> Option<Self> {
+ let day_diff = match weekday as i8 - self.weekday() as i8 {
+ 1 | -6 => 6,
+ 2 | -5 => 5,
+ 3 | -4 => 4,
+ 4 | -3 => 3,
+ 5 | -2 => 2,
+ 6 | -1 => 1,
+ val => {
+ debug_assert!(val == 0);
+ 7
+ }
+ };
+
+ self.checked_sub(Duration::days(day_diff))
+ }
+
+ /// Calculates the `n`th occurrence of a weekday that is strictly later than a given `Date`.
+ /// Returns `None` if an overflow occurred or if `n == 0`.
+ pub(crate) const fn checked_nth_next_occurrence(self, weekday: Weekday, n: u8) -> Option<Self> {
+ if n == 0 {
+ return None;
+ }
+
+ const_try_opt!(self.checked_next_occurrence(weekday))
+ .checked_add(Duration::weeks(n as i64 - 1))
+ }
+
+ /// Calculates the `n`th occurrence of a weekday that is strictly earlier than a given `Date`.
+ /// Returns `None` if an overflow occurred or if `n == 0`.
+ pub(crate) const fn checked_nth_prev_occurrence(self, weekday: Weekday, n: u8) -> Option<Self> {
+ if n == 0 {
+ return None;
+ }
+
+ const_try_opt!(self.checked_prev_occurrence(weekday))
+ .checked_sub(Duration::weeks(n as i64 - 1))
+ }
+
+ /// Computes `self + duration`, saturating value on overflow.
+ ///
+ /// ```rust
+ /// # use time::{Date, ext::NumericalDuration};
+ /// # use time_macros::date;
+ /// assert_eq!(Date::MAX.saturating_add(1.days()), Date::MAX);
+ /// assert_eq!(Date::MIN.saturating_add((-2).days()), Date::MIN);
+ /// assert_eq!(
+ /// date!(2020-12-31).saturating_add(2.days()),
+ /// date!(2021-01-02)
+ /// );
+ /// ```
+ ///
+ /// # Note
+ ///
+ /// This function only takes whole days into account.
+ ///
+ /// ```rust
+ /// # use time::ext::NumericalDuration;
+ /// # use time_macros::date;
+ /// assert_eq!(
+ /// date!(2020-12-31).saturating_add(23.hours()),
+ /// date!(2020-12-31)
+ /// );
+ /// assert_eq!(
+ /// date!(2020-12-31).saturating_add(47.hours()),
+ /// date!(2021-01-01)
+ /// );
+ /// ```
+ pub const fn saturating_add(self, duration: Duration) -> Self {
+ if let Some(datetime) = self.checked_add(duration) {
+ datetime
+ } else if duration.is_negative() {
+ Self::MIN
+ } else {
+ debug_assert!(duration.is_positive());
+ Self::MAX
+ }
+ }
+
+ /// Computes `self - duration`, saturating value on overflow.
+ ///
+ /// ```
+ /// # use time::{Date, ext::NumericalDuration};
+ /// # use time_macros::date;
+ /// assert_eq!(Date::MAX.saturating_sub((-2).days()), Date::MAX);
+ /// assert_eq!(Date::MIN.saturating_sub(1.days()), Date::MIN);
+ /// assert_eq!(
+ /// date!(2020-12-31).saturating_sub(2.days()),
+ /// date!(2020-12-29)
+ /// );
+ /// ```
+ ///
+ /// # Note
+ ///
+ /// This function only takes whole days into account.
+ ///
+ /// ```
+ /// # use time::ext::NumericalDuration;
+ /// # use time_macros::date;
+ /// assert_eq!(
+ /// date!(2020-12-31).saturating_sub(23.hours()),
+ /// date!(2020-12-31)
+ /// );
+ /// assert_eq!(
+ /// date!(2020-12-31).saturating_sub(47.hours()),
+ /// date!(2020-12-30)
+ /// );
+ /// ```
+ pub const fn saturating_sub(self, duration: Duration) -> Self {
+ if let Some(datetime) = self.checked_sub(duration) {
+ datetime
+ } else if duration.is_negative() {
+ Self::MAX
+ } else {
+ debug_assert!(duration.is_positive());
+ Self::MIN
+ }
+ }
+
+ /// Replace the year. The month and day will be unchanged.
+ ///
+ /// ```rust
+ /// # use time_macros::date;
+ /// assert_eq!(
+ /// date!(2022-02-18).replace_year(2019),
+ /// Ok(date!(2019-02-18))
+ /// );
+ /// assert!(date!(2022-02-18).replace_year(-1_000_000_000).is_err()); // -1_000_000_000 isn't a valid year
+ /// assert!(date!(2022-02-18).replace_year(1_000_000_000).is_err()); // 1_000_000_000 isn't a valid year
+ /// ```
+ #[must_use = "This method does not mutate the original `Date`."]
+ pub const fn replace_year(self, year: i32) -> Result<Self, error::ComponentRange> {
+ ensure_ranged!(Year: year);
+
+ let ordinal = self.ordinal();
+
+ // Dates in January and February are unaffected by leap years.
+ if ordinal <= 59 {
+ // Safety: `ordinal` is not zero.
+ return Ok(unsafe { Self::__from_ordinal_date_unchecked(year, ordinal) });
+ }
+
+ match (self.is_in_leap_year(), is_leap_year(year)) {
+ (false, false) | (true, true) => {
+ // Safety: `ordinal` is not zero.
+ Ok(unsafe { Self::__from_ordinal_date_unchecked(year, ordinal) })
+ }
+ // February 29 does not exist in common years.
+ (true, false) if ordinal == 60 => Err(error::ComponentRange {
+ name: "day",
+ value: 29,
+ minimum: 1,
+ maximum: 28,
+ conditional_message: Some("for the given month and year"),
+ }),
+ // We're going from a common year to a leap year. Shift dates in March and later by
+ // one day.
+ // Safety: `ordinal` is not zero.
+ (false, true) => Ok(unsafe { Self::__from_ordinal_date_unchecked(year, ordinal + 1) }),
+ // We're going from a leap year to a common year. Shift dates in January and
+ // February by one day.
+ // Safety: `ordinal` is not zero.
+ (true, false) => Ok(unsafe { Self::__from_ordinal_date_unchecked(year, ordinal - 1) }),
+ }
+ }
+
+ /// Replace the month of the year.
+ ///
+ /// ```rust
+ /// # use time_macros::date;
+ /// # use time::Month;
+ /// assert_eq!(
+ /// date!(2022-02-18).replace_month(Month::January),
+ /// Ok(date!(2022-01-18))
+ /// );
+ /// assert!(date!(2022-01-30)
+ /// .replace_month(Month::February)
+ /// .is_err()); // 30 isn't a valid day in February
+ /// ```
+ #[must_use = "This method does not mutate the original `Date`."]
+ pub const fn replace_month(self, month: Month) -> Result<Self, error::ComponentRange> {
+ let (year, _, day) = self.to_calendar_date();
+ Self::from_calendar_date(year, month, day)
+ }
+
+ /// Replace the day of the month.
+ ///
+ /// ```rust
+ /// # use time_macros::date;
+ /// assert_eq!(date!(2022-02-18).replace_day(1), Ok(date!(2022-02-01)));
+ /// assert!(date!(2022-02-18).replace_day(0).is_err()); // 0 isn't a valid day
+ /// assert!(date!(2022-02-18).replace_day(30).is_err()); // 30 isn't a valid day in February
+ /// ```
+ #[must_use = "This method does not mutate the original `Date`."]
+ pub const fn replace_day(self, day: u8) -> Result<Self, error::ComponentRange> {
+ match day {
+ 1..=28 => {}
+ 29..=31 if day <= self.month().length(self.year()) => {}
+ _ => {
+ return Err(error::ComponentRange {
+ name: "day",
+ minimum: 1,
+ maximum: self.month().length(self.year()) as i64,
+ value: day as i64,
+ conditional_message: Some("for the given month and year"),
+ });
+ }
+ }
+
+ // Safety: `ordinal` is not zero.
+ Ok(unsafe {
+ Self::__from_ordinal_date_unchecked(
+ self.year(),
+ (self.ordinal() as i16 - self.day() as i16 + day as i16) as u16,
+ )
+ })
+ }
+
+ /// Replace the day of the year.
+ ///
+ /// ```rust
+ /// # use time_macros::date;
+ /// assert_eq!(date!(2022-049).replace_ordinal(1), Ok(date!(2022-001)));
+ /// assert!(date!(2022-049).replace_ordinal(0).is_err()); // 0 isn't a valid ordinal
+ /// assert!(date!(2022-049).replace_ordinal(366).is_err()); // 2022 isn't a leap year
+ /// ````
+ #[must_use = "This method does not mutate the original `Date`."]
+ pub const fn replace_ordinal(self, ordinal: u16) -> Result<Self, error::ComponentRange> {
+ match ordinal {
+ 1..=365 => {}
+ 366 if self.is_in_leap_year() => {}
+ _ => {
+ return Err(error::ComponentRange {
+ name: "ordinal",
+ minimum: 1,
+ maximum: days_in_year(self.year()) as i64,
+ value: ordinal as i64,
+ conditional_message: Some("for the given year"),
+ });
+ }
+ }
+
+ // Safety: `ordinal` is in range.
+ Ok(unsafe { Self::__from_ordinal_date_unchecked(self.year(), ordinal) })
+ }
+}
+
+/// Methods to add a [`Time`] component, resulting in a [`PrimitiveDateTime`].
+impl Date {
+ /// Create a [`PrimitiveDateTime`] using the existing date. The [`Time`] component will be set
+ /// to midnight.
+ ///
+ /// ```rust
+ /// # use time_macros::{date, datetime};
+ /// assert_eq!(date!(1970-01-01).midnight(), datetime!(1970-01-01 0:00));
+ /// ```
+ pub const fn midnight(self) -> PrimitiveDateTime {
+ PrimitiveDateTime::new(self, Time::MIDNIGHT)
+ }
+
+ /// Create a [`PrimitiveDateTime`] using the existing date and the provided [`Time`].
+ ///
+ /// ```rust
+ /// # use time_macros::{date, datetime, time};
+ /// assert_eq!(
+ /// date!(1970-01-01).with_time(time!(0:00)),
+ /// datetime!(1970-01-01 0:00),
+ /// );
+ /// ```
+ pub const fn with_time(self, time: Time) -> PrimitiveDateTime {
+ PrimitiveDateTime::new(self, time)
+ }
+
+ /// Attempt to create a [`PrimitiveDateTime`] using the existing date and the provided time.
+ ///
+ /// ```rust
+ /// # use time_macros::date;
+ /// assert!(date!(1970-01-01).with_hms(0, 0, 0).is_ok());
+ /// assert!(date!(1970-01-01).with_hms(24, 0, 0).is_err());
+ /// ```
+ pub const fn with_hms(
+ self,
+ hour: u8,
+ minute: u8,
+ second: u8,
+ ) -> Result<PrimitiveDateTime, error::ComponentRange> {
+ Ok(PrimitiveDateTime::new(
+ self,
+ const_try!(Time::from_hms(hour, minute, second)),
+ ))
+ }
+
+ /// Attempt to create a [`PrimitiveDateTime`] using the existing date and the provided time.
+ ///
+ /// ```rust
+ /// # use time_macros::date;
+ /// assert!(date!(1970-01-01).with_hms_milli(0, 0, 0, 0).is_ok());
+ /// assert!(date!(1970-01-01).with_hms_milli(24, 0, 0, 0).is_err());
+ /// ```
+ pub const fn with_hms_milli(
+ self,
+ hour: u8,
+ minute: u8,
+ second: u8,
+ millisecond: u16,
+ ) -> Result<PrimitiveDateTime, error::ComponentRange> {
+ Ok(PrimitiveDateTime::new(
+ self,
+ const_try!(Time::from_hms_milli(hour, minute, second, millisecond)),
+ ))
+ }
+
+ /// Attempt to create a [`PrimitiveDateTime`] using the existing date and the provided time.
+ ///
+ /// ```rust
+ /// # use time_macros::date;
+ /// assert!(date!(1970-01-01).with_hms_micro(0, 0, 0, 0).is_ok());
+ /// assert!(date!(1970-01-01).with_hms_micro(24, 0, 0, 0).is_err());
+ /// ```
+ pub const fn with_hms_micro(
+ self,
+ hour: u8,
+ minute: u8,
+ second: u8,
+ microsecond: u32,
+ ) -> Result<PrimitiveDateTime, error::ComponentRange> {
+ Ok(PrimitiveDateTime::new(
+ self,
+ const_try!(Time::from_hms_micro(hour, minute, second, microsecond)),
+ ))
+ }
+
+ /// Attempt to create a [`PrimitiveDateTime`] using the existing date and the provided time.
+ ///
+ /// ```rust
+ /// # use time_macros::date;
+ /// assert!(date!(1970-01-01).with_hms_nano(0, 0, 0, 0).is_ok());
+ /// assert!(date!(1970-01-01).with_hms_nano(24, 0, 0, 0).is_err());
+ /// ```
+ pub const fn with_hms_nano(
+ self,
+ hour: u8,
+ minute: u8,
+ second: u8,
+ nanosecond: u32,
+ ) -> Result<PrimitiveDateTime, error::ComponentRange> {
+ Ok(PrimitiveDateTime::new(
+ self,
+ const_try!(Time::from_hms_nano(hour, minute, second, nanosecond)),
+ ))
+ }
+}
+
+#[cfg(feature = "formatting")]
+impl Date {
+ /// Format the `Date` using the provided [format description](crate::format_description).
+ pub fn format_into(
+ self,
+ output: &mut (impl io::Write + ?Sized),
+ format: &(impl Formattable + ?Sized),
+ ) -> Result<usize, error::Format> {
+ format.format_into(output, Some(self), None, None)
+ }
+
+ /// Format the `Date` using the provided [format description](crate::format_description).
+ ///
+ /// ```rust
+ /// # use time::{format_description};
+ /// # use time_macros::date;
+ /// let format = format_description::parse("[year]-[month]-[day]")?;
+ /// assert_eq!(date!(2020-01-02).format(&format)?, "2020-01-02");
+ /// # Ok::<_, time::Error>(())
+ /// ```
+ pub fn format(self, format: &(impl Formattable + ?Sized)) -> Result<String, error::Format> {
+ format.format(Some(self), None, None)
+ }
+}
+
+#[cfg(feature = "parsing")]
+impl Date {
+ /// Parse a `Date` from the input using the provided [format
+ /// description](crate::format_description).
+ ///
+ /// ```rust
+ /// # use time::Date;
+ /// # use time_macros::{date, format_description};
+ /// let format = format_description!("[year]-[month]-[day]");
+ /// assert_eq!(Date::parse("2020-01-02", &format)?, date!(2020-01-02));
+ /// # Ok::<_, time::Error>(())
+ /// ```
+ pub fn parse(
+ input: &str,
+ description: &(impl Parsable + ?Sized),
+ ) -> Result<Self, error::Parse> {
+ description.parse_date(input.as_bytes())
+ }
+}
+
+mod private {
+ #[non_exhaustive]
+ #[derive(Debug, Clone, Copy)]
+ pub struct DateMetadata {
+ /// The width of the year component, including the sign.
+ pub(super) year_width: u8,
+ /// Whether the sign should be displayed.
+ pub(super) display_sign: bool,
+ pub(super) year: i32,
+ pub(super) month: u8,
+ pub(super) day: u8,
+ }
+}
+use private::DateMetadata;
+
+impl SmartDisplay for Date {
+ type Metadata = DateMetadata;
+
+ fn metadata(&self, _: FormatterOptions) -> Metadata<Self> {
+ let (year, month, day) = self.to_calendar_date();
+
+ // There is a minimum of four digits for any year.
+ let mut year_width = cmp::max(year.unsigned_abs().num_digits(), 4);
+ let display_sign = if !(0..10_000).contains(&year) {
+ // An extra character is required for the sign.
+ year_width += 1;
+ true
+ } else {
+ false
+ };
+
+ let formatted_width = year_width.extend::<usize>()
+ + smart_display::padded_width_of!(
+ "-",
+ u8::from(month) => width(2),
+ "-",
+ day => width(2),
+ );
+
+ Metadata::new(
+ formatted_width,
+ self,
+ DateMetadata {
+ year_width,
+ display_sign,
+ year,
+ month: u8::from(month),
+ day,
+ },
+ )
+ }
+
+ fn fmt_with_metadata(
+ &self,
+ f: &mut fmt::Formatter<'_>,
+ metadata: Metadata<Self>,
+ ) -> fmt::Result {
+ let DateMetadata {
+ year_width,
+ display_sign,
+ year,
+ month,
+ day,
+ } = *metadata;
+ let year_width = year_width.extend();
+
+ if display_sign {
+ f.pad_with_width(
+ metadata.unpadded_width(),
+ format_args!("{year:+0year_width$}-{month:02}-{day:02}"),
+ )
+ } else {
+ f.pad_with_width(
+ metadata.unpadded_width(),
+ format_args!("{year:0year_width$}-{month:02}-{day:02}"),
+ )
+ }
+ }
+}
+
+impl fmt::Display for Date {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ SmartDisplay::fmt(self, f)
+ }
+}
+
+impl fmt::Debug for Date {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
+ fmt::Display::fmt(self, f)
+ }
+}
+
+impl Add<Duration> for Date {
+ type Output = Self;
+
+ /// # Panics
+ ///
+ /// This may panic if an overflow occurs.
+ fn add(self, duration: Duration) -> Self::Output {
+ self.checked_add(duration)
+ .expect("overflow adding duration to date")
+ }
+}
+
+impl Add<StdDuration> for Date {
+ type Output = Self;
+
+ /// # Panics
+ ///
+ /// This may panic if an overflow occurs.
+ fn add(self, duration: StdDuration) -> Self::Output {
+ self.checked_add_std(duration)
+ .expect("overflow adding duration to date")
+ }
+}
+
+impl_add_assign!(Date: Duration, StdDuration);
+
+impl Sub<Duration> for Date {
+ type Output = Self;
+
+ /// # Panics
+ ///
+ /// This may panic if an overflow occurs.
+ fn sub(self, duration: Duration) -> Self::Output {
+ self.checked_sub(duration)
+ .expect("overflow subtracting duration from date")
+ }
+}
+
+impl Sub<StdDuration> for Date {
+ type Output = Self;
+
+ /// # Panics
+ ///
+ /// This may panic if an overflow occurs.
+ fn sub(self, duration: StdDuration) -> Self::Output {
+ self.checked_sub_std(duration)
+ .expect("overflow subtracting duration from date")
+ }
+}
+
+impl_sub_assign!(Date: Duration, StdDuration);
+
+impl Sub for Date {
+ type Output = Duration;
+
+ fn sub(self, other: Self) -> Self::Output {
+ Duration::days((self.to_julian_day() - other.to_julian_day()).extend())
+ }
+}
diff --git a/vendor/time/src/duration.rs b/vendor/time/src/duration.rs
new file mode 100644
index 00000000..b86bfe7c
--- /dev/null
+++ b/vendor/time/src/duration.rs
@@ -0,0 +1,1598 @@
+//! The [`Duration`] struct and its associated `impl`s.
+
+use core::cmp::Ordering;
+use core::fmt;
+use core::iter::Sum;
+use core::ops::{Add, AddAssign, Div, Mul, Neg, Sub, SubAssign};
+use core::time::Duration as StdDuration;
+#[cfg(feature = "std")]
+use std::time::SystemTime;
+
+use deranged::RangedI32;
+use num_conv::prelude::*;
+
+use crate::convert::*;
+use crate::error;
+use crate::internal_macros::{
+ const_try_opt, expect_opt, impl_add_assign, impl_div_assign, impl_mul_assign, impl_sub_assign,
+};
+#[cfg(feature = "std")]
+#[allow(deprecated)]
+use crate::Instant;
+
+/// By explicitly inserting this enum where padding is expected, the compiler is able to better
+/// perform niche value optimization.
+#[repr(u32)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
+pub(crate) enum Padding {
+ #[allow(clippy::missing_docs_in_private_items)]
+ Optimize,
+}
+
+/// The type of the `nanosecond` field of `Duration`.
+type Nanoseconds =
+ RangedI32<{ -(Nanosecond::per(Second) as i32 - 1) }, { Nanosecond::per(Second) as i32 - 1 }>;
+
+/// A span of time with nanosecond precision.
+///
+/// Each `Duration` is composed of a whole number of seconds and a fractional part represented in
+/// nanoseconds.
+///
+/// This implementation allows for negative durations, unlike [`core::time::Duration`].
+#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
+pub struct Duration {
+ /// Number of whole seconds.
+ seconds: i64,
+ /// Number of nanoseconds within the second. The sign always matches the `seconds` field.
+ // Sign must match that of `seconds` (though this is not a safety requirement).
+ nanoseconds: Nanoseconds,
+ padding: Padding,
+}
+
+impl fmt::Debug for Duration {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("Duration")
+ .field("seconds", &self.seconds)
+ .field("nanoseconds", &self.nanoseconds)
+ .finish()
+ }
+}
+
+impl Default for Duration {
+ fn default() -> Self {
+ Self {
+ seconds: 0,
+ nanoseconds: Nanoseconds::new_static::<0>(),
+ padding: Padding::Optimize,
+ }
+ }
+}
+
+/// This is adapted from the [`std` implementation][std], which uses mostly bit
+/// operations to ensure the highest precision:
+///
+/// Changes from `std` are marked and explained below.
+///
+/// [std]: https://github.com/rust-lang/rust/blob/3a37c2f0523c87147b64f1b8099fc9df22e8c53e/library/core/src/time.rs#L1262-L1340
+#[rustfmt::skip] // Skip `rustfmt` because it reformats the arguments of the macro weirdly.
+macro_rules! try_from_secs {
+ (
+ secs = $secs: expr,
+ mantissa_bits = $mant_bits: literal,
+ exponent_bits = $exp_bits: literal,
+ offset = $offset: literal,
+ bits_ty = $bits_ty:ty,
+ bits_ty_signed = $bits_ty_signed:ty,
+ double_ty = $double_ty:ty,
+ float_ty = $float_ty:ty,
+ is_nan = $is_nan:expr,
+ is_overflow = $is_overflow:expr,
+ ) => {{
+ 'value: {
+ const MIN_EXP: i16 = 1 - (1i16 << $exp_bits) / 2;
+ const MANT_MASK: $bits_ty = (1 << $mant_bits) - 1;
+ const EXP_MASK: $bits_ty = (1 << $exp_bits) - 1;
+
+ // Change from std: No error check for negative values necessary.
+
+ let bits = $secs.to_bits();
+ let mant = (bits & MANT_MASK) | (MANT_MASK + 1);
+ let exp = ((bits >> $mant_bits) & EXP_MASK) as i16 + MIN_EXP;
+
+ let (secs, nanos) = if exp < -31 {
+ // the input represents less than 1ns and can not be rounded to it
+ (0u64, 0u32)
+ } else if exp < 0 {
+ // the input is less than 1 second
+ let t = <$double_ty>::from(mant) << ($offset + exp);
+ let nanos_offset = $mant_bits + $offset;
+ let nanos_tmp = u128::from(Nanosecond::per(Second)) * u128::from(t);
+ let nanos = (nanos_tmp >> nanos_offset) as u32;
+
+ let rem_mask = (1 << nanos_offset) - 1;
+ let rem_msb_mask = 1 << (nanos_offset - 1);
+ let rem = nanos_tmp & rem_mask;
+ let is_tie = rem == rem_msb_mask;
+ let is_even = (nanos & 1) == 0;
+ let rem_msb = nanos_tmp & rem_msb_mask == 0;
+ let add_ns = !(rem_msb || (is_even && is_tie));
+
+ // f32 does not have enough precision to trigger the second branch
+ // since it can not represent numbers between 0.999_999_940_395 and 1.0.
+ let nanos = nanos + add_ns as u32;
+ if ($mant_bits == 23) || (nanos != Nanosecond::per(Second)) {
+ (0, nanos)
+ } else {
+ (1, 0)
+ }
+ } else if exp < $mant_bits {
+ let secs = u64::from(mant >> ($mant_bits - exp));
+ let t = <$double_ty>::from((mant << exp) & MANT_MASK);
+ let nanos_offset = $mant_bits;
+ let nanos_tmp = <$double_ty>::from(Nanosecond::per(Second)) * t;
+ let nanos = (nanos_tmp >> nanos_offset) as u32;
+
+ let rem_mask = (1 << nanos_offset) - 1;
+ let rem_msb_mask = 1 << (nanos_offset - 1);
+ let rem = nanos_tmp & rem_mask;
+ let is_tie = rem == rem_msb_mask;
+ let is_even = (nanos & 1) == 0;
+ let rem_msb = nanos_tmp & rem_msb_mask == 0;
+ let add_ns = !(rem_msb || (is_even && is_tie));
+
+ // f32 does not have enough precision to trigger the second branch.
+ // For example, it can not represent numbers between 1.999_999_880...
+ // and 2.0. Bigger values result in even smaller precision of the
+ // fractional part.
+ let nanos = nanos + add_ns as u32;
+ if ($mant_bits == 23) || (nanos != Nanosecond::per(Second)) {
+ (secs, nanos)
+ } else {
+ (secs + 1, 0)
+ }
+ } else if exp < 63 {
+ // Change from std: The exponent here is 63 instead of 64,
+ // because i64::MAX + 1 is 2^63.
+
+ // the input has no fractional part
+ let secs = u64::from(mant) << (exp - $mant_bits);
+ (secs, 0)
+ } else if bits == (i64::MIN as $float_ty).to_bits() {
+ // Change from std: Signed integers are asymmetrical in that
+ // iN::MIN is -iN::MAX - 1. So for example i8 covers the
+ // following numbers -128..=127. The check above (exp < 63)
+ // doesn't cover i64::MIN as that is -2^63, so we have this
+ // additional case to handle the asymmetry of iN::MIN.
+ break 'value Self::new_ranged_unchecked(i64::MIN, Nanoseconds::new_static::<0>());
+ } else if $secs.is_nan() {
+ // Change from std: std doesn't differentiate between the error
+ // cases.
+ $is_nan
+ } else {
+ $is_overflow
+ };
+
+ // Change from std: All the code is mostly unmodified in that it
+ // simply calculates an unsigned integer. Here we extract the sign
+ // bit and assign it to the number. We basically manually do two's
+ // complement here, we could also use an if and just negate the
+ // numbers based on the sign, but it turns out to be quite a bit
+ // slower.
+ let mask = (bits as $bits_ty_signed) >> ($mant_bits + $exp_bits);
+ #[allow(trivial_numeric_casts)]
+ let secs_signed = ((secs as i64) ^ (mask as i64)) - (mask as i64);
+ #[allow(trivial_numeric_casts)]
+ let nanos_signed = ((nanos as i32) ^ (mask as i32)) - (mask as i32);
+ // Safety: `nanos_signed` is in range.
+ unsafe { Self::new_unchecked(secs_signed, nanos_signed) }
+ }
+ }};
+}
+
+impl Duration {
+ /// Equivalent to `0.seconds()`.
+ ///
+ /// ```rust
+ /// # use time::{Duration, ext::NumericalDuration};
+ /// assert_eq!(Duration::ZERO, 0.seconds());
+ /// ```
+ pub const ZERO: Self = Self::seconds(0);
+
+ /// Equivalent to `1.nanoseconds()`.
+ ///
+ /// ```rust
+ /// # use time::{Duration, ext::NumericalDuration};
+ /// assert_eq!(Duration::NANOSECOND, 1.nanoseconds());
+ /// ```
+ pub const NANOSECOND: Self = Self::nanoseconds(1);
+
+ /// Equivalent to `1.microseconds()`.
+ ///
+ /// ```rust
+ /// # use time::{Duration, ext::NumericalDuration};
+ /// assert_eq!(Duration::MICROSECOND, 1.microseconds());
+ /// ```
+ pub const MICROSECOND: Self = Self::microseconds(1);
+
+ /// Equivalent to `1.milliseconds()`.
+ ///
+ /// ```rust
+ /// # use time::{Duration, ext::NumericalDuration};
+ /// assert_eq!(Duration::MILLISECOND, 1.milliseconds());
+ /// ```
+ pub const MILLISECOND: Self = Self::milliseconds(1);
+
+ /// Equivalent to `1.seconds()`.
+ ///
+ /// ```rust
+ /// # use time::{Duration, ext::NumericalDuration};
+ /// assert_eq!(Duration::SECOND, 1.seconds());
+ /// ```
+ pub const SECOND: Self = Self::seconds(1);
+
+ /// Equivalent to `1.minutes()`.
+ ///
+ /// ```rust
+ /// # use time::{Duration, ext::NumericalDuration};
+ /// assert_eq!(Duration::MINUTE, 1.minutes());
+ /// ```
+ pub const MINUTE: Self = Self::minutes(1);
+
+ /// Equivalent to `1.hours()`.
+ ///
+ /// ```rust
+ /// # use time::{Duration, ext::NumericalDuration};
+ /// assert_eq!(Duration::HOUR, 1.hours());
+ /// ```
+ pub const HOUR: Self = Self::hours(1);
+
+ /// Equivalent to `1.days()`.
+ ///
+ /// ```rust
+ /// # use time::{Duration, ext::NumericalDuration};
+ /// assert_eq!(Duration::DAY, 1.days());
+ /// ```
+ pub const DAY: Self = Self::days(1);
+
+ /// Equivalent to `1.weeks()`.
+ ///
+ /// ```rust
+ /// # use time::{Duration, ext::NumericalDuration};
+ /// assert_eq!(Duration::WEEK, 1.weeks());
+ /// ```
+ pub const WEEK: Self = Self::weeks(1);
+
+ /// The minimum possible duration. Adding any negative duration to this will cause an overflow.
+ pub const MIN: Self = Self::new_ranged(i64::MIN, Nanoseconds::MIN);
+
+ /// The maximum possible duration. Adding any positive duration to this will cause an overflow.
+ pub const MAX: Self = Self::new_ranged(i64::MAX, Nanoseconds::MAX);
+
+ /// Check if a duration is exactly zero.
+ ///
+ /// ```rust
+ /// # use time::ext::NumericalDuration;
+ /// assert!(0.seconds().is_zero());
+ /// assert!(!1.nanoseconds().is_zero());
+ /// ```
+ pub const fn is_zero(self) -> bool {
+ self.seconds == 0 && self.nanoseconds.get() == 0
+ }
+
+ /// Check if a duration is negative.
+ ///
+ /// ```rust
+ /// # use time::ext::NumericalDuration;
+ /// assert!((-1).seconds().is_negative());
+ /// assert!(!0.seconds().is_negative());
+ /// assert!(!1.seconds().is_negative());
+ /// ```
+ pub const fn is_negative(self) -> bool {
+ self.seconds < 0 || self.nanoseconds.get() < 0
+ }
+
+ /// Check if a duration is positive.
+ ///
+ /// ```rust
+ /// # use time::ext::NumericalDuration;
+ /// assert!(1.seconds().is_positive());
+ /// assert!(!0.seconds().is_positive());
+ /// assert!(!(-1).seconds().is_positive());
+ /// ```
+ pub const fn is_positive(self) -> bool {
+ self.seconds > 0 || self.nanoseconds.get() > 0
+ }
+
+ /// Get the absolute value of the duration.
+ ///
+ /// This method saturates the returned value if it would otherwise overflow.
+ ///
+ /// ```rust
+ /// # use time::ext::NumericalDuration;
+ /// assert_eq!(1.seconds().abs(), 1.seconds());
+ /// assert_eq!(0.seconds().abs(), 0.seconds());
+ /// assert_eq!((-1).seconds().abs(), 1.seconds());
+ /// ```
+ pub const fn abs(self) -> Self {
+ match self.seconds.checked_abs() {
+ Some(seconds) => Self::new_ranged_unchecked(seconds, self.nanoseconds.abs()),
+ None => Self::MAX,
+ }
+ }
+
+ /// Convert the existing `Duration` to a `std::time::Duration` and its sign. This returns a
+ /// [`std::time::Duration`] and does not saturate the returned value (unlike [`Duration::abs`]).
+ ///
+ /// ```rust
+ /// # use time::ext::{NumericalDuration, NumericalStdDuration};
+ /// assert_eq!(1.seconds().unsigned_abs(), 1.std_seconds());
+ /// assert_eq!(0.seconds().unsigned_abs(), 0.std_seconds());
+ /// assert_eq!((-1).seconds().unsigned_abs(), 1.std_seconds());
+ /// ```
+ pub const fn unsigned_abs(self) -> StdDuration {
+ StdDuration::new(
+ self.seconds.unsigned_abs(),
+ self.nanoseconds.get().unsigned_abs(),
+ )
+ }
+
+ /// Create a new `Duration` without checking the validity of the components.
+ ///
+ /// # Safety
+ ///
+ /// - `nanoseconds` must be in the range `-999_999_999..=999_999_999`.
+ ///
+ /// While the sign of `nanoseconds` is required to be the same as the sign of `seconds`, this is
+ /// not a safety invariant.
+ pub(crate) const unsafe fn new_unchecked(seconds: i64, nanoseconds: i32) -> Self {
+ Self::new_ranged_unchecked(
+ seconds,
+ // Safety: The caller must uphold the safety invariants.
+ unsafe { Nanoseconds::new_unchecked(nanoseconds) },
+ )
+ }
+
+ /// Create a new `Duration` without checking the validity of the components.
+ pub(crate) const fn new_ranged_unchecked(seconds: i64, nanoseconds: Nanoseconds) -> Self {
+ if seconds < 0 {
+ debug_assert!(nanoseconds.get() <= 0);
+ } else if seconds > 0 {
+ debug_assert!(nanoseconds.get() >= 0);
+ }
+
+ Self {
+ seconds,
+ nanoseconds,
+ padding: Padding::Optimize,
+ }
+ }
+
+ /// Create a new `Duration` with the provided seconds and nanoseconds. If nanoseconds is at
+ /// least ±10<sup>9</sup>, it will wrap to the number of seconds.
+ ///
+ /// ```rust
+ /// # use time::{Duration, ext::NumericalDuration};
+ /// assert_eq!(Duration::new(1, 0), 1.seconds());
+ /// assert_eq!(Duration::new(-1, 0), (-1).seconds());
+ /// assert_eq!(Duration::new(1, 2_000_000_000), 3.seconds());
+ /// ```
+ ///
+ /// # Panics
+ ///
+ /// This may panic if an overflow occurs.
+ pub const fn new(mut seconds: i64, mut nanoseconds: i32) -> Self {
+ seconds = expect_opt!(
+ seconds.checked_add(nanoseconds as i64 / Nanosecond::per(Second) as i64),
+ "overflow constructing `time::Duration`"
+ );
+ nanoseconds %= Nanosecond::per(Second) as i32;
+
+ if seconds > 0 && nanoseconds < 0 {
+ // `seconds` cannot overflow here because it is positive.
+ seconds -= 1;
+ nanoseconds += Nanosecond::per(Second) as i32;
+ } else if seconds < 0 && nanoseconds > 0 {
+ // `seconds` cannot overflow here because it is negative.
+ seconds += 1;
+ nanoseconds -= Nanosecond::per(Second) as i32;
+ }
+
+ // Safety: `nanoseconds` is in range due to the modulus above.
+ unsafe { Self::new_unchecked(seconds, nanoseconds) }
+ }
+
+ /// Create a new `Duration` with the provided seconds and nanoseconds.
+ pub(crate) const fn new_ranged(mut seconds: i64, mut nanoseconds: Nanoseconds) -> Self {
+ if seconds > 0 && nanoseconds.get() < 0 {
+ // `seconds` cannot overflow here because it is positive.
+ seconds -= 1;
+ // Safety: `nanoseconds` is negative with a maximum of 999,999,999, so adding a billion
+ // to it is guaranteed to result in an in-range value.
+ nanoseconds = unsafe {
+ Nanoseconds::new_unchecked(nanoseconds.get() + Nanosecond::per(Second) as i32)
+ };
+ } else if seconds < 0 && nanoseconds.get() > 0 {
+ // `seconds` cannot overflow here because it is negative.
+ seconds += 1;
+ // Safety: `nanoseconds` is positive with a minimum of -999,999,999, so subtracting a
+ // billion from it is guaranteed to result in an in-range value.
+ nanoseconds = unsafe {
+ Nanoseconds::new_unchecked(nanoseconds.get() - Nanosecond::per(Second) as i32)
+ };
+ }
+
+ Self::new_ranged_unchecked(seconds, nanoseconds)
+ }
+
+ /// Create a new `Duration` with the given number of weeks. Equivalent to
+ /// `Duration::seconds(weeks * 604_800)`.
+ ///
+ /// ```rust
+ /// # use time::{Duration, ext::NumericalDuration};
+ /// assert_eq!(Duration::weeks(1), 604_800.seconds());
+ /// ```
+ ///
+ /// # Panics
+ ///
+ /// This may panic if an overflow occurs.
+ pub const fn weeks(weeks: i64) -> Self {
+ Self::seconds(expect_opt!(
+ weeks.checked_mul(Second::per(Week) as i64),
+ "overflow constructing `time::Duration`"
+ ))
+ }
+
+ /// Create a new `Duration` with the given number of days. Equivalent to
+ /// `Duration::seconds(days * 86_400)`.
+ ///
+ /// ```rust
+ /// # use time::{Duration, ext::NumericalDuration};
+ /// assert_eq!(Duration::days(1), 86_400.seconds());
+ /// ```
+ ///
+ /// # Panics
+ ///
+ /// This may panic if an overflow occurs.
+ pub const fn days(days: i64) -> Self {
+ Self::seconds(expect_opt!(
+ days.checked_mul(Second::per(Day) as i64),
+ "overflow constructing `time::Duration`"
+ ))
+ }
+
+ /// Create a new `Duration` with the given number of hours. Equivalent to
+ /// `Duration::seconds(hours * 3_600)`.
+ ///
+ /// ```rust
+ /// # use time::{Duration, ext::NumericalDuration};
+ /// assert_eq!(Duration::hours(1), 3_600.seconds());
+ /// ```
+ ///
+ /// # Panics
+ ///
+ /// This may panic if an overflow occurs.
+ pub const fn hours(hours: i64) -> Self {
+ Self::seconds(expect_opt!(
+ hours.checked_mul(Second::per(Hour) as i64),
+ "overflow constructing `time::Duration`"
+ ))
+ }
+
+ /// Create a new `Duration` with the given number of minutes. Equivalent to
+ /// `Duration::seconds(minutes * 60)`.
+ ///
+ /// ```rust
+ /// # use time::{Duration, ext::NumericalDuration};
+ /// assert_eq!(Duration::minutes(1), 60.seconds());
+ /// ```
+ ///
+ /// # Panics
+ ///
+ /// This may panic if an overflow occurs.
+ pub const fn minutes(minutes: i64) -> Self {
+ Self::seconds(expect_opt!(
+ minutes.checked_mul(Second::per(Minute) as i64),
+ "overflow constructing `time::Duration`"
+ ))
+ }
+
+ /// Create a new `Duration` with the given number of seconds.
+ ///
+ /// ```rust
+ /// # use time::{Duration, ext::NumericalDuration};
+ /// assert_eq!(Duration::seconds(1), 1_000.milliseconds());
+ /// ```
+ pub const fn seconds(seconds: i64) -> Self {
+ Self::new_ranged_unchecked(seconds, Nanoseconds::new_static::<0>())
+ }
+
+ /// Creates a new `Duration` from the specified number of seconds represented as `f64`.
+ ///
+ /// ```rust
+ /// # use time::{Duration, ext::NumericalDuration};
+ /// assert_eq!(Duration::seconds_f64(0.5), 0.5.seconds());
+ /// assert_eq!(Duration::seconds_f64(-0.5), (-0.5).seconds());
+ /// ```
+ pub fn seconds_f64(seconds: f64) -> Self {
+ try_from_secs!(
+ secs = seconds,
+ mantissa_bits = 52,
+ exponent_bits = 11,
+ offset = 44,
+ bits_ty = u64,
+ bits_ty_signed = i64,
+ double_ty = u128,
+ float_ty = f64,
+ is_nan = crate::expect_failed("passed NaN to `time::Duration::seconds_f64`"),
+ is_overflow = crate::expect_failed("overflow constructing `time::Duration`"),
+ )
+ }
+
+ /// Creates a new `Duration` from the specified number of seconds represented as `f32`.
+ ///
+ /// ```rust
+ /// # use time::{Duration, ext::NumericalDuration};
+ /// assert_eq!(Duration::seconds_f32(0.5), 0.5.seconds());
+ /// assert_eq!(Duration::seconds_f32(-0.5), (-0.5).seconds());
+ /// ```
+ pub fn seconds_f32(seconds: f32) -> Self {
+ try_from_secs!(
+ secs = seconds,
+ mantissa_bits = 23,
+ exponent_bits = 8,
+ offset = 41,
+ bits_ty = u32,
+ bits_ty_signed = i32,
+ double_ty = u64,
+ float_ty = f32,
+ is_nan = crate::expect_failed("passed NaN to `time::Duration::seconds_f32`"),
+ is_overflow = crate::expect_failed("overflow constructing `time::Duration`"),
+ )
+ }
+
+ /// Creates a new `Duration` from the specified number of seconds
+ /// represented as `f64`. Any values that are out of bounds are saturated at
+ /// the minimum or maximum respectively. `NaN` gets turned into a `Duration`
+ /// of 0 seconds.
+ ///
+ /// ```rust
+ /// # use time::{Duration, ext::NumericalDuration};
+ /// assert_eq!(Duration::saturating_seconds_f64(0.5), 0.5.seconds());
+ /// assert_eq!(Duration::saturating_seconds_f64(-0.5), (-0.5).seconds());
+ /// assert_eq!(
+ /// Duration::saturating_seconds_f64(f64::NAN),
+ /// Duration::new(0, 0),
+ /// );
+ /// assert_eq!(
+ /// Duration::saturating_seconds_f64(f64::NEG_INFINITY),
+ /// Duration::MIN,
+ /// );
+ /// assert_eq!(
+ /// Duration::saturating_seconds_f64(f64::INFINITY),
+ /// Duration::MAX,
+ /// );
+ /// ```
+ pub fn saturating_seconds_f64(seconds: f64) -> Self {
+ try_from_secs!(
+ secs = seconds,
+ mantissa_bits = 52,
+ exponent_bits = 11,
+ offset = 44,
+ bits_ty = u64,
+ bits_ty_signed = i64,
+ double_ty = u128,
+ float_ty = f64,
+ is_nan = return Self::ZERO,
+ is_overflow = return if seconds < 0.0 { Self::MIN } else { Self::MAX },
+ )
+ }
+
+ /// Creates a new `Duration` from the specified number of seconds
+ /// represented as `f32`. Any values that are out of bounds are saturated at
+ /// the minimum or maximum respectively. `NaN` gets turned into a `Duration`
+ /// of 0 seconds.
+ ///
+ /// ```rust
+ /// # use time::{Duration, ext::NumericalDuration};
+ /// assert_eq!(Duration::saturating_seconds_f32(0.5), 0.5.seconds());
+ /// assert_eq!(Duration::saturating_seconds_f32(-0.5), (-0.5).seconds());
+ /// assert_eq!(
+ /// Duration::saturating_seconds_f32(f32::NAN),
+ /// Duration::new(0, 0),
+ /// );
+ /// assert_eq!(
+ /// Duration::saturating_seconds_f32(f32::NEG_INFINITY),
+ /// Duration::MIN,
+ /// );
+ /// assert_eq!(
+ /// Duration::saturating_seconds_f32(f32::INFINITY),
+ /// Duration::MAX,
+ /// );
+ /// ```
+ pub fn saturating_seconds_f32(seconds: f32) -> Self {
+ try_from_secs!(
+ secs = seconds,
+ mantissa_bits = 23,
+ exponent_bits = 8,
+ offset = 41,
+ bits_ty = u32,
+ bits_ty_signed = i32,
+ double_ty = u64,
+ float_ty = f32,
+ is_nan = return Self::ZERO,
+ is_overflow = return if seconds < 0.0 { Self::MIN } else { Self::MAX },
+ )
+ }
+
+ /// Creates a new `Duration` from the specified number of seconds
+ /// represented as `f64`. Returns `None` if the `Duration` can't be
+ /// represented.
+ ///
+ /// ```rust
+ /// # use time::{Duration, ext::NumericalDuration};
+ /// assert_eq!(Duration::checked_seconds_f64(0.5), Some(0.5.seconds()));
+ /// assert_eq!(Duration::checked_seconds_f64(-0.5), Some((-0.5).seconds()));
+ /// assert_eq!(Duration::checked_seconds_f64(f64::NAN), None);
+ /// assert_eq!(Duration::checked_seconds_f64(f64::NEG_INFINITY), None);
+ /// assert_eq!(Duration::checked_seconds_f64(f64::INFINITY), None);
+ /// ```
+ pub fn checked_seconds_f64(seconds: f64) -> Option<Self> {
+ Some(try_from_secs!(
+ secs = seconds,
+ mantissa_bits = 52,
+ exponent_bits = 11,
+ offset = 44,
+ bits_ty = u64,
+ bits_ty_signed = i64,
+ double_ty = u128,
+ float_ty = f64,
+ is_nan = return None,
+ is_overflow = return None,
+ ))
+ }
+
+ /// Creates a new `Duration` from the specified number of seconds
+ /// represented as `f32`. Returns `None` if the `Duration` can't be
+ /// represented.
+ ///
+ /// ```rust
+ /// # use time::{Duration, ext::NumericalDuration};
+ /// assert_eq!(Duration::checked_seconds_f32(0.5), Some(0.5.seconds()));
+ /// assert_eq!(Duration::checked_seconds_f32(-0.5), Some((-0.5).seconds()));
+ /// assert_eq!(Duration::checked_seconds_f32(f32::NAN), None);
+ /// assert_eq!(Duration::checked_seconds_f32(f32::NEG_INFINITY), None);
+ /// assert_eq!(Duration::checked_seconds_f32(f32::INFINITY), None);
+ /// ```
+ pub fn checked_seconds_f32(seconds: f32) -> Option<Self> {
+ Some(try_from_secs!(
+ secs = seconds,
+ mantissa_bits = 23,
+ exponent_bits = 8,
+ offset = 41,
+ bits_ty = u32,
+ bits_ty_signed = i32,
+ double_ty = u64,
+ float_ty = f32,
+ is_nan = return None,
+ is_overflow = return None,
+ ))
+ }
+
+ /// Create a new `Duration` with the given number of milliseconds.
+ ///
+ /// ```rust
+ /// # use time::{Duration, ext::NumericalDuration};
+ /// assert_eq!(Duration::milliseconds(1), 1_000.microseconds());
+ /// assert_eq!(Duration::milliseconds(-1), (-1_000).microseconds());
+ /// ```
+ pub const fn milliseconds(milliseconds: i64) -> Self {
+ // Safety: `nanoseconds` is guaranteed to be in range because of the modulus.
+ unsafe {
+ Self::new_unchecked(
+ milliseconds / Millisecond::per(Second) as i64,
+ (milliseconds % Millisecond::per(Second) as i64
+ * Nanosecond::per(Millisecond) as i64) as i32,
+ )
+ }
+ }
+
+ /// Create a new `Duration` with the given number of microseconds.
+ ///
+ /// ```rust
+ /// # use time::{Duration, ext::NumericalDuration};
+ /// assert_eq!(Duration::microseconds(1), 1_000.nanoseconds());
+ /// assert_eq!(Duration::microseconds(-1), (-1_000).nanoseconds());
+ /// ```
+ pub const fn microseconds(microseconds: i64) -> Self {
+ // Safety: `nanoseconds` is guaranteed to be in range because of the modulus.
+ unsafe {
+ Self::new_unchecked(
+ microseconds / Microsecond::per(Second) as i64,
+ (microseconds % Microsecond::per(Second) as i64
+ * Nanosecond::per(Microsecond) as i64) as i32,
+ )
+ }
+ }
+
+ /// Create a new `Duration` with the given number of nanoseconds.
+ ///
+ /// ```rust
+ /// # use time::{Duration, ext::NumericalDuration};
+ /// assert_eq!(Duration::nanoseconds(1), 1.microseconds() / 1_000);
+ /// assert_eq!(Duration::nanoseconds(-1), (-1).microseconds() / 1_000);
+ /// ```
+ pub const fn nanoseconds(nanoseconds: i64) -> Self {
+ // Safety: `nanoseconds` is guaranteed to be in range because of the modulus.
+ unsafe {
+ Self::new_unchecked(
+ nanoseconds / Nanosecond::per(Second) as i64,
+ (nanoseconds % Nanosecond::per(Second) as i64) as i32,
+ )
+ }
+ }
+
+ /// Create a new `Duration` with the given number of nanoseconds.
+ ///
+ /// As the input range cannot be fully mapped to the output, this should only be used where it's
+ /// known to result in a valid value.
+ pub(crate) const fn nanoseconds_i128(nanoseconds: i128) -> Self {
+ let seconds = nanoseconds / Nanosecond::per(Second) as i128;
+ let nanoseconds = nanoseconds % Nanosecond::per(Second) as i128;
+
+ if seconds > i64::MAX as i128 || seconds < i64::MIN as i128 {
+ crate::expect_failed("overflow constructing `time::Duration`");
+ }
+
+ // Safety: `nanoseconds` is guaranteed to be in range because of the modulus above.
+ unsafe { Self::new_unchecked(seconds as i64, nanoseconds as i32) }
+ }
+
+ /// Get the number of whole weeks in the duration.
+ ///
+ /// ```rust
+ /// # use time::ext::NumericalDuration;
+ /// assert_eq!(1.weeks().whole_weeks(), 1);
+ /// assert_eq!((-1).weeks().whole_weeks(), -1);
+ /// assert_eq!(6.days().whole_weeks(), 0);
+ /// assert_eq!((-6).days().whole_weeks(), 0);
+ /// ```
+ pub const fn whole_weeks(self) -> i64 {
+ self.whole_seconds() / Second::per(Week) as i64
+ }
+
+ /// Get the number of whole days in the duration.
+ ///
+ /// ```rust
+ /// # use time::ext::NumericalDuration;
+ /// assert_eq!(1.days().whole_days(), 1);
+ /// assert_eq!((-1).days().whole_days(), -1);
+ /// assert_eq!(23.hours().whole_days(), 0);
+ /// assert_eq!((-23).hours().whole_days(), 0);
+ /// ```
+ pub const fn whole_days(self) -> i64 {
+ self.whole_seconds() / Second::per(Day) as i64
+ }
+
+ /// Get the number of whole hours in the duration.
+ ///
+ /// ```rust
+ /// # use time::ext::NumericalDuration;
+ /// assert_eq!(1.hours().whole_hours(), 1);
+ /// assert_eq!((-1).hours().whole_hours(), -1);
+ /// assert_eq!(59.minutes().whole_hours(), 0);
+ /// assert_eq!((-59).minutes().whole_hours(), 0);
+ /// ```
+ pub const fn whole_hours(self) -> i64 {
+ self.whole_seconds() / Second::per(Hour) as i64
+ }
+
+ /// Get the number of whole minutes in the duration.
+ ///
+ /// ```rust
+ /// # use time::ext::NumericalDuration;
+ /// assert_eq!(1.minutes().whole_minutes(), 1);
+ /// assert_eq!((-1).minutes().whole_minutes(), -1);
+ /// assert_eq!(59.seconds().whole_minutes(), 0);
+ /// assert_eq!((-59).seconds().whole_minutes(), 0);
+ /// ```
+ pub const fn whole_minutes(self) -> i64 {
+ self.whole_seconds() / Second::per(Minute) as i64
+ }
+
+ /// Get the number of whole seconds in the duration.
+ ///
+ /// ```rust
+ /// # use time::ext::NumericalDuration;
+ /// assert_eq!(1.seconds().whole_seconds(), 1);
+ /// assert_eq!((-1).seconds().whole_seconds(), -1);
+ /// assert_eq!(1.minutes().whole_seconds(), 60);
+ /// assert_eq!((-1).minutes().whole_seconds(), -60);
+ /// ```
+ pub const fn whole_seconds(self) -> i64 {
+ self.seconds
+ }
+
+ /// Get the number of fractional seconds in the duration.
+ ///
+ /// ```rust
+ /// # use time::ext::NumericalDuration;
+ /// assert_eq!(1.5.seconds().as_seconds_f64(), 1.5);
+ /// assert_eq!((-1.5).seconds().as_seconds_f64(), -1.5);
+ /// ```
+ pub fn as_seconds_f64(self) -> f64 {
+ self.seconds as f64 + self.nanoseconds.get() as f64 / Nanosecond::per(Second) as f64
+ }
+
+ /// Get the number of fractional seconds in the duration.
+ ///
+ /// ```rust
+ /// # use time::ext::NumericalDuration;
+ /// assert_eq!(1.5.seconds().as_seconds_f32(), 1.5);
+ /// assert_eq!((-1.5).seconds().as_seconds_f32(), -1.5);
+ /// ```
+ pub fn as_seconds_f32(self) -> f32 {
+ self.seconds as f32 + self.nanoseconds.get() as f32 / Nanosecond::per(Second) as f32
+ }
+
+ /// Get the number of whole milliseconds in the duration.
+ ///
+ /// ```rust
+ /// # use time::ext::NumericalDuration;
+ /// assert_eq!(1.seconds().whole_milliseconds(), 1_000);
+ /// assert_eq!((-1).seconds().whole_milliseconds(), -1_000);
+ /// assert_eq!(1.milliseconds().whole_milliseconds(), 1);
+ /// assert_eq!((-1).milliseconds().whole_milliseconds(), -1);
+ /// ```
+ pub const fn whole_milliseconds(self) -> i128 {
+ self.seconds as i128 * Millisecond::per(Second) as i128
+ + self.nanoseconds.get() as i128 / Nanosecond::per(Millisecond) as i128
+ }
+
+ /// Get the number of milliseconds past the number of whole seconds.
+ ///
+ /// Always in the range `-999..=999`.
+ ///
+ /// ```rust
+ /// # use time::ext::NumericalDuration;
+ /// assert_eq!(1.4.seconds().subsec_milliseconds(), 400);
+ /// assert_eq!((-1.4).seconds().subsec_milliseconds(), -400);
+ /// ```
+ // Allow the lint, as the value is guaranteed to be less than 1000.
+ pub const fn subsec_milliseconds(self) -> i16 {
+ (self.nanoseconds.get() / Nanosecond::per(Millisecond) as i32) as i16
+ }
+
+ /// Get the number of whole microseconds in the duration.
+ ///
+ /// ```rust
+ /// # use time::ext::NumericalDuration;
+ /// assert_eq!(1.milliseconds().whole_microseconds(), 1_000);
+ /// assert_eq!((-1).milliseconds().whole_microseconds(), -1_000);
+ /// assert_eq!(1.microseconds().whole_microseconds(), 1);
+ /// assert_eq!((-1).microseconds().whole_microseconds(), -1);
+ /// ```
+ pub const fn whole_microseconds(self) -> i128 {
+ self.seconds as i128 * Microsecond::per(Second) as i128
+ + self.nanoseconds.get() as i128 / Nanosecond::per(Microsecond) as i128
+ }
+
+ /// Get the number of microseconds past the number of whole seconds.
+ ///
+ /// Always in the range `-999_999..=999_999`.
+ ///
+ /// ```rust
+ /// # use time::ext::NumericalDuration;
+ /// assert_eq!(1.0004.seconds().subsec_microseconds(), 400);
+ /// assert_eq!((-1.0004).seconds().subsec_microseconds(), -400);
+ /// ```
+ pub const fn subsec_microseconds(self) -> i32 {
+ self.nanoseconds.get() / Nanosecond::per(Microsecond) as i32
+ }
+
+ /// Get the number of nanoseconds in the duration.
+ ///
+ /// ```rust
+ /// # use time::ext::NumericalDuration;
+ /// assert_eq!(1.microseconds().whole_nanoseconds(), 1_000);
+ /// assert_eq!((-1).microseconds().whole_nanoseconds(), -1_000);
+ /// assert_eq!(1.nanoseconds().whole_nanoseconds(), 1);
+ /// assert_eq!((-1).nanoseconds().whole_nanoseconds(), -1);
+ /// ```
+ pub const fn whole_nanoseconds(self) -> i128 {
+ self.seconds as i128 * Nanosecond::per(Second) as i128 + self.nanoseconds.get() as i128
+ }
+
+ /// Get the number of nanoseconds past the number of whole seconds.
+ ///
+ /// The returned value will always be in the range `-999_999_999..=999_999_999`.
+ ///
+ /// ```rust
+ /// # use time::ext::NumericalDuration;
+ /// assert_eq!(1.000_000_400.seconds().subsec_nanoseconds(), 400);
+ /// assert_eq!((-1.000_000_400).seconds().subsec_nanoseconds(), -400);
+ /// ```
+ pub const fn subsec_nanoseconds(self) -> i32 {
+ self.nanoseconds.get()
+ }
+
+ /// Get the number of nanoseconds past the number of whole seconds.
+ #[cfg(feature = "quickcheck")]
+ pub(crate) const fn subsec_nanoseconds_ranged(self) -> Nanoseconds {
+ self.nanoseconds
+ }
+
+ /// Computes `self + rhs`, returning `None` if an overflow occurred.
+ ///
+ /// ```rust
+ /// # use time::{Duration, ext::NumericalDuration};
+ /// assert_eq!(5.seconds().checked_add(5.seconds()), Some(10.seconds()));
+ /// assert_eq!(Duration::MAX.checked_add(1.nanoseconds()), None);
+ /// assert_eq!((-5).seconds().checked_add(5.seconds()), Some(0.seconds()));
+ /// ```
+ pub const fn checked_add(self, rhs: Self) -> Option<Self> {
+ let mut seconds = const_try_opt!(self.seconds.checked_add(rhs.seconds));
+ let mut nanoseconds = self.nanoseconds.get() + rhs.nanoseconds.get();
+
+ if nanoseconds >= Nanosecond::per(Second) as i32 || seconds < 0 && nanoseconds > 0 {
+ nanoseconds -= Nanosecond::per(Second) as i32;
+ seconds = const_try_opt!(seconds.checked_add(1));
+ } else if nanoseconds <= -(Nanosecond::per(Second) as i32) || seconds > 0 && nanoseconds < 0
+ {
+ nanoseconds += Nanosecond::per(Second) as i32;
+ seconds = const_try_opt!(seconds.checked_sub(1));
+ }
+
+ // Safety: `nanoseconds` is guaranteed to be in range because of the overflow handling.
+ unsafe { Some(Self::new_unchecked(seconds, nanoseconds)) }
+ }
+
+ /// Computes `self - rhs`, returning `None` if an overflow occurred.
+ ///
+ /// ```rust
+ /// # use time::{Duration, ext::NumericalDuration};
+ /// assert_eq!(5.seconds().checked_sub(5.seconds()), Some(Duration::ZERO));
+ /// assert_eq!(Duration::MIN.checked_sub(1.nanoseconds()), None);
+ /// assert_eq!(5.seconds().checked_sub(10.seconds()), Some((-5).seconds()));
+ /// ```
+ pub const fn checked_sub(self, rhs: Self) -> Option<Self> {
+ let mut seconds = const_try_opt!(self.seconds.checked_sub(rhs.seconds));
+ let mut nanoseconds = self.nanoseconds.get() - rhs.nanoseconds.get();
+
+ if nanoseconds >= Nanosecond::per(Second) as i32 || seconds < 0 && nanoseconds > 0 {
+ nanoseconds -= Nanosecond::per(Second) as i32;
+ seconds = const_try_opt!(seconds.checked_add(1));
+ } else if nanoseconds <= -(Nanosecond::per(Second) as i32) || seconds > 0 && nanoseconds < 0
+ {
+ nanoseconds += Nanosecond::per(Second) as i32;
+ seconds = const_try_opt!(seconds.checked_sub(1));
+ }
+
+ // Safety: `nanoseconds` is guaranteed to be in range because of the overflow handling.
+ unsafe { Some(Self::new_unchecked(seconds, nanoseconds)) }
+ }
+
+ /// Computes `self * rhs`, returning `None` if an overflow occurred.
+ ///
+ /// ```rust
+ /// # use time::{Duration, ext::NumericalDuration};
+ /// assert_eq!(5.seconds().checked_mul(2), Some(10.seconds()));
+ /// assert_eq!(5.seconds().checked_mul(-2), Some((-10).seconds()));
+ /// assert_eq!(5.seconds().checked_mul(0), Some(0.seconds()));
+ /// assert_eq!(Duration::MAX.checked_mul(2), None);
+ /// assert_eq!(Duration::MIN.checked_mul(2), None);
+ /// ```
+ pub const fn checked_mul(self, rhs: i32) -> Option<Self> {
+ // Multiply nanoseconds as i64, because it cannot overflow that way.
+ let total_nanos = self.nanoseconds.get() as i64 * rhs as i64;
+ let extra_secs = total_nanos / Nanosecond::per(Second) as i64;
+ let nanoseconds = (total_nanos % Nanosecond::per(Second) as i64) as i32;
+ let seconds = const_try_opt!(
+ const_try_opt!(self.seconds.checked_mul(rhs as i64)).checked_add(extra_secs)
+ );
+
+ // Safety: `nanoseconds` is guaranteed to be in range because of the modulus above.
+ unsafe { Some(Self::new_unchecked(seconds, nanoseconds)) }
+ }
+
+ /// Computes `self / rhs`, returning `None` if `rhs == 0` or if the result would overflow.
+ ///
+ /// ```rust
+ /// # use time::ext::NumericalDuration;
+ /// assert_eq!(10.seconds().checked_div(2), Some(5.seconds()));
+ /// assert_eq!(10.seconds().checked_div(-2), Some((-5).seconds()));
+ /// assert_eq!(1.seconds().checked_div(0), None);
+ /// ```
+ pub const fn checked_div(self, rhs: i32) -> Option<Self> {
+ let (secs, extra_secs) = (
+ const_try_opt!(self.seconds.checked_div(rhs as i64)),
+ self.seconds % (rhs as i64),
+ );
+ let (mut nanos, extra_nanos) = (self.nanoseconds.get() / rhs, self.nanoseconds.get() % rhs);
+ nanos += ((extra_secs * (Nanosecond::per(Second) as i64) + extra_nanos as i64)
+ / (rhs as i64)) as i32;
+
+ // Safety: `nanoseconds` is in range.
+ unsafe { Some(Self::new_unchecked(secs, nanos)) }
+ }
+
+ /// Computes `-self`, returning `None` if the result would overflow.
+ ///
+ /// ```rust
+ /// # use time::ext::NumericalDuration;
+ /// # use time::Duration;
+ /// assert_eq!(5.seconds().checked_neg(), Some((-5).seconds()));
+ /// assert_eq!(Duration::MIN.checked_neg(), None);
+ /// ```
+ pub const fn checked_neg(self) -> Option<Self> {
+ if self.seconds == i64::MIN {
+ None
+ } else {
+ Some(Self::new_ranged_unchecked(
+ -self.seconds,
+ self.nanoseconds.neg(),
+ ))
+ }
+ }
+
+ /// Computes `self + rhs`, saturating if an overflow occurred.
+ ///
+ /// ```rust
+ /// # use time::{Duration, ext::NumericalDuration};
+ /// assert_eq!(5.seconds().saturating_add(5.seconds()), 10.seconds());
+ /// assert_eq!(Duration::MAX.saturating_add(1.nanoseconds()), Duration::MAX);
+ /// assert_eq!(
+ /// Duration::MIN.saturating_add((-1).nanoseconds()),
+ /// Duration::MIN
+ /// );
+ /// assert_eq!((-5).seconds().saturating_add(5.seconds()), Duration::ZERO);
+ /// ```
+ pub const fn saturating_add(self, rhs: Self) -> Self {
+ let (mut seconds, overflow) = self.seconds.overflowing_add(rhs.seconds);
+ if overflow {
+ if self.seconds > 0 {
+ return Self::MAX;
+ }
+ return Self::MIN;
+ }
+ let mut nanoseconds = self.nanoseconds.get() + rhs.nanoseconds.get();
+
+ if nanoseconds >= Nanosecond::per(Second) as i32 || seconds < 0 && nanoseconds > 0 {
+ nanoseconds -= Nanosecond::per(Second) as i32;
+ seconds = match seconds.checked_add(1) {
+ Some(seconds) => seconds,
+ None => return Self::MAX,
+ };
+ } else if nanoseconds <= -(Nanosecond::per(Second) as i32) || seconds > 0 && nanoseconds < 0
+ {
+ nanoseconds += Nanosecond::per(Second) as i32;
+ seconds = match seconds.checked_sub(1) {
+ Some(seconds) => seconds,
+ None => return Self::MIN,
+ };
+ }
+
+ // Safety: `nanoseconds` is guaranteed to be in range because of the overflow handling.
+ unsafe { Self::new_unchecked(seconds, nanoseconds) }
+ }
+
+ /// Computes `self - rhs`, saturating if an overflow occurred.
+ ///
+ /// ```rust
+ /// # use time::{Duration, ext::NumericalDuration};
+ /// assert_eq!(5.seconds().saturating_sub(5.seconds()), Duration::ZERO);
+ /// assert_eq!(Duration::MIN.saturating_sub(1.nanoseconds()), Duration::MIN);
+ /// assert_eq!(
+ /// Duration::MAX.saturating_sub((-1).nanoseconds()),
+ /// Duration::MAX
+ /// );
+ /// assert_eq!(5.seconds().saturating_sub(10.seconds()), (-5).seconds());
+ /// ```
+ pub const fn saturating_sub(self, rhs: Self) -> Self {
+ let (mut seconds, overflow) = self.seconds.overflowing_sub(rhs.seconds);
+ if overflow {
+ if self.seconds > 0 {
+ return Self::MAX;
+ }
+ return Self::MIN;
+ }
+ let mut nanoseconds = self.nanoseconds.get() - rhs.nanoseconds.get();
+
+ if nanoseconds >= Nanosecond::per(Second) as i32 || seconds < 0 && nanoseconds > 0 {
+ nanoseconds -= Nanosecond::per(Second) as i32;
+ seconds = match seconds.checked_add(1) {
+ Some(seconds) => seconds,
+ None => return Self::MAX,
+ };
+ } else if nanoseconds <= -(Nanosecond::per(Second) as i32) || seconds > 0 && nanoseconds < 0
+ {
+ nanoseconds += Nanosecond::per(Second) as i32;
+ seconds = match seconds.checked_sub(1) {
+ Some(seconds) => seconds,
+ None => return Self::MIN,
+ };
+ }
+
+ // Safety: `nanoseconds` is guaranteed to be in range because of the overflow handling.
+ unsafe { Self::new_unchecked(seconds, nanoseconds) }
+ }
+
+ /// Computes `self * rhs`, saturating if an overflow occurred.
+ ///
+ /// ```rust
+ /// # use time::{Duration, ext::NumericalDuration};
+ /// assert_eq!(5.seconds().saturating_mul(2), 10.seconds());
+ /// assert_eq!(5.seconds().saturating_mul(-2), (-10).seconds());
+ /// assert_eq!(5.seconds().saturating_mul(0), Duration::ZERO);
+ /// assert_eq!(Duration::MAX.saturating_mul(2), Duration::MAX);
+ /// assert_eq!(Duration::MIN.saturating_mul(2), Duration::MIN);
+ /// assert_eq!(Duration::MAX.saturating_mul(-2), Duration::MIN);
+ /// assert_eq!(Duration::MIN.saturating_mul(-2), Duration::MAX);
+ /// ```
+ pub const fn saturating_mul(self, rhs: i32) -> Self {
+ // Multiply nanoseconds as i64, because it cannot overflow that way.
+ let total_nanos = self.nanoseconds.get() as i64 * rhs as i64;
+ let extra_secs = total_nanos / Nanosecond::per(Second) as i64;
+ let nanoseconds = (total_nanos % Nanosecond::per(Second) as i64) as i32;
+ let (seconds, overflow1) = self.seconds.overflowing_mul(rhs as i64);
+ if overflow1 {
+ if self.seconds > 0 && rhs > 0 || self.seconds < 0 && rhs < 0 {
+ return Self::MAX;
+ }
+ return Self::MIN;
+ }
+ let (seconds, overflow2) = seconds.overflowing_add(extra_secs);
+ if overflow2 {
+ if self.seconds > 0 && rhs > 0 {
+ return Self::MAX;
+ }
+ return Self::MIN;
+ }
+
+ // Safety: `nanoseconds` is guaranteed to be in range because of to the modulus above.
+ unsafe { Self::new_unchecked(seconds, nanoseconds) }
+ }
+
+ /// Runs a closure, returning the duration of time it took to run. The return value of the
+ /// closure is provided in the second part of the tuple.
+ #[doc(hidden)]
+ #[cfg(feature = "std")]
+ #[deprecated(
+ since = "0.3.32",
+ note = "extremely limited use case, not intended for benchmarking"
+ )]
+ #[allow(deprecated)]
+ pub fn time_fn<T>(f: impl FnOnce() -> T) -> (Self, T) {
+ let start = Instant::now();
+ let return_value = f();
+ let end = Instant::now();
+
+ (end - start, return_value)
+ }
+}
+
+/// The format returned by this implementation is not stable and must not be relied upon.
+///
+/// By default this produces an exact, full-precision printout of the duration.
+/// For a concise, rounded printout instead, you can use the `.N` format specifier:
+///
+/// ```
+/// # use time::Duration;
+/// #
+/// let duration = Duration::new(123456, 789011223);
+/// println!("{duration:.3}");
+/// ```
+///
+/// For the purposes of this implementation, a day is exactly 24 hours and a minute is exactly 60
+/// seconds.
+impl fmt::Display for Duration {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ if self.is_negative() {
+ f.write_str("-")?;
+ }
+
+ if let Some(_precision) = f.precision() {
+ // Concise, rounded representation.
+
+ if self.is_zero() {
+ // Write a zero value with the requested precision.
+ return (0.).fmt(f).and_then(|_| f.write_str("s"));
+ }
+
+ /// Format the first item that produces a value greater than 1 and then break.
+ macro_rules! item {
+ ($name:literal, $value:expr) => {
+ let value = $value;
+ if value >= 1.0 {
+ return value.fmt(f).and_then(|_| f.write_str($name));
+ }
+ };
+ }
+
+ // Even if this produces a de-normal float, because we're rounding we don't really care.
+ let seconds = self.unsigned_abs().as_secs_f64();
+
+ item!("d", seconds / Second::per(Day) as f64);
+ item!("h", seconds / Second::per(Hour) as f64);
+ item!("m", seconds / Second::per(Minute) as f64);
+ item!("s", seconds);
+ item!("ms", seconds * Millisecond::per(Second) as f64);
+ item!("µs", seconds * Microsecond::per(Second) as f64);
+ item!("ns", seconds * Nanosecond::per(Second) as f64);
+ } else {
+ // Precise, but verbose representation.
+
+ if self.is_zero() {
+ return f.write_str("0s");
+ }
+
+ /// Format a single item.
+ macro_rules! item {
+ ($name:literal, $value:expr) => {
+ match $value {
+ 0 => Ok(()),
+ value => value.fmt(f).and_then(|_| f.write_str($name)),
+ }
+ };
+ }
+
+ let seconds = self.seconds.unsigned_abs();
+ let nanoseconds = self.nanoseconds.get().unsigned_abs();
+
+ item!("d", seconds / Second::per(Day).extend::<u64>())?;
+ item!(
+ "h",
+ seconds / Second::per(Hour).extend::<u64>() % Hour::per(Day).extend::<u64>()
+ )?;
+ item!(
+ "m",
+ seconds / Second::per(Minute).extend::<u64>() % Minute::per(Hour).extend::<u64>()
+ )?;
+ item!("s", seconds % Second::per(Minute).extend::<u64>())?;
+ item!("ms", nanoseconds / Nanosecond::per(Millisecond))?;
+ item!(
+ "µs",
+ nanoseconds / Nanosecond::per(Microsecond).extend::<u32>()
+ % Microsecond::per(Millisecond).extend::<u32>()
+ )?;
+ item!(
+ "ns",
+ nanoseconds % Nanosecond::per(Microsecond).extend::<u32>()
+ )?;
+ }
+
+ Ok(())
+ }
+}
+
+impl TryFrom<StdDuration> for Duration {
+ type Error = error::ConversionRange;
+
+ fn try_from(original: StdDuration) -> Result<Self, error::ConversionRange> {
+ Ok(Self::new(
+ original
+ .as_secs()
+ .try_into()
+ .map_err(|_| error::ConversionRange)?,
+ original.subsec_nanos().cast_signed(),
+ ))
+ }
+}
+
+impl TryFrom<Duration> for StdDuration {
+ type Error = error::ConversionRange;
+
+ fn try_from(duration: Duration) -> Result<Self, error::ConversionRange> {
+ Ok(Self::new(
+ duration
+ .seconds
+ .try_into()
+ .map_err(|_| error::ConversionRange)?,
+ duration
+ .nanoseconds
+ .get()
+ .try_into()
+ .map_err(|_| error::ConversionRange)?,
+ ))
+ }
+}
+
+impl Add for Duration {
+ type Output = Self;
+
+ /// # Panics
+ ///
+ /// This may panic if an overflow occurs.
+ fn add(self, rhs: Self) -> Self::Output {
+ self.checked_add(rhs)
+ .expect("overflow when adding durations")
+ }
+}
+
+impl Add<StdDuration> for Duration {
+ type Output = Self;
+
+ /// # Panics
+ ///
+ /// This may panic if an overflow occurs.
+ fn add(self, std_duration: StdDuration) -> Self::Output {
+ self + Self::try_from(std_duration)
+ .expect("overflow converting `std::time::Duration` to `time::Duration`")
+ }
+}
+
+impl Add<Duration> for StdDuration {
+ type Output = Duration;
+
+ fn add(self, rhs: Duration) -> Self::Output {
+ rhs + self
+ }
+}
+
+impl_add_assign!(Duration: Self, StdDuration);
+
+impl AddAssign<Duration> for StdDuration {
+ /// # Panics
+ ///
+ /// This may panic if the resulting addition cannot be represented.
+ fn add_assign(&mut self, rhs: Duration) {
+ *self = (*self + rhs).try_into().expect(
+ "Cannot represent a resulting duration in std. Try `let x = x + rhs;`, which will \
+ change the type.",
+ );
+ }
+}
+
+impl Neg for Duration {
+ type Output = Self;
+
+ fn neg(self) -> Self::Output {
+ self.checked_neg().expect("overflow when negating duration")
+ }
+}
+
+impl Sub for Duration {
+ type Output = Self;
+
+ /// # Panics
+ ///
+ /// This may panic if an overflow occurs.
+ fn sub(self, rhs: Self) -> Self::Output {
+ self.checked_sub(rhs)
+ .expect("overflow when subtracting durations")
+ }
+}
+
+impl Sub<StdDuration> for Duration {
+ type Output = Self;
+
+ /// # Panics
+ ///
+ /// This may panic if an overflow occurs.
+ fn sub(self, rhs: StdDuration) -> Self::Output {
+ self - Self::try_from(rhs)
+ .expect("overflow converting `std::time::Duration` to `time::Duration`")
+ }
+}
+
+impl Sub<Duration> for StdDuration {
+ type Output = Duration;
+
+ /// # Panics
+ ///
+ /// This may panic if an overflow occurs.
+ fn sub(self, rhs: Duration) -> Self::Output {
+ Duration::try_from(self)
+ .expect("overflow converting `std::time::Duration` to `time::Duration`")
+ - rhs
+ }
+}
+
+impl_sub_assign!(Duration: Self, StdDuration);
+
+impl SubAssign<Duration> for StdDuration {
+ /// # Panics
+ ///
+ /// This may panic if the resulting subtraction can not be represented.
+ fn sub_assign(&mut self, rhs: Duration) {
+ *self = (*self - rhs).try_into().expect(
+ "Cannot represent a resulting duration in std. Try `let x = x - rhs;`, which will \
+ change the type.",
+ );
+ }
+}
+
+/// Implement `Mul` (reflexively) and `Div` for `Duration` for various types.
+macro_rules! duration_mul_div_int {
+ ($($type:ty),+) => {$(
+ impl Mul<$type> for Duration {
+ type Output = Self;
+
+ fn mul(self, rhs: $type) -> Self::Output {
+ Self::nanoseconds_i128(
+ self.whole_nanoseconds()
+ .checked_mul(rhs.cast_signed().extend::<i128>())
+ .expect("overflow when multiplying duration")
+ )
+ }
+ }
+
+ impl Mul<Duration> for $type {
+ type Output = Duration;
+
+ fn mul(self, rhs: Duration) -> Self::Output {
+ rhs * self
+ }
+ }
+
+ impl Div<$type> for Duration {
+ type Output = Self;
+
+ fn div(self, rhs: $type) -> Self::Output {
+ Self::nanoseconds_i128(
+ self.whole_nanoseconds() / rhs.cast_signed().extend::<i128>()
+ )
+ }
+ }
+ )+};
+}
+duration_mul_div_int![i8, i16, i32, u8, u16, u32];
+
+impl Mul<f32> for Duration {
+ type Output = Self;
+
+ fn mul(self, rhs: f32) -> Self::Output {
+ Self::seconds_f32(self.as_seconds_f32() * rhs)
+ }
+}
+
+impl Mul<Duration> for f32 {
+ type Output = Duration;
+
+ fn mul(self, rhs: Duration) -> Self::Output {
+ rhs * self
+ }
+}
+
+impl Mul<f64> for Duration {
+ type Output = Self;
+
+ fn mul(self, rhs: f64) -> Self::Output {
+ Self::seconds_f64(self.as_seconds_f64() * rhs)
+ }
+}
+
+impl Mul<Duration> for f64 {
+ type Output = Duration;
+
+ fn mul(self, rhs: Duration) -> Self::Output {
+ rhs * self
+ }
+}
+
+impl_mul_assign!(Duration: i8, i16, i32, u8, u16, u32, f32, f64);
+
+impl Div<f32> for Duration {
+ type Output = Self;
+
+ fn div(self, rhs: f32) -> Self::Output {
+ Self::seconds_f32(self.as_seconds_f32() / rhs)
+ }
+}
+
+impl Div<f64> for Duration {
+ type Output = Self;
+
+ fn div(self, rhs: f64) -> Self::Output {
+ Self::seconds_f64(self.as_seconds_f64() / rhs)
+ }
+}
+
+impl_div_assign!(Duration: i8, i16, i32, u8, u16, u32, f32, f64);
+
+impl Div for Duration {
+ type Output = f64;
+
+ fn div(self, rhs: Self) -> Self::Output {
+ self.as_seconds_f64() / rhs.as_seconds_f64()
+ }
+}
+
+impl Div<StdDuration> for Duration {
+ type Output = f64;
+
+ fn div(self, rhs: StdDuration) -> Self::Output {
+ self.as_seconds_f64() / rhs.as_secs_f64()
+ }
+}
+
+impl Div<Duration> for StdDuration {
+ type Output = f64;
+
+ fn div(self, rhs: Duration) -> Self::Output {
+ self.as_secs_f64() / rhs.as_seconds_f64()
+ }
+}
+
+impl PartialEq<StdDuration> for Duration {
+ fn eq(&self, rhs: &StdDuration) -> bool {
+ Ok(*self) == Self::try_from(*rhs)
+ }
+}
+
+impl PartialEq<Duration> for StdDuration {
+ fn eq(&self, rhs: &Duration) -> bool {
+ rhs == self
+ }
+}
+
+impl PartialOrd<StdDuration> for Duration {
+ fn partial_cmp(&self, rhs: &StdDuration) -> Option<Ordering> {
+ if rhs.as_secs() > i64::MAX.cast_unsigned() {
+ return Some(Ordering::Less);
+ }
+
+ Some(
+ self.seconds
+ .cmp(&rhs.as_secs().cast_signed())
+ .then_with(|| {
+ self.nanoseconds
+ .get()
+ .cmp(&rhs.subsec_nanos().cast_signed())
+ }),
+ )
+ }
+}
+
+impl PartialOrd<Duration> for StdDuration {
+ fn partial_cmp(&self, rhs: &Duration) -> Option<Ordering> {
+ rhs.partial_cmp(self).map(Ordering::reverse)
+ }
+}
+
+impl Sum for Duration {
+ fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
+ iter.reduce(|a, b| a + b).unwrap_or_default()
+ }
+}
+
+impl<'a> Sum<&'a Self> for Duration {
+ fn sum<I: Iterator<Item = &'a Self>>(iter: I) -> Self {
+ iter.copied().sum()
+ }
+}
+
+#[cfg(feature = "std")]
+impl Add<Duration> for SystemTime {
+ type Output = Self;
+
+ fn add(self, duration: Duration) -> Self::Output {
+ if duration.is_zero() {
+ self
+ } else if duration.is_positive() {
+ self + duration.unsigned_abs()
+ } else {
+ debug_assert!(duration.is_negative());
+ self - duration.unsigned_abs()
+ }
+ }
+}
+
+impl_add_assign!(SystemTime: #[cfg(feature = "std")] Duration);
+
+#[cfg(feature = "std")]
+impl Sub<Duration> for SystemTime {
+ type Output = Self;
+
+ fn sub(self, duration: Duration) -> Self::Output {
+ if duration.is_zero() {
+ self
+ } else if duration.is_positive() {
+ self - duration.unsigned_abs()
+ } else {
+ debug_assert!(duration.is_negative());
+ self + duration.unsigned_abs()
+ }
+ }
+}
+
+impl_sub_assign!(SystemTime: #[cfg(feature = "std")] Duration);
diff --git a/vendor/time/src/error/component_range.rs b/vendor/time/src/error/component_range.rs
new file mode 100644
index 00000000..dc980234
--- /dev/null
+++ b/vendor/time/src/error/component_range.rs
@@ -0,0 +1,114 @@
+//! Component range error
+
+use core::{fmt, hash};
+
+use crate::error;
+
+/// An error type indicating that a component provided to a method was out of range, causing a
+/// failure.
+// i64 is the narrowest type fitting all use cases. This eliminates the need for a type parameter.
+#[derive(Debug, Clone, Copy, Eq)]
+pub struct ComponentRange {
+ /// Name of the component.
+ pub(crate) name: &'static str,
+ /// Minimum allowed value, inclusive.
+ pub(crate) minimum: i64,
+ /// Maximum allowed value, inclusive.
+ pub(crate) maximum: i64,
+ /// Value that was provided.
+ pub(crate) value: i64,
+ /// The minimum and/or maximum value is conditional on the value of other
+ /// parameters.
+ pub(crate) conditional_message: Option<&'static str>,
+}
+
+impl ComponentRange {
+ /// Obtain the name of the component whose value was out of range.
+ pub const fn name(self) -> &'static str {
+ self.name
+ }
+
+ /// Whether the value's permitted range is conditional, i.e. whether an input with this
+ /// value could have succeeded if the values of other components were different.
+ pub const fn is_conditional(self) -> bool {
+ self.conditional_message.is_some()
+ }
+}
+
+impl PartialEq for ComponentRange {
+ fn eq(&self, other: &Self) -> bool {
+ self.name == other.name
+ && self.minimum == other.minimum
+ && self.maximum == other.maximum
+ && self.value == other.value
+ // Skip the contents of the message when comparing for equality.
+ && self.conditional_message.is_some() == other.conditional_message.is_some()
+ }
+}
+
+impl hash::Hash for ComponentRange {
+ fn hash<H: hash::Hasher>(&self, state: &mut H) {
+ self.name.hash(state);
+ self.minimum.hash(state);
+ self.maximum.hash(state);
+ self.value.hash(state);
+ // Skip the contents of the message when comparing for equality.
+ self.conditional_message.is_some().hash(state);
+ }
+}
+
+impl fmt::Display for ComponentRange {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(
+ f,
+ "{} must be in the range {}..={}",
+ self.name, self.minimum, self.maximum
+ )?;
+
+ if let Some(message) = self.conditional_message {
+ write!(f, " {message}")?;
+ }
+
+ Ok(())
+ }
+}
+
+impl From<ComponentRange> for crate::Error {
+ fn from(original: ComponentRange) -> Self {
+ Self::ComponentRange(original)
+ }
+}
+
+impl TryFrom<crate::Error> for ComponentRange {
+ type Error = error::DifferentVariant;
+
+ fn try_from(err: crate::Error) -> Result<Self, Self::Error> {
+ match err {
+ crate::Error::ComponentRange(err) => Ok(err),
+ _ => Err(error::DifferentVariant),
+ }
+ }
+}
+
+/// **This trait implementation is deprecated and will be removed in a future breaking release.**
+#[cfg(feature = "serde")]
+impl serde::de::Expected for ComponentRange {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(
+ f,
+ "a value in the range {}..={}",
+ self.minimum, self.maximum
+ )
+ }
+}
+
+#[cfg(feature = "serde")]
+impl ComponentRange {
+ /// Convert the error to a deserialization error.
+ pub(crate) fn into_de_error<E: serde::de::Error>(self) -> E {
+ E::invalid_value(serde::de::Unexpected::Signed(self.value), &self)
+ }
+}
+
+#[cfg(feature = "std")]
+impl std::error::Error for ComponentRange {}
diff --git a/vendor/time/src/error/conversion_range.rs b/vendor/time/src/error/conversion_range.rs
new file mode 100644
index 00000000..d6d9243e
--- /dev/null
+++ b/vendor/time/src/error/conversion_range.rs
@@ -0,0 +1,36 @@
+//! Conversion range error
+
+use core::fmt;
+
+use crate::error;
+
+/// An error type indicating that a conversion failed because the target type could not store the
+/// initial value.
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub struct ConversionRange;
+
+impl fmt::Display for ConversionRange {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.write_str("Source value is out of range for the target type")
+ }
+}
+
+#[cfg(feature = "std")]
+impl std::error::Error for ConversionRange {}
+
+impl From<ConversionRange> for crate::Error {
+ fn from(err: ConversionRange) -> Self {
+ Self::ConversionRange(err)
+ }
+}
+
+impl TryFrom<crate::Error> for ConversionRange {
+ type Error = error::DifferentVariant;
+
+ fn try_from(err: crate::Error) -> Result<Self, Self::Error> {
+ match err {
+ crate::Error::ConversionRange(err) => Ok(err),
+ _ => Err(error::DifferentVariant),
+ }
+ }
+}
diff --git a/vendor/time/src/error/different_variant.rs b/vendor/time/src/error/different_variant.rs
new file mode 100644
index 00000000..22e21cb0
--- /dev/null
+++ b/vendor/time/src/error/different_variant.rs
@@ -0,0 +1,34 @@
+//! Different variant error
+
+use core::fmt;
+
+/// An error type indicating that a [`TryFrom`](core::convert::TryFrom) call failed because the
+/// original value was of a different variant.
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub struct DifferentVariant;
+
+impl fmt::Display for DifferentVariant {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "value was of a different variant than required")
+ }
+}
+
+#[cfg(feature = "std")]
+impl std::error::Error for DifferentVariant {}
+
+impl From<DifferentVariant> for crate::Error {
+ fn from(err: DifferentVariant) -> Self {
+ Self::DifferentVariant(err)
+ }
+}
+
+impl TryFrom<crate::Error> for DifferentVariant {
+ type Error = Self;
+
+ fn try_from(err: crate::Error) -> Result<Self, Self::Error> {
+ match err {
+ crate::Error::DifferentVariant(err) => Ok(err),
+ _ => Err(Self),
+ }
+ }
+}
diff --git a/vendor/time/src/error/format.rs b/vendor/time/src/error/format.rs
new file mode 100644
index 00000000..906a58c0
--- /dev/null
+++ b/vendor/time/src/error/format.rs
@@ -0,0 +1,113 @@
+//! Error formatting a struct
+
+use alloc::boxed::Box;
+use core::fmt;
+use std::io;
+
+use crate::error;
+
+/// An error occurred when formatting.
+#[non_exhaustive]
+#[derive(Debug)]
+pub enum Format {
+ /// The type being formatted does not contain sufficient information to format a component.
+ #[non_exhaustive]
+ InsufficientTypeInformation,
+ /// The component named has a value that cannot be formatted into the requested format.
+ ///
+ /// This variant is only returned when using well-known formats.
+ InvalidComponent(&'static str),
+ /// A component provided was out of range.
+ ComponentRange(Box<error::ComponentRange>),
+ /// A value of `std::io::Error` was returned internally.
+ StdIo(io::Error),
+}
+
+impl fmt::Display for Format {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self {
+ Self::InsufficientTypeInformation => f.write_str(
+ "The type being formatted does not contain sufficient information to format a \
+ component.",
+ ),
+ Self::InvalidComponent(component) => write!(
+ f,
+ "The {component} component cannot be formatted into the requested format."
+ ),
+ Self::ComponentRange(err) => err.fmt(f),
+ Self::StdIo(err) => err.fmt(f),
+ }
+ }
+}
+
+impl From<error::ComponentRange> for Format {
+ fn from(err: error::ComponentRange) -> Self {
+ Self::ComponentRange(Box::new(err))
+ }
+}
+
+impl From<io::Error> for Format {
+ fn from(err: io::Error) -> Self {
+ Self::StdIo(err)
+ }
+}
+
+impl TryFrom<Format> for error::ComponentRange {
+ type Error = error::DifferentVariant;
+
+ fn try_from(err: Format) -> Result<Self, Self::Error> {
+ match err {
+ Format::ComponentRange(err) => Ok(*err),
+ _ => Err(error::DifferentVariant),
+ }
+ }
+}
+
+impl TryFrom<Format> for io::Error {
+ type Error = error::DifferentVariant;
+
+ fn try_from(err: Format) -> Result<Self, Self::Error> {
+ match err {
+ Format::StdIo(err) => Ok(err),
+ _ => Err(error::DifferentVariant),
+ }
+ }
+}
+
+#[cfg(feature = "std")]
+impl std::error::Error for Format {
+ fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
+ match self {
+ Self::InsufficientTypeInformation | Self::InvalidComponent(_) => None,
+ Self::ComponentRange(err) => Some(&**err),
+ Self::StdIo(err) => Some(err),
+ }
+ }
+}
+
+impl From<Format> for crate::Error {
+ fn from(original: Format) -> Self {
+ Self::Format(original)
+ }
+}
+
+impl TryFrom<crate::Error> for Format {
+ type Error = error::DifferentVariant;
+
+ fn try_from(err: crate::Error) -> Result<Self, Self::Error> {
+ match err {
+ crate::Error::Format(err) => Ok(err),
+ _ => Err(error::DifferentVariant),
+ }
+ }
+}
+
+#[cfg(feature = "serde")]
+impl Format {
+ /// Obtain an error type for the serializer.
+ #[doc(hidden)] // Exposed only for the `declare_format_string` macro
+ pub fn into_invalid_serde_value<S: serde::Serializer>(self) -> S::Error {
+ use serde::ser::Error;
+ S::Error::custom(self)
+ }
+}
diff --git a/vendor/time/src/error/indeterminate_offset.rs b/vendor/time/src/error/indeterminate_offset.rs
new file mode 100644
index 00000000..d25d4164
--- /dev/null
+++ b/vendor/time/src/error/indeterminate_offset.rs
@@ -0,0 +1,35 @@
+//! Indeterminate offset
+
+use core::fmt;
+
+use crate::error;
+
+/// The system's UTC offset could not be determined at the given datetime.
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub struct IndeterminateOffset;
+
+impl fmt::Display for IndeterminateOffset {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.write_str("The system's UTC offset could not be determined")
+ }
+}
+
+#[cfg(feature = "std")]
+impl std::error::Error for IndeterminateOffset {}
+
+impl From<IndeterminateOffset> for crate::Error {
+ fn from(err: IndeterminateOffset) -> Self {
+ Self::IndeterminateOffset(err)
+ }
+}
+
+impl TryFrom<crate::Error> for IndeterminateOffset {
+ type Error = error::DifferentVariant;
+
+ fn try_from(err: crate::Error) -> Result<Self, Self::Error> {
+ match err {
+ crate::Error::IndeterminateOffset(err) => Ok(err),
+ _ => Err(error::DifferentVariant),
+ }
+ }
+}
diff --git a/vendor/time/src/error/invalid_format_description.rs b/vendor/time/src/error/invalid_format_description.rs
new file mode 100644
index 00000000..635fee75
--- /dev/null
+++ b/vendor/time/src/error/invalid_format_description.rs
@@ -0,0 +1,132 @@
+//! Invalid format description
+
+use alloc::string::String;
+use core::fmt;
+
+use crate::error;
+
+/// The format description provided was not valid.
+#[non_exhaustive]
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub enum InvalidFormatDescription {
+ /// There was a bracket pair that was opened but not closed.
+ #[non_exhaustive]
+ UnclosedOpeningBracket {
+ /// The zero-based index of the opening bracket.
+ index: usize,
+ },
+ /// A component name is not valid.
+ #[non_exhaustive]
+ InvalidComponentName {
+ /// The name of the invalid component name.
+ name: String,
+ /// The zero-based index the component name starts at.
+ index: usize,
+ },
+ /// A modifier is not valid.
+ #[non_exhaustive]
+ InvalidModifier {
+ /// The value of the invalid modifier.
+ value: String,
+ /// The zero-based index the modifier starts at.
+ index: usize,
+ },
+ /// A component name is missing.
+ #[non_exhaustive]
+ MissingComponentName {
+ /// The zero-based index where the component name should start.
+ index: usize,
+ },
+ /// A required modifier is missing.
+ #[non_exhaustive]
+ MissingRequiredModifier {
+ /// The name of the modifier that is missing.
+ name: &'static str,
+ /// The zero-based index of the component.
+ index: usize,
+ },
+ /// Something was expected, but not found.
+ #[non_exhaustive]
+ Expected {
+ /// What was expected to be present, but wasn't.
+ what: &'static str,
+ /// The zero-based index the item was expected to be found at.
+ index: usize,
+ },
+ /// Certain behavior is not supported in the given context.
+ #[non_exhaustive]
+ NotSupported {
+ /// The behavior that is not supported.
+ what: &'static str,
+ /// The context in which the behavior is not supported.
+ context: &'static str,
+ /// The zero-based index the error occurred at.
+ index: usize,
+ },
+}
+
+impl From<InvalidFormatDescription> for crate::Error {
+ fn from(original: InvalidFormatDescription) -> Self {
+ Self::InvalidFormatDescription(original)
+ }
+}
+
+impl TryFrom<crate::Error> for InvalidFormatDescription {
+ type Error = error::DifferentVariant;
+
+ fn try_from(err: crate::Error) -> Result<Self, Self::Error> {
+ match err {
+ crate::Error::InvalidFormatDescription(err) => Ok(err),
+ _ => Err(error::DifferentVariant),
+ }
+ }
+}
+
+impl fmt::Display for InvalidFormatDescription {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ use InvalidFormatDescription::*;
+ match self {
+ UnclosedOpeningBracket { index } => {
+ write!(f, "unclosed opening bracket at byte index {index}")
+ }
+ InvalidComponentName { name, index } => {
+ write!(f, "invalid component name `{name}` at byte index {index}")
+ }
+ InvalidModifier { value, index } => {
+ write!(f, "invalid modifier `{value}` at byte index {index}")
+ }
+ MissingComponentName { index } => {
+ write!(f, "missing component name at byte index {index}")
+ }
+ MissingRequiredModifier { name, index } => {
+ write!(
+ f,
+ "missing required modifier `{name}` for component at byte index {index}"
+ )
+ }
+ Expected {
+ what: expected,
+ index,
+ } => {
+ write!(f, "expected {expected} at byte index {index}")
+ }
+ NotSupported {
+ what,
+ context,
+ index,
+ } => {
+ if context.is_empty() {
+ write!(f, "{what} is not supported at byte index {index}")
+ } else {
+ write!(
+ f,
+ "{what} is not supported in {context} at byte index {index}"
+ )
+ }
+ }
+ }
+ }
+}
+
+#[cfg(feature = "std")]
+impl std::error::Error for InvalidFormatDescription {}
diff --git a/vendor/time/src/error/invalid_variant.rs b/vendor/time/src/error/invalid_variant.rs
new file mode 100644
index 00000000..396a749a
--- /dev/null
+++ b/vendor/time/src/error/invalid_variant.rs
@@ -0,0 +1,34 @@
+//! Invalid variant error
+
+use core::fmt;
+
+/// An error type indicating that a [`FromStr`](core::str::FromStr) call failed because the value
+/// was not a valid variant.
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub struct InvalidVariant;
+
+impl fmt::Display for InvalidVariant {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "value was not a valid variant")
+ }
+}
+
+#[cfg(feature = "std")]
+impl std::error::Error for InvalidVariant {}
+
+impl From<InvalidVariant> for crate::Error {
+ fn from(err: InvalidVariant) -> Self {
+ Self::InvalidVariant(err)
+ }
+}
+
+impl TryFrom<crate::Error> for InvalidVariant {
+ type Error = crate::error::DifferentVariant;
+
+ fn try_from(err: crate::Error) -> Result<Self, Self::Error> {
+ match err {
+ crate::Error::InvalidVariant(err) => Ok(err),
+ _ => Err(crate::error::DifferentVariant),
+ }
+ }
+}
diff --git a/vendor/time/src/error/mod.rs b/vendor/time/src/error/mod.rs
new file mode 100644
index 00000000..78b15380
--- /dev/null
+++ b/vendor/time/src/error/mod.rs
@@ -0,0 +1,131 @@
+//! Various error types returned by methods in the time crate.
+
+mod component_range;
+mod conversion_range;
+mod different_variant;
+#[cfg(feature = "formatting")]
+mod format;
+#[cfg(feature = "local-offset")]
+mod indeterminate_offset;
+#[cfg(all(any(feature = "formatting", feature = "parsing"), feature = "alloc"))]
+mod invalid_format_description;
+mod invalid_variant;
+#[cfg(feature = "parsing")]
+mod parse;
+#[cfg(feature = "parsing")]
+mod parse_from_description;
+#[cfg(feature = "parsing")]
+mod try_from_parsed;
+
+#[cfg(feature = "parsing")]
+use core::convert::Infallible;
+use core::fmt;
+
+pub use component_range::ComponentRange;
+pub use conversion_range::ConversionRange;
+pub use different_variant::DifferentVariant;
+#[cfg(feature = "formatting")]
+pub use format::Format;
+#[cfg(feature = "local-offset")]
+pub use indeterminate_offset::IndeterminateOffset;
+#[cfg(all(any(feature = "formatting", feature = "parsing"), feature = "alloc"))]
+pub use invalid_format_description::InvalidFormatDescription;
+pub use invalid_variant::InvalidVariant;
+#[cfg(feature = "parsing")]
+pub use parse::Parse;
+#[cfg(feature = "parsing")]
+pub use parse_from_description::ParseFromDescription;
+#[cfg(feature = "parsing")]
+pub use try_from_parsed::TryFromParsed;
+
+/// A unified error type for anything returned by a method in the time crate.
+///
+/// This can be used when you either don't know or don't care about the exact error returned.
+/// `Result<_, time::Error>` (or its alias `time::Result<_>`) will work in these situations.
+#[non_exhaustive]
+#[derive(Debug)]
+pub enum Error {
+ #[allow(missing_docs)]
+ ConversionRange(ConversionRange),
+ #[allow(missing_docs)]
+ ComponentRange(ComponentRange),
+ #[cfg(feature = "local-offset")]
+ #[allow(missing_docs)]
+ IndeterminateOffset(IndeterminateOffset),
+ #[cfg(feature = "formatting")]
+ #[allow(missing_docs)]
+ Format(Format),
+ #[cfg(feature = "parsing")]
+ #[allow(missing_docs)]
+ ParseFromDescription(ParseFromDescription),
+ #[cfg(feature = "parsing")]
+ #[allow(missing_docs)]
+ #[non_exhaustive]
+ #[deprecated(
+ since = "0.3.28",
+ note = "no longer output. moved to the `ParseFromDescription` variant"
+ )]
+ UnexpectedTrailingCharacters {
+ #[doc(hidden)]
+ never: Infallible,
+ },
+ #[cfg(feature = "parsing")]
+ #[allow(missing_docs)]
+ TryFromParsed(TryFromParsed),
+ #[cfg(all(any(feature = "formatting", feature = "parsing"), feature = "alloc"))]
+ #[allow(missing_docs)]
+ InvalidFormatDescription(InvalidFormatDescription),
+ #[allow(missing_docs)]
+ DifferentVariant(DifferentVariant),
+ #[allow(missing_docs)]
+ InvalidVariant(InvalidVariant),
+}
+
+impl fmt::Display for Error {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self {
+ Self::ConversionRange(e) => e.fmt(f),
+ Self::ComponentRange(e) => e.fmt(f),
+ #[cfg(feature = "local-offset")]
+ Self::IndeterminateOffset(e) => e.fmt(f),
+ #[cfg(feature = "formatting")]
+ Self::Format(e) => e.fmt(f),
+ #[cfg(feature = "parsing")]
+ Self::ParseFromDescription(e) => e.fmt(f),
+ #[cfg(feature = "parsing")]
+ #[allow(deprecated)]
+ Self::UnexpectedTrailingCharacters { never } => match *never {},
+ #[cfg(feature = "parsing")]
+ Self::TryFromParsed(e) => e.fmt(f),
+ #[cfg(all(any(feature = "formatting", feature = "parsing"), feature = "alloc"))]
+ Self::InvalidFormatDescription(e) => e.fmt(f),
+ Self::DifferentVariant(e) => e.fmt(f),
+ Self::InvalidVariant(e) => e.fmt(f),
+ }
+ }
+}
+
+#[cfg(feature = "std")]
+impl std::error::Error for Error {
+ fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
+ match self {
+ Self::ConversionRange(err) => Some(err),
+ Self::ComponentRange(err) => Some(err),
+ #[cfg(feature = "local-offset")]
+ Self::IndeterminateOffset(err) => Some(err),
+ #[cfg(feature = "formatting")]
+ Self::Format(err) => Some(err),
+ #[cfg(feature = "parsing")]
+ Self::ParseFromDescription(err) => Some(err),
+ #[cfg(feature = "parsing")]
+ #[allow(deprecated)]
+ Self::UnexpectedTrailingCharacters { never } => match *never {},
+ #[cfg(feature = "parsing")]
+ Self::TryFromParsed(err) => Some(err),
+ #[cfg(all(any(feature = "formatting", feature = "parsing"), feature = "alloc"))]
+ Self::InvalidFormatDescription(err) => Some(err),
+ Self::DifferentVariant(err) => Some(err),
+ Self::InvalidVariant(err) => Some(err),
+ }
+ }
+}
diff --git a/vendor/time/src/error/parse.rs b/vendor/time/src/error/parse.rs
new file mode 100644
index 00000000..ee3f87b7
--- /dev/null
+++ b/vendor/time/src/error/parse.rs
@@ -0,0 +1,109 @@
+//! Error that occurred at some stage of parsing
+
+use core::convert::Infallible;
+use core::fmt;
+
+use crate::error::{self, ParseFromDescription, TryFromParsed};
+
+/// An error that occurred at some stage of parsing.
+#[non_exhaustive]
+#[allow(variant_size_differences)]
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum Parse {
+ #[allow(missing_docs)]
+ TryFromParsed(TryFromParsed),
+ #[allow(missing_docs)]
+ ParseFromDescription(ParseFromDescription),
+ #[allow(missing_docs)]
+ #[non_exhaustive]
+ #[deprecated(
+ since = "0.3.28",
+ note = "no longer output. moved to the `ParseFromDescription` variant"
+ )]
+ UnexpectedTrailingCharacters {
+ #[doc(hidden)]
+ never: Infallible,
+ },
+}
+
+impl fmt::Display for Parse {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self {
+ Self::TryFromParsed(err) => err.fmt(f),
+ Self::ParseFromDescription(err) => err.fmt(f),
+ #[allow(deprecated)]
+ Self::UnexpectedTrailingCharacters { never } => match *never {},
+ }
+ }
+}
+
+#[cfg(feature = "std")]
+impl std::error::Error for Parse {
+ fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
+ match self {
+ Self::TryFromParsed(err) => Some(err),
+ Self::ParseFromDescription(err) => Some(err),
+ #[allow(deprecated)]
+ Self::UnexpectedTrailingCharacters { never } => match *never {},
+ }
+ }
+}
+
+impl From<TryFromParsed> for Parse {
+ fn from(err: TryFromParsed) -> Self {
+ Self::TryFromParsed(err)
+ }
+}
+
+impl TryFrom<Parse> for TryFromParsed {
+ type Error = error::DifferentVariant;
+
+ fn try_from(err: Parse) -> Result<Self, Self::Error> {
+ match err {
+ Parse::TryFromParsed(err) => Ok(err),
+ _ => Err(error::DifferentVariant),
+ }
+ }
+}
+
+impl From<ParseFromDescription> for Parse {
+ fn from(err: ParseFromDescription) -> Self {
+ Self::ParseFromDescription(err)
+ }
+}
+
+impl TryFrom<Parse> for ParseFromDescription {
+ type Error = error::DifferentVariant;
+
+ fn try_from(err: Parse) -> Result<Self, Self::Error> {
+ match err {
+ Parse::ParseFromDescription(err) => Ok(err),
+ _ => Err(error::DifferentVariant),
+ }
+ }
+}
+
+impl From<Parse> for crate::Error {
+ fn from(err: Parse) -> Self {
+ match err {
+ Parse::TryFromParsed(err) => Self::TryFromParsed(err),
+ Parse::ParseFromDescription(err) => Self::ParseFromDescription(err),
+ #[allow(deprecated)]
+ Parse::UnexpectedTrailingCharacters { never } => match never {},
+ }
+ }
+}
+
+impl TryFrom<crate::Error> for Parse {
+ type Error = error::DifferentVariant;
+
+ fn try_from(err: crate::Error) -> Result<Self, Self::Error> {
+ match err {
+ crate::Error::ParseFromDescription(err) => Ok(Self::ParseFromDescription(err)),
+ #[allow(deprecated)]
+ crate::Error::UnexpectedTrailingCharacters { never } => match never {},
+ crate::Error::TryFromParsed(err) => Ok(Self::TryFromParsed(err)),
+ _ => Err(error::DifferentVariant),
+ }
+ }
+}
diff --git a/vendor/time/src/error/parse_from_description.rs b/vendor/time/src/error/parse_from_description.rs
new file mode 100644
index 00000000..40124dce
--- /dev/null
+++ b/vendor/time/src/error/parse_from_description.rs
@@ -0,0 +1,53 @@
+//! Error parsing an input into a [`Parsed`](crate::parsing::Parsed) struct
+
+use core::fmt;
+
+use crate::error;
+
+/// An error that occurred while parsing the input into a [`Parsed`](crate::parsing::Parsed) struct.
+#[non_exhaustive]
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum ParseFromDescription {
+ /// A string literal was not what was expected.
+ #[non_exhaustive]
+ InvalidLiteral,
+ /// A dynamic component was not valid.
+ InvalidComponent(&'static str),
+ /// The input was expected to have ended, but there are characters that remain.
+ #[non_exhaustive]
+ UnexpectedTrailingCharacters,
+}
+
+impl fmt::Display for ParseFromDescription {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self {
+ Self::InvalidLiteral => f.write_str("a character literal was not valid"),
+ Self::InvalidComponent(name) => {
+ write!(f, "the '{name}' component could not be parsed")
+ }
+ Self::UnexpectedTrailingCharacters => {
+ f.write_str("unexpected trailing characters; the end of input was expected")
+ }
+ }
+ }
+}
+
+#[cfg(feature = "std")]
+impl std::error::Error for ParseFromDescription {}
+
+impl From<ParseFromDescription> for crate::Error {
+ fn from(original: ParseFromDescription) -> Self {
+ Self::ParseFromDescription(original)
+ }
+}
+
+impl TryFrom<crate::Error> for ParseFromDescription {
+ type Error = error::DifferentVariant;
+
+ fn try_from(err: crate::Error) -> Result<Self, Self::Error> {
+ match err {
+ crate::Error::ParseFromDescription(err) => Ok(err),
+ _ => Err(error::DifferentVariant),
+ }
+ }
+}
diff --git a/vendor/time/src/error/try_from_parsed.rs b/vendor/time/src/error/try_from_parsed.rs
new file mode 100644
index 00000000..da8e6947
--- /dev/null
+++ b/vendor/time/src/error/try_from_parsed.rs
@@ -0,0 +1,71 @@
+//! Error converting a [`Parsed`](crate::parsing::Parsed) struct to another type
+
+use core::fmt;
+
+use crate::error;
+
+/// An error that occurred when converting a [`Parsed`](crate::parsing::Parsed) to another type.
+#[non_exhaustive]
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum TryFromParsed {
+ /// The [`Parsed`](crate::parsing::Parsed) did not include enough information to construct the
+ /// type.
+ InsufficientInformation,
+ /// Some component contained an invalid value for the type.
+ ComponentRange(error::ComponentRange),
+}
+
+impl fmt::Display for TryFromParsed {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self {
+ Self::InsufficientInformation => f.write_str(
+ "the `Parsed` struct did not include enough information to construct the type",
+ ),
+ Self::ComponentRange(err) => err.fmt(f),
+ }
+ }
+}
+
+impl From<error::ComponentRange> for TryFromParsed {
+ fn from(v: error::ComponentRange) -> Self {
+ Self::ComponentRange(v)
+ }
+}
+
+impl TryFrom<TryFromParsed> for error::ComponentRange {
+ type Error = error::DifferentVariant;
+
+ fn try_from(err: TryFromParsed) -> Result<Self, Self::Error> {
+ match err {
+ TryFromParsed::ComponentRange(err) => Ok(err),
+ _ => Err(error::DifferentVariant),
+ }
+ }
+}
+
+#[cfg(feature = "std")]
+impl std::error::Error for TryFromParsed {
+ fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
+ match self {
+ Self::InsufficientInformation => None,
+ Self::ComponentRange(err) => Some(err),
+ }
+ }
+}
+
+impl From<TryFromParsed> for crate::Error {
+ fn from(original: TryFromParsed) -> Self {
+ Self::TryFromParsed(original)
+ }
+}
+
+impl TryFrom<crate::Error> for TryFromParsed {
+ type Error = error::DifferentVariant;
+
+ fn try_from(err: crate::Error) -> Result<Self, Self::Error> {
+ match err {
+ crate::Error::TryFromParsed(err) => Ok(err),
+ _ => Err(error::DifferentVariant),
+ }
+ }
+}
diff --git a/vendor/time/src/ext/digit_count.rs b/vendor/time/src/ext/digit_count.rs
new file mode 100644
index 00000000..fb42ce9e
--- /dev/null
+++ b/vendor/time/src/ext/digit_count.rs
@@ -0,0 +1,26 @@
+use num_conv::prelude::*;
+
+/// A trait that indicates the formatted width of the value can be determined.
+///
+/// Note that this should not be implemented for any signed integers. This forces the caller to
+/// write the sign if desired.
+pub(crate) trait DigitCount {
+ /// The number of digits in the stringified value.
+ fn num_digits(self) -> u8;
+}
+
+/// A macro to generate implementations of `DigitCount` for unsigned integers.
+macro_rules! impl_digit_count {
+ ($($t:ty),* $(,)?) => {
+ $(impl DigitCount for $t {
+ fn num_digits(self) -> u8 {
+ match self.checked_ilog10() {
+ Some(n) => n.truncate::<u8>() + 1,
+ None => 1,
+ }
+ }
+ })*
+ };
+}
+
+impl_digit_count!(u8, u16, u32);
diff --git a/vendor/time/src/ext/instant.rs b/vendor/time/src/ext/instant.rs
new file mode 100644
index 00000000..313ad5b1
--- /dev/null
+++ b/vendor/time/src/ext/instant.rs
@@ -0,0 +1,98 @@
+use std::time::Instant as StdInstant;
+
+use crate::Duration;
+
+/// Sealed trait to prevent downstream implementations.
+mod sealed {
+ /// A trait that cannot be implemented by downstream users.
+ pub trait Sealed: Sized {}
+ impl Sealed for std::time::Instant {}
+}
+
+/// An extension trait for [`std::time::Instant`] that adds methods for
+/// [`time::Duration`](Duration)s.
+pub trait InstantExt: sealed::Sealed {
+ /// # Panics
+ ///
+ /// This function may panic if the resulting point in time cannot be represented by the
+ /// underlying data structure. See [`InstantExt::checked_add_signed`] for a non-panicking
+ /// version.
+ fn add_signed(self, duration: Duration) -> Self {
+ self.checked_add_signed(duration)
+ .expect("overflow when adding duration to instant")
+ }
+
+ /// # Panics
+ ///
+ /// This function may panic if the resulting point in time cannot be represented by the
+ /// underlying data structure. See [`InstantExt::checked_sub_signed`] for a non-panicking
+ /// version.
+ fn sub_signed(self, duration: Duration) -> Self {
+ self.checked_sub_signed(duration)
+ .expect("overflow when subtracting duration from instant")
+ }
+
+ /// Returns `Some(t)` where `t` is the time `self.checked_add_signed(duration)` if `t` can be
+ /// represented as `Instant` (which means it's inside the bounds of the underlying data
+ /// structure), `None` otherwise.
+ fn checked_add_signed(&self, duration: Duration) -> Option<Self>;
+
+ /// Returns `Some(t)` where `t` is the time `self.checked_sub_signed(duration)` if `t` can be
+ /// represented as `Instant` (which means it's inside the bounds of the underlying data
+ /// structure), `None` otherwise.
+ fn checked_sub_signed(&self, duration: Duration) -> Option<Self>;
+
+ /// Returns the amount of time elapsed from another instant to this one. This will be negative
+ /// if `earlier` is later than `self`.
+ ///
+ /// # Example
+ ///
+ /// ```rust
+ /// # use std::thread::sleep;
+ /// # use std::time::{Duration, Instant};
+ /// # use time::ext::InstantExt;
+ /// let now = Instant::now();
+ /// sleep(Duration::new(1, 0));
+ /// let new_now = Instant::now();
+ /// println!("{:?}", new_now.signed_duration_since(now)); // positive
+ /// println!("{:?}", now.signed_duration_since(new_now)); // negative
+ /// ```
+ fn signed_duration_since(&self, earlier: Self) -> Duration;
+}
+
+impl InstantExt for StdInstant {
+ fn checked_add_signed(&self, duration: Duration) -> Option<Self> {
+ if duration.is_positive() {
+ self.checked_add(duration.unsigned_abs())
+ } else if duration.is_negative() {
+ self.checked_sub(duration.unsigned_abs())
+ } else {
+ debug_assert!(duration.is_zero());
+ Some(*self)
+ }
+ }
+
+ fn checked_sub_signed(&self, duration: Duration) -> Option<Self> {
+ if duration.is_positive() {
+ self.checked_sub(duration.unsigned_abs())
+ } else if duration.is_negative() {
+ self.checked_add(duration.unsigned_abs())
+ } else {
+ debug_assert!(duration.is_zero());
+ Some(*self)
+ }
+ }
+
+ fn signed_duration_since(&self, earlier: Self) -> Duration {
+ if *self > earlier {
+ self.saturating_duration_since(earlier)
+ .try_into()
+ .unwrap_or(Duration::MAX)
+ } else {
+ earlier
+ .saturating_duration_since(*self)
+ .try_into()
+ .map_or(Duration::MIN, |d: Duration| -d)
+ }
+ }
+}
diff --git a/vendor/time/src/ext/mod.rs b/vendor/time/src/ext/mod.rs
new file mode 100644
index 00000000..7cc2d0d9
--- /dev/null
+++ b/vendor/time/src/ext/mod.rs
@@ -0,0 +1,13 @@
+//! Extension traits.
+
+mod digit_count;
+#[cfg(feature = "std")]
+mod instant;
+mod numerical_duration;
+mod numerical_std_duration;
+
+pub(crate) use self::digit_count::DigitCount;
+#[cfg(feature = "std")]
+pub use self::instant::InstantExt;
+pub use self::numerical_duration::NumericalDuration;
+pub use self::numerical_std_duration::NumericalStdDuration;
diff --git a/vendor/time/src/ext/numerical_duration.rs b/vendor/time/src/ext/numerical_duration.rs
new file mode 100644
index 00000000..a1e93cc4
--- /dev/null
+++ b/vendor/time/src/ext/numerical_duration.rs
@@ -0,0 +1,140 @@
+use crate::convert::*;
+use crate::Duration;
+
+/// Sealed trait to prevent downstream implementations.
+mod sealed {
+ /// A trait that cannot be implemented by downstream users.
+ pub trait Sealed {}
+ impl Sealed for i64 {}
+ impl Sealed for f64 {}
+}
+
+/// Create [`Duration`]s from numeric literals.
+///
+/// # Examples
+///
+/// Basic construction of [`Duration`]s.
+///
+/// ```rust
+/// # use time::{Duration, ext::NumericalDuration};
+/// assert_eq!(5.nanoseconds(), Duration::nanoseconds(5));
+/// assert_eq!(5.microseconds(), Duration::microseconds(5));
+/// assert_eq!(5.milliseconds(), Duration::milliseconds(5));
+/// assert_eq!(5.seconds(), Duration::seconds(5));
+/// assert_eq!(5.minutes(), Duration::minutes(5));
+/// assert_eq!(5.hours(), Duration::hours(5));
+/// assert_eq!(5.days(), Duration::days(5));
+/// assert_eq!(5.weeks(), Duration::weeks(5));
+/// ```
+///
+/// Signed integers work as well!
+///
+/// ```rust
+/// # use time::{Duration, ext::NumericalDuration};
+/// assert_eq!((-5).nanoseconds(), Duration::nanoseconds(-5));
+/// assert_eq!((-5).microseconds(), Duration::microseconds(-5));
+/// assert_eq!((-5).milliseconds(), Duration::milliseconds(-5));
+/// assert_eq!((-5).seconds(), Duration::seconds(-5));
+/// assert_eq!((-5).minutes(), Duration::minutes(-5));
+/// assert_eq!((-5).hours(), Duration::hours(-5));
+/// assert_eq!((-5).days(), Duration::days(-5));
+/// assert_eq!((-5).weeks(), Duration::weeks(-5));
+/// ```
+///
+/// Just like any other [`Duration`], they can be added, subtracted, etc.
+///
+/// ```rust
+/// # use time::ext::NumericalDuration;
+/// assert_eq!(2.seconds() + 500.milliseconds(), 2_500.milliseconds());
+/// assert_eq!(2.seconds() - 500.milliseconds(), 1_500.milliseconds());
+/// ```
+///
+/// When called on floating point values, any remainder of the floating point value will be
+/// truncated. Keep in mind that floating point numbers are inherently imprecise and have
+/// limited capacity.
+pub trait NumericalDuration: sealed::Sealed {
+ /// Create a [`Duration`] from the number of nanoseconds.
+ fn nanoseconds(self) -> Duration;
+ /// Create a [`Duration`] from the number of microseconds.
+ fn microseconds(self) -> Duration;
+ /// Create a [`Duration`] from the number of milliseconds.
+ fn milliseconds(self) -> Duration;
+ /// Create a [`Duration`] from the number of seconds.
+ fn seconds(self) -> Duration;
+ /// Create a [`Duration`] from the number of minutes.
+ fn minutes(self) -> Duration;
+ /// Create a [`Duration`] from the number of hours.
+ fn hours(self) -> Duration;
+ /// Create a [`Duration`] from the number of days.
+ fn days(self) -> Duration;
+ /// Create a [`Duration`] from the number of weeks.
+ fn weeks(self) -> Duration;
+}
+
+impl NumericalDuration for i64 {
+ fn nanoseconds(self) -> Duration {
+ Duration::nanoseconds(self)
+ }
+
+ fn microseconds(self) -> Duration {
+ Duration::microseconds(self)
+ }
+
+ fn milliseconds(self) -> Duration {
+ Duration::milliseconds(self)
+ }
+
+ fn seconds(self) -> Duration {
+ Duration::seconds(self)
+ }
+
+ fn minutes(self) -> Duration {
+ Duration::minutes(self)
+ }
+
+ fn hours(self) -> Duration {
+ Duration::hours(self)
+ }
+
+ fn days(self) -> Duration {
+ Duration::days(self)
+ }
+
+ fn weeks(self) -> Duration {
+ Duration::weeks(self)
+ }
+}
+
+impl NumericalDuration for f64 {
+ fn nanoseconds(self) -> Duration {
+ Duration::nanoseconds(self as i64)
+ }
+
+ fn microseconds(self) -> Duration {
+ Duration::nanoseconds((self * Nanosecond::per(Microsecond) as Self) as i64)
+ }
+
+ fn milliseconds(self) -> Duration {
+ Duration::nanoseconds((self * Nanosecond::per(Millisecond) as Self) as i64)
+ }
+
+ fn seconds(self) -> Duration {
+ Duration::nanoseconds((self * Nanosecond::per(Second) as Self) as i64)
+ }
+
+ fn minutes(self) -> Duration {
+ Duration::nanoseconds((self * Nanosecond::per(Minute) as Self) as i64)
+ }
+
+ fn hours(self) -> Duration {
+ Duration::nanoseconds((self * Nanosecond::per(Hour) as Self) as i64)
+ }
+
+ fn days(self) -> Duration {
+ Duration::nanoseconds((self * Nanosecond::per(Day) as Self) as i64)
+ }
+
+ fn weeks(self) -> Duration {
+ Duration::nanoseconds((self * Nanosecond::per(Week) as Self) as i64)
+ }
+}
diff --git a/vendor/time/src/ext/numerical_std_duration.rs b/vendor/time/src/ext/numerical_std_duration.rs
new file mode 100644
index 00000000..d6bc7bab
--- /dev/null
+++ b/vendor/time/src/ext/numerical_std_duration.rs
@@ -0,0 +1,192 @@
+use core::time::Duration as StdDuration;
+
+use num_conv::prelude::*;
+
+use crate::convert::*;
+
+/// Sealed trait to prevent downstream implementations.
+mod sealed {
+ /// A trait that cannot be implemented by downstream users.
+ pub trait Sealed {}
+ impl Sealed for u64 {}
+ impl Sealed for f64 {}
+}
+
+/// Create [`std::time::Duration`]s from numeric literals.
+///
+/// # Examples
+///
+/// Basic construction of [`std::time::Duration`]s.
+///
+/// ```rust
+/// # use time::ext::NumericalStdDuration;
+/// # use core::time::Duration;
+/// assert_eq!(5.std_nanoseconds(), Duration::from_nanos(5));
+/// assert_eq!(5.std_microseconds(), Duration::from_micros(5));
+/// assert_eq!(5.std_milliseconds(), Duration::from_millis(5));
+/// assert_eq!(5.std_seconds(), Duration::from_secs(5));
+/// assert_eq!(5.std_minutes(), Duration::from_secs(5 * 60));
+/// assert_eq!(5.std_hours(), Duration::from_secs(5 * 3_600));
+/// assert_eq!(5.std_days(), Duration::from_secs(5 * 86_400));
+/// assert_eq!(5.std_weeks(), Duration::from_secs(5 * 604_800));
+/// ```
+///
+/// Just like any other [`std::time::Duration`], they can be added, subtracted, etc.
+///
+/// ```rust
+/// # use time::ext::NumericalStdDuration;
+/// assert_eq!(
+/// 2.std_seconds() + 500.std_milliseconds(),
+/// 2_500.std_milliseconds()
+/// );
+/// assert_eq!(
+/// 2.std_seconds() - 500.std_milliseconds(),
+/// 1_500.std_milliseconds()
+/// );
+/// ```
+///
+/// When called on floating point values, any remainder of the floating point value will be
+/// truncated. Keep in mind that floating point numbers are inherently imprecise and have
+/// limited capacity.
+pub trait NumericalStdDuration: sealed::Sealed {
+ /// Create a [`std::time::Duration`] from the number of nanoseconds.
+ fn std_nanoseconds(self) -> StdDuration;
+ /// Create a [`std::time::Duration`] from the number of microseconds.
+ fn std_microseconds(self) -> StdDuration;
+ /// Create a [`std::time::Duration`] from the number of milliseconds.
+ fn std_milliseconds(self) -> StdDuration;
+ /// Create a [`std::time::Duration`] from the number of seconds.
+ fn std_seconds(self) -> StdDuration;
+ /// Create a [`std::time::Duration`] from the number of minutes.
+ fn std_minutes(self) -> StdDuration;
+ /// Create a [`std::time::Duration`] from the number of hours.
+ fn std_hours(self) -> StdDuration;
+ /// Create a [`std::time::Duration`] from the number of days.
+ fn std_days(self) -> StdDuration;
+ /// Create a [`std::time::Duration`] from the number of weeks.
+ fn std_weeks(self) -> StdDuration;
+}
+
+impl NumericalStdDuration for u64 {
+ fn std_nanoseconds(self) -> StdDuration {
+ StdDuration::from_nanos(self)
+ }
+
+ fn std_microseconds(self) -> StdDuration {
+ StdDuration::from_micros(self)
+ }
+
+ fn std_milliseconds(self) -> StdDuration {
+ StdDuration::from_millis(self)
+ }
+
+ fn std_seconds(self) -> StdDuration {
+ StdDuration::from_secs(self)
+ }
+
+ /// # Panics
+ ///
+ /// This may panic if an overflow occurs.
+ fn std_minutes(self) -> StdDuration {
+ StdDuration::from_secs(
+ self.checked_mul(Second::per(Minute).extend())
+ .expect("overflow constructing `time::Duration`"),
+ )
+ }
+
+ /// # Panics
+ ///
+ /// This may panic if an overflow occurs.
+ fn std_hours(self) -> StdDuration {
+ StdDuration::from_secs(
+ self.checked_mul(Second::per(Hour).extend())
+ .expect("overflow constructing `time::Duration`"),
+ )
+ }
+
+ /// # Panics
+ ///
+ /// This may panic if an overflow occurs.
+ fn std_days(self) -> StdDuration {
+ StdDuration::from_secs(
+ self.checked_mul(Second::per(Day).extend())
+ .expect("overflow constructing `time::Duration`"),
+ )
+ }
+
+ /// # Panics
+ ///
+ /// This may panic if an overflow occurs.
+ fn std_weeks(self) -> StdDuration {
+ StdDuration::from_secs(
+ self.checked_mul(Second::per(Week).extend())
+ .expect("overflow constructing `time::Duration`"),
+ )
+ }
+}
+
+impl NumericalStdDuration for f64 {
+ /// # Panics
+ ///
+ /// This will panic if self is negative.
+ fn std_nanoseconds(self) -> StdDuration {
+ assert!(self >= 0.);
+ StdDuration::from_nanos(self as u64)
+ }
+
+ /// # Panics
+ ///
+ /// This will panic if self is negative.
+ fn std_microseconds(self) -> StdDuration {
+ assert!(self >= 0.);
+ StdDuration::from_nanos((self * Nanosecond::per(Microsecond) as Self) as u64)
+ }
+
+ /// # Panics
+ ///
+ /// This will panic if self is negative.
+ fn std_milliseconds(self) -> StdDuration {
+ assert!(self >= 0.);
+ StdDuration::from_nanos((self * Nanosecond::per(Millisecond) as Self) as u64)
+ }
+
+ /// # Panics
+ ///
+ /// This will panic if self is negative.
+ fn std_seconds(self) -> StdDuration {
+ assert!(self >= 0.);
+ StdDuration::from_nanos((self * Nanosecond::per(Second) as Self) as u64)
+ }
+
+ /// # Panics
+ ///
+ /// This will panic if self is negative.
+ fn std_minutes(self) -> StdDuration {
+ assert!(self >= 0.);
+ StdDuration::from_nanos((self * Nanosecond::per(Minute) as Self) as u64)
+ }
+
+ /// # Panics
+ ///
+ /// This will panic if self is negative.
+ fn std_hours(self) -> StdDuration {
+ assert!(self >= 0.);
+ StdDuration::from_nanos((self * Nanosecond::per(Hour) as Self) as u64)
+ }
+
+ /// # Panics
+ ///
+ /// This will panic if self is negative.
+ fn std_days(self) -> StdDuration {
+ assert!(self >= 0.);
+ StdDuration::from_nanos((self * Nanosecond::per(Day) as Self) as u64)
+ }
+
+ /// # Panics
+ ///
+ /// This will panic if self is negative.
+ fn std_weeks(self) -> StdDuration {
+ assert!(self >= 0.);
+ StdDuration::from_nanos((self * Nanosecond::per(Week) as Self) as u64)
+ }
+}
diff --git a/vendor/time/src/format_description/borrowed_format_item.rs b/vendor/time/src/format_description/borrowed_format_item.rs
new file mode 100644
index 00000000..2e97efd4
--- /dev/null
+++ b/vendor/time/src/format_description/borrowed_format_item.rs
@@ -0,0 +1,106 @@
+//! A format item with borrowed data.
+
+#[cfg(feature = "alloc")]
+use alloc::string::String;
+#[cfg(feature = "alloc")]
+use core::fmt;
+
+use crate::error;
+use crate::format_description::Component;
+
+/// A complete description of how to format and parse a type.
+#[non_exhaustive]
+#[cfg_attr(not(feature = "alloc"), derive(Debug))]
+#[derive(Clone, PartialEq, Eq)]
+pub enum BorrowedFormatItem<'a> {
+ /// Bytes that are formatted as-is.
+ ///
+ /// **Note**: These bytes **should** be UTF-8, but are not required to be. The value is passed
+ /// through `String::from_utf8_lossy` when necessary.
+ Literal(&'a [u8]),
+ /// A minimal representation of a single non-literal item.
+ Component(Component),
+ /// A series of literals or components that collectively form a partial or complete
+ /// description.
+ Compound(&'a [Self]),
+ /// A `FormatItem` that may or may not be present when parsing. If parsing fails, there
+ /// will be no effect on the resulting `struct`.
+ ///
+ /// This variant has no effect on formatting, as the value is guaranteed to be present.
+ Optional(&'a Self),
+ /// A series of `FormatItem`s where, when parsing, the first successful parse is used. When
+ /// formatting, the first element of the slice is used. An empty slice is a no-op when
+ /// formatting or parsing.
+ First(&'a [Self]),
+}
+
+#[cfg(feature = "alloc")]
+impl fmt::Debug for BorrowedFormatItem<'_> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self {
+ Self::Literal(literal) => f.write_str(&String::from_utf8_lossy(literal)),
+ Self::Component(component) => component.fmt(f),
+ Self::Compound(compound) => compound.fmt(f),
+ Self::Optional(item) => f.debug_tuple("Optional").field(item).finish(),
+ Self::First(items) => f.debug_tuple("First").field(items).finish(),
+ }
+ }
+}
+
+impl From<Component> for BorrowedFormatItem<'_> {
+ fn from(component: Component) -> Self {
+ Self::Component(component)
+ }
+}
+
+impl TryFrom<BorrowedFormatItem<'_>> for Component {
+ type Error = error::DifferentVariant;
+
+ fn try_from(value: BorrowedFormatItem<'_>) -> Result<Self, Self::Error> {
+ match value {
+ BorrowedFormatItem::Component(component) => Ok(component),
+ _ => Err(error::DifferentVariant),
+ }
+ }
+}
+
+impl<'a> From<&'a [BorrowedFormatItem<'_>]> for BorrowedFormatItem<'a> {
+ fn from(items: &'a [BorrowedFormatItem<'_>]) -> Self {
+ Self::Compound(items)
+ }
+}
+
+impl<'a> TryFrom<BorrowedFormatItem<'a>> for &[BorrowedFormatItem<'a>] {
+ type Error = error::DifferentVariant;
+
+ fn try_from(value: BorrowedFormatItem<'a>) -> Result<Self, Self::Error> {
+ match value {
+ BorrowedFormatItem::Compound(items) => Ok(items),
+ _ => Err(error::DifferentVariant),
+ }
+ }
+}
+
+impl PartialEq<Component> for BorrowedFormatItem<'_> {
+ fn eq(&self, rhs: &Component) -> bool {
+ matches!(self, Self::Component(component) if component == rhs)
+ }
+}
+
+impl PartialEq<BorrowedFormatItem<'_>> for Component {
+ fn eq(&self, rhs: &BorrowedFormatItem<'_>) -> bool {
+ rhs == self
+ }
+}
+
+impl PartialEq<&[Self]> for BorrowedFormatItem<'_> {
+ fn eq(&self, rhs: &&[Self]) -> bool {
+ matches!(self, Self::Compound(compound) if compound == rhs)
+ }
+}
+
+impl PartialEq<BorrowedFormatItem<'_>> for &[BorrowedFormatItem<'_>] {
+ fn eq(&self, rhs: &BorrowedFormatItem<'_>) -> bool {
+ rhs == self
+ }
+}
diff --git a/vendor/time/src/format_description/component.rs b/vendor/time/src/format_description/component.rs
new file mode 100644
index 00000000..9119c090
--- /dev/null
+++ b/vendor/time/src/format_description/component.rs
@@ -0,0 +1,44 @@
+//! Part of a format description.
+
+use crate::format_description::modifier;
+
+/// A component of a larger format description.
+#[non_exhaustive]
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum Component {
+ /// Day of the month.
+ Day(modifier::Day),
+ /// Month of the year.
+ Month(modifier::Month),
+ /// Ordinal day of the year.
+ Ordinal(modifier::Ordinal),
+ /// Day of the week.
+ Weekday(modifier::Weekday),
+ /// Week within the year.
+ WeekNumber(modifier::WeekNumber),
+ /// Year of the date.
+ Year(modifier::Year),
+ /// Hour of the day.
+ Hour(modifier::Hour),
+ /// Minute within the hour.
+ Minute(modifier::Minute),
+ /// AM/PM part of the time.
+ Period(modifier::Period),
+ /// Second within the minute.
+ Second(modifier::Second),
+ /// Subsecond within the second.
+ Subsecond(modifier::Subsecond),
+ /// Hour of the UTC offset.
+ OffsetHour(modifier::OffsetHour),
+ /// Minute within the hour of the UTC offset.
+ OffsetMinute(modifier::OffsetMinute),
+ /// Second within the minute of the UTC offset.
+ OffsetSecond(modifier::OffsetSecond),
+ /// A number of bytes to ignore when parsing. This has no effect on formatting.
+ Ignore(modifier::Ignore),
+ /// A Unix timestamp.
+ UnixTimestamp(modifier::UnixTimestamp),
+ /// The end of input. Parsing this component will fail if there is any input remaining. This
+ /// component neither affects formatting nor consumes any input when parsing.
+ End(modifier::End),
+}
diff --git a/vendor/time/src/format_description/mod.rs b/vendor/time/src/format_description/mod.rs
new file mode 100644
index 00000000..9e7d5202
--- /dev/null
+++ b/vendor/time/src/format_description/mod.rs
@@ -0,0 +1,41 @@
+//! Description of how types should be formatted and parsed.
+//!
+//! The formatted value will be output to the provided writer. Format descriptions can be
+//! [well-known](crate::format_description::well_known) or obtained by using the
+//! [`format_description!`](crate::macros::format_description) macro or a function listed below.
+//!
+//! For examples, see the implementors of [Formattable](crate::formatting::Formattable),
+//! e.g. [`well_known::Rfc3339`].
+
+mod borrowed_format_item;
+mod component;
+pub mod modifier;
+#[cfg(feature = "alloc")]
+mod owned_format_item;
+#[cfg(feature = "alloc")]
+mod parse;
+
+pub use borrowed_format_item::BorrowedFormatItem;
+#[doc(hidden)]
+#[deprecated(since = "0.3.37", note = "use `BorrowedFormatItem` for clarity")]
+pub use borrowed_format_item::BorrowedFormatItem as FormatItem;
+#[cfg(feature = "alloc")]
+pub use owned_format_item::OwnedFormatItem;
+
+pub use self::component::Component;
+#[cfg(feature = "alloc")]
+pub use self::parse::{
+ parse, parse_borrowed, parse_owned, parse_strftime_borrowed, parse_strftime_owned,
+};
+
+/// Well-known formats, typically standards.
+pub mod well_known {
+ pub mod iso8601;
+ mod rfc2822;
+ mod rfc3339;
+
+ #[doc(inline)]
+ pub use iso8601::Iso8601;
+ pub use rfc2822::Rfc2822;
+ pub use rfc3339::Rfc3339;
+}
diff --git a/vendor/time/src/format_description/modifier.rs b/vendor/time/src/format_description/modifier.rs
new file mode 100644
index 00000000..82fca805
--- /dev/null
+++ b/vendor/time/src/format_description/modifier.rs
@@ -0,0 +1,434 @@
+//! Various modifiers for components.
+
+use core::num::NonZeroU16;
+
+/// Day of the month.
+#[non_exhaustive]
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub struct Day {
+ /// The padding to obtain the minimum width.
+ pub padding: Padding,
+}
+
+/// The representation of a month.
+#[non_exhaustive]
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum MonthRepr {
+ /// The number of the month (January is 1, December is 12).
+ Numerical,
+ /// The long form of the month name (e.g. "January").
+ Long,
+ /// The short form of the month name (e.g. "Jan").
+ Short,
+}
+
+/// Month of the year.
+#[non_exhaustive]
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub struct Month {
+ /// The padding to obtain the minimum width.
+ pub padding: Padding,
+ /// What form of representation should be used?
+ pub repr: MonthRepr,
+ /// Is the value case sensitive when parsing?
+ pub case_sensitive: bool,
+}
+
+/// Ordinal day of the year.
+#[non_exhaustive]
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub struct Ordinal {
+ /// The padding to obtain the minimum width.
+ pub padding: Padding,
+}
+
+/// The representation used for the day of the week.
+#[non_exhaustive]
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum WeekdayRepr {
+ /// The short form of the weekday (e.g. "Mon").
+ Short,
+ /// The long form of the weekday (e.g. "Monday").
+ Long,
+ /// A numerical representation using Sunday as the first day of the week.
+ ///
+ /// Sunday is either 0 or 1, depending on the other modifier's value.
+ Sunday,
+ /// A numerical representation using Monday as the first day of the week.
+ ///
+ /// Monday is either 0 or 1, depending on the other modifier's value.
+ Monday,
+}
+
+/// Day of the week.
+#[non_exhaustive]
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub struct Weekday {
+ /// What form of representation should be used?
+ pub repr: WeekdayRepr,
+ /// When using a numerical representation, should it be zero or one-indexed?
+ pub one_indexed: bool,
+ /// Is the value case sensitive when parsing?
+ pub case_sensitive: bool,
+}
+
+/// The representation used for the week number.
+#[non_exhaustive]
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum WeekNumberRepr {
+ /// Week 1 is the week that contains January 4.
+ Iso,
+ /// Week 1 begins on the first Sunday of the calendar year.
+ Sunday,
+ /// Week 1 begins on the first Monday of the calendar year.
+ Monday,
+}
+
+/// Week within the year.
+#[non_exhaustive]
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub struct WeekNumber {
+ /// The padding to obtain the minimum width.
+ pub padding: Padding,
+ /// What kind of representation should be used?
+ pub repr: WeekNumberRepr,
+}
+
+/// The representation used for a year value.
+#[non_exhaustive]
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum YearRepr {
+ /// The full value of the year.
+ Full,
+ /// All digits except the last two. Includes the sign, if any.
+ Century,
+ /// Only the last two digits of the year.
+ LastTwo,
+}
+
+/// The range of years that are supported.
+///
+/// This modifier has no effect when the year repr is [`LastTwo`](YearRepr::LastTwo).
+#[non_exhaustive]
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum YearRange {
+ /// Years between -9999 and 9999 are supported.
+ Standard,
+ /// Years between -999_999 and 999_999 are supported, with the sign being required if the year
+ /// contains more than four digits.
+ ///
+ /// If the `large-dates` feature is not enabled, this variant is equivalent to `Standard`.
+ Extended,
+}
+
+/// Year of the date.
+#[non_exhaustive]
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub struct Year {
+ /// The padding to obtain the minimum width.
+ pub padding: Padding,
+ /// What kind of representation should be used?
+ pub repr: YearRepr,
+ /// What range of years is supported?
+ pub range: YearRange,
+ /// Whether the value is based on the ISO week number or the Gregorian calendar.
+ pub iso_week_based: bool,
+ /// Whether the `+` sign is present when a positive year contains fewer than five digits.
+ pub sign_is_mandatory: bool,
+}
+
+/// Hour of the day.
+#[non_exhaustive]
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub struct Hour {
+ /// The padding to obtain the minimum width.
+ pub padding: Padding,
+ /// Is the hour displayed using a 12 or 24-hour clock?
+ pub is_12_hour_clock: bool,
+}
+
+/// Minute within the hour.
+#[non_exhaustive]
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub struct Minute {
+ /// The padding to obtain the minimum width.
+ pub padding: Padding,
+}
+
+/// AM/PM part of the time.
+#[non_exhaustive]
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub struct Period {
+ /// Is the period uppercase or lowercase?
+ pub is_uppercase: bool,
+ /// Is the value case sensitive when parsing?
+ ///
+ /// Note that when `false`, the `is_uppercase` field has no effect on parsing behavior.
+ pub case_sensitive: bool,
+}
+
+/// Second within the minute.
+#[non_exhaustive]
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub struct Second {
+ /// The padding to obtain the minimum width.
+ pub padding: Padding,
+}
+
+/// The number of digits present in a subsecond representation.
+#[non_exhaustive]
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum SubsecondDigits {
+ /// Exactly one digit.
+ One,
+ /// Exactly two digits.
+ Two,
+ /// Exactly three digits.
+ Three,
+ /// Exactly four digits.
+ Four,
+ /// Exactly five digits.
+ Five,
+ /// Exactly six digits.
+ Six,
+ /// Exactly seven digits.
+ Seven,
+ /// Exactly eight digits.
+ Eight,
+ /// Exactly nine digits.
+ Nine,
+ /// Any number of digits (up to nine) that is at least one. When formatting, the minimum digits
+ /// necessary will be used.
+ OneOrMore,
+}
+
+/// Subsecond within the second.
+#[non_exhaustive]
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub struct Subsecond {
+ /// How many digits are present in the component?
+ pub digits: SubsecondDigits,
+}
+
+/// Hour of the UTC offset.
+#[non_exhaustive]
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub struct OffsetHour {
+ /// Whether the `+` sign is present on positive values.
+ pub sign_is_mandatory: bool,
+ /// The padding to obtain the minimum width.
+ pub padding: Padding,
+}
+
+/// Minute within the hour of the UTC offset.
+#[non_exhaustive]
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub struct OffsetMinute {
+ /// The padding to obtain the minimum width.
+ pub padding: Padding,
+}
+
+/// Second within the minute of the UTC offset.
+#[non_exhaustive]
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub struct OffsetSecond {
+ /// The padding to obtain the minimum width.
+ pub padding: Padding,
+}
+
+/// Type of padding to ensure a minimum width.
+#[non_exhaustive]
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum Padding {
+ /// A space character (` `) should be used as padding.
+ Space,
+ /// A zero character (`0`) should be used as padding.
+ Zero,
+ /// There is no padding. This can result in a width below the otherwise minimum number of
+ /// characters.
+ None,
+}
+
+/// Ignore some number of bytes.
+///
+/// This has no effect when formatting.
+#[non_exhaustive]
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub struct Ignore {
+ /// The number of bytes to ignore.
+ pub count: NonZeroU16,
+}
+
+// Needed as `Default` is deliberately not implemented for `Ignore`. The number of bytes to ignore
+// must be explicitly provided.
+impl Ignore {
+ /// Create an instance of `Ignore` with the provided number of bytes to ignore.
+ pub const fn count(count: NonZeroU16) -> Self {
+ Self { count }
+ }
+}
+
+/// The precision of a Unix timestamp.
+#[non_exhaustive]
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum UnixTimestampPrecision {
+ /// Seconds since the Unix epoch.
+ Second,
+ /// Milliseconds since the Unix epoch.
+ Millisecond,
+ /// Microseconds since the Unix epoch.
+ Microsecond,
+ /// Nanoseconds since the Unix epoch.
+ Nanosecond,
+}
+
+/// A Unix timestamp.
+#[non_exhaustive]
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub struct UnixTimestamp {
+ /// The precision of the timestamp.
+ pub precision: UnixTimestampPrecision,
+ /// Whether the `+` sign must be present for a non-negative timestamp.
+ pub sign_is_mandatory: bool,
+}
+
+/// The end of input.
+///
+/// There is currently not customization for this modifier.
+#[non_exhaustive]
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub struct End;
+
+/// Generate the provided code if and only if `pub` is present.
+macro_rules! if_pub {
+ (pub $(#[$attr:meta])*; $($x:tt)*) => {
+ $(#[$attr])*
+ ///
+ /// This function exists since [`Default::default()`] cannot be used in a `const` context.
+ /// It may be removed once that becomes possible. As the [`Default`] trait is in the
+ /// prelude, removing this function in the future will not cause any resolution failures for
+ /// the overwhelming majority of users; only users who use `#![no_implicit_prelude]` will be
+ /// affected. As such it will not be considered a breaking change.
+ $($x)*
+ };
+ ($($_:tt)*) => {};
+}
+
+/// Implement `Default` for the given type. This also generates an inherent implementation of a
+/// `default` method that is `const fn`, permitting the default value to be used in const contexts.
+// Every modifier should use this macro rather than a derived `Default`.
+macro_rules! impl_const_default {
+ ($($(#[$doc:meta])* $(@$pub:ident)? $type:ty => $default:expr;)*) => {$(
+ impl $type {
+ if_pub! {
+ $($pub)?
+ $(#[$doc])*;
+ pub const fn default() -> Self {
+ $default
+ }
+ }
+ }
+
+ $(#[$doc])*
+ impl Default for $type {
+ fn default() -> Self {
+ $default
+ }
+ }
+ )*};
+}
+
+impl_const_default! {
+ /// Creates a modifier that indicates the value is [padded with zeroes](Padding::Zero).
+ @pub Day => Self { padding: Padding::Zero };
+ /// Creates a modifier that indicates the value uses the
+ /// [`Numerical`](Self::Numerical) representation.
+ MonthRepr => Self::Numerical;
+ /// Creates an instance of this type that indicates the value uses the
+ /// [`Numerical`](MonthRepr::Numerical) representation, is [padded with zeroes](Padding::Zero),
+ /// and is case-sensitive when parsing.
+ @pub Month => Self {
+ padding: Padding::Zero,
+ repr: MonthRepr::Numerical,
+ case_sensitive: true,
+ };
+ /// Creates a modifier that indicates the value is [padded with zeroes](Padding::Zero).
+ @pub Ordinal => Self { padding: Padding::Zero };
+ /// Creates a modifier that indicates the value uses the [`Long`](Self::Long) representation.
+ WeekdayRepr => Self::Long;
+ /// Creates a modifier that indicates the value uses the [`Long`](WeekdayRepr::Long)
+ /// representation and is case-sensitive when parsing. If the representation is changed to a
+ /// numerical one, the instance defaults to one-based indexing.
+ @pub Weekday => Self {
+ repr: WeekdayRepr::Long,
+ one_indexed: true,
+ case_sensitive: true,
+ };
+ /// Creates a modifier that indicates that the value uses the [`Iso`](Self::Iso) representation.
+ WeekNumberRepr => Self::Iso;
+ /// Creates a modifier that indicates that the value is [padded with zeroes](Padding::Zero)
+ /// and uses the [`Iso`](WeekNumberRepr::Iso) representation.
+ @pub WeekNumber => Self {
+ padding: Padding::Zero,
+ repr: WeekNumberRepr::Iso,
+ };
+ /// Creates a modifier that indicates the value uses the [`Full`](Self::Full) representation.
+ YearRepr => Self::Full;
+ /// Creates a modifier that indicates the value uses the [`Extended`](Self::Extended) range.
+ YearRange => Self::Extended;
+ /// Creates a modifier that indicates the value uses the [`Full`](YearRepr::Full)
+ /// representation, is [padded with zeroes](Padding::Zero), uses the Gregorian calendar as its
+ /// base, and only includes the year's sign if necessary.
+ @pub Year => Self {
+ padding: Padding::Zero,
+ repr: YearRepr::Full,
+ range: YearRange::Extended,
+ iso_week_based: false,
+ sign_is_mandatory: false,
+ };
+ /// Creates a modifier that indicates the value is [padded with zeroes](Padding::Zero) and
+ /// has the 24-hour representation.
+ @pub Hour => Self {
+ padding: Padding::Zero,
+ is_12_hour_clock: false,
+ };
+ /// Creates a modifier that indicates the value is [padded with zeroes](Padding::Zero).
+ @pub Minute => Self { padding: Padding::Zero };
+ /// Creates a modifier that indicates the value uses the upper-case representation and is
+ /// case-sensitive when parsing.
+ @pub Period => Self {
+ is_uppercase: true,
+ case_sensitive: true,
+ };
+ /// Creates a modifier that indicates the value is [padded with zeroes](Padding::Zero).
+ @pub Second => Self { padding: Padding::Zero };
+ /// Creates a modifier that indicates the stringified value contains [one or more
+ /// digits](Self::OneOrMore).
+ SubsecondDigits => Self::OneOrMore;
+ /// Creates a modifier that indicates the stringified value contains [one or more
+ /// digits](SubsecondDigits::OneOrMore).
+ @pub Subsecond => Self { digits: SubsecondDigits::OneOrMore };
+ /// Creates a modifier that indicates the value only uses a sign for negative values and is
+ /// [padded with zeroes](Padding::Zero).
+ @pub OffsetHour => Self {
+ sign_is_mandatory: false,
+ padding: Padding::Zero,
+ };
+ /// Creates a modifier that indicates the value is [padded with zeroes](Padding::Zero).
+ @pub OffsetMinute => Self { padding: Padding::Zero };
+ /// Creates a modifier that indicates the value is [padded with zeroes](Padding::Zero).
+ @pub OffsetSecond => Self { padding: Padding::Zero };
+ /// Creates a modifier that indicates the value is [padded with zeroes](Self::Zero).
+ Padding => Self::Zero;
+ /// Creates a modifier that indicates the value represents the [number of seconds](Self::Second)
+ /// since the Unix epoch.
+ UnixTimestampPrecision => Self::Second;
+ /// Creates a modifier that indicates the value represents the [number of
+ /// seconds](UnixTimestampPrecision::Second) since the Unix epoch. The sign is not mandatory.
+ @pub UnixTimestamp => Self {
+ precision: UnixTimestampPrecision::Second,
+ sign_is_mandatory: false,
+ };
+ /// Creates a modifier used to represent the end of input.
+ @pub End => End;
+}
diff --git a/vendor/time/src/format_description/owned_format_item.rs b/vendor/time/src/format_description/owned_format_item.rs
new file mode 100644
index 00000000..391e76f0
--- /dev/null
+++ b/vendor/time/src/format_description/owned_format_item.rs
@@ -0,0 +1,158 @@
+//! A format item with owned data.
+
+use alloc::boxed::Box;
+use alloc::string::String;
+use alloc::vec::Vec;
+use core::fmt;
+
+use crate::error;
+use crate::format_description::{BorrowedFormatItem, Component};
+
+/// A complete description of how to format and parse a type.
+#[non_exhaustive]
+#[derive(Clone, PartialEq, Eq)]
+pub enum OwnedFormatItem {
+ /// Bytes that are formatted as-is.
+ ///
+ /// **Note**: These bytes **should** be UTF-8, but are not required to be. The value is passed
+ /// through `String::from_utf8_lossy` when necessary.
+ Literal(Box<[u8]>),
+ /// A minimal representation of a single non-literal item.
+ Component(Component),
+ /// A series of literals or components that collectively form a partial or complete
+ /// description.
+ Compound(Box<[Self]>),
+ /// A `FormatItem` that may or may not be present when parsing. If parsing fails, there
+ /// will be no effect on the resulting `struct`.
+ ///
+ /// This variant has no effect on formatting, as the value is guaranteed to be present.
+ Optional(Box<Self>),
+ /// A series of `FormatItem`s where, when parsing, the first successful parse is used. When
+ /// formatting, the first element of the [`Vec`] is used. An empty [`Vec`] is a no-op when
+ /// formatting or parsing.
+ First(Box<[Self]>),
+}
+
+impl fmt::Debug for OwnedFormatItem {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self {
+ Self::Literal(literal) => f.write_str(&String::from_utf8_lossy(literal)),
+ Self::Component(component) => component.fmt(f),
+ Self::Compound(compound) => compound.fmt(f),
+ Self::Optional(item) => f.debug_tuple("Optional").field(item).finish(),
+ Self::First(items) => f.debug_tuple("First").field(items).finish(),
+ }
+ }
+}
+
+impl From<BorrowedFormatItem<'_>> for OwnedFormatItem {
+ fn from(item: BorrowedFormatItem<'_>) -> Self {
+ (&item).into()
+ }
+}
+
+impl From<&BorrowedFormatItem<'_>> for OwnedFormatItem {
+ fn from(item: &BorrowedFormatItem<'_>) -> Self {
+ match item {
+ BorrowedFormatItem::Literal(literal) => {
+ Self::Literal(literal.to_vec().into_boxed_slice())
+ }
+ BorrowedFormatItem::Component(component) => Self::Component(*component),
+ BorrowedFormatItem::Compound(compound) => Self::Compound(
+ compound
+ .iter()
+ .cloned()
+ .map(Into::into)
+ .collect::<Vec<_>>()
+ .into_boxed_slice(),
+ ),
+ BorrowedFormatItem::Optional(item) => Self::Optional(Box::new((*item).into())),
+ BorrowedFormatItem::First(items) => Self::First(
+ items
+ .iter()
+ .cloned()
+ .map(Into::into)
+ .collect::<Vec<_>>()
+ .into_boxed_slice(),
+ ),
+ }
+ }
+}
+
+impl From<Vec<BorrowedFormatItem<'_>>> for OwnedFormatItem {
+ fn from(items: Vec<BorrowedFormatItem<'_>>) -> Self {
+ items.as_slice().into()
+ }
+}
+
+impl<'a, T: AsRef<[BorrowedFormatItem<'a>]> + ?Sized> From<&T> for OwnedFormatItem {
+ fn from(items: &T) -> Self {
+ Self::Compound(
+ items
+ .as_ref()
+ .iter()
+ .cloned()
+ .map(Into::into)
+ .collect::<Vec<_>>()
+ .into_boxed_slice(),
+ )
+ }
+}
+
+impl From<Component> for OwnedFormatItem {
+ fn from(component: Component) -> Self {
+ Self::Component(component)
+ }
+}
+
+impl TryFrom<OwnedFormatItem> for Component {
+ type Error = error::DifferentVariant;
+
+ fn try_from(value: OwnedFormatItem) -> Result<Self, Self::Error> {
+ match value {
+ OwnedFormatItem::Component(component) => Ok(component),
+ _ => Err(error::DifferentVariant),
+ }
+ }
+}
+
+impl From<Vec<Self>> for OwnedFormatItem {
+ fn from(items: Vec<Self>) -> Self {
+ Self::Compound(items.into_boxed_slice())
+ }
+}
+
+impl TryFrom<OwnedFormatItem> for Vec<OwnedFormatItem> {
+ type Error = error::DifferentVariant;
+
+ fn try_from(value: OwnedFormatItem) -> Result<Self, Self::Error> {
+ match value {
+ OwnedFormatItem::Compound(items) => Ok(items.into_vec()),
+ _ => Err(error::DifferentVariant),
+ }
+ }
+}
+
+impl PartialEq<Component> for OwnedFormatItem {
+ fn eq(&self, rhs: &Component) -> bool {
+ matches!(self, Self::Component(component) if component == rhs)
+ }
+}
+
+impl PartialEq<OwnedFormatItem> for Component {
+ fn eq(&self, rhs: &OwnedFormatItem) -> bool {
+ rhs == self
+ }
+}
+
+impl PartialEq<&[Self]> for OwnedFormatItem {
+ fn eq(&self, rhs: &&[Self]) -> bool {
+ matches!(self, Self::Compound(compound) if &&**compound == rhs)
+ }
+}
+
+impl PartialEq<OwnedFormatItem> for &[OwnedFormatItem] {
+ fn eq(&self, rhs: &OwnedFormatItem) -> bool {
+ rhs == self
+ }
+}
diff --git a/vendor/time/src/format_description/parse/ast.rs b/vendor/time/src/format_description/parse/ast.rs
new file mode 100644
index 00000000..cf13de89
--- /dev/null
+++ b/vendor/time/src/format_description/parse/ast.rs
@@ -0,0 +1,384 @@
+//! AST for parsing format descriptions.
+
+use alloc::boxed::Box;
+use alloc::string::String;
+use alloc::vec::Vec;
+use core::iter;
+
+use super::{lexer, unused, Error, Location, Spanned, SpannedValue, Unused};
+use crate::internal_macros::bug;
+
+/// One part of a complete format description.
+pub(super) enum Item<'a> {
+ /// A literal string, formatted and parsed as-is.
+ ///
+ /// This should never be present inside a nested format description.
+ Literal(Spanned<&'a [u8]>),
+ /// A sequence of brackets. The first acts as the escape character.
+ ///
+ /// This should never be present if the lexer has `BACKSLASH_ESCAPE` set to `true`.
+ EscapedBracket {
+ /// The first bracket.
+ _first: Unused<Location>,
+ /// The second bracket.
+ _second: Unused<Location>,
+ },
+ /// Part of a type, along with its modifiers.
+ Component {
+ /// Where the opening bracket was in the format string.
+ _opening_bracket: Unused<Location>,
+ /// Whitespace between the opening bracket and name.
+ _leading_whitespace: Unused<Option<Spanned<&'a [u8]>>>,
+ /// The name of the component.
+ name: Spanned<&'a [u8]>,
+ /// The modifiers for the component.
+ modifiers: Box<[Modifier<'a>]>,
+ /// Whitespace between the modifiers and closing bracket.
+ _trailing_whitespace: Unused<Option<Spanned<&'a [u8]>>>,
+ /// Where the closing bracket was in the format string.
+ _closing_bracket: Unused<Location>,
+ },
+ /// An optional sequence of items.
+ Optional {
+ /// Where the opening bracket was in the format string.
+ opening_bracket: Location,
+ /// Whitespace between the opening bracket and "optional".
+ _leading_whitespace: Unused<Option<Spanned<&'a [u8]>>>,
+ /// The "optional" keyword.
+ _optional_kw: Unused<Spanned<&'a [u8]>>,
+ /// Whitespace between the "optional" keyword and the opening bracket.
+ _whitespace: Unused<Spanned<&'a [u8]>>,
+ /// The items within the optional sequence.
+ nested_format_description: NestedFormatDescription<'a>,
+ /// Where the closing bracket was in the format string.
+ closing_bracket: Location,
+ },
+ /// The first matching parse of a sequence of items.
+ First {
+ /// Where the opening bracket was in the format string.
+ opening_bracket: Location,
+ /// Whitespace between the opening bracket and "first".
+ _leading_whitespace: Unused<Option<Spanned<&'a [u8]>>>,
+ /// The "first" keyword.
+ _first_kw: Unused<Spanned<&'a [u8]>>,
+ /// Whitespace between the "first" keyword and the opening bracket.
+ _whitespace: Unused<Spanned<&'a [u8]>>,
+ /// The sequences of items to try.
+ nested_format_descriptions: Box<[NestedFormatDescription<'a>]>,
+ /// Where the closing bracket was in the format string.
+ closing_bracket: Location,
+ },
+}
+
+/// A format description that is nested within another format description.
+pub(super) struct NestedFormatDescription<'a> {
+ /// Where the opening bracket was in the format string.
+ pub(super) _opening_bracket: Unused<Location>,
+ /// The items within the nested format description.
+ pub(super) items: Box<[Item<'a>]>,
+ /// Where the closing bracket was in the format string.
+ pub(super) _closing_bracket: Unused<Location>,
+ /// Whitespace between the closing bracket and the next item.
+ pub(super) _trailing_whitespace: Unused<Option<Spanned<&'a [u8]>>>,
+}
+
+/// A modifier for a component.
+pub(super) struct Modifier<'a> {
+ /// Whitespace preceding the modifier.
+ pub(super) _leading_whitespace: Unused<Spanned<&'a [u8]>>,
+ /// The key of the modifier.
+ pub(super) key: Spanned<&'a [u8]>,
+ /// Where the colon of the modifier was in the format string.
+ pub(super) _colon: Unused<Location>,
+ /// The value of the modifier.
+ pub(super) value: Spanned<&'a [u8]>,
+}
+
+/// Parse the provided tokens into an AST.
+pub(super) fn parse<
+ 'item: 'iter,
+ 'iter,
+ I: Iterator<Item = Result<lexer::Token<'item>, Error>>,
+ const VERSION: usize,
+>(
+ tokens: &'iter mut lexer::Lexed<I>,
+) -> impl Iterator<Item = Result<Item<'item>, Error>> + 'iter {
+ validate_version!(VERSION);
+ parse_inner::<_, false, VERSION>(tokens)
+}
+
+/// Parse the provided tokens into an AST. The const generic indicates whether the resulting
+/// [`Item`] will be used directly or as part of a [`NestedFormatDescription`].
+fn parse_inner<
+ 'item,
+ I: Iterator<Item = Result<lexer::Token<'item>, Error>>,
+ const NESTED: bool,
+ const VERSION: usize,
+>(
+ tokens: &mut lexer::Lexed<I>,
+) -> impl Iterator<Item = Result<Item<'item>, Error>> + '_ {
+ validate_version!(VERSION);
+ iter::from_fn(move || {
+ if NESTED && tokens.peek_closing_bracket().is_some() {
+ return None;
+ }
+
+ let next = match tokens.next()? {
+ Ok(token) => token,
+ Err(err) => return Some(Err(err)),
+ };
+
+ Some(match next {
+ lexer::Token::Literal(Spanned { value: _, span: _ }) if NESTED => {
+ bug!("literal should not be present in nested description")
+ }
+ lexer::Token::Literal(value) => Ok(Item::Literal(value)),
+ lexer::Token::Bracket {
+ kind: lexer::BracketKind::Opening,
+ location,
+ } => {
+ if version!(..=1) {
+ if let Some(second_location) = tokens.next_if_opening_bracket() {
+ Ok(Item::EscapedBracket {
+ _first: unused(location),
+ _second: unused(second_location),
+ })
+ } else {
+ parse_component::<_, VERSION>(location, tokens)
+ }
+ } else {
+ parse_component::<_, VERSION>(location, tokens)
+ }
+ }
+ lexer::Token::Bracket {
+ kind: lexer::BracketKind::Closing,
+ location: _,
+ } if NESTED => {
+ bug!("closing bracket should be caught by the `if` statement")
+ }
+ lexer::Token::Bracket {
+ kind: lexer::BracketKind::Closing,
+ location: _,
+ } => {
+ bug!("closing bracket should have been consumed by `parse_component`")
+ }
+ lexer::Token::ComponentPart {
+ kind: _, // whitespace is significant in nested components
+ value,
+ } if NESTED => Ok(Item::Literal(value)),
+ lexer::Token::ComponentPart { kind: _, value: _ } => {
+ bug!("component part should have been consumed by `parse_component`")
+ }
+ })
+ })
+}
+
+/// Parse a component. This assumes that the opening bracket has already been consumed.
+fn parse_component<
+ 'a,
+ I: Iterator<Item = Result<lexer::Token<'a>, Error>>,
+ const VERSION: usize,
+>(
+ opening_bracket: Location,
+ tokens: &mut lexer::Lexed<I>,
+) -> Result<Item<'a>, Error> {
+ validate_version!(VERSION);
+ let leading_whitespace = tokens.next_if_whitespace();
+
+ let Some(name) = tokens.next_if_not_whitespace() else {
+ let span = match leading_whitespace {
+ Some(Spanned { value: _, span }) => span,
+ None => opening_bracket.to_self(),
+ };
+ return Err(Error {
+ _inner: unused(span.error("expected component name")),
+ public: crate::error::InvalidFormatDescription::MissingComponentName {
+ index: span.start.byte as usize,
+ },
+ });
+ };
+
+ if *name == b"optional" {
+ let Some(whitespace) = tokens.next_if_whitespace() else {
+ return Err(Error {
+ _inner: unused(name.span.error("expected whitespace after `optional`")),
+ public: crate::error::InvalidFormatDescription::Expected {
+ what: "whitespace after `optional`",
+ index: name.span.end.byte as usize,
+ },
+ });
+ };
+
+ let nested = parse_nested::<_, VERSION>(whitespace.span.end, tokens)?;
+
+ let Some(closing_bracket) = tokens.next_if_closing_bracket() else {
+ return Err(Error {
+ _inner: unused(opening_bracket.error("unclosed bracket")),
+ public: crate::error::InvalidFormatDescription::UnclosedOpeningBracket {
+ index: opening_bracket.byte as usize,
+ },
+ });
+ };
+
+ return Ok(Item::Optional {
+ opening_bracket,
+ _leading_whitespace: unused(leading_whitespace),
+ _optional_kw: unused(name),
+ _whitespace: unused(whitespace),
+ nested_format_description: nested,
+ closing_bracket,
+ });
+ }
+
+ if *name == b"first" {
+ let Some(whitespace) = tokens.next_if_whitespace() else {
+ return Err(Error {
+ _inner: unused(name.span.error("expected whitespace after `first`")),
+ public: crate::error::InvalidFormatDescription::Expected {
+ what: "whitespace after `first`",
+ index: name.span.end.byte as usize,
+ },
+ });
+ };
+
+ let mut nested_format_descriptions = Vec::new();
+ while let Ok(description) = parse_nested::<_, VERSION>(whitespace.span.end, tokens) {
+ nested_format_descriptions.push(description);
+ }
+
+ let Some(closing_bracket) = tokens.next_if_closing_bracket() else {
+ return Err(Error {
+ _inner: unused(opening_bracket.error("unclosed bracket")),
+ public: crate::error::InvalidFormatDescription::UnclosedOpeningBracket {
+ index: opening_bracket.byte as usize,
+ },
+ });
+ };
+
+ return Ok(Item::First {
+ opening_bracket,
+ _leading_whitespace: unused(leading_whitespace),
+ _first_kw: unused(name),
+ _whitespace: unused(whitespace),
+ nested_format_descriptions: nested_format_descriptions.into_boxed_slice(),
+ closing_bracket,
+ });
+ }
+
+ let mut modifiers = Vec::new();
+ let trailing_whitespace = loop {
+ let Some(whitespace) = tokens.next_if_whitespace() else {
+ break None;
+ };
+
+ // This is not necessary for proper parsing, but provides a much better error when a nested
+ // description is used where it's not allowed.
+ if let Some(location) = tokens.next_if_opening_bracket() {
+ return Err(Error {
+ _inner: unused(
+ location
+ .to_self()
+ .error("modifier must be of the form `key:value`"),
+ ),
+ public: crate::error::InvalidFormatDescription::InvalidModifier {
+ value: String::from("["),
+ index: location.byte as usize,
+ },
+ });
+ }
+
+ let Some(Spanned { value, span }) = tokens.next_if_not_whitespace() else {
+ break Some(whitespace);
+ };
+
+ let Some(colon_index) = value.iter().position(|&b| b == b':') else {
+ return Err(Error {
+ _inner: unused(span.error("modifier must be of the form `key:value`")),
+ public: crate::error::InvalidFormatDescription::InvalidModifier {
+ value: String::from_utf8_lossy(value).into_owned(),
+ index: span.start.byte as usize,
+ },
+ });
+ };
+ let key = &value[..colon_index];
+ let value = &value[colon_index + 1..];
+
+ if key.is_empty() {
+ return Err(Error {
+ _inner: unused(span.shrink_to_start().error("expected modifier key")),
+ public: crate::error::InvalidFormatDescription::InvalidModifier {
+ value: String::new(),
+ index: span.start.byte as usize,
+ },
+ });
+ }
+ if value.is_empty() {
+ return Err(Error {
+ _inner: unused(span.shrink_to_end().error("expected modifier value")),
+ public: crate::error::InvalidFormatDescription::InvalidModifier {
+ value: String::new(),
+ index: span.shrink_to_end().start.byte as usize,
+ },
+ });
+ }
+
+ modifiers.push(Modifier {
+ _leading_whitespace: unused(whitespace),
+ key: key.spanned(span.shrink_to_before(colon_index as u32)),
+ _colon: unused(span.start.offset(colon_index as u32)),
+ value: value.spanned(span.shrink_to_after(colon_index as u32)),
+ });
+ };
+
+ let Some(closing_bracket) = tokens.next_if_closing_bracket() else {
+ return Err(Error {
+ _inner: unused(opening_bracket.error("unclosed bracket")),
+ public: crate::error::InvalidFormatDescription::UnclosedOpeningBracket {
+ index: opening_bracket.byte as usize,
+ },
+ });
+ };
+
+ Ok(Item::Component {
+ _opening_bracket: unused(opening_bracket),
+ _leading_whitespace: unused(leading_whitespace),
+ name,
+ modifiers: modifiers.into_boxed_slice(),
+ _trailing_whitespace: unused(trailing_whitespace),
+ _closing_bracket: unused(closing_bracket),
+ })
+}
+
+/// Parse a nested format description. The location provided is the the most recent one consumed.
+fn parse_nested<'a, I: Iterator<Item = Result<lexer::Token<'a>, Error>>, const VERSION: usize>(
+ last_location: Location,
+ tokens: &mut lexer::Lexed<I>,
+) -> Result<NestedFormatDescription<'a>, Error> {
+ validate_version!(VERSION);
+ let Some(opening_bracket) = tokens.next_if_opening_bracket() else {
+ return Err(Error {
+ _inner: unused(last_location.error("expected opening bracket")),
+ public: crate::error::InvalidFormatDescription::Expected {
+ what: "opening bracket",
+ index: last_location.byte as usize,
+ },
+ });
+ };
+ let items = parse_inner::<_, true, VERSION>(tokens).collect::<Result<_, _>>()?;
+ let Some(closing_bracket) = tokens.next_if_closing_bracket() else {
+ return Err(Error {
+ _inner: unused(opening_bracket.error("unclosed bracket")),
+ public: crate::error::InvalidFormatDescription::UnclosedOpeningBracket {
+ index: opening_bracket.byte as usize,
+ },
+ });
+ };
+ let trailing_whitespace = tokens.next_if_whitespace();
+
+ Ok(NestedFormatDescription {
+ _opening_bracket: unused(opening_bracket),
+ items,
+ _closing_bracket: unused(closing_bracket),
+ _trailing_whitespace: unused(trailing_whitespace),
+ })
+}
diff --git a/vendor/time/src/format_description/parse/format_item.rs b/vendor/time/src/format_description/parse/format_item.rs
new file mode 100644
index 00000000..d401daa5
--- /dev/null
+++ b/vendor/time/src/format_description/parse/format_item.rs
@@ -0,0 +1,549 @@
+//! Typed, validated representation of a parsed format description.
+
+use alloc::boxed::Box;
+use alloc::string::String;
+use core::num::NonZeroU16;
+use core::str::{self, FromStr};
+
+use super::{ast, unused, Error, Span, Spanned};
+use crate::internal_macros::bug;
+
+/// Parse an AST iterator into a sequence of format items.
+pub(super) fn parse<'a>(
+ ast_items: impl Iterator<Item = Result<ast::Item<'a>, Error>>,
+) -> impl Iterator<Item = Result<Item<'a>, Error>> {
+ ast_items.map(|ast_item| ast_item.and_then(Item::from_ast))
+}
+
+/// A description of how to format and parse one part of a type.
+pub(super) enum Item<'a> {
+ /// A literal string.
+ Literal(&'a [u8]),
+ /// Part of a type, along with its modifiers.
+ Component(Component),
+ /// A sequence of optional items.
+ Optional {
+ /// The items themselves.
+ value: Box<[Self]>,
+ /// The span of the full sequence.
+ span: Span,
+ },
+ /// The first matching parse of a sequence of format descriptions.
+ First {
+ /// The sequence of format descriptions.
+ value: Box<[Box<[Self]>]>,
+ /// The span of the full sequence.
+ span: Span,
+ },
+}
+
+impl Item<'_> {
+ /// Parse an AST item into a format item.
+ pub(super) fn from_ast(ast_item: ast::Item<'_>) -> Result<Item<'_>, Error> {
+ Ok(match ast_item {
+ ast::Item::Component {
+ _opening_bracket: _,
+ _leading_whitespace: _,
+ name,
+ modifiers,
+ _trailing_whitespace: _,
+ _closing_bracket: _,
+ } => Item::Component(component_from_ast(&name, &modifiers)?),
+ ast::Item::Literal(Spanned { value, span: _ }) => Item::Literal(value),
+ ast::Item::EscapedBracket {
+ _first: _,
+ _second: _,
+ } => Item::Literal(b"["),
+ ast::Item::Optional {
+ opening_bracket,
+ _leading_whitespace: _,
+ _optional_kw: _,
+ _whitespace: _,
+ nested_format_description,
+ closing_bracket,
+ } => {
+ let items = nested_format_description
+ .items
+ .into_vec()
+ .into_iter()
+ .map(Item::from_ast)
+ .collect::<Result<_, _>>()?;
+ Item::Optional {
+ value: items,
+ span: opening_bracket.to(closing_bracket),
+ }
+ }
+ ast::Item::First {
+ opening_bracket,
+ _leading_whitespace: _,
+ _first_kw: _,
+ _whitespace: _,
+ nested_format_descriptions,
+ closing_bracket,
+ } => {
+ let items = nested_format_descriptions
+ .into_vec()
+ .into_iter()
+ .map(|nested_format_description| {
+ nested_format_description
+ .items
+ .into_vec()
+ .into_iter()
+ .map(Item::from_ast)
+ .collect()
+ })
+ .collect::<Result<_, _>>()?;
+ Item::First {
+ value: items,
+ span: opening_bracket.to(closing_bracket),
+ }
+ }
+ })
+ }
+}
+
+impl<'a> TryFrom<Item<'a>> for crate::format_description::BorrowedFormatItem<'a> {
+ type Error = Error;
+
+ fn try_from(item: Item<'a>) -> Result<Self, Self::Error> {
+ match item {
+ Item::Literal(literal) => Ok(Self::Literal(literal)),
+ Item::Component(component) => Ok(Self::Component(component.into())),
+ Item::Optional { value: _, span } => Err(Error {
+ _inner: unused(span.error(
+ "optional items are not supported in runtime-parsed format descriptions",
+ )),
+ public: crate::error::InvalidFormatDescription::NotSupported {
+ what: "optional item",
+ context: "runtime-parsed format descriptions",
+ index: span.start.byte as usize,
+ },
+ }),
+ Item::First { value: _, span } => Err(Error {
+ _inner: unused(span.error(
+ "'first' items are not supported in runtime-parsed format descriptions",
+ )),
+ public: crate::error::InvalidFormatDescription::NotSupported {
+ what: "'first' item",
+ context: "runtime-parsed format descriptions",
+ index: span.start.byte as usize,
+ },
+ }),
+ }
+ }
+}
+
+impl From<Item<'_>> for crate::format_description::OwnedFormatItem {
+ fn from(item: Item<'_>) -> Self {
+ match item {
+ Item::Literal(literal) => Self::Literal(literal.to_vec().into_boxed_slice()),
+ Item::Component(component) => Self::Component(component.into()),
+ Item::Optional { value, span: _ } => Self::Optional(Box::new(value.into())),
+ Item::First { value, span: _ } => {
+ Self::First(value.into_vec().into_iter().map(Into::into).collect())
+ }
+ }
+ }
+}
+
+impl<'a> From<Box<[Item<'a>]>> for crate::format_description::OwnedFormatItem {
+ fn from(items: Box<[Item<'a>]>) -> Self {
+ let items = items.into_vec();
+ match <[_; 1]>::try_from(items) {
+ Ok([item]) => item.into(),
+ Err(vec) => Self::Compound(vec.into_iter().map(Into::into).collect()),
+ }
+ }
+}
+
+/// Declare the `Component` struct.
+macro_rules! component_definition {
+ (@if_required required then { $($then:tt)* } $(else { $($else:tt)* })?) => { $($then)* };
+ (@if_required then { $($then:tt)* } $(else { $($else:tt)* })?) => { $($($else)*)? };
+ (@if_from_str from_str then { $($then:tt)* } $(else { $($else:tt)* })?) => { $($then)* };
+ (@if_from_str then { $($then:tt)* } $(else { $($else:tt)* })?) => { $($($else)*)? };
+
+ ($vis:vis enum $name:ident {
+ $($variant:ident = $parse_variant:literal {$(
+ $(#[$required:tt])?
+ $field:ident = $parse_field:literal:
+ Option<$(#[$from_str:tt])? $field_type:ty>
+ => $target_field:ident
+ ),* $(,)?}),* $(,)?
+ }) => {
+ $vis enum $name {
+ $($variant($variant),)*
+ }
+
+ $($vis struct $variant {
+ $($field: Option<$field_type>),*
+ })*
+
+ $(impl $variant {
+ /// Parse the component from the AST, given its modifiers.
+ fn with_modifiers(
+ modifiers: &[ast::Modifier<'_>],
+ _component_span: Span,
+ ) -> Result<Self, Error>
+ {
+ // rustc will complain if the modifier is empty.
+ #[allow(unused_mut)]
+ let mut this = Self {
+ $($field: None),*
+ };
+
+ for modifier in modifiers {
+ $(#[allow(clippy::string_lit_as_bytes)]
+ if modifier.key.eq_ignore_ascii_case($parse_field.as_bytes()) {
+ this.$field = component_definition!(@if_from_str $($from_str)?
+ then {
+ parse_from_modifier_value::<$field_type>(&modifier.value)?
+ } else {
+ <$field_type>::from_modifier_value(&modifier.value)?
+ });
+ continue;
+ })*
+ return Err(Error {
+ _inner: unused(modifier.key.span.error("invalid modifier key")),
+ public: crate::error::InvalidFormatDescription::InvalidModifier {
+ value: String::from_utf8_lossy(*modifier.key).into_owned(),
+ index: modifier.key.span.start.byte as usize,
+ }
+ });
+ }
+
+ $(component_definition! { @if_required $($required)? then {
+ if this.$field.is_none() {
+ return Err(Error {
+ _inner: unused(_component_span.error("missing required modifier")),
+ public:
+ crate::error::InvalidFormatDescription::MissingRequiredModifier {
+ name: $parse_field,
+ index: _component_span.start.byte as usize,
+ }
+ });
+ }
+ }})*
+
+ Ok(this)
+ }
+ })*
+
+ impl From<$name> for crate::format_description::Component {
+ fn from(component: $name) -> Self {
+ match component {$(
+ $name::$variant($variant { $($field),* }) => {
+ $crate::format_description::component::Component::$variant(
+ $crate::format_description::modifier::$variant {$(
+ $target_field: component_definition! { @if_required $($required)?
+ then {
+ match $field {
+ Some(value) => value.into(),
+ None => bug!("required modifier was not set"),
+ }
+ } else {
+ $field.unwrap_or_default().into()
+ }
+ }
+ ),*}
+ )
+ }
+ )*}
+ }
+ }
+
+ /// Parse a component from the AST, given its name and modifiers.
+ fn component_from_ast(
+ name: &Spanned<&[u8]>,
+ modifiers: &[ast::Modifier<'_>],
+ ) -> Result<Component, Error> {
+ $(#[allow(clippy::string_lit_as_bytes)]
+ if name.eq_ignore_ascii_case($parse_variant.as_bytes()) {
+ return Ok(Component::$variant($variant::with_modifiers(&modifiers, name.span)?));
+ })*
+ Err(Error {
+ _inner: unused(name.span.error("invalid component")),
+ public: crate::error::InvalidFormatDescription::InvalidComponentName {
+ name: String::from_utf8_lossy(name).into_owned(),
+ index: name.span.start.byte as usize,
+ },
+ })
+ }
+ }
+}
+
+// Keep in alphabetical order.
+component_definition! {
+ pub(super) enum Component {
+ Day = "day" {
+ padding = "padding": Option<Padding> => padding,
+ },
+ End = "end" {},
+ Hour = "hour" {
+ padding = "padding": Option<Padding> => padding,
+ base = "repr": Option<HourBase> => is_12_hour_clock,
+ },
+ Ignore = "ignore" {
+ #[required]
+ count = "count": Option<#[from_str] NonZeroU16> => count,
+ },
+ Minute = "minute" {
+ padding = "padding": Option<Padding> => padding,
+ },
+ Month = "month" {
+ padding = "padding": Option<Padding> => padding,
+ repr = "repr": Option<MonthRepr> => repr,
+ case_sensitive = "case_sensitive": Option<MonthCaseSensitive> => case_sensitive,
+ },
+ OffsetHour = "offset_hour" {
+ sign_behavior = "sign": Option<SignBehavior> => sign_is_mandatory,
+ padding = "padding": Option<Padding> => padding,
+ },
+ OffsetMinute = "offset_minute" {
+ padding = "padding": Option<Padding> => padding,
+ },
+ OffsetSecond = "offset_second" {
+ padding = "padding": Option<Padding> => padding,
+ },
+ Ordinal = "ordinal" {
+ padding = "padding": Option<Padding> => padding,
+ },
+ Period = "period" {
+ case = "case": Option<PeriodCase> => is_uppercase,
+ case_sensitive = "case_sensitive": Option<PeriodCaseSensitive> => case_sensitive,
+ },
+ Second = "second" {
+ padding = "padding": Option<Padding> => padding,
+ },
+ Subsecond = "subsecond" {
+ digits = "digits": Option<SubsecondDigits> => digits,
+ },
+ UnixTimestamp = "unix_timestamp" {
+ precision = "precision": Option<UnixTimestampPrecision> => precision,
+ sign_behavior = "sign": Option<SignBehavior> => sign_is_mandatory,
+ },
+ Weekday = "weekday" {
+ repr = "repr": Option<WeekdayRepr> => repr,
+ one_indexed = "one_indexed": Option<WeekdayOneIndexed> => one_indexed,
+ case_sensitive = "case_sensitive": Option<WeekdayCaseSensitive> => case_sensitive,
+ },
+ WeekNumber = "week_number" {
+ padding = "padding": Option<Padding> => padding,
+ repr = "repr": Option<WeekNumberRepr> => repr,
+ },
+ Year = "year" {
+ padding = "padding": Option<Padding> => padding,
+ repr = "repr": Option<YearRepr> => repr,
+ range = "range": Option<YearRange> => range,
+ base = "base": Option<YearBase> => iso_week_based,
+ sign_behavior = "sign": Option<SignBehavior> => sign_is_mandatory,
+ },
+ }
+}
+
+/// Get the target type for a given enum.
+macro_rules! target_ty {
+ ($name:ident $type:ty) => {
+ $type
+ };
+ ($name:ident) => {
+ $crate::format_description::modifier::$name
+ };
+}
+
+/// Get the target value for a given enum.
+macro_rules! target_value {
+ ($name:ident $variant:ident $value:expr) => {
+ $value
+ };
+ ($name:ident $variant:ident) => {
+ $crate::format_description::modifier::$name::$variant
+ };
+}
+
+/// Declare the various modifiers.
+///
+/// For the general case, ordinary syntax can be used. Note that you _must_ declare a default
+/// variant. The only significant change is that the string representation of the variant must be
+/// provided after the variant name. For example, `Numerical = b"numerical"` declares a variant
+/// named `Numerical` with the string representation `b"numerical"`. This is the value that will be
+/// used when parsing the modifier. The value is not case sensitive.
+///
+/// If the type in the public API does not have the same name as the type in the internal
+/// representation, then the former must be specified in parenthesis after the internal name. For
+/// example, `HourBase(bool)` has an internal name "HourBase", but is represented as a boolean in
+/// the public API.
+///
+/// By default, the internal variant name is assumed to be the same as the public variant name. If
+/// this is not the case, the qualified path to the variant must be specified in parenthesis after
+/// the internal variant name. For example, `Twelve(true)` has an internal variant name "Twelve",
+/// but is represented as `true` in the public API.
+macro_rules! modifier {
+ ($(
+ enum $name:ident $(($target_ty:ty))? {
+ $(
+ $(#[$attr:meta])?
+ $variant:ident $(($target_value:expr))? = $parse_variant:literal
+ ),* $(,)?
+ }
+ )+) => {$(
+ #[derive(Default)]
+ enum $name {
+ $($(#[$attr])? $variant),*
+ }
+
+ impl $name {
+ /// Parse the modifier from its string representation.
+ fn from_modifier_value(value: &Spanned<&[u8]>) -> Result<Option<Self>, Error> {
+ $(if value.eq_ignore_ascii_case($parse_variant) {
+ return Ok(Some(Self::$variant));
+ })*
+ Err(Error {
+ _inner: unused(value.span.error("invalid modifier value")),
+ public: crate::error::InvalidFormatDescription::InvalidModifier {
+ value: String::from_utf8_lossy(value).into_owned(),
+ index: value.span.start.byte as usize,
+ },
+ })
+ }
+ }
+
+ impl From<$name> for target_ty!($name $($target_ty)?) {
+ fn from(modifier: $name) -> Self {
+ match modifier {
+ $($name::$variant => target_value!($name $variant $($target_value)?)),*
+ }
+ }
+ }
+ )+};
+}
+
+// Keep in alphabetical order.
+modifier! {
+ enum HourBase(bool) {
+ Twelve(true) = b"12",
+ #[default]
+ TwentyFour(false) = b"24",
+ }
+
+ enum MonthCaseSensitive(bool) {
+ False(false) = b"false",
+ #[default]
+ True(true) = b"true",
+ }
+
+ enum MonthRepr {
+ #[default]
+ Numerical = b"numerical",
+ Long = b"long",
+ Short = b"short",
+ }
+
+ enum Padding {
+ Space = b"space",
+ #[default]
+ Zero = b"zero",
+ None = b"none",
+ }
+
+ enum PeriodCase(bool) {
+ Lower(false) = b"lower",
+ #[default]
+ Upper(true) = b"upper",
+ }
+
+ enum PeriodCaseSensitive(bool) {
+ False(false) = b"false",
+ #[default]
+ True(true) = b"true",
+ }
+
+ enum SignBehavior(bool) {
+ #[default]
+ Automatic(false) = b"automatic",
+ Mandatory(true) = b"mandatory",
+ }
+
+ enum SubsecondDigits {
+ One = b"1",
+ Two = b"2",
+ Three = b"3",
+ Four = b"4",
+ Five = b"5",
+ Six = b"6",
+ Seven = b"7",
+ Eight = b"8",
+ Nine = b"9",
+ #[default]
+ OneOrMore = b"1+",
+ }
+
+ enum UnixTimestampPrecision {
+ #[default]
+ Second = b"second",
+ Millisecond = b"millisecond",
+ Microsecond = b"microsecond",
+ Nanosecond = b"nanosecond",
+ }
+
+ enum WeekNumberRepr {
+ #[default]
+ Iso = b"iso",
+ Sunday = b"sunday",
+ Monday = b"monday",
+ }
+
+ enum WeekdayCaseSensitive(bool) {
+ False(false) = b"false",
+ #[default]
+ True(true) = b"true",
+ }
+
+ enum WeekdayOneIndexed(bool) {
+ False(false) = b"false",
+ #[default]
+ True(true) = b"true",
+ }
+
+ enum WeekdayRepr {
+ Short = b"short",
+ #[default]
+ Long = b"long",
+ Sunday = b"sunday",
+ Monday = b"monday",
+ }
+
+ enum YearBase(bool) {
+ #[default]
+ Calendar(false) = b"calendar",
+ IsoWeek(true) = b"iso_week",
+ }
+
+ enum YearRepr {
+ #[default]
+ Full = b"full",
+ Century = b"century",
+ LastTwo = b"last_two",
+ }
+
+ enum YearRange {
+ Standard = b"standard",
+ #[default]
+ Extended = b"extended",
+ }
+}
+
+/// Parse a modifier value using `FromStr`. Requires the modifier value to be valid UTF-8.
+fn parse_from_modifier_value<T: FromStr>(value: &Spanned<&[u8]>) -> Result<Option<T>, Error> {
+ str::from_utf8(value)
+ .ok()
+ .and_then(|val| val.parse::<T>().ok())
+ .map(|val| Some(val))
+ .ok_or_else(|| Error {
+ _inner: unused(value.span.error("invalid modifier value")),
+ public: crate::error::InvalidFormatDescription::InvalidModifier {
+ value: String::from_utf8_lossy(value).into_owned(),
+ index: value.span.start.byte as usize,
+ },
+ })
+}
diff --git a/vendor/time/src/format_description/parse/lexer.rs b/vendor/time/src/format_description/parse/lexer.rs
new file mode 100644
index 00000000..a63722e1
--- /dev/null
+++ b/vendor/time/src/format_description/parse/lexer.rs
@@ -0,0 +1,284 @@
+//! Lexer for parsing format descriptions.
+
+use core::iter;
+
+use super::{attach_location, unused, Error, Location, Spanned, SpannedValue};
+
+/// An iterator over the lexed tokens.
+pub(super) struct Lexed<I: Iterator> {
+ /// The internal iterator.
+ iter: iter::Peekable<I>,
+}
+
+impl<I: Iterator> Iterator for Lexed<I> {
+ type Item = I::Item;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.iter.next()
+ }
+}
+
+impl<'iter, 'token: 'iter, I: Iterator<Item = Result<Token<'token>, Error>> + 'iter> Lexed<I> {
+ /// Peek at the next item in the iterator.
+ pub(super) fn peek(&mut self) -> Option<&I::Item> {
+ self.iter.peek()
+ }
+
+ /// Consume the next token if it is whitespace.
+ pub(super) fn next_if_whitespace(&mut self) -> Option<Spanned<&'token [u8]>> {
+ if let Some(&Ok(Token::ComponentPart {
+ kind: ComponentKind::Whitespace,
+ value,
+ })) = self.peek()
+ {
+ self.next(); // consume
+ Some(value)
+ } else {
+ None
+ }
+ }
+
+ /// Consume the next token if it is a component item that is not whitespace.
+ pub(super) fn next_if_not_whitespace(&mut self) -> Option<Spanned<&'token [u8]>> {
+ if let Some(&Ok(Token::ComponentPart {
+ kind: ComponentKind::NotWhitespace,
+ value,
+ })) = self.peek()
+ {
+ self.next(); // consume
+ Some(value)
+ } else {
+ None
+ }
+ }
+
+ /// Consume the next token if it is an opening bracket.
+ pub(super) fn next_if_opening_bracket(&mut self) -> Option<Location> {
+ if let Some(&Ok(Token::Bracket {
+ kind: BracketKind::Opening,
+ location,
+ })) = self.peek()
+ {
+ self.next(); // consume
+ Some(location)
+ } else {
+ None
+ }
+ }
+
+ /// Peek at the next token if it is a closing bracket.
+ pub(super) fn peek_closing_bracket(&'iter mut self) -> Option<&'iter Location> {
+ if let Some(Ok(Token::Bracket {
+ kind: BracketKind::Closing,
+ location,
+ })) = self.peek()
+ {
+ Some(location)
+ } else {
+ None
+ }
+ }
+
+ /// Consume the next token if it is a closing bracket.
+ pub(super) fn next_if_closing_bracket(&mut self) -> Option<Location> {
+ if let Some(&Ok(Token::Bracket {
+ kind: BracketKind::Closing,
+ location,
+ })) = self.peek()
+ {
+ self.next(); // consume
+ Some(location)
+ } else {
+ None
+ }
+ }
+}
+
+/// A token emitted by the lexer. There is no semantic meaning at this stage.
+pub(super) enum Token<'a> {
+ /// A literal string, formatted and parsed as-is.
+ Literal(Spanned<&'a [u8]>),
+ /// An opening or closing bracket. May or may not be the start or end of a component.
+ Bracket {
+ /// Whether the bracket is opening or closing.
+ kind: BracketKind,
+ /// Where the bracket was in the format string.
+ location: Location,
+ },
+ /// One part of a component. This could be its name, a modifier, or whitespace.
+ ComponentPart {
+ /// Whether the part is whitespace or not.
+ kind: ComponentKind,
+ /// The part itself.
+ value: Spanned<&'a [u8]>,
+ },
+}
+
+/// What type of bracket is present.
+pub(super) enum BracketKind {
+ /// An opening bracket: `[`
+ Opening,
+ /// A closing bracket: `]`
+ Closing,
+}
+
+/// Indicates whether the component is whitespace or not.
+pub(super) enum ComponentKind {
+ Whitespace,
+ NotWhitespace,
+}
+
+/// Parse the string into a series of [`Token`]s.
+///
+/// `VERSION` controls the version of the format description that is being parsed. Currently, this
+/// must be 1 or 2.
+///
+/// - When `VERSION` is 1, `[[` is the only escape sequence, resulting in a literal `[`.
+/// - When `VERSION` is 2, all escape sequences begin with `\`. The only characters that may
+/// currently follow are `\`, `[`, and `]`, all of which result in the literal character. All
+/// other characters result in a lex error.
+pub(super) fn lex<const VERSION: usize>(
+ mut input: &[u8],
+) -> Lexed<impl Iterator<Item = Result<Token<'_>, Error>>> {
+ validate_version!(VERSION);
+
+ let mut depth: u8 = 0;
+ let mut iter = attach_location(input.iter()).peekable();
+ let mut second_bracket_location = None;
+
+ let iter = iter::from_fn(move || {
+ // The flag is only set when version is zero.
+ if version!(..=1) {
+ // There is a flag set to emit the second half of an escaped bracket pair.
+ if let Some(location) = second_bracket_location.take() {
+ return Some(Ok(Token::Bracket {
+ kind: BracketKind::Opening,
+ location,
+ }));
+ }
+ }
+
+ Some(Ok(match iter.next()? {
+ // possible escape sequence
+ (b'\\', backslash_loc) if version!(2..) => {
+ match iter.next() {
+ Some((b'\\' | b'[' | b']', char_loc)) => {
+ // The escaped character is emitted as-is.
+ let char = &input[1..2];
+ input = &input[2..];
+ if depth == 0 {
+ Token::Literal(char.spanned(backslash_loc.to(char_loc)))
+ } else {
+ Token::ComponentPart {
+ kind: ComponentKind::NotWhitespace,
+ value: char.spanned(backslash_loc.to(char_loc)),
+ }
+ }
+ }
+ Some((_, loc)) => {
+ return Some(Err(Error {
+ _inner: unused(loc.error("invalid escape sequence")),
+ public: crate::error::InvalidFormatDescription::Expected {
+ what: "valid escape sequence",
+ index: loc.byte as usize,
+ },
+ }));
+ }
+ None => {
+ return Some(Err(Error {
+ _inner: unused(backslash_loc.error("unexpected end of input")),
+ public: crate::error::InvalidFormatDescription::Expected {
+ what: "valid escape sequence",
+ index: backslash_loc.byte as usize,
+ },
+ }));
+ }
+ }
+ }
+ // potentially escaped opening bracket
+ (b'[', location) if version!(..=1) => {
+ if let Some((_, second_location)) = iter.next_if(|&(&byte, _)| byte == b'[') {
+ // Escaped bracket. Store the location of the second so we can emit it later.
+ second_bracket_location = Some(second_location);
+ input = &input[2..];
+ } else {
+ // opening bracket
+ depth += 1;
+ input = &input[1..];
+ }
+
+ Token::Bracket {
+ kind: BracketKind::Opening,
+ location,
+ }
+ }
+ // opening bracket
+ (b'[', location) => {
+ depth += 1;
+ input = &input[1..];
+
+ Token::Bracket {
+ kind: BracketKind::Opening,
+ location,
+ }
+ }
+ // closing bracket
+ (b']', location) if depth > 0 => {
+ depth -= 1;
+ input = &input[1..];
+
+ Token::Bracket {
+ kind: BracketKind::Closing,
+ location,
+ }
+ }
+ // literal
+ (_, start_location) if depth == 0 => {
+ let mut bytes = 1;
+ let mut end_location = start_location;
+
+ while let Some((_, location)) =
+ iter.next_if(|&(&byte, _)| !((version!(2..) && byte == b'\\') || byte == b'['))
+ {
+ end_location = location;
+ bytes += 1;
+ }
+
+ let value = &input[..bytes];
+ input = &input[bytes..];
+
+ Token::Literal(value.spanned(start_location.to(end_location)))
+ }
+ // component part
+ (byte, start_location) => {
+ let mut bytes = 1;
+ let mut end_location = start_location;
+ let is_whitespace = byte.is_ascii_whitespace();
+
+ while let Some((_, location)) = iter.next_if(|&(byte, _)| {
+ !matches!(byte, b'\\' | b'[' | b']')
+ && is_whitespace == byte.is_ascii_whitespace()
+ }) {
+ end_location = location;
+ bytes += 1;
+ }
+
+ let value = &input[..bytes];
+ input = &input[bytes..];
+
+ Token::ComponentPart {
+ kind: if is_whitespace {
+ ComponentKind::Whitespace
+ } else {
+ ComponentKind::NotWhitespace
+ },
+ value: value.spanned(start_location.to(end_location)),
+ }
+ }
+ }))
+ });
+
+ Lexed {
+ iter: iter.peekable(),
+ }
+}
diff --git a/vendor/time/src/format_description/parse/mod.rs b/vendor/time/src/format_description/parse/mod.rs
new file mode 100644
index 00000000..d058594d
--- /dev/null
+++ b/vendor/time/src/format_description/parse/mod.rs
@@ -0,0 +1,262 @@
+//! Parser for format descriptions.
+
+use alloc::boxed::Box;
+use alloc::vec::Vec;
+
+pub use self::strftime::{parse_strftime_borrowed, parse_strftime_owned};
+use crate::{error, format_description};
+
+/// A helper macro to make version restrictions simpler to read and write.
+macro_rules! version {
+ ($range:expr) => {
+ $range.contains(&VERSION)
+ };
+}
+
+/// A helper macro to statically validate the version (when used as a const parameter).
+macro_rules! validate_version {
+ ($version:ident) => {
+ let _ = $crate::format_description::parse::Version::<$version>::IS_VALID;
+ };
+}
+
+mod ast;
+mod format_item;
+mod lexer;
+mod strftime;
+
+/// A struct that is used to ensure that the version is valid.
+struct Version<const N: usize>;
+impl<const N: usize> Version<N> {
+ /// A constant that panics if the version is not valid. This results in a post-monomorphization
+ /// error.
+ const IS_VALID: () = assert!(N >= 1 && N <= 2);
+}
+
+/// Parse a sequence of items from the format description.
+///
+/// The syntax for the format description can be found in [the
+/// book](https://time-rs.github.io/book/api/format-description.html).
+///
+/// This function exists for backward compatibility reasons. It is equivalent to calling
+/// `parse_borrowed::<1>(s)`. In the future, this function will be deprecated in favor of
+/// `parse_borrowed`.
+pub fn parse(
+ s: &str,
+) -> Result<Vec<format_description::BorrowedFormatItem<'_>>, error::InvalidFormatDescription> {
+ parse_borrowed::<1>(s)
+}
+
+/// Parse a sequence of items from the format description.
+///
+/// The syntax for the format description can be found in [the
+/// book](https://time-rs.github.io/book/api/format-description.html). The version of the format
+/// description is provided as the const parameter. **It is recommended to use version 2.**
+pub fn parse_borrowed<const VERSION: usize>(
+ s: &str,
+) -> Result<Vec<format_description::BorrowedFormatItem<'_>>, error::InvalidFormatDescription> {
+ validate_version!(VERSION);
+ let mut lexed = lexer::lex::<VERSION>(s.as_bytes());
+ let ast = ast::parse::<_, VERSION>(&mut lexed);
+ let format_items = format_item::parse(ast);
+ Ok(format_items
+ .map(|res| res.and_then(TryInto::try_into))
+ .collect::<Result<_, _>>()?)
+}
+
+/// Parse a sequence of items from the format description.
+///
+/// The syntax for the format description can be found in [the
+/// book](https://time-rs.github.io/book/api/format-description.html). The version of the format
+/// description is provided as the const parameter.
+///
+/// Unlike [`parse`], this function returns [`OwnedFormatItem`], which owns its contents. This means
+/// that there is no lifetime that needs to be handled. **It is recommended to use version 2.**
+///
+/// [`OwnedFormatItem`]: crate::format_description::OwnedFormatItem
+pub fn parse_owned<const VERSION: usize>(
+ s: &str,
+) -> Result<format_description::OwnedFormatItem, error::InvalidFormatDescription> {
+ validate_version!(VERSION);
+ let mut lexed = lexer::lex::<VERSION>(s.as_bytes());
+ let ast = ast::parse::<_, VERSION>(&mut lexed);
+ let format_items = format_item::parse(ast);
+ let items = format_items.collect::<Result<Box<_>, _>>()?;
+ Ok(items.into())
+}
+
+/// Attach [`Location`] information to each byte in the iterator.
+fn attach_location<'item>(
+ iter: impl Iterator<Item = &'item u8>,
+) -> impl Iterator<Item = (&'item u8, Location)> {
+ let mut byte_pos = 0;
+
+ iter.map(move |byte| {
+ let location = Location { byte: byte_pos };
+ byte_pos += 1;
+ (byte, location)
+ })
+}
+
+/// A location within a string.
+#[derive(Clone, Copy)]
+struct Location {
+ /// The zero-indexed byte of the string.
+ byte: u32,
+}
+
+impl Location {
+ /// Create a new [`Span`] from `self` to `other`.
+ const fn to(self, end: Self) -> Span {
+ Span { start: self, end }
+ }
+
+ /// Create a new [`Span`] consisting entirely of `self`.
+ const fn to_self(self) -> Span {
+ Span {
+ start: self,
+ end: self,
+ }
+ }
+
+ /// Offset the location by the provided amount.
+ ///
+ /// Note that this assumes the resulting location is on the same line as the original location.
+ #[must_use = "this does not modify the original value"]
+ const fn offset(&self, offset: u32) -> Self {
+ Self {
+ byte: self.byte + offset,
+ }
+ }
+
+ /// Create an error with the provided message at this location.
+ const fn error(self, message: &'static str) -> ErrorInner {
+ ErrorInner {
+ _message: message,
+ _span: Span {
+ start: self,
+ end: self,
+ },
+ }
+ }
+}
+
+/// A start and end point within a string.
+#[derive(Clone, Copy)]
+struct Span {
+ start: Location,
+ end: Location,
+}
+
+impl Span {
+ /// Obtain a `Span` pointing at the start of the pre-existing span.
+ #[must_use = "this does not modify the original value"]
+ const fn shrink_to_start(&self) -> Self {
+ Self {
+ start: self.start,
+ end: self.start,
+ }
+ }
+
+ /// Obtain a `Span` pointing at the end of the pre-existing span.
+ #[must_use = "this does not modify the original value"]
+ const fn shrink_to_end(&self) -> Self {
+ Self {
+ start: self.end,
+ end: self.end,
+ }
+ }
+
+ /// Obtain a `Span` that ends before the provided position of the pre-existing span.
+ #[must_use = "this does not modify the original value"]
+ const fn shrink_to_before(&self, pos: u32) -> Self {
+ Self {
+ start: self.start,
+ end: Location {
+ byte: self.start.byte + pos - 1,
+ },
+ }
+ }
+
+ /// Obtain a `Span` that starts after provided position to the end of the pre-existing span.
+ #[must_use = "this does not modify the original value"]
+ const fn shrink_to_after(&self, pos: u32) -> Self {
+ Self {
+ start: Location {
+ byte: self.start.byte + pos + 1,
+ },
+ end: self.end,
+ }
+ }
+
+ /// Create an error with the provided message at this span.
+ const fn error(self, message: &'static str) -> ErrorInner {
+ ErrorInner {
+ _message: message,
+ _span: self,
+ }
+ }
+}
+
+/// A value with an associated [`Span`].
+#[derive(Clone, Copy)]
+struct Spanned<T> {
+ /// The value.
+ value: T,
+ /// Where the value was in the format string.
+ span: Span,
+}
+
+impl<T> core::ops::Deref for Spanned<T> {
+ type Target = T;
+
+ fn deref(&self) -> &Self::Target {
+ &self.value
+ }
+}
+
+/// Helper trait to attach a [`Span`] to a value.
+trait SpannedValue: Sized {
+ /// Attach a [`Span`] to a value.
+ fn spanned(self, span: Span) -> Spanned<Self>;
+}
+
+impl<T> SpannedValue for T {
+ fn spanned(self, span: Span) -> Spanned<Self> {
+ Spanned { value: self, span }
+ }
+}
+
+/// The internal error type.
+struct ErrorInner {
+ /// The message displayed to the user.
+ _message: &'static str,
+ /// Where the error originated.
+ _span: Span,
+}
+
+/// A complete error description.
+struct Error {
+ /// The internal error.
+ _inner: Unused<ErrorInner>,
+ /// The error needed for interoperability with the rest of `time`.
+ public: error::InvalidFormatDescription,
+}
+
+impl From<Error> for error::InvalidFormatDescription {
+ fn from(error: Error) -> Self {
+ error.public
+ }
+}
+
+/// A value that may be used in the future, but currently is not.
+///
+/// This struct exists so that data can semantically be passed around without _actually_ passing it
+/// around. This way the data still exists if it is needed in the future.
+// `PhantomData` is not used directly because we don't want to introduce any trait implementations.
+struct Unused<T>(core::marker::PhantomData<T>);
+
+/// Indicate that a value is currently unused.
+fn unused<T>(_: T) -> Unused<T> {
+ Unused(core::marker::PhantomData)
+}
diff --git a/vendor/time/src/format_description/parse/strftime.rs b/vendor/time/src/format_description/parse/strftime.rs
new file mode 100644
index 00000000..5fcaf184
--- /dev/null
+++ b/vendor/time/src/format_description/parse/strftime.rs
@@ -0,0 +1,487 @@
+use alloc::string::String;
+use alloc::vec::Vec;
+use core::iter;
+
+use crate::error::InvalidFormatDescription;
+use crate::format_description::parse::{
+ attach_location, unused, Error, ErrorInner, Location, Spanned, SpannedValue, Unused,
+};
+use crate::format_description::{self, modifier, BorrowedFormatItem, Component};
+
+/// Parse a sequence of items from the [`strftime` format description][strftime docs].
+///
+/// The only heap allocation required is for the `Vec` itself. All components are bound to the
+/// lifetime of the input.
+///
+/// [strftime docs]: https://man7.org/linux/man-pages/man3/strftime.3.html
+#[doc(alias = "parse_strptime_borrowed")]
+pub fn parse_strftime_borrowed(
+ s: &str,
+) -> Result<Vec<BorrowedFormatItem<'_>>, InvalidFormatDescription> {
+ let tokens = lex(s.as_bytes());
+ let items = into_items(tokens).collect::<Result<_, _>>()?;
+ Ok(items)
+}
+
+/// Parse a sequence of items from the [`strftime` format description][strftime docs].
+///
+/// This requires heap allocation for some owned items.
+///
+/// [strftime docs]: https://man7.org/linux/man-pages/man3/strftime.3.html
+#[doc(alias = "parse_strptime_owned")]
+pub fn parse_strftime_owned(
+ s: &str,
+) -> Result<format_description::OwnedFormatItem, InvalidFormatDescription> {
+ parse_strftime_borrowed(s).map(Into::into)
+}
+
+#[derive(Debug, Clone, Copy, PartialEq)]
+enum Padding {
+ /// The default padding for a numeric component. Indicated by no character.
+ Default,
+ /// Pad a numeric component with spaces. Indicated by an underscore.
+ Spaces,
+ /// Do not pad a numeric component. Indicated by a hyphen.
+ None,
+ /// Pad a numeric component with zeroes. Indicated by a zero.
+ Zeroes,
+}
+
+enum Token<'a> {
+ Literal(Spanned<&'a [u8]>),
+ Component {
+ _percent: Unused<Location>,
+ padding: Spanned<Padding>,
+ component: Spanned<u8>,
+ },
+}
+
+fn lex(mut input: &[u8]) -> iter::Peekable<impl Iterator<Item = Result<Token<'_>, Error>>> {
+ let mut iter = attach_location(input.iter()).peekable();
+
+ iter::from_fn(move || {
+ Some(Ok(match iter.next()? {
+ (b'%', percent_loc) => match iter.next() {
+ Some((padding @ (b'_' | b'-' | b'0'), padding_loc)) => {
+ let padding = match padding {
+ b'_' => Padding::Spaces,
+ b'-' => Padding::None,
+ b'0' => Padding::Zeroes,
+ _ => unreachable!(),
+ };
+ let (&component, component_loc) = iter.next()?;
+ input = &input[3..];
+ Token::Component {
+ _percent: unused(percent_loc),
+ padding: padding.spanned(padding_loc.to_self()),
+ component: component.spanned(component_loc.to_self()),
+ }
+ }
+ Some((&component, component_loc)) => {
+ input = &input[2..];
+ let span = component_loc.to_self();
+ Token::Component {
+ _percent: unused(percent_loc),
+ padding: Padding::Default.spanned(span),
+ component: component.spanned(span),
+ }
+ }
+ None => {
+ return Some(Err(Error {
+ _inner: unused(percent_loc.error("unexpected end of input")),
+ public: InvalidFormatDescription::Expected {
+ what: "valid escape sequence",
+ index: percent_loc.byte as usize,
+ },
+ }));
+ }
+ },
+ (_, start_location) => {
+ let mut bytes = 1;
+ let mut end_location = start_location;
+
+ while let Some((_, location)) = iter.next_if(|&(&byte, _)| byte != b'%') {
+ end_location = location;
+ bytes += 1;
+ }
+
+ let value = &input[..bytes];
+ input = &input[bytes..];
+
+ Token::Literal(value.spanned(start_location.to(end_location)))
+ }
+ }))
+ })
+ .peekable()
+}
+
+fn into_items<'iter, 'token: 'iter>(
+ mut tokens: iter::Peekable<impl Iterator<Item = Result<Token<'token>, Error>> + 'iter>,
+) -> impl Iterator<Item = Result<BorrowedFormatItem<'token>, Error>> + 'iter {
+ iter::from_fn(move || {
+ let next = match tokens.next()? {
+ Ok(token) => token,
+ Err(err) => return Some(Err(err)),
+ };
+
+ Some(match next {
+ Token::Literal(spanned) => Ok(BorrowedFormatItem::Literal(*spanned)),
+ Token::Component {
+ _percent,
+ padding,
+ component,
+ } => parse_component(padding, component),
+ })
+ })
+}
+
+fn parse_component(
+ padding: Spanned<Padding>,
+ component: Spanned<u8>,
+) -> Result<BorrowedFormatItem<'static>, Error> {
+ let padding_or_default = |padding: Padding, default| match padding {
+ Padding::Default => default,
+ Padding::Spaces => modifier::Padding::Space,
+ Padding::None => modifier::Padding::None,
+ Padding::Zeroes => modifier::Padding::Zero,
+ };
+
+ /// Helper macro to create a component.
+ macro_rules! component {
+ ($name:ident { $($inner:tt)* }) => {
+ BorrowedFormatItem::Component(Component::$name(modifier::$name {
+ $($inner)*
+ }))
+ }
+ }
+
+ Ok(match *component {
+ b'%' => BorrowedFormatItem::Literal(b"%"),
+ b'a' => component!(Weekday {
+ repr: modifier::WeekdayRepr::Short,
+ one_indexed: true,
+ case_sensitive: true,
+ }),
+ b'A' => component!(Weekday {
+ repr: modifier::WeekdayRepr::Long,
+ one_indexed: true,
+ case_sensitive: true,
+ }),
+ b'b' | b'h' => component!(Month {
+ repr: modifier::MonthRepr::Short,
+ padding: modifier::Padding::Zero,
+ case_sensitive: true,
+ }),
+ b'B' => component!(Month {
+ repr: modifier::MonthRepr::Long,
+ padding: modifier::Padding::Zero,
+ case_sensitive: true,
+ }),
+ b'c' => BorrowedFormatItem::Compound(&[
+ component!(Weekday {
+ repr: modifier::WeekdayRepr::Short,
+ one_indexed: true,
+ case_sensitive: true,
+ }),
+ BorrowedFormatItem::Literal(b" "),
+ component!(Month {
+ repr: modifier::MonthRepr::Short,
+ padding: modifier::Padding::Zero,
+ case_sensitive: true,
+ }),
+ BorrowedFormatItem::Literal(b" "),
+ component!(Day {
+ padding: modifier::Padding::Space
+ }),
+ BorrowedFormatItem::Literal(b" "),
+ component!(Hour {
+ padding: modifier::Padding::Zero,
+ is_12_hour_clock: false,
+ }),
+ BorrowedFormatItem::Literal(b":"),
+ component!(Minute {
+ padding: modifier::Padding::Zero,
+ }),
+ BorrowedFormatItem::Literal(b":"),
+ component!(Second {
+ padding: modifier::Padding::Zero,
+ }),
+ BorrowedFormatItem::Literal(b" "),
+ component!(Year {
+ padding: modifier::Padding::Zero,
+ repr: modifier::YearRepr::Full,
+ range: modifier::YearRange::Extended,
+ iso_week_based: false,
+ sign_is_mandatory: false,
+ }),
+ ]),
+ b'C' => component!(Year {
+ padding: padding_or_default(*padding, modifier::Padding::Zero),
+ repr: modifier::YearRepr::Century,
+ range: modifier::YearRange::Extended,
+ iso_week_based: false,
+ sign_is_mandatory: false,
+ }),
+ b'd' => component!(Day {
+ padding: padding_or_default(*padding, modifier::Padding::Zero),
+ }),
+ b'D' => BorrowedFormatItem::Compound(&[
+ component!(Month {
+ repr: modifier::MonthRepr::Numerical,
+ padding: modifier::Padding::Zero,
+ case_sensitive: true,
+ }),
+ BorrowedFormatItem::Literal(b"/"),
+ component!(Day {
+ padding: modifier::Padding::Zero,
+ }),
+ BorrowedFormatItem::Literal(b"/"),
+ component!(Year {
+ padding: modifier::Padding::Zero,
+ repr: modifier::YearRepr::LastTwo,
+ range: modifier::YearRange::Extended,
+ iso_week_based: false,
+ sign_is_mandatory: false,
+ }),
+ ]),
+ b'e' => component!(Day {
+ padding: padding_or_default(*padding, modifier::Padding::Space),
+ }),
+ b'F' => BorrowedFormatItem::Compound(&[
+ component!(Year {
+ padding: modifier::Padding::Zero,
+ repr: modifier::YearRepr::Full,
+ range: modifier::YearRange::Extended,
+ iso_week_based: false,
+ sign_is_mandatory: false,
+ }),
+ BorrowedFormatItem::Literal(b"-"),
+ component!(Month {
+ padding: modifier::Padding::Zero,
+ repr: modifier::MonthRepr::Numerical,
+ case_sensitive: true,
+ }),
+ BorrowedFormatItem::Literal(b"-"),
+ component!(Day {
+ padding: modifier::Padding::Zero,
+ }),
+ ]),
+ b'g' => component!(Year {
+ padding: padding_or_default(*padding, modifier::Padding::Zero),
+ repr: modifier::YearRepr::LastTwo,
+ range: modifier::YearRange::Extended,
+ iso_week_based: true,
+ sign_is_mandatory: false,
+ }),
+ b'G' => component!(Year {
+ padding: modifier::Padding::Zero,
+ repr: modifier::YearRepr::Full,
+ range: modifier::YearRange::Extended,
+ iso_week_based: true,
+ sign_is_mandatory: false,
+ }),
+ b'H' => component!(Hour {
+ padding: padding_or_default(*padding, modifier::Padding::Zero),
+ is_12_hour_clock: false,
+ }),
+ b'I' => component!(Hour {
+ padding: padding_or_default(*padding, modifier::Padding::Zero),
+ is_12_hour_clock: true,
+ }),
+ b'j' => component!(Ordinal {
+ padding: padding_or_default(*padding, modifier::Padding::Zero),
+ }),
+ b'k' => component!(Hour {
+ padding: padding_or_default(*padding, modifier::Padding::Space),
+ is_12_hour_clock: false,
+ }),
+ b'l' => component!(Hour {
+ padding: padding_or_default(*padding, modifier::Padding::Space),
+ is_12_hour_clock: true,
+ }),
+ b'm' => component!(Month {
+ padding: padding_or_default(*padding, modifier::Padding::Zero),
+ repr: modifier::MonthRepr::Numerical,
+ case_sensitive: true,
+ }),
+ b'M' => component!(Minute {
+ padding: padding_or_default(*padding, modifier::Padding::Zero),
+ }),
+ b'n' => BorrowedFormatItem::Literal(b"\n"),
+ b'O' => {
+ return Err(Error {
+ _inner: unused(ErrorInner {
+ _message: "unsupported modifier",
+ _span: component.span,
+ }),
+ public: InvalidFormatDescription::NotSupported {
+ what: "modifier",
+ context: "",
+ index: component.span.start.byte as usize,
+ },
+ })
+ }
+ b'p' => component!(Period {
+ is_uppercase: true,
+ case_sensitive: true
+ }),
+ b'P' => component!(Period {
+ is_uppercase: false,
+ case_sensitive: true
+ }),
+ b'r' => BorrowedFormatItem::Compound(&[
+ component!(Hour {
+ padding: modifier::Padding::Zero,
+ is_12_hour_clock: true,
+ }),
+ BorrowedFormatItem::Literal(b":"),
+ component!(Minute {
+ padding: modifier::Padding::Zero,
+ }),
+ BorrowedFormatItem::Literal(b":"),
+ component!(Second {
+ padding: modifier::Padding::Zero,
+ }),
+ BorrowedFormatItem::Literal(b" "),
+ component!(Period {
+ is_uppercase: true,
+ case_sensitive: true,
+ }),
+ ]),
+ b'R' => BorrowedFormatItem::Compound(&[
+ component!(Hour {
+ padding: modifier::Padding::Zero,
+ is_12_hour_clock: false,
+ }),
+ BorrowedFormatItem::Literal(b":"),
+ component!(Minute {
+ padding: modifier::Padding::Zero,
+ }),
+ ]),
+ b's' => component!(UnixTimestamp {
+ precision: modifier::UnixTimestampPrecision::Second,
+ sign_is_mandatory: false,
+ }),
+ b'S' => component!(Second {
+ padding: padding_or_default(*padding, modifier::Padding::Zero),
+ }),
+ b't' => BorrowedFormatItem::Literal(b"\t"),
+ b'T' => BorrowedFormatItem::Compound(&[
+ component!(Hour {
+ padding: modifier::Padding::Zero,
+ is_12_hour_clock: false,
+ }),
+ BorrowedFormatItem::Literal(b":"),
+ component!(Minute {
+ padding: modifier::Padding::Zero,
+ }),
+ BorrowedFormatItem::Literal(b":"),
+ component!(Second {
+ padding: modifier::Padding::Zero,
+ }),
+ ]),
+ b'u' => component!(Weekday {
+ repr: modifier::WeekdayRepr::Monday,
+ one_indexed: true,
+ case_sensitive: true,
+ }),
+ b'U' => component!(WeekNumber {
+ padding: padding_or_default(*padding, modifier::Padding::Zero),
+ repr: modifier::WeekNumberRepr::Sunday,
+ }),
+ b'V' => component!(WeekNumber {
+ padding: padding_or_default(*padding, modifier::Padding::Zero),
+ repr: modifier::WeekNumberRepr::Iso,
+ }),
+ b'w' => component!(Weekday {
+ repr: modifier::WeekdayRepr::Sunday,
+ one_indexed: true,
+ case_sensitive: true,
+ }),
+ b'W' => component!(WeekNumber {
+ padding: padding_or_default(*padding, modifier::Padding::Zero),
+ repr: modifier::WeekNumberRepr::Monday,
+ }),
+ b'x' => BorrowedFormatItem::Compound(&[
+ component!(Month {
+ repr: modifier::MonthRepr::Numerical,
+ padding: modifier::Padding::Zero,
+ case_sensitive: true,
+ }),
+ BorrowedFormatItem::Literal(b"/"),
+ component!(Day {
+ padding: modifier::Padding::Zero
+ }),
+ BorrowedFormatItem::Literal(b"/"),
+ component!(Year {
+ padding: modifier::Padding::Zero,
+ repr: modifier::YearRepr::LastTwo,
+ range: modifier::YearRange::Extended,
+ iso_week_based: false,
+ sign_is_mandatory: false,
+ }),
+ ]),
+ b'X' => BorrowedFormatItem::Compound(&[
+ component!(Hour {
+ padding: modifier::Padding::Zero,
+ is_12_hour_clock: false,
+ }),
+ BorrowedFormatItem::Literal(b":"),
+ component!(Minute {
+ padding: modifier::Padding::Zero,
+ }),
+ BorrowedFormatItem::Literal(b":"),
+ component!(Second {
+ padding: modifier::Padding::Zero,
+ }),
+ ]),
+ b'y' => component!(Year {
+ padding: padding_or_default(*padding, modifier::Padding::Zero),
+ repr: modifier::YearRepr::LastTwo,
+ range: modifier::YearRange::Extended,
+ iso_week_based: false,
+ sign_is_mandatory: false,
+ }),
+ b'Y' => component!(Year {
+ padding: modifier::Padding::Zero,
+ repr: modifier::YearRepr::Full,
+ range: modifier::YearRange::Extended,
+ iso_week_based: false,
+ sign_is_mandatory: false,
+ }),
+ b'z' => BorrowedFormatItem::Compound(&[
+ component!(OffsetHour {
+ sign_is_mandatory: true,
+ padding: modifier::Padding::Zero,
+ }),
+ component!(OffsetMinute {
+ padding: modifier::Padding::Zero,
+ }),
+ ]),
+ b'Z' => {
+ return Err(Error {
+ _inner: unused(ErrorInner {
+ _message: "unsupported component",
+ _span: component.span,
+ }),
+ public: InvalidFormatDescription::NotSupported {
+ what: "component",
+ context: "",
+ index: component.span.start.byte as usize,
+ },
+ })
+ }
+ _ => {
+ return Err(Error {
+ _inner: unused(ErrorInner {
+ _message: "invalid component",
+ _span: component.span,
+ }),
+ public: InvalidFormatDescription::InvalidComponentName {
+ name: String::from_utf8_lossy(&[*component]).into_owned(),
+ index: component.span.start.byte as usize,
+ },
+ })
+ }
+ })
+}
diff --git a/vendor/time/src/format_description/well_known/iso8601.rs b/vendor/time/src/format_description/well_known/iso8601.rs
new file mode 100644
index 00000000..6b8ff2ab
--- /dev/null
+++ b/vendor/time/src/format_description/well_known/iso8601.rs
@@ -0,0 +1,257 @@
+//! The format described in ISO 8601.
+
+mod adt_hack;
+
+use core::num::NonZeroU8;
+
+#[doc(hidden, no_inline)]
+pub use self::adt_hack::DoNotRelyOnWhatThisIs;
+pub use self::adt_hack::EncodedConfig;
+
+/// The format described in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html).
+///
+/// This implementation is of ISO 8601-1:2019. It may not be compatible with other versions.
+///
+/// The const parameter `CONFIG` **must** be a value that was returned by [`Config::encode`].
+/// Passing any other value is **unspecified behavior**.
+///
+/// Example: 1997-11-21T09:55:06.000000000-06:00
+///
+/// # Examples
+#[cfg_attr(feature = "formatting", doc = "```rust")]
+#[cfg_attr(not(feature = "formatting"), doc = "```rust,ignore")]
+/// # use time::format_description::well_known::Iso8601;
+/// # use time_macros::datetime;
+/// assert_eq!(
+/// datetime!(1997-11-12 9:55:06 -6:00).format(&Iso8601::DEFAULT)?,
+/// "1997-11-12T09:55:06.000000000-06:00"
+/// );
+/// # Ok::<_, time::Error>(())
+/// ```
+#[derive(Clone, Copy, PartialEq, Eq)]
+pub struct Iso8601<const CONFIG: EncodedConfig = { Config::DEFAULT.encode() }>;
+
+impl<const CONFIG: EncodedConfig> core::fmt::Debug for Iso8601<CONFIG> {
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+ f.debug_struct("Iso8601")
+ .field("config", &Config::decode(CONFIG))
+ .finish()
+ }
+}
+
+/// Define associated constants for `Iso8601`.
+macro_rules! define_assoc_consts {
+ ($($(#[$doc:meta])* $vis:vis const $const_name:ident = $format:expr;)*) => {$(
+ const $const_name: EncodedConfig = $format.encode();
+ impl Iso8601<$const_name> {
+ $(#[$doc])*
+ $vis const $const_name: Self = Self;
+ }
+ )*};
+}
+
+define_assoc_consts! {
+ /// An [`Iso8601`] with the default configuration.
+ ///
+ /// The following is the default behavior:
+ ///
+ /// - The configuration can be used for both formatting and parsing.
+ /// - The date, time, and UTC offset are all formatted.
+ /// - Separators (such as `-` and `:`) are included.
+ /// - The year contains four digits, such that the year must be between 0 and 9999.
+ /// - The date uses the calendar format.
+ /// - The time has precision to the second and nine decimal digits.
+ /// - The UTC offset has precision to the minute.
+ ///
+ /// If you need different behavior, use another associated constant. For full customization, use
+ /// [`Config::DEFAULT`] and [`Config`]'s methods to create a custom configuration.
+ pub const DEFAULT = Config::DEFAULT;
+ /// An [`Iso8601`] that can only be used for parsing. Using this to format a value is
+ /// unspecified behavior.
+ pub const PARSING = Config::PARSING;
+ /// An [`Iso8601`] that handles only the date, but is otherwise the same as [`Config::DEFAULT`].
+ pub const DATE = Config::DEFAULT.set_formatted_components(FormattedComponents::Date);
+ /// An [`Iso8601`] that handles only the time, but is otherwise the same as [`Config::DEFAULT`].
+ pub const TIME = Config::DEFAULT.set_formatted_components(FormattedComponents::Time);
+ /// An [`Iso8601`] that handles only the UTC offset, but is otherwise the same as
+ /// [`Config::DEFAULT`].
+ pub const OFFSET = Config::DEFAULT.set_formatted_components(FormattedComponents::Offset);
+ /// An [`Iso8601`] that handles the date and time, but is otherwise the same as
+ /// [`Config::DEFAULT`].
+ pub const DATE_TIME = Config::DEFAULT.set_formatted_components(FormattedComponents::DateTime);
+ /// An [`Iso8601`] that handles the date, time, and UTC offset. This is the same as
+ /// [`Config::DEFAULT`].
+ pub const DATE_TIME_OFFSET = Config::DEFAULT;
+ /// An [`Iso8601`] that handles the time and UTC offset, but is otherwise the same as
+ /// [`Config::DEFAULT`].
+ pub const TIME_OFFSET = Config::DEFAULT
+ .set_formatted_components(FormattedComponents::TimeOffset);
+}
+
+/// Which components to format.
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum FormattedComponents {
+ /// The configuration can only be used for parsing. Using this to format a value is
+ /// unspecified behavior.
+ None,
+ /// Format only the date.
+ Date,
+ /// Format only the time.
+ Time,
+ /// Format only the UTC offset.
+ Offset,
+ /// Format the date and time.
+ DateTime,
+ /// Format the date, time, and UTC offset.
+ DateTimeOffset,
+ /// Format the time and UTC offset.
+ TimeOffset,
+}
+
+/// Which format to use for the date.
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum DateKind {
+ /// Use the year-month-day format.
+ Calendar,
+ /// Use the year-week-weekday format.
+ Week,
+ /// Use the week-ordinal format.
+ Ordinal,
+}
+
+/// The precision and number of decimal digits present for the time.
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum TimePrecision {
+ /// Format the hour only. Minutes, seconds, and nanoseconds will be represented with the
+ /// specified number of decimal digits, if any.
+ Hour {
+ #[allow(missing_docs)]
+ decimal_digits: Option<NonZeroU8>,
+ },
+ /// Format the hour and minute. Seconds and nanoseconds will be represented with the specified
+ /// number of decimal digits, if any.
+ Minute {
+ #[allow(missing_docs)]
+ decimal_digits: Option<NonZeroU8>,
+ },
+ /// Format the hour, minute, and second. Nanoseconds will be represented with the specified
+ /// number of decimal digits, if any.
+ Second {
+ #[allow(missing_docs)]
+ decimal_digits: Option<NonZeroU8>,
+ },
+}
+
+/// The precision for the UTC offset.
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum OffsetPrecision {
+ /// Format only the offset hour. Requires the offset minute to be zero.
+ Hour,
+ /// Format both the offset hour and minute.
+ Minute,
+}
+
+/// Configuration for [`Iso8601`].
+// This is only used as a const generic, so there's no need to have a number of implementations on
+// it.
+#[allow(missing_copy_implementations)]
+#[doc(alias = "EncodedConfig")] // People will likely search for `EncodedConfig`, so show them this.
+#[derive(Debug)]
+pub struct Config {
+ /// Which components, if any, will be formatted.
+ pub(crate) formatted_components: FormattedComponents,
+ /// Whether the format contains separators (such as `-` or `:`).
+ pub(crate) use_separators: bool,
+ /// Whether the year is six digits.
+ pub(crate) year_is_six_digits: bool,
+ /// The format used for the date.
+ pub(crate) date_kind: DateKind,
+ /// The precision and number of decimal digits present for the time.
+ pub(crate) time_precision: TimePrecision,
+ /// The precision for the UTC offset.
+ pub(crate) offset_precision: OffsetPrecision,
+}
+
+impl Config {
+ /// A configuration for the [`Iso8601`] format.
+ ///
+ /// The following is the default behavior:
+ ///
+ /// - The configuration can be used for both formatting and parsing.
+ /// - The date, time, and UTC offset are all formatted.
+ /// - Separators (such as `-` and `:`) are included.
+ /// - The year contains four digits, such that the year must be between 0 and 9999.
+ /// - The date uses the calendar format.
+ /// - The time has precision to the second and nine decimal digits.
+ /// - The UTC offset has precision to the minute.
+ ///
+ /// If you need different behavior, use the setter methods on this struct.
+ pub const DEFAULT: Self = Self {
+ formatted_components: FormattedComponents::DateTimeOffset,
+ use_separators: true,
+ year_is_six_digits: false,
+ date_kind: DateKind::Calendar,
+ time_precision: TimePrecision::Second {
+ decimal_digits: NonZeroU8::new(9),
+ },
+ offset_precision: OffsetPrecision::Minute,
+ };
+
+ /// A configuration that can only be used for parsing. Using this to format a value is
+ /// unspecified behavior.
+ const PARSING: Self = Self {
+ formatted_components: FormattedComponents::None,
+ use_separators: false,
+ year_is_six_digits: false,
+ date_kind: DateKind::Calendar,
+ time_precision: TimePrecision::Hour {
+ decimal_digits: None,
+ },
+ offset_precision: OffsetPrecision::Hour,
+ };
+
+ /// Set whether the format the date, time, and/or UTC offset.
+ pub const fn set_formatted_components(self, formatted_components: FormattedComponents) -> Self {
+ Self {
+ formatted_components,
+ ..self
+ }
+ }
+
+ /// Set whether the format contains separators (such as `-` or `:`).
+ pub const fn set_use_separators(self, use_separators: bool) -> Self {
+ Self {
+ use_separators,
+ ..self
+ }
+ }
+
+ /// Set whether the year is six digits.
+ pub const fn set_year_is_six_digits(self, year_is_six_digits: bool) -> Self {
+ Self {
+ year_is_six_digits,
+ ..self
+ }
+ }
+
+ /// Set the format used for the date.
+ pub const fn set_date_kind(self, date_kind: DateKind) -> Self {
+ Self { date_kind, ..self }
+ }
+
+ /// Set the precision and number of decimal digits present for the time.
+ pub const fn set_time_precision(self, time_precision: TimePrecision) -> Self {
+ Self {
+ time_precision,
+ ..self
+ }
+ }
+
+ /// Set the precision for the UTC offset.
+ pub const fn set_offset_precision(self, offset_precision: OffsetPrecision) -> Self {
+ Self {
+ offset_precision,
+ ..self
+ }
+ }
+}
diff --git a/vendor/time/src/format_description/well_known/iso8601/adt_hack.rs b/vendor/time/src/format_description/well_known/iso8601/adt_hack.rs
new file mode 100644
index 00000000..6d3daebb
--- /dev/null
+++ b/vendor/time/src/format_description/well_known/iso8601/adt_hack.rs
@@ -0,0 +1,247 @@
+//! Hackery to work around not being able to use ADTs in const generics on stable.
+
+use core::num::NonZeroU8;
+
+#[cfg(feature = "formatting")]
+use super::Iso8601;
+use super::{Config, DateKind, FormattedComponents as FC, OffsetPrecision, TimePrecision};
+
+// This provides a way to include `EncodedConfig` in documentation without displaying the type it is
+// aliased to.
+#[doc(hidden)]
+pub type DoNotRelyOnWhatThisIs = u128;
+
+/// An encoded [`Config`] that can be used as a const parameter to [`Iso8601`](super::Iso8601).
+///
+/// The type this is aliased to must not be relied upon. It can change in any release without
+/// notice.
+pub type EncodedConfig = DoNotRelyOnWhatThisIs;
+
+#[cfg(feature = "formatting")]
+impl<const CONFIG: EncodedConfig> Iso8601<CONFIG> {
+ /// The user-provided configuration for the ISO 8601 format.
+ const CONFIG: Config = Config::decode(CONFIG);
+ /// Whether the date should be formatted.
+ pub(crate) const FORMAT_DATE: bool = matches!(
+ Self::CONFIG.formatted_components,
+ FC::Date | FC::DateTime | FC::DateTimeOffset
+ );
+ /// Whether the time should be formatted.
+ pub(crate) const FORMAT_TIME: bool = matches!(
+ Self::CONFIG.formatted_components,
+ FC::Time | FC::DateTime | FC::DateTimeOffset | FC::TimeOffset
+ );
+ /// Whether the UTC offset should be formatted.
+ pub(crate) const FORMAT_OFFSET: bool = matches!(
+ Self::CONFIG.formatted_components,
+ FC::Offset | FC::DateTimeOffset | FC::TimeOffset
+ );
+ /// Whether the year is six digits.
+ pub(crate) const YEAR_IS_SIX_DIGITS: bool = Self::CONFIG.year_is_six_digits;
+ /// Whether the format contains separators (such as `-` or `:`).
+ pub(crate) const USE_SEPARATORS: bool = Self::CONFIG.use_separators;
+ /// Which format to use for the date.
+ pub(crate) const DATE_KIND: DateKind = Self::CONFIG.date_kind;
+ /// The precision and number of decimal digits to use for the time.
+ pub(crate) const TIME_PRECISION: TimePrecision = Self::CONFIG.time_precision;
+ /// The precision for the UTC offset.
+ pub(crate) const OFFSET_PRECISION: OffsetPrecision = Self::CONFIG.offset_precision;
+}
+
+impl Config {
+ /// Encode the configuration, permitting it to be used as a const parameter of [`Iso8601`].
+ ///
+ /// The value returned by this method must only be used as a const parameter to [`Iso8601`]. Any
+ /// other usage is unspecified behavior.
+ pub const fn encode(&self) -> EncodedConfig {
+ let mut bytes = [0; EncodedConfig::BITS as usize / 8];
+
+ bytes[0] = match self.formatted_components {
+ FC::None => 0,
+ FC::Date => 1,
+ FC::Time => 2,
+ FC::Offset => 3,
+ FC::DateTime => 4,
+ FC::DateTimeOffset => 5,
+ FC::TimeOffset => 6,
+ };
+ bytes[1] = self.use_separators as u8;
+ bytes[2] = self.year_is_six_digits as u8;
+ bytes[3] = match self.date_kind {
+ DateKind::Calendar => 0,
+ DateKind::Week => 1,
+ DateKind::Ordinal => 2,
+ };
+ bytes[4] = match self.time_precision {
+ TimePrecision::Hour { .. } => 0,
+ TimePrecision::Minute { .. } => 1,
+ TimePrecision::Second { .. } => 2,
+ };
+ bytes[5] = match self.time_precision {
+ TimePrecision::Hour { decimal_digits }
+ | TimePrecision::Minute { decimal_digits }
+ | TimePrecision::Second { decimal_digits } => match decimal_digits {
+ None => 0,
+ Some(decimal_digits) => decimal_digits.get(),
+ },
+ };
+ bytes[6] = match self.offset_precision {
+ OffsetPrecision::Hour => 0,
+ OffsetPrecision::Minute => 1,
+ };
+
+ EncodedConfig::from_be_bytes(bytes)
+ }
+
+ /// Decode the configuration. The configuration must have been generated from
+ /// [`Config::encode`].
+ pub(super) const fn decode(encoded: EncodedConfig) -> Self {
+ let bytes = encoded.to_be_bytes();
+
+ let formatted_components = match bytes[0] {
+ 0 => FC::None,
+ 1 => FC::Date,
+ 2 => FC::Time,
+ 3 => FC::Offset,
+ 4 => FC::DateTime,
+ 5 => FC::DateTimeOffset,
+ 6 => FC::TimeOffset,
+ _ => panic!("invalid configuration"),
+ };
+ let use_separators = match bytes[1] {
+ 0 => false,
+ 1 => true,
+ _ => panic!("invalid configuration"),
+ };
+ let year_is_six_digits = match bytes[2] {
+ 0 => false,
+ 1 => true,
+ _ => panic!("invalid configuration"),
+ };
+ let date_kind = match bytes[3] {
+ 0 => DateKind::Calendar,
+ 1 => DateKind::Week,
+ 2 => DateKind::Ordinal,
+ _ => panic!("invalid configuration"),
+ };
+ let time_precision = match bytes[4] {
+ 0 => TimePrecision::Hour {
+ decimal_digits: NonZeroU8::new(bytes[5]),
+ },
+ 1 => TimePrecision::Minute {
+ decimal_digits: NonZeroU8::new(bytes[5]),
+ },
+ 2 => TimePrecision::Second {
+ decimal_digits: NonZeroU8::new(bytes[5]),
+ },
+ _ => panic!("invalid configuration"),
+ };
+ let offset_precision = match bytes[6] {
+ 0 => OffsetPrecision::Hour,
+ 1 => OffsetPrecision::Minute,
+ _ => panic!("invalid configuration"),
+ };
+
+ // No `for` loops in `const fn`.
+ let mut idx = 7; // first unused byte
+ while idx < EncodedConfig::BITS as usize / 8 {
+ assert!(bytes[idx] == 0, "invalid configuration");
+ idx += 1;
+ }
+
+ Self {
+ formatted_components,
+ use_separators,
+ year_is_six_digits,
+ date_kind,
+ time_precision,
+ offset_precision,
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ macro_rules! eq {
+ ($a:expr, $b:expr) => {{
+ let a = $a;
+ let b = $b;
+ a.formatted_components == b.formatted_components
+ && a.use_separators == b.use_separators
+ && a.year_is_six_digits == b.year_is_six_digits
+ && a.date_kind == b.date_kind
+ && a.time_precision == b.time_precision
+ && a.offset_precision == b.offset_precision
+ }};
+ }
+
+ #[test]
+ fn encoding_roundtrip() {
+ macro_rules! assert_roundtrip {
+ ($config:expr) => {
+ let config = $config;
+ let encoded = config.encode();
+ let decoded = Config::decode(encoded);
+ assert!(eq!(config, decoded));
+ };
+ }
+
+ assert_roundtrip!(Config::DEFAULT);
+ assert_roundtrip!(Config::DEFAULT.set_formatted_components(FC::None));
+ assert_roundtrip!(Config::DEFAULT.set_formatted_components(FC::Date));
+ assert_roundtrip!(Config::DEFAULT.set_formatted_components(FC::Time));
+ assert_roundtrip!(Config::DEFAULT.set_formatted_components(FC::Offset));
+ assert_roundtrip!(Config::DEFAULT.set_formatted_components(FC::DateTime));
+ assert_roundtrip!(Config::DEFAULT.set_formatted_components(FC::DateTimeOffset));
+ assert_roundtrip!(Config::DEFAULT.set_formatted_components(FC::TimeOffset));
+ assert_roundtrip!(Config::DEFAULT.set_use_separators(false));
+ assert_roundtrip!(Config::DEFAULT.set_use_separators(true));
+ assert_roundtrip!(Config::DEFAULT.set_year_is_six_digits(false));
+ assert_roundtrip!(Config::DEFAULT.set_year_is_six_digits(true));
+ assert_roundtrip!(Config::DEFAULT.set_date_kind(DateKind::Calendar));
+ assert_roundtrip!(Config::DEFAULT.set_date_kind(DateKind::Week));
+ assert_roundtrip!(Config::DEFAULT.set_date_kind(DateKind::Ordinal));
+ assert_roundtrip!(Config::DEFAULT.set_time_precision(TimePrecision::Hour {
+ decimal_digits: None,
+ }));
+ assert_roundtrip!(Config::DEFAULT.set_time_precision(TimePrecision::Minute {
+ decimal_digits: None,
+ }));
+ assert_roundtrip!(Config::DEFAULT.set_time_precision(TimePrecision::Second {
+ decimal_digits: None,
+ }));
+ assert_roundtrip!(Config::DEFAULT.set_time_precision(TimePrecision::Hour {
+ decimal_digits: NonZeroU8::new(1),
+ }));
+ assert_roundtrip!(Config::DEFAULT.set_time_precision(TimePrecision::Minute {
+ decimal_digits: NonZeroU8::new(1),
+ }));
+ assert_roundtrip!(Config::DEFAULT.set_time_precision(TimePrecision::Second {
+ decimal_digits: NonZeroU8::new(1),
+ }));
+ assert_roundtrip!(Config::DEFAULT.set_offset_precision(OffsetPrecision::Hour));
+ assert_roundtrip!(Config::DEFAULT.set_offset_precision(OffsetPrecision::Minute));
+ }
+
+ macro_rules! assert_decode_fail {
+ ($encoding:expr) => {
+ assert!(std::panic::catch_unwind(|| {
+ Config::decode($encoding);
+ })
+ .is_err());
+ };
+ }
+
+ #[test]
+ fn decode_fail() {
+ assert_decode_fail!(0x07_00_00_00_00_00_00_00_00_00_00_00_00_00_00_00);
+ assert_decode_fail!(0x00_02_00_00_00_00_00_00_00_00_00_00_00_00_00_00);
+ assert_decode_fail!(0x00_00_02_00_00_00_00_00_00_00_00_00_00_00_00_00);
+ assert_decode_fail!(0x00_00_00_03_00_00_00_00_00_00_00_00_00_00_00_00);
+ assert_decode_fail!(0x00_00_00_00_03_00_00_00_00_00_00_00_00_00_00_00);
+ assert_decode_fail!(0x00_00_00_00_00_00_02_00_00_00_00_00_00_00_00_00);
+ assert_decode_fail!(0x00_00_00_00_00_00_00_01_00_00_00_00_00_00_00_00);
+ }
+}
diff --git a/vendor/time/src/format_description/well_known/rfc2822.rs b/vendor/time/src/format_description/well_known/rfc2822.rs
new file mode 100644
index 00000000..3c890ab1
--- /dev/null
+++ b/vendor/time/src/format_description/well_known/rfc2822.rs
@@ -0,0 +1,30 @@
+//! The format described in RFC 2822.
+
+/// The format described in [RFC 2822](https://tools.ietf.org/html/rfc2822#section-3.3).
+///
+/// Example: Fri, 21 Nov 1997 09:55:06 -0600
+///
+/// # Examples
+#[cfg_attr(feature = "parsing", doc = "```rust")]
+#[cfg_attr(not(feature = "parsing"), doc = "```rust,ignore")]
+/// # use time::{format_description::well_known::Rfc2822, OffsetDateTime};
+/// use time_macros::datetime;
+/// assert_eq!(
+/// OffsetDateTime::parse("Sat, 12 Jun 1993 13:25:19 GMT", &Rfc2822)?,
+/// datetime!(1993-06-12 13:25:19 +00:00)
+/// );
+/// # Ok::<_, time::Error>(())
+/// ```
+///
+#[cfg_attr(feature = "formatting", doc = "```rust")]
+#[cfg_attr(not(feature = "formatting"), doc = "```rust,ignore")]
+/// # use time::format_description::well_known::Rfc2822;
+/// # use time_macros::datetime;
+/// assert_eq!(
+/// datetime!(1997-11-21 09:55:06 -06:00).format(&Rfc2822)?,
+/// "Fri, 21 Nov 1997 09:55:06 -0600"
+/// );
+/// # Ok::<_, time::Error>(())
+/// ```
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub struct Rfc2822;
diff --git a/vendor/time/src/format_description/well_known/rfc3339.rs b/vendor/time/src/format_description/well_known/rfc3339.rs
new file mode 100644
index 00000000..f0873cba
--- /dev/null
+++ b/vendor/time/src/format_description/well_known/rfc3339.rs
@@ -0,0 +1,30 @@
+//! The format described in RFC 3339.
+
+/// The format described in [RFC 3339](https://tools.ietf.org/html/rfc3339#section-5.6).
+///
+/// Format example: 1985-04-12T23:20:50.52Z
+///
+/// # Examples
+#[cfg_attr(feature = "parsing", doc = "```rust")]
+#[cfg_attr(not(feature = "parsing"), doc = "```rust,ignore")]
+/// # use time::{format_description::well_known::Rfc3339, OffsetDateTime};
+/// # use time_macros::datetime;
+/// assert_eq!(
+/// OffsetDateTime::parse("1985-04-12T23:20:50.52Z", &Rfc3339)?,
+/// datetime!(1985-04-12 23:20:50.52 +00:00)
+/// );
+/// # Ok::<_, time::Error>(())
+/// ```
+///
+#[cfg_attr(feature = "formatting", doc = "```rust")]
+#[cfg_attr(not(feature = "formatting"), doc = "```rust,ignore")]
+/// # use time::format_description::well_known::Rfc3339;
+/// # use time_macros::datetime;
+/// assert_eq!(
+/// datetime!(1985-04-12 23:20:50.52 +00:00).format(&Rfc3339)?,
+/// "1985-04-12T23:20:50.52Z"
+/// );
+/// # Ok::<_, time::Error>(())
+/// ```
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub struct Rfc3339;
diff --git a/vendor/time/src/formatting/formattable.rs b/vendor/time/src/formatting/formattable.rs
new file mode 100644
index 00000000..7d1ce031
--- /dev/null
+++ b/vendor/time/src/formatting/formattable.rs
@@ -0,0 +1,312 @@
+//! A trait that can be used to format an item from its components.
+
+use alloc::string::String;
+use alloc::vec::Vec;
+use core::ops::Deref;
+use std::io;
+
+use num_conv::prelude::*;
+
+use crate::format_description::well_known::iso8601::EncodedConfig;
+use crate::format_description::well_known::{Iso8601, Rfc2822, Rfc3339};
+use crate::format_description::{BorrowedFormatItem, OwnedFormatItem};
+use crate::formatting::{
+ format_component, format_number_pad_zero, iso8601, write, MONTH_NAMES, WEEKDAY_NAMES,
+};
+use crate::{error, Date, Time, UtcOffset};
+
+/// A type that describes a format.
+///
+/// Implementors of [`Formattable`] are [format descriptions](crate::format_description).
+///
+/// [`Date::format`] and [`Time::format`] each use a format description to generate
+/// a String from their data. See the respective methods for usage examples.
+#[cfg_attr(docsrs, doc(notable_trait))]
+pub trait Formattable: sealed::Sealed {}
+impl Formattable for BorrowedFormatItem<'_> {}
+impl Formattable for [BorrowedFormatItem<'_>] {}
+impl Formattable for OwnedFormatItem {}
+impl Formattable for [OwnedFormatItem] {}
+impl Formattable for Rfc3339 {}
+impl Formattable for Rfc2822 {}
+impl<const CONFIG: EncodedConfig> Formattable for Iso8601<CONFIG> {}
+impl<T: Deref> Formattable for T where T::Target: Formattable {}
+
+/// Seal the trait to prevent downstream users from implementing it.
+mod sealed {
+ #[allow(clippy::wildcard_imports)]
+ use super::*;
+
+ /// Format the item using a format description, the intended output, and the various components.
+ pub trait Sealed {
+ /// Format the item into the provided output, returning the number of bytes written.
+ fn format_into(
+ &self,
+ output: &mut (impl io::Write + ?Sized),
+ date: Option<Date>,
+ time: Option<Time>,
+ offset: Option<UtcOffset>,
+ ) -> Result<usize, error::Format>;
+
+ /// Format the item directly to a `String`.
+ fn format(
+ &self,
+ date: Option<Date>,
+ time: Option<Time>,
+ offset: Option<UtcOffset>,
+ ) -> Result<String, error::Format> {
+ let mut buf = Vec::new();
+ self.format_into(&mut buf, date, time, offset)?;
+ Ok(String::from_utf8_lossy(&buf).into_owned())
+ }
+ }
+}
+
+impl sealed::Sealed for BorrowedFormatItem<'_> {
+ fn format_into(
+ &self,
+ output: &mut (impl io::Write + ?Sized),
+ date: Option<Date>,
+ time: Option<Time>,
+ offset: Option<UtcOffset>,
+ ) -> Result<usize, error::Format> {
+ Ok(match *self {
+ Self::Literal(literal) => write(output, literal)?,
+ Self::Component(component) => format_component(output, component, date, time, offset)?,
+ Self::Compound(items) => items.format_into(output, date, time, offset)?,
+ Self::Optional(item) => item.format_into(output, date, time, offset)?,
+ Self::First(items) => match items {
+ [] => 0,
+ [item, ..] => item.format_into(output, date, time, offset)?,
+ },
+ })
+ }
+}
+
+impl sealed::Sealed for [BorrowedFormatItem<'_>] {
+ fn format_into(
+ &self,
+ output: &mut (impl io::Write + ?Sized),
+ date: Option<Date>,
+ time: Option<Time>,
+ offset: Option<UtcOffset>,
+ ) -> Result<usize, error::Format> {
+ let mut bytes = 0;
+ for item in self.iter() {
+ bytes += item.format_into(output, date, time, offset)?;
+ }
+ Ok(bytes)
+ }
+}
+
+impl sealed::Sealed for OwnedFormatItem {
+ fn format_into(
+ &self,
+ output: &mut (impl io::Write + ?Sized),
+ date: Option<Date>,
+ time: Option<Time>,
+ offset: Option<UtcOffset>,
+ ) -> Result<usize, error::Format> {
+ match self {
+ Self::Literal(literal) => Ok(write(output, literal)?),
+ Self::Component(component) => format_component(output, *component, date, time, offset),
+ Self::Compound(items) => items.format_into(output, date, time, offset),
+ Self::Optional(item) => item.format_into(output, date, time, offset),
+ Self::First(items) => match &**items {
+ [] => Ok(0),
+ [item, ..] => item.format_into(output, date, time, offset),
+ },
+ }
+ }
+}
+
+impl sealed::Sealed for [OwnedFormatItem] {
+ fn format_into(
+ &self,
+ output: &mut (impl io::Write + ?Sized),
+ date: Option<Date>,
+ time: Option<Time>,
+ offset: Option<UtcOffset>,
+ ) -> Result<usize, error::Format> {
+ let mut bytes = 0;
+ for item in self.iter() {
+ bytes += item.format_into(output, date, time, offset)?;
+ }
+ Ok(bytes)
+ }
+}
+
+impl<T: Deref> sealed::Sealed for T
+where
+ T::Target: sealed::Sealed,
+{
+ fn format_into(
+ &self,
+ output: &mut (impl io::Write + ?Sized),
+ date: Option<Date>,
+ time: Option<Time>,
+ offset: Option<UtcOffset>,
+ ) -> Result<usize, error::Format> {
+ self.deref().format_into(output, date, time, offset)
+ }
+}
+
+impl sealed::Sealed for Rfc2822 {
+ fn format_into(
+ &self,
+ output: &mut (impl io::Write + ?Sized),
+ date: Option<Date>,
+ time: Option<Time>,
+ offset: Option<UtcOffset>,
+ ) -> Result<usize, error::Format> {
+ let date = date.ok_or(error::Format::InsufficientTypeInformation)?;
+ let time = time.ok_or(error::Format::InsufficientTypeInformation)?;
+ let offset = offset.ok_or(error::Format::InsufficientTypeInformation)?;
+
+ let mut bytes = 0;
+
+ let (year, month, day) = date.to_calendar_date();
+
+ if year < 1900 {
+ return Err(error::Format::InvalidComponent("year"));
+ }
+ if offset.seconds_past_minute() != 0 {
+ return Err(error::Format::InvalidComponent("offset_second"));
+ }
+
+ bytes += write(
+ output,
+ &WEEKDAY_NAMES[date.weekday().number_days_from_monday().extend::<usize>()][..3],
+ )?;
+ bytes += write(output, b", ")?;
+ bytes += format_number_pad_zero::<2>(output, day)?;
+ bytes += write(output, b" ")?;
+ bytes += write(
+ output,
+ &MONTH_NAMES[u8::from(month).extend::<usize>() - 1][..3],
+ )?;
+ bytes += write(output, b" ")?;
+ bytes += format_number_pad_zero::<4>(output, year.cast_unsigned())?;
+ bytes += write(output, b" ")?;
+ bytes += format_number_pad_zero::<2>(output, time.hour())?;
+ bytes += write(output, b":")?;
+ bytes += format_number_pad_zero::<2>(output, time.minute())?;
+ bytes += write(output, b":")?;
+ bytes += format_number_pad_zero::<2>(output, time.second())?;
+ bytes += write(output, b" ")?;
+ bytes += write(output, if offset.is_negative() { b"-" } else { b"+" })?;
+ bytes += format_number_pad_zero::<2>(output, offset.whole_hours().unsigned_abs())?;
+ bytes += format_number_pad_zero::<2>(output, offset.minutes_past_hour().unsigned_abs())?;
+
+ Ok(bytes)
+ }
+}
+
+impl sealed::Sealed for Rfc3339 {
+ fn format_into(
+ &self,
+ output: &mut (impl io::Write + ?Sized),
+ date: Option<Date>,
+ time: Option<Time>,
+ offset: Option<UtcOffset>,
+ ) -> Result<usize, error::Format> {
+ let date = date.ok_or(error::Format::InsufficientTypeInformation)?;
+ let time = time.ok_or(error::Format::InsufficientTypeInformation)?;
+ let offset = offset.ok_or(error::Format::InsufficientTypeInformation)?;
+
+ let mut bytes = 0;
+
+ let year = date.year();
+
+ if !(0..10_000).contains(&year) {
+ return Err(error::Format::InvalidComponent("year"));
+ }
+ if offset.whole_hours().unsigned_abs() > 23 {
+ return Err(error::Format::InvalidComponent("offset_hour"));
+ }
+ if offset.seconds_past_minute() != 0 {
+ return Err(error::Format::InvalidComponent("offset_second"));
+ }
+
+ bytes += format_number_pad_zero::<4>(output, year.cast_unsigned())?;
+ bytes += write(output, b"-")?;
+ bytes += format_number_pad_zero::<2>(output, u8::from(date.month()))?;
+ bytes += write(output, b"-")?;
+ bytes += format_number_pad_zero::<2>(output, date.day())?;
+ bytes += write(output, b"T")?;
+ bytes += format_number_pad_zero::<2>(output, time.hour())?;
+ bytes += write(output, b":")?;
+ bytes += format_number_pad_zero::<2>(output, time.minute())?;
+ bytes += write(output, b":")?;
+ bytes += format_number_pad_zero::<2>(output, time.second())?;
+
+ if time.nanosecond() != 0 {
+ let nanos = time.nanosecond();
+ bytes += write(output, b".")?;
+ bytes += if nanos % 10 != 0 {
+ format_number_pad_zero::<9>(output, nanos)
+ } else if (nanos / 10) % 10 != 0 {
+ format_number_pad_zero::<8>(output, nanos / 10)
+ } else if (nanos / 100) % 10 != 0 {
+ format_number_pad_zero::<7>(output, nanos / 100)
+ } else if (nanos / 1_000) % 10 != 0 {
+ format_number_pad_zero::<6>(output, nanos / 1_000)
+ } else if (nanos / 10_000) % 10 != 0 {
+ format_number_pad_zero::<5>(output, nanos / 10_000)
+ } else if (nanos / 100_000) % 10 != 0 {
+ format_number_pad_zero::<4>(output, nanos / 100_000)
+ } else if (nanos / 1_000_000) % 10 != 0 {
+ format_number_pad_zero::<3>(output, nanos / 1_000_000)
+ } else if (nanos / 10_000_000) % 10 != 0 {
+ format_number_pad_zero::<2>(output, nanos / 10_000_000)
+ } else {
+ format_number_pad_zero::<1>(output, nanos / 100_000_000)
+ }?;
+ }
+
+ if offset == UtcOffset::UTC {
+ bytes += write(output, b"Z")?;
+ return Ok(bytes);
+ }
+
+ bytes += write(output, if offset.is_negative() { b"-" } else { b"+" })?;
+ bytes += format_number_pad_zero::<2>(output, offset.whole_hours().unsigned_abs())?;
+ bytes += write(output, b":")?;
+ bytes += format_number_pad_zero::<2>(output, offset.minutes_past_hour().unsigned_abs())?;
+
+ Ok(bytes)
+ }
+}
+
+impl<const CONFIG: EncodedConfig> sealed::Sealed for Iso8601<CONFIG> {
+ fn format_into(
+ &self,
+ output: &mut (impl io::Write + ?Sized),
+ date: Option<Date>,
+ time: Option<Time>,
+ offset: Option<UtcOffset>,
+ ) -> Result<usize, error::Format> {
+ let mut bytes = 0;
+
+ if Self::FORMAT_DATE {
+ let date = date.ok_or(error::Format::InsufficientTypeInformation)?;
+ bytes += iso8601::format_date::<CONFIG>(output, date)?;
+ }
+ if Self::FORMAT_TIME {
+ let time = time.ok_or(error::Format::InsufficientTypeInformation)?;
+ bytes += iso8601::format_time::<CONFIG>(output, time)?;
+ }
+ if Self::FORMAT_OFFSET {
+ let offset = offset.ok_or(error::Format::InsufficientTypeInformation)?;
+ bytes += iso8601::format_offset::<CONFIG>(output, offset)?;
+ }
+
+ if bytes == 0 {
+ // The only reason there would be no bytes written is if the format was only for
+ // parsing.
+ panic!("attempted to format a parsing-only format description");
+ }
+
+ Ok(bytes)
+ }
+}
diff --git a/vendor/time/src/formatting/iso8601.rs b/vendor/time/src/formatting/iso8601.rs
new file mode 100644
index 00000000..a2d2affa
--- /dev/null
+++ b/vendor/time/src/formatting/iso8601.rs
@@ -0,0 +1,142 @@
+//! Helpers for implementing formatting for ISO 8601.
+
+use std::io;
+
+use num_conv::prelude::*;
+
+use crate::convert::*;
+use crate::format_description::well_known::iso8601::{
+ DateKind, EncodedConfig, OffsetPrecision, TimePrecision,
+};
+use crate::format_description::well_known::Iso8601;
+use crate::formatting::{format_float, format_number_pad_zero, write, write_if, write_if_else};
+use crate::{error, Date, Time, UtcOffset};
+
+/// Format the date portion of ISO 8601.
+pub(super) fn format_date<const CONFIG: EncodedConfig>(
+ output: &mut (impl io::Write + ?Sized),
+ date: Date,
+) -> Result<usize, error::Format> {
+ let mut bytes = 0;
+
+ match Iso8601::<CONFIG>::DATE_KIND {
+ DateKind::Calendar => {
+ let (year, month, day) = date.to_calendar_date();
+ if Iso8601::<CONFIG>::YEAR_IS_SIX_DIGITS {
+ bytes += write_if_else(output, year < 0, b"-", b"+")?;
+ bytes += format_number_pad_zero::<6>(output, year.unsigned_abs())?;
+ } else if !(0..=9999).contains(&year) {
+ return Err(error::Format::InvalidComponent("year"));
+ } else {
+ bytes += format_number_pad_zero::<4>(output, year.cast_unsigned())?;
+ }
+ bytes += write_if(output, Iso8601::<CONFIG>::USE_SEPARATORS, b"-")?;
+ bytes += format_number_pad_zero::<2>(output, u8::from(month))?;
+ bytes += write_if(output, Iso8601::<CONFIG>::USE_SEPARATORS, b"-")?;
+ bytes += format_number_pad_zero::<2>(output, day)?;
+ }
+ DateKind::Week => {
+ let (year, week, day) = date.to_iso_week_date();
+ if Iso8601::<CONFIG>::YEAR_IS_SIX_DIGITS {
+ bytes += write_if_else(output, year < 0, b"-", b"+")?;
+ bytes += format_number_pad_zero::<6>(output, year.unsigned_abs())?;
+ } else if !(0..=9999).contains(&year) {
+ return Err(error::Format::InvalidComponent("year"));
+ } else {
+ bytes += format_number_pad_zero::<4>(output, year.cast_unsigned())?;
+ }
+ bytes += write_if_else(output, Iso8601::<CONFIG>::USE_SEPARATORS, b"-W", b"W")?;
+ bytes += format_number_pad_zero::<2>(output, week)?;
+ bytes += write_if(output, Iso8601::<CONFIG>::USE_SEPARATORS, b"-")?;
+ bytes += format_number_pad_zero::<1>(output, day.number_from_monday())?;
+ }
+ DateKind::Ordinal => {
+ let (year, day) = date.to_ordinal_date();
+ if Iso8601::<CONFIG>::YEAR_IS_SIX_DIGITS {
+ bytes += write_if_else(output, year < 0, b"-", b"+")?;
+ bytes += format_number_pad_zero::<6>(output, year.unsigned_abs())?;
+ } else if !(0..=9999).contains(&year) {
+ return Err(error::Format::InvalidComponent("year"));
+ } else {
+ bytes += format_number_pad_zero::<4>(output, year.cast_unsigned())?;
+ }
+ bytes += write_if(output, Iso8601::<CONFIG>::USE_SEPARATORS, b"-")?;
+ bytes += format_number_pad_zero::<3>(output, day)?;
+ }
+ }
+
+ Ok(bytes)
+}
+
+/// Format the time portion of ISO 8601.
+pub(super) fn format_time<const CONFIG: EncodedConfig>(
+ output: &mut (impl io::Write + ?Sized),
+ time: Time,
+) -> Result<usize, error::Format> {
+ let mut bytes = 0;
+
+ // The "T" can only be omitted in extended format where there is no date being formatted.
+ bytes += write_if(
+ output,
+ Iso8601::<CONFIG>::USE_SEPARATORS || Iso8601::<CONFIG>::FORMAT_DATE,
+ b"T",
+ )?;
+
+ let (hours, minutes, seconds, nanoseconds) = time.as_hms_nano();
+
+ match Iso8601::<CONFIG>::TIME_PRECISION {
+ TimePrecision::Hour { decimal_digits } => {
+ let hours = (hours as f64)
+ + (minutes as f64) / Minute::per(Hour) as f64
+ + (seconds as f64) / Second::per(Hour) as f64
+ + (nanoseconds as f64) / Nanosecond::per(Hour) as f64;
+ format_float(output, hours, 2, decimal_digits)?;
+ }
+ TimePrecision::Minute { decimal_digits } => {
+ bytes += format_number_pad_zero::<2>(output, hours)?;
+ bytes += write_if(output, Iso8601::<CONFIG>::USE_SEPARATORS, b":")?;
+ let minutes = (minutes as f64)
+ + (seconds as f64) / Second::per(Minute) as f64
+ + (nanoseconds as f64) / Nanosecond::per(Minute) as f64;
+ bytes += format_float(output, minutes, 2, decimal_digits)?;
+ }
+ TimePrecision::Second { decimal_digits } => {
+ bytes += format_number_pad_zero::<2>(output, hours)?;
+ bytes += write_if(output, Iso8601::<CONFIG>::USE_SEPARATORS, b":")?;
+ bytes += format_number_pad_zero::<2>(output, minutes)?;
+ bytes += write_if(output, Iso8601::<CONFIG>::USE_SEPARATORS, b":")?;
+ let seconds = (seconds as f64) + (nanoseconds as f64) / Nanosecond::per(Second) as f64;
+ bytes += format_float(output, seconds, 2, decimal_digits)?;
+ }
+ }
+
+ Ok(bytes)
+}
+
+/// Format the UTC offset portion of ISO 8601.
+pub(super) fn format_offset<const CONFIG: EncodedConfig>(
+ output: &mut (impl io::Write + ?Sized),
+ offset: UtcOffset,
+) -> Result<usize, error::Format> {
+ if Iso8601::<CONFIG>::FORMAT_TIME && offset.is_utc() {
+ return Ok(write(output, b"Z")?);
+ }
+
+ let mut bytes = 0;
+
+ let (hours, minutes, seconds) = offset.as_hms();
+ if seconds != 0 {
+ return Err(error::Format::InvalidComponent("offset_second"));
+ }
+ bytes += write_if_else(output, offset.is_negative(), b"-", b"+")?;
+ bytes += format_number_pad_zero::<2>(output, hours.unsigned_abs())?;
+
+ if Iso8601::<CONFIG>::OFFSET_PRECISION == OffsetPrecision::Hour && minutes != 0 {
+ return Err(error::Format::InvalidComponent("offset_minute"));
+ } else if Iso8601::<CONFIG>::OFFSET_PRECISION == OffsetPrecision::Minute {
+ bytes += write_if(output, Iso8601::<CONFIG>::USE_SEPARATORS, b":")?;
+ bytes += format_number_pad_zero::<2>(output, minutes.unsigned_abs())?;
+ }
+
+ Ok(bytes)
+}
diff --git a/vendor/time/src/formatting/mod.rs b/vendor/time/src/formatting/mod.rs
new file mode 100644
index 00000000..c3837107
--- /dev/null
+++ b/vendor/time/src/formatting/mod.rs
@@ -0,0 +1,517 @@
+//! Formatting for various types.
+
+pub(crate) mod formattable;
+mod iso8601;
+
+use core::num::NonZeroU8;
+use std::io;
+
+use num_conv::prelude::*;
+
+pub use self::formattable::Formattable;
+use crate::convert::*;
+use crate::ext::DigitCount;
+use crate::format_description::{modifier, Component};
+use crate::{error, Date, OffsetDateTime, Time, UtcOffset};
+
+const MONTH_NAMES: [&[u8]; 12] = [
+ b"January",
+ b"February",
+ b"March",
+ b"April",
+ b"May",
+ b"June",
+ b"July",
+ b"August",
+ b"September",
+ b"October",
+ b"November",
+ b"December",
+];
+
+const WEEKDAY_NAMES: [&[u8]; 7] = [
+ b"Monday",
+ b"Tuesday",
+ b"Wednesday",
+ b"Thursday",
+ b"Friday",
+ b"Saturday",
+ b"Sunday",
+];
+
+/// Write all bytes to the output, returning the number of bytes written.
+pub(crate) fn write(output: &mut (impl io::Write + ?Sized), bytes: &[u8]) -> io::Result<usize> {
+ output.write_all(bytes)?;
+ Ok(bytes.len())
+}
+
+/// If `pred` is true, write all bytes to the output, returning the number of bytes written.
+pub(crate) fn write_if(
+ output: &mut (impl io::Write + ?Sized),
+ pred: bool,
+ bytes: &[u8],
+) -> io::Result<usize> {
+ if pred {
+ write(output, bytes)
+ } else {
+ Ok(0)
+ }
+}
+
+/// If `pred` is true, write `true_bytes` to the output. Otherwise, write `false_bytes`.
+pub(crate) fn write_if_else(
+ output: &mut (impl io::Write + ?Sized),
+ pred: bool,
+ true_bytes: &[u8],
+ false_bytes: &[u8],
+) -> io::Result<usize> {
+ write(output, if pred { true_bytes } else { false_bytes })
+}
+
+/// Write the floating point number to the output, returning the number of bytes written.
+///
+/// This method accepts the number of digits before and after the decimal. The value will be padded
+/// with zeroes to the left if necessary.
+pub(crate) fn format_float(
+ output: &mut (impl io::Write + ?Sized),
+ value: f64,
+ digits_before_decimal: u8,
+ digits_after_decimal: Option<NonZeroU8>,
+) -> io::Result<usize> {
+ match digits_after_decimal {
+ Some(digits_after_decimal) => {
+ // Truncate the decimal points up to the precision
+ let trunc_num = 10_f64.powi(digits_after_decimal.get().cast_signed().extend());
+ let value = f64::trunc(value * trunc_num) / trunc_num;
+
+ let digits_after_decimal = digits_after_decimal.get().extend();
+ let width = digits_before_decimal.extend::<usize>() + 1 + digits_after_decimal;
+ write!(output, "{value:0>width$.digits_after_decimal$}")?;
+ Ok(width)
+ }
+ None => {
+ let value = value.trunc() as u64;
+ let width = digits_before_decimal.extend();
+ write!(output, "{value:0>width$}")?;
+ Ok(width)
+ }
+ }
+}
+
+/// Format a number with the provided padding and width.
+///
+/// The sign must be written by the caller.
+pub(crate) fn format_number<const WIDTH: u8>(
+ output: &mut (impl io::Write + ?Sized),
+ value: impl itoa::Integer + DigitCount + Copy,
+ padding: modifier::Padding,
+) -> Result<usize, io::Error> {
+ match padding {
+ modifier::Padding::Space => format_number_pad_space::<WIDTH>(output, value),
+ modifier::Padding::Zero => format_number_pad_zero::<WIDTH>(output, value),
+ modifier::Padding::None => format_number_pad_none(output, value),
+ }
+}
+
+/// Format a number with the provided width and spaces as padding.
+///
+/// The sign must be written by the caller.
+pub(crate) fn format_number_pad_space<const WIDTH: u8>(
+ output: &mut (impl io::Write + ?Sized),
+ value: impl itoa::Integer + DigitCount + Copy,
+) -> Result<usize, io::Error> {
+ let mut bytes = 0;
+ for _ in 0..(WIDTH.saturating_sub(value.num_digits())) {
+ bytes += write(output, b" ")?;
+ }
+ bytes += write(output, itoa::Buffer::new().format(value).as_bytes())?;
+ Ok(bytes)
+}
+
+/// Format a number with the provided width and zeros as padding.
+///
+/// The sign must be written by the caller.
+pub(crate) fn format_number_pad_zero<const WIDTH: u8>(
+ output: &mut (impl io::Write + ?Sized),
+ value: impl itoa::Integer + DigitCount + Copy,
+) -> Result<usize, io::Error> {
+ let mut bytes = 0;
+ for _ in 0..(WIDTH.saturating_sub(value.num_digits())) {
+ bytes += write(output, b"0")?;
+ }
+ bytes += write(output, itoa::Buffer::new().format(value).as_bytes())?;
+ Ok(bytes)
+}
+
+/// Format a number with no padding.
+///
+/// If the sign is mandatory, the sign must be written by the caller.
+pub(crate) fn format_number_pad_none(
+ output: &mut (impl io::Write + ?Sized),
+ value: impl itoa::Integer + Copy,
+) -> Result<usize, io::Error> {
+ write(output, itoa::Buffer::new().format(value).as_bytes())
+}
+
+/// Format the provided component into the designated output. An `Err` will be returned if the
+/// component requires information that it does not provide or if the value cannot be output to the
+/// stream.
+pub(crate) fn format_component(
+ output: &mut (impl io::Write + ?Sized),
+ component: Component,
+ date: Option<Date>,
+ time: Option<Time>,
+ offset: Option<UtcOffset>,
+) -> Result<usize, error::Format> {
+ use Component::*;
+ Ok(match (component, date, time, offset) {
+ (Day(modifier), Some(date), ..) => fmt_day(output, date, modifier)?,
+ (Month(modifier), Some(date), ..) => fmt_month(output, date, modifier)?,
+ (Ordinal(modifier), Some(date), ..) => fmt_ordinal(output, date, modifier)?,
+ (Weekday(modifier), Some(date), ..) => fmt_weekday(output, date, modifier)?,
+ (WeekNumber(modifier), Some(date), ..) => fmt_week_number(output, date, modifier)?,
+ (Year(modifier), Some(date), ..) => fmt_year(output, date, modifier)?,
+ (Hour(modifier), _, Some(time), _) => fmt_hour(output, time, modifier)?,
+ (Minute(modifier), _, Some(time), _) => fmt_minute(output, time, modifier)?,
+ (Period(modifier), _, Some(time), _) => fmt_period(output, time, modifier)?,
+ (Second(modifier), _, Some(time), _) => fmt_second(output, time, modifier)?,
+ (Subsecond(modifier), _, Some(time), _) => fmt_subsecond(output, time, modifier)?,
+ (OffsetHour(modifier), .., Some(offset)) => fmt_offset_hour(output, offset, modifier)?,
+ (OffsetMinute(modifier), .., Some(offset)) => fmt_offset_minute(output, offset, modifier)?,
+ (OffsetSecond(modifier), .., Some(offset)) => fmt_offset_second(output, offset, modifier)?,
+ (Ignore(_), ..) => 0,
+ (UnixTimestamp(modifier), Some(date), Some(time), Some(offset)) => {
+ fmt_unix_timestamp(output, date, time, offset, modifier)?
+ }
+ (End(modifier::End {}), ..) => 0,
+
+ // This is functionally the same as a wildcard arm, but it will cause an error if a new
+ // component is added. This is to avoid a bug where a new component, the code compiles, and
+ // formatting fails.
+ // Allow unreachable patterns because some branches may be fully matched above.
+ #[allow(unreachable_patterns)]
+ (
+ Day(_) | Month(_) | Ordinal(_) | Weekday(_) | WeekNumber(_) | Year(_) | Hour(_)
+ | Minute(_) | Period(_) | Second(_) | Subsecond(_) | OffsetHour(_) | OffsetMinute(_)
+ | OffsetSecond(_) | Ignore(_) | UnixTimestamp(_) | End(_),
+ ..,
+ ) => return Err(error::Format::InsufficientTypeInformation),
+ })
+}
+
+/// Format the day into the designated output.
+fn fmt_day(
+ output: &mut (impl io::Write + ?Sized),
+ date: Date,
+ modifier::Day { padding }: modifier::Day,
+) -> Result<usize, io::Error> {
+ format_number::<2>(output, date.day(), padding)
+}
+
+/// Format the month into the designated output.
+fn fmt_month(
+ output: &mut (impl io::Write + ?Sized),
+ date: Date,
+ modifier::Month {
+ padding,
+ repr,
+ case_sensitive: _, // no effect on formatting
+ }: modifier::Month,
+) -> Result<usize, io::Error> {
+ match repr {
+ modifier::MonthRepr::Numerical => {
+ format_number::<2>(output, u8::from(date.month()), padding)
+ }
+ modifier::MonthRepr::Long => write(
+ output,
+ MONTH_NAMES[u8::from(date.month()).extend::<usize>() - 1],
+ ),
+ modifier::MonthRepr::Short => write(
+ output,
+ &MONTH_NAMES[u8::from(date.month()).extend::<usize>() - 1][..3],
+ ),
+ }
+}
+
+/// Format the ordinal into the designated output.
+fn fmt_ordinal(
+ output: &mut (impl io::Write + ?Sized),
+ date: Date,
+ modifier::Ordinal { padding }: modifier::Ordinal,
+) -> Result<usize, io::Error> {
+ format_number::<3>(output, date.ordinal(), padding)
+}
+
+/// Format the weekday into the designated output.
+fn fmt_weekday(
+ output: &mut (impl io::Write + ?Sized),
+ date: Date,
+ modifier::Weekday {
+ repr,
+ one_indexed,
+ case_sensitive: _, // no effect on formatting
+ }: modifier::Weekday,
+) -> Result<usize, io::Error> {
+ match repr {
+ modifier::WeekdayRepr::Short => write(
+ output,
+ &WEEKDAY_NAMES[date.weekday().number_days_from_monday().extend::<usize>()][..3],
+ ),
+ modifier::WeekdayRepr::Long => write(
+ output,
+ WEEKDAY_NAMES[date.weekday().number_days_from_monday().extend::<usize>()],
+ ),
+ modifier::WeekdayRepr::Sunday => format_number::<1>(
+ output,
+ date.weekday().number_days_from_sunday() + u8::from(one_indexed),
+ modifier::Padding::None,
+ ),
+ modifier::WeekdayRepr::Monday => format_number::<1>(
+ output,
+ date.weekday().number_days_from_monday() + u8::from(one_indexed),
+ modifier::Padding::None,
+ ),
+ }
+}
+
+/// Format the week number into the designated output.
+fn fmt_week_number(
+ output: &mut (impl io::Write + ?Sized),
+ date: Date,
+ modifier::WeekNumber { padding, repr }: modifier::WeekNumber,
+) -> Result<usize, io::Error> {
+ format_number::<2>(
+ output,
+ match repr {
+ modifier::WeekNumberRepr::Iso => date.iso_week(),
+ modifier::WeekNumberRepr::Sunday => date.sunday_based_week(),
+ modifier::WeekNumberRepr::Monday => date.monday_based_week(),
+ },
+ padding,
+ )
+}
+
+/// Format the year into the designated output.
+fn fmt_year(
+ output: &mut (impl io::Write + ?Sized),
+ date: Date,
+ modifier::Year {
+ padding,
+ repr,
+ range,
+ iso_week_based,
+ sign_is_mandatory,
+ }: modifier::Year,
+) -> Result<usize, error::Format> {
+ let full_year = if iso_week_based {
+ date.iso_year_week().0
+ } else {
+ date.year()
+ };
+ let value = match repr {
+ modifier::YearRepr::Full => full_year,
+ modifier::YearRepr::Century => full_year / 100,
+ modifier::YearRepr::LastTwo => (full_year % 100).abs(),
+ };
+ let format_number = if cfg!(feature = "large-dates") && range == modifier::YearRange::Extended {
+ match repr {
+ modifier::YearRepr::Full if value.abs() >= 100_000 => format_number::<6>,
+ modifier::YearRepr::Full if value.abs() >= 10_000 => format_number::<5>,
+ modifier::YearRepr::Full => format_number::<4>,
+ modifier::YearRepr::Century if value.abs() >= 1_000 => format_number::<4>,
+ modifier::YearRepr::Century if value.abs() >= 100 => format_number::<3>,
+ modifier::YearRepr::Century => format_number::<2>,
+ modifier::YearRepr::LastTwo => format_number::<2>,
+ }
+ } else {
+ match repr {
+ modifier::YearRepr::Full | modifier::YearRepr::Century if full_year.abs() >= 10_000 => {
+ return Err(error::ComponentRange {
+ name: "year",
+ minimum: -9999,
+ maximum: 9999,
+ value: full_year.extend(),
+ conditional_message: Some("when `range:standard` is used"),
+ }
+ .into());
+ }
+ _ => {}
+ }
+ match repr {
+ modifier::YearRepr::Full => format_number::<4>,
+ modifier::YearRepr::Century => format_number::<2>,
+ modifier::YearRepr::LastTwo => format_number::<2>,
+ }
+ };
+ let mut bytes = 0;
+ if repr != modifier::YearRepr::LastTwo {
+ if full_year < 0 {
+ bytes += write(output, b"-")?;
+ } else if sign_is_mandatory || cfg!(feature = "large-dates") && full_year >= 10_000 {
+ bytes += write(output, b"+")?;
+ }
+ }
+ bytes += format_number(output, value.unsigned_abs(), padding)?;
+ Ok(bytes)
+}
+
+/// Format the hour into the designated output.
+fn fmt_hour(
+ output: &mut (impl io::Write + ?Sized),
+ time: Time,
+ modifier::Hour {
+ padding,
+ is_12_hour_clock,
+ }: modifier::Hour,
+) -> Result<usize, io::Error> {
+ let value = match (time.hour(), is_12_hour_clock) {
+ (hour, false) => hour,
+ (0 | 12, true) => 12,
+ (hour, true) if hour < 12 => hour,
+ (hour, true) => hour - 12,
+ };
+ format_number::<2>(output, value, padding)
+}
+
+/// Format the minute into the designated output.
+fn fmt_minute(
+ output: &mut (impl io::Write + ?Sized),
+ time: Time,
+ modifier::Minute { padding }: modifier::Minute,
+) -> Result<usize, io::Error> {
+ format_number::<2>(output, time.minute(), padding)
+}
+
+/// Format the period into the designated output.
+fn fmt_period(
+ output: &mut (impl io::Write + ?Sized),
+ time: Time,
+ modifier::Period {
+ is_uppercase,
+ case_sensitive: _, // no effect on formatting
+ }: modifier::Period,
+) -> Result<usize, io::Error> {
+ match (time.hour() >= 12, is_uppercase) {
+ (false, false) => write(output, b"am"),
+ (false, true) => write(output, b"AM"),
+ (true, false) => write(output, b"pm"),
+ (true, true) => write(output, b"PM"),
+ }
+}
+
+/// Format the second into the designated output.
+fn fmt_second(
+ output: &mut (impl io::Write + ?Sized),
+ time: Time,
+ modifier::Second { padding }: modifier::Second,
+) -> Result<usize, io::Error> {
+ format_number::<2>(output, time.second(), padding)
+}
+
+/// Format the subsecond into the designated output.
+fn fmt_subsecond(
+ output: &mut (impl io::Write + ?Sized),
+ time: Time,
+ modifier::Subsecond { digits }: modifier::Subsecond,
+) -> Result<usize, io::Error> {
+ use modifier::SubsecondDigits::*;
+ let nanos = time.nanosecond();
+
+ if digits == Nine || (digits == OneOrMore && nanos % 10 != 0) {
+ format_number_pad_zero::<9>(output, nanos)
+ } else if digits == Eight || (digits == OneOrMore && (nanos / 10) % 10 != 0) {
+ format_number_pad_zero::<8>(output, nanos / 10)
+ } else if digits == Seven || (digits == OneOrMore && (nanos / 100) % 10 != 0) {
+ format_number_pad_zero::<7>(output, nanos / 100)
+ } else if digits == Six || (digits == OneOrMore && (nanos / 1_000) % 10 != 0) {
+ format_number_pad_zero::<6>(output, nanos / 1_000)
+ } else if digits == Five || (digits == OneOrMore && (nanos / 10_000) % 10 != 0) {
+ format_number_pad_zero::<5>(output, nanos / 10_000)
+ } else if digits == Four || (digits == OneOrMore && (nanos / 100_000) % 10 != 0) {
+ format_number_pad_zero::<4>(output, nanos / 100_000)
+ } else if digits == Three || (digits == OneOrMore && (nanos / 1_000_000) % 10 != 0) {
+ format_number_pad_zero::<3>(output, nanos / 1_000_000)
+ } else if digits == Two || (digits == OneOrMore && (nanos / 10_000_000) % 10 != 0) {
+ format_number_pad_zero::<2>(output, nanos / 10_000_000)
+ } else {
+ format_number_pad_zero::<1>(output, nanos / 100_000_000)
+ }
+}
+
+/// Format the offset hour into the designated output.
+fn fmt_offset_hour(
+ output: &mut (impl io::Write + ?Sized),
+ offset: UtcOffset,
+ modifier::OffsetHour {
+ padding,
+ sign_is_mandatory,
+ }: modifier::OffsetHour,
+) -> Result<usize, io::Error> {
+ let mut bytes = 0;
+ if offset.is_negative() {
+ bytes += write(output, b"-")?;
+ } else if sign_is_mandatory {
+ bytes += write(output, b"+")?;
+ }
+ bytes += format_number::<2>(output, offset.whole_hours().unsigned_abs(), padding)?;
+ Ok(bytes)
+}
+
+/// Format the offset minute into the designated output.
+fn fmt_offset_minute(
+ output: &mut (impl io::Write + ?Sized),
+ offset: UtcOffset,
+ modifier::OffsetMinute { padding }: modifier::OffsetMinute,
+) -> Result<usize, io::Error> {
+ format_number::<2>(output, offset.minutes_past_hour().unsigned_abs(), padding)
+}
+
+/// Format the offset second into the designated output.
+fn fmt_offset_second(
+ output: &mut (impl io::Write + ?Sized),
+ offset: UtcOffset,
+ modifier::OffsetSecond { padding }: modifier::OffsetSecond,
+) -> Result<usize, io::Error> {
+ format_number::<2>(output, offset.seconds_past_minute().unsigned_abs(), padding)
+}
+
+/// Format the Unix timestamp into the designated output.
+fn fmt_unix_timestamp(
+ output: &mut (impl io::Write + ?Sized),
+ date: Date,
+ time: Time,
+ offset: UtcOffset,
+ modifier::UnixTimestamp {
+ precision,
+ sign_is_mandatory,
+ }: modifier::UnixTimestamp,
+) -> Result<usize, io::Error> {
+ let date_time = OffsetDateTime::new_in_offset(date, time, offset).to_offset(UtcOffset::UTC);
+
+ if date_time < OffsetDateTime::UNIX_EPOCH {
+ write(output, b"-")?;
+ } else if sign_is_mandatory {
+ write(output, b"+")?;
+ }
+
+ match precision {
+ modifier::UnixTimestampPrecision::Second => {
+ format_number_pad_none(output, date_time.unix_timestamp().unsigned_abs())
+ }
+ modifier::UnixTimestampPrecision::Millisecond => format_number_pad_none(
+ output,
+ (date_time.unix_timestamp_nanos()
+ / Nanosecond::per(Millisecond).cast_signed().extend::<i128>())
+ .unsigned_abs(),
+ ),
+ modifier::UnixTimestampPrecision::Microsecond => format_number_pad_none(
+ output,
+ (date_time.unix_timestamp_nanos()
+ / Nanosecond::per(Microsecond).cast_signed().extend::<i128>())
+ .unsigned_abs(),
+ ),
+ modifier::UnixTimestampPrecision::Nanosecond => {
+ format_number_pad_none(output, date_time.unix_timestamp_nanos().unsigned_abs())
+ }
+ }
+}
diff --git a/vendor/time/src/hint.rs b/vendor/time/src/hint.rs
new file mode 100644
index 00000000..ded72d4c
--- /dev/null
+++ b/vendor/time/src/hint.rs
@@ -0,0 +1,26 @@
+//! Hints to the compiler that affects how code should be emitted or optimized.
+
+#![allow(dead_code)] // may be used in the future and has minimal overhead
+
+/// Indicate that a given branch is **not** likely to be taken, relatively speaking.
+#[inline(always)]
+#[cold]
+pub(crate) const fn cold_path() {}
+
+/// Indicate that a given condition is likely to be true.
+#[inline(always)]
+pub(crate) const fn likely(b: bool) -> bool {
+ if !b {
+ cold_path();
+ }
+ b
+}
+
+/// Indicate that a given condition is likely to be false.
+#[inline(always)]
+pub(crate) const fn unlikely(b: bool) -> bool {
+ if b {
+ cold_path();
+ }
+ b
+}
diff --git a/vendor/time/src/instant.rs b/vendor/time/src/instant.rs
new file mode 100644
index 00000000..66264007
--- /dev/null
+++ b/vendor/time/src/instant.rs
@@ -0,0 +1,287 @@
+//! The [`Instant`] struct and its associated `impl`s.
+
+#![allow(deprecated)]
+
+use core::borrow::Borrow;
+use core::cmp::{Ord, Ordering, PartialEq, PartialOrd};
+use core::ops::{Add, Sub};
+use core::time::Duration as StdDuration;
+use std::time::Instant as StdInstant;
+
+use crate::internal_macros::{impl_add_assign, impl_sub_assign};
+use crate::Duration;
+
+/// A measurement of a monotonically non-decreasing clock. Opaque and useful only with [`Duration`].
+///
+/// Instants are always guaranteed to be no less than any previously measured instant when created,
+/// and are often useful for tasks such as measuring benchmarks or timing how long an operation
+/// takes.
+///
+/// Note, however, that instants are not guaranteed to be **steady**. In other words, each tick of
+/// the underlying clock may not be the same length (e.g. some seconds may be longer than others).
+/// An instant may jump forwards or experience time dilation (slow down or speed up), but it will
+/// never go backwards.
+///
+/// Instants are opaque types that can only be compared to one another. There is no method to get
+/// "the number of seconds" from an instant. Instead, it only allows measuring the duration between
+/// two instants (or comparing two instants).
+///
+/// This implementation allows for operations with signed [`Duration`]s, but is otherwise identical
+/// to [`std::time::Instant`].
+#[doc(hidden)]
+#[deprecated(
+ since = "0.3.35",
+ note = "import `std::time::Instant` and `time::ext::InstantExt` instead"
+)]
+#[repr(transparent)]
+#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub struct Instant(pub StdInstant);
+
+impl Instant {
+ /// Returns an `Instant` corresponding to "now".
+ ///
+ /// ```rust
+ /// # #![allow(deprecated)]
+ /// # use time::Instant;
+ /// println!("{:?}", Instant::now());
+ /// ```
+ pub fn now() -> Self {
+ Self(StdInstant::now())
+ }
+
+ /// Returns the amount of time elapsed since this instant was created. The duration will always
+ /// be nonnegative if the instant is not synthetically created.
+ ///
+ /// ```rust
+ /// # #![allow(deprecated)]
+ /// # use time::{Instant, ext::{NumericalStdDuration, NumericalDuration}};
+ /// # use std::thread;
+ /// let instant = Instant::now();
+ /// thread::sleep(1.std_milliseconds());
+ /// assert!(instant.elapsed() >= 1.milliseconds());
+ /// ```
+ pub fn elapsed(self) -> Duration {
+ Self::now() - self
+ }
+
+ /// Returns `Some(t)` where `t` is the time `self + duration` if `t` can be represented as
+ /// `Instant` (which means it's inside the bounds of the underlying data structure), `None`
+ /// otherwise.
+ ///
+ /// ```rust
+ /// # #![allow(deprecated)]
+ /// # use time::{Instant, ext::NumericalDuration};
+ /// let now = Instant::now();
+ /// assert_eq!(now.checked_add(5.seconds()), Some(now + 5.seconds()));
+ /// assert_eq!(now.checked_add((-5).seconds()), Some(now + (-5).seconds()));
+ /// ```
+ pub fn checked_add(self, duration: Duration) -> Option<Self> {
+ if duration.is_zero() {
+ Some(self)
+ } else if duration.is_positive() {
+ self.0.checked_add(duration.unsigned_abs()).map(Self)
+ } else {
+ debug_assert!(duration.is_negative());
+ self.0.checked_sub(duration.unsigned_abs()).map(Self)
+ }
+ }
+
+ /// Returns `Some(t)` where `t` is the time `self - duration` if `t` can be represented as
+ /// `Instant` (which means it's inside the bounds of the underlying data structure), `None`
+ /// otherwise.
+ ///
+ /// ```rust
+ /// # #![allow(deprecated)]
+ /// # use time::{Instant, ext::NumericalDuration};
+ /// let now = Instant::now();
+ /// assert_eq!(now.checked_sub(5.seconds()), Some(now - 5.seconds()));
+ /// assert_eq!(now.checked_sub((-5).seconds()), Some(now - (-5).seconds()));
+ /// ```
+ pub fn checked_sub(self, duration: Duration) -> Option<Self> {
+ if duration.is_zero() {
+ Some(self)
+ } else if duration.is_positive() {
+ self.0.checked_sub(duration.unsigned_abs()).map(Self)
+ } else {
+ debug_assert!(duration.is_negative());
+ self.0.checked_add(duration.unsigned_abs()).map(Self)
+ }
+ }
+
+ /// Obtain the inner [`std::time::Instant`].
+ ///
+ /// ```rust
+ /// # #![allow(deprecated)]
+ /// # use time::Instant;
+ /// let now = Instant::now();
+ /// assert_eq!(now.into_inner(), now.0);
+ /// ```
+ pub const fn into_inner(self) -> StdInstant {
+ self.0
+ }
+}
+
+impl From<StdInstant> for Instant {
+ fn from(instant: StdInstant) -> Self {
+ Self(instant)
+ }
+}
+
+impl From<Instant> for StdInstant {
+ fn from(instant: Instant) -> Self {
+ instant.0
+ }
+}
+
+impl Sub for Instant {
+ type Output = Duration;
+
+ /// # Panics
+ ///
+ /// This may panic if an overflow occurs.
+ fn sub(self, other: Self) -> Self::Output {
+ match self.0.cmp(&other.0) {
+ Ordering::Equal => Duration::ZERO,
+ Ordering::Greater => (self.0 - other.0)
+ .try_into()
+ .expect("overflow converting `std::time::Duration` to `time::Duration`"),
+ Ordering::Less => -Duration::try_from(other.0 - self.0)
+ .expect("overflow converting `std::time::Duration` to `time::Duration`"),
+ }
+ }
+}
+
+impl Sub<StdInstant> for Instant {
+ type Output = Duration;
+
+ fn sub(self, other: StdInstant) -> Self::Output {
+ self - Self(other)
+ }
+}
+
+impl Sub<Instant> for StdInstant {
+ type Output = Duration;
+
+ fn sub(self, other: Instant) -> Self::Output {
+ Instant(self) - other
+ }
+}
+
+impl Add<Duration> for Instant {
+ type Output = Self;
+
+ /// # Panics
+ ///
+ /// This function may panic if the resulting point in time cannot be represented by the
+ /// underlying data structure.
+ fn add(self, duration: Duration) -> Self::Output {
+ if duration.is_positive() {
+ Self(self.0 + duration.unsigned_abs())
+ } else if duration.is_negative() {
+ #[allow(clippy::unchecked_duration_subtraction)]
+ Self(self.0 - duration.unsigned_abs())
+ } else {
+ debug_assert!(duration.is_zero());
+ self
+ }
+ }
+}
+
+impl Add<Duration> for StdInstant {
+ type Output = Self;
+
+ fn add(self, duration: Duration) -> Self::Output {
+ (Instant(self) + duration).0
+ }
+}
+
+impl Add<StdDuration> for Instant {
+ type Output = Self;
+
+ fn add(self, duration: StdDuration) -> Self::Output {
+ Self(self.0 + duration)
+ }
+}
+
+impl_add_assign!(Instant: Duration, StdDuration);
+impl_add_assign!(StdInstant: Duration);
+
+impl Sub<Duration> for Instant {
+ type Output = Self;
+
+ /// # Panics
+ ///
+ /// This function may panic if the resulting point in time cannot be represented by the
+ /// underlying data structure.
+ fn sub(self, duration: Duration) -> Self::Output {
+ if duration.is_positive() {
+ #[allow(clippy::unchecked_duration_subtraction)]
+ Self(self.0 - duration.unsigned_abs())
+ } else if duration.is_negative() {
+ Self(self.0 + duration.unsigned_abs())
+ } else {
+ debug_assert!(duration.is_zero());
+ self
+ }
+ }
+}
+
+impl Sub<Duration> for StdInstant {
+ type Output = Self;
+
+ fn sub(self, duration: Duration) -> Self::Output {
+ (Instant(self) - duration).0
+ }
+}
+
+impl Sub<StdDuration> for Instant {
+ type Output = Self;
+
+ /// # Panics
+ ///
+ /// This function may panic if the resulting point in time cannot be represented by the
+ /// underlying data structure.
+ fn sub(self, duration: StdDuration) -> Self::Output {
+ #[allow(clippy::unchecked_duration_subtraction)]
+ Self(self.0 - duration)
+ }
+}
+
+impl_sub_assign!(Instant: Duration, StdDuration);
+impl_sub_assign!(StdInstant: Duration);
+
+impl PartialEq<StdInstant> for Instant {
+ fn eq(&self, rhs: &StdInstant) -> bool {
+ self.0.eq(rhs)
+ }
+}
+
+impl PartialEq<Instant> for StdInstant {
+ fn eq(&self, rhs: &Instant) -> bool {
+ self.eq(&rhs.0)
+ }
+}
+
+impl PartialOrd<StdInstant> for Instant {
+ fn partial_cmp(&self, rhs: &StdInstant) -> Option<Ordering> {
+ self.0.partial_cmp(rhs)
+ }
+}
+
+impl PartialOrd<Instant> for StdInstant {
+ fn partial_cmp(&self, rhs: &Instant) -> Option<Ordering> {
+ self.partial_cmp(&rhs.0)
+ }
+}
+
+impl AsRef<StdInstant> for Instant {
+ fn as_ref(&self) -> &StdInstant {
+ &self.0
+ }
+}
+
+impl Borrow<StdInstant> for Instant {
+ fn borrow(&self) -> &StdInstant {
+ &self.0
+ }
+}
diff --git a/vendor/time/src/internal_macros.rs b/vendor/time/src/internal_macros.rs
new file mode 100644
index 00000000..74205ac4
--- /dev/null
+++ b/vendor/time/src/internal_macros.rs
@@ -0,0 +1,209 @@
+//! Macros for use within the library. They are not publicly available.
+
+/// Helper macro for easily implementing `OpAssign`.
+macro_rules! __impl_assign {
+ ($sym:tt $op:ident $fn:ident $target:ty : $($(#[$attr:meta])* $t:ty),+) => {$(
+ #[allow(unused_qualifications)]
+ $(#[$attr])*
+ impl core::ops::$op<$t> for $target {
+ fn $fn(&mut self, rhs: $t) {
+ *self = *self $sym rhs;
+ }
+ }
+ )+};
+}
+
+/// Implement `AddAssign` for the provided types.
+macro_rules! impl_add_assign {
+ ($target:ty : $($(#[$attr:meta])* $t:ty),+ $(,)?) => {
+ $crate::internal_macros::__impl_assign!(
+ + AddAssign add_assign $target : $($(#[$attr])* $t),+
+ );
+ };
+}
+
+/// Implement `SubAssign` for the provided types.
+macro_rules! impl_sub_assign {
+ ($target:ty : $($(#[$attr:meta])* $t:ty),+ $(,)?) => {
+ $crate::internal_macros::__impl_assign!(
+ - SubAssign sub_assign $target : $($(#[$attr])* $t),+
+ );
+ };
+}
+
+/// Implement `MulAssign` for the provided types.
+macro_rules! impl_mul_assign {
+ ($target:ty : $($(#[$attr:meta])* $t:ty),+ $(,)?) => {
+ $crate::internal_macros::__impl_assign!(
+ * MulAssign mul_assign $target : $($(#[$attr])* $t),+
+ );
+ };
+}
+
+/// Implement `DivAssign` for the provided types.
+macro_rules! impl_div_assign {
+ ($target:ty : $($(#[$attr:meta])* $t:ty),+ $(,)?) => {
+ $crate::internal_macros::__impl_assign!(
+ / DivAssign div_assign $target : $($(#[$attr])* $t),+
+ );
+ };
+}
+
+/// Division of integers, rounding the resulting value towards negative infinity.
+macro_rules! div_floor {
+ ($self:expr, $rhs:expr) => {
+ match ($self, $rhs) {
+ (this, rhs) => {
+ let d = this / rhs;
+ let r = this % rhs;
+
+ // If the remainder is non-zero, we need to subtract one if the
+ // signs of self and rhs differ, as this means we rounded upwards
+ // instead of downwards. We do this branchlessly by creating a mask
+ // which is all-ones iff the signs differ, and 0 otherwise. Then by
+ // adding this mask (which corresponds to the signed value -1), we
+ // get our correction.
+ let correction = (this ^ rhs) >> ($crate::size_of_val(&this) * 8 - 1);
+ if r != 0 {
+ d + correction
+ } else {
+ d
+ }
+ }
+ }
+ };
+}
+
+/// Cascade an out-of-bounds value.
+macro_rules! cascade {
+ (@ordinal ordinal) => {};
+ (@year year) => {};
+
+ // Cascade an out-of-bounds value from "from" to "to".
+ ($from:ident in $min:literal.. $max:expr => $to:tt) => {
+ #[allow(unused_comparisons, unused_assignments)]
+ let min = $min;
+ let max = $max;
+ if $from >= max {
+ $from -= max - min;
+ $to += 1;
+ } else if $from < min {
+ $from += max - min;
+ $to -= 1;
+ }
+ };
+
+ // Special case the ordinal-to-year cascade, as it has different behavior.
+ ($ordinal:ident => $year:ident) => {
+ // We need to actually capture the idents. Without this, macro hygiene causes errors.
+ cascade!(@ordinal $ordinal);
+ cascade!(@year $year);
+ #[allow(unused_assignments)]
+ if $ordinal > crate::util::days_in_year($year) as i16 {
+ $ordinal -= crate::util::days_in_year($year) as i16;
+ $year += 1;
+ } else if $ordinal < 1 {
+ $year -= 1;
+ $ordinal += crate::util::days_in_year($year) as i16;
+ }
+ };
+}
+
+/// Constructs a ranged integer, returning a `ComponentRange` error if the value is out of range.
+macro_rules! ensure_ranged {
+ ($type:ident : $value:ident) => {
+ match $type::new($value) {
+ Some(val) => val,
+ None => {
+ #[allow(trivial_numeric_casts)]
+ return Err(crate::error::ComponentRange {
+ name: stringify!($value),
+ minimum: $type::MIN.get() as i64,
+ maximum: $type::MAX.get() as i64,
+ value: $value as i64,
+ conditional_message: None,
+ });
+ }
+ }
+ };
+
+ ($type:ident : $value:ident $(as $as_type:ident)? * $factor:expr) => {
+ match ($value $(as $as_type)?).checked_mul($factor) {
+ Some(val) => match $type::new(val) {
+ Some(val) => val,
+ None => {
+ #[allow(trivial_numeric_casts)]
+ return Err(crate::error::ComponentRange {
+ name: stringify!($value),
+ minimum: $type::MIN.get() as i64 / $factor as i64,
+ maximum: $type::MAX.get() as i64 / $factor as i64,
+ value: $value as i64,
+ conditional_message: None,
+ });
+ }
+ },
+ None => {
+ return Err(crate::error::ComponentRange {
+ name: stringify!($value),
+ minimum: $type::MIN.get() as i64 / $factor as i64,
+ maximum: $type::MAX.get() as i64 / $factor as i64,
+ value: $value as i64,
+ conditional_message: None,
+ });
+ }
+ }
+ };
+}
+
+/// Try to unwrap an expression, returning if not possible.
+///
+/// This is similar to the `?` operator, but does not perform `.into()`. Because of this, it is
+/// usable in `const` contexts.
+macro_rules! const_try {
+ ($e:expr) => {
+ match $e {
+ Ok(value) => value,
+ Err(error) => return Err(error),
+ }
+ };
+}
+
+/// Try to unwrap an expression, returning if not possible.
+///
+/// This is similar to the `?` operator, but is usable in `const` contexts.
+macro_rules! const_try_opt {
+ ($e:expr) => {
+ match $e {
+ Some(value) => value,
+ None => return None,
+ }
+ };
+}
+
+/// Try to unwrap an expression, panicking if not possible.
+///
+/// This is similar to `$e.expect($message)`, but is usable in `const` contexts.
+macro_rules! expect_opt {
+ ($e:expr, $message:literal) => {
+ match $e {
+ Some(value) => value,
+ None => crate::expect_failed($message),
+ }
+ };
+}
+
+/// `unreachable!()`, but better.
+#[cfg(any(feature = "formatting", feature = "parsing"))]
+macro_rules! bug {
+ () => { compile_error!("provide an error message to help fix a possible bug") };
+ ($descr:literal $($rest:tt)?) => {
+ panic!(concat!("internal error: ", $descr) $($rest)?)
+ }
+}
+
+#[cfg(any(feature = "formatting", feature = "parsing"))]
+pub(crate) use bug;
+pub(crate) use {
+ __impl_assign, cascade, const_try, const_try_opt, div_floor, ensure_ranged, expect_opt,
+ impl_add_assign, impl_div_assign, impl_mul_assign, impl_sub_assign,
+};
diff --git a/vendor/time/src/interop/js_sys_date_offsetdatetime.rs b/vendor/time/src/interop/js_sys_date_offsetdatetime.rs
new file mode 100644
index 00000000..ecbd601e
--- /dev/null
+++ b/vendor/time/src/interop/js_sys_date_offsetdatetime.rs
@@ -0,0 +1,27 @@
+use num_conv::prelude::*;
+
+use crate::convert::*;
+use crate::OffsetDateTime;
+
+impl From<js_sys::Date> for OffsetDateTime {
+ /// # Panics
+ ///
+ /// This may panic if the timestamp can not be represented.
+ fn from(js_date: js_sys::Date) -> Self {
+ // get_time() returns milliseconds
+ let timestamp_nanos = js_date.get_time() as i128
+ * Nanosecond::per(Millisecond).cast_signed().extend::<i128>();
+ Self::from_unix_timestamp_nanos(timestamp_nanos)
+ .expect("invalid timestamp: Timestamp cannot fit in range")
+ }
+}
+
+impl From<OffsetDateTime> for js_sys::Date {
+ fn from(datetime: OffsetDateTime) -> Self {
+ // new Date() takes milliseconds
+ let timestamp = (datetime.unix_timestamp_nanos()
+ / Nanosecond::per(Millisecond).cast_signed().extend::<i128>())
+ as f64;
+ Self::new(&timestamp.into())
+ }
+}
diff --git a/vendor/time/src/interop/js_sys_date_utcdatetime.rs b/vendor/time/src/interop/js_sys_date_utcdatetime.rs
new file mode 100644
index 00000000..e387c684
--- /dev/null
+++ b/vendor/time/src/interop/js_sys_date_utcdatetime.rs
@@ -0,0 +1,26 @@
+use num_conv::prelude::*;
+
+use crate::convert::*;
+use crate::UtcDateTime;
+
+impl From<js_sys::Date> for UtcDateTime {
+ /// # Panics
+ ///
+ /// This may panic if the timestamp can not be represented.
+ fn from(js_date: js_sys::Date) -> Self {
+ // get_time() returns milliseconds
+ let timestamp_nanos = (js_date.get_time() * Nanosecond::per(Millisecond) as f64) as i128;
+ Self::from_unix_timestamp_nanos(timestamp_nanos)
+ .expect("invalid timestamp: Timestamp cannot fit in range")
+ }
+}
+
+impl From<UtcDateTime> for js_sys::Date {
+ fn from(datetime: UtcDateTime) -> Self {
+ // new Date() takes milliseconds
+ let timestamp = (datetime.unix_timestamp_nanos()
+ / Nanosecond::per(Millisecond).cast_signed().extend::<i128>())
+ as f64;
+ Self::new(&timestamp.into())
+ }
+}
diff --git a/vendor/time/src/interop/mod.rs b/vendor/time/src/interop/mod.rs
new file mode 100644
index 00000000..d562663c
--- /dev/null
+++ b/vendor/time/src/interop/mod.rs
@@ -0,0 +1,28 @@
+//! Comparison, arithmetic, and conversion between various types in `time` and the standard library.
+//!
+//! Currently, full interoperability is present between [`OffsetDateTime`](crate::OffsetDateTime),
+//! [`UtcDateTime`](crate::UtcDateTime), and [`SystemTime`](std::time::SystemTime). Partial
+//! interoperability is present with [`js_sys::Date`]. Note that
+//! [`PrimitiveDateTime`](crate::PrimitiveDateTime) is not interoperable with any of these types due
+//! to the lack of an associated UTC offset.
+
+// Module names should have the two types sorted in alphabetical order. This avoids any question
+// of which type should be the "primary" type in the module name.
+
+#[cfg(all(
+ target_family = "wasm",
+ not(any(target_os = "emscripten", target_os = "wasi")),
+ feature = "wasm-bindgen"
+))]
+mod js_sys_date_offsetdatetime;
+#[cfg(all(
+ target_family = "wasm",
+ not(any(target_os = "emscripten", target_os = "wasi")),
+ feature = "wasm-bindgen"
+))]
+mod js_sys_date_utcdatetime;
+#[cfg(feature = "std")]
+mod offsetdatetime_systemtime;
+mod offsetdatetime_utcdatetime;
+#[cfg(feature = "std")]
+mod utcdatetime_systemtime;
diff --git a/vendor/time/src/interop/offsetdatetime_systemtime.rs b/vendor/time/src/interop/offsetdatetime_systemtime.rs
new file mode 100644
index 00000000..21a5d7f1
--- /dev/null
+++ b/vendor/time/src/interop/offsetdatetime_systemtime.rs
@@ -0,0 +1,75 @@
+use core::cmp::Ordering;
+use core::ops::Sub;
+use std::time::SystemTime;
+
+use crate::{Duration, OffsetDateTime};
+
+impl Sub<SystemTime> for OffsetDateTime {
+ type Output = Duration;
+
+ /// # Panics
+ ///
+ /// This may panic if an overflow occurs.
+ fn sub(self, rhs: SystemTime) -> Self::Output {
+ self - Self::from(rhs)
+ }
+}
+
+impl Sub<OffsetDateTime> for SystemTime {
+ type Output = Duration;
+
+ /// # Panics
+ ///
+ /// This may panic if an overflow occurs.
+ fn sub(self, rhs: OffsetDateTime) -> Self::Output {
+ OffsetDateTime::from(self) - rhs
+ }
+}
+
+impl PartialEq<SystemTime> for OffsetDateTime {
+ fn eq(&self, rhs: &SystemTime) -> bool {
+ self == &Self::from(*rhs)
+ }
+}
+
+impl PartialEq<OffsetDateTime> for SystemTime {
+ fn eq(&self, rhs: &OffsetDateTime) -> bool {
+ &OffsetDateTime::from(*self) == rhs
+ }
+}
+
+impl PartialOrd<SystemTime> for OffsetDateTime {
+ fn partial_cmp(&self, other: &SystemTime) -> Option<Ordering> {
+ self.partial_cmp(&Self::from(*other))
+ }
+}
+
+impl PartialOrd<OffsetDateTime> for SystemTime {
+ fn partial_cmp(&self, other: &OffsetDateTime) -> Option<Ordering> {
+ OffsetDateTime::from(*self).partial_cmp(other)
+ }
+}
+
+impl From<SystemTime> for OffsetDateTime {
+ fn from(system_time: SystemTime) -> Self {
+ match system_time.duration_since(SystemTime::UNIX_EPOCH) {
+ Ok(duration) => Self::UNIX_EPOCH + duration,
+ Err(err) => Self::UNIX_EPOCH - err.duration(),
+ }
+ }
+}
+
+impl From<OffsetDateTime> for SystemTime {
+ fn from(datetime: OffsetDateTime) -> Self {
+ let duration = datetime - OffsetDateTime::UNIX_EPOCH;
+
+ if duration.is_zero() {
+ Self::UNIX_EPOCH
+ } else if duration.is_positive() {
+ Self::UNIX_EPOCH + duration.unsigned_abs()
+ } else {
+ debug_assert!(duration.is_negative());
+ Self::UNIX_EPOCH - duration.unsigned_abs()
+ }
+ }
+}
diff --git a/vendor/time/src/interop/offsetdatetime_utcdatetime.rs b/vendor/time/src/interop/offsetdatetime_utcdatetime.rs
new file mode 100644
index 00000000..34a4887d
--- /dev/null
+++ b/vendor/time/src/interop/offsetdatetime_utcdatetime.rs
@@ -0,0 +1,68 @@
+use core::cmp::Ordering;
+use core::ops::Sub;
+
+use crate::{Duration, OffsetDateTime, UtcDateTime};
+
+impl Sub<OffsetDateTime> for UtcDateTime {
+ type Output = Duration;
+
+ /// # Panics
+ ///
+ /// This may panic if an overflow occurs.
+ fn sub(self, rhs: OffsetDateTime) -> Self::Output {
+ OffsetDateTime::from(self) - rhs
+ }
+}
+
+impl Sub<UtcDateTime> for OffsetDateTime {
+ type Output = Duration;
+
+ /// # Panics
+ ///
+ /// This may panic if an overflow occurs.
+ fn sub(self, rhs: UtcDateTime) -> Self::Output {
+ self - Self::from(rhs)
+ }
+}
+
+impl PartialEq<OffsetDateTime> for UtcDateTime {
+ fn eq(&self, other: &OffsetDateTime) -> bool {
+ OffsetDateTime::from(*self) == *other
+ }
+}
+
+impl PartialEq<UtcDateTime> for OffsetDateTime {
+ fn eq(&self, other: &UtcDateTime) -> bool {
+ *self == Self::from(*other)
+ }
+}
+
+impl PartialOrd<OffsetDateTime> for UtcDateTime {
+ fn partial_cmp(&self, other: &OffsetDateTime) -> Option<Ordering> {
+ OffsetDateTime::from(*self).partial_cmp(other)
+ }
+}
+
+impl PartialOrd<UtcDateTime> for OffsetDateTime {
+ fn partial_cmp(&self, other: &UtcDateTime) -> Option<Ordering> {
+ self.partial_cmp(&Self::from(*other))
+ }
+}
+
+impl From<OffsetDateTime> for UtcDateTime {
+ /// # Panics
+ ///
+ /// This may panic if an overflow occurs.
+ fn from(datetime: OffsetDateTime) -> Self {
+ datetime.to_utc()
+ }
+}
+
+impl From<UtcDateTime> for OffsetDateTime {
+ /// # Panics
+ ///
+ /// This may panic if an overflow occurs.
+ fn from(datetime: UtcDateTime) -> Self {
+ datetime.as_primitive().assume_utc()
+ }
+}
diff --git a/vendor/time/src/interop/utcdatetime_systemtime.rs b/vendor/time/src/interop/utcdatetime_systemtime.rs
new file mode 100644
index 00000000..7cfb44e1
--- /dev/null
+++ b/vendor/time/src/interop/utcdatetime_systemtime.rs
@@ -0,0 +1,75 @@
+use core::cmp::Ordering;
+use core::ops::Sub;
+use std::time::SystemTime;
+
+use crate::{Duration, UtcDateTime};
+
+impl Sub<SystemTime> for UtcDateTime {
+ type Output = Duration;
+
+ /// # Panics
+ ///
+ /// This may panic if an overflow occurs.
+ fn sub(self, rhs: SystemTime) -> Self::Output {
+ self - Self::from(rhs)
+ }
+}
+
+impl Sub<UtcDateTime> for SystemTime {
+ type Output = Duration;
+
+ /// # Panics
+ ///
+ /// This may panic if an overflow occurs.
+ fn sub(self, rhs: UtcDateTime) -> Self::Output {
+ UtcDateTime::from(self) - rhs
+ }
+}
+
+impl PartialEq<SystemTime> for UtcDateTime {
+ fn eq(&self, rhs: &SystemTime) -> bool {
+ self == &Self::from(*rhs)
+ }
+}
+
+impl PartialEq<UtcDateTime> for SystemTime {
+ fn eq(&self, rhs: &UtcDateTime) -> bool {
+ &UtcDateTime::from(*self) == rhs
+ }
+}
+
+impl PartialOrd<SystemTime> for UtcDateTime {
+ fn partial_cmp(&self, other: &SystemTime) -> Option<Ordering> {
+ self.partial_cmp(&Self::from(*other))
+ }
+}
+
+impl PartialOrd<UtcDateTime> for SystemTime {
+ fn partial_cmp(&self, other: &UtcDateTime) -> Option<Ordering> {
+ UtcDateTime::from(*self).partial_cmp(other)
+ }
+}
+
+impl From<SystemTime> for UtcDateTime {
+ fn from(system_time: SystemTime) -> Self {
+ match system_time.duration_since(SystemTime::UNIX_EPOCH) {
+ Ok(duration) => Self::UNIX_EPOCH + duration,
+ Err(err) => Self::UNIX_EPOCH - err.duration(),
+ }
+ }
+}
+
+impl From<UtcDateTime> for SystemTime {
+ fn from(datetime: UtcDateTime) -> Self {
+ let duration = datetime - UtcDateTime::UNIX_EPOCH;
+
+ if duration.is_zero() {
+ Self::UNIX_EPOCH
+ } else if duration.is_positive() {
+ Self::UNIX_EPOCH + duration.unsigned_abs()
+ } else {
+ debug_assert!(duration.is_negative());
+ Self::UNIX_EPOCH - duration.unsigned_abs()
+ }
+ }
+}
diff --git a/vendor/time/src/lib.rs b/vendor/time/src/lib.rs
new file mode 100644
index 00000000..d8765d17
--- /dev/null
+++ b/vendor/time/src/lib.rs
@@ -0,0 +1,153 @@
+//! # Feature flags
+//!
+//! This crate exposes a number of features. These can be enabled or disabled as shown
+//! [in Cargo's documentation](https://doc.rust-lang.org/cargo/reference/features.html). Features
+//! are _disabled_ by default unless otherwise noted.
+//!
+//! Reliance on a given feature is always indicated alongside the item definition.
+//!
+//! - `std` (_enabled by default, implicitly enables `alloc`_)
+//!
+//! This enables a number of features that depend on the standard library.
+//!
+//! - `alloc` (_enabled by default via `std`_)
+//!
+//! Enables a number of features that require the ability to dynamically allocate memory.
+//!
+//! - `macros`
+//!
+//! Enables macros that provide compile-time verification of values and intuitive syntax.
+//!
+//! - `formatting` (_implicitly enables `std`_)
+//!
+//! Enables formatting of most structs.
+//!
+//! - `parsing`
+//!
+//! Enables parsing of most structs.
+//!
+//! - `local-offset` (_implicitly enables `std`_)
+//!
+//! This feature enables a number of methods that allow obtaining the system's UTC offset.
+//!
+//! - `large-dates`
+//!
+//! By default, only years within the ±9999 range (inclusive) are supported. If you need support
+//! for years outside this range, consider enabling this feature; the supported range will be
+//! increased to ±999,999.
+//!
+//! Note that enabling this feature has some costs, as it means forgoing some optimizations.
+//! Ambiguities may be introduced when parsing that would not otherwise exist.
+//!
+//! - `serde`
+//!
+//! Enables [serde](https://docs.rs/serde) support for all types.
+//!
+//! - `serde-human-readable` (_implicitly enables `serde`, `formatting`, and `parsing`_)
+//!
+//! Allows serde representations to use a human-readable format. This is determined by the
+//! serializer, not the user. If this feature is not enabled or if the serializer requests a
+//! non-human-readable format, a format optimized for binary representation will be used.
+//!
+//! Libraries should never enable this feature, as the decision of what format to use should be up
+//! to the user.
+//!
+//! - `rand`
+//!
+//! Enables [rand](https://docs.rs/rand) support for all types.
+//!
+//! - `quickcheck` (_implicitly enables `alloc`_)
+//!
+//! Enables [quickcheck](https://docs.rs/quickcheck) support for all types.
+//!
+//! - `wasm-bindgen`
+//!
+//! Enables [wasm-bindgen](https://github.com/rustwasm/wasm-bindgen) support for converting
+//! [JavaScript dates](https://rustwasm.github.io/wasm-bindgen/api/js_sys/struct.Date.html), as
+//! well as obtaining the UTC offset from JavaScript.
+
+#![doc(html_playground_url = "https://play.rust-lang.org")]
+#![cfg_attr(docsrs, feature(doc_auto_cfg, doc_notable_trait))]
+#![no_std]
+#![doc(html_favicon_url = "https://avatars0.githubusercontent.com/u/55999857")]
+#![doc(html_logo_url = "https://avatars0.githubusercontent.com/u/55999857")]
+#![doc(test(attr(deny(warnings))))]
+
+#[allow(unused_extern_crates)]
+#[cfg(feature = "alloc")]
+extern crate alloc;
+
+#[cfg(feature = "std")]
+extern crate std;
+
+mod date;
+mod duration;
+pub mod error;
+pub mod ext;
+#[cfg(any(feature = "formatting", feature = "parsing"))]
+pub mod format_description;
+#[cfg(feature = "formatting")]
+pub mod formatting;
+mod hint;
+#[cfg(feature = "std")]
+mod instant;
+mod internal_macros;
+mod interop;
+#[cfg(feature = "macros")]
+pub mod macros;
+mod month;
+mod offset_date_time;
+#[cfg(feature = "parsing")]
+pub mod parsing;
+mod primitive_date_time;
+#[cfg(feature = "quickcheck")]
+mod quickcheck;
+#[cfg(feature = "rand")]
+mod rand;
+#[cfg(feature = "serde")]
+pub mod serde;
+mod sys;
+#[cfg(test)]
+mod tests;
+mod time;
+mod utc_date_time;
+mod utc_offset;
+pub mod util;
+mod weekday;
+
+pub use time_core::convert;
+
+pub use crate::date::Date;
+pub use crate::duration::Duration;
+pub use crate::error::Error;
+#[doc(hidden)]
+#[cfg(feature = "std")]
+#[allow(deprecated)]
+pub use crate::instant::Instant;
+pub use crate::month::Month;
+pub use crate::offset_date_time::OffsetDateTime;
+pub use crate::primitive_date_time::PrimitiveDateTime;
+pub use crate::time::Time;
+pub use crate::utc_date_time::UtcDateTime;
+pub use crate::utc_offset::UtcOffset;
+pub use crate::weekday::Weekday;
+
+/// An alias for [`std::result::Result`] with a generic error from the time crate.
+pub type Result<T> = core::result::Result<T, Error>;
+
+/// This is a separate function to reduce the code size of `expect_opt!`.
+#[inline(never)]
+#[cold]
+#[track_caller]
+const fn expect_failed(message: &str) -> ! {
+ panic!("{}", message)
+}
+
+/// Returns the size of the pointed-to value in bytes.
+///
+/// This is a `const fn` in the standard library starting in Rust 1.85. When MSRV is at least that,
+/// this can be removed.
+#[allow(unused_qualifications)] // added to prelude after MSRV
+const fn size_of_val<T>(_: &T) -> usize {
+ core::mem::size_of::<T>()
+}
diff --git a/vendor/time/src/macros.rs b/vendor/time/src/macros.rs
new file mode 100644
index 00000000..e9ca572e
--- /dev/null
+++ b/vendor/time/src/macros.rs
@@ -0,0 +1,149 @@
+//! Macros to construct statically known values.
+
+/// Construct a [`Date`](crate::Date) with a statically known value.
+///
+/// The resulting expression can be used in `const` or `static` declarations.
+///
+/// Three formats are supported: year-week-weekday, year-ordinal, and year-month-day.
+///
+/// ```rust
+/// # use time::{Date, Weekday::*, Month, macros::date};
+/// assert_eq!(
+/// date!(2020 - W 01 - 3),
+/// Date::from_iso_week_date(2020, 1, Wednesday)?
+/// );
+/// assert_eq!(date!(2020-001), Date::from_ordinal_date(2020, 1)?);
+/// assert_eq!(
+/// date!(2020-01-01),
+/// Date::from_calendar_date(2020, Month::January, 1)?
+/// );
+/// # Ok::<_, time::Error>(())
+/// ```
+pub use time_macros::date;
+/// Construct a [`PrimitiveDateTime`] or [`OffsetDateTime`] with a statically known value.
+///
+/// The resulting expression can be used in `const` or `static` declarations.
+///
+/// The syntax accepted by this macro is the same as [`date!`] and [`time!`], with an optional
+/// [`offset!`], all space-separated. If an [`offset!`] is provided, the resulting value will
+/// be an [`OffsetDateTime`]; otherwise it will be a [`PrimitiveDateTime`].
+///
+/// [`OffsetDateTime`]: crate::OffsetDateTime
+/// [`PrimitiveDateTime`]: crate::PrimitiveDateTime
+///
+/// ```rust
+/// # use time::{Date, Month, macros::datetime, UtcOffset};
+/// assert_eq!(
+/// datetime!(2020-01-01 0:00),
+/// Date::from_calendar_date(2020, Month::January, 1)?.midnight()
+/// );
+/// assert_eq!(
+/// datetime!(2020-01-01 0:00 UTC),
+/// Date::from_calendar_date(2020, Month::January, 1)?.midnight().assume_utc()
+/// );
+/// assert_eq!(
+/// datetime!(2020-01-01 0:00 -1),
+/// Date::from_calendar_date(2020, Month::January, 1)?.midnight()
+/// .assume_offset(UtcOffset::from_hms(-1, 0, 0)?)
+/// );
+/// # Ok::<_, time::Error>(())
+/// ```
+pub use time_macros::datetime;
+/// Equivalent of performing [`format_description::parse()`] at compile time.
+///
+/// Using the macro instead of the function results in a static slice rather than a
+/// [`Vec`](alloc::vec::Vec), such that it can be used in `#![no_alloc]` situations.
+///
+/// The resulting expression can be used in `const` or `static` declarations, and implements
+/// the sealed traits required for both formatting and parsing.
+#[cfg_attr(feature = "alloc", doc = "```rust")]
+#[cfg_attr(not(feature = "alloc"), doc = "```rust,ignore")]
+/// # use time::{format_description, macros::format_description};
+/// assert_eq!(
+/// format_description!("[hour]:[minute]:[second]"),
+/// format_description::parse("[hour]:[minute]:[second]")?
+/// );
+/// # Ok::<_, time::Error>(())
+/// ```
+///
+/// The syntax accepted by this macro is the same as [`format_description::parse()`], which can
+/// be found in [the book](https://time-rs.github.io/book/api/format-description.html).
+///
+/// [`format_description::parse()`]: crate::format_description::parse()
+#[cfg(any(feature = "formatting", feature = "parsing"))]
+pub use time_macros::format_description;
+/// Construct a [`UtcOffset`](crate::UtcOffset) with a statically known value.
+///
+/// The resulting expression can be used in `const` or `static` declarations.
+///
+/// A sign and the hour must be provided; minutes and seconds default to zero. `UTC` (both
+/// uppercase and lowercase) is also allowed.
+///
+/// ```rust
+/// # use time::{UtcOffset, macros::offset};
+/// assert_eq!(offset!(UTC), UtcOffset::from_hms(0, 0, 0)?);
+/// assert_eq!(offset!(utc), UtcOffset::from_hms(0, 0, 0)?);
+/// assert_eq!(offset!(+0), UtcOffset::from_hms(0, 0, 0)?);
+/// assert_eq!(offset!(+1), UtcOffset::from_hms(1, 0, 0)?);
+/// assert_eq!(offset!(-1), UtcOffset::from_hms(-1, 0, 0)?);
+/// assert_eq!(offset!(+1:30), UtcOffset::from_hms(1, 30, 0)?);
+/// assert_eq!(offset!(-1:30), UtcOffset::from_hms(-1, -30, 0)?);
+/// assert_eq!(offset!(+1:30:59), UtcOffset::from_hms(1, 30, 59)?);
+/// assert_eq!(offset!(-1:30:59), UtcOffset::from_hms(-1, -30, -59)?);
+/// assert_eq!(offset!(+23:59:59), UtcOffset::from_hms(23, 59, 59)?);
+/// assert_eq!(offset!(-23:59:59), UtcOffset::from_hms(-23, -59, -59)?);
+/// # Ok::<_, time::Error>(())
+/// ```
+pub use time_macros::offset;
+/// Construct a [`Time`](crate::Time) with a statically known value.
+///
+/// The resulting expression can be used in `const` or `static` declarations.
+///
+/// Hours and minutes must be provided, while seconds defaults to zero. AM/PM is allowed
+/// (either uppercase or lowercase). Any number of subsecond digits may be provided (though any
+/// past nine will be discarded).
+///
+/// All components are validated at compile-time. An error will be raised if any value is
+/// invalid.
+///
+/// ```rust
+/// # use time::{Time, macros::time};
+/// assert_eq!(time!(0:00), Time::from_hms(0, 0, 0)?);
+/// assert_eq!(time!(1:02:03), Time::from_hms(1, 2, 3)?);
+/// assert_eq!(
+/// time!(1:02:03.004_005_006),
+/// Time::from_hms_nano(1, 2, 3, 4_005_006)?
+/// );
+/// assert_eq!(time!(12:00 am), Time::from_hms(0, 0, 0)?);
+/// assert_eq!(time!(1:02:03 am), Time::from_hms(1, 2, 3)?);
+/// assert_eq!(
+/// time!(1:02:03.004_005_006 am),
+/// Time::from_hms_nano(1, 2, 3, 4_005_006)?
+/// );
+/// assert_eq!(time!(12 pm), Time::from_hms(12, 0, 0)?);
+/// assert_eq!(time!(12:00 pm), Time::from_hms(12, 0, 0)?);
+/// assert_eq!(time!(1:02:03 pm), Time::from_hms(13, 2, 3)?);
+/// assert_eq!(
+/// time!(1:02:03.004_005_006 pm),
+/// Time::from_hms_nano(13, 2, 3, 4_005_006)?
+/// );
+/// # Ok::<_, time::Error>(())
+/// ```
+pub use time_macros::time;
+/// Construct a [`UtcDateTime`] with a statically known value.
+///
+/// The resulting expression can be used in `const` or `static` declarations.
+///
+/// The syntax accepted by this macro is the same as a space-separated [`date!`] and [`time!`].
+///
+/// [`UtcDateTime`]: crate::UtcDateTime
+///
+/// ```rust
+/// # use time::{Date, Month, macros::utc_datetime};
+/// assert_eq!(
+/// utc_datetime!(2020-01-01 0:00),
+/// Date::from_calendar_date(2020, Month::January, 1)?.midnight().as_utc()
+/// );
+/// # Ok::<_, time::Error>(())
+/// ```
+pub use time_macros::utc_datetime;
diff --git a/vendor/time/src/month.rs b/vendor/time/src/month.rs
new file mode 100644
index 00000000..18bb091c
--- /dev/null
+++ b/vendor/time/src/month.rs
@@ -0,0 +1,273 @@
+//! The `Month` enum and its associated `impl`s.
+
+use core::fmt;
+use core::num::NonZeroU8;
+use core::str::FromStr;
+
+use powerfmt::smart_display::{FormatterOptions, Metadata, SmartDisplay};
+
+use self::Month::*;
+use crate::{error, util};
+
+/// Months of the year.
+#[repr(u8)]
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub enum Month {
+ #[allow(missing_docs)]
+ January = 1,
+ #[allow(missing_docs)]
+ February = 2,
+ #[allow(missing_docs)]
+ March = 3,
+ #[allow(missing_docs)]
+ April = 4,
+ #[allow(missing_docs)]
+ May = 5,
+ #[allow(missing_docs)]
+ June = 6,
+ #[allow(missing_docs)]
+ July = 7,
+ #[allow(missing_docs)]
+ August = 8,
+ #[allow(missing_docs)]
+ September = 9,
+ #[allow(missing_docs)]
+ October = 10,
+ #[allow(missing_docs)]
+ November = 11,
+ #[allow(missing_docs)]
+ December = 12,
+}
+
+impl Month {
+ /// Create a `Month` from its numerical value.
+ pub(crate) const fn from_number(n: NonZeroU8) -> Result<Self, error::ComponentRange> {
+ match n.get() {
+ 1 => Ok(January),
+ 2 => Ok(February),
+ 3 => Ok(March),
+ 4 => Ok(April),
+ 5 => Ok(May),
+ 6 => Ok(June),
+ 7 => Ok(July),
+ 8 => Ok(August),
+ 9 => Ok(September),
+ 10 => Ok(October),
+ 11 => Ok(November),
+ 12 => Ok(December),
+ n => Err(error::ComponentRange {
+ name: "month",
+ minimum: 1,
+ maximum: 12,
+ value: n as i64,
+ conditional_message: None,
+ }),
+ }
+ }
+
+ /// Get the number of days in the month of a given year.
+ ///
+ /// ```rust
+ /// # use time::Month;
+ /// assert_eq!(Month::February.length(2020), 29);
+ /// ```
+ pub const fn length(self, year: i32) -> u8 {
+ util::days_in_month(self, year)
+ }
+
+ /// Get the previous month.
+ ///
+ /// ```rust
+ /// # use time::Month;
+ /// assert_eq!(Month::January.previous(), Month::December);
+ /// ```
+ pub const fn previous(self) -> Self {
+ match self {
+ January => December,
+ February => January,
+ March => February,
+ April => March,
+ May => April,
+ June => May,
+ July => June,
+ August => July,
+ September => August,
+ October => September,
+ November => October,
+ December => November,
+ }
+ }
+
+ /// Get the next month.
+ ///
+ /// ```rust
+ /// # use time::Month;
+ /// assert_eq!(Month::January.next(), Month::February);
+ /// ```
+ pub const fn next(self) -> Self {
+ match self {
+ January => February,
+ February => March,
+ March => April,
+ April => May,
+ May => June,
+ June => July,
+ July => August,
+ August => September,
+ September => October,
+ October => November,
+ November => December,
+ December => January,
+ }
+ }
+
+ /// Get n-th next month.
+ ///
+ /// ```rust
+ /// # use time::Month;
+ /// assert_eq!(Month::January.nth_next(4), Month::May);
+ /// assert_eq!(Month::July.nth_next(9), Month::April);
+ /// ```
+ pub const fn nth_next(self, n: u8) -> Self {
+ match (self as u8 - 1 + n % 12) % 12 {
+ 0 => January,
+ 1 => February,
+ 2 => March,
+ 3 => April,
+ 4 => May,
+ 5 => June,
+ 6 => July,
+ 7 => August,
+ 8 => September,
+ 9 => October,
+ 10 => November,
+ val => {
+ debug_assert!(val == 11);
+ December
+ }
+ }
+ }
+
+ /// Get n-th previous month.
+ ///
+ /// ```rust
+ /// # use time::Month;
+ /// assert_eq!(Month::January.nth_prev(4), Month::September);
+ /// assert_eq!(Month::July.nth_prev(9), Month::October);
+ /// ```
+ pub const fn nth_prev(self, n: u8) -> Self {
+ match self as i8 - 1 - (n % 12) as i8 {
+ 1 | -11 => February,
+ 2 | -10 => March,
+ 3 | -9 => April,
+ 4 | -8 => May,
+ 5 | -7 => June,
+ 6 | -6 => July,
+ 7 | -5 => August,
+ 8 | -4 => September,
+ 9 | -3 => October,
+ 10 | -2 => November,
+ 11 | -1 => December,
+ val => {
+ debug_assert!(val == 0);
+ January
+ }
+ }
+ }
+}
+
+mod private {
+ #[non_exhaustive]
+ #[derive(Debug, Clone, Copy)]
+ pub struct MonthMetadata;
+}
+use private::MonthMetadata;
+
+impl SmartDisplay for Month {
+ type Metadata = MonthMetadata;
+
+ fn metadata(&self, _: FormatterOptions) -> Metadata<Self> {
+ match self {
+ January => Metadata::new(7, self, MonthMetadata),
+ February => Metadata::new(8, self, MonthMetadata),
+ March => Metadata::new(5, self, MonthMetadata),
+ April => Metadata::new(5, self, MonthMetadata),
+ May => Metadata::new(3, self, MonthMetadata),
+ June => Metadata::new(4, self, MonthMetadata),
+ July => Metadata::new(4, self, MonthMetadata),
+ August => Metadata::new(6, self, MonthMetadata),
+ September => Metadata::new(9, self, MonthMetadata),
+ October => Metadata::new(7, self, MonthMetadata),
+ November => Metadata::new(8, self, MonthMetadata),
+ December => Metadata::new(8, self, MonthMetadata),
+ }
+ }
+
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.pad(match self {
+ January => "January",
+ February => "February",
+ March => "March",
+ April => "April",
+ May => "May",
+ June => "June",
+ July => "July",
+ August => "August",
+ September => "September",
+ October => "October",
+ November => "November",
+ December => "December",
+ })
+ }
+}
+
+impl fmt::Display for Month {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ SmartDisplay::fmt(self, f)
+ }
+}
+
+impl FromStr for Month {
+ type Err = error::InvalidVariant;
+
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
+ match s {
+ "January" => Ok(January),
+ "February" => Ok(February),
+ "March" => Ok(March),
+ "April" => Ok(April),
+ "May" => Ok(May),
+ "June" => Ok(June),
+ "July" => Ok(July),
+ "August" => Ok(August),
+ "September" => Ok(September),
+ "October" => Ok(October),
+ "November" => Ok(November),
+ "December" => Ok(December),
+ _ => Err(error::InvalidVariant),
+ }
+ }
+}
+
+impl From<Month> for u8 {
+ fn from(month: Month) -> Self {
+ month as Self
+ }
+}
+
+impl TryFrom<u8> for Month {
+ type Error = error::ComponentRange;
+
+ fn try_from(value: u8) -> Result<Self, Self::Error> {
+ match NonZeroU8::new(value) {
+ Some(value) => Self::from_number(value),
+ None => Err(error::ComponentRange {
+ name: "month",
+ minimum: 1,
+ maximum: 12,
+ value: 0,
+ conditional_message: None,
+ }),
+ }
+ }
+}
diff --git a/vendor/time/src/offset_date_time.rs b/vendor/time/src/offset_date_time.rs
new file mode 100644
index 00000000..274fad2b
--- /dev/null
+++ b/vendor/time/src/offset_date_time.rs
@@ -0,0 +1,1511 @@
+//! The [`OffsetDateTime`] struct and its associated `impl`s.
+
+#[cfg(feature = "formatting")]
+use alloc::string::String;
+use core::cmp::Ordering;
+use core::fmt;
+use core::hash::Hash;
+use core::ops::{Add, AddAssign, Sub, SubAssign};
+use core::time::Duration as StdDuration;
+#[cfg(feature = "formatting")]
+use std::io;
+
+use deranged::RangedI64;
+use num_conv::prelude::*;
+use powerfmt::ext::FormatterExt as _;
+use powerfmt::smart_display::{self, FormatterOptions, Metadata, SmartDisplay};
+use time_core::convert::*;
+
+use crate::date::{MAX_YEAR, MIN_YEAR};
+#[cfg(feature = "formatting")]
+use crate::formatting::Formattable;
+use crate::internal_macros::{
+ cascade, const_try, const_try_opt, div_floor, ensure_ranged, expect_opt,
+};
+#[cfg(feature = "parsing")]
+use crate::parsing::Parsable;
+use crate::{
+ error, util, Date, Duration, Month, PrimitiveDateTime, Time, UtcDateTime, UtcOffset, Weekday,
+};
+
+/// The Julian day of the Unix epoch.
+const UNIX_EPOCH_JULIAN_DAY: i32 = OffsetDateTime::UNIX_EPOCH.to_julian_day();
+
+/// A [`PrimitiveDateTime`] with a [`UtcOffset`].
+///
+/// All comparisons are performed using the UTC time.
+#[derive(Clone, Copy, Eq)]
+pub struct OffsetDateTime {
+ local_date_time: PrimitiveDateTime,
+ offset: UtcOffset,
+}
+
+impl PartialEq for OffsetDateTime {
+ fn eq(&self, other: &Self) -> bool {
+ self.to_offset_raw(UtcOffset::UTC) == other.to_offset_raw(UtcOffset::UTC)
+ }
+}
+
+impl PartialOrd for OffsetDateTime {
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ Some(self.cmp(other))
+ }
+}
+
+impl Ord for OffsetDateTime {
+ fn cmp(&self, other: &Self) -> Ordering {
+ self.to_offset_raw(UtcOffset::UTC)
+ .cmp(&other.to_offset_raw(UtcOffset::UTC))
+ }
+}
+
+impl Hash for OffsetDateTime {
+ fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
+ self.to_offset_raw(UtcOffset::UTC).hash(state);
+ }
+}
+
+impl OffsetDateTime {
+ /// Midnight, 1 January, 1970 (UTC).
+ ///
+ /// ```rust
+ /// # use time::OffsetDateTime;
+ /// # use time_macros::datetime;
+ /// assert_eq!(OffsetDateTime::UNIX_EPOCH, datetime!(1970-01-01 0:00 UTC));
+ /// ```
+ pub const UNIX_EPOCH: Self = Self::new_in_offset(
+ // Safety: `ordinal` is not zero.
+ unsafe { Date::__from_ordinal_date_unchecked(1970, 1) },
+ Time::MIDNIGHT,
+ UtcOffset::UTC,
+ );
+
+ /// Create a new `OffsetDateTime` with the current date and time in UTC.
+ ///
+ /// ```rust
+ /// # use time::OffsetDateTime;
+ /// # use time_macros::offset;
+ /// assert!(OffsetDateTime::now_utc().year() >= 2019);
+ /// assert_eq!(OffsetDateTime::now_utc().offset(), offset!(UTC));
+ /// ```
+ #[cfg(feature = "std")]
+ pub fn now_utc() -> Self {
+ #[cfg(all(
+ target_family = "wasm",
+ not(any(target_os = "emscripten", target_os = "wasi")),
+ feature = "wasm-bindgen"
+ ))]
+ {
+ js_sys::Date::new_0().into()
+ }
+
+ #[cfg(not(all(
+ target_family = "wasm",
+ not(any(target_os = "emscripten", target_os = "wasi")),
+ feature = "wasm-bindgen"
+ )))]
+ std::time::SystemTime::now().into()
+ }
+
+ /// Attempt to create a new `OffsetDateTime` with the current date and time in the local offset.
+ /// If the offset cannot be determined, an error is returned.
+ ///
+ /// ```rust
+ /// # use time::OffsetDateTime;
+ /// # if false {
+ /// assert!(OffsetDateTime::now_local().is_ok());
+ /// # }
+ /// ```
+ #[cfg(feature = "local-offset")]
+ pub fn now_local() -> Result<Self, error::IndeterminateOffset> {
+ let t = Self::now_utc();
+ Ok(t.to_offset(UtcOffset::local_offset_at(t)?))
+ }
+
+ /// Create a new `OffsetDateTime` with the given [`Date`], [`Time`], and [`UtcOffset`].
+ ///
+ /// ```
+ /// # use time::{Date, Month, OffsetDateTime, Time, UtcOffset};
+ /// # use time_macros::datetime;
+ /// let dt = OffsetDateTime::new_in_offset(
+ /// Date::from_calendar_date(2024, Month::January, 1)?,
+ /// Time::from_hms_nano(12, 59, 59, 500_000_000)?,
+ /// UtcOffset::from_hms(-5, 0, 0)?,
+ /// );
+ /// assert_eq!(dt, datetime!(2024-01-01 12:59:59.5 -5));
+ /// # Ok::<_, time::error::Error>(())
+ /// ```
+ pub const fn new_in_offset(date: Date, time: Time, offset: UtcOffset) -> Self {
+ Self {
+ local_date_time: date.with_time(time),
+ offset,
+ }
+ }
+
+ /// Create a new `OffsetDateTime` with the given [`Date`] and [`Time`] in the UTC timezone.
+ ///
+ /// ```
+ /// # use time::{Date, Month, OffsetDateTime, Time};
+ /// # use time_macros::datetime;
+ /// let dt = OffsetDateTime::new_utc(
+ /// Date::from_calendar_date(2024, Month::January, 1)?,
+ /// Time::from_hms_nano(12, 59, 59, 500_000_000)?,
+ /// );
+ /// assert_eq!(dt, datetime!(2024-01-01 12:59:59.5 UTC));
+ /// # Ok::<_, time::error::Error>(())
+ /// ```
+ pub const fn new_utc(date: Date, time: Time) -> Self {
+ PrimitiveDateTime::new(date, time).assume_utc()
+ }
+
+ /// Convert the `OffsetDateTime` from the current [`UtcOffset`] to the provided [`UtcOffset`].
+ ///
+ /// ```rust
+ /// # use time_macros::{datetime, offset};
+ /// assert_eq!(
+ /// datetime!(2000-01-01 0:00 UTC)
+ /// .to_offset(offset!(-1))
+ /// .year(),
+ /// 1999,
+ /// );
+ ///
+ /// // Let's see what time Sydney's new year's celebration is in New York and Los Angeles.
+ ///
+ /// // Construct midnight on new year's in Sydney.
+ /// let sydney = datetime!(2000-01-01 0:00 +11);
+ /// let new_york = sydney.to_offset(offset!(-5));
+ /// let los_angeles = sydney.to_offset(offset!(-8));
+ /// assert_eq!(sydney.hour(), 0);
+ /// assert_eq!(new_york.hour(), 8);
+ /// assert_eq!(los_angeles.hour(), 5);
+ /// ```
+ ///
+ /// # Panics
+ ///
+ /// This method panics if the local date-time in the new offset is outside the supported range.
+ pub const fn to_offset(self, offset: UtcOffset) -> Self {
+ expect_opt!(
+ self.checked_to_offset(offset),
+ "local datetime out of valid range"
+ )
+ }
+
+ /// Convert the `OffsetDateTime` from the current [`UtcOffset`] to the provided [`UtcOffset`],
+ /// returning `None` if the date-time in the resulting offset is invalid.
+ ///
+ /// ```rust
+ /// # use time::PrimitiveDateTime;
+ /// # use time_macros::{datetime, offset};
+ /// assert_eq!(
+ /// datetime!(2000-01-01 0:00 UTC)
+ /// .checked_to_offset(offset!(-1))
+ /// .unwrap()
+ /// .year(),
+ /// 1999,
+ /// );
+ /// assert_eq!(
+ /// PrimitiveDateTime::MAX
+ /// .assume_utc()
+ /// .checked_to_offset(offset!(+1)),
+ /// None,
+ /// );
+ /// ```
+ pub const fn checked_to_offset(self, offset: UtcOffset) -> Option<Self> {
+ if self.offset.whole_hours() == offset.whole_hours()
+ && self.offset.minutes_past_hour() == offset.minutes_past_hour()
+ && self.offset.seconds_past_minute() == offset.seconds_past_minute()
+ {
+ return Some(self.replace_offset(offset));
+ }
+
+ let (year, ordinal, time) = self.to_offset_raw(offset);
+
+ if year > MAX_YEAR || year < MIN_YEAR {
+ return None;
+ }
+
+ Some(Self::new_in_offset(
+ // Safety: `ordinal` is not zero.
+ unsafe { Date::__from_ordinal_date_unchecked(year, ordinal) },
+ time,
+ offset,
+ ))
+ }
+
+ /// Convert the `OffsetDateTime` from the current [`UtcOffset`] to UTC, returning a
+ /// [`UtcDateTime`].
+ ///
+ /// ```rust
+ /// # use time_macros::datetime;
+ /// assert_eq!(
+ /// datetime!(2000-01-01 0:00 +1)
+ /// .to_utc()
+ /// .year(),
+ /// 1999,
+ /// );
+ /// ```
+ ///
+ /// # Panics
+ ///
+ /// This method panics if the UTC date-time is outside the supported range.
+ pub const fn to_utc(self) -> UtcDateTime {
+ self.to_offset(UtcOffset::UTC).local_date_time.as_utc()
+ }
+
+ /// Convert the `OffsetDateTime` from the current [`UtcOffset`] to UTC, returning `None` if the
+ /// UTC date-time is invalid. Returns a [`UtcDateTime`].
+ ///
+ /// ```rust
+ /// # use time_macros::datetime;
+ /// assert_eq!(
+ /// datetime!(2000-01-01 0:00 +1)
+ /// .checked_to_utc()
+ /// .unwrap()
+ /// .year(),
+ /// 1999,
+ /// );
+ /// assert_eq!(
+ #[cfg_attr(
+ feature = "large-dates",
+ doc = " datetime!(+999999-12-31 23:59:59 -1).checked_to_utc(),"
+ )]
+ #[cfg_attr(
+ not(feature = "large-dates"),
+ doc = " datetime!(9999-12-31 23:59:59 -1).checked_to_utc(),"
+ )]
+ /// None,
+ /// );
+ /// ```
+ pub const fn checked_to_utc(self) -> Option<UtcDateTime> {
+ Some(
+ const_try_opt!(self.checked_to_offset(UtcOffset::UTC))
+ .local_date_time
+ .as_utc(),
+ )
+ }
+
+ /// Equivalent to `.to_offset(UtcOffset::UTC)`, but returning the year, ordinal, and time. This
+ /// avoids constructing an invalid [`Date`] if the new value is out of range.
+ pub(crate) const fn to_offset_raw(self, offset: UtcOffset) -> (i32, u16, Time) {
+ let from = self.offset;
+ let to = offset;
+
+ // Fast path for when no conversion is necessary.
+ if from.whole_hours() == to.whole_hours()
+ && from.minutes_past_hour() == to.minutes_past_hour()
+ && from.seconds_past_minute() == to.seconds_past_minute()
+ {
+ return (self.year(), self.ordinal(), self.time());
+ }
+
+ let mut second = self.second() as i16 - from.seconds_past_minute() as i16
+ + to.seconds_past_minute() as i16;
+ let mut minute =
+ self.minute() as i16 - from.minutes_past_hour() as i16 + to.minutes_past_hour() as i16;
+ let mut hour = self.hour() as i8 - from.whole_hours() + to.whole_hours();
+ let (mut year, ordinal) = self.to_ordinal_date();
+ let mut ordinal = ordinal as i16;
+
+ // Cascade the values twice. This is needed because the values are adjusted twice above.
+ cascade!(second in 0..Second::per(Minute) as i16 => minute);
+ cascade!(second in 0..Second::per(Minute) as i16 => minute);
+ cascade!(minute in 0..Minute::per(Hour) as i16 => hour);
+ cascade!(minute in 0..Minute::per(Hour) as i16 => hour);
+ cascade!(hour in 0..Hour::per(Day) as i8 => ordinal);
+ cascade!(hour in 0..Hour::per(Day) as i8 => ordinal);
+ cascade!(ordinal => year);
+
+ debug_assert!(ordinal > 0);
+ debug_assert!(ordinal <= util::days_in_year(year) as i16);
+
+ (
+ year,
+ ordinal as u16,
+ // Safety: The cascades above ensure the values are in range.
+ unsafe {
+ Time::__from_hms_nanos_unchecked(
+ hour as u8,
+ minute as u8,
+ second as u8,
+ self.nanosecond(),
+ )
+ },
+ )
+ }
+
+ /// Create an `OffsetDateTime` from the provided Unix timestamp. Calling `.offset()` on the
+ /// resulting value is guaranteed to return UTC.
+ ///
+ /// ```rust
+ /// # use time::OffsetDateTime;
+ /// # use time_macros::datetime;
+ /// assert_eq!(
+ /// OffsetDateTime::from_unix_timestamp(0),
+ /// Ok(OffsetDateTime::UNIX_EPOCH),
+ /// );
+ /// assert_eq!(
+ /// OffsetDateTime::from_unix_timestamp(1_546_300_800),
+ /// Ok(datetime!(2019-01-01 0:00 UTC)),
+ /// );
+ /// ```
+ ///
+ /// If you have a timestamp-nanosecond pair, you can use something along the lines of the
+ /// following:
+ ///
+ /// ```rust
+ /// # use time::{Duration, OffsetDateTime, ext::NumericalDuration};
+ /// let (timestamp, nanos) = (1, 500_000_000);
+ /// assert_eq!(
+ /// OffsetDateTime::from_unix_timestamp(timestamp)? + Duration::nanoseconds(nanos),
+ /// OffsetDateTime::UNIX_EPOCH + 1.5.seconds()
+ /// );
+ /// # Ok::<_, time::Error>(())
+ /// ```
+ pub const fn from_unix_timestamp(timestamp: i64) -> Result<Self, error::ComponentRange> {
+ type Timestamp = RangedI64<
+ {
+ OffsetDateTime::new_in_offset(Date::MIN, Time::MIDNIGHT, UtcOffset::UTC)
+ .unix_timestamp()
+ },
+ {
+ OffsetDateTime::new_in_offset(Date::MAX, Time::MAX, UtcOffset::UTC).unix_timestamp()
+ },
+ >;
+ ensure_ranged!(Timestamp: timestamp);
+
+ // Use the unchecked method here, as the input validity has already been verified.
+ // Safety: The Julian day number is in range.
+ let date = unsafe {
+ Date::from_julian_day_unchecked(
+ UNIX_EPOCH_JULIAN_DAY + div_floor!(timestamp, Second::per(Day) as i64) as i32,
+ )
+ };
+
+ let seconds_within_day = timestamp.rem_euclid(Second::per(Day) as i64);
+ // Safety: All values are in range.
+ let time = unsafe {
+ Time::__from_hms_nanos_unchecked(
+ (seconds_within_day / Second::per(Hour) as i64) as u8,
+ ((seconds_within_day % Second::per(Hour) as i64) / Minute::per(Hour) as i64) as u8,
+ (seconds_within_day % Second::per(Minute) as i64) as u8,
+ 0,
+ )
+ };
+
+ Ok(Self::new_in_offset(date, time, UtcOffset::UTC))
+ }
+
+ /// Construct an `OffsetDateTime` from the provided Unix timestamp (in nanoseconds). Calling
+ /// `.offset()` on the resulting value is guaranteed to return UTC.
+ ///
+ /// ```rust
+ /// # use time::OffsetDateTime;
+ /// # use time_macros::datetime;
+ /// assert_eq!(
+ /// OffsetDateTime::from_unix_timestamp_nanos(0),
+ /// Ok(OffsetDateTime::UNIX_EPOCH),
+ /// );
+ /// assert_eq!(
+ /// OffsetDateTime::from_unix_timestamp_nanos(1_546_300_800_000_000_000),
+ /// Ok(datetime!(2019-01-01 0:00 UTC)),
+ /// );
+ /// ```
+ pub const fn from_unix_timestamp_nanos(timestamp: i128) -> Result<Self, error::ComponentRange> {
+ let datetime = const_try!(Self::from_unix_timestamp(div_floor!(
+ timestamp,
+ Nanosecond::per(Second) as i128
+ ) as i64));
+
+ Ok(Self::new_in_offset(
+ datetime.date(),
+ // Safety: `nanosecond` is in range due to `rem_euclid`.
+ unsafe {
+ Time::__from_hms_nanos_unchecked(
+ datetime.hour(),
+ datetime.minute(),
+ datetime.second(),
+ timestamp.rem_euclid(Nanosecond::per(Second) as i128) as u32,
+ )
+ },
+ UtcOffset::UTC,
+ ))
+ }
+
+ /// Get the [`UtcOffset`].
+ ///
+ /// ```rust
+ /// # use time_macros::{datetime, offset};
+ /// assert_eq!(datetime!(2019-01-01 0:00 UTC).offset(), offset!(UTC));
+ /// assert_eq!(datetime!(2019-01-01 0:00 +1).offset(), offset!(+1));
+ /// ```
+ pub const fn offset(self) -> UtcOffset {
+ self.offset
+ }
+
+ /// Get the [Unix timestamp](https://en.wikipedia.org/wiki/Unix_time).
+ ///
+ /// ```rust
+ /// # use time_macros::datetime;
+ /// assert_eq!(datetime!(1970-01-01 0:00 UTC).unix_timestamp(), 0);
+ /// assert_eq!(datetime!(1970-01-01 0:00 -1).unix_timestamp(), 3_600);
+ /// ```
+ pub const fn unix_timestamp(self) -> i64 {
+ let days =
+ (self.to_julian_day() as i64 - UNIX_EPOCH_JULIAN_DAY as i64) * Second::per(Day) as i64;
+ let hours = self.hour() as i64 * Second::per(Hour) as i64;
+ let minutes = self.minute() as i64 * Second::per(Minute) as i64;
+ let seconds = self.second() as i64;
+ let offset_seconds = self.offset.whole_seconds() as i64;
+ days + hours + minutes + seconds - offset_seconds
+ }
+
+ /// Get the Unix timestamp in nanoseconds.
+ ///
+ /// ```rust
+ /// use time_macros::datetime;
+ /// assert_eq!(datetime!(1970-01-01 0:00 UTC).unix_timestamp_nanos(), 0);
+ /// assert_eq!(
+ /// datetime!(1970-01-01 0:00 -1).unix_timestamp_nanos(),
+ /// 3_600_000_000_000,
+ /// );
+ /// ```
+ pub const fn unix_timestamp_nanos(self) -> i128 {
+ self.unix_timestamp() as i128 * Nanosecond::per(Second) as i128 + self.nanosecond() as i128
+ }
+
+ /// Get the [`PrimitiveDateTime`] in the stored offset.
+ pub(crate) const fn date_time(self) -> PrimitiveDateTime {
+ self.local_date_time
+ }
+
+ /// Get the [`Date`] in the stored offset.
+ ///
+ /// ```rust
+ /// # use time_macros::{date, datetime, offset};
+ /// assert_eq!(datetime!(2019-01-01 0:00 UTC).date(), date!(2019-01-01));
+ /// assert_eq!(
+ /// datetime!(2019-01-01 0:00 UTC)
+ /// .to_offset(offset!(-1))
+ /// .date(),
+ /// date!(2018-12-31),
+ /// );
+ /// ```
+ pub const fn date(self) -> Date {
+ self.date_time().date()
+ }
+
+ /// Get the [`Time`] in the stored offset.
+ ///
+ /// ```rust
+ /// # use time_macros::{datetime, offset, time};
+ /// assert_eq!(datetime!(2019-01-01 0:00 UTC).time(), time!(0:00));
+ /// assert_eq!(
+ /// datetime!(2019-01-01 0:00 UTC)
+ /// .to_offset(offset!(-1))
+ /// .time(),
+ /// time!(23:00)
+ /// );
+ /// ```
+ pub const fn time(self) -> Time {
+ self.date_time().time()
+ }
+
+ /// Get the year of the date in the stored offset.
+ ///
+ /// ```rust
+ /// # use time_macros::{datetime, offset};
+ /// assert_eq!(datetime!(2019-01-01 0:00 UTC).year(), 2019);
+ /// assert_eq!(
+ /// datetime!(2019-12-31 23:00 UTC)
+ /// .to_offset(offset!(+1))
+ /// .year(),
+ /// 2020,
+ /// );
+ /// assert_eq!(datetime!(2020-01-01 0:00 UTC).year(), 2020);
+ /// ```
+ pub const fn year(self) -> i32 {
+ self.date().year()
+ }
+
+ /// Get the month of the date in the stored offset.
+ ///
+ /// ```rust
+ /// # use time::Month;
+ /// # use time_macros::{datetime, offset};
+ /// assert_eq!(datetime!(2019-01-01 0:00 UTC).month(), Month::January);
+ /// assert_eq!(
+ /// datetime!(2019-12-31 23:00 UTC)
+ /// .to_offset(offset!(+1))
+ /// .month(),
+ /// Month::January,
+ /// );
+ /// ```
+ pub const fn month(self) -> Month {
+ self.date().month()
+ }
+
+ /// Get the day of the date in the stored offset.
+ ///
+ /// The returned value will always be in the range `1..=31`.
+ ///
+ /// ```rust
+ /// # use time_macros::{datetime, offset};
+ /// assert_eq!(datetime!(2019-01-01 0:00 UTC).day(), 1);
+ /// assert_eq!(
+ /// datetime!(2019-12-31 23:00 UTC)
+ /// .to_offset(offset!(+1))
+ /// .day(),
+ /// 1,
+ /// );
+ /// ```
+ pub const fn day(self) -> u8 {
+ self.date().day()
+ }
+
+ /// Get the day of the year of the date in the stored offset.
+ ///
+ /// The returned value will always be in the range `1..=366`.
+ ///
+ /// ```rust
+ /// # use time_macros::{datetime, offset};
+ /// assert_eq!(datetime!(2019-01-01 0:00 UTC).ordinal(), 1);
+ /// assert_eq!(
+ /// datetime!(2019-12-31 23:00 UTC)
+ /// .to_offset(offset!(+1))
+ /// .ordinal(),
+ /// 1,
+ /// );
+ /// ```
+ pub const fn ordinal(self) -> u16 {
+ self.date().ordinal()
+ }
+
+ /// Get the ISO week number of the date in the stored offset.
+ ///
+ /// The returned value will always be in the range `1..=53`.
+ ///
+ /// ```rust
+ /// # use time_macros::datetime;
+ /// assert_eq!(datetime!(2019-01-01 0:00 UTC).iso_week(), 1);
+ /// assert_eq!(datetime!(2020-01-01 0:00 UTC).iso_week(), 1);
+ /// assert_eq!(datetime!(2020-12-31 0:00 UTC).iso_week(), 53);
+ /// assert_eq!(datetime!(2021-01-01 0:00 UTC).iso_week(), 53);
+ /// ```
+ pub const fn iso_week(self) -> u8 {
+ self.date().iso_week()
+ }
+
+ /// Get the week number where week 1 begins on the first Sunday.
+ ///
+ /// The returned value will always be in the range `0..=53`.
+ ///
+ /// ```rust
+ /// # use time_macros::datetime;
+ /// assert_eq!(datetime!(2019-01-01 0:00 UTC).sunday_based_week(), 0);
+ /// assert_eq!(datetime!(2020-01-01 0:00 UTC).sunday_based_week(), 0);
+ /// assert_eq!(datetime!(2020-12-31 0:00 UTC).sunday_based_week(), 52);
+ /// assert_eq!(datetime!(2021-01-01 0:00 UTC).sunday_based_week(), 0);
+ /// ```
+ pub const fn sunday_based_week(self) -> u8 {
+ self.date().sunday_based_week()
+ }
+
+ /// Get the week number where week 1 begins on the first Monday.
+ ///
+ /// The returned value will always be in the range `0..=53`.
+ ///
+ /// ```rust
+ /// # use time_macros::datetime;
+ /// assert_eq!(datetime!(2019-01-01 0:00 UTC).monday_based_week(), 0);
+ /// assert_eq!(datetime!(2020-01-01 0:00 UTC).monday_based_week(), 0);
+ /// assert_eq!(datetime!(2020-12-31 0:00 UTC).monday_based_week(), 52);
+ /// assert_eq!(datetime!(2021-01-01 0:00 UTC).monday_based_week(), 0);
+ /// ```
+ pub const fn monday_based_week(self) -> u8 {
+ self.date().monday_based_week()
+ }
+
+ /// Get the year, month, and day.
+ ///
+ /// ```rust
+ /// # use time::Month;
+ /// # use time_macros::datetime;
+ /// assert_eq!(
+ /// datetime!(2019-01-01 0:00 UTC).to_calendar_date(),
+ /// (2019, Month::January, 1)
+ /// );
+ /// ```
+ pub const fn to_calendar_date(self) -> (i32, Month, u8) {
+ self.date().to_calendar_date()
+ }
+
+ /// Get the year and ordinal day number.
+ ///
+ /// ```rust
+ /// # use time_macros::datetime;
+ /// assert_eq!(
+ /// datetime!(2019-01-01 0:00 UTC).to_ordinal_date(),
+ /// (2019, 1)
+ /// );
+ /// ```
+ pub const fn to_ordinal_date(self) -> (i32, u16) {
+ self.date().to_ordinal_date()
+ }
+
+ /// Get the ISO 8601 year, week number, and weekday.
+ ///
+ /// ```rust
+ /// # use time::Weekday::*;
+ /// # use time_macros::datetime;
+ /// assert_eq!(
+ /// datetime!(2019-01-01 0:00 UTC).to_iso_week_date(),
+ /// (2019, 1, Tuesday)
+ /// );
+ /// assert_eq!(
+ /// datetime!(2019-10-04 0:00 UTC).to_iso_week_date(),
+ /// (2019, 40, Friday)
+ /// );
+ /// assert_eq!(
+ /// datetime!(2020-01-01 0:00 UTC).to_iso_week_date(),
+ /// (2020, 1, Wednesday)
+ /// );
+ /// assert_eq!(
+ /// datetime!(2020-12-31 0:00 UTC).to_iso_week_date(),
+ /// (2020, 53, Thursday)
+ /// );
+ /// assert_eq!(
+ /// datetime!(2021-01-01 0:00 UTC).to_iso_week_date(),
+ /// (2020, 53, Friday)
+ /// );
+ /// ```
+ pub const fn to_iso_week_date(self) -> (i32, u8, Weekday) {
+ self.date().to_iso_week_date()
+ }
+
+ /// Get the weekday of the date in the stored offset.
+ ///
+ /// ```rust
+ /// # use time::Weekday::*;
+ /// # use time_macros::datetime;
+ /// assert_eq!(datetime!(2019-01-01 0:00 UTC).weekday(), Tuesday);
+ /// assert_eq!(datetime!(2019-02-01 0:00 UTC).weekday(), Friday);
+ /// assert_eq!(datetime!(2019-03-01 0:00 UTC).weekday(), Friday);
+ /// ```
+ pub const fn weekday(self) -> Weekday {
+ self.date().weekday()
+ }
+
+ /// Get the Julian day for the date. The time is not taken into account for this calculation.
+ ///
+ /// The algorithm to perform this conversion is derived from one provided by Peter Baum; it is
+ /// freely available [here](https://www.researchgate.net/publication/316558298_Date_Algorithms).
+ ///
+ /// ```rust
+ /// # use time_macros::datetime;
+ /// assert_eq!(datetime!(-4713-11-24 0:00 UTC).to_julian_day(), 0);
+ /// assert_eq!(datetime!(2000-01-01 0:00 UTC).to_julian_day(), 2_451_545);
+ /// assert_eq!(datetime!(2019-01-01 0:00 UTC).to_julian_day(), 2_458_485);
+ /// assert_eq!(datetime!(2019-12-31 0:00 UTC).to_julian_day(), 2_458_849);
+ /// ```
+ pub const fn to_julian_day(self) -> i32 {
+ self.date().to_julian_day()
+ }
+
+ /// Get the clock hour, minute, and second.
+ ///
+ /// ```rust
+ /// # use time_macros::datetime;
+ /// assert_eq!(datetime!(2020-01-01 0:00:00 UTC).to_hms(), (0, 0, 0));
+ /// assert_eq!(datetime!(2020-01-01 23:59:59 UTC).to_hms(), (23, 59, 59));
+ /// ```
+ pub const fn to_hms(self) -> (u8, u8, u8) {
+ self.time().as_hms()
+ }
+
+ /// Get the clock hour, minute, second, and millisecond.
+ ///
+ /// ```rust
+ /// # use time_macros::datetime;
+ /// assert_eq!(
+ /// datetime!(2020-01-01 0:00:00 UTC).to_hms_milli(),
+ /// (0, 0, 0, 0)
+ /// );
+ /// assert_eq!(
+ /// datetime!(2020-01-01 23:59:59.999 UTC).to_hms_milli(),
+ /// (23, 59, 59, 999)
+ /// );
+ /// ```
+ pub const fn to_hms_milli(self) -> (u8, u8, u8, u16) {
+ self.time().as_hms_milli()
+ }
+
+ /// Get the clock hour, minute, second, and microsecond.
+ ///
+ /// ```rust
+ /// # use time_macros::datetime;
+ /// assert_eq!(
+ /// datetime!(2020-01-01 0:00:00 UTC).to_hms_micro(),
+ /// (0, 0, 0, 0)
+ /// );
+ /// assert_eq!(
+ /// datetime!(2020-01-01 23:59:59.999_999 UTC).to_hms_micro(),
+ /// (23, 59, 59, 999_999)
+ /// );
+ /// ```
+ pub const fn to_hms_micro(self) -> (u8, u8, u8, u32) {
+ self.time().as_hms_micro()
+ }
+
+ /// Get the clock hour, minute, second, and nanosecond.
+ ///
+ /// ```rust
+ /// # use time_macros::datetime;
+ /// assert_eq!(
+ /// datetime!(2020-01-01 0:00:00 UTC).to_hms_nano(),
+ /// (0, 0, 0, 0)
+ /// );
+ /// assert_eq!(
+ /// datetime!(2020-01-01 23:59:59.999_999_999 UTC).to_hms_nano(),
+ /// (23, 59, 59, 999_999_999)
+ /// );
+ /// ```
+ pub const fn to_hms_nano(self) -> (u8, u8, u8, u32) {
+ self.time().as_hms_nano()
+ }
+
+ /// Get the clock hour in the stored offset.
+ ///
+ /// The returned value will always be in the range `0..24`.
+ ///
+ /// ```rust
+ /// # use time_macros::{datetime, offset};
+ /// assert_eq!(datetime!(2019-01-01 0:00 UTC).hour(), 0);
+ /// assert_eq!(
+ /// datetime!(2019-01-01 23:59:59 UTC)
+ /// .to_offset(offset!(-2))
+ /// .hour(),
+ /// 21,
+ /// );
+ /// ```
+ pub const fn hour(self) -> u8 {
+ self.time().hour()
+ }
+
+ /// Get the minute within the hour in the stored offset.
+ ///
+ /// The returned value will always be in the range `0..60`.
+ ///
+ /// ```rust
+ /// # use time_macros::{datetime, offset};
+ /// assert_eq!(datetime!(2019-01-01 0:00 UTC).minute(), 0);
+ /// assert_eq!(
+ /// datetime!(2019-01-01 23:59:59 UTC)
+ /// .to_offset(offset!(+0:30))
+ /// .minute(),
+ /// 29,
+ /// );
+ /// ```
+ pub const fn minute(self) -> u8 {
+ self.time().minute()
+ }
+
+ /// Get the second within the minute in the stored offset.
+ ///
+ /// The returned value will always be in the range `0..60`.
+ ///
+ /// ```rust
+ /// # use time_macros::{datetime, offset};
+ /// assert_eq!(datetime!(2019-01-01 0:00 UTC).second(), 0);
+ /// assert_eq!(
+ /// datetime!(2019-01-01 23:59:59 UTC)
+ /// .to_offset(offset!(+0:00:30))
+ /// .second(),
+ /// 29,
+ /// );
+ /// ```
+ pub const fn second(self) -> u8 {
+ self.time().second()
+ }
+
+ // Because a `UtcOffset` is limited in resolution to one second, any subsecond value will not
+ // change when adjusting for the offset.
+
+ /// Get the milliseconds within the second in the stored offset.
+ ///
+ /// The returned value will always be in the range `0..1_000`.
+ ///
+ /// ```rust
+ /// # use time_macros::datetime;
+ /// assert_eq!(datetime!(2019-01-01 0:00 UTC).millisecond(), 0);
+ /// assert_eq!(datetime!(2019-01-01 23:59:59.999 UTC).millisecond(), 999);
+ /// ```
+ pub const fn millisecond(self) -> u16 {
+ self.time().millisecond()
+ }
+
+ /// Get the microseconds within the second in the stored offset.
+ ///
+ /// The returned value will always be in the range `0..1_000_000`.
+ ///
+ /// ```rust
+ /// # use time_macros::datetime;
+ /// assert_eq!(datetime!(2019-01-01 0:00 UTC).microsecond(), 0);
+ /// assert_eq!(
+ /// datetime!(2019-01-01 23:59:59.999_999 UTC).microsecond(),
+ /// 999_999,
+ /// );
+ /// ```
+ pub const fn microsecond(self) -> u32 {
+ self.time().microsecond()
+ }
+
+ /// Get the nanoseconds within the second in the stored offset.
+ ///
+ /// The returned value will always be in the range `0..1_000_000_000`.
+ ///
+ /// ```rust
+ /// # use time_macros::datetime;
+ /// assert_eq!(datetime!(2019-01-01 0:00 UTC).nanosecond(), 0);
+ /// assert_eq!(
+ /// datetime!(2019-01-01 23:59:59.999_999_999 UTC).nanosecond(),
+ /// 999_999_999,
+ /// );
+ /// ```
+ pub const fn nanosecond(self) -> u32 {
+ self.time().nanosecond()
+ }
+
+ /// Computes `self + duration`, returning `None` if an overflow occurred.
+ ///
+ /// ```
+ /// # use time::{Date, ext::NumericalDuration};
+ /// # use time_macros::{datetime, offset};
+ /// let datetime = Date::MIN.midnight().assume_offset(offset!(+10));
+ /// assert_eq!(datetime.checked_add((-2).days()), None);
+ ///
+ /// let datetime = Date::MAX.midnight().assume_offset(offset!(+10));
+ /// assert_eq!(datetime.checked_add(2.days()), None);
+ ///
+ /// assert_eq!(
+ /// datetime!(2019-11-25 15:30 +10).checked_add(27.hours()),
+ /// Some(datetime!(2019-11-26 18:30 +10))
+ /// );
+ /// ```
+ pub const fn checked_add(self, duration: Duration) -> Option<Self> {
+ Some(const_try_opt!(self.date_time().checked_add(duration)).assume_offset(self.offset()))
+ }
+
+ /// Computes `self - duration`, returning `None` if an overflow occurred.
+ ///
+ /// ```
+ /// # use time::{Date, ext::NumericalDuration};
+ /// # use time_macros::{datetime, offset};
+ /// let datetime = Date::MIN.midnight().assume_offset(offset!(+10));
+ /// assert_eq!(datetime.checked_sub(2.days()), None);
+ ///
+ /// let datetime = Date::MAX.midnight().assume_offset(offset!(+10));
+ /// assert_eq!(datetime.checked_sub((-2).days()), None);
+ ///
+ /// assert_eq!(
+ /// datetime!(2019-11-25 15:30 +10).checked_sub(27.hours()),
+ /// Some(datetime!(2019-11-24 12:30 +10))
+ /// );
+ /// ```
+ pub const fn checked_sub(self, duration: Duration) -> Option<Self> {
+ Some(const_try_opt!(self.date_time().checked_sub(duration)).assume_offset(self.offset()))
+ }
+
+ /// Computes `self + duration`, saturating value on overflow.
+ ///
+ /// ```
+ /// # use time::ext::NumericalDuration;
+ /// # use time_macros::datetime;
+ /// assert_eq!(
+ #[cfg_attr(
+ feature = "large-dates",
+ doc = " datetime!(-999999-01-01 0:00 +10).saturating_add((-2).days()),"
+ )]
+ #[cfg_attr(feature = "large-dates", doc = " datetime!(-999999-01-01 0:00 +10)")]
+ #[cfg_attr(
+ not(feature = "large-dates"),
+ doc = " datetime!(-9999-01-01 0:00 +10).saturating_add((-2).days()),"
+ )]
+ #[cfg_attr(
+ not(feature = "large-dates"),
+ doc = " datetime!(-9999-01-01 0:00 +10)"
+ )]
+ /// );
+ ///
+ /// assert_eq!(
+ #[cfg_attr(
+ feature = "large-dates",
+ doc = " datetime!(+999999-12-31 23:59:59.999_999_999 +10).saturating_add(2.days()),"
+ )]
+ #[cfg_attr(
+ feature = "large-dates",
+ doc = " datetime!(+999999-12-31 23:59:59.999_999_999 +10)"
+ )]
+ #[cfg_attr(
+ not(feature = "large-dates"),
+ doc = " datetime!(+9999-12-31 23:59:59.999_999_999 +10).saturating_add(2.days()),"
+ )]
+ #[cfg_attr(
+ not(feature = "large-dates"),
+ doc = " datetime!(+9999-12-31 23:59:59.999_999_999 +10)"
+ )]
+ /// );
+ ///
+ /// assert_eq!(
+ /// datetime!(2019-11-25 15:30 +10).saturating_add(27.hours()),
+ /// datetime!(2019-11-26 18:30 +10)
+ /// );
+ /// ```
+ pub const fn saturating_add(self, duration: Duration) -> Self {
+ if let Some(datetime) = self.checked_add(duration) {
+ datetime
+ } else if duration.is_negative() {
+ PrimitiveDateTime::MIN.assume_offset(self.offset())
+ } else {
+ PrimitiveDateTime::MAX.assume_offset(self.offset())
+ }
+ }
+
+ /// Computes `self - duration`, saturating value on overflow.
+ ///
+ /// ```
+ /// # use time::ext::NumericalDuration;
+ /// # use time_macros::datetime;
+ /// assert_eq!(
+ #[cfg_attr(
+ feature = "large-dates",
+ doc = " datetime!(-999999-01-01 0:00 +10).saturating_sub(2.days()),"
+ )]
+ #[cfg_attr(feature = "large-dates", doc = " datetime!(-999999-01-01 0:00 +10)")]
+ #[cfg_attr(
+ not(feature = "large-dates"),
+ doc = " datetime!(-9999-01-01 0:00 +10).saturating_sub(2.days()),"
+ )]
+ #[cfg_attr(
+ not(feature = "large-dates"),
+ doc = " datetime!(-9999-01-01 0:00 +10)"
+ )]
+ /// );
+ ///
+ /// assert_eq!(
+ #[cfg_attr(
+ feature = "large-dates",
+ doc = " datetime!(+999999-12-31 23:59:59.999_999_999 +10).saturating_sub((-2).days()),"
+ )]
+ #[cfg_attr(
+ feature = "large-dates",
+ doc = " datetime!(+999999-12-31 23:59:59.999_999_999 +10)"
+ )]
+ #[cfg_attr(
+ not(feature = "large-dates"),
+ doc = " datetime!(+9999-12-31 23:59:59.999_999_999 +10).saturating_sub((-2).days()),"
+ )]
+ #[cfg_attr(
+ not(feature = "large-dates"),
+ doc = " datetime!(+9999-12-31 23:59:59.999_999_999 +10)"
+ )]
+ /// );
+ ///
+ /// assert_eq!(
+ /// datetime!(2019-11-25 15:30 +10).saturating_sub(27.hours()),
+ /// datetime!(2019-11-24 12:30 +10)
+ /// );
+ /// ```
+ pub const fn saturating_sub(self, duration: Duration) -> Self {
+ if let Some(datetime) = self.checked_sub(duration) {
+ datetime
+ } else if duration.is_negative() {
+ PrimitiveDateTime::MAX.assume_offset(self.offset())
+ } else {
+ PrimitiveDateTime::MIN.assume_offset(self.offset())
+ }
+ }
+}
+
+/// Methods that replace part of the `OffsetDateTime`.
+impl OffsetDateTime {
+ /// Replace the time, which is assumed to be in the stored offset. The date and offset
+ /// components are unchanged.
+ ///
+ /// ```rust
+ /// # use time_macros::{datetime, time};
+ /// assert_eq!(
+ /// datetime!(2020-01-01 5:00 UTC).replace_time(time!(12:00)),
+ /// datetime!(2020-01-01 12:00 UTC)
+ /// );
+ /// assert_eq!(
+ /// datetime!(2020-01-01 12:00 -5).replace_time(time!(7:00)),
+ /// datetime!(2020-01-01 7:00 -5)
+ /// );
+ /// assert_eq!(
+ /// datetime!(2020-01-01 0:00 +1).replace_time(time!(12:00)),
+ /// datetime!(2020-01-01 12:00 +1)
+ /// );
+ /// ```
+ #[must_use = "This method does not mutate the original `OffsetDateTime`."]
+ pub const fn replace_time(self, time: Time) -> Self {
+ Self::new_in_offset(self.date(), time, self.offset())
+ }
+
+ /// Replace the date, which is assumed to be in the stored offset. The time and offset
+ /// components are unchanged.
+ ///
+ /// ```rust
+ /// # use time_macros::{datetime, date};
+ /// assert_eq!(
+ /// datetime!(2020-01-01 12:00 UTC).replace_date(date!(2020-01-30)),
+ /// datetime!(2020-01-30 12:00 UTC)
+ /// );
+ /// assert_eq!(
+ /// datetime!(2020-01-01 0:00 +1).replace_date(date!(2020-01-30)),
+ /// datetime!(2020-01-30 0:00 +1)
+ /// );
+ /// ```
+ #[must_use = "This method does not mutate the original `OffsetDateTime`."]
+ pub const fn replace_date(self, date: Date) -> Self {
+ Self::new_in_offset(date, self.time(), self.offset())
+ }
+
+ /// Replace the date and time, which are assumed to be in the stored offset. The offset
+ /// component remains unchanged.
+ ///
+ /// ```rust
+ /// # use time_macros::datetime;
+ /// assert_eq!(
+ /// datetime!(2020-01-01 12:00 UTC).replace_date_time(datetime!(2020-01-30 16:00)),
+ /// datetime!(2020-01-30 16:00 UTC)
+ /// );
+ /// assert_eq!(
+ /// datetime!(2020-01-01 12:00 +1).replace_date_time(datetime!(2020-01-30 0:00)),
+ /// datetime!(2020-01-30 0:00 +1)
+ /// );
+ /// ```
+ #[must_use = "This method does not mutate the original `OffsetDateTime`."]
+ pub const fn replace_date_time(self, date_time: PrimitiveDateTime) -> Self {
+ date_time.assume_offset(self.offset())
+ }
+
+ /// Replace the offset. The date and time components remain unchanged.
+ ///
+ /// ```rust
+ /// # use time_macros::{datetime, offset};
+ /// assert_eq!(
+ /// datetime!(2020-01-01 0:00 UTC).replace_offset(offset!(-5)),
+ /// datetime!(2020-01-01 0:00 -5)
+ /// );
+ /// ```
+ #[must_use = "This method does not mutate the original `OffsetDateTime`."]
+ pub const fn replace_offset(self, offset: UtcOffset) -> Self {
+ self.date_time().assume_offset(offset)
+ }
+
+ /// Replace the year. The month and day will be unchanged.
+ ///
+ /// ```rust
+ /// # use time_macros::datetime;
+ /// assert_eq!(
+ /// datetime!(2022-02-18 12:00 +01).replace_year(2019),
+ /// Ok(datetime!(2019-02-18 12:00 +01))
+ /// );
+ /// assert!(datetime!(2022-02-18 12:00 +01).replace_year(-1_000_000_000).is_err()); // -1_000_000_000 isn't a valid year
+ /// assert!(datetime!(2022-02-18 12:00 +01).replace_year(1_000_000_000).is_err()); // 1_000_000_000 isn't a valid year
+ /// ```
+ #[must_use = "This method does not mutate the original `OffsetDateTime`."]
+ pub const fn replace_year(self, year: i32) -> Result<Self, error::ComponentRange> {
+ Ok(const_try!(self.date_time().replace_year(year)).assume_offset(self.offset()))
+ }
+
+ /// Replace the month of the year.
+ ///
+ /// ```rust
+ /// # use time_macros::datetime;
+ /// # use time::Month;
+ /// assert_eq!(
+ /// datetime!(2022-02-18 12:00 +01).replace_month(Month::January),
+ /// Ok(datetime!(2022-01-18 12:00 +01))
+ /// );
+ /// assert!(datetime!(2022-01-30 12:00 +01).replace_month(Month::February).is_err()); // 30 isn't a valid day in February
+ /// ```
+ #[must_use = "This method does not mutate the original `OffsetDateTime`."]
+ pub const fn replace_month(self, month: Month) -> Result<Self, error::ComponentRange> {
+ Ok(const_try!(self.date_time().replace_month(month)).assume_offset(self.offset()))
+ }
+
+ /// Replace the day of the month.
+ ///
+ /// ```rust
+ /// # use time_macros::datetime;
+ /// assert_eq!(
+ /// datetime!(2022-02-18 12:00 +01).replace_day(1),
+ /// Ok(datetime!(2022-02-01 12:00 +01))
+ /// );
+ /// assert!(datetime!(2022-02-18 12:00 +01).replace_day(0).is_err()); // 00 isn't a valid day
+ /// assert!(datetime!(2022-02-18 12:00 +01).replace_day(30).is_err()); // 30 isn't a valid day in February
+ /// ```
+ #[must_use = "This method does not mutate the original `OffsetDateTime`."]
+ pub const fn replace_day(self, day: u8) -> Result<Self, error::ComponentRange> {
+ Ok(const_try!(self.date_time().replace_day(day)).assume_offset(self.offset()))
+ }
+
+ /// Replace the day of the year.
+ ///
+ /// ```rust
+ /// # use time_macros::datetime;
+ /// assert_eq!(datetime!(2022-049 12:00 +01).replace_ordinal(1), Ok(datetime!(2022-001 12:00 +01)));
+ /// assert!(datetime!(2022-049 12:00 +01).replace_ordinal(0).is_err()); // 0 isn't a valid ordinal
+ /// assert!(datetime!(2022-049 12:00 +01).replace_ordinal(366).is_err()); // 2022 isn't a leap year
+ /// ```
+ #[must_use = "This method does not mutate the original `OffsetDateTime`."]
+ pub const fn replace_ordinal(self, ordinal: u16) -> Result<Self, error::ComponentRange> {
+ Ok(const_try!(self.date_time().replace_ordinal(ordinal)).assume_offset(self.offset()))
+ }
+
+ /// Replace the clock hour.
+ ///
+ /// ```rust
+ /// # use time_macros::datetime;
+ /// assert_eq!(
+ /// datetime!(2022-02-18 01:02:03.004_005_006 +01).replace_hour(7),
+ /// Ok(datetime!(2022-02-18 07:02:03.004_005_006 +01))
+ /// );
+ /// assert!(datetime!(2022-02-18 01:02:03.004_005_006 +01).replace_hour(24).is_err()); // 24 isn't a valid hour
+ /// ```
+ #[must_use = "This method does not mutate the original `OffsetDateTime`."]
+ pub const fn replace_hour(self, hour: u8) -> Result<Self, error::ComponentRange> {
+ Ok(const_try!(self.date_time().replace_hour(hour)).assume_offset(self.offset()))
+ }
+
+ /// Replace the minutes within the hour.
+ ///
+ /// ```rust
+ /// # use time_macros::datetime;
+ /// assert_eq!(
+ /// datetime!(2022-02-18 01:02:03.004_005_006 +01).replace_minute(7),
+ /// Ok(datetime!(2022-02-18 01:07:03.004_005_006 +01))
+ /// );
+ /// assert!(datetime!(2022-02-18 01:02:03.004_005_006 +01).replace_minute(60).is_err()); // 60 isn't a valid minute
+ /// ```
+ #[must_use = "This method does not mutate the original `OffsetDateTime`."]
+ pub const fn replace_minute(self, minute: u8) -> Result<Self, error::ComponentRange> {
+ Ok(const_try!(self.date_time().replace_minute(minute)).assume_offset(self.offset()))
+ }
+
+ /// Replace the seconds within the minute.
+ ///
+ /// ```rust
+ /// # use time_macros::datetime;
+ /// assert_eq!(
+ /// datetime!(2022-02-18 01:02:03.004_005_006 +01).replace_second(7),
+ /// Ok(datetime!(2022-02-18 01:02:07.004_005_006 +01))
+ /// );
+ /// assert!(datetime!(2022-02-18 01:02:03.004_005_006 +01).replace_second(60).is_err()); // 60 isn't a valid second
+ /// ```
+ #[must_use = "This method does not mutate the original `OffsetDateTime`."]
+ pub const fn replace_second(self, second: u8) -> Result<Self, error::ComponentRange> {
+ Ok(const_try!(self.date_time().replace_second(second)).assume_offset(self.offset()))
+ }
+
+ /// Replace the milliseconds within the second.
+ ///
+ /// ```rust
+ /// # use time_macros::datetime;
+ /// assert_eq!(
+ /// datetime!(2022-02-18 01:02:03.004_005_006 +01).replace_millisecond(7),
+ /// Ok(datetime!(2022-02-18 01:02:03.007 +01))
+ /// );
+ /// assert!(datetime!(2022-02-18 01:02:03.004_005_006 +01).replace_millisecond(1_000).is_err()); // 1_000 isn't a valid millisecond
+ /// ```
+ #[must_use = "This method does not mutate the original `OffsetDateTime`."]
+ pub const fn replace_millisecond(
+ self,
+ millisecond: u16,
+ ) -> Result<Self, error::ComponentRange> {
+ Ok(
+ const_try!(self.date_time().replace_millisecond(millisecond))
+ .assume_offset(self.offset()),
+ )
+ }
+
+ /// Replace the microseconds within the second.
+ ///
+ /// ```rust
+ /// # use time_macros::datetime;
+ /// assert_eq!(
+ /// datetime!(2022-02-18 01:02:03.004_005_006 +01).replace_microsecond(7_008),
+ /// Ok(datetime!(2022-02-18 01:02:03.007_008 +01))
+ /// );
+ /// assert!(datetime!(2022-02-18 01:02:03.004_005_006 +01).replace_microsecond(1_000_000).is_err()); // 1_000_000 isn't a valid microsecond
+ /// ```
+ #[must_use = "This method does not mutate the original `OffsetDateTime`."]
+ pub const fn replace_microsecond(
+ self,
+ microsecond: u32,
+ ) -> Result<Self, error::ComponentRange> {
+ Ok(
+ const_try!(self.date_time().replace_microsecond(microsecond))
+ .assume_offset(self.offset()),
+ )
+ }
+
+ /// Replace the nanoseconds within the second.
+ ///
+ /// ```rust
+ /// # use time_macros::datetime;
+ /// assert_eq!(
+ /// datetime!(2022-02-18 01:02:03.004_005_006 +01).replace_nanosecond(7_008_009),
+ /// Ok(datetime!(2022-02-18 01:02:03.007_008_009 +01))
+ /// );
+ /// assert!(datetime!(2022-02-18 01:02:03.004_005_006 +01).replace_nanosecond(1_000_000_000).is_err()); // 1_000_000_000 isn't a valid nanosecond
+ /// ```
+ #[must_use = "This method does not mutate the original `OffsetDateTime`."]
+ pub const fn replace_nanosecond(self, nanosecond: u32) -> Result<Self, error::ComponentRange> {
+ Ok(
+ const_try!(self.date_time().replace_nanosecond(nanosecond))
+ .assume_offset(self.offset()),
+ )
+ }
+}
+
+#[cfg(feature = "formatting")]
+impl OffsetDateTime {
+ /// Format the `OffsetDateTime` using the provided [format
+ /// description](crate::format_description).
+ pub fn format_into(
+ self,
+ output: &mut (impl io::Write + ?Sized),
+ format: &(impl Formattable + ?Sized),
+ ) -> Result<usize, error::Format> {
+ format.format_into(
+ output,
+ Some(self.date()),
+ Some(self.time()),
+ Some(self.offset()),
+ )
+ }
+
+ /// Format the `OffsetDateTime` using the provided [format
+ /// description](crate::format_description).
+ ///
+ /// ```rust
+ /// # use time::format_description;
+ /// # use time_macros::datetime;
+ /// let format = format_description::parse(
+ /// "[year]-[month]-[day] [hour]:[minute]:[second] [offset_hour \
+ /// sign:mandatory]:[offset_minute]:[offset_second]",
+ /// )?;
+ /// assert_eq!(
+ /// datetime!(2020-01-02 03:04:05 +06:07:08).format(&format)?,
+ /// "2020-01-02 03:04:05 +06:07:08"
+ /// );
+ /// # Ok::<_, time::Error>(())
+ /// ```
+ pub fn format(self, format: &(impl Formattable + ?Sized)) -> Result<String, error::Format> {
+ format.format(Some(self.date()), Some(self.time()), Some(self.offset()))
+ }
+}
+
+#[cfg(feature = "parsing")]
+impl OffsetDateTime {
+ /// Parse an `OffsetDateTime` from the input using the provided [format
+ /// description](crate::format_description).
+ ///
+ /// ```rust
+ /// # use time::OffsetDateTime;
+ /// # use time_macros::{datetime, format_description};
+ /// let format = format_description!(
+ /// "[year]-[month]-[day] [hour]:[minute]:[second] [offset_hour \
+ /// sign:mandatory]:[offset_minute]:[offset_second]"
+ /// );
+ /// assert_eq!(
+ /// OffsetDateTime::parse("2020-01-02 03:04:05 +06:07:08", &format)?,
+ /// datetime!(2020-01-02 03:04:05 +06:07:08)
+ /// );
+ /// # Ok::<_, time::Error>(())
+ /// ```
+ pub fn parse(
+ input: &str,
+ description: &(impl Parsable + ?Sized),
+ ) -> Result<Self, error::Parse> {
+ description.parse_offset_date_time(input.as_bytes())
+ }
+
+ /// A helper method to check if the `OffsetDateTime` is a valid representation of a leap second.
+ /// Leap seconds, when parsed, are represented as the preceding nanosecond. However, leap
+ /// seconds can only occur as the last second of a month UTC.
+ #[cfg(feature = "parsing")]
+ pub(crate) const fn is_valid_leap_second_stand_in(self) -> bool {
+ // This comparison doesn't need to be adjusted for the stored offset, so check it first for
+ // speed.
+ if self.nanosecond() != 999_999_999 {
+ return false;
+ }
+
+ let (year, ordinal, time) = self.to_offset_raw(UtcOffset::UTC);
+ let Ok(date) = Date::from_ordinal_date(year, ordinal) else {
+ return false;
+ };
+
+ time.hour() == 23
+ && time.minute() == 59
+ && time.second() == 59
+ && date.day() == date.month().length(year)
+ }
+}
+
+impl SmartDisplay for OffsetDateTime {
+ type Metadata = ();
+
+ fn metadata(&self, _: FormatterOptions) -> Metadata<Self> {
+ let width =
+ smart_display::padded_width_of!(self.date(), " ", self.time(), " ", self.offset());
+ Metadata::new(width, self, ())
+ }
+
+ fn fmt_with_metadata(
+ &self,
+ f: &mut fmt::Formatter<'_>,
+ metadata: Metadata<Self>,
+ ) -> fmt::Result {
+ f.pad_with_width(
+ metadata.unpadded_width(),
+ format_args!("{} {} {}", self.date(), self.time(), self.offset()),
+ )
+ }
+}
+
+impl fmt::Display for OffsetDateTime {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ SmartDisplay::fmt(self, f)
+ }
+}
+
+impl fmt::Debug for OffsetDateTime {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt::Display::fmt(self, f)
+ }
+}
+
+impl Add<Duration> for OffsetDateTime {
+ type Output = Self;
+
+ /// # Panics
+ ///
+ /// This may panic if an overflow occurs.
+ fn add(self, duration: Duration) -> Self::Output {
+ self.checked_add(duration)
+ .expect("resulting value is out of range")
+ }
+}
+
+impl Add<StdDuration> for OffsetDateTime {
+ type Output = Self;
+
+ /// # Panics
+ ///
+ /// This may panic if an overflow occurs.
+ fn add(self, duration: StdDuration) -> Self::Output {
+ let (is_next_day, time) = self.time().adjusting_add_std(duration);
+
+ Self::new_in_offset(
+ if is_next_day {
+ (self.date() + duration)
+ .next_day()
+ .expect("resulting value is out of range")
+ } else {
+ self.date() + duration
+ },
+ time,
+ self.offset,
+ )
+ }
+}
+
+impl AddAssign<Duration> for OffsetDateTime {
+ /// # Panics
+ ///
+ /// This may panic if an overflow occurs.
+ fn add_assign(&mut self, rhs: Duration) {
+ *self = *self + rhs;
+ }
+}
+
+impl AddAssign<StdDuration> for OffsetDateTime {
+ /// # Panics
+ ///
+ /// This may panic if an overflow occurs.
+ fn add_assign(&mut self, rhs: StdDuration) {
+ *self = *self + rhs;
+ }
+}
+
+impl Sub<Duration> for OffsetDateTime {
+ type Output = Self;
+
+ /// # Panics
+ ///
+ /// This may panic if an overflow occurs.
+ fn sub(self, rhs: Duration) -> Self::Output {
+ self.checked_sub(rhs)
+ .expect("resulting value is out of range")
+ }
+}
+
+impl Sub<StdDuration> for OffsetDateTime {
+ type Output = Self;
+
+ /// # Panics
+ ///
+ /// This may panic if an overflow occurs.
+ fn sub(self, duration: StdDuration) -> Self::Output {
+ let (is_previous_day, time) = self.time().adjusting_sub_std(duration);
+
+ Self::new_in_offset(
+ if is_previous_day {
+ (self.date() - duration)
+ .previous_day()
+ .expect("resulting value is out of range")
+ } else {
+ self.date() - duration
+ },
+ time,
+ self.offset,
+ )
+ }
+}
+
+impl SubAssign<Duration> for OffsetDateTime {
+ /// # Panics
+ ///
+ /// This may panic if an overflow occurs.
+ fn sub_assign(&mut self, rhs: Duration) {
+ *self = *self - rhs;
+ }
+}
+
+impl SubAssign<StdDuration> for OffsetDateTime {
+ /// # Panics
+ ///
+ /// This may panic if an overflow occurs.
+ fn sub_assign(&mut self, rhs: StdDuration) {
+ *self = *self - rhs;
+ }
+}
+
+impl Sub for OffsetDateTime {
+ type Output = Duration;
+
+ /// # Panics
+ ///
+ /// This may panic if an overflow occurs.
+ fn sub(self, rhs: Self) -> Self::Output {
+ let base = self.date_time() - rhs.date_time();
+ let adjustment = Duration::seconds(
+ (self.offset.whole_seconds() - rhs.offset.whole_seconds()).extend::<i64>(),
+ );
+ base - adjustment
+ }
+}
diff --git a/vendor/time/src/parsing/combinator/mod.rs b/vendor/time/src/parsing/combinator/mod.rs
new file mode 100644
index 00000000..e3e1df76
--- /dev/null
+++ b/vendor/time/src/parsing/combinator/mod.rs
@@ -0,0 +1,194 @@
+//! Implementations of the low-level parser combinators.
+
+pub(crate) mod rfc;
+
+use num_conv::prelude::*;
+
+use crate::format_description::modifier::Padding;
+use crate::parsing::shim::{Integer, IntegerParseBytes};
+use crate::parsing::ParsedItem;
+
+/// Parse a "+" or "-" sign. Returns the ASCII byte representing the sign, if present.
+pub(crate) const fn sign(input: &[u8]) -> Option<ParsedItem<'_, u8>> {
+ match input {
+ [sign @ (b'-' | b'+'), remaining @ ..] => Some(ParsedItem(remaining, *sign)),
+ _ => None,
+ }
+}
+
+/// Consume the first matching item, returning its associated value.
+pub(crate) fn first_match<'a, T>(
+ options: impl IntoIterator<Item = (&'a [u8], T)>,
+ case_sensitive: bool,
+) -> impl FnMut(&'a [u8]) -> Option<ParsedItem<'a, T>> {
+ let mut options = options.into_iter();
+ move |input| {
+ options.find_map(|(expected, t)| {
+ if case_sensitive {
+ Some(ParsedItem(input.strip_prefix(expected)?, t))
+ } else {
+ let n = expected.len();
+ if n <= input.len() {
+ let (head, tail) = input.split_at(n);
+ if head.eq_ignore_ascii_case(expected) {
+ return Some(ParsedItem(tail, t));
+ }
+ }
+ None
+ }
+ })
+ }
+}
+
+/// Consume zero or more instances of the provided parser. The parser must return the unit value.
+pub(crate) fn zero_or_more<'a, P: Fn(&'a [u8]) -> Option<ParsedItem<'a, ()>>>(
+ parser: P,
+) -> impl FnMut(&'a [u8]) -> ParsedItem<'a, ()> {
+ move |mut input| {
+ while let Some(remaining) = parser(input) {
+ input = remaining.into_inner();
+ }
+ ParsedItem(input, ())
+ }
+}
+
+/// Consume one of or more instances of the provided parser. The parser must produce the unit value.
+pub(crate) fn one_or_more<'a, P: Fn(&'a [u8]) -> Option<ParsedItem<'a, ()>>>(
+ parser: P,
+) -> impl Fn(&'a [u8]) -> Option<ParsedItem<'a, ()>> {
+ move |mut input| {
+ input = parser(input)?.into_inner();
+ while let Some(remaining) = parser(input) {
+ input = remaining.into_inner();
+ }
+ Some(ParsedItem(input, ()))
+ }
+}
+
+/// Consume between `n` and `m` instances of the provided parser.
+pub(crate) fn n_to_m<
+ 'a,
+ const N: u8,
+ const M: u8,
+ T,
+ P: Fn(&'a [u8]) -> Option<ParsedItem<'a, T>>,
+>(
+ parser: P,
+) -> impl Fn(&'a [u8]) -> Option<ParsedItem<'a, &'a [u8]>> {
+ debug_assert!(M >= N);
+ move |mut input| {
+ // We need to keep this to determine the total length eventually consumed.
+ let orig_input = input;
+
+ // Mandatory
+ for _ in 0..N {
+ input = parser(input)?.0;
+ }
+
+ // Optional
+ for _ in N..M {
+ match parser(input) {
+ Some(parsed) => input = parsed.0,
+ None => break,
+ }
+ }
+
+ Some(ParsedItem(
+ input,
+ &orig_input[..(orig_input.len() - input.len())],
+ ))
+ }
+}
+
+/// Consume between `n` and `m` digits, returning the numerical value.
+pub(crate) fn n_to_m_digits<const N: u8, const M: u8, T: Integer>(
+ input: &[u8],
+) -> Option<ParsedItem<'_, T>> {
+ debug_assert!(M >= N);
+ n_to_m::<N, M, _, _>(any_digit)(input)?.flat_map(|value| value.parse_bytes())
+}
+
+/// Consume exactly `n` digits, returning the numerical value.
+pub(crate) fn exactly_n_digits<const N: u8, T: Integer>(input: &[u8]) -> Option<ParsedItem<'_, T>> {
+ n_to_m_digits::<N, N, _>(input)
+}
+
+/// Consume exactly `n` digits, returning the numerical value.
+pub(crate) fn exactly_n_digits_padded<'a, const N: u8, T: Integer>(
+ padding: Padding,
+) -> impl Fn(&'a [u8]) -> Option<ParsedItem<'a, T>> {
+ n_to_m_digits_padded::<N, N, _>(padding)
+}
+
+/// Consume between `n` and `m` digits, returning the numerical value.
+pub(crate) fn n_to_m_digits_padded<'a, const N: u8, const M: u8, T: Integer>(
+ padding: Padding,
+) -> impl Fn(&'a [u8]) -> Option<ParsedItem<'a, T>> {
+ debug_assert!(M >= N);
+ move |mut input| match padding {
+ Padding::None => n_to_m_digits::<1, M, _>(input),
+ Padding::Space => {
+ debug_assert!(N > 0);
+
+ let mut orig_input = input;
+ for _ in 0..(N - 1) {
+ match ascii_char::<b' '>(input) {
+ Some(parsed) => input = parsed.0,
+ None => break,
+ }
+ }
+ let pad_width = (orig_input.len() - input.len()).truncate::<u8>();
+
+ orig_input = input;
+ for _ in 0..(N - pad_width) {
+ input = any_digit(input)?.0;
+ }
+ for _ in N..M {
+ match any_digit(input) {
+ Some(parsed) => input = parsed.0,
+ None => break,
+ }
+ }
+
+ ParsedItem(input, &orig_input[..(orig_input.len() - input.len())])
+ .flat_map(|value| value.parse_bytes())
+ }
+ Padding::Zero => n_to_m_digits::<N, M, _>(input),
+ }
+}
+
+/// Consume exactly one digit.
+pub(crate) const fn any_digit(input: &[u8]) -> Option<ParsedItem<'_, u8>> {
+ match input {
+ [c, remaining @ ..] if c.is_ascii_digit() => Some(ParsedItem(remaining, *c)),
+ _ => None,
+ }
+}
+
+/// Consume exactly one of the provided ASCII characters.
+pub(crate) fn ascii_char<const CHAR: u8>(input: &[u8]) -> Option<ParsedItem<'_, ()>> {
+ debug_assert!(CHAR.is_ascii_graphic() || CHAR.is_ascii_whitespace());
+ match input {
+ [c, remaining @ ..] if *c == CHAR => Some(ParsedItem(remaining, ())),
+ _ => None,
+ }
+}
+
+/// Consume exactly one of the provided ASCII characters, case-insensitive.
+pub(crate) fn ascii_char_ignore_case<const CHAR: u8>(input: &[u8]) -> Option<ParsedItem<'_, ()>> {
+ debug_assert!(CHAR.is_ascii_graphic() || CHAR.is_ascii_whitespace());
+ match input {
+ [c, remaining @ ..] if c.eq_ignore_ascii_case(&CHAR) => Some(ParsedItem(remaining, ())),
+ _ => None,
+ }
+}
+
+/// Optionally consume an input with a given parser.
+pub(crate) fn opt<'a, T>(
+ parser: impl Fn(&'a [u8]) -> Option<ParsedItem<'a, T>>,
+) -> impl Fn(&'a [u8]) -> ParsedItem<'a, Option<T>> {
+ move |input| match parser(input) {
+ Some(value) => value.map(Some),
+ None => ParsedItem(input, None),
+ }
+}
diff --git a/vendor/time/src/parsing/combinator/rfc/iso8601.rs b/vendor/time/src/parsing/combinator/rfc/iso8601.rs
new file mode 100644
index 00000000..4a1ebc46
--- /dev/null
+++ b/vendor/time/src/parsing/combinator/rfc/iso8601.rs
@@ -0,0 +1,177 @@
+//! Rules defined in [ISO 8601].
+//!
+//! [ISO 8601]: https://www.iso.org/iso-8601-date-and-time-format.html
+
+use core::num::{NonZeroU16, NonZeroU8};
+
+use num_conv::prelude::*;
+
+use crate::parsing::combinator::{any_digit, ascii_char, exactly_n_digits, first_match, sign};
+use crate::parsing::ParsedItem;
+use crate::{Month, Weekday};
+
+/// What kind of format is being parsed. This is used to ensure each part of the format (date, time,
+/// offset) is the same kind.
+#[derive(Debug, Clone, Copy)]
+pub(crate) enum ExtendedKind {
+ /// The basic format.
+ Basic,
+ /// The extended format.
+ Extended,
+ /// ¯\_(ツ)_/¯
+ Unknown,
+}
+
+impl ExtendedKind {
+ /// Is it possible that the format is extended?
+ pub(crate) const fn maybe_extended(self) -> bool {
+ matches!(self, Self::Extended | Self::Unknown)
+ }
+
+ /// Is the format known for certain to be extended?
+ pub(crate) const fn is_extended(self) -> bool {
+ matches!(self, Self::Extended)
+ }
+
+ /// If the kind is `Unknown`, make it `Basic`. Otherwise, do nothing. Returns `Some` if and only
+ /// if the kind is now `Basic`.
+ pub(crate) fn coerce_basic(&mut self) -> Option<()> {
+ match self {
+ Self::Basic => Some(()),
+ Self::Extended => None,
+ Self::Unknown => {
+ *self = Self::Basic;
+ Some(())
+ }
+ }
+ }
+
+ /// If the kind is `Unknown`, make it `Extended`. Otherwise, do nothing. Returns `Some` if and
+ /// only if the kind is now `Extended`.
+ pub(crate) fn coerce_extended(&mut self) -> Option<()> {
+ match self {
+ Self::Basic => None,
+ Self::Extended => Some(()),
+ Self::Unknown => {
+ *self = Self::Extended;
+ Some(())
+ }
+ }
+ }
+}
+
+/// Parse a possibly expanded year.
+pub(crate) fn year(input: &[u8]) -> Option<ParsedItem<'_, i32>> {
+ Some(match sign(input) {
+ Some(ParsedItem(input, sign)) => exactly_n_digits::<6, u32>(input)?.map(|val| {
+ let val = val.cast_signed();
+ if sign == b'-' {
+ -val
+ } else {
+ val
+ }
+ }),
+ None => exactly_n_digits::<4, u32>(input)?.map(|val| val.cast_signed()),
+ })
+}
+
+/// Parse a month.
+pub(crate) fn month(input: &[u8]) -> Option<ParsedItem<'_, Month>> {
+ first_match(
+ [
+ (b"01".as_slice(), Month::January),
+ (b"02".as_slice(), Month::February),
+ (b"03".as_slice(), Month::March),
+ (b"04".as_slice(), Month::April),
+ (b"05".as_slice(), Month::May),
+ (b"06".as_slice(), Month::June),
+ (b"07".as_slice(), Month::July),
+ (b"08".as_slice(), Month::August),
+ (b"09".as_slice(), Month::September),
+ (b"10".as_slice(), Month::October),
+ (b"11".as_slice(), Month::November),
+ (b"12".as_slice(), Month::December),
+ ],
+ true,
+ )(input)
+}
+
+/// Parse a week number.
+pub(crate) fn week(input: &[u8]) -> Option<ParsedItem<'_, NonZeroU8>> {
+ exactly_n_digits::<2, _>(input)
+}
+
+/// Parse a day of the month.
+pub(crate) fn day(input: &[u8]) -> Option<ParsedItem<'_, NonZeroU8>> {
+ exactly_n_digits::<2, _>(input)
+}
+
+/// Parse a day of the week.
+pub(crate) fn dayk(input: &[u8]) -> Option<ParsedItem<'_, Weekday>> {
+ first_match(
+ [
+ (b"1".as_slice(), Weekday::Monday),
+ (b"2".as_slice(), Weekday::Tuesday),
+ (b"3".as_slice(), Weekday::Wednesday),
+ (b"4".as_slice(), Weekday::Thursday),
+ (b"5".as_slice(), Weekday::Friday),
+ (b"6".as_slice(), Weekday::Saturday),
+ (b"7".as_slice(), Weekday::Sunday),
+ ],
+ true,
+ )(input)
+}
+
+/// Parse a day of the year.
+pub(crate) fn dayo(input: &[u8]) -> Option<ParsedItem<'_, NonZeroU16>> {
+ exactly_n_digits::<3, _>(input)
+}
+
+/// Parse the hour.
+pub(crate) fn hour(input: &[u8]) -> Option<ParsedItem<'_, u8>> {
+ exactly_n_digits::<2, _>(input)
+}
+
+/// Parse the minute.
+pub(crate) fn min(input: &[u8]) -> Option<ParsedItem<'_, u8>> {
+ exactly_n_digits::<2, _>(input)
+}
+
+/// Parse a floating point number as its integer and optional fractional parts.
+///
+/// The number must have two digits before the decimal point. If a decimal point is present, at
+/// least one digit must follow.
+///
+/// The return type is a tuple of the integer part and optional fraction part.
+pub(crate) fn float(input: &[u8]) -> Option<ParsedItem<'_, (u8, Option<f64>)>> {
+ // Two digits before the decimal.
+ let ParsedItem(input, integer_part) = match input {
+ [first_digit @ b'0'..=b'9', second_digit @ b'0'..=b'9', input @ ..] => {
+ ParsedItem(input, (first_digit - b'0') * 10 + (second_digit - b'0'))
+ }
+ _ => return None,
+ };
+
+ if let Some(ParsedItem(input, ())) = decimal_sign(input) {
+ // Mandatory post-decimal digit.
+ let ParsedItem(mut input, mut fractional_part) =
+ any_digit(input)?.map(|digit| ((digit - b'0') as f64) / 10.);
+
+ let mut divisor = 10.;
+ // Any number of subsequent digits.
+ while let Some(ParsedItem(new_input, digit)) = any_digit(input) {
+ input = new_input;
+ divisor *= 10.;
+ fractional_part += (digit - b'0') as f64 / divisor;
+ }
+
+ Some(ParsedItem(input, (integer_part, Some(fractional_part))))
+ } else {
+ Some(ParsedItem(input, (integer_part, None)))
+ }
+}
+
+/// Parse a "decimal sign", which is either a comma or a period.
+fn decimal_sign(input: &[u8]) -> Option<ParsedItem<'_, ()>> {
+ ascii_char::<b'.'>(input).or_else(|| ascii_char::<b','>(input))
+}
diff --git a/vendor/time/src/parsing/combinator/rfc/mod.rs b/vendor/time/src/parsing/combinator/rfc/mod.rs
new file mode 100644
index 00000000..2974a4d5
--- /dev/null
+++ b/vendor/time/src/parsing/combinator/rfc/mod.rs
@@ -0,0 +1,10 @@
+//! Combinators for rules as defined in a standard.
+//!
+//! When applicable, these rules have been converted strictly following the ABNF syntax as specified
+//! in [RFC 2234].
+//!
+//! [RFC 2234]: https://datatracker.ietf.org/doc/html/rfc2234
+
+pub(crate) mod iso8601;
+pub(crate) mod rfc2234;
+pub(crate) mod rfc2822;
diff --git a/vendor/time/src/parsing/combinator/rfc/rfc2234.rs b/vendor/time/src/parsing/combinator/rfc/rfc2234.rs
new file mode 100644
index 00000000..67534443
--- /dev/null
+++ b/vendor/time/src/parsing/combinator/rfc/rfc2234.rs
@@ -0,0 +1,13 @@
+//! Rules defined in [RFC 2234].
+//!
+//! [RFC 2234]: https://datatracker.ietf.org/doc/html/rfc2234
+
+use crate::parsing::ParsedItem;
+
+/// Consume exactly one space or tab.
+pub(crate) const fn wsp(input: &[u8]) -> Option<ParsedItem<'_, ()>> {
+ match input {
+ [b' ' | b'\t', rest @ ..] => Some(ParsedItem(rest, ())),
+ _ => None,
+ }
+}
diff --git a/vendor/time/src/parsing/combinator/rfc/rfc2822.rs b/vendor/time/src/parsing/combinator/rfc/rfc2822.rs
new file mode 100644
index 00000000..0e886ee4
--- /dev/null
+++ b/vendor/time/src/parsing/combinator/rfc/rfc2822.rs
@@ -0,0 +1,108 @@
+//! Rules defined in [RFC 2822].
+//!
+//! [RFC 2822]: https://datatracker.ietf.org/doc/html/rfc2822
+
+use crate::parsing::combinator::rfc::rfc2234::wsp;
+use crate::parsing::combinator::{ascii_char, one_or_more, zero_or_more};
+use crate::parsing::ParsedItem;
+
+/// Consume the `fws` rule.
+// The full rule is equivalent to /\r\n[ \t]+|[ \t]+(?:\r\n[ \t]+)*/
+pub(crate) fn fws(mut input: &[u8]) -> Option<ParsedItem<'_, ()>> {
+ if let [b'\r', b'\n', rest @ ..] = input {
+ one_or_more(wsp)(rest)
+ } else {
+ input = one_or_more(wsp)(input)?.into_inner();
+ while let [b'\r', b'\n', rest @ ..] = input {
+ input = one_or_more(wsp)(rest)?.into_inner();
+ }
+ Some(ParsedItem(input, ()))
+ }
+}
+
+/// Consume the `cfws` rule.
+// The full rule is equivalent to any combination of `fws` and `comment` so long as it is not empty.
+pub(crate) fn cfws(input: &[u8]) -> Option<ParsedItem<'_, ()>> {
+ one_or_more(|input| fws(input).or_else(|| comment(input)))(input)
+}
+
+/// Consume the `comment` rule.
+fn comment(mut input: &[u8]) -> Option<ParsedItem<'_, ()>> {
+ input = ascii_char::<b'('>(input)?.into_inner();
+ input = zero_or_more(fws)(input).into_inner();
+ while let Some(rest) = ccontent(input) {
+ input = rest.into_inner();
+ input = zero_or_more(fws)(input).into_inner();
+ }
+ input = ascii_char::<b')'>(input)?.into_inner();
+
+ Some(ParsedItem(input, ()))
+}
+
+/// Consume the `ccontent` rule.
+fn ccontent(input: &[u8]) -> Option<ParsedItem<'_, ()>> {
+ ctext(input)
+ .or_else(|| quoted_pair(input))
+ .or_else(|| comment(input))
+}
+
+/// Consume the `ctext` rule.
+#[allow(clippy::unnecessary_lazy_evaluations)] // rust-lang/rust-clippy#8522
+fn ctext(input: &[u8]) -> Option<ParsedItem<'_, ()>> {
+ no_ws_ctl(input).or_else(|| match input {
+ [33..=39 | 42..=91 | 93..=126, rest @ ..] => Some(ParsedItem(rest, ())),
+ _ => None,
+ })
+}
+
+/// Consume the `quoted_pair` rule.
+fn quoted_pair(mut input: &[u8]) -> Option<ParsedItem<'_, ()>> {
+ input = ascii_char::<b'\\'>(input)?.into_inner();
+ input = text(input).into_inner();
+
+ // If nothing is parsed by `text`, this means by hit the `obs-text` rule and nothing matched.
+ // This is technically a success, and we used to check the `obs-qp` rule to ensure everything
+ // possible was consumed. After further analysis, it was determined that this check was
+ // unnecessary due to `obs-text` wholly subsuming `obs-qp` in this context. For this reason, if
+ // `text` fails to parse anything, we consider it a success without further consideration.
+
+ Some(ParsedItem(input, ()))
+}
+
+/// Consume the `no_ws_ctl` rule.
+const fn no_ws_ctl(input: &[u8]) -> Option<ParsedItem<'_, ()>> {
+ match input {
+ [1..=8 | 11..=12 | 14..=31 | 127, rest @ ..] => Some(ParsedItem(rest, ())),
+ _ => None,
+ }
+}
+
+/// Consume the `text` rule.
+fn text<'a>(input: &'a [u8]) -> ParsedItem<'a, ()> {
+ let new_text = |input: &'a [u8]| match input {
+ [1..=9 | 11..=12 | 14..=127, rest @ ..] => Some(ParsedItem(rest, ())),
+ _ => None,
+ };
+
+ let obs_char = |input: &'a [u8]| match input {
+ // This is technically allowed, but consuming this would mean the rest of the string is
+ // eagerly consumed without consideration for where the comment actually ends.
+ [b')', ..] => None,
+ [0..=9 | 11..=12 | 14..=127, rest @ ..] => Some(rest),
+ _ => None,
+ };
+
+ let obs_text = |mut input| {
+ input = zero_or_more(ascii_char::<b'\n'>)(input).into_inner();
+ input = zero_or_more(ascii_char::<b'\r'>)(input).into_inner();
+ while let Some(rest) = obs_char(input) {
+ input = rest;
+ input = zero_or_more(ascii_char::<b'\n'>)(input).into_inner();
+ input = zero_or_more(ascii_char::<b'\r'>)(input).into_inner();
+ }
+
+ ParsedItem(input, ())
+ };
+
+ new_text(input).unwrap_or_else(|| obs_text(input))
+}
diff --git a/vendor/time/src/parsing/component.rs b/vendor/time/src/parsing/component.rs
new file mode 100644
index 00000000..79645704
--- /dev/null
+++ b/vendor/time/src/parsing/component.rs
@@ -0,0 +1,379 @@
+//! Parsing implementations for all [`Component`](crate::format_description::Component)s.
+
+use core::num::{NonZeroU16, NonZeroU8};
+
+use num_conv::prelude::*;
+
+use crate::convert::*;
+use crate::format_description::modifier;
+use crate::parsing::combinator::{
+ any_digit, exactly_n_digits, exactly_n_digits_padded, first_match, n_to_m_digits,
+ n_to_m_digits_padded, opt, sign,
+};
+use crate::parsing::ParsedItem;
+use crate::{Month, Weekday};
+
+/// Parse the "year" component of a `Date`.
+pub(crate) fn parse_year(
+ input: &[u8],
+ modifiers: modifier::Year,
+) -> Option<ParsedItem<'_, (i32, bool)>> {
+ match modifiers.repr {
+ modifier::YearRepr::Full => {
+ let ParsedItem(input, sign) = opt(sign)(input);
+
+ if let Some(sign) = sign {
+ let ParsedItem(input, year) = if cfg!(feature = "large-dates")
+ && modifiers.range == modifier::YearRange::Extended
+ {
+ n_to_m_digits_padded::<4, 6, u32>(modifiers.padding)(input)?
+ } else {
+ exactly_n_digits_padded::<4, u32>(modifiers.padding)(input)?
+ };
+
+ Some(if sign == b'-' {
+ ParsedItem(input, (-year.cast_signed(), true))
+ } else {
+ ParsedItem(input, (year.cast_signed(), false))
+ })
+ } else if modifiers.sign_is_mandatory {
+ None
+ } else {
+ let ParsedItem(input, year) =
+ exactly_n_digits_padded::<4, u32>(modifiers.padding)(input)?;
+ Some(ParsedItem(input, (year.cast_signed(), false)))
+ }
+ }
+ modifier::YearRepr::Century => {
+ let ParsedItem(input, sign) = opt(sign)(input);
+
+ if let Some(sign) = sign {
+ let ParsedItem(input, year) = if cfg!(feature = "large-dates")
+ && modifiers.range == modifier::YearRange::Extended
+ {
+ n_to_m_digits_padded::<2, 4, u32>(modifiers.padding)(input)?
+ } else {
+ exactly_n_digits_padded::<2, u32>(modifiers.padding)(input)?
+ };
+
+ Some(if sign == b'-' {
+ ParsedItem(input, (-year.cast_signed(), true))
+ } else {
+ ParsedItem(input, (year.cast_signed(), false))
+ })
+ } else if modifiers.sign_is_mandatory {
+ None
+ } else {
+ let ParsedItem(input, year) =
+ n_to_m_digits_padded::<1, 2, u32>(modifiers.padding)(input)?;
+ Some(ParsedItem(input, (year.cast_signed(), false)))
+ }
+ }
+ modifier::YearRepr::LastTwo => Some(
+ exactly_n_digits_padded::<2, u32>(modifiers.padding)(input)?
+ .map(|v| (v.cast_signed(), false)),
+ ),
+ }
+}
+
+/// Parse the "month" component of a `Date`.
+pub(crate) fn parse_month(
+ input: &[u8],
+ modifiers: modifier::Month,
+) -> Option<ParsedItem<'_, Month>> {
+ use Month::*;
+ let ParsedItem(remaining, value) = first_match(
+ match modifiers.repr {
+ modifier::MonthRepr::Numerical => {
+ return exactly_n_digits_padded::<2, _>(modifiers.padding)(input)?
+ .flat_map(|n| Month::from_number(n).ok());
+ }
+ modifier::MonthRepr::Long => [
+ (b"January".as_slice(), January),
+ (b"February".as_slice(), February),
+ (b"March".as_slice(), March),
+ (b"April".as_slice(), April),
+ (b"May".as_slice(), May),
+ (b"June".as_slice(), June),
+ (b"July".as_slice(), July),
+ (b"August".as_slice(), August),
+ (b"September".as_slice(), September),
+ (b"October".as_slice(), October),
+ (b"November".as_slice(), November),
+ (b"December".as_slice(), December),
+ ],
+ modifier::MonthRepr::Short => [
+ (b"Jan".as_slice(), January),
+ (b"Feb".as_slice(), February),
+ (b"Mar".as_slice(), March),
+ (b"Apr".as_slice(), April),
+ (b"May".as_slice(), May),
+ (b"Jun".as_slice(), June),
+ (b"Jul".as_slice(), July),
+ (b"Aug".as_slice(), August),
+ (b"Sep".as_slice(), September),
+ (b"Oct".as_slice(), October),
+ (b"Nov".as_slice(), November),
+ (b"Dec".as_slice(), December),
+ ],
+ },
+ modifiers.case_sensitive,
+ )(input)?;
+ Some(ParsedItem(remaining, value))
+}
+
+/// Parse the "week number" component of a `Date`.
+pub(crate) fn parse_week_number(
+ input: &[u8],
+ modifiers: modifier::WeekNumber,
+) -> Option<ParsedItem<'_, u8>> {
+ exactly_n_digits_padded::<2, _>(modifiers.padding)(input)
+}
+
+/// Parse the "weekday" component of a `Date`.
+pub(crate) fn parse_weekday(
+ input: &[u8],
+ modifiers: modifier::Weekday,
+) -> Option<ParsedItem<'_, Weekday>> {
+ first_match(
+ match (modifiers.repr, modifiers.one_indexed) {
+ (modifier::WeekdayRepr::Short, _) => [
+ (b"Mon".as_slice(), Weekday::Monday),
+ (b"Tue".as_slice(), Weekday::Tuesday),
+ (b"Wed".as_slice(), Weekday::Wednesday),
+ (b"Thu".as_slice(), Weekday::Thursday),
+ (b"Fri".as_slice(), Weekday::Friday),
+ (b"Sat".as_slice(), Weekday::Saturday),
+ (b"Sun".as_slice(), Weekday::Sunday),
+ ],
+ (modifier::WeekdayRepr::Long, _) => [
+ (b"Monday".as_slice(), Weekday::Monday),
+ (b"Tuesday".as_slice(), Weekday::Tuesday),
+ (b"Wednesday".as_slice(), Weekday::Wednesday),
+ (b"Thursday".as_slice(), Weekday::Thursday),
+ (b"Friday".as_slice(), Weekday::Friday),
+ (b"Saturday".as_slice(), Weekday::Saturday),
+ (b"Sunday".as_slice(), Weekday::Sunday),
+ ],
+ (modifier::WeekdayRepr::Sunday, false) => [
+ (b"1".as_slice(), Weekday::Monday),
+ (b"2".as_slice(), Weekday::Tuesday),
+ (b"3".as_slice(), Weekday::Wednesday),
+ (b"4".as_slice(), Weekday::Thursday),
+ (b"5".as_slice(), Weekday::Friday),
+ (b"6".as_slice(), Weekday::Saturday),
+ (b"0".as_slice(), Weekday::Sunday),
+ ],
+ (modifier::WeekdayRepr::Sunday, true) => [
+ (b"2".as_slice(), Weekday::Monday),
+ (b"3".as_slice(), Weekday::Tuesday),
+ (b"4".as_slice(), Weekday::Wednesday),
+ (b"5".as_slice(), Weekday::Thursday),
+ (b"6".as_slice(), Weekday::Friday),
+ (b"7".as_slice(), Weekday::Saturday),
+ (b"1".as_slice(), Weekday::Sunday),
+ ],
+ (modifier::WeekdayRepr::Monday, false) => [
+ (b"0".as_slice(), Weekday::Monday),
+ (b"1".as_slice(), Weekday::Tuesday),
+ (b"2".as_slice(), Weekday::Wednesday),
+ (b"3".as_slice(), Weekday::Thursday),
+ (b"4".as_slice(), Weekday::Friday),
+ (b"5".as_slice(), Weekday::Saturday),
+ (b"6".as_slice(), Weekday::Sunday),
+ ],
+ (modifier::WeekdayRepr::Monday, true) => [
+ (b"1".as_slice(), Weekday::Monday),
+ (b"2".as_slice(), Weekday::Tuesday),
+ (b"3".as_slice(), Weekday::Wednesday),
+ (b"4".as_slice(), Weekday::Thursday),
+ (b"5".as_slice(), Weekday::Friday),
+ (b"6".as_slice(), Weekday::Saturday),
+ (b"7".as_slice(), Weekday::Sunday),
+ ],
+ },
+ modifiers.case_sensitive,
+ )(input)
+}
+
+/// Parse the "ordinal" component of a `Date`.
+pub(crate) fn parse_ordinal(
+ input: &[u8],
+ modifiers: modifier::Ordinal,
+) -> Option<ParsedItem<'_, NonZeroU16>> {
+ exactly_n_digits_padded::<3, _>(modifiers.padding)(input)
+}
+
+/// Parse the "day" component of a `Date`.
+pub(crate) fn parse_day(
+ input: &[u8],
+ modifiers: modifier::Day,
+) -> Option<ParsedItem<'_, NonZeroU8>> {
+ exactly_n_digits_padded::<2, _>(modifiers.padding)(input)
+}
+
+/// Indicate whether the hour is "am" or "pm".
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub(crate) enum Period {
+ #[allow(clippy::missing_docs_in_private_items)]
+ Am,
+ #[allow(clippy::missing_docs_in_private_items)]
+ Pm,
+}
+
+/// Parse the "hour" component of a `Time`.
+pub(crate) fn parse_hour(input: &[u8], modifiers: modifier::Hour) -> Option<ParsedItem<'_, u8>> {
+ exactly_n_digits_padded::<2, _>(modifiers.padding)(input)
+}
+
+/// Parse the "minute" component of a `Time`.
+pub(crate) fn parse_minute(
+ input: &[u8],
+ modifiers: modifier::Minute,
+) -> Option<ParsedItem<'_, u8>> {
+ exactly_n_digits_padded::<2, _>(modifiers.padding)(input)
+}
+
+/// Parse the "second" component of a `Time`.
+pub(crate) fn parse_second(
+ input: &[u8],
+ modifiers: modifier::Second,
+) -> Option<ParsedItem<'_, u8>> {
+ exactly_n_digits_padded::<2, _>(modifiers.padding)(input)
+}
+
+/// Parse the "period" component of a `Time`. Required if the hour is on a 12-hour clock.
+pub(crate) fn parse_period(
+ input: &[u8],
+ modifiers: modifier::Period,
+) -> Option<ParsedItem<'_, Period>> {
+ first_match(
+ if modifiers.is_uppercase {
+ [
+ (b"AM".as_slice(), Period::Am),
+ (b"PM".as_slice(), Period::Pm),
+ ]
+ } else {
+ [
+ (b"am".as_slice(), Period::Am),
+ (b"pm".as_slice(), Period::Pm),
+ ]
+ },
+ modifiers.case_sensitive,
+ )(input)
+}
+
+/// Parse the "subsecond" component of a `Time`.
+pub(crate) fn parse_subsecond(
+ input: &[u8],
+ modifiers: modifier::Subsecond,
+) -> Option<ParsedItem<'_, u32>> {
+ use modifier::SubsecondDigits::*;
+ Some(match modifiers.digits {
+ One => exactly_n_digits::<1, u32>(input)?.map(|v| v * 100_000_000),
+ Two => exactly_n_digits::<2, u32>(input)?.map(|v| v * 10_000_000),
+ Three => exactly_n_digits::<3, u32>(input)?.map(|v| v * 1_000_000),
+ Four => exactly_n_digits::<4, u32>(input)?.map(|v| v * 100_000),
+ Five => exactly_n_digits::<5, u32>(input)?.map(|v| v * 10_000),
+ Six => exactly_n_digits::<6, u32>(input)?.map(|v| v * 1_000),
+ Seven => exactly_n_digits::<7, u32>(input)?.map(|v| v * 100),
+ Eight => exactly_n_digits::<8, u32>(input)?.map(|v| v * 10),
+ Nine => exactly_n_digits::<9, _>(input)?,
+ OneOrMore => {
+ let ParsedItem(mut input, mut value) =
+ any_digit(input)?.map(|v| (v - b'0').extend::<u32>() * 100_000_000);
+
+ let mut multiplier = 10_000_000;
+ while let Some(ParsedItem(new_input, digit)) = any_digit(input) {
+ value += (digit - b'0').extend::<u32>() * multiplier;
+ input = new_input;
+ multiplier /= 10;
+ }
+
+ ParsedItem(input, value)
+ }
+ })
+}
+
+/// Parse the "hour" component of a `UtcOffset`.
+///
+/// Returns the value and whether the value is negative. This is used for when "-0" is parsed.
+pub(crate) fn parse_offset_hour(
+ input: &[u8],
+ modifiers: modifier::OffsetHour,
+) -> Option<ParsedItem<'_, (i8, bool)>> {
+ let ParsedItem(input, sign) = opt(sign)(input);
+ let ParsedItem(input, hour) = exactly_n_digits_padded::<2, u8>(modifiers.padding)(input)?;
+ match sign {
+ Some(b'-') => Some(ParsedItem(input, (-hour.cast_signed(), true))),
+ None if modifiers.sign_is_mandatory => None,
+ _ => Some(ParsedItem(input, (hour.cast_signed(), false))),
+ }
+}
+
+/// Parse the "minute" component of a `UtcOffset`.
+pub(crate) fn parse_offset_minute(
+ input: &[u8],
+ modifiers: modifier::OffsetMinute,
+) -> Option<ParsedItem<'_, i8>> {
+ Some(
+ exactly_n_digits_padded::<2, u8>(modifiers.padding)(input)?
+ .map(|offset_minute| offset_minute.cast_signed()),
+ )
+}
+
+/// Parse the "second" component of a `UtcOffset`.
+pub(crate) fn parse_offset_second(
+ input: &[u8],
+ modifiers: modifier::OffsetSecond,
+) -> Option<ParsedItem<'_, i8>> {
+ Some(
+ exactly_n_digits_padded::<2, u8>(modifiers.padding)(input)?
+ .map(|offset_second| offset_second.cast_signed()),
+ )
+}
+
+/// Ignore the given number of bytes.
+pub(crate) fn parse_ignore(
+ input: &[u8],
+ modifiers: modifier::Ignore,
+) -> Option<ParsedItem<'_, ()>> {
+ let modifier::Ignore { count } = modifiers;
+ let input = input.get((count.get().extend())..)?;
+ Some(ParsedItem(input, ()))
+}
+
+/// Parse the Unix timestamp component.
+pub(crate) fn parse_unix_timestamp(
+ input: &[u8],
+ modifiers: modifier::UnixTimestamp,
+) -> Option<ParsedItem<'_, i128>> {
+ let ParsedItem(input, sign) = opt(sign)(input);
+ let ParsedItem(input, nano_timestamp) = match modifiers.precision {
+ modifier::UnixTimestampPrecision::Second => n_to_m_digits::<1, 14, u128>(input)?
+ .map(|val| val * Nanosecond::per(Second).extend::<u128>()),
+ modifier::UnixTimestampPrecision::Millisecond => n_to_m_digits::<1, 17, u128>(input)?
+ .map(|val| val * Nanosecond::per(Millisecond).extend::<u128>()),
+ modifier::UnixTimestampPrecision::Microsecond => n_to_m_digits::<1, 20, u128>(input)?
+ .map(|val| val * Nanosecond::per(Microsecond).extend::<u128>()),
+ modifier::UnixTimestampPrecision::Nanosecond => n_to_m_digits::<1, 23, _>(input)?,
+ };
+
+ match sign {
+ Some(b'-') => Some(ParsedItem(input, -nano_timestamp.cast_signed())),
+ None if modifiers.sign_is_mandatory => None,
+ _ => Some(ParsedItem(input, nano_timestamp.cast_signed())),
+ }
+}
+
+/// Parse the `end` component, which represents the end of input. If any input is remaining, `None`
+/// is returned.
+pub(crate) const fn parse_end(input: &[u8], end: modifier::End) -> Option<ParsedItem<'_, ()>> {
+ let modifier::End {} = end;
+
+ if input.is_empty() {
+ Some(ParsedItem(input, ()))
+ } else {
+ None
+ }
+}
diff --git a/vendor/time/src/parsing/iso8601.rs b/vendor/time/src/parsing/iso8601.rs
new file mode 100644
index 00000000..a57d6274
--- /dev/null
+++ b/vendor/time/src/parsing/iso8601.rs
@@ -0,0 +1,332 @@
+//! Parse parts of an ISO 8601-formatted value.
+
+use num_conv::prelude::*;
+
+use crate::convert::*;
+use crate::error;
+use crate::error::ParseFromDescription::{InvalidComponent, InvalidLiteral};
+use crate::format_description::well_known::iso8601::EncodedConfig;
+use crate::format_description::well_known::Iso8601;
+use crate::parsing::combinator::rfc::iso8601::{
+ day, dayk, dayo, float, hour, min, month, week, year, ExtendedKind,
+};
+use crate::parsing::combinator::{ascii_char, sign};
+use crate::parsing::{Parsed, ParsedItem};
+
+impl<const CONFIG: EncodedConfig> Iso8601<CONFIG> {
+ // Basic: [year][month][day]
+ // Extended: [year]["-"][month]["-"][day]
+ // Basic: [year][dayo]
+ // Extended: [year]["-"][dayo]
+ // Basic: [year]["W"][week][dayk]
+ // Extended: [year]["-"]["W"][week]["-"][dayk]
+ /// Parse a date in the basic or extended format. Reduced precision is permitted.
+ pub(crate) fn parse_date<'a>(
+ parsed: &'a mut Parsed,
+ extended_kind: &'a mut ExtendedKind,
+ ) -> impl FnMut(&[u8]) -> Result<&[u8], error::Parse> + 'a {
+ move |input| {
+ // Same for any acceptable format.
+ let ParsedItem(mut input, year) = year(input).ok_or(InvalidComponent("year"))?;
+ *extended_kind = match ascii_char::<b'-'>(input) {
+ Some(ParsedItem(new_input, ())) => {
+ input = new_input;
+ ExtendedKind::Extended
+ }
+ None => ExtendedKind::Basic, // no separator before mandatory month/ordinal/week
+ };
+
+ let parsed_month_day = (|| {
+ let ParsedItem(mut input, month) = month(input).ok_or(InvalidComponent("month"))?;
+ if extended_kind.is_extended() {
+ input = ascii_char::<b'-'>(input)
+ .ok_or(InvalidLiteral)?
+ .into_inner();
+ }
+ let ParsedItem(input, day) = day(input).ok_or(InvalidComponent("day"))?;
+ Ok(ParsedItem(input, (month, day)))
+ })();
+ let mut ret_error = match parsed_month_day {
+ Ok(ParsedItem(input, (month, day))) => {
+ *parsed = parsed
+ .with_year(year)
+ .ok_or(InvalidComponent("year"))?
+ .with_month(month)
+ .ok_or(InvalidComponent("month"))?
+ .with_day(day)
+ .ok_or(InvalidComponent("day"))?;
+ return Ok(input);
+ }
+ Err(err) => err,
+ };
+
+ // Don't check for `None`, as the error from year-month-day will always take priority.
+ if let Some(ParsedItem(input, ordinal)) = dayo(input) {
+ *parsed = parsed
+ .with_year(year)
+ .ok_or(InvalidComponent("year"))?
+ .with_ordinal(ordinal)
+ .ok_or(InvalidComponent("ordinal"))?;
+ return Ok(input);
+ }
+
+ let parsed_week_weekday = (|| {
+ let input = ascii_char::<b'W'>(input)
+ .ok_or((false, InvalidLiteral))?
+ .into_inner();
+ let ParsedItem(mut input, week) =
+ week(input).ok_or((true, InvalidComponent("week")))?;
+ if extended_kind.is_extended() {
+ input = ascii_char::<b'-'>(input)
+ .ok_or((true, InvalidLiteral))?
+ .into_inner();
+ }
+ let ParsedItem(input, weekday) =
+ dayk(input).ok_or((true, InvalidComponent("weekday")))?;
+ Ok(ParsedItem(input, (week, weekday)))
+ })();
+ match parsed_week_weekday {
+ Ok(ParsedItem(input, (week, weekday))) => {
+ *parsed = parsed
+ .with_iso_year(year)
+ .ok_or(InvalidComponent("year"))?
+ .with_iso_week_number(week)
+ .ok_or(InvalidComponent("week"))?
+ .with_weekday(weekday)
+ .ok_or(InvalidComponent("weekday"))?;
+ return Ok(input);
+ }
+ Err((false, _err)) => {}
+ // This error is more accurate than the one from year-month-day.
+ Err((true, err)) => ret_error = err,
+ }
+
+ Err(ret_error.into())
+ }
+ }
+
+ // Basic: ["T"][hour][min][sec]
+ // Extended: ["T"][hour][":"][min][":"][sec]
+ // Reduced precision: components after [hour] (including their preceding separator) can be
+ // omitted. ["T"] can be omitted if there is no date present.
+ /// Parse a time in the basic or extended format. Reduced precision is permitted.
+ pub(crate) fn parse_time<'a>(
+ parsed: &'a mut Parsed,
+ extended_kind: &'a mut ExtendedKind,
+ date_is_present: bool,
+ ) -> impl FnMut(&[u8]) -> Result<&[u8], error::Parse> + 'a {
+ move |mut input| {
+ if date_is_present {
+ input = ascii_char::<b'T'>(input)
+ .ok_or(InvalidLiteral)?
+ .into_inner();
+ }
+
+ let ParsedItem(mut input, hour) = float(input).ok_or(InvalidComponent("hour"))?;
+ match hour {
+ (hour, None) => parsed.set_hour_24(hour).ok_or(InvalidComponent("hour"))?,
+ (hour, Some(fractional_part)) => {
+ *parsed = parsed
+ .with_hour_24(hour)
+ .ok_or(InvalidComponent("hour"))?
+ .with_minute((fractional_part * Second::per(Minute) as f64) as u8)
+ .ok_or(InvalidComponent("minute"))?
+ .with_second(
+ (fractional_part * Second::per(Hour) as f64 % Minute::per(Hour) as f64)
+ as u8,
+ )
+ .ok_or(InvalidComponent("second"))?
+ .with_subsecond(
+ (fractional_part * Nanosecond::per(Hour) as f64
+ % Nanosecond::per(Second) as f64)
+ as u32,
+ )
+ .ok_or(InvalidComponent("subsecond"))?;
+ return Ok(input);
+ }
+ };
+
+ if let Some(ParsedItem(new_input, ())) = ascii_char::<b':'>(input) {
+ extended_kind
+ .coerce_extended()
+ .ok_or(InvalidComponent("minute"))?;
+ input = new_input;
+ };
+
+ let mut input = match float(input) {
+ Some(ParsedItem(input, (minute, None))) => {
+ extended_kind.coerce_basic();
+ parsed
+ .set_minute(minute)
+ .ok_or(InvalidComponent("minute"))?;
+ input
+ }
+ Some(ParsedItem(input, (minute, Some(fractional_part)))) => {
+ // `None` is valid behavior, so don't error if this fails.
+ extended_kind.coerce_basic();
+ *parsed = parsed
+ .with_minute(minute)
+ .ok_or(InvalidComponent("minute"))?
+ .with_second((fractional_part * Second::per(Minute) as f64) as u8)
+ .ok_or(InvalidComponent("second"))?
+ .with_subsecond(
+ (fractional_part * Nanosecond::per(Minute) as f64
+ % Nanosecond::per(Second) as f64)
+ as u32,
+ )
+ .ok_or(InvalidComponent("subsecond"))?;
+ return Ok(input);
+ }
+ // colon was present, so minutes are required
+ None if extended_kind.is_extended() => {
+ return Err(error::Parse::ParseFromDescription(InvalidComponent(
+ "minute",
+ )));
+ }
+ None => {
+ // Missing components are assumed to be zero.
+ *parsed = parsed
+ .with_minute(0)
+ .ok_or(InvalidComponent("minute"))?
+ .with_second(0)
+ .ok_or(InvalidComponent("second"))?
+ .with_subsecond(0)
+ .ok_or(InvalidComponent("subsecond"))?;
+ return Ok(input);
+ }
+ };
+
+ if extended_kind.is_extended() {
+ match ascii_char::<b':'>(input) {
+ Some(ParsedItem(new_input, ())) => input = new_input,
+ None => {
+ *parsed = parsed
+ .with_second(0)
+ .ok_or(InvalidComponent("second"))?
+ .with_subsecond(0)
+ .ok_or(InvalidComponent("subsecond"))?;
+ return Ok(input);
+ }
+ }
+ }
+
+ let (input, second, subsecond) = match float(input) {
+ Some(ParsedItem(input, (second, None))) => (input, second, 0),
+ Some(ParsedItem(input, (second, Some(fractional_part)))) => (
+ input,
+ second,
+ round(fractional_part * Nanosecond::per(Second) as f64) as u32,
+ ),
+ None if extended_kind.is_extended() => {
+ return Err(error::Parse::ParseFromDescription(InvalidComponent(
+ "second",
+ )));
+ }
+ // Missing components are assumed to be zero.
+ None => (input, 0, 0),
+ };
+ *parsed = parsed
+ .with_second(second)
+ .ok_or(InvalidComponent("second"))?
+ .with_subsecond(subsecond)
+ .ok_or(InvalidComponent("subsecond"))?;
+
+ Ok(input)
+ }
+ }
+
+ // Basic: [±][hour][min] or ["Z"]
+ // Extended: [±][hour][":"][min] or ["Z"]
+ // Reduced precision: [±][hour] or ["Z"]
+ /// Parse a UTC offset in the basic or extended format. Reduced precision is supported.
+ pub(crate) fn parse_offset<'a>(
+ parsed: &'a mut Parsed,
+ extended_kind: &'a mut ExtendedKind,
+ ) -> impl FnMut(&[u8]) -> Result<&[u8], error::Parse> + 'a {
+ move |input| {
+ if let Some(ParsedItem(input, ())) = ascii_char::<b'Z'>(input) {
+ *parsed = parsed
+ .with_offset_hour(0)
+ .ok_or(InvalidComponent("offset hour"))?
+ .with_offset_minute_signed(0)
+ .ok_or(InvalidComponent("offset minute"))?
+ .with_offset_second_signed(0)
+ .ok_or(InvalidComponent("offset second"))?;
+ return Ok(input);
+ }
+
+ let ParsedItem(input, sign) = sign(input).ok_or(InvalidComponent("offset hour"))?;
+ let mut input = hour(input)
+ .and_then(|parsed_item| {
+ parsed_item.consume_value(|hour| {
+ parsed.set_offset_hour(if sign == b'-' {
+ -hour.cast_signed()
+ } else {
+ hour.cast_signed()
+ })
+ })
+ })
+ .ok_or(InvalidComponent("offset hour"))?;
+
+ if extended_kind.maybe_extended() {
+ if let Some(ParsedItem(new_input, ())) = ascii_char::<b':'>(input) {
+ extended_kind
+ .coerce_extended()
+ .ok_or(InvalidComponent("offset minute"))?;
+ input = new_input;
+ };
+ }
+
+ match min(input) {
+ Some(ParsedItem(new_input, min)) => {
+ input = new_input;
+ parsed
+ .set_offset_minute_signed(if sign == b'-' {
+ -min.cast_signed()
+ } else {
+ min.cast_signed()
+ })
+ .ok_or(InvalidComponent("offset minute"))?;
+ }
+ None => {
+ // Omitted offset minute is assumed to be zero.
+ parsed.set_offset_minute_signed(0);
+ }
+ }
+
+ // If `:` was present, the format has already been set to extended. As such, this call
+ // will do nothing in that case. If there wasn't `:` but minutes were
+ // present, we know it's the basic format. Do not use `?` on the call, as
+ // returning `None` is valid behavior.
+ extended_kind.coerce_basic();
+
+ Ok(input)
+ }
+ }
+}
+
+/// Round wrapper that uses hardware implementation if `std` is available, falling back to manual
+/// implementation for `no_std`
+fn round(value: f64) -> f64 {
+ #[cfg(feature = "std")]
+ {
+ value.round()
+ }
+ #[cfg(not(feature = "std"))]
+ {
+ round_impl(value)
+ }
+}
+
+#[cfg(not(feature = "std"))]
+#[allow(clippy::missing_docs_in_private_items)]
+fn round_impl(value: f64) -> f64 {
+ debug_assert!(value.is_sign_positive() && !value.is_nan());
+
+ let f = value % 1.;
+ if f < 0.5 {
+ value - f
+ } else {
+ value - f + 1.
+ }
+}
diff --git a/vendor/time/src/parsing/mod.rs b/vendor/time/src/parsing/mod.rs
new file mode 100644
index 00000000..34e92736
--- /dev/null
+++ b/vendor/time/src/parsing/mod.rs
@@ -0,0 +1,57 @@
+//! Parsing for various types.
+
+pub(crate) mod combinator;
+pub(crate) mod component;
+mod iso8601;
+pub(crate) mod parsable;
+mod parsed;
+pub(crate) mod shim;
+
+pub use self::parsable::Parsable;
+pub use self::parsed::Parsed;
+
+/// An item that has been parsed. Represented as a `(remaining, value)` pair.
+#[derive(Debug)]
+pub(crate) struct ParsedItem<'a, T>(pub(crate) &'a [u8], pub(crate) T);
+
+impl<'a, T> ParsedItem<'a, T> {
+ /// Map the value to a new value, preserving the remaining input.
+ pub(crate) fn map<U>(self, f: impl FnOnce(T) -> U) -> ParsedItem<'a, U> {
+ ParsedItem(self.0, f(self.1))
+ }
+
+ /// Map the value to a new, optional value, preserving the remaining input.
+ pub(crate) fn flat_map<U>(self, f: impl FnOnce(T) -> Option<U>) -> Option<ParsedItem<'a, U>> {
+ Some(ParsedItem(self.0, f(self.1)?))
+ }
+
+ /// Consume the stored value with the provided function. The remaining input is returned.
+ #[must_use = "this returns the remaining input"]
+ pub(crate) fn consume_value(self, f: impl FnOnce(T) -> Option<()>) -> Option<&'a [u8]> {
+ f(self.1)?;
+ Some(self.0)
+ }
+
+ /// Filter the value with the provided function. If the function returns `false`, the value
+ /// is discarded and `None` is returned. Otherwise, the value is preserved and `Some(self)` is
+ /// returned.
+ pub(crate) fn filter(self, f: impl FnOnce(&T) -> bool) -> Option<Self> {
+ f(&self.1).then_some(self)
+ }
+}
+
+impl<'a> ParsedItem<'a, ()> {
+ /// Discard the unit value, returning the remaining input.
+ #[must_use = "this returns the remaining input"]
+ pub(crate) const fn into_inner(self) -> &'a [u8] {
+ self.0
+ }
+}
+
+impl<'a> ParsedItem<'a, Option<()>> {
+ /// Discard the potential unit value, returning the remaining input.
+ #[must_use = "this returns the remaining input"]
+ pub(crate) const fn into_inner(self) -> &'a [u8] {
+ self.0
+ }
+}
diff --git a/vendor/time/src/parsing/parsable.rs b/vendor/time/src/parsing/parsable.rs
new file mode 100644
index 00000000..c631c5fe
--- /dev/null
+++ b/vendor/time/src/parsing/parsable.rs
@@ -0,0 +1,800 @@
+//! A trait that can be used to parse an item from an input.
+
+use core::ops::Deref;
+
+use num_conv::prelude::*;
+
+use crate::error::TryFromParsed;
+use crate::format_description::well_known::iso8601::EncodedConfig;
+use crate::format_description::well_known::{Iso8601, Rfc2822, Rfc3339};
+use crate::format_description::BorrowedFormatItem;
+#[cfg(feature = "alloc")]
+use crate::format_description::OwnedFormatItem;
+use crate::internal_macros::bug;
+use crate::parsing::{Parsed, ParsedItem};
+use crate::{error, Date, Month, OffsetDateTime, Time, UtcOffset, Weekday};
+
+/// A type that can be parsed.
+#[cfg_attr(docsrs, doc(notable_trait))]
+#[doc(alias = "Parseable")]
+pub trait Parsable: sealed::Sealed {}
+impl Parsable for BorrowedFormatItem<'_> {}
+impl Parsable for [BorrowedFormatItem<'_>] {}
+#[cfg(feature = "alloc")]
+impl Parsable for OwnedFormatItem {}
+#[cfg(feature = "alloc")]
+impl Parsable for [OwnedFormatItem] {}
+impl Parsable for Rfc2822 {}
+impl Parsable for Rfc3339 {}
+impl<const CONFIG: EncodedConfig> Parsable for Iso8601<CONFIG> {}
+impl<T: Deref> Parsable for T where T::Target: Parsable {}
+
+/// Seal the trait to prevent downstream users from implementing it, while still allowing it to
+/// exist in generic bounds.
+mod sealed {
+ #[allow(clippy::wildcard_imports)]
+ use super::*;
+ use crate::{PrimitiveDateTime, UtcDateTime};
+
+ /// Parse the item using a format description and an input.
+ pub trait Sealed {
+ /// Parse the item into the provided [`Parsed`] struct.
+ ///
+ /// This method can be used to parse a single component without parsing the full value.
+ fn parse_into<'a>(
+ &self,
+ input: &'a [u8],
+ parsed: &mut Parsed,
+ ) -> Result<&'a [u8], error::Parse>;
+
+ /// Parse the item into a new [`Parsed`] struct.
+ ///
+ /// This method can only be used to parse a complete value of a type. If any characters
+ /// remain after parsing, an error will be returned.
+ fn parse(&self, input: &[u8]) -> Result<Parsed, error::Parse> {
+ let mut parsed = Parsed::new();
+ if self.parse_into(input, &mut parsed)?.is_empty() {
+ Ok(parsed)
+ } else {
+ Err(error::Parse::ParseFromDescription(
+ error::ParseFromDescription::UnexpectedTrailingCharacters,
+ ))
+ }
+ }
+
+ /// Parse a [`Date`] from the format description.
+ fn parse_date(&self, input: &[u8]) -> Result<Date, error::Parse> {
+ Ok(self.parse(input)?.try_into()?)
+ }
+
+ /// Parse a [`Time`] from the format description.
+ fn parse_time(&self, input: &[u8]) -> Result<Time, error::Parse> {
+ Ok(self.parse(input)?.try_into()?)
+ }
+
+ /// Parse a [`UtcOffset`] from the format description.
+ fn parse_offset(&self, input: &[u8]) -> Result<UtcOffset, error::Parse> {
+ Ok(self.parse(input)?.try_into()?)
+ }
+
+ /// Parse a [`PrimitiveDateTime`] from the format description.
+ fn parse_primitive_date_time(
+ &self,
+ input: &[u8],
+ ) -> Result<PrimitiveDateTime, error::Parse> {
+ Ok(self.parse(input)?.try_into()?)
+ }
+
+ /// Parse a [`UtcDateTime`] from the format description.
+ fn parse_utc_date_time(&self, input: &[u8]) -> Result<UtcDateTime, error::Parse> {
+ Ok(self.parse(input)?.try_into()?)
+ }
+
+ /// Parse a [`OffsetDateTime`] from the format description.
+ fn parse_offset_date_time(&self, input: &[u8]) -> Result<OffsetDateTime, error::Parse> {
+ Ok(self.parse(input)?.try_into()?)
+ }
+ }
+}
+
+impl sealed::Sealed for BorrowedFormatItem<'_> {
+ fn parse_into<'a>(
+ &self,
+ input: &'a [u8],
+ parsed: &mut Parsed,
+ ) -> Result<&'a [u8], error::Parse> {
+ Ok(parsed.parse_item(input, self)?)
+ }
+}
+
+impl sealed::Sealed for [BorrowedFormatItem<'_>] {
+ fn parse_into<'a>(
+ &self,
+ input: &'a [u8],
+ parsed: &mut Parsed,
+ ) -> Result<&'a [u8], error::Parse> {
+ Ok(parsed.parse_items(input, self)?)
+ }
+}
+
+#[cfg(feature = "alloc")]
+impl sealed::Sealed for OwnedFormatItem {
+ fn parse_into<'a>(
+ &self,
+ input: &'a [u8],
+ parsed: &mut Parsed,
+ ) -> Result<&'a [u8], error::Parse> {
+ Ok(parsed.parse_item(input, self)?)
+ }
+}
+
+#[cfg(feature = "alloc")]
+impl sealed::Sealed for [OwnedFormatItem] {
+ fn parse_into<'a>(
+ &self,
+ input: &'a [u8],
+ parsed: &mut Parsed,
+ ) -> Result<&'a [u8], error::Parse> {
+ Ok(parsed.parse_items(input, self)?)
+ }
+}
+
+impl<T: Deref> sealed::Sealed for T
+where
+ T::Target: sealed::Sealed,
+{
+ fn parse_into<'a>(
+ &self,
+ input: &'a [u8],
+ parsed: &mut Parsed,
+ ) -> Result<&'a [u8], error::Parse> {
+ self.deref().parse_into(input, parsed)
+ }
+}
+
+impl sealed::Sealed for Rfc2822 {
+ fn parse_into<'a>(
+ &self,
+ input: &'a [u8],
+ parsed: &mut Parsed,
+ ) -> Result<&'a [u8], error::Parse> {
+ use crate::error::ParseFromDescription::{InvalidComponent, InvalidLiteral};
+ use crate::parsing::combinator::rfc::rfc2822::{cfws, fws};
+ use crate::parsing::combinator::{
+ ascii_char, exactly_n_digits, first_match, n_to_m_digits, opt, sign,
+ };
+
+ let colon = ascii_char::<b':'>;
+ let comma = ascii_char::<b','>;
+
+ let input = opt(cfws)(input).into_inner();
+ let weekday = first_match(
+ [
+ (b"Mon".as_slice(), Weekday::Monday),
+ (b"Tue".as_slice(), Weekday::Tuesday),
+ (b"Wed".as_slice(), Weekday::Wednesday),
+ (b"Thu".as_slice(), Weekday::Thursday),
+ (b"Fri".as_slice(), Weekday::Friday),
+ (b"Sat".as_slice(), Weekday::Saturday),
+ (b"Sun".as_slice(), Weekday::Sunday),
+ ],
+ false,
+ )(input);
+ let input = if let Some(item) = weekday {
+ let input = item
+ .consume_value(|value| parsed.set_weekday(value))
+ .ok_or(InvalidComponent("weekday"))?;
+ let input = comma(input).ok_or(InvalidLiteral)?.into_inner();
+ opt(cfws)(input).into_inner()
+ } else {
+ input
+ };
+ let input = n_to_m_digits::<1, 2, _>(input)
+ .and_then(|item| item.consume_value(|value| parsed.set_day(value)))
+ .ok_or(InvalidComponent("day"))?;
+ let input = cfws(input).ok_or(InvalidLiteral)?.into_inner();
+ let input = first_match(
+ [
+ (b"Jan".as_slice(), Month::January),
+ (b"Feb".as_slice(), Month::February),
+ (b"Mar".as_slice(), Month::March),
+ (b"Apr".as_slice(), Month::April),
+ (b"May".as_slice(), Month::May),
+ (b"Jun".as_slice(), Month::June),
+ (b"Jul".as_slice(), Month::July),
+ (b"Aug".as_slice(), Month::August),
+ (b"Sep".as_slice(), Month::September),
+ (b"Oct".as_slice(), Month::October),
+ (b"Nov".as_slice(), Month::November),
+ (b"Dec".as_slice(), Month::December),
+ ],
+ false,
+ )(input)
+ .and_then(|item| item.consume_value(|value| parsed.set_month(value)))
+ .ok_or(InvalidComponent("month"))?;
+ let input = cfws(input).ok_or(InvalidLiteral)?.into_inner();
+ let input = match exactly_n_digits::<4, u32>(input) {
+ Some(item) => {
+ let input = item
+ .flat_map(|year| if year >= 1900 { Some(year) } else { None })
+ .and_then(|item| {
+ item.consume_value(|value| parsed.set_year(value.cast_signed()))
+ })
+ .ok_or(InvalidComponent("year"))?;
+ fws(input).ok_or(InvalidLiteral)?.into_inner()
+ }
+ None => {
+ let input = exactly_n_digits::<2, u32>(input)
+ .and_then(|item| {
+ item.map(|year| if year < 50 { year + 2000 } else { year + 1900 })
+ .map(|year| year.cast_signed())
+ .consume_value(|value| parsed.set_year(value))
+ })
+ .ok_or(InvalidComponent("year"))?;
+ cfws(input).ok_or(InvalidLiteral)?.into_inner()
+ }
+ };
+
+ let input = exactly_n_digits::<2, _>(input)
+ .and_then(|item| item.consume_value(|value| parsed.set_hour_24(value)))
+ .ok_or(InvalidComponent("hour"))?;
+ let input = opt(cfws)(input).into_inner();
+ let input = colon(input).ok_or(InvalidLiteral)?.into_inner();
+ let input = opt(cfws)(input).into_inner();
+ let input = exactly_n_digits::<2, _>(input)
+ .and_then(|item| item.consume_value(|value| parsed.set_minute(value)))
+ .ok_or(InvalidComponent("minute"))?;
+
+ let input = if let Some(input) = colon(opt(cfws)(input).into_inner()) {
+ let input = input.into_inner(); // discard the colon
+ let input = opt(cfws)(input).into_inner();
+ let input = exactly_n_digits::<2, _>(input)
+ .and_then(|item| item.consume_value(|value| parsed.set_second(value)))
+ .ok_or(InvalidComponent("second"))?;
+ cfws(input).ok_or(InvalidLiteral)?.into_inner()
+ } else {
+ cfws(input).ok_or(InvalidLiteral)?.into_inner()
+ };
+
+ // The RFC explicitly allows leap seconds.
+ parsed.leap_second_allowed = true;
+
+ #[allow(clippy::unnecessary_lazy_evaluations)] // rust-lang/rust-clippy#8522
+ let zone_literal = first_match(
+ [
+ (b"UT".as_slice(), 0),
+ (b"GMT".as_slice(), 0),
+ (b"EST".as_slice(), -5),
+ (b"EDT".as_slice(), -4),
+ (b"CST".as_slice(), -6),
+ (b"CDT".as_slice(), -5),
+ (b"MST".as_slice(), -7),
+ (b"MDT".as_slice(), -6),
+ (b"PST".as_slice(), -8),
+ (b"PDT".as_slice(), -7),
+ ],
+ false,
+ )(input)
+ .or_else(|| match input {
+ [b'a'..=b'i' | b'k'..=b'z' | b'A'..=b'I' | b'K'..=b'Z', rest @ ..] => {
+ Some(ParsedItem(rest, 0))
+ }
+ _ => None,
+ });
+ if let Some(zone_literal) = zone_literal {
+ let input = zone_literal
+ .consume_value(|value| parsed.set_offset_hour(value))
+ .ok_or(InvalidComponent("offset hour"))?;
+ parsed
+ .set_offset_minute_signed(0)
+ .ok_or(InvalidComponent("offset minute"))?;
+ parsed
+ .set_offset_second_signed(0)
+ .ok_or(InvalidComponent("offset second"))?;
+ return Ok(input);
+ }
+
+ let ParsedItem(input, offset_sign) = sign(input).ok_or(InvalidComponent("offset hour"))?;
+ let input = exactly_n_digits::<2, u8>(input)
+ .and_then(|item| {
+ item.map(|offset_hour| {
+ if offset_sign == b'-' {
+ -offset_hour.cast_signed()
+ } else {
+ offset_hour.cast_signed()
+ }
+ })
+ .consume_value(|value| parsed.set_offset_hour(value))
+ })
+ .ok_or(InvalidComponent("offset hour"))?;
+ let input = exactly_n_digits::<2, u8>(input)
+ .and_then(|item| {
+ item.consume_value(|value| parsed.set_offset_minute_signed(value.cast_signed()))
+ })
+ .ok_or(InvalidComponent("offset minute"))?;
+
+ let input = opt(cfws)(input).into_inner();
+
+ Ok(input)
+ }
+
+ fn parse_offset_date_time(&self, input: &[u8]) -> Result<OffsetDateTime, error::Parse> {
+ use crate::error::ParseFromDescription::{InvalidComponent, InvalidLiteral};
+ use crate::parsing::combinator::rfc::rfc2822::{cfws, fws};
+ use crate::parsing::combinator::{
+ ascii_char, exactly_n_digits, first_match, n_to_m_digits, opt, sign,
+ };
+
+ let colon = ascii_char::<b':'>;
+ let comma = ascii_char::<b','>;
+
+ let input = opt(cfws)(input).into_inner();
+ // This parses the weekday, but we don't actually use the value anywhere. Because of this,
+ // just return `()` to avoid unnecessary generated code.
+ let weekday = first_match(
+ [
+ (b"Mon".as_slice(), ()),
+ (b"Tue".as_slice(), ()),
+ (b"Wed".as_slice(), ()),
+ (b"Thu".as_slice(), ()),
+ (b"Fri".as_slice(), ()),
+ (b"Sat".as_slice(), ()),
+ (b"Sun".as_slice(), ()),
+ ],
+ false,
+ )(input);
+ let input = if let Some(item) = weekday {
+ let input = item.into_inner();
+ let input = comma(input).ok_or(InvalidLiteral)?.into_inner();
+ opt(cfws)(input).into_inner()
+ } else {
+ input
+ };
+ let ParsedItem(input, day) =
+ n_to_m_digits::<1, 2, _>(input).ok_or(InvalidComponent("day"))?;
+ let input = cfws(input).ok_or(InvalidLiteral)?.into_inner();
+ let ParsedItem(input, month) = first_match(
+ [
+ (b"Jan".as_slice(), Month::January),
+ (b"Feb".as_slice(), Month::February),
+ (b"Mar".as_slice(), Month::March),
+ (b"Apr".as_slice(), Month::April),
+ (b"May".as_slice(), Month::May),
+ (b"Jun".as_slice(), Month::June),
+ (b"Jul".as_slice(), Month::July),
+ (b"Aug".as_slice(), Month::August),
+ (b"Sep".as_slice(), Month::September),
+ (b"Oct".as_slice(), Month::October),
+ (b"Nov".as_slice(), Month::November),
+ (b"Dec".as_slice(), Month::December),
+ ],
+ false,
+ )(input)
+ .ok_or(InvalidComponent("month"))?;
+ let input = cfws(input).ok_or(InvalidLiteral)?.into_inner();
+ let (input, year) = match exactly_n_digits::<4, u32>(input) {
+ Some(item) => {
+ let ParsedItem(input, year) = item
+ .flat_map(|year| if year >= 1900 { Some(year) } else { None })
+ .ok_or(InvalidComponent("year"))?;
+ let input = fws(input).ok_or(InvalidLiteral)?.into_inner();
+ (input, year)
+ }
+ None => {
+ let ParsedItem(input, year) = exactly_n_digits::<2, u32>(input)
+ .map(|item| item.map(|year| if year < 50 { year + 2000 } else { year + 1900 }))
+ .ok_or(InvalidComponent("year"))?;
+ let input = cfws(input).ok_or(InvalidLiteral)?.into_inner();
+ (input, year)
+ }
+ };
+
+ let ParsedItem(input, hour) =
+ exactly_n_digits::<2, _>(input).ok_or(InvalidComponent("hour"))?;
+ let input = opt(cfws)(input).into_inner();
+ let input = colon(input).ok_or(InvalidLiteral)?.into_inner();
+ let input = opt(cfws)(input).into_inner();
+ let ParsedItem(input, minute) =
+ exactly_n_digits::<2, _>(input).ok_or(InvalidComponent("minute"))?;
+
+ let (input, mut second) = if let Some(input) = colon(opt(cfws)(input).into_inner()) {
+ let input = input.into_inner(); // discard the colon
+ let input = opt(cfws)(input).into_inner();
+ let ParsedItem(input, second) =
+ exactly_n_digits::<2, _>(input).ok_or(InvalidComponent("second"))?;
+ let input = cfws(input).ok_or(InvalidLiteral)?.into_inner();
+ (input, second)
+ } else {
+ (cfws(input).ok_or(InvalidLiteral)?.into_inner(), 0)
+ };
+
+ #[allow(clippy::unnecessary_lazy_evaluations)] // rust-lang/rust-clippy#8522
+ let zone_literal = first_match(
+ [
+ (b"UT".as_slice(), 0),
+ (b"GMT".as_slice(), 0),
+ (b"EST".as_slice(), -5),
+ (b"EDT".as_slice(), -4),
+ (b"CST".as_slice(), -6),
+ (b"CDT".as_slice(), -5),
+ (b"MST".as_slice(), -7),
+ (b"MDT".as_slice(), -6),
+ (b"PST".as_slice(), -8),
+ (b"PDT".as_slice(), -7),
+ ],
+ false,
+ )(input)
+ .or_else(|| match input {
+ [b'a'..=b'i' | b'k'..=b'z' | b'A'..=b'I' | b'K'..=b'Z', rest @ ..] => {
+ Some(ParsedItem(rest, 0))
+ }
+ _ => None,
+ });
+
+ let (input, offset_hour, offset_minute) = if let Some(zone_literal) = zone_literal {
+ let ParsedItem(input, offset_hour) = zone_literal;
+ (input, offset_hour, 0)
+ } else {
+ let ParsedItem(input, offset_sign) =
+ sign(input).ok_or(InvalidComponent("offset hour"))?;
+ let ParsedItem(input, offset_hour) = exactly_n_digits::<2, u8>(input)
+ .map(|item| {
+ item.map(|offset_hour| {
+ if offset_sign == b'-' {
+ -offset_hour.cast_signed()
+ } else {
+ offset_hour.cast_signed()
+ }
+ })
+ })
+ .ok_or(InvalidComponent("offset hour"))?;
+ let ParsedItem(input, offset_minute) =
+ exactly_n_digits::<2, u8>(input).ok_or(InvalidComponent("offset minute"))?;
+ (input, offset_hour, offset_minute.cast_signed())
+ };
+
+ let input = opt(cfws)(input).into_inner();
+
+ if !input.is_empty() {
+ return Err(error::Parse::ParseFromDescription(
+ error::ParseFromDescription::UnexpectedTrailingCharacters,
+ ));
+ }
+
+ let mut nanosecond = 0;
+ let leap_second_input = if second == 60 {
+ second = 59;
+ nanosecond = 999_999_999;
+ true
+ } else {
+ false
+ };
+
+ let dt = (|| {
+ let date = Date::from_calendar_date(year.cast_signed(), month, day)?;
+ let time = Time::from_hms_nano(hour, minute, second, nanosecond)?;
+ let offset = UtcOffset::from_hms(offset_hour, offset_minute, 0)?;
+ Ok(OffsetDateTime::new_in_offset(date, time, offset))
+ })()
+ .map_err(TryFromParsed::ComponentRange)?;
+
+ if leap_second_input && !dt.is_valid_leap_second_stand_in() {
+ return Err(error::Parse::TryFromParsed(TryFromParsed::ComponentRange(
+ error::ComponentRange {
+ name: "second",
+ minimum: 0,
+ maximum: 59,
+ value: 60,
+ conditional_message: Some("because leap seconds are not supported"),
+ },
+ )));
+ }
+
+ Ok(dt)
+ }
+}
+
+impl sealed::Sealed for Rfc3339 {
+ fn parse_into<'a>(
+ &self,
+ input: &'a [u8],
+ parsed: &mut Parsed,
+ ) -> Result<&'a [u8], error::Parse> {
+ use crate::error::ParseFromDescription::{InvalidComponent, InvalidLiteral};
+ use crate::parsing::combinator::{
+ any_digit, ascii_char, ascii_char_ignore_case, exactly_n_digits, sign,
+ };
+
+ let dash = ascii_char::<b'-'>;
+ let colon = ascii_char::<b':'>;
+
+ let input = exactly_n_digits::<4, u32>(input)
+ .and_then(|item| item.consume_value(|value| parsed.set_year(value.cast_signed())))
+ .ok_or(InvalidComponent("year"))?;
+ let input = dash(input).ok_or(InvalidLiteral)?.into_inner();
+ let input = exactly_n_digits::<2, _>(input)
+ .and_then(|item| item.flat_map(|value| Month::from_number(value).ok()))
+ .and_then(|item| item.consume_value(|value| parsed.set_month(value)))
+ .ok_or(InvalidComponent("month"))?;
+ let input = dash(input).ok_or(InvalidLiteral)?.into_inner();
+ let input = exactly_n_digits::<2, _>(input)
+ .and_then(|item| item.consume_value(|value| parsed.set_day(value)))
+ .ok_or(InvalidComponent("day"))?;
+
+ // RFC3339 allows any separator, not just `T`, not just `space`.
+ // cf. Section 5.6: Internet Date/Time Format:
+ // NOTE: ISO 8601 defines date and time separated by "T".
+ // Applications using this syntax may choose, for the sake of
+ // readability, to specify a full-date and full-time separated by
+ // (say) a space character.
+ // Specifically, rusqlite uses space separators.
+ let input = input.get(1..).ok_or(InvalidComponent("separator"))?;
+
+ let input = exactly_n_digits::<2, _>(input)
+ .and_then(|item| item.consume_value(|value| parsed.set_hour_24(value)))
+ .ok_or(InvalidComponent("hour"))?;
+ let input = colon(input).ok_or(InvalidLiteral)?.into_inner();
+ let input = exactly_n_digits::<2, _>(input)
+ .and_then(|item| item.consume_value(|value| parsed.set_minute(value)))
+ .ok_or(InvalidComponent("minute"))?;
+ let input = colon(input).ok_or(InvalidLiteral)?.into_inner();
+ let input = exactly_n_digits::<2, _>(input)
+ .and_then(|item| item.consume_value(|value| parsed.set_second(value)))
+ .ok_or(InvalidComponent("second"))?;
+ let input = if let Some(ParsedItem(input, ())) = ascii_char::<b'.'>(input) {
+ let ParsedItem(mut input, mut value) = any_digit(input)
+ .ok_or(InvalidComponent("subsecond"))?
+ .map(|v| (v - b'0').extend::<u32>() * 100_000_000);
+
+ let mut multiplier = 10_000_000;
+ while let Some(ParsedItem(new_input, digit)) = any_digit(input) {
+ value += (digit - b'0').extend::<u32>() * multiplier;
+ input = new_input;
+ multiplier /= 10;
+ }
+
+ parsed
+ .set_subsecond(value)
+ .ok_or(InvalidComponent("subsecond"))?;
+ input
+ } else {
+ input
+ };
+
+ // The RFC explicitly allows leap seconds.
+ parsed.leap_second_allowed = true;
+
+ if let Some(ParsedItem(input, ())) = ascii_char_ignore_case::<b'Z'>(input) {
+ parsed
+ .set_offset_hour(0)
+ .ok_or(InvalidComponent("offset hour"))?;
+ parsed
+ .set_offset_minute_signed(0)
+ .ok_or(InvalidComponent("offset minute"))?;
+ parsed
+ .set_offset_second_signed(0)
+ .ok_or(InvalidComponent("offset second"))?;
+ return Ok(input);
+ }
+
+ let ParsedItem(input, offset_sign) = sign(input).ok_or(InvalidComponent("offset hour"))?;
+ let input = exactly_n_digits::<2, u8>(input)
+ .and_then(|item| {
+ item.filter(|&offset_hour| offset_hour <= 23)?
+ .map(|offset_hour| {
+ if offset_sign == b'-' {
+ -offset_hour.cast_signed()
+ } else {
+ offset_hour.cast_signed()
+ }
+ })
+ .consume_value(|value| parsed.set_offset_hour(value))
+ })
+ .ok_or(InvalidComponent("offset hour"))?;
+ let input = colon(input).ok_or(InvalidLiteral)?.into_inner();
+ let input = exactly_n_digits::<2, u8>(input)
+ .and_then(|item| {
+ item.map(|offset_minute| {
+ if offset_sign == b'-' {
+ -offset_minute.cast_signed()
+ } else {
+ offset_minute.cast_signed()
+ }
+ })
+ .consume_value(|value| parsed.set_offset_minute_signed(value))
+ })
+ .ok_or(InvalidComponent("offset minute"))?;
+
+ Ok(input)
+ }
+
+ fn parse_offset_date_time(&self, input: &[u8]) -> Result<OffsetDateTime, error::Parse> {
+ use crate::error::ParseFromDescription::{InvalidComponent, InvalidLiteral};
+ use crate::parsing::combinator::{
+ any_digit, ascii_char, ascii_char_ignore_case, exactly_n_digits, sign,
+ };
+
+ let dash = ascii_char::<b'-'>;
+ let colon = ascii_char::<b':'>;
+
+ let ParsedItem(input, year) =
+ exactly_n_digits::<4, u32>(input).ok_or(InvalidComponent("year"))?;
+ let input = dash(input).ok_or(InvalidLiteral)?.into_inner();
+ let ParsedItem(input, month) =
+ exactly_n_digits::<2, _>(input).ok_or(InvalidComponent("month"))?;
+ let input = dash(input).ok_or(InvalidLiteral)?.into_inner();
+ let ParsedItem(input, day) =
+ exactly_n_digits::<2, _>(input).ok_or(InvalidComponent("day"))?;
+
+ // RFC3339 allows any separator, not just `T`, not just `space`.
+ // cf. Section 5.6: Internet Date/Time Format:
+ // NOTE: ISO 8601 defines date and time separated by "T".
+ // Applications using this syntax may choose, for the sake of
+ // readability, to specify a full-date and full-time separated by
+ // (say) a space character.
+ // Specifically, rusqlite uses space separators.
+ let input = input.get(1..).ok_or(InvalidComponent("separator"))?;
+
+ let ParsedItem(input, hour) =
+ exactly_n_digits::<2, _>(input).ok_or(InvalidComponent("hour"))?;
+ let input = colon(input).ok_or(InvalidLiteral)?.into_inner();
+ let ParsedItem(input, minute) =
+ exactly_n_digits::<2, _>(input).ok_or(InvalidComponent("minute"))?;
+ let input = colon(input).ok_or(InvalidLiteral)?.into_inner();
+ let ParsedItem(input, mut second) =
+ exactly_n_digits::<2, _>(input).ok_or(InvalidComponent("second"))?;
+ let ParsedItem(input, mut nanosecond) =
+ if let Some(ParsedItem(input, ())) = ascii_char::<b'.'>(input) {
+ let ParsedItem(mut input, mut value) = any_digit(input)
+ .ok_or(InvalidComponent("subsecond"))?
+ .map(|v| (v - b'0').extend::<u32>() * 100_000_000);
+
+ let mut multiplier = 10_000_000;
+ while let Some(ParsedItem(new_input, digit)) = any_digit(input) {
+ value += (digit - b'0').extend::<u32>() * multiplier;
+ input = new_input;
+ multiplier /= 10;
+ }
+
+ ParsedItem(input, value)
+ } else {
+ ParsedItem(input, 0)
+ };
+ let ParsedItem(input, offset) = {
+ if let Some(ParsedItem(input, ())) = ascii_char_ignore_case::<b'Z'>(input) {
+ ParsedItem(input, UtcOffset::UTC)
+ } else {
+ let ParsedItem(input, offset_sign) =
+ sign(input).ok_or(InvalidComponent("offset hour"))?;
+ let ParsedItem(input, offset_hour) = exactly_n_digits::<2, u8>(input)
+ .and_then(|parsed| parsed.filter(|&offset_hour| offset_hour <= 23))
+ .ok_or(InvalidComponent("offset hour"))?;
+ let input = colon(input).ok_or(InvalidLiteral)?.into_inner();
+ let ParsedItem(input, offset_minute) =
+ exactly_n_digits::<2, u8>(input).ok_or(InvalidComponent("offset minute"))?;
+ UtcOffset::from_hms(
+ if offset_sign == b'-' {
+ -offset_hour.cast_signed()
+ } else {
+ offset_hour.cast_signed()
+ },
+ if offset_sign == b'-' {
+ -offset_minute.cast_signed()
+ } else {
+ offset_minute.cast_signed()
+ },
+ 0,
+ )
+ .map(|offset| ParsedItem(input, offset))
+ .map_err(|mut err| {
+ // Provide the user a more accurate error.
+ if err.name == "hours" {
+ err.name = "offset hour";
+ } else if err.name == "minutes" {
+ err.name = "offset minute";
+ }
+ err
+ })
+ .map_err(TryFromParsed::ComponentRange)?
+ }
+ };
+
+ if !input.is_empty() {
+ return Err(error::Parse::ParseFromDescription(
+ error::ParseFromDescription::UnexpectedTrailingCharacters,
+ ));
+ }
+
+ // The RFC explicitly permits leap seconds. We don't currently support them, so treat it as
+ // the preceding nanosecond. However, leap seconds can only occur as the last second of the
+ // month UTC.
+ let leap_second_input = if second == 60 {
+ second = 59;
+ nanosecond = 999_999_999;
+ true
+ } else {
+ false
+ };
+
+ let date = Month::from_number(month)
+ .and_then(|month| Date::from_calendar_date(year.cast_signed(), month, day))
+ .map_err(TryFromParsed::ComponentRange)?;
+ let time = Time::from_hms_nano(hour, minute, second, nanosecond)
+ .map_err(TryFromParsed::ComponentRange)?;
+ let dt = OffsetDateTime::new_in_offset(date, time, offset);
+
+ if leap_second_input && !dt.is_valid_leap_second_stand_in() {
+ return Err(error::Parse::TryFromParsed(TryFromParsed::ComponentRange(
+ error::ComponentRange {
+ name: "second",
+ minimum: 0,
+ maximum: 59,
+ value: 60,
+ conditional_message: Some("because leap seconds are not supported"),
+ },
+ )));
+ }
+
+ Ok(dt)
+ }
+}
+
+impl<const CONFIG: EncodedConfig> sealed::Sealed for Iso8601<CONFIG> {
+ fn parse_into<'a>(
+ &self,
+ mut input: &'a [u8],
+ parsed: &mut Parsed,
+ ) -> Result<&'a [u8], error::Parse> {
+ use crate::parsing::combinator::rfc::iso8601::ExtendedKind;
+
+ let mut extended_kind = ExtendedKind::Unknown;
+ let mut date_is_present = false;
+ let mut time_is_present = false;
+ let mut offset_is_present = false;
+ let mut first_error = None;
+
+ parsed.leap_second_allowed = true;
+
+ match Self::parse_date(parsed, &mut extended_kind)(input) {
+ Ok(new_input) => {
+ input = new_input;
+ date_is_present = true;
+ }
+ Err(err) => {
+ first_error.get_or_insert(err);
+ }
+ }
+
+ match Self::parse_time(parsed, &mut extended_kind, date_is_present)(input) {
+ Ok(new_input) => {
+ input = new_input;
+ time_is_present = true;
+ }
+ Err(err) => {
+ first_error.get_or_insert(err);
+ }
+ }
+
+ // If a date and offset are present, a time must be as well.
+ if !date_is_present || time_is_present {
+ match Self::parse_offset(parsed, &mut extended_kind)(input) {
+ Ok(new_input) => {
+ input = new_input;
+ offset_is_present = true;
+ }
+ Err(err) => {
+ first_error.get_or_insert(err);
+ }
+ }
+ }
+
+ if !date_is_present && !time_is_present && !offset_is_present {
+ match first_error {
+ Some(err) => return Err(err),
+ None => bug!("an error should be present if no components were parsed"),
+ }
+ }
+
+ Ok(input)
+ }
+}
diff --git a/vendor/time/src/parsing/parsed.rs b/vendor/time/src/parsing/parsed.rs
new file mode 100644
index 00000000..a6f00d9b
--- /dev/null
+++ b/vendor/time/src/parsing/parsed.rs
@@ -0,0 +1,1118 @@
+//! Information parsed from an input and format description.
+
+use core::num::{NonZeroU16, NonZeroU8};
+
+use deranged::{
+ OptionRangedI128, OptionRangedI16, OptionRangedI32, OptionRangedI8, OptionRangedU16,
+ OptionRangedU32, OptionRangedU8, RangedI128, RangedI16, RangedI32, RangedI8, RangedU16,
+ RangedU32, RangedU8,
+};
+use num_conv::prelude::*;
+
+use crate::convert::{Day, Hour, Minute, Nanosecond, Second};
+use crate::date::{MAX_YEAR, MIN_YEAR};
+use crate::error::TryFromParsed::InsufficientInformation;
+#[cfg(feature = "alloc")]
+use crate::format_description::OwnedFormatItem;
+use crate::format_description::{modifier, BorrowedFormatItem, Component};
+use crate::internal_macros::{bug, const_try_opt};
+use crate::parsing::component::{
+ parse_day, parse_end, parse_hour, parse_ignore, parse_minute, parse_month, parse_offset_hour,
+ parse_offset_minute, parse_offset_second, parse_ordinal, parse_period, parse_second,
+ parse_subsecond, parse_unix_timestamp, parse_week_number, parse_weekday, parse_year, Period,
+};
+use crate::parsing::ParsedItem;
+use crate::{
+ error, Date, Month, OffsetDateTime, PrimitiveDateTime, Time, UtcDateTime, UtcOffset, Weekday,
+};
+
+/// Sealed to prevent downstream implementations.
+mod sealed {
+ use super::*;
+
+ /// A trait to allow `parse_item` to be generic.
+ pub trait AnyFormatItem {
+ /// Parse a single item, returning the remaining input on success.
+ fn parse_item<'a>(
+ &self,
+ parsed: &mut Parsed,
+ input: &'a [u8],
+ ) -> Result<&'a [u8], error::ParseFromDescription>;
+ }
+}
+
+impl sealed::AnyFormatItem for BorrowedFormatItem<'_> {
+ fn parse_item<'a>(
+ &self,
+ parsed: &mut Parsed,
+ input: &'a [u8],
+ ) -> Result<&'a [u8], error::ParseFromDescription> {
+ match self {
+ Self::Literal(literal) => Parsed::parse_literal(input, literal),
+ Self::Component(component) => parsed.parse_component(input, *component),
+ Self::Compound(compound) => parsed.parse_items(input, compound),
+ Self::Optional(item) => parsed.parse_item(input, *item).or(Ok(input)),
+ Self::First(items) => {
+ let mut first_err = None;
+
+ for item in items.iter() {
+ match parsed.parse_item(input, item) {
+ Ok(remaining_input) => return Ok(remaining_input),
+ Err(err) if first_err.is_none() => first_err = Some(err),
+ Err(_) => {}
+ }
+ }
+
+ match first_err {
+ Some(err) => Err(err),
+ // This location will be reached if the slice is empty, skipping the `for` loop.
+ // As this case is expected to be uncommon, there's no need to check up front.
+ None => Ok(input),
+ }
+ }
+ }
+ }
+}
+
+#[cfg(feature = "alloc")]
+impl sealed::AnyFormatItem for OwnedFormatItem {
+ fn parse_item<'a>(
+ &self,
+ parsed: &mut Parsed,
+ input: &'a [u8],
+ ) -> Result<&'a [u8], error::ParseFromDescription> {
+ match self {
+ Self::Literal(literal) => Parsed::parse_literal(input, literal),
+ Self::Component(component) => parsed.parse_component(input, *component),
+ Self::Compound(compound) => parsed.parse_items(input, compound),
+ Self::Optional(item) => parsed.parse_item(input, item.as_ref()).or(Ok(input)),
+ Self::First(items) => {
+ let mut first_err = None;
+
+ for item in items.iter() {
+ match parsed.parse_item(input, item) {
+ Ok(remaining_input) => return Ok(remaining_input),
+ Err(err) if first_err.is_none() => first_err = Some(err),
+ Err(_) => {}
+ }
+ }
+
+ match first_err {
+ Some(err) => Err(err),
+ // This location will be reached if the slice is empty, skipping the `for` loop.
+ // As this case is expected to be uncommon, there's no need to check up front.
+ None => Ok(input),
+ }
+ }
+ }
+ }
+}
+
+/// All information parsed.
+///
+/// This information is directly used to construct the final values.
+///
+/// Most users will not need think about this struct in any way. It is public to allow for manual
+/// control over values, in the instance that the default parser is insufficient.
+#[derive(Debug, Clone, Copy)]
+pub struct Parsed {
+ /// Calendar year.
+ year: OptionRangedI32<{ MIN_YEAR }, { MAX_YEAR }>,
+ /// All digits except the last two of the calendar year.
+ year_century: OptionRangedI16<{ (MIN_YEAR / 100) as i16 }, { (MAX_YEAR / 100) as i16 }>,
+ /// The last two digits of the calendar year.
+ year_last_two: OptionRangedU8<0, 99>,
+ /// Year of the [ISO week date](https://en.wikipedia.org/wiki/ISO_week_date).
+ iso_year: OptionRangedI32<{ MIN_YEAR }, { MAX_YEAR }>,
+ /// All digits except the last two of the ISO week year.
+ iso_year_century: OptionRangedI16<{ (MIN_YEAR / 100) as i16 }, { (MAX_YEAR / 100) as i16 }>,
+ /// The last two digits of the ISO week year.
+ iso_year_last_two: OptionRangedU8<0, 99>,
+ /// Month of the year.
+ month: Option<Month>,
+ /// Week of the year, where week one begins on the first Sunday of the calendar year.
+ sunday_week_number: OptionRangedU8<0, 53>,
+ /// Week of the year, where week one begins on the first Monday of the calendar year.
+ monday_week_number: OptionRangedU8<0, 53>,
+ /// Week of the year, where week one is the Monday-to-Sunday period containing January 4.
+ iso_week_number: OptionRangedU8<1, 53>,
+ /// Day of the week.
+ weekday: Option<Weekday>,
+ /// Day of the year.
+ ordinal: OptionRangedU16<1, 366>,
+ /// Day of the month.
+ day: OptionRangedU8<1, 31>,
+ /// Hour within the day.
+ hour_24: OptionRangedU8<0, { Hour::per(Day) - 1 }>,
+ /// Hour within the 12-hour period (midnight to noon or vice versa). This is typically used in
+ /// conjunction with AM/PM, which is indicated by the `hour_12_is_pm` field.
+ hour_12: OptionRangedU8<1, 12>,
+ /// Whether the `hour_12` field indicates a time that "PM".
+ hour_12_is_pm: Option<bool>,
+ /// Minute within the hour.
+ minute: OptionRangedU8<0, { Minute::per(Hour) - 1 }>,
+ /// Second within the minute.
+ // do not subtract one, as leap seconds may be allowed
+ second: OptionRangedU8<0, { Second::per(Minute) }>,
+ /// Nanosecond within the second.
+ subsecond: OptionRangedU32<0, { Nanosecond::per(Second) - 1 }>,
+ /// Whole hours of the UTC offset.
+ offset_hour: OptionRangedI8<-23, 23>,
+ /// Minutes within the hour of the UTC offset.
+ offset_minute:
+ OptionRangedI8<{ -((Minute::per(Hour) - 1) as i8) }, { (Minute::per(Hour) - 1) as i8 }>,
+ /// Seconds within the minute of the UTC offset.
+ offset_second:
+ OptionRangedI8<{ -((Second::per(Minute) - 1) as i8) }, { (Second::per(Minute) - 1) as i8 }>,
+ /// The Unix timestamp in nanoseconds.
+ unix_timestamp_nanos: OptionRangedI128<
+ {
+ OffsetDateTime::new_in_offset(Date::MIN, Time::MIDNIGHT, UtcOffset::UTC)
+ .unix_timestamp_nanos()
+ },
+ {
+ OffsetDateTime::new_in_offset(Date::MAX, Time::MAX, UtcOffset::UTC)
+ .unix_timestamp_nanos()
+ },
+ >,
+ /// Indicates whether the [`UtcOffset`] is negative. This information is obtained when parsing
+ /// the offset hour, but may not otherwise be stored due to "-0" being equivalent to "0".
+ offset_is_negative: bool,
+ /// Indicates whether the `year_century` component is negative. This information is obtained
+ /// when parsing, but may not otherwise be stored due to "-0" being equivalent to "0".
+ year_century_is_negative: bool,
+ /// Indicates whether the `iso_year_century` component is negative. This information is
+ /// obtained when parsing, but may not otherwise be stored due to "-0" being equivalent to "0".
+ iso_year_century_is_negative: bool,
+ /// Indicates whether a leap second is permitted to be parsed. This is required by some
+ /// well-known formats.
+ pub(super) leap_second_allowed: bool,
+}
+
+impl Default for Parsed {
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
+impl Parsed {
+ /// Create a new instance of `Parsed` with no information known.
+ pub const fn new() -> Self {
+ Self {
+ year: OptionRangedI32::None,
+ year_century: OptionRangedI16::None,
+ year_last_two: OptionRangedU8::None,
+ iso_year: OptionRangedI32::None,
+ iso_year_century: OptionRangedI16::None,
+ iso_year_last_two: OptionRangedU8::None,
+ month: None,
+ sunday_week_number: OptionRangedU8::None,
+ monday_week_number: OptionRangedU8::None,
+ iso_week_number: OptionRangedU8::None,
+ weekday: None,
+ ordinal: OptionRangedU16::None,
+ day: OptionRangedU8::None,
+ hour_24: OptionRangedU8::None,
+ hour_12: OptionRangedU8::None,
+ hour_12_is_pm: None,
+ minute: OptionRangedU8::None,
+ second: OptionRangedU8::None,
+ subsecond: OptionRangedU32::None,
+ offset_hour: OptionRangedI8::None,
+ offset_minute: OptionRangedI8::None,
+ offset_second: OptionRangedI8::None,
+ unix_timestamp_nanos: OptionRangedI128::None,
+ offset_is_negative: false,
+ year_century_is_negative: false,
+ iso_year_century_is_negative: false,
+ leap_second_allowed: false,
+ }
+ }
+
+ /// Parse a single [`BorrowedFormatItem`] or [`OwnedFormatItem`], mutating the struct. The
+ /// remaining input is returned as the `Ok` value.
+ ///
+ /// If a [`BorrowedFormatItem::Optional`] or [`OwnedFormatItem::Optional`] is passed, parsing
+ /// will not fail; the input will be returned as-is if the expected format is not present.
+ pub fn parse_item<'a>(
+ &mut self,
+ input: &'a [u8],
+ item: &impl sealed::AnyFormatItem,
+ ) -> Result<&'a [u8], error::ParseFromDescription> {
+ item.parse_item(self, input)
+ }
+
+ /// Parse a sequence of [`BorrowedFormatItem`]s or [`OwnedFormatItem`]s, mutating the struct.
+ /// The remaining input is returned as the `Ok` value.
+ ///
+ /// This method will fail if any of the contained [`BorrowedFormatItem`]s or
+ /// [`OwnedFormatItem`]s fail to parse. `self` will not be mutated in this instance.
+ pub fn parse_items<'a>(
+ &mut self,
+ mut input: &'a [u8],
+ items: &[impl sealed::AnyFormatItem],
+ ) -> Result<&'a [u8], error::ParseFromDescription> {
+ // Make a copy that we can mutate. It will only be set to the user's copy if everything
+ // succeeds.
+ let mut this = *self;
+ for item in items {
+ input = this.parse_item(input, item)?;
+ }
+ *self = this;
+ Ok(input)
+ }
+
+ /// Parse a literal byte sequence. The remaining input is returned as the `Ok` value.
+ pub fn parse_literal<'a>(
+ input: &'a [u8],
+ literal: &[u8],
+ ) -> Result<&'a [u8], error::ParseFromDescription> {
+ input
+ .strip_prefix(literal)
+ .ok_or(error::ParseFromDescription::InvalidLiteral)
+ }
+
+ /// Parse a single component, mutating the struct. The remaining input is returned as the `Ok`
+ /// value.
+ pub fn parse_component<'a>(
+ &mut self,
+ input: &'a [u8],
+ component: Component,
+ ) -> Result<&'a [u8], error::ParseFromDescription> {
+ use error::ParseFromDescription::InvalidComponent;
+
+ match component {
+ Component::Day(modifiers) => parse_day(input, modifiers)
+ .and_then(|parsed| parsed.consume_value(|value| self.set_day(value)))
+ .ok_or(InvalidComponent("day")),
+ Component::Month(modifiers) => parse_month(input, modifiers)
+ .and_then(|parsed| parsed.consume_value(|value| self.set_month(value)))
+ .ok_or(InvalidComponent("month")),
+ Component::Ordinal(modifiers) => parse_ordinal(input, modifiers)
+ .and_then(|parsed| parsed.consume_value(|value| self.set_ordinal(value)))
+ .ok_or(InvalidComponent("ordinal")),
+ Component::Weekday(modifiers) => parse_weekday(input, modifiers)
+ .and_then(|parsed| parsed.consume_value(|value| self.set_weekday(value)))
+ .ok_or(InvalidComponent("weekday")),
+ Component::WeekNumber(modifiers) => {
+ let ParsedItem(remaining, value) =
+ parse_week_number(input, modifiers).ok_or(InvalidComponent("week number"))?;
+ match modifiers.repr {
+ modifier::WeekNumberRepr::Iso => {
+ NonZeroU8::new(value).and_then(|value| self.set_iso_week_number(value))
+ }
+ modifier::WeekNumberRepr::Sunday => self.set_sunday_week_number(value),
+ modifier::WeekNumberRepr::Monday => self.set_monday_week_number(value),
+ }
+ .ok_or(InvalidComponent("week number"))?;
+ Ok(remaining)
+ }
+ Component::Year(modifiers) => {
+ let ParsedItem(remaining, (value, is_negative)) =
+ parse_year(input, modifiers).ok_or(InvalidComponent("year"))?;
+ match (modifiers.iso_week_based, modifiers.repr) {
+ (false, modifier::YearRepr::Full) => self.set_year(value),
+ (false, modifier::YearRepr::Century) => {
+ self.set_year_century(value.truncate(), is_negative)
+ }
+ (false, modifier::YearRepr::LastTwo) => {
+ self.set_year_last_two(value.cast_unsigned().truncate())
+ }
+ (true, modifier::YearRepr::Full) => self.set_iso_year(value),
+ (true, modifier::YearRepr::Century) => {
+ self.set_iso_year_century(value.truncate(), is_negative)
+ }
+ (true, modifier::YearRepr::LastTwo) => {
+ self.set_iso_year_last_two(value.cast_unsigned().truncate())
+ }
+ }
+ .ok_or(InvalidComponent("year"))?;
+ Ok(remaining)
+ }
+ Component::Hour(modifiers) => {
+ let ParsedItem(remaining, value) =
+ parse_hour(input, modifiers).ok_or(InvalidComponent("hour"))?;
+ if modifiers.is_12_hour_clock {
+ NonZeroU8::new(value).and_then(|value| self.set_hour_12(value))
+ } else {
+ self.set_hour_24(value)
+ }
+ .ok_or(InvalidComponent("hour"))?;
+ Ok(remaining)
+ }
+ Component::Minute(modifiers) => parse_minute(input, modifiers)
+ .and_then(|parsed| parsed.consume_value(|value| self.set_minute(value)))
+ .ok_or(InvalidComponent("minute")),
+ Component::Period(modifiers) => parse_period(input, modifiers)
+ .and_then(|parsed| {
+ parsed.consume_value(|value| self.set_hour_12_is_pm(value == Period::Pm))
+ })
+ .ok_or(InvalidComponent("period")),
+ Component::Second(modifiers) => parse_second(input, modifiers)
+ .and_then(|parsed| parsed.consume_value(|value| self.set_second(value)))
+ .ok_or(InvalidComponent("second")),
+ Component::Subsecond(modifiers) => parse_subsecond(input, modifiers)
+ .and_then(|parsed| parsed.consume_value(|value| self.set_subsecond(value)))
+ .ok_or(InvalidComponent("subsecond")),
+ Component::OffsetHour(modifiers) => parse_offset_hour(input, modifiers)
+ .and_then(|parsed| {
+ parsed.consume_value(|(value, is_negative)| {
+ self.set_offset_hour(value)?;
+ self.offset_is_negative = is_negative;
+ Some(())
+ })
+ })
+ .ok_or(InvalidComponent("offset hour")),
+ Component::OffsetMinute(modifiers) => parse_offset_minute(input, modifiers)
+ .and_then(|parsed| {
+ parsed.consume_value(|value| self.set_offset_minute_signed(value))
+ })
+ .ok_or(InvalidComponent("offset minute")),
+ Component::OffsetSecond(modifiers) => parse_offset_second(input, modifiers)
+ .and_then(|parsed| {
+ parsed.consume_value(|value| self.set_offset_second_signed(value))
+ })
+ .ok_or(InvalidComponent("offset second")),
+ Component::Ignore(modifiers) => parse_ignore(input, modifiers)
+ .map(ParsedItem::<()>::into_inner)
+ .ok_or(InvalidComponent("ignore")),
+ Component::UnixTimestamp(modifiers) => parse_unix_timestamp(input, modifiers)
+ .and_then(|parsed| {
+ parsed.consume_value(|value| self.set_unix_timestamp_nanos(value))
+ })
+ .ok_or(InvalidComponent("unix_timestamp")),
+ Component::End(modifiers) => parse_end(input, modifiers)
+ .map(ParsedItem::<()>::into_inner)
+ .ok_or(error::ParseFromDescription::UnexpectedTrailingCharacters),
+ }
+ }
+}
+
+/// Getter methods
+impl Parsed {
+ /// Obtain the `year` component.
+ pub const fn year(&self) -> Option<i32> {
+ self.year.get_primitive()
+ }
+
+ /// Obtain the `year_century` component.
+ ///
+ /// If the year is zero, the sign of the century is not stored. To differentiate between
+ /// positive and negative zero, use `year_century_is_negative`.
+ pub const fn year_century(&self) -> Option<i16> {
+ self.year_century.get_primitive()
+ }
+
+ /// Obtain the `year_century_is_negative` component.
+ ///
+ /// This indicates whether the value returned from `year_century` is negative. If the year is
+ /// zero, it is necessary to call this method for disambiguation.
+ pub const fn year_century_is_negative(&self) -> Option<bool> {
+ match self.year_century() {
+ Some(_) => Some(self.year_century_is_negative),
+ None => None,
+ }
+ }
+
+ /// Obtain the `year_last_two` component.
+ pub const fn year_last_two(&self) -> Option<u8> {
+ self.year_last_two.get_primitive()
+ }
+
+ /// Obtain the `iso_year` component.
+ pub const fn iso_year(&self) -> Option<i32> {
+ self.iso_year.get_primitive()
+ }
+
+ /// Obtain the `iso_year_century` component.
+ ///
+ /// If the year is zero, the sign of the century is not stored. To differentiate between
+ /// positive and negative zero, use `iso_year_century_is_negative`.
+ pub const fn iso_year_century(&self) -> Option<i16> {
+ self.iso_year_century.get_primitive()
+ }
+
+ /// Obtain the `iso_year_century_is_negative` component.
+ ///
+ /// This indicates whether the value returned from `iso_year_century` is negative. If the year
+ /// is zero, it is necessary to call this method for disambiguation.
+ pub const fn iso_year_century_is_negative(&self) -> Option<bool> {
+ match self.iso_year_century() {
+ Some(_) => Some(self.iso_year_century_is_negative),
+ None => None,
+ }
+ }
+
+ /// Obtain the `iso_year_last_two` component.
+ pub const fn iso_year_last_two(&self) -> Option<u8> {
+ self.iso_year_last_two.get_primitive()
+ }
+
+ /// Obtain the `month` component.
+ pub const fn month(&self) -> Option<Month> {
+ self.month
+ }
+
+ /// Obtain the `sunday_week_number` component.
+ pub const fn sunday_week_number(&self) -> Option<u8> {
+ self.sunday_week_number.get_primitive()
+ }
+
+ /// Obtain the `monday_week_number` component.
+ pub const fn monday_week_number(&self) -> Option<u8> {
+ self.monday_week_number.get_primitive()
+ }
+
+ /// Obtain the `iso_week_number` component.
+ pub const fn iso_week_number(&self) -> Option<NonZeroU8> {
+ NonZeroU8::new(const_try_opt!(self.iso_week_number.get_primitive()))
+ }
+
+ /// Obtain the `weekday` component.
+ pub const fn weekday(&self) -> Option<Weekday> {
+ self.weekday
+ }
+
+ /// Obtain the `ordinal` component.
+ pub const fn ordinal(&self) -> Option<NonZeroU16> {
+ NonZeroU16::new(const_try_opt!(self.ordinal.get_primitive()))
+ }
+
+ /// Obtain the `day` component.
+ pub const fn day(&self) -> Option<NonZeroU8> {
+ NonZeroU8::new(const_try_opt!(self.day.get_primitive()))
+ }
+
+ /// Obtain the `hour_24` component.
+ pub const fn hour_24(&self) -> Option<u8> {
+ self.hour_24.get_primitive()
+ }
+
+ /// Obtain the `hour_12` component.
+ pub const fn hour_12(&self) -> Option<NonZeroU8> {
+ NonZeroU8::new(const_try_opt!(self.hour_12.get_primitive()))
+ }
+
+ /// Obtain the `hour_12_is_pm` component.
+ pub const fn hour_12_is_pm(&self) -> Option<bool> {
+ self.hour_12_is_pm
+ }
+
+ /// Obtain the `minute` component.
+ pub const fn minute(&self) -> Option<u8> {
+ self.minute.get_primitive()
+ }
+
+ /// Obtain the `second` component.
+ pub const fn second(&self) -> Option<u8> {
+ self.second.get_primitive()
+ }
+
+ /// Obtain the `subsecond` component.
+ pub const fn subsecond(&self) -> Option<u32> {
+ self.subsecond.get_primitive()
+ }
+
+ /// Obtain the `offset_hour` component.
+ pub const fn offset_hour(&self) -> Option<i8> {
+ self.offset_hour.get_primitive()
+ }
+
+ /// Obtain the absolute value of the `offset_minute` component.
+ #[doc(hidden)]
+ #[deprecated(since = "0.3.8", note = "use `parsed.offset_minute_signed()` instead")]
+ pub const fn offset_minute(&self) -> Option<u8> {
+ Some(const_try_opt!(self.offset_minute_signed()).unsigned_abs())
+ }
+
+ /// Obtain the `offset_minute` component.
+ pub const fn offset_minute_signed(&self) -> Option<i8> {
+ match (self.offset_minute.get_primitive(), self.offset_is_negative) {
+ (Some(offset_minute), true) => Some(-offset_minute),
+ (Some(offset_minute), _) => Some(offset_minute),
+ (None, _) => None,
+ }
+ }
+
+ /// Obtain the absolute value of the `offset_second` component.
+ #[doc(hidden)]
+ #[deprecated(since = "0.3.8", note = "use `parsed.offset_second_signed()` instead")]
+ pub const fn offset_second(&self) -> Option<u8> {
+ Some(const_try_opt!(self.offset_second_signed()).unsigned_abs())
+ }
+
+ /// Obtain the `offset_second` component.
+ pub const fn offset_second_signed(&self) -> Option<i8> {
+ match (self.offset_second.get_primitive(), self.offset_is_negative) {
+ (Some(offset_second), true) => Some(-offset_second),
+ (Some(offset_second), _) => Some(offset_second),
+ (None, _) => None,
+ }
+ }
+
+ /// Obtain the `unix_timestamp_nanos` component.
+ pub const fn unix_timestamp_nanos(&self) -> Option<i128> {
+ self.unix_timestamp_nanos.get_primitive()
+ }
+}
+
+/// Generate setters based on the builders.
+macro_rules! setters {
+ ($($name:ident $setter:ident $builder:ident $type:ty;)*) => {$(
+ #[doc = concat!("Set the `", stringify!($name), "` component.")]
+ pub fn $setter(&mut self, value: $type) -> Option<()> {
+ *self = self.$builder(value)?;
+ Some(())
+ }
+ )*};
+}
+
+/// Setter methods
+///
+/// All setters return `Option<()>`, which is `Some` if the value was set, and `None` if not. The
+/// setters _may_ fail if the value is invalid, though behavior is not guaranteed.
+impl Parsed {
+ setters! {
+ year set_year with_year i32;
+ }
+
+ /// Set the `year_century` component.
+ ///
+ /// If the value is zero, the sign of the century is taken from the second parameter. Otherwise
+ /// the sign is inferred from the value.
+ pub fn set_year_century(&mut self, value: i16, is_negative: bool) -> Option<()> {
+ self.year_century = OptionRangedI16::Some(const_try_opt!(RangedI16::new(value)));
+ if value != 0 {
+ self.year_century_is_negative = value.is_negative();
+ } else {
+ self.year_century_is_negative = is_negative;
+ }
+ Some(())
+ }
+
+ setters! {
+ year_last_two set_year_last_two with_year_last_two u8;
+ iso_year set_iso_year with_iso_year i32;
+ iso_year_last_two set_iso_year_last_two with_iso_year_last_two u8;
+ }
+
+ /// Set the `iso_year_century` component.
+ ///
+ /// If the value is zero, the sign of the century is taken from the second parameter. Otherwise
+ /// the sign is inferred from the value.
+ pub fn set_iso_year_century(&mut self, value: i16, is_negative: bool) -> Option<()> {
+ self.iso_year_century = OptionRangedI16::Some(const_try_opt!(RangedI16::new(value)));
+ if value != 0 {
+ self.iso_year_century_is_negative = value.is_negative();
+ } else {
+ self.iso_year_century_is_negative = is_negative;
+ }
+ Some(())
+ }
+
+ setters! {
+ month set_month with_month Month;
+ sunday_week_number set_sunday_week_number with_sunday_week_number u8;
+ monday_week_number set_monday_week_number with_monday_week_number u8;
+ iso_week_number set_iso_week_number with_iso_week_number NonZeroU8;
+ weekday set_weekday with_weekday Weekday;
+ ordinal set_ordinal with_ordinal NonZeroU16;
+ day set_day with_day NonZeroU8;
+ hour_24 set_hour_24 with_hour_24 u8;
+ hour_12 set_hour_12 with_hour_12 NonZeroU8;
+ hour_12_is_pm set_hour_12_is_pm with_hour_12_is_pm bool;
+ minute set_minute with_minute u8;
+ second set_second with_second u8;
+ subsecond set_subsecond with_subsecond u32;
+ offset_hour set_offset_hour with_offset_hour i8;
+ offset_minute set_offset_minute_signed with_offset_minute_signed i8;
+ offset_second set_offset_second_signed with_offset_second_signed i8;
+ unix_timestamp_nanos set_unix_timestamp_nanos with_unix_timestamp_nanos i128;
+ }
+
+ /// Set the `offset_minute` component.
+ #[doc(hidden)]
+ #[deprecated(
+ since = "0.3.8",
+ note = "use `parsed.set_offset_minute_signed()` instead"
+ )]
+ pub fn set_offset_minute(&mut self, value: u8) -> Option<()> {
+ if value > i8::MAX.cast_unsigned() {
+ None
+ } else {
+ self.set_offset_minute_signed(value.cast_signed())
+ }
+ }
+
+ /// Set the `offset_minute` component.
+ #[doc(hidden)]
+ #[deprecated(
+ since = "0.3.8",
+ note = "use `parsed.set_offset_second_signed()` instead"
+ )]
+ pub fn set_offset_second(&mut self, value: u8) -> Option<()> {
+ if value > i8::MAX.cast_unsigned() {
+ None
+ } else {
+ self.set_offset_second_signed(value.cast_signed())
+ }
+ }
+}
+
+/// Builder methods
+///
+/// All builder methods return `Option<Self>`, which is `Some` if the value was set, and `None` if
+/// not. The builder methods _may_ fail if the value is invalid, though behavior is not guaranteed.
+impl Parsed {
+ /// Set the `year` component and return `self`.
+ pub const fn with_year(mut self, value: i32) -> Option<Self> {
+ self.year = OptionRangedI32::Some(const_try_opt!(RangedI32::new(value)));
+ Some(self)
+ }
+
+ /// Set the `year_century` component and return `self`.
+ ///
+ /// If the value is zero, the sign of the century is taken from the second parameter. Otherwise
+ /// the sign is inferred from the value.
+ pub const fn with_year_century(mut self, value: i16, is_negative: bool) -> Option<Self> {
+ self.year_century = OptionRangedI16::Some(const_try_opt!(RangedI16::new(value)));
+ if value != 0 {
+ self.year_century_is_negative = value.is_negative();
+ } else {
+ self.year_century_is_negative = is_negative;
+ }
+ Some(self)
+ }
+
+ /// Set the `year_last_two` component and return `self`.
+ pub const fn with_year_last_two(mut self, value: u8) -> Option<Self> {
+ self.year_last_two = OptionRangedU8::Some(const_try_opt!(RangedU8::new(value)));
+ Some(self)
+ }
+
+ /// Set the `iso_year` component and return `self`.
+ pub const fn with_iso_year(mut self, value: i32) -> Option<Self> {
+ self.iso_year = OptionRangedI32::Some(const_try_opt!(RangedI32::new(value)));
+ Some(self)
+ }
+
+ /// Set the `iso_year_century` component and return `self`.
+ ///
+ /// If the value is zero, the sign of the century is taken from the second parameter. Otherwise
+ /// the sign is inferred from the value.
+ pub const fn with_iso_year_century(mut self, value: i16, is_negative: bool) -> Option<Self> {
+ self.iso_year_century = OptionRangedI16::Some(const_try_opt!(RangedI16::new(value)));
+ if value != 0 {
+ self.iso_year_century_is_negative = value.is_negative();
+ } else {
+ self.iso_year_century_is_negative = is_negative;
+ }
+ Some(self)
+ }
+
+ /// Set the `iso_year_last_two` component and return `self`.
+ pub const fn with_iso_year_last_two(mut self, value: u8) -> Option<Self> {
+ self.iso_year_last_two = OptionRangedU8::Some(const_try_opt!(RangedU8::new(value)));
+ Some(self)
+ }
+
+ /// Set the `month` component and return `self`.
+ pub const fn with_month(mut self, value: Month) -> Option<Self> {
+ self.month = Some(value);
+ Some(self)
+ }
+
+ /// Set the `sunday_week_number` component and return `self`.
+ pub const fn with_sunday_week_number(mut self, value: u8) -> Option<Self> {
+ self.sunday_week_number = OptionRangedU8::Some(const_try_opt!(RangedU8::new(value)));
+ Some(self)
+ }
+
+ /// Set the `monday_week_number` component and return `self`.
+ pub const fn with_monday_week_number(mut self, value: u8) -> Option<Self> {
+ self.monday_week_number = OptionRangedU8::Some(const_try_opt!(RangedU8::new(value)));
+ Some(self)
+ }
+
+ /// Set the `iso_week_number` component and return `self`.
+ pub const fn with_iso_week_number(mut self, value: NonZeroU8) -> Option<Self> {
+ self.iso_week_number = OptionRangedU8::Some(const_try_opt!(RangedU8::new(value.get())));
+ Some(self)
+ }
+
+ /// Set the `weekday` component and return `self`.
+ pub const fn with_weekday(mut self, value: Weekday) -> Option<Self> {
+ self.weekday = Some(value);
+ Some(self)
+ }
+
+ /// Set the `ordinal` component and return `self`.
+ pub const fn with_ordinal(mut self, value: NonZeroU16) -> Option<Self> {
+ self.ordinal = OptionRangedU16::Some(const_try_opt!(RangedU16::new(value.get())));
+ Some(self)
+ }
+
+ /// Set the `day` component and return `self`.
+ pub const fn with_day(mut self, value: NonZeroU8) -> Option<Self> {
+ self.day = OptionRangedU8::Some(const_try_opt!(RangedU8::new(value.get())));
+ Some(self)
+ }
+
+ /// Set the `hour_24` component and return `self`.
+ pub const fn with_hour_24(mut self, value: u8) -> Option<Self> {
+ self.hour_24 = OptionRangedU8::Some(const_try_opt!(RangedU8::new(value)));
+ Some(self)
+ }
+
+ /// Set the `hour_12` component and return `self`.
+ pub const fn with_hour_12(mut self, value: NonZeroU8) -> Option<Self> {
+ self.hour_12 = OptionRangedU8::Some(const_try_opt!(RangedU8::new(value.get())));
+ Some(self)
+ }
+
+ /// Set the `hour_12_is_pm` component and return `self`.
+ pub const fn with_hour_12_is_pm(mut self, value: bool) -> Option<Self> {
+ self.hour_12_is_pm = Some(value);
+ Some(self)
+ }
+
+ /// Set the `minute` component and return `self`.
+ pub const fn with_minute(mut self, value: u8) -> Option<Self> {
+ self.minute = OptionRangedU8::Some(const_try_opt!(RangedU8::new(value)));
+ Some(self)
+ }
+
+ /// Set the `second` component and return `self`.
+ pub const fn with_second(mut self, value: u8) -> Option<Self> {
+ self.second = OptionRangedU8::Some(const_try_opt!(RangedU8::new(value)));
+ Some(self)
+ }
+
+ /// Set the `subsecond` component and return `self`.
+ pub const fn with_subsecond(mut self, value: u32) -> Option<Self> {
+ self.subsecond = OptionRangedU32::Some(const_try_opt!(RangedU32::new(value)));
+ Some(self)
+ }
+
+ /// Set the `offset_hour` component and return `self`.
+ pub const fn with_offset_hour(mut self, value: i8) -> Option<Self> {
+ self.offset_hour = OptionRangedI8::Some(const_try_opt!(RangedI8::new(value)));
+ Some(self)
+ }
+
+ /// Set the `offset_minute` component and return `self`.
+ #[doc(hidden)]
+ #[deprecated(
+ since = "0.3.8",
+ note = "use `parsed.with_offset_minute_signed()` instead"
+ )]
+ pub const fn with_offset_minute(self, value: u8) -> Option<Self> {
+ if value > i8::MAX as u8 {
+ None
+ } else {
+ self.with_offset_minute_signed(value as i8)
+ }
+ }
+
+ /// Set the `offset_minute` component and return `self`.
+ pub const fn with_offset_minute_signed(mut self, value: i8) -> Option<Self> {
+ self.offset_minute = OptionRangedI8::Some(const_try_opt!(RangedI8::new(value)));
+ Some(self)
+ }
+
+ /// Set the `offset_minute` component and return `self`.
+ #[doc(hidden)]
+ #[deprecated(
+ since = "0.3.8",
+ note = "use `parsed.with_offset_second_signed()` instead"
+ )]
+ pub const fn with_offset_second(self, value: u8) -> Option<Self> {
+ if value > i8::MAX as u8 {
+ None
+ } else {
+ self.with_offset_second_signed(value as i8)
+ }
+ }
+
+ /// Set the `offset_second` component and return `self`.
+ pub const fn with_offset_second_signed(mut self, value: i8) -> Option<Self> {
+ self.offset_second = OptionRangedI8::Some(const_try_opt!(RangedI8::new(value)));
+ Some(self)
+ }
+
+ /// Set the `unix_timestamp_nanos` component and return `self`.
+ pub const fn with_unix_timestamp_nanos(mut self, value: i128) -> Option<Self> {
+ self.unix_timestamp_nanos = OptionRangedI128::Some(const_try_opt!(RangedI128::new(value)));
+ Some(self)
+ }
+}
+
+impl TryFrom<Parsed> for Date {
+ type Error = error::TryFromParsed;
+
+ fn try_from(mut parsed: Parsed) -> Result<Self, Self::Error> {
+ /// Match on the components that need to be present.
+ macro_rules! match_ {
+ (_ => $catch_all:expr $(,)?) => {
+ $catch_all
+ };
+ (($($name:ident),* $(,)?) => $arm:expr, $($rest:tt)*) => {
+ if let ($(Some($name)),*) = ($(parsed.$name()),*) {
+ $arm
+ } else {
+ match_!($($rest)*)
+ }
+ };
+ }
+
+ /// Get the value needed to adjust the ordinal day for Sunday and Monday-based week
+ /// numbering.
+ const fn adjustment(year: i32) -> i16 {
+ // Safety: `ordinal` is not zero.
+ match unsafe { Date::__from_ordinal_date_unchecked(year, 1) }.weekday() {
+ Weekday::Monday => 7,
+ Weekday::Tuesday => 1,
+ Weekday::Wednesday => 2,
+ Weekday::Thursday => 3,
+ Weekday::Friday => 4,
+ Weekday::Saturday => 5,
+ Weekday::Sunday => 6,
+ }
+ }
+
+ // If we do not have the year but we have *both* the century and the last two digits, we can
+ // construct the year. Likewise for the ISO year.
+ if let (None, Some(century), Some(is_negative), Some(last_two)) = (
+ parsed.year(),
+ parsed.year_century(),
+ parsed.year_century_is_negative(),
+ parsed.year_last_two(),
+ ) {
+ let year = if is_negative {
+ 100 * century.extend::<i32>() - last_two.cast_signed().extend::<i32>()
+ } else {
+ 100 * century.extend::<i32>() + last_two.cast_signed().extend::<i32>()
+ };
+ parsed.year = OptionRangedI32::from(RangedI32::new(year));
+ }
+ if let (None, Some(century), Some(is_negative), Some(last_two)) = (
+ parsed.iso_year(),
+ parsed.iso_year_century(),
+ parsed.iso_year_century_is_negative(),
+ parsed.iso_year_last_two(),
+ ) {
+ let iso_year = if is_negative {
+ 100 * century.extend::<i32>() - last_two.cast_signed().extend::<i32>()
+ } else {
+ 100 * century.extend::<i32>() + last_two.cast_signed().extend::<i32>()
+ };
+ parsed.iso_year = OptionRangedI32::from(RangedI32::new(iso_year));
+ }
+
+ match_! {
+ (year, ordinal) => Ok(Self::from_ordinal_date(year, ordinal.get())?),
+ (year, month, day) => Ok(Self::from_calendar_date(year, month, day.get())?),
+ (iso_year, iso_week_number, weekday) => Ok(Self::from_iso_week_date(
+ iso_year,
+ iso_week_number.get(),
+ weekday,
+ )?),
+ (year, sunday_week_number, weekday) => Ok(Self::from_ordinal_date(
+ year,
+ (sunday_week_number.cast_signed().extend::<i16>() * 7
+ + weekday.number_days_from_sunday().cast_signed().extend::<i16>()
+ - adjustment(year)
+ + 1).cast_unsigned(),
+ )?),
+ (year, monday_week_number, weekday) => Ok(Self::from_ordinal_date(
+ year,
+ (monday_week_number.cast_signed().extend::<i16>() * 7
+ + weekday.number_days_from_monday().cast_signed().extend::<i16>()
+ - adjustment(year)
+ + 1).cast_unsigned(),
+ )?),
+ _ => Err(InsufficientInformation),
+ }
+ }
+}
+
+impl TryFrom<Parsed> for Time {
+ type Error = error::TryFromParsed;
+
+ fn try_from(parsed: Parsed) -> Result<Self, Self::Error> {
+ let hour = match (parsed.hour_24(), parsed.hour_12(), parsed.hour_12_is_pm()) {
+ (Some(hour), _, _) => hour,
+ (_, Some(hour), Some(false)) if hour.get() == 12 => 0,
+ (_, Some(hour), Some(true)) if hour.get() == 12 => 12,
+ (_, Some(hour), Some(false)) => hour.get(),
+ (_, Some(hour), Some(true)) => hour.get() + 12,
+ _ => return Err(InsufficientInformation),
+ };
+
+ if parsed.hour_24().is_none()
+ && parsed.hour_12().is_some()
+ && parsed.hour_12_is_pm().is_some()
+ && parsed.minute().is_none()
+ && parsed.second().is_none()
+ && parsed.subsecond().is_none()
+ {
+ return Ok(Self::from_hms_nano(hour, 0, 0, 0)?);
+ }
+
+ // Reject combinations such as hour-second with minute omitted.
+ match (parsed.minute(), parsed.second(), parsed.subsecond()) {
+ (None, None, None) => Ok(Self::from_hms_nano(hour, 0, 0, 0)?),
+ (Some(minute), None, None) => Ok(Self::from_hms_nano(hour, minute, 0, 0)?),
+ (Some(minute), Some(second), None) => Ok(Self::from_hms_nano(hour, minute, second, 0)?),
+ (Some(minute), Some(second), Some(subsecond)) => {
+ Ok(Self::from_hms_nano(hour, minute, second, subsecond)?)
+ }
+ _ => Err(InsufficientInformation),
+ }
+ }
+}
+
+fn utc_offset_try_from_parsed<const REQUIRED: bool>(
+ parsed: Parsed,
+) -> Result<UtcOffset, error::TryFromParsed> {
+ let hour = match (REQUIRED, parsed.offset_hour()) {
+ // An offset is required, but the hour is missing. Return an error.
+ (true, None) => return Err(InsufficientInformation),
+ // An offset is not required (e.g. for `UtcDateTime`). As the hour is missing, minutes and
+ // seconds are not parsed. This is UTC.
+ (false, None) => return Ok(UtcOffset::UTC),
+ // Any other situation has an hour present.
+ (_, Some(hour)) => hour,
+ };
+ let minute = parsed.offset_minute_signed();
+ // Force `second` to be `None` if `minute` is `None`.
+ let second = minute.and_then(|_| parsed.offset_second_signed());
+
+ let minute = minute.unwrap_or(0);
+ let second = second.unwrap_or(0);
+
+ UtcOffset::from_hms(hour, minute, second).map_err(|mut err| {
+ // Provide the user a more accurate error.
+ if err.name == "hours" {
+ err.name = "offset hour";
+ } else if err.name == "minutes" {
+ err.name = "offset minute";
+ } else if err.name == "seconds" {
+ err.name = "offset second";
+ }
+ err.into()
+ })
+}
+
+impl TryFrom<Parsed> for UtcOffset {
+ type Error = error::TryFromParsed;
+
+ fn try_from(parsed: Parsed) -> Result<Self, Self::Error> {
+ utc_offset_try_from_parsed::<true>(parsed)
+ }
+}
+
+impl TryFrom<Parsed> for PrimitiveDateTime {
+ type Error = error::TryFromParsed;
+
+ fn try_from(parsed: Parsed) -> Result<Self, Self::Error> {
+ Ok(Self::new(parsed.try_into()?, parsed.try_into()?))
+ }
+}
+
+impl TryFrom<Parsed> for UtcDateTime {
+ type Error = error::TryFromParsed;
+
+ fn try_from(mut parsed: Parsed) -> Result<Self, Self::Error> {
+ if let Some(timestamp) = parsed.unix_timestamp_nanos() {
+ let mut value = Self::from_unix_timestamp_nanos(timestamp)?;
+ if let Some(subsecond) = parsed.subsecond() {
+ value = value.replace_nanosecond(subsecond)?;
+ }
+ return Ok(value);
+ }
+
+ // Some well-known formats explicitly allow leap seconds. We don't currently support them,
+ // so treat it as the nearest preceding moment that can be represented. Because leap seconds
+ // always fall at the end of a month UTC, reject any that are at other times.
+ let leap_second_input = if parsed.leap_second_allowed && parsed.second() == Some(60) {
+ if parsed.set_second(59).is_none() {
+ bug!("59 is a valid second");
+ }
+ if parsed.set_subsecond(999_999_999).is_none() {
+ bug!("999_999_999 is a valid subsecond");
+ }
+ true
+ } else {
+ false
+ };
+
+ let dt = OffsetDateTime::new_in_offset(
+ Date::try_from(parsed)?,
+ Time::try_from(parsed)?,
+ utc_offset_try_from_parsed::<false>(parsed)?,
+ )
+ .to_utc();
+
+ if leap_second_input && !dt.is_valid_leap_second_stand_in() {
+ return Err(error::TryFromParsed::ComponentRange(
+ error::ComponentRange {
+ name: "second",
+ minimum: 0,
+ maximum: 59,
+ value: 60,
+ conditional_message: Some("because leap seconds are not supported"),
+ },
+ ));
+ }
+ Ok(dt)
+ }
+}
+
+impl TryFrom<Parsed> for OffsetDateTime {
+ type Error = error::TryFromParsed;
+
+ fn try_from(mut parsed: Parsed) -> Result<Self, Self::Error> {
+ if let Some(timestamp) = parsed.unix_timestamp_nanos() {
+ let mut value = Self::from_unix_timestamp_nanos(timestamp)?;
+ if let Some(subsecond) = parsed.subsecond() {
+ value = value.replace_nanosecond(subsecond)?;
+ }
+ return Ok(value);
+ }
+
+ // Some well-known formats explicitly allow leap seconds. We don't currently support them,
+ // so treat it as the nearest preceding moment that can be represented. Because leap seconds
+ // always fall at the end of a month UTC, reject any that are at other times.
+ let leap_second_input = if parsed.leap_second_allowed && parsed.second() == Some(60) {
+ if parsed.set_second(59).is_none() {
+ bug!("59 is a valid second");
+ }
+ if parsed.set_subsecond(999_999_999).is_none() {
+ bug!("999_999_999 is a valid subsecond");
+ }
+ true
+ } else {
+ false
+ };
+
+ let dt = Self::new_in_offset(
+ Date::try_from(parsed)?,
+ Time::try_from(parsed)?,
+ UtcOffset::try_from(parsed)?,
+ );
+
+ if leap_second_input && !dt.is_valid_leap_second_stand_in() {
+ return Err(error::TryFromParsed::ComponentRange(
+ error::ComponentRange {
+ name: "second",
+ minimum: 0,
+ maximum: 59,
+ value: 60,
+ conditional_message: Some("because leap seconds are not supported"),
+ },
+ ));
+ }
+ Ok(dt)
+ }
+}
diff --git a/vendor/time/src/parsing/shim.rs b/vendor/time/src/parsing/shim.rs
new file mode 100644
index 00000000..ced7feb0
--- /dev/null
+++ b/vendor/time/src/parsing/shim.rs
@@ -0,0 +1,50 @@
+//! Extension traits for things either not implemented or not yet stable in the MSRV.
+
+/// Equivalent of `foo.parse()` for slices.
+pub(crate) trait IntegerParseBytes<T> {
+ #[allow(clippy::missing_docs_in_private_items)]
+ fn parse_bytes(&self) -> Option<T>;
+}
+
+impl<T: Integer> IntegerParseBytes<T> for [u8] {
+ fn parse_bytes(&self) -> Option<T> {
+ T::parse_bytes(self)
+ }
+}
+
+/// Marker trait for all integer types, including `NonZero*`
+pub(crate) trait Integer: Sized {
+ #[allow(clippy::missing_docs_in_private_items)]
+ fn parse_bytes(src: &[u8]) -> Option<Self>;
+}
+
+/// Parse the given types from bytes.
+macro_rules! impl_parse_bytes {
+ ($($t:ty)*) => ($(
+ impl Integer for $t {
+ #[allow(trivial_numeric_casts)]
+ fn parse_bytes(src: &[u8]) -> Option<Self> {
+ src.iter().try_fold::<Self, _, _>(0, |result, c| {
+ result.checked_mul(10)?.checked_add((c - b'0') as Self)
+ })
+ }
+ }
+ )*)
+}
+impl_parse_bytes! { u8 u16 u32 u128 }
+
+/// Parse the given types from bytes.
+macro_rules! impl_parse_bytes_nonzero {
+ ($($t:ty)*) => {$(
+ impl Integer for $t {
+ fn parse_bytes(src: &[u8]) -> Option<Self> {
+ Self::new(src.parse_bytes()?)
+ }
+ }
+ )*}
+}
+
+impl_parse_bytes_nonzero! {
+ core::num::NonZeroU8
+ core::num::NonZeroU16
+}
diff --git a/vendor/time/src/primitive_date_time.rs b/vendor/time/src/primitive_date_time.rs
new file mode 100644
index 00000000..07c11cba
--- /dev/null
+++ b/vendor/time/src/primitive_date_time.rs
@@ -0,0 +1,1050 @@
+//! The [`PrimitiveDateTime`] struct and its associated `impl`s.
+
+#[cfg(feature = "formatting")]
+use alloc::string::String;
+use core::fmt;
+use core::ops::{Add, AddAssign, Sub, SubAssign};
+use core::time::Duration as StdDuration;
+#[cfg(feature = "formatting")]
+use std::io;
+
+use powerfmt::ext::FormatterExt as _;
+use powerfmt::smart_display::{self, FormatterOptions, Metadata, SmartDisplay};
+
+#[cfg(feature = "formatting")]
+use crate::formatting::Formattable;
+use crate::internal_macros::{const_try, const_try_opt};
+#[cfg(feature = "parsing")]
+use crate::parsing::Parsable;
+use crate::{
+ error, util, Date, Duration, Month, OffsetDateTime, Time, UtcDateTime, UtcOffset, Weekday,
+};
+
+/// Combined date and time.
+#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
+pub struct PrimitiveDateTime {
+ date: Date,
+ time: Time,
+}
+
+impl PrimitiveDateTime {
+ /// The smallest value that can be represented by `PrimitiveDateTime`.
+ ///
+ /// Depending on `large-dates` feature flag, value of this constant may vary.
+ ///
+ /// 1. With `large-dates` disabled it is equal to `-9999-01-01 00:00:00.0`
+ /// 2. With `large-dates` enabled it is equal to `-999999-01-01 00:00:00.0`
+ ///
+ /// ```rust
+ /// # use time::PrimitiveDateTime;
+ /// # use time_macros::datetime;
+ #[cfg_attr(
+ feature = "large-dates",
+ doc = "// Assuming `large-dates` feature is enabled."
+ )]
+ #[cfg_attr(
+ feature = "large-dates",
+ doc = "assert_eq!(PrimitiveDateTime::MIN, datetime!(-999999-01-01 0:00));"
+ )]
+ #[cfg_attr(
+ not(feature = "large-dates"),
+ doc = "// Assuming `large-dates` feature is disabled."
+ )]
+ #[cfg_attr(
+ not(feature = "large-dates"),
+ doc = "assert_eq!(PrimitiveDateTime::MIN, datetime!(-9999-01-01 0:00));"
+ )]
+ /// ```
+ pub const MIN: Self = Self {
+ date: Date::MIN,
+ time: Time::MIDNIGHT,
+ };
+
+ /// The largest value that can be represented by `PrimitiveDateTime`.
+ ///
+ /// Depending on `large-dates` feature flag, value of this constant may vary.
+ ///
+ /// 1. With `large-dates` disabled it is equal to `9999-12-31 23:59:59.999_999_999`
+ /// 2. With `large-dates` enabled it is equal to `999999-12-31 23:59:59.999_999_999`
+ ///
+ /// ```rust
+ /// # use time::PrimitiveDateTime;
+ /// # use time_macros::datetime;
+ #[cfg_attr(
+ feature = "large-dates",
+ doc = "// Assuming `large-dates` feature is enabled."
+ )]
+ #[cfg_attr(
+ feature = "large-dates",
+ doc = "assert_eq!(PrimitiveDateTime::MAX, datetime!(+999999-12-31 23:59:59.999_999_999));"
+ )]
+ #[cfg_attr(
+ not(feature = "large-dates"),
+ doc = "// Assuming `large-dates` feature is disabled."
+ )]
+ #[cfg_attr(
+ not(feature = "large-dates"),
+ doc = "assert_eq!(PrimitiveDateTime::MAX, datetime!(+9999-12-31 23:59:59.999_999_999));"
+ )]
+ /// ```
+ pub const MAX: Self = Self {
+ date: Date::MAX,
+ time: Time::MAX,
+ };
+
+ /// Create a new `PrimitiveDateTime` from the provided [`Date`] and [`Time`].
+ ///
+ /// ```rust
+ /// # use time::PrimitiveDateTime;
+ /// # use time_macros::{date, datetime, time};
+ /// assert_eq!(
+ /// PrimitiveDateTime::new(date!(2019-01-01), time!(0:00)),
+ /// datetime!(2019-01-01 0:00),
+ /// );
+ /// ```
+ pub const fn new(date: Date, time: Time) -> Self {
+ Self { date, time }
+ }
+
+ /// Get the [`Date`] component of the `PrimitiveDateTime`.
+ ///
+ /// ```rust
+ /// # use time_macros::{date, datetime};
+ /// assert_eq!(datetime!(2019-01-01 0:00).date(), date!(2019-01-01));
+ /// ```
+ pub const fn date(self) -> Date {
+ self.date
+ }
+
+ /// Get the [`Time`] component of the `PrimitiveDateTime`.
+ ///
+ /// ```rust
+ /// # use time_macros::{datetime, time};
+ /// assert_eq!(datetime!(2019-01-01 0:00).time(), time!(0:00));
+ /// ```
+ pub const fn time(self) -> Time {
+ self.time
+ }
+
+ /// Get the year of the date.
+ ///
+ /// ```rust
+ /// # use time_macros::datetime;
+ /// assert_eq!(datetime!(2019-01-01 0:00).year(), 2019);
+ /// assert_eq!(datetime!(2019-12-31 0:00).year(), 2019);
+ /// assert_eq!(datetime!(2020-01-01 0:00).year(), 2020);
+ /// ```
+ pub const fn year(self) -> i32 {
+ self.date().year()
+ }
+
+ /// Get the month of the date.
+ ///
+ /// ```rust
+ /// # use time::Month;
+ /// # use time_macros::datetime;
+ /// assert_eq!(datetime!(2019-01-01 0:00).month(), Month::January);
+ /// assert_eq!(datetime!(2019-12-31 0:00).month(), Month::December);
+ /// ```
+ pub const fn month(self) -> Month {
+ self.date().month()
+ }
+
+ /// Get the day of the date.
+ ///
+ /// The returned value will always be in the range `1..=31`.
+ ///
+ /// ```rust
+ /// # use time_macros::datetime;
+ /// assert_eq!(datetime!(2019-01-01 0:00).day(), 1);
+ /// assert_eq!(datetime!(2019-12-31 0:00).day(), 31);
+ /// ```
+ pub const fn day(self) -> u8 {
+ self.date().day()
+ }
+
+ /// Get the day of the year.
+ ///
+ /// The returned value will always be in the range `1..=366` (`1..=365` for common years).
+ ///
+ /// ```rust
+ /// # use time_macros::datetime;
+ /// assert_eq!(datetime!(2019-01-01 0:00).ordinal(), 1);
+ /// assert_eq!(datetime!(2019-12-31 0:00).ordinal(), 365);
+ /// ```
+ pub const fn ordinal(self) -> u16 {
+ self.date().ordinal()
+ }
+
+ /// Get the ISO week number.
+ ///
+ /// The returned value will always be in the range `1..=53`.
+ ///
+ /// ```rust
+ /// # use time_macros::datetime;
+ /// assert_eq!(datetime!(2019-01-01 0:00).iso_week(), 1);
+ /// assert_eq!(datetime!(2019-10-04 0:00).iso_week(), 40);
+ /// assert_eq!(datetime!(2020-01-01 0:00).iso_week(), 1);
+ /// assert_eq!(datetime!(2020-12-31 0:00).iso_week(), 53);
+ /// assert_eq!(datetime!(2021-01-01 0:00).iso_week(), 53);
+ /// ```
+ pub const fn iso_week(self) -> u8 {
+ self.date().iso_week()
+ }
+
+ /// Get the week number where week 1 begins on the first Sunday.
+ ///
+ /// The returned value will always be in the range `0..=53`.
+ ///
+ /// ```rust
+ /// # use time_macros::datetime;
+ /// assert_eq!(datetime!(2019-01-01 0:00).sunday_based_week(), 0);
+ /// assert_eq!(datetime!(2020-01-01 0:00).sunday_based_week(), 0);
+ /// assert_eq!(datetime!(2020-12-31 0:00).sunday_based_week(), 52);
+ /// assert_eq!(datetime!(2021-01-01 0:00).sunday_based_week(), 0);
+ /// ```
+ pub const fn sunday_based_week(self) -> u8 {
+ self.date().sunday_based_week()
+ }
+
+ /// Get the week number where week 1 begins on the first Monday.
+ ///
+ /// The returned value will always be in the range `0..=53`.
+ ///
+ /// ```rust
+ /// # use time_macros::datetime;
+ /// assert_eq!(datetime!(2019-01-01 0:00).monday_based_week(), 0);
+ /// assert_eq!(datetime!(2020-01-01 0:00).monday_based_week(), 0);
+ /// assert_eq!(datetime!(2020-12-31 0:00).monday_based_week(), 52);
+ /// assert_eq!(datetime!(2021-01-01 0:00).monday_based_week(), 0);
+ /// ```
+ pub const fn monday_based_week(self) -> u8 {
+ self.date().monday_based_week()
+ }
+
+ /// Get the year, month, and day.
+ ///
+ /// ```rust
+ /// # use time::Month;
+ /// # use time_macros::datetime;
+ /// assert_eq!(
+ /// datetime!(2019-01-01 0:00).to_calendar_date(),
+ /// (2019, Month::January, 1)
+ /// );
+ /// ```
+ pub const fn to_calendar_date(self) -> (i32, Month, u8) {
+ self.date().to_calendar_date()
+ }
+
+ /// Get the year and ordinal day number.
+ ///
+ /// ```rust
+ /// # use time_macros::datetime;
+ /// assert_eq!(datetime!(2019-01-01 0:00).to_ordinal_date(), (2019, 1));
+ /// ```
+ pub const fn to_ordinal_date(self) -> (i32, u16) {
+ self.date().to_ordinal_date()
+ }
+
+ /// Get the ISO 8601 year, week number, and weekday.
+ ///
+ /// ```rust
+ /// # use time::Weekday::*;
+ /// # use time_macros::datetime;
+ /// assert_eq!(
+ /// datetime!(2019-01-01 0:00).to_iso_week_date(),
+ /// (2019, 1, Tuesday)
+ /// );
+ /// assert_eq!(
+ /// datetime!(2019-10-04 0:00).to_iso_week_date(),
+ /// (2019, 40, Friday)
+ /// );
+ /// assert_eq!(
+ /// datetime!(2020-01-01 0:00).to_iso_week_date(),
+ /// (2020, 1, Wednesday)
+ /// );
+ /// assert_eq!(
+ /// datetime!(2020-12-31 0:00).to_iso_week_date(),
+ /// (2020, 53, Thursday)
+ /// );
+ /// assert_eq!(
+ /// datetime!(2021-01-01 0:00).to_iso_week_date(),
+ /// (2020, 53, Friday)
+ /// );
+ /// ```
+ pub const fn to_iso_week_date(self) -> (i32, u8, Weekday) {
+ self.date().to_iso_week_date()
+ }
+
+ /// Get the weekday.
+ ///
+ /// ```rust
+ /// # use time::Weekday::*;
+ /// # use time_macros::datetime;
+ /// assert_eq!(datetime!(2019-01-01 0:00).weekday(), Tuesday);
+ /// assert_eq!(datetime!(2019-02-01 0:00).weekday(), Friday);
+ /// assert_eq!(datetime!(2019-03-01 0:00).weekday(), Friday);
+ /// assert_eq!(datetime!(2019-04-01 0:00).weekday(), Monday);
+ /// assert_eq!(datetime!(2019-05-01 0:00).weekday(), Wednesday);
+ /// assert_eq!(datetime!(2019-06-01 0:00).weekday(), Saturday);
+ /// assert_eq!(datetime!(2019-07-01 0:00).weekday(), Monday);
+ /// assert_eq!(datetime!(2019-08-01 0:00).weekday(), Thursday);
+ /// assert_eq!(datetime!(2019-09-01 0:00).weekday(), Sunday);
+ /// assert_eq!(datetime!(2019-10-01 0:00).weekday(), Tuesday);
+ /// assert_eq!(datetime!(2019-11-01 0:00).weekday(), Friday);
+ /// assert_eq!(datetime!(2019-12-01 0:00).weekday(), Sunday);
+ /// ```
+ pub const fn weekday(self) -> Weekday {
+ self.date().weekday()
+ }
+
+ /// Get the Julian day for the date. The time is not taken into account for this calculation.
+ ///
+ /// The algorithm to perform this conversion is derived from one provided by Peter Baum; it is
+ /// freely available [here](https://www.researchgate.net/publication/316558298_Date_Algorithms).
+ ///
+ /// ```rust
+ /// # use time_macros::datetime;
+ /// assert_eq!(datetime!(-4713-11-24 0:00).to_julian_day(), 0);
+ /// assert_eq!(datetime!(2000-01-01 0:00).to_julian_day(), 2_451_545);
+ /// assert_eq!(datetime!(2019-01-01 0:00).to_julian_day(), 2_458_485);
+ /// assert_eq!(datetime!(2019-12-31 0:00).to_julian_day(), 2_458_849);
+ /// ```
+ pub const fn to_julian_day(self) -> i32 {
+ self.date().to_julian_day()
+ }
+
+ /// Get the clock hour, minute, and second.
+ ///
+ /// ```rust
+ /// # use time_macros::datetime;
+ /// assert_eq!(datetime!(2020-01-01 0:00:00).as_hms(), (0, 0, 0));
+ /// assert_eq!(datetime!(2020-01-01 23:59:59).as_hms(), (23, 59, 59));
+ /// ```
+ pub const fn as_hms(self) -> (u8, u8, u8) {
+ self.time().as_hms()
+ }
+
+ /// Get the clock hour, minute, second, and millisecond.
+ ///
+ /// ```rust
+ /// # use time_macros::datetime;
+ /// assert_eq!(datetime!(2020-01-01 0:00:00).as_hms_milli(), (0, 0, 0, 0));
+ /// assert_eq!(
+ /// datetime!(2020-01-01 23:59:59.999).as_hms_milli(),
+ /// (23, 59, 59, 999)
+ /// );
+ /// ```
+ pub const fn as_hms_milli(self) -> (u8, u8, u8, u16) {
+ self.time().as_hms_milli()
+ }
+
+ /// Get the clock hour, minute, second, and microsecond.
+ ///
+ /// ```rust
+ /// # use time_macros::datetime;
+ /// assert_eq!(datetime!(2020-01-01 0:00:00).as_hms_micro(), (0, 0, 0, 0));
+ /// assert_eq!(
+ /// datetime!(2020-01-01 23:59:59.999_999).as_hms_micro(),
+ /// (23, 59, 59, 999_999)
+ /// );
+ /// ```
+ pub const fn as_hms_micro(self) -> (u8, u8, u8, u32) {
+ self.time().as_hms_micro()
+ }
+
+ /// Get the clock hour, minute, second, and nanosecond.
+ ///
+ /// ```rust
+ /// # use time_macros::datetime;
+ /// assert_eq!(datetime!(2020-01-01 0:00:00).as_hms_nano(), (0, 0, 0, 0));
+ /// assert_eq!(
+ /// datetime!(2020-01-01 23:59:59.999_999_999).as_hms_nano(),
+ /// (23, 59, 59, 999_999_999)
+ /// );
+ /// ```
+ pub const fn as_hms_nano(self) -> (u8, u8, u8, u32) {
+ self.time().as_hms_nano()
+ }
+
+ /// Get the clock hour.
+ ///
+ /// The returned value will always be in the range `0..24`.
+ ///
+ /// ```rust
+ /// # use time_macros::datetime;
+ /// assert_eq!(datetime!(2019-01-01 0:00).hour(), 0);
+ /// assert_eq!(datetime!(2019-01-01 23:59:59).hour(), 23);
+ /// ```
+ pub const fn hour(self) -> u8 {
+ self.time().hour()
+ }
+
+ /// Get the minute within the hour.
+ ///
+ /// The returned value will always be in the range `0..60`.
+ ///
+ /// ```rust
+ /// # use time_macros::datetime;
+ /// assert_eq!(datetime!(2019-01-01 0:00).minute(), 0);
+ /// assert_eq!(datetime!(2019-01-01 23:59:59).minute(), 59);
+ /// ```
+ pub const fn minute(self) -> u8 {
+ self.time().minute()
+ }
+
+ /// Get the second within the minute.
+ ///
+ /// The returned value will always be in the range `0..60`.
+ ///
+ /// ```rust
+ /// # use time_macros::datetime;
+ /// assert_eq!(datetime!(2019-01-01 0:00).second(), 0);
+ /// assert_eq!(datetime!(2019-01-01 23:59:59).second(), 59);
+ /// ```
+ pub const fn second(self) -> u8 {
+ self.time().second()
+ }
+
+ /// Get the milliseconds within the second.
+ ///
+ /// The returned value will always be in the range `0..1_000`.
+ ///
+ /// ```rust
+ /// # use time_macros::datetime;
+ /// assert_eq!(datetime!(2019-01-01 0:00).millisecond(), 0);
+ /// assert_eq!(datetime!(2019-01-01 23:59:59.999).millisecond(), 999);
+ /// ```
+ pub const fn millisecond(self) -> u16 {
+ self.time().millisecond()
+ }
+
+ /// Get the microseconds within the second.
+ ///
+ /// The returned value will always be in the range `0..1_000_000`.
+ ///
+ /// ```rust
+ /// # use time_macros::datetime;
+ /// assert_eq!(datetime!(2019-01-01 0:00).microsecond(), 0);
+ /// assert_eq!(
+ /// datetime!(2019-01-01 23:59:59.999_999).microsecond(),
+ /// 999_999
+ /// );
+ /// ```
+ pub const fn microsecond(self) -> u32 {
+ self.time().microsecond()
+ }
+
+ /// Get the nanoseconds within the second.
+ ///
+ /// The returned value will always be in the range `0..1_000_000_000`.
+ ///
+ /// ```rust
+ /// # use time_macros::datetime;
+ /// assert_eq!(datetime!(2019-01-01 0:00).nanosecond(), 0);
+ /// assert_eq!(
+ /// datetime!(2019-01-01 23:59:59.999_999_999).nanosecond(),
+ /// 999_999_999,
+ /// );
+ /// ```
+ pub const fn nanosecond(self) -> u32 {
+ self.time().nanosecond()
+ }
+
+ /// Assuming that the existing `PrimitiveDateTime` represents a moment in the provided
+ /// [`UtcOffset`], return an [`OffsetDateTime`].
+ ///
+ /// ```rust
+ /// # use time_macros::{datetime, offset};
+ /// assert_eq!(
+ /// datetime!(2019-01-01 0:00)
+ /// .assume_offset(offset!(UTC))
+ /// .unix_timestamp(),
+ /// 1_546_300_800,
+ /// );
+ /// assert_eq!(
+ /// datetime!(2019-01-01 0:00)
+ /// .assume_offset(offset!(-1))
+ /// .unix_timestamp(),
+ /// 1_546_304_400,
+ /// );
+ /// ```
+ pub const fn assume_offset(self, offset: UtcOffset) -> OffsetDateTime {
+ OffsetDateTime::new_in_offset(self.date, self.time, offset)
+ }
+
+ /// Assuming that the existing `PrimitiveDateTime` represents a moment in UTC, return an
+ /// [`OffsetDateTime`].
+ ///
+ /// ```rust
+ /// # use time_macros::datetime;
+ /// assert_eq!(
+ /// datetime!(2019-01-01 0:00).assume_utc().unix_timestamp(),
+ /// 1_546_300_800,
+ /// );
+ /// ```
+ ///
+ /// **Note**: You may want a [`UtcDateTime`] instead, which can be obtained with the
+ /// [`PrimitiveDateTime::as_utc`] method.
+ pub const fn assume_utc(self) -> OffsetDateTime {
+ self.assume_offset(UtcOffset::UTC)
+ }
+
+ /// Assuming that the existing `PrimitiveDateTime` represents a moment in UTC, return a
+ /// [`UtcDateTime`].
+ ///
+ /// ```rust
+ /// # use time_macros::datetime;
+ /// assert_eq!(
+ /// datetime!(2019-01-01 0:00).as_utc().unix_timestamp(),
+ /// 1_546_300_800,
+ /// );
+ /// ```
+ pub const fn as_utc(self) -> UtcDateTime {
+ UtcDateTime::from_primitive(self)
+ }
+
+ /// Computes `self + duration`, returning `None` if an overflow occurred.
+ ///
+ /// ```
+ /// # use time::{Date, ext::NumericalDuration};
+ /// # use time_macros::datetime;
+ /// let datetime = Date::MIN.midnight();
+ /// assert_eq!(datetime.checked_add((-2).days()), None);
+ ///
+ /// let datetime = Date::MAX.midnight();
+ /// assert_eq!(datetime.checked_add(1.days()), None);
+ ///
+ /// assert_eq!(
+ /// datetime!(2019-11-25 15:30).checked_add(27.hours()),
+ /// Some(datetime!(2019-11-26 18:30))
+ /// );
+ /// ```
+ pub const fn checked_add(self, duration: Duration) -> Option<Self> {
+ let (date_adjustment, time) = self.time.adjusting_add(duration);
+ let date = const_try_opt!(self.date.checked_add(duration));
+
+ Some(Self {
+ date: match date_adjustment {
+ util::DateAdjustment::Previous => const_try_opt!(date.previous_day()),
+ util::DateAdjustment::Next => const_try_opt!(date.next_day()),
+ util::DateAdjustment::None => date,
+ },
+ time,
+ })
+ }
+
+ /// Computes `self - duration`, returning `None` if an overflow occurred.
+ ///
+ /// ```
+ /// # use time::{Date, ext::NumericalDuration};
+ /// # use time_macros::datetime;
+ /// let datetime = Date::MIN.midnight();
+ /// assert_eq!(datetime.checked_sub(2.days()), None);
+ ///
+ /// let datetime = Date::MAX.midnight();
+ /// assert_eq!(datetime.checked_sub((-1).days()), None);
+ ///
+ /// assert_eq!(
+ /// datetime!(2019-11-25 15:30).checked_sub(27.hours()),
+ /// Some(datetime!(2019-11-24 12:30))
+ /// );
+ /// ```
+ pub const fn checked_sub(self, duration: Duration) -> Option<Self> {
+ let (date_adjustment, time) = self.time.adjusting_sub(duration);
+ let date = const_try_opt!(self.date.checked_sub(duration));
+
+ Some(Self {
+ date: match date_adjustment {
+ util::DateAdjustment::Previous => const_try_opt!(date.previous_day()),
+ util::DateAdjustment::Next => const_try_opt!(date.next_day()),
+ util::DateAdjustment::None => date,
+ },
+ time,
+ })
+ }
+
+ /// Computes `self + duration`, saturating value on overflow.
+ ///
+ /// ```
+ /// # use time::{PrimitiveDateTime, ext::NumericalDuration};
+ /// # use time_macros::datetime;
+ /// assert_eq!(
+ /// PrimitiveDateTime::MIN.saturating_add((-2).days()),
+ /// PrimitiveDateTime::MIN
+ /// );
+ ///
+ /// assert_eq!(
+ /// PrimitiveDateTime::MAX.saturating_add(2.days()),
+ /// PrimitiveDateTime::MAX
+ /// );
+ ///
+ /// assert_eq!(
+ /// datetime!(2019-11-25 15:30).saturating_add(27.hours()),
+ /// datetime!(2019-11-26 18:30)
+ /// );
+ /// ```
+ pub const fn saturating_add(self, duration: Duration) -> Self {
+ if let Some(datetime) = self.checked_add(duration) {
+ datetime
+ } else if duration.is_negative() {
+ Self::MIN
+ } else {
+ Self::MAX
+ }
+ }
+
+ /// Computes `self - duration`, saturating value on overflow.
+ ///
+ /// ```
+ /// # use time::{PrimitiveDateTime, ext::NumericalDuration};
+ /// # use time_macros::datetime;
+ /// assert_eq!(
+ /// PrimitiveDateTime::MIN.saturating_sub(2.days()),
+ /// PrimitiveDateTime::MIN
+ /// );
+ ///
+ /// assert_eq!(
+ /// PrimitiveDateTime::MAX.saturating_sub((-2).days()),
+ /// PrimitiveDateTime::MAX
+ /// );
+ ///
+ /// assert_eq!(
+ /// datetime!(2019-11-25 15:30).saturating_sub(27.hours()),
+ /// datetime!(2019-11-24 12:30)
+ /// );
+ /// ```
+ pub const fn saturating_sub(self, duration: Duration) -> Self {
+ if let Some(datetime) = self.checked_sub(duration) {
+ datetime
+ } else if duration.is_negative() {
+ Self::MAX
+ } else {
+ Self::MIN
+ }
+ }
+}
+
+/// Methods that replace part of the `PrimitiveDateTime`.
+impl PrimitiveDateTime {
+ /// Replace the time, preserving the date.
+ ///
+ /// ```rust
+ /// # use time_macros::{datetime, time};
+ /// assert_eq!(
+ /// datetime!(2020-01-01 17:00).replace_time(time!(5:00)),
+ /// datetime!(2020-01-01 5:00)
+ /// );
+ /// ```
+ #[must_use = "This method does not mutate the original `PrimitiveDateTime`."]
+ pub const fn replace_time(self, time: Time) -> Self {
+ Self {
+ date: self.date,
+ time,
+ }
+ }
+
+ /// Replace the date, preserving the time.
+ ///
+ /// ```rust
+ /// # use time_macros::{datetime, date};
+ /// assert_eq!(
+ /// datetime!(2020-01-01 12:00).replace_date(date!(2020-01-30)),
+ /// datetime!(2020-01-30 12:00)
+ /// );
+ /// ```
+ #[must_use = "This method does not mutate the original `PrimitiveDateTime`."]
+ pub const fn replace_date(self, date: Date) -> Self {
+ Self {
+ date,
+ time: self.time,
+ }
+ }
+
+ /// Replace the year. The month and day will be unchanged.
+ ///
+ /// ```rust
+ /// # use time_macros::datetime;
+ /// assert_eq!(
+ /// datetime!(2022-02-18 12:00).replace_year(2019),
+ /// Ok(datetime!(2019-02-18 12:00))
+ /// );
+ /// assert!(datetime!(2022-02-18 12:00).replace_year(-1_000_000_000).is_err()); // -1_000_000_000 isn't a valid year
+ /// assert!(datetime!(2022-02-18 12:00).replace_year(1_000_000_000).is_err()); // 1_000_000_000 isn't a valid year
+ /// ```
+ #[must_use = "This method does not mutate the original `PrimitiveDateTime`."]
+ pub const fn replace_year(self, year: i32) -> Result<Self, error::ComponentRange> {
+ Ok(Self {
+ date: const_try!(self.date.replace_year(year)),
+ time: self.time,
+ })
+ }
+
+ /// Replace the month of the year.
+ ///
+ /// ```rust
+ /// # use time_macros::datetime;
+ /// # use time::Month;
+ /// assert_eq!(
+ /// datetime!(2022-02-18 12:00).replace_month(Month::January),
+ /// Ok(datetime!(2022-01-18 12:00))
+ /// );
+ /// assert!(datetime!(2022-01-30 12:00).replace_month(Month::February).is_err()); // 30 isn't a valid day in February
+ /// ```
+ #[must_use = "This method does not mutate the original `PrimitiveDateTime`."]
+ pub const fn replace_month(self, month: Month) -> Result<Self, error::ComponentRange> {
+ Ok(Self {
+ date: const_try!(self.date.replace_month(month)),
+ time: self.time,
+ })
+ }
+
+ /// Replace the day of the month.
+ ///
+ /// ```rust
+ /// # use time_macros::datetime;
+ /// assert_eq!(
+ /// datetime!(2022-02-18 12:00).replace_day(1),
+ /// Ok(datetime!(2022-02-01 12:00))
+ /// );
+ /// assert!(datetime!(2022-02-18 12:00).replace_day(0).is_err()); // 00 isn't a valid day
+ /// assert!(datetime!(2022-02-18 12:00).replace_day(30).is_err()); // 30 isn't a valid day in February
+ /// ```
+ #[must_use = "This method does not mutate the original `PrimitiveDateTime`."]
+ pub const fn replace_day(self, day: u8) -> Result<Self, error::ComponentRange> {
+ Ok(Self {
+ date: const_try!(self.date.replace_day(day)),
+ time: self.time,
+ })
+ }
+
+ /// Replace the day of the year.
+ ///
+ /// ```rust
+ /// # use time_macros::datetime;
+ /// assert_eq!(datetime!(2022-049 12:00).replace_ordinal(1), Ok(datetime!(2022-001 12:00)));
+ /// assert!(datetime!(2022-049 12:00).replace_ordinal(0).is_err()); // 0 isn't a valid ordinal
+ /// assert!(datetime!(2022-049 12:00).replace_ordinal(366).is_err()); // 2022 isn't a leap year
+ /// ````
+ #[must_use = "This method does not mutate the original `PrimitiveDateTime`."]
+ pub const fn replace_ordinal(self, ordinal: u16) -> Result<Self, error::ComponentRange> {
+ Ok(Self {
+ date: const_try!(self.date.replace_ordinal(ordinal)),
+ time: self.time,
+ })
+ }
+
+ /// Replace the clock hour.
+ ///
+ /// ```rust
+ /// # use time_macros::datetime;
+ /// assert_eq!(
+ /// datetime!(2022-02-18 01:02:03.004_005_006).replace_hour(7),
+ /// Ok(datetime!(2022-02-18 07:02:03.004_005_006))
+ /// );
+ /// assert!(datetime!(2022-02-18 01:02:03.004_005_006).replace_hour(24).is_err()); // 24 isn't a valid hour
+ /// ```
+ #[must_use = "This method does not mutate the original `PrimitiveDateTime`."]
+ pub const fn replace_hour(self, hour: u8) -> Result<Self, error::ComponentRange> {
+ Ok(Self {
+ date: self.date,
+ time: const_try!(self.time.replace_hour(hour)),
+ })
+ }
+
+ /// Replace the minutes within the hour.
+ ///
+ /// ```rust
+ /// # use time_macros::datetime;
+ /// assert_eq!(
+ /// datetime!(2022-02-18 01:02:03.004_005_006).replace_minute(7),
+ /// Ok(datetime!(2022-02-18 01:07:03.004_005_006))
+ /// );
+ /// assert!(datetime!(2022-02-18 01:02:03.004_005_006).replace_minute(60).is_err()); // 60 isn't a valid minute
+ /// ```
+ #[must_use = "This method does not mutate the original `PrimitiveDateTime`."]
+ pub const fn replace_minute(self, minute: u8) -> Result<Self, error::ComponentRange> {
+ Ok(Self {
+ date: self.date,
+ time: const_try!(self.time.replace_minute(minute)),
+ })
+ }
+
+ /// Replace the seconds within the minute.
+ ///
+ /// ```rust
+ /// # use time_macros::datetime;
+ /// assert_eq!(
+ /// datetime!(2022-02-18 01:02:03.004_005_006).replace_second(7),
+ /// Ok(datetime!(2022-02-18 01:02:07.004_005_006))
+ /// );
+ /// assert!(datetime!(2022-02-18 01:02:03.004_005_006).replace_second(60).is_err()); // 60 isn't a valid second
+ /// ```
+ #[must_use = "This method does not mutate the original `PrimitiveDateTime`."]
+ pub const fn replace_second(self, second: u8) -> Result<Self, error::ComponentRange> {
+ Ok(Self {
+ date: self.date,
+ time: const_try!(self.time.replace_second(second)),
+ })
+ }
+
+ /// Replace the milliseconds within the second.
+ ///
+ /// ```rust
+ /// # use time_macros::datetime;
+ /// assert_eq!(
+ /// datetime!(2022-02-18 01:02:03.004_005_006).replace_millisecond(7),
+ /// Ok(datetime!(2022-02-18 01:02:03.007))
+ /// );
+ /// assert!(datetime!(2022-02-18 01:02:03.004_005_006).replace_millisecond(1_000).is_err()); // 1_000 isn't a valid millisecond
+ /// ```
+ #[must_use = "This method does not mutate the original `PrimitiveDateTime`."]
+ pub const fn replace_millisecond(
+ self,
+ millisecond: u16,
+ ) -> Result<Self, error::ComponentRange> {
+ Ok(Self {
+ date: self.date,
+ time: const_try!(self.time.replace_millisecond(millisecond)),
+ })
+ }
+
+ /// Replace the microseconds within the second.
+ ///
+ /// ```rust
+ /// # use time_macros::datetime;
+ /// assert_eq!(
+ /// datetime!(2022-02-18 01:02:03.004_005_006).replace_microsecond(7_008),
+ /// Ok(datetime!(2022-02-18 01:02:03.007_008))
+ /// );
+ /// assert!(datetime!(2022-02-18 01:02:03.004_005_006).replace_microsecond(1_000_000).is_err()); // 1_000_000 isn't a valid microsecond
+ /// ```
+ #[must_use = "This method does not mutate the original `PrimitiveDateTime`."]
+ pub const fn replace_microsecond(
+ self,
+ microsecond: u32,
+ ) -> Result<Self, error::ComponentRange> {
+ Ok(Self {
+ date: self.date,
+ time: const_try!(self.time.replace_microsecond(microsecond)),
+ })
+ }
+
+ /// Replace the nanoseconds within the second.
+ ///
+ /// ```rust
+ /// # use time_macros::datetime;
+ /// assert_eq!(
+ /// datetime!(2022-02-18 01:02:03.004_005_006).replace_nanosecond(7_008_009),
+ /// Ok(datetime!(2022-02-18 01:02:03.007_008_009))
+ /// );
+ /// assert!(datetime!(2022-02-18 01:02:03.004_005_006).replace_nanosecond(1_000_000_000).is_err()); // 1_000_000_000 isn't a valid nanosecond
+ /// ```
+ #[must_use = "This method does not mutate the original `PrimitiveDateTime`."]
+ pub const fn replace_nanosecond(self, nanosecond: u32) -> Result<Self, error::ComponentRange> {
+ Ok(Self {
+ date: self.date,
+ time: const_try!(self.time.replace_nanosecond(nanosecond)),
+ })
+ }
+}
+
+#[cfg(feature = "formatting")]
+impl PrimitiveDateTime {
+ /// Format the `PrimitiveDateTime` using the provided [format
+ /// description](crate::format_description).
+ pub fn format_into(
+ self,
+ output: &mut (impl io::Write + ?Sized),
+ format: &(impl Formattable + ?Sized),
+ ) -> Result<usize, error::Format> {
+ format.format_into(output, Some(self.date), Some(self.time), None)
+ }
+
+ /// Format the `PrimitiveDateTime` using the provided [format
+ /// description](crate::format_description).
+ ///
+ /// ```rust
+ /// # use time::format_description;
+ /// # use time_macros::datetime;
+ /// let format = format_description::parse("[year]-[month]-[day] [hour]:[minute]:[second]")?;
+ /// assert_eq!(
+ /// datetime!(2020-01-02 03:04:05).format(&format)?,
+ /// "2020-01-02 03:04:05"
+ /// );
+ /// # Ok::<_, time::Error>(())
+ /// ```
+ pub fn format(self, format: &(impl Formattable + ?Sized)) -> Result<String, error::Format> {
+ format.format(Some(self.date), Some(self.time), None)
+ }
+}
+
+#[cfg(feature = "parsing")]
+impl PrimitiveDateTime {
+ /// Parse a `PrimitiveDateTime` from the input using the provided [format
+ /// description](crate::format_description).
+ ///
+ /// ```rust
+ /// # use time::PrimitiveDateTime;
+ /// # use time_macros::{datetime, format_description};
+ /// let format = format_description!("[year]-[month]-[day] [hour]:[minute]:[second]");
+ /// assert_eq!(
+ /// PrimitiveDateTime::parse("2020-01-02 03:04:05", &format)?,
+ /// datetime!(2020-01-02 03:04:05)
+ /// );
+ /// # Ok::<_, time::Error>(())
+ /// ```
+ pub fn parse(
+ input: &str,
+ description: &(impl Parsable + ?Sized),
+ ) -> Result<Self, error::Parse> {
+ description.parse_primitive_date_time(input.as_bytes())
+ }
+}
+
+impl SmartDisplay for PrimitiveDateTime {
+ type Metadata = ();
+
+ fn metadata(&self, _: FormatterOptions) -> Metadata<Self> {
+ let width = smart_display::padded_width_of!(self.date, " ", self.time);
+ Metadata::new(width, self, ())
+ }
+
+ fn fmt_with_metadata(
+ &self,
+ f: &mut fmt::Formatter<'_>,
+ metadata: Metadata<Self>,
+ ) -> fmt::Result {
+ f.pad_with_width(
+ metadata.unpadded_width(),
+ format_args!("{} {}", self.date, self.time),
+ )
+ }
+}
+
+impl fmt::Display for PrimitiveDateTime {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ SmartDisplay::fmt(self, f)
+ }
+}
+
+impl fmt::Debug for PrimitiveDateTime {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt::Display::fmt(self, f)
+ }
+}
+
+impl Add<Duration> for PrimitiveDateTime {
+ type Output = Self;
+
+ /// # Panics
+ ///
+ /// This may panic if an overflow occurs.
+ fn add(self, duration: Duration) -> Self::Output {
+ self.checked_add(duration)
+ .expect("resulting value is out of range")
+ }
+}
+
+impl Add<StdDuration> for PrimitiveDateTime {
+ type Output = Self;
+
+ /// # Panics
+ ///
+ /// This may panic if an overflow occurs.
+ fn add(self, duration: StdDuration) -> Self::Output {
+ let (is_next_day, time) = self.time.adjusting_add_std(duration);
+
+ Self {
+ date: if is_next_day {
+ (self.date + duration)
+ .next_day()
+ .expect("resulting value is out of range")
+ } else {
+ self.date + duration
+ },
+ time,
+ }
+ }
+}
+
+impl AddAssign<Duration> for PrimitiveDateTime {
+ /// # Panics
+ ///
+ /// This may panic if an overflow occurs.
+ fn add_assign(&mut self, duration: Duration) {
+ *self = *self + duration;
+ }
+}
+
+impl AddAssign<StdDuration> for PrimitiveDateTime {
+ /// # Panics
+ ///
+ /// This may panic if an overflow occurs.
+ fn add_assign(&mut self, duration: StdDuration) {
+ *self = *self + duration;
+ }
+}
+
+impl Sub<Duration> for PrimitiveDateTime {
+ type Output = Self;
+
+ /// # Panics
+ ///
+ /// This may panic if an overflow occurs.
+ fn sub(self, duration: Duration) -> Self::Output {
+ self.checked_sub(duration)
+ .expect("resulting value is out of range")
+ }
+}
+
+impl Sub<StdDuration> for PrimitiveDateTime {
+ type Output = Self;
+
+ /// # Panics
+ ///
+ /// This may panic if an overflow occurs.
+ fn sub(self, duration: StdDuration) -> Self::Output {
+ let (is_previous_day, time) = self.time.adjusting_sub_std(duration);
+
+ Self {
+ date: if is_previous_day {
+ (self.date - duration)
+ .previous_day()
+ .expect("resulting value is out of range")
+ } else {
+ self.date - duration
+ },
+ time,
+ }
+ }
+}
+
+impl SubAssign<Duration> for PrimitiveDateTime {
+ /// # Panics
+ ///
+ /// This may panic if an overflow occurs.
+ fn sub_assign(&mut self, duration: Duration) {
+ *self = *self - duration;
+ }
+}
+
+impl SubAssign<StdDuration> for PrimitiveDateTime {
+ /// # Panics
+ ///
+ /// This may panic if an overflow occurs.
+ fn sub_assign(&mut self, duration: StdDuration) {
+ *self = *self - duration;
+ }
+}
+
+impl Sub for PrimitiveDateTime {
+ type Output = Duration;
+
+ /// # Panics
+ ///
+ /// This may panic if an overflow occurs.
+ fn sub(self, rhs: Self) -> Self::Output {
+ (self.date - rhs.date) + (self.time - rhs.time)
+ }
+}
diff --git a/vendor/time/src/quickcheck.rs b/vendor/time/src/quickcheck.rs
new file mode 100644
index 00000000..6336ec25
--- /dev/null
+++ b/vendor/time/src/quickcheck.rs
@@ -0,0 +1,230 @@
+//! Implementations of the [`quickcheck::Arbitrary`](quickcheck::Arbitrary) trait.
+//!
+//! This enables users to write tests such as this, and have test values provided automatically:
+//!
+//! ```ignore
+//! # #![allow(dead_code)]
+//! use quickcheck::quickcheck;
+//! use time::Date;
+//!
+//! struct DateRange {
+//! from: Date,
+//! to: Date,
+//! }
+//!
+//! impl DateRange {
+//! fn new(from: Date, to: Date) -> Result<Self, ()> {
+//! Ok(DateRange { from, to })
+//! }
+//! }
+//!
+//! quickcheck! {
+//! fn date_range_is_well_defined(from: Date, to: Date) -> bool {
+//! let r = DateRange::new(from, to);
+//! if from <= to {
+//! r.is_ok()
+//! } else {
+//! r.is_err()
+//! }
+//! }
+//! }
+//! ```
+//!
+//! An implementation for `Instant` is intentionally omitted since its values are only meaningful in
+//! relation to a [`Duration`], and obtaining an `Instant` from a [`Duration`] is very simple
+//! anyway.
+
+use alloc::boxed::Box;
+
+use quickcheck::{empty_shrinker, single_shrinker, Arbitrary, Gen};
+
+use crate::{
+ Date, Duration, Month, OffsetDateTime, PrimitiveDateTime, Time, UtcDateTime, UtcOffset, Weekday,
+};
+
+/// Obtain an arbitrary value between the minimum and maximum inclusive.
+macro_rules! arbitrary_between {
+ ($type:ty; $gen:expr, $min:expr, $max:expr) => {{
+ let min = $min;
+ let max = $max;
+ let range = max - min;
+ <$type>::arbitrary($gen).rem_euclid(range + 1) + min
+ }};
+}
+
+impl Arbitrary for Date {
+ fn arbitrary(g: &mut Gen) -> Self {
+ // Safety: The Julian day number is in range.
+ unsafe {
+ Self::from_julian_day_unchecked(arbitrary_between!(
+ i32;
+ g,
+ Self::MIN.to_julian_day(),
+ Self::MAX.to_julian_day()
+ ))
+ }
+ }
+
+ fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
+ Box::new(
+ self.to_ordinal_date()
+ .shrink()
+ .flat_map(|(year, ordinal)| Self::from_ordinal_date(year, ordinal)),
+ )
+ }
+}
+
+impl Arbitrary for Duration {
+ fn arbitrary(g: &mut Gen) -> Self {
+ Self::new_ranged(<_>::arbitrary(g), <_>::arbitrary(g))
+ }
+
+ fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
+ Box::new(
+ (self.subsec_nanoseconds_ranged(), self.whole_seconds())
+ .shrink()
+ .map(|(mut nanoseconds, seconds)| {
+ // Coerce the sign if necessary.
+ if (seconds > 0 && nanoseconds.get() < 0)
+ || (seconds < 0 && nanoseconds.get() > 0)
+ {
+ nanoseconds = nanoseconds.neg();
+ }
+
+ Self::new_ranged_unchecked(seconds, nanoseconds)
+ }),
+ )
+ }
+}
+
+impl Arbitrary for Time {
+ fn arbitrary(g: &mut Gen) -> Self {
+ Self::from_hms_nanos_ranged(
+ <_>::arbitrary(g),
+ <_>::arbitrary(g),
+ <_>::arbitrary(g),
+ <_>::arbitrary(g),
+ )
+ }
+
+ fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
+ Box::new(
+ self.as_hms_nano_ranged()
+ .shrink()
+ .map(|(hour, minute, second, nanosecond)| {
+ Self::from_hms_nanos_ranged(hour, minute, second, nanosecond)
+ }),
+ )
+ }
+}
+
+impl Arbitrary for PrimitiveDateTime {
+ fn arbitrary(g: &mut Gen) -> Self {
+ Self::new(<_>::arbitrary(g), <_>::arbitrary(g))
+ }
+
+ fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
+ Box::new(
+ (self.date(), self.time())
+ .shrink()
+ .map(|(date, time)| Self::new(date, time)),
+ )
+ }
+}
+
+impl Arbitrary for UtcOffset {
+ fn arbitrary(g: &mut Gen) -> Self {
+ Self::from_hms_ranged(<_>::arbitrary(g), <_>::arbitrary(g), <_>::arbitrary(g))
+ }
+
+ fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
+ Box::new(
+ self.as_hms_ranged()
+ .shrink()
+ .map(|(hours, minutes, seconds)| Self::from_hms_ranged(hours, minutes, seconds)),
+ )
+ }
+}
+
+impl Arbitrary for OffsetDateTime {
+ fn arbitrary(g: &mut Gen) -> Self {
+ Self::new_in_offset(<_>::arbitrary(g), <_>::arbitrary(g), <_>::arbitrary(g))
+ }
+
+ fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
+ Box::new(
+ (self.date(), self.time(), self.offset())
+ .shrink()
+ .map(|(date, time, offset)| Self::new_in_offset(date, time, offset)),
+ )
+ }
+}
+
+impl Arbitrary for UtcDateTime {
+ fn arbitrary(g: &mut Gen) -> Self {
+ Self::new(<_>::arbitrary(g), <_>::arbitrary(g))
+ }
+
+ fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
+ Box::new(
+ (self.date(), self.time())
+ .shrink()
+ .map(|(date, time)| Self::new(date, time)),
+ )
+ }
+}
+
+impl Arbitrary for Weekday {
+ fn arbitrary(g: &mut Gen) -> Self {
+ use Weekday::*;
+ match arbitrary_between!(u8; g, 0, 6) {
+ 0 => Monday,
+ 1 => Tuesday,
+ 2 => Wednesday,
+ 3 => Thursday,
+ 4 => Friday,
+ 5 => Saturday,
+ val => {
+ debug_assert!(val == 6);
+ Sunday
+ }
+ }
+ }
+
+ fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
+ match self {
+ Self::Monday => empty_shrinker(),
+ _ => single_shrinker(self.previous()),
+ }
+ }
+}
+
+impl Arbitrary for Month {
+ fn arbitrary(g: &mut Gen) -> Self {
+ use Month::*;
+ match arbitrary_between!(u8; g, 1, 12) {
+ 1 => January,
+ 2 => February,
+ 3 => March,
+ 4 => April,
+ 5 => May,
+ 6 => June,
+ 7 => July,
+ 8 => August,
+ 9 => September,
+ 10 => October,
+ 11 => November,
+ val => {
+ debug_assert!(val == 12);
+ December
+ }
+ }
+ }
+
+ fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
+ match self {
+ Self::January => empty_shrinker(),
+ _ => single_shrinker(self.previous()),
+ }
+ }
+}
diff --git a/vendor/time/src/rand.rs b/vendor/time/src/rand.rs
new file mode 100644
index 00000000..8e4098cb
--- /dev/null
+++ b/vendor/time/src/rand.rs
@@ -0,0 +1,90 @@
+//! Implementation of [`Distribution`] for various structs.
+
+use rand::distributions::{Distribution, Standard};
+use rand::Rng;
+
+use crate::{Date, Duration, Month, OffsetDateTime, PrimitiveDateTime, Time, UtcOffset, Weekday};
+
+impl Distribution<Time> for Standard {
+ fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Time {
+ Time::from_hms_nanos_ranged(rng.r#gen(), rng.r#gen(), rng.r#gen(), rng.r#gen())
+ }
+}
+
+impl Distribution<Date> for Standard {
+ fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Date {
+ // Safety: The Julian day number is in range.
+ unsafe {
+ Date::from_julian_day_unchecked(
+ rng.gen_range(Date::MIN.to_julian_day()..=Date::MAX.to_julian_day()),
+ )
+ }
+ }
+}
+
+impl Distribution<UtcOffset> for Standard {
+ fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> UtcOffset {
+ UtcOffset::from_hms_ranged(rng.r#gen(), rng.r#gen(), rng.r#gen())
+ }
+}
+
+impl Distribution<PrimitiveDateTime> for Standard {
+ fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> PrimitiveDateTime {
+ PrimitiveDateTime::new(Self.sample(rng), Self.sample(rng))
+ }
+}
+
+impl Distribution<OffsetDateTime> for Standard {
+ fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> OffsetDateTime {
+ let date_time: PrimitiveDateTime = Self.sample(rng);
+ date_time.assume_offset(Self.sample(rng))
+ }
+}
+
+impl Distribution<Duration> for Standard {
+ fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Duration {
+ Duration::new_ranged(rng.r#gen(), rng.r#gen())
+ }
+}
+
+impl Distribution<Weekday> for Standard {
+ fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Weekday {
+ use Weekday::*;
+
+ match rng.gen_range(0u8..7) {
+ 0 => Monday,
+ 1 => Tuesday,
+ 2 => Wednesday,
+ 3 => Thursday,
+ 4 => Friday,
+ 5 => Saturday,
+ val => {
+ debug_assert!(val == 6);
+ Sunday
+ }
+ }
+ }
+}
+
+impl Distribution<Month> for Standard {
+ fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Month {
+ use Month::*;
+ match rng.gen_range(1u8..=12) {
+ 1 => January,
+ 2 => February,
+ 3 => March,
+ 4 => April,
+ 5 => May,
+ 6 => June,
+ 7 => July,
+ 8 => August,
+ 9 => September,
+ 10 => October,
+ 11 => November,
+ val => {
+ debug_assert!(val == 12);
+ December
+ }
+ }
+ }
+}
diff --git a/vendor/time/src/serde/iso8601.rs b/vendor/time/src/serde/iso8601.rs
new file mode 100644
index 00000000..f08cf511
--- /dev/null
+++ b/vendor/time/src/serde/iso8601.rs
@@ -0,0 +1,76 @@
+//! Use the well-known [ISO 8601 format] when serializing and deserializing an [`OffsetDateTime`].
+//!
+//! Use this module in combination with serde's [`#[with]`][with] attribute.
+//!
+//! [ISO 8601 format]: https://www.iso.org/iso-8601-date-and-time-format.html
+//! [with]: https://serde.rs/field-attrs.html#with
+
+#[cfg(feature = "parsing")]
+use core::marker::PhantomData;
+
+#[cfg(feature = "formatting")]
+use serde::ser::Error as _;
+#[cfg(feature = "parsing")]
+use serde::Deserializer;
+#[cfg(feature = "formatting")]
+use serde::{Serialize, Serializer};
+
+#[cfg(feature = "parsing")]
+use super::Visitor;
+use crate::format_description::well_known::iso8601::{Config, EncodedConfig};
+use crate::format_description::well_known::Iso8601;
+use crate::OffsetDateTime;
+
+/// The configuration of ISO 8601 used for serde implementations.
+pub(crate) const SERDE_CONFIG: EncodedConfig =
+ Config::DEFAULT.set_year_is_six_digits(true).encode();
+
+/// Serialize an [`OffsetDateTime`] using the well-known ISO 8601 format.
+#[cfg(feature = "formatting")]
+pub fn serialize<S: Serializer>(
+ datetime: &OffsetDateTime,
+ serializer: S,
+) -> Result<S::Ok, S::Error> {
+ datetime
+ .format(&Iso8601::<SERDE_CONFIG>)
+ .map_err(S::Error::custom)?
+ .serialize(serializer)
+}
+
+/// Deserialize an [`OffsetDateTime`] from its ISO 8601 representation.
+#[cfg(feature = "parsing")]
+pub fn deserialize<'a, D: Deserializer<'a>>(deserializer: D) -> Result<OffsetDateTime, D::Error> {
+ deserializer.deserialize_str(Visitor::<Iso8601<SERDE_CONFIG>>(PhantomData))
+}
+
+/// Use the well-known ISO 8601 format when serializing and deserializing an
+/// [`Option<OffsetDateTime>`].
+///
+/// Use this module in combination with serde's [`#[with]`][with] attribute.
+///
+/// [ISO 8601 format]: https://www.iso.org/iso-8601-date-and-time-format.html
+/// [with]: https://serde.rs/field-attrs.html#with
+pub mod option {
+ use super::*;
+
+ /// Serialize an [`Option<OffsetDateTime>`] using the well-known ISO 8601 format.
+ #[cfg(feature = "formatting")]
+ pub fn serialize<S: Serializer>(
+ option: &Option<OffsetDateTime>,
+ serializer: S,
+ ) -> Result<S::Ok, S::Error> {
+ option
+ .map(|odt| odt.format(&Iso8601::<SERDE_CONFIG>))
+ .transpose()
+ .map_err(S::Error::custom)?
+ .serialize(serializer)
+ }
+
+ /// Deserialize an [`Option<OffsetDateTime>`] from its ISO 8601 representation.
+ #[cfg(feature = "parsing")]
+ pub fn deserialize<'a, D: Deserializer<'a>>(
+ deserializer: D,
+ ) -> Result<Option<OffsetDateTime>, D::Error> {
+ deserializer.deserialize_option(Visitor::<Option<Iso8601<SERDE_CONFIG>>>(PhantomData))
+ }
+}
diff --git a/vendor/time/src/serde/mod.rs b/vendor/time/src/serde/mod.rs
new file mode 100644
index 00000000..72b43721
--- /dev/null
+++ b/vendor/time/src/serde/mod.rs
@@ -0,0 +1,535 @@
+//! Differential formats for serde.
+// This also includes the serde implementations for all types. This doesn't need to be externally
+// documented, though.
+
+// Types with guaranteed stable serde representations. Strings are avoided to allow for optimal
+// representations in various binary forms.
+
+/// Consume the next item in a sequence.
+macro_rules! item {
+ ($seq:expr, $name:literal) => {
+ $seq.next_element()?
+ .ok_or_else(|| <A::Error as serde::de::Error>::custom(concat!("expected ", $name)))
+ };
+}
+
+#[cfg(any(feature = "formatting", feature = "parsing"))]
+pub mod iso8601;
+#[cfg(any(feature = "formatting", feature = "parsing"))]
+pub mod rfc2822;
+#[cfg(any(feature = "formatting", feature = "parsing"))]
+pub mod rfc3339;
+pub mod timestamp;
+mod visitor;
+
+#[cfg(feature = "serde-human-readable")]
+use alloc::string::ToString;
+use core::marker::PhantomData;
+
+#[cfg(feature = "serde-human-readable")]
+use serde::ser::Error as _;
+use serde::{Deserialize, Deserializer, Serialize, Serializer};
+/// Generate a custom serializer and deserializer from a format string or an existing format.
+///
+/// The syntax accepted by this macro is the same as [`format_description::parse()`], which can
+/// be found in [the book](https://time-rs.github.io/book/api/format-description.html).
+///
+/// # Usage
+///
+/// Invoked as `serde::format_description!(mod_name, Date, FORMAT)` where `FORMAT` is either a
+/// `"<format string>"` or something that implements
+#[cfg_attr(
+ all(feature = "formatting", feature = "parsing"),
+ doc = "[`Formattable`](crate::formatting::Formattable) and \
+ [`Parsable`](crate::parsing::Parsable)."
+)]
+#[cfg_attr(
+ all(feature = "formatting", not(feature = "parsing")),
+ doc = "[`Formattable`](crate::formatting::Formattable)."
+)]
+#[cfg_attr(
+ all(not(feature = "formatting"), feature = "parsing"),
+ doc = "[`Parsable`](crate::parsing::Parsable)."
+)]
+/// This puts a module named `mod_name` in the current scope that can be used to format `Date`
+/// structs. A submodule (`mod_name::option`) is also generated for `Option<Date>`. Both
+/// modules are only visible in the current scope by default. To increase visibility, you can
+/// specify `pub`, `pub(crate)`, or similar before the module name:
+/// `serde::format_description!(pub mod_name, Date, FORMAT)`.
+///
+/// The returned `Option` will contain a deserialized value if present and `None` if the field
+/// is present but the value is `null` (or the equivalent in other formats). To return `None`
+/// when the field is not present, you should use `#[serde(default)]` on the field.
+///
+/// # Examples
+///
+/// Using a format string:
+///
+/// ```rust,no_run
+/// # use time::OffsetDateTime;
+#[cfg_attr(
+ all(feature = "formatting", feature = "parsing"),
+ doc = "use ::serde::{Serialize, Deserialize};"
+)]
+#[cfg_attr(
+ all(feature = "formatting", not(feature = "parsing")),
+ doc = "use ::serde::Serialize;"
+)]
+#[cfg_attr(
+ all(not(feature = "formatting"), feature = "parsing"),
+ doc = "use ::serde::Deserialize;"
+)]
+/// use time::serde;
+///
+/// // Makes a module `mod my_format { ... }`.
+/// serde::format_description!(my_format, OffsetDateTime, "hour=[hour], minute=[minute]");
+///
+/// # #[allow(dead_code)]
+#[cfg_attr(
+ all(feature = "formatting", feature = "parsing"),
+ doc = "#[derive(Serialize, Deserialize)]"
+)]
+#[cfg_attr(
+ all(feature = "formatting", not(feature = "parsing")),
+ doc = "#[derive(Serialize)]"
+)]
+#[cfg_attr(
+ all(not(feature = "formatting"), feature = "parsing"),
+ doc = "#[derive(Deserialize)]"
+)]
+/// struct SerializesWithCustom {
+/// #[serde(with = "my_format")]
+/// dt: OffsetDateTime,
+/// #[serde(with = "my_format::option")]
+/// maybe_dt: Option<OffsetDateTime>,
+/// }
+/// ```
+///
+/// Define the format separately to be used in multiple places:
+/// ```rust,no_run
+/// # use time::OffsetDateTime;
+#[cfg_attr(
+ all(feature = "formatting", feature = "parsing"),
+ doc = "use ::serde::{Serialize, Deserialize};"
+)]
+#[cfg_attr(
+ all(feature = "formatting", not(feature = "parsing")),
+ doc = "use ::serde::Serialize;"
+)]
+#[cfg_attr(
+ all(not(feature = "formatting"), feature = "parsing"),
+ doc = "use ::serde::Deserialize;"
+)]
+/// use time::serde;
+/// use time::format_description::BorrowedFormatItem;
+///
+/// const DATE_TIME_FORMAT: &[BorrowedFormatItem<'_>] = time::macros::format_description!(
+/// "hour=[hour], minute=[minute]"
+/// );
+///
+/// // Makes a module `mod my_format { ... }`.
+/// serde::format_description!(my_format, OffsetDateTime, DATE_TIME_FORMAT);
+///
+/// # #[allow(dead_code)]
+#[cfg_attr(
+ all(feature = "formatting", feature = "parsing"),
+ doc = "#[derive(Serialize, Deserialize)]"
+)]
+#[cfg_attr(
+ all(feature = "formatting", not(feature = "parsing")),
+ doc = "#[derive(Serialize)]"
+)]
+#[cfg_attr(
+ all(not(feature = "formatting"), feature = "parsing"),
+ doc = "#[derive(Deserialize)]"
+)]
+/// struct SerializesWithCustom {
+/// #[serde(with = "my_format")]
+/// dt: OffsetDateTime,
+/// #[serde(with = "my_format::option")]
+/// maybe_dt: Option<OffsetDateTime>,
+/// }
+///
+/// fn main() {
+/// # #[allow(unused_variables)]
+/// let str_ts = OffsetDateTime::now_utc().format(DATE_TIME_FORMAT).unwrap();
+/// }
+/// ```
+///
+/// Customize the configuration of ISO 8601 formatting/parsing:
+/// ```rust,no_run
+/// # use time::OffsetDateTime;
+#[cfg_attr(
+ all(feature = "formatting", feature = "parsing"),
+ doc = "use ::serde::{Serialize, Deserialize};"
+)]
+#[cfg_attr(
+ all(feature = "formatting", not(feature = "parsing")),
+ doc = "use ::serde::Serialize;"
+)]
+#[cfg_attr(
+ all(not(feature = "formatting"), feature = "parsing"),
+ doc = "use ::serde::Deserialize;"
+)]
+/// use time::serde;
+/// use time::format_description::well_known::{iso8601, Iso8601};
+///
+/// # #[allow(dead_code)]
+/// const CONFIG: iso8601::EncodedConfig = iso8601::Config::DEFAULT
+/// .set_year_is_six_digits(false)
+/// .encode();
+/// # #[allow(dead_code)]
+/// const FORMAT: Iso8601<CONFIG> = Iso8601::<CONFIG>;
+///
+/// // Makes a module `mod my_format { ... }`.
+/// serde::format_description!(my_format, OffsetDateTime, FORMAT);
+///
+/// # #[allow(dead_code)]
+#[cfg_attr(
+ all(feature = "formatting", feature = "parsing"),
+ doc = "#[derive(Serialize, Deserialize)]"
+)]
+#[cfg_attr(
+ all(feature = "formatting", not(feature = "parsing")),
+ doc = "#[derive(Serialize)]"
+)]
+#[cfg_attr(
+ all(not(feature = "formatting"), feature = "parsing"),
+ doc = "#[derive(Deserialize)]"
+)]
+/// struct SerializesWithCustom {
+/// #[serde(with = "my_format")]
+/// dt: OffsetDateTime,
+/// #[serde(with = "my_format::option")]
+/// maybe_dt: Option<OffsetDateTime>,
+/// }
+/// # fn main() {}
+/// ```
+///
+/// [`format_description::parse()`]: crate::format_description::parse()
+#[cfg(all(feature = "macros", any(feature = "formatting", feature = "parsing")))]
+pub use time_macros::serde_format_description as format_description;
+
+use self::visitor::Visitor;
+#[cfg(feature = "parsing")]
+use crate::format_description::{modifier, BorrowedFormatItem, Component};
+use crate::{
+ Date, Duration, Month, OffsetDateTime, PrimitiveDateTime, Time, UtcDateTime, UtcOffset, Weekday,
+};
+
+/// The format used when serializing and deserializing a human-readable `Date`.
+#[cfg(feature = "parsing")]
+const DATE_FORMAT: &[BorrowedFormatItem<'_>] = &[
+ BorrowedFormatItem::Component(Component::Year(modifier::Year::default())),
+ BorrowedFormatItem::Literal(b"-"),
+ BorrowedFormatItem::Component(Component::Month(modifier::Month::default())),
+ BorrowedFormatItem::Literal(b"-"),
+ BorrowedFormatItem::Component(Component::Day(modifier::Day::default())),
+];
+
+impl Serialize for Date {
+ fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
+ #[cfg(feature = "serde-human-readable")]
+ if serializer.is_human_readable() {
+ let Ok(s) = self.format(&DATE_FORMAT) else {
+ return Err(S::Error::custom("failed formatting `Date`"));
+ };
+ return serializer.serialize_str(&s);
+ }
+
+ (self.year(), self.ordinal()).serialize(serializer)
+ }
+}
+
+impl<'a> Deserialize<'a> for Date {
+ fn deserialize<D: Deserializer<'a>>(deserializer: D) -> Result<Self, D::Error> {
+ if cfg!(feature = "serde-human-readable") && deserializer.is_human_readable() {
+ deserializer.deserialize_any(Visitor::<Self>(PhantomData))
+ } else {
+ deserializer.deserialize_tuple(2, Visitor::<Self>(PhantomData))
+ }
+ }
+}
+
+impl Serialize for Duration {
+ fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
+ #[cfg(feature = "serde-human-readable")]
+ if serializer.is_human_readable() {
+ return serializer.collect_str(&format_args!(
+ "{}{}.{:>09}",
+ if self.is_negative() { "-" } else { "" },
+ self.whole_seconds().unsigned_abs(),
+ self.subsec_nanoseconds().abs(),
+ ));
+ }
+
+ (self.whole_seconds(), self.subsec_nanoseconds()).serialize(serializer)
+ }
+}
+
+impl<'a> Deserialize<'a> for Duration {
+ fn deserialize<D: Deserializer<'a>>(deserializer: D) -> Result<Self, D::Error> {
+ if cfg!(feature = "serde-human-readable") && deserializer.is_human_readable() {
+ deserializer.deserialize_any(Visitor::<Self>(PhantomData))
+ } else {
+ deserializer.deserialize_tuple(2, Visitor::<Self>(PhantomData))
+ }
+ }
+}
+
+/// The format used when serializing and deserializing a human-readable `OffsetDateTime`.
+#[cfg(feature = "parsing")]
+const OFFSET_DATE_TIME_FORMAT: &[BorrowedFormatItem<'_>] = &[
+ BorrowedFormatItem::Compound(DATE_FORMAT),
+ BorrowedFormatItem::Literal(b" "),
+ BorrowedFormatItem::Compound(TIME_FORMAT),
+ BorrowedFormatItem::Literal(b" "),
+ BorrowedFormatItem::Compound(UTC_OFFSET_FORMAT),
+];
+
+impl Serialize for OffsetDateTime {
+ fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
+ #[cfg(feature = "serde-human-readable")]
+ if serializer.is_human_readable() {
+ let Ok(s) = self.format(&OFFSET_DATE_TIME_FORMAT) else {
+ return Err(S::Error::custom("failed formatting `OffsetDateTime`"));
+ };
+ return serializer.serialize_str(&s);
+ }
+
+ (
+ self.year(),
+ self.ordinal(),
+ self.hour(),
+ self.minute(),
+ self.second(),
+ self.nanosecond(),
+ self.offset().whole_hours(),
+ self.offset().minutes_past_hour(),
+ self.offset().seconds_past_minute(),
+ )
+ .serialize(serializer)
+ }
+}
+
+impl<'a> Deserialize<'a> for OffsetDateTime {
+ fn deserialize<D: Deserializer<'a>>(deserializer: D) -> Result<Self, D::Error> {
+ if cfg!(feature = "serde-human-readable") && deserializer.is_human_readable() {
+ deserializer.deserialize_any(Visitor::<Self>(PhantomData))
+ } else {
+ deserializer.deserialize_tuple(9, Visitor::<Self>(PhantomData))
+ }
+ }
+}
+
+/// The format used when serializing and deserializing a human-readable `PrimitiveDateTime`.
+#[cfg(feature = "parsing")]
+const PRIMITIVE_DATE_TIME_FORMAT: &[BorrowedFormatItem<'_>] = &[
+ BorrowedFormatItem::Compound(DATE_FORMAT),
+ BorrowedFormatItem::Literal(b" "),
+ BorrowedFormatItem::Compound(TIME_FORMAT),
+];
+
+impl Serialize for PrimitiveDateTime {
+ fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
+ #[cfg(feature = "serde-human-readable")]
+ if serializer.is_human_readable() {
+ let Ok(s) = self.format(&PRIMITIVE_DATE_TIME_FORMAT) else {
+ return Err(S::Error::custom("failed formatting `PrimitiveDateTime`"));
+ };
+ return serializer.serialize_str(&s);
+ }
+
+ (
+ self.year(),
+ self.ordinal(),
+ self.hour(),
+ self.minute(),
+ self.second(),
+ self.nanosecond(),
+ )
+ .serialize(serializer)
+ }
+}
+
+impl<'a> Deserialize<'a> for PrimitiveDateTime {
+ fn deserialize<D: Deserializer<'a>>(deserializer: D) -> Result<Self, D::Error> {
+ if cfg!(feature = "serde-human-readable") && deserializer.is_human_readable() {
+ deserializer.deserialize_any(Visitor::<Self>(PhantomData))
+ } else {
+ deserializer.deserialize_tuple(6, Visitor::<Self>(PhantomData))
+ }
+ }
+}
+
+/// The format used when serializing and deserializing a human-readable `UtcDateTime`.
+#[cfg(feature = "parsing")]
+const UTC_DATE_TIME_FORMAT: &[BorrowedFormatItem<'_>] = PRIMITIVE_DATE_TIME_FORMAT;
+
+impl Serialize for UtcDateTime {
+ fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
+ #[cfg(feature = "serde-human-readable")]
+ if serializer.is_human_readable() {
+ let Ok(s) = self.format(&PRIMITIVE_DATE_TIME_FORMAT) else {
+ return Err(S::Error::custom("failed formatting `UtcDateTime`"));
+ };
+ return serializer.serialize_str(&s);
+ }
+
+ (
+ self.year(),
+ self.ordinal(),
+ self.hour(),
+ self.minute(),
+ self.second(),
+ self.nanosecond(),
+ )
+ .serialize(serializer)
+ }
+}
+
+impl<'a> Deserialize<'a> for UtcDateTime {
+ fn deserialize<D: Deserializer<'a>>(deserializer: D) -> Result<Self, D::Error> {
+ if cfg!(feature = "serde-human-readable") && deserializer.is_human_readable() {
+ deserializer.deserialize_any(Visitor::<Self>(PhantomData))
+ } else {
+ deserializer.deserialize_tuple(6, Visitor::<Self>(PhantomData))
+ }
+ }
+}
+
+/// The format used when serializing and deserializing a human-readable `Time`.
+#[cfg(feature = "parsing")]
+const TIME_FORMAT: &[BorrowedFormatItem<'_>] = &[
+ BorrowedFormatItem::Component(Component::Hour(modifier::Hour::default())),
+ BorrowedFormatItem::Literal(b":"),
+ BorrowedFormatItem::Component(Component::Minute(modifier::Minute::default())),
+ BorrowedFormatItem::Literal(b":"),
+ BorrowedFormatItem::Component(Component::Second(modifier::Second::default())),
+ BorrowedFormatItem::Literal(b"."),
+ BorrowedFormatItem::Component(Component::Subsecond(modifier::Subsecond::default())),
+];
+
+impl Serialize for Time {
+ fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
+ #[cfg(feature = "serde-human-readable")]
+ if serializer.is_human_readable() {
+ let Ok(s) = self.format(&TIME_FORMAT) else {
+ return Err(S::Error::custom("failed formatting `Time`"));
+ };
+ return serializer.serialize_str(&s);
+ }
+
+ (self.hour(), self.minute(), self.second(), self.nanosecond()).serialize(serializer)
+ }
+}
+
+impl<'a> Deserialize<'a> for Time {
+ fn deserialize<D: Deserializer<'a>>(deserializer: D) -> Result<Self, D::Error> {
+ if cfg!(feature = "serde-human-readable") && deserializer.is_human_readable() {
+ deserializer.deserialize_any(Visitor::<Self>(PhantomData))
+ } else {
+ deserializer.deserialize_tuple(4, Visitor::<Self>(PhantomData))
+ }
+ }
+}
+
+// FIXME: turn these constants into `const { ... }` blocks once we can depend on Rust 1.79.
+#[cfg(feature = "parsing")]
+const UTC_OFFSET_HOUR: modifier::OffsetHour = {
+ let mut m = modifier::OffsetHour::default();
+ m.sign_is_mandatory = true;
+ m
+};
+#[cfg(feature = "parsing")]
+const UTC_OFFSET_MINUTE: modifier::OffsetMinute = modifier::OffsetMinute::default();
+#[cfg(feature = "parsing")]
+const UTC_OFFSET_SECOND: modifier::OffsetSecond = modifier::OffsetSecond::default();
+/// The format used when serializing and deserializing a human-readable `UtcOffset`.
+#[cfg(feature = "parsing")]
+const UTC_OFFSET_FORMAT: &[BorrowedFormatItem<'_>] = &[
+ BorrowedFormatItem::Component(Component::OffsetHour(UTC_OFFSET_HOUR)),
+ BorrowedFormatItem::Optional(&BorrowedFormatItem::Compound(&[
+ BorrowedFormatItem::Literal(b":"),
+ BorrowedFormatItem::Component(Component::OffsetMinute(UTC_OFFSET_MINUTE)),
+ BorrowedFormatItem::Optional(&BorrowedFormatItem::Compound(&[
+ BorrowedFormatItem::Literal(b":"),
+ BorrowedFormatItem::Component(Component::OffsetSecond(UTC_OFFSET_SECOND)),
+ ])),
+ ])),
+];
+
+impl Serialize for UtcOffset {
+ fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
+ #[cfg(feature = "serde-human-readable")]
+ if serializer.is_human_readable() {
+ let Ok(s) = self.format(&UTC_OFFSET_FORMAT) else {
+ return Err(S::Error::custom("failed formatting `UtcOffset`"));
+ };
+ return serializer.serialize_str(&s);
+ }
+
+ (
+ self.whole_hours(),
+ self.minutes_past_hour(),
+ self.seconds_past_minute(),
+ )
+ .serialize(serializer)
+ }
+}
+
+impl<'a> Deserialize<'a> for UtcOffset {
+ fn deserialize<D: Deserializer<'a>>(deserializer: D) -> Result<Self, D::Error> {
+ if cfg!(feature = "serde-human-readable") && deserializer.is_human_readable() {
+ deserializer.deserialize_any(Visitor::<Self>(PhantomData))
+ } else {
+ deserializer.deserialize_tuple(3, Visitor::<Self>(PhantomData))
+ }
+ }
+}
+
+impl Serialize for Weekday {
+ fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
+ #[cfg(feature = "serde-human-readable")]
+ if serializer.is_human_readable() {
+ #[cfg(not(feature = "std"))]
+ use alloc::string::ToString;
+ return self.to_string().serialize(serializer);
+ }
+
+ self.number_from_monday().serialize(serializer)
+ }
+}
+
+impl<'a> Deserialize<'a> for Weekday {
+ fn deserialize<D: Deserializer<'a>>(deserializer: D) -> Result<Self, D::Error> {
+ if cfg!(feature = "serde-human-readable") && deserializer.is_human_readable() {
+ deserializer.deserialize_any(Visitor::<Self>(PhantomData))
+ } else {
+ deserializer.deserialize_u8(Visitor::<Self>(PhantomData))
+ }
+ }
+}
+
+impl Serialize for Month {
+ fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
+ #[cfg(feature = "serde-human-readable")]
+ if serializer.is_human_readable() {
+ #[cfg(not(feature = "std"))]
+ use alloc::string::String;
+ return self.to_string().serialize(serializer);
+ }
+
+ u8::from(*self).serialize(serializer)
+ }
+}
+
+impl<'a> Deserialize<'a> for Month {
+ fn deserialize<D: Deserializer<'a>>(deserializer: D) -> Result<Self, D::Error> {
+ if cfg!(feature = "serde-human-readable") && deserializer.is_human_readable() {
+ deserializer.deserialize_any(Visitor::<Self>(PhantomData))
+ } else {
+ deserializer.deserialize_u8(Visitor::<Self>(PhantomData))
+ }
+ }
+}
diff --git a/vendor/time/src/serde/rfc2822.rs b/vendor/time/src/serde/rfc2822.rs
new file mode 100644
index 00000000..c6716d58
--- /dev/null
+++ b/vendor/time/src/serde/rfc2822.rs
@@ -0,0 +1,71 @@
+//! Use the well-known [RFC2822 format] when serializing and deserializing an [`OffsetDateTime`].
+//!
+//! Use this module in combination with serde's [`#[with]`][with] attribute.
+//!
+//! [RFC2822 format]: https://tools.ietf.org/html/rfc2822#section-3.3
+//! [with]: https://serde.rs/field-attrs.html#with
+
+#[cfg(feature = "parsing")]
+use core::marker::PhantomData;
+
+#[cfg(feature = "formatting")]
+use serde::ser::Error as _;
+#[cfg(feature = "parsing")]
+use serde::Deserializer;
+#[cfg(feature = "formatting")]
+use serde::{Serialize, Serializer};
+
+#[cfg(feature = "parsing")]
+use super::Visitor;
+use crate::format_description::well_known::Rfc2822;
+use crate::OffsetDateTime;
+
+/// Serialize an [`OffsetDateTime`] using the well-known RFC2822 format.
+#[cfg(feature = "formatting")]
+pub fn serialize<S: Serializer>(
+ datetime: &OffsetDateTime,
+ serializer: S,
+) -> Result<S::Ok, S::Error> {
+ datetime
+ .format(&Rfc2822)
+ .map_err(S::Error::custom)?
+ .serialize(serializer)
+}
+
+/// Deserialize an [`OffsetDateTime`] from its RFC2822 representation.
+#[cfg(feature = "parsing")]
+pub fn deserialize<'a, D: Deserializer<'a>>(deserializer: D) -> Result<OffsetDateTime, D::Error> {
+ deserializer.deserialize_str(Visitor::<Rfc2822>(PhantomData))
+}
+
+/// Use the well-known [RFC2822 format] when serializing and deserializing an
+/// [`Option<OffsetDateTime>`].
+///
+/// Use this module in combination with serde's [`#[with]`][with] attribute.
+///
+/// [RFC2822 format]: https://tools.ietf.org/html/rfc2822#section-3.3
+/// [with]: https://serde.rs/field-attrs.html#with
+pub mod option {
+ use super::*;
+
+ /// Serialize an [`Option<OffsetDateTime>`] using the well-known RFC2822 format.
+ #[cfg(feature = "formatting")]
+ pub fn serialize<S: Serializer>(
+ option: &Option<OffsetDateTime>,
+ serializer: S,
+ ) -> Result<S::Ok, S::Error> {
+ option
+ .map(|odt| odt.format(&Rfc2822))
+ .transpose()
+ .map_err(S::Error::custom)?
+ .serialize(serializer)
+ }
+
+ /// Deserialize an [`Option<OffsetDateTime>`] from its RFC2822 representation.
+ #[cfg(feature = "parsing")]
+ pub fn deserialize<'a, D: Deserializer<'a>>(
+ deserializer: D,
+ ) -> Result<Option<OffsetDateTime>, D::Error> {
+ deserializer.deserialize_option(Visitor::<Option<Rfc2822>>(PhantomData))
+ }
+}
diff --git a/vendor/time/src/serde/rfc3339.rs b/vendor/time/src/serde/rfc3339.rs
new file mode 100644
index 00000000..4cccd635
--- /dev/null
+++ b/vendor/time/src/serde/rfc3339.rs
@@ -0,0 +1,71 @@
+//! Use the well-known [RFC3339 format] when serializing and deserializing an [`OffsetDateTime`].
+//!
+//! Use this module in combination with serde's [`#[with]`][with] attribute.
+//!
+//! [RFC3339 format]: https://tools.ietf.org/html/rfc3339#section-5.6
+//! [with]: https://serde.rs/field-attrs.html#with
+
+#[cfg(feature = "parsing")]
+use core::marker::PhantomData;
+
+#[cfg(feature = "formatting")]
+use serde::ser::Error as _;
+#[cfg(feature = "parsing")]
+use serde::Deserializer;
+#[cfg(feature = "formatting")]
+use serde::{Serialize, Serializer};
+
+#[cfg(feature = "parsing")]
+use super::Visitor;
+use crate::format_description::well_known::Rfc3339;
+use crate::OffsetDateTime;
+
+/// Serialize an [`OffsetDateTime`] using the well-known RFC3339 format.
+#[cfg(feature = "formatting")]
+pub fn serialize<S: Serializer>(
+ datetime: &OffsetDateTime,
+ serializer: S,
+) -> Result<S::Ok, S::Error> {
+ datetime
+ .format(&Rfc3339)
+ .map_err(S::Error::custom)?
+ .serialize(serializer)
+}
+
+/// Deserialize an [`OffsetDateTime`] from its RFC3339 representation.
+#[cfg(feature = "parsing")]
+pub fn deserialize<'a, D: Deserializer<'a>>(deserializer: D) -> Result<OffsetDateTime, D::Error> {
+ deserializer.deserialize_str(Visitor::<Rfc3339>(PhantomData))
+}
+
+/// Use the well-known [RFC3339 format] when serializing and deserializing an
+/// [`Option<OffsetDateTime>`].
+///
+/// Use this module in combination with serde's [`#[with]`][with] attribute.
+///
+/// [RFC3339 format]: https://tools.ietf.org/html/rfc3339#section-5.6
+/// [with]: https://serde.rs/field-attrs.html#with
+pub mod option {
+ use super::*;
+
+ /// Serialize an [`Option<OffsetDateTime>`] using the well-known RFC3339 format.
+ #[cfg(feature = "formatting")]
+ pub fn serialize<S: Serializer>(
+ option: &Option<OffsetDateTime>,
+ serializer: S,
+ ) -> Result<S::Ok, S::Error> {
+ option
+ .map(|odt| odt.format(&Rfc3339))
+ .transpose()
+ .map_err(S::Error::custom)?
+ .serialize(serializer)
+ }
+
+ /// Deserialize an [`Option<OffsetDateTime>`] from its RFC3339 representation.
+ #[cfg(feature = "parsing")]
+ pub fn deserialize<'a, D: Deserializer<'a>>(
+ deserializer: D,
+ ) -> Result<Option<OffsetDateTime>, D::Error> {
+ deserializer.deserialize_option(Visitor::<Option<Rfc3339>>(PhantomData))
+ }
+}
diff --git a/vendor/time/src/serde/timestamp/microseconds.rs b/vendor/time/src/serde/timestamp/microseconds.rs
new file mode 100644
index 00000000..65c603ec
--- /dev/null
+++ b/vendor/time/src/serde/timestamp/microseconds.rs
@@ -0,0 +1,63 @@
+//! Treat an [`OffsetDateTime`] as a [Unix timestamp] with microseconds for
+//! the purposes of serde.
+//!
+//! Use this module in combination with serde's [`#[with]`][with] attribute.
+//!
+//! When deserializing, the offset is assumed to be UTC.
+//!
+//! [Unix timestamp]: https://en.wikipedia.org/wiki/Unix_time
+//! [with]: https://serde.rs/field-attrs.html#with
+
+use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
+
+use crate::OffsetDateTime;
+
+/// Serialize an `OffsetDateTime` as its Unix timestamp with microseconds
+pub fn serialize<S: Serializer>(
+ datetime: &OffsetDateTime,
+ serializer: S,
+) -> Result<S::Ok, S::Error> {
+ let timestamp = datetime.unix_timestamp_nanos() / 1_000;
+ timestamp.serialize(serializer)
+}
+
+/// Deserialize an `OffsetDateTime` from its Unix timestamp with microseconds
+pub fn deserialize<'a, D: Deserializer<'a>>(deserializer: D) -> Result<OffsetDateTime, D::Error> {
+ let value: i128 = <_>::deserialize(deserializer)?;
+ OffsetDateTime::from_unix_timestamp_nanos(value * 1_000)
+ .map_err(|err| de::Error::invalid_value(de::Unexpected::Signed(err.value), &err))
+}
+
+/// Treat an `Option<OffsetDateTime>` as a [Unix timestamp] with microseconds
+/// for the purposes of serde.
+///
+/// Use this module in combination with serde's [`#[with]`][with] attribute.
+///
+/// When deserializing, the offset is assumed to be UTC.
+///
+/// [Unix timestamp]: https://en.wikipedia.org/wiki/Unix_time
+/// [with]: https://serde.rs/field-attrs.html#with
+pub mod option {
+ #[allow(clippy::wildcard_imports)]
+ use super::*;
+
+ /// Serialize an `Option<OffsetDateTime>` as its Unix timestamp with microseconds
+ pub fn serialize<S: Serializer>(
+ option: &Option<OffsetDateTime>,
+ serializer: S,
+ ) -> Result<S::Ok, S::Error> {
+ option
+ .map(|timestamp| timestamp.unix_timestamp_nanos() / 1_000)
+ .serialize(serializer)
+ }
+
+ /// Deserialize an `Option<OffsetDateTime>` from its Unix timestamp with microseconds
+ pub fn deserialize<'a, D: Deserializer<'a>>(
+ deserializer: D,
+ ) -> Result<Option<OffsetDateTime>, D::Error> {
+ Option::deserialize(deserializer)?
+ .map(|value: i128| OffsetDateTime::from_unix_timestamp_nanos(value * 1_000))
+ .transpose()
+ .map_err(|err| de::Error::invalid_value(de::Unexpected::Signed(err.value), &err))
+ }
+}
diff --git a/vendor/time/src/serde/timestamp/milliseconds.rs b/vendor/time/src/serde/timestamp/milliseconds.rs
new file mode 100644
index 00000000..e571b6c9
--- /dev/null
+++ b/vendor/time/src/serde/timestamp/milliseconds.rs
@@ -0,0 +1,63 @@
+//! Treat an [`OffsetDateTime`] as a [Unix timestamp] with milliseconds for
+//! the purposes of serde.
+//!
+//! Use this module in combination with serde's [`#[with]`][with] attribute.
+//!
+//! When deserializing, the offset is assumed to be UTC.
+//!
+//! [Unix timestamp]: https://en.wikipedia.org/wiki/Unix_time
+//! [with]: https://serde.rs/field-attrs.html#with
+
+use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
+
+use crate::OffsetDateTime;
+
+/// Serialize an `OffsetDateTime` as its Unix timestamp with milliseconds
+pub fn serialize<S: Serializer>(
+ datetime: &OffsetDateTime,
+ serializer: S,
+) -> Result<S::Ok, S::Error> {
+ let timestamp = datetime.unix_timestamp_nanos() / 1_000_000;
+ timestamp.serialize(serializer)
+}
+
+/// Deserialize an `OffsetDateTime` from its Unix timestamp with milliseconds
+pub fn deserialize<'a, D: Deserializer<'a>>(deserializer: D) -> Result<OffsetDateTime, D::Error> {
+ let value: i128 = <_>::deserialize(deserializer)?;
+ OffsetDateTime::from_unix_timestamp_nanos(value * 1_000_000)
+ .map_err(|err| de::Error::invalid_value(de::Unexpected::Signed(err.value), &err))
+}
+
+/// Treat an `Option<OffsetDateTime>` as a [Unix timestamp] with milliseconds
+/// for the purposes of serde.
+///
+/// Use this module in combination with serde's [`#[with]`][with] attribute.
+///
+/// When deserializing, the offset is assumed to be UTC.
+///
+/// [Unix timestamp]: https://en.wikipedia.org/wiki/Unix_time
+/// [with]: https://serde.rs/field-attrs.html#with
+pub mod option {
+ #[allow(clippy::wildcard_imports)]
+ use super::*;
+
+ /// Serialize an `Option<OffsetDateTime>` as its Unix timestamp with milliseconds
+ pub fn serialize<S: Serializer>(
+ option: &Option<OffsetDateTime>,
+ serializer: S,
+ ) -> Result<S::Ok, S::Error> {
+ option
+ .map(|timestamp| timestamp.unix_timestamp_nanos() / 1_000_000)
+ .serialize(serializer)
+ }
+
+ /// Deserialize an `Option<OffsetDateTime>` from its Unix timestamp with milliseconds
+ pub fn deserialize<'a, D: Deserializer<'a>>(
+ deserializer: D,
+ ) -> Result<Option<OffsetDateTime>, D::Error> {
+ Option::deserialize(deserializer)?
+ .map(|value: i128| OffsetDateTime::from_unix_timestamp_nanos(value * 1_000_000))
+ .transpose()
+ .map_err(|err| de::Error::invalid_value(de::Unexpected::Signed(err.value), &err))
+ }
+}
diff --git a/vendor/time/src/serde/timestamp/milliseconds_i64.rs b/vendor/time/src/serde/timestamp/milliseconds_i64.rs
new file mode 100644
index 00000000..59f44644
--- /dev/null
+++ b/vendor/time/src/serde/timestamp/milliseconds_i64.rs
@@ -0,0 +1,66 @@
+//! Treat an [`OffsetDateTime`] as a [Unix timestamp] with milliseconds for
+//! the purposes of serde.
+//!
+//! Use this module in combination with serde's [`#[with]`][with] attribute.
+//!
+//! When deserializing, the offset is assumed to be UTC.
+//!
+//! [Unix timestamp]: https://en.wikipedia.org/wiki/Unix_time
+//! [with]: https://serde.rs/field-attrs.html#with
+
+use num_conv::prelude::*;
+use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
+
+use crate::OffsetDateTime;
+
+/// Serialize an `OffsetDateTime` as its Unix timestamp with milliseconds
+pub fn serialize<S: Serializer>(
+ datetime: &OffsetDateTime,
+ serializer: S,
+) -> Result<S::Ok, S::Error> {
+ let timestamp = (datetime.unix_timestamp_nanos() / 1_000_000).truncate::<i64>();
+ timestamp.serialize(serializer)
+}
+
+/// Deserialize an `OffsetDateTime` from its Unix timestamp with milliseconds
+pub fn deserialize<'a, D: Deserializer<'a>>(deserializer: D) -> Result<OffsetDateTime, D::Error> {
+ let value: i64 = <_>::deserialize(deserializer)?;
+ OffsetDateTime::from_unix_timestamp_nanos(value.extend::<i128>() * 1_000_000)
+ .map_err(|err| de::Error::invalid_value(de::Unexpected::Signed(err.value), &err))
+}
+
+/// Treat an `Option<OffsetDateTime>` as a [Unix timestamp] with milliseconds
+/// for the purposes of serde.
+///
+/// Use this module in combination with serde's [`#[with]`][with] attribute.
+///
+/// When deserializing, the offset is assumed to be UTC.
+///
+/// [Unix timestamp]: https://en.wikipedia.org/wiki/Unix_time
+/// [with]: https://serde.rs/field-attrs.html#with
+pub mod option {
+ #[allow(clippy::wildcard_imports)]
+ use super::*;
+
+ /// Serialize an `Option<OffsetDateTime>` as its Unix timestamp with milliseconds
+ pub fn serialize<S: Serializer>(
+ option: &Option<OffsetDateTime>,
+ serializer: S,
+ ) -> Result<S::Ok, S::Error> {
+ option
+ .map(|timestamp| (timestamp.unix_timestamp_nanos() / 1_000_000).truncate::<i64>())
+ .serialize(serializer)
+ }
+
+ /// Deserialize an `Option<OffsetDateTime>` from its Unix timestamp with milliseconds
+ pub fn deserialize<'a, D: Deserializer<'a>>(
+ deserializer: D,
+ ) -> Result<Option<OffsetDateTime>, D::Error> {
+ Option::deserialize(deserializer)?
+ .map(|value: i64| {
+ OffsetDateTime::from_unix_timestamp_nanos(value.extend::<i128>() * 1_000_000)
+ })
+ .transpose()
+ .map_err(|err| de::Error::invalid_value(de::Unexpected::Signed(err.value), &err))
+ }
+}
diff --git a/vendor/time/src/serde/timestamp/mod.rs b/vendor/time/src/serde/timestamp/mod.rs
new file mode 100644
index 00000000..d27836b6
--- /dev/null
+++ b/vendor/time/src/serde/timestamp/mod.rs
@@ -0,0 +1,65 @@
+//! Treat an [`OffsetDateTime`] as a [Unix timestamp] for the purposes of serde.
+//!
+//! Use this module in combination with serde's [`#[with]`][with] attribute.
+//!
+//! When deserializing, the offset is assumed to be UTC.
+//!
+//! [Unix timestamp]: https://en.wikipedia.org/wiki/Unix_time
+//! [with]: https://serde.rs/field-attrs.html#with
+
+pub mod microseconds;
+pub mod milliseconds;
+pub mod milliseconds_i64;
+pub mod nanoseconds;
+
+use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
+
+use crate::OffsetDateTime;
+
+/// Serialize an `OffsetDateTime` as its Unix timestamp
+pub fn serialize<S: Serializer>(
+ datetime: &OffsetDateTime,
+ serializer: S,
+) -> Result<S::Ok, S::Error> {
+ datetime.unix_timestamp().serialize(serializer)
+}
+
+/// Deserialize an `OffsetDateTime` from its Unix timestamp
+pub fn deserialize<'a, D: Deserializer<'a>>(deserializer: D) -> Result<OffsetDateTime, D::Error> {
+ OffsetDateTime::from_unix_timestamp(<_>::deserialize(deserializer)?)
+ .map_err(|err| de::Error::invalid_value(de::Unexpected::Signed(err.value), &err))
+}
+
+/// Treat an `Option<OffsetDateTime>` as a [Unix timestamp] for the purposes of
+/// serde.
+///
+/// Use this module in combination with serde's [`#[with]`][with] attribute.
+///
+/// When deserializing, the offset is assumed to be UTC.
+///
+/// [Unix timestamp]: https://en.wikipedia.org/wiki/Unix_time
+/// [with]: https://serde.rs/field-attrs.html#with
+pub mod option {
+ #[allow(clippy::wildcard_imports)]
+ use super::*;
+
+ /// Serialize an `Option<OffsetDateTime>` as its Unix timestamp
+ pub fn serialize<S: Serializer>(
+ option: &Option<OffsetDateTime>,
+ serializer: S,
+ ) -> Result<S::Ok, S::Error> {
+ option
+ .map(OffsetDateTime::unix_timestamp)
+ .serialize(serializer)
+ }
+
+ /// Deserialize an `Option<OffsetDateTime>` from its Unix timestamp
+ pub fn deserialize<'a, D: Deserializer<'a>>(
+ deserializer: D,
+ ) -> Result<Option<OffsetDateTime>, D::Error> {
+ Option::deserialize(deserializer)?
+ .map(OffsetDateTime::from_unix_timestamp)
+ .transpose()
+ .map_err(|err| de::Error::invalid_value(de::Unexpected::Signed(err.value), &err))
+ }
+}
diff --git a/vendor/time/src/serde/timestamp/nanoseconds.rs b/vendor/time/src/serde/timestamp/nanoseconds.rs
new file mode 100644
index 00000000..c71d1e7c
--- /dev/null
+++ b/vendor/time/src/serde/timestamp/nanoseconds.rs
@@ -0,0 +1,61 @@
+//! Treat an [`OffsetDateTime`] as a [Unix timestamp] with nanoseconds for
+//! the purposes of serde.
+//!
+//! Use this module in combination with serde's [`#[with]`][with] attribute.
+//!
+//! When deserializing, the offset is assumed to be UTC.
+//!
+//! [Unix timestamp]: https://en.wikipedia.org/wiki/Unix_time
+//! [with]: https://serde.rs/field-attrs.html#with
+
+use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
+
+use crate::OffsetDateTime;
+
+/// Serialize an `OffsetDateTime` as its Unix timestamp with nanoseconds
+pub fn serialize<S: Serializer>(
+ datetime: &OffsetDateTime,
+ serializer: S,
+) -> Result<S::Ok, S::Error> {
+ datetime.unix_timestamp_nanos().serialize(serializer)
+}
+
+/// Deserialize an `OffsetDateTime` from its Unix timestamp with nanoseconds
+pub fn deserialize<'a, D: Deserializer<'a>>(deserializer: D) -> Result<OffsetDateTime, D::Error> {
+ OffsetDateTime::from_unix_timestamp_nanos(<_>::deserialize(deserializer)?)
+ .map_err(|err| de::Error::invalid_value(de::Unexpected::Signed(err.value), &err))
+}
+
+/// Treat an `Option<OffsetDateTime>` as a [Unix timestamp] with nanoseconds
+/// for the purposes of serde.
+///
+/// Use this module in combination with serde's [`#[with]`][with] attribute.
+///
+/// When deserializing, the offset is assumed to be UTC.
+///
+/// [Unix timestamp]: https://en.wikipedia.org/wiki/Unix_time
+/// [with]: https://serde.rs/field-attrs.html#with
+pub mod option {
+ #[allow(clippy::wildcard_imports)]
+ use super::*;
+
+ /// Serialize an `Option<OffsetDateTime>` as its Unix timestamp with nanoseconds
+ pub fn serialize<S: Serializer>(
+ option: &Option<OffsetDateTime>,
+ serializer: S,
+ ) -> Result<S::Ok, S::Error> {
+ option
+ .map(OffsetDateTime::unix_timestamp_nanos)
+ .serialize(serializer)
+ }
+
+ /// Deserialize an `Option<OffsetDateTime>` from its Unix timestamp with nanoseconds
+ pub fn deserialize<'a, D: Deserializer<'a>>(
+ deserializer: D,
+ ) -> Result<Option<OffsetDateTime>, D::Error> {
+ Option::deserialize(deserializer)?
+ .map(OffsetDateTime::from_unix_timestamp_nanos)
+ .transpose()
+ .map_err(|err| de::Error::invalid_value(de::Unexpected::Signed(err.value), &err))
+ }
+}
diff --git a/vendor/time/src/serde/visitor.rs b/vendor/time/src/serde/visitor.rs
new file mode 100644
index 00000000..b7034020
--- /dev/null
+++ b/vendor/time/src/serde/visitor.rs
@@ -0,0 +1,355 @@
+//! Serde visitor for various types.
+
+use core::fmt;
+use core::marker::PhantomData;
+
+use serde::de;
+#[cfg(feature = "parsing")]
+use serde::Deserializer;
+
+#[cfg(feature = "parsing")]
+use super::{
+ DATE_FORMAT, OFFSET_DATE_TIME_FORMAT, PRIMITIVE_DATE_TIME_FORMAT, TIME_FORMAT,
+ UTC_DATE_TIME_FORMAT, UTC_OFFSET_FORMAT,
+};
+use crate::error::ComponentRange;
+#[cfg(feature = "parsing")]
+use crate::format_description::well_known::*;
+use crate::{
+ Date, Duration, Month, OffsetDateTime, PrimitiveDateTime, Time, UtcDateTime, UtcOffset, Weekday,
+};
+
+/// A serde visitor for various types.
+pub(super) struct Visitor<T: ?Sized>(pub(super) PhantomData<T>);
+
+impl<'a> de::Visitor<'a> for Visitor<Date> {
+ type Value = Date;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+ formatter.write_str("a `Date`")
+ }
+
+ #[cfg(feature = "parsing")]
+ fn visit_str<E: de::Error>(self, value: &str) -> Result<Date, E> {
+ Date::parse(value, &DATE_FORMAT).map_err(E::custom)
+ }
+
+ fn visit_seq<A: de::SeqAccess<'a>>(self, mut seq: A) -> Result<Date, A::Error> {
+ let year = item!(seq, "year")?;
+ let ordinal = item!(seq, "day of year")?;
+ Date::from_ordinal_date(year, ordinal).map_err(ComponentRange::into_de_error)
+ }
+}
+
+impl<'a> de::Visitor<'a> for Visitor<Duration> {
+ type Value = Duration;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+ formatter.write_str("a `Duration`")
+ }
+
+ fn visit_str<E: de::Error>(self, value: &str) -> Result<Duration, E> {
+ let (seconds, nanoseconds) = value.split_once('.').ok_or_else(|| {
+ de::Error::invalid_value(de::Unexpected::Str(value), &"a decimal point")
+ })?;
+
+ let seconds = seconds
+ .parse()
+ .map_err(|_| de::Error::invalid_value(de::Unexpected::Str(seconds), &"seconds"))?;
+ let mut nanoseconds = nanoseconds.parse().map_err(|_| {
+ de::Error::invalid_value(de::Unexpected::Str(nanoseconds), &"nanoseconds")
+ })?;
+
+ if seconds < 0
+ // make sure sign does not disappear when seconds == 0
+ || (seconds == 0 && value.starts_with("-"))
+ {
+ nanoseconds *= -1;
+ }
+
+ Ok(Duration::new(seconds, nanoseconds))
+ }
+
+ fn visit_seq<A: de::SeqAccess<'a>>(self, mut seq: A) -> Result<Duration, A::Error> {
+ let seconds = item!(seq, "seconds")?;
+ let nanoseconds = item!(seq, "nanoseconds")?;
+ Ok(Duration::new(seconds, nanoseconds))
+ }
+}
+
+impl<'a> de::Visitor<'a> for Visitor<OffsetDateTime> {
+ type Value = OffsetDateTime;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+ formatter.write_str("an `OffsetDateTime`")
+ }
+
+ #[cfg(feature = "parsing")]
+ fn visit_str<E: de::Error>(self, value: &str) -> Result<OffsetDateTime, E> {
+ OffsetDateTime::parse(value, &OFFSET_DATE_TIME_FORMAT).map_err(E::custom)
+ }
+
+ fn visit_seq<A: de::SeqAccess<'a>>(self, mut seq: A) -> Result<OffsetDateTime, A::Error> {
+ let year = item!(seq, "year")?;
+ let ordinal = item!(seq, "day of year")?;
+ let hour = item!(seq, "hour")?;
+ let minute = item!(seq, "minute")?;
+ let second = item!(seq, "second")?;
+ let nanosecond = item!(seq, "nanosecond")?;
+ let offset_hours = item!(seq, "offset hours")?;
+ let offset_minutes = item!(seq, "offset minutes")?;
+ let offset_seconds = item!(seq, "offset seconds")?;
+
+ Date::from_ordinal_date(year, ordinal)
+ .and_then(|date| date.with_hms_nano(hour, minute, second, nanosecond))
+ .and_then(|datetime| {
+ UtcOffset::from_hms(offset_hours, offset_minutes, offset_seconds)
+ .map(|offset| datetime.assume_offset(offset))
+ })
+ .map_err(ComponentRange::into_de_error)
+ }
+}
+
+impl<'a> de::Visitor<'a> for Visitor<PrimitiveDateTime> {
+ type Value = PrimitiveDateTime;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+ formatter.write_str("a `PrimitiveDateTime`")
+ }
+
+ #[cfg(feature = "parsing")]
+ fn visit_str<E: de::Error>(self, value: &str) -> Result<PrimitiveDateTime, E> {
+ PrimitiveDateTime::parse(value, &PRIMITIVE_DATE_TIME_FORMAT).map_err(E::custom)
+ }
+
+ fn visit_seq<A: de::SeqAccess<'a>>(self, mut seq: A) -> Result<PrimitiveDateTime, A::Error> {
+ let year = item!(seq, "year")?;
+ let ordinal = item!(seq, "day of year")?;
+ let hour = item!(seq, "hour")?;
+ let minute = item!(seq, "minute")?;
+ let second = item!(seq, "second")?;
+ let nanosecond = item!(seq, "nanosecond")?;
+
+ Date::from_ordinal_date(year, ordinal)
+ .and_then(|date| date.with_hms_nano(hour, minute, second, nanosecond))
+ .map_err(ComponentRange::into_de_error)
+ }
+}
+
+impl<'a> de::Visitor<'a> for Visitor<UtcDateTime> {
+ type Value = UtcDateTime;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+ formatter.write_str("a `PrimitiveDateTime`")
+ }
+
+ #[cfg(feature = "parsing")]
+ fn visit_str<E: de::Error>(self, value: &str) -> Result<UtcDateTime, E> {
+ UtcDateTime::parse(value, &UTC_DATE_TIME_FORMAT).map_err(E::custom)
+ }
+
+ fn visit_seq<A: de::SeqAccess<'a>>(self, mut seq: A) -> Result<UtcDateTime, A::Error> {
+ let year = item!(seq, "year")?;
+ let ordinal = item!(seq, "day of year")?;
+ let hour = item!(seq, "hour")?;
+ let minute = item!(seq, "minute")?;
+ let second = item!(seq, "second")?;
+ let nanosecond = item!(seq, "nanosecond")?;
+
+ Date::from_ordinal_date(year, ordinal)
+ .and_then(|date| date.with_hms_nano(hour, minute, second, nanosecond))
+ .map(UtcDateTime::from_primitive)
+ .map_err(ComponentRange::into_de_error)
+ }
+}
+
+impl<'a> de::Visitor<'a> for Visitor<Time> {
+ type Value = Time;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+ formatter.write_str("a `Time`")
+ }
+
+ #[cfg(feature = "parsing")]
+ fn visit_str<E: de::Error>(self, value: &str) -> Result<Time, E> {
+ Time::parse(value, &TIME_FORMAT).map_err(E::custom)
+ }
+
+ fn visit_seq<A: de::SeqAccess<'a>>(self, mut seq: A) -> Result<Time, A::Error> {
+ let hour = item!(seq, "hour")?;
+ let minute = item!(seq, "minute")?;
+ let second = item!(seq, "second")?;
+ let nanosecond = item!(seq, "nanosecond")?;
+
+ Time::from_hms_nano(hour, minute, second, nanosecond).map_err(ComponentRange::into_de_error)
+ }
+}
+
+impl<'a> de::Visitor<'a> for Visitor<UtcOffset> {
+ type Value = UtcOffset;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+ formatter.write_str("a `UtcOffset`")
+ }
+
+ #[cfg(feature = "parsing")]
+ fn visit_str<E: de::Error>(self, value: &str) -> Result<UtcOffset, E> {
+ UtcOffset::parse(value, &UTC_OFFSET_FORMAT).map_err(E::custom)
+ }
+
+ fn visit_seq<A: de::SeqAccess<'a>>(self, mut seq: A) -> Result<UtcOffset, A::Error> {
+ let hours = item!(seq, "offset hours")?;
+ let mut minutes = 0;
+ let mut seconds = 0;
+
+ if let Ok(Some(min)) = seq.next_element() {
+ minutes = min;
+ if let Ok(Some(sec)) = seq.next_element() {
+ seconds = sec;
+ }
+ };
+
+ UtcOffset::from_hms(hours, minutes, seconds).map_err(ComponentRange::into_de_error)
+ }
+}
+
+impl de::Visitor<'_> for Visitor<Weekday> {
+ type Value = Weekday;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+ formatter.write_str("a `Weekday`")
+ }
+
+ fn visit_str<E: de::Error>(self, value: &str) -> Result<Weekday, E> {
+ match value {
+ "Monday" => Ok(Weekday::Monday),
+ "Tuesday" => Ok(Weekday::Tuesday),
+ "Wednesday" => Ok(Weekday::Wednesday),
+ "Thursday" => Ok(Weekday::Thursday),
+ "Friday" => Ok(Weekday::Friday),
+ "Saturday" => Ok(Weekday::Saturday),
+ "Sunday" => Ok(Weekday::Sunday),
+ _ => Err(E::invalid_value(de::Unexpected::Str(value), &"a `Weekday`")),
+ }
+ }
+
+ fn visit_u64<E: de::Error>(self, value: u64) -> Result<Weekday, E> {
+ match value {
+ 1 => Ok(Weekday::Monday),
+ 2 => Ok(Weekday::Tuesday),
+ 3 => Ok(Weekday::Wednesday),
+ 4 => Ok(Weekday::Thursday),
+ 5 => Ok(Weekday::Friday),
+ 6 => Ok(Weekday::Saturday),
+ 7 => Ok(Weekday::Sunday),
+ _ => Err(E::invalid_value(
+ de::Unexpected::Unsigned(value),
+ &"a value in the range 1..=7",
+ )),
+ }
+ }
+}
+
+impl de::Visitor<'_> for Visitor<Month> {
+ type Value = Month;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+ formatter.write_str("a `Month`")
+ }
+
+ fn visit_str<E: de::Error>(self, value: &str) -> Result<Month, E> {
+ match value {
+ "January" => Ok(Month::January),
+ "February" => Ok(Month::February),
+ "March" => Ok(Month::March),
+ "April" => Ok(Month::April),
+ "May" => Ok(Month::May),
+ "June" => Ok(Month::June),
+ "July" => Ok(Month::July),
+ "August" => Ok(Month::August),
+ "September" => Ok(Month::September),
+ "October" => Ok(Month::October),
+ "November" => Ok(Month::November),
+ "December" => Ok(Month::December),
+ _ => Err(E::invalid_value(de::Unexpected::Str(value), &"a `Month`")),
+ }
+ }
+
+ fn visit_u64<E: de::Error>(self, value: u64) -> Result<Month, E> {
+ match value {
+ 1 => Ok(Month::January),
+ 2 => Ok(Month::February),
+ 3 => Ok(Month::March),
+ 4 => Ok(Month::April),
+ 5 => Ok(Month::May),
+ 6 => Ok(Month::June),
+ 7 => Ok(Month::July),
+ 8 => Ok(Month::August),
+ 9 => Ok(Month::September),
+ 10 => Ok(Month::October),
+ 11 => Ok(Month::November),
+ 12 => Ok(Month::December),
+ _ => Err(E::invalid_value(
+ de::Unexpected::Unsigned(value),
+ &"a value in the range 1..=12",
+ )),
+ }
+ }
+}
+
+/// Implement a visitor for a well-known format.
+macro_rules! well_known {
+ ($article:literal, $name:literal, $($ty:tt)+) => {
+ #[cfg(feature = "parsing")]
+ impl de::Visitor<'_> for Visitor<$($ty)+> {
+ type Value = OffsetDateTime;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+ formatter.write_str(concat!($article, " ", $name, "-formatted `OffsetDateTime`"))
+ }
+
+ fn visit_str<E: de::Error>(self, value: &str) -> Result<OffsetDateTime, E> {
+ OffsetDateTime::parse(value, &$($ty)+).map_err(E::custom)
+ }
+ }
+
+ #[cfg(feature = "parsing")]
+ impl<'a> de::Visitor<'a> for Visitor<Option<$($ty)+>> {
+ type Value = Option<OffsetDateTime>;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+ formatter.write_str(concat!(
+ $article,
+ " ",
+ $name,
+ "-formatted `Option<OffsetDateTime>`"
+ ))
+ }
+
+ fn visit_some<D: Deserializer<'a>>(
+ self,
+ deserializer: D,
+ ) -> Result<Option<OffsetDateTime>, D::Error> {
+ deserializer
+ .deserialize_any(Visitor::<$($ty)+>(PhantomData))
+ .map(Some)
+ }
+
+ fn visit_none<E: de::Error>(self) -> Result<Option<OffsetDateTime>, E> {
+ Ok(None)
+ }
+
+ fn visit_unit<E: de::Error>(self) -> Result<Self::Value, E> {
+ Ok(None)
+ }
+ }
+ };
+}
+
+well_known!("an", "RFC2822", Rfc2822);
+well_known!("an", "RFC3339", Rfc3339);
+well_known!(
+ "an",
+ "ISO 8601",
+ Iso8601::<{ super::iso8601::SERDE_CONFIG }>
+);
diff --git a/vendor/time/src/sys/local_offset_at/imp.rs b/vendor/time/src/sys/local_offset_at/imp.rs
new file mode 100644
index 00000000..251fa667
--- /dev/null
+++ b/vendor/time/src/sys/local_offset_at/imp.rs
@@ -0,0 +1,8 @@
+//! A fallback for any OS not covered.
+
+use crate::{OffsetDateTime, UtcOffset};
+
+#[allow(clippy::missing_docs_in_private_items)]
+pub(super) fn local_offset_at(_datetime: OffsetDateTime) -> Option<UtcOffset> {
+ None
+}
diff --git a/vendor/time/src/sys/local_offset_at/mod.rs b/vendor/time/src/sys/local_offset_at/mod.rs
new file mode 100644
index 00000000..04cfffd5
--- /dev/null
+++ b/vendor/time/src/sys/local_offset_at/mod.rs
@@ -0,0 +1,23 @@
+//! A method to obtain the local offset from UTC.
+
+#![allow(clippy::missing_const_for_fn)]
+
+#[cfg_attr(target_family = "windows", path = "windows.rs")]
+#[cfg_attr(target_family = "unix", path = "unix.rs")]
+#[cfg_attr(
+ all(
+ target_family = "wasm",
+ not(any(target_os = "emscripten", target_os = "wasi")),
+ feature = "wasm-bindgen"
+ ),
+ path = "wasm_js.rs"
+)]
+mod imp;
+
+use crate::{OffsetDateTime, UtcOffset};
+
+/// Attempt to obtain the system's UTC offset. If the offset cannot be determined, `None` is
+/// returned.
+pub(crate) fn local_offset_at(datetime: OffsetDateTime) -> Option<UtcOffset> {
+ imp::local_offset_at(datetime)
+}
diff --git a/vendor/time/src/sys/local_offset_at/unix.rs b/vendor/time/src/sys/local_offset_at/unix.rs
new file mode 100644
index 00000000..d036a0e0
--- /dev/null
+++ b/vendor/time/src/sys/local_offset_at/unix.rs
@@ -0,0 +1,101 @@
+//! Get the system's UTC offset on Unix.
+
+use core::mem::MaybeUninit;
+
+use crate::{OffsetDateTime, UtcOffset};
+
+/// Convert the given Unix timestamp to a `libc::tm`. Returns `None` on any error.
+fn timestamp_to_tm(timestamp: i64) -> Option<libc::tm> {
+ // The exact type of `timestamp` beforehand can vary, so this conversion is necessary.
+ #[allow(clippy::useless_conversion)]
+ let timestamp = timestamp.try_into().ok()?;
+
+ let mut tm = MaybeUninit::uninit();
+
+ // Safety: We are calling a system API, which mutates the `tm` variable. If a null
+ // pointer is returned, an error occurred.
+ let tm_ptr = unsafe { libc::localtime_r(&timestamp, tm.as_mut_ptr()) };
+
+ if tm_ptr.is_null() {
+ None
+ } else {
+ // Safety: The value was initialized, as we no longer have a null pointer.
+ Some(unsafe { tm.assume_init() })
+ }
+}
+
+/// Convert a `libc::tm` to a `UtcOffset`. Returns `None` on any error.
+// This is available to any target known to have the `tm_gmtoff` extension.
+#[cfg(any(
+ target_os = "redox",
+ target_os = "linux",
+ target_os = "l4re",
+ target_os = "android",
+ target_os = "emscripten",
+ target_os = "macos",
+ target_os = "ios",
+ target_os = "watchos",
+ target_os = "freebsd",
+ target_os = "dragonfly",
+ target_os = "openbsd",
+ target_os = "netbsd",
+ target_os = "haiku",
+))]
+fn tm_to_offset(_unix_timestamp: i64, tm: libc::tm) -> Option<UtcOffset> {
+ let seconds = tm.tm_gmtoff.try_into().ok()?;
+ UtcOffset::from_whole_seconds(seconds).ok()
+}
+
+/// Convert a `libc::tm` to a `UtcOffset`. Returns `None` on any error.
+///
+/// This method can return an incorrect value, as it only approximates the `tm_gmtoff` field. The
+/// reason for this is that daylight saving time does not start on the same date every year, nor are
+/// the rules for daylight saving time the same for every year. This implementation assumes 1970 is
+/// equivalent to every other year, which is not always the case.
+#[cfg(not(any(
+ target_os = "redox",
+ target_os = "linux",
+ target_os = "l4re",
+ target_os = "android",
+ target_os = "emscripten",
+ target_os = "macos",
+ target_os = "ios",
+ target_os = "watchos",
+ target_os = "freebsd",
+ target_os = "dragonfly",
+ target_os = "openbsd",
+ target_os = "netbsd",
+ target_os = "haiku",
+)))]
+fn tm_to_offset(unix_timestamp: i64, tm: libc::tm) -> Option<UtcOffset> {
+ use crate::Date;
+
+ let mut tm = tm;
+ if tm.tm_sec == 60 {
+ // Leap seconds are not currently supported.
+ tm.tm_sec = 59;
+ }
+
+ let local_timestamp =
+ Date::from_ordinal_date(1900 + tm.tm_year, u16::try_from(tm.tm_yday).ok()? + 1)
+ .ok()?
+ .with_hms(
+ tm.tm_hour.try_into().ok()?,
+ tm.tm_min.try_into().ok()?,
+ tm.tm_sec.try_into().ok()?,
+ )
+ .ok()?
+ .assume_utc()
+ .unix_timestamp();
+
+ let diff_secs = (local_timestamp - unix_timestamp).try_into().ok()?;
+
+ UtcOffset::from_whole_seconds(diff_secs).ok()
+}
+
+/// Obtain the system's UTC offset.
+pub(super) fn local_offset_at(datetime: OffsetDateTime) -> Option<UtcOffset> {
+ let unix_timestamp = datetime.unix_timestamp();
+ let tm = timestamp_to_tm(unix_timestamp)?;
+ tm_to_offset(unix_timestamp, tm)
+}
diff --git a/vendor/time/src/sys/local_offset_at/wasm_js.rs b/vendor/time/src/sys/local_offset_at/wasm_js.rs
new file mode 100644
index 00000000..a985e7c4
--- /dev/null
+++ b/vendor/time/src/sys/local_offset_at/wasm_js.rs
@@ -0,0 +1,16 @@
+use num_conv::prelude::*;
+
+use crate::convert::*;
+use crate::{OffsetDateTime, UtcOffset};
+
+/// Obtain the system's UTC offset.
+pub(super) fn local_offset_at(datetime: OffsetDateTime) -> Option<UtcOffset> {
+ let js_date: js_sys::Date = datetime.into();
+ // The number of minutes returned by getTimezoneOffset() is positive if the local time zone
+ // is behind UTC, and negative if the local time zone is ahead of UTC. For example,
+ // for UTC+10, -600 will be returned.
+ let timezone_offset =
+ (js_date.get_timezone_offset() as i32) * -Minute::per(Hour).cast_signed().extend::<i32>();
+
+ UtcOffset::from_whole_seconds(timezone_offset).ok()
+}
diff --git a/vendor/time/src/sys/local_offset_at/windows.rs b/vendor/time/src/sys/local_offset_at/windows.rs
new file mode 100644
index 00000000..d1442920
--- /dev/null
+++ b/vendor/time/src/sys/local_offset_at/windows.rs
@@ -0,0 +1,113 @@
+//! Get the system's UTC offset on Windows.
+
+use core::mem::MaybeUninit;
+
+use num_conv::prelude::*;
+
+use crate::convert::*;
+use crate::{OffsetDateTime, UtcOffset};
+
+// ffi: WINAPI FILETIME struct
+#[repr(C)]
+#[allow(non_snake_case, clippy::missing_docs_in_private_items)]
+struct FileTime {
+ dwLowDateTime: u32,
+ dwHighDateTime: u32,
+}
+
+// ffi: WINAPI SYSTEMTIME struct
+#[repr(C)]
+#[allow(non_snake_case, clippy::missing_docs_in_private_items)]
+struct SystemTime {
+ wYear: u16,
+ wMonth: u16,
+ wDayOfWeek: u16,
+ wDay: u16,
+ wHour: u16,
+ wMinute: u16,
+ wSecond: u16,
+ wMilliseconds: u16,
+}
+
+#[link(name = "kernel32")]
+extern "system" {
+ // https://docs.microsoft.com/en-us/windows/win32/api/timezoneapi/nf-timezoneapi-systemtimetofiletime
+ fn SystemTimeToFileTime(lpSystemTime: *const SystemTime, lpFileTime: *mut FileTime) -> i32;
+
+ // https://docs.microsoft.com/en-us/windows/win32/api/timezoneapi/nf-timezoneapi-systemtimetotzspecificlocaltime
+ fn SystemTimeToTzSpecificLocalTime(
+ lpTimeZoneInformation: *const core::ffi::c_void, // We only pass `nullptr` here
+ lpUniversalTime: *const SystemTime,
+ lpLocalTime: *mut SystemTime,
+ ) -> i32;
+}
+
+/// Convert a `SYSTEMTIME` to a `FILETIME`. Returns `None` if any error occurred.
+fn systemtime_to_filetime(systime: &SystemTime) -> Option<FileTime> {
+ let mut ft = MaybeUninit::uninit();
+
+ // Safety: `SystemTimeToFileTime` is thread-safe.
+ if 0 == unsafe { SystemTimeToFileTime(systime, ft.as_mut_ptr()) } {
+ // failed
+ None
+ } else {
+ // Safety: The call succeeded.
+ Some(unsafe { ft.assume_init() })
+ }
+}
+
+/// Convert a `FILETIME` to an `i64`, representing a number of seconds.
+fn filetime_to_secs(filetime: &FileTime) -> i64 {
+ /// FILETIME represents 100-nanosecond intervals
+ const FT_TO_SECS: u64 = Nanosecond::per(Second) as u64 / 100;
+ ((filetime.dwHighDateTime.extend::<u64>() << 32 | filetime.dwLowDateTime.extend::<u64>())
+ / FT_TO_SECS) as i64
+}
+
+/// Convert an [`OffsetDateTime`] to a `SYSTEMTIME`.
+fn offset_to_systemtime(datetime: OffsetDateTime) -> SystemTime {
+ let (_, month, day_of_month) = datetime.to_offset(UtcOffset::UTC).date().to_calendar_date();
+ SystemTime {
+ wYear: datetime.year().cast_unsigned().truncate(),
+ wMonth: u8::from(month).extend(),
+ wDay: day_of_month.extend(),
+ wDayOfWeek: 0, // ignored
+ wHour: datetime.hour().extend(),
+ wMinute: datetime.minute().extend(),
+ wSecond: datetime.second().extend(),
+ wMilliseconds: datetime.millisecond(),
+ }
+}
+
+/// Obtain the system's UTC offset.
+pub(super) fn local_offset_at(datetime: OffsetDateTime) -> Option<UtcOffset> {
+ // This function falls back to UTC if any system call fails.
+ let systime_utc = offset_to_systemtime(datetime.to_offset(UtcOffset::UTC));
+
+ // Safety: `local_time` is only read if it is properly initialized, and
+ // `SystemTimeToTzSpecificLocalTime` is thread-safe.
+ let systime_local = unsafe {
+ let mut local_time = MaybeUninit::uninit();
+
+ if 0 == SystemTimeToTzSpecificLocalTime(
+ core::ptr::null(), // use system's current timezone
+ &systime_utc,
+ local_time.as_mut_ptr(),
+ ) {
+ // call failed
+ return None;
+ } else {
+ local_time.assume_init()
+ }
+ };
+
+ // Convert SYSTEMTIMEs to FILETIMEs so we can perform arithmetic on them.
+ let ft_system = systemtime_to_filetime(&systime_utc)?;
+ let ft_local = systemtime_to_filetime(&systime_local)?;
+
+ let diff_secs = (filetime_to_secs(&ft_local) - filetime_to_secs(&ft_system))
+ .try_into()
+ .ok()?;
+
+ UtcOffset::from_whole_seconds(diff_secs).ok()
+}
diff --git a/vendor/time/src/sys/mod.rs b/vendor/time/src/sys/mod.rs
new file mode 100644
index 00000000..76ca93b5
--- /dev/null
+++ b/vendor/time/src/sys/mod.rs
@@ -0,0 +1,11 @@
+//! Functions with a common interface that rely on system calls.
+
+#[cfg(feature = "local-offset")]
+mod local_offset_at;
+#[cfg(feature = "local-offset")]
+mod refresh_tz;
+
+#[cfg(feature = "local-offset")]
+pub(crate) use self::local_offset_at::local_offset_at;
+#[cfg(feature = "local-offset")]
+pub(crate) use self::refresh_tz::{refresh_tz, refresh_tz_unchecked};
diff --git a/vendor/time/src/sys/refresh_tz/imp.rs b/vendor/time/src/sys/refresh_tz/imp.rs
new file mode 100644
index 00000000..6f8b1328
--- /dev/null
+++ b/vendor/time/src/sys/refresh_tz/imp.rs
@@ -0,0 +1,9 @@
+//! A fallback for any OS not covered.
+
+#[allow(clippy::missing_docs_in_private_items)]
+pub(super) unsafe fn refresh_tz_unchecked() {}
+
+#[allow(clippy::missing_docs_in_private_items)]
+pub(super) fn refresh_tz() -> Option<()> {
+ Some(())
+}
diff --git a/vendor/time/src/sys/refresh_tz/mod.rs b/vendor/time/src/sys/refresh_tz/mod.rs
new file mode 100644
index 00000000..90ddaa99
--- /dev/null
+++ b/vendor/time/src/sys/refresh_tz/mod.rs
@@ -0,0 +1,17 @@
+#[cfg_attr(target_family = "unix", path = "unix.rs")]
+mod imp;
+
+/// Update time zone information from the system.
+///
+/// For safety documentation, see [`time::util::refresh_tz`].
+pub(crate) unsafe fn refresh_tz_unchecked() {
+ // Safety: The caller must uphold the safety requirements.
+ unsafe { imp::refresh_tz_unchecked() }
+}
+
+/// Attempt to update time zone information from the system.
+///
+/// Returns `None` if the call is not known to be sound.
+pub(crate) fn refresh_tz() -> Option<()> {
+ imp::refresh_tz()
+}
diff --git a/vendor/time/src/sys/refresh_tz/unix.rs b/vendor/time/src/sys/refresh_tz/unix.rs
new file mode 100644
index 00000000..6c9813e2
--- /dev/null
+++ b/vendor/time/src/sys/refresh_tz/unix.rs
@@ -0,0 +1,48 @@
+/// Whether the operating system has a thread-safe environment. This allows bypassing the check for
+/// if the process is multi-threaded.
+// This is the same value as `cfg!(target_os = "x")`.
+// Use byte-strings to work around current limitations of const eval.
+const OS_HAS_THREAD_SAFE_ENVIRONMENT: bool = match std::env::consts::OS.as_bytes() {
+ // https://github.com/illumos/illumos-gate/blob/0fb96ba1f1ce26ff8b286f8f928769a6afcb00a6/usr/src/lib/libc/port/gen/getenv.c
+ b"illumos"
+ // https://github.com/NetBSD/src/blob/f45028636a44111bc4af44d460924958a4460844/lib/libc/stdlib/getenv.c
+ // https://github.com/NetBSD/src/blob/f45028636a44111bc4af44d460924958a4460844/lib/libc/stdlib/setenv.c
+ | b"netbsd"
+ => true,
+ _ => false,
+};
+
+/// Update time zone information from the system.
+///
+/// For safety documentation, see [`time::util::refresh_tz`].
+pub(super) unsafe fn refresh_tz_unchecked() {
+ extern "C" {
+ #[cfg_attr(target_os = "netbsd", link_name = "__tzset50")]
+ fn tzset();
+ }
+
+ // Safety: The caller must uphold the safety requirements.
+ unsafe { tzset() };
+}
+
+/// Attempt to update time zone information from the system. Returns `None` if the call is not known
+/// to be sound.
+pub(super) fn refresh_tz() -> Option<()> {
+ // Refresh $TZ if and only if the call is known to be sound.
+ //
+ // Soundness can be guaranteed either by knowledge of the operating system or knowledge that the
+ // process is single-threaded. If the process is single-threaded, then the environment cannot
+ // be mutated by a different thread in the process while execution of this function is taking
+ // place, which can cause a segmentation fault by dereferencing a dangling pointer.
+ //
+ // If the `num_threads` crate is incapable of determining the number of running threads, then
+ // we conservatively return `None` to avoid a soundness bug.
+
+ if OS_HAS_THREAD_SAFE_ENVIRONMENT || num_threads::is_single_threaded() == Some(true) {
+ // Safety: The caller must uphold the safety requirements.
+ unsafe { refresh_tz_unchecked() };
+ Some(())
+ } else {
+ None
+ }
+}
diff --git a/vendor/time/src/tests.rs b/vendor/time/src/tests.rs
new file mode 100644
index 00000000..1a404aa9
--- /dev/null
+++ b/vendor/time/src/tests.rs
@@ -0,0 +1,104 @@
+#![cfg(all( // require `--all-features` to be passed
+ feature = "default",
+ feature = "alloc",
+ feature = "formatting",
+ feature = "large-dates",
+ feature = "local-offset",
+ feature = "macros",
+ feature = "parsing",
+ feature = "quickcheck",
+ feature = "serde-human-readable",
+ feature = "serde-well-known",
+ feature = "std",
+ feature = "rand",
+ feature = "serde",
+))]
+#![allow(
+ let_underscore_drop,
+ clippy::clone_on_copy,
+ clippy::cognitive_complexity,
+ clippy::std_instead_of_core
+)]
+
+//! Tests for internal details.
+//!
+//! This module should only be used when it is not possible to test the implementation in a
+//! reasonable manner externally.
+
+use std::format;
+use std::num::NonZeroU8;
+
+use crate::ext::DigitCount;
+use crate::parsing::combinator::rfc::iso8601;
+use crate::parsing::shim::Integer;
+use crate::{duration, parsing};
+
+#[test]
+fn digit_count() {
+ assert_eq!(1_u8.num_digits(), 1);
+ assert_eq!(9_u8.num_digits(), 1);
+ assert_eq!(10_u8.num_digits(), 2);
+ assert_eq!(99_u8.num_digits(), 2);
+ assert_eq!(100_u8.num_digits(), 3);
+
+ assert_eq!(1_u16.num_digits(), 1);
+ assert_eq!(9_u16.num_digits(), 1);
+ assert_eq!(10_u16.num_digits(), 2);
+ assert_eq!(99_u16.num_digits(), 2);
+ assert_eq!(100_u16.num_digits(), 3);
+ assert_eq!(999_u16.num_digits(), 3);
+ assert_eq!(1_000_u16.num_digits(), 4);
+ assert_eq!(9_999_u16.num_digits(), 4);
+ assert_eq!(10_000_u16.num_digits(), 5);
+
+ assert_eq!(1_u32.num_digits(), 1);
+ assert_eq!(9_u32.num_digits(), 1);
+ assert_eq!(10_u32.num_digits(), 2);
+ assert_eq!(99_u32.num_digits(), 2);
+ assert_eq!(100_u32.num_digits(), 3);
+ assert_eq!(999_u32.num_digits(), 3);
+ assert_eq!(1_000_u32.num_digits(), 4);
+ assert_eq!(9_999_u32.num_digits(), 4);
+ assert_eq!(10_000_u32.num_digits(), 5);
+ assert_eq!(99_999_u32.num_digits(), 5);
+ assert_eq!(100_000_u32.num_digits(), 6);
+ assert_eq!(999_999_u32.num_digits(), 6);
+ assert_eq!(1_000_000_u32.num_digits(), 7);
+ assert_eq!(9_999_999_u32.num_digits(), 7);
+ assert_eq!(10_000_000_u32.num_digits(), 8);
+ assert_eq!(99_999_999_u32.num_digits(), 8);
+ assert_eq!(100_000_000_u32.num_digits(), 9);
+ assert_eq!(999_999_999_u32.num_digits(), 9);
+ assert_eq!(1_000_000_000_u32.num_digits(), 10);
+}
+
+#[test]
+fn debug() {
+ let _ = format!("{:?}", duration::Padding::Optimize);
+ let _ = format!("{:?}", parsing::ParsedItem(b"", 0));
+ let _ = format!("{:?}", parsing::component::Period::Am);
+ let _ = format!("{:?}", iso8601::ExtendedKind::Basic);
+}
+
+#[test]
+fn clone() {
+ assert_eq!(
+ parsing::component::Period::Am.clone(),
+ parsing::component::Period::Am
+ );
+ // does not impl Debug
+ assert!(crate::time::Padding::Optimize.clone() == crate::time::Padding::Optimize);
+ // does not impl PartialEq
+ assert!(matches!(
+ iso8601::ExtendedKind::Basic.clone(),
+ iso8601::ExtendedKind::Basic
+ ));
+}
+
+#[test]
+fn parsing_internals() {
+ assert!(parsing::ParsedItem(b"", ())
+ .flat_map(|_| None::<()>)
+ .is_none());
+ assert!(<NonZeroU8 as Integer>::parse_bytes(b"256").is_none());
+}
diff --git a/vendor/time/src/time.rs b/vendor/time/src/time.rs
new file mode 100644
index 00000000..627a2504
--- /dev/null
+++ b/vendor/time/src/time.rs
@@ -0,0 +1,937 @@
+//! The [`Time`] struct and its associated `impl`s.
+
+#[cfg(feature = "formatting")]
+use alloc::string::String;
+use core::fmt;
+use core::ops::{Add, Sub};
+use core::time::Duration as StdDuration;
+#[cfg(feature = "formatting")]
+use std::io;
+
+use deranged::{RangedU32, RangedU8};
+use num_conv::prelude::*;
+use powerfmt::ext::FormatterExt;
+use powerfmt::smart_display::{self, FormatterOptions, Metadata, SmartDisplay};
+
+use crate::convert::*;
+#[cfg(feature = "formatting")]
+use crate::formatting::Formattable;
+use crate::internal_macros::{cascade, ensure_ranged, impl_add_assign, impl_sub_assign};
+#[cfg(feature = "parsing")]
+use crate::parsing::Parsable;
+use crate::util::DateAdjustment;
+use crate::{error, Duration};
+
+/// By explicitly inserting this enum where padding is expected, the compiler is able to better
+/// perform niche value optimization.
+#[repr(u8)]
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub(crate) enum Padding {
+ #[allow(clippy::missing_docs_in_private_items)]
+ Optimize,
+}
+
+/// The type of the `hour` field of `Time`.
+type Hours = RangedU8<0, { Hour::per(Day) - 1 }>;
+/// The type of the `minute` field of `Time`.
+type Minutes = RangedU8<0, { Minute::per(Hour) - 1 }>;
+/// The type of the `second` field of `Time`.
+type Seconds = RangedU8<0, { Second::per(Minute) - 1 }>;
+/// The type of the `nanosecond` field of `Time`.
+type Nanoseconds = RangedU32<0, { Nanosecond::per(Second) - 1 }>;
+
+/// The clock time within a given date. Nanosecond precision.
+///
+/// All minutes are assumed to have exactly 60 seconds; no attempt is made to handle leap seconds
+/// (either positive or negative).
+///
+/// When comparing two `Time`s, they are assumed to be in the same calendar date.
+#[derive(Clone, Copy, Eq)]
+#[repr(C)]
+pub struct Time {
+ // The order of this struct's fields matter!
+ // Do not change them.
+
+ // Little endian version
+ #[cfg(target_endian = "little")]
+ nanosecond: Nanoseconds,
+ #[cfg(target_endian = "little")]
+ second: Seconds,
+ #[cfg(target_endian = "little")]
+ minute: Minutes,
+ #[cfg(target_endian = "little")]
+ hour: Hours,
+ #[cfg(target_endian = "little")]
+ padding: Padding,
+
+ // Big endian version
+ #[cfg(target_endian = "big")]
+ padding: Padding,
+ #[cfg(target_endian = "big")]
+ hour: Hours,
+ #[cfg(target_endian = "big")]
+ minute: Minutes,
+ #[cfg(target_endian = "big")]
+ second: Seconds,
+ #[cfg(target_endian = "big")]
+ nanosecond: Nanoseconds,
+}
+
+impl core::hash::Hash for Time {
+ fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
+ self.as_u64().hash(state)
+ }
+}
+
+impl PartialEq for Time {
+ fn eq(&self, other: &Self) -> bool {
+ self.as_u64().eq(&other.as_u64())
+ }
+}
+
+impl PartialOrd for Time {
+ fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
+ Some(self.cmp(other))
+ }
+}
+
+impl Ord for Time {
+ fn cmp(&self, other: &Self) -> core::cmp::Ordering {
+ self.as_u64().cmp(&other.as_u64())
+ }
+}
+
+impl Time {
+ /// Provides an u64 based representation **of the correct endianness**
+ ///
+ /// This representation can be used to do comparisons equality testing or hashing.
+ const fn as_u64(self) -> u64 {
+ let nano_bytes = self.nanosecond.get().to_ne_bytes();
+
+ #[cfg(target_endian = "big")]
+ return u64::from_be_bytes([
+ self.padding as u8,
+ self.hour.get(),
+ self.minute.get(),
+ self.second.get(),
+ nano_bytes[0],
+ nano_bytes[1],
+ nano_bytes[2],
+ nano_bytes[3],
+ ]);
+
+ #[cfg(target_endian = "little")]
+ return u64::from_le_bytes([
+ nano_bytes[0],
+ nano_bytes[1],
+ nano_bytes[2],
+ nano_bytes[3],
+ self.second.get(),
+ self.minute.get(),
+ self.hour.get(),
+ self.padding as u8,
+ ]);
+ }
+
+ /// A `Time` that is exactly midnight. This is the smallest possible value for a `Time`.
+ ///
+ /// ```rust
+ /// # use time::Time;
+ /// # use time_macros::time;
+ /// assert_eq!(Time::MIDNIGHT, time!(0:00));
+ /// ```
+ #[doc(alias = "MIN")]
+ pub const MIDNIGHT: Self =
+ Self::from_hms_nanos_ranged(Hours::MIN, Minutes::MIN, Seconds::MIN, Nanoseconds::MIN);
+
+ /// A `Time` that is one nanosecond before midnight. This is the largest possible value for a
+ /// `Time`.
+ ///
+ /// ```rust
+ /// # use time::Time;
+ /// # use time_macros::time;
+ /// assert_eq!(Time::MAX, time!(23:59:59.999_999_999));
+ /// ```
+ pub const MAX: Self =
+ Self::from_hms_nanos_ranged(Hours::MAX, Minutes::MAX, Seconds::MAX, Nanoseconds::MAX);
+
+ /// Create a `Time` from its components.
+ ///
+ /// # Safety
+ ///
+ /// - `hours` must be in the range `0..=23`.
+ /// - `minutes` must be in the range `0..=59`.
+ /// - `seconds` must be in the range `0..=59`.
+ /// - `nanoseconds` must be in the range `0..=999_999_999`.
+ #[doc(hidden)]
+ pub const unsafe fn __from_hms_nanos_unchecked(
+ hour: u8,
+ minute: u8,
+ second: u8,
+ nanosecond: u32,
+ ) -> Self {
+ // Safety: The caller must uphold the safety invariants.
+ unsafe {
+ Self::from_hms_nanos_ranged(
+ Hours::new_unchecked(hour),
+ Minutes::new_unchecked(minute),
+ Seconds::new_unchecked(second),
+ Nanoseconds::new_unchecked(nanosecond),
+ )
+ }
+ }
+
+ /// Attempt to create a `Time` from the hour, minute, and second.
+ ///
+ /// ```rust
+ /// # use time::Time;
+ /// assert!(Time::from_hms(1, 2, 3).is_ok());
+ /// ```
+ ///
+ /// ```rust
+ /// # use time::Time;
+ /// assert!(Time::from_hms(24, 0, 0).is_err()); // 24 isn't a valid hour.
+ /// assert!(Time::from_hms(0, 60, 0).is_err()); // 60 isn't a valid minute.
+ /// assert!(Time::from_hms(0, 0, 60).is_err()); // 60 isn't a valid second.
+ /// ```
+ pub const fn from_hms(hour: u8, minute: u8, second: u8) -> Result<Self, error::ComponentRange> {
+ Ok(Self::from_hms_nanos_ranged(
+ ensure_ranged!(Hours: hour),
+ ensure_ranged!(Minutes: minute),
+ ensure_ranged!(Seconds: second),
+ Nanoseconds::MIN,
+ ))
+ }
+
+ /// Create a `Time` from the hour, minute, second, and nanosecond.
+ pub(crate) const fn from_hms_nanos_ranged(
+ hour: Hours,
+ minute: Minutes,
+ second: Seconds,
+ nanosecond: Nanoseconds,
+ ) -> Self {
+ Self {
+ hour,
+ minute,
+ second,
+ nanosecond,
+ padding: Padding::Optimize,
+ }
+ }
+
+ /// Attempt to create a `Time` from the hour, minute, second, and millisecond.
+ ///
+ /// ```rust
+ /// # use time::Time;
+ /// assert!(Time::from_hms_milli(1, 2, 3, 4).is_ok());
+ /// ```
+ ///
+ /// ```rust
+ /// # use time::Time;
+ /// assert!(Time::from_hms_milli(24, 0, 0, 0).is_err()); // 24 isn't a valid hour.
+ /// assert!(Time::from_hms_milli(0, 60, 0, 0).is_err()); // 60 isn't a valid minute.
+ /// assert!(Time::from_hms_milli(0, 0, 60, 0).is_err()); // 60 isn't a valid second.
+ /// assert!(Time::from_hms_milli(0, 0, 0, 1_000).is_err()); // 1_000 isn't a valid millisecond.
+ /// ```
+ pub const fn from_hms_milli(
+ hour: u8,
+ minute: u8,
+ second: u8,
+ millisecond: u16,
+ ) -> Result<Self, error::ComponentRange> {
+ Ok(Self::from_hms_nanos_ranged(
+ ensure_ranged!(Hours: hour),
+ ensure_ranged!(Minutes: minute),
+ ensure_ranged!(Seconds: second),
+ ensure_ranged!(Nanoseconds: millisecond as u32 * Nanosecond::per(Millisecond)),
+ ))
+ }
+
+ /// Attempt to create a `Time` from the hour, minute, second, and microsecond.
+ ///
+ /// ```rust
+ /// # use time::Time;
+ /// assert!(Time::from_hms_micro(1, 2, 3, 4).is_ok());
+ /// ```
+ ///
+ /// ```rust
+ /// # use time::Time;
+ /// assert!(Time::from_hms_micro(24, 0, 0, 0).is_err()); // 24 isn't a valid hour.
+ /// assert!(Time::from_hms_micro(0, 60, 0, 0).is_err()); // 60 isn't a valid minute.
+ /// assert!(Time::from_hms_micro(0, 0, 60, 0).is_err()); // 60 isn't a valid second.
+ /// assert!(Time::from_hms_micro(0, 0, 0, 1_000_000).is_err()); // 1_000_000 isn't a valid microsecond.
+ /// ```
+ pub const fn from_hms_micro(
+ hour: u8,
+ minute: u8,
+ second: u8,
+ microsecond: u32,
+ ) -> Result<Self, error::ComponentRange> {
+ Ok(Self::from_hms_nanos_ranged(
+ ensure_ranged!(Hours: hour),
+ ensure_ranged!(Minutes: minute),
+ ensure_ranged!(Seconds: second),
+ ensure_ranged!(Nanoseconds: microsecond * Nanosecond::per(Microsecond) as u32),
+ ))
+ }
+
+ /// Attempt to create a `Time` from the hour, minute, second, and nanosecond.
+ ///
+ /// ```rust
+ /// # use time::Time;
+ /// assert!(Time::from_hms_nano(1, 2, 3, 4).is_ok());
+ /// ```
+ ///
+ /// ```rust
+ /// # use time::Time;
+ /// assert!(Time::from_hms_nano(24, 0, 0, 0).is_err()); // 24 isn't a valid hour.
+ /// assert!(Time::from_hms_nano(0, 60, 0, 0).is_err()); // 60 isn't a valid minute.
+ /// assert!(Time::from_hms_nano(0, 0, 60, 0).is_err()); // 60 isn't a valid second.
+ /// assert!(Time::from_hms_nano(0, 0, 0, 1_000_000_000).is_err()); // 1_000_000_000 isn't a valid nanosecond.
+ /// ```
+ pub const fn from_hms_nano(
+ hour: u8,
+ minute: u8,
+ second: u8,
+ nanosecond: u32,
+ ) -> Result<Self, error::ComponentRange> {
+ Ok(Self::from_hms_nanos_ranged(
+ ensure_ranged!(Hours: hour),
+ ensure_ranged!(Minutes: minute),
+ ensure_ranged!(Seconds: second),
+ ensure_ranged!(Nanoseconds: nanosecond),
+ ))
+ }
+
+ /// Get the clock hour, minute, and second.
+ ///
+ /// ```rust
+ /// # use time_macros::time;
+ /// assert_eq!(time!(0:00:00).as_hms(), (0, 0, 0));
+ /// assert_eq!(time!(23:59:59).as_hms(), (23, 59, 59));
+ /// ```
+ pub const fn as_hms(self) -> (u8, u8, u8) {
+ (self.hour.get(), self.minute.get(), self.second.get())
+ }
+
+ /// Get the clock hour, minute, second, and millisecond.
+ ///
+ /// ```rust
+ /// # use time_macros::time;
+ /// assert_eq!(time!(0:00:00).as_hms_milli(), (0, 0, 0, 0));
+ /// assert_eq!(time!(23:59:59.999).as_hms_milli(), (23, 59, 59, 999));
+ /// ```
+ pub const fn as_hms_milli(self) -> (u8, u8, u8, u16) {
+ (
+ self.hour.get(),
+ self.minute.get(),
+ self.second.get(),
+ (self.nanosecond.get() / Nanosecond::per(Millisecond)) as u16,
+ )
+ }
+
+ /// Get the clock hour, minute, second, and microsecond.
+ ///
+ /// ```rust
+ /// # use time_macros::time;
+ /// assert_eq!(time!(0:00:00).as_hms_micro(), (0, 0, 0, 0));
+ /// assert_eq!(
+ /// time!(23:59:59.999_999).as_hms_micro(),
+ /// (23, 59, 59, 999_999)
+ /// );
+ /// ```
+ pub const fn as_hms_micro(self) -> (u8, u8, u8, u32) {
+ (
+ self.hour.get(),
+ self.minute.get(),
+ self.second.get(),
+ self.nanosecond.get() / Nanosecond::per(Microsecond) as u32,
+ )
+ }
+
+ /// Get the clock hour, minute, second, and nanosecond.
+ ///
+ /// ```rust
+ /// # use time_macros::time;
+ /// assert_eq!(time!(0:00:00).as_hms_nano(), (0, 0, 0, 0));
+ /// assert_eq!(
+ /// time!(23:59:59.999_999_999).as_hms_nano(),
+ /// (23, 59, 59, 999_999_999)
+ /// );
+ /// ```
+ pub const fn as_hms_nano(self) -> (u8, u8, u8, u32) {
+ (
+ self.hour.get(),
+ self.minute.get(),
+ self.second.get(),
+ self.nanosecond.get(),
+ )
+ }
+
+ /// Get the clock hour, minute, second, and nanosecond.
+ #[cfg(feature = "quickcheck")]
+ pub(crate) const fn as_hms_nano_ranged(self) -> (Hours, Minutes, Seconds, Nanoseconds) {
+ (self.hour, self.minute, self.second, self.nanosecond)
+ }
+
+ /// Get the clock hour.
+ ///
+ /// The returned value will always be in the range `0..24`.
+ ///
+ /// ```rust
+ /// # use time_macros::time;
+ /// assert_eq!(time!(0:00:00).hour(), 0);
+ /// assert_eq!(time!(23:59:59).hour(), 23);
+ /// ```
+ pub const fn hour(self) -> u8 {
+ self.hour.get()
+ }
+
+ /// Get the minute within the hour.
+ ///
+ /// The returned value will always be in the range `0..60`.
+ ///
+ /// ```rust
+ /// # use time_macros::time;
+ /// assert_eq!(time!(0:00:00).minute(), 0);
+ /// assert_eq!(time!(23:59:59).minute(), 59);
+ /// ```
+ pub const fn minute(self) -> u8 {
+ self.minute.get()
+ }
+
+ /// Get the second within the minute.
+ ///
+ /// The returned value will always be in the range `0..60`.
+ ///
+ /// ```rust
+ /// # use time_macros::time;
+ /// assert_eq!(time!(0:00:00).second(), 0);
+ /// assert_eq!(time!(23:59:59).second(), 59);
+ /// ```
+ pub const fn second(self) -> u8 {
+ self.second.get()
+ }
+
+ /// Get the milliseconds within the second.
+ ///
+ /// The returned value will always be in the range `0..1_000`.
+ ///
+ /// ```rust
+ /// # use time_macros::time;
+ /// assert_eq!(time!(0:00).millisecond(), 0);
+ /// assert_eq!(time!(23:59:59.999).millisecond(), 999);
+ /// ```
+ pub const fn millisecond(self) -> u16 {
+ (self.nanosecond.get() / Nanosecond::per(Millisecond)) as u16
+ }
+
+ /// Get the microseconds within the second.
+ ///
+ /// The returned value will always be in the range `0..1_000_000`.
+ ///
+ /// ```rust
+ /// # use time_macros::time;
+ /// assert_eq!(time!(0:00).microsecond(), 0);
+ /// assert_eq!(time!(23:59:59.999_999).microsecond(), 999_999);
+ /// ```
+ pub const fn microsecond(self) -> u32 {
+ self.nanosecond.get() / Nanosecond::per(Microsecond) as u32
+ }
+
+ /// Get the nanoseconds within the second.
+ ///
+ /// The returned value will always be in the range `0..1_000_000_000`.
+ ///
+ /// ```rust
+ /// # use time_macros::time;
+ /// assert_eq!(time!(0:00).nanosecond(), 0);
+ /// assert_eq!(time!(23:59:59.999_999_999).nanosecond(), 999_999_999);
+ /// ```
+ pub const fn nanosecond(self) -> u32 {
+ self.nanosecond.get()
+ }
+
+ /// Add the sub-day time of the [`Duration`] to the `Time`. Wraps on overflow, returning whether
+ /// the date is different.
+ pub(crate) const fn adjusting_add(self, duration: Duration) -> (DateAdjustment, Self) {
+ let mut nanoseconds = self.nanosecond.get() as i32 + duration.subsec_nanoseconds();
+ let mut seconds =
+ self.second.get() as i8 + (duration.whole_seconds() % Second::per(Minute) as i64) as i8;
+ let mut minutes =
+ self.minute.get() as i8 + (duration.whole_minutes() % Minute::per(Hour) as i64) as i8;
+ let mut hours =
+ self.hour.get() as i8 + (duration.whole_hours() % Hour::per(Day) as i64) as i8;
+ let mut date_adjustment = DateAdjustment::None;
+
+ cascade!(nanoseconds in 0..Nanosecond::per(Second) as i32 => seconds);
+ cascade!(seconds in 0..Second::per(Minute) as i8 => minutes);
+ cascade!(minutes in 0..Minute::per(Hour) as i8 => hours);
+ if hours >= Hour::per(Day) as i8 {
+ hours -= Hour::per(Day) as i8;
+ date_adjustment = DateAdjustment::Next;
+ } else if hours < 0 {
+ hours += Hour::per(Day) as i8;
+ date_adjustment = DateAdjustment::Previous;
+ }
+
+ (
+ date_adjustment,
+ // Safety: The cascades above ensure the values are in range.
+ unsafe {
+ Self::__from_hms_nanos_unchecked(
+ hours as u8,
+ minutes as u8,
+ seconds as u8,
+ nanoseconds as u32,
+ )
+ },
+ )
+ }
+
+ /// Subtract the sub-day time of the [`Duration`] to the `Time`. Wraps on overflow, returning
+ /// whether the date is different.
+ pub(crate) const fn adjusting_sub(self, duration: Duration) -> (DateAdjustment, Self) {
+ let mut nanoseconds = self.nanosecond.get() as i32 - duration.subsec_nanoseconds();
+ let mut seconds =
+ self.second.get() as i8 - (duration.whole_seconds() % Second::per(Minute) as i64) as i8;
+ let mut minutes =
+ self.minute.get() as i8 - (duration.whole_minutes() % Minute::per(Hour) as i64) as i8;
+ let mut hours =
+ self.hour.get() as i8 - (duration.whole_hours() % Hour::per(Day) as i64) as i8;
+ let mut date_adjustment = DateAdjustment::None;
+
+ cascade!(nanoseconds in 0..Nanosecond::per(Second) as i32 => seconds);
+ cascade!(seconds in 0..Second::per(Minute) as i8 => minutes);
+ cascade!(minutes in 0..Minute::per(Hour) as i8 => hours);
+ if hours >= Hour::per(Day) as i8 {
+ hours -= Hour::per(Day) as i8;
+ date_adjustment = DateAdjustment::Next;
+ } else if hours < 0 {
+ hours += Hour::per(Day) as i8;
+ date_adjustment = DateAdjustment::Previous;
+ }
+
+ (
+ date_adjustment,
+ // Safety: The cascades above ensure the values are in range.
+ unsafe {
+ Self::__from_hms_nanos_unchecked(
+ hours as u8,
+ minutes as u8,
+ seconds as u8,
+ nanoseconds as u32,
+ )
+ },
+ )
+ }
+
+ /// Add the sub-day time of the [`std::time::Duration`] to the `Time`. Wraps on overflow,
+ /// returning whether the date is the previous date as the first element of the tuple.
+ pub(crate) const fn adjusting_add_std(self, duration: StdDuration) -> (bool, Self) {
+ let mut nanosecond = self.nanosecond.get() + duration.subsec_nanos();
+ let mut second =
+ self.second.get() + (duration.as_secs() % Second::per(Minute) as u64) as u8;
+ let mut minute = self.minute.get()
+ + ((duration.as_secs() / Second::per(Minute) as u64) % Minute::per(Hour) as u64) as u8;
+ let mut hour = self.hour.get()
+ + ((duration.as_secs() / Second::per(Hour) as u64) % Hour::per(Day) as u64) as u8;
+ let mut is_next_day = false;
+
+ cascade!(nanosecond in 0..Nanosecond::per(Second) => second);
+ cascade!(second in 0..Second::per(Minute) => minute);
+ cascade!(minute in 0..Minute::per(Hour) => hour);
+ if hour >= Hour::per(Day) {
+ hour -= Hour::per(Day);
+ is_next_day = true;
+ }
+
+ (
+ is_next_day,
+ // Safety: The cascades above ensure the values are in range.
+ unsafe { Self::__from_hms_nanos_unchecked(hour, minute, second, nanosecond) },
+ )
+ }
+
+ /// Subtract the sub-day time of the [`std::time::Duration`] to the `Time`. Wraps on overflow,
+ /// returning whether the date is the previous date as the first element of the tuple.
+ pub(crate) const fn adjusting_sub_std(self, duration: StdDuration) -> (bool, Self) {
+ let mut nanosecond = self.nanosecond.get() as i32 - duration.subsec_nanos() as i32;
+ let mut second =
+ self.second.get() as i8 - (duration.as_secs() % Second::per(Minute) as u64) as i8;
+ let mut minute = self.minute.get() as i8
+ - ((duration.as_secs() / Second::per(Minute) as u64) % Minute::per(Hour) as u64) as i8;
+ let mut hour = self.hour.get() as i8
+ - ((duration.as_secs() / Second::per(Hour) as u64) % Hour::per(Day) as u64) as i8;
+ let mut is_previous_day = false;
+
+ cascade!(nanosecond in 0..Nanosecond::per(Second) as i32 => second);
+ cascade!(second in 0..Second::per(Minute) as i8 => minute);
+ cascade!(minute in 0..Minute::per(Hour) as i8 => hour);
+ if hour < 0 {
+ hour += Hour::per(Day) as i8;
+ is_previous_day = true;
+ }
+
+ (
+ is_previous_day,
+ // Safety: The cascades above ensure the values are in range.
+ unsafe {
+ Self::__from_hms_nanos_unchecked(
+ hour as u8,
+ minute as u8,
+ second as u8,
+ nanosecond as u32,
+ )
+ },
+ )
+ }
+
+ /// Replace the clock hour.
+ ///
+ /// ```rust
+ /// # use time_macros::time;
+ /// assert_eq!(
+ /// time!(01:02:03.004_005_006).replace_hour(7),
+ /// Ok(time!(07:02:03.004_005_006))
+ /// );
+ /// assert!(time!(01:02:03.004_005_006).replace_hour(24).is_err()); // 24 isn't a valid hour
+ /// ```
+ #[must_use = "This method does not mutate the original `Time`."]
+ pub const fn replace_hour(mut self, hour: u8) -> Result<Self, error::ComponentRange> {
+ self.hour = ensure_ranged!(Hours: hour);
+ Ok(self)
+ }
+
+ /// Replace the minutes within the hour.
+ ///
+ /// ```rust
+ /// # use time_macros::time;
+ /// assert_eq!(
+ /// time!(01:02:03.004_005_006).replace_minute(7),
+ /// Ok(time!(01:07:03.004_005_006))
+ /// );
+ /// assert!(time!(01:02:03.004_005_006).replace_minute(60).is_err()); // 60 isn't a valid minute
+ /// ```
+ #[must_use = "This method does not mutate the original `Time`."]
+ pub const fn replace_minute(mut self, minute: u8) -> Result<Self, error::ComponentRange> {
+ self.minute = ensure_ranged!(Minutes: minute);
+ Ok(self)
+ }
+
+ /// Replace the seconds within the minute.
+ ///
+ /// ```rust
+ /// # use time_macros::time;
+ /// assert_eq!(
+ /// time!(01:02:03.004_005_006).replace_second(7),
+ /// Ok(time!(01:02:07.004_005_006))
+ /// );
+ /// assert!(time!(01:02:03.004_005_006).replace_second(60).is_err()); // 60 isn't a valid second
+ /// ```
+ #[must_use = "This method does not mutate the original `Time`."]
+ pub const fn replace_second(mut self, second: u8) -> Result<Self, error::ComponentRange> {
+ self.second = ensure_ranged!(Seconds: second);
+ Ok(self)
+ }
+
+ /// Replace the milliseconds within the second.
+ ///
+ /// ```rust
+ /// # use time_macros::time;
+ /// assert_eq!(
+ /// time!(01:02:03.004_005_006).replace_millisecond(7),
+ /// Ok(time!(01:02:03.007))
+ /// );
+ /// assert!(time!(01:02:03.004_005_006)
+ /// .replace_millisecond(1_000)
+ /// .is_err()); // 1_000 isn't a valid millisecond
+ /// ```
+ #[must_use = "This method does not mutate the original `Time`."]
+ pub const fn replace_millisecond(
+ mut self,
+ millisecond: u16,
+ ) -> Result<Self, error::ComponentRange> {
+ self.nanosecond =
+ ensure_ranged!(Nanoseconds: millisecond as u32 * Nanosecond::per(Millisecond));
+ Ok(self)
+ }
+
+ /// Replace the microseconds within the second.
+ ///
+ /// ```rust
+ /// # use time_macros::time;
+ /// assert_eq!(
+ /// time!(01:02:03.004_005_006).replace_microsecond(7_008),
+ /// Ok(time!(01:02:03.007_008))
+ /// );
+ /// assert!(time!(01:02:03.004_005_006)
+ /// .replace_microsecond(1_000_000)
+ /// .is_err()); // 1_000_000 isn't a valid microsecond
+ /// ```
+ #[must_use = "This method does not mutate the original `Time`."]
+ pub const fn replace_microsecond(
+ mut self,
+ microsecond: u32,
+ ) -> Result<Self, error::ComponentRange> {
+ self.nanosecond =
+ ensure_ranged!(Nanoseconds: microsecond * Nanosecond::per(Microsecond) as u32);
+ Ok(self)
+ }
+
+ /// Replace the nanoseconds within the second.
+ ///
+ /// ```rust
+ /// # use time_macros::time;
+ /// assert_eq!(
+ /// time!(01:02:03.004_005_006).replace_nanosecond(7_008_009),
+ /// Ok(time!(01:02:03.007_008_009))
+ /// );
+ /// assert!(time!(01:02:03.004_005_006)
+ /// .replace_nanosecond(1_000_000_000)
+ /// .is_err()); // 1_000_000_000 isn't a valid nanosecond
+ /// ```
+ #[must_use = "This method does not mutate the original `Time`."]
+ pub const fn replace_nanosecond(
+ mut self,
+ nanosecond: u32,
+ ) -> Result<Self, error::ComponentRange> {
+ self.nanosecond = ensure_ranged!(Nanoseconds: nanosecond);
+ Ok(self)
+ }
+}
+
+#[cfg(feature = "formatting")]
+impl Time {
+ /// Format the `Time` using the provided [format description](crate::format_description).
+ pub fn format_into(
+ self,
+ output: &mut (impl io::Write + ?Sized),
+ format: &(impl Formattable + ?Sized),
+ ) -> Result<usize, error::Format> {
+ format.format_into(output, None, Some(self), None)
+ }
+
+ /// Format the `Time` using the provided [format description](crate::format_description).
+ ///
+ /// ```rust
+ /// # use time::format_description;
+ /// # use time_macros::time;
+ /// let format = format_description::parse("[hour]:[minute]:[second]")?;
+ /// assert_eq!(time!(12:00).format(&format)?, "12:00:00");
+ /// # Ok::<_, time::Error>(())
+ /// ```
+ pub fn format(self, format: &(impl Formattable + ?Sized)) -> Result<String, error::Format> {
+ format.format(None, Some(self), None)
+ }
+}
+
+#[cfg(feature = "parsing")]
+impl Time {
+ /// Parse a `Time` from the input using the provided [format
+ /// description](crate::format_description).
+ ///
+ /// ```rust
+ /// # use time::Time;
+ /// # use time_macros::{time, format_description};
+ /// let format = format_description!("[hour]:[minute]:[second]");
+ /// assert_eq!(Time::parse("12:00:00", &format)?, time!(12:00));
+ /// # Ok::<_, time::Error>(())
+ /// ```
+ pub fn parse(
+ input: &str,
+ description: &(impl Parsable + ?Sized),
+ ) -> Result<Self, error::Parse> {
+ description.parse_time(input.as_bytes())
+ }
+}
+
+mod private {
+ #[non_exhaustive]
+ #[derive(Debug, Clone, Copy)]
+ pub struct TimeMetadata {
+ /// How many characters wide the formatted subsecond is.
+ pub(super) subsecond_width: u8,
+ /// The value to use when formatting the subsecond. Leading zeroes will be added as
+ /// necessary.
+ pub(super) subsecond_value: u32,
+ }
+}
+use private::TimeMetadata;
+
+impl SmartDisplay for Time {
+ type Metadata = TimeMetadata;
+
+ fn metadata(&self, _: FormatterOptions) -> Metadata<Self> {
+ let (subsecond_value, subsecond_width) = match self.nanosecond() {
+ nanos if nanos % 10 != 0 => (nanos, 9),
+ nanos if (nanos / 10) % 10 != 0 => (nanos / 10, 8),
+ nanos if (nanos / 100) % 10 != 0 => (nanos / 100, 7),
+ nanos if (nanos / 1_000) % 10 != 0 => (nanos / 1_000, 6),
+ nanos if (nanos / 10_000) % 10 != 0 => (nanos / 10_000, 5),
+ nanos if (nanos / 100_000) % 10 != 0 => (nanos / 100_000, 4),
+ nanos if (nanos / 1_000_000) % 10 != 0 => (nanos / 1_000_000, 3),
+ nanos if (nanos / 10_000_000) % 10 != 0 => (nanos / 10_000_000, 2),
+ nanos => (nanos / 100_000_000, 1),
+ };
+
+ let formatted_width = smart_display::padded_width_of!(
+ self.hour.get(),
+ ":",
+ self.minute.get() => width(2) fill('0'),
+ ":",
+ self.second.get() => width(2) fill('0'),
+ ".",
+ ) + subsecond_width;
+
+ Metadata::new(
+ formatted_width,
+ self,
+ TimeMetadata {
+ subsecond_width: subsecond_width.truncate(),
+ subsecond_value,
+ },
+ )
+ }
+
+ fn fmt_with_metadata(
+ &self,
+ f: &mut fmt::Formatter<'_>,
+ metadata: Metadata<Self>,
+ ) -> fmt::Result {
+ let subsecond_width = metadata.subsecond_width.extend();
+ let subsecond_value = metadata.subsecond_value;
+
+ f.pad_with_width(
+ metadata.unpadded_width(),
+ format_args!(
+ "{}:{:02}:{:02}.{subsecond_value:0subsecond_width$}",
+ self.hour, self.minute, self.second
+ ),
+ )
+ }
+}
+
+impl fmt::Display for Time {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ SmartDisplay::fmt(self, f)
+ }
+}
+
+impl fmt::Debug for Time {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt::Display::fmt(self, f)
+ }
+}
+
+impl Add<Duration> for Time {
+ type Output = Self;
+
+ /// Add the sub-day time of the [`Duration`] to the `Time`. Wraps on overflow.
+ ///
+ /// ```rust
+ /// # use time::ext::NumericalDuration;
+ /// # use time_macros::time;
+ /// assert_eq!(time!(12:00) + 2.hours(), time!(14:00));
+ /// assert_eq!(time!(0:00:01) + (-2).seconds(), time!(23:59:59));
+ /// ```
+ fn add(self, duration: Duration) -> Self::Output {
+ self.adjusting_add(duration).1
+ }
+}
+
+impl Add<StdDuration> for Time {
+ type Output = Self;
+
+ /// Add the sub-day time of the [`std::time::Duration`] to the `Time`. Wraps on overflow.
+ ///
+ /// ```rust
+ /// # use time::ext::NumericalStdDuration;
+ /// # use time_macros::time;
+ /// assert_eq!(time!(12:00) + 2.std_hours(), time!(14:00));
+ /// assert_eq!(time!(23:59:59) + 2.std_seconds(), time!(0:00:01));
+ /// ```
+ fn add(self, duration: StdDuration) -> Self::Output {
+ self.adjusting_add_std(duration).1
+ }
+}
+
+impl_add_assign!(Time: Duration, StdDuration);
+
+impl Sub<Duration> for Time {
+ type Output = Self;
+
+ /// Subtract the sub-day time of the [`Duration`] from the `Time`. Wraps on overflow.
+ ///
+ /// ```rust
+ /// # use time::ext::NumericalDuration;
+ /// # use time_macros::time;
+ /// assert_eq!(time!(14:00) - 2.hours(), time!(12:00));
+ /// assert_eq!(time!(23:59:59) - (-2).seconds(), time!(0:00:01));
+ /// ```
+ fn sub(self, duration: Duration) -> Self::Output {
+ self.adjusting_sub(duration).1
+ }
+}
+
+impl Sub<StdDuration> for Time {
+ type Output = Self;
+
+ /// Subtract the sub-day time of the [`std::time::Duration`] from the `Time`. Wraps on overflow.
+ ///
+ /// ```rust
+ /// # use time::ext::NumericalStdDuration;
+ /// # use time_macros::time;
+ /// assert_eq!(time!(14:00) - 2.std_hours(), time!(12:00));
+ /// assert_eq!(time!(0:00:01) - 2.std_seconds(), time!(23:59:59));
+ /// ```
+ fn sub(self, duration: StdDuration) -> Self::Output {
+ self.adjusting_sub_std(duration).1
+ }
+}
+
+impl_sub_assign!(Time: Duration, StdDuration);
+
+impl Sub for Time {
+ type Output = Duration;
+
+ /// Subtract two `Time`s, returning the [`Duration`] between. This assumes both `Time`s are in
+ /// the same calendar day.
+ ///
+ /// ```rust
+ /// # use time::ext::NumericalDuration;
+ /// # use time_macros::time;
+ /// assert_eq!(time!(0:00) - time!(0:00), 0.seconds());
+ /// assert_eq!(time!(1:00) - time!(0:00), 1.hours());
+ /// assert_eq!(time!(0:00) - time!(1:00), (-1).hours());
+ /// assert_eq!(time!(0:00) - time!(23:00), (-23).hours());
+ /// ```
+ fn sub(self, rhs: Self) -> Self::Output {
+ let hour_diff = self.hour.get().cast_signed() - rhs.hour.get().cast_signed();
+ let minute_diff = self.minute.get().cast_signed() - rhs.minute.get().cast_signed();
+ let second_diff = self.second.get().cast_signed() - rhs.second.get().cast_signed();
+ let nanosecond_diff =
+ self.nanosecond.get().cast_signed() - rhs.nanosecond.get().cast_signed();
+
+ let seconds = hour_diff.extend::<i64>() * Second::per(Hour).cast_signed().extend::<i64>()
+ + minute_diff.extend::<i64>() * Second::per(Minute).cast_signed().extend::<i64>()
+ + second_diff.extend::<i64>();
+
+ let (seconds, nanoseconds) = if seconds > 0 && nanosecond_diff < 0 {
+ (
+ seconds - 1,
+ nanosecond_diff + Nanosecond::per(Second).cast_signed(),
+ )
+ } else if seconds < 0 && nanosecond_diff > 0 {
+ (
+ seconds + 1,
+ nanosecond_diff - Nanosecond::per(Second).cast_signed(),
+ )
+ } else {
+ (seconds, nanosecond_diff)
+ };
+
+ // Safety: `nanoseconds` is in range due to the overflow handling.
+ unsafe { Duration::new_unchecked(seconds, nanoseconds) }
+ }
+}
diff --git a/vendor/time/src/utc_date_time.rs b/vendor/time/src/utc_date_time.rs
new file mode 100644
index 00000000..e7bb8026
--- /dev/null
+++ b/vendor/time/src/utc_date_time.rs
@@ -0,0 +1,1223 @@
+//! The [`UtcDateTime`] struct and associated `impl`s.
+
+#[cfg(feature = "formatting")]
+use alloc::string::String;
+use core::fmt;
+use core::ops::{Add, AddAssign, Sub, SubAssign};
+use core::time::Duration as StdDuration;
+#[cfg(feature = "formatting")]
+use std::io;
+
+use deranged::RangedI64;
+use powerfmt::ext::FormatterExt as _;
+use powerfmt::smart_display::{self, FormatterOptions, Metadata, SmartDisplay};
+
+use crate::convert::*;
+use crate::date::{MAX_YEAR, MIN_YEAR};
+#[cfg(feature = "formatting")]
+use crate::formatting::Formattable;
+use crate::internal_macros::{
+ cascade, const_try, const_try_opt, div_floor, ensure_ranged, expect_opt,
+};
+#[cfg(feature = "parsing")]
+use crate::parsing::Parsable;
+use crate::{
+ error, util, Date, Duration, Month, OffsetDateTime, PrimitiveDateTime, Time, UtcOffset, Weekday,
+};
+
+/// The Julian day of the Unix epoch.
+const UNIX_EPOCH_JULIAN_DAY: i32 = UtcDateTime::UNIX_EPOCH.to_julian_day();
+
+/// A [`PrimitiveDateTime`] that is known to be UTC.
+///
+/// `UtcDateTime` is guaranteed to be ABI-compatible with [`PrimitiveDateTime`], meaning that
+/// transmuting from one to the other will not result in undefined behavior.
+#[repr(transparent)]
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub struct UtcDateTime {
+ inner: PrimitiveDateTime,
+}
+
+impl UtcDateTime {
+ /// Midnight, 1 January, 1970.
+ ///
+ /// ```rust
+ /// # use time::UtcDateTime;
+ /// # use time_macros::utc_datetime;
+ /// assert_eq!(UtcDateTime::UNIX_EPOCH, utc_datetime!(1970-01-01 0:00));
+ /// ```
+ pub const UNIX_EPOCH: Self = Self::new(
+ // Safety: `ordinal` is not zero.
+ unsafe { Date::__from_ordinal_date_unchecked(1970, 1) },
+ Time::MIDNIGHT,
+ );
+
+ /// The smallest value that can be represented by `UtcDateTime`.
+ ///
+ /// Depending on `large-dates` feature flag, value of this constant may vary.
+ ///
+ /// 1. With `large-dates` disabled it is equal to `-9999-01-01 00:00:00.0`
+ /// 2. With `large-dates` enabled it is equal to `-999999-01-01 00:00:00.0`
+ ///
+ /// ```rust
+ /// # use time::UtcDateTime;
+ /// # use time_macros::utc_datetime;
+ #[cfg_attr(
+ feature = "large-dates",
+ doc = "// Assuming `large-dates` feature is enabled."
+ )]
+ #[cfg_attr(
+ feature = "large-dates",
+ doc = "assert_eq!(UtcDateTime::MIN, utc_datetime!(-999999-01-01 0:00));"
+ )]
+ #[cfg_attr(
+ not(feature = "large-dates"),
+ doc = "// Assuming `large-dates` feature is disabled."
+ )]
+ #[cfg_attr(
+ not(feature = "large-dates"),
+ doc = "assert_eq!(UtcDateTime::MIN, utc_datetime!(-9999-01-01 0:00));"
+ )]
+ /// ```
+ pub const MIN: Self = Self::new(Date::MIN, Time::MIDNIGHT);
+
+ /// The largest value that can be represented by `UtcDateTime`.
+ ///
+ /// Depending on `large-dates` feature flag, value of this constant may vary.
+ ///
+ /// 1. With `large-dates` disabled it is equal to `9999-12-31 23:59:59.999_999_999`
+ /// 2. With `large-dates` enabled it is equal to `999999-12-31 23:59:59.999_999_999`
+ ///
+ /// ```rust
+ /// # use time::UtcDateTime;
+ /// # use time_macros::utc_datetime;
+ #[cfg_attr(
+ feature = "large-dates",
+ doc = "// Assuming `large-dates` feature is enabled."
+ )]
+ #[cfg_attr(
+ feature = "large-dates",
+ doc = "assert_eq!(UtcDateTime::MAX, utc_datetime!(+999999-12-31 23:59:59.999_999_999));"
+ )]
+ #[cfg_attr(
+ not(feature = "large-dates"),
+ doc = "// Assuming `large-dates` feature is disabled."
+ )]
+ #[cfg_attr(
+ not(feature = "large-dates"),
+ doc = "assert_eq!(UtcDateTime::MAX, utc_datetime!(+9999-12-31 23:59:59.999_999_999));"
+ )]
+ /// ```
+ pub const MAX: Self = Self::new(Date::MAX, Time::MAX);
+
+ /// Create a new `UtcDateTime` with the current date and time.
+ ///
+ /// ```rust
+ /// # use time::UtcDateTime;
+ /// assert!(UtcDateTime::now().year() >= 2019);
+ /// ```
+ #[cfg(feature = "std")]
+ pub fn now() -> Self {
+ #[cfg(all(
+ target_family = "wasm",
+ not(any(target_os = "emscripten", target_os = "wasi")),
+ feature = "wasm-bindgen"
+ ))]
+ {
+ js_sys::Date::new_0().into()
+ }
+
+ #[cfg(not(all(
+ target_family = "wasm",
+ not(any(target_os = "emscripten", target_os = "wasi")),
+ feature = "wasm-bindgen"
+ )))]
+ std::time::SystemTime::now().into()
+ }
+
+ /// Create a new `UtcDateTime` from the provided [`Date`] and [`Time`].
+ ///
+ /// ```rust
+ /// # use time::UtcDateTime;
+ /// # use time_macros::{date, utc_datetime, time};
+ /// assert_eq!(
+ /// UtcDateTime::new(date!(2019-01-01), time!(0:00)),
+ /// utc_datetime!(2019-01-01 0:00),
+ /// );
+ /// ```
+ pub const fn new(date: Date, time: Time) -> Self {
+ Self {
+ inner: PrimitiveDateTime::new(date, time),
+ }
+ }
+
+ /// Create a new `UtcDateTime` from the [`PrimitiveDateTime`], assuming that the latter is UTC.
+ pub(crate) const fn from_primitive(date_time: PrimitiveDateTime) -> Self {
+ Self { inner: date_time }
+ }
+
+ /// Obtain the [`PrimitiveDateTime`] that this `UtcDateTime` represents. The no-longer-attached
+ /// [`UtcOffset`] is assumed to be UTC.
+ pub(crate) const fn as_primitive(self) -> PrimitiveDateTime {
+ self.inner
+ }
+
+ /// Create a `UtcDateTime` from the provided Unix timestamp.
+ ///
+ /// ```rust
+ /// # use time::UtcDateTime;
+ /// # use time_macros::utc_datetime;
+ /// assert_eq!(
+ /// UtcDateTime::from_unix_timestamp(0),
+ /// Ok(UtcDateTime::UNIX_EPOCH),
+ /// );
+ /// assert_eq!(
+ /// UtcDateTime::from_unix_timestamp(1_546_300_800),
+ /// Ok(utc_datetime!(2019-01-01 0:00)),
+ /// );
+ /// ```
+ ///
+ /// If you have a timestamp-nanosecond pair, you can use something along the lines of the
+ /// following:
+ ///
+ /// ```rust
+ /// # use time::{Duration, UtcDateTime, ext::NumericalDuration};
+ /// let (timestamp, nanos) = (1, 500_000_000);
+ /// assert_eq!(
+ /// UtcDateTime::from_unix_timestamp(timestamp)? + Duration::nanoseconds(nanos),
+ /// UtcDateTime::UNIX_EPOCH + 1.5.seconds()
+ /// );
+ /// # Ok::<_, time::Error>(())
+ /// ```
+ pub const fn from_unix_timestamp(timestamp: i64) -> Result<Self, error::ComponentRange> {
+ type Timestamp =
+ RangedI64<{ UtcDateTime::MIN.unix_timestamp() }, { UtcDateTime::MAX.unix_timestamp() }>;
+ ensure_ranged!(Timestamp: timestamp);
+
+ // Use the unchecked method here, as the input validity has already been verified.
+ // Safety: The Julian day number is in range.
+ let date = unsafe {
+ Date::from_julian_day_unchecked(
+ UNIX_EPOCH_JULIAN_DAY + div_floor!(timestamp, Second::per(Day) as i64) as i32,
+ )
+ };
+
+ let seconds_within_day = timestamp.rem_euclid(Second::per(Day) as i64);
+ // Safety: All values are in range.
+ let time = unsafe {
+ Time::__from_hms_nanos_unchecked(
+ (seconds_within_day / Second::per(Hour) as i64) as u8,
+ ((seconds_within_day % Second::per(Hour) as i64) / Minute::per(Hour) as i64) as u8,
+ (seconds_within_day % Second::per(Minute) as i64) as u8,
+ 0,
+ )
+ };
+
+ Ok(Self::new(date, time))
+ }
+
+ /// Construct an `UtcDateTime` from the provided Unix timestamp (in nanoseconds).
+ ///
+ /// ```rust
+ /// # use time::UtcDateTime;
+ /// # use time_macros::utc_datetime;
+ /// assert_eq!(
+ /// UtcDateTime::from_unix_timestamp_nanos(0),
+ /// Ok(UtcDateTime::UNIX_EPOCH),
+ /// );
+ /// assert_eq!(
+ /// UtcDateTime::from_unix_timestamp_nanos(1_546_300_800_000_000_000),
+ /// Ok(utc_datetime!(2019-01-01 0:00)),
+ /// );
+ /// ```
+ pub const fn from_unix_timestamp_nanos(timestamp: i128) -> Result<Self, error::ComponentRange> {
+ let datetime = const_try!(Self::from_unix_timestamp(div_floor!(
+ timestamp,
+ Nanosecond::per(Second) as i128
+ ) as i64));
+
+ Ok(Self::new(
+ datetime.date(),
+ // Safety: `nanosecond` is in range due to `rem_euclid`.
+ unsafe {
+ Time::__from_hms_nanos_unchecked(
+ datetime.hour(),
+ datetime.minute(),
+ datetime.second(),
+ timestamp.rem_euclid(Nanosecond::per(Second) as i128) as u32,
+ )
+ },
+ ))
+ }
+
+ /// Convert the `UtcDateTime` from UTC to the provided [`UtcOffset`], returning an
+ /// [`OffsetDateTime`].
+ ///
+ /// ```rust
+ /// # use time_macros::{utc_datetime, offset};
+ /// assert_eq!(
+ /// utc_datetime!(2000-01-01 0:00)
+ /// .to_offset(offset!(-1))
+ /// .year(),
+ /// 1999,
+ /// );
+ ///
+ /// // Construct midnight on new year's, UTC.
+ /// let utc = utc_datetime!(2000-01-01 0:00);
+ /// let new_york = utc.to_offset(offset!(-5));
+ /// let los_angeles = utc.to_offset(offset!(-8));
+ /// assert_eq!(utc.hour(), 0);
+ /// assert_eq!(new_york.hour(), 19);
+ /// assert_eq!(los_angeles.hour(), 16);
+ /// ```
+ ///
+ /// # Panics
+ ///
+ /// This method panics if the local date-time in the new offset is outside the supported range.
+ pub const fn to_offset(self, offset: UtcOffset) -> OffsetDateTime {
+ expect_opt!(
+ self.checked_to_offset(offset),
+ "local datetime out of valid range"
+ )
+ }
+
+ /// Convert the `UtcDateTime` from UTC to the provided [`UtcOffset`], returning an
+ /// [`OffsetDateTime`]. `None` is returned if the date-time in the resulting offset is
+ /// invalid.
+ ///
+ /// ```rust
+ /// # use time::UtcDateTime;
+ /// # use time_macros::{utc_datetime, offset};
+ /// assert_eq!(
+ /// utc_datetime!(2000-01-01 0:00)
+ /// .checked_to_offset(offset!(-1))
+ /// .unwrap()
+ /// .year(),
+ /// 1999,
+ /// );
+ /// assert_eq!(
+ /// UtcDateTime::MAX.checked_to_offset(offset!(+1)),
+ /// None,
+ /// );
+ /// ```
+ pub const fn checked_to_offset(self, offset: UtcOffset) -> Option<OffsetDateTime> {
+ // Fast path for when no conversion is necessary.
+ if offset.is_utc() {
+ return Some(self.inner.assume_utc());
+ }
+
+ let (year, ordinal, time) = self.to_offset_raw(offset);
+
+ if year > MAX_YEAR || year < MIN_YEAR {
+ return None;
+ }
+
+ Some(OffsetDateTime::new_in_offset(
+ // Safety: `ordinal` is not zero.
+ unsafe { Date::__from_ordinal_date_unchecked(year, ordinal) },
+ time,
+ offset,
+ ))
+ }
+
+ /// Equivalent to `.to_offset(UtcOffset::UTC)`, but returning the year, ordinal, and time. This
+ /// avoids constructing an invalid [`Date`] if the new value is out of range.
+ pub(crate) const fn to_offset_raw(self, offset: UtcOffset) -> (i32, u16, Time) {
+ let mut second = self.second() as i16 + offset.seconds_past_minute() as i16;
+ let mut minute = self.minute() as i16 + offset.minutes_past_hour() as i16;
+ let mut hour = self.hour() as i8 + offset.whole_hours();
+ let (mut year, ordinal) = self.to_ordinal_date();
+ let mut ordinal = ordinal as i16;
+
+ cascade!(second in 0..Second::per(Minute) as i16 => minute);
+ cascade!(minute in 0..Minute::per(Hour) as i16 => hour);
+ cascade!(hour in 0..Hour::per(Day) as i8 => ordinal);
+ cascade!(ordinal => year);
+
+ debug_assert!(ordinal > 0);
+ debug_assert!(ordinal <= util::days_in_year(year) as i16);
+
+ (
+ year,
+ ordinal as u16,
+ // Safety: The cascades above ensure the values are in range.
+ unsafe {
+ Time::__from_hms_nanos_unchecked(
+ hour as u8,
+ minute as u8,
+ second as u8,
+ self.nanosecond(),
+ )
+ },
+ )
+ }
+
+ /// Get the [Unix timestamp](https://en.wikipedia.org/wiki/Unix_time).
+ ///
+ /// ```rust
+ /// # use time_macros::utc_datetime;
+ /// assert_eq!(utc_datetime!(1970-01-01 0:00).unix_timestamp(), 0);
+ /// assert_eq!(utc_datetime!(1970-01-01 1:00).unix_timestamp(), 3_600);
+ /// ```
+ pub const fn unix_timestamp(self) -> i64 {
+ let days =
+ (self.to_julian_day() as i64 - UNIX_EPOCH_JULIAN_DAY as i64) * Second::per(Day) as i64;
+ let hours = self.hour() as i64 * Second::per(Hour) as i64;
+ let minutes = self.minute() as i64 * Second::per(Minute) as i64;
+ let seconds = self.second() as i64;
+ days + hours + minutes + seconds
+ }
+
+ /// Get the Unix timestamp in nanoseconds.
+ ///
+ /// ```rust
+ /// use time_macros::utc_datetime;
+ /// assert_eq!(utc_datetime!(1970-01-01 0:00).unix_timestamp_nanos(), 0);
+ /// assert_eq!(
+ /// utc_datetime!(1970-01-01 1:00).unix_timestamp_nanos(),
+ /// 3_600_000_000_000,
+ /// );
+ /// ```
+ pub const fn unix_timestamp_nanos(self) -> i128 {
+ self.unix_timestamp() as i128 * Nanosecond::per(Second) as i128 + self.nanosecond() as i128
+ }
+
+ /// Get the [`Date`] component of the `UtcDateTime`.
+ ///
+ /// ```rust
+ /// # use time_macros::{date, utc_datetime};
+ /// assert_eq!(utc_datetime!(2019-01-01 0:00).date(), date!(2019-01-01));
+ /// ```
+ pub const fn date(self) -> Date {
+ self.inner.date()
+ }
+
+ /// Get the [`Time`] component of the `UtcDateTime`.
+ ///
+ /// ```rust
+ /// # use time_macros::{utc_datetime, time};
+ /// assert_eq!(utc_datetime!(2019-01-01 0:00).time(), time!(0:00));
+ /// ```
+ pub const fn time(self) -> Time {
+ self.inner.time()
+ }
+
+ /// Get the year of the date.
+ ///
+ /// ```rust
+ /// # use time_macros::utc_datetime;
+ /// assert_eq!(utc_datetime!(2019-01-01 0:00).year(), 2019);
+ /// assert_eq!(utc_datetime!(2019-12-31 0:00).year(), 2019);
+ /// assert_eq!(utc_datetime!(2020-01-01 0:00).year(), 2020);
+ /// ```
+ pub const fn year(self) -> i32 {
+ self.date().year()
+ }
+
+ /// Get the month of the date.
+ ///
+ /// ```rust
+ /// # use time::Month;
+ /// # use time_macros::utc_datetime;
+ /// assert_eq!(utc_datetime!(2019-01-01 0:00).month(), Month::January);
+ /// assert_eq!(utc_datetime!(2019-12-31 0:00).month(), Month::December);
+ /// ```
+ pub const fn month(self) -> Month {
+ self.date().month()
+ }
+
+ /// Get the day of the date.
+ ///
+ /// The returned value will always be in the range `1..=31`.
+ ///
+ /// ```rust
+ /// # use time_macros::utc_datetime;
+ /// assert_eq!(utc_datetime!(2019-01-01 0:00).day(), 1);
+ /// assert_eq!(utc_datetime!(2019-12-31 0:00).day(), 31);
+ /// ```
+ pub const fn day(self) -> u8 {
+ self.date().day()
+ }
+
+ /// Get the day of the year.
+ ///
+ /// The returned value will always be in the range `1..=366` (`1..=365` for common years).
+ ///
+ /// ```rust
+ /// # use time_macros::utc_datetime;
+ /// assert_eq!(utc_datetime!(2019-01-01 0:00).ordinal(), 1);
+ /// assert_eq!(utc_datetime!(2019-12-31 0:00).ordinal(), 365);
+ /// ```
+ pub const fn ordinal(self) -> u16 {
+ self.date().ordinal()
+ }
+
+ /// Get the ISO week number.
+ ///
+ /// The returned value will always be in the range `1..=53`.
+ ///
+ /// ```rust
+ /// # use time_macros::utc_datetime;
+ /// assert_eq!(utc_datetime!(2019-01-01 0:00).iso_week(), 1);
+ /// assert_eq!(utc_datetime!(2019-10-04 0:00).iso_week(), 40);
+ /// assert_eq!(utc_datetime!(2020-01-01 0:00).iso_week(), 1);
+ /// assert_eq!(utc_datetime!(2020-12-31 0:00).iso_week(), 53);
+ /// assert_eq!(utc_datetime!(2021-01-01 0:00).iso_week(), 53);
+ /// ```
+ pub const fn iso_week(self) -> u8 {
+ self.date().iso_week()
+ }
+
+ /// Get the week number where week 1 begins on the first Sunday.
+ ///
+ /// The returned value will always be in the range `0..=53`.
+ ///
+ /// ```rust
+ /// # use time_macros::utc_datetime;
+ /// assert_eq!(utc_datetime!(2019-01-01 0:00).sunday_based_week(), 0);
+ /// assert_eq!(utc_datetime!(2020-01-01 0:00).sunday_based_week(), 0);
+ /// assert_eq!(utc_datetime!(2020-12-31 0:00).sunday_based_week(), 52);
+ /// assert_eq!(utc_datetime!(2021-01-01 0:00).sunday_based_week(), 0);
+ /// ```
+ pub const fn sunday_based_week(self) -> u8 {
+ self.date().sunday_based_week()
+ }
+
+ /// Get the week number where week 1 begins on the first Monday.
+ ///
+ /// The returned value will always be in the range `0..=53`.
+ ///
+ /// ```rust
+ /// # use time_macros::utc_datetime;
+ /// assert_eq!(utc_datetime!(2019-01-01 0:00).monday_based_week(), 0);
+ /// assert_eq!(utc_datetime!(2020-01-01 0:00).monday_based_week(), 0);
+ /// assert_eq!(utc_datetime!(2020-12-31 0:00).monday_based_week(), 52);
+ /// assert_eq!(utc_datetime!(2021-01-01 0:00).monday_based_week(), 0);
+ /// ```
+ pub const fn monday_based_week(self) -> u8 {
+ self.date().monday_based_week()
+ }
+
+ /// Get the year, month, and day.
+ ///
+ /// ```rust
+ /// # use time::Month;
+ /// # use time_macros::utc_datetime;
+ /// assert_eq!(
+ /// utc_datetime!(2019-01-01 0:00).to_calendar_date(),
+ /// (2019, Month::January, 1)
+ /// );
+ /// ```
+ pub const fn to_calendar_date(self) -> (i32, Month, u8) {
+ self.date().to_calendar_date()
+ }
+
+ /// Get the year and ordinal day number.
+ ///
+ /// ```rust
+ /// # use time_macros::utc_datetime;
+ /// assert_eq!(utc_datetime!(2019-01-01 0:00).to_ordinal_date(), (2019, 1));
+ /// ```
+ pub const fn to_ordinal_date(self) -> (i32, u16) {
+ self.date().to_ordinal_date()
+ }
+
+ /// Get the ISO 8601 year, week number, and weekday.
+ ///
+ /// ```rust
+ /// # use time::Weekday::*;
+ /// # use time_macros::utc_datetime;
+ /// assert_eq!(
+ /// utc_datetime!(2019-01-01 0:00).to_iso_week_date(),
+ /// (2019, 1, Tuesday)
+ /// );
+ /// assert_eq!(
+ /// utc_datetime!(2019-10-04 0:00).to_iso_week_date(),
+ /// (2019, 40, Friday)
+ /// );
+ /// assert_eq!(
+ /// utc_datetime!(2020-01-01 0:00).to_iso_week_date(),
+ /// (2020, 1, Wednesday)
+ /// );
+ /// assert_eq!(
+ /// utc_datetime!(2020-12-31 0:00).to_iso_week_date(),
+ /// (2020, 53, Thursday)
+ /// );
+ /// assert_eq!(
+ /// utc_datetime!(2021-01-01 0:00).to_iso_week_date(),
+ /// (2020, 53, Friday)
+ /// );
+ /// ```
+ pub const fn to_iso_week_date(self) -> (i32, u8, Weekday) {
+ self.date().to_iso_week_date()
+ }
+
+ /// Get the weekday.
+ ///
+ /// ```rust
+ /// # use time::Weekday::*;
+ /// # use time_macros::utc_datetime;
+ /// assert_eq!(utc_datetime!(2019-01-01 0:00).weekday(), Tuesday);
+ /// assert_eq!(utc_datetime!(2019-02-01 0:00).weekday(), Friday);
+ /// assert_eq!(utc_datetime!(2019-03-01 0:00).weekday(), Friday);
+ /// assert_eq!(utc_datetime!(2019-04-01 0:00).weekday(), Monday);
+ /// assert_eq!(utc_datetime!(2019-05-01 0:00).weekday(), Wednesday);
+ /// assert_eq!(utc_datetime!(2019-06-01 0:00).weekday(), Saturday);
+ /// assert_eq!(utc_datetime!(2019-07-01 0:00).weekday(), Monday);
+ /// assert_eq!(utc_datetime!(2019-08-01 0:00).weekday(), Thursday);
+ /// assert_eq!(utc_datetime!(2019-09-01 0:00).weekday(), Sunday);
+ /// assert_eq!(utc_datetime!(2019-10-01 0:00).weekday(), Tuesday);
+ /// assert_eq!(utc_datetime!(2019-11-01 0:00).weekday(), Friday);
+ /// assert_eq!(utc_datetime!(2019-12-01 0:00).weekday(), Sunday);
+ /// ```
+ pub const fn weekday(self) -> Weekday {
+ self.date().weekday()
+ }
+
+ /// Get the Julian day for the date. The time is not taken into account for this calculation.
+ ///
+ /// The algorithm to perform this conversion is derived from one provided by Peter Baum; it is
+ /// freely available [here](https://www.researchgate.net/publication/316558298_Date_Algorithms).
+ ///
+ /// ```rust
+ /// # use time_macros::utc_datetime;
+ /// assert_eq!(utc_datetime!(-4713-11-24 0:00).to_julian_day(), 0);
+ /// assert_eq!(utc_datetime!(2000-01-01 0:00).to_julian_day(), 2_451_545);
+ /// assert_eq!(utc_datetime!(2019-01-01 0:00).to_julian_day(), 2_458_485);
+ /// assert_eq!(utc_datetime!(2019-12-31 0:00).to_julian_day(), 2_458_849);
+ /// ```
+ pub const fn to_julian_day(self) -> i32 {
+ self.date().to_julian_day()
+ }
+
+ /// Get the clock hour, minute, and second.
+ ///
+ /// ```rust
+ /// # use time_macros::utc_datetime;
+ /// assert_eq!(utc_datetime!(2020-01-01 0:00:00).as_hms(), (0, 0, 0));
+ /// assert_eq!(utc_datetime!(2020-01-01 23:59:59).as_hms(), (23, 59, 59));
+ /// ```
+ pub const fn as_hms(self) -> (u8, u8, u8) {
+ self.time().as_hms()
+ }
+
+ /// Get the clock hour, minute, second, and millisecond.
+ ///
+ /// ```rust
+ /// # use time_macros::utc_datetime;
+ /// assert_eq!(utc_datetime!(2020-01-01 0:00:00).as_hms_milli(), (0, 0, 0, 0));
+ /// assert_eq!(
+ /// utc_datetime!(2020-01-01 23:59:59.999).as_hms_milli(),
+ /// (23, 59, 59, 999)
+ /// );
+ /// ```
+ pub const fn as_hms_milli(self) -> (u8, u8, u8, u16) {
+ self.time().as_hms_milli()
+ }
+
+ /// Get the clock hour, minute, second, and microsecond.
+ ///
+ /// ```rust
+ /// # use time_macros::utc_datetime;
+ /// assert_eq!(utc_datetime!(2020-01-01 0:00:00).as_hms_micro(), (0, 0, 0, 0));
+ /// assert_eq!(
+ /// utc_datetime!(2020-01-01 23:59:59.999_999).as_hms_micro(),
+ /// (23, 59, 59, 999_999)
+ /// );
+ /// ```
+ pub const fn as_hms_micro(self) -> (u8, u8, u8, u32) {
+ self.time().as_hms_micro()
+ }
+
+ /// Get the clock hour, minute, second, and nanosecond.
+ ///
+ /// ```rust
+ /// # use time_macros::utc_datetime;
+ /// assert_eq!(utc_datetime!(2020-01-01 0:00:00).as_hms_nano(), (0, 0, 0, 0));
+ /// assert_eq!(
+ /// utc_datetime!(2020-01-01 23:59:59.999_999_999).as_hms_nano(),
+ /// (23, 59, 59, 999_999_999)
+ /// );
+ /// ```
+ pub const fn as_hms_nano(self) -> (u8, u8, u8, u32) {
+ self.time().as_hms_nano()
+ }
+
+ /// Get the clock hour.
+ ///
+ /// The returned value will always be in the range `0..24`.
+ ///
+ /// ```rust
+ /// # use time_macros::utc_datetime;
+ /// assert_eq!(utc_datetime!(2019-01-01 0:00).hour(), 0);
+ /// assert_eq!(utc_datetime!(2019-01-01 23:59:59).hour(), 23);
+ /// ```
+ pub const fn hour(self) -> u8 {
+ self.time().hour()
+ }
+
+ /// Get the minute within the hour.
+ ///
+ /// The returned value will always be in the range `0..60`.
+ ///
+ /// ```rust
+ /// # use time_macros::utc_datetime;
+ /// assert_eq!(utc_datetime!(2019-01-01 0:00).minute(), 0);
+ /// assert_eq!(utc_datetime!(2019-01-01 23:59:59).minute(), 59);
+ /// ```
+ pub const fn minute(self) -> u8 {
+ self.time().minute()
+ }
+
+ /// Get the second within the minute.
+ ///
+ /// The returned value will always be in the range `0..60`.
+ ///
+ /// ```rust
+ /// # use time_macros::utc_datetime;
+ /// assert_eq!(utc_datetime!(2019-01-01 0:00).second(), 0);
+ /// assert_eq!(utc_datetime!(2019-01-01 23:59:59).second(), 59);
+ /// ```
+ pub const fn second(self) -> u8 {
+ self.time().second()
+ }
+
+ /// Get the milliseconds within the second.
+ ///
+ /// The returned value will always be in the range `0..1_000`.
+ ///
+ /// ```rust
+ /// # use time_macros::utc_datetime;
+ /// assert_eq!(utc_datetime!(2019-01-01 0:00).millisecond(), 0);
+ /// assert_eq!(utc_datetime!(2019-01-01 23:59:59.999).millisecond(), 999);
+ /// ```
+ pub const fn millisecond(self) -> u16 {
+ self.time().millisecond()
+ }
+
+ /// Get the microseconds within the second.
+ ///
+ /// The returned value will always be in the range `0..1_000_000`.
+ ///
+ /// ```rust
+ /// # use time_macros::utc_datetime;
+ /// assert_eq!(utc_datetime!(2019-01-01 0:00).microsecond(), 0);
+ /// assert_eq!(
+ /// utc_datetime!(2019-01-01 23:59:59.999_999).microsecond(),
+ /// 999_999
+ /// );
+ /// ```
+ pub const fn microsecond(self) -> u32 {
+ self.time().microsecond()
+ }
+
+ /// Get the nanoseconds within the second.
+ ///
+ /// The returned value will always be in the range `0..1_000_000_000`.
+ ///
+ /// ```rust
+ /// # use time_macros::utc_datetime;
+ /// assert_eq!(utc_datetime!(2019-01-01 0:00).nanosecond(), 0);
+ /// assert_eq!(
+ /// utc_datetime!(2019-01-01 23:59:59.999_999_999).nanosecond(),
+ /// 999_999_999,
+ /// );
+ /// ```
+ pub const fn nanosecond(self) -> u32 {
+ self.time().nanosecond()
+ }
+
+ /// Computes `self + duration`, returning `None` if an overflow occurred.
+ ///
+ /// ```rust
+ /// # use time::{UtcDateTime, ext::NumericalDuration};
+ /// # use time_macros::utc_datetime;
+ /// assert_eq!(UtcDateTime::MIN.checked_add((-2).days()), None);
+ /// assert_eq!(UtcDateTime::MAX.checked_add(1.days()), None);
+ /// assert_eq!(
+ /// utc_datetime!(2019 - 11 - 25 15:30).checked_add(27.hours()),
+ /// Some(utc_datetime!(2019 - 11 - 26 18:30))
+ /// );
+ /// ```
+ pub const fn checked_add(self, duration: Duration) -> Option<Self> {
+ Some(Self::from_primitive(const_try_opt!(self
+ .inner
+ .checked_add(duration))))
+ }
+
+ /// Computes `self - duration`, returning `None` if an overflow occurred.
+ ///
+ /// ```rust
+ /// # use time::{UtcDateTime, ext::NumericalDuration};
+ /// # use time_macros::utc_datetime;
+ /// assert_eq!(UtcDateTime::MIN.checked_sub(2.days()), None);
+ /// assert_eq!(UtcDateTime::MAX.checked_sub((-1).days()), None);
+ /// assert_eq!(
+ /// utc_datetime!(2019 - 11 - 25 15:30).checked_sub(27.hours()),
+ /// Some(utc_datetime!(2019 - 11 - 24 12:30))
+ /// );
+ /// ```
+ pub const fn checked_sub(self, duration: Duration) -> Option<Self> {
+ Some(Self::from_primitive(const_try_opt!(self
+ .inner
+ .checked_sub(duration))))
+ }
+
+ /// Computes `self + duration`, saturating value on overflow.
+ ///
+ /// ```rust
+ /// # use time::{UtcDateTime, ext::NumericalDuration};
+ /// # use time_macros::utc_datetime;
+ /// assert_eq!(
+ /// UtcDateTime::MIN.saturating_add((-2).days()),
+ /// UtcDateTime::MIN
+ /// );
+ /// assert_eq!(
+ /// UtcDateTime::MAX.saturating_add(2.days()),
+ /// UtcDateTime::MAX
+ /// );
+ /// assert_eq!(
+ /// utc_datetime!(2019 - 11 - 25 15:30).saturating_add(27.hours()),
+ /// utc_datetime!(2019 - 11 - 26 18:30)
+ /// );
+ /// ```
+ pub const fn saturating_add(self, duration: Duration) -> Self {
+ Self::from_primitive(self.inner.saturating_add(duration))
+ }
+
+ /// Computes `self - duration`, saturating value on overflow.
+ ///
+ /// ```rust
+ /// # use time::{UtcDateTime, ext::NumericalDuration};
+ /// # use time_macros::utc_datetime;
+ /// assert_eq!(
+ /// UtcDateTime::MIN.saturating_sub(2.days()),
+ /// UtcDateTime::MIN
+ /// );
+ /// assert_eq!(
+ /// UtcDateTime::MAX.saturating_sub((-2).days()),
+ /// UtcDateTime::MAX
+ /// );
+ /// assert_eq!(
+ /// utc_datetime!(2019 - 11 - 25 15:30).saturating_sub(27.hours()),
+ /// utc_datetime!(2019 - 11 - 24 12:30)
+ /// );
+ /// ```
+ pub const fn saturating_sub(self, duration: Duration) -> Self {
+ Self::from_primitive(self.inner.saturating_sub(duration))
+ }
+}
+
+/// Methods that replace part of the `UtcDateTime`.
+impl UtcDateTime {
+ /// Replace the time, preserving the date.
+ ///
+ /// ```rust
+ /// # use time_macros::{utc_datetime, time};
+ /// assert_eq!(
+ /// utc_datetime!(2020-01-01 17:00).replace_time(time!(5:00)),
+ /// utc_datetime!(2020-01-01 5:00)
+ /// );
+ /// ```
+ #[must_use = "This method does not mutate the original `UtcDateTime`."]
+ pub const fn replace_time(self, time: Time) -> Self {
+ Self::from_primitive(self.inner.replace_time(time))
+ }
+
+ /// Replace the date, preserving the time.
+ ///
+ /// ```rust
+ /// # use time_macros::{utc_datetime, date};
+ /// assert_eq!(
+ /// utc_datetime!(2020-01-01 12:00).replace_date(date!(2020-01-30)),
+ /// utc_datetime!(2020-01-30 12:00)
+ /// );
+ /// ```
+ #[must_use = "This method does not mutate the original `UtcDateTime`."]
+ pub const fn replace_date(self, date: Date) -> Self {
+ Self::from_primitive(self.inner.replace_date(date))
+ }
+
+ /// Replace the year. The month and day will be unchanged.
+ ///
+ /// ```rust
+ /// # use time_macros::utc_datetime;
+ /// assert_eq!(
+ /// utc_datetime!(2022 - 02 - 18 12:00).replace_year(2019),
+ /// Ok(utc_datetime!(2019 - 02 - 18 12:00))
+ /// );
+ /// assert!(utc_datetime!(2022 - 02 - 18 12:00).replace_year(-1_000_000_000).is_err()); // -1_000_000_000 isn't a valid year
+ /// assert!(utc_datetime!(2022 - 02 - 18 12:00).replace_year(1_000_000_000).is_err()); // 1_000_000_000 isn't a valid year
+ /// ```
+ #[must_use = "This method does not mutate the original `UtcDateTime`."]
+ pub const fn replace_year(self, year: i32) -> Result<Self, error::ComponentRange> {
+ Ok(Self::from_primitive(const_try!(self
+ .inner
+ .replace_year(year))))
+ }
+
+ /// Replace the month of the year.
+ ///
+ /// ```rust
+ /// # use time_macros::utc_datetime;
+ /// # use time::Month;
+ /// assert_eq!(
+ /// utc_datetime!(2022 - 02 - 18 12:00).replace_month(Month::January),
+ /// Ok(utc_datetime!(2022 - 01 - 18 12:00))
+ /// );
+ /// assert!(utc_datetime!(2022 - 01 - 30 12:00).replace_month(Month::February).is_err()); // 30 isn't a valid day in February
+ /// ```
+ #[must_use = "This method does not mutate the original `UtcDateTime`."]
+ pub const fn replace_month(self, month: Month) -> Result<Self, error::ComponentRange> {
+ Ok(Self::from_primitive(const_try!(self
+ .inner
+ .replace_month(month))))
+ }
+
+ /// Replace the day of the month.
+ ///
+ /// ```rust
+ /// # use time_macros::utc_datetime;
+ /// assert_eq!(
+ /// utc_datetime!(2022 - 02 - 18 12:00).replace_day(1),
+ /// Ok(utc_datetime!(2022 - 02 - 01 12:00))
+ /// );
+ /// assert!(utc_datetime!(2022 - 02 - 18 12:00).replace_day(0).is_err()); // 00 isn't a valid day
+ /// assert!(utc_datetime!(2022 - 02 - 18 12:00).replace_day(30).is_err()); // 30 isn't a valid day in February
+ /// ```
+ #[must_use = "This method does not mutate the original `UtcDateTime`."]
+ pub const fn replace_day(self, day: u8) -> Result<Self, error::ComponentRange> {
+ Ok(Self::from_primitive(const_try!(self
+ .inner
+ .replace_day(day))))
+ }
+
+ /// Replace the day of the year.
+ ///
+ /// ```rust
+ /// # use time_macros::utc_datetime;
+ /// assert_eq!(utc_datetime!(2022-049 12:00).replace_ordinal(1), Ok(utc_datetime!(2022-001 12:00)));
+ /// assert!(utc_datetime!(2022-049 12:00).replace_ordinal(0).is_err()); // 0 isn't a valid ordinal
+ /// assert!(utc_datetime!(2022-049 12:00).replace_ordinal(366).is_err()); // 2022 isn't a leap year
+ /// ```
+ #[must_use = "This method does not mutate the original `UtcDateTime`."]
+ pub const fn replace_ordinal(self, ordinal: u16) -> Result<Self, error::ComponentRange> {
+ Ok(Self::from_primitive(const_try!(self
+ .inner
+ .replace_ordinal(ordinal))))
+ }
+
+ /// Replace the clock hour.
+ ///
+ /// ```rust
+ /// # use time_macros::utc_datetime;
+ /// assert_eq!(
+ /// utc_datetime!(2022 - 02 - 18 01:02:03.004_005_006).replace_hour(7),
+ /// Ok(utc_datetime!(2022 - 02 - 18 07:02:03.004_005_006))
+ /// );
+ /// assert!(utc_datetime!(2022 - 02 - 18 01:02:03.004_005_006).replace_hour(24).is_err()); // 24 isn't a valid hour
+ /// ```
+ #[must_use = "This method does not mutate the original `UtcDateTime`."]
+ pub const fn replace_hour(self, hour: u8) -> Result<Self, error::ComponentRange> {
+ Ok(Self::from_primitive(const_try!(self
+ .inner
+ .replace_hour(hour))))
+ }
+
+ /// Replace the minutes within the hour.
+ ///
+ /// ```rust
+ /// # use time_macros::utc_datetime;
+ /// assert_eq!(
+ /// utc_datetime!(2022 - 02 - 18 01:02:03.004_005_006).replace_minute(7),
+ /// Ok(utc_datetime!(2022 - 02 - 18 01:07:03.004_005_006))
+ /// );
+ /// assert!(utc_datetime!(2022 - 02 - 18 01:02:03.004_005_006).replace_minute(60).is_err()); // 60 isn't a valid minute
+ /// ```
+ #[must_use = "This method does not mutate the original `UtcDateTime`."]
+ pub const fn replace_minute(
+ self,
+ sunday_based_week: u8,
+ ) -> Result<Self, error::ComponentRange> {
+ Ok(Self::from_primitive(const_try!(self
+ .inner
+ .replace_minute(sunday_based_week))))
+ }
+
+ /// Replace the seconds within the minute.
+ ///
+ /// ```rust
+ /// # use time_macros::utc_datetime;
+ /// assert_eq!(
+ /// utc_datetime!(2022 - 02 - 18 01:02:03.004_005_006).replace_second(7),
+ /// Ok(utc_datetime!(2022 - 02 - 18 01:02:07.004_005_006))
+ /// );
+ /// assert!(utc_datetime!(2022 - 02 - 18 01:02:03.004_005_006).replace_second(60).is_err()); // 60 isn't a valid second
+ /// ```
+ #[must_use = "This method does not mutate the original `UtcDateTime`."]
+ pub const fn replace_second(
+ self,
+ monday_based_week: u8,
+ ) -> Result<Self, error::ComponentRange> {
+ Ok(Self::from_primitive(const_try!(self
+ .inner
+ .replace_second(monday_based_week))))
+ }
+
+ /// Replace the milliseconds within the second.
+ ///
+ /// ```rust
+ /// # use time_macros::utc_datetime;
+ /// assert_eq!(
+ /// utc_datetime!(2022 - 02 - 18 01:02:03.004_005_006).replace_millisecond(7),
+ /// Ok(utc_datetime!(2022 - 02 - 18 01:02:03.007))
+ /// );
+ /// assert!(utc_datetime!(2022 - 02 - 18 01:02:03.004_005_006).replace_millisecond(1_000).is_err()); // 1_000 isn't a valid millisecond
+ /// ```
+ #[must_use = "This method does not mutate the original `UtcDateTime`."]
+ pub const fn replace_millisecond(
+ self,
+ millisecond: u16,
+ ) -> Result<Self, error::ComponentRange> {
+ Ok(Self::from_primitive(const_try!(self
+ .inner
+ .replace_millisecond(millisecond))))
+ }
+
+ /// Replace the microseconds within the second.
+ ///
+ /// ```rust
+ /// # use time_macros::utc_datetime;
+ /// assert_eq!(
+ /// utc_datetime!(2022 - 02 - 18 01:02:03.004_005_006).replace_microsecond(7_008),
+ /// Ok(utc_datetime!(2022 - 02 - 18 01:02:03.007_008))
+ /// );
+ /// assert!(utc_datetime!(2022 - 02 - 18 01:02:03.004_005_006).replace_microsecond(1_000_000).is_err()); // 1_000_000 isn't a valid microsecond
+ /// ```
+ #[must_use = "This method does not mutate the original `UtcDateTime`."]
+ pub const fn replace_microsecond(
+ self,
+ microsecond: u32,
+ ) -> Result<Self, error::ComponentRange> {
+ Ok(Self::from_primitive(const_try!(self
+ .inner
+ .replace_microsecond(microsecond))))
+ }
+
+ /// Replace the nanoseconds within the second.
+ ///
+ /// ```rust
+ /// # use time_macros::utc_datetime;
+ /// assert_eq!(
+ /// utc_datetime!(2022 - 02 - 18 01:02:03.004_005_006).replace_nanosecond(7_008_009),
+ /// Ok(utc_datetime!(2022 - 02 - 18 01:02:03.007_008_009))
+ /// );
+ /// assert!(utc_datetime!(2022 - 02 - 18 01:02:03.004_005_006).replace_nanosecond(1_000_000_000).is_err()); // 1_000_000_000 isn't a valid nanosecond
+ /// ```
+ #[must_use = "This method does not mutate the original `UtcDateTime`."]
+ pub const fn replace_nanosecond(self, nanosecond: u32) -> Result<Self, error::ComponentRange> {
+ Ok(Self::from_primitive(const_try!(self
+ .inner
+ .replace_nanosecond(nanosecond))))
+ }
+}
+
+#[cfg(feature = "formatting")]
+impl UtcDateTime {
+ /// Format the `UtcDateTime` using the provided [format
+ /// description](crate::format_description).
+ pub fn format_into(
+ self,
+ output: &mut (impl io::Write + ?Sized),
+ format: &(impl Formattable + ?Sized),
+ ) -> Result<usize, error::Format> {
+ format.format_into(
+ output,
+ Some(self.date()),
+ Some(self.time()),
+ Some(UtcOffset::UTC),
+ )
+ }
+
+ /// Format the `UtcDateTime` using the provided [format
+ /// description](crate::format_description).
+ ///
+ /// ```rust
+ /// # use time::format_description;
+ /// # use time_macros::utc_datetime;
+ /// let format = format_description::parse(
+ /// "[year]-[month]-[day] [hour]:[minute]:[second] [offset_hour \
+ /// sign:mandatory]:[offset_minute]:[offset_second]",
+ /// )?;
+ /// assert_eq!(
+ /// utc_datetime!(2020-01-02 03:04:05).format(&format)?,
+ /// "2020-01-02 03:04:05 +00:00:00"
+ /// );
+ /// # Ok::<_, time::Error>(())
+ /// ```
+ pub fn format(self, format: &(impl Formattable + ?Sized)) -> Result<String, error::Format> {
+ format.format(Some(self.date()), Some(self.time()), Some(UtcOffset::UTC))
+ }
+}
+
+#[cfg(feature = "parsing")]
+impl UtcDateTime {
+ /// Parse an `UtcDateTime` from the input using the provided [format
+ /// description](crate::format_description). A [`UtcOffset`] is permitted, but not required to
+ /// be present. If present, the value will be converted to UTC.
+ ///
+ /// ```rust
+ /// # use time::UtcDateTime;
+ /// # use time_macros::{utc_datetime, format_description};
+ /// let format = format_description!("[year]-[month]-[day] [hour]:[minute]:[second]");
+ /// assert_eq!(
+ /// UtcDateTime::parse("2020-01-02 03:04:05", &format)?,
+ /// utc_datetime!(2020-01-02 03:04:05)
+ /// );
+ /// # Ok::<_, time::Error>(())
+ /// ```
+ pub fn parse(
+ input: &str,
+ description: &(impl Parsable + ?Sized),
+ ) -> Result<Self, error::Parse> {
+ description.parse_utc_date_time(input.as_bytes())
+ }
+
+ /// A helper method to check if the `UtcDateTime` is a valid representation of a leap second.
+ /// Leap seconds, when parsed, are represented as the preceding nanosecond. However, leap
+ /// seconds can only occur as the last second of a month UTC.
+ #[cfg(feature = "parsing")]
+ pub(crate) const fn is_valid_leap_second_stand_in(self) -> bool {
+ let dt = self.inner;
+
+ dt.hour() == 23
+ && dt.minute() == 59
+ && dt.second() == 59
+ && dt.nanosecond() == 999_999_999
+ && dt.day() == dt.month().length(dt.year())
+ }
+}
+
+impl SmartDisplay for UtcDateTime {
+ type Metadata = ();
+
+ fn metadata(&self, _: FormatterOptions) -> Metadata<Self> {
+ let width = smart_display::padded_width_of!(self.date(), " ", self.time(), " +00");
+ Metadata::new(width, self, ())
+ }
+
+ fn fmt_with_metadata(
+ &self,
+ f: &mut fmt::Formatter<'_>,
+ metadata: Metadata<Self>,
+ ) -> fmt::Result {
+ f.pad_with_width(
+ metadata.unpadded_width(),
+ format_args!("{} {} +00", self.date(), self.time()),
+ )
+ }
+}
+
+impl fmt::Display for UtcDateTime {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ SmartDisplay::fmt(self, f)
+ }
+}
+
+impl fmt::Debug for UtcDateTime {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt::Display::fmt(self, f)
+ }
+}
+
+impl Add<Duration> for UtcDateTime {
+ type Output = Self;
+
+ /// # Panics
+ ///
+ /// This may panic if an overflow occurs.
+ fn add(self, duration: Duration) -> Self::Output {
+ self.inner.add(duration).as_utc()
+ }
+}
+
+impl Add<StdDuration> for UtcDateTime {
+ type Output = Self;
+
+ /// # Panics
+ ///
+ /// This may panic if an overflow occurs.
+ fn add(self, duration: StdDuration) -> Self::Output {
+ self.inner.add(duration).as_utc()
+ }
+}
+
+impl AddAssign<Duration> for UtcDateTime {
+ /// # Panics
+ ///
+ /// This may panic if an overflow occurs.
+ fn add_assign(&mut self, rhs: Duration) {
+ self.inner.add_assign(rhs);
+ }
+}
+
+impl AddAssign<StdDuration> for UtcDateTime {
+ /// # Panics
+ ///
+ /// This may panic if an overflow occurs.
+ fn add_assign(&mut self, rhs: StdDuration) {
+ self.inner.add_assign(rhs);
+ }
+}
+
+impl Sub<Duration> for UtcDateTime {
+ type Output = Self;
+
+ /// # Panics
+ ///
+ /// This may panic if an overflow occurs.
+ fn sub(self, rhs: Duration) -> Self::Output {
+ self.checked_sub(rhs)
+ .expect("resulting value is out of range")
+ }
+}
+
+impl Sub<StdDuration> for UtcDateTime {
+ type Output = Self;
+
+ /// # Panics
+ ///
+ /// This may panic if an overflow occurs.
+ fn sub(self, duration: StdDuration) -> Self::Output {
+ Self::from_primitive(self.inner.sub(duration))
+ }
+}
+
+impl SubAssign<Duration> for UtcDateTime {
+ /// # Panics
+ ///
+ /// This may panic if an overflow occurs.
+ fn sub_assign(&mut self, rhs: Duration) {
+ self.inner.sub_assign(rhs);
+ }
+}
+
+impl SubAssign<StdDuration> for UtcDateTime {
+ /// # Panics
+ ///
+ /// This may panic if an overflow occurs.
+ fn sub_assign(&mut self, rhs: StdDuration) {
+ self.inner.sub_assign(rhs);
+ }
+}
+
+impl Sub for UtcDateTime {
+ type Output = Duration;
+
+ /// # Panics
+ ///
+ /// This may panic if an overflow occurs.
+ fn sub(self, rhs: Self) -> Self::Output {
+ self.inner.sub(rhs.inner)
+ }
+}
diff --git a/vendor/time/src/utc_offset.rs b/vendor/time/src/utc_offset.rs
new file mode 100644
index 00000000..73bcf2d1
--- /dev/null
+++ b/vendor/time/src/utc_offset.rs
@@ -0,0 +1,464 @@
+//! The [`UtcOffset`] struct and its associated `impl`s.
+
+#[cfg(feature = "formatting")]
+use alloc::string::String;
+use core::fmt;
+use core::ops::Neg;
+#[cfg(feature = "formatting")]
+use std::io;
+
+use deranged::{RangedI32, RangedI8};
+use powerfmt::ext::FormatterExt;
+use powerfmt::smart_display::{self, FormatterOptions, Metadata, SmartDisplay};
+
+use crate::convert::*;
+use crate::error;
+#[cfg(feature = "formatting")]
+use crate::formatting::Formattable;
+use crate::internal_macros::ensure_ranged;
+#[cfg(feature = "parsing")]
+use crate::parsing::Parsable;
+#[cfg(feature = "local-offset")]
+use crate::sys::local_offset_at;
+#[cfg(feature = "local-offset")]
+use crate::OffsetDateTime;
+
+/// The type of the `hours` field of `UtcOffset`.
+type Hours = RangedI8<-25, 25>;
+/// The type of the `minutes` field of `UtcOffset`.
+type Minutes = RangedI8<{ -(Minute::per(Hour) as i8 - 1) }, { Minute::per(Hour) as i8 - 1 }>;
+/// The type of the `seconds` field of `UtcOffset`.
+type Seconds = RangedI8<{ -(Second::per(Minute) as i8 - 1) }, { Second::per(Minute) as i8 - 1 }>;
+/// The type capable of storing the range of whole seconds that a `UtcOffset` can encompass.
+type WholeSeconds = RangedI32<
+ {
+ Hours::MIN.get() as i32 * Second::per(Hour) as i32
+ + Minutes::MIN.get() as i32 * Second::per(Minute) as i32
+ + Seconds::MIN.get() as i32
+ },
+ {
+ Hours::MAX.get() as i32 * Second::per(Hour) as i32
+ + Minutes::MAX.get() as i32 * Second::per(Minute) as i32
+ + Seconds::MAX.get() as i32
+ },
+>;
+
+/// An offset from UTC.
+///
+/// This struct can store values up to ±25:59:59. If you need support outside this range, please
+/// file an issue with your use case.
+// All three components _must_ have the same sign.
+#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
+pub struct UtcOffset {
+ hours: Hours,
+ minutes: Minutes,
+ seconds: Seconds,
+}
+
+impl UtcOffset {
+ /// A `UtcOffset` that is UTC.
+ ///
+ /// ```rust
+ /// # use time::UtcOffset;
+ /// # use time_macros::offset;
+ /// assert_eq!(UtcOffset::UTC, offset!(UTC));
+ /// ```
+ pub const UTC: Self = Self::from_whole_seconds_ranged(WholeSeconds::new_static::<0>());
+
+ /// Create a `UtcOffset` representing an offset of the hours, minutes, and seconds provided, the
+ /// validity of which must be guaranteed by the caller. All three parameters must have the same
+ /// sign.
+ ///
+ /// # Safety
+ ///
+ /// - Hours must be in the range `-25..=25`.
+ /// - Minutes must be in the range `-59..=59`.
+ /// - Seconds must be in the range `-59..=59`.
+ ///
+ /// While the signs of the parameters are required to match to avoid bugs, this is not a safety
+ /// invariant.
+ #[doc(hidden)]
+ pub const unsafe fn __from_hms_unchecked(hours: i8, minutes: i8, seconds: i8) -> Self {
+ // Safety: The caller must uphold the safety invariants.
+ unsafe {
+ Self::from_hms_ranged_unchecked(
+ Hours::new_unchecked(hours),
+ Minutes::new_unchecked(minutes),
+ Seconds::new_unchecked(seconds),
+ )
+ }
+ }
+
+ /// Create a `UtcOffset` representing an offset by the number of hours, minutes, and seconds
+ /// provided.
+ ///
+ /// The sign of all three components should match. If they do not, all smaller components will
+ /// have their signs flipped.
+ ///
+ /// ```rust
+ /// # use time::UtcOffset;
+ /// assert_eq!(UtcOffset::from_hms(1, 2, 3)?.as_hms(), (1, 2, 3));
+ /// assert_eq!(UtcOffset::from_hms(1, -2, -3)?.as_hms(), (1, 2, 3));
+ /// # Ok::<_, time::Error>(())
+ /// ```
+ pub const fn from_hms(
+ hours: i8,
+ minutes: i8,
+ seconds: i8,
+ ) -> Result<Self, error::ComponentRange> {
+ Ok(Self::from_hms_ranged(
+ ensure_ranged!(Hours: hours),
+ ensure_ranged!(Minutes: minutes),
+ ensure_ranged!(Seconds: seconds),
+ ))
+ }
+
+ /// Create a `UtcOffset` representing an offset of the hours, minutes, and seconds provided. All
+ /// three parameters must have the same sign.
+ ///
+ /// While the signs of the parameters are required to match, this is not a safety invariant.
+ pub(crate) const fn from_hms_ranged_unchecked(
+ hours: Hours,
+ minutes: Minutes,
+ seconds: Seconds,
+ ) -> Self {
+ if hours.get() < 0 {
+ debug_assert!(minutes.get() <= 0);
+ debug_assert!(seconds.get() <= 0);
+ } else if hours.get() > 0 {
+ debug_assert!(minutes.get() >= 0);
+ debug_assert!(seconds.get() >= 0);
+ }
+ if minutes.get() < 0 {
+ debug_assert!(seconds.get() <= 0);
+ } else if minutes.get() > 0 {
+ debug_assert!(seconds.get() >= 0);
+ }
+
+ Self {
+ hours,
+ minutes,
+ seconds,
+ }
+ }
+
+ /// Create a `UtcOffset` representing an offset by the number of hours, minutes, and seconds
+ /// provided.
+ ///
+ /// The sign of all three components should match. If they do not, all smaller components will
+ /// have their signs flipped.
+ pub(crate) const fn from_hms_ranged(
+ hours: Hours,
+ mut minutes: Minutes,
+ mut seconds: Seconds,
+ ) -> Self {
+ if (hours.get() > 0 && minutes.get() < 0) || (hours.get() < 0 && minutes.get() > 0) {
+ minutes = minutes.neg();
+ }
+ if (hours.get() > 0 && seconds.get() < 0)
+ || (hours.get() < 0 && seconds.get() > 0)
+ || (minutes.get() > 0 && seconds.get() < 0)
+ || (minutes.get() < 0 && seconds.get() > 0)
+ {
+ seconds = seconds.neg();
+ }
+
+ Self {
+ hours,
+ minutes,
+ seconds,
+ }
+ }
+
+ /// Create a `UtcOffset` representing an offset by the number of seconds provided.
+ ///
+ /// ```rust
+ /// # use time::UtcOffset;
+ /// assert_eq!(UtcOffset::from_whole_seconds(3_723)?.as_hms(), (1, 2, 3));
+ /// # Ok::<_, time::Error>(())
+ /// ```
+ pub const fn from_whole_seconds(seconds: i32) -> Result<Self, error::ComponentRange> {
+ Ok(Self::from_whole_seconds_ranged(
+ ensure_ranged!(WholeSeconds: seconds),
+ ))
+ }
+
+ /// Create a `UtcOffset` representing an offset by the number of seconds provided.
+ // ignore because the function is crate-private
+ /// ```rust,ignore
+ /// # use time::UtcOffset;
+ /// # use deranged::RangedI32;
+ /// assert_eq!(
+ /// UtcOffset::from_whole_seconds_ranged(RangedI32::new_static::<3_723>()).as_hms(),
+ /// (1, 2, 3)
+ /// );
+ /// # Ok::<_, time::Error>(())
+ /// ```
+ pub(crate) const fn from_whole_seconds_ranged(seconds: WholeSeconds) -> Self {
+ // Safety: The type of `seconds` guarantees that all values are in range.
+ unsafe {
+ Self::__from_hms_unchecked(
+ (seconds.get() / Second::per(Hour) as i32) as i8,
+ ((seconds.get() % Second::per(Hour) as i32) / Minute::per(Hour) as i32) as i8,
+ (seconds.get() % Second::per(Minute) as i32) as i8,
+ )
+ }
+ }
+
+ /// Obtain the UTC offset as its hours, minutes, and seconds. The sign of all three components
+ /// will always match. A positive value indicates an offset to the east; a negative to the west.
+ ///
+ /// ```rust
+ /// # use time_macros::offset;
+ /// assert_eq!(offset!(+1:02:03).as_hms(), (1, 2, 3));
+ /// assert_eq!(offset!(-1:02:03).as_hms(), (-1, -2, -3));
+ /// ```
+ pub const fn as_hms(self) -> (i8, i8, i8) {
+ (self.hours.get(), self.minutes.get(), self.seconds.get())
+ }
+
+ /// Obtain the UTC offset as its hours, minutes, and seconds. The sign of all three components
+ /// will always match. A positive value indicates an offset to the east; a negative to the west.
+ #[cfg(feature = "quickcheck")]
+ pub(crate) const fn as_hms_ranged(self) -> (Hours, Minutes, Seconds) {
+ (self.hours, self.minutes, self.seconds)
+ }
+
+ /// Obtain the number of whole hours the offset is from UTC. A positive value indicates an
+ /// offset to the east; a negative to the west.
+ ///
+ /// ```rust
+ /// # use time_macros::offset;
+ /// assert_eq!(offset!(+1:02:03).whole_hours(), 1);
+ /// assert_eq!(offset!(-1:02:03).whole_hours(), -1);
+ /// ```
+ pub const fn whole_hours(self) -> i8 {
+ self.hours.get()
+ }
+
+ /// Obtain the number of whole minutes the offset is from UTC. A positive value indicates an
+ /// offset to the east; a negative to the west.
+ ///
+ /// ```rust
+ /// # use time_macros::offset;
+ /// assert_eq!(offset!(+1:02:03).whole_minutes(), 62);
+ /// assert_eq!(offset!(-1:02:03).whole_minutes(), -62);
+ /// ```
+ pub const fn whole_minutes(self) -> i16 {
+ self.hours.get() as i16 * Minute::per(Hour) as i16 + self.minutes.get() as i16
+ }
+
+ /// Obtain the number of minutes past the hour the offset is from UTC. A positive value
+ /// indicates an offset to the east; a negative to the west.
+ ///
+ /// ```rust
+ /// # use time_macros::offset;
+ /// assert_eq!(offset!(+1:02:03).minutes_past_hour(), 2);
+ /// assert_eq!(offset!(-1:02:03).minutes_past_hour(), -2);
+ /// ```
+ pub const fn minutes_past_hour(self) -> i8 {
+ self.minutes.get()
+ }
+
+ /// Obtain the number of whole seconds the offset is from UTC. A positive value indicates an
+ /// offset to the east; a negative to the west.
+ ///
+ /// ```rust
+ /// # use time_macros::offset;
+ /// assert_eq!(offset!(+1:02:03).whole_seconds(), 3723);
+ /// assert_eq!(offset!(-1:02:03).whole_seconds(), -3723);
+ /// ```
+ // This may be useful for anyone manually implementing arithmetic, as it
+ // would let them construct a `Duration` directly.
+ pub const fn whole_seconds(self) -> i32 {
+ self.hours.get() as i32 * Second::per(Hour) as i32
+ + self.minutes.get() as i32 * Second::per(Minute) as i32
+ + self.seconds.get() as i32
+ }
+
+ /// Obtain the number of seconds past the minute the offset is from UTC. A positive value
+ /// indicates an offset to the east; a negative to the west.
+ ///
+ /// ```rust
+ /// # use time_macros::offset;
+ /// assert_eq!(offset!(+1:02:03).seconds_past_minute(), 3);
+ /// assert_eq!(offset!(-1:02:03).seconds_past_minute(), -3);
+ /// ```
+ pub const fn seconds_past_minute(self) -> i8 {
+ self.seconds.get()
+ }
+
+ /// Check if the offset is exactly UTC.
+ ///
+ ///
+ /// ```rust
+ /// # use time_macros::offset;
+ /// assert!(!offset!(+1:02:03).is_utc());
+ /// assert!(!offset!(-1:02:03).is_utc());
+ /// assert!(offset!(UTC).is_utc());
+ /// ```
+ pub const fn is_utc(self) -> bool {
+ self.hours.get() == 0 && self.minutes.get() == 0 && self.seconds.get() == 0
+ }
+
+ /// Check if the offset is positive, or east of UTC.
+ ///
+ /// ```rust
+ /// # use time_macros::offset;
+ /// assert!(offset!(+1:02:03).is_positive());
+ /// assert!(!offset!(-1:02:03).is_positive());
+ /// assert!(!offset!(UTC).is_positive());
+ /// ```
+ pub const fn is_positive(self) -> bool {
+ self.hours.get() > 0 || self.minutes.get() > 0 || self.seconds.get() > 0
+ }
+
+ /// Check if the offset is negative, or west of UTC.
+ ///
+ /// ```rust
+ /// # use time_macros::offset;
+ /// assert!(!offset!(+1:02:03).is_negative());
+ /// assert!(offset!(-1:02:03).is_negative());
+ /// assert!(!offset!(UTC).is_negative());
+ /// ```
+ pub const fn is_negative(self) -> bool {
+ self.hours.get() < 0 || self.minutes.get() < 0 || self.seconds.get() < 0
+ }
+
+ /// Attempt to obtain the system's UTC offset at a known moment in time. If the offset cannot be
+ /// determined, an error is returned.
+ ///
+ /// ```rust
+ /// # use time::{UtcOffset, OffsetDateTime};
+ /// let local_offset = UtcOffset::local_offset_at(OffsetDateTime::UNIX_EPOCH);
+ /// # if false {
+ /// assert!(local_offset.is_ok());
+ /// # }
+ /// ```
+ #[cfg(feature = "local-offset")]
+ pub fn local_offset_at(datetime: OffsetDateTime) -> Result<Self, error::IndeterminateOffset> {
+ local_offset_at(datetime).ok_or(error::IndeterminateOffset)
+ }
+
+ /// Attempt to obtain the system's current UTC offset. If the offset cannot be determined, an
+ /// error is returned.
+ ///
+ /// ```rust
+ /// # use time::UtcOffset;
+ /// let local_offset = UtcOffset::current_local_offset();
+ /// # if false {
+ /// assert!(local_offset.is_ok());
+ /// # }
+ /// ```
+ #[cfg(feature = "local-offset")]
+ pub fn current_local_offset() -> Result<Self, error::IndeterminateOffset> {
+ let now = OffsetDateTime::now_utc();
+ local_offset_at(now).ok_or(error::IndeterminateOffset)
+ }
+}
+
+#[cfg(feature = "formatting")]
+impl UtcOffset {
+ /// Format the `UtcOffset` using the provided [format description](crate::format_description).
+ pub fn format_into(
+ self,
+ output: &mut (impl io::Write + ?Sized),
+ format: &(impl Formattable + ?Sized),
+ ) -> Result<usize, error::Format> {
+ format.format_into(output, None, None, Some(self))
+ }
+
+ /// Format the `UtcOffset` using the provided [format description](crate::format_description).
+ ///
+ /// ```rust
+ /// # use time::format_description;
+ /// # use time_macros::offset;
+ /// let format = format_description::parse("[offset_hour sign:mandatory]:[offset_minute]")?;
+ /// assert_eq!(offset!(+1).format(&format)?, "+01:00");
+ /// # Ok::<_, time::Error>(())
+ /// ```
+ pub fn format(self, format: &(impl Formattable + ?Sized)) -> Result<String, error::Format> {
+ format.format(None, None, Some(self))
+ }
+}
+
+#[cfg(feature = "parsing")]
+impl UtcOffset {
+ /// Parse a `UtcOffset` from the input using the provided [format
+ /// description](crate::format_description).
+ ///
+ /// ```rust
+ /// # use time::UtcOffset;
+ /// # use time_macros::{offset, format_description};
+ /// let format = format_description!("[offset_hour]:[offset_minute]");
+ /// assert_eq!(UtcOffset::parse("-03:42", &format)?, offset!(-3:42));
+ /// # Ok::<_, time::Error>(())
+ /// ```
+ pub fn parse(
+ input: &str,
+ description: &(impl Parsable + ?Sized),
+ ) -> Result<Self, error::Parse> {
+ description.parse_offset(input.as_bytes())
+ }
+}
+
+mod private {
+ #[non_exhaustive]
+ #[derive(Debug, Clone, Copy)]
+ pub struct UtcOffsetMetadata;
+}
+use private::UtcOffsetMetadata;
+
+impl SmartDisplay for UtcOffset {
+ type Metadata = UtcOffsetMetadata;
+
+ fn metadata(&self, _: FormatterOptions) -> Metadata<Self> {
+ let sign = if self.is_negative() { '-' } else { '+' };
+ let width = smart_display::padded_width_of!(
+ sign,
+ self.hours.abs() => width(2),
+ ":",
+ self.minutes.abs() => width(2),
+ ":",
+ self.seconds.abs() => width(2),
+ );
+ Metadata::new(width, self, UtcOffsetMetadata)
+ }
+
+ fn fmt_with_metadata(
+ &self,
+ f: &mut fmt::Formatter<'_>,
+ metadata: Metadata<Self>,
+ ) -> fmt::Result {
+ f.pad_with_width(
+ metadata.unpadded_width(),
+ format_args!(
+ "{}{:02}:{:02}:{:02}",
+ if self.is_negative() { '-' } else { '+' },
+ self.hours.abs(),
+ self.minutes.abs(),
+ self.seconds.abs(),
+ ),
+ )
+ }
+}
+
+impl fmt::Display for UtcOffset {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ SmartDisplay::fmt(self, f)
+ }
+}
+
+impl fmt::Debug for UtcOffset {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt::Display::fmt(self, f)
+ }
+}
+
+impl Neg for UtcOffset {
+ type Output = Self;
+
+ fn neg(self) -> Self::Output {
+ Self::from_hms_ranged(self.hours.neg(), self.minutes.neg(), self.seconds.neg())
+ }
+}
diff --git a/vendor/time/src/util.rs b/vendor/time/src/util.rs
new file mode 100644
index 00000000..c5166a70
--- /dev/null
+++ b/vendor/time/src/util.rs
@@ -0,0 +1,105 @@
+//! Utility functions, including updating time zone information.
+
+pub use time_core::util::{days_in_year, is_leap_year, weeks_in_year};
+
+use crate::Month;
+
+/// Whether to adjust the date, and in which direction. Useful when implementing arithmetic.
+pub(crate) enum DateAdjustment {
+ /// The previous day should be used.
+ Previous,
+ /// The next day should be used.
+ Next,
+ /// The date should be used as-is.
+ None,
+}
+
+/// Get the number of days in the month of a given year.
+///
+/// ```rust
+/// # use time::{Month, util};
+/// assert_eq!(util::days_in_month(Month::February, 2020), 29);
+/// ```
+pub const fn days_in_month(month: Month, year: i32) -> u8 {
+ time_core::util::days_in_month(month as u8, year)
+}
+
+/// Get the number of days in the month of a given year.
+///
+/// ```rust
+/// # #![allow(deprecated)]
+/// # use time::{Month, util};
+/// assert_eq!(util::days_in_year_month(2020, Month::February), 29);
+/// ```
+#[deprecated(
+ since = "0.3.37",
+ note = "use `days_in_month` or `Month::length` instead"
+)]
+pub const fn days_in_year_month(year: i32, month: Month) -> u8 {
+ days_in_month(month, year)
+}
+
+/// Update time zone information from the system.
+///
+/// For a version of this function that is guaranteed to be sound, see [`refresh_tz`].
+///
+/// # Safety
+///
+/// This is a system call with specific requirements. The following is from POSIX's description of
+/// `tzset`:
+///
+/// > If a thread accesses `tzname`, `daylight`, or `timezone` directly while another thread is in a
+/// > call to `tzset()`, or to any function that is required or allowed to set timezone information
+/// > as if by calling `tzset()`, the behavior is undefined.
+///
+/// Effectively, this translates to the requirement that at least one of the following must be true:
+///
+/// - The operating system provides a thread-safe environment.
+/// - The process is single-threaded.
+/// - The process is multi-threaded **and** no other thread is mutating the environment in any way
+/// at the same time a call to a method that obtains the local UTC offset. This includes adding,
+/// removing, or modifying an environment variable.
+///
+/// ## Soundness is global
+///
+/// You must not only verify this safety conditions for your code, but for **all** code that will be
+/// included in the final binary. Notably, it applies to both direct and transitive dependencies and
+/// to both Rust and non-Rust code. **For this reason it is not possible for a library to soundly
+/// call this method.**
+///
+/// ## Forward compatibility
+///
+/// This currently only does anything on Unix-like systems. On other systems, it is a no-op. This
+/// may change in the future if necessary, expanding the safety requirements. It is expected that,
+/// at a minimum, calling this method when the process is single-threaded will remain sound.
+#[cfg(feature = "local-offset")]
+pub unsafe fn refresh_tz_unchecked() {
+ // Safety: The caller must uphold the safety requirements.
+ unsafe { crate::sys::refresh_tz_unchecked() };
+}
+
+/// Attempt to update time zone information from the system.
+///
+/// Returns `None` if the call is not known to be sound.
+#[cfg(feature = "local-offset")]
+pub fn refresh_tz() -> Option<()> {
+ crate::sys::refresh_tz()
+}
+
+#[doc(hidden)]
+#[cfg(feature = "local-offset")]
+#[allow(clippy::missing_const_for_fn)]
+#[deprecated(since = "0.3.37", note = "no longer needed; TZ is refreshed manually")]
+pub mod local_offset {
+ #[derive(Debug, Clone, Copy, PartialEq, Eq)]
+ pub enum Soundness {
+ Sound,
+ Unsound,
+ }
+
+ pub unsafe fn set_soundness(_: Soundness) {}
+
+ pub fn get_soundness() -> Soundness {
+ Soundness::Sound
+ }
+}
diff --git a/vendor/time/src/weekday.rs b/vendor/time/src/weekday.rs
new file mode 100644
index 00000000..4331da83
--- /dev/null
+++ b/vendor/time/src/weekday.rs
@@ -0,0 +1,220 @@
+//! Days of the week.
+
+use core::fmt;
+use core::str::FromStr;
+
+use powerfmt::smart_display::{FormatterOptions, Metadata, SmartDisplay};
+
+use self::Weekday::*;
+use crate::error;
+
+/// Days of the week.
+///
+/// As order is dependent on context (Sunday could be either two days after or five days before
+/// Friday), this type does not implement `PartialOrd` or `Ord`.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub enum Weekday {
+ #[allow(missing_docs)]
+ Monday,
+ #[allow(missing_docs)]
+ Tuesday,
+ #[allow(missing_docs)]
+ Wednesday,
+ #[allow(missing_docs)]
+ Thursday,
+ #[allow(missing_docs)]
+ Friday,
+ #[allow(missing_docs)]
+ Saturday,
+ #[allow(missing_docs)]
+ Sunday,
+}
+
+impl Weekday {
+ /// Get the previous weekday.
+ ///
+ /// ```rust
+ /// # use time::Weekday;
+ /// assert_eq!(Weekday::Tuesday.previous(), Weekday::Monday);
+ /// ```
+ pub const fn previous(self) -> Self {
+ match self {
+ Monday => Sunday,
+ Tuesday => Monday,
+ Wednesday => Tuesday,
+ Thursday => Wednesday,
+ Friday => Thursday,
+ Saturday => Friday,
+ Sunday => Saturday,
+ }
+ }
+
+ /// Get the next weekday.
+ ///
+ /// ```rust
+ /// # use time::Weekday;
+ /// assert_eq!(Weekday::Monday.next(), Weekday::Tuesday);
+ /// ```
+ pub const fn next(self) -> Self {
+ match self {
+ Monday => Tuesday,
+ Tuesday => Wednesday,
+ Wednesday => Thursday,
+ Thursday => Friday,
+ Friday => Saturday,
+ Saturday => Sunday,
+ Sunday => Monday,
+ }
+ }
+
+ /// Get n-th next day.
+ ///
+ /// ```rust
+ /// # use time::Weekday;
+ /// assert_eq!(Weekday::Monday.nth_next(1), Weekday::Tuesday);
+ /// assert_eq!(Weekday::Sunday.nth_next(10), Weekday::Wednesday);
+ /// ```
+ pub const fn nth_next(self, n: u8) -> Self {
+ match (self.number_days_from_monday() + n % 7) % 7 {
+ 0 => Monday,
+ 1 => Tuesday,
+ 2 => Wednesday,
+ 3 => Thursday,
+ 4 => Friday,
+ 5 => Saturday,
+ val => {
+ debug_assert!(val == 6);
+ Sunday
+ }
+ }
+ }
+
+ /// Get n-th previous day.
+ ///
+ /// ```rust
+ /// # use time::Weekday;
+ /// assert_eq!(Weekday::Monday.nth_prev(1), Weekday::Sunday);
+ /// assert_eq!(Weekday::Sunday.nth_prev(10), Weekday::Thursday);
+ /// ```
+ pub const fn nth_prev(self, n: u8) -> Self {
+ match self.number_days_from_monday() as i8 - (n % 7) as i8 {
+ 1 | -6 => Tuesday,
+ 2 | -5 => Wednesday,
+ 3 | -4 => Thursday,
+ 4 | -3 => Friday,
+ 5 | -2 => Saturday,
+ 6 | -1 => Sunday,
+ val => {
+ debug_assert!(val == 0);
+ Monday
+ }
+ }
+ }
+
+ /// Get the one-indexed number of days from Monday.
+ ///
+ /// ```rust
+ /// # use time::Weekday;
+ /// assert_eq!(Weekday::Monday.number_from_monday(), 1);
+ /// ```
+ #[doc(alias = "iso_weekday_number")]
+ pub const fn number_from_monday(self) -> u8 {
+ self.number_days_from_monday() + 1
+ }
+
+ /// Get the one-indexed number of days from Sunday.
+ ///
+ /// ```rust
+ /// # use time::Weekday;
+ /// assert_eq!(Weekday::Monday.number_from_sunday(), 2);
+ /// ```
+ pub const fn number_from_sunday(self) -> u8 {
+ self.number_days_from_sunday() + 1
+ }
+
+ /// Get the zero-indexed number of days from Monday.
+ ///
+ /// ```rust
+ /// # use time::Weekday;
+ /// assert_eq!(Weekday::Monday.number_days_from_monday(), 0);
+ /// ```
+ pub const fn number_days_from_monday(self) -> u8 {
+ self as u8
+ }
+
+ /// Get the zero-indexed number of days from Sunday.
+ ///
+ /// ```rust
+ /// # use time::Weekday;
+ /// assert_eq!(Weekday::Monday.number_days_from_sunday(), 1);
+ /// ```
+ pub const fn number_days_from_sunday(self) -> u8 {
+ match self {
+ Monday => 1,
+ Tuesday => 2,
+ Wednesday => 3,
+ Thursday => 4,
+ Friday => 5,
+ Saturday => 6,
+ Sunday => 0,
+ }
+ }
+}
+
+mod private {
+ #[non_exhaustive]
+ #[derive(Debug, Clone, Copy)]
+ pub struct WeekdayMetadata;
+}
+use private::WeekdayMetadata;
+
+impl SmartDisplay for Weekday {
+ type Metadata = WeekdayMetadata;
+
+ fn metadata(&self, _: FormatterOptions) -> Metadata<'_, Self> {
+ match self {
+ Monday => Metadata::new(6, self, WeekdayMetadata),
+ Tuesday => Metadata::new(7, self, WeekdayMetadata),
+ Wednesday => Metadata::new(9, self, WeekdayMetadata),
+ Thursday => Metadata::new(8, self, WeekdayMetadata),
+ Friday => Metadata::new(6, self, WeekdayMetadata),
+ Saturday => Metadata::new(8, self, WeekdayMetadata),
+ Sunday => Metadata::new(6, self, WeekdayMetadata),
+ }
+ }
+
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.pad(match self {
+ Monday => "Monday",
+ Tuesday => "Tuesday",
+ Wednesday => "Wednesday",
+ Thursday => "Thursday",
+ Friday => "Friday",
+ Saturday => "Saturday",
+ Sunday => "Sunday",
+ })
+ }
+}
+
+impl fmt::Display for Weekday {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ SmartDisplay::fmt(self, f)
+ }
+}
+
+impl FromStr for Weekday {
+ type Err = error::InvalidVariant;
+
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
+ match s {
+ "Monday" => Ok(Monday),
+ "Tuesday" => Ok(Tuesday),
+ "Wednesday" => Ok(Wednesday),
+ "Thursday" => Ok(Thursday),
+ "Friday" => Ok(Friday),
+ "Saturday" => Ok(Saturday),
+ "Sunday" => Ok(Sunday),
+ _ => Err(error::InvalidVariant),
+ }
+ }
+}