diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-30 03:57:31 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-30 03:57:31 +0000 |
commit | dc0db358abe19481e475e10c32149b53370f1a1c (patch) | |
tree | ab8ce99c4b255ce46f99ef402c27916055b899ee /vendor/chrono | |
parent | Releasing progress-linux version 1.71.1+dfsg1-2~progress7.99u1. (diff) | |
download | rustc-dc0db358abe19481e475e10c32149b53370f1a1c.tar.xz rustc-dc0db358abe19481e475e10c32149b53370f1a1c.zip |
Merging upstream version 1.72.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/chrono')
41 files changed, 1665 insertions, 1345 deletions
diff --git a/vendor/chrono/.cargo-checksum.json b/vendor/chrono/.cargo-checksum.json index 5d66a6fc4..259fad17d 100644 --- a/vendor/chrono/.cargo-checksum.json +++ b/vendor/chrono/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"AUTHORS.txt":"8bfaf8f8599111cd6eef4408a55b98ba188611d1bcab0295e5b6a35def1343df","CHANGELOG.md":"1cc518c80946bc676a8c691428abe1cdf5a2e4e210b3cacc264b2efc5489d566","Cargo.toml":"d43fb7f28cbbd4c4e5410fdca9b5d22f8fb6ff8ae880f09038a0fb20c7916a13","LICENSE.txt":"46610329ff0b38effb9cb05979ff1ef761e465fed96b2eaca39e439d00129fd7","Makefile":"1a85008275ee7bf7cc0f0c054b1b393f34a4e614a28ebf3418c9d6b6e53b1b2c","README.md":"9260b662c38f931780e5bf89c837e351dada72affc29cacc9cfea6c558003845","appveyor.yml":"bcfcff73097a37be373e91934294cfea31fbdfe7a4b01a83bcbc64a8a56c3971","benches/chrono.rs":"a18e8f87e80d7e32cc4a1103d7c075b868ff3018eec2a09cc3b4c80e773fa987","benches/serde.rs":"0cebd95c96f0ddf0f7b6ca2d4a4fa307c7ccc691ee5eb090556f89807120eb9f","clippy.toml":"0ee2428866ddc7519d178a46d9073399e28b3c879a9d14658a1e7c5c023c3a7c","deny.toml":"4189fcb1125499ac851c0bd29f3f27a614b28573fa3299f712ee4bdace897dd3","rustfmt.toml":"f74204a6f92aa7422a16ecb2ffe2d5bae0f123b778d08b5db1a398a3c9ca4306","src/date.rs":"4929ac7b68a3d26ae7f94e1b375017a08a3f80581432f69c6e068832377a0ff6","src/datetime/mod.rs":"8eee73e7fe6e903e05b8d39acdb1e835d9163f6e1638d8f0ba74de7ea8ec1fd1","src/datetime/rustc_serialize.rs":"8cef7bba6aec9e75679c78b5544f22be41989c15e253fb739b76fcc4c9ee9fbe","src/datetime/serde.rs":"85d8bd79ded20fe68d7b8b68889c19a9f9dad5af6620885554190365d58967f2","src/datetime/tests.rs":"80c6e770c8dabebfee45ee67ede5a7418bdae24b5de9957bb15ecaca630e7c33","src/format/locales.rs":"8c14cb93c68b747947b74ab2933aae53c8a0edd009ff16815e756015fbea6e9f","src/format/mod.rs":"abf92d8f13683d13167a094add4a2908cb1a2cba0ec6867018e93ce4dbc5df8d","src/format/parse.rs":"74aeac3d34385497901a889f0ed55faea9a489391e9db1055e6bd1af1819d6e8","src/format/parsed.rs":"999fadd3e787b4c69b2f2471247fbfce32951156705bac20170da5aed76c2b98","src/format/scan.rs":"392c12418cd0cc3b570ea68542db9281d01f1ec595e95005d743d9287752e0ff","src/format/strftime.rs":"a10f904e4a86748657f2a8f4fe5fc0f44bf99275311ac8ac50b821208e41e891","src/lib.rs":"935de4f470a6189b92ca4a78ea14b149d3d418fbd4abdfb1b90f84c4bfcfe480","src/month.rs":"198802cc8a6dfd6614842e81729eef2fa9e6f5b2d418bad64e4bb1a49fcd3c21","src/naive/date.rs":"803664c44eef75e2f0bbc8a8174679208146d01fc3da18b1036d6fabd7ca0f46","src/naive/datetime/mod.rs":"ab619388eaa0659934c71fdc06b51fbd0f0250fe0ad6bfd88d6e76b090ab4d1e","src/naive/datetime/rustc_serialize.rs":"50491c855583694f01aed7d577c43dee9adf9bd548377b6707b4d596d887e0b2","src/naive/datetime/serde.rs":"8f677be5ece94f799219b66d018bd9dc82471c2192e2374c9d904ceabf982686","src/naive/datetime/tests.rs":"9bfbe494525fa1c8943c22c985bb9ce358459a97b8939fbdb8540b45fc6c2c8a","src/naive/internals.rs":"c73325b4f63ed221436643ebd58935004f8f76b4aa25a20a0703a2ebfc2a6c12","src/naive/isoweek.rs":"6c34cda15d21bdc095393c1de5bfaefa9611e6c35417aa21af82c4b44b4d6765","src/naive/mod.rs":"743e0ba276a235baa536005108e11597c1ca4ee100ed86e09cbad2216a91939d","src/naive/time/mod.rs":"c8cff488deb75943f02fe73e905fe16cc63cea52c84a6d8a1c5f2c7592338a51","src/naive/time/rustc_serialize.rs":"ce93c81341f35e29ec32a43644fd892a27823643b8ac2f010194824f434180ca","src/naive/time/serde.rs":"a89c1f0d127e89793d8bc1b786996babf02d5aa0a2d859d53a6d3ad02399d9a1","src/naive/time/tests.rs":"b8586903b65c1b050253c04bc9770f7889bfd4db87d02143a2b7fddbecf56dea","src/offset/fixed.rs":"9ac52822a66eac1f7eab92c8c77235573a40a5ca0b58c17e7894df51ae8edaa4","src/offset/local/mod.rs":"7160b6db6efcf06b6604cba363323f741c9dd8b235b2bd062b70eeb19f5d07b6","src/offset/local/stub.rs":"c753e9f45b85834e834191a38802c1105098ae17c56c31c2d99be42c50e6247c","src/offset/local/tz_info/mod.rs":"3488ac6811ea2a39418ff22f0de282ebddba4620dc916595d8b250d50d0bfb20","src/offset/local/tz_info/parser.rs":"47a569bf39eec6121ab9cd69d8fafb679be463d1e919e9d81a7d523667868136","src/offset/local/tz_info/rule.rs":"a88ad07f638ead425ae2dcc1aa76842b44a9f939c9f736cfa6fe2189e2b9f2a5","src/offset/local/tz_info/timezone.rs":"7dee5dd24c5bec63b2e94e3355d3f7e1ed5055771ffb6b70a449bd8f6b22fba8","src/offset/local/unix.rs":"e854d1cb52e9d18c4161ed660b03c62bc8d05418f85c746e2799dd1bdf7ed105","src/offset/local/windows.rs":"edda38f1f78f2392e0e89d01f6f06454ed8f1f269df0505d533107eeed9e713f","src/offset/mod.rs":"f0d486ab04c803a887b6b775e7f50a0b341b050497d3b4df67abc211daaa41f7","src/offset/utc.rs":"e15afd6a7aba6d2706d262f75b6e6b38e4536af0611b077446da04b06f40be6e","src/oldtime.rs":"8a4a0e1c932a04a30aa306bafdaf2457ffdbcd7f735c9b5cc365e56fdcba2ddc","src/round.rs":"3b70e5a88ea00ab2b70307b4b19c9cd1b42a8bf3356f0f63e4bd4696f46f3a84","src/traits.rs":"48d78381164232c13449dbd229b653ad05215ab44c7901fb026da94938d2ec9d","src/weekday.rs":"61891524fb27ad43d751b47dd4c0115b7f6d4ce509801953d03b8e44afd3e31a","tests/dateutils.rs":"eeff9ce9bf705818690af811f8611990eb8c580756b10f4d8c1691517a8ff969","tests/wasm.rs":"026c36013894a2a55794b4510f893eabeae89c2600b578ea428473ad339db333"},"package":"4e3c5919066adf22df73762e50cffcde3a758f2a848b113b586d1f86728b673b"}
\ No newline at end of file +{"files":{"CHANGELOG.md":"1cc518c80946bc676a8c691428abe1cdf5a2e4e210b3cacc264b2efc5489d566","Cargo.toml":"2fd03d64b57769ecc8cd9d6ae29681eec3ef1b2a52478c0f2c4c3c020240bb3f","LICENSE.txt":"46610329ff0b38effb9cb05979ff1ef761e465fed96b2eaca39e439d00129fd7","Makefile":"1a85008275ee7bf7cc0f0c054b1b393f34a4e614a28ebf3418c9d6b6e53b1b2c","README.md":"25308c06a4e16008c9b1fafd31fea67ba8e61ff6f7b5ec5b919a127d40c4f530","appveyor.yml":"bcfcff73097a37be373e91934294cfea31fbdfe7a4b01a83bcbc64a8a56c3971","benches/chrono.rs":"878752a20e1ef655e45697540bcc610ab08e9a99651fef84cb7154e39a10db9d","benches/serde.rs":"0cebd95c96f0ddf0f7b6ca2d4a4fa307c7ccc691ee5eb090556f89807120eb9f","deny.toml":"4189fcb1125499ac851c0bd29f3f27a614b28573fa3299f712ee4bdace897dd3","rustfmt.toml":"f74204a6f92aa7422a16ecb2ffe2d5bae0f123b778d08b5db1a398a3c9ca4306","src/date.rs":"62bd777c64a6108f8362990dd17219a5721c1044170397214234d2d72145cea2","src/datetime/mod.rs":"0cb9d965e3b7014dbd415f5c1574372e7d71355bdf2daca332b7ae95bdf73bda","src/datetime/rustc_serialize.rs":"8cef7bba6aec9e75679c78b5544f22be41989c15e253fb739b76fcc4c9ee9fbe","src/datetime/serde.rs":"11bc2a04d74566d9bbbd893faa2e27fddc81994e5d5cf8760235e1c32ee50ea3","src/datetime/tests.rs":"b5b75a8738bb5074866fad2372cead4a1e935ff68a7210b9c15b3a806a39a815","src/format/locales.rs":"d24c08f87b98f1f88ea86020f1f55c8c2cefc74a0eb9b3513d820f6e200192d3","src/format/mod.rs":"b93b41021e994a7444382a23749093a535ef1126a88023c021e2fbcfa37a91c8","src/format/parse.rs":"3e8daa91c4bff4f00b52e91ab9166b816b4780c18e6811aec45c19fd6f309bc6","src/format/parsed.rs":"e55129bf34d3f2974c843868b435b87d0b4a418cbb803a6f0bb74844a6a71328","src/format/scan.rs":"057e182001d66d2f0c84dbd41898561b3289bdbc9b39068d4f86fc6ec5a43bdd","src/format/strftime.rs":"3ee6f4d8d9f66b971f111f36e3ecd22e001996e43a63363590d761333dd66998","src/lib.rs":"33a434b25adb6a8bb96db57976dab8cb5a41f4b528a8e283c55013d7efb6cc7d","src/month.rs":"7e7639941aca103bc3b086e2e1d4ba4e1cc9337fac2e6031007a38ecb39faf6d","src/naive/date.rs":"8b9299609b0b3e80b44362f92fe643096859251c265f2b53ae566973e0cbb53a","src/naive/datetime/mod.rs":"3744899f3aba44b2a687ceecd3a59abda7fa5772bf1a86fad7a44bdb476ba1db","src/naive/datetime/rustc_serialize.rs":"50491c855583694f01aed7d577c43dee9adf9bd548377b6707b4d596d887e0b2","src/naive/datetime/serde.rs":"0d0a71231f519fe0e07e4b0ff745e63b6eb3a706e143f143ca3d879353c6645d","src/naive/datetime/tests.rs":"047a67038ab4d9e06d35a9832206460bc8c7fb396ffe3485b74e5884bf62a587","src/naive/internals.rs":"ce83d5847a845eb9e6e6b02c0b92218b76fec71fa40f9865ce906864cced18d1","src/naive/isoweek.rs":"6f18d4b3d1120b8a426a9f82d855e2a4021fac80a6ebcce106f6af1ad12b9fd9","src/naive/mod.rs":"743e0ba276a235baa536005108e11597c1ca4ee100ed86e09cbad2216a91939d","src/naive/time/mod.rs":"3555f9ab4c924c2b88536560d32a4b28b58fdd4d91af1a853497f9f8ba8cd26c","src/naive/time/rustc_serialize.rs":"ce93c81341f35e29ec32a43644fd892a27823643b8ac2f010194824f434180ca","src/naive/time/serde.rs":"a89c1f0d127e89793d8bc1b786996babf02d5aa0a2d859d53a6d3ad02399d9a1","src/naive/time/tests.rs":"b8586903b65c1b050253c04bc9770f7889bfd4db87d02143a2b7fddbecf56dea","src/offset/fixed.rs":"a59c40d7dc741715f4628863a5830efa983d6c7ad49eebcf10f50d5a32b7de22","src/offset/local/mod.rs":"0944133a2e277bdf3e6ca729064a48109f7ba37f0d720c0d12343d6393ca8800","src/offset/local/tz_info/mod.rs":"c8096637c04687ea396e444c25fdf0008e2b9975ab3c173a41dd63ac213c7877","src/offset/local/tz_info/parser.rs":"4e2f34a6e760833392bc7da038721fb5e266eebb8e4b327a8140e2d8504de4ec","src/offset/local/tz_info/rule.rs":"54df6b45c4517e5442c04654a87c3082dc789b48761237449389802b829acab9","src/offset/local/tz_info/timezone.rs":"64a0dda51a2dc2c76ca6944ae69d67c3ab75fa891e53d8a79c54539b0ddb3f10","src/offset/local/unix.rs":"5a03f58cf5e8efb8046308a88f2fcf36dbd295077071398300e7d7c5da1bfdbf","src/offset/local/windows.rs":"9f7f9e6abd2b1efe4c5e9c8c962dccf160fdeea0f7b223efa7d466d4f3630964","src/offset/mod.rs":"9082d9544516ff671d11515f82a7c2e53acae46642ecc36298afe011e70c3906","src/offset/utc.rs":"3855758f6d931bef03afc06fb7f47879601225984a43950ea7a541f34ae9708b","src/oldtime.rs":"b64a301069cf6cc94ef65f5d35aee7e7a785b052fd6a9b22cfd991d88893f8d8","src/round.rs":"ac1ffe7c9ebd06fd9ee2c71815336270dd82f84c74e5d3be3be1fa19e4e2b026","src/traits.rs":"6e9a33e7af1c2f2a098101818f21dd39f61e04b4a6d2f77c7de2a74010f509a5","src/weekday.rs":"1c2c11af3cfa8938b5416dbd004646ac0f16f60247f7a40da02c8845b1828521","tests/dateutils.rs":"d27af7c3b98fda2fbd1cd90dc421c38d19a2241e3fda76c1dbe2130ceee6ed34","tests/wasm.rs":"026c36013894a2a55794b4510f893eabeae89c2600b578ea428473ad339db333"},"package":"ec837a71355b28f6556dbd569b37b3f363091c0bd4b2e735674521b4c5fd9bc5"}
\ No newline at end of file diff --git a/vendor/chrono/AUTHORS.txt b/vendor/chrono/AUTHORS.txt deleted file mode 100644 index caff57915..000000000 --- a/vendor/chrono/AUTHORS.txt +++ /dev/null @@ -1,43 +0,0 @@ -Chrono is mainly written by Kang Seonghoon <public+rust@mearie.org>, -and also the following people (in ascending order): - -Alex Mikhalev <alexmikhalevalex@gmail.com> -Alexander Bulaev <alexbool@yandex-team.ru> -Ashley Mannix <ashleymannix@live.com.au> -Ben Boeckel <mathstuf@gmail.com> -Ben Eills <ben@beneills.com> -Brandon W Maister <bwm@knewton.com> -Brandon W Maister <quodlibetor@gmail.com> -Cecile Tonglet <cecile.tonglet@cecton.com> -Colin Ray <r.colinray@gmail.com> -Corey Farwell <coreyf@rwell.org> -Dan <dan@ebip.co.uk> -Danilo Bargen <mail@dbrgn.ch> -David Hewson <dev@daveid.co.uk> -David Ross <daboross@daboross.net> -David Tolnay <dtolnay@gmail.com> -David Willie <david.willie.1@gmail.com> -Eric Findlay <e.findlay@protonmail.ch> -Eunchong Yu <kroisse@gmail.com> -Frans Skarman <frans.skarman@gmail.com> -Huon Wilson <dbau.pp+github@gmail.com> -Igor Gnatenko <ignatenko@redhat.com> -Jake Vossen <jake@vossen.dev> -Jim Turner <jturner314@gmail.com> -Jisoo Park <xxxyel@gmail.com> -Joe Wilm <joe@jwilm.com> -John Heitmann <jheitmann@gmail.com> -John Nagle <nagle@sitetruth.com> -Jonas mg <jonasmg@yepmail.net> -János Illés <ijanos@gmail.com> -Ken Tossell <ken@tossell.net> -Martin Risell Lilja <martin.risell.lilja@gmail.com> -Richard Petrie <rap1011@ksu.edu> -Ryan Lewis <ryansname@gmail.com> -Sergey V. Shadoy <shadoysv@yandex.ru> -Sergey V. Galtsev <sergey.v.galtsev@github.com> -Steve Klabnik <steve@steveklabnik.com> -Tom Gallacher <tomgallacher23@gmail.com> -klutzy <klutzytheklutzy@gmail.com> -kud1ing <github@kudling.de> -Yohan Boogaert <yozhgoor@outlook.com> diff --git a/vendor/chrono/Cargo.toml b/vendor/chrono/Cargo.toml index eaf0e6945..7f49bad0b 100644 --- a/vendor/chrono/Cargo.toml +++ b/vendor/chrono/Cargo.toml @@ -10,9 +10,10 @@ # See Cargo.toml.orig for the original contents. [package] -edition = "2018" +edition = "2021" +rust-version = "1.56.0" name = "chrono" -version = "0.4.24" +version = "0.4.26" exclude = ["/ci/*"] description = "Date and time library for Rust" homepage = "https://github.com/chronotope/chrono" @@ -62,10 +63,6 @@ optional = true version = "0.4.0" optional = true -[dependencies.num-integer] -version = "0.1.36" -default-features = false - [dependencies.num-traits] version = "0.2" default-features = false @@ -97,10 +94,6 @@ version = "1.3.0" [dev-dependencies.doc-comment] version = "0.3" -[dev-dependencies.num-iter] -version = "0.1.35" -default-features = false - [dev-dependencies.serde_derive] version = "1" default-features = false @@ -146,6 +139,9 @@ optional = true [target."cfg(all(target_arch = \"wasm32\", not(any(target_os = \"emscripten\", target_os = \"wasi\"))))".dev-dependencies.wasm-bindgen-test] version = "0.3" +[target."cfg(target_os = \"android\")".dependencies.android-tzdata] +version = "0.1.1" + [target."cfg(unix)".dependencies.iana-time-zone] version = "0.1.45" features = ["fallback"] @@ -158,5 +154,6 @@ features = [ "minwinbase", "minwindef", "timezoneapi", + "sysinfoapi", ] optional = true diff --git a/vendor/chrono/README.md b/vendor/chrono/README.md index ad9591889..639a09144 100644 --- a/vendor/chrono/README.md +++ b/vendor/chrono/README.md @@ -1,4 +1,4 @@ -[Chrono][docsrs]: Date and Time for Rust +[Chrono][docsrs]: Timezone-aware date and time handling ======================================== [![Chrono GitHub Actions][gh-image]][gh-checks] @@ -15,45 +15,66 @@ [gitter-image]: https://badges.gitter.im/chrono-rs/chrono.svg [gitter]: https://gitter.im/chrono-rs/chrono -It aims to be a feature-complete superset of -the [time](https://github.com/rust-lang-deprecated/time) library. -In particular, +Chrono aims to provide all functionality needed to do correct operations on dates and times in the +[proleptic Gregorian calendar](https://en.wikipedia.org/wiki/Proleptic_Gregorian_calendar): -* Chrono strictly adheres to ISO 8601. -* Chrono is timezone-aware by default, with separate timezone-naive types. -* Chrono is space-optimal and (while not being the primary goal) reasonably efficient. +* The [`DateTime`](https://docs.rs/chrono/latest/chrono/struct.DateTime.html) type is timezone-aware + by default, with separate timezone-naive types. +* Operations that may produce an invalid or ambiguous date and time return `Option` or + [`LocalResult`](https://docs.rs/chrono/latest/chrono/offset/enum.LocalResult.html). +* Configurable parsing and formatting with an `strftime` inspired date and time formatting syntax. +* The [`Local`](https://docs.rs/chrono/latest/chrono/offset/struct.Local.html) timezone works with + the current timezone of the OS. +* Types and operations are implemented to be reasonably efficient. -There were several previous attempts to bring a good date and time library to Rust, -which Chrono builds upon and should acknowledge: +Timezone data is not shipped with chrono by default to limit binary sizes. Use the companion crate +[Chrono-TZ](https://crates.io/crates/chrono-tz) or [`tzfile`](https://crates.io/crates/tzfile) for +full timezone support. -* [Initial research on - the wiki](https://github.com/rust-lang/rust-wiki-backup/blob/master/Lib-datetime.md) -* Dietrich Epp's [datetime-rs](https://github.com/depp/datetime-rs) -* Luis de Bethencourt's [rust-datetime](https://github.com/luisbg/rust-datetime) +## Documentation + +See [docs.rs](https://docs.rs/chrono/latest/chrono/) for the API reference. ## Limitations -Only proleptic Gregorian calendar (i.e. extended to support older dates) is supported. -Be very careful if you really have to deal with pre-20C dates, they can be in Julian or others. +* Only the proleptic Gregorian calendar (i.e. extended to support older dates) is supported. +* Date types are limited to about +/- 262,000 years from the common epoch. +* Time types are limited to nanosecond accuracy. +* Leap seconds can be represented, but Chrono does not fully support them. + See [Leap Second Handling](https://docs.rs/chrono/latest/chrono/naive/struct.NaiveTime.html#leap-second-handling). + +## Crate features + +Default features: + +* `alloc`: Enable features that depend on allocation (primarily string formatting) +* `std`: Enables functionality that depends on the standard library. This is a superset of `alloc` + and adds interoperation with standard library types and traits. +* `clock`: Enables reading the system time (`now`) and local timezone (`Local`). +* `wasmbind`: Interface with the JS Date API for the `wasm32` target. + +Optional features: + +* `serde`: Enable serialization/deserialization via serde. +* `rkyv`: Enable serialization/deserialization via rkyv. +* `rustc-serialize`: Enable serialization/deserialization via rustc-serialize (deprecated). +* `old_time`: compatability with the `Duration` type of the `time` 0.1 crate (deprecated). +* `arbitrary`: construct arbitrary instances of a type with the Arbitrary crate. +* `unstable-locales`: Enable localization. This adds various methods with a `_localized` suffix. + The implementation and API may change or even be removed in a patch release. Feedback welcome. + +## Rust version requirements + +The Minimum Supported Rust Version (MSRV) is currently **Rust 1.56.0**. -Date types are limited in about +/- 262,000 years from the common epoch. -Time types are limited in the nanosecond accuracy. +The MSRV is explicitly tested in CI. It may be bumped in minor releases, but this is not done +lightly. -[Leap seconds are supported in the representation but -Chrono doesn't try to make use of them](https://docs.rs/chrono/0.4/chrono/naive/struct.NaiveTime.html#leap-second-handling). -(The main reason is that leap seconds are not really predictable.) -Almost *every* operation over the possible leap seconds will ignore them. -Consider using `NaiveDateTime` with the implicit TAI (International Atomic Time) scale -if you want. +## License -Chrono inherently does not support an inaccurate or partial date and time representation. -Any operation that can be ambiguous will return `None` in such cases. -For example, "a month later" of 2014-01-30 is not well-defined -and consequently `Utc.ymd_opt(2014, 1, 30).unwrap().with_month(2)` returns `None`. +This project is licensed under either of -Non ISO week handling is not yet supported. -For now you can use the [chrono_ext](https://crates.io/crates/chrono_ext) -crate ([sources](https://github.com/bcourtine/chrono-ext/)). +* [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0) +* [MIT License](https://opensource.org/licenses/MIT) -Advanced time zone handling is not yet supported. -For now you can try the [Chrono-tz](https://github.com/chronotope/chrono-tz/) crate instead. +at your option. diff --git a/vendor/chrono/benches/chrono.rs b/vendor/chrono/benches/chrono.rs index 246271b81..216616b82 100644 --- a/vendor/chrono/benches/chrono.rs +++ b/vendor/chrono/benches/chrono.rs @@ -64,7 +64,7 @@ fn bench_year_flags_from_year(c: &mut Criterion) { c.bench_function("bench_year_flags_from_year", |b| { b.iter(|| { for year in -999i32..1000 { - __BenchYearFlags::from_year(year); + let _ = __BenchYearFlags::from_year(black_box(year)); } }) }); diff --git a/vendor/chrono/clippy.toml b/vendor/chrono/clippy.toml deleted file mode 100644 index 749c3b58a..000000000 --- a/vendor/chrono/clippy.toml +++ /dev/null @@ -1 +0,0 @@ -msrv = "1.38" diff --git a/vendor/chrono/src/date.rs b/vendor/chrono/src/date.rs index bad4bfbb8..962555651 100644 --- a/vendor/chrono/src/date.rs +++ b/vendor/chrono/src/date.rs @@ -77,6 +77,7 @@ impl<Tz: TimeZone> Date<Tz> { // // note: this constructor is purposely not named to `new` to discourage the direct usage. #[inline] + #[must_use] pub fn from_utc(date: NaiveDate, offset: Tz::Offset) -> Date<Tz> { Date { date, offset } } @@ -86,6 +87,7 @@ impl<Tz: TimeZone> Date<Tz> { /// /// Panics on invalid datetime. #[inline] + #[must_use] pub fn and_time(&self, time: NaiveTime) -> Option<DateTime<Tz>> { let localdt = self.naive_local().and_time(time); self.timezone().from_local_datetime(&localdt).single() @@ -97,6 +99,7 @@ impl<Tz: TimeZone> Date<Tz> { /// Panics on invalid hour, minute and/or second. #[deprecated(since = "0.4.23", note = "Use and_hms_opt() instead")] #[inline] + #[must_use] pub fn and_hms(&self, hour: u32, min: u32, sec: u32) -> DateTime<Tz> { self.and_hms_opt(hour, min, sec).expect("invalid time") } @@ -106,6 +109,7 @@ impl<Tz: TimeZone> Date<Tz> { /// /// Returns `None` on invalid hour, minute and/or second. #[inline] + #[must_use] pub fn and_hms_opt(&self, hour: u32, min: u32, sec: u32) -> Option<DateTime<Tz>> { NaiveTime::from_hms_opt(hour, min, sec).and_then(|time| self.and_time(time)) } @@ -117,6 +121,7 @@ impl<Tz: TimeZone> Date<Tz> { /// Panics on invalid hour, minute, second and/or millisecond. #[deprecated(since = "0.4.23", note = "Use and_hms_milli_opt() instead")] #[inline] + #[must_use] pub fn and_hms_milli(&self, hour: u32, min: u32, sec: u32, milli: u32) -> DateTime<Tz> { self.and_hms_milli_opt(hour, min, sec, milli).expect("invalid time") } @@ -127,6 +132,7 @@ impl<Tz: TimeZone> Date<Tz> { /// /// Returns `None` on invalid hour, minute, second and/or millisecond. #[inline] + #[must_use] pub fn and_hms_milli_opt( &self, hour: u32, @@ -144,6 +150,7 @@ impl<Tz: TimeZone> Date<Tz> { /// Panics on invalid hour, minute, second and/or microsecond. #[deprecated(since = "0.4.23", note = "Use and_hms_micro_opt() instead")] #[inline] + #[must_use] pub fn and_hms_micro(&self, hour: u32, min: u32, sec: u32, micro: u32) -> DateTime<Tz> { self.and_hms_micro_opt(hour, min, sec, micro).expect("invalid time") } @@ -154,6 +161,7 @@ impl<Tz: TimeZone> Date<Tz> { /// /// Returns `None` on invalid hour, minute, second and/or microsecond. #[inline] + #[must_use] pub fn and_hms_micro_opt( &self, hour: u32, @@ -171,6 +179,7 @@ impl<Tz: TimeZone> Date<Tz> { /// Panics on invalid hour, minute, second and/or nanosecond. #[deprecated(since = "0.4.23", note = "Use and_hms_nano_opt() instead")] #[inline] + #[must_use] pub fn and_hms_nano(&self, hour: u32, min: u32, sec: u32, nano: u32) -> DateTime<Tz> { self.and_hms_nano_opt(hour, min, sec, nano).expect("invalid time") } @@ -181,6 +190,7 @@ impl<Tz: TimeZone> Date<Tz> { /// /// Returns `None` on invalid hour, minute, second and/or nanosecond. #[inline] + #[must_use] pub fn and_hms_nano_opt( &self, hour: u32, @@ -196,6 +206,7 @@ impl<Tz: TimeZone> Date<Tz> { /// Panics when `self` is the last representable date. #[deprecated(since = "0.4.23", note = "Use succ_opt() instead")] #[inline] + #[must_use] pub fn succ(&self) -> Date<Tz> { self.succ_opt().expect("out of bound") } @@ -204,6 +215,7 @@ impl<Tz: TimeZone> Date<Tz> { /// /// Returns `None` when `self` is the last representable date. #[inline] + #[must_use] pub fn succ_opt(&self) -> Option<Date<Tz>> { self.date.succ_opt().map(|date| Date::from_utc(date, self.offset.clone())) } @@ -213,6 +225,7 @@ impl<Tz: TimeZone> Date<Tz> { /// Panics when `self` is the first representable date. #[deprecated(since = "0.4.23", note = "Use pred_opt() instead")] #[inline] + #[must_use] pub fn pred(&self) -> Date<Tz> { self.pred_opt().expect("out of bound") } @@ -221,18 +234,21 @@ impl<Tz: TimeZone> Date<Tz> { /// /// Returns `None` when `self` is the first representable date. #[inline] + #[must_use] pub fn pred_opt(&self) -> Option<Date<Tz>> { self.date.pred_opt().map(|date| Date::from_utc(date, self.offset.clone())) } /// Retrieves an associated offset from UTC. #[inline] + #[must_use] pub fn offset(&self) -> &Tz::Offset { &self.offset } /// Retrieves an associated time zone. #[inline] + #[must_use] pub fn timezone(&self) -> Tz { TimeZone::from_offset(&self.offset) } @@ -240,6 +256,7 @@ impl<Tz: TimeZone> Date<Tz> { /// Changes the associated time zone. /// This does not change the actual `Date` (but will change the string representation). #[inline] + #[must_use] pub fn with_timezone<Tz2: TimeZone>(&self, tz: &Tz2) -> Date<Tz2> { tz.from_utc_date(&self.date) } @@ -248,6 +265,7 @@ impl<Tz: TimeZone> Date<Tz> { /// /// Returns `None` when it will result in overflow. #[inline] + #[must_use] pub fn checked_add_signed(self, rhs: OldDuration) -> Option<Date<Tz>> { let date = self.date.checked_add_signed(rhs)?; Some(Date { date, offset: self.offset }) @@ -257,6 +275,7 @@ impl<Tz: TimeZone> Date<Tz> { /// /// Returns `None` when it will result in overflow. #[inline] + #[must_use] pub fn checked_sub_signed(self, rhs: OldDuration) -> Option<Date<Tz>> { let date = self.date.checked_sub_signed(rhs)?; Some(Date { date, offset: self.offset }) @@ -268,12 +287,14 @@ impl<Tz: TimeZone> Date<Tz> { /// This does not overflow or underflow at all, /// as all possible output fits in the range of `Duration`. #[inline] + #[must_use] pub fn signed_duration_since<Tz2: TimeZone>(self, rhs: Date<Tz2>) -> OldDuration { self.date.signed_duration_since(rhs.date) } /// Returns a view to the naive UTC date. #[inline] + #[must_use] pub fn naive_utc(&self) -> NaiveDate { self.date } @@ -284,11 +305,13 @@ impl<Tz: TimeZone> Date<Tz> { /// because the offset is restricted to never exceed one day, /// but provided for the consistency. #[inline] + #[must_use] pub fn naive_local(&self) -> NaiveDate { self.date } /// Returns the number of whole years from the given `base` until `self`. + #[must_use] pub fn years_since(&self, base: Self) -> Option<u32> { self.date.years_since(base.date) } @@ -315,6 +338,7 @@ where #[cfg(any(feature = "alloc", feature = "std", test))] #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))] #[inline] + #[must_use] pub fn format_with_items<'a, I, B>(&self, items: I) -> DelayedFormat<I> where I: Iterator<Item = B> + Clone, @@ -329,6 +353,7 @@ where #[cfg(any(feature = "alloc", feature = "std", test))] #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))] #[inline] + #[must_use] pub fn format<'a>(&self, fmt: &'a str) -> DelayedFormat<StrftimeItems<'a>> { self.format_with_items(StrftimeItems::new(fmt)) } @@ -337,6 +362,7 @@ where #[cfg(feature = "unstable-locales")] #[cfg_attr(docsrs, doc(cfg(feature = "unstable-locales")))] #[inline] + #[must_use] pub fn format_localized_with_items<'a, I, B>( &self, items: I, @@ -361,6 +387,7 @@ where #[cfg(feature = "unstable-locales")] #[cfg_attr(docsrs, doc(cfg(feature = "unstable-locales")))] #[inline] + #[must_use] pub fn format_localized<'a>( &self, fmt: &'a str, diff --git a/vendor/chrono/src/datetime/mod.rs b/vendor/chrono/src/datetime/mod.rs index 38416cb6f..65a39aa8d 100644 --- a/vendor/chrono/src/datetime/mod.rs +++ b/vendor/chrono/src/datetime/mod.rs @@ -23,7 +23,7 @@ use std::time::{SystemTime, UNIX_EPOCH}; use crate::format::DelayedFormat; #[cfg(feature = "unstable-locales")] use crate::format::Locale; -use crate::format::{parse, ParseError, ParseResult, Parsed, StrftimeItems}; +use crate::format::{parse, parse_and_remainder, ParseError, ParseResult, Parsed, StrftimeItems}; use crate::format::{Fixed, Item}; use crate::naive::{Days, IsoWeek, NaiveDate, NaiveDateTime, NaiveTime}; #[cfg(feature = "clock")] @@ -113,6 +113,7 @@ impl<Tz: TimeZone> DateTime<Tz> { // // note: this constructor is purposely not named to `new` to discourage the direct usage. #[inline] + #[must_use] pub fn from_utc(datetime: NaiveDateTime, offset: Tz::Offset) -> DateTime<Tz> { DateTime { datetime, offset } } @@ -142,6 +143,7 @@ impl<Tz: TimeZone> DateTime<Tz> { /// assert_eq!(datetime_west, datetime_utc.with_timezone(&timezone_west)); /// ``` #[inline] + #[must_use] pub fn from_local(datetime: NaiveDateTime, offset: Tz::Offset) -> DateTime<Tz> { let datetime_utc = datetime - offset.fix(); @@ -156,6 +158,7 @@ impl<Tz: TimeZone> DateTime<Tz> { #[inline] #[deprecated(since = "0.4.23", note = "Use `date_naive()` instead")] #[allow(deprecated)] + #[must_use] pub fn date(&self) -> Date<Tz> { Date::from_utc(self.naive_local().date(), self.offset.clone()) } @@ -173,6 +176,7 @@ impl<Tz: TimeZone> DateTime<Tz> { /// assert_eq!(date.date_naive(), other.date_naive()); /// ``` #[inline] + #[must_use] pub fn date_naive(&self) -> NaiveDate { let local = self.naive_local(); NaiveDate::from_ymd_opt(local.year(), local.month(), local.day()).unwrap() @@ -181,6 +185,7 @@ impl<Tz: TimeZone> DateTime<Tz> { /// Retrieves a time component. /// Unlike `date`, this is not associated to the time zone. #[inline] + #[must_use] pub fn time(&self) -> NaiveTime { self.datetime.time() + self.offset.fix() } @@ -188,6 +193,7 @@ impl<Tz: TimeZone> DateTime<Tz> { /// Returns the number of non-leap seconds since January 1, 1970 0:00:00 UTC /// (aka "UNIX timestamp"). #[inline] + #[must_use] pub fn timestamp(&self) -> i64 { self.datetime.timestamp() } @@ -202,7 +208,7 @@ impl<Tz: TimeZone> DateTime<Tz> { /// # Example /// /// ``` - /// use chrono::{Utc, TimeZone, NaiveDate}; + /// use chrono::{Utc, NaiveDate}; /// /// let dt = NaiveDate::from_ymd_opt(1970, 1, 1).unwrap().and_hms_milli_opt(0, 0, 1, 444).unwrap().and_local_timezone(Utc).unwrap(); /// assert_eq!(dt.timestamp_millis(), 1_444); @@ -211,6 +217,7 @@ impl<Tz: TimeZone> DateTime<Tz> { /// assert_eq!(dt.timestamp_millis(), 1_000_000_000_555); /// ``` #[inline] + #[must_use] pub fn timestamp_millis(&self) -> i64 { self.datetime.timestamp_millis() } @@ -225,7 +232,7 @@ impl<Tz: TimeZone> DateTime<Tz> { /// # Example /// /// ``` - /// use chrono::{Utc, TimeZone, NaiveDate}; + /// use chrono::{Utc, NaiveDate}; /// /// let dt = NaiveDate::from_ymd_opt(1970, 1, 1).unwrap().and_hms_micro_opt(0, 0, 1, 444).unwrap().and_local_timezone(Utc).unwrap(); /// assert_eq!(dt.timestamp_micros(), 1_000_444); @@ -234,6 +241,7 @@ impl<Tz: TimeZone> DateTime<Tz> { /// assert_eq!(dt.timestamp_micros(), 1_000_000_000_000_555); /// ``` #[inline] + #[must_use] pub fn timestamp_micros(&self) -> i64 { self.datetime.timestamp_micros() } @@ -248,7 +256,7 @@ impl<Tz: TimeZone> DateTime<Tz> { /// # Example /// /// ``` - /// use chrono::{Utc, TimeZone, NaiveDate}; + /// use chrono::{Utc, NaiveDate}; /// /// let dt = NaiveDate::from_ymd_opt(1970, 1, 1).unwrap().and_hms_nano_opt(0, 0, 1, 444).unwrap().and_local_timezone(Utc).unwrap(); /// assert_eq!(dt.timestamp_nanos(), 1_000_000_444); @@ -257,6 +265,7 @@ impl<Tz: TimeZone> DateTime<Tz> { /// assert_eq!(dt.timestamp_nanos(), 1_000_000_000_000_000_555); /// ``` #[inline] + #[must_use] pub fn timestamp_nanos(&self) -> i64 { self.datetime.timestamp_nanos() } @@ -267,6 +276,7 @@ impl<Tz: TimeZone> DateTime<Tz> { /// /// note: this is not the number of milliseconds since January 1, 1970 0:00:00 UTC #[inline] + #[must_use] pub fn timestamp_subsec_millis(&self) -> u32 { self.datetime.timestamp_subsec_millis() } @@ -277,6 +287,7 @@ impl<Tz: TimeZone> DateTime<Tz> { /// /// note: this is not the number of microseconds since January 1, 1970 0:00:00 UTC #[inline] + #[must_use] pub fn timestamp_subsec_micros(&self) -> u32 { self.datetime.timestamp_subsec_micros() } @@ -287,18 +298,21 @@ impl<Tz: TimeZone> DateTime<Tz> { /// /// note: this is not the number of nanoseconds since January 1, 1970 0:00:00 UTC #[inline] + #[must_use] pub fn timestamp_subsec_nanos(&self) -> u32 { self.datetime.timestamp_subsec_nanos() } /// Retrieves an associated offset from UTC. #[inline] + #[must_use] pub fn offset(&self) -> &Tz::Offset { &self.offset } /// Retrieves an associated time zone. #[inline] + #[must_use] pub fn timezone(&self) -> Tz { TimeZone::from_offset(&self.offset) } @@ -306,14 +320,24 @@ impl<Tz: TimeZone> DateTime<Tz> { /// Changes the associated time zone. /// The returned `DateTime` references the same instant of time from the perspective of the provided time zone. #[inline] + #[must_use] pub fn with_timezone<Tz2: TimeZone>(&self, tz: &Tz2) -> DateTime<Tz2> { tz.from_utc_datetime(&self.datetime) } + /// Fix the offset from UTC to its current value, dropping the associated timezone information. + /// This it useful for converting a generic `DateTime<Tz: Timezone>` to `DateTime<FixedOffset>`. + #[inline] + #[must_use] + pub fn fixed_offset(&self) -> DateTime<FixedOffset> { + self.with_timezone(&self.offset().fix()) + } + /// Adds given `Duration` to the current date and time. /// /// Returns `None` when it will result in overflow. #[inline] + #[must_use] pub fn checked_add_signed(self, rhs: OldDuration) -> Option<DateTime<Tz>> { let datetime = self.datetime.checked_add_signed(rhs)?; let tz = self.timezone(); @@ -326,6 +350,7 @@ impl<Tz: TimeZone> DateTime<Tz> { /// local time is not valid on the newly calculated date. /// /// See [`NaiveDate::checked_add_months`] for more details on behavior + #[must_use] pub fn checked_add_months(self, rhs: Months) -> Option<DateTime<Tz>> { self.naive_local() .checked_add_months(rhs)? @@ -337,6 +362,7 @@ impl<Tz: TimeZone> DateTime<Tz> { /// /// Returns `None` when it will result in overflow. #[inline] + #[must_use] pub fn checked_sub_signed(self, rhs: OldDuration) -> Option<DateTime<Tz>> { let datetime = self.datetime.checked_sub_signed(rhs)?; let tz = self.timezone(); @@ -349,6 +375,7 @@ impl<Tz: TimeZone> DateTime<Tz> { /// local time is not valid on the newly calculated date. /// /// See [`NaiveDate::checked_sub_months`] for more details on behavior + #[must_use] pub fn checked_sub_months(self, rhs: Months) -> Option<DateTime<Tz>> { self.naive_local() .checked_sub_months(rhs)? @@ -359,6 +386,7 @@ impl<Tz: TimeZone> DateTime<Tz> { /// Add a duration in [`Days`] to the date part of the `DateTime` /// /// Returns `None` if the resulting date would be out of range. + #[must_use] pub fn checked_add_days(self, days: Days) -> Option<Self> { self.naive_local() .checked_add_days(days)? @@ -369,6 +397,7 @@ impl<Tz: TimeZone> DateTime<Tz> { /// Subtract a duration in [`Days`] from the date part of the `DateTime` /// /// Returns `None` if the resulting date would be out of range. + #[must_use] pub fn checked_sub_days(self, days: Days) -> Option<Self> { self.naive_local() .checked_sub_days(days)? @@ -379,23 +408,27 @@ impl<Tz: TimeZone> DateTime<Tz> { /// Subtracts another `DateTime` from the current date and time. /// This does not overflow or underflow at all. #[inline] + #[must_use] pub fn signed_duration_since<Tz2: TimeZone>(self, rhs: DateTime<Tz2>) -> OldDuration { self.datetime.signed_duration_since(rhs.datetime) } /// Returns a view to the naive UTC datetime. #[inline] + #[must_use] pub fn naive_utc(&self) -> NaiveDateTime { self.datetime } /// Returns a view to the naive local datetime. #[inline] + #[must_use] pub fn naive_local(&self) -> NaiveDateTime { self.datetime + self.offset.fix() } /// Retrieve the elapsed years from now to the given [`DateTime`]. + #[must_use] pub fn years_since(&self, base: Self) -> Option<u32> { let mut years = self.year() - base.year(); let earlier_time = @@ -504,10 +537,9 @@ impl From<DateTime<Local>> for DateTime<Utc> { impl From<DateTime<Local>> for DateTime<FixedOffset> { /// Convert this `DateTime<Local>` instance into a `DateTime<FixedOffset>` instance. /// - /// Conversion is performed via [`DateTime::with_timezone`]. Note that the converted value returned - /// by this will be created with a fixed timezone offset of 0. + /// Conversion is performed via [`DateTime::with_timezone`]. fn from(src: DateTime<Local>) -> Self { - src.with_timezone(&FixedOffset::east_opt(0).unwrap()) + src.with_timezone(&src.offset().fix()) } } @@ -520,14 +552,16 @@ where } impl DateTime<FixedOffset> { - /// Parses an RFC 2822 date and time string such as `Tue, 1 Jul 2003 10:52:37 +0200`, - /// then returns a new [`DateTime`] with a parsed [`FixedOffset`]. + /// Parses an RFC 2822 date-and-time string into a `DateTime<FixedOffset>` value. /// - /// RFC 2822 is the internet message standard that specifies the - /// representation of times in HTTP and email headers. + /// This parses valid RFC 2822 datetime strings (such as `Tue, 1 Jul 2003 10:52:37 +0200`) + /// and returns a new [`DateTime`] instance with the parsed timezone as the [`FixedOffset`]. + /// + /// RFC 2822 is the internet message standard that specifies the representation of times in HTTP + /// and email headers. /// /// ``` - /// # use chrono::{DateTime, FixedOffset, TimeZone, NaiveDate}; + /// # use chrono::{DateTime, FixedOffset, TimeZone}; /// assert_eq!( /// DateTime::parse_from_rfc2822("Wed, 18 Feb 2015 23:16:09 GMT").unwrap(), /// FixedOffset::east_opt(0).unwrap().with_ymd_and_hms(2015, 2, 18, 23, 16, 9).unwrap() @@ -540,11 +574,19 @@ impl DateTime<FixedOffset> { parsed.to_datetime() } - /// Parses an RFC 3339 and ISO 8601 date and time string such as `1996-12-19T16:39:57-08:00`, - /// then returns a new [`DateTime`] with a parsed [`FixedOffset`]. + /// Parses an RFC 3339 date-and-time string into a `DateTime<FixedOffset>` value. + /// + /// Parses all valid RFC 3339 values (as well as the subset of valid ISO 8601 values that are + /// also valid RFC 3339 date-and-time values) and returns a new [`DateTime`] with a + /// [`FixedOffset`] corresponding to the parsed timezone. While RFC 3339 values come in a wide + /// variety of shapes and sizes, `1996-12-19T16:39:57-08:00` is an example of the most commonly + /// encountered variety of RFC 3339 formats. /// - /// Why isn't this named `parse_from_iso8601`? That's because ISO 8601 allows some freedom - /// over the syntax and RFC 3339 exercises that freedom to rigidly define a fixed format. + /// Why isn't this named `parse_from_iso8601`? That's because ISO 8601 allows representing + /// values in a wide range of formats, only some of which represent actual date-and-time + /// instances (rather than periods, ranges, dates, or times). Some valid ISO 8601 values are + /// also simultaneously valid RFC 3339 values, but not all RFC 3339 values are valid ISO 8601 + /// values (or the other way around). pub fn parse_from_rfc3339(s: &str) -> ParseResult<DateTime<FixedOffset>> { const ITEMS: &[Item<'static>] = &[Item::Fixed(Fixed::RFC3339)]; let mut parsed = Parsed::new(); @@ -552,18 +594,15 @@ impl DateTime<FixedOffset> { parsed.to_datetime() } - /// Parses a string with the specified format string and returns a new - /// [`DateTime`] with a parsed [`FixedOffset`]. + /// Parses a string from a user-specified format into a `DateTime<FixedOffset>` value. /// - /// See the [`crate::format::strftime`] module on the supported escape - /// sequences. - /// - /// See also [`TimeZone::datetime_from_str`] which gives a local - /// [`DateTime`] on specific time zone. + /// Note that this method *requires a timezone* in the input string. See + /// [`NaiveDateTime::parse_from_str`](./naive/struct.NaiveDateTime.html#method.parse_from_str) + /// for a version that does not require a timezone in the to-be-parsed str. The returned + /// [`DateTime`] value will have a [`FixedOffset`] reflecting the parsed timezone. /// - /// Note that this method *requires a timezone* in the string. See - /// [`NaiveDateTime::parse_from_str`] - /// for a version that does not require a timezone in the to-be-parsed str. + /// See the [`format::strftime` module](./format/strftime/index.html) for supported format + /// sequences. /// /// # Example /// @@ -579,6 +618,40 @@ impl DateTime<FixedOffset> { parse(&mut parsed, s, StrftimeItems::new(fmt))?; parsed.to_datetime() } + + /// Parses a string from a user-specified format into a `DateTime<FixedOffset>` value, and a + /// slice with the remaining portion of the string. + /// + /// Note that this method *requires a timezone* in the input string. See + /// [`NaiveDateTime::parse_and_remainder`] for a version that does not + /// require a timezone in `s`. The returned [`DateTime`] value will have a [`FixedOffset`] + /// reflecting the parsed timezone. + /// + /// See the [`format::strftime` module](./format/strftime/index.html) for supported format + /// sequences. + /// + /// Similar to [`parse_from_str`](#method.parse_from_str). + /// + /// # Example + /// + /// ```rust + /// # use chrono::{DateTime, FixedOffset, TimeZone}; + /// let (datetime, remainder) = DateTime::parse_and_remainder( + /// "2015-02-18 23:16:09 +0200 trailing text", "%Y-%m-%d %H:%M:%S %z").unwrap(); + /// assert_eq!( + /// datetime, + /// FixedOffset::east_opt(2*3600).unwrap().with_ymd_and_hms(2015, 2, 18, 23, 16, 9).unwrap() + /// ); + /// assert_eq!(remainder, " trailing text"); + /// ``` + pub fn parse_and_remainder<'a>( + s: &'a str, + fmt: &str, + ) -> ParseResult<(DateTime<FixedOffset>, &'a str)> { + let mut parsed = Parsed::new(); + let remainder = parse_and_remainder(&mut parsed, s, StrftimeItems::new(fmt))?; + parsed.to_datetime().map(|d| (d, remainder)) + } } impl<Tz: TimeZone> DateTime<Tz> @@ -588,6 +661,7 @@ where /// Returns an RFC 2822 date and time string such as `Tue, 1 Jul 2003 10:52:37 +0200`. #[cfg(any(feature = "alloc", feature = "std", test))] #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))] + #[must_use] pub fn to_rfc2822(&self) -> String { let mut result = String::with_capacity(32); crate::format::write_rfc2822(&mut result, self.naive_local(), self.offset.fix()) @@ -598,6 +672,7 @@ where /// Returns an RFC 3339 and ISO 8601 date and time string such as `1996-12-19T16:39:57-08:00`. #[cfg(any(feature = "alloc", feature = "std", test))] #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))] + #[must_use] pub fn to_rfc3339(&self) -> String { let mut result = String::with_capacity(32); crate::format::write_rfc3339(&mut result, self.naive_local(), self.offset.fix()) @@ -606,16 +681,16 @@ where } /// Return an RFC 3339 and ISO 8601 date and time string with subseconds - /// formatted as per a `SecondsFormat`. + /// formatted as per `SecondsFormat`. /// - /// If passed `use_z` true and the timezone is UTC (offset 0), use 'Z', as - /// per [`Fixed::TimezoneOffsetColonZ`] If passed `use_z` false, use + /// If `use_z` is true and the timezone is UTC (offset 0), uses `Z` as + /// per [`Fixed::TimezoneOffsetColonZ`]. If `use_z` is false, uses /// [`Fixed::TimezoneOffsetColon`] /// /// # Examples /// /// ```rust - /// # use chrono::{DateTime, FixedOffset, SecondsFormat, TimeZone, Utc, NaiveDate}; + /// # use chrono::{FixedOffset, SecondsFormat, TimeZone, Utc, NaiveDate}; /// let dt = NaiveDate::from_ymd_opt(2018, 1, 26).unwrap().and_hms_micro_opt(18, 30, 9, 453_829).unwrap().and_local_timezone(Utc).unwrap(); /// assert_eq!(dt.to_rfc3339_opts(SecondsFormat::Millis, false), /// "2018-01-26T18:30:09.453+00:00"); @@ -631,6 +706,7 @@ where /// ``` #[cfg(any(feature = "alloc", feature = "std", test))] #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))] + #[must_use] pub fn to_rfc3339_opts(&self, secform: SecondsFormat, use_z: bool) -> String { use crate::format::Numeric::*; use crate::format::Pad::Zero; @@ -677,6 +753,7 @@ where #[cfg(any(feature = "alloc", feature = "std", test))] #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))] #[inline] + #[must_use] pub fn format_with_items<'a, I, B>(&self, items: I) -> DelayedFormat<I> where I: Iterator<Item = B> + Clone, @@ -686,9 +763,9 @@ where DelayedFormat::new_with_offset(Some(local.date()), Some(local.time()), &self.offset, items) } - /// Formats the combined date and time with the specified format string. - /// See the [`crate::format::strftime`] module - /// on the supported escape sequences. + /// Formats the combined date and time per the specified format string. + /// + /// See the [`crate::format::strftime`] module for the supported escape sequences. /// /// # Example /// ```rust @@ -701,6 +778,7 @@ where #[cfg(any(feature = "alloc", feature = "std", test))] #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))] #[inline] + #[must_use] pub fn format<'a>(&self, fmt: &'a str) -> DelayedFormat<StrftimeItems<'a>> { self.format_with_items(StrftimeItems::new(fmt)) } @@ -709,6 +787,7 @@ where #[cfg(feature = "unstable-locales")] #[cfg_attr(docsrs, doc(cfg(feature = "unstable-locales")))] #[inline] + #[must_use] pub fn format_localized_with_items<'a, I, B>( &self, items: I, @@ -728,7 +807,7 @@ where ) } - /// Formats the combined date and time with the specified format string and + /// Formats the combined date and time per the specified format string and /// locale. /// /// See the [`crate::format::strftime`] module on the supported escape @@ -736,6 +815,7 @@ where #[cfg(feature = "unstable-locales")] #[cfg_attr(docsrs, doc(cfg(feature = "unstable-locales")))] #[inline] + #[must_use] pub fn format_localized<'a>( &self, fmt: &'a str, @@ -1002,14 +1082,16 @@ where /// Accepts a relaxed form of RFC3339. /// A space or a 'T' are acepted as the separator between the date and time -/// parts. Additional spaces are allowed between each component. +/// parts. /// /// All of these examples are equivalent: /// ``` /// # use chrono::{DateTime, Utc}; -/// "2012-12-12T12:12:12Z".parse::<DateTime<Utc>>(); -/// "2012-12-12 12:12:12Z".parse::<DateTime<Utc>>(); -/// "2012- 12-12T12: 12:12Z".parse::<DateTime<Utc>>(); +/// "2012-12-12T12:12:12Z".parse::<DateTime<Utc>>()?; +/// "2012-12-12 12:12:12Z".parse::<DateTime<Utc>>()?; +/// "2012-12-12 12:12:12+0000".parse::<DateTime<Utc>>()?; +/// "2012-12-12 12:12:12+00:00".parse::<DateTime<Utc>>()?; +/// # Ok::<(), chrono::ParseError>(()) /// ``` impl str::FromStr for DateTime<Utc> { type Err = ParseError; @@ -1021,14 +1103,16 @@ impl str::FromStr for DateTime<Utc> { /// Accepts a relaxed form of RFC3339. /// A space or a 'T' are acepted as the separator between the date and time -/// parts. Additional spaces are allowed between each component. +/// parts. /// /// All of these examples are equivalent: /// ``` /// # use chrono::{DateTime, Local}; -/// "2012-12-12T12:12:12Z".parse::<DateTime<Local>>(); -/// "2012-12-12 12:12:12Z".parse::<DateTime<Local>>(); -/// "2012- 12-12T12: 12:12Z".parse::<DateTime<Local>>(); +/// "2012-12-12T12:12:12Z".parse::<DateTime<Local>>()?; +/// "2012-12-12 12:12:12Z".parse::<DateTime<Local>>()?; +/// "2012-12-12 12:12:12+0000".parse::<DateTime<Local>>()?; +/// "2012-12-12 12:12:12+00:00".parse::<DateTime<Local>>()?; +/// # Ok::<(), chrono::ParseError>(()) /// ``` #[cfg(feature = "clock")] #[cfg_attr(docsrs, doc(cfg(feature = "clock")))] diff --git a/vendor/chrono/src/datetime/serde.rs b/vendor/chrono/src/datetime/serde.rs index ab0126e2b..72ada0cca 100644 --- a/vendor/chrono/src/datetime/serde.rs +++ b/vendor/chrono/src/datetime/serde.rs @@ -122,7 +122,7 @@ impl<'de> de::Deserialize<'de> for DateTime<Local> { /// # Example: /// /// ```rust -/// # use chrono::{TimeZone, DateTime, Utc, NaiveDate}; +/// # use chrono::{DateTime, Utc, NaiveDate}; /// # use serde_derive::{Deserialize, Serialize}; /// use chrono::serde::ts_nanoseconds; /// #[derive(Deserialize, Serialize)] @@ -158,7 +158,7 @@ pub mod ts_nanoseconds { /// # Example: /// /// ```rust - /// # use chrono::{TimeZone, DateTime, Utc, NaiveDate}; + /// # use chrono::{DateTime, Utc, NaiveDate}; /// # use serde_derive::Serialize; /// use chrono::serde::ts_nanoseconds::serialize as to_nano_ts; /// #[derive(Serialize)] @@ -174,6 +174,7 @@ pub mod ts_nanoseconds { /// assert_eq!(as_string, r#"{"time":1526522699918355733}"#); /// # Ok::<(), serde_json::Error>(()) /// ``` + #[must_use] pub fn serialize<S>(dt: &DateTime<Utc>, serializer: S) -> Result<S::Ok, S::Error> where S: ser::Serializer, @@ -188,18 +189,20 @@ pub mod ts_nanoseconds { /// # Example: /// /// ```rust - /// # use chrono::{DateTime, Utc}; + /// # use chrono::{DateTime, TimeZone, Utc}; /// # use serde_derive::Deserialize; /// use chrono::serde::ts_nanoseconds::deserialize as from_nano_ts; - /// #[derive(Deserialize)] + /// #[derive(Debug, PartialEq, Deserialize)] /// struct S { /// #[serde(deserialize_with = "from_nano_ts")] /// time: DateTime<Utc> /// } /// /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918355733 }"#)?; + /// assert_eq!(my_s, S { time: Utc.timestamp_opt(1526522699, 918355733).unwrap() }); /// # Ok::<(), serde_json::Error>(()) /// ``` + #[must_use] pub fn deserialize<'de, D>(d: D) -> Result<DateTime<Utc>, D::Error> where D: de::Deserializer<'de>, @@ -245,7 +248,7 @@ pub mod ts_nanoseconds { /// # Example: /// /// ```rust -/// # use chrono::{TimeZone, DateTime, Utc, NaiveDate}; +/// # use chrono::{DateTime, Utc, NaiveDate}; /// # use serde_derive::{Deserialize, Serialize}; /// use chrono::serde::ts_nanoseconds_option; /// #[derive(Deserialize, Serialize)] @@ -280,7 +283,7 @@ pub mod ts_nanoseconds_option { /// # Example: /// /// ```rust - /// # use chrono::{TimeZone, DateTime, Utc, NaiveDate}; + /// # use chrono::{DateTime, Utc, NaiveDate}; /// # use serde_derive::Serialize; /// use chrono::serde::ts_nanoseconds_option::serialize as to_nano_tsopt; /// #[derive(Serialize)] @@ -296,6 +299,7 @@ pub mod ts_nanoseconds_option { /// assert_eq!(as_string, r#"{"time":1526522699918355733}"#); /// # Ok::<(), serde_json::Error>(()) /// ``` + #[must_use] pub fn serialize<S>(opt: &Option<DateTime<Utc>>, serializer: S) -> Result<S::Ok, S::Error> where S: ser::Serializer, @@ -313,18 +317,20 @@ pub mod ts_nanoseconds_option { /// # Example: /// /// ```rust - /// # use chrono::{DateTime, Utc}; + /// # use chrono::{DateTime, TimeZone, Utc}; /// # use serde_derive::Deserialize; /// use chrono::serde::ts_nanoseconds_option::deserialize as from_nano_tsopt; - /// #[derive(Deserialize)] + /// #[derive(Debug, PartialEq, Deserialize)] /// struct S { /// #[serde(deserialize_with = "from_nano_tsopt")] /// time: Option<DateTime<Utc>> /// } /// /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918355733 }"#)?; + /// assert_eq!(my_s, S { time: Utc.timestamp_opt(1526522699, 918355733).single() }); /// # Ok::<(), serde_json::Error>(()) /// ``` + #[must_use] pub fn deserialize<'de, D>(d: D) -> Result<Option<DateTime<Utc>>, D::Error> where D: de::Deserializer<'de>, @@ -374,7 +380,7 @@ pub mod ts_nanoseconds_option { /// # Example: /// /// ```rust -/// # use chrono::{TimeZone, DateTime, Utc, NaiveDate}; +/// # use chrono::{DateTime, Utc, NaiveDate}; /// # use serde_derive::{Deserialize, Serialize}; /// use chrono::serde::ts_microseconds; /// #[derive(Deserialize, Serialize)] @@ -409,7 +415,7 @@ pub mod ts_microseconds { /// # Example: /// /// ```rust - /// # use chrono::{TimeZone, DateTime, Utc, NaiveDate}; + /// # use chrono::{DateTime, Utc, NaiveDate}; /// # use serde_derive::Serialize; /// use chrono::serde::ts_microseconds::serialize as to_micro_ts; /// #[derive(Serialize)] @@ -425,6 +431,7 @@ pub mod ts_microseconds { /// assert_eq!(as_string, r#"{"time":1526522699918355}"#); /// # Ok::<(), serde_json::Error>(()) /// ``` + #[must_use] pub fn serialize<S>(dt: &DateTime<Utc>, serializer: S) -> Result<S::Ok, S::Error> where S: ser::Serializer, @@ -439,18 +446,20 @@ pub mod ts_microseconds { /// # Example: /// /// ```rust - /// # use chrono::{DateTime, Utc}; + /// # use chrono::{DateTime, TimeZone, Utc}; /// # use serde_derive::Deserialize; /// use chrono::serde::ts_microseconds::deserialize as from_micro_ts; - /// #[derive(Deserialize)] + /// #[derive(Debug, PartialEq, Deserialize)] /// struct S { /// #[serde(deserialize_with = "from_micro_ts")] /// time: DateTime<Utc> /// } /// /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918355 }"#)?; + /// assert_eq!(my_s, S { time: Utc.timestamp_opt(1526522699, 918355000).unwrap() }); /// # Ok::<(), serde_json::Error>(()) /// ``` + #[must_use] pub fn deserialize<'de, D>(d: D) -> Result<DateTime<Utc>, D::Error> where D: de::Deserializer<'de>, @@ -496,7 +505,7 @@ pub mod ts_microseconds { /// # Example: /// /// ```rust -/// # use chrono::{TimeZone, DateTime, Utc, NaiveDate}; +/// # use chrono::{DateTime, Utc, NaiveDate}; /// # use serde_derive::{Deserialize, Serialize}; /// use chrono::serde::ts_microseconds_option; /// #[derive(Deserialize, Serialize)] @@ -530,7 +539,7 @@ pub mod ts_microseconds_option { /// # Example: /// /// ```rust - /// # use chrono::{TimeZone, DateTime, Utc, NaiveDate}; + /// # use chrono::{DateTime, Utc, NaiveDate}; /// # use serde_derive::Serialize; /// use chrono::serde::ts_microseconds_option::serialize as to_micro_tsopt; /// #[derive(Serialize)] @@ -546,6 +555,7 @@ pub mod ts_microseconds_option { /// assert_eq!(as_string, r#"{"time":1526522699918355}"#); /// # Ok::<(), serde_json::Error>(()) /// ``` + #[must_use] pub fn serialize<S>(opt: &Option<DateTime<Utc>>, serializer: S) -> Result<S::Ok, S::Error> where S: ser::Serializer, @@ -563,18 +573,20 @@ pub mod ts_microseconds_option { /// # Example: /// /// ```rust - /// # use chrono::{DateTime, Utc}; + /// # use chrono::{DateTime, TimeZone, Utc}; /// # use serde_derive::Deserialize; /// use chrono::serde::ts_microseconds_option::deserialize as from_micro_tsopt; - /// #[derive(Deserialize)] + /// #[derive(Debug, PartialEq, Deserialize)] /// struct S { /// #[serde(deserialize_with = "from_micro_tsopt")] /// time: Option<DateTime<Utc>> /// } /// /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918355 }"#)?; + /// assert_eq!(my_s, S { time: Utc.timestamp_opt(1526522699, 918355000).single() }); /// # Ok::<(), serde_json::Error>(()) /// ``` + #[must_use] pub fn deserialize<'de, D>(d: D) -> Result<Option<DateTime<Utc>>, D::Error> where D: de::Deserializer<'de>, @@ -624,7 +636,7 @@ pub mod ts_microseconds_option { /// # Example /// /// ```rust -/// # use chrono::{TimeZone, DateTime, Utc, NaiveDate}; +/// # use chrono::{DateTime, Utc, NaiveDate}; /// # use serde_derive::{Deserialize, Serialize}; /// use chrono::serde::ts_milliseconds; /// #[derive(Deserialize, Serialize)] @@ -659,7 +671,7 @@ pub mod ts_milliseconds { /// # Example: /// /// ```rust - /// # use chrono::{TimeZone, DateTime, Utc, NaiveDate}; + /// # use chrono::{DateTime, Utc, NaiveDate}; /// # use serde_derive::Serialize; /// use chrono::serde::ts_milliseconds::serialize as to_milli_ts; /// #[derive(Serialize)] @@ -675,6 +687,7 @@ pub mod ts_milliseconds { /// assert_eq!(as_string, r#"{"time":1526522699918}"#); /// # Ok::<(), serde_json::Error>(()) /// ``` + #[must_use] pub fn serialize<S>(dt: &DateTime<Utc>, serializer: S) -> Result<S::Ok, S::Error> where S: ser::Serializer, @@ -689,18 +702,20 @@ pub mod ts_milliseconds { /// # Example: /// /// ```rust - /// # use chrono::{DateTime, Utc}; + /// # use chrono::{DateTime, TimeZone, Utc}; /// # use serde_derive::Deserialize; /// use chrono::serde::ts_milliseconds::deserialize as from_milli_ts; - /// #[derive(Deserialize)] + /// #[derive(Debug, PartialEq, Deserialize)] /// struct S { /// #[serde(deserialize_with = "from_milli_ts")] /// time: DateTime<Utc> /// } /// /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918 }"#)?; + /// assert_eq!(my_s, S { time: Utc.timestamp_opt(1526522699, 918000000).unwrap() }); /// # Ok::<(), serde_json::Error>(()) /// ``` + #[must_use] pub fn deserialize<'de, D>(d: D) -> Result<DateTime<Utc>, D::Error> where D: de::Deserializer<'de>, @@ -743,7 +758,7 @@ pub mod ts_milliseconds { /// # Example /// /// ```rust -/// # use chrono::{TimeZone, DateTime, Utc, NaiveDate}; +/// # use chrono::{DateTime, Utc, NaiveDate}; /// # use serde_derive::{Deserialize, Serialize}; /// use chrono::serde::ts_milliseconds_option; /// #[derive(Deserialize, Serialize)] @@ -777,7 +792,7 @@ pub mod ts_milliseconds_option { /// # Example: /// /// ```rust - /// # use chrono::{TimeZone, DateTime, Utc, NaiveDate}; + /// # use chrono::{DateTime, Utc, NaiveDate}; /// # use serde_derive::Serialize; /// use chrono::serde::ts_milliseconds_option::serialize as to_milli_tsopt; /// #[derive(Serialize)] @@ -793,6 +808,7 @@ pub mod ts_milliseconds_option { /// assert_eq!(as_string, r#"{"time":1526522699918}"#); /// # Ok::<(), serde_json::Error>(()) /// ``` + #[must_use] pub fn serialize<S>(opt: &Option<DateTime<Utc>>, serializer: S) -> Result<S::Ok, S::Error> where S: ser::Serializer, @@ -827,13 +843,14 @@ pub mod ts_milliseconds_option { /// } /// /// let my_s: E<S> = serde_json::from_str(r#"{ "time": 1526522699918 }"#)?; - /// assert_eq!(my_s, E::V(S { time: Some(Utc.timestamp(1526522699, 918000000)) })); + /// assert_eq!(my_s, E::V(S { time: Some(Utc.timestamp_opt(1526522699, 918000000).unwrap()) })); /// let s: E<S> = serde_json::from_str(r#"{ "time": null }"#)?; /// assert_eq!(s, E::V(S { time: None })); /// let t: E<S> = serde_json::from_str(r#"{}"#)?; /// assert_eq!(t, E::V(S { time: None })); /// # Ok::<(), serde_json::Error>(()) /// ``` + #[must_use] pub fn deserialize<'de, D>(d: D) -> Result<Option<DateTime<Utc>>, D::Error> where D: de::Deserializer<'de>, @@ -935,6 +952,7 @@ pub mod ts_seconds { /// assert_eq!(as_string, r#"{"time":1431684000}"#); /// # Ok::<(), serde_json::Error>(()) /// ``` + #[must_use] pub fn serialize<S>(dt: &DateTime<Utc>, serializer: S) -> Result<S::Ok, S::Error> where S: ser::Serializer, @@ -949,18 +967,20 @@ pub mod ts_seconds { /// # Example: /// /// ```rust - /// # use chrono::{DateTime, Utc}; + /// # use chrono::{DateTime, TimeZone, Utc}; /// # use serde_derive::Deserialize; /// use chrono::serde::ts_seconds::deserialize as from_ts; - /// #[derive(Deserialize)] + /// #[derive(Debug, PartialEq, Deserialize)] /// struct S { /// #[serde(deserialize_with = "from_ts")] /// time: DateTime<Utc> /// } /// /// let my_s: S = serde_json::from_str(r#"{ "time": 1431684000 }"#)?; + /// assert_eq!(my_s, S { time: Utc.timestamp_opt(1431684000, 0).unwrap() }); /// # Ok::<(), serde_json::Error>(()) /// ``` + #[must_use] pub fn deserialize<'de, D>(d: D) -> Result<DateTime<Utc>, D::Error> where D: de::Deserializer<'de>, @@ -1050,6 +1070,7 @@ pub mod ts_seconds_option { /// assert_eq!(as_string, r#"{"time":1431684000}"#); /// # Ok::<(), serde_json::Error>(()) /// ``` + #[must_use] pub fn serialize<S>(opt: &Option<DateTime<Utc>>, serializer: S) -> Result<S::Ok, S::Error> where S: ser::Serializer, @@ -1067,18 +1088,20 @@ pub mod ts_seconds_option { /// # Example: /// /// ```rust - /// # use chrono::{DateTime, Utc}; + /// # use chrono::{DateTime, TimeZone, Utc}; /// # use serde_derive::Deserialize; /// use chrono::serde::ts_seconds_option::deserialize as from_tsopt; - /// #[derive(Deserialize)] + /// #[derive(Debug, PartialEq, Deserialize)] /// struct S { /// #[serde(deserialize_with = "from_tsopt")] /// time: Option<DateTime<Utc>> /// } /// /// let my_s: S = serde_json::from_str(r#"{ "time": 1431684000 }"#)?; + /// assert_eq!(my_s, S { time: Utc.timestamp_opt(1431684000, 0).single() }); /// # Ok::<(), serde_json::Error>(()) /// ``` + #[must_use] pub fn deserialize<'de, D>(d: D) -> Result<Option<DateTime<Utc>>, D::Error> where D: de::Deserializer<'de>, diff --git a/vendor/chrono/src/datetime/tests.rs b/vendor/chrono/src/datetime/tests.rs index ebd32cae9..c6be142d0 100644 --- a/vendor/chrono/src/datetime/tests.rs +++ b/vendor/chrono/src/datetime/tests.rs @@ -2,13 +2,11 @@ use std::time::{SystemTime, UNIX_EPOCH}; use super::DateTime; use crate::naive::{NaiveDate, NaiveTime}; -#[cfg(feature = "clock")] -use crate::offset::Local; use crate::offset::{FixedOffset, TimeZone, Utc}; -use crate::oldtime::Duration; #[cfg(feature = "clock")] -use crate::Datelike; -use crate::{Days, LocalResult, Months, NaiveDateTime}; +use crate::offset::{Local, Offset}; +use crate::oldtime::Duration; +use crate::{Datelike, Days, LocalResult, Months, NaiveDateTime}; #[derive(Clone)] struct DstTester; @@ -472,7 +470,7 @@ fn test_rfc3339_opts() { fn test_rfc3339_opts_nonexhaustive() { use crate::SecondsFormat; let dt = Utc.with_ymd_and_hms(1999, 10, 9, 1, 2, 3).unwrap(); - dt.to_rfc3339_opts(SecondsFormat::__NonExhaustive, true); + let _ = dt.to_rfc3339_opts(SecondsFormat::__NonExhaustive, true); } #[test] @@ -950,3 +948,64 @@ fn test_datetime_sub_assign_local() { assert_eq!(datetime_sub, datetime - Duration::days(i)) } } + +#[test] +#[cfg(all(target_os = "windows", feature = "clock"))] +fn test_from_naive_date_time_windows() { + let min_year = NaiveDate::from_ymd_opt(1601, 1, 3).unwrap().and_hms_opt(0, 0, 0).unwrap(); + + let max_year = NaiveDate::from_ymd_opt(30827, 12, 29).unwrap().and_hms_opt(23, 59, 59).unwrap(); + + let too_low_year = + NaiveDate::from_ymd_opt(1600, 12, 29).unwrap().and_hms_opt(23, 59, 59).unwrap(); + + let too_high_year = NaiveDate::from_ymd_opt(30829, 1, 3).unwrap().and_hms_opt(0, 0, 0).unwrap(); + + let _ = Local.from_utc_datetime(&min_year); + let _ = Local.from_utc_datetime(&max_year); + + let _ = Local.from_local_datetime(&min_year); + let _ = Local.from_local_datetime(&max_year); + + let local_too_low = Local.from_local_datetime(&too_low_year); + let local_too_high = Local.from_local_datetime(&too_high_year); + + assert_eq!(local_too_low, LocalResult::None); + assert_eq!(local_too_high, LocalResult::None); + + let err = std::panic::catch_unwind(|| { + Local.from_utc_datetime(&too_low_year); + }); + assert!(err.is_err()); + + let err = std::panic::catch_unwind(|| { + Local.from_utc_datetime(&too_high_year); + }); + assert!(err.is_err()); +} + +#[test] +#[cfg(feature = "clock")] +fn test_datetime_local_from_preserves_offset() { + let naivedatetime = NaiveDate::from_ymd_opt(2023, 1, 1).unwrap().and_hms_opt(0, 0, 0).unwrap(); + + let datetime = Local.from_utc_datetime(&naivedatetime); + let offset = datetime.offset().fix(); + + let datetime_fixed: DateTime<FixedOffset> = datetime.into(); + assert_eq!(&offset, datetime_fixed.offset()); + assert_eq!(datetime.fixed_offset(), datetime_fixed); +} + +#[test] +fn test_datetime_fixed_offset() { + let naivedatetime = NaiveDate::from_ymd_opt(2023, 1, 1).unwrap().and_hms_opt(0, 0, 0).unwrap(); + + let datetime = Utc.from_utc_datetime(&naivedatetime); + let fixed_utc = FixedOffset::east_opt(0).unwrap(); + assert_eq!(datetime.fixed_offset(), fixed_utc.from_local_datetime(&naivedatetime).unwrap()); + + let fixed_offset = FixedOffset::east_opt(3600).unwrap(); + let datetime_fixed = fixed_offset.from_local_datetime(&naivedatetime).unwrap(); + assert_eq!(datetime_fixed.fixed_offset(), datetime_fixed); +} diff --git a/vendor/chrono/src/format/locales.rs b/vendor/chrono/src/format/locales.rs index f7b4bbde5..d6fecc978 100644 --- a/vendor/chrono/src/format/locales.rs +++ b/vendor/chrono/src/format/locales.rs @@ -1,33 +1,33 @@ use pure_rust_locales::{locale_match, Locale}; -pub(crate) fn short_months(locale: Locale) -> &'static [&'static str] { +pub(crate) const fn short_months(locale: Locale) -> &'static [&'static str] { locale_match!(locale => LC_TIME::ABMON) } -pub(crate) fn long_months(locale: Locale) -> &'static [&'static str] { +pub(crate) const fn long_months(locale: Locale) -> &'static [&'static str] { locale_match!(locale => LC_TIME::MON) } -pub(crate) fn short_weekdays(locale: Locale) -> &'static [&'static str] { +pub(crate) const fn short_weekdays(locale: Locale) -> &'static [&'static str] { locale_match!(locale => LC_TIME::ABDAY) } -pub(crate) fn long_weekdays(locale: Locale) -> &'static [&'static str] { +pub(crate) const fn long_weekdays(locale: Locale) -> &'static [&'static str] { locale_match!(locale => LC_TIME::DAY) } -pub(crate) fn am_pm(locale: Locale) -> &'static [&'static str] { +pub(crate) const fn am_pm(locale: Locale) -> &'static [&'static str] { locale_match!(locale => LC_TIME::AM_PM) } -pub(crate) fn d_fmt(locale: Locale) -> &'static str { +pub(crate) const fn d_fmt(locale: Locale) -> &'static str { locale_match!(locale => LC_TIME::D_FMT) } -pub(crate) fn d_t_fmt(locale: Locale) -> &'static str { +pub(crate) const fn d_t_fmt(locale: Locale) -> &'static str { locale_match!(locale => LC_TIME::D_T_FMT) } -pub(crate) fn t_fmt(locale: Locale) -> &'static str { +pub(crate) const fn t_fmt(locale: Locale) -> &'static str { locale_match!(locale => LC_TIME::T_FMT) } diff --git a/vendor/chrono/src/format/mod.rs b/vendor/chrono/src/format/mod.rs index c05ba4d04..93c9f86d0 100644 --- a/vendor/chrono/src/format/mod.rs +++ b/vendor/chrono/src/format/mod.rs @@ -16,9 +16,9 @@ //! C's `strftime` format. The available options can be found [here](./strftime/index.html). //! //! # Example -//! ```rust -//! # use std::error::Error; -//! use chrono::prelude::*; +#![cfg_attr(not(feature = "std"), doc = "```ignore")] +#![cfg_attr(feature = "std", doc = "```rust")] +//! use chrono::{TimeZone, Utc}; //! //! let date_time = Utc.with_ymd_and_hms(2020, 11, 10, 0, 1, 32).unwrap(); //! @@ -56,7 +56,7 @@ use crate::{Month, ParseMonthError, ParseWeekdayError, Weekday}; #[cfg(feature = "unstable-locales")] pub(crate) mod locales; -pub use parse::parse; +pub use parse::{parse, parse_and_remainder}; pub use parsed::Parsed; /// L10n locales. #[cfg(feature = "unstable-locales")] @@ -356,6 +356,7 @@ impl ParseError { } /// The category of parse error +#[allow(clippy::manual_non_exhaustive)] #[derive(Debug, Clone, PartialEq, Eq, Copy, Hash)] pub enum ParseErrorKind { /// Given field is out of permitted range. @@ -386,7 +387,7 @@ pub enum ParseErrorKind { /// There was an error on the formatting string, or there were non-supported formating items. BadFormat, - // TODO: Change this to `#[non_exhaustive]` (on the enum) when MSRV is increased + // TODO: Change this to `#[non_exhaustive]` (on the enum) with the next breaking release. #[doc(hidden)] __Nonexhaustive, } @@ -510,8 +511,6 @@ fn format_inner( ) -> fmt::Result { let locale = Locales::new(locale); - use num_integer::{div_floor, mod_floor}; - match *item { Item::Literal(s) | Item::Space(s) => result.push_str(s), #[cfg(any(feature = "alloc", feature = "std", test))] @@ -525,11 +524,11 @@ fn format_inner( let (width, v) = match *spec { Year => (4, date.map(|d| i64::from(d.year()))), - YearDiv100 => (2, date.map(|d| div_floor(i64::from(d.year()), 100))), - YearMod100 => (2, date.map(|d| mod_floor(i64::from(d.year()), 100))), + YearDiv100 => (2, date.map(|d| i64::from(d.year()).div_euclid(100))), + YearMod100 => (2, date.map(|d| i64::from(d.year()).rem_euclid(100))), IsoYear => (4, date.map(|d| i64::from(d.iso_week().year()))), - IsoYearDiv100 => (2, date.map(|d| div_floor(i64::from(d.iso_week().year()), 100))), - IsoYearMod100 => (2, date.map(|d| mod_floor(i64::from(d.iso_week().year()), 100))), + IsoYearDiv100 => (2, date.map(|d| i64::from(d.iso_week().year()).div_euclid(100))), + IsoYearMod100 => (2, date.map(|d| i64::from(d.iso_week().year()).rem_euclid(100))), Month => (2, date.map(|d| i64::from(d.month()))), Day => (2, date.map(|d| i64::from(d.day()))), WeekFromSun => (2, date.map(|d| i64::from(week_from_sun(d)))), @@ -867,6 +866,7 @@ pub struct DelayedFormat<I> { #[cfg(any(feature = "alloc", feature = "std", test))] impl<'a, I: Iterator<Item = B> + Clone, B: Borrow<Item<'a>>> DelayedFormat<I> { /// Makes a new `DelayedFormat` value out of local date and time. + #[must_use] pub fn new(date: Option<NaiveDate>, time: Option<NaiveTime>, items: I) -> DelayedFormat<I> { DelayedFormat { date, @@ -879,6 +879,7 @@ impl<'a, I: Iterator<Item = B> + Clone, B: Borrow<Item<'a>>> DelayedFormat<I> { } /// Makes a new `DelayedFormat` value out of local date and time and UTC offset. + #[must_use] pub fn new_with_offset<Off>( date: Option<NaiveDate>, time: Option<NaiveTime>, @@ -902,6 +903,7 @@ impl<'a, I: Iterator<Item = B> + Clone, B: Borrow<Item<'a>>> DelayedFormat<I> { /// Makes a new `DelayedFormat` value out of local date and time and locale. #[cfg(feature = "unstable-locales")] #[cfg_attr(docsrs, doc(cfg(feature = "unstable-locales")))] + #[must_use] pub fn new_with_locale( date: Option<NaiveDate>, time: Option<NaiveTime>, @@ -914,6 +916,7 @@ impl<'a, I: Iterator<Item = B> + Clone, B: Borrow<Item<'a>>> DelayedFormat<I> { /// Makes a new `DelayedFormat` value out of local date and time, UTC offset and locale. #[cfg(feature = "unstable-locales")] #[cfg_attr(docsrs, doc(cfg(feature = "unstable-locales")))] + #[must_use] pub fn new_with_offset_and_locale<Off>( date: Option<NaiveDate>, time: Option<NaiveTime>, diff --git a/vendor/chrono/src/format/parse.rs b/vendor/chrono/src/format/parse.rs index 69204d2e9..ed3f91f6d 100644 --- a/vendor/chrono/src/format/parse.rs +++ b/vendor/chrono/src/format/parse.rs @@ -248,6 +248,36 @@ where parse_internal(parsed, s, items).map(|_| ()).map_err(|(_s, e)| e) } +/// Tries to parse given string into `parsed` with given formatting items. +/// Returns `Ok` with a slice of the unparsed remainder. +/// +/// This particular date and time parser is: +/// +/// - Greedy. It will consume the longest possible prefix. +/// For example, `April` is always consumed entirely when the long month name is requested; +/// it equally accepts `Apr`, but prefers the longer prefix in this case. +/// +/// - Padding-agnostic (for numeric items). +/// The [`Pad`](./enum.Pad.html) field is completely ignored, +/// so one can prepend any number of zeroes before numbers. +/// +/// - (Still) obeying the intrinsic parsing width. This allows, for example, parsing `HHMMSS`. +pub fn parse_and_remainder<'a, 'b, I, B>( + parsed: &mut Parsed, + s: &'b str, + items: I, +) -> ParseResult<&'b str> +where + I: Iterator<Item = B>, + B: Borrow<Item<'a>>, +{ + match parse_internal(parsed, s, items) { + Ok(s) => Ok(s), + Err((s, ParseError(ParseErrorKind::TooLong))) => Ok(s), + Err((_s, e)) => Err(e), + } +} + fn parse_internal<'a, 'b, I, B>( parsed: &mut Parsed, mut s: &'b str, @@ -474,9 +504,10 @@ where /// All of these examples are equivalent: /// ``` /// # use chrono::{DateTime, offset::FixedOffset}; -/// "2012-12-12T12:12:12Z".parse::<DateTime<FixedOffset>>(); -/// "2012-12-12 12:12:12Z".parse::<DateTime<FixedOffset>>(); -/// "2012- 12-12T12: 12:12Z".parse::<DateTime<FixedOffset>>(); +/// "2012-12-12T12:12:12Z".parse::<DateTime<FixedOffset>>()?; +/// "2012-12-12 12:12:12Z".parse::<DateTime<FixedOffset>>()?; +/// "2012- 12-12T12: 12:12Z".parse::<DateTime<FixedOffset>>()?; +/// # Ok::<(), chrono::ParseError>(()) /// ``` impl str::FromStr for DateTime<FixedOffset> { type Err = ParseError; @@ -686,6 +717,7 @@ fn test_parse() { // fixed: dot plus nanoseconds check!("", [fix!(Nanosecond)]; ); // no field set, but not an error + check!(".", [fix!(Nanosecond)]; TOO_SHORT); check!("4", [fix!(Nanosecond)]; TOO_LONG); // never consumes `4` check!("4", [fix!(Nanosecond), num!(Second)]; second: 4); check!(".0", [fix!(Nanosecond)]; nanosecond: 0); @@ -704,6 +736,7 @@ fn test_parse() { // fixed: nanoseconds without the dot check!("", [internal_fix!(Nanosecond3NoDot)]; TOO_SHORT); + check!(".", [internal_fix!(Nanosecond3NoDot)]; TOO_SHORT); check!("0", [internal_fix!(Nanosecond3NoDot)]; TOO_SHORT); check!("4", [internal_fix!(Nanosecond3NoDot)]; TOO_SHORT); check!("42", [internal_fix!(Nanosecond3NoDot)]; TOO_SHORT); @@ -715,6 +748,7 @@ fn test_parse() { check!(".421", [internal_fix!(Nanosecond3NoDot)]; INVALID); check!("", [internal_fix!(Nanosecond6NoDot)]; TOO_SHORT); + check!(".", [internal_fix!(Nanosecond6NoDot)]; TOO_SHORT); check!("0", [internal_fix!(Nanosecond6NoDot)]; TOO_SHORT); check!("42195", [internal_fix!(Nanosecond6NoDot)]; TOO_SHORT); check!("421950", [internal_fix!(Nanosecond6NoDot)]; nanosecond: 421_950_000); @@ -725,6 +759,7 @@ fn test_parse() { check!(".42100", [internal_fix!(Nanosecond6NoDot)]; INVALID); check!("", [internal_fix!(Nanosecond9NoDot)]; TOO_SHORT); + check!(".", [internal_fix!(Nanosecond9NoDot)]; TOO_SHORT); check!("42195", [internal_fix!(Nanosecond9NoDot)]; TOO_SHORT); check!("421950803", [internal_fix!(Nanosecond9NoDot)]; nanosecond: 421_950_803); check!("000000003", [internal_fix!(Nanosecond9NoDot)]; nanosecond: 3); @@ -854,6 +889,28 @@ fn test_rfc2822() { ("Tue, 20 Jan 2015 17:35:20 -0890", Err(OUT_OF_RANGE)), // bad offset ("6 Jun 1944 04:00:00Z", Err(INVALID)), // bad offset (zulu not allowed) ("Tue, 20 Jan 2015 17:35:20 HAS", Err(NOT_ENOUGH)), // bad named time zone + // named timezones that have specific timezone offsets + // see https://www.rfc-editor.org/rfc/rfc2822#section-4.3 + ("Tue, 20 Jan 2015 17:35:20 GMT", Ok("Tue, 20 Jan 2015 17:35:20 +0000")), + ("Tue, 20 Jan 2015 17:35:20 UT", Ok("Tue, 20 Jan 2015 17:35:20 +0000")), + ("Tue, 20 Jan 2015 17:35:20 ut", Ok("Tue, 20 Jan 2015 17:35:20 +0000")), + ("Tue, 20 Jan 2015 17:35:20 EDT", Ok("Tue, 20 Jan 2015 17:35:20 -0400")), + ("Tue, 20 Jan 2015 17:35:20 EST", Ok("Tue, 20 Jan 2015 17:35:20 -0500")), + ("Tue, 20 Jan 2015 17:35:20 CDT", Ok("Tue, 20 Jan 2015 17:35:20 -0500")), + ("Tue, 20 Jan 2015 17:35:20 CST", Ok("Tue, 20 Jan 2015 17:35:20 -0600")), + ("Tue, 20 Jan 2015 17:35:20 MDT", Ok("Tue, 20 Jan 2015 17:35:20 -0600")), + ("Tue, 20 Jan 2015 17:35:20 MST", Ok("Tue, 20 Jan 2015 17:35:20 -0700")), + ("Tue, 20 Jan 2015 17:35:20 PDT", Ok("Tue, 20 Jan 2015 17:35:20 -0700")), + ("Tue, 20 Jan 2015 17:35:20 PST", Ok("Tue, 20 Jan 2015 17:35:20 -0800")), + ("Tue, 20 Jan 2015 17:35:20 pst", Ok("Tue, 20 Jan 2015 17:35:20 -0800")), + // named single-letter military timezones must fallback to +0000 + ("Tue, 20 Jan 2015 17:35:20 Z", Ok("Tue, 20 Jan 2015 17:35:20 +0000")), + ("Tue, 20 Jan 2015 17:35:20 A", Ok("Tue, 20 Jan 2015 17:35:20 +0000")), + ("Tue, 20 Jan 2015 17:35:20 a", Ok("Tue, 20 Jan 2015 17:35:20 +0000")), + ("Tue, 20 Jan 2015 17:35:20 K", Ok("Tue, 20 Jan 2015 17:35:20 +0000")), + ("Tue, 20 Jan 2015 17:35:20 k", Ok("Tue, 20 Jan 2015 17:35:20 +0000")), + // named single-letter timezone "J" is specifically not valid + ("Tue, 20 Jan 2015 17:35:20 J", Err(NOT_ENOUGH)), ]; fn rfc2822_to_datetime(date: &str) -> ParseResult<DateTime<FixedOffset>> { @@ -975,3 +1032,11 @@ fn test_rfc3339() { } } } + +#[cfg(test)] +#[test] +fn test_issue_1010() { + let dt = crate::NaiveDateTime::parse_from_str("\u{c}SUN\u{e}\u{3000}\0m@J\u{3000}\0\u{3000}\0m\u{c}!\u{c}\u{b}\u{c}\u{c}\u{c}\u{c}%A\u{c}\u{b}\0SU\u{c}\u{c}", + "\u{c}\u{c}%A\u{c}\u{b}\0SUN\u{c}\u{c}\u{c}SUNN\u{c}\u{c}\u{c}SUN\u{c}\u{c}!\u{c}\u{b}\u{c}\u{c}\u{c}\u{c}%A\u{c}\u{b}%a"); + assert_eq!(dt, Err(ParseError(ParseErrorKind::Invalid))); +} diff --git a/vendor/chrono/src/format/parsed.rs b/vendor/chrono/src/format/parsed.rs index 6cc29e9d4..9526785ee 100644 --- a/vendor/chrono/src/format/parsed.rs +++ b/vendor/chrono/src/format/parsed.rs @@ -4,9 +4,6 @@ //! A collection of parsed date and time items. //! They can be constructed incrementally while being checked for consistency. -use num_integer::div_rem; -use num_traits::ToPrimitive; - use super::{ParseResult, IMPOSSIBLE, NOT_ENOUGH, OUT_OF_RANGE}; use crate::naive::{NaiveDate, NaiveDateTime, NaiveTime}; use crate::offset::{FixedOffset, LocalResult, Offset, TimeZone}; @@ -22,6 +19,7 @@ use crate::{Datelike, Timelike}; /// /// - `to_*` methods try to make a concrete date and time value out of set fields. /// It fully checks any remaining out-of-range conditions and inconsistent/impossible fields. +#[allow(clippy::manual_non_exhaustive)] #[derive(Clone, PartialEq, Eq, Debug, Default, Hash)] pub struct Parsed { /// Year. @@ -106,6 +104,7 @@ pub struct Parsed { pub offset: Option<i32>, /// A dummy field to make this type not fully destructible (required for API stability). + // TODO: Change this to `#[non_exhaustive]` (on the enum) with the next breaking release. _dummy: (), } @@ -127,6 +126,7 @@ fn set_if_consistent<T: PartialEq>(old: &mut Option<T>, new: T) -> ParseResult<( impl Parsed { /// Returns the initial value of parsed parts. + #[must_use] pub fn new() -> Parsed { Parsed::default() } @@ -134,7 +134,7 @@ impl Parsed { /// Tries to set the [`year`](#structfield.year) field from given value. #[inline] pub fn set_year(&mut self, value: i64) -> ParseResult<()> { - set_if_consistent(&mut self.year, value.to_i32().ok_or(OUT_OF_RANGE)?) + set_if_consistent(&mut self.year, i32::try_from(value).map_err(|_| OUT_OF_RANGE)?) } /// Tries to set the [`year_div_100`](#structfield.year_div_100) field from given value. @@ -143,7 +143,7 @@ impl Parsed { if value < 0 { return Err(OUT_OF_RANGE); } - set_if_consistent(&mut self.year_div_100, value.to_i32().ok_or(OUT_OF_RANGE)?) + set_if_consistent(&mut self.year_div_100, i32::try_from(value).map_err(|_| OUT_OF_RANGE)?) } /// Tries to set the [`year_mod_100`](#structfield.year_mod_100) field from given value. @@ -152,13 +152,13 @@ impl Parsed { if value < 0 { return Err(OUT_OF_RANGE); } - set_if_consistent(&mut self.year_mod_100, value.to_i32().ok_or(OUT_OF_RANGE)?) + set_if_consistent(&mut self.year_mod_100, i32::try_from(value).map_err(|_| OUT_OF_RANGE)?) } /// Tries to set the [`isoyear`](#structfield.isoyear) field from given value. #[inline] pub fn set_isoyear(&mut self, value: i64) -> ParseResult<()> { - set_if_consistent(&mut self.isoyear, value.to_i32().ok_or(OUT_OF_RANGE)?) + set_if_consistent(&mut self.isoyear, i32::try_from(value).map_err(|_| OUT_OF_RANGE)?) } /// Tries to set the [`isoyear_div_100`](#structfield.isoyear_div_100) field from given value. @@ -167,7 +167,10 @@ impl Parsed { if value < 0 { return Err(OUT_OF_RANGE); } - set_if_consistent(&mut self.isoyear_div_100, value.to_i32().ok_or(OUT_OF_RANGE)?) + set_if_consistent( + &mut self.isoyear_div_100, + i32::try_from(value).map_err(|_| OUT_OF_RANGE)?, + ) } /// Tries to set the [`isoyear_mod_100`](#structfield.isoyear_mod_100) field from given value. @@ -176,31 +179,34 @@ impl Parsed { if value < 0 { return Err(OUT_OF_RANGE); } - set_if_consistent(&mut self.isoyear_mod_100, value.to_i32().ok_or(OUT_OF_RANGE)?) + set_if_consistent( + &mut self.isoyear_mod_100, + i32::try_from(value).map_err(|_| OUT_OF_RANGE)?, + ) } /// Tries to set the [`month`](#structfield.month) field from given value. #[inline] pub fn set_month(&mut self, value: i64) -> ParseResult<()> { - set_if_consistent(&mut self.month, value.to_u32().ok_or(OUT_OF_RANGE)?) + set_if_consistent(&mut self.month, u32::try_from(value).map_err(|_| OUT_OF_RANGE)?) } /// Tries to set the [`week_from_sun`](#structfield.week_from_sun) field from given value. #[inline] pub fn set_week_from_sun(&mut self, value: i64) -> ParseResult<()> { - set_if_consistent(&mut self.week_from_sun, value.to_u32().ok_or(OUT_OF_RANGE)?) + set_if_consistent(&mut self.week_from_sun, u32::try_from(value).map_err(|_| OUT_OF_RANGE)?) } /// Tries to set the [`week_from_mon`](#structfield.week_from_mon) field from given value. #[inline] pub fn set_week_from_mon(&mut self, value: i64) -> ParseResult<()> { - set_if_consistent(&mut self.week_from_mon, value.to_u32().ok_or(OUT_OF_RANGE)?) + set_if_consistent(&mut self.week_from_mon, u32::try_from(value).map_err(|_| OUT_OF_RANGE)?) } /// Tries to set the [`isoweek`](#structfield.isoweek) field from given value. #[inline] pub fn set_isoweek(&mut self, value: i64) -> ParseResult<()> { - set_if_consistent(&mut self.isoweek, value.to_u32().ok_or(OUT_OF_RANGE)?) + set_if_consistent(&mut self.isoweek, u32::try_from(value).map_err(|_| OUT_OF_RANGE)?) } /// Tries to set the [`weekday`](#structfield.weekday) field from given value. @@ -212,13 +218,13 @@ impl Parsed { /// Tries to set the [`ordinal`](#structfield.ordinal) field from given value. #[inline] pub fn set_ordinal(&mut self, value: i64) -> ParseResult<()> { - set_if_consistent(&mut self.ordinal, value.to_u32().ok_or(OUT_OF_RANGE)?) + set_if_consistent(&mut self.ordinal, u32::try_from(value).map_err(|_| OUT_OF_RANGE)?) } /// Tries to set the [`day`](#structfield.day) field from given value. #[inline] pub fn set_day(&mut self, value: i64) -> ParseResult<()> { - set_if_consistent(&mut self.day, value.to_u32().ok_or(OUT_OF_RANGE)?) + set_if_consistent(&mut self.day, u32::try_from(value).map_err(|_| OUT_OF_RANGE)?) } /// Tries to set the [`hour_div_12`](#structfield.hour_div_12) field from given value. @@ -242,7 +248,7 @@ impl Parsed { /// [`hour_mod_12`](#structfield.hour_mod_12) fields from given value. #[inline] pub fn set_hour(&mut self, value: i64) -> ParseResult<()> { - let v = value.to_u32().ok_or(OUT_OF_RANGE)?; + let v = u32::try_from(value).map_err(|_| OUT_OF_RANGE)?; set_if_consistent(&mut self.hour_div_12, v / 12)?; set_if_consistent(&mut self.hour_mod_12, v % 12)?; Ok(()) @@ -251,19 +257,19 @@ impl Parsed { /// Tries to set the [`minute`](#structfield.minute) field from given value. #[inline] pub fn set_minute(&mut self, value: i64) -> ParseResult<()> { - set_if_consistent(&mut self.minute, value.to_u32().ok_or(OUT_OF_RANGE)?) + set_if_consistent(&mut self.minute, u32::try_from(value).map_err(|_| OUT_OF_RANGE)?) } /// Tries to set the [`second`](#structfield.second) field from given value. #[inline] pub fn set_second(&mut self, value: i64) -> ParseResult<()> { - set_if_consistent(&mut self.second, value.to_u32().ok_or(OUT_OF_RANGE)?) + set_if_consistent(&mut self.second, u32::try_from(value).map_err(|_| OUT_OF_RANGE)?) } /// Tries to set the [`nanosecond`](#structfield.nanosecond) field from given value. #[inline] pub fn set_nanosecond(&mut self, value: i64) -> ParseResult<()> { - set_if_consistent(&mut self.nanosecond, value.to_u32().ok_or(OUT_OF_RANGE)?) + set_if_consistent(&mut self.nanosecond, u32::try_from(value).map_err(|_| OUT_OF_RANGE)?) } /// Tries to set the [`timestamp`](#structfield.timestamp) field from given value. @@ -275,7 +281,7 @@ impl Parsed { /// Tries to set the [`offset`](#structfield.offset) field from given value. #[inline] pub fn set_offset(&mut self, value: i64) -> ParseResult<()> { - set_if_consistent(&mut self.offset, value.to_i32().ok_or(OUT_OF_RANGE)?) + set_if_consistent(&mut self.offset, i32::try_from(value).map_err(|_| OUT_OF_RANGE)?) } /// Returns a parsed naive date out of given fields. @@ -308,7 +314,8 @@ impl Parsed { if y < 0 { return Err(OUT_OF_RANGE); } - let (q_, r_) = div_rem(y, 100); + let q_ = y / 100; + let r_ = y % 100; if q.unwrap_or(q_) == q_ && r.unwrap_or(r_) == r_ { Ok(Some(y)) } else { @@ -343,8 +350,7 @@ impl Parsed { let verify_ymd = |date: NaiveDate| { let year = date.year(); let (year_div_100, year_mod_100) = if year >= 0 { - let (q, r) = div_rem(year, 100); - (Some(q), Some(r)) + (Some(year / 100), Some(year % 100)) } else { (None, None) // they should be empty to be consistent }; @@ -364,8 +370,7 @@ impl Parsed { let isoweek = week.week(); let weekday = date.weekday(); let (isoyear_div_100, isoyear_mod_100) = if isoyear >= 0 { - let (q, r) = div_rem(isoyear, 100); - (Some(q), Some(r)) + (Some(isoyear / 100), Some(isoyear % 100)) } else { (None, None) // they should be empty to be consistent }; @@ -1286,4 +1291,18 @@ mod tests { // TODO test with a variable time zone (for None and Ambiguous cases) } + + #[test] + fn issue_551() { + use crate::Weekday; + let mut parsed = Parsed::new(); + + parsed.year = Some(2002); + parsed.week_from_mon = Some(22); + parsed.weekday = Some(Weekday::Mon); + assert_eq!(NaiveDate::from_ymd_opt(2002, 6, 3).unwrap(), parsed.to_naive_date().unwrap()); + + parsed.year = Some(2001); + assert_eq!(NaiveDate::from_ymd_opt(2001, 5, 28).unwrap(), parsed.to_naive_date().unwrap()); + } } diff --git a/vendor/chrono/src/format/scan.rs b/vendor/chrono/src/format/scan.rs index 263fec556..2962ef162 100644 --- a/vendor/chrono/src/format/scan.rs +++ b/vendor/chrono/src/format/scan.rs @@ -12,8 +12,8 @@ use crate::Weekday; /// Returns true when two slices are equal case-insensitively (in ASCII). /// Assumes that the `pattern` is already converted to lower case. -fn equals(s: &str, pattern: &str) -> bool { - let mut xs = s.as_bytes().iter().map(|&c| match c { +fn equals(s: &[u8], pattern: &str) -> bool { + let mut xs = s.iter().map(|&c| match c { b'A'..=b'Z' => c + 32, _ => c, }); @@ -48,7 +48,7 @@ pub(super) fn number(s: &str, min: usize, max: usize) -> ParseResult<(&str, i64) let mut n = 0i64; for (i, c) in bytes.iter().take(max).cloned().enumerate() { // cloned() = copied() - if !(b'0'..=b'9').contains(&c) { + if !c.is_ascii_digit() { if i < min { return Err(INVALID); } else { @@ -79,7 +79,7 @@ pub(super) fn nanosecond(s: &str) -> ParseResult<(&str, i64)> { let v = v.checked_mul(SCALE[consumed]).ok_or(OUT_OF_RANGE)?; // if there are more than 9 digits, skip next digits. - let s = s.trim_left_matches(|c: char| ('0'..='9').contains(&c)); + let s = s.trim_left_matches(|c: char| c.is_ascii_digit()); Ok((s, v)) } @@ -152,7 +152,7 @@ pub(super) fn short_or_long_month0(s: &str) -> ParseResult<(&str, u8)> { // tries to consume the suffix if possible let suffix = LONG_MONTH_SUFFIXES[month0 as usize]; - if s.len() >= suffix.len() && equals(&s[..suffix.len()], suffix) { + if s.len() >= suffix.len() && equals(&s.as_bytes()[..suffix.len()], suffix) { s = &s[suffix.len()..]; } @@ -170,7 +170,7 @@ pub(super) fn short_or_long_weekday(s: &str) -> ParseResult<(&str, Weekday)> { // tries to consume the suffix if possible let suffix = LONG_WEEKDAY_SUFFIXES[weekday.num_days_from_monday() as usize]; - if s.len() >= suffix.len() && equals(&s[..suffix.len()], suffix) { + if s.len() >= suffix.len() && equals(&s.as_bytes()[..suffix.len()], suffix) { s = &s[suffix.len()..]; } @@ -222,7 +222,7 @@ fn timezone_offset_internal<F>( where F: FnMut(&str) -> ParseResult<&str>, { - fn digits(s: &str) -> ParseResult<(u8, u8)> { + const fn digits(s: &str) -> ParseResult<(u8, u8)> { let b = s.as_bytes(); if b.len() < 2 { Err(TOO_SHORT) @@ -308,18 +308,14 @@ where /// Same as `timezone_offset` but also allows for RFC 2822 legacy timezones. /// May return `None` which indicates an insufficient offset data (i.e. `-0000`). +/// See [RFC 2822 Section 4.3]. +/// +/// [RFC 2822 Section 4.3]: https://tools.ietf.org/html/rfc2822#section-4.3 pub(super) fn timezone_offset_2822(s: &str) -> ParseResult<(&str, Option<i32>)> { // tries to parse legacy time zone names - let upto = s - .as_bytes() - .iter() - .position(|&c| match c { - b'a'..=b'z' | b'A'..=b'Z' => false, - _ => true, - }) - .unwrap_or(s.len()); + let upto = s.as_bytes().iter().position(|&c| !c.is_ascii_alphabetic()).unwrap_or(s.len()); if upto > 0 { - let name = &s[..upto]; + let name = &s.as_bytes()[..upto]; let s = &s[upto..]; let offset_hours = |o| Ok((s, Some(o * 3600))); if equals(name, "gmt") || equals(name, "ut") { @@ -334,8 +330,14 @@ pub(super) fn timezone_offset_2822(s: &str) -> ParseResult<(&str, Option<i32>)> offset_hours(-7) } else if equals(name, "pst") { offset_hours(-8) + } else if name.len() == 1 { + match name[0] { + // recommended by RFC 2822: consume but treat it as -0000 + b'a'..=b'i' | b'k'..=b'z' | b'A'..=b'I' | b'K'..=b'Z' => offset_hours(0), + _ => Ok((s, None)), + } } else { - Ok((s, None)) // recommended by RFC 2822: consume but treat it as -0000 + Ok((s, None)) } } else { let (s_, offset) = timezone_offset(s, |s| Ok(s))?; diff --git a/vendor/chrono/src/format/strftime.rs b/vendor/chrono/src/format/strftime.rs index dcaabe49f..24bae20c0 100644 --- a/vendor/chrono/src/format/strftime.rs +++ b/vendor/chrono/src/format/strftime.rs @@ -68,7 +68,7 @@ The following specifiers are available both to formatting and parsing. | `%r` | `12:34:60 AM` | Hour-minute-second format in 12-hour clocks. Same as `%I:%M:%S %p`. | | | | | | | | **TIME ZONE SPECIFIERS:** | -| `%Z` | `ACST` | Local time zone name. Skips all non-whitespace characters during parsing. [^8] | +| `%Z` | `ACST` | Local time zone name. Skips all non-whitespace characters during parsing. Identical to `%:z` when formatting. [^8] | | `%z` | `+0930` | Offset from the local time to UTC (with UTC being `+0000`). | | `%:z` | `+09:30` | Same as `%z` but with a colon. | |`%::z`|`+09:30:00`| Offset from the local time to UTC with seconds. | @@ -164,6 +164,12 @@ Notes: Note that they can read nothing if the fractional part is zero. [^8]: `%Z`: + Since `chrono` is not aware of timezones beyond their offsets, this specifier + **only prints the offset** when used for formatting. The timezone abbreviation + will NOT be printed. See [this issue](https://github.com/chronotope/chrono/issues/960) + for more information. + <br> + <br> Offset will not be populated from the parsed data, nor will it be validated. Timezone is completely ignored. Similar to the glibc `strptime` treatment of this format code. @@ -227,6 +233,7 @@ pub struct StrftimeItems<'a> { impl<'a> StrftimeItems<'a> { /// Creates a new parsing iterator from the `strftime`-like format string. + #[must_use] pub fn new(s: &'a str) -> StrftimeItems<'a> { Self::with_remainer(s) } @@ -234,6 +241,7 @@ impl<'a> StrftimeItems<'a> { /// Creates a new parsing iterator from the `strftime`-like format string. #[cfg(feature = "unstable-locales")] #[cfg_attr(docsrs, doc(cfg(feature = "unstable-locales")))] + #[must_use] pub fn new_with_locale(s: &'a str, locale: Locale) -> StrftimeItems<'a> { let d_fmt = StrftimeItems::new(locales::d_fmt(locale)).collect(); let d_t_fmt = StrftimeItems::new(locales::d_t_fmt(locale)).collect(); diff --git a/vendor/chrono/src/lib.rs b/vendor/chrono/src/lib.rs index 861ee1059..3737d1a9b 100644 --- a/vendor/chrono/src/lib.rs +++ b/vendor/chrono/src/lib.rs @@ -110,7 +110,8 @@ //! or in the local time zone //! ([`Local::now()`](./offset/struct.Local.html#method.now)). //! -//! ```rust +#![cfg_attr(not(feature = "clock"), doc = "```ignore")] +#![cfg_attr(feature = "clock", doc = "```rust")] //! use chrono::prelude::*; //! //! let utc: DateTime<Utc> = Utc::now(); // e.g. `2014-11-28T12:45:59.324310806Z` @@ -122,25 +123,30 @@ //! This is a bit verbose due to Rust's lack of function and method overloading, //! but in turn we get a rich combination of initialization methods. //! -//! ```rust +#![cfg_attr(not(feature = "std"), doc = "```ignore")] +#![cfg_attr(feature = "std", doc = "```rust")] //! use chrono::prelude::*; //! use chrono::offset::LocalResult; //! +//! # fn doctest() -> Option<()> { +//! //! let dt = Utc.with_ymd_and_hms(2014, 7, 8, 9, 10, 11).unwrap(); // `2014-07-08T09:10:11Z` +//! assert_eq!(dt, NaiveDate::from_ymd_opt(2014, 7, 8)?.and_hms_opt(9, 10, 11)?.and_local_timezone(Utc).unwrap()); +//! //! // July 8 is 188th day of the year 2014 (`o` for "ordinal") -//! assert_eq!(dt, Utc.yo(2014, 189).and_hms_opt(9, 10, 11).unwrap()); +//! assert_eq!(dt, NaiveDate::from_yo_opt(2014, 189)?.and_hms_opt(9, 10, 11)?.and_utc()); //! // July 8 is Tuesday in ISO week 28 of the year 2014. -//! assert_eq!(dt, Utc.isoywd(2014, 28, Weekday::Tue).and_hms_opt(9, 10, 11).unwrap()); +//! assert_eq!(dt, NaiveDate::from_isoywd_opt(2014, 28, Weekday::Tue)?.and_hms_opt(9, 10, 11)?.and_utc()); //! -//! let dt = NaiveDate::from_ymd_opt(2014, 7, 8).unwrap().and_hms_milli_opt(9, 10, 11, 12).unwrap().and_local_timezone(Utc).unwrap(); // `2014-07-08T09:10:11.012Z` -//! assert_eq!(dt, NaiveDate::from_ymd_opt(2014, 7, 8).unwrap().and_hms_micro_opt(9, 10, 11, 12_000).unwrap().and_local_timezone(Utc).unwrap()); -//! assert_eq!(dt, NaiveDate::from_ymd_opt(2014, 7, 8).unwrap().and_hms_nano_opt(9, 10, 11, 12_000_000).unwrap().and_local_timezone(Utc).unwrap()); +//! let dt = NaiveDate::from_ymd_opt(2014, 7, 8)?.and_hms_milli_opt(9, 10, 11, 12)?.and_local_timezone(Utc).unwrap(); // `2014-07-08T09:10:11.012Z` +//! assert_eq!(dt, NaiveDate::from_ymd_opt(2014, 7, 8)?.and_hms_micro_opt(9, 10, 11, 12_000)?.and_local_timezone(Utc).unwrap()); +//! assert_eq!(dt, NaiveDate::from_ymd_opt(2014, 7, 8)?.and_hms_nano_opt(9, 10, 11, 12_000_000)?.and_local_timezone(Utc).unwrap()); //! //! // dynamic verification -//! assert_eq!(Utc.ymd_opt(2014, 7, 8).and_hms_opt(21, 15, 33), -//! LocalResult::Single(Utc.with_ymd_and_hms(2014, 7, 8, 21, 15, 33).unwrap())); -//! assert_eq!(Utc.ymd_opt(2014, 7, 8).and_hms_opt(80, 15, 33), LocalResult::None); -//! assert_eq!(Utc.ymd_opt(2014, 7, 38).and_hms_opt(21, 15, 33), LocalResult::None); +//! assert_eq!(Utc.with_ymd_and_hms(2014, 7, 8, 21, 15, 33), +//! LocalResult::Single(NaiveDate::from_ymd_opt(2014, 7, 8)?.and_hms_opt(21, 15, 33)?.and_utc())); +//! assert_eq!(Utc.with_ymd_and_hms(2014, 7, 8, 80, 15, 33), LocalResult::None); +//! assert_eq!(Utc.with_ymd_and_hms(2014, 7, 38, 21, 15, 33), LocalResult::None); //! //! // other time zone objects can be used to construct a local datetime. //! // obviously, `local_dt` is normally different from `dt`, but `fixed_dt` should be identical. @@ -148,6 +154,9 @@ //! let fixed_dt = FixedOffset::east_opt(9 * 3600).unwrap().from_local_datetime(&NaiveDate::from_ymd_opt(2014, 7, 8).unwrap().and_hms_milli_opt(18, 10, 11, 12).unwrap()).unwrap(); //! assert_eq!(dt, fixed_dt); //! # let _ = local_dt; +//! # Some(()) +//! # } +//! # doctest().unwrap(); //! ``` //! //! Various properties are available to the date and time, and can be altered individually. @@ -217,6 +226,7 @@ //! The `unstable-locales` feature requires and implies at least the `alloc` feature. //! //! ```rust +//! # #[allow(unused_imports)] //! use chrono::prelude::*; //! //! # #[cfg(feature = "unstable-locales")] @@ -314,12 +324,13 @@ //! [`DateTime.timestamp_subsec_nanos`](./struct.DateTime.html#method.timestamp_subsec_nanos) //! to get the number of additional number of nanoseconds. //! -//! ```rust +#![cfg_attr(not(feature = "std"), doc = "```ignore")] +#![cfg_attr(feature = "std", doc = "```rust")] //! // We need the trait in scope to use Utc::timestamp(). //! use chrono::{DateTime, TimeZone, Utc}; //! //! // Construct a datetime from epoch: -//! let dt = Utc.timestamp(1_500_000_000, 0); +//! let dt = Utc.timestamp_opt(1_500_000_000, 0).unwrap(); //! assert_eq!(dt.to_rfc2822(), "Fri, 14 Jul 2017 02:40:00 +0000"); //! //! // Get epoch value from a datetime: @@ -327,33 +338,6 @@ //! assert_eq!(dt.timestamp(), 1_500_000_000); //! ``` //! -//! ### Individual date -//! -//! Chrono also provides an individual date type ([**`Date`**](./struct.Date.html)). -//! It also has time zones attached, and have to be constructed via time zones. -//! Most operations available to `DateTime` are also available to `Date` whenever appropriate. -//! -//! ```rust -//! use chrono::prelude::*; -//! use chrono::offset::LocalResult; -//! -//! # // these *may* fail, but only very rarely. just rerun the test if you were that unfortunate ;) -//! assert_eq!(Utc::today(), Utc::now().date()); -//! assert_eq!(Local::today(), Local::now().date()); -//! -//! assert_eq!(Utc.ymd_opt(2014, 11, 28).unwrap().weekday(), Weekday::Fri); -//! assert_eq!(Utc.ymd_opt(2014, 11, 31), LocalResult::None); -//! assert_eq!(NaiveDate::from_ymd_opt(2014, 11, 28).unwrap().and_hms_milli_opt(7, 8, 9, 10).unwrap().and_local_timezone(Utc).unwrap().format("%H%M%S").to_string(), -//! "070809"); -//! ``` -//! -//! There is no timezone-aware `Time` due to the lack of usefulness and also the complexity. -//! -//! `DateTime` has [`date`](./struct.DateTime.html#method.date) method -//! which returns a `Date` which represents its date component. -//! There is also a [`time`](./struct.DateTime.html#method.time) method, -//! which simply returns a naive local time described below. -//! //! ### Naive date and time //! //! Chrono provides naive counterparts to `Date`, (non-existent) `Time` and `DateTime` @@ -398,7 +382,7 @@ //! Advanced time zone handling is not yet supported. //! For now you can try the [Chrono-tz](https://github.com/chronotope/chrono-tz/) crate instead. -#![doc(html_root_url = "https://docs.rs/chrono/latest/")] +#![doc(html_root_url = "https://docs.rs/chrono/latest/", test(attr(deny(warnings))))] #![cfg_attr(feature = "bench", feature(test))] // lib stability features as per RFC #507 #![deny(missing_docs)] #![deny(missing_debug_implementations)] @@ -418,6 +402,8 @@ mod oldtime; // this reexport is to aid the transition and should not be in the prelude! pub use oldtime::{Duration, OutOfRangeError}; +use core::fmt; + #[cfg(feature = "__doctest")] #[cfg_attr(feature = "__doctest", cfg(doctest))] use doc_comment::doctest; @@ -502,26 +488,41 @@ pub use naive::__BenchYearFlags; /// Serialization/Deserialization with serde. /// /// This module provides default implementations for `DateTime` using the [RFC 3339][1] format and various -/// alternatives for use with serde's [`with` annotation][1]. +/// alternatives for use with serde's [`with` annotation][2]. /// /// *Available on crate feature 'serde' only.* /// /// [1]: https://tools.ietf.org/html/rfc3339 -/// [2]: https://serde.rs/attributes.html#field-attributes +/// [2]: https://serde.rs/field-attrs.html#with #[cfg(feature = "serde")] #[cfg_attr(docsrs, doc(cfg(feature = "serde")))] pub mod serde { pub use super::datetime::serde::*; } -/// MSRV 1.42 -#[cfg(test)] -#[macro_export] -macro_rules! matches { - ($expression:expr, $(|)? $( $pattern:pat )|+ $( if $guard: expr )? $(,)?) => { - match $expression { - $( $pattern )|+ $( if $guard )? => true, - _ => false - } +/// Out of range error type used in various converting APIs +#[derive(Clone, Copy, Hash, PartialEq, Eq)] +pub struct OutOfRange { + _private: (), +} + +impl OutOfRange { + const fn new() -> OutOfRange { + OutOfRange { _private: () } } } + +impl fmt::Display for OutOfRange { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "out of range") + } +} + +impl fmt::Debug for OutOfRange { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "out of range") + } +} + +#[cfg(feature = "std")] +impl std::error::Error for OutOfRange {} diff --git a/vendor/chrono/src/month.rs b/vendor/chrono/src/month.rs index 46f09d0fb..11df7613d 100644 --- a/vendor/chrono/src/month.rs +++ b/vendor/chrono/src/month.rs @@ -3,6 +3,8 @@ use core::fmt; #[cfg(feature = "rkyv")] use rkyv::{Archive, Deserialize, Serialize}; +use crate::OutOfRange; + /// The month of the year. /// /// This enum is just a convenience implementation. @@ -10,11 +12,10 @@ use rkyv::{Archive, Deserialize, Serialize}; /// /// It is possible to convert from a date to a month independently /// ``` -/// use num_traits::FromPrimitive; /// use chrono::prelude::*; /// let date = Utc.with_ymd_and_hms(2019, 10, 28, 9, 10, 11).unwrap(); /// // `2019-10-28T09:10:11Z` -/// let month = Month::from_u32(date.month()); +/// let month = Month::try_from(u8::try_from(date.month()).unwrap()).ok(); /// assert_eq!(month, Some(Month::October)) /// ``` /// Or from a Month to an integer usable by dates @@ -27,7 +28,7 @@ use rkyv::{Archive, Deserialize, Serialize}; /// Allows mapping from and to month, from 1-January to 12-December. /// Can be Serialized/Deserialized with serde // Actual implementation is zero-indexed, API intended as 1-indexed for more intuitive behavior. -#[derive(PartialEq, Eq, Copy, Clone, Debug, Hash)] +#[derive(PartialEq, Eq, Copy, Clone, Debug, Hash, PartialOrd)] #[cfg_attr(feature = "rustc-serialize", derive(RustcEncodable, RustcDecodable))] #[cfg_attr(feature = "rkyv", derive(Archive, Deserialize, Serialize))] #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] @@ -65,7 +66,8 @@ impl Month { /// ----------- | --------- | ---------- | --- | --------- /// `m.succ()`: | `February` | `March` | `...` | `January` #[inline] - pub fn succ(&self) -> Month { + #[must_use] + pub const fn succ(&self) -> Month { match *self { Month::January => Month::February, Month::February => Month::March, @@ -88,7 +90,8 @@ impl Month { /// ----------- | --------- | ---------- | --- | --------- /// `m.pred()`: | `December` | `January` | `...` | `November` #[inline] - pub fn pred(&self) -> Month { + #[must_use] + pub const fn pred(&self) -> Month { match *self { Month::January => Month::December, Month::February => Month::January, @@ -111,7 +114,8 @@ impl Month { /// -------------------------| --------- | ---------- | --- | ----- /// `m.number_from_month()`: | 1 | 2 | `...` | 12 #[inline] - pub fn number_from_month(&self) -> u32 { + #[must_use] + pub const fn number_from_month(&self) -> u32 { match *self { Month::January => 1, Month::February => 2, @@ -135,7 +139,8 @@ impl Month { /// /// assert_eq!(Month::January.name(), "January") /// ``` - pub fn name(&self) -> &'static str { + #[must_use] + pub const fn name(&self) -> &'static str { match *self { Month::January => "January", Month::February => "February", @@ -153,6 +158,28 @@ impl Month { } } +impl TryFrom<u8> for Month { + type Error = OutOfRange; + + fn try_from(value: u8) -> Result<Self, Self::Error> { + 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(OutOfRange::new()), + } + } +} + impl num_traits::FromPrimitive for Month { /// Returns an `Option<Month>` from a i64, assuming a 1-index, January = 1. /// @@ -322,7 +349,22 @@ mod month_serde { #[cfg(test)] mod tests { use super::Month; - use crate::{Datelike, TimeZone, Utc}; + use crate::{Datelike, OutOfRange, TimeZone, Utc}; + + #[test] + fn test_month_enum_try_from() { + assert_eq!(Month::try_from(1), Ok(Month::January)); + assert_eq!(Month::try_from(2), Ok(Month::February)); + assert_eq!(Month::try_from(12), Ok(Month::December)); + assert_eq!(Month::try_from(13), Err(OutOfRange::new())); + + let date = Utc.with_ymd_and_hms(2019, 10, 28, 9, 10, 11).unwrap(); + assert_eq!(Month::try_from(date.month() as u8), Ok(Month::October)); + + let month = Month::January; + let dt = Utc.with_ymd_and_hms(2019, month.number_from_month(), 28, 9, 10, 11).unwrap(); + assert_eq!((dt.year(), dt.month(), dt.day()), (2019, 1, 28)); + } #[test] fn test_month_enum_primitive_parse() { @@ -352,4 +394,13 @@ mod tests { assert_eq!(Month::January.pred(), Month::December); assert_eq!(Month::February.pred(), Month::January); } + + #[test] + fn test_month_partial_ord() { + assert!(Month::January <= Month::January); + assert!(Month::January < Month::February); + assert!(Month::January < Month::December); + assert!(Month::July >= Month::May); + assert!(Month::September > Month::March); + } } diff --git a/vendor/chrono/src/naive/date.rs b/vendor/chrono/src/naive/date.rs index 64af978f3..b9404a15f 100644 --- a/vendor/chrono/src/naive/date.rs +++ b/vendor/chrono/src/naive/date.rs @@ -5,12 +5,9 @@ #[cfg(any(feature = "alloc", feature = "std", test))] use core::borrow::Borrow; -use core::convert::TryFrom; use core::ops::{Add, AddAssign, RangeInclusive, Sub, SubAssign}; use core::{fmt, str}; -use num_integer::div_mod_floor; -use num_traits::ToPrimitive; #[cfg(feature = "rkyv")] use rkyv::{Archive, Deserialize, Serialize}; @@ -20,8 +17,10 @@ use pure_rust_locales::Locale; #[cfg(any(feature = "alloc", feature = "std", test))] use crate::format::DelayedFormat; -use crate::format::{parse, write_hundreds, ParseError, ParseResult, Parsed, StrftimeItems}; -use crate::format::{Item, Numeric, Pad}; +use crate::format::{ + parse, parse_and_remainder, write_hundreds, Item, Numeric, Pad, ParseError, ParseResult, + Parsed, StrftimeItems, +}; use crate::month::Months; use crate::naive::{IsoWeek, NaiveDateTime, NaiveTime}; use crate::oldtime::Duration as OldDuration; @@ -77,11 +76,15 @@ impl NaiveWeek { /// assert!(week.first_day() <= date); /// ``` #[inline] + #[must_use] pub fn first_day(&self) -> NaiveDate { - let start = self.start.num_days_from_monday(); - let end = self.date.weekday().num_days_from_monday(); - let days = if start > end { 7 - start + end } else { end - start }; - self.date - Duration::days(days.into()) + let start = self.start.num_days_from_monday() as i32; + let ref_day = self.date.weekday().num_days_from_monday() as i32; + // Calculate the number of days to subtract from `self.date`. + // Do not construct an intermediate date beyond `self.date`, because that may be out of + // range if `date` is close to `NaiveDate::MAX`. + let days = start - ref_day - if start > ref_day { 7 } else { 0 }; + self.date.diff_days(days as i64).unwrap() } /// Returns a date representing the last day of the week. @@ -96,8 +99,15 @@ impl NaiveWeek { /// assert!(week.last_day() >= date); /// ``` #[inline] + #[must_use] pub fn last_day(&self) -> NaiveDate { - self.first_day() + Duration::days(6) + let end = self.start.pred().num_days_from_monday() as i32; + let ref_day = self.date.weekday().num_days_from_monday() as i32; + // Calculate the number of days to add to `self.date`. + // Do not construct an intermediate date before `self.date` (like with `first_day()`), + // because that may be out of range if `date` is close to `NaiveDate::MIN`. + let days = end - ref_day + if end < ref_day { 7 } else { 0 }; + self.date.diff_days(days as i64).unwrap() } /// Returns a [`RangeInclusive<T>`] representing the whole week bounded by @@ -115,6 +125,7 @@ impl NaiveWeek { /// assert!(days.contains(&date)); /// ``` #[inline] + #[must_use] pub fn days(&self) -> RangeInclusive<NaiveDate> { self.first_day()..=self.last_day() } @@ -137,8 +148,7 @@ impl Days { } /// ISO 8601 calendar date without timezone. -/// Allows for every [proleptic Gregorian date](#calendar-date) -/// from Jan 1, 262145 BCE to Dec 31, 262143 CE. +/// Allows for every [proleptic Gregorian date] from Jan 1, 262145 BCE to Dec 31, 262143 CE. /// Also supports the conversion from ISO 8601 ordinal and week date. /// /// # Calendar Date @@ -184,6 +194,8 @@ impl Days { /// The year number is the same as that of the [calendar date](#calendar-date). /// /// This is currently the internal format of Chrono's date types. +/// +/// [proleptic Gregorian date]: crate::NaiveDate#calendar-date #[derive(PartialEq, Eq, Hash, PartialOrd, Ord, Copy, Clone)] #[cfg_attr(feature = "rkyv", derive(Archive, Deserialize, Serialize))] pub struct NaiveDate { @@ -239,19 +251,35 @@ impl NaiveDate { pub(crate) fn weeks_from(&self, day: Weekday) -> i32 { (self.ordinal() as i32 - self.weekday().num_days_from(day) as i32 + 6) / 7 } - /// Makes a new `NaiveDate` from year and packed ordinal-flags, with a verification. - fn from_of(year: i32, of: Of) -> Option<NaiveDate> { - if (MIN_YEAR..=MAX_YEAR).contains(&year) && of.valid() { - let Of(of) = of; - Some(NaiveDate { ymdf: (year << 13) | (of as DateImpl) }) - } else { - None + + /// Makes a new `NaiveDate` from year, ordinal and flags. + /// Does not check whether the flags are correct for the provided year. + const fn from_ordinal_and_flags( + year: i32, + ordinal: u32, + flags: YearFlags, + ) -> Option<NaiveDate> { + if year < MIN_YEAR || year > MAX_YEAR { + return None; // Out-of-range + } + // Enable debug check once the MSRV >= 1.57 (panicking in const feature) + // debug_assert!(YearFlags::from_year(year).0 == flags.0); + match Of::new(ordinal, flags) { + Some(of) => Some(NaiveDate { ymdf: (year << 13) | (of.inner() as DateImpl) }), + None => None, // Invalid: Ordinal outside of the nr of days in a year with those flags. } } - /// Makes a new `NaiveDate` from year and packed month-day-flags, with a verification. - fn from_mdf(year: i32, mdf: Mdf) -> Option<NaiveDate> { - NaiveDate::from_of(year, mdf.to_of()) + /// Makes a new `NaiveDate` from year and packed month-day-flags. + /// Does not check whether the flags are correct for the provided year. + const fn from_mdf(year: i32, mdf: Mdf) -> Option<NaiveDate> { + if year < MIN_YEAR || year > MAX_YEAR { + return None; // Out-of-range + } + match mdf.to_of() { + Some(of) => Some(NaiveDate { ymdf: (year << 13) | (of.inner() as DateImpl) }), + None => None, // Non-existing date + } } /// Makes a new `NaiveDate` from the [calendar date](#calendar-date) @@ -259,6 +287,7 @@ impl NaiveDate { /// /// Panics on the out-of-range date, invalid month and/or day. #[deprecated(since = "0.4.23", note = "use `from_ymd_opt()` instead")] + #[must_use] pub fn from_ymd(year: i32, month: u32, day: u32) -> NaiveDate { NaiveDate::from_ymd_opt(year, month, day).expect("invalid or out-of-range date") } @@ -282,6 +311,7 @@ impl NaiveDate { /// assert!(from_ymd_opt(400000, 1, 1).is_none()); /// assert!(from_ymd_opt(-400000, 1, 1).is_none()); /// ``` + #[must_use] pub fn from_ymd_opt(year: i32, month: u32, day: u32) -> Option<NaiveDate> { let flags = YearFlags::from_year(year); NaiveDate::from_mdf(year, Mdf::new(month, day, flags)?) @@ -292,6 +322,7 @@ impl NaiveDate { /// /// Panics on the out-of-range date and/or invalid day of year. #[deprecated(since = "0.4.23", note = "use `from_yo_opt()` instead")] + #[must_use] pub fn from_yo(year: i32, ordinal: u32) -> NaiveDate { NaiveDate::from_yo_opt(year, ordinal).expect("invalid or out-of-range date") } @@ -316,9 +347,10 @@ impl NaiveDate { /// assert!(from_yo_opt(400000, 1).is_none()); /// assert!(from_yo_opt(-400000, 1).is_none()); /// ``` + #[must_use] pub fn from_yo_opt(year: i32, ordinal: u32) -> Option<NaiveDate> { let flags = YearFlags::from_year(year); - NaiveDate::from_of(year, Of::new(ordinal, flags)?) + NaiveDate::from_ordinal_and_flags(year, ordinal, flags) } /// Makes a new `NaiveDate` from the [ISO week date](#week-date) @@ -327,6 +359,7 @@ impl NaiveDate { /// /// Panics on the out-of-range date and/or invalid week number. #[deprecated(since = "0.4.23", note = "use `from_isoywd_opt()` instead")] + #[must_use] pub fn from_isoywd(year: i32, week: u32, weekday: Weekday) -> NaiveDate { NaiveDate::from_isoywd_opt(year, week, weekday).expect("invalid or out-of-range date") } @@ -342,7 +375,7 @@ impl NaiveDate { /// ``` /// use chrono::{NaiveDate, Weekday}; /// - /// let from_ymd = NaiveDate::from_ymd; + /// let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap(); /// let from_isoywd_opt = NaiveDate::from_isoywd_opt; /// /// assert_eq!(from_isoywd_opt(2015, 0, Weekday::Sun), None); @@ -358,7 +391,7 @@ impl NaiveDate { /// /// ``` /// # use chrono::{NaiveDate, Weekday}; - /// # let from_ymd = NaiveDate::from_ymd; + /// # let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap(); /// # let from_isoywd_opt = NaiveDate::from_isoywd_opt; /// // Mo Tu We Th Fr Sa Su /// // 2014-W52 22 23 24 25 26 27 28 has 4+ days of new year, @@ -375,6 +408,7 @@ impl NaiveDate { /// assert_eq!(from_isoywd_opt(2015, 54, Weekday::Mon), None); /// assert_eq!(from_isoywd_opt(2016, 1, Weekday::Mon), Some(from_ymd(2016, 1, 4))); /// ``` + #[must_use] pub fn from_isoywd_opt(year: i32, week: u32, weekday: Weekday) -> Option<NaiveDate> { let flags = YearFlags::from_year(year); let nweeks = flags.nisoweeks(); @@ -385,20 +419,21 @@ impl NaiveDate { if weekord <= delta { // ordinal < 1, previous year let prevflags = YearFlags::from_year(year - 1); - NaiveDate::from_of( + NaiveDate::from_ordinal_and_flags( year - 1, - Of::new(weekord + prevflags.ndays() - delta, prevflags)?, + weekord + prevflags.ndays() - delta, + prevflags, ) } else { let ordinal = weekord - delta; let ndays = flags.ndays(); if ordinal <= ndays { // this year - NaiveDate::from_of(year, Of::new(ordinal, flags)?) + NaiveDate::from_ordinal_and_flags(year, ordinal, flags) } else { // ordinal > ndays, next year let nextflags = YearFlags::from_year(year + 1); - NaiveDate::from_of(year + 1, Of::new(ordinal - ndays, nextflags)?) + NaiveDate::from_ordinal_and_flags(year + 1, ordinal - ndays, nextflags) } } } else { @@ -412,6 +447,7 @@ impl NaiveDate { /// Panics if the date is out of range. #[deprecated(since = "0.4.23", note = "use `from_num_days_from_ce_opt()` instead")] #[inline] + #[must_use] pub fn from_num_days_from_ce(days: i32) -> NaiveDate { NaiveDate::from_num_days_from_ce_opt(days).expect("out-of-range date") } @@ -436,12 +472,13 @@ impl NaiveDate { /// assert_eq!(from_ndays_opt(100_000_000), None); /// assert_eq!(from_ndays_opt(-100_000_000), None); /// ``` + #[must_use] pub fn from_num_days_from_ce_opt(days: i32) -> Option<NaiveDate> { - let days = days + 365; // make December 31, 1 BCE equal to day 0 + let days = days.checked_add(365)?; // make December 31, 1 BCE equal to day 0 let (year_div_400, cycle) = div_mod_floor(days, 146_097); let (year_mod_400, ordinal) = internals::cycle_to_yo(cycle as u32); let flags = YearFlags::from_year_mod_400(year_mod_400 as i32); - NaiveDate::from_of(year_div_400 * 400 + year_mod_400 as i32, Of::new(ordinal, flags)?) + NaiveDate::from_ordinal_and_flags(year_div_400 * 400 + year_mod_400 as i32, ordinal, flags) } /// Makes a new `NaiveDate` by counting the number of occurrences of a particular day-of-week @@ -455,6 +492,7 @@ impl NaiveDate { /// /// `n` is 1-indexed. Passing `n=0` will cause a panic. #[deprecated(since = "0.4.23", note = "use `from_weekday_of_month_opt()` instead")] + #[must_use] pub fn from_weekday_of_month(year: i32, month: u32, weekday: Weekday, n: u8) -> NaiveDate { NaiveDate::from_weekday_of_month_opt(year, month, weekday, n).expect("out-of-range date") } @@ -471,6 +509,7 @@ impl NaiveDate { /// /// Returns `None` if `n` out-of-range; ie. if `n` is larger than the number of `weekday` in /// `month` (eg. the 6th Friday of March 2017), or if `n == 0`. + #[must_use] pub fn from_weekday_of_month_opt( year: i32, month: u32, @@ -534,6 +573,28 @@ impl NaiveDate { parsed.to_naive_date() } + /// Parses a string from a user-specified format into a new `NaiveDate` value, and a slice with + /// the remaining portion of the string. + /// See the [`format::strftime` module](../format/strftime/index.html) + /// on the supported escape sequences. + /// + /// Similar to [`parse_from_str`](#method.parse_from_str). + /// + /// # Example + /// + /// ```rust + /// # use chrono::{NaiveDate}; + /// let (date, remainder) = NaiveDate::parse_and_remainder( + /// "2015-02-18 trailing text", "%Y-%m-%d").unwrap(); + /// assert_eq!(date, NaiveDate::from_ymd_opt(2015, 2, 18).unwrap()); + /// assert_eq!(remainder, " trailing text"); + /// ``` + pub fn parse_and_remainder<'a>(s: &'a str, fmt: &str) -> ParseResult<(NaiveDate, &'a str)> { + let mut parsed = Parsed::new(); + let remainder = parse_and_remainder(&mut parsed, s, StrftimeItems::new(fmt))?; + parsed.to_naive_date().map(|d| (d, remainder)) + } + /// Add a duration in [`Months`] to the date /// /// If the day would be out of range for the resulting month, use the last day for that month. @@ -551,6 +612,7 @@ impl NaiveDate { /// Some(NaiveDate::from_ymd_opt(2022, 9, 30).unwrap()) /// ); /// ``` + #[must_use] pub fn checked_add_months(self, months: Months) -> Option<Self> { if months.0 == 0 { return Some(self); @@ -581,6 +643,7 @@ impl NaiveDate { /// None /// ); /// ``` + #[must_use] pub fn checked_sub_months(self, months: Months) -> Option<Self> { if months.0 == 0 { return Some(self); @@ -654,6 +717,7 @@ impl NaiveDate { /// None /// ); /// ``` + #[must_use] pub fn checked_add_days(self, days: Days) -> Option<Self> { if days.0 == 0 { return Some(self); @@ -677,6 +741,7 @@ impl NaiveDate { /// None /// ); /// ``` + #[must_use] pub fn checked_sub_days(self, days: Days) -> Option<Self> { if days.0 == 0 { return Some(self); @@ -708,6 +773,7 @@ impl NaiveDate { /// assert_eq!(dt.time(), t); /// ``` #[inline] + #[must_use] pub const fn and_time(&self, time: NaiveTime) -> NaiveDateTime { NaiveDateTime::new(*self, time) } @@ -720,6 +786,7 @@ impl NaiveDate { /// Panics on invalid hour, minute and/or second. #[deprecated(since = "0.4.23", note = "use `and_hms_opt()` instead")] #[inline] + #[must_use] pub fn and_hms(&self, hour: u32, min: u32, sec: u32) -> NaiveDateTime { self.and_hms_opt(hour, min, sec).expect("invalid time") } @@ -743,6 +810,7 @@ impl NaiveDate { /// assert!(d.and_hms_opt(24, 34, 56).is_none()); /// ``` #[inline] + #[must_use] pub fn and_hms_opt(&self, hour: u32, min: u32, sec: u32) -> Option<NaiveDateTime> { NaiveTime::from_hms_opt(hour, min, sec).map(|time| self.and_time(time)) } @@ -755,6 +823,7 @@ impl NaiveDate { /// Panics on invalid hour, minute, second and/or millisecond. #[deprecated(since = "0.4.23", note = "use `and_hms_milli_opt()` instead")] #[inline] + #[must_use] pub fn and_hms_milli(&self, hour: u32, min: u32, sec: u32, milli: u32) -> NaiveDateTime { self.and_hms_milli_opt(hour, min, sec, milli).expect("invalid time") } @@ -780,6 +849,7 @@ impl NaiveDate { /// assert!(d.and_hms_milli_opt(24, 34, 56, 789).is_none()); /// ``` #[inline] + #[must_use] pub fn and_hms_milli_opt( &self, hour: u32, @@ -804,7 +874,7 @@ impl NaiveDate { /// /// let d = NaiveDate::from_ymd_opt(2015, 6, 3).unwrap(); /// - /// let dt: NaiveDateTime = d.and_hms_micro(12, 34, 56, 789_012); + /// let dt: NaiveDateTime = d.and_hms_micro_opt(12, 34, 56, 789_012).unwrap(); /// assert_eq!(dt.year(), 2015); /// assert_eq!(dt.weekday(), Weekday::Wed); /// assert_eq!(dt.second(), 56); @@ -812,6 +882,7 @@ impl NaiveDate { /// ``` #[deprecated(since = "0.4.23", note = "use `and_hms_micro_opt()` instead")] #[inline] + #[must_use] pub fn and_hms_micro(&self, hour: u32, min: u32, sec: u32, micro: u32) -> NaiveDateTime { self.and_hms_micro_opt(hour, min, sec, micro).expect("invalid time") } @@ -837,6 +908,7 @@ impl NaiveDate { /// assert!(d.and_hms_micro_opt(24, 34, 56, 789_012).is_none()); /// ``` #[inline] + #[must_use] pub fn and_hms_micro_opt( &self, hour: u32, @@ -855,6 +927,7 @@ impl NaiveDate { /// Panics on invalid hour, minute, second and/or nanosecond. #[deprecated(since = "0.4.23", note = "use `and_hms_nano_opt()` instead")] #[inline] + #[must_use] pub fn and_hms_nano(&self, hour: u32, min: u32, sec: u32, nano: u32) -> NaiveDateTime { self.and_hms_nano_opt(hour, min, sec, nano).expect("invalid time") } @@ -880,6 +953,7 @@ impl NaiveDate { /// assert!(d.and_hms_nano_opt(24, 34, 56, 789_012_345).is_none()); /// ``` #[inline] + #[must_use] pub fn and_hms_nano_opt( &self, hour: u32, @@ -899,7 +973,7 @@ impl NaiveDate { /// Returns the packed ordinal-flags. #[inline] const fn of(&self) -> Of { - Of((self.ymdf & 0b1_1111_1111_1111) as u32) + Of::from_date_impl(self.ymdf) } /// Makes a new `NaiveDate` with the packed month-day-flags changed. @@ -907,20 +981,16 @@ impl NaiveDate { /// Returns `None` when the resulting `NaiveDate` would be invalid. #[inline] fn with_mdf(&self, mdf: Mdf) -> Option<NaiveDate> { - self.with_of(mdf.to_of()) + Some(self.with_of(mdf.to_of()?)) } /// Makes a new `NaiveDate` with the packed ordinal-flags changed. /// /// Returns `None` when the resulting `NaiveDate` would be invalid. + /// Does not check if the year flags match the year. #[inline] - fn with_of(&self, of: Of) -> Option<NaiveDate> { - if of.valid() { - let Of(of) = of; - Some(NaiveDate { ymdf: (self.ymdf & !0b1_1111_1111_1111) | of as DateImpl }) - } else { - None - } + const fn with_of(&self, of: Of) -> NaiveDate { + NaiveDate { ymdf: (self.ymdf & !0b1_1111_1111_1111) | of.inner() as DateImpl } } /// Makes a new `NaiveDate` for the next calendar date. @@ -928,6 +998,7 @@ impl NaiveDate { /// Panics when `self` is the last representable date. #[deprecated(since = "0.4.23", note = "use `succ_opt()` instead")] #[inline] + #[must_use] pub fn succ(&self) -> NaiveDate { self.succ_opt().expect("out of bound") } @@ -946,8 +1017,12 @@ impl NaiveDate { /// assert_eq!(NaiveDate::MAX.succ_opt(), None); /// ``` #[inline] + #[must_use] pub fn succ_opt(&self) -> Option<NaiveDate> { - self.with_of(self.of().succ()).or_else(|| NaiveDate::from_ymd_opt(self.year() + 1, 1, 1)) + match self.of().succ() { + Some(of) => Some(self.with_of(of)), + None => NaiveDate::from_ymd_opt(self.year() + 1, 1, 1), + } } /// Makes a new `NaiveDate` for the previous calendar date. @@ -955,6 +1030,7 @@ impl NaiveDate { /// Panics when `self` is the first representable date. #[deprecated(since = "0.4.23", note = "use `pred_opt()` instead")] #[inline] + #[must_use] pub fn pred(&self) -> NaiveDate { self.pred_opt().expect("out of bound") } @@ -973,8 +1049,12 @@ impl NaiveDate { /// assert_eq!(NaiveDate::MIN.pred_opt(), None); /// ``` #[inline] + #[must_use] pub fn pred_opt(&self) -> Option<NaiveDate> { - self.with_of(self.of().pred()).or_else(|| NaiveDate::from_ymd_opt(self.year() - 1, 12, 31)) + match self.of().pred() { + Some(of) => Some(self.with_of(of)), + None => NaiveDate::from_ymd_opt(self.year() - 1, 12, 31), + } } /// Adds the `days` part of given `Duration` to the current date. @@ -995,17 +1075,18 @@ impl NaiveDate { /// assert_eq!(d.checked_add_signed(Duration::days(-1_000_000_000)), None); /// assert_eq!(NaiveDate::MAX.checked_add_signed(Duration::days(1)), None); /// ``` + #[must_use] pub fn checked_add_signed(self, rhs: OldDuration) -> Option<NaiveDate> { let year = self.year(); let (mut year_div_400, year_mod_400) = div_mod_floor(year, 400); let cycle = internals::yo_to_cycle(year_mod_400 as u32, self.of().ordinal()); - let cycle = (cycle as i32).checked_add(rhs.num_days().to_i32()?)?; + let cycle = (cycle as i32).checked_add(i32::try_from(rhs.num_days()).ok()?)?; let (cycle_div_400y, cycle) = div_mod_floor(cycle, 146_097); year_div_400 += cycle_div_400y; let (year_mod_400, ordinal) = internals::cycle_to_yo(cycle as u32); let flags = YearFlags::from_year_mod_400(year_mod_400 as i32); - NaiveDate::from_of(year_div_400 * 400 + year_mod_400 as i32, Of::new(ordinal, flags)?) + NaiveDate::from_ordinal_and_flags(year_div_400 * 400 + year_mod_400 as i32, ordinal, flags) } /// Subtracts the `days` part of given `Duration` from the current date. @@ -1026,17 +1107,18 @@ impl NaiveDate { /// assert_eq!(d.checked_sub_signed(Duration::days(-1_000_000_000)), None); /// assert_eq!(NaiveDate::MIN.checked_sub_signed(Duration::days(1)), None); /// ``` + #[must_use] pub fn checked_sub_signed(self, rhs: OldDuration) -> Option<NaiveDate> { let year = self.year(); let (mut year_div_400, year_mod_400) = div_mod_floor(year, 400); let cycle = internals::yo_to_cycle(year_mod_400 as u32, self.of().ordinal()); - let cycle = (cycle as i32).checked_sub(rhs.num_days().to_i32()?)?; + let cycle = (cycle as i32).checked_sub(i32::try_from(rhs.num_days()).ok()?)?; let (cycle_div_400y, cycle) = div_mod_floor(cycle, 146_097); year_div_400 += cycle_div_400y; let (year_mod_400, ordinal) = internals::cycle_to_yo(cycle as u32); let flags = YearFlags::from_year_mod_400(year_mod_400 as i32); - NaiveDate::from_of(year_div_400 * 400 + year_mod_400 as i32, Of::new(ordinal, flags)?) + NaiveDate::from_ordinal_and_flags(year_div_400 * 400 + year_mod_400 as i32, ordinal, flags) } /// Subtracts another `NaiveDate` from the current date. @@ -1050,7 +1132,7 @@ impl NaiveDate { /// ``` /// use chrono::{Duration, NaiveDate}; /// - /// let from_ymd = NaiveDate::from_ymd; + /// let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap(); /// let since = NaiveDate::signed_duration_since; /// /// assert_eq!(since(from_ymd(2014, 1, 1), from_ymd(2014, 1, 1)), Duration::zero()); @@ -1061,6 +1143,7 @@ impl NaiveDate { /// assert_eq!(since(from_ymd(2014, 1, 1), from_ymd(2010, 1, 1)), Duration::days(365*4 + 1)); /// assert_eq!(since(from_ymd(2014, 1, 1), from_ymd(1614, 1, 1)), Duration::days(365*400 + 97)); /// ``` + #[must_use] pub fn signed_duration_since(self, rhs: NaiveDate) -> OldDuration { let year1 = self.year(); let year2 = rhs.year(); @@ -1074,6 +1157,7 @@ impl NaiveDate { } /// Returns the number of whole years from the given `base` until `self`. + #[must_use] pub fn years_since(&self, base: Self) -> Option<u32> { let mut years = self.year() - base.year(); if (self.month(), self.day()) < (base.month(), base.day()) { @@ -1116,6 +1200,7 @@ impl NaiveDate { #[cfg(any(feature = "alloc", feature = "std", test))] #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))] #[inline] + #[must_use] pub fn format_with_items<'a, I, B>(&self, items: I) -> DelayedFormat<I> where I: Iterator<Item = B> + Clone, @@ -1159,6 +1244,7 @@ impl NaiveDate { #[cfg(any(feature = "alloc", feature = "std", test))] #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))] #[inline] + #[must_use] pub fn format<'a>(&self, fmt: &'a str) -> DelayedFormat<StrftimeItems<'a>> { self.format_with_items(StrftimeItems::new(fmt)) } @@ -1167,6 +1253,7 @@ impl NaiveDate { #[cfg(feature = "unstable-locales")] #[cfg_attr(docsrs, doc(cfg(feature = "unstable-locales")))] #[inline] + #[must_use] pub fn format_localized_with_items<'a, I, B>( &self, items: I, @@ -1186,6 +1273,7 @@ impl NaiveDate { #[cfg(feature = "unstable-locales")] #[cfg_attr(docsrs, doc(cfg(feature = "unstable-locales")))] #[inline] + #[must_use] pub fn format_localized<'a>( &self, fmt: &'a str, @@ -1345,7 +1433,7 @@ impl Datelike for NaiveDate { /// let d = NaiveDate::from_ymd_opt(y, m, 1).unwrap(); /// /// // ...is preceded by the last day of the original month - /// d.pred().day() + /// d.pred_opt().unwrap().day() /// } /// /// assert_eq!(ndays_in_month(2015, 8), 31); @@ -1401,7 +1489,7 @@ impl Datelike for NaiveDate { /// let d = NaiveDate::from_ymd_opt(year + 1, 1, 1).unwrap(); /// /// // ...is preceded by the last day of the original year - /// d.pred().ordinal() + /// d.pred_opt().unwrap().ordinal() /// } /// /// assert_eq!(ndays_in_year(2015), 365); @@ -1521,7 +1609,8 @@ impl Datelike for NaiveDate { /// ``` #[inline] fn with_month0(&self, month0: u32) -> Option<NaiveDate> { - self.with_mdf(self.mdf().with_month(month0 + 1)?) + let month = month0.checked_add(1)?; + self.with_mdf(self.mdf().with_month(month)?) } /// Makes a new `NaiveDate` with the day of month (starting from 1) changed. @@ -1559,7 +1648,8 @@ impl Datelike for NaiveDate { /// ``` #[inline] fn with_day0(&self, day0: u32) -> Option<NaiveDate> { - self.with_mdf(self.mdf().with_day(day0 + 1)?) + let day = day0.checked_add(1)?; + self.with_mdf(self.mdf().with_day(day)?) } /// Makes a new `NaiveDate` with the day of year (starting from 1) changed. @@ -1583,7 +1673,7 @@ impl Datelike for NaiveDate { /// ``` #[inline] fn with_ordinal(&self, ordinal: u32) -> Option<NaiveDate> { - self.with_of(self.of().with_ordinal(ordinal)?) + self.of().with_ordinal(ordinal).map(|of| self.with_of(of)) } /// Makes a new `NaiveDate` with the day of year (starting from 0) changed. @@ -1607,22 +1697,22 @@ impl Datelike for NaiveDate { /// ``` #[inline] fn with_ordinal0(&self, ordinal0: u32) -> Option<NaiveDate> { - self.with_of(self.of().with_ordinal(ordinal0 + 1)?) + let ordinal = ordinal0.checked_add(1)?; + self.with_ordinal(ordinal) } } /// An addition of `Duration` to `NaiveDate` discards the fractional days, /// rounding to the closest integral number of days towards `Duration::zero()`. /// -/// Panics on underflow or overflow. -/// Use [`NaiveDate::checked_add_signed`](#method.checked_add_signed) to detect that. +/// Panics on underflow or overflow. Use [`NaiveDate::checked_add_signed`] to detect that. /// /// # Example /// /// ``` /// use chrono::{Duration, NaiveDate}; /// -/// let from_ymd = NaiveDate::from_ymd; +/// let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap(); /// /// assert_eq!(from_ymd(2014, 1, 1) + Duration::zero(), from_ymd(2014, 1, 1)); /// assert_eq!(from_ymd(2014, 1, 1) + Duration::seconds(86399), from_ymd(2014, 1, 1)); @@ -1633,6 +1723,8 @@ impl Datelike for NaiveDate { /// assert_eq!(from_ymd(2014, 1, 1) + Duration::days(365*4 + 1), from_ymd(2018, 1, 1)); /// assert_eq!(from_ymd(2014, 1, 1) + Duration::days(365*400 + 97), from_ymd(2414, 1, 1)); /// ``` +/// +/// [`NaiveDate::checked_add_signed`]: crate::NaiveDate::checked_add_signed impl Add<OldDuration> for NaiveDate { type Output = NaiveDate; @@ -1661,9 +1753,9 @@ impl Add<Months> for NaiveDate { /// # Example /// /// ``` - /// use chrono::{Duration, NaiveDate, Months}; + /// use chrono::{NaiveDate, Months}; /// - /// let from_ymd = NaiveDate::from_ymd; + /// let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap(); /// /// assert_eq!(from_ymd(2014, 1, 1) + Months::new(1), from_ymd(2014, 2, 1)); /// assert_eq!(from_ymd(2014, 1, 1) + Months::new(11), from_ymd(2014, 12, 1)); @@ -1689,9 +1781,9 @@ impl Sub<Months> for NaiveDate { /// # Example /// /// ``` - /// use chrono::{Duration, NaiveDate, Months}; + /// use chrono::{NaiveDate, Months}; /// - /// let from_ymd = NaiveDate::from_ymd; + /// let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap(); /// /// assert_eq!(from_ymd(2014, 1, 1) - Months::new(11), from_ymd(2013, 2, 1)); /// assert_eq!(from_ymd(2014, 1, 1) - Months::new(12), from_ymd(2013, 1, 1)); @@ -1722,15 +1814,14 @@ impl Sub<Days> for NaiveDate { /// rounding to the closest integral number of days towards `Duration::zero()`. /// It is the same as the addition with a negated `Duration`. /// -/// Panics on underflow or overflow. -/// Use [`NaiveDate::checked_sub_signed`](#method.checked_sub_signed) to detect that. +/// Panics on underflow or overflow. Use [`NaiveDate::checked_sub_signed`] to detect that. /// /// # Example /// /// ``` /// use chrono::{Duration, NaiveDate}; /// -/// let from_ymd = NaiveDate::from_ymd; +/// let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap(); /// /// assert_eq!(from_ymd(2014, 1, 1) - Duration::zero(), from_ymd(2014, 1, 1)); /// assert_eq!(from_ymd(2014, 1, 1) - Duration::seconds(86399), from_ymd(2014, 1, 1)); @@ -1741,6 +1832,8 @@ impl Sub<Days> for NaiveDate { /// assert_eq!(from_ymd(2014, 1, 1) - Duration::days(365*4 + 1), from_ymd(2010, 1, 1)); /// assert_eq!(from_ymd(2014, 1, 1) - Duration::days(365*400 + 97), from_ymd(1614, 1, 1)); /// ``` +/// +/// [`NaiveDate::checked_sub_signed`]: crate::NaiveDate::checked_sub_signed impl Sub<OldDuration> for NaiveDate { type Output = NaiveDate; @@ -1771,7 +1864,7 @@ impl SubAssign<OldDuration> for NaiveDate { /// ``` /// use chrono::{Duration, NaiveDate}; /// -/// let from_ymd = NaiveDate::from_ymd; +/// let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap(); /// /// assert_eq!(from_ymd(2014, 1, 1) - from_ymd(2014, 1, 1), Duration::zero()); /// assert_eq!(from_ymd(2014, 1, 1) - from_ymd(2013, 12, 31), Duration::days(1)); @@ -1790,6 +1883,12 @@ impl Sub<NaiveDate> for NaiveDate { } } +impl From<NaiveDateTime> for NaiveDate { + fn from(naive_datetime: NaiveDateTime) -> Self { + naive_datetime.date() + } +} + /// Iterator over `NaiveDate` with a step size of one day. #[derive(Debug, Copy, Clone, Hash, PartialEq, PartialOrd, Eq, Ord)] pub struct NaiveDateDaysIterator { @@ -1993,6 +2092,10 @@ impl Default for NaiveDate { } } +fn div_mod_floor(val: i32, div: i32) -> (i32, i32) { + (val.div_euclid(div), val.rem_euclid(div)) +} + #[cfg(all(test, any(feature = "rustc-serialize", feature = "serde")))] fn test_encodable_json<F, E>(to_string: F) where @@ -2183,10 +2286,7 @@ mod tests { }; use crate::oldtime::Duration; use crate::{Datelike, Weekday}; - use std::{ - convert::{TryFrom, TryInto}, - i32, u32, - }; + use std::{i32, u32}; #[test] fn diff_months() { @@ -2208,7 +2308,7 @@ mod tests { assert_eq!( NaiveDate::from_ymd_opt(2022, 8, 3) .unwrap() - .checked_sub_months(Months::new((i32::MIN as i64).abs() as u32 + 1)), + .checked_sub_months(Months::new(i32::MIN.unsigned_abs() + 1)), None ); @@ -2275,9 +2375,7 @@ mod tests { #[test] fn test_readme_doomsday() { - use num_iter::range_inclusive; - - for y in range_inclusive(NaiveDate::MIN.year(), NaiveDate::MAX.year()) { + for y in NaiveDate::MIN.year()..=NaiveDate::MAX.year() { // even months let d4 = NaiveDate::from_ymd_opt(y, 4, 4).unwrap(); let d6 = NaiveDate::from_ymd_opt(y, 6, 6).unwrap(); @@ -2459,6 +2557,9 @@ mod tests { assert_eq!(from_ndays_from_ce(NaiveDate::MIN.num_days_from_ce() - 1), None); assert_eq!(from_ndays_from_ce(NaiveDate::MAX.num_days_from_ce()), Some(NaiveDate::MAX)); assert_eq!(from_ndays_from_ce(NaiveDate::MAX.num_days_from_ce() + 1), None); + + assert_eq!(from_ndays_from_ce(i32::MIN), None); + assert_eq!(from_ndays_from_ce(i32::MAX), None); } #[test] @@ -2915,24 +3016,32 @@ mod tests { fn test_naiveweek() { let date = NaiveDate::from_ymd_opt(2022, 5, 18).unwrap(); let asserts = vec![ - (Weekday::Mon, "2022-05-16", "2022-05-22"), - (Weekday::Tue, "2022-05-17", "2022-05-23"), - (Weekday::Wed, "2022-05-18", "2022-05-24"), - (Weekday::Thu, "2022-05-12", "2022-05-18"), - (Weekday::Fri, "2022-05-13", "2022-05-19"), - (Weekday::Sat, "2022-05-14", "2022-05-20"), - (Weekday::Sun, "2022-05-15", "2022-05-21"), + (Weekday::Mon, "Mon 2022-05-16", "Sun 2022-05-22"), + (Weekday::Tue, "Tue 2022-05-17", "Mon 2022-05-23"), + (Weekday::Wed, "Wed 2022-05-18", "Tue 2022-05-24"), + (Weekday::Thu, "Thu 2022-05-12", "Wed 2022-05-18"), + (Weekday::Fri, "Fri 2022-05-13", "Thu 2022-05-19"), + (Weekday::Sat, "Sat 2022-05-14", "Fri 2022-05-20"), + (Weekday::Sun, "Sun 2022-05-15", "Sat 2022-05-21"), ]; for (start, first_day, last_day) in asserts { let week = date.week(start); let days = week.days(); - assert_eq!(Ok(week.first_day()), NaiveDate::parse_from_str(first_day, "%Y-%m-%d")); - assert_eq!(Ok(week.last_day()), NaiveDate::parse_from_str(last_day, "%Y-%m-%d")); + assert_eq!(Ok(week.first_day()), NaiveDate::parse_from_str(first_day, "%a %Y-%m-%d")); + assert_eq!(Ok(week.last_day()), NaiveDate::parse_from_str(last_day, "%a %Y-%m-%d")); assert!(days.contains(&date)); } } #[test] + fn test_naiveweek_min_max() { + let date_max = NaiveDate::MAX; + assert!(date_max.week(Weekday::Mon).first_day() <= date_max); + let date_min = NaiveDate::MIN; + assert!(date_min.week(Weekday::Mon).last_day() >= date_min); + } + + #[test] fn test_weeks_from() { // tests per: https://github.com/chronotope/chrono/issues/961 // these internally use `weeks_from` via the parsing infrastructure @@ -2994,4 +3103,12 @@ mod tests { } } } + + #[test] + fn test_with_0_overflow() { + let dt = NaiveDate::from_ymd_opt(2023, 4, 18).unwrap(); + assert!(dt.with_month0(4294967295).is_none()); + assert!(dt.with_day0(4294967295).is_none()); + assert!(dt.with_ordinal0(4294967295).is_none()); + } } diff --git a/vendor/chrono/src/naive/datetime/mod.rs b/vendor/chrono/src/naive/datetime/mod.rs index ec0d842c0..0a3f70380 100644 --- a/vendor/chrono/src/naive/datetime/mod.rs +++ b/vendor/chrono/src/naive/datetime/mod.rs @@ -5,24 +5,21 @@ #[cfg(any(feature = "alloc", feature = "std", test))] use core::borrow::Borrow; -use core::convert::TryFrom; use core::fmt::Write; use core::ops::{Add, AddAssign, Sub, SubAssign}; use core::{fmt, str}; -use num_integer::div_mod_floor; -use num_traits::ToPrimitive; #[cfg(feature = "rkyv")] use rkyv::{Archive, Deserialize, Serialize}; #[cfg(any(feature = "alloc", feature = "std", test))] use crate::format::DelayedFormat; -use crate::format::{parse, ParseError, ParseResult, Parsed, StrftimeItems}; +use crate::format::{parse, parse_and_remainder, ParseError, ParseResult, Parsed, StrftimeItems}; use crate::format::{Fixed, Item, Numeric, Pad}; use crate::naive::{Days, IsoWeek, NaiveDate, NaiveTime}; +use crate::offset::Utc; use crate::oldtime::Duration as OldDuration; use crate::{DateTime, Datelike, LocalResult, Months, TimeZone, Timelike, Weekday}; -use core::cmp::Ordering; #[cfg(feature = "rustc-serialize")] pub(super) mod rustc_serialize; @@ -42,11 +39,6 @@ mod tests; /// touching that call when we are already sure that it WILL overflow... const MAX_SECS_BITS: usize = 44; -/// Number of nanoseconds in a millisecond -const NANOS_IN_MILLISECOND: u32 = 1_000_000; -/// Number of nanoseconds in a second -const NANOS_IN_SECOND: u32 = 1000 * NANOS_IN_MILLISECOND; - /// The minimum possible `NaiveDateTime`. #[deprecated(since = "0.4.20", note = "Use NaiveDateTime::MIN instead")] pub const MIN_DATETIME: NaiveDateTime = NaiveDateTime::MIN; @@ -87,32 +79,6 @@ pub struct NaiveDateTime { time: NaiveTime, } -/// The unit of a timestamp expressed in fractions of a second. -/// Currently either milliseconds or microseconds. -/// -/// This is a private type, used in the implementation of -/// [NaiveDateTime::from_timestamp_millis] and [NaiveDateTime::from_timestamp_micros]. -#[derive(Clone, Copy, Debug)] -enum TimestampUnit { - Millis, - Micros, -} - -impl TimestampUnit { - fn per_second(self) -> u32 { - match self { - TimestampUnit::Millis => 1_000, - TimestampUnit::Micros => 1_000_000, - } - } - fn nanos_per(self) -> u32 { - match self { - TimestampUnit::Millis => 1_000_000, - TimestampUnit::Micros => 1_000, - } - } -} - impl NaiveDateTime { /// Makes a new `NaiveDateTime` from date and time components. /// Equivalent to [`date.and_time(time)`](./struct.NaiveDate.html#method.and_time) @@ -150,6 +116,7 @@ impl NaiveDateTime { /// Panics on the out-of-range number of seconds and/or invalid nanosecond. #[deprecated(since = "0.4.23", note = "use `from_timestamp_opt()` instead")] #[inline] + #[must_use] pub fn from_timestamp(secs: i64, nsecs: u32) -> NaiveDateTime { let datetime = NaiveDateTime::from_timestamp_opt(secs, nsecs); datetime.expect("invalid or out-of-range datetime") @@ -177,8 +144,11 @@ impl NaiveDateTime { /// assert_eq!(timestamp_millis, naive_datetime.unwrap().timestamp_millis()); /// ``` #[inline] + #[must_use] pub fn from_timestamp_millis(millis: i64) -> Option<NaiveDateTime> { - Self::from_timestamp_unit(millis, TimestampUnit::Millis) + let secs = millis.div_euclid(1000); + let nsecs = millis.rem_euclid(1000) as u32 * 1_000_000; + NaiveDateTime::from_timestamp_opt(secs, nsecs) } /// Creates a new [NaiveDateTime] from microseconds since the UNIX epoch. @@ -203,8 +173,11 @@ impl NaiveDateTime { /// assert_eq!(timestamp_micros, naive_datetime.unwrap().timestamp_micros()); /// ``` #[inline] + #[must_use] pub fn from_timestamp_micros(micros: i64) -> Option<NaiveDateTime> { - Self::from_timestamp_unit(micros, TimestampUnit::Micros) + let secs = micros.div_euclid(1_000_000); + let nsecs = micros.rem_euclid(1_000_000) as u32 * 1000; + NaiveDateTime::from_timestamp_opt(secs, nsecs) } /// Makes a new `NaiveDateTime` corresponding to a UTC date and time, @@ -222,7 +195,7 @@ impl NaiveDateTime { /// # Example /// /// ``` - /// use chrono::{NaiveDateTime, NaiveDate}; + /// use chrono::NaiveDateTime; /// use std::i64; /// /// let from_timestamp_opt = NaiveDateTime::from_timestamp_opt; @@ -234,10 +207,12 @@ impl NaiveDateTime { /// assert!(from_timestamp_opt(i64::MAX, 0).is_none()); /// ``` #[inline] + #[must_use] pub fn from_timestamp_opt(secs: i64, nsecs: u32) -> Option<NaiveDateTime> { - let (days, secs) = div_mod_floor(secs, 86_400); - let date = days - .to_i32() + let days = secs.div_euclid(86_400); + let secs = secs.rem_euclid(86_400); + let date = i32::try_from(days) + .ok() .and_then(|days| days.checked_add(719_163)) .and_then(NaiveDate::from_num_days_from_ce_opt); let time = NaiveTime::from_num_seconds_from_midnight_opt(secs as u32, nsecs); @@ -312,18 +287,43 @@ impl NaiveDateTime { /// Years before 1 BCE or after 9999 CE, require an initial sign /// ///``` - /// # use chrono::{NaiveDate, NaiveDateTime}; + /// # use chrono::NaiveDateTime; /// # let parse_from_str = NaiveDateTime::parse_from_str; /// let fmt = "%Y-%m-%d %H:%M:%S"; /// assert!(parse_from_str("10000-09-09 01:46:39", fmt).is_err()); /// assert!(parse_from_str("+10000-09-09 01:46:39", fmt).is_ok()); - ///``` + ///``` pub fn parse_from_str(s: &str, fmt: &str) -> ParseResult<NaiveDateTime> { let mut parsed = Parsed::new(); parse(&mut parsed, s, StrftimeItems::new(fmt))?; parsed.to_naive_datetime_with_offset(0) // no offset adjustment } + /// Parses a string with the specified format string and returns a new `NaiveDateTime`, and a + /// slice with the remaining portion of the string. + /// See the [`format::strftime` module](../format/strftime/index.html) + /// on the supported escape sequences. + /// + /// Similar to [`parse_from_str`](#method.parse_from_str). + /// + /// # Example + /// + /// ```rust + /// # use chrono::{NaiveDate, NaiveDateTime}; + /// let (datetime, remainder) = NaiveDateTime::parse_and_remainder( + /// "2015-02-18 23:16:09 trailing text", "%Y-%m-%d %H:%M:%S").unwrap(); + /// assert_eq!( + /// datetime, + /// NaiveDate::from_ymd_opt(2015, 2, 18).unwrap().and_hms_opt(23, 16, 9).unwrap() + /// ); + /// assert_eq!(remainder, " trailing text"); + /// ``` + pub fn parse_and_remainder<'a>(s: &'a str, fmt: &str) -> ParseResult<(NaiveDateTime, &'a str)> { + let mut parsed = Parsed::new(); + let remainder = parse_and_remainder(&mut parsed, s, StrftimeItems::new(fmt))?; + parsed.to_naive_datetime_with_offset(0).map(|d| (d, remainder)) // no offset adjustment + } + /// Retrieves a date component. /// /// # Example @@ -377,6 +377,7 @@ impl NaiveDateTime { /// assert_eq!(dt.timestamp(), -62198755200); /// ``` #[inline] + #[must_use] pub fn timestamp(&self) -> i64 { const UNIX_EPOCH_DAY: i64 = 719_163; let gregorian_day = i64::from(self.date.num_days_from_ce()); @@ -409,6 +410,7 @@ impl NaiveDateTime { /// assert_eq!(dt.timestamp_millis(), -900); /// ``` #[inline] + #[must_use] pub fn timestamp_millis(&self) -> i64 { let as_ms = self.timestamp() * 1000; as_ms + i64::from(self.timestamp_subsec_millis()) @@ -436,6 +438,7 @@ impl NaiveDateTime { /// assert_eq!(dt.timestamp_micros(), 1_000_000_000_000_555); /// ``` #[inline] + #[must_use] pub fn timestamp_micros(&self) -> i64 { let as_us = self.timestamp() * 1_000_000; as_us + i64::from(self.timestamp_subsec_micros()) @@ -470,11 +473,12 @@ impl NaiveDateTime { /// let nanos = dt.timestamp_nanos(); /// assert_eq!(nanos, 1_000_000_000_000_000_555); /// assert_eq!( - /// dt, - /// NaiveDateTime::from_timestamp(nanos / A_BILLION, (nanos % A_BILLION) as u32) + /// Some(dt), + /// NaiveDateTime::from_timestamp_opt(nanos / A_BILLION, (nanos % A_BILLION) as u32) /// ); /// ``` #[inline] + #[must_use] pub fn timestamp_nanos(&self) -> i64 { let as_ns = self.timestamp() * 1_000_000_000; as_ns + i64::from(self.timestamp_subsec_nanos()) @@ -497,6 +501,7 @@ impl NaiveDateTime { /// assert_eq!(dt.timestamp_subsec_millis(), 1_234); /// ``` #[inline] + #[must_use] pub fn timestamp_subsec_millis(&self) -> u32 { self.timestamp_subsec_nanos() / 1_000_000 } @@ -518,6 +523,7 @@ impl NaiveDateTime { /// assert_eq!(dt.timestamp_subsec_micros(), 1_234_567); /// ``` #[inline] + #[must_use] pub fn timestamp_subsec_micros(&self) -> u32 { self.timestamp_subsec_nanos() / 1_000 } @@ -539,6 +545,7 @@ impl NaiveDateTime { /// assert_eq!(dt.timestamp_subsec_nanos(), 1_234_567_890); /// ``` #[inline] + #[must_use] pub fn timestamp_subsec_nanos(&self) -> u32 { self.time.nanosecond() } @@ -557,7 +564,7 @@ impl NaiveDateTime { /// ``` /// use chrono::{Duration, NaiveDate}; /// - /// let from_ymd = NaiveDate::from_ymd; + /// let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap(); /// /// let d = from_ymd(2016, 7, 8); /// let hms = |h, m, s| d.and_hms_opt(h, m, s).unwrap(); @@ -590,7 +597,7 @@ impl NaiveDateTime { /// /// ``` /// # use chrono::{Duration, NaiveDate}; - /// # let from_ymd = NaiveDate::from_ymd; + /// # let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap(); /// # let hmsm = |h, m, s, milli| from_ymd(2016, 7, 8).and_hms_milli_opt(h, m, s, milli).unwrap(); /// let leap = hmsm(3, 5, 59, 1_300); /// assert_eq!(leap.checked_add_signed(Duration::zero()), @@ -608,6 +615,7 @@ impl NaiveDateTime { /// assert_eq!(leap.checked_add_signed(Duration::days(1)), /// Some(from_ymd(2016, 7, 9).and_hms_milli_opt(3, 5, 59, 300).unwrap())); /// ``` + #[must_use] pub fn checked_add_signed(self, rhs: OldDuration) -> Option<NaiveDateTime> { let (time, rhs) = self.time.overflowing_add_signed(rhs); @@ -629,8 +637,7 @@ impl NaiveDateTime { /// # Example /// /// ``` - /// use std::str::FromStr; - /// use chrono::{Months, NaiveDate, NaiveDateTime}; + /// use chrono::{Months, NaiveDate}; /// /// assert_eq!( /// NaiveDate::from_ymd_opt(2014, 1, 1).unwrap().and_hms_opt(1, 0, 0).unwrap() @@ -644,6 +651,7 @@ impl NaiveDateTime { /// None /// ); /// ``` + #[must_use] pub fn checked_add_months(self, rhs: Months) -> Option<NaiveDateTime> { Some(Self { date: self.date.checked_add_months(rhs)?, time: self.time }) } @@ -662,7 +670,7 @@ impl NaiveDateTime { /// ``` /// use chrono::{Duration, NaiveDate}; /// - /// let from_ymd = NaiveDate::from_ymd; + /// let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap(); /// /// let d = from_ymd(2016, 7, 8); /// let hms = |h, m, s| d.and_hms_opt(h, m, s).unwrap(); @@ -695,7 +703,7 @@ impl NaiveDateTime { /// /// ``` /// # use chrono::{Duration, NaiveDate}; - /// # let from_ymd = NaiveDate::from_ymd; + /// # let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap(); /// # let hmsm = |h, m, s, milli| from_ymd(2016, 7, 8).and_hms_milli_opt(h, m, s, milli).unwrap(); /// let leap = hmsm(3, 5, 59, 1_300); /// assert_eq!(leap.checked_sub_signed(Duration::zero()), @@ -709,6 +717,7 @@ impl NaiveDateTime { /// assert_eq!(leap.checked_sub_signed(Duration::days(1)), /// Some(from_ymd(2016, 7, 7).and_hms_milli_opt(3, 6, 0, 300).unwrap())); /// ``` + #[must_use] pub fn checked_sub_signed(self, rhs: OldDuration) -> Option<NaiveDateTime> { let (time, rhs) = self.time.overflowing_sub_signed(rhs); @@ -730,8 +739,7 @@ impl NaiveDateTime { /// # Example /// /// ``` - /// use std::str::FromStr; - /// use chrono::{Months, NaiveDate, NaiveDateTime}; + /// use chrono::{Months, NaiveDate}; /// /// assert_eq!( /// NaiveDate::from_ymd_opt(2014, 1, 1).unwrap().and_hms_opt(1, 0, 0).unwrap() @@ -745,6 +753,7 @@ impl NaiveDateTime { /// None /// ); /// ``` + #[must_use] pub fn checked_sub_months(self, rhs: Months) -> Option<NaiveDateTime> { Some(Self { date: self.date.checked_sub_months(rhs)?, time: self.time }) } @@ -752,6 +761,7 @@ impl NaiveDateTime { /// Add a duration in [`Days`] to the date part of the `NaiveDateTime` /// /// Returns `None` if the resulting date would be out of range. + #[must_use] pub fn checked_add_days(self, days: Days) -> Option<Self> { Some(Self { date: self.date.checked_add_days(days)?, ..self }) } @@ -759,6 +769,7 @@ impl NaiveDateTime { /// Subtract a duration in [`Days`] from the date part of the `NaiveDateTime` /// /// Returns `None` if the resulting date would be out of range. + #[must_use] pub fn checked_sub_days(self, days: Days) -> Option<Self> { Some(Self { date: self.date.checked_sub_days(days)?, ..self }) } @@ -777,7 +788,7 @@ impl NaiveDateTime { /// ``` /// use chrono::{Duration, NaiveDate}; /// - /// let from_ymd = NaiveDate::from_ymd; + /// let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap(); /// /// let d = from_ymd(2016, 7, 8); /// assert_eq!(d.and_hms_opt(3, 5, 7).unwrap().signed_duration_since(d.and_hms_opt(2, 4, 6).unwrap()), @@ -794,13 +805,14 @@ impl NaiveDateTime { /// /// ``` /// # use chrono::{Duration, NaiveDate}; - /// # let from_ymd = NaiveDate::from_ymd; + /// # let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap(); /// let leap = from_ymd(2015, 6, 30).and_hms_milli_opt(23, 59, 59, 1_500).unwrap(); /// assert_eq!(leap.signed_duration_since(from_ymd(2015, 6, 30).and_hms_opt(23, 0, 0).unwrap()), /// Duration::seconds(3600) + Duration::milliseconds(500)); /// assert_eq!(from_ymd(2015, 7, 1).and_hms_opt(1, 0, 0).unwrap().signed_duration_since(leap), /// Duration::seconds(3600) - Duration::milliseconds(500)); /// ``` + #[must_use] pub fn signed_duration_since(self, rhs: NaiveDateTime) -> OldDuration { self.date.signed_duration_since(rhs.date) + self.time.signed_duration_since(rhs.time) } @@ -835,6 +847,7 @@ impl NaiveDateTime { #[cfg(any(feature = "alloc", feature = "std", test))] #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))] #[inline] + #[must_use] pub fn format_with_items<'a, I, B>(&self, items: I) -> DelayedFormat<I> where I: Iterator<Item = B> + Clone, @@ -878,6 +891,7 @@ impl NaiveDateTime { #[cfg(any(feature = "alloc", feature = "std", test))] #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))] #[inline] + #[must_use] pub fn format<'a>(&self, fmt: &'a str) -> DelayedFormat<StrftimeItems<'a>> { self.format_with_items(StrftimeItems::new(fmt)) } @@ -896,51 +910,39 @@ impl NaiveDateTime { /// # Example /// /// ``` - /// use chrono::{NaiveDate, Utc}; - /// let dt = NaiveDate::from_ymd_opt(2015, 9, 5).unwrap().and_hms_opt(23, 56, 4).unwrap().and_local_timezone(Utc).unwrap(); - /// assert_eq!(dt.timezone(), Utc); + /// use chrono::{NaiveDate, FixedOffset}; + /// let hour = 3600; + /// let tz = FixedOffset::east_opt(5 * hour).unwrap(); + /// let dt = NaiveDate::from_ymd_opt(2015, 9, 5).unwrap().and_hms_opt(23, 56, 4).unwrap().and_local_timezone(tz).unwrap(); + /// assert_eq!(dt.timezone(), tz); + /// ``` + #[must_use] pub fn and_local_timezone<Tz: TimeZone>(&self, tz: Tz) -> LocalResult<DateTime<Tz>> { tz.from_local_datetime(self) } + /// Converts the `NaiveDateTime` into the timezone-aware `DateTime<Utc>`. + /// + /// # Example + /// + /// ``` + /// use chrono::{NaiveDate, Utc}; + /// let dt = NaiveDate::from_ymd_opt(2023, 1, 30).unwrap().and_hms_opt(19, 32, 33).unwrap().and_utc(); + /// assert_eq!(dt.timezone(), Utc); + /// ``` + #[must_use] + pub fn and_utc(&self) -> DateTime<Utc> { + Utc.from_utc_datetime(self) + } + /// The minimum possible `NaiveDateTime`. pub const MIN: Self = Self { date: NaiveDate::MIN, time: NaiveTime::MIN }; /// The maximum possible `NaiveDateTime`. pub const MAX: Self = Self { date: NaiveDate::MAX, time: NaiveTime::MAX }; - - /// Creates a new [NaiveDateTime] from milliseconds or microseconds since the UNIX epoch. - /// - /// This is a private function used by [from_timestamp_millis] and [from_timestamp_micros]. - #[inline] - fn from_timestamp_unit(value: i64, unit: TimestampUnit) -> Option<NaiveDateTime> { - let (secs, subsecs) = - (value / i64::from(unit.per_second()), value % i64::from(unit.per_second())); - - match subsecs.cmp(&0) { - Ordering::Less => { - // in the case where our subsec part is negative, then we are actually in the earlier second - // hence we subtract one from the seconds part, and we then add a whole second worth of nanos - // to our nanos part. Due to the use of u32 datatype, it is more convenient to subtract - // the absolute value of the subsec nanos from a whole second worth of nanos - let nsecs = u32::try_from(subsecs.abs()).ok()? * unit.nanos_per(); - NaiveDateTime::from_timestamp_opt( - secs.checked_sub(1)?, - NANOS_IN_SECOND.checked_sub(nsecs)?, - ) - } - Ordering::Equal => NaiveDateTime::from_timestamp_opt(secs, 0), - Ordering::Greater => { - // convert the subsec millis into nanosecond scale so they can be supplied - // as the nanoseconds parameter - let nsecs = u32::try_from(subsecs).ok()? * unit.nanos_per(); - NaiveDateTime::from_timestamp_opt(secs, nsecs) - } - } - } } impl Datelike for NaiveDateTime { - /// Returns the year number in the [calendar date](./index.html#calendar-date). + /// Returns the year number in the [calendar date](./struct.NaiveDate.html#calendar-date). /// /// See also the [`NaiveDate::year`] method. /// @@ -1415,10 +1417,9 @@ impl Timelike for NaiveDateTime { /// An addition of `Duration` to `NaiveDateTime` yields another `NaiveDateTime`. /// -/// As a part of Chrono's [leap second handling](./struct.NaiveTime.html#leap-second-handling), -/// the addition assumes that **there is no leap second ever**, -/// except when the `NaiveDateTime` itself represents a leap second -/// in which case the assumption becomes that **there is exactly a single leap second ever**. +/// As a part of Chrono's [leap second handling], the addition assumes that **there is no leap +/// second ever**, except when the `NaiveDateTime` itself represents a leap second in which case +/// the assumption becomes that **there is exactly a single leap second ever**. /// /// Panics on underflow or overflow. Use [`NaiveDateTime::checked_add_signed`] /// to detect that. @@ -1428,7 +1429,7 @@ impl Timelike for NaiveDateTime { /// ``` /// use chrono::{Duration, NaiveDate}; /// -/// let from_ymd = NaiveDate::from_ymd; +/// let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap(); /// /// let d = from_ymd(2016, 7, 8); /// let hms = |h, m, s| d.and_hms_opt(h, m, s).unwrap(); @@ -1450,7 +1451,7 @@ impl Timelike for NaiveDateTime { /// /// ``` /// # use chrono::{Duration, NaiveDate}; -/// # let from_ymd = NaiveDate::from_ymd; +/// # let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap(); /// # let hmsm = |h, m, s, milli| from_ymd(2016, 7, 8).and_hms_milli_opt(h, m, s, milli).unwrap(); /// let leap = hmsm(3, 5, 59, 1_300); /// assert_eq!(leap + Duration::zero(), hmsm(3, 5, 59, 1_300)); @@ -1462,6 +1463,8 @@ impl Timelike for NaiveDateTime { /// assert_eq!(leap + Duration::days(1), /// from_ymd(2016, 7, 9).and_hms_milli_opt(3, 5, 59, 300).unwrap()); /// ``` +/// +/// [leap second handling]: crate::NaiveTime#leap-second-handling impl Add<OldDuration> for NaiveDateTime { type Output = NaiveDateTime; @@ -1490,8 +1493,7 @@ impl Add<Months> for NaiveDateTime { /// # Example /// /// ``` - /// use chrono::{Duration, NaiveDateTime, Months, NaiveDate}; - /// use std::str::FromStr; + /// use chrono::{Months, NaiveDate}; /// /// assert_eq!( /// NaiveDate::from_ymd_opt(2014, 1, 1).unwrap().and_hms_opt(1, 0, 0).unwrap() + Months::new(1), @@ -1526,10 +1528,9 @@ impl Add<Months> for NaiveDateTime { /// A subtraction of `Duration` from `NaiveDateTime` yields another `NaiveDateTime`. /// It is the same as the addition with a negated `Duration`. /// -/// As a part of Chrono's [leap second handling](./struct.NaiveTime.html#leap-second-handling), -/// the addition assumes that **there is no leap second ever**, -/// except when the `NaiveDateTime` itself represents a leap second -/// in which case the assumption becomes that **there is exactly a single leap second ever**. +/// As a part of Chrono's [leap second handling] the subtraction assumes that **there is no leap +/// second ever**, except when the `NaiveDateTime` itself represents a leap second in which case +/// the assumption becomes that **there is exactly a single leap second ever**. /// /// Panics on underflow or overflow. Use [`NaiveDateTime::checked_sub_signed`] /// to detect that. @@ -1539,7 +1540,7 @@ impl Add<Months> for NaiveDateTime { /// ``` /// use chrono::{Duration, NaiveDate}; /// -/// let from_ymd = NaiveDate::from_ymd; +/// let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap(); /// /// let d = from_ymd(2016, 7, 8); /// let hms = |h, m, s| d.and_hms_opt(h, m, s).unwrap(); @@ -1561,7 +1562,7 @@ impl Add<Months> for NaiveDateTime { /// /// ``` /// # use chrono::{Duration, NaiveDate}; -/// # let from_ymd = NaiveDate::from_ymd; +/// # let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap(); /// # let hmsm = |h, m, s, milli| from_ymd(2016, 7, 8).and_hms_milli_opt(h, m, s, milli).unwrap(); /// let leap = hmsm(3, 5, 59, 1_300); /// assert_eq!(leap - Duration::zero(), hmsm(3, 5, 59, 1_300)); @@ -1571,6 +1572,8 @@ impl Add<Months> for NaiveDateTime { /// assert_eq!(leap - Duration::days(1), /// from_ymd(2016, 7, 7).and_hms_milli_opt(3, 6, 0, 300).unwrap()); /// ``` +/// +/// [leap second handling]: crate::NaiveTime#leap-second-handling impl Sub<OldDuration> for NaiveDateTime { type Output = NaiveDateTime; @@ -1596,8 +1599,7 @@ impl SubAssign<OldDuration> for NaiveDateTime { /// # Example /// /// ``` -/// use chrono::{Duration, NaiveDateTime, Months, NaiveDate}; -/// use std::str::FromStr; +/// use chrono::{Months, NaiveDate}; /// /// assert_eq!( /// NaiveDate::from_ymd_opt(2014, 01, 01).unwrap().and_hms_opt(01, 00, 00).unwrap() - Months::new(11), @@ -1636,7 +1638,7 @@ impl Sub<Months> for NaiveDateTime { /// ``` /// use chrono::{Duration, NaiveDate}; /// -/// let from_ymd = NaiveDate::from_ymd; +/// let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap(); /// /// let d = from_ymd(2016, 7, 8); /// assert_eq!(d.and_hms_opt(3, 5, 7).unwrap() - d.and_hms_opt(2, 4, 6).unwrap(), Duration::seconds(3600 + 60 + 1)); @@ -1652,7 +1654,7 @@ impl Sub<Months> for NaiveDateTime { /// /// ``` /// # use chrono::{Duration, NaiveDate}; -/// # let from_ymd = NaiveDate::from_ymd; +/// # let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap(); /// let leap = from_ymd(2015, 6, 30).and_hms_milli_opt(23, 59, 59, 1_500).unwrap(); /// assert_eq!(leap - from_ymd(2015, 6, 30).and_hms_opt(23, 0, 0).unwrap(), /// Duration::seconds(3600) + Duration::milliseconds(500)); @@ -1808,7 +1810,7 @@ impl str::FromStr for NaiveDateTime { /// use chrono::NaiveDateTime; /// /// let default_date = NaiveDateTime::default(); -/// assert_eq!(default_date, NaiveDateTime::from_timestamp(0, 0)); +/// assert_eq!(Some(default_date), NaiveDateTime::from_timestamp_opt(0, 0)); /// ``` impl Default for NaiveDateTime { fn default() -> Self { diff --git a/vendor/chrono/src/naive/datetime/serde.rs b/vendor/chrono/src/naive/datetime/serde.rs index 40695fa74..8107f384d 100644 --- a/vendor/chrono/src/naive/datetime/serde.rs +++ b/vendor/chrono/src/naive/datetime/serde.rs @@ -110,6 +110,7 @@ pub mod ts_nanoseconds { /// assert_eq!(as_string, r#"{"time":1526522699918355733}"#); /// # Ok::<(), serde_json::Error>(()) /// ``` + #[must_use] pub fn serialize<S>(dt: &NaiveDateTime, serializer: S) -> Result<S::Ok, S::Error> where S: ser::Serializer, @@ -127,15 +128,17 @@ pub mod ts_nanoseconds { /// # use chrono::NaiveDateTime; /// # use serde_derive::Deserialize; /// use chrono::naive::serde::ts_nanoseconds::deserialize as from_nano_ts; - /// #[derive(Deserialize)] + /// #[derive(Debug, PartialEq, Deserialize)] /// struct S { /// #[serde(deserialize_with = "from_nano_ts")] /// time: NaiveDateTime /// } /// /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918355733 }"#)?; + /// assert_eq!(my_s, S { time: NaiveDateTime::from_timestamp_opt(1526522699, 918355733).unwrap() }); /// # Ok::<(), serde_json::Error>(()) /// ``` + #[must_use] pub fn deserialize<'de, D>(d: D) -> Result<NaiveDateTime, D::Error> where D: de::Deserializer<'de>, @@ -230,6 +233,7 @@ pub mod ts_nanoseconds_option { /// assert_eq!(as_string, r#"{"time":1526522699918355733}"#); /// # Ok::<(), serde_json::Error>(()) /// ``` + #[must_use] pub fn serialize<S>(opt: &Option<NaiveDateTime>, serializer: S) -> Result<S::Ok, S::Error> where S: ser::Serializer, @@ -247,18 +251,20 @@ pub mod ts_nanoseconds_option { /// # Example: /// /// ```rust - /// # use chrono::naive::{NaiveDate, NaiveDateTime}; + /// # use chrono::naive::NaiveDateTime; /// # use serde_derive::Deserialize; /// use chrono::naive::serde::ts_nanoseconds_option::deserialize as from_nano_tsopt; - /// #[derive(Deserialize)] + /// #[derive(Debug, PartialEq, Deserialize)] /// struct S { /// #[serde(deserialize_with = "from_nano_tsopt")] /// time: Option<NaiveDateTime> /// } /// /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918355733 }"#)?; + /// assert_eq!(my_s, S { time: NaiveDateTime::from_timestamp_opt(1526522699, 918355733) }); /// # Ok::<(), serde_json::Error>(()) /// ``` + #[must_use] pub fn deserialize<'de, D>(d: D) -> Result<Option<NaiveDateTime>, D::Error> where D: de::Deserializer<'de>, @@ -356,6 +362,7 @@ pub mod ts_microseconds { /// assert_eq!(as_string, r#"{"time":1526522699918355}"#); /// # Ok::<(), serde_json::Error>(()) /// ``` + #[must_use] pub fn serialize<S>(dt: &NaiveDateTime, serializer: S) -> Result<S::Ok, S::Error> where S: ser::Serializer, @@ -373,15 +380,17 @@ pub mod ts_microseconds { /// # use chrono::NaiveDateTime; /// # use serde_derive::Deserialize; /// use chrono::naive::serde::ts_microseconds::deserialize as from_micro_ts; - /// #[derive(Deserialize)] + /// #[derive(Debug, PartialEq, Deserialize)] /// struct S { /// #[serde(deserialize_with = "from_micro_ts")] /// time: NaiveDateTime /// } /// /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918355 }"#)?; + /// assert_eq!(my_s, S { time: NaiveDateTime::from_timestamp_opt(1526522699, 918355000).unwrap() }); /// # Ok::<(), serde_json::Error>(()) /// ``` + #[must_use] pub fn deserialize<'de, D>(d: D) -> Result<NaiveDateTime, D::Error> where D: de::Deserializer<'de>, @@ -479,6 +488,7 @@ pub mod ts_microseconds_option { /// assert_eq!(as_string, r#"{"time":1526522699918355}"#); /// # Ok::<(), serde_json::Error>(()) /// ``` + #[must_use] pub fn serialize<S>(opt: &Option<NaiveDateTime>, serializer: S) -> Result<S::Ok, S::Error> where S: ser::Serializer, @@ -496,18 +506,20 @@ pub mod ts_microseconds_option { /// # Example: /// /// ```rust - /// # use chrono::naive::{NaiveDate, NaiveDateTime}; + /// # use chrono::naive::NaiveDateTime; /// # use serde_derive::Deserialize; /// use chrono::naive::serde::ts_microseconds_option::deserialize as from_micro_tsopt; - /// #[derive(Deserialize)] + /// #[derive(Debug, PartialEq, Deserialize)] /// struct S { /// #[serde(deserialize_with = "from_micro_tsopt")] /// time: Option<NaiveDateTime> /// } /// /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918355 }"#)?; + /// assert_eq!(my_s, S { time: NaiveDateTime::from_timestamp_opt(1526522699, 918355000) }); /// # Ok::<(), serde_json::Error>(()) /// ``` + #[must_use] pub fn deserialize<'de, D>(d: D) -> Result<Option<NaiveDateTime>, D::Error> where D: de::Deserializer<'de>, @@ -605,6 +617,7 @@ pub mod ts_milliseconds { /// assert_eq!(as_string, r#"{"time":1526522699918}"#); /// # Ok::<(), serde_json::Error>(()) /// ``` + #[must_use] pub fn serialize<S>(dt: &NaiveDateTime, serializer: S) -> Result<S::Ok, S::Error> where S: ser::Serializer, @@ -622,15 +635,17 @@ pub mod ts_milliseconds { /// # use chrono::NaiveDateTime; /// # use serde_derive::Deserialize; /// use chrono::naive::serde::ts_milliseconds::deserialize as from_milli_ts; - /// #[derive(Deserialize)] + /// #[derive(Debug, PartialEq, Deserialize)] /// struct S { /// #[serde(deserialize_with = "from_milli_ts")] /// time: NaiveDateTime /// } /// /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918 }"#)?; + /// assert_eq!(my_s, S { time: NaiveDateTime::from_timestamp_opt(1526522699, 918000000).unwrap() }); /// # Ok::<(), serde_json::Error>(()) /// ``` + #[must_use] pub fn deserialize<'de, D>(d: D) -> Result<NaiveDateTime, D::Error> where D: de::Deserializer<'de>, @@ -725,6 +740,7 @@ pub mod ts_milliseconds_option { /// assert_eq!(as_string, r#"{"time":1526522699918}"#); /// # Ok::<(), serde_json::Error>(()) /// ``` + #[must_use] pub fn serialize<S>(opt: &Option<NaiveDateTime>, serializer: S) -> Result<S::Ok, S::Error> where S: ser::Serializer, @@ -735,25 +751,27 @@ pub mod ts_milliseconds_option { } } - /// Deserialize a `NaiveDateTime` from a nanosecond timestamp or none + /// Deserialize a `NaiveDateTime` from a millisecond timestamp or none /// /// Intended for use with `serde`s `deserialize_with` attribute. /// /// # Example: /// /// ```rust - /// # use chrono::naive::{NaiveDate, NaiveDateTime}; + /// # use chrono::naive::NaiveDateTime; /// # use serde_derive::Deserialize; /// use chrono::naive::serde::ts_milliseconds_option::deserialize as from_milli_tsopt; - /// #[derive(Deserialize)] + /// #[derive(Debug, PartialEq, Deserialize)] /// struct S { /// #[serde(deserialize_with = "from_milli_tsopt")] /// time: Option<NaiveDateTime> /// } /// - /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918355 }"#)?; + /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918 }"#)?; + /// assert_eq!(my_s, S { time: NaiveDateTime::from_timestamp_opt(1526522699, 918000000) }); /// # Ok::<(), serde_json::Error>(()) /// ``` + #[must_use] pub fn deserialize<'de, D>(d: D) -> Result<Option<NaiveDateTime>, D::Error> where D: de::Deserializer<'de>, @@ -851,6 +869,7 @@ pub mod ts_seconds { /// assert_eq!(as_string, r#"{"time":1431684000}"#); /// # Ok::<(), serde_json::Error>(()) /// ``` + #[must_use] pub fn serialize<S>(dt: &NaiveDateTime, serializer: S) -> Result<S::Ok, S::Error> where S: ser::Serializer, @@ -868,15 +887,17 @@ pub mod ts_seconds { /// # use chrono::NaiveDateTime; /// # use serde_derive::Deserialize; /// use chrono::naive::serde::ts_seconds::deserialize as from_ts; - /// #[derive(Deserialize)] + /// #[derive(Debug, PartialEq, Deserialize)] /// struct S { /// #[serde(deserialize_with = "from_ts")] /// time: NaiveDateTime /// } /// /// let my_s: S = serde_json::from_str(r#"{ "time": 1431684000 }"#)?; + /// assert_eq!(my_s, S { time: NaiveDateTime::from_timestamp_opt(1431684000, 0).unwrap() }); /// # Ok::<(), serde_json::Error>(()) /// ``` + #[must_use] pub fn deserialize<'de, D>(d: D) -> Result<NaiveDateTime, D::Error> where D: de::Deserializer<'de>, @@ -968,6 +989,7 @@ pub mod ts_seconds_option { /// assert_eq!(as_string, r#"{"time":1526522699}"#); /// # Ok::<(), serde_json::Error>(()) /// ``` + #[must_use] pub fn serialize<S>(opt: &Option<NaiveDateTime>, serializer: S) -> Result<S::Ok, S::Error> where S: ser::Serializer, @@ -985,18 +1007,20 @@ pub mod ts_seconds_option { /// # Example: /// /// ```rust - /// # use chrono::naive::{NaiveDate, NaiveDateTime}; + /// # use chrono::naive::NaiveDateTime; /// # use serde_derive::Deserialize; /// use chrono::naive::serde::ts_seconds_option::deserialize as from_tsopt; - /// #[derive(Deserialize)] + /// #[derive(Debug, PartialEq, Deserialize)] /// struct S { /// #[serde(deserialize_with = "from_tsopt")] /// time: Option<NaiveDateTime> /// } /// /// let my_s: S = serde_json::from_str(r#"{ "time": 1431684000 }"#)?; + /// assert_eq!(my_s, S { time: NaiveDateTime::from_timestamp_opt(1431684000, 0) }); /// # Ok::<(), serde_json::Error>(()) /// ``` + #[must_use] pub fn deserialize<'de, D>(d: D) -> Result<Option<NaiveDateTime>, D::Error> where D: de::Deserializer<'de>, diff --git a/vendor/chrono/src/naive/datetime/tests.rs b/vendor/chrono/src/naive/datetime/tests.rs index 202bdb34d..07309a48a 100644 --- a/vendor/chrono/src/naive/datetime/tests.rs +++ b/vendor/chrono/src/naive/datetime/tests.rs @@ -330,7 +330,7 @@ fn test_nanosecond_range() { } #[test] -fn test_and_timezone() { +fn test_and_local_timezone() { let ndt = NaiveDate::from_ymd_opt(2022, 6, 15).unwrap().and_hms_opt(18, 59, 36).unwrap(); let dt_utc = ndt.and_local_timezone(Utc).unwrap(); assert_eq!(dt_utc.naive_local(), ndt); @@ -341,3 +341,11 @@ fn test_and_timezone() { assert_eq!(dt_offset.naive_local(), ndt); assert_eq!(dt_offset.timezone(), offset_tz); } + +#[test] +fn test_and_utc() { + let ndt = NaiveDate::from_ymd_opt(2023, 1, 30).unwrap().and_hms_opt(19, 32, 33).unwrap(); + let dt_utc = ndt.and_utc(); + assert_eq!(dt_utc.naive_local(), ndt); + assert_eq!(dt_utc.timezone(), Utc); +} diff --git a/vendor/chrono/src/naive/internals.rs b/vendor/chrono/src/naive/internals.rs index 05305b506..65b47ae73 100644 --- a/vendor/chrono/src/naive/internals.rs +++ b/vendor/chrono/src/naive/internals.rs @@ -17,10 +17,8 @@ use crate::Weekday; use core::{fmt, i32}; -use num_integer::{div_rem, mod_floor}; -use num_traits::FromPrimitive; -/// The internal date representation. This also includes the packed `Mdf` value. +/// The internal date representation: `year << 13 | Of` pub(super) type DateImpl = i32; pub(super) const MAX_YEAR: DateImpl = i32::MAX >> 13; @@ -53,7 +51,7 @@ pub(super) const FE: YearFlags = YearFlags(0o07); pub(super) const G: YearFlags = YearFlags(0o16); pub(super) const GF: YearFlags = YearFlags(0o06); -static YEAR_TO_FLAGS: [YearFlags; 400] = [ +const YEAR_TO_FLAGS: &[YearFlags; 400] = &[ BA, G, F, E, DC, B, A, G, FE, D, C, B, AG, F, E, D, CB, A, G, F, ED, C, B, A, GF, E, D, C, BA, G, F, E, DC, B, A, G, FE, D, C, B, AG, F, E, D, CB, A, G, F, ED, C, B, A, GF, E, D, C, BA, G, F, E, DC, B, A, G, FE, D, C, B, AG, F, E, D, CB, A, G, F, ED, C, B, A, GF, E, D, C, BA, G, F, @@ -72,7 +70,7 @@ static YEAR_TO_FLAGS: [YearFlags; 400] = [ D, CB, A, G, F, ED, C, B, A, GF, E, D, C, // 400 ]; -static YEAR_DELTAS: [u8; 401] = [ +const YEAR_DELTAS: &[u8; 401] = &[ 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 11, 11, 11, 11, 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19, 20, 20, 20, 20, @@ -94,46 +92,48 @@ static YEAR_DELTAS: [u8; 401] = [ 96, 97, 97, 97, 97, // 400+1 ]; -pub(super) fn cycle_to_yo(cycle: u32) -> (u32, u32) { - let (mut year_mod_400, mut ordinal0) = div_rem(cycle, 365); - let delta = u32::from(YEAR_DELTAS[year_mod_400 as usize]); +pub(super) const fn cycle_to_yo(cycle: u32) -> (u32, u32) { + let mut year_mod_400 = cycle / 365; + let mut ordinal0 = cycle % 365; + let delta = YEAR_DELTAS[year_mod_400 as usize] as u32; if ordinal0 < delta { year_mod_400 -= 1; - ordinal0 += 365 - u32::from(YEAR_DELTAS[year_mod_400 as usize]); + ordinal0 += 365 - YEAR_DELTAS[year_mod_400 as usize] as u32; } else { ordinal0 -= delta; } (year_mod_400, ordinal0 + 1) } -pub(super) fn yo_to_cycle(year_mod_400: u32, ordinal: u32) -> u32 { - year_mod_400 * 365 + u32::from(YEAR_DELTAS[year_mod_400 as usize]) + ordinal - 1 +pub(super) const fn yo_to_cycle(year_mod_400: u32, ordinal: u32) -> u32 { + year_mod_400 * 365 + YEAR_DELTAS[year_mod_400 as usize] as u32 + ordinal - 1 } impl YearFlags { #[allow(unreachable_pub)] // public as an alias for benchmarks only #[doc(hidden)] // for benchmarks only #[inline] - pub fn from_year(year: i32) -> YearFlags { - let year = mod_floor(year, 400); + #[must_use] + pub const fn from_year(year: i32) -> YearFlags { + let year = year.rem_euclid(400); YearFlags::from_year_mod_400(year) } #[inline] - pub(super) fn from_year_mod_400(year: i32) -> YearFlags { + pub(super) const fn from_year_mod_400(year: i32) -> YearFlags { YEAR_TO_FLAGS[year as usize] } #[inline] - pub(super) fn ndays(&self) -> u32 { + pub(super) const fn ndays(&self) -> u32 { let YearFlags(flags) = *self; - 366 - u32::from(flags >> 3) + 366 - (flags >> 3) as u32 } #[inline] - pub(super) fn isoweek_delta(&self) -> u32 { + pub(super) const fn isoweek_delta(&self) -> u32 { let YearFlags(flags) = *self; - let mut delta = u32::from(flags) & 0b0111; + let mut delta = (flags & 0b0111) as u32; if delta < 3 { delta += 7; } @@ -172,12 +172,13 @@ impl fmt::Debug for YearFlags { } } +// OL: (ordinal << 1) | leap year flag pub(super) const MIN_OL: u32 = 1 << 1; -pub(super) const MAX_OL: u32 = 366 << 1; // larger than the non-leap last day `(365 << 1) | 1` +pub(super) const MAX_OL: u32 = 366 << 1; // `(366 << 1) | 1` would be day 366 in a non-leap year pub(super) const MAX_MDL: u32 = (12 << 6) | (31 << 1) | 1; const XX: i8 = -128; -static MDL_TO_OL: [i8; MAX_MDL as usize + 1] = [ +const MDL_TO_OL: &[i8; MAX_MDL as usize + 1] = &[ XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, // 0 @@ -220,7 +221,7 @@ static MDL_TO_OL: [i8; MAX_MDL as usize + 1] = [ 100, // 12 ]; -static OL_TO_MDL: [u8; MAX_OL as usize + 1] = [ +const OL_TO_MDL: &[u8; MAX_OL as usize + 1] = &[ 0, 0, // 0 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, @@ -265,60 +266,76 @@ static OL_TO_MDL: [u8; MAX_OL as usize + 1] = [ /// /// The whole bits except for the least 3 bits are referred as `Ol` (ordinal and leap flag), /// which is an index to the `OL_TO_MDL` lookup table. +/// +/// The methods implemented on `Of` always return a valid value. #[derive(PartialEq, PartialOrd, Copy, Clone)] -pub(super) struct Of(pub(crate) u32); +pub(super) struct Of(u32); impl Of { #[inline] - pub(super) fn new(ordinal: u32, YearFlags(flags): YearFlags) -> Option<Of> { - match ordinal <= 366 { - true => Some(Of((ordinal << 4) | u32::from(flags))), - false => None, - } + pub(super) const fn new(ordinal: u32, YearFlags(flags): YearFlags) -> Option<Of> { + let of = Of((ordinal << 4) | flags as u32); + of.validate() + } + + pub(super) const fn from_date_impl(date_impl: DateImpl) -> Of { + // We assume the value in the `DateImpl` is valid. + Of((date_impl & 0b1_1111_1111_1111) as u32) } #[inline] - pub(super) fn from_mdf(Mdf(mdf): Mdf) -> Of { + pub(super) const fn from_mdf(Mdf(mdf): Mdf) -> Option<Of> { let mdl = mdf >> 3; - match MDL_TO_OL.get(mdl as usize) { - Some(&v) => Of(mdf.wrapping_sub((i32::from(v) as u32 & 0x3ff) << 3)), - None => Of(0), + if mdl > MAX_MDL { + // Panicking on out-of-bounds indexing would be reasonable, but just return `None`. + return None; } + // Array is indexed from `[1..=MAX_MDL]`, with a `0` index having a meaningless value. + let v = MDL_TO_OL[mdl as usize]; + let of = Of(mdf.wrapping_sub((v as i32 as u32 & 0x3ff) << 3)); + of.validate() } #[inline] - pub(super) fn valid(&self) -> bool { - let Of(of) = *self; - let ol = of >> 3; - (MIN_OL..=MAX_OL).contains(&ol) + pub(super) const fn inner(&self) -> u32 { + self.0 } + /// Returns `(ordinal << 1) | leap-year-flag`. #[inline] - pub(super) const fn ordinal(&self) -> u32 { - let Of(of) = *self; - of >> 4 + const fn ol(&self) -> u32 { + self.0 >> 3 } #[inline] - pub(super) fn with_ordinal(&self, ordinal: u32) -> Option<Of> { - if ordinal > 366 { - return None; + const fn validate(self) -> Option<Of> { + let ol = self.ol(); + match ol >= MIN_OL && ol <= MAX_OL { + true => Some(self), + false => None, } + } - let Of(of) = *self; - Some(Of((of & 0b1111) | (ordinal << 4))) + #[inline] + pub(super) const fn ordinal(&self) -> u32 { + self.0 >> 4 + } + + #[inline] + pub(super) const fn with_ordinal(&self, ordinal: u32) -> Option<Of> { + let of = Of((ordinal << 4) | (self.0 & 0b1111)); + of.validate() } #[inline] pub(super) const fn flags(&self) -> YearFlags { - let Of(of) = *self; - YearFlags((of & 0b1111) as u8) + YearFlags((self.0 & 0b1111) as u8) } #[inline] - pub(super) fn weekday(&self) -> Weekday { + pub(super) const fn weekday(&self) -> Weekday { let Of(of) = *self; - Weekday::from_u32(((of >> 4) + (of & 0b111)) % 7).unwrap() + weekday_from_u32_mod7((of >> 4) + (of & 0b111)) } #[inline] @@ -326,25 +343,29 @@ impl Of { // week ordinal = ordinal + delta let Of(of) = *self; let weekord = (of >> 4).wrapping_add(self.flags().isoweek_delta()); - (weekord / 7, Weekday::from_u32(weekord % 7).unwrap()) + (weekord / 7, weekday_from_u32_mod7(weekord)) } #[cfg_attr(feature = "cargo-clippy", allow(clippy::wrong_self_convention))] #[inline] - pub(super) fn to_mdf(&self) -> Mdf { + pub(super) const fn to_mdf(&self) -> Mdf { Mdf::from_of(*self) } + /// Returns an `Of` with the next day, or `None` if this is the last day of the year. #[inline] - pub(super) const fn succ(&self) -> Of { - let Of(of) = *self; - Of(of + (1 << 4)) + pub(super) const fn succ(&self) -> Option<Of> { + let of = Of(self.0 + (1 << 4)); + of.validate() } + /// Returns an `Of` with the previous day, or `None` if this is the first day of the year. #[inline] - pub(super) const fn pred(&self) -> Of { - let Of(of) = *self; - Of(of - (1 << 4)) + pub(super) const fn pred(&self) -> Option<Of> { + match self.ordinal() { + 1 => None, + _ => Some(Of(self.0 - (1 << 4))), + } } } @@ -366,34 +387,44 @@ impl fmt::Debug for Of { /// The whole bits except for the least 3 bits are referred as `Mdl` /// (month, day of month and leap flag), /// which is an index to the `MDL_TO_OL` lookup table. +/// +/// The methods implemented on `Mdf` do not always return a valid value. +/// Dates that can't exist, like February 30, can still be represented. +/// Use `Mdl::valid` to check whether the date is valid. #[derive(PartialEq, PartialOrd, Copy, Clone)] -pub(super) struct Mdf(pub(super) u32); +pub(super) struct Mdf(u32); impl Mdf { #[inline] - pub(super) fn new(month: u32, day: u32, YearFlags(flags): YearFlags) -> Option<Mdf> { - match month <= 12 && day <= 31 { - true => Some(Mdf((month << 9) | (day << 4) | u32::from(flags))), + pub(super) const fn new(month: u32, day: u32, YearFlags(flags): YearFlags) -> Option<Mdf> { + match month >= 1 && month <= 12 && day >= 1 && day <= 31 { + true => Some(Mdf((month << 9) | (day << 4) | flags as u32)), false => None, } } #[inline] - pub(super) fn from_of(Of(of): Of) -> Mdf { + pub(super) const fn from_of(Of(of): Of) -> Mdf { let ol = of >> 3; - match OL_TO_MDL.get(ol as usize) { - Some(&v) => Mdf(of + (u32::from(v) << 3)), - None => Mdf(0), + if ol <= MAX_OL { + // Array is indexed from `[1..=MAX_OL]`, with a `0` index having a meaningless value. + Mdf(of + ((OL_TO_MDL[ol as usize] as u32) << 3)) + } else { + // Panicking here would be reasonable, but we are just going on with a safe value. + Mdf(0) } } #[cfg(test)] - pub(super) fn valid(&self) -> bool { + pub(super) const fn valid(&self) -> bool { let Mdf(mdf) = *self; let mdl = mdf >> 3; - match MDL_TO_OL.get(mdl as usize) { - Some(&v) => v >= 0, - None => false, + if mdl <= MAX_MDL { + // Array is indexed from `[1..=MAX_MDL]`, with a `0` index having a meaningless value. + MDL_TO_OL[mdl as usize] >= 0 + } else { + // Panicking here would be reasonable, but we are just going on with a safe value. + false } } @@ -404,7 +435,7 @@ impl Mdf { } #[inline] - pub(super) fn with_month(&self, month: u32) -> Option<Mdf> { + pub(super) const fn with_month(&self, month: u32) -> Option<Mdf> { if month > 12 { return None; } @@ -420,7 +451,7 @@ impl Mdf { } #[inline] - pub(super) fn with_day(&self, day: u32) -> Option<Mdf> { + pub(super) const fn with_day(&self, day: u32) -> Option<Mdf> { if day > 31 { return None; } @@ -430,14 +461,14 @@ impl Mdf { } #[inline] - pub(super) fn with_flags(&self, YearFlags(flags): YearFlags) -> Mdf { + pub(super) const fn with_flags(&self, YearFlags(flags): YearFlags) -> Mdf { let Mdf(mdf) = *self; - Mdf((mdf & !0b1111) | u32::from(flags)) + Mdf((mdf & !0b1111) | flags as u32) } #[cfg_attr(feature = "cargo-clippy", allow(clippy::wrong_self_convention))] #[inline] - pub(super) fn to_of(&self) -> Of { + pub(super) const fn to_of(&self) -> Option<Of> { Of::from_mdf(*self) } } @@ -456,11 +487,26 @@ impl fmt::Debug for Mdf { } } +/// Create a `Weekday` from an `u32`, with Monday = 0. +/// Infallible, takes any `n` and applies `% 7`. +#[inline] +const fn weekday_from_u32_mod7(n: u32) -> Weekday { + match n % 7 { + 0 => Weekday::Mon, + 1 => Weekday::Tue, + 2 => Weekday::Wed, + 3 => Weekday::Thu, + 4 => Weekday::Fri, + 5 => Weekday::Sat, + _ => Weekday::Sun, + } +} + #[cfg(test)] mod tests { - use num_iter::range_inclusive; use std::u32; + use super::weekday_from_u32_mod7; use super::{Mdf, Of}; use super::{YearFlags, A, AG, B, BA, C, CB, D, DC, E, ED, F, FE, G, GF}; use crate::Weekday; @@ -507,7 +553,7 @@ mod tests { #[test] fn test_of() { fn check(expected: bool, flags: YearFlags, ordinal1: u32, ordinal2: u32) { - for ordinal in range_inclusive(ordinal1, ordinal2) { + for ordinal in ordinal1..=ordinal2 { let of = match Of::new(ordinal, flags) { Some(of) => of, None if !expected => continue, @@ -515,7 +561,7 @@ mod tests { }; assert!( - of.valid() == expected, + of.validate().is_some() == expected, "ordinal {} = {:?} should be {} for dominical year {:?}", ordinal, of, @@ -543,8 +589,8 @@ mod tests { #[test] fn test_mdf_valid() { fn check(expected: bool, flags: YearFlags, month1: u32, day1: u32, month2: u32, day2: u32) { - for month in range_inclusive(month1, month2) { - for day in range_inclusive(day1, day2) { + for month in month1..=month2 { + for day in day1..=day2 { let mdf = match Mdf::new(month, day, flags) { Some(mdf) => mdf, None if !expected => continue, @@ -634,9 +680,8 @@ mod tests { #[test] fn test_of_fields() { for &flags in FLAGS.iter() { - for ordinal in range_inclusive(1u32, 366) { - let of = Of::new(ordinal, flags).unwrap(); - if of.valid() { + for ordinal in 1u32..=366 { + if let Some(of) = Of::new(ordinal, flags) { assert_eq!(of.ordinal(), ordinal); } } @@ -648,15 +693,10 @@ mod tests { fn check(flags: YearFlags, ordinal: u32) { let of = Of::new(ordinal, flags).unwrap(); - for ordinal in range_inclusive(0u32, 1024) { - let of = match of.with_ordinal(ordinal) { - Some(of) => of, - None if ordinal > 366 => continue, - None => panic!("failed to create Of with ordinal {}", ordinal), - }; - - assert_eq!(of.valid(), Of::new(ordinal, flags).unwrap().valid()); - if of.valid() { + for ordinal in 0u32..=1024 { + let of = of.with_ordinal(ordinal); + assert_eq!(of, Of::new(ordinal, flags)); + if let Some(of) = of { assert_eq!(of.ordinal(), ordinal); } } @@ -691,7 +731,7 @@ mod tests { for &flags in FLAGS.iter() { let mut prev = Of::new(1, flags).unwrap().weekday(); - for ordinal in range_inclusive(2u32, flags.ndays()) { + for ordinal in 2u32..=flags.ndays() { let of = Of::new(ordinal, flags).unwrap(); let expected = prev.succ(); assert_eq!(of.weekday(), expected); @@ -703,8 +743,8 @@ mod tests { #[test] fn test_mdf_fields() { for &flags in FLAGS.iter() { - for month in range_inclusive(1u32, 12) { - for day in range_inclusive(1u32, 31) { + for month in 1u32..=12 { + for day in 1u32..31 { let mdf = match Mdf::new(month, day, flags) { Some(mdf) => mdf, None => continue, @@ -724,7 +764,7 @@ mod tests { fn check(flags: YearFlags, month: u32, day: u32) { let mdf = Mdf::new(month, day, flags).unwrap(); - for month in range_inclusive(0u32, 16) { + for month in 0u32..=16 { let mdf = match mdf.with_month(month) { Some(mdf) => mdf, None if month > 12 => continue, @@ -737,7 +777,7 @@ mod tests { } } - for day in range_inclusive(0u32, 1024) { + for day in 0u32..=1024 { let mdf = match mdf.with_day(day) { Some(mdf) => mdf, None if day > 31 => continue, @@ -780,37 +820,74 @@ mod tests { #[test] fn test_of_to_mdf() { - for i in range_inclusive(0u32, 8192) { - let of = Of(i); - assert_eq!(of.valid(), of.to_mdf().valid()); + for i in 0u32..=8192 { + if let Some(of) = Of(i).validate() { + assert!(of.to_mdf().valid()); + } } } #[test] fn test_mdf_to_of() { - for i in range_inclusive(0u32, 8192) { + for i in 0u32..=8192 { let mdf = Mdf(i); - assert_eq!(mdf.valid(), mdf.to_of().valid()); + assert_eq!(mdf.valid(), mdf.to_of().is_some()); } } #[test] fn test_of_to_mdf_to_of() { - for i in range_inclusive(0u32, 8192) { - let of = Of(i); - if of.valid() { - assert_eq!(of, of.to_mdf().to_of()); + for i in 0u32..=8192 { + if let Some(of) = Of(i).validate() { + assert_eq!(of, of.to_mdf().to_of().unwrap()); } } } #[test] fn test_mdf_to_of_to_mdf() { - for i in range_inclusive(0u32, 8192) { + for i in 0u32..=8192 { let mdf = Mdf(i); if mdf.valid() { - assert_eq!(mdf, mdf.to_of().to_mdf()); + assert_eq!(mdf, mdf.to_of().unwrap().to_mdf()); } } } + + #[test] + fn test_invalid_returns_none() { + let regular_year = YearFlags::from_year(2023); + let leap_year = YearFlags::from_year(2024); + assert!(Of::new(0, regular_year).is_none()); + assert!(Of::new(366, regular_year).is_none()); + assert!(Of::new(366, leap_year).is_some()); + assert!(Of::new(367, regular_year).is_none()); + + assert!(Mdf::new(0, 1, regular_year).is_none()); + assert!(Mdf::new(13, 1, regular_year).is_none()); + assert!(Mdf::new(1, 0, regular_year).is_none()); + assert!(Mdf::new(1, 32, regular_year).is_none()); + assert!(Mdf::new(2, 31, regular_year).is_some()); + + assert!(Of::from_mdf(Mdf::new(2, 30, regular_year).unwrap()).is_none()); + assert!(Of::from_mdf(Mdf::new(2, 30, leap_year).unwrap()).is_none()); + assert!(Of::from_mdf(Mdf::new(2, 29, regular_year).unwrap()).is_none()); + assert!(Of::from_mdf(Mdf::new(2, 29, leap_year).unwrap()).is_some()); + assert!(Of::from_mdf(Mdf::new(2, 28, regular_year).unwrap()).is_some()); + + assert!(Of::new(365, regular_year).unwrap().succ().is_none()); + assert!(Of::new(365, leap_year).unwrap().succ().is_some()); + assert!(Of::new(366, leap_year).unwrap().succ().is_none()); + + assert!(Of::new(1, regular_year).unwrap().pred().is_none()); + assert!(Of::new(1, leap_year).unwrap().pred().is_none()); + } + + #[test] + fn test_weekday_from_u32_mod7() { + for i in 0..=1000 { + assert_eq!(weekday_from_u32_mod7(i), Weekday::try_from((i % 7) as u8).unwrap()); + } + assert_eq!(weekday_from_u32_mod7(u32::MAX), Weekday::Thu); + } } diff --git a/vendor/chrono/src/naive/isoweek.rs b/vendor/chrono/src/naive/isoweek.rs index 6a4fcfd11..df5556a12 100644 --- a/vendor/chrono/src/naive/isoweek.rs +++ b/vendor/chrono/src/naive/isoweek.rs @@ -46,7 +46,8 @@ pub(super) fn iso_week_from_yof(year: i32, of: Of) -> IsoWeek { (year, rawweek) } }; - IsoWeek { ywf: (year << 10) | (week << 4) as DateImpl | DateImpl::from(of.flags().0) } + let flags = YearFlags::from_year(year); + IsoWeek { ywf: (year << 10) | (week << 4) as DateImpl | DateImpl::from(flags.0) } } impl IsoWeek { @@ -57,7 +58,7 @@ impl IsoWeek { /// ``` /// use chrono::{NaiveDate, Datelike, Weekday}; /// - /// let d = NaiveDate::from_isoywd(2015, 1, Weekday::Mon); + /// let d = NaiveDate::from_isoywd_opt(2015, 1, Weekday::Mon).unwrap(); /// assert_eq!(d.iso_week().year(), 2015); /// ``` /// @@ -66,7 +67,7 @@ impl IsoWeek { /// /// ``` /// # use chrono::{NaiveDate, Datelike, Weekday}; - /// # let d = NaiveDate::from_isoywd(2015, 1, Weekday::Mon); + /// # let d = NaiveDate::from_isoywd_opt(2015, 1, Weekday::Mon).unwrap(); /// assert_eq!(d.year(), 2014); /// assert_eq!(d, NaiveDate::from_ymd_opt(2014, 12, 29).unwrap()); /// ``` @@ -84,7 +85,7 @@ impl IsoWeek { /// ``` /// use chrono::{NaiveDate, Datelike, Weekday}; /// - /// let d = NaiveDate::from_isoywd(2015, 15, Weekday::Mon); + /// let d = NaiveDate::from_isoywd_opt(2015, 15, Weekday::Mon).unwrap(); /// assert_eq!(d.iso_week().week(), 15); /// ``` #[inline] @@ -101,7 +102,7 @@ impl IsoWeek { /// ``` /// use chrono::{NaiveDate, Datelike, Weekday}; /// - /// let d = NaiveDate::from_isoywd(2015, 15, Weekday::Mon); + /// let d = NaiveDate::from_isoywd_opt(2015, 15, Weekday::Mon).unwrap(); /// assert_eq!(d.iso_week().week0(), 14); /// ``` #[inline] @@ -164,4 +165,38 @@ mod tests { assert_eq!(maxweek.week0(), 0); assert_eq!(format!("{:?}", maxweek), NaiveDate::MAX.format("%G-W%V").to_string()); } + + #[test] + fn test_iso_week_equivalence_for_first_week() { + let monday = NaiveDate::from_ymd_opt(2024, 12, 30).unwrap(); + let friday = NaiveDate::from_ymd_opt(2025, 1, 3).unwrap(); + + assert_eq!(monday.iso_week(), friday.iso_week()); + } + + #[test] + fn test_iso_week_equivalence_for_last_week() { + let monday = NaiveDate::from_ymd_opt(2026, 12, 28).unwrap(); + let friday = NaiveDate::from_ymd_opt(2027, 1, 1).unwrap(); + + assert_eq!(monday.iso_week(), friday.iso_week()); + } + + #[test] + fn test_iso_week_ordering_for_first_week() { + let monday = NaiveDate::from_ymd_opt(2024, 12, 30).unwrap(); + let friday = NaiveDate::from_ymd_opt(2025, 1, 3).unwrap(); + + assert!(monday.iso_week() >= friday.iso_week()); + assert!(monday.iso_week() <= friday.iso_week()); + } + + #[test] + fn test_iso_week_ordering_for_last_week() { + let monday = NaiveDate::from_ymd_opt(2026, 12, 28).unwrap(); + let friday = NaiveDate::from_ymd_opt(2027, 1, 1).unwrap(); + + assert!(monday.iso_week() >= friday.iso_week()); + assert!(monday.iso_week() <= friday.iso_week()); + } } diff --git a/vendor/chrono/src/naive/time/mod.rs b/vendor/chrono/src/naive/time/mod.rs index 1d36583aa..3700c5cba 100644 --- a/vendor/chrono/src/naive/time/mod.rs +++ b/vendor/chrono/src/naive/time/mod.rs @@ -8,14 +8,15 @@ use core::borrow::Borrow; use core::ops::{Add, AddAssign, Sub, SubAssign}; use core::{fmt, str}; -use num_integer::div_mod_floor; #[cfg(feature = "rkyv")] use rkyv::{Archive, Deserialize, Serialize}; #[cfg(any(feature = "alloc", feature = "std", test))] use crate::format::DelayedFormat; -use crate::format::{parse, write_hundreds, ParseError, ParseResult, Parsed, StrftimeItems}; -use crate::format::{Fixed, Item, Numeric, Pad}; +use crate::format::{ + parse, parse_and_remainder, write_hundreds, Fixed, Item, Numeric, Pad, ParseError, ParseResult, + Parsed, StrftimeItems, +}; use crate::oldtime::Duration as OldDuration; use crate::Timelike; @@ -74,7 +75,7 @@ mod tests; /// All methods accepting fractional seconds will accept such values. /// /// ``` -/// use chrono::{NaiveDate, NaiveTime, Utc, TimeZone}; +/// use chrono::{NaiveDate, NaiveTime, Utc}; /// /// let t = NaiveTime::from_hms_milli_opt(8, 59, 59, 1_000).unwrap(); /// @@ -161,7 +162,7 @@ mod tests; /// will be represented as the second part being 60, as required by ISO 8601. /// /// ``` -/// use chrono::{Utc, TimeZone, NaiveDate}; +/// use chrono::{Utc, NaiveDate}; /// /// let dt = NaiveDate::from_ymd_opt(2015, 6, 30).unwrap().and_hms_milli_opt(23, 59, 59, 1_000).unwrap().and_local_timezone(Utc).unwrap(); /// assert_eq!(format!("{:?}", dt), "2015-06-30T23:59:60Z"); @@ -214,6 +215,7 @@ impl NaiveTime { /// Panics on invalid hour, minute and/or second. #[deprecated(since = "0.4.23", note = "use `from_hms_opt()` instead")] #[inline] + #[must_use] pub fn from_hms(hour: u32, min: u32, sec: u32) -> NaiveTime { NaiveTime::from_hms_opt(hour, min, sec).expect("invalid time") } @@ -239,7 +241,8 @@ impl NaiveTime { /// assert!(from_hms_opt(23, 59, 60).is_none()); /// ``` #[inline] - pub fn from_hms_opt(hour: u32, min: u32, sec: u32) -> Option<NaiveTime> { + #[must_use] + pub const fn from_hms_opt(hour: u32, min: u32, sec: u32) -> Option<NaiveTime> { NaiveTime::from_hms_nano_opt(hour, min, sec, 0) } @@ -251,6 +254,7 @@ impl NaiveTime { /// Panics on invalid hour, minute, second and/or millisecond. #[deprecated(since = "0.4.23", note = "use `from_hms_milli_opt()` instead")] #[inline] + #[must_use] pub fn from_hms_milli(hour: u32, min: u32, sec: u32, milli: u32) -> NaiveTime { NaiveTime::from_hms_milli_opt(hour, min, sec, milli).expect("invalid time") } @@ -278,6 +282,7 @@ impl NaiveTime { /// assert!(from_hmsm_opt(23, 59, 59, 2_000).is_none()); /// ``` #[inline] + #[must_use] pub fn from_hms_milli_opt(hour: u32, min: u32, sec: u32, milli: u32) -> Option<NaiveTime> { milli .checked_mul(1_000_000) @@ -292,6 +297,7 @@ impl NaiveTime { /// Panics on invalid hour, minute, second and/or microsecond. #[deprecated(since = "0.4.23", note = "use `from_hms_micro_opt()` instead")] #[inline] + #[must_use] pub fn from_hms_micro(hour: u32, min: u32, sec: u32, micro: u32) -> NaiveTime { NaiveTime::from_hms_micro_opt(hour, min, sec, micro).expect("invalid time") } @@ -319,6 +325,7 @@ impl NaiveTime { /// assert!(from_hmsu_opt(23, 59, 59, 2_000_000).is_none()); /// ``` #[inline] + #[must_use] pub fn from_hms_micro_opt(hour: u32, min: u32, sec: u32, micro: u32) -> Option<NaiveTime> { micro.checked_mul(1_000).and_then(|nano| NaiveTime::from_hms_nano_opt(hour, min, sec, nano)) } @@ -331,6 +338,7 @@ impl NaiveTime { /// Panics on invalid hour, minute, second and/or nanosecond. #[deprecated(since = "0.4.23", note = "use `from_hms_nano_opt()` instead")] #[inline] + #[must_use] pub fn from_hms_nano(hour: u32, min: u32, sec: u32, nano: u32) -> NaiveTime { NaiveTime::from_hms_nano_opt(hour, min, sec, nano).expect("invalid time") } @@ -358,7 +366,8 @@ impl NaiveTime { /// assert!(from_hmsn_opt(23, 59, 59, 2_000_000_000).is_none()); /// ``` #[inline] - pub fn from_hms_nano_opt(hour: u32, min: u32, sec: u32, nano: u32) -> Option<NaiveTime> { + #[must_use] + pub const fn from_hms_nano_opt(hour: u32, min: u32, sec: u32, nano: u32) -> Option<NaiveTime> { if hour >= 24 || min >= 60 || sec >= 60 || nano >= 2_000_000_000 { return None; } @@ -374,6 +383,7 @@ impl NaiveTime { /// Panics on invalid number of seconds and/or nanosecond. #[deprecated(since = "0.4.23", note = "use `from_num_seconds_from_midnight_opt()` instead")] #[inline] + #[must_use] pub fn from_num_seconds_from_midnight(secs: u32, nano: u32) -> NaiveTime { NaiveTime::from_num_seconds_from_midnight_opt(secs, nano).expect("invalid time") } @@ -399,7 +409,8 @@ impl NaiveTime { /// assert!(from_nsecs_opt(86399, 2_000_000_000).is_none()); /// ``` #[inline] - pub fn from_num_seconds_from_midnight_opt(secs: u32, nano: u32) -> Option<NaiveTime> { + #[must_use] + pub const fn from_num_seconds_from_midnight_opt(secs: u32, nano: u32) -> Option<NaiveTime> { if secs >= 86_400 || nano >= 2_000_000_000 { return None; } @@ -473,6 +484,28 @@ impl NaiveTime { parsed.to_naive_time() } + /// Parses a string from a user-specified format into a new `NaiveTime` value, and a slice with + /// the remaining portion of the string. + /// See the [`format::strftime` module](../format/strftime/index.html) + /// on the supported escape sequences. + /// + /// Similar to [`parse_from_str`](#method.parse_from_str). + /// + /// # Example + /// + /// ```rust + /// # use chrono::{NaiveTime}; + /// let (time, remainder) = NaiveTime::parse_and_remainder( + /// "3h4m33s trailing text", "%-Hh%-Mm%-Ss").unwrap(); + /// assert_eq!(time, NaiveTime::from_hms_opt(3, 4, 33).unwrap()); + /// assert_eq!(remainder, " trailing text"); + /// ``` + pub fn parse_and_remainder<'a>(s: &'a str, fmt: &str) -> ParseResult<(NaiveTime, &'a str)> { + let mut parsed = Parsed::new(); + let remainder = parse_and_remainder(&mut parsed, s, StrftimeItems::new(fmt))?; + parsed.to_naive_time().map(|t| (t, remainder)) + } + /// Adds given `Duration` to the current time, /// and also returns the number of *seconds* /// in the integral number of days ignored from the addition. @@ -483,7 +516,7 @@ impl NaiveTime { /// ``` /// use chrono::{Duration, NaiveTime}; /// - /// let from_hms = NaiveTime::from_hms; + /// let from_hms = |h, m, s| { NaiveTime::from_hms_opt(h, m, s).unwrap() }; /// /// assert_eq!(from_hms(3, 4, 5).overflowing_add_signed(Duration::hours(11)), /// (from_hms(14, 4, 5), 0)); @@ -492,6 +525,7 @@ impl NaiveTime { /// assert_eq!(from_hms(3, 4, 5).overflowing_add_signed(Duration::hours(-7)), /// (from_hms(20, 4, 5), -86_400)); /// ``` + #[must_use] pub fn overflowing_add_signed(&self, mut rhs: OldDuration) -> (NaiveTime, i64) { let mut secs = self.secs; let mut frac = self.frac; @@ -565,7 +599,7 @@ impl NaiveTime { /// ``` /// use chrono::{Duration, NaiveTime}; /// - /// let from_hms = NaiveTime::from_hms; + /// let from_hms = |h, m, s| { NaiveTime::from_hms_opt(h, m, s).unwrap() }; /// /// assert_eq!(from_hms(3, 4, 5).overflowing_sub_signed(Duration::hours(2)), /// (from_hms(1, 4, 5), 0)); @@ -575,6 +609,7 @@ impl NaiveTime { /// (from_hms(1, 4, 5), -86_400)); /// ``` #[inline] + #[must_use] pub fn overflowing_sub_signed(&self, rhs: OldDuration) -> (NaiveTime, i64) { let (time, rhs) = self.overflowing_add_signed(-rhs); (time, -rhs) // safe to negate, rhs is within +/- (2^63 / 1000) @@ -595,7 +630,7 @@ impl NaiveTime { /// ``` /// use chrono::{Duration, NaiveTime}; /// - /// let from_hmsm = NaiveTime::from_hms_milli; + /// let from_hmsm = |h, m, s, milli| { NaiveTime::from_hms_milli_opt(h, m, s, milli).unwrap() }; /// let since = NaiveTime::signed_duration_since; /// /// assert_eq!(since(from_hmsm(3, 5, 7, 900), from_hmsm(3, 5, 7, 900)), @@ -621,7 +656,7 @@ impl NaiveTime { /// /// ``` /// # use chrono::{Duration, NaiveTime}; - /// # let from_hmsm = NaiveTime::from_hms_milli; + /// # let from_hmsm = |h, m, s, milli| { NaiveTime::from_hms_milli_opt(h, m, s, milli).unwrap() }; /// # let since = NaiveTime::signed_duration_since; /// assert_eq!(since(from_hmsm(3, 0, 59, 1_000), from_hmsm(3, 0, 59, 0)), /// Duration::seconds(1)); @@ -634,6 +669,7 @@ impl NaiveTime { /// assert_eq!(since(from_hmsm(3, 0, 59, 1_000), from_hmsm(2, 59, 59, 1_000)), /// Duration::seconds(61)); /// ``` + #[must_use] pub fn signed_duration_since(self, rhs: NaiveTime) -> OldDuration { // | | :leap| | | | | | | :leap| | // | | : | | | | | | | : | | @@ -696,6 +732,7 @@ impl NaiveTime { #[cfg(any(feature = "alloc", feature = "std", test))] #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))] #[inline] + #[must_use] pub fn format_with_items<'a, I, B>(&self, items: I) -> DelayedFormat<I> where I: Iterator<Item = B> + Clone, @@ -741,14 +778,17 @@ impl NaiveTime { #[cfg(any(feature = "alloc", feature = "std", test))] #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))] #[inline] + #[must_use] pub fn format<'a>(&self, fmt: &'a str) -> DelayedFormat<StrftimeItems<'a>> { self.format_with_items(StrftimeItems::new(fmt)) } /// Returns a triple of the hour, minute and second numbers. fn hms(&self) -> (u32, u32, u32) { - let (mins, sec) = div_mod_floor(self.secs, 60); - let (hour, min) = div_mod_floor(mins, 60); + let sec = self.secs % 60; + let mins = self.secs / 60; + let min = mins % 60; + let hour = mins / 60; (hour, min, sec) } @@ -803,7 +843,8 @@ impl Timelike for NaiveTime { /// ([Why?](#leap-second-handling)) /// Use the proper [formatting method](#method.format) to get a human-readable representation. /// - /// ``` + #[cfg_attr(not(feature = "std"), doc = "```ignore")] + #[cfg_attr(feature = "std", doc = "```")] /// # use chrono::{NaiveTime, Timelike}; /// let leap = NaiveTime::from_hms_milli_opt(23, 59, 59, 1_000).unwrap(); /// assert_eq!(leap.second(), 59); @@ -831,7 +872,8 @@ impl Timelike for NaiveTime { /// You can reduce the range with `time.nanosecond() % 1_000_000_000`, or /// use the proper [formatting method](#method.format) to get a human-readable representation. /// - /// ``` + #[cfg_attr(not(feature = "std"), doc = "```ignore")] + #[cfg_attr(feature = "std", doc = "```")] /// # use chrono::{NaiveTime, Timelike}; /// let leap = NaiveTime::from_hms_milli_opt(23, 59, 59, 1_000).unwrap(); /// assert_eq!(leap.nanosecond(), 1_000_000_000); @@ -969,17 +1011,16 @@ impl Timelike for NaiveTime { /// An addition of `Duration` to `NaiveTime` wraps around and never overflows or underflows. /// In particular the addition ignores integral number of days. /// -/// As a part of Chrono's [leap second handling](#leap-second-handling), -/// the addition assumes that **there is no leap second ever**, -/// except when the `NaiveTime` itself represents a leap second -/// in which case the assumption becomes that **there is exactly a single leap second ever**. +/// As a part of Chrono's [leap second handling], the addition assumes that **there is no leap +/// second ever**, except when the `NaiveTime` itself represents a leap second in which case the +/// assumption becomes that **there is exactly a single leap second ever**. /// /// # Example /// /// ``` /// use chrono::{Duration, NaiveTime}; /// -/// let from_hmsm = NaiveTime::from_hms_milli; +/// let from_hmsm = |h, m, s, milli| { NaiveTime::from_hms_milli_opt(h, m, s, milli).unwrap() }; /// /// assert_eq!(from_hmsm(3, 5, 7, 0) + Duration::zero(), from_hmsm(3, 5, 7, 0)); /// assert_eq!(from_hmsm(3, 5, 7, 0) + Duration::seconds(1), from_hmsm(3, 5, 8, 0)); @@ -995,7 +1036,7 @@ impl Timelike for NaiveTime { /// /// ``` /// # use chrono::{Duration, NaiveTime}; -/// # let from_hmsm = NaiveTime::from_hms_milli; +/// # let from_hmsm = |h, m, s, milli| { NaiveTime::from_hms_milli_opt(h, m, s, milli).unwrap() }; /// assert_eq!(from_hmsm(3, 5, 7, 0) + Duration::seconds(22*60*60), from_hmsm(1, 5, 7, 0)); /// assert_eq!(from_hmsm(3, 5, 7, 0) + Duration::seconds(-8*60*60), from_hmsm(19, 5, 7, 0)); /// assert_eq!(from_hmsm(3, 5, 7, 0) + Duration::days(800), from_hmsm(3, 5, 7, 0)); @@ -1005,7 +1046,7 @@ impl Timelike for NaiveTime { /// /// ``` /// # use chrono::{Duration, NaiveTime}; -/// # let from_hmsm = NaiveTime::from_hms_milli; +/// # let from_hmsm = |h, m, s, milli| { NaiveTime::from_hms_milli_opt(h, m, s, milli).unwrap() }; /// let leap = from_hmsm(3, 5, 59, 1_300); /// assert_eq!(leap + Duration::zero(), from_hmsm(3, 5, 59, 1_300)); /// assert_eq!(leap + Duration::milliseconds(-500), from_hmsm(3, 5, 59, 800)); @@ -1015,6 +1056,8 @@ impl Timelike for NaiveTime { /// assert_eq!(leap + Duration::seconds(-10), from_hmsm(3, 5, 50, 300)); /// assert_eq!(leap + Duration::days(1), from_hmsm(3, 5, 59, 300)); /// ``` +/// +/// [leap second handling]: crate::NaiveTime#leap-second-handling impl Add<OldDuration> for NaiveTime { type Output = NaiveTime; @@ -1035,17 +1078,16 @@ impl AddAssign<OldDuration> for NaiveTime { /// In particular the addition ignores integral number of days. /// It is the same as the addition with a negated `Duration`. /// -/// As a part of Chrono's [leap second handling](#leap-second-handling), -/// the addition assumes that **there is no leap second ever**, -/// except when the `NaiveTime` itself represents a leap second -/// in which case the assumption becomes that **there is exactly a single leap second ever**. +/// As a part of Chrono's [leap second handling], the subtraction assumes that **there is no leap +/// second ever**, except when the `NaiveTime` itself represents a leap second in which case the +/// assumption becomes that **there is exactly a single leap second ever**. /// /// # Example /// /// ``` /// use chrono::{Duration, NaiveTime}; /// -/// let from_hmsm = NaiveTime::from_hms_milli; +/// let from_hmsm = |h, m, s, milli| { NaiveTime::from_hms_milli_opt(h, m, s, milli).unwrap() }; /// /// assert_eq!(from_hmsm(3, 5, 7, 0) - Duration::zero(), from_hmsm(3, 5, 7, 0)); /// assert_eq!(from_hmsm(3, 5, 7, 0) - Duration::seconds(1), from_hmsm(3, 5, 6, 0)); @@ -1059,7 +1101,7 @@ impl AddAssign<OldDuration> for NaiveTime { /// /// ``` /// # use chrono::{Duration, NaiveTime}; -/// # let from_hmsm = NaiveTime::from_hms_milli; +/// # let from_hmsm = |h, m, s, milli| { NaiveTime::from_hms_milli_opt(h, m, s, milli).unwrap() }; /// assert_eq!(from_hmsm(3, 5, 7, 0) - Duration::seconds(8*60*60), from_hmsm(19, 5, 7, 0)); /// assert_eq!(from_hmsm(3, 5, 7, 0) - Duration::days(800), from_hmsm(3, 5, 7, 0)); /// ``` @@ -1068,7 +1110,7 @@ impl AddAssign<OldDuration> for NaiveTime { /// /// ``` /// # use chrono::{Duration, NaiveTime}; -/// # let from_hmsm = NaiveTime::from_hms_milli; +/// # let from_hmsm = |h, m, s, milli| { NaiveTime::from_hms_milli_opt(h, m, s, milli).unwrap() }; /// let leap = from_hmsm(3, 5, 59, 1_300); /// assert_eq!(leap - Duration::zero(), from_hmsm(3, 5, 59, 1_300)); /// assert_eq!(leap - Duration::milliseconds(200), from_hmsm(3, 5, 59, 1_100)); @@ -1076,6 +1118,8 @@ impl AddAssign<OldDuration> for NaiveTime { /// assert_eq!(leap - Duration::seconds(60), from_hmsm(3, 5, 0, 300)); /// assert_eq!(leap - Duration::days(1), from_hmsm(3, 6, 0, 300)); /// ``` +/// +/// [leap second handling]: crate::NaiveTime#leap-second-handling impl Sub<OldDuration> for NaiveTime { type Output = NaiveTime; @@ -1110,7 +1154,7 @@ impl SubAssign<OldDuration> for NaiveTime { /// ``` /// use chrono::{Duration, NaiveTime}; /// -/// let from_hmsm = NaiveTime::from_hms_milli; +/// let from_hmsm = |h, m, s, milli| { NaiveTime::from_hms_milli_opt(h, m, s, milli).unwrap() }; /// /// assert_eq!(from_hmsm(3, 5, 7, 900) - from_hmsm(3, 5, 7, 900), Duration::zero()); /// assert_eq!(from_hmsm(3, 5, 7, 900) - from_hmsm(3, 5, 7, 875), Duration::milliseconds(25)); @@ -1128,7 +1172,7 @@ impl SubAssign<OldDuration> for NaiveTime { /// /// ``` /// # use chrono::{Duration, NaiveTime}; -/// # let from_hmsm = NaiveTime::from_hms_milli; +/// # let from_hmsm = |h, m, s, milli| { NaiveTime::from_hms_milli_opt(h, m, s, milli).unwrap() }; /// assert_eq!(from_hmsm(3, 0, 59, 1_000) - from_hmsm(3, 0, 59, 0), Duration::seconds(1)); /// assert_eq!(from_hmsm(3, 0, 59, 1_500) - from_hmsm(3, 0, 59, 0), /// Duration::milliseconds(1500)); diff --git a/vendor/chrono/src/offset/fixed.rs b/vendor/chrono/src/offset/fixed.rs index 0989dfa5b..246d6666e 100644 --- a/vendor/chrono/src/offset/fixed.rs +++ b/vendor/chrono/src/offset/fixed.rs @@ -6,7 +6,6 @@ use core::fmt; use core::ops::{Add, Sub}; -use num_integer::div_mod_floor; #[cfg(feature = "rkyv")] use rkyv::{Archive, Deserialize, Serialize}; @@ -34,6 +33,7 @@ impl FixedOffset { /// /// Panics on the out-of-bound `secs`. #[deprecated(since = "0.4.23", note = "use `east_opt()` instead")] + #[must_use] pub fn east(secs: i32) -> FixedOffset { FixedOffset::east_opt(secs).expect("FixedOffset::east out of bounds") } @@ -45,14 +45,18 @@ impl FixedOffset { /// /// # Example /// - /// ``` + #[cfg_attr(not(feature = "std"), doc = "```ignore")] + #[cfg_attr(feature = "std", doc = "```")] /// use chrono::{FixedOffset, TimeZone}; /// let hour = 3600; - /// let datetime = FixedOffset::east_opt(5 * hour).unwrap().ymd_opt(2016, 11, 08).unwrap() - /// .and_hms_opt(0, 0, 0).unwrap(); + /// let datetime = FixedOffset::east_opt(5 * hour) + /// .unwrap() + /// .with_ymd_and_hms(2016, 11, 08, 0, 0, 0) + /// .unwrap(); /// assert_eq!(&datetime.to_rfc3339(), "2016-11-08T00:00:00+05:00") /// ``` - pub fn east_opt(secs: i32) -> Option<FixedOffset> { + #[must_use] + pub const fn east_opt(secs: i32) -> Option<FixedOffset> { if -86_400 < secs && secs < 86_400 { Some(FixedOffset { local_minus_utc: secs }) } else { @@ -65,6 +69,7 @@ impl FixedOffset { /// /// Panics on the out-of-bound `secs`. #[deprecated(since = "0.4.23", note = "use `west_opt()` instead")] + #[must_use] pub fn west(secs: i32) -> FixedOffset { FixedOffset::west_opt(secs).expect("FixedOffset::west out of bounds") } @@ -76,14 +81,18 @@ impl FixedOffset { /// /// # Example /// - /// ``` + #[cfg_attr(not(feature = "std"), doc = "```ignore")] + #[cfg_attr(feature = "std", doc = "```")] /// use chrono::{FixedOffset, TimeZone}; /// let hour = 3600; - /// let datetime = FixedOffset::west_opt(5 * hour).unwrap().ymd_opt(2016, 11, 08).unwrap() - /// .and_hms_opt(0, 0, 0).unwrap(); + /// let datetime = FixedOffset::west_opt(5 * hour) + /// .unwrap() + /// .with_ymd_and_hms(2016, 11, 08, 0, 0, 0) + /// .unwrap(); /// assert_eq!(&datetime.to_rfc3339(), "2016-11-08T00:00:00-05:00") /// ``` - pub fn west_opt(secs: i32) -> Option<FixedOffset> { + #[must_use] + pub const fn west_opt(secs: i32) -> Option<FixedOffset> { if -86_400 < secs && secs < 86_400 { Some(FixedOffset { local_minus_utc: -secs }) } else { @@ -136,8 +145,10 @@ impl fmt::Debug for FixedOffset { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let offset = self.local_minus_utc; let (sign, offset) = if offset < 0 { ('-', -offset) } else { ('+', offset) }; - let (mins, sec) = div_mod_floor(offset, 60); - let (hour, min) = div_mod_floor(mins, 60); + let sec = offset.rem_euclid(60); + let mins = offset.div_euclid(60); + let min = mins.rem_euclid(60); + let hour = mins.div_euclid(60); if sec == 0 { write!(f, "{}{:02}:{:02}", sign, hour, min) } else { diff --git a/vendor/chrono/src/offset/local/mod.rs b/vendor/chrono/src/offset/local/mod.rs index e280c7800..372fd4976 100644 --- a/vendor/chrono/src/offset/local/mod.rs +++ b/vendor/chrono/src/offset/local/mod.rs @@ -8,12 +8,19 @@ use rkyv::{Archive, Deserialize, Serialize}; use super::fixed::FixedOffset; use super::{LocalResult, TimeZone}; -use crate::naive::{NaiveDate, NaiveDateTime}; +use crate::naive::{NaiveDate, NaiveDateTime, NaiveTime}; #[allow(deprecated)] -use crate::{Date, DateTime}; +use crate::Date; +use crate::{DateTime, Utc}; + +#[cfg(unix)] +#[path = "unix.rs"] +mod inner; + +#[cfg(windows)] +#[path = "windows.rs"] +mod inner; -// we don't want `stub.rs` when the target_os is not wasi or emscripten -// as we use js-sys to get the date instead #[cfg(all( not(unix), not(windows), @@ -23,16 +30,37 @@ use crate::{Date, DateTime}; not(any(target_os = "emscripten", target_os = "wasi")) )) ))] -#[path = "stub.rs"] -mod inner; +mod inner { + use crate::{FixedOffset, LocalResult, NaiveDateTime}; -#[cfg(unix)] -#[path = "unix.rs"] -mod inner; + pub(super) fn offset_from_utc_datetime(_utc_time: &NaiveDateTime) -> LocalResult<FixedOffset> { + LocalResult::Single(FixedOffset::east_opt(0).unwrap()) + } -#[cfg(windows)] -#[path = "windows.rs"] -mod inner; + pub(super) fn offset_from_local_datetime( + _local_time: &NaiveDateTime, + ) -> LocalResult<FixedOffset> { + LocalResult::Single(FixedOffset::east_opt(0).unwrap()) + } +} + +#[cfg(all( + target_arch = "wasm32", + feature = "wasmbind", + not(any(target_os = "emscripten", target_os = "wasi")) +))] +mod inner { + use crate::{FixedOffset, LocalResult, NaiveDateTime}; + + pub(super) fn offset_from_utc_datetime(_utc: &NaiveDateTime) -> LocalResult<FixedOffset> { + let offset = js_sys::Date::new_0().get_timezone_offset(); + LocalResult::Single(FixedOffset::west_opt((offset as i32) * 60).unwrap()) + } + + pub(super) fn offset_from_local_datetime(local: &NaiveDateTime) -> LocalResult<FixedOffset> { + offset_from_utc_datetime(local) + } +} #[cfg(unix)] mod tz_info; @@ -48,8 +76,9 @@ mod tz_info; /// ``` /// use chrono::{Local, DateTime, TimeZone}; /// -/// let dt: DateTime<Local> = Local::now(); -/// let dt: DateTime<Local> = Local.timestamp(0, 0); +/// let dt1: DateTime<Local> = Local::now(); +/// let dt2: DateTime<Local> = Local.timestamp_opt(0, 0).unwrap(); +/// assert!(dt1 >= dt2); /// ``` #[derive(Copy, Clone, Debug)] #[cfg_attr(feature = "rkyv", derive(Archive, Deserialize, Serialize))] @@ -60,6 +89,7 @@ impl Local { /// Returns a `Date` which corresponds to the current date. #[deprecated(since = "0.4.23", note = "use `Local::now()` instead")] #[allow(deprecated)] + #[must_use] pub fn today() -> Date<Local> { Local::now().date() } @@ -70,8 +100,9 @@ impl Local { feature = "wasmbind", not(any(target_os = "emscripten", target_os = "wasi")) )))] + #[must_use] pub fn now() -> DateTime<Local> { - inner::now() + Utc::now().with_timezone(&Local) } /// Returns a `DateTime` which corresponds to the current date and time. @@ -80,6 +111,7 @@ impl Local { feature = "wasmbind", not(any(target_os = "emscripten", target_os = "wasi")) ))] + #[must_use] pub fn now() -> DateTime<Local> { use super::Utc; let now: DateTime<Utc> = super::Utc::now(); @@ -99,87 +131,24 @@ impl TimeZone for Local { Local } - // they are easier to define in terms of the finished date and time unlike other offsets #[allow(deprecated)] fn offset_from_local_date(&self, local: &NaiveDate) -> LocalResult<FixedOffset> { - self.from_local_date(local).map(|date| *date.offset()) + // Get the offset at local midnight. + self.offset_from_local_datetime(&local.and_time(NaiveTime::MIN)) } fn offset_from_local_datetime(&self, local: &NaiveDateTime) -> LocalResult<FixedOffset> { - self.from_local_datetime(local).map(|datetime| *datetime.offset()) + inner::offset_from_local_datetime(local) } #[allow(deprecated)] fn offset_from_utc_date(&self, utc: &NaiveDate) -> FixedOffset { - *self.from_utc_date(utc).offset() + // Get the offset at midnight. + self.offset_from_utc_datetime(&utc.and_time(NaiveTime::MIN)) } fn offset_from_utc_datetime(&self, utc: &NaiveDateTime) -> FixedOffset { - *self.from_utc_datetime(utc).offset() - } - - // override them for avoiding redundant works - #[allow(deprecated)] - fn from_local_date(&self, local: &NaiveDate) -> LocalResult<Date<Local>> { - // this sounds very strange, but required for keeping `TimeZone::ymd` sane. - // in the other words, we use the offset at the local midnight - // but keep the actual date unaltered (much like `FixedOffset`). - let midnight = self.from_local_datetime(&local.and_hms_opt(0, 0, 0).unwrap()); - midnight.map(|datetime| Date::from_utc(*local, *datetime.offset())) - } - - #[cfg(all( - target_arch = "wasm32", - feature = "wasmbind", - not(any(target_os = "emscripten", target_os = "wasi")) - ))] - fn from_local_datetime(&self, local: &NaiveDateTime) -> LocalResult<DateTime<Local>> { - let mut local = local.clone(); - // Get the offset from the js runtime - let offset = - FixedOffset::west_opt((js_sys::Date::new_0().get_timezone_offset() as i32) * 60) - .unwrap(); - local -= crate::Duration::seconds(offset.local_minus_utc() as i64); - LocalResult::Single(DateTime::from_utc(local, offset)) - } - - #[cfg(not(all( - target_arch = "wasm32", - feature = "wasmbind", - not(any(target_os = "emscripten", target_os = "wasi")) - )))] - fn from_local_datetime(&self, local: &NaiveDateTime) -> LocalResult<DateTime<Local>> { - inner::naive_to_local(local, true) - } - - #[allow(deprecated)] - fn from_utc_date(&self, utc: &NaiveDate) -> Date<Local> { - let midnight = self.from_utc_datetime(&utc.and_hms_opt(0, 0, 0).unwrap()); - Date::from_utc(*utc, *midnight.offset()) - } - - #[cfg(all( - target_arch = "wasm32", - feature = "wasmbind", - not(any(target_os = "emscripten", target_os = "wasi")) - ))] - fn from_utc_datetime(&self, utc: &NaiveDateTime) -> DateTime<Local> { - // Get the offset from the js runtime - let offset = - FixedOffset::west_opt((js_sys::Date::new_0().get_timezone_offset() as i32) * 60) - .unwrap(); - DateTime::from_utc(*utc, offset) - } - - #[cfg(not(all( - target_arch = "wasm32", - feature = "wasmbind", - not(any(target_os = "emscripten", target_os = "wasi")) - )))] - fn from_utc_datetime(&self, utc: &NaiveDateTime) -> DateTime<Local> { - // this is OK to unwrap as getting local time from a UTC - // timestamp is never ambiguous - inner::naive_to_local(utc, false).unwrap() + inner::offset_from_utc_datetime(utc).unwrap() } } @@ -243,18 +212,32 @@ mod tests { // issue #123 let today = Utc::now().date_naive(); - let dt = today.and_hms_milli_opt(1, 2, 59, 1000).unwrap(); - let timestr = dt.time().to_string(); - // the OS API may or may not support the leap second, - // but there are only two sensible options. - assert!(timestr == "01:02:60" || timestr == "01:03:00", "unexpected timestr {:?}", timestr); - - let dt = today.and_hms_milli_opt(1, 2, 3, 1234).unwrap(); - let timestr = dt.time().to_string(); - assert!( - timestr == "01:02:03.234" || timestr == "01:02:04.234", - "unexpected timestr {:?}", - timestr - ); + if let Some(dt) = today.and_hms_milli_opt(15, 2, 59, 1000) { + let timestr = dt.time().to_string(); + // the OS API may or may not support the leap second, + // but there are only two sensible options. + assert!( + timestr == "15:02:60" || timestr == "15:03:00", + "unexpected timestr {:?}", + timestr + ); + } + + if let Some(dt) = today.and_hms_milli_opt(15, 2, 3, 1234) { + let timestr = dt.time().to_string(); + assert!( + timestr == "15:02:03.234" || timestr == "15:02:04.234", + "unexpected timestr {:?}", + timestr + ); + } + } + + /// Test Issue #866 + #[test] + fn test_issue_866() { + #[allow(deprecated)] + let local_20221106 = Local.ymd(2022, 11, 6); + let _dt_20221106 = local_20221106.and_hms_milli_opt(1, 2, 59, 1000).unwrap(); } } diff --git a/vendor/chrono/src/offset/local/stub.rs b/vendor/chrono/src/offset/local/stub.rs deleted file mode 100644 index 9ececd3c2..000000000 --- a/vendor/chrono/src/offset/local/stub.rs +++ /dev/null @@ -1,236 +0,0 @@ -// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use std::time::{SystemTime, UNIX_EPOCH}; - -use super::{FixedOffset, Local}; -use crate::{DateTime, Datelike, LocalResult, NaiveDate, NaiveDateTime, NaiveTime, Timelike}; - -pub(super) fn now() -> DateTime<Local> { - tm_to_datetime(Timespec::now().local()) -} - -/// Converts a local `NaiveDateTime` to the `time::Timespec`. -#[cfg(not(all( - target_arch = "wasm32", - feature = "wasmbind", - not(any(target_os = "emscripten", target_os = "wasi")) -)))] -pub(super) fn naive_to_local(d: &NaiveDateTime, local: bool) -> LocalResult<DateTime<Local>> { - let tm = Tm { - tm_sec: d.second() as i32, - tm_min: d.minute() as i32, - tm_hour: d.hour() as i32, - tm_mday: d.day() as i32, - tm_mon: d.month0() as i32, // yes, C is that strange... - tm_year: d.year() - 1900, // this doesn't underflow, we know that d is `NaiveDateTime`. - tm_wday: 0, // to_local ignores this - tm_yday: 0, // and this - tm_isdst: -1, - // This seems pretty fake? - tm_utcoff: if local { 1 } else { 0 }, - // do not set this, OS APIs are heavily inconsistent in terms of leap second handling - tm_nsec: 0, - }; - - let spec = Timespec { - sec: match local { - false => utc_tm_to_time(&tm), - true => local_tm_to_time(&tm), - }, - nsec: tm.tm_nsec, - }; - - // Adjust for leap seconds - let mut tm = spec.local(); - assert_eq!(tm.tm_nsec, 0); - tm.tm_nsec = d.nanosecond() as i32; - - LocalResult::Single(tm_to_datetime(tm)) -} - -/// Converts a `time::Tm` struct into the timezone-aware `DateTime`. -/// This assumes that `time` is working correctly, i.e. any error is fatal. -#[cfg(not(all( - target_arch = "wasm32", - feature = "wasmbind", - not(any(target_os = "emscripten", target_os = "wasi")) -)))] -fn tm_to_datetime(mut tm: Tm) -> DateTime<Local> { - if tm.tm_sec >= 60 { - tm.tm_nsec += (tm.tm_sec - 59) * 1_000_000_000; - tm.tm_sec = 59; - } - - let date = NaiveDate::from_yo(tm.tm_year + 1900, tm.tm_yday as u32 + 1); - let time = NaiveTime::from_hms_nano( - tm.tm_hour as u32, - tm.tm_min as u32, - tm.tm_sec as u32, - tm.tm_nsec as u32, - ); - - let offset = FixedOffset::east_opt(tm.tm_utcoff).unwrap(); - DateTime::from_utc(date.and_time(time) - offset, offset) -} - -/// A record specifying a time value in seconds and nanoseconds, where -/// nanoseconds represent the offset from the given second. -/// -/// For example a timespec of 1.2 seconds after the beginning of the epoch would -/// be represented as {sec: 1, nsec: 200000000}. -struct Timespec { - sec: i64, - nsec: i32, -} - -impl Timespec { - /// Constructs a timespec representing the current time in UTC. - fn now() -> Timespec { - let st = - SystemTime::now().duration_since(UNIX_EPOCH).expect("system time before Unix epoch"); - Timespec { sec: st.as_secs() as i64, nsec: st.subsec_nanos() as i32 } - } - - /// Converts this timespec into the system's local time. - fn local(self) -> Tm { - let mut tm = Tm { - tm_sec: 0, - tm_min: 0, - tm_hour: 0, - tm_mday: 0, - tm_mon: 0, - tm_year: 0, - tm_wday: 0, - tm_yday: 0, - tm_isdst: 0, - tm_utcoff: 0, - tm_nsec: 0, - }; - time_to_local_tm(self.sec, &mut tm); - tm.tm_nsec = self.nsec; - tm - } -} - -/// Holds a calendar date and time broken down into its components (year, month, -/// day, and so on), also called a broken-down time value. -// FIXME: use c_int instead of i32? -#[repr(C)] -pub(super) struct Tm { - /// Seconds after the minute - [0, 60] - tm_sec: i32, - - /// Minutes after the hour - [0, 59] - tm_min: i32, - - /// Hours after midnight - [0, 23] - tm_hour: i32, - - /// Day of the month - [1, 31] - tm_mday: i32, - - /// Months since January - [0, 11] - tm_mon: i32, - - /// Years since 1900 - tm_year: i32, - - /// Days since Sunday - [0, 6]. 0 = Sunday, 1 = Monday, ..., 6 = Saturday. - tm_wday: i32, - - /// Days since January 1 - [0, 365] - tm_yday: i32, - - /// Daylight Saving Time flag. - /// - /// This value is positive if Daylight Saving Time is in effect, zero if - /// Daylight Saving Time is not in effect, and negative if this information - /// is not available. - tm_isdst: i32, - - /// Identifies the time zone that was used to compute this broken-down time - /// value, including any adjustment for Daylight Saving Time. This is the - /// number of seconds east of UTC. For example, for U.S. Pacific Daylight - /// Time, the value is `-7*60*60 = -25200`. - tm_utcoff: i32, - - /// Nanoseconds after the second - [0, 10<sup>9</sup> - 1] - tm_nsec: i32, -} - -fn time_to_tm(ts: i64, tm: &mut Tm) { - let leapyear = |year| -> bool { year % 4 == 0 && (year % 100 != 0 || year % 400 == 0) }; - - static YTAB: [[i64; 12]; 2] = [ - [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31], - [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31], - ]; - - let mut year = 1970; - - let dayclock = ts % 86400; - let mut dayno = ts / 86400; - - tm.tm_sec = (dayclock % 60) as i32; - tm.tm_min = ((dayclock % 3600) / 60) as i32; - tm.tm_hour = (dayclock / 3600) as i32; - tm.tm_wday = ((dayno + 4) % 7) as i32; - loop { - let yearsize = if leapyear(year) { 366 } else { 365 }; - if dayno >= yearsize { - dayno -= yearsize; - year += 1; - } else { - break; - } - } - tm.tm_year = (year - 1900) as i32; - tm.tm_yday = dayno as i32; - let mut mon = 0; - while dayno >= YTAB[if leapyear(year) { 1 } else { 0 }][mon] { - dayno -= YTAB[if leapyear(year) { 1 } else { 0 }][mon]; - mon += 1; - } - tm.tm_mon = mon as i32; - tm.tm_mday = dayno as i32 + 1; - tm.tm_isdst = 0; -} - -fn tm_to_time(tm: &Tm) -> i64 { - let mut y = tm.tm_year as i64 + 1900; - let mut m = tm.tm_mon as i64 + 1; - if m <= 2 { - y -= 1; - m += 12; - } - let d = tm.tm_mday as i64; - let h = tm.tm_hour as i64; - let mi = tm.tm_min as i64; - let s = tm.tm_sec as i64; - (365 * y + y / 4 - y / 100 + y / 400 + 3 * (m + 1) / 5 + 30 * m + d - 719561) * 86400 - + 3600 * h - + 60 * mi - + s -} - -pub(super) fn time_to_local_tm(sec: i64, tm: &mut Tm) { - // FIXME: Add timezone logic - time_to_tm(sec, tm); -} - -pub(super) fn utc_tm_to_time(tm: &Tm) -> i64 { - tm_to_time(tm) -} - -pub(super) fn local_tm_to_time(tm: &Tm) -> i64 { - // FIXME: Add timezone logic - tm_to_time(tm) -} diff --git a/vendor/chrono/src/offset/local/tz_info/mod.rs b/vendor/chrono/src/offset/local/tz_info/mod.rs index bd2693b6b..780e15ace 100644 --- a/vendor/chrono/src/offset/local/tz_info/mod.rs +++ b/vendor/chrono/src/offset/local/tz_info/mod.rs @@ -100,21 +100,6 @@ impl From<Utf8Error> for Error { } } -// MSRV: 1.38 -#[inline] -fn rem_euclid(v: i64, rhs: i64) -> i64 { - let r = v % rhs; - if r < 0 { - if rhs < 0 { - r - rhs - } else { - r + rhs - } - } else { - r - } -} - /// Number of hours in one day const HOURS_PER_DAY: i64 = 24; /// Number of seconds in one hour diff --git a/vendor/chrono/src/offset/local/tz_info/parser.rs b/vendor/chrono/src/offset/local/tz_info/parser.rs index 5652a0ea9..47cc0377e 100644 --- a/vendor/chrono/src/offset/local/tz_info/parser.rs +++ b/vendor/chrono/src/offset/local/tz_info/parser.rs @@ -7,7 +7,6 @@ use super::rule::TransitionRule; use super::timezone::{LeapSecond, LocalTimeType, TimeZone, Transition}; use super::Error; -#[allow(clippy::map_clone)] // MSRV: 1.36 pub(super) fn parse(bytes: &[u8]) -> Result<TimeZone, Error> { let mut cursor = Cursor::new(bytes); let state = State::new(&mut cursor, true)?; @@ -66,8 +65,8 @@ pub(super) fn parse(bytes: &[u8]) -> Result<TimeZone, Error> { leap_seconds.push(LeapSecond::new(unix_leap_time, correction)); } - let std_walls_iter = state.std_walls.iter().map(|&i| i).chain(iter::repeat(0)); - let ut_locals_iter = state.ut_locals.iter().map(|&i| i).chain(iter::repeat(0)); + let std_walls_iter = state.std_walls.iter().copied().chain(iter::repeat(0)); + let ut_locals_iter = state.ut_locals.iter().copied().chain(iter::repeat(0)); if std_walls_iter.zip(ut_locals_iter).take(state.header.type_count).any(|pair| pair == (0, 1)) { return Err(Error::InvalidTzFile( "invalid couple of standard/wall and UT/local indicators", @@ -238,7 +237,7 @@ impl<'a> Cursor<'a> { } /// Returns `true` if data is remaining - pub(crate) fn is_empty(&self) -> bool { + pub(crate) const fn is_empty(&self) -> bool { self.remaining.is_empty() } diff --git a/vendor/chrono/src/offset/local/tz_info/rule.rs b/vendor/chrono/src/offset/local/tz_info/rule.rs index 7befddb5c..369e317a4 100644 --- a/vendor/chrono/src/offset/local/tz_info/rule.rs +++ b/vendor/chrono/src/offset/local/tz_info/rule.rs @@ -3,7 +3,7 @@ use std::cmp::Ordering; use super::parser::Cursor; use super::timezone::{LocalTimeType, SECONDS_PER_WEEK}; use super::{ - rem_euclid, Error, CUMUL_DAY_IN_MONTHS_NORMAL_YEAR, DAYS_PER_WEEK, DAY_IN_MONTHS_NORMAL_YEAR, + Error, CUMUL_DAY_IN_MONTHS_NORMAL_YEAR, DAYS_PER_WEEK, DAY_IN_MONTHS_NORMAL_YEAR, SECONDS_PER_DAY, }; @@ -127,7 +127,7 @@ pub(super) struct AlternateTime { impl AlternateTime { /// Construct a transition rule representing alternate local time types - fn new( + const fn new( std: LocalTimeType, dst: LocalTimeType, dst_start: RuleDay, @@ -504,7 +504,7 @@ impl RuleDay { } /// Construct a transition rule day represented by a zero-based Julian day in `[0, 365]`, taking occasional Feb 29 into account - fn julian_0(julian_day_0: u16) -> Result<Self, Error> { + const fn julian_0(julian_day_0: u16) -> Result<Self, Error> { if julian_day_0 > 365 { return Err(Error::TransitionRule("invalid rule day julian day")); } @@ -589,9 +589,9 @@ impl RuleDay { } let week_day_of_first_month_day = - rem_euclid(4 + days_since_unix_epoch(year, month, 1), DAYS_PER_WEEK); + (4 + days_since_unix_epoch(year, month, 1)).rem_euclid(DAYS_PER_WEEK); let first_week_day_occurence_in_month = - 1 + rem_euclid(week_day as i64 - week_day_of_first_month_day, DAYS_PER_WEEK); + 1 + (week_day as i64 - week_day_of_first_month_day).rem_euclid(DAYS_PER_WEEK); let mut month_day = first_week_day_occurence_in_month + (week as i64 - 1) * DAYS_PER_WEEK; @@ -737,7 +737,7 @@ const DAY_IN_MONTHS_LEAP_YEAR_FROM_MARCH: [i64; 12] = /// * `year`: Year /// * `month`: Month in `[1, 12]` /// * `month_day`: Day of the month in `[1, 31]` -pub(crate) fn days_since_unix_epoch(year: i32, month: usize, month_day: i64) -> i64 { +pub(crate) const fn days_since_unix_epoch(year: i32, month: usize, month_day: i64) -> i64 { let is_leap_year = is_leap_year(year); let year = year as i64; @@ -768,7 +768,7 @@ pub(crate) fn days_since_unix_epoch(year: i32, month: usize, month_day: i64) -> } /// Check if a year is a leap year -pub(crate) fn is_leap_year(year: i32) -> bool { +pub(crate) const fn is_leap_year(year: i32) -> bool { year % 400 == 0 || (year % 4 == 0 && year % 100 != 0) } @@ -777,7 +777,6 @@ mod tests { use super::super::timezone::Transition; use super::super::{Error, TimeZone}; use super::{AlternateTime, LocalTimeType, RuleDay, TransitionRule}; - use crate::matches; #[test] fn test_quoted() -> Result<(), Error> { diff --git a/vendor/chrono/src/offset/local/tz_info/timezone.rs b/vendor/chrono/src/offset/local/tz_info/timezone.rs index 8572825a8..33c89060c 100644 --- a/vendor/chrono/src/offset/local/tz_info/timezone.rs +++ b/vendor/chrono/src/offset/local/tz_info/timezone.rs @@ -43,6 +43,14 @@ impl TimeZone { return Self::from_tz_data(&fs::read("/etc/localtime")?); } + // attributes are not allowed on if blocks in Rust 1.38 + #[cfg(target_os = "android")] + { + if let Ok(bytes) = android_tzdata::find_tz_data(tz_string) { + return Self::from_tz_data(&bytes); + } + } + let mut chars = tz_string.chars(); if chars.next() == Some(':') { return Self::from_file(&mut find_tz_file(chars.as_str())?); @@ -374,7 +382,7 @@ impl<'a> TimeZoneRef<'a> { } /// Convert Unix time to Unix leap time, from the list of leap seconds in a time zone - fn unix_time_to_unix_leap_time(&self, unix_time: i64) -> Result<i64, Error> { + const fn unix_time_to_unix_leap_time(&self, unix_time: i64) -> Result<i64, Error> { let mut unix_leap_time = unix_time; let mut i = 0; @@ -563,7 +571,7 @@ impl LocalTimeType { } /// Construct a local time type with the specified UTC offset in seconds - pub(super) fn with_offset(ut_offset: i32) -> Result<Self, Error> { + pub(super) const fn with_offset(ut_offset: i32) -> Result<Self, Error> { if ut_offset == i32::min_value() { return Err(Error::LocalTimeType("invalid UTC offset")); } @@ -608,7 +616,7 @@ fn find_tz_file(path: impl AsRef<Path>) -> Result<File, Error> { } #[inline] -fn saturating_abs(v: i32) -> i32 { +const fn saturating_abs(v: i32) -> i32 { if v.is_positive() { v } else if v == i32::min_value() { @@ -620,8 +628,8 @@ fn saturating_abs(v: i32) -> i32 { // Possible system timezone directories #[cfg(unix)] -const ZONE_INFO_DIRECTORIES: [&str; 3] = - ["/usr/share/zoneinfo", "/share/zoneinfo", "/etc/zoneinfo"]; +const ZONE_INFO_DIRECTORIES: [&str; 4] = + ["/usr/share/zoneinfo", "/share/zoneinfo", "/etc/zoneinfo", "/usr/share/lib/zoneinfo"]; /// Number of seconds in one week pub(crate) const SECONDS_PER_WEEK: i64 = SECONDS_PER_DAY * DAYS_PER_WEEK; @@ -632,7 +640,6 @@ const SECONDS_PER_28_DAYS: i64 = SECONDS_PER_DAY * 28; mod tests { use super::super::Error; use super::{LeapSecond, LocalTimeType, TimeZone, TimeZoneName, Transition, TransitionRule}; - use crate::matches; #[test] fn test_no_dst() -> Result<(), Error> { diff --git a/vendor/chrono/src/offset/local/unix.rs b/vendor/chrono/src/offset/local/unix.rs index 32aa31618..ce96a6e3b 100644 --- a/vendor/chrono/src/offset/local/unix.rs +++ b/vendor/chrono/src/offset/local/unix.rs @@ -11,15 +11,18 @@ use std::{cell::RefCell, collections::hash_map, env, fs, hash::Hasher, time::SystemTime}; use super::tz_info::TimeZone; -use super::{DateTime, FixedOffset, Local, NaiveDateTime}; -use crate::{Datelike, LocalResult, Utc}; +use super::{FixedOffset, NaiveDateTime}; +use crate::{Datelike, LocalResult}; -pub(super) fn now() -> DateTime<Local> { - let now = Utc::now().naive_utc(); - naive_to_local(&now, false).unwrap() +pub(super) fn offset_from_utc_datetime(utc: &NaiveDateTime) -> LocalResult<FixedOffset> { + offset(utc, false) } -pub(super) fn naive_to_local(d: &NaiveDateTime, local: bool) -> LocalResult<DateTime<Local>> { +pub(super) fn offset_from_local_datetime(local: &NaiveDateTime) -> LocalResult<FixedOffset> { + offset(local, true) +} + +fn offset(d: &NaiveDateTime, local: bool) -> LocalResult<FixedOffset> { TZ_INFO.with(|maybe_cache| { maybe_cache.borrow_mut().get_or_insert_with(Cache::default).offset(*d, local) }) @@ -68,19 +71,18 @@ struct Cache { last_checked: SystemTime, } -#[cfg(target_os = "android")] -const TZDB_LOCATION: &str = " /system/usr/share/zoneinfo"; - #[cfg(target_os = "aix")] const TZDB_LOCATION: &str = "/usr/share/lib/zoneinfo"; -#[allow(dead_code)] // keeps the cfg simpler #[cfg(not(any(target_os = "android", target_os = "aix")))] const TZDB_LOCATION: &str = "/usr/share/zoneinfo"; fn fallback_timezone() -> Option<TimeZone> { let tz_name = iana_time_zone::get_timezone().ok()?; + #[cfg(not(target_os = "android"))] let bytes = fs::read(format!("{}/{}", TZDB_LOCATION, tz_name)).ok()?; + #[cfg(target_os = "android")] + let bytes = android_tzdata::find_tz_data(&tz_name).ok()?; TimeZone::from_tz_data(&bytes).ok() } @@ -88,7 +90,7 @@ impl Default for Cache { fn default() -> Cache { // default to UTC if no local timezone can be found let env_tz = env::var("TZ").ok(); - let env_ref = env_tz.as_ref().map(|s| s.as_str()); + let env_ref = env_tz.as_deref(); Cache { last_checked: SystemTime::now(), source: Source::new(env_ref), @@ -102,7 +104,7 @@ fn current_zone(var: Option<&str>) -> TimeZone { } impl Cache { - fn offset(&mut self, d: NaiveDateTime, local: bool) -> LocalResult<DateTime<Local>> { + fn offset(&mut self, d: NaiveDateTime, local: bool) -> LocalResult<FixedOffset> { let now = SystemTime::now(); match now.duration_since(self.last_checked) { @@ -114,7 +116,7 @@ impl Cache { Ok(d) if d.as_secs() < 1 => (), Ok(_) | Err(_) => { let env_tz = env::var("TZ").ok(); - let env_ref = env_tz.as_ref().map(|s| s.as_str()); + let env_ref = env_tz.as_deref(); let new_source = Source::new(env_ref); let out_of_date = match (&self.source, &new_source) { @@ -154,32 +156,16 @@ impl Cache { .offset(); return match FixedOffset::east_opt(offset) { - Some(offset) => LocalResult::Single(DateTime::from_utc(d, offset)), + Some(offset) => LocalResult::Single(offset), None => LocalResult::None, }; } // we pass through the year as the year of a local point in time must either be valid in that locale, or - // the entire time was skipped in which case we will return LocalResult::None anywa. - match self - .zone + // the entire time was skipped in which case we will return LocalResult::None anyway. + self.zone .find_local_time_type_from_local(d.timestamp(), d.year()) .expect("unable to select local time type") - { - LocalResult::None => LocalResult::None, - LocalResult::Ambiguous(early, late) => { - let early_offset = FixedOffset::east_opt(early.offset()).unwrap(); - let late_offset = FixedOffset::east_opt(late.offset()).unwrap(); - - LocalResult::Ambiguous( - DateTime::from_utc(d - early_offset, early_offset), - DateTime::from_utc(d - late_offset, late_offset), - ) - } - LocalResult::Single(tt) => { - let offset = FixedOffset::east_opt(tt.offset()).unwrap(); - LocalResult::Single(DateTime::from_utc(d - offset, offset)) - } - } + .map(|o| FixedOffset::east_opt(o.offset()).unwrap()) } } diff --git a/vendor/chrono/src/offset/local/windows.rs b/vendor/chrono/src/offset/local/windows.rs index e6415015c..84585170c 100644 --- a/vendor/chrono/src/offset/local/windows.rs +++ b/vendor/chrono/src/offset/local/windows.rs @@ -8,271 +8,133 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::io; -use std::mem; -use std::time::{SystemTime, UNIX_EPOCH}; +use core::mem::MaybeUninit; +use std::io::Error; +use std::ptr; +use std::result::Result; -use winapi::shared::minwindef::*; +use winapi::shared::minwindef::FILETIME; use winapi::um::minwinbase::SYSTEMTIME; -use winapi::um::timezoneapi::*; +use winapi::um::timezoneapi::{ + SystemTimeToFileTime, SystemTimeToTzSpecificLocalTime, TzSpecificLocalTimeToSystemTime, +}; -use super::{FixedOffset, Local}; -use crate::{DateTime, Datelike, LocalResult, NaiveDate, NaiveDateTime, NaiveTime, Timelike}; +use super::FixedOffset; +use crate::{Datelike, LocalResult, NaiveDateTime, Timelike}; -pub(super) fn now() -> DateTime<Local> { - tm_to_datetime(Timespec::now().local()) -} - -/// Converts a local `NaiveDateTime` to the `time::Timespec`. -pub(super) fn naive_to_local(d: &NaiveDateTime, local: bool) -> LocalResult<DateTime<Local>> { - let tm = Tm { - tm_sec: d.second() as i32, - tm_min: d.minute() as i32, - tm_hour: d.hour() as i32, - tm_mday: d.day() as i32, - tm_mon: d.month0() as i32, // yes, C is that strange... - tm_year: d.year() - 1900, // this doesn't underflow, we know that d is `NaiveDateTime`. - tm_wday: 0, // to_local ignores this - tm_yday: 0, // and this - tm_isdst: -1, - // This seems pretty fake? - tm_utcoff: if local { 1 } else { 0 }, - // do not set this, OS APIs are heavily inconsistent in terms of leap second handling - tm_nsec: 0, - }; - - let spec = Timespec { - sec: match local { - false => utc_tm_to_time(&tm), - true => local_tm_to_time(&tm), - }, - nsec: tm.tm_nsec, - }; - - // Adjust for leap seconds - let mut tm = spec.local(); - assert_eq!(tm.tm_nsec, 0); - tm.tm_nsec = d.nanosecond() as i32; - - // #TODO - there should be ambiguous cases, investigate? - LocalResult::Single(tm_to_datetime(tm)) -} - -/// Converts a `time::Tm` struct into the timezone-aware `DateTime`. -fn tm_to_datetime(mut tm: Tm) -> DateTime<Local> { - if tm.tm_sec >= 60 { - tm.tm_nsec += (tm.tm_sec - 59) * 1_000_000_000; - tm.tm_sec = 59; - } - - let date = NaiveDate::from_ymd_opt(tm.tm_year + 1900, tm.tm_mon as u32 + 1, tm.tm_mday as u32) - .unwrap(); - let time = NaiveTime::from_hms_nano( - tm.tm_hour as u32, - tm.tm_min as u32, - tm.tm_sec as u32, - tm.tm_nsec as u32, - ); - - let offset = FixedOffset::east_opt(tm.tm_utcoff).unwrap(); - DateTime::from_utc(date.and_time(time) - offset, offset) -} - -/// A record specifying a time value in seconds and nanoseconds, where -/// nanoseconds represent the offset from the given second. +/// This macro calls a Windows API FFI and checks whether the function errored with the provided error_id. If an error returns, +/// the macro will return an `Error::last_os_error()`. /// -/// For example a timespec of 1.2 seconds after the beginning of the epoch would -/// be represented as {sec: 1, nsec: 200000000}. -struct Timespec { - sec: i64, - nsec: i32, -} - -impl Timespec { - /// Constructs a timespec representing the current time in UTC. - fn now() -> Timespec { - let st = - SystemTime::now().duration_since(UNIX_EPOCH).expect("system time before Unix epoch"); - Timespec { sec: st.as_secs() as i64, nsec: st.subsec_nanos() as i32 } - } - - /// Converts this timespec into the system's local time. - fn local(self) -> Tm { - let mut tm = Tm { - tm_sec: 0, - tm_min: 0, - tm_hour: 0, - tm_mday: 0, - tm_mon: 0, - tm_year: 0, - tm_wday: 0, - tm_yday: 0, - tm_isdst: 0, - tm_utcoff: 0, - tm_nsec: 0, - }; - time_to_local_tm(self.sec, &mut tm); - tm.tm_nsec = self.nsec; - tm +/// # Safety +/// +/// The provided error ID must align with the provided Windows API, providing the wrong ID could lead to UB. +macro_rules! windows_sys_call { + ($name:ident($($arg:expr),*), $error_id:expr) => { + if $name($($arg),*) == $error_id { + return Err(Error::last_os_error()); + } } } -/// Holds a calendar date and time broken down into its components (year, month, -/// day, and so on), also called a broken-down time value. -// FIXME: use c_int instead of i32? -#[repr(C)] -struct Tm { - /// Seconds after the minute - [0, 60] - tm_sec: i32, - - /// Minutes after the hour - [0, 59] - tm_min: i32, - - /// Hours after midnight - [0, 23] - tm_hour: i32, - - /// Day of the month - [1, 31] - tm_mday: i32, - - /// Months since January - [0, 11] - tm_mon: i32, - - /// Years since 1900 - tm_year: i32, - - /// Days since Sunday - [0, 6]. 0 = Sunday, 1 = Monday, ..., 6 = Saturday. - tm_wday: i32, - - /// Days since January 1 - [0, 365] - tm_yday: i32, - - /// Daylight Saving Time flag. - /// - /// This value is positive if Daylight Saving Time is in effect, zero if - /// Daylight Saving Time is not in effect, and negative if this information - /// is not available. - tm_isdst: i32, - - /// Identifies the time zone that was used to compute this broken-down time - /// value, including any adjustment for Daylight Saving Time. This is the - /// number of seconds east of UTC. For example, for U.S. Pacific Daylight - /// Time, the value is `-7*60*60 = -25200`. - tm_utcoff: i32, - - /// Nanoseconds after the second - [0, 10<sup>9</sup> - 1] - tm_nsec: i32, -} - const HECTONANOSECS_IN_SEC: i64 = 10_000_000; const HECTONANOSEC_TO_UNIX_EPOCH: i64 = 11_644_473_600 * HECTONANOSECS_IN_SEC; -fn time_to_file_time(sec: i64) -> FILETIME { - let t = ((sec * HECTONANOSECS_IN_SEC) + HECTONANOSEC_TO_UNIX_EPOCH) as u64; - FILETIME { dwLowDateTime: t as DWORD, dwHighDateTime: (t >> 32) as DWORD } -} - -fn file_time_as_u64(ft: &FILETIME) -> u64 { - ((ft.dwHighDateTime as u64) << 32) | (ft.dwLowDateTime as u64) +pub(super) fn offset_from_utc_datetime(utc: &NaiveDateTime) -> LocalResult<FixedOffset> { + offset(utc, false) } -fn file_time_to_unix_seconds(ft: &FILETIME) -> i64 { - let t = file_time_as_u64(ft) as i64; - ((t - HECTONANOSEC_TO_UNIX_EPOCH) / HECTONANOSECS_IN_SEC) as i64 +pub(super) fn offset_from_local_datetime(local: &NaiveDateTime) -> LocalResult<FixedOffset> { + offset(local, true) } -fn system_time_to_file_time(sys: &SYSTEMTIME) -> FILETIME { - unsafe { - let mut ft = mem::zeroed(); - SystemTimeToFileTime(sys, &mut ft); - ft - } -} - -fn tm_to_system_time(tm: &Tm) -> SYSTEMTIME { - let mut sys: SYSTEMTIME = unsafe { mem::zeroed() }; - sys.wSecond = tm.tm_sec as WORD; - sys.wMinute = tm.tm_min as WORD; - sys.wHour = tm.tm_hour as WORD; - sys.wDay = tm.tm_mday as WORD; - sys.wDayOfWeek = tm.tm_wday as WORD; - sys.wMonth = (tm.tm_mon + 1) as WORD; - sys.wYear = (tm.tm_year + 1900) as WORD; - sys -} - -fn system_time_to_tm(sys: &SYSTEMTIME, tm: &mut Tm) { - tm.tm_sec = sys.wSecond as i32; - tm.tm_min = sys.wMinute as i32; - tm.tm_hour = sys.wHour as i32; - tm.tm_mday = sys.wDay as i32; - tm.tm_wday = sys.wDayOfWeek as i32; - tm.tm_mon = (sys.wMonth - 1) as i32; - tm.tm_year = (sys.wYear - 1900) as i32; - tm.tm_yday = yday(tm.tm_year, tm.tm_mon + 1, tm.tm_mday); - - fn yday(year: i32, month: i32, day: i32) -> i32 { - let leap = if month > 2 { - if year % 4 == 0 { - 1 - } else { - 2 - } - } else { - 0 - }; - let july = if month > 7 { 1 } else { 0 }; +/// Converts a local `NaiveDateTime` to the `time::Timespec`. +pub(super) fn offset(d: &NaiveDateTime, local: bool) -> LocalResult<FixedOffset> { + let naive_sys_time = system_time_from_naive_date_time(d); - (month - 1) * 30 + month / 2 + (day - 1) - leap + july - } -} + let local_sys_time = match local { + false => from_utc_time(naive_sys_time), + true => from_local_time(naive_sys_time), + }; -macro_rules! call { - ($name:ident($($arg:expr),*)) => { - if $name($($arg),*) == 0 { - panic!(concat!(stringify!($name), " failed with: {}"), - io::Error::last_os_error()); - } + if let Ok(offset) = local_sys_time { + return LocalResult::Single(offset); } -} - -fn time_to_local_tm(sec: i64, tm: &mut Tm) { - let ft = time_to_file_time(sec); - unsafe { - let mut utc = mem::zeroed(); - let mut local = mem::zeroed(); - call!(FileTimeToSystemTime(&ft, &mut utc)); - call!(SystemTimeToTzSpecificLocalTime(0 as *const _, &mut utc, &mut local)); - system_time_to_tm(&local, tm); - - let local = system_time_to_file_time(&local); - let local_sec = file_time_to_unix_seconds(&local); - - let mut tz = mem::zeroed(); - GetTimeZoneInformation(&mut tz); - - // SystemTimeToTzSpecificLocalTime already applied the biases so - // check if it non standard - tm.tm_utcoff = (local_sec - sec) as i32; - tm.tm_isdst = if tm.tm_utcoff == -60 * (tz.Bias + tz.StandardBias) { 0 } else { 1 }; + LocalResult::None +} + +fn from_utc_time(utc_time: SYSTEMTIME) -> Result<FixedOffset, Error> { + let local_time = utc_to_local_time(&utc_time)?; + let utc_secs = system_time_as_unix_seconds(&utc_time)?; + let local_secs = system_time_as_unix_seconds(&local_time)?; + let offset = (local_secs - utc_secs) as i32; + Ok(FixedOffset::east_opt(offset).unwrap()) +} + +fn from_local_time(local_time: SYSTEMTIME) -> Result<FixedOffset, Error> { + let utc_time = local_to_utc_time(&local_time)?; + let utc_secs = system_time_as_unix_seconds(&utc_time)?; + let local_secs = system_time_as_unix_seconds(&local_time)?; + let offset = (local_secs - utc_secs) as i32; + Ok(FixedOffset::east_opt(offset).unwrap()) +} + +fn system_time_from_naive_date_time(dt: &NaiveDateTime) -> SYSTEMTIME { + SYSTEMTIME { + // Valid values: 1601-30827 + wYear: dt.year() as u16, + // Valid values:1-12 + wMonth: dt.month() as u16, + // Valid values: 0-6, starting Sunday. + // NOTE: enum returns 1-7, starting Monday, so we are + // off here, but this is not currently used in local. + wDayOfWeek: dt.weekday() as u16, + // Valid values: 1-31 + wDay: dt.day() as u16, + // Valid values: 0-23 + wHour: dt.hour() as u16, + // Valid values: 0-59 + wMinute: dt.minute() as u16, + // Valid values: 0-59 + wSecond: dt.second() as u16, + // Valid values: 0-999 + wMilliseconds: 0, } } -fn utc_tm_to_time(tm: &Tm) -> i64 { +pub(crate) fn local_to_utc_time(local: &SYSTEMTIME) -> Result<SYSTEMTIME, Error> { + let mut sys_time = MaybeUninit::<SYSTEMTIME>::uninit(); unsafe { - let mut ft = mem::zeroed(); - let sys_time = tm_to_system_time(tm); - call!(SystemTimeToFileTime(&sys_time, &mut ft)); - file_time_to_unix_seconds(&ft) - } + windows_sys_call!( + TzSpecificLocalTimeToSystemTime(ptr::null(), local, sys_time.as_mut_ptr()), + 0 + ) + }; + // SAFETY: TzSpecificLocalTimeToSystemTime must have succeeded at this point, so we can + // assume the value is initialized. + Ok(unsafe { sys_time.assume_init() }) } -fn local_tm_to_time(tm: &Tm) -> i64 { +pub(crate) fn utc_to_local_time(utc_time: &SYSTEMTIME) -> Result<SYSTEMTIME, Error> { + let mut local = MaybeUninit::<SYSTEMTIME>::uninit(); unsafe { - let mut ft = mem::zeroed(); - let mut utc = mem::zeroed(); - let mut sys_time = tm_to_system_time(tm); - call!(TzSpecificLocalTimeToSystemTime(0 as *mut _, &mut sys_time, &mut utc)); - call!(SystemTimeToFileTime(&utc, &mut ft)); - file_time_to_unix_seconds(&ft) - } + windows_sys_call!( + SystemTimeToTzSpecificLocalTime(ptr::null(), utc_time, local.as_mut_ptr()), + 0 + ) + }; + // SAFETY: SystemTimeToTzSpecificLocalTime must have succeeded at this point, so we can + // assume the value is initialized. + Ok(unsafe { local.assume_init() }) +} + +/// Returns a i64 value representing the unix seconds conversion of the current `WinSystemTime`. +pub(crate) fn system_time_as_unix_seconds(st: &SYSTEMTIME) -> Result<i64, Error> { + let mut init = MaybeUninit::<FILETIME>::uninit(); + unsafe { windows_sys_call!(SystemTimeToFileTime(st, init.as_mut_ptr()), 0) } + // SystemTimeToFileTime must have succeeded at this point, so we can assum the value is + // initalized. + let filetime = unsafe { init.assume_init() }; + let bit_shift = ((filetime.dwHighDateTime as u64) << 32) | (filetime.dwLowDateTime as u64); + let unix_secs = (bit_shift as i64 - HECTONANOSEC_TO_UNIX_EPOCH) / HECTONANOSECS_IN_SEC; + Ok(unix_secs) } diff --git a/vendor/chrono/src/offset/mod.rs b/vendor/chrono/src/offset/mod.rs index 09d0714e9..ee1fe7e23 100644 --- a/vendor/chrono/src/offset/mod.rs +++ b/vendor/chrono/src/offset/mod.rs @@ -52,6 +52,7 @@ pub enum LocalResult<T> { impl<T> LocalResult<T> { /// Returns `Some` only when the conversion result is unique, or `None` otherwise. + #[must_use] pub fn single(self) -> Option<T> { match self { LocalResult::Single(t) => Some(t), @@ -60,6 +61,7 @@ impl<T> LocalResult<T> { } /// Returns `Some` for the earliest possible conversion result, or `None` if none. + #[must_use] pub fn earliest(self) -> Option<T> { match self { LocalResult::Single(t) | LocalResult::Ambiguous(t, _) => Some(t), @@ -68,6 +70,7 @@ impl<T> LocalResult<T> { } /// Returns `Some` for the latest possible conversion result, or `None` if none. + #[must_use] pub fn latest(self) -> Option<T> { match self { LocalResult::Single(t) | LocalResult::Ambiguous(_, t) => Some(t), @@ -76,6 +79,7 @@ impl<T> LocalResult<T> { } /// Maps a `LocalResult<T>` into `LocalResult<U>` with given function. + #[must_use] pub fn map<U, F: FnMut(T) -> U>(self, mut f: F) -> LocalResult<U> { match self { LocalResult::None => LocalResult::None, @@ -92,6 +96,7 @@ impl<Tz: TimeZone> LocalResult<Date<Tz>> { /// /// Propagates any error. Ambiguous result would be discarded. #[inline] + #[must_use] pub fn and_time(self, time: NaiveTime) -> LocalResult<DateTime<Tz>> { match self { LocalResult::Single(d) => { @@ -106,6 +111,7 @@ impl<Tz: TimeZone> LocalResult<Date<Tz>> { /// /// Propagates any error. Ambiguous result would be discarded. #[inline] + #[must_use] pub fn and_hms_opt(self, hour: u32, min: u32, sec: u32) -> LocalResult<DateTime<Tz>> { match self { LocalResult::Single(d) => { @@ -121,6 +127,7 @@ impl<Tz: TimeZone> LocalResult<Date<Tz>> { /// /// Propagates any error. Ambiguous result would be discarded. #[inline] + #[must_use] pub fn and_hms_milli_opt( self, hour: u32, @@ -142,6 +149,7 @@ impl<Tz: TimeZone> LocalResult<Date<Tz>> { /// /// Propagates any error. Ambiguous result would be discarded. #[inline] + #[must_use] pub fn and_hms_micro_opt( self, hour: u32, @@ -163,6 +171,7 @@ impl<Tz: TimeZone> LocalResult<Date<Tz>> { /// /// Propagates any error. Ambiguous result would be discarded. #[inline] + #[must_use] pub fn and_hms_nano_opt( self, hour: u32, @@ -181,6 +190,8 @@ impl<Tz: TimeZone> LocalResult<Date<Tz>> { impl<T: fmt::Debug> LocalResult<T> { /// Returns the single unique conversion result, or panics accordingly. + #[must_use] + #[track_caller] pub fn unwrap(self) -> T { match self { LocalResult::None => panic!("No such local time"), diff --git a/vendor/chrono/src/offset/utc.rs b/vendor/chrono/src/offset/utc.rs index cfed754b2..dbcb8eecb 100644 --- a/vendor/chrono/src/offset/utc.rs +++ b/vendor/chrono/src/offset/utc.rs @@ -35,9 +35,9 @@ use crate::{Date, DateTime}; /// ``` /// use chrono::{DateTime, TimeZone, NaiveDateTime, Utc}; /// -/// let dt = DateTime::<Utc>::from_utc(NaiveDateTime::from_timestamp(61, 0), Utc); +/// let dt = DateTime::<Utc>::from_utc(NaiveDateTime::from_timestamp_opt(61, 0).unwrap(), Utc); /// -/// assert_eq!(Utc.timestamp(61, 0), dt); +/// assert_eq!(Utc.timestamp_opt(61, 0).unwrap(), dt); /// assert_eq!(Utc.with_ymd_and_hms(1970, 1, 1, 0, 1, 1).unwrap(), dt); /// ``` #[derive(Copy, Clone, PartialEq, Eq, Hash)] @@ -54,6 +54,7 @@ impl Utc { note = "use `Utc::now()` instead, potentially with `.date_naive()`" )] #[allow(deprecated)] + #[must_use] pub fn today() -> Date<Utc> { Utc::now().date() } @@ -64,6 +65,7 @@ impl Utc { feature = "wasmbind", not(any(target_os = "emscripten", target_os = "wasi")) )))] + #[must_use] pub fn now() -> DateTime<Utc> { let now = SystemTime::now().duration_since(UNIX_EPOCH).expect("system time before Unix epoch"); @@ -78,6 +80,7 @@ impl Utc { feature = "wasmbind", not(any(target_os = "emscripten", target_os = "wasi")) ))] + #[must_use] pub fn now() -> DateTime<Utc> { let now = js_sys::Date::new_0(); DateTime::<Utc>::from(now) diff --git a/vendor/chrono/src/oldtime.rs b/vendor/chrono/src/oldtime.rs index 8e2b3d2c0..e27be7db6 100644 --- a/vendor/chrono/src/oldtime.rs +++ b/vendor/chrono/src/oldtime.rs @@ -74,6 +74,7 @@ impl Duration { /// Equivalent to `Duration::seconds(weeks * 7 * 24 * 60 * 60)` with overflow checks. /// Panics when the duration is out of bounds. #[inline] + #[must_use] pub fn weeks(weeks: i64) -> Duration { let secs = weeks.checked_mul(SECS_PER_WEEK).expect("Duration::weeks out of bounds"); Duration::seconds(secs) @@ -83,6 +84,7 @@ impl Duration { /// Equivalent to `Duration::seconds(days * 24 * 60 * 60)` with overflow checks. /// Panics when the duration is out of bounds. #[inline] + #[must_use] pub fn days(days: i64) -> Duration { let secs = days.checked_mul(SECS_PER_DAY).expect("Duration::days out of bounds"); Duration::seconds(secs) @@ -92,6 +94,7 @@ impl Duration { /// Equivalent to `Duration::seconds(hours * 60 * 60)` with overflow checks. /// Panics when the duration is out of bounds. #[inline] + #[must_use] pub fn hours(hours: i64) -> Duration { let secs = hours.checked_mul(SECS_PER_HOUR).expect("Duration::hours ouf of bounds"); Duration::seconds(secs) @@ -101,6 +104,7 @@ impl Duration { /// Equivalent to `Duration::seconds(minutes * 60)` with overflow checks. /// Panics when the duration is out of bounds. #[inline] + #[must_use] pub fn minutes(minutes: i64) -> Duration { let secs = minutes.checked_mul(SECS_PER_MINUTE).expect("Duration::minutes out of bounds"); Duration::seconds(secs) @@ -110,6 +114,7 @@ impl Duration { /// Panics when the duration is more than `i64::MAX` seconds /// or less than `i64::MIN` seconds. #[inline] + #[must_use] pub fn seconds(seconds: i64) -> Duration { let d = Duration { secs: seconds, nanos: 0 }; if d < MIN || d > MAX { @@ -211,6 +216,7 @@ impl Duration { } /// Add two durations, returning `None` if overflow occurred. + #[must_use] pub fn checked_add(&self, rhs: &Duration) -> Option<Duration> { let mut secs = try_opt!(self.secs.checked_add(rhs.secs)); let mut nanos = self.nanos + rhs.nanos; @@ -229,6 +235,7 @@ impl Duration { } /// Subtract two durations, returning `None` if overflow occurred. + #[must_use] pub fn checked_sub(&self, rhs: &Duration) -> Option<Duration> { let mut secs = try_opt!(self.secs.checked_sub(rhs.secs)); let mut nanos = self.nanos - rhs.nanos; @@ -455,31 +462,9 @@ impl Error for OutOfRangeError { } } -// Copied from libnum #[inline] const fn div_mod_floor_64(this: i64, other: i64) -> (i64, i64) { - (div_floor_64(this, other), mod_floor_64(this, other)) -} - -#[inline] -const fn div_floor_64(this: i64, other: i64) -> i64 { - match div_rem_64(this, other) { - (d, r) if (r > 0 && other < 0) || (r < 0 && other > 0) => d - 1, - (d, _) => d, - } -} - -#[inline] -const fn mod_floor_64(this: i64, other: i64) -> i64 { - match this % other { - r if (r > 0 && other < 0) || (r < 0 && other > 0) => r + other, - r => r, - } -} - -#[inline] -const fn div_rem_64(this: i64, other: i64) -> (i64, i64) { - (this / other, this % other) + (this.div_euclid(other), this.rem_euclid(other)) } #[cfg(feature = "arbitrary")] diff --git a/vendor/chrono/src/round.rs b/vendor/chrono/src/round.rs index b95f24570..f43ab595c 100644 --- a/vendor/chrono/src/round.rs +++ b/vendor/chrono/src/round.rs @@ -24,7 +24,7 @@ pub trait SubsecRound { /// /// # Example /// ``` rust - /// # use chrono::{DateTime, SubsecRound, Timelike, TimeZone, Utc, NaiveDate}; + /// # use chrono::{SubsecRound, Timelike, Utc, NaiveDate}; /// let dt = NaiveDate::from_ymd_opt(2018, 1, 11).unwrap().and_hms_milli_opt(12, 0, 0, 154).unwrap().and_local_timezone(Utc).unwrap(); /// assert_eq!(dt.round_subsecs(2).nanosecond(), 150_000_000); /// assert_eq!(dt.round_subsecs(1).nanosecond(), 200_000_000); @@ -36,7 +36,7 @@ pub trait SubsecRound { /// /// # Example /// ``` rust - /// # use chrono::{DateTime, SubsecRound, Timelike, TimeZone, Utc, NaiveDate}; + /// # use chrono::{SubsecRound, Timelike, Utc, NaiveDate}; /// let dt = NaiveDate::from_ymd_opt(2018, 1, 11).unwrap().and_hms_milli_opt(12, 0, 0, 154).unwrap().and_local_timezone(Utc).unwrap(); /// assert_eq!(dt.trunc_subsecs(2).nanosecond(), 150_000_000); /// assert_eq!(dt.trunc_subsecs(1).nanosecond(), 100_000_000); @@ -75,7 +75,7 @@ where } // Return the maximum span in nanoseconds for the target number of digits. -fn span_for_digits(digits: u16) -> u32 { +const fn span_for_digits(digits: u16) -> u32 { // fast lookup form of: 10^(9-min(9,digits)) match digits { 0 => 1_000_000_000, @@ -111,7 +111,7 @@ pub trait DurationRound: Sized { /// /// # Example /// ``` rust - /// # use chrono::{DateTime, DurationRound, Duration, TimeZone, Utc, NaiveDate}; + /// # use chrono::{DurationRound, Duration, Utc, NaiveDate}; /// let dt = NaiveDate::from_ymd_opt(2018, 1, 11).unwrap().and_hms_milli_opt(12, 0, 0, 154).unwrap().and_local_timezone(Utc).unwrap(); /// assert_eq!( /// dt.duration_round(Duration::milliseconds(10)).unwrap().to_string(), @@ -128,7 +128,7 @@ pub trait DurationRound: Sized { /// /// # Example /// ``` rust - /// # use chrono::{DateTime, DurationRound, Duration, TimeZone, Utc, NaiveDate}; + /// # use chrono::{DurationRound, Duration, Utc, NaiveDate}; /// let dt = NaiveDate::from_ymd_opt(2018, 1, 11).unwrap().and_hms_milli_opt(12, 0, 0, 154).unwrap().and_local_timezone(Utc).unwrap(); /// assert_eq!( /// dt.duration_trunc(Duration::milliseconds(10)).unwrap().to_string(), @@ -178,6 +178,9 @@ where T: Timelike + Add<Duration, Output = T> + Sub<Duration, Output = T>, { if let Some(span) = duration.num_nanoseconds() { + if span < 0 { + return Err(RoundingError::DurationExceedsLimit); + } if naive.timestamp().abs() > MAX_SECONDS_TIMESTAMP_FOR_NANOS { return Err(RoundingError::TimestampExceedsLimit); } @@ -217,6 +220,9 @@ where T: Timelike + Add<Duration, Output = T> + Sub<Duration, Output = T>, { if let Some(span) = duration.num_nanoseconds() { + if span < 0 { + return Err(RoundingError::DurationExceedsLimit); + } if naive.timestamp().abs() > MAX_SECONDS_TIMESTAMP_FOR_NANOS { return Err(RoundingError::TimestampExceedsLimit); } @@ -243,7 +249,7 @@ pub enum RoundingError { /// Error when the Duration exceeds the Duration from or until the Unix epoch. /// /// ``` rust - /// # use chrono::{DateTime, DurationRound, Duration, RoundingError, TimeZone, Utc}; + /// # use chrono::{DurationRound, Duration, RoundingError, TimeZone, Utc}; /// let dt = Utc.with_ymd_and_hms(1970, 12, 12, 0, 0, 0).unwrap(); /// /// assert_eq!( @@ -256,7 +262,7 @@ pub enum RoundingError { /// Error when `Duration.num_nanoseconds` exceeds the limit. /// /// ``` rust - /// # use chrono::{DateTime, DurationRound, Duration, RoundingError, TimeZone, Utc, NaiveDate}; + /// # use chrono::{DurationRound, Duration, RoundingError, Utc, NaiveDate}; /// let dt = NaiveDate::from_ymd_opt(2260, 12, 31).unwrap().and_hms_nano_opt(23, 59, 59, 1_75_500_000).unwrap().and_local_timezone(Utc).unwrap(); /// /// assert_eq!( @@ -269,7 +275,7 @@ pub enum RoundingError { /// Error when `DateTime.timestamp_nanos` exceeds the limit. /// /// ``` rust - /// # use chrono::{DateTime, DurationRound, Duration, RoundingError, TimeZone, Utc}; + /// # use chrono::{DurationRound, Duration, RoundingError, TimeZone, Utc}; /// let dt = Utc.with_ymd_and_hms(2300, 12, 12, 0, 0, 0).unwrap(); /// /// assert_eq!(dt.duration_round(Duration::days(1)), Err(RoundingError::TimestampExceedsLimit),); @@ -304,10 +310,10 @@ impl std::error::Error for RoundingError { #[cfg(test)] mod tests { - use super::{Duration, DurationRound, SubsecRound}; + use super::{Duration, DurationRound, RoundingError, SubsecRound}; use crate::offset::{FixedOffset, TimeZone, Utc}; - use crate::NaiveDate; use crate::Timelike; + use crate::{NaiveDate, NaiveDateTime}; #[test] fn test_round_subsecs() { @@ -760,4 +766,19 @@ mod tests { "1969-12-12 12:10:00 UTC" ); } + + #[test] + fn issue1010() { + let dt = NaiveDateTime::from_timestamp_opt(-4227854320, 1678774288).unwrap(); + let span = Duration::microseconds(-7019067213869040); + assert_eq!(dt.duration_trunc(span), Err(RoundingError::DurationExceedsLimit)); + + let dt = NaiveDateTime::from_timestamp_opt(320041586, 1920103021).unwrap(); + let span = Duration::nanoseconds(-8923838508697114584); + assert_eq!(dt.duration_round(span), Err(RoundingError::DurationExceedsLimit)); + + let dt = NaiveDateTime::from_timestamp_opt(-2621440, 0).unwrap(); + let span = Duration::nanoseconds(-9223372036854771421); + assert_eq!(dt.duration_round(span), Err(RoundingError::DurationExceedsLimit)); + } } diff --git a/vendor/chrono/src/traits.rs b/vendor/chrono/src/traits.rs index 1b6af6926..a6199dc6d 100644 --- a/vendor/chrono/src/traits.rs +++ b/vendor/chrono/src/traits.rs @@ -219,9 +219,7 @@ mod tests { date.ordinal() as i32 + 365 * diff(1) + diff(4) - diff(100) + diff(400) } - use num_iter::range_inclusive; - - for year in range_inclusive(NaiveDate::MIN.year(), NaiveDate::MAX.year()) { + for year in NaiveDate::MIN.year()..=NaiveDate::MAX.year() { let jan1_year = NaiveDate::from_ymd_opt(year, 1, 1).unwrap(); assert_eq!( jan1_year.num_days_from_ce(), diff --git a/vendor/chrono/src/weekday.rs b/vendor/chrono/src/weekday.rs index 72e384673..e2973cf79 100644 --- a/vendor/chrono/src/weekday.rs +++ b/vendor/chrono/src/weekday.rs @@ -3,11 +3,32 @@ use core::fmt; #[cfg(feature = "rkyv")] use rkyv::{Archive, Deserialize, Serialize}; +use crate::OutOfRange; + /// The day of week. /// /// The order of the days of week depends on the context. /// (This is why this type does *not* implement `PartialOrd` or `Ord` traits.) /// One should prefer `*_from_monday` or `*_from_sunday` methods to get the correct result. +/// +/// # Example +/// ``` +/// use chrono::Weekday; +/// +/// let monday = "Monday".parse::<Weekday>().unwrap(); +/// assert_eq!(monday, Weekday::Mon); +/// +/// let sunday = Weekday::try_from(6).unwrap(); +/// assert_eq!(sunday, Weekday::Sun); +/// +/// assert_eq!(sunday.num_days_from_monday(), 6); // starts counting with Monday = 0 +/// assert_eq!(sunday.number_from_monday(), 7); // starts counting with Monday = 1 +/// assert_eq!(sunday.num_days_from_sunday(), 0); // starts counting with Sunday = 0 +/// assert_eq!(sunday.number_from_sunday(), 1); // starts counting with Sunday = 1 +/// +/// assert_eq!(sunday.succ(), monday); +/// assert_eq!(sunday.pred(), Weekday::Sat); +/// ``` #[derive(PartialEq, Eq, Copy, Clone, Debug, Hash)] #[cfg_attr(feature = "rustc-serialize", derive(RustcEncodable, RustcDecodable))] #[cfg_attr(feature = "rkyv", derive(Archive, Deserialize, Serialize))] @@ -36,7 +57,8 @@ impl Weekday { /// ----------- | ----- | ----- | ----- | ----- | ----- | ----- | ----- /// `w.succ()`: | `Tue` | `Wed` | `Thu` | `Fri` | `Sat` | `Sun` | `Mon` #[inline] - pub fn succ(&self) -> Weekday { + #[must_use] + pub const fn succ(&self) -> Weekday { match *self { Weekday::Mon => Weekday::Tue, Weekday::Tue => Weekday::Wed, @@ -54,7 +76,8 @@ impl Weekday { /// ----------- | ----- | ----- | ----- | ----- | ----- | ----- | ----- /// `w.pred()`: | `Sun` | `Mon` | `Tue` | `Wed` | `Thu` | `Fri` | `Sat` #[inline] - pub fn pred(&self) -> Weekday { + #[must_use] + pub const fn pred(&self) -> Weekday { match *self { Weekday::Mon => Weekday::Sun, Weekday::Tue => Weekday::Mon, @@ -108,7 +131,7 @@ impl Weekday { /// Returns a day-of-week number starting from the parameter `day` (D) = 0. /// - /// `w`: | `D` | `D+1` | `D+2` | `D+3` | `D+4` | `D+5` | `D+6` + /// `w`: | `D` | `D+1` | `D+2` | `D+3` | `D+4` | `D+5` | `D+6` /// --------------------------- | ----- | ----- | ----- | ----- | ----- | ----- | ----- /// `w.num_days_from(wd)`: | 0 | 1 | 2 | 3 | 4 | 5 | 6 #[inline] @@ -134,6 +157,26 @@ impl fmt::Display for Weekday { /// Any weekday can be represented as an integer from 0 to 6, which equals to /// [`Weekday::num_days_from_monday`](#method.num_days_from_monday) in this implementation. /// Do not heavily depend on this though; use explicit methods whenever possible. +impl TryFrom<u8> for Weekday { + type Error = OutOfRange; + + fn try_from(value: u8) -> Result<Self, Self::Error> { + match value { + 0 => Ok(Weekday::Mon), + 1 => Ok(Weekday::Tue), + 2 => Ok(Weekday::Wed), + 3 => Ok(Weekday::Thu), + 4 => Ok(Weekday::Fri), + 5 => Ok(Weekday::Sat), + 6 => Ok(Weekday::Sun), + _ => Err(OutOfRange::new()), + } + } +} + +/// Any weekday can be represented as an integer from 0 to 6, which equals to +/// [`Weekday::num_days_from_monday`](#method.num_days_from_monday) in this implementation. +/// Do not heavily depend on this though; use explicit methods whenever possible. impl num_traits::FromPrimitive for Weekday { #[inline] fn from_i64(n: i64) -> Option<Weekday> { @@ -188,14 +231,12 @@ impl fmt::Debug for ParseWeekdayError { #[cfg(test)] mod tests { - use num_traits::FromPrimitive; - use super::Weekday; #[test] fn test_num_days_from() { for i in 0..7 { - let base_day = Weekday::from_u64(i).unwrap(); + let base_day = Weekday::try_from(i).unwrap(); assert_eq!(base_day.num_days_from_monday(), base_day.num_days_from(Weekday::Mon)); assert_eq!(base_day.num_days_from_sunday(), base_day.num_days_from(Weekday::Sun)); diff --git a/vendor/chrono/tests/dateutils.rs b/vendor/chrono/tests/dateutils.rs index dec6bfe11..d671ecca8 100644 --- a/vendor/chrono/tests/dateutils.rs +++ b/vendor/chrono/tests/dateutils.rs @@ -1,7 +1,11 @@ +#[cfg(unix)] use chrono::offset::TimeZone; +#[cfg(unix)] use chrono::Local; +#[cfg(unix)] use chrono::{Datelike, NaiveDate, NaiveDateTime, Timelike}; +#[cfg(unix)] use std::{path, process}; #[cfg(unix)] @@ -48,31 +52,68 @@ fn verify_against_date_command_local(path: &'static str, dt: NaiveDateTime) { } } +/// path to Unix `date` command. Should work on most Linux and Unixes. Not the +/// path for MacOS (/bin/date) which uses a different version of `date` with +/// different arguments (so it won't run which is okay). +/// for testing only +#[allow(dead_code)] +#[cfg(not(target_os = "aix"))] +const DATE_PATH: &'static str = "/usr/bin/date"; +#[allow(dead_code)] +#[cfg(target_os = "aix")] +const DATE_PATH: &'static str = "/opt/freeware/bin/date"; + +#[cfg(test)] +/// test helper to sanity check the date command behaves as expected +/// asserts the command succeeded +fn assert_run_date_version() { + // note environment variable `LANG` + match std::env::var_os("LANG") { + Some(lang) => eprintln!("LANG: {:?}", lang), + None => eprintln!("LANG not set"), + } + let out = process::Command::new(DATE_PATH).arg("--version").output().unwrap(); + let stdout = String::from_utf8(out.stdout).unwrap(); + let stderr = String::from_utf8(out.stderr).unwrap(); + // note the `date` binary version + eprintln!("command: {:?} --version\nstdout: {:?}\nstderr: {:?}", DATE_PATH, stdout, stderr); + assert!(out.status.success(), "command failed: {:?} --version", DATE_PATH); +} + #[test] #[cfg(unix)] fn try_verify_against_date_command() { - let date_path = "/usr/bin/date"; - - if !path::Path::new(date_path).exists() { - // date command not found, skipping - // avoid running this on macOS, which has path /bin/date - // as the required CLI arguments are not present in the - // macOS build. + if !path::Path::new(DATE_PATH).exists() { + eprintln!("date command {:?} not found, skipping", DATE_PATH); return; } + assert_run_date_version(); let mut date = NaiveDate::from_ymd_opt(1975, 1, 1).unwrap().and_hms_opt(0, 0, 0).unwrap(); + eprintln!( + "Run command {:?} for every hour from {} to 2077, skipping some years...", + DATE_PATH, + date.year() + ); + let mut count: u64 = 0; + let mut year_at = date.year(); while date.year() < 2078 { if (1975..=1977).contains(&date.year()) || (2020..=2022).contains(&date.year()) || (2073..=2077).contains(&date.year()) { - verify_against_date_command_local(date_path, date); + if date.year() != year_at { + eprintln!("at year {}...", date.year()); + year_at = date.year(); + } + verify_against_date_command_local(DATE_PATH, date); + count += 1; } date += chrono::Duration::hours(1); } + eprintln!("Command {:?} was run {} times", DATE_PATH, count); } #[cfg(target_os = "linux")] @@ -91,6 +132,7 @@ fn verify_against_date_command_format_local(path: &'static str, dt: NaiveDateTim // Z%Z - too many ways to represent it, will most likely fail let output = process::Command::new(path) + .env("LANG", "c") .arg("-d") .arg(format!( "{}-{:02}-{:02} {:02}:{:02}:{:02}", @@ -117,15 +159,15 @@ fn verify_against_date_command_format_local(path: &'static str, dt: NaiveDateTim #[test] #[cfg(target_os = "linux")] fn try_verify_against_date_command_format() { - let date_path = "/usr/bin/date"; - - if !path::Path::new(date_path).exists() { - // date command not found, skipping + if !path::Path::new(DATE_PATH).exists() { + eprintln!("date command {:?} not found, skipping", DATE_PATH); return; } + assert_run_date_version(); + let mut date = NaiveDate::from_ymd_opt(1970, 1, 1).unwrap().and_hms_opt(12, 11, 13).unwrap(); while date.year() < 2008 { - verify_against_date_command_format_local(date_path, date); + verify_against_date_command_format_local(DATE_PATH, date); date += chrono::Duration::days(55); } } |