summaryrefslogtreecommitdiffstats
path: root/vendor/chrono
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/chrono')
-rw-r--r--vendor/chrono/.cargo-checksum.json2
-rw-r--r--vendor/chrono/AUTHORS.txt2
-rw-r--r--vendor/chrono/CHANGELOG.md15
-rw-r--r--vendor/chrono/Cargo.toml97
-rw-r--r--vendor/chrono/Makefile26
-rw-r--r--vendor/chrono/README.md364
-rw-r--r--vendor/chrono/appveyor.yml12
-rw-r--r--vendor/chrono/benches/chrono.rs39
-rw-r--r--vendor/chrono/benches/serde.rs3
-rw-r--r--vendor/chrono/clippy.toml1
-rw-r--r--vendor/chrono/deny.toml13
-rw-r--r--vendor/chrono/src/date.rs221
-rw-r--r--vendor/chrono/src/datetime.rs2589
-rw-r--r--vendor/chrono/src/datetime/mod.rs1322
-rw-r--r--vendor/chrono/src/datetime/rustc_serialize.rs123
-rw-r--r--vendor/chrono/src/datetime/serde.rs1150
-rw-r--r--vendor/chrono/src/datetime/tests.rs952
-rw-r--r--vendor/chrono/src/div.rs41
-rw-r--r--vendor/chrono/src/format/mod.rs483
-rw-r--r--vendor/chrono/src/format/parse.rs97
-rw-r--r--vendor/chrono/src/format/parsed.rs160
-rw-r--r--vendor/chrono/src/format/scan.rs121
-rw-r--r--vendor/chrono/src/format/strftime.rs177
-rw-r--r--vendor/chrono/src/lib.rs1226
-rw-r--r--vendor/chrono/src/month.rs355
-rw-r--r--vendor/chrono/src/naive/date.rs1765
-rw-r--r--vendor/chrono/src/naive/datetime.rs2507
-rw-r--r--vendor/chrono/src/naive/datetime/mod.rs1946
-rw-r--r--vendor/chrono/src/naive/datetime/rustc_serialize.rs73
-rw-r--r--vendor/chrono/src/naive/datetime/serde.rs1133
-rw-r--r--vendor/chrono/src/naive/datetime/tests.rs343
-rw-r--r--vendor/chrono/src/naive/internals.rs277
-rw-r--r--vendor/chrono/src/naive/isoweek.rs66
-rw-r--r--vendor/chrono/src/naive/mod.rs39
-rw-r--r--vendor/chrono/src/naive/time/mod.rs (renamed from vendor/chrono/src/naive/time.rs)940
-rw-r--r--vendor/chrono/src/naive/time/rustc_serialize.rs29
-rw-r--r--vendor/chrono/src/naive/time/serde.rs65
-rw-r--r--vendor/chrono/src/naive/time/tests.rs317
-rw-r--r--vendor/chrono/src/offset/fixed.rs112
-rw-r--r--vendor/chrono/src/offset/local.rs227
-rw-r--r--vendor/chrono/src/offset/local/mod.rs260
-rw-r--r--vendor/chrono/src/offset/local/stub.rs236
-rw-r--r--vendor/chrono/src/offset/local/tz_info/mod.rs131
-rw-r--r--vendor/chrono/src/offset/local/tz_info/parser.rs334
-rw-r--r--vendor/chrono/src/offset/local/tz_info/rule.rs1046
-rw-r--r--vendor/chrono/src/offset/local/tz_info/timezone.rs904
-rw-r--r--vendor/chrono/src/offset/local/unix.rs185
-rw-r--r--vendor/chrono/src/offset/local/windows.rs278
-rw-r--r--vendor/chrono/src/offset/mod.rs184
-rw-r--r--vendor/chrono/src/offset/utc.rs55
-rw-r--r--vendor/chrono/src/oldtime.rs131
-rw-r--r--vendor/chrono/src/round.rs487
-rw-r--r--vendor/chrono/src/sys.rs126
-rw-r--r--vendor/chrono/src/sys/stub.rs80
-rw-r--r--vendor/chrono/src/sys/unix.rs126
-rw-r--r--vendor/chrono/src/sys/windows.rs131
-rw-r--r--vendor/chrono/src/traits.rs241
-rw-r--r--vendor/chrono/src/weekday.rs329
-rw-r--r--vendor/chrono/tests/dateutils.rs131
-rw-r--r--vendor/chrono/tests/wasm.rs128
60 files changed, 15471 insertions, 9482 deletions
diff --git a/vendor/chrono/.cargo-checksum.json b/vendor/chrono/.cargo-checksum.json
index 278002f2a..5d66a6fc4 100644
--- a/vendor/chrono/.cargo-checksum.json
+++ b/vendor/chrono/.cargo-checksum.json
@@ -1 +1 @@
-{"files":{"AUTHORS.txt":"bcca43c486176e81edcb64d065d418986cb5ca71af7ee4a648236a644305960d","CHANGELOG.md":"a925f71022f1c9e34e5df7c016ab2a32e9be22fc503929aa87d567900ebe064b","Cargo.toml":"13fab9c53580e2754c4fa075768ee9591e8d4b4a437ac9dbae503c4d4b6daf09","LICENSE.txt":"46610329ff0b38effb9cb05979ff1ef761e465fed96b2eaca39e439d00129fd7","README.md":"39985917c9bc71ee87a24808369ddfab22f3c6343da7c87c2274c965e1eec9db","benches/chrono.rs":"4de07b4c7bc907926e5a6ed20fc00a30e4e0491604f3d78eece81f1a8b45870a","benches/serde.rs":"e1a9624bcad4892c4cc7b76d5ad14607a016305a27b2231c2c77814b1d4448a8","rustfmt.toml":"f74204a6f92aa7422a16ecb2ffe2d5bae0f123b778d08b5db1a398a3c9ca4306","src/date.rs":"ec234e777efa9d8cd2f0c7f87db9296eda04bd4d56c994232a3329eb863acd34","src/datetime.rs":"63e582cd17f3070cbcb586bea15b5102ead1a898252e14b1817a498750043102","src/div.rs":"6c0a08648bb688b418b42f1c7be8387057a9db9774d3f09e97df2a183b79cd9f","src/format/locales.rs":"8c14cb93c68b747947b74ab2933aae53c8a0edd009ff16815e756015fbea6e9f","src/format/mod.rs":"09c66dee24e69325ce9a7be5b6c830317515ee37f7c2a26f48835484ed155c89","src/format/parse.rs":"c98217756370c6186bdab117373912208c018a2c6411f9be0fd1aecab54fb10c","src/format/parsed.rs":"6d4453a5fedc753fae268e0f545fcc817d48f9ce6803231d1c83aeb1f626c138","src/format/scan.rs":"1846554a45c776d164239ec6874881c6c97468631a1c00c8c956630420ea408f","src/format/strftime.rs":"8bbe43ca06c8a5e71187431890a54ff1faeb3be990c0d9d8c2fd8ee8b5c1361f","src/lib.rs":"522163d278acefa80fd1af4afeec2fdd2648e13e3fbdde8e6d31214253b013f9","src/naive/date.rs":"8be6146b3c15c395a71d30449a799b6e4387d1cd515e7e849509b824161fa6e3","src/naive/datetime.rs":"fd0de90d13793e5a8ecf99f63fa27592a6add57ba39a116495f9b2b253323fce","src/naive/internals.rs":"8c1aa5ab3373e04b51d36ed1591d667e1450055208b8c44d3fb720a496722c57","src/naive/isoweek.rs":"a8c5ae43ee1b916a2f79d42230aea448bf85691d615c4d271fcf1809e763df01","src/naive/time.rs":"b83e4ae0a809badce9131a19e3c5c75dbb823db4ef2f79d50bd522126ba0b48f","src/offset/fixed.rs":"19b97271300b821407756e14f64a42d48eb25a71c7011b2967885e4946e089ef","src/offset/local.rs":"9bc3af0ebf35a49858647302ac7e44abe344cbb76819d273311e50d234d1e6b2","src/offset/mod.rs":"a1036f75fc686603b216f9bb45b1689c8b34198b617b204800ceafb87b66ec45","src/offset/utc.rs":"2940ade0e834a9e1247600e92d38ee7bb11653f2d267862f99f292f617e25ca4","src/oldtime.rs":"780bc4ae5652affa8f7020580bb5977e9f32b304b0905c742124fd87a82ae50e","src/round.rs":"f7ae453ec0caacffc23bc0bad38b2c59b616c097ccaa0a15c0e7bcb8d1e1aed3","src/sys.rs":"4a3e8a96a2060e7df82c57405a5de4fffa54132a77fdd919970d51f3c43442cb","src/sys/stub.rs":"78babcdbe867ce5978bd69935e141ee15313ee7d90edce52355a19ab906a019b","src/sys/unix.rs":"c838ba088423c2b26643bd7191fe1914f099c14d632c9874f236c9c2c9dbd2d6","src/sys/windows.rs":"5c19383e9ffe11c16102008b5984dbd3455fd4003df15ac1565720c0a5edfac8","tests/wasm.rs":"d152681d5a79d9bbb69684433388bb8d7ca90e181387d4690cf5bda8cf25d17f"},"package":"670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73"} \ No newline at end of file
+{"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
diff --git a/vendor/chrono/AUTHORS.txt b/vendor/chrono/AUTHORS.txt
index 9501a9d05..caff57915 100644
--- a/vendor/chrono/AUTHORS.txt
+++ b/vendor/chrono/AUTHORS.txt
@@ -22,6 +22,7 @@ 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>
@@ -39,3 +40,4 @@ 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/CHANGELOG.md b/vendor/chrono/CHANGELOG.md
index be289ae88..1e6f6f935 100644
--- a/vendor/chrono/CHANGELOG.md
+++ b/vendor/chrono/CHANGELOG.md
@@ -1,17 +1,9 @@
ChangeLog for Chrono
====================
-This documents all notable changes to [Chrono](https://github.com/chronotope/chrono).
-
-Chrono obeys the principle of [Semantic Versioning](http://semver.org/), with one caveat: we may
-move previously-existing code behind a feature gate and put it behind a new feature. This new
-feature will always be placed in the `previously-default` feature, which you can use to prevent
-breakage if you use `no-default-features`.
-
-There were/are numerous minor versions before 1.0 due to the language changes.
-Versions with only mechanical changes will be omitted from the following list.
-
-## 0.4.20 (unreleased)
+This documents notable changes to [Chrono](https://github.com/chronotope/chrono)
+up to and including version 0.4.19. For later releases, please review the
+release notes on [GitHub](https://github.com/chronotope/chrono/releases).
## 0.4.19
@@ -737,4 +729,3 @@ and replaced by 0.2.25 very shortly. Duh.)
## 0.1.0 (2014-11-20)
The initial version that was available to `crates.io`.
-
diff --git a/vendor/chrono/Cargo.toml b/vendor/chrono/Cargo.toml
index 2d3e76433..eaf0e6945 100644
--- a/vendor/chrono/Cargo.toml
+++ b/vendor/chrono/Cargo.toml
@@ -3,28 +3,36 @@
# When uploading crates to the registry Cargo will automatically
# "normalize" Cargo.toml files for maximal compatibility
# with all versions of Cargo and also rewrite `path` dependencies
-# to registry (e.g., crates.io) dependencies
+# to registry (e.g., crates.io) dependencies.
#
-# If you believe there's an error in this file please file an
-# issue against the rust-lang/cargo repository. If you're
-# editing this file be aware that the upstream Cargo.toml
-# will likely look very different (and much more reasonable)
+# If you are reading this file be aware that the original Cargo.toml
+# will likely look very different (and much more reasonable).
+# See Cargo.toml.orig for the original contents.
[package]
+edition = "2018"
name = "chrono"
-version = "0.4.19"
-authors = ["Kang Seonghoon <public+rust@mearie.org>", "Brandon W Maister <quodlibetor@gmail.com>"]
-exclude = ["/ci/*", "/.travis.yml", "/appveyor.yml", "/Makefile"]
+version = "0.4.24"
+exclude = ["/ci/*"]
description = "Date and time library for Rust"
homepage = "https://github.com/chronotope/chrono"
documentation = "https://docs.rs/chrono/"
readme = "README.md"
-keywords = ["date", "time", "calendar"]
+keywords = [
+ "date",
+ "time",
+ "calendar",
+]
categories = ["date-and-time"]
license = "MIT/Apache-2.0"
repository = "https://github.com/chronotope/chrono"
+
[package.metadata.docs.rs]
features = ["serde"]
+rustdoc-args = [
+ "--cfg",
+ "docsrs",
+]
[package.metadata.playground]
features = ["serde"]
@@ -40,9 +48,18 @@ required-features = ["__internal_bench"]
[[bench]]
name = "serde"
harness = false
-required-features = ["serde"]
-[dependencies.libc]
-version = "0.2.69"
+required-features = [
+ "__internal_bench",
+ "serde",
+]
+
+[dependencies.arbitrary]
+version = "1.0.0"
+features = ["derive"]
+optional = true
+
+[dependencies.criterion]
+version = "0.4.0"
optional = true
[dependencies.num-integer]
@@ -57,6 +74,10 @@ default-features = false
version = "0.5.2"
optional = true
+[dependencies.rkyv]
+version = "0.7"
+optional = true
+
[dependencies.rustc-serialize]
version = "0.3.20"
optional = true
@@ -69,11 +90,9 @@ default-features = false
[dependencies.time]
version = "0.1.43"
optional = true
-[dev-dependencies.bincode]
-version = "0.8.0"
-[dev-dependencies.criterion]
-version = "0.3"
+[dev-dependencies.bincode]
+version = "1.3.0"
[dev-dependencies.doc-comment]
version = "0.3"
@@ -91,14 +110,31 @@ version = "1"
[features]
__doctest = []
-__internal_bench = []
+__internal_bench = ["criterion"]
alloc = []
-clock = ["libc", "std", "winapi"]
-default = ["clock", "std", "oldtime"]
+clock = [
+ "std",
+ "winapi",
+ "iana-time-zone",
+]
+default = [
+ "clock",
+ "std",
+ "oldtime",
+ "wasmbind",
+]
+libc = []
oldtime = ["time"]
std = []
-unstable-locales = ["pure-rust-locales", "alloc"]
-wasmbind = ["wasm-bindgen", "js-sys"]
+unstable-locales = [
+ "pure-rust-locales",
+ "alloc",
+]
+wasmbind = [
+ "wasm-bindgen",
+ "js-sys",
+]
+
[target."cfg(all(target_arch = \"wasm32\", not(any(target_os = \"emscripten\", target_os = \"wasi\"))))".dependencies.js-sys]
version = "0.3"
optional = true
@@ -106,14 +142,21 @@ optional = true
[target."cfg(all(target_arch = \"wasm32\", not(any(target_os = \"emscripten\", target_os = \"wasi\"))))".dependencies.wasm-bindgen]
version = "0.2"
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(unix)".dependencies.iana-time-zone]
+version = "0.1.45"
+features = ["fallback"]
+optional = true
+
[target."cfg(windows)".dependencies.winapi]
version = "0.3.0"
-features = ["std", "minwinbase", "minwindef", "timezoneapi"]
+features = [
+ "std",
+ "minwinbase",
+ "minwindef",
+ "timezoneapi",
+]
optional = true
-[badges.appveyor]
-repository = "chronotope/chrono"
-
-[badges.travis-ci]
-repository = "chronotope/chrono"
diff --git a/vendor/chrono/Makefile b/vendor/chrono/Makefile
new file mode 100644
index 000000000..63aef15ac
--- /dev/null
+++ b/vendor/chrono/Makefile
@@ -0,0 +1,26 @@
+# this Makefile is mostly for the packaging convenience.
+# casual users should use `cargo` to retrieve the appropriate version of Chrono.
+
+CHANNEL=stable
+
+.PHONY: all
+all:
+ @echo 'Try `cargo build` instead.'
+
+.PHONY: authors
+authors:
+ echo 'Chrono is mainly written by Kang Seonghoon <public+rust@mearie.org>,' > AUTHORS.txt
+ echo 'and also the following people (in ascending order):' >> AUTHORS.txt
+ echo >> AUTHORS.txt
+ git log --format='%aN <%aE>' | grep -v 'Kang Seonghoon' | sort -u >> AUTHORS.txt
+
+.PHONY: readme README.md
+readme: README.md
+
+.PHONY: test
+test:
+ CHANNEL=$(CHANNEL) ./ci/travis.sh
+
+.PHONY: doc
+doc: authors readme
+ cargo doc --features 'serde rustc-serialize bincode'
diff --git a/vendor/chrono/README.md b/vendor/chrono/README.md
index 5a5a74b42..ad9591889 100644
--- a/vendor/chrono/README.md
+++ b/vendor/chrono/README.md
@@ -6,7 +6,7 @@
[![Chrono on docs.rs][docsrs-image]][docsrs]
[![Join the chat at https://gitter.im/chrono-rs/chrono][gitter-image]][gitter]
-[gh-image]: https://github.com/chronotope/chrono/workflows/test/badge.svg
+[gh-image]: https://github.com/chronotope/chrono/actions/workflows/test.yml/badge.svg
[gh-checks]: https://github.com/chronotope/chrono/actions?query=workflow%3Atest
[cratesio-image]: https://img.shields.io/crates/v/chrono.svg
[cratesio]: https://crates.io/crates/chrono
@@ -31,365 +31,6 @@ which Chrono builds upon and should acknowledge:
* Dietrich Epp's [datetime-rs](https://github.com/depp/datetime-rs)
* Luis de Bethencourt's [rust-datetime](https://github.com/luisbg/rust-datetime)
-Any significant changes to Chrono are documented in
-the [`CHANGELOG.md`](https://github.com/chronotope/chrono/blob/main/CHANGELOG.md) file.
-
-
-## Usage
-
-Put this in your `Cargo.toml`:
-
-```toml
-[dependencies]
-chrono = "0.4"
-```
-
-### Features
-
-Chrono supports various runtime environments and operating systems, and has
-several features that may be enabled or disabled.
-
-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`), independent of whether
- `std::time::SystemTime` is present, depends on having a libc.
-
-Optional features:
-
-- `wasmbind`: Enable integration with [wasm-bindgen][] and its `js-sys` project
-- [`serde`][]: Enable serialization/deserialization via serde.
-- `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.
-
-[`serde`]: https://github.com/serde-rs/serde
-[wasm-bindgen]: https://github.com/rustwasm/wasm-bindgen
-
-See the [cargo docs][] for examples of specifying features.
-
-[cargo docs]: https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#choosing-features
-
-## Overview
-
-### Duration
-
-Chrono currently uses its own [`Duration`] type to represent the magnitude
-of a time span. Since this has the same name as the newer, standard type for
-duration, the reference will refer this type as `OldDuration`.
-
-Note that this is an "accurate" duration represented as seconds and
-nanoseconds and does not represent "nominal" components such as days or
-months.
-
-When the `oldtime` feature is enabled, [`Duration`] is an alias for the
-[`time::Duration`](https://docs.rs/time/0.1.40/time/struct.Duration.html)
-type from v0.1 of the time crate. time v0.1 is deprecated, so new code
-should disable the `oldtime` feature and use the `chrono::Duration` type
-instead. The `oldtime` feature is enabled by default for backwards
-compatibility, but future versions of Chrono are likely to remove the
-feature entirely.
-
-Chrono does not yet natively support
-the standard [`Duration`](https://doc.rust-lang.org/std/time/struct.Duration.html) type,
-but it will be supported in the future.
-Meanwhile you can convert between two types with
-[`Duration::from_std`](https://docs.rs/time/0.1.40/time/struct.Duration.html#method.from_std)
-and
-[`Duration::to_std`](https://docs.rs/time/0.1.40/time/struct.Duration.html#method.to_std)
-methods.
-
-### Date and Time
-
-Chrono provides a
-[**`DateTime`**](https://docs.rs/chrono/0.4/chrono/struct.DateTime.html)
-type to represent a date and a time in a timezone.
-
-For more abstract moment-in-time tracking such as internal timekeeping
-that is unconcerned with timezones, consider
-[`time::SystemTime`](https://doc.rust-lang.org/std/time/struct.SystemTime.html),
-which tracks your system clock, or
-[`time::Instant`](https://doc.rust-lang.org/std/time/struct.Instant.html), which
-is an opaque but monotonically-increasing representation of a moment in time.
-
-`DateTime` is timezone-aware and must be constructed from
-the [**`TimeZone`**](https://docs.rs/chrono/0.4/chrono/offset/trait.TimeZone.html) object,
-which defines how the local date is converted to and back from the UTC date.
-There are three well-known `TimeZone` implementations:
-
-* [**`Utc`**](https://docs.rs/chrono/0.4/chrono/offset/struct.Utc.html) specifies the UTC time zone. It is most efficient.
-
-* [**`Local`**](https://docs.rs/chrono/0.4/chrono/offset/struct.Local.html) specifies the system local time zone.
-
-* [**`FixedOffset`**](https://docs.rs/chrono/0.4/chrono/offset/struct.FixedOffset.html) specifies
- an arbitrary, fixed time zone such as UTC+09:00 or UTC-10:30.
- This often results from the parsed textual date and time.
- Since it stores the most information and does not depend on the system environment,
- you would want to normalize other `TimeZone`s into this type.
-
-`DateTime`s with different `TimeZone` types are distinct and do not mix,
-but can be converted to each other using
-the [`DateTime::with_timezone`](https://docs.rs/chrono/0.4/chrono/struct.DateTime.html#method.with_timezone) method.
-
-You can get the current date and time in the UTC time zone
-([`Utc::now()`](https://docs.rs/chrono/0.4/chrono/offset/struct.Utc.html#method.now))
-or in the local time zone
-([`Local::now()`](https://docs.rs/chrono/0.4/chrono/offset/struct.Local.html#method.now)).
-
-```rust
-use chrono::prelude::*;
-
-let utc: DateTime<Utc> = Utc::now(); // e.g. `2014-11-28T12:45:59.324310806Z`
-let local: DateTime<Local> = Local::now(); // e.g. `2014-11-28T21:45:59.324310806+09:00`
-```
-
-Alternatively, you can create your own date and time.
-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
-use chrono::prelude::*;
-use chrono::offset::LocalResult;
-
-let dt = Utc.ymd(2014, 7, 8).and_hms(9, 10, 11); // `2014-07-08T09:10:11Z`
-// July 8 is 188th day of the year 2014 (`o` for "ordinal")
-assert_eq!(dt, Utc.yo(2014, 189).and_hms(9, 10, 11));
-// July 8 is Tuesday in ISO week 28 of the year 2014.
-assert_eq!(dt, Utc.isoywd(2014, 28, Weekday::Tue).and_hms(9, 10, 11));
-
-let dt = Utc.ymd(2014, 7, 8).and_hms_milli(9, 10, 11, 12); // `2014-07-08T09:10:11.012Z`
-assert_eq!(dt, Utc.ymd(2014, 7, 8).and_hms_micro(9, 10, 11, 12_000));
-assert_eq!(dt, Utc.ymd(2014, 7, 8).and_hms_nano(9, 10, 11, 12_000_000));
-
-// dynamic verification
-assert_eq!(Utc.ymd_opt(2014, 7, 8).and_hms_opt(21, 15, 33),
- LocalResult::Single(Utc.ymd(2014, 7, 8).and_hms(21, 15, 33)));
-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);
-
-// 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.
-let local_dt = Local.ymd(2014, 7, 8).and_hms_milli(9, 10, 11, 12);
-let fixed_dt = FixedOffset::east(9 * 3600).ymd(2014, 7, 8).and_hms_milli(18, 10, 11, 12);
-assert_eq!(dt, fixed_dt);
-```
-
-Various properties are available to the date and time, and can be altered individually.
-Most of them are defined in the traits [`Datelike`](https://docs.rs/chrono/0.4/chrono/trait.Datelike.html) and
-[`Timelike`](https://docs.rs/chrono/0.4/chrono/trait.Timelike.html) which you should `use` before.
-Addition and subtraction is also supported.
-The following illustrates most supported operations to the date and time:
-
-```rust
-
-use chrono::prelude::*;
-use chrono::Duration;
-
-// assume this returned `2014-11-28T21:45:59.324310806+09:00`:
-let dt = FixedOffset::east(9*3600).ymd(2014, 11, 28).and_hms_nano(21, 45, 59, 324310806);
-
-// property accessors
-assert_eq!((dt.year(), dt.month(), dt.day()), (2014, 11, 28));
-assert_eq!((dt.month0(), dt.day0()), (10, 27)); // for unfortunate souls
-assert_eq!((dt.hour(), dt.minute(), dt.second()), (21, 45, 59));
-assert_eq!(dt.weekday(), Weekday::Fri);
-assert_eq!(dt.weekday().number_from_monday(), 5); // Mon=1, ..., Sun=7
-assert_eq!(dt.ordinal(), 332); // the day of year
-assert_eq!(dt.num_days_from_ce(), 735565); // the number of days from and including Jan 1, 1
-
-// time zone accessor and manipulation
-assert_eq!(dt.offset().fix().local_minus_utc(), 9 * 3600);
-assert_eq!(dt.timezone(), FixedOffset::east(9 * 3600));
-assert_eq!(dt.with_timezone(&Utc), Utc.ymd(2014, 11, 28).and_hms_nano(12, 45, 59, 324310806));
-
-// a sample of property manipulations (validates dynamically)
-assert_eq!(dt.with_day(29).unwrap().weekday(), Weekday::Sat); // 2014-11-29 is Saturday
-assert_eq!(dt.with_day(32), None);
-assert_eq!(dt.with_year(-300).unwrap().num_days_from_ce(), -109606); // November 29, 301 BCE
-
-// arithmetic operations
-let dt1 = Utc.ymd(2014, 11, 14).and_hms(8, 9, 10);
-let dt2 = Utc.ymd(2014, 11, 14).and_hms(10, 9, 8);
-assert_eq!(dt1.signed_duration_since(dt2), Duration::seconds(-2 * 3600 + 2));
-assert_eq!(dt2.signed_duration_since(dt1), Duration::seconds(2 * 3600 - 2));
-assert_eq!(Utc.ymd(1970, 1, 1).and_hms(0, 0, 0) + Duration::seconds(1_000_000_000),
- Utc.ymd(2001, 9, 9).and_hms(1, 46, 40));
-assert_eq!(Utc.ymd(1970, 1, 1).and_hms(0, 0, 0) - Duration::seconds(1_000_000_000),
- Utc.ymd(1938, 4, 24).and_hms(22, 13, 20));
-```
-
-### Formatting and Parsing
-
-Formatting is done via the [`format`](https://docs.rs/chrono/0.4/chrono/struct.DateTime.html#method.format) method,
-which format is equivalent to the familiar `strftime` format.
-
-See [`format::strftime`](https://docs.rs/chrono/0.4/chrono/format/strftime/index.html#specifiers)
-documentation for full syntax and list of specifiers.
-
-The default `to_string` method and `{:?}` specifier also give a reasonable representation.
-Chrono also provides [`to_rfc2822`](https://docs.rs/chrono/0.4/chrono/struct.DateTime.html#method.to_rfc2822) and
-[`to_rfc3339`](https://docs.rs/chrono/0.4/chrono/struct.DateTime.html#method.to_rfc3339) methods
-for well-known formats.
-
-Chrono now also provides date formatting in almost any language without the
-help of an additional C library. This functionality is under the feature
-`unstable-locales`:
-
-```text
-chrono { version = "0.4", features = ["unstable-locales"]
-```
-
-The `unstable-locales` feature requires and implies at least the `alloc` feature.
-
-```rust
-use chrono::prelude::*;
-
-let dt = Utc.ymd(2014, 11, 28).and_hms(12, 0, 9);
-assert_eq!(dt.format("%Y-%m-%d %H:%M:%S").to_string(), "2014-11-28 12:00:09");
-assert_eq!(dt.format("%a %b %e %T %Y").to_string(), "Fri Nov 28 12:00:09 2014");
-assert_eq!(dt.format_localized("%A %e %B %Y, %T", Locale::fr_BE).to_string(), "vendredi 28 novembre 2014, 12:00:09");
-assert_eq!(dt.format("%a %b %e %T %Y").to_string(), dt.format("%c").to_string());
-
-assert_eq!(dt.to_string(), "2014-11-28 12:00:09 UTC");
-assert_eq!(dt.to_rfc2822(), "Fri, 28 Nov 2014 12:00:09 +0000");
-assert_eq!(dt.to_rfc3339(), "2014-11-28T12:00:09+00:00");
-assert_eq!(format!("{:?}", dt), "2014-11-28T12:00:09Z");
-
-// Note that milli/nanoseconds are only printed if they are non-zero
-let dt_nano = Utc.ymd(2014, 11, 28).and_hms_nano(12, 0, 9, 1);
-assert_eq!(format!("{:?}", dt_nano), "2014-11-28T12:00:09.000000001Z");
-```
-
-Parsing can be done with three methods:
-
-1. The standard [`FromStr`](https://doc.rust-lang.org/std/str/trait.FromStr.html) trait
- (and [`parse`](https://doc.rust-lang.org/std/primitive.str.html#method.parse) method
- on a string) can be used for parsing `DateTime<FixedOffset>`, `DateTime<Utc>` and
- `DateTime<Local>` values. This parses what the `{:?}`
- ([`std::fmt::Debug`](https://doc.rust-lang.org/std/fmt/trait.Debug.html))
- format specifier prints, and requires the offset to be present.
-
-2. [`DateTime::parse_from_str`](https://docs.rs/chrono/0.4/chrono/struct.DateTime.html#method.parse_from_str) parses
- a date and time with offsets and returns `DateTime<FixedOffset>`.
- This should be used when the offset is a part of input and the caller cannot guess that.
- It *cannot* be used when the offset can be missing.
- [`DateTime::parse_from_rfc2822`](https://docs.rs/chrono/0.4/chrono/struct.DateTime.html#method.parse_from_rfc2822)
- and
- [`DateTime::parse_from_rfc3339`](https://docs.rs/chrono/0.4/chrono/struct.DateTime.html#method.parse_from_rfc3339)
- are similar but for well-known formats.
-
-3. [`Offset::datetime_from_str`](https://docs.rs/chrono/0.4/chrono/offset/trait.TimeZone.html#method.datetime_from_str) is
- similar but returns `DateTime` of given offset.
- When the explicit offset is missing from the input, it simply uses given offset.
- It issues an error when the input contains an explicit offset different
- from the current offset.
-
-More detailed control over the parsing process is available via
-[`format`](https://docs.rs/chrono/0.4/chrono/format/index.html) module.
-
-```rust
-use chrono::prelude::*;
-
-let dt = Utc.ymd(2014, 11, 28).and_hms(12, 0, 9);
-let fixed_dt = dt.with_timezone(&FixedOffset::east(9*3600));
-
-// method 1
-assert_eq!("2014-11-28T12:00:09Z".parse::<DateTime<Utc>>(), Ok(dt.clone()));
-assert_eq!("2014-11-28T21:00:09+09:00".parse::<DateTime<Utc>>(), Ok(dt.clone()));
-assert_eq!("2014-11-28T21:00:09+09:00".parse::<DateTime<FixedOffset>>(), Ok(fixed_dt.clone()));
-
-// method 2
-assert_eq!(DateTime::parse_from_str("2014-11-28 21:00:09 +09:00", "%Y-%m-%d %H:%M:%S %z"),
- Ok(fixed_dt.clone()));
-assert_eq!(DateTime::parse_from_rfc2822("Fri, 28 Nov 2014 21:00:09 +0900"),
- Ok(fixed_dt.clone()));
-assert_eq!(DateTime::parse_from_rfc3339("2014-11-28T21:00:09+09:00"), Ok(fixed_dt.clone()));
-
-// method 3
-assert_eq!(Utc.datetime_from_str("2014-11-28 12:00:09", "%Y-%m-%d %H:%M:%S"), Ok(dt.clone()));
-assert_eq!(Utc.datetime_from_str("Fri Nov 28 12:00:09 2014", "%a %b %e %T %Y"), Ok(dt.clone()));
-
-// oops, the year is missing!
-assert!(Utc.datetime_from_str("Fri Nov 28 12:00:09", "%a %b %e %T %Y").is_err());
-// oops, the format string does not include the year at all!
-assert!(Utc.datetime_from_str("Fri Nov 28 12:00:09", "%a %b %e %T").is_err());
-// oops, the weekday is incorrect!
-assert!(Utc.datetime_from_str("Sat Nov 28 12:00:09 2014", "%a %b %e %T %Y").is_err());
-```
-
-Again : See [`format::strftime`](https://docs.rs/chrono/0.4/chrono/format/strftime/index.html#specifiers)
-documentation for full syntax and list of specifiers.
-
-### Conversion from and to EPOCH timestamps
-
-Use [`Utc.timestamp(seconds, nanoseconds)`](https://docs.rs/chrono/0.4/chrono/offset/trait.TimeZone.html#method.timestamp)
-to construct a [`DateTime<Utc>`](https://docs.rs/chrono/0.4/chrono/struct.DateTime.html) from a UNIX timestamp
-(seconds, nanoseconds that passed since January 1st 1970).
-
-Use [`DateTime.timestamp`](https://docs.rs/chrono/0.4/chrono/struct.DateTime.html#method.timestamp) to get the timestamp (in seconds)
-from a [`DateTime`](https://docs.rs/chrono/0.4/chrono/struct.DateTime.html). Additionally, you can use
-[`DateTime.timestamp_subsec_nanos`](https://docs.rs/chrono/0.4/chrono/struct.DateTime.html#method.timestamp_subsec_nanos)
-to get the number of additional number of nanoseconds.
-
-```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);
-assert_eq!(dt.to_rfc2822(), "Fri, 14 Jul 2017 02:40:00 +0000");
-
-// Get epoch value from a datetime:
-let dt = DateTime::parse_from_rfc2822("Fri, 14 Jul 2017 02:40:00 +0000").unwrap();
-assert_eq!(dt.timestamp(), 1_500_000_000);
-```
-
-### Individual date
-
-Chrono also provides an individual date type ([**`Date`**](https://docs.rs/chrono/0.4/chrono/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;
-
-assert_eq!(Utc::today(), Utc::now().date());
-assert_eq!(Local::today(), Local::now().date());
-
-assert_eq!(Utc.ymd(2014, 11, 28).weekday(), Weekday::Fri);
-assert_eq!(Utc.ymd_opt(2014, 11, 31), LocalResult::None);
-assert_eq!(Utc.ymd(2014, 11, 28).and_hms_milli(7, 8, 9, 10).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`](https://docs.rs/chrono/0.4/chrono/struct.DateTime.html#method.date) method
-which returns a `Date` which represents its date component.
-There is also a [`time`](https://docs.rs/chrono/0.4/chrono/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`
-as [**`NaiveDate`**](https://docs.rs/chrono/0.4/chrono/naive/struct.NaiveDate.html),
-[**`NaiveTime`**](https://docs.rs/chrono/0.4/chrono/naive/struct.NaiveTime.html) and
-[**`NaiveDateTime`**](https://docs.rs/chrono/0.4/chrono/naive/struct.NaiveDateTime.html) respectively.
-
-They have almost equivalent interfaces as their timezone-aware twins,
-but are not associated to time zones obviously and can be quite low-level.
-They are mostly useful for building blocks for higher-level types.
-
-Timezone-aware `DateTime` and `Date` types have two methods returning naive versions:
-[`naive_local`](https://docs.rs/chrono/0.4/chrono/struct.DateTime.html#method.naive_local) returns
-a view to the naive local time,
-and [`naive_utc`](https://docs.rs/chrono/0.4/chrono/struct.DateTime.html#method.naive_utc) returns
-a view to the naive UTC time.
-
## Limitations
Only proleptic Gregorian calendar (i.e. extended to support older dates) is supported.
@@ -408,7 +49,7 @@ if you want.
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(2014, 1, 30).with_month(2)` returns `None`.
+and consequently `Utc.ymd_opt(2014, 1, 30).unwrap().with_month(2)` returns `None`.
Non ISO week handling is not yet supported.
For now you can use the [chrono_ext](https://crates.io/crates/chrono_ext)
@@ -416,4 +57,3 @@ crate ([sources](https://github.com/bcourtine/chrono-ext/)).
Advanced time zone handling is not yet supported.
For now you can try the [Chrono-tz](https://github.com/chronotope/chrono-tz/) crate instead.
-
diff --git a/vendor/chrono/appveyor.yml b/vendor/chrono/appveyor.yml
new file mode 100644
index 000000000..6057e851e
--- /dev/null
+++ b/vendor/chrono/appveyor.yml
@@ -0,0 +1,12 @@
+# TODO: delete this without breaking all PRs
+environment:
+ matrix:
+ - TARGET: nightly-i686-pc-windows-gnu
+matrix:
+ allow_failures:
+ - channel: nightly
+
+build: false
+
+test_script:
+ - echo "stub"
diff --git a/vendor/chrono/benches/chrono.rs b/vendor/chrono/benches/chrono.rs
index 1c640634a..246271b81 100644
--- a/vendor/chrono/benches/chrono.rs
+++ b/vendor/chrono/benches/chrono.rs
@@ -1,12 +1,10 @@
//! Benchmarks for chrono that just depend on std
-
-extern crate chrono;
-extern crate criterion;
+#![cfg(feature = "__internal_bench")]
use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion};
use chrono::prelude::*;
-use chrono::{DateTime, FixedOffset, Utc, __BenchYearFlags};
+use chrono::{DateTime, FixedOffset, Local, Utc, __BenchYearFlags};
fn bench_datetime_parse_from_rfc2822(c: &mut Criterion) {
c.bench_function("bench_datetime_parse_from_rfc2822", |b| {
@@ -37,14 +35,28 @@ fn bench_datetime_from_str(c: &mut Criterion) {
}
fn bench_datetime_to_rfc2822(c: &mut Criterion) {
- let pst = FixedOffset::east(8 * 60 * 60);
- let dt = pst.ymd(2018, 1, 11).and_hms_nano(10, 5, 13, 084_660_000);
+ let pst = FixedOffset::east_opt(8 * 60 * 60).unwrap();
+ let dt = pst
+ .from_local_datetime(
+ &NaiveDate::from_ymd_opt(2018, 1, 11)
+ .unwrap()
+ .and_hms_nano_opt(10, 5, 13, 84_660_000)
+ .unwrap(),
+ )
+ .unwrap();
c.bench_function("bench_datetime_to_rfc2822", |b| b.iter(|| black_box(dt).to_rfc2822()));
}
fn bench_datetime_to_rfc3339(c: &mut Criterion) {
- let pst = FixedOffset::east(8 * 60 * 60);
- let dt = pst.ymd(2018, 1, 11).and_hms_nano(10, 5, 13, 084_660_000);
+ let pst = FixedOffset::east_opt(8 * 60 * 60).unwrap();
+ let dt = pst
+ .from_local_datetime(
+ &NaiveDate::from_ymd_opt(2018, 1, 11)
+ .unwrap()
+ .and_hms_nano_opt(10, 5, 13, 84_660_000)
+ .unwrap(),
+ )
+ .unwrap();
c.bench_function("bench_datetime_to_rfc3339", |b| b.iter(|| black_box(dt).to_rfc3339()));
}
@@ -58,6 +70,14 @@ fn bench_year_flags_from_year(c: &mut Criterion) {
});
}
+fn bench_get_local_time(c: &mut Criterion) {
+ c.bench_function("bench_get_local_time", |b| {
+ b.iter(|| {
+ let _ = Local::now();
+ })
+ });
+}
+
/// Returns the number of multiples of `div` in the range `start..end`.
///
/// If the range `start..end` is back-to-front, i.e. `start` is greater than `end`, the
@@ -92,7 +112,7 @@ fn num_days_from_ce_alt<Date: Datelike>(date: &Date) -> i32 {
fn bench_num_days_from_ce(c: &mut Criterion) {
let mut group = c.benchmark_group("num_days_from_ce");
for year in &[1, 500, 2000, 2019] {
- let d = NaiveDate::from_ymd(*year, 1, 1);
+ let d = NaiveDate::from_ymd_opt(*year, 1, 1).unwrap();
group.bench_with_input(BenchmarkId::new("new", year), &d, |b, y| {
b.iter(|| num_days_from_ce_alt(y))
});
@@ -111,6 +131,7 @@ criterion_group!(
bench_datetime_to_rfc3339,
bench_year_flags_from_year,
bench_num_days_from_ce,
+ bench_get_local_time,
);
criterion_main!(benches);
diff --git a/vendor/chrono/benches/serde.rs b/vendor/chrono/benches/serde.rs
index 860b06e1a..e9de4408e 100644
--- a/vendor/chrono/benches/serde.rs
+++ b/vendor/chrono/benches/serde.rs
@@ -1,5 +1,4 @@
-extern crate chrono;
-extern crate criterion;
+#![cfg(feature = "__internal_bench")]
use criterion::{black_box, criterion_group, criterion_main, Criterion};
diff --git a/vendor/chrono/clippy.toml b/vendor/chrono/clippy.toml
new file mode 100644
index 000000000..749c3b58a
--- /dev/null
+++ b/vendor/chrono/clippy.toml
@@ -0,0 +1 @@
+msrv = "1.38"
diff --git a/vendor/chrono/deny.toml b/vendor/chrono/deny.toml
new file mode 100644
index 000000000..13b9fac5f
--- /dev/null
+++ b/vendor/chrono/deny.toml
@@ -0,0 +1,13 @@
+[licenses]
+allow-osi-fsf-free = "either"
+copyleft = "deny"
+
+[advisories]
+ignore = [
+ "RUSTSEC-2020-0071", # time 0.1, doesn't affect the API we use
+ "RUSTSEC-2021-0145", # atty (dev-deps only, dependency of criterion)
+ "RUSTSEC-2022-0004", # rustc_serialize, cannot remove due to compatibility
+]
+unmaintained = "deny"
+unsound = "deny"
+yanked = "deny"
diff --git a/vendor/chrono/src/date.rs b/vendor/chrono/src/date.rs
index 0012d3604..bad4bfbb8 100644
--- a/vendor/chrono/src/date.rs
+++ b/vendor/chrono/src/date.rs
@@ -2,57 +2,74 @@
// See README.md and LICENSE.txt for details.
//! ISO 8601 calendar date with time zone.
+#![allow(deprecated)]
#[cfg(any(feature = "alloc", feature = "std", test))]
use core::borrow::Borrow;
use core::cmp::Ordering;
-use core::ops::{Add, Sub};
+use core::ops::{Add, AddAssign, Sub, SubAssign};
use core::{fmt, hash};
-use oldtime::Duration as OldDuration;
+
+#[cfg(feature = "rkyv")]
+use rkyv::{Archive, Deserialize, Serialize};
#[cfg(feature = "unstable-locales")]
-use format::Locale;
+use crate::format::Locale;
#[cfg(any(feature = "alloc", feature = "std", test))]
-use format::{DelayedFormat, Item, StrftimeItems};
-use naive::{self, IsoWeek, NaiveDate, NaiveTime};
-use offset::{TimeZone, Utc};
-use DateTime;
-use {Datelike, Weekday};
+use crate::format::{DelayedFormat, Item, StrftimeItems};
+use crate::naive::{IsoWeek, NaiveDate, NaiveTime};
+use crate::offset::{TimeZone, Utc};
+use crate::oldtime::Duration as OldDuration;
+use crate::DateTime;
+use crate::{Datelike, Weekday};
/// ISO 8601 calendar date with time zone.
///
-/// This type should be considered ambiguous at best,
-/// due to the inherent lack of precision required for the time zone resolution.
-/// For serialization and deserialization uses, it is best to use `NaiveDate` instead.
+/// You almost certainly want to be using a [`NaiveDate`] instead of this type.
+///
+/// This type primarily exists to aid in the construction of DateTimes that
+/// have a timezone by way of the [`TimeZone`] datelike constructors (e.g.
+/// [`TimeZone::ymd`]).
+///
+/// This type should be considered ambiguous at best, due to the inherent lack
+/// of precision required for the time zone resolution.
+///
/// There are some guarantees on the usage of `Date<Tz>`:
///
-/// - If properly constructed via `TimeZone::ymd` and others without an error,
+/// - If properly constructed via [`TimeZone::ymd`] and others without an error,
/// the corresponding local date should exist for at least a moment.
/// (It may still have a gap from the offset changes.)
///
-/// - The `TimeZone` is free to assign *any* `Offset` to the local date,
-/// as long as that offset did occur in given day.
+/// - The `TimeZone` is free to assign *any* [`Offset`](crate::offset::Offset) to the
+/// local date, as long as that offset did occur in given day.
+///
/// For example, if `2015-03-08T01:59-08:00` is followed by `2015-03-08T03:00-07:00`,
/// it may produce either `2015-03-08-08:00` or `2015-03-08-07:00`
/// but *not* `2015-03-08+00:00` and others.
///
-/// - Once constructed as a full `DateTime`,
-/// `DateTime::date` and other associated methods should return those for the original `Date`.
-/// For example, if `dt = tz.ymd(y,m,d).hms(h,n,s)` were valid, `dt.date() == tz.ymd(y,m,d)`.
+/// - Once constructed as a full `DateTime`, [`DateTime::date`] and other associated
+/// methods should return those for the original `Date`. For example, if `dt =
+/// tz.ymd_opt(y,m,d).unwrap().hms(h,n,s)` were valid, `dt.date() == tz.ymd_opt(y,m,d).unwrap()`.
///
/// - The date is timezone-agnostic up to one day (i.e. practically always),
/// so the local date and UTC date should be equal for most cases
/// even though the raw calculation between `NaiveDate` and `Duration` may not.
+#[deprecated(since = "0.4.23", note = "Use `NaiveDate` or `DateTime<Tz>` instead")]
#[derive(Clone)]
+#[cfg_attr(feature = "rkyv", derive(Archive, Deserialize, Serialize))]
pub struct Date<Tz: TimeZone> {
date: NaiveDate,
offset: Tz::Offset,
}
/// The minimum possible `Date`.
-pub const MIN_DATE: Date<Utc> = Date { date: naive::MIN_DATE, offset: Utc };
+#[allow(deprecated)]
+#[deprecated(since = "0.4.20", note = "Use Date::MIN_UTC instead")]
+pub const MIN_DATE: Date<Utc> = Date::<Utc>::MIN_UTC;
/// The maximum possible `Date`.
-pub const MAX_DATE: Date<Utc> = Date { date: naive::MAX_DATE, offset: Utc };
+#[allow(deprecated)]
+#[deprecated(since = "0.4.20", note = "Use Date::MAX_UTC instead")]
+pub const MAX_DATE: Date<Utc> = Date::<Utc>::MAX_UTC;
impl<Tz: TimeZone> Date<Tz> {
/// Makes a new `Date` with given *UTC* date and offset.
@@ -61,7 +78,7 @@ impl<Tz: TimeZone> Date<Tz> {
// note: this constructor is purposely not named to `new` to discourage the direct usage.
#[inline]
pub fn from_utc(date: NaiveDate, offset: Tz::Offset) -> Date<Tz> {
- Date { date: date, offset: offset }
+ Date { date, offset }
}
/// Makes a new `DateTime` from the current date and given `NaiveTime`.
@@ -78,6 +95,7 @@ impl<Tz: TimeZone> Date<Tz> {
/// The offset in the current date is preserved.
///
/// Panics on invalid hour, minute and/or second.
+ #[deprecated(since = "0.4.23", note = "Use and_hms_opt() instead")]
#[inline]
pub fn and_hms(&self, hour: u32, min: u32, sec: u32) -> DateTime<Tz> {
self.and_hms_opt(hour, min, sec).expect("invalid time")
@@ -97,6 +115,7 @@ impl<Tz: TimeZone> Date<Tz> {
/// The offset in the current date is preserved.
///
/// Panics on invalid hour, minute, second and/or millisecond.
+ #[deprecated(since = "0.4.23", note = "Use and_hms_milli_opt() instead")]
#[inline]
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")
@@ -123,6 +142,7 @@ impl<Tz: TimeZone> Date<Tz> {
/// The offset in the current date is preserved.
///
/// Panics on invalid hour, minute, second and/or microsecond.
+ #[deprecated(since = "0.4.23", note = "Use and_hms_micro_opt() instead")]
#[inline]
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")
@@ -149,6 +169,7 @@ impl<Tz: TimeZone> Date<Tz> {
/// The offset in the current date is preserved.
///
/// Panics on invalid hour, minute, second and/or nanosecond.
+ #[deprecated(since = "0.4.23", note = "Use and_hms_nano_opt() instead")]
#[inline]
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")
@@ -173,6 +194,7 @@ impl<Tz: TimeZone> Date<Tz> {
/// Makes a new `Date` for the next date.
///
/// Panics when `self` is the last representable date.
+ #[deprecated(since = "0.4.23", note = "Use succ_opt() instead")]
#[inline]
pub fn succ(&self) -> Date<Tz> {
self.succ_opt().expect("out of bound")
@@ -189,6 +211,7 @@ impl<Tz: TimeZone> Date<Tz> {
/// Makes a new `Date` for the prior date.
///
/// Panics when `self` is the first representable date.
+ #[deprecated(since = "0.4.23", note = "Use pred_opt() instead")]
#[inline]
pub fn pred(&self) -> Date<Tz> {
self.pred_opt().expect("out of bound")
@@ -226,8 +249,8 @@ impl<Tz: TimeZone> Date<Tz> {
/// Returns `None` when it will result in overflow.
#[inline]
pub fn checked_add_signed(self, rhs: OldDuration) -> Option<Date<Tz>> {
- let date = try_opt!(self.date.checked_add_signed(rhs));
- Some(Date { date: date, offset: self.offset })
+ let date = self.date.checked_add_signed(rhs)?;
+ Some(Date { date, offset: self.offset })
}
/// Subtracts given `Duration` from the current date.
@@ -235,8 +258,8 @@ impl<Tz: TimeZone> Date<Tz> {
/// Returns `None` when it will result in overflow.
#[inline]
pub fn checked_sub_signed(self, rhs: OldDuration) -> Option<Date<Tz>> {
- let date = try_opt!(self.date.checked_sub_signed(rhs));
- Some(Date { date: date, offset: self.offset })
+ let date = self.date.checked_sub_signed(rhs)?;
+ Some(Date { date, offset: self.offset })
}
/// Subtracts another `Date` from the current date.
@@ -264,6 +287,16 @@ impl<Tz: TimeZone> Date<Tz> {
pub fn naive_local(&self) -> NaiveDate {
self.date
}
+
+ /// Returns the number of whole years from the given `base` until `self`.
+ pub fn years_since(&self, base: Self) -> Option<u32> {
+ self.date.years_since(base.date)
+ }
+
+ /// The minimum possible `Date`.
+ pub const MIN_UTC: Date<Utc> = Date { date: NaiveDate::MIN, offset: Utc };
+ /// The maximum possible `Date`.
+ pub const MAX_UTC: Date<Utc> = Date { date: NaiveDate::MAX, offset: Utc };
}
/// Maps the local date to other date with given conversion function.
@@ -280,6 +313,7 @@ where
{
/// Formats the date with the specified formatting items.
#[cfg(any(feature = "alloc", feature = "std", test))]
+ #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))]
#[inline]
pub fn format_with_items<'a, I, B>(&self, items: I) -> DelayedFormat<I>
where
@@ -290,9 +324,10 @@ where
}
/// Formats the date with the specified format string.
- /// See the [`format::strftime` module](./format/strftime/index.html)
+ /// See the [`crate::format::strftime`] module
/// on the supported escape sequences.
#[cfg(any(feature = "alloc", feature = "std", test))]
+ #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))]
#[inline]
pub fn format<'a>(&self, fmt: &'a str) -> DelayedFormat<StrftimeItems<'a>> {
self.format_with_items(StrftimeItems::new(fmt))
@@ -300,6 +335,7 @@ where
/// Formats the date with the specified formatting items and locale.
#[cfg(feature = "unstable-locales")]
+ #[cfg_attr(docsrs, doc(cfg(feature = "unstable-locales")))]
#[inline]
pub fn format_localized_with_items<'a, I, B>(
&self,
@@ -320,9 +356,10 @@ where
}
/// Formats the date with the specified format string and locale.
- /// See the [`format::strftime` module](./format/strftime/index.html)
+ /// See the [`crate::format::strftime`] module
/// on the supported escape sequences.
#[cfg(feature = "unstable-locales")]
+ #[cfg_attr(docsrs, doc(cfg(feature = "unstable-locales")))]
#[inline]
pub fn format_localized<'a>(
&self,
@@ -446,6 +483,13 @@ impl<Tz: TimeZone> Add<OldDuration> for Date<Tz> {
}
}
+impl<Tz: TimeZone> AddAssign<OldDuration> for Date<Tz> {
+ #[inline]
+ fn add_assign(&mut self, rhs: OldDuration) {
+ self.date = self.date.checked_add_signed(rhs).expect("`Date + Duration` overflowed");
+ }
+}
+
impl<Tz: TimeZone> Sub<OldDuration> for Date<Tz> {
type Output = Date<Tz>;
@@ -455,6 +499,13 @@ impl<Tz: TimeZone> Sub<OldDuration> for Date<Tz> {
}
}
+impl<Tz: TimeZone> SubAssign<OldDuration> for Date<Tz> {
+ #[inline]
+ fn sub_assign(&mut self, rhs: OldDuration) {
+ self.date = self.date.checked_sub_signed(rhs).expect("`Date - Duration` overflowed");
+ }
+}
+
impl<Tz: TimeZone> Sub<Date<Tz>> for Date<Tz> {
type Output = OldDuration;
@@ -466,7 +517,8 @@ impl<Tz: TimeZone> Sub<Date<Tz>> for Date<Tz> {
impl<Tz: TimeZone> fmt::Debug for Date<Tz> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "{:?}{:?}", self.naive_local(), self.offset)
+ self.naive_local().fmt(f)?;
+ self.offset.fmt(f)
}
}
@@ -475,6 +527,119 @@ where
Tz::Offset: fmt::Display,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "{}{}", self.naive_local(), self.offset)
+ self.naive_local().fmt(f)?;
+ self.offset.fmt(f)
+ }
+}
+
+// Note that implementation of Arbitrary cannot be automatically derived for Date<Tz>, due to
+// the nontrivial bound <Tz as TimeZone>::Offset: Arbitrary.
+#[cfg(feature = "arbitrary")]
+impl<'a, Tz> arbitrary::Arbitrary<'a> for Date<Tz>
+where
+ Tz: TimeZone,
+ <Tz as TimeZone>::Offset: arbitrary::Arbitrary<'a>,
+{
+ fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Date<Tz>> {
+ let date = NaiveDate::arbitrary(u)?;
+ let offset = <Tz as TimeZone>::Offset::arbitrary(u)?;
+ Ok(Date::from_utc(date, offset))
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::Date;
+
+ use crate::oldtime::Duration;
+ use crate::{FixedOffset, NaiveDate, Utc};
+
+ #[cfg(feature = "clock")]
+ use crate::offset::{Local, TimeZone};
+
+ #[test]
+ #[cfg(feature = "clock")]
+ fn test_years_elapsed() {
+ const WEEKS_PER_YEAR: f32 = 52.1775;
+
+ // This is always at least one year because 1 year = 52.1775 weeks.
+ let one_year_ago = Utc::today() - Duration::weeks((WEEKS_PER_YEAR * 1.5).ceil() as i64);
+ // A bit more than 2 years.
+ let two_year_ago = Utc::today() - Duration::weeks((WEEKS_PER_YEAR * 2.5).ceil() as i64);
+
+ assert_eq!(Utc::today().years_since(one_year_ago), Some(1));
+ assert_eq!(Utc::today().years_since(two_year_ago), Some(2));
+
+ // If the given DateTime is later than now, the function will always return 0.
+ let future = Utc::today() + Duration::weeks(12);
+ assert_eq!(Utc::today().years_since(future), None);
+ }
+
+ #[test]
+ fn test_date_add_assign() {
+ let naivedate = NaiveDate::from_ymd_opt(2000, 1, 1).unwrap();
+ let date = Date::<Utc>::from_utc(naivedate, Utc);
+ let mut date_add = date;
+
+ date_add += Duration::days(5);
+ assert_eq!(date_add, date + Duration::days(5));
+
+ let timezone = FixedOffset::east_opt(60 * 60).unwrap();
+ let date = date.with_timezone(&timezone);
+ let date_add = date_add.with_timezone(&timezone);
+
+ assert_eq!(date_add, date + Duration::days(5));
+
+ let timezone = FixedOffset::west_opt(2 * 60 * 60).unwrap();
+ let date = date.with_timezone(&timezone);
+ let date_add = date_add.with_timezone(&timezone);
+
+ assert_eq!(date_add, date + Duration::days(5));
+ }
+
+ #[test]
+ #[cfg(feature = "clock")]
+ fn test_date_add_assign_local() {
+ let naivedate = NaiveDate::from_ymd_opt(2000, 1, 1).unwrap();
+
+ let date = Local.from_utc_date(&naivedate);
+ let mut date_add = date;
+
+ date_add += Duration::days(5);
+ assert_eq!(date_add, date + Duration::days(5));
+ }
+
+ #[test]
+ fn test_date_sub_assign() {
+ let naivedate = NaiveDate::from_ymd_opt(2000, 1, 1).unwrap();
+ let date = Date::<Utc>::from_utc(naivedate, Utc);
+ let mut date_sub = date;
+
+ date_sub -= Duration::days(5);
+ assert_eq!(date_sub, date - Duration::days(5));
+
+ let timezone = FixedOffset::east_opt(60 * 60).unwrap();
+ let date = date.with_timezone(&timezone);
+ let date_sub = date_sub.with_timezone(&timezone);
+
+ assert_eq!(date_sub, date - Duration::days(5));
+
+ let timezone = FixedOffset::west_opt(2 * 60 * 60).unwrap();
+ let date = date.with_timezone(&timezone);
+ let date_sub = date_sub.with_timezone(&timezone);
+
+ assert_eq!(date_sub, date - Duration::days(5));
+ }
+
+ #[test]
+ #[cfg(feature = "clock")]
+ fn test_date_sub_assign_local() {
+ let naivedate = NaiveDate::from_ymd_opt(2000, 1, 1).unwrap();
+
+ let date = Local.from_utc_date(&naivedate);
+ let mut date_sub = date;
+
+ date_sub -= Duration::days(5);
+ assert_eq!(date_sub, date - Duration::days(5));
}
}
diff --git a/vendor/chrono/src/datetime.rs b/vendor/chrono/src/datetime.rs
deleted file mode 100644
index ecd464250..000000000
--- a/vendor/chrono/src/datetime.rs
+++ /dev/null
@@ -1,2589 +0,0 @@
-// This is a part of Chrono.
-// See README.md and LICENSE.txt for details.
-
-//! ISO 8601 date and time with time zone.
-
-use core::cmp::Ordering;
-use core::ops::{Add, Sub};
-use core::{fmt, hash, str};
-use oldtime::Duration as OldDuration;
-#[cfg(any(feature = "std", test))]
-use std::time::{SystemTime, UNIX_EPOCH};
-
-#[cfg(all(not(feature = "std"), feature = "alloc"))]
-use alloc::string::{String, ToString};
-#[cfg(feature = "std")]
-use std::string::ToString;
-
-#[cfg(any(feature = "alloc", feature = "std", test))]
-use core::borrow::Borrow;
-#[cfg(any(feature = "alloc", feature = "std", test))]
-use format::DelayedFormat;
-#[cfg(feature = "unstable-locales")]
-use format::Locale;
-use format::{parse, ParseError, ParseResult, Parsed, StrftimeItems};
-use format::{Fixed, Item};
-use naive::{self, IsoWeek, NaiveDateTime, NaiveTime};
-#[cfg(feature = "clock")]
-use offset::Local;
-use offset::{FixedOffset, Offset, TimeZone, Utc};
-use Date;
-use {Datelike, Timelike, Weekday};
-
-/// Specific formatting options for seconds. This may be extended in the
-/// future, so exhaustive matching in external code is not recommended.
-///
-/// See the `TimeZone::to_rfc3339_opts` function for usage.
-#[derive(Clone, Copy, Debug, Eq, PartialEq)]
-pub enum SecondsFormat {
- /// Format whole seconds only, with no decimal point nor subseconds.
- Secs,
-
- /// Use fixed 3 subsecond digits. This corresponds to
- /// [Fixed::Nanosecond3](format/enum.Fixed.html#variant.Nanosecond3).
- Millis,
-
- /// Use fixed 6 subsecond digits. This corresponds to
- /// [Fixed::Nanosecond6](format/enum.Fixed.html#variant.Nanosecond6).
- Micros,
-
- /// Use fixed 9 subsecond digits. This corresponds to
- /// [Fixed::Nanosecond9](format/enum.Fixed.html#variant.Nanosecond9).
- Nanos,
-
- /// Automatically select one of `Secs`, `Millis`, `Micros`, or `Nanos` to
- /// display all available non-zero sub-second digits. This corresponds to
- /// [Fixed::Nanosecond](format/enum.Fixed.html#variant.Nanosecond).
- AutoSi,
-
- // Do not match against this.
- #[doc(hidden)]
- __NonExhaustive,
-}
-
-/// ISO 8601 combined date and time with time zone.
-///
-/// There are some constructors implemented here (the `from_*` methods), but
-/// the general-purpose constructors are all via the methods on the
-/// [`TimeZone`](./offset/trait.TimeZone.html) implementations.
-#[derive(Clone)]
-pub struct DateTime<Tz: TimeZone> {
- datetime: NaiveDateTime,
- offset: Tz::Offset,
-}
-
-/// The minimum possible `DateTime<Utc>`.
-pub const MIN_DATETIME: DateTime<Utc> = DateTime { datetime: naive::MIN_DATETIME, offset: Utc };
-/// The maximum possible `DateTime<Utc>`.
-pub const MAX_DATETIME: DateTime<Utc> = DateTime { datetime: naive::MAX_DATETIME, offset: Utc };
-
-impl<Tz: TimeZone> DateTime<Tz> {
- /// Makes a new `DateTime` with given *UTC* datetime and offset.
- /// The local datetime should be constructed via the `TimeZone` trait.
- ///
- /// # Example
- ///
- /// ~~~~
- /// use chrono::{DateTime, TimeZone, NaiveDateTime, Utc};
- ///
- /// let dt = DateTime::<Utc>::from_utc(NaiveDateTime::from_timestamp(61, 0), Utc);
- /// assert_eq!(Utc.timestamp(61, 0), dt);
- /// ~~~~
- //
- // note: this constructor is purposely not named to `new` to discourage the direct usage.
- #[inline]
- pub fn from_utc(datetime: NaiveDateTime, offset: Tz::Offset) -> DateTime<Tz> {
- DateTime { datetime: datetime, offset: offset }
- }
-
- /// Retrieves a date component.
- #[inline]
- pub fn date(&self) -> Date<Tz> {
- Date::from_utc(self.naive_local().date(), self.offset.clone())
- }
-
- /// Retrieves a time component.
- /// Unlike `date`, this is not associated to the time zone.
- #[inline]
- pub fn time(&self) -> NaiveTime {
- self.datetime.time() + self.offset.fix()
- }
-
- /// Returns the number of non-leap seconds since January 1, 1970 0:00:00 UTC
- /// (aka "UNIX timestamp").
- #[inline]
- pub fn timestamp(&self) -> i64 {
- self.datetime.timestamp()
- }
-
- /// Returns the number of non-leap-milliseconds since January 1, 1970 UTC
- ///
- /// Note that this does reduce the number of years that can be represented
- /// from ~584 Billion to ~584 Million. (If this is a problem, please file
- /// an issue to let me know what domain needs millisecond precision over
- /// billions of years, I'm curious.)
- ///
- /// # Example
- ///
- /// ~~~~
- /// use chrono::Utc;
- /// use chrono::TimeZone;
- ///
- /// let dt = Utc.ymd(1970, 1, 1).and_hms_milli(0, 0, 1, 444);
- /// assert_eq!(dt.timestamp_millis(), 1_444);
- ///
- /// let dt = Utc.ymd(2001, 9, 9).and_hms_milli(1, 46, 40, 555);
- /// assert_eq!(dt.timestamp_millis(), 1_000_000_000_555);
- /// ~~~~
- #[inline]
- pub fn timestamp_millis(&self) -> i64 {
- self.datetime.timestamp_millis()
- }
-
- /// Returns the number of non-leap-nanoseconds since January 1, 1970 UTC
- ///
- /// Note that this does reduce the number of years that can be represented
- /// from ~584 Billion to ~584. (If this is a problem, please file
- /// an issue to let me know what domain needs nanosecond precision over
- /// millennia, I'm curious.)
- ///
- /// # Example
- ///
- /// ~~~~
- /// use chrono::Utc;
- /// use chrono::TimeZone;
- ///
- /// let dt = Utc.ymd(1970, 1, 1).and_hms_nano(0, 0, 1, 444);
- /// assert_eq!(dt.timestamp_nanos(), 1_000_000_444);
- ///
- /// let dt = Utc.ymd(2001, 9, 9).and_hms_nano(1, 46, 40, 555);
- /// assert_eq!(dt.timestamp_nanos(), 1_000_000_000_000_000_555);
- /// ~~~~
- #[inline]
- pub fn timestamp_nanos(&self) -> i64 {
- self.datetime.timestamp_nanos()
- }
-
- /// Returns the number of milliseconds since the last second boundary
- ///
- /// warning: in event of a leap second, this may exceed 999
- ///
- /// note: this is not the number of milliseconds since January 1, 1970 0:00:00 UTC
- #[inline]
- pub fn timestamp_subsec_millis(&self) -> u32 {
- self.datetime.timestamp_subsec_millis()
- }
-
- /// Returns the number of microseconds since the last second boundary
- ///
- /// warning: in event of a leap second, this may exceed 999_999
- ///
- /// note: this is not the number of microseconds since January 1, 1970 0:00:00 UTC
- #[inline]
- pub fn timestamp_subsec_micros(&self) -> u32 {
- self.datetime.timestamp_subsec_micros()
- }
-
- /// Returns the number of nanoseconds since the last second boundary
- ///
- /// warning: in event of a leap second, this may exceed 999_999_999
- ///
- /// note: this is not the number of nanoseconds since January 1, 1970 0:00:00 UTC
- #[inline]
- pub fn timestamp_subsec_nanos(&self) -> u32 {
- self.datetime.timestamp_subsec_nanos()
- }
-
- /// Retrieves an associated offset from UTC.
- #[inline]
- pub fn offset(&self) -> &Tz::Offset {
- &self.offset
- }
-
- /// Retrieves an associated time zone.
- #[inline]
- pub fn timezone(&self) -> Tz {
- TimeZone::from_offset(&self.offset)
- }
-
- /// Changes the associated time zone.
- /// This does not change the actual `DateTime` (but will change the string representation).
- #[inline]
- pub fn with_timezone<Tz2: TimeZone>(&self, tz: &Tz2) -> DateTime<Tz2> {
- tz.from_utc_datetime(&self.datetime)
- }
-
- /// Adds given `Duration` to the current date and time.
- ///
- /// Returns `None` when it will result in overflow.
- #[inline]
- pub fn checked_add_signed(self, rhs: OldDuration) -> Option<DateTime<Tz>> {
- let datetime = try_opt!(self.datetime.checked_add_signed(rhs));
- let tz = self.timezone();
- Some(tz.from_utc_datetime(&datetime))
- }
-
- /// Subtracts given `Duration` from the current date and time.
- ///
- /// Returns `None` when it will result in overflow.
- #[inline]
- pub fn checked_sub_signed(self, rhs: OldDuration) -> Option<DateTime<Tz>> {
- let datetime = try_opt!(self.datetime.checked_sub_signed(rhs));
- let tz = self.timezone();
- Some(tz.from_utc_datetime(&datetime))
- }
-
- /// Subtracts another `DateTime` from the current date and time.
- /// This does not overflow or underflow at all.
- #[inline]
- 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]
- pub fn naive_utc(&self) -> NaiveDateTime {
- self.datetime
- }
-
- /// Returns a view to the naive local datetime.
- #[inline]
- pub fn naive_local(&self) -> NaiveDateTime {
- self.datetime + self.offset.fix()
- }
-}
-
-/// Convert a `DateTime<Utc>` instance into a `DateTime<FixedOffset>` instance.
-impl From<DateTime<Utc>> for DateTime<FixedOffset> {
- /// Convert this `DateTime<Utc>` instance into a `DateTime<FixedOffset>` instance.
- ///
- /// Conversion is done via [`DateTime::with_timezone`]. Note that the converted value returned by
- /// this will be created with a fixed timezone offset of 0.
- fn from(src: DateTime<Utc>) -> Self {
- src.with_timezone(&FixedOffset::east(0))
- }
-}
-
-/// Convert a `DateTime<Utc>` instance into a `DateTime<Local>` instance.
-#[cfg(feature = "clock")]
-impl From<DateTime<Utc>> for DateTime<Local> {
- /// Convert this `DateTime<Utc>` instance into a `DateTime<Local>` instance.
- ///
- /// Conversion is performed via [`DateTime::with_timezone`], accounting for the difference in timezones.
- fn from(src: DateTime<Utc>) -> Self {
- src.with_timezone(&Local)
- }
-}
-
-/// Convert a `DateTime<FixedOffset>` instance into a `DateTime<Utc>` instance.
-impl From<DateTime<FixedOffset>> for DateTime<Utc> {
- /// Convert this `DateTime<FixedOffset>` instance into a `DateTime<Utc>` instance.
- ///
- /// Conversion is performed via [`DateTime::with_timezone`], accounting for the timezone
- /// difference.
- fn from(src: DateTime<FixedOffset>) -> Self {
- src.with_timezone(&Utc)
- }
-}
-
-/// Convert a `DateTime<FixedOffset>` instance into a `DateTime<Local>` instance.
-#[cfg(feature = "clock")]
-impl From<DateTime<FixedOffset>> for DateTime<Local> {
- /// Convert this `DateTime<FixedOffset>` instance into a `DateTime<Local>` instance.
- ///
- /// Conversion is performed via [`DateTime::with_timezone`]. Returns the equivalent value in local
- /// time.
- fn from(src: DateTime<FixedOffset>) -> Self {
- src.with_timezone(&Local)
- }
-}
-
-/// Convert a `DateTime<Local>` instance into a `DateTime<Utc>` instance.
-#[cfg(feature = "clock")]
-impl From<DateTime<Local>> for DateTime<Utc> {
- /// Convert this `DateTime<Local>` instance into a `DateTime<Utc>` instance.
- ///
- /// Conversion is performed via [`DateTime::with_timezone`], accounting for the difference in
- /// timezones.
- fn from(src: DateTime<Local>) -> Self {
- src.with_timezone(&Utc)
- }
-}
-
-/// Convert a `DateTime<Local>` instance into a `DateTime<FixedOffset>` instance.
-#[cfg(feature = "clock")]
-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.
- fn from(src: DateTime<Local>) -> Self {
- src.with_timezone(&FixedOffset::east(0))
- }
-}
-
-/// Maps the local datetime to other datetime with given conversion function.
-fn map_local<Tz: TimeZone, F>(dt: &DateTime<Tz>, mut f: F) -> Option<DateTime<Tz>>
-where
- F: FnMut(NaiveDateTime) -> Option<NaiveDateTime>,
-{
- f(dt.naive_local()).and_then(|datetime| dt.timezone().from_local_datetime(&datetime).single())
-}
-
-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`.
- ///
- /// RFC 2822 is the internet message standard that specifices the
- /// representation of times in HTTP and email headers.
- ///
- /// ```
- /// # use chrono::{DateTime, FixedOffset, TimeZone};
- /// assert_eq!(
- /// DateTime::parse_from_rfc2822("Wed, 18 Feb 2015 23:16:09 GMT").unwrap(),
- /// FixedOffset::east(0).ymd(2015, 2, 18).and_hms(23, 16, 9)
- /// );
- /// ```
- pub fn parse_from_rfc2822(s: &str) -> ParseResult<DateTime<FixedOffset>> {
- const ITEMS: &'static [Item<'static>] = &[Item::Fixed(Fixed::RFC2822)];
- let mut parsed = Parsed::new();
- parse(&mut parsed, s, ITEMS.iter())?;
- 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`.
- ///
- /// 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.
- pub fn parse_from_rfc3339(s: &str) -> ParseResult<DateTime<FixedOffset>> {
- const ITEMS: &'static [Item<'static>] = &[Item::Fixed(Fixed::RFC3339)];
- let mut parsed = Parsed::new();
- parse(&mut parsed, s, ITEMS.iter())?;
- parsed.to_datetime()
- }
-
- /// Parses a string with the specified format string and
- /// returns a new `DateTime` with a parsed `FixedOffset`.
- /// See the [`format::strftime` module](./format/strftime/index.html)
- /// on the supported escape sequences.
- ///
- /// See also `Offset::datetime_from_str` which gives a local `DateTime` on specific time zone.
- ///
- /// Note that this method *requires a timezone* in the 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.
- ///
- /// # Example
- ///
- /// ```rust
- /// use chrono::{DateTime, FixedOffset, TimeZone};
- ///
- /// let dt = DateTime::parse_from_str(
- /// "1983 Apr 13 12:09:14.274 +0000", "%Y %b %d %H:%M:%S%.3f %z");
- /// assert_eq!(dt, Ok(FixedOffset::east(0).ymd(1983, 4, 13).and_hms_milli(12, 9, 14, 274)));
- /// ```
- pub fn parse_from_str(s: &str, fmt: &str) -> ParseResult<DateTime<FixedOffset>> {
- let mut parsed = Parsed::new();
- parse(&mut parsed, s, StrftimeItems::new(fmt))?;
- parsed.to_datetime()
- }
-}
-
-impl<Tz: TimeZone> DateTime<Tz>
-where
- Tz::Offset: fmt::Display,
-{
- /// 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))]
- pub fn to_rfc2822(&self) -> String {
- const ITEMS: &'static [Item<'static>] = &[Item::Fixed(Fixed::RFC2822)];
- self.format_with_items(ITEMS.iter()).to_string()
- }
-
- /// 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))]
- pub fn to_rfc3339(&self) -> String {
- const ITEMS: &'static [Item<'static>] = &[Item::Fixed(Fixed::RFC3339)];
- self.format_with_items(ITEMS.iter()).to_string()
- }
-
- /// Return an RFC 3339 and ISO 8601 date and time string with subseconds
- /// formatted as per a `SecondsFormat`. If passed `use_z` true and the
- /// timezone is UTC (offset 0), use 'Z', as per
- /// [Fixed::TimezoneOffsetColonZ](format/enum.Fixed.html#variant.TimezoneOffsetColonZ).
- /// If passed `use_z` false, use
- /// [Fixed::TimezoneOffsetColon](format/enum.Fixed.html#variant.TimezoneOffsetColon).
- ///
- /// # Examples
- ///
- /// ```rust
- /// # use chrono::{DateTime, FixedOffset, SecondsFormat, TimeZone, Utc};
- /// let dt = Utc.ymd(2018, 1, 26).and_hms_micro(18, 30, 9, 453_829);
- /// assert_eq!(dt.to_rfc3339_opts(SecondsFormat::Millis, false),
- /// "2018-01-26T18:30:09.453+00:00");
- /// assert_eq!(dt.to_rfc3339_opts(SecondsFormat::Millis, true),
- /// "2018-01-26T18:30:09.453Z");
- /// assert_eq!(dt.to_rfc3339_opts(SecondsFormat::Secs, true),
- /// "2018-01-26T18:30:09Z");
- ///
- /// let pst = FixedOffset::east(8 * 60 * 60);
- /// let dt = pst.ymd(2018, 1, 26).and_hms_micro(10, 30, 9, 453_829);
- /// assert_eq!(dt.to_rfc3339_opts(SecondsFormat::Secs, true),
- /// "2018-01-26T10:30:09+08:00");
- /// ```
- #[cfg(any(feature = "alloc", feature = "std", test))]
- pub fn to_rfc3339_opts(&self, secform: SecondsFormat, use_z: bool) -> String {
- use format::Numeric::*;
- use format::Pad::Zero;
- use SecondsFormat::*;
-
- debug_assert!(secform != __NonExhaustive, "Do not use __NonExhaustive!");
-
- const PREFIX: &'static [Item<'static>] = &[
- Item::Numeric(Year, Zero),
- Item::Literal("-"),
- Item::Numeric(Month, Zero),
- Item::Literal("-"),
- Item::Numeric(Day, Zero),
- Item::Literal("T"),
- Item::Numeric(Hour, Zero),
- Item::Literal(":"),
- Item::Numeric(Minute, Zero),
- Item::Literal(":"),
- Item::Numeric(Second, Zero),
- ];
-
- let ssitem = match secform {
- Secs => None,
- Millis => Some(Item::Fixed(Fixed::Nanosecond3)),
- Micros => Some(Item::Fixed(Fixed::Nanosecond6)),
- Nanos => Some(Item::Fixed(Fixed::Nanosecond9)),
- AutoSi => Some(Item::Fixed(Fixed::Nanosecond)),
- __NonExhaustive => unreachable!(),
- };
-
- let tzitem = Item::Fixed(if use_z {
- Fixed::TimezoneOffsetColonZ
- } else {
- Fixed::TimezoneOffsetColon
- });
-
- match ssitem {
- None => self.format_with_items(PREFIX.iter().chain([tzitem].iter())).to_string(),
- Some(s) => self.format_with_items(PREFIX.iter().chain([s, tzitem].iter())).to_string(),
- }
- }
-
- /// Formats the combined date and time with the specified formatting items.
- #[cfg(any(feature = "alloc", feature = "std", test))]
- #[inline]
- pub fn format_with_items<'a, I, B>(&self, items: I) -> DelayedFormat<I>
- where
- I: Iterator<Item = B> + Clone,
- B: Borrow<Item<'a>>,
- {
- let local = self.naive_local();
- 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 [`format::strftime` module](./format/strftime/index.html)
- /// on the supported escape sequences.
- #[cfg(any(feature = "alloc", feature = "std", test))]
- #[inline]
- pub fn format<'a>(&self, fmt: &'a str) -> DelayedFormat<StrftimeItems<'a>> {
- self.format_with_items(StrftimeItems::new(fmt))
- }
-
- /// Formats the combined date and time with the specified formatting items and locale.
- #[cfg(feature = "unstable-locales")]
- #[inline]
- pub fn format_localized_with_items<'a, I, B>(
- &self,
- items: I,
- locale: Locale,
- ) -> DelayedFormat<I>
- where
- I: Iterator<Item = B> + Clone,
- B: Borrow<Item<'a>>,
- {
- let local = self.naive_local();
- DelayedFormat::new_with_offset_and_locale(
- Some(local.date()),
- Some(local.time()),
- &self.offset,
- items,
- locale,
- )
- }
-
- /// Formats the combined date and time with the specified format string and locale.
- /// See the [`format::strftime` module](./format/strftime/index.html)
- /// on the supported escape sequences.
- #[cfg(feature = "unstable-locales")]
- #[inline]
- pub fn format_localized<'a>(
- &self,
- fmt: &'a str,
- locale: Locale,
- ) -> DelayedFormat<StrftimeItems<'a>> {
- self.format_localized_with_items(StrftimeItems::new_with_locale(fmt, locale), locale)
- }
-}
-
-impl<Tz: TimeZone> Datelike for DateTime<Tz> {
- #[inline]
- fn year(&self) -> i32 {
- self.naive_local().year()
- }
- #[inline]
- fn month(&self) -> u32 {
- self.naive_local().month()
- }
- #[inline]
- fn month0(&self) -> u32 {
- self.naive_local().month0()
- }
- #[inline]
- fn day(&self) -> u32 {
- self.naive_local().day()
- }
- #[inline]
- fn day0(&self) -> u32 {
- self.naive_local().day0()
- }
- #[inline]
- fn ordinal(&self) -> u32 {
- self.naive_local().ordinal()
- }
- #[inline]
- fn ordinal0(&self) -> u32 {
- self.naive_local().ordinal0()
- }
- #[inline]
- fn weekday(&self) -> Weekday {
- self.naive_local().weekday()
- }
- #[inline]
- fn iso_week(&self) -> IsoWeek {
- self.naive_local().iso_week()
- }
-
- #[inline]
- fn with_year(&self, year: i32) -> Option<DateTime<Tz>> {
- map_local(self, |datetime| datetime.with_year(year))
- }
-
- #[inline]
- fn with_month(&self, month: u32) -> Option<DateTime<Tz>> {
- map_local(self, |datetime| datetime.with_month(month))
- }
-
- #[inline]
- fn with_month0(&self, month0: u32) -> Option<DateTime<Tz>> {
- map_local(self, |datetime| datetime.with_month0(month0))
- }
-
- #[inline]
- fn with_day(&self, day: u32) -> Option<DateTime<Tz>> {
- map_local(self, |datetime| datetime.with_day(day))
- }
-
- #[inline]
- fn with_day0(&self, day0: u32) -> Option<DateTime<Tz>> {
- map_local(self, |datetime| datetime.with_day0(day0))
- }
-
- #[inline]
- fn with_ordinal(&self, ordinal: u32) -> Option<DateTime<Tz>> {
- map_local(self, |datetime| datetime.with_ordinal(ordinal))
- }
-
- #[inline]
- fn with_ordinal0(&self, ordinal0: u32) -> Option<DateTime<Tz>> {
- map_local(self, |datetime| datetime.with_ordinal0(ordinal0))
- }
-}
-
-impl<Tz: TimeZone> Timelike for DateTime<Tz> {
- #[inline]
- fn hour(&self) -> u32 {
- self.naive_local().hour()
- }
- #[inline]
- fn minute(&self) -> u32 {
- self.naive_local().minute()
- }
- #[inline]
- fn second(&self) -> u32 {
- self.naive_local().second()
- }
- #[inline]
- fn nanosecond(&self) -> u32 {
- self.naive_local().nanosecond()
- }
-
- #[inline]
- fn with_hour(&self, hour: u32) -> Option<DateTime<Tz>> {
- map_local(self, |datetime| datetime.with_hour(hour))
- }
-
- #[inline]
- fn with_minute(&self, min: u32) -> Option<DateTime<Tz>> {
- map_local(self, |datetime| datetime.with_minute(min))
- }
-
- #[inline]
- fn with_second(&self, sec: u32) -> Option<DateTime<Tz>> {
- map_local(self, |datetime| datetime.with_second(sec))
- }
-
- #[inline]
- fn with_nanosecond(&self, nano: u32) -> Option<DateTime<Tz>> {
- map_local(self, |datetime| datetime.with_nanosecond(nano))
- }
-}
-
-// we need them as automatic impls cannot handle associated types
-impl<Tz: TimeZone> Copy for DateTime<Tz> where <Tz as TimeZone>::Offset: Copy {}
-unsafe impl<Tz: TimeZone> Send for DateTime<Tz> where <Tz as TimeZone>::Offset: Send {}
-
-impl<Tz: TimeZone, Tz2: TimeZone> PartialEq<DateTime<Tz2>> for DateTime<Tz> {
- fn eq(&self, other: &DateTime<Tz2>) -> bool {
- self.datetime == other.datetime
- }
-}
-
-impl<Tz: TimeZone> Eq for DateTime<Tz> {}
-
-impl<Tz: TimeZone, Tz2: TimeZone> PartialOrd<DateTime<Tz2>> for DateTime<Tz> {
- /// Compare two DateTimes based on their true time, ignoring time zones
- ///
- /// # Example
- ///
- /// ```
- /// use chrono::prelude::*;
- ///
- /// let earlier = Utc.ymd(2015, 5, 15).and_hms(2, 0, 0).with_timezone(&FixedOffset::west(1 * 3600));
- /// let later = Utc.ymd(2015, 5, 15).and_hms(3, 0, 0).with_timezone(&FixedOffset::west(5 * 3600));
- ///
- /// assert_eq!(earlier.to_string(), "2015-05-15 01:00:00 -01:00");
- /// assert_eq!(later.to_string(), "2015-05-14 22:00:00 -05:00");
- ///
- /// assert!(later > earlier);
- /// ```
- fn partial_cmp(&self, other: &DateTime<Tz2>) -> Option<Ordering> {
- self.datetime.partial_cmp(&other.datetime)
- }
-}
-
-impl<Tz: TimeZone> Ord for DateTime<Tz> {
- fn cmp(&self, other: &DateTime<Tz>) -> Ordering {
- self.datetime.cmp(&other.datetime)
- }
-}
-
-impl<Tz: TimeZone> hash::Hash for DateTime<Tz> {
- fn hash<H: hash::Hasher>(&self, state: &mut H) {
- self.datetime.hash(state)
- }
-}
-
-impl<Tz: TimeZone> Add<OldDuration> for DateTime<Tz> {
- type Output = DateTime<Tz>;
-
- #[inline]
- fn add(self, rhs: OldDuration) -> DateTime<Tz> {
- self.checked_add_signed(rhs).expect("`DateTime + Duration` overflowed")
- }
-}
-
-impl<Tz: TimeZone> Sub<OldDuration> for DateTime<Tz> {
- type Output = DateTime<Tz>;
-
- #[inline]
- fn sub(self, rhs: OldDuration) -> DateTime<Tz> {
- self.checked_sub_signed(rhs).expect("`DateTime - Duration` overflowed")
- }
-}
-
-impl<Tz: TimeZone> Sub<DateTime<Tz>> for DateTime<Tz> {
- type Output = OldDuration;
-
- #[inline]
- fn sub(self, rhs: DateTime<Tz>) -> OldDuration {
- self.signed_duration_since(rhs)
- }
-}
-
-impl<Tz: TimeZone> fmt::Debug for DateTime<Tz> {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "{:?}{:?}", self.naive_local(), self.offset)
- }
-}
-
-impl<Tz: TimeZone> fmt::Display for DateTime<Tz>
-where
- Tz::Offset: fmt::Display,
-{
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "{} {}", self.naive_local(), self.offset)
- }
-}
-
-impl str::FromStr for DateTime<Utc> {
- type Err = ParseError;
-
- fn from_str(s: &str) -> ParseResult<DateTime<Utc>> {
- s.parse::<DateTime<FixedOffset>>().map(|dt| dt.with_timezone(&Utc))
- }
-}
-
-#[cfg(feature = "clock")]
-impl str::FromStr for DateTime<Local> {
- type Err = ParseError;
-
- fn from_str(s: &str) -> ParseResult<DateTime<Local>> {
- s.parse::<DateTime<FixedOffset>>().map(|dt| dt.with_timezone(&Local))
- }
-}
-
-#[cfg(any(feature = "std", test))]
-impl From<SystemTime> for DateTime<Utc> {
- fn from(t: SystemTime) -> DateTime<Utc> {
- let (sec, nsec) = match t.duration_since(UNIX_EPOCH) {
- Ok(dur) => (dur.as_secs() as i64, dur.subsec_nanos()),
- Err(e) => {
- // unlikely but should be handled
- let dur = e.duration();
- let (sec, nsec) = (dur.as_secs() as i64, dur.subsec_nanos());
- if nsec == 0 {
- (-sec, 0)
- } else {
- (-sec - 1, 1_000_000_000 - nsec)
- }
- }
- };
- Utc.timestamp(sec, nsec)
- }
-}
-
-#[cfg(feature = "clock")]
-impl From<SystemTime> for DateTime<Local> {
- fn from(t: SystemTime) -> DateTime<Local> {
- DateTime::<Utc>::from(t).with_timezone(&Local)
- }
-}
-
-#[cfg(any(feature = "std", test))]
-impl<Tz: TimeZone> From<DateTime<Tz>> for SystemTime {
- fn from(dt: DateTime<Tz>) -> SystemTime {
- use std::time::Duration;
-
- let sec = dt.timestamp();
- let nsec = dt.timestamp_subsec_nanos();
- if sec < 0 {
- // unlikely but should be handled
- UNIX_EPOCH - Duration::new(-sec as u64, 0) + Duration::new(0, nsec)
- } else {
- UNIX_EPOCH + Duration::new(sec as u64, nsec)
- }
- }
-}
-
-#[cfg(all(target_arch = "wasm32", not(target_os = "wasi"), feature = "wasmbind"))]
-impl From<js_sys::Date> for DateTime<Utc> {
- fn from(date: js_sys::Date) -> DateTime<Utc> {
- DateTime::<Utc>::from(&date)
- }
-}
-
-#[cfg(all(target_arch = "wasm32", not(target_os = "wasi"), feature = "wasmbind"))]
-impl From<&js_sys::Date> for DateTime<Utc> {
- fn from(date: &js_sys::Date) -> DateTime<Utc> {
- let millisecs_since_unix_epoch: u64 = date.get_time() as u64;
- let secs = millisecs_since_unix_epoch / 1000;
- let nanos = 1_000_000 * (millisecs_since_unix_epoch % 1000);
- let naive = NaiveDateTime::from_timestamp(secs as i64, nanos as u32);
- DateTime::from_utc(naive, Utc)
- }
-}
-
-#[cfg(all(target_arch = "wasm32", not(target_os = "wasi"), feature = "wasmbind"))]
-impl From<DateTime<Utc>> for js_sys::Date {
- fn from(date: DateTime<Utc>) -> js_sys::Date {
- let js_date = js_sys::Date::new_0();
-
- js_date.set_utc_full_year_with_month_date(
- date.year() as u32,
- date.month0() as i32,
- date.day() as i32,
- );
-
- js_date.set_utc_hours(date.hour());
- js_date.set_utc_minutes(date.minute());
- js_date.set_utc_seconds(date.second());
-
- js_date
- }
-}
-
-#[test]
-fn test_auto_conversion() {
- let utc_dt = Utc.ymd(2018, 9, 5).and_hms(23, 58, 0);
- let cdt_dt = FixedOffset::west(5 * 60 * 60).ymd(2018, 9, 5).and_hms(18, 58, 0);
- let utc_dt2: DateTime<Utc> = cdt_dt.into();
- assert_eq!(utc_dt, utc_dt2);
-}
-
-#[cfg(all(test, any(feature = "rustc-serialize", feature = "serde")))]
-fn test_encodable_json<FUtc, FFixed, E>(to_string_utc: FUtc, to_string_fixed: FFixed)
-where
- FUtc: Fn(&DateTime<Utc>) -> Result<String, E>,
- FFixed: Fn(&DateTime<FixedOffset>) -> Result<String, E>,
- E: ::core::fmt::Debug,
-{
- assert_eq!(
- to_string_utc(&Utc.ymd(2014, 7, 24).and_hms(12, 34, 6)).ok(),
- Some(r#""2014-07-24T12:34:06Z""#.into())
- );
-
- assert_eq!(
- to_string_fixed(&FixedOffset::east(3660).ymd(2014, 7, 24).and_hms(12, 34, 6)).ok(),
- Some(r#""2014-07-24T12:34:06+01:01""#.into())
- );
- assert_eq!(
- to_string_fixed(&FixedOffset::east(3650).ymd(2014, 7, 24).and_hms(12, 34, 6)).ok(),
- Some(r#""2014-07-24T12:34:06+01:00:50""#.into())
- );
-}
-
-#[cfg(all(test, feature = "clock", any(feature = "rustc-serialize", feature = "serde")))]
-fn test_decodable_json<FUtc, FFixed, FLocal, E>(
- utc_from_str: FUtc,
- fixed_from_str: FFixed,
- local_from_str: FLocal,
-) where
- FUtc: Fn(&str) -> Result<DateTime<Utc>, E>,
- FFixed: Fn(&str) -> Result<DateTime<FixedOffset>, E>,
- FLocal: Fn(&str) -> Result<DateTime<Local>, E>,
- E: ::core::fmt::Debug,
-{
- // should check against the offset as well (the normal DateTime comparison will ignore them)
- fn norm<Tz: TimeZone>(dt: &Option<DateTime<Tz>>) -> Option<(&DateTime<Tz>, &Tz::Offset)> {
- dt.as_ref().map(|dt| (dt, dt.offset()))
- }
-
- assert_eq!(
- norm(&utc_from_str(r#""2014-07-24T12:34:06Z""#).ok()),
- norm(&Some(Utc.ymd(2014, 7, 24).and_hms(12, 34, 6)))
- );
- assert_eq!(
- norm(&utc_from_str(r#""2014-07-24T13:57:06+01:23""#).ok()),
- norm(&Some(Utc.ymd(2014, 7, 24).and_hms(12, 34, 6)))
- );
-
- assert_eq!(
- norm(&fixed_from_str(r#""2014-07-24T12:34:06Z""#).ok()),
- norm(&Some(FixedOffset::east(0).ymd(2014, 7, 24).and_hms(12, 34, 6)))
- );
- assert_eq!(
- norm(&fixed_from_str(r#""2014-07-24T13:57:06+01:23""#).ok()),
- norm(&Some(FixedOffset::east(60 * 60 + 23 * 60).ymd(2014, 7, 24).and_hms(13, 57, 6)))
- );
-
- // we don't know the exact local offset but we can check that
- // the conversion didn't change the instant itself
- assert_eq!(
- local_from_str(r#""2014-07-24T12:34:06Z""#).expect("local shouuld parse"),
- Utc.ymd(2014, 7, 24).and_hms(12, 34, 6)
- );
- assert_eq!(
- local_from_str(r#""2014-07-24T13:57:06+01:23""#).expect("local should parse with offset"),
- Utc.ymd(2014, 7, 24).and_hms(12, 34, 6)
- );
-
- assert!(utc_from_str(r#""2014-07-32T12:34:06Z""#).is_err());
- assert!(fixed_from_str(r#""2014-07-32T12:34:06Z""#).is_err());
-}
-
-#[cfg(all(test, feature = "clock", feature = "rustc-serialize"))]
-fn test_decodable_json_timestamps<FUtc, FFixed, FLocal, E>(
- utc_from_str: FUtc,
- fixed_from_str: FFixed,
- local_from_str: FLocal,
-) where
- FUtc: Fn(&str) -> Result<rustc_serialize::TsSeconds<Utc>, E>,
- FFixed: Fn(&str) -> Result<rustc_serialize::TsSeconds<FixedOffset>, E>,
- FLocal: Fn(&str) -> Result<rustc_serialize::TsSeconds<Local>, E>,
- E: ::core::fmt::Debug,
-{
- fn norm<Tz: TimeZone>(dt: &Option<DateTime<Tz>>) -> Option<(&DateTime<Tz>, &Tz::Offset)> {
- dt.as_ref().map(|dt| (dt, dt.offset()))
- }
-
- assert_eq!(
- norm(&utc_from_str("0").ok().map(DateTime::from)),
- norm(&Some(Utc.ymd(1970, 1, 1).and_hms(0, 0, 0)))
- );
- assert_eq!(
- norm(&utc_from_str("-1").ok().map(DateTime::from)),
- norm(&Some(Utc.ymd(1969, 12, 31).and_hms(23, 59, 59)))
- );
-
- assert_eq!(
- norm(&fixed_from_str("0").ok().map(DateTime::from)),
- norm(&Some(FixedOffset::east(0).ymd(1970, 1, 1).and_hms(0, 0, 0)))
- );
- assert_eq!(
- norm(&fixed_from_str("-1").ok().map(DateTime::from)),
- norm(&Some(FixedOffset::east(0).ymd(1969, 12, 31).and_hms(23, 59, 59)))
- );
-
- assert_eq!(
- *fixed_from_str("0").expect("0 timestamp should parse"),
- Utc.ymd(1970, 1, 1).and_hms(0, 0, 0)
- );
- assert_eq!(
- *local_from_str("-1").expect("-1 timestamp should parse"),
- Utc.ymd(1969, 12, 31).and_hms(23, 59, 59)
- );
-}
-
-#[cfg(feature = "rustc-serialize")]
-pub mod rustc_serialize {
- use super::DateTime;
- use core::fmt;
- use core::ops::Deref;
- #[cfg(feature = "clock")]
- use offset::Local;
- use offset::{FixedOffset, LocalResult, TimeZone, Utc};
- use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
-
- impl<Tz: TimeZone> Encodable for DateTime<Tz> {
- fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
- format!("{:?}", self).encode(s)
- }
- }
-
- // lik? function to convert a LocalResult into a serde-ish Result
- fn from<T, D>(me: LocalResult<T>, d: &mut D) -> Result<T, D::Error>
- where
- D: Decoder,
- T: fmt::Display,
- {
- match me {
- LocalResult::None => Err(d.error("value is not a legal timestamp")),
- LocalResult::Ambiguous(..) => Err(d.error("value is an ambiguous timestamp")),
- LocalResult::Single(val) => Ok(val),
- }
- }
-
- impl Decodable for DateTime<FixedOffset> {
- fn decode<D: Decoder>(d: &mut D) -> Result<DateTime<FixedOffset>, D::Error> {
- d.read_str()?
- .parse::<DateTime<FixedOffset>>()
- .map_err(|_| d.error("invalid date and time"))
- }
- }
-
- #[allow(deprecated)]
- impl Decodable for TsSeconds<FixedOffset> {
- #[allow(deprecated)]
- fn decode<D: Decoder>(d: &mut D) -> Result<TsSeconds<FixedOffset>, D::Error> {
- from(FixedOffset::east(0).timestamp_opt(d.read_i64()?, 0), d).map(TsSeconds)
- }
- }
-
- impl Decodable for DateTime<Utc> {
- fn decode<D: Decoder>(d: &mut D) -> Result<DateTime<Utc>, D::Error> {
- d.read_str()?
- .parse::<DateTime<FixedOffset>>()
- .map(|dt| dt.with_timezone(&Utc))
- .map_err(|_| d.error("invalid date and time"))
- }
- }
-
- /// A `DateTime` that can be deserialized from a timestamp
- ///
- /// A timestamp here is seconds since the epoch
- #[derive(Debug)]
- pub struct TsSeconds<Tz: TimeZone>(DateTime<Tz>);
-
- #[allow(deprecated)]
- impl<Tz: TimeZone> From<TsSeconds<Tz>> for DateTime<Tz> {
- /// Pull the inner DateTime<Tz> out
- #[allow(deprecated)]
- fn from(obj: TsSeconds<Tz>) -> DateTime<Tz> {
- obj.0
- }
- }
-
- #[allow(deprecated)]
- impl<Tz: TimeZone> Deref for TsSeconds<Tz> {
- type Target = DateTime<Tz>;
-
- fn deref(&self) -> &Self::Target {
- &self.0
- }
- }
-
- #[allow(deprecated)]
- impl Decodable for TsSeconds<Utc> {
- fn decode<D: Decoder>(d: &mut D) -> Result<TsSeconds<Utc>, D::Error> {
- from(Utc.timestamp_opt(d.read_i64()?, 0), d).map(TsSeconds)
- }
- }
-
- #[cfg(feature = "clock")]
- impl Decodable for DateTime<Local> {
- fn decode<D: Decoder>(d: &mut D) -> Result<DateTime<Local>, D::Error> {
- match d.read_str()?.parse::<DateTime<FixedOffset>>() {
- Ok(dt) => Ok(dt.with_timezone(&Local)),
- Err(_) => Err(d.error("invalid date and time")),
- }
- }
- }
-
- #[cfg(feature = "clock")]
- #[allow(deprecated)]
- impl Decodable for TsSeconds<Local> {
- #[allow(deprecated)]
- fn decode<D: Decoder>(d: &mut D) -> Result<TsSeconds<Local>, D::Error> {
- from(Utc.timestamp_opt(d.read_i64()?, 0), d)
- .map(|dt| TsSeconds(dt.with_timezone(&Local)))
- }
- }
-
- #[cfg(test)]
- use rustc_serialize::json;
-
- #[test]
- fn test_encodable() {
- super::test_encodable_json(json::encode, json::encode);
- }
-
- #[cfg(feature = "clock")]
- #[test]
- fn test_decodable() {
- super::test_decodable_json(json::decode, json::decode, json::decode);
- }
-
- #[cfg(feature = "clock")]
- #[test]
- fn test_decodable_timestamps() {
- super::test_decodable_json_timestamps(json::decode, json::decode, json::decode);
- }
-}
-
-/// documented at re-export site
-#[cfg(feature = "serde")]
-pub mod serde {
- use super::DateTime;
- use core::fmt;
- #[cfg(feature = "clock")]
- use offset::Local;
- use offset::{FixedOffset, LocalResult, TimeZone, Utc};
- use serdelib::{de, ser};
- use {ne_timestamp, SerdeError};
-
- #[doc(hidden)]
- #[derive(Debug)]
- pub struct SecondsTimestampVisitor;
-
- #[doc(hidden)]
- #[derive(Debug)]
- pub struct NanoSecondsTimestampVisitor;
-
- #[doc(hidden)]
- #[derive(Debug)]
- pub struct MilliSecondsTimestampVisitor;
-
- // lik? function to convert a LocalResult into a serde-ish Result
- fn serde_from<T, E, V>(me: LocalResult<T>, ts: &V) -> Result<T, E>
- where
- E: de::Error,
- V: fmt::Display,
- T: fmt::Display,
- {
- match me {
- LocalResult::None => Err(E::custom(ne_timestamp(ts))),
- LocalResult::Ambiguous(min, max) => {
- Err(E::custom(SerdeError::Ambiguous { timestamp: ts, min: min, max: max }))
- }
- LocalResult::Single(val) => Ok(val),
- }
- }
-
- /// Ser/de to/from timestamps in nanoseconds
- ///
- /// Intended for use with `serde`'s `with` attribute.
- ///
- /// # Example:
- ///
- /// ```rust
- /// # // We mark this ignored so that we can test on 1.13 (which does not
- /// # // support custom derive), and run tests with --ignored on beta and
- /// # // nightly to actually trigger these.
- /// #
- /// # #[macro_use] extern crate serde_derive;
- /// # #[macro_use] extern crate serde_json;
- /// # extern crate chrono;
- /// # use chrono::{TimeZone, DateTime, Utc};
- /// use chrono::serde::ts_nanoseconds;
- /// #[derive(Deserialize, Serialize)]
- /// struct S {
- /// #[serde(with = "ts_nanoseconds")]
- /// time: DateTime<Utc>
- /// }
- ///
- /// # fn example() -> Result<S, serde_json::Error> {
- /// let time = Utc.ymd(2018, 5, 17).and_hms_nano(02, 04, 59, 918355733);
- /// let my_s = S {
- /// time: time.clone(),
- /// };
- ///
- /// let as_string = serde_json::to_string(&my_s)?;
- /// assert_eq!(as_string, r#"{"time":1526522699918355733}"#);
- /// let my_s: S = serde_json::from_str(&as_string)?;
- /// assert_eq!(my_s.time, time);
- /// # Ok(my_s)
- /// # }
- /// # fn main() { example().unwrap(); }
- /// ```
- pub mod ts_nanoseconds {
- use core::fmt;
- use serdelib::{de, ser};
-
- use offset::TimeZone;
- use {DateTime, Utc};
-
- use super::{serde_from, NanoSecondsTimestampVisitor};
-
- /// Serialize a UTC datetime into an integer number of nanoseconds since the epoch
- ///
- /// Intended for use with `serde`s `serialize_with` attribute.
- ///
- /// # Example:
- ///
- /// ```rust
- /// # // We mark this ignored so that we can test on 1.13 (which does not
- /// # // support custom derive), and run tests with --ignored on beta and
- /// # // nightly to actually trigger these.
- /// #
- /// # #[macro_use] extern crate serde_derive;
- /// # #[macro_use] extern crate serde_json;
- /// # extern crate chrono;
- /// # use chrono::{TimeZone, DateTime, Utc};
- /// use chrono::serde::ts_nanoseconds::serialize as to_nano_ts;
- /// #[derive(Serialize)]
- /// struct S {
- /// #[serde(serialize_with = "to_nano_ts")]
- /// time: DateTime<Utc>
- /// }
- ///
- /// # fn example() -> Result<String, serde_json::Error> {
- /// let my_s = S {
- /// time: Utc.ymd(2018, 5, 17).and_hms_nano(02, 04, 59, 918355733),
- /// };
- /// let as_string = serde_json::to_string(&my_s)?;
- /// assert_eq!(as_string, r#"{"time":1526522699918355733}"#);
- /// # Ok(as_string)
- /// # }
- /// # fn main() { example().unwrap(); }
- /// ```
- pub fn serialize<S>(dt: &DateTime<Utc>, serializer: S) -> Result<S::Ok, S::Error>
- where
- S: ser::Serializer,
- {
- serializer.serialize_i64(dt.timestamp_nanos())
- }
-
- /// Deserialize a `DateTime` from a nanosecond timestamp
- ///
- /// Intended for use with `serde`s `deserialize_with` attribute.
- ///
- /// # Example:
- ///
- /// ```rust
- /// # // We mark this ignored so that we can test on 1.13 (which does not
- /// # // support custom derive), and run tests with --ignored on beta and
- /// # // nightly to actually trigger these.
- /// #
- /// # #[macro_use] extern crate serde_derive;
- /// # #[macro_use] extern crate serde_json;
- /// # extern crate chrono;
- /// # use chrono::{DateTime, Utc};
- /// use chrono::serde::ts_nanoseconds::deserialize as from_nano_ts;
- /// #[derive(Deserialize)]
- /// struct S {
- /// #[serde(deserialize_with = "from_nano_ts")]
- /// time: DateTime<Utc>
- /// }
- ///
- /// # fn example() -> Result<S, serde_json::Error> {
- /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918355733 }"#)?;
- /// # Ok(my_s)
- /// # }
- /// # fn main() { example().unwrap(); }
- /// ```
- pub fn deserialize<'de, D>(d: D) -> Result<DateTime<Utc>, D::Error>
- where
- D: de::Deserializer<'de>,
- {
- Ok(d.deserialize_i64(NanoSecondsTimestampVisitor)?)
- }
-
- impl<'de> de::Visitor<'de> for NanoSecondsTimestampVisitor {
- type Value = DateTime<Utc>;
-
- fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
- write!(formatter, "a unix timestamp in nanoseconds")
- }
-
- /// Deserialize a timestamp in nanoseconds since the epoch
- fn visit_i64<E>(self, value: i64) -> Result<DateTime<Utc>, E>
- where
- E: de::Error,
- {
- serde_from(
- Utc.timestamp_opt(value / 1_000_000_000, (value % 1_000_000_000) as u32),
- &value,
- )
- }
-
- /// Deserialize a timestamp in nanoseconds since the epoch
- fn visit_u64<E>(self, value: u64) -> Result<DateTime<Utc>, E>
- where
- E: de::Error,
- {
- serde_from(
- Utc.timestamp_opt(
- (value / 1_000_000_000) as i64,
- (value % 1_000_000_000) as u32,
- ),
- &value,
- )
- }
- }
- }
-
- /// Ser/de to/from optional timestamps in nanoseconds
- ///
- /// Intended for use with `serde`'s `with` attribute.
- ///
- /// # Example:
- ///
- /// ```rust
- /// # // We mark this ignored so that we can test on 1.13 (which does not
- /// # // support custom derive), and run tests with --ignored on beta and
- /// # // nightly to actually trigger these.
- /// #
- /// # #[macro_use] extern crate serde_derive;
- /// # #[macro_use] extern crate serde_json;
- /// # extern crate chrono;
- /// # use chrono::{TimeZone, DateTime, Utc};
- /// use chrono::serde::ts_nanoseconds_option;
- /// #[derive(Deserialize, Serialize)]
- /// struct S {
- /// #[serde(with = "ts_nanoseconds_option")]
- /// time: Option<DateTime<Utc>>
- /// }
- ///
- /// # fn example() -> Result<S, serde_json::Error> {
- /// let time = Some(Utc.ymd(2018, 5, 17).and_hms_nano(02, 04, 59, 918355733));
- /// let my_s = S {
- /// time: time.clone(),
- /// };
- ///
- /// let as_string = serde_json::to_string(&my_s)?;
- /// assert_eq!(as_string, r#"{"time":1526522699918355733}"#);
- /// let my_s: S = serde_json::from_str(&as_string)?;
- /// assert_eq!(my_s.time, time);
- /// # Ok(my_s)
- /// # }
- /// # fn main() { example().unwrap(); }
- /// ```
- pub mod ts_nanoseconds_option {
- use core::fmt;
- use serdelib::{de, ser};
-
- use {DateTime, Utc};
-
- use super::NanoSecondsTimestampVisitor;
-
- /// Serialize a UTC datetime into an integer number of nanoseconds since the epoch or none
- ///
- /// Intended for use with `serde`s `serialize_with` attribute.
- ///
- /// # Example:
- ///
- /// ```rust
- /// # // We mark this ignored so that we can test on 1.13 (which does not
- /// # // support custom derive), and run tests with --ignored on beta and
- /// # // nightly to actually trigger these.
- /// #
- /// # #[macro_use] extern crate serde_derive;
- /// # #[macro_use] extern crate serde_json;
- /// # extern crate chrono;
- /// # use chrono::{TimeZone, DateTime, Utc};
- /// use chrono::serde::ts_nanoseconds_option::serialize as to_nano_tsopt;
- /// #[derive(Serialize)]
- /// struct S {
- /// #[serde(serialize_with = "to_nano_tsopt")]
- /// time: Option<DateTime<Utc>>
- /// }
- ///
- /// # fn example() -> Result<String, serde_json::Error> {
- /// let my_s = S {
- /// time: Some(Utc.ymd(2018, 5, 17).and_hms_nano(02, 04, 59, 918355733)),
- /// };
- /// let as_string = serde_json::to_string(&my_s)?;
- /// assert_eq!(as_string, r#"{"time":1526522699918355733}"#);
- /// # Ok(as_string)
- /// # }
- /// # fn main() { example().unwrap(); }
- /// ```
- pub fn serialize<S>(opt: &Option<DateTime<Utc>>, serializer: S) -> Result<S::Ok, S::Error>
- where
- S: ser::Serializer,
- {
- match *opt {
- Some(ref dt) => serializer.serialize_some(&dt.timestamp_nanos()),
- None => serializer.serialize_none(),
- }
- }
-
- /// Deserialize a `DateTime` from a nanosecond timestamp or none
- ///
- /// Intended for use with `serde`s `deserialize_with` attribute.
- ///
- /// # Example:
- ///
- /// ```rust
- /// # // We mark this ignored so that we can test on 1.13 (which does not
- /// # // support custom derive), and run tests with --ignored on beta and
- /// # // nightly to actually trigger these.
- /// #
- /// # #[macro_use] extern crate serde_derive;
- /// # #[macro_use] extern crate serde_json;
- /// # extern crate chrono;
- /// # use chrono::{DateTime, Utc};
- /// use chrono::serde::ts_nanoseconds_option::deserialize as from_nano_tsopt;
- /// #[derive(Deserialize)]
- /// struct S {
- /// #[serde(deserialize_with = "from_nano_tsopt")]
- /// time: Option<DateTime<Utc>>
- /// }
- ///
- /// # fn example() -> Result<S, serde_json::Error> {
- /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918355733 }"#)?;
- /// # Ok(my_s)
- /// # }
- /// # fn main() { example().unwrap(); }
- /// ```
- pub fn deserialize<'de, D>(d: D) -> Result<Option<DateTime<Utc>>, D::Error>
- where
- D: de::Deserializer<'de>,
- {
- Ok(d.deserialize_option(OptionNanoSecondsTimestampVisitor)?)
- }
-
- struct OptionNanoSecondsTimestampVisitor;
-
- impl<'de> de::Visitor<'de> for OptionNanoSecondsTimestampVisitor {
- type Value = Option<DateTime<Utc>>;
-
- fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
- formatter.write_str("a unix timestamp in nanoseconds or none")
- }
-
- /// Deserialize a timestamp in seconds since the epoch
- fn visit_some<D>(self, d: D) -> Result<Option<DateTime<Utc>>, D::Error>
- where
- D: de::Deserializer<'de>,
- {
- d.deserialize_i64(NanoSecondsTimestampVisitor).map(Some)
- }
-
- /// Deserialize a timestamp in seconds since the epoch
- fn visit_none<E>(self) -> Result<Option<DateTime<Utc>>, E>
- where
- E: de::Error,
- {
- Ok(None)
- }
-
- /// Deserialize a timestamp in seconds since the epoch
- fn visit_unit<E>(self) -> Result<Option<DateTime<Utc>>, E>
- where
- E: de::Error,
- {
- Ok(None)
- }
- }
- }
-
- /// Ser/de to/from timestamps in milliseconds
- ///
- /// Intended for use with `serde`s `with` attribute.
- ///
- /// # Example
- ///
- /// ```rust
- /// # // We mark this ignored so that we can test on 1.13 (which does not
- /// # // support custom derive), and run tests with --ignored on beta and
- /// # // nightly to actually trigger these.
- /// #
- /// # #[macro_use] extern crate serde_derive;
- /// # #[macro_use] extern crate serde_json;
- /// # extern crate chrono;
- /// # use chrono::{TimeZone, DateTime, Utc};
- /// use chrono::serde::ts_milliseconds;
- /// #[derive(Deserialize, Serialize)]
- /// struct S {
- /// #[serde(with = "ts_milliseconds")]
- /// time: DateTime<Utc>
- /// }
- ///
- /// # fn example() -> Result<S, serde_json::Error> {
- /// let time = Utc.ymd(2018, 5, 17).and_hms_milli(02, 04, 59, 918);
- /// let my_s = S {
- /// time: time.clone(),
- /// };
- ///
- /// let as_string = serde_json::to_string(&my_s)?;
- /// assert_eq!(as_string, r#"{"time":1526522699918}"#);
- /// let my_s: S = serde_json::from_str(&as_string)?;
- /// assert_eq!(my_s.time, time);
- /// # Ok(my_s)
- /// # }
- /// # fn main() { example().unwrap(); }
- /// ```
- pub mod ts_milliseconds {
- use core::fmt;
- use serdelib::{de, ser};
-
- use offset::TimeZone;
- use {DateTime, Utc};
-
- use super::{serde_from, MilliSecondsTimestampVisitor};
-
- /// Serialize a UTC datetime into an integer number of milliseconds since the epoch
- ///
- /// Intended for use with `serde`s `serialize_with` attribute.
- ///
- /// # Example:
- ///
- /// ```rust
- /// # // We mark this ignored so that we can test on 1.13 (which does not
- /// # // support custom derive), and run tests with --ignored on beta and
- /// # // nightly to actually trigger these.
- /// #
- /// # #[macro_use] extern crate serde_derive;
- /// # #[macro_use] extern crate serde_json;
- /// # extern crate chrono;
- /// # use chrono::{TimeZone, DateTime, Utc};
- /// use chrono::serde::ts_milliseconds::serialize as to_milli_ts;
- /// #[derive(Serialize)]
- /// struct S {
- /// #[serde(serialize_with = "to_milli_ts")]
- /// time: DateTime<Utc>
- /// }
- ///
- /// # fn example() -> Result<String, serde_json::Error> {
- /// let my_s = S {
- /// time: Utc.ymd(2018, 5, 17).and_hms_milli(02, 04, 59, 918),
- /// };
- /// let as_string = serde_json::to_string(&my_s)?;
- /// assert_eq!(as_string, r#"{"time":1526522699918}"#);
- /// # Ok(as_string)
- /// # }
- /// # fn main() { example().unwrap(); }
- /// ```
- pub fn serialize<S>(dt: &DateTime<Utc>, serializer: S) -> Result<S::Ok, S::Error>
- where
- S: ser::Serializer,
- {
- serializer.serialize_i64(dt.timestamp_millis())
- }
-
- /// Deserialize a `DateTime` from a millisecond timestamp
- ///
- /// Intended for use with `serde`s `deserialize_with` attribute.
- ///
- /// # Example:
- ///
- /// ```rust
- /// # // We mark this ignored so that we can test on 1.13 (which does not
- /// # // support custom derive), and run tests with --ignored on beta and
- /// # // nightly to actually trigger these.
- /// #
- /// # #[macro_use] extern crate serde_derive;
- /// # #[macro_use] extern crate serde_json;
- /// # extern crate chrono;
- /// # use chrono::{DateTime, Utc};
- /// use chrono::serde::ts_milliseconds::deserialize as from_milli_ts;
- /// #[derive(Deserialize)]
- /// struct S {
- /// #[serde(deserialize_with = "from_milli_ts")]
- /// time: DateTime<Utc>
- /// }
- ///
- /// # fn example() -> Result<S, serde_json::Error> {
- /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918 }"#)?;
- /// # Ok(my_s)
- /// # }
- /// # fn main() { example().unwrap(); }
- /// ```
- pub fn deserialize<'de, D>(d: D) -> Result<DateTime<Utc>, D::Error>
- where
- D: de::Deserializer<'de>,
- {
- Ok(d.deserialize_i64(MilliSecondsTimestampVisitor).map(|dt| dt.with_timezone(&Utc))?)
- }
-
- impl<'de> de::Visitor<'de> for MilliSecondsTimestampVisitor {
- type Value = DateTime<Utc>;
-
- fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
- formatter.write_str("a unix timestamp in milliseconds")
- }
-
- /// Deserialize a timestamp in milliseconds since the epoch
- fn visit_i64<E>(self, value: i64) -> Result<DateTime<Utc>, E>
- where
- E: de::Error,
- {
- serde_from(
- Utc.timestamp_opt(value / 1000, ((value % 1000) * 1_000_000) as u32),
- &value,
- )
- }
-
- /// Deserialize a timestamp in milliseconds since the epoch
- fn visit_u64<E>(self, value: u64) -> Result<DateTime<Utc>, E>
- where
- E: de::Error,
- {
- serde_from(
- Utc.timestamp_opt((value / 1000) as i64, ((value % 1000) * 1_000_000) as u32),
- &value,
- )
- }
- }
- }
-
- /// Ser/de to/from optional timestamps in milliseconds
- ///
- /// Intended for use with `serde`s `with` attribute.
- ///
- /// # Example
- ///
- /// ```rust
- /// # // We mark this ignored so that we can test on 1.13 (which does not
- /// # // support custom derive), and run tests with --ignored on beta and
- /// # // nightly to actually trigger these.
- /// #
- /// # #[macro_use] extern crate serde_derive;
- /// # #[macro_use] extern crate serde_json;
- /// # extern crate chrono;
- /// # use chrono::{TimeZone, DateTime, Utc};
- /// use chrono::serde::ts_milliseconds_option;
- /// #[derive(Deserialize, Serialize)]
- /// struct S {
- /// #[serde(with = "ts_milliseconds_option")]
- /// time: Option<DateTime<Utc>>
- /// }
- ///
- /// # fn example() -> Result<S, serde_json::Error> {
- /// let time = Some(Utc.ymd(2018, 5, 17).and_hms_milli(02, 04, 59, 918));
- /// let my_s = S {
- /// time: time.clone(),
- /// };
- ///
- /// let as_string = serde_json::to_string(&my_s)?;
- /// assert_eq!(as_string, r#"{"time":1526522699918}"#);
- /// let my_s: S = serde_json::from_str(&as_string)?;
- /// assert_eq!(my_s.time, time);
- /// # Ok(my_s)
- /// # }
- /// # fn main() { example().unwrap(); }
- /// ```
- pub mod ts_milliseconds_option {
- use core::fmt;
- use serdelib::{de, ser};
-
- use {DateTime, Utc};
-
- use super::MilliSecondsTimestampVisitor;
-
- /// Serialize a UTC datetime into an integer number of milliseconds since the epoch or none
- ///
- /// Intended for use with `serde`s `serialize_with` attribute.
- ///
- /// # Example:
- ///
- /// ```rust
- /// # // We mark this ignored so that we can test on 1.13 (which does not
- /// # // support custom derive), and run tests with --ignored on beta and
- /// # // nightly to actually trigger these.
- /// #
- /// # #[macro_use] extern crate serde_derive;
- /// # #[macro_use] extern crate serde_json;
- /// # extern crate chrono;
- /// # use chrono::{TimeZone, DateTime, Utc};
- /// use chrono::serde::ts_milliseconds_option::serialize as to_milli_tsopt;
- /// #[derive(Serialize)]
- /// struct S {
- /// #[serde(serialize_with = "to_milli_tsopt")]
- /// time: Option<DateTime<Utc>>
- /// }
- ///
- /// # fn example() -> Result<String, serde_json::Error> {
- /// let my_s = S {
- /// time: Some(Utc.ymd(2018, 5, 17).and_hms_milli(02, 04, 59, 918)),
- /// };
- /// let as_string = serde_json::to_string(&my_s)?;
- /// assert_eq!(as_string, r#"{"time":1526522699918}"#);
- /// # Ok(as_string)
- /// # }
- /// # fn main() { example().unwrap(); }
- /// ```
- pub fn serialize<S>(opt: &Option<DateTime<Utc>>, serializer: S) -> Result<S::Ok, S::Error>
- where
- S: ser::Serializer,
- {
- match *opt {
- Some(ref dt) => serializer.serialize_some(&dt.timestamp_millis()),
- None => serializer.serialize_none(),
- }
- }
-
- /// Deserialize a `DateTime` from a millisecond timestamp or none
- ///
- /// Intended for use with `serde`s `deserialize_with` attribute.
- ///
- /// # Example:
- ///
- /// ```rust
- /// # // We mark this ignored so that we can test on 1.13 (which does not
- /// # // support custom derive), and run tests with --ignored on beta and
- /// # // nightly to actually trigger these.
- /// #
- /// # #[macro_use] extern crate serde_derive;
- /// # #[macro_use] extern crate serde_json;
- /// # extern crate chrono;
- /// # use chrono::prelude::*;
- /// use chrono::serde::ts_milliseconds_option::deserialize as from_milli_tsopt;
- ///
- /// #[derive(Deserialize, PartialEq, Debug)]
- /// #[serde(untagged)]
- /// enum E<T> {
- /// V(T),
- /// }
- ///
- /// #[derive(Deserialize, PartialEq, Debug)]
- /// struct S {
- /// #[serde(default, deserialize_with = "from_milli_tsopt")]
- /// time: Option<DateTime<Utc>>
- /// }
- ///
- /// # fn example() -> Result<(), serde_json::Error> {
- /// 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)) }));
- /// 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(())
- /// # }
- /// # fn main() { example().unwrap(); }
- /// ```
- pub fn deserialize<'de, D>(d: D) -> Result<Option<DateTime<Utc>>, D::Error>
- where
- D: de::Deserializer<'de>,
- {
- Ok(d.deserialize_option(OptionMilliSecondsTimestampVisitor)
- .map(|opt| opt.map(|dt| dt.with_timezone(&Utc)))?)
- }
-
- struct OptionMilliSecondsTimestampVisitor;
-
- impl<'de> de::Visitor<'de> for OptionMilliSecondsTimestampVisitor {
- type Value = Option<DateTime<Utc>>;
-
- fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
- formatter.write_str("a unix timestamp in milliseconds or none")
- }
-
- /// Deserialize a timestamp in seconds since the epoch
- fn visit_some<D>(self, d: D) -> Result<Option<DateTime<Utc>>, D::Error>
- where
- D: de::Deserializer<'de>,
- {
- d.deserialize_i64(MilliSecondsTimestampVisitor).map(Some)
- }
-
- /// Deserialize a timestamp in seconds since the epoch
- fn visit_none<E>(self) -> Result<Option<DateTime<Utc>>, E>
- where
- E: de::Error,
- {
- Ok(None)
- }
-
- /// Deserialize a timestamp in seconds since the epoch
- fn visit_unit<E>(self) -> Result<Option<DateTime<Utc>>, E>
- where
- E: de::Error,
- {
- Ok(None)
- }
- }
- }
-
- /// Ser/de to/from timestamps in seconds
- ///
- /// Intended for use with `serde`'s `with` attribute.
- ///
- /// # Example:
- ///
- /// ```rust
- /// # // We mark this ignored so that we can test on 1.13 (which does not
- /// # // support custom derive), and run tests with --ignored on beta and
- /// # // nightly to actually trigger these.
- /// #
- /// # #[macro_use] extern crate serde_derive;
- /// # #[macro_use] extern crate serde_json;
- /// # extern crate chrono;
- /// # use chrono::{TimeZone, DateTime, Utc};
- /// use chrono::serde::ts_seconds;
- /// #[derive(Deserialize, Serialize)]
- /// struct S {
- /// #[serde(with = "ts_seconds")]
- /// time: DateTime<Utc>
- /// }
- ///
- /// # fn example() -> Result<S, serde_json::Error> {
- /// let time = Utc.ymd(2015, 5, 15).and_hms(10, 0, 0);
- /// let my_s = S {
- /// time: time.clone(),
- /// };
- ///
- /// let as_string = serde_json::to_string(&my_s)?;
- /// assert_eq!(as_string, r#"{"time":1431684000}"#);
- /// let my_s: S = serde_json::from_str(&as_string)?;
- /// assert_eq!(my_s.time, time);
- /// # Ok(my_s)
- /// # }
- /// # fn main() { example().unwrap(); }
- /// ```
- pub mod ts_seconds {
- use core::fmt;
- use serdelib::{de, ser};
-
- use offset::TimeZone;
- use {DateTime, Utc};
-
- use super::{serde_from, SecondsTimestampVisitor};
-
- /// Serialize a UTC datetime into an integer number of seconds since the epoch
- ///
- /// Intended for use with `serde`s `serialize_with` attribute.
- ///
- /// # Example:
- ///
- /// ```rust
- /// # // We mark this ignored so that we can test on 1.13 (which does not
- /// # // support custom derive), and run tests with --ignored on beta and
- /// # // nightly to actually trigger these.
- /// #
- /// # #[macro_use] extern crate serde_derive;
- /// # #[macro_use] extern crate serde_json;
- /// # extern crate chrono;
- /// # use chrono::{TimeZone, DateTime, Utc};
- /// use chrono::serde::ts_seconds::serialize as to_ts;
- /// #[derive(Serialize)]
- /// struct S {
- /// #[serde(serialize_with = "to_ts")]
- /// time: DateTime<Utc>
- /// }
- ///
- /// # fn example() -> Result<String, serde_json::Error> {
- /// let my_s = S {
- /// time: Utc.ymd(2015, 5, 15).and_hms(10, 0, 0),
- /// };
- /// let as_string = serde_json::to_string(&my_s)?;
- /// assert_eq!(as_string, r#"{"time":1431684000}"#);
- /// # Ok(as_string)
- /// # }
- /// # fn main() { example().unwrap(); }
- /// ```
- pub fn serialize<S>(dt: &DateTime<Utc>, serializer: S) -> Result<S::Ok, S::Error>
- where
- S: ser::Serializer,
- {
- serializer.serialize_i64(dt.timestamp())
- }
-
- /// Deserialize a `DateTime` from a seconds timestamp
- ///
- /// Intended for use with `serde`s `deserialize_with` attribute.
- ///
- /// # Example:
- ///
- /// ```rust
- /// # // We mark this ignored so that we can test on 1.13 (which does not
- /// # // support custom derive), and run tests with --ignored on beta and
- /// # // nightly to actually trigger these.
- /// #
- /// # #[macro_use] extern crate serde_derive;
- /// # #[macro_use] extern crate serde_json;
- /// # extern crate chrono;
- /// # use chrono::{DateTime, Utc};
- /// use chrono::serde::ts_seconds::deserialize as from_ts;
- /// #[derive(Deserialize)]
- /// struct S {
- /// #[serde(deserialize_with = "from_ts")]
- /// time: DateTime<Utc>
- /// }
- ///
- /// # fn example() -> Result<S, serde_json::Error> {
- /// let my_s: S = serde_json::from_str(r#"{ "time": 1431684000 }"#)?;
- /// # Ok(my_s)
- /// # }
- /// # fn main() { example().unwrap(); }
- /// ```
- pub fn deserialize<'de, D>(d: D) -> Result<DateTime<Utc>, D::Error>
- where
- D: de::Deserializer<'de>,
- {
- Ok(d.deserialize_i64(SecondsTimestampVisitor)?)
- }
-
- impl<'de> de::Visitor<'de> for SecondsTimestampVisitor {
- type Value = DateTime<Utc>;
-
- fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
- formatter.write_str("a unix timestamp in seconds")
- }
-
- /// Deserialize a timestamp in seconds since the epoch
- fn visit_i64<E>(self, value: i64) -> Result<DateTime<Utc>, E>
- where
- E: de::Error,
- {
- serde_from(Utc.timestamp_opt(value, 0), &value)
- }
-
- /// Deserialize a timestamp in seconds since the epoch
- fn visit_u64<E>(self, value: u64) -> Result<DateTime<Utc>, E>
- where
- E: de::Error,
- {
- serde_from(Utc.timestamp_opt(value as i64, 0), &value)
- }
- }
- }
-
- /// Ser/de to/from optional timestamps in seconds
- ///
- /// Intended for use with `serde`'s `with` attribute.
- ///
- /// # Example:
- ///
- /// ```rust
- /// # // We mark this ignored so that we can test on 1.13 (which does not
- /// # // support custom derive), and run tests with --ignored on beta and
- /// # // nightly to actually trigger these.
- /// #
- /// # #[macro_use] extern crate serde_derive;
- /// # #[macro_use] extern crate serde_json;
- /// # extern crate chrono;
- /// # use chrono::{TimeZone, DateTime, Utc};
- /// use chrono::serde::ts_seconds_option;
- /// #[derive(Deserialize, Serialize)]
- /// struct S {
- /// #[serde(with = "ts_seconds_option")]
- /// time: Option<DateTime<Utc>>
- /// }
- ///
- /// # fn example() -> Result<S, serde_json::Error> {
- /// let time = Some(Utc.ymd(2015, 5, 15).and_hms(10, 0, 0));
- /// let my_s = S {
- /// time: time.clone(),
- /// };
- ///
- /// let as_string = serde_json::to_string(&my_s)?;
- /// assert_eq!(as_string, r#"{"time":1431684000}"#);
- /// let my_s: S = serde_json::from_str(&as_string)?;
- /// assert_eq!(my_s.time, time);
- /// # Ok(my_s)
- /// # }
- /// # fn main() { example().unwrap(); }
- /// ```
- pub mod ts_seconds_option {
- use core::fmt;
- use serdelib::{de, ser};
-
- use {DateTime, Utc};
-
- use super::SecondsTimestampVisitor;
-
- /// Serialize a UTC datetime into an integer number of seconds since the epoch or none
- ///
- /// Intended for use with `serde`s `serialize_with` attribute.
- ///
- /// # Example:
- ///
- /// ```rust
- /// # // We mark this ignored so that we can test on 1.13 (which does not
- /// # // support custom derive), and run tests with --ignored on beta and
- /// # // nightly to actually trigger these.
- /// #
- /// # #[macro_use] extern crate serde_derive;
- /// # #[macro_use] extern crate serde_json;
- /// # extern crate chrono;
- /// # use chrono::{TimeZone, DateTime, Utc};
- /// use chrono::serde::ts_seconds_option::serialize as to_tsopt;
- /// #[derive(Serialize)]
- /// struct S {
- /// #[serde(serialize_with = "to_tsopt")]
- /// time: Option<DateTime<Utc>>
- /// }
- ///
- /// # fn example() -> Result<String, serde_json::Error> {
- /// let my_s = S {
- /// time: Some(Utc.ymd(2015, 5, 15).and_hms(10, 0, 0)),
- /// };
- /// let as_string = serde_json::to_string(&my_s)?;
- /// assert_eq!(as_string, r#"{"time":1431684000}"#);
- /// # Ok(as_string)
- /// # }
- /// # fn main() { example().unwrap(); }
- /// ```
- pub fn serialize<S>(opt: &Option<DateTime<Utc>>, serializer: S) -> Result<S::Ok, S::Error>
- where
- S: ser::Serializer,
- {
- match *opt {
- Some(ref dt) => serializer.serialize_some(&dt.timestamp()),
- None => serializer.serialize_none(),
- }
- }
-
- /// Deserialize a `DateTime` from a seconds timestamp or none
- ///
- /// Intended for use with `serde`s `deserialize_with` attribute.
- ///
- /// # Example:
- ///
- /// ```rust
- /// # // We mark this ignored so that we can test on 1.13 (which does not
- /// # // support custom derive), and run tests with --ignored on beta and
- /// # // nightly to actually trigger these.
- /// #
- /// # #[macro_use] extern crate serde_derive;
- /// # #[macro_use] extern crate serde_json;
- /// # extern crate chrono;
- /// # use chrono::{DateTime, Utc};
- /// use chrono::serde::ts_seconds_option::deserialize as from_tsopt;
- /// #[derive(Deserialize)]
- /// struct S {
- /// #[serde(deserialize_with = "from_tsopt")]
- /// time: Option<DateTime<Utc>>
- /// }
- ///
- /// # fn example() -> Result<S, serde_json::Error> {
- /// let my_s: S = serde_json::from_str(r#"{ "time": 1431684000 }"#)?;
- /// # Ok(my_s)
- /// # }
- /// # fn main() { example().unwrap(); }
- /// ```
- pub fn deserialize<'de, D>(d: D) -> Result<Option<DateTime<Utc>>, D::Error>
- where
- D: de::Deserializer<'de>,
- {
- Ok(d.deserialize_option(OptionSecondsTimestampVisitor)?)
- }
-
- struct OptionSecondsTimestampVisitor;
-
- impl<'de> de::Visitor<'de> for OptionSecondsTimestampVisitor {
- type Value = Option<DateTime<Utc>>;
-
- fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
- formatter.write_str("a unix timestamp in seconds or none")
- }
-
- /// Deserialize a timestamp in seconds since the epoch
- fn visit_some<D>(self, d: D) -> Result<Option<DateTime<Utc>>, D::Error>
- where
- D: de::Deserializer<'de>,
- {
- d.deserialize_i64(SecondsTimestampVisitor).map(Some)
- }
-
- /// Deserialize a timestamp in seconds since the epoch
- fn visit_none<E>(self) -> Result<Option<DateTime<Utc>>, E>
- where
- E: de::Error,
- {
- Ok(None)
- }
-
- /// Deserialize a timestamp in seconds since the epoch
- fn visit_unit<E>(self) -> Result<Option<DateTime<Utc>>, E>
- where
- E: de::Error,
- {
- Ok(None)
- }
- }
- }
-
- impl<Tz: TimeZone> ser::Serialize for DateTime<Tz> {
- /// Serialize into a rfc3339 time string
- ///
- /// See [the `serde` module](./serde/index.html) for alternate
- /// serializations.
- fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
- where
- S: ser::Serializer,
- {
- struct FormatWrapped<'a, D: 'a> {
- inner: &'a D,
- }
-
- impl<'a, D: fmt::Debug> fmt::Display for FormatWrapped<'a, D> {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- self.inner.fmt(f)
- }
- }
-
- // Debug formatting is correct RFC3339, and it allows Zulu.
- serializer.collect_str(&FormatWrapped { inner: &self })
- }
- }
-
- struct DateTimeVisitor;
-
- impl<'de> de::Visitor<'de> for DateTimeVisitor {
- type Value = DateTime<FixedOffset>;
-
- fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
- write!(formatter, "a formatted date and time string or a unix timestamp")
- }
-
- fn visit_str<E>(self, value: &str) -> Result<DateTime<FixedOffset>, E>
- where
- E: de::Error,
- {
- value.parse().map_err(|err: ::format::ParseError| E::custom(err))
- }
- }
-
- /// Deserialize a value that optionally includes a timezone offset in its
- /// string representation
- ///
- /// The value to be deserialized must be an rfc3339 string.
- ///
- /// See [the `serde` module](./serde/index.html) for alternate
- /// deserialization formats.
- impl<'de> de::Deserialize<'de> for DateTime<FixedOffset> {
- fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
- where
- D: de::Deserializer<'de>,
- {
- deserializer.deserialize_str(DateTimeVisitor)
- }
- }
-
- /// Deserialize into a UTC value
- ///
- /// The value to be deserialized must be an rfc3339 string.
- ///
- /// See [the `serde` module](./serde/index.html) for alternate
- /// deserialization formats.
- impl<'de> de::Deserialize<'de> for DateTime<Utc> {
- fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
- where
- D: de::Deserializer<'de>,
- {
- deserializer.deserialize_str(DateTimeVisitor).map(|dt| dt.with_timezone(&Utc))
- }
- }
-
- /// Deserialize a value that includes no timezone in its string
- /// representation
- ///
- /// The value to be deserialized must be an rfc3339 string.
- ///
- /// See [the `serde` module](./serde/index.html) for alternate
- /// serialization formats.
- #[cfg(feature = "clock")]
- impl<'de> de::Deserialize<'de> for DateTime<Local> {
- fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
- where
- D: de::Deserializer<'de>,
- {
- deserializer.deserialize_str(DateTimeVisitor).map(|dt| dt.with_timezone(&Local))
- }
- }
-
- #[cfg(test)]
- extern crate bincode;
- #[cfg(test)]
- extern crate serde_json;
-
- #[test]
- fn test_serde_serialize() {
- super::test_encodable_json(self::serde_json::to_string, self::serde_json::to_string);
- }
-
- #[cfg(feature = "clock")]
- #[test]
- fn test_serde_deserialize() {
- super::test_decodable_json(
- |input| self::serde_json::from_str(&input),
- |input| self::serde_json::from_str(&input),
- |input| self::serde_json::from_str(&input),
- );
- }
-
- #[test]
- fn test_serde_bincode() {
- // Bincode is relevant to test separately from JSON because
- // it is not self-describing.
- use self::bincode::{deserialize, serialize, Infinite};
-
- let dt = Utc.ymd(2014, 7, 24).and_hms(12, 34, 6);
- let encoded = serialize(&dt, Infinite).unwrap();
- let decoded: DateTime<Utc> = deserialize(&encoded).unwrap();
- assert_eq!(dt, decoded);
- assert_eq!(dt.offset(), decoded.offset());
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::DateTime;
- use naive::{NaiveDate, NaiveTime};
- #[cfg(feature = "clock")]
- use offset::Local;
- use offset::{FixedOffset, TimeZone, Utc};
- use oldtime::Duration;
- use std::time::{SystemTime, UNIX_EPOCH};
- #[cfg(feature = "clock")]
- use Datelike;
-
- #[test]
- #[allow(non_snake_case)]
- fn test_datetime_offset() {
- let Est = FixedOffset::west(5 * 60 * 60);
- let Edt = FixedOffset::west(4 * 60 * 60);
- let Kst = FixedOffset::east(9 * 60 * 60);
-
- assert_eq!(format!("{}", Utc.ymd(2014, 5, 6).and_hms(7, 8, 9)), "2014-05-06 07:08:09 UTC");
- assert_eq!(
- format!("{}", Edt.ymd(2014, 5, 6).and_hms(7, 8, 9)),
- "2014-05-06 07:08:09 -04:00"
- );
- assert_eq!(
- format!("{}", Kst.ymd(2014, 5, 6).and_hms(7, 8, 9)),
- "2014-05-06 07:08:09 +09:00"
- );
- assert_eq!(format!("{:?}", Utc.ymd(2014, 5, 6).and_hms(7, 8, 9)), "2014-05-06T07:08:09Z");
- assert_eq!(
- format!("{:?}", Edt.ymd(2014, 5, 6).and_hms(7, 8, 9)),
- "2014-05-06T07:08:09-04:00"
- );
- assert_eq!(
- format!("{:?}", Kst.ymd(2014, 5, 6).and_hms(7, 8, 9)),
- "2014-05-06T07:08:09+09:00"
- );
-
- // edge cases
- assert_eq!(format!("{:?}", Utc.ymd(2014, 5, 6).and_hms(0, 0, 0)), "2014-05-06T00:00:00Z");
- assert_eq!(
- format!("{:?}", Edt.ymd(2014, 5, 6).and_hms(0, 0, 0)),
- "2014-05-06T00:00:00-04:00"
- );
- assert_eq!(
- format!("{:?}", Kst.ymd(2014, 5, 6).and_hms(0, 0, 0)),
- "2014-05-06T00:00:00+09:00"
- );
- assert_eq!(
- format!("{:?}", Utc.ymd(2014, 5, 6).and_hms(23, 59, 59)),
- "2014-05-06T23:59:59Z"
- );
- assert_eq!(
- format!("{:?}", Edt.ymd(2014, 5, 6).and_hms(23, 59, 59)),
- "2014-05-06T23:59:59-04:00"
- );
- assert_eq!(
- format!("{:?}", Kst.ymd(2014, 5, 6).and_hms(23, 59, 59)),
- "2014-05-06T23:59:59+09:00"
- );
-
- let dt = Utc.ymd(2014, 5, 6).and_hms(7, 8, 9);
- assert_eq!(dt, Edt.ymd(2014, 5, 6).and_hms(3, 8, 9));
- assert_eq!(dt + Duration::seconds(3600 + 60 + 1), Utc.ymd(2014, 5, 6).and_hms(8, 9, 10));
- assert_eq!(
- dt.signed_duration_since(Edt.ymd(2014, 5, 6).and_hms(10, 11, 12)),
- Duration::seconds(-7 * 3600 - 3 * 60 - 3)
- );
-
- assert_eq!(*Utc.ymd(2014, 5, 6).and_hms(7, 8, 9).offset(), Utc);
- assert_eq!(*Edt.ymd(2014, 5, 6).and_hms(7, 8, 9).offset(), Edt);
- assert!(*Edt.ymd(2014, 5, 6).and_hms(7, 8, 9).offset() != Est);
- }
-
- #[test]
- fn test_datetime_date_and_time() {
- let tz = FixedOffset::east(5 * 60 * 60);
- let d = tz.ymd(2014, 5, 6).and_hms(7, 8, 9);
- assert_eq!(d.time(), NaiveTime::from_hms(7, 8, 9));
- assert_eq!(d.date(), tz.ymd(2014, 5, 6));
- assert_eq!(d.date().naive_local(), NaiveDate::from_ymd(2014, 5, 6));
- assert_eq!(d.date().and_time(d.time()), Some(d));
-
- let tz = FixedOffset::east(4 * 60 * 60);
- let d = tz.ymd(2016, 5, 4).and_hms(3, 2, 1);
- assert_eq!(d.time(), NaiveTime::from_hms(3, 2, 1));
- assert_eq!(d.date(), tz.ymd(2016, 5, 4));
- assert_eq!(d.date().naive_local(), NaiveDate::from_ymd(2016, 5, 4));
- assert_eq!(d.date().and_time(d.time()), Some(d));
-
- let tz = FixedOffset::west(13 * 60 * 60);
- let d = tz.ymd(2017, 8, 9).and_hms(12, 34, 56);
- assert_eq!(d.time(), NaiveTime::from_hms(12, 34, 56));
- assert_eq!(d.date(), tz.ymd(2017, 8, 9));
- assert_eq!(d.date().naive_local(), NaiveDate::from_ymd(2017, 8, 9));
- assert_eq!(d.date().and_time(d.time()), Some(d));
-
- let utc_d = Utc.ymd(2017, 8, 9).and_hms(12, 34, 56);
- assert!(utc_d < d);
- }
-
- #[test]
- #[cfg(feature = "clock")]
- fn test_datetime_with_timezone() {
- let local_now = Local::now();
- let utc_now = local_now.with_timezone(&Utc);
- let local_now2 = utc_now.with_timezone(&Local);
- assert_eq!(local_now, local_now2);
- }
-
- #[test]
- #[allow(non_snake_case)]
- fn test_datetime_rfc2822_and_rfc3339() {
- let EDT = FixedOffset::east(5 * 60 * 60);
- assert_eq!(
- Utc.ymd(2015, 2, 18).and_hms(23, 16, 9).to_rfc2822(),
- "Wed, 18 Feb 2015 23:16:09 +0000"
- );
- assert_eq!(
- Utc.ymd(2015, 2, 18).and_hms(23, 16, 9).to_rfc3339(),
- "2015-02-18T23:16:09+00:00"
- );
- assert_eq!(
- EDT.ymd(2015, 2, 18).and_hms_milli(23, 16, 9, 150).to_rfc2822(),
- "Wed, 18 Feb 2015 23:16:09 +0500"
- );
- assert_eq!(
- EDT.ymd(2015, 2, 18).and_hms_milli(23, 16, 9, 150).to_rfc3339(),
- "2015-02-18T23:16:09.150+05:00"
- );
- assert_eq!(
- EDT.ymd(2015, 2, 18).and_hms_micro(23, 59, 59, 1_234_567).to_rfc2822(),
- "Wed, 18 Feb 2015 23:59:60 +0500"
- );
- assert_eq!(
- EDT.ymd(2015, 2, 18).and_hms_micro(23, 59, 59, 1_234_567).to_rfc3339(),
- "2015-02-18T23:59:60.234567+05:00"
- );
-
- assert_eq!(
- DateTime::parse_from_rfc2822("Wed, 18 Feb 2015 23:16:09 +0000"),
- Ok(FixedOffset::east(0).ymd(2015, 2, 18).and_hms(23, 16, 9))
- );
- assert_eq!(
- DateTime::parse_from_rfc2822("Wed, 18 Feb 2015 23:16:09 -0000"),
- Ok(FixedOffset::east(0).ymd(2015, 2, 18).and_hms(23, 16, 9))
- );
- assert_eq!(
- DateTime::parse_from_rfc3339("2015-02-18T23:16:09Z"),
- Ok(FixedOffset::east(0).ymd(2015, 2, 18).and_hms(23, 16, 9))
- );
- assert_eq!(
- DateTime::parse_from_rfc2822("Wed, 18 Feb 2015 23:59:60 +0500"),
- Ok(EDT.ymd(2015, 2, 18).and_hms_milli(23, 59, 59, 1_000))
- );
- assert_eq!(
- DateTime::parse_from_rfc3339("2015-02-18T23:59:60.234567+05:00"),
- Ok(EDT.ymd(2015, 2, 18).and_hms_micro(23, 59, 59, 1_234_567))
- );
- }
-
- #[test]
- fn test_rfc3339_opts() {
- use SecondsFormat::*;
- let pst = FixedOffset::east(8 * 60 * 60);
- let dt = pst.ymd(2018, 1, 11).and_hms_nano(10, 5, 13, 084_660_000);
- assert_eq!(dt.to_rfc3339_opts(Secs, false), "2018-01-11T10:05:13+08:00");
- assert_eq!(dt.to_rfc3339_opts(Secs, true), "2018-01-11T10:05:13+08:00");
- assert_eq!(dt.to_rfc3339_opts(Millis, false), "2018-01-11T10:05:13.084+08:00");
- assert_eq!(dt.to_rfc3339_opts(Micros, false), "2018-01-11T10:05:13.084660+08:00");
- assert_eq!(dt.to_rfc3339_opts(Nanos, false), "2018-01-11T10:05:13.084660000+08:00");
- assert_eq!(dt.to_rfc3339_opts(AutoSi, false), "2018-01-11T10:05:13.084660+08:00");
-
- let ut = DateTime::<Utc>::from_utc(dt.naive_utc(), Utc);
- assert_eq!(ut.to_rfc3339_opts(Secs, false), "2018-01-11T02:05:13+00:00");
- assert_eq!(ut.to_rfc3339_opts(Secs, true), "2018-01-11T02:05:13Z");
- assert_eq!(ut.to_rfc3339_opts(Millis, false), "2018-01-11T02:05:13.084+00:00");
- assert_eq!(ut.to_rfc3339_opts(Millis, true), "2018-01-11T02:05:13.084Z");
- assert_eq!(ut.to_rfc3339_opts(Micros, true), "2018-01-11T02:05:13.084660Z");
- assert_eq!(ut.to_rfc3339_opts(Nanos, true), "2018-01-11T02:05:13.084660000Z");
- assert_eq!(ut.to_rfc3339_opts(AutoSi, true), "2018-01-11T02:05:13.084660Z");
- }
-
- #[test]
- #[should_panic]
- fn test_rfc3339_opts_nonexhaustive() {
- use SecondsFormat;
- let dt = Utc.ymd(1999, 10, 9).and_hms(1, 2, 3);
- dt.to_rfc3339_opts(SecondsFormat::__NonExhaustive, true);
- }
-
- #[test]
- fn test_datetime_from_str() {
- assert_eq!(
- "2015-02-18T23:16:9.15Z".parse::<DateTime<FixedOffset>>(),
- Ok(FixedOffset::east(0).ymd(2015, 2, 18).and_hms_milli(23, 16, 9, 150))
- );
- assert_eq!(
- "2015-02-18T23:16:9.15Z".parse::<DateTime<Utc>>(),
- Ok(Utc.ymd(2015, 2, 18).and_hms_milli(23, 16, 9, 150))
- );
- assert_eq!(
- "2015-02-18T23:16:9.15 UTC".parse::<DateTime<Utc>>(),
- Ok(Utc.ymd(2015, 2, 18).and_hms_milli(23, 16, 9, 150))
- );
- assert_eq!(
- "2015-02-18T23:16:9.15UTC".parse::<DateTime<Utc>>(),
- Ok(Utc.ymd(2015, 2, 18).and_hms_milli(23, 16, 9, 150))
- );
-
- assert_eq!(
- "2015-2-18T23:16:9.15Z".parse::<DateTime<FixedOffset>>(),
- Ok(FixedOffset::east(0).ymd(2015, 2, 18).and_hms_milli(23, 16, 9, 150))
- );
- assert_eq!(
- "2015-2-18T13:16:9.15-10:00".parse::<DateTime<FixedOffset>>(),
- Ok(FixedOffset::west(10 * 3600).ymd(2015, 2, 18).and_hms_milli(13, 16, 9, 150))
- );
- assert!("2015-2-18T23:16:9.15".parse::<DateTime<FixedOffset>>().is_err());
-
- assert_eq!(
- "2015-2-18T23:16:9.15Z".parse::<DateTime<Utc>>(),
- Ok(Utc.ymd(2015, 2, 18).and_hms_milli(23, 16, 9, 150))
- );
- assert_eq!(
- "2015-2-18T13:16:9.15-10:00".parse::<DateTime<Utc>>(),
- Ok(Utc.ymd(2015, 2, 18).and_hms_milli(23, 16, 9, 150))
- );
- assert!("2015-2-18T23:16:9.15".parse::<DateTime<Utc>>().is_err());
-
- // no test for `DateTime<Local>`, we cannot verify that much.
- }
-
- #[test]
- fn test_datetime_parse_from_str() {
- let ymdhms = |y, m, d, h, n, s, off| FixedOffset::east(off).ymd(y, m, d).and_hms(h, n, s);
- assert_eq!(
- DateTime::parse_from_str("2014-5-7T12:34:56+09:30", "%Y-%m-%dT%H:%M:%S%z"),
- Ok(ymdhms(2014, 5, 7, 12, 34, 56, 570 * 60))
- ); // ignore offset
- assert!(DateTime::parse_from_str("20140507000000", "%Y%m%d%H%M%S").is_err()); // no offset
- assert!(DateTime::parse_from_str(
- "Fri, 09 Aug 2013 23:54:35 GMT",
- "%a, %d %b %Y %H:%M:%S GMT"
- )
- .is_err());
- assert_eq!(
- Utc.datetime_from_str("Fri, 09 Aug 2013 23:54:35 GMT", "%a, %d %b %Y %H:%M:%S GMT"),
- Ok(Utc.ymd(2013, 8, 9).and_hms(23, 54, 35))
- );
- }
-
- #[test]
- fn test_to_string_round_trip() {
- let dt = Utc.ymd(2000, 1, 1).and_hms(0, 0, 0);
- let _dt: DateTime<Utc> = dt.to_string().parse().unwrap();
-
- let ndt_fixed = dt.with_timezone(&FixedOffset::east(3600));
- let _dt: DateTime<FixedOffset> = ndt_fixed.to_string().parse().unwrap();
-
- let ndt_fixed = dt.with_timezone(&FixedOffset::east(0));
- let _dt: DateTime<FixedOffset> = ndt_fixed.to_string().parse().unwrap();
- }
-
- #[test]
- #[cfg(feature = "clock")]
- fn test_to_string_round_trip_with_local() {
- let ndt = Local::now();
- let _dt: DateTime<FixedOffset> = ndt.to_string().parse().unwrap();
- }
-
- #[test]
- #[cfg(feature = "clock")]
- fn test_datetime_format_with_local() {
- // if we are not around the year boundary, local and UTC date should have the same year
- let dt = Local::now().with_month(5).unwrap();
- assert_eq!(dt.format("%Y").to_string(), dt.with_timezone(&Utc).format("%Y").to_string());
- }
-
- #[test]
- #[cfg(feature = "clock")]
- fn test_datetime_is_copy() {
- // UTC is known to be `Copy`.
- let a = Utc::now();
- let b = a;
- assert_eq!(a, b);
- }
-
- #[test]
- #[cfg(feature = "clock")]
- fn test_datetime_is_send() {
- use std::thread;
-
- // UTC is known to be `Send`.
- let a = Utc::now();
- thread::spawn(move || {
- let _ = a;
- })
- .join()
- .unwrap();
- }
-
- #[test]
- fn test_subsecond_part() {
- let datetime = Utc.ymd(2014, 7, 8).and_hms_nano(9, 10, 11, 1234567);
-
- assert_eq!(1, datetime.timestamp_subsec_millis());
- assert_eq!(1234, datetime.timestamp_subsec_micros());
- assert_eq!(1234567, datetime.timestamp_subsec_nanos());
- }
-
- #[test]
- #[cfg(not(target_os = "windows"))]
- fn test_from_system_time() {
- use std::time::Duration;
-
- let epoch = Utc.ymd(1970, 1, 1).and_hms(0, 0, 0);
- let nanos = 999_999_999;
-
- // SystemTime -> DateTime<Utc>
- assert_eq!(DateTime::<Utc>::from(UNIX_EPOCH), epoch);
- assert_eq!(
- DateTime::<Utc>::from(UNIX_EPOCH + Duration::new(999_999_999, nanos)),
- Utc.ymd(2001, 9, 9).and_hms_nano(1, 46, 39, nanos)
- );
- assert_eq!(
- DateTime::<Utc>::from(UNIX_EPOCH - Duration::new(999_999_999, nanos)),
- Utc.ymd(1938, 4, 24).and_hms_nano(22, 13, 20, 1)
- );
-
- // DateTime<Utc> -> SystemTime
- assert_eq!(SystemTime::from(epoch), UNIX_EPOCH);
- assert_eq!(
- SystemTime::from(Utc.ymd(2001, 9, 9).and_hms_nano(1, 46, 39, nanos)),
- UNIX_EPOCH + Duration::new(999_999_999, nanos)
- );
- assert_eq!(
- SystemTime::from(Utc.ymd(1938, 4, 24).and_hms_nano(22, 13, 20, 1)),
- UNIX_EPOCH - Duration::new(999_999_999, 999_999_999)
- );
-
- // DateTime<any tz> -> SystemTime (via `with_timezone`)
- #[cfg(feature = "clock")]
- {
- assert_eq!(SystemTime::from(epoch.with_timezone(&Local)), UNIX_EPOCH);
- }
- assert_eq!(SystemTime::from(epoch.with_timezone(&FixedOffset::east(32400))), UNIX_EPOCH);
- assert_eq!(SystemTime::from(epoch.with_timezone(&FixedOffset::west(28800))), UNIX_EPOCH);
- }
-
- #[test]
- #[cfg(target_os = "windows")]
- fn test_from_system_time() {
- use std::time::Duration;
-
- let nanos = 999_999_000;
-
- let epoch = Utc.ymd(1970, 1, 1).and_hms(0, 0, 0);
-
- // SystemTime -> DateTime<Utc>
- assert_eq!(DateTime::<Utc>::from(UNIX_EPOCH), epoch);
- assert_eq!(
- DateTime::<Utc>::from(UNIX_EPOCH + Duration::new(999_999_999, nanos)),
- Utc.ymd(2001, 9, 9).and_hms_nano(1, 46, 39, nanos)
- );
- assert_eq!(
- DateTime::<Utc>::from(UNIX_EPOCH - Duration::new(999_999_999, nanos)),
- Utc.ymd(1938, 4, 24).and_hms_nano(22, 13, 20, 1_000)
- );
-
- // DateTime<Utc> -> SystemTime
- assert_eq!(SystemTime::from(epoch), UNIX_EPOCH);
- assert_eq!(
- SystemTime::from(Utc.ymd(2001, 9, 9).and_hms_nano(1, 46, 39, nanos)),
- UNIX_EPOCH + Duration::new(999_999_999, nanos)
- );
- assert_eq!(
- SystemTime::from(Utc.ymd(1938, 4, 24).and_hms_nano(22, 13, 20, 1_000)),
- UNIX_EPOCH - Duration::new(999_999_999, nanos)
- );
-
- // DateTime<any tz> -> SystemTime (via `with_timezone`)
- #[cfg(feature = "clock")]
- {
- assert_eq!(SystemTime::from(epoch.with_timezone(&Local)), UNIX_EPOCH);
- }
- assert_eq!(SystemTime::from(epoch.with_timezone(&FixedOffset::east(32400))), UNIX_EPOCH);
- assert_eq!(SystemTime::from(epoch.with_timezone(&FixedOffset::west(28800))), UNIX_EPOCH);
- }
-
- #[test]
- fn test_datetime_format_alignment() {
- let datetime = Utc.ymd(2007, 01, 02);
-
- // Item::Literal
- let percent = datetime.format("%%");
- assert_eq!(" %", format!("{:>3}", percent));
- assert_eq!("% ", format!("{:<3}", percent));
- assert_eq!(" % ", format!("{:^3}", percent));
-
- // Item::Numeric
- let year = datetime.format("%Y");
- assert_eq!(" 2007", format!("{:>6}", year));
- assert_eq!("2007 ", format!("{:<6}", year));
- assert_eq!(" 2007 ", format!("{:^6}", year));
-
- // Item::Fixed
- let tz = datetime.format("%Z");
- assert_eq!(" UTC", format!("{:>5}", tz));
- assert_eq!("UTC ", format!("{:<5}", tz));
- assert_eq!(" UTC ", format!("{:^5}", tz));
-
- // [Item::Numeric, Item::Space, Item::Literal, Item::Space, Item::Numeric]
- let ymd = datetime.format("%Y %B %d");
- let ymd_formatted = "2007 January 02";
- assert_eq!(format!(" {}", ymd_formatted), format!("{:>17}", ymd));
- assert_eq!(format!("{} ", ymd_formatted), format!("{:<17}", ymd));
- assert_eq!(format!(" {} ", ymd_formatted), format!("{:^17}", ymd));
- }
-}
diff --git a/vendor/chrono/src/datetime/mod.rs b/vendor/chrono/src/datetime/mod.rs
new file mode 100644
index 000000000..38416cb6f
--- /dev/null
+++ b/vendor/chrono/src/datetime/mod.rs
@@ -0,0 +1,1322 @@
+// This is a part of Chrono.
+// See README.md and LICENSE.txt for details.
+
+//! ISO 8601 date and time with time zone.
+
+#[cfg(feature = "alloc")]
+extern crate alloc;
+
+#[cfg(all(not(feature = "std"), feature = "alloc"))]
+use alloc::string::{String, ToString};
+#[cfg(any(feature = "alloc", feature = "std", test))]
+use core::borrow::Borrow;
+use core::cmp::Ordering;
+use core::fmt::Write;
+use core::ops::{Add, AddAssign, Sub, SubAssign};
+use core::{fmt, hash, str};
+#[cfg(feature = "std")]
+use std::string::ToString;
+#[cfg(any(feature = "std", test))]
+use std::time::{SystemTime, UNIX_EPOCH};
+
+#[cfg(any(feature = "alloc", feature = "std", test))]
+use crate::format::DelayedFormat;
+#[cfg(feature = "unstable-locales")]
+use crate::format::Locale;
+use crate::format::{parse, ParseError, ParseResult, Parsed, StrftimeItems};
+use crate::format::{Fixed, Item};
+use crate::naive::{Days, IsoWeek, NaiveDate, NaiveDateTime, NaiveTime};
+#[cfg(feature = "clock")]
+use crate::offset::Local;
+use crate::offset::{FixedOffset, Offset, TimeZone, Utc};
+use crate::oldtime::Duration as OldDuration;
+#[allow(deprecated)]
+use crate::Date;
+use crate::Months;
+use crate::{Datelike, Timelike, Weekday};
+
+#[cfg(feature = "rkyv")]
+use rkyv::{Archive, Deserialize, Serialize};
+
+#[cfg(feature = "rustc-serialize")]
+pub(super) mod rustc_serialize;
+
+/// documented at re-export site
+#[cfg(feature = "serde")]
+pub(super) mod serde;
+
+#[cfg(test)]
+mod tests;
+
+/// Specific formatting options for seconds. This may be extended in the
+/// future, so exhaustive matching in external code is not recommended.
+///
+/// See the `TimeZone::to_rfc3339_opts` function for usage.
+#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
+pub enum SecondsFormat {
+ /// Format whole seconds only, with no decimal point nor subseconds.
+ Secs,
+
+ /// Use fixed 3 subsecond digits. This corresponds to
+ /// [Fixed::Nanosecond3](format/enum.Fixed.html#variant.Nanosecond3).
+ Millis,
+
+ /// Use fixed 6 subsecond digits. This corresponds to
+ /// [Fixed::Nanosecond6](format/enum.Fixed.html#variant.Nanosecond6).
+ Micros,
+
+ /// Use fixed 9 subsecond digits. This corresponds to
+ /// [Fixed::Nanosecond9](format/enum.Fixed.html#variant.Nanosecond9).
+ Nanos,
+
+ /// Automatically select one of `Secs`, `Millis`, `Micros`, or `Nanos` to
+ /// display all available non-zero sub-second digits. This corresponds to
+ /// [Fixed::Nanosecond](format/enum.Fixed.html#variant.Nanosecond).
+ AutoSi,
+
+ // Do not match against this.
+ #[doc(hidden)]
+ __NonExhaustive,
+}
+
+/// ISO 8601 combined date and time with time zone.
+///
+/// There are some constructors implemented here (the `from_*` methods), but
+/// the general-purpose constructors are all via the methods on the
+/// [`TimeZone`](./offset/trait.TimeZone.html) implementations.
+#[derive(Clone)]
+#[cfg_attr(feature = "rkyv", derive(Archive, Deserialize, Serialize))]
+pub struct DateTime<Tz: TimeZone> {
+ datetime: NaiveDateTime,
+ offset: Tz::Offset,
+}
+
+/// The minimum possible `DateTime<Utc>`.
+#[deprecated(since = "0.4.20", note = "Use DateTime::MIN_UTC instead")]
+pub const MIN_DATETIME: DateTime<Utc> = DateTime::<Utc>::MIN_UTC;
+/// The maximum possible `DateTime<Utc>`.
+#[deprecated(since = "0.4.20", note = "Use DateTime::MAX_UTC instead")]
+pub const MAX_DATETIME: DateTime<Utc> = DateTime::<Utc>::MAX_UTC;
+
+impl<Tz: TimeZone> DateTime<Tz> {
+ /// Makes a new `DateTime` with given *UTC* datetime and offset.
+ /// The local datetime should be constructed via the `TimeZone` trait.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use chrono::{DateTime, TimeZone, NaiveDateTime, Utc};
+ ///
+ /// let dt = DateTime::<Utc>::from_utc(NaiveDateTime::from_timestamp_opt(61, 0).unwrap(), Utc);
+ /// assert_eq!(Utc.timestamp_opt(61, 0).unwrap(), dt);
+ /// ```
+ //
+ // note: this constructor is purposely not named to `new` to discourage the direct usage.
+ #[inline]
+ pub fn from_utc(datetime: NaiveDateTime, offset: Tz::Offset) -> DateTime<Tz> {
+ DateTime { datetime, offset }
+ }
+
+ /// Makes a new `DateTime` with given **local** datetime and offset that
+ /// presents local timezone.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use chrono::DateTime;
+ /// use chrono::naive::NaiveDate;
+ /// use chrono::offset::{Utc, FixedOffset};
+ ///
+ /// let naivedatetime_utc = NaiveDate::from_ymd_opt(2000, 1, 12).unwrap().and_hms_opt(2, 0, 0).unwrap();
+ /// let datetime_utc = DateTime::<Utc>::from_utc(naivedatetime_utc, Utc);
+ ///
+ /// let timezone_east = FixedOffset::east_opt(8 * 60 * 60).unwrap();
+ /// let naivedatetime_east = NaiveDate::from_ymd_opt(2000, 1, 12).unwrap().and_hms_opt(10, 0, 0).unwrap();
+ /// let datetime_east = DateTime::<FixedOffset>::from_local(naivedatetime_east, timezone_east);
+ ///
+ /// let timezone_west = FixedOffset::west_opt(7 * 60 * 60).unwrap();
+ /// let naivedatetime_west = NaiveDate::from_ymd_opt(2000, 1, 11).unwrap().and_hms_opt(19, 0, 0).unwrap();
+ /// let datetime_west = DateTime::<FixedOffset>::from_local(naivedatetime_west, timezone_west);
+
+ /// assert_eq!(datetime_east, datetime_utc.with_timezone(&timezone_east));
+ /// assert_eq!(datetime_west, datetime_utc.with_timezone(&timezone_west));
+ /// ```
+ #[inline]
+ pub fn from_local(datetime: NaiveDateTime, offset: Tz::Offset) -> DateTime<Tz> {
+ let datetime_utc = datetime - offset.fix();
+
+ DateTime { datetime: datetime_utc, offset }
+ }
+
+ /// Retrieves a date component
+ ///
+ /// Unless you are immediately planning on turning this into a `DateTime`
+ /// with the same Timezone you should use the
+ /// [`date_naive`](DateTime::date_naive) method.
+ #[inline]
+ #[deprecated(since = "0.4.23", note = "Use `date_naive()` instead")]
+ #[allow(deprecated)]
+ pub fn date(&self) -> Date<Tz> {
+ Date::from_utc(self.naive_local().date(), self.offset.clone())
+ }
+
+ /// Retrieves the Date without an associated timezone
+ ///
+ /// [`NaiveDate`] is a more well-defined type, and has more traits implemented on it,
+ /// so should be preferred to [`Date`] any time you truly want to operate on Dates.
+ ///
+ /// ```
+ /// use chrono::prelude::*;
+ ///
+ /// let date: DateTime<Utc> = Utc.with_ymd_and_hms(2020, 1, 1, 0, 0, 0).unwrap();
+ /// let other: DateTime<FixedOffset> = FixedOffset::east_opt(23).unwrap().with_ymd_and_hms(2020, 1, 1, 0, 0, 0).unwrap();
+ /// assert_eq!(date.date_naive(), other.date_naive());
+ /// ```
+ #[inline]
+ pub fn date_naive(&self) -> NaiveDate {
+ let local = self.naive_local();
+ NaiveDate::from_ymd_opt(local.year(), local.month(), local.day()).unwrap()
+ }
+
+ /// Retrieves a time component.
+ /// Unlike `date`, this is not associated to the time zone.
+ #[inline]
+ pub fn time(&self) -> NaiveTime {
+ self.datetime.time() + self.offset.fix()
+ }
+
+ /// Returns the number of non-leap seconds since January 1, 1970 0:00:00 UTC
+ /// (aka "UNIX timestamp").
+ #[inline]
+ pub fn timestamp(&self) -> i64 {
+ self.datetime.timestamp()
+ }
+
+ /// Returns the number of non-leap-milliseconds since January 1, 1970 UTC
+ ///
+ /// Note that this does reduce the number of years that can be represented
+ /// from ~584 Billion to ~584 Million. (If this is a problem, please file
+ /// an issue to let me know what domain needs millisecond precision over
+ /// billions of years, I'm curious.)
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use chrono::{Utc, TimeZone, 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);
+ ///
+ /// let dt = NaiveDate::from_ymd_opt(2001, 9, 9).unwrap().and_hms_milli_opt(1, 46, 40, 555).unwrap().and_local_timezone(Utc).unwrap();
+ /// assert_eq!(dt.timestamp_millis(), 1_000_000_000_555);
+ /// ```
+ #[inline]
+ pub fn timestamp_millis(&self) -> i64 {
+ self.datetime.timestamp_millis()
+ }
+
+ /// Returns the number of non-leap-microseconds since January 1, 1970 UTC
+ ///
+ /// Note that this does reduce the number of years that can be represented
+ /// from ~584 Billion to ~584 Thousand. (If this is a problem, please file
+ /// an issue to let me know what domain needs microsecond precision over
+ /// millennia, I'm curious.)
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use chrono::{Utc, TimeZone, 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);
+ ///
+ /// let dt = NaiveDate::from_ymd_opt(2001, 9, 9).unwrap().and_hms_micro_opt(1, 46, 40, 555).unwrap().and_local_timezone(Utc).unwrap();
+ /// assert_eq!(dt.timestamp_micros(), 1_000_000_000_000_555);
+ /// ```
+ #[inline]
+ pub fn timestamp_micros(&self) -> i64 {
+ self.datetime.timestamp_micros()
+ }
+
+ /// Returns the number of non-leap-nanoseconds since January 1, 1970 UTC
+ ///
+ /// Note that this does reduce the number of years that can be represented
+ /// from ~584 Billion to ~584. (If this is a problem, please file
+ /// an issue to let me know what domain needs nanosecond precision over
+ /// millennia, I'm curious.)
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use chrono::{Utc, TimeZone, 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);
+ ///
+ /// let dt = NaiveDate::from_ymd_opt(2001, 9, 9).unwrap().and_hms_nano_opt(1, 46, 40, 555).unwrap().and_local_timezone(Utc).unwrap();
+ /// assert_eq!(dt.timestamp_nanos(), 1_000_000_000_000_000_555);
+ /// ```
+ #[inline]
+ pub fn timestamp_nanos(&self) -> i64 {
+ self.datetime.timestamp_nanos()
+ }
+
+ /// Returns the number of milliseconds since the last second boundary
+ ///
+ /// warning: in event of a leap second, this may exceed 999
+ ///
+ /// note: this is not the number of milliseconds since January 1, 1970 0:00:00 UTC
+ #[inline]
+ pub fn timestamp_subsec_millis(&self) -> u32 {
+ self.datetime.timestamp_subsec_millis()
+ }
+
+ /// Returns the number of microseconds since the last second boundary
+ ///
+ /// warning: in event of a leap second, this may exceed 999_999
+ ///
+ /// note: this is not the number of microseconds since January 1, 1970 0:00:00 UTC
+ #[inline]
+ pub fn timestamp_subsec_micros(&self) -> u32 {
+ self.datetime.timestamp_subsec_micros()
+ }
+
+ /// Returns the number of nanoseconds since the last second boundary
+ ///
+ /// warning: in event of a leap second, this may exceed 999_999_999
+ ///
+ /// note: this is not the number of nanoseconds since January 1, 1970 0:00:00 UTC
+ #[inline]
+ pub fn timestamp_subsec_nanos(&self) -> u32 {
+ self.datetime.timestamp_subsec_nanos()
+ }
+
+ /// Retrieves an associated offset from UTC.
+ #[inline]
+ pub fn offset(&self) -> &Tz::Offset {
+ &self.offset
+ }
+
+ /// Retrieves an associated time zone.
+ #[inline]
+ pub fn timezone(&self) -> Tz {
+ TimeZone::from_offset(&self.offset)
+ }
+
+ /// Changes the associated time zone.
+ /// The returned `DateTime` references the same instant of time from the perspective of the provided time zone.
+ #[inline]
+ pub fn with_timezone<Tz2: TimeZone>(&self, tz: &Tz2) -> DateTime<Tz2> {
+ tz.from_utc_datetime(&self.datetime)
+ }
+
+ /// Adds given `Duration` to the current date and time.
+ ///
+ /// Returns `None` when it will result in overflow.
+ #[inline]
+ pub fn checked_add_signed(self, rhs: OldDuration) -> Option<DateTime<Tz>> {
+ let datetime = self.datetime.checked_add_signed(rhs)?;
+ let tz = self.timezone();
+ Some(tz.from_utc_datetime(&datetime))
+ }
+
+ /// Adds given `Months` to the current date and time.
+ ///
+ /// Returns `None` when it will result in overflow, or if the
+ /// local time is not valid on the newly calculated date.
+ ///
+ /// See [`NaiveDate::checked_add_months`] for more details on behavior
+ pub fn checked_add_months(self, rhs: Months) -> Option<DateTime<Tz>> {
+ self.naive_local()
+ .checked_add_months(rhs)?
+ .and_local_timezone(Tz::from_offset(&self.offset))
+ .single()
+ }
+
+ /// Subtracts given `Duration` from the current date and time.
+ ///
+ /// Returns `None` when it will result in overflow.
+ #[inline]
+ pub fn checked_sub_signed(self, rhs: OldDuration) -> Option<DateTime<Tz>> {
+ let datetime = self.datetime.checked_sub_signed(rhs)?;
+ let tz = self.timezone();
+ Some(tz.from_utc_datetime(&datetime))
+ }
+
+ /// Subtracts given `Months` from the current date and time.
+ ///
+ /// Returns `None` when it will result in overflow, or if the
+ /// local time is not valid on the newly calculated date.
+ ///
+ /// See [`NaiveDate::checked_sub_months`] for more details on behavior
+ pub fn checked_sub_months(self, rhs: Months) -> Option<DateTime<Tz>> {
+ self.naive_local()
+ .checked_sub_months(rhs)?
+ .and_local_timezone(Tz::from_offset(&self.offset))
+ .single()
+ }
+
+ /// Add a duration in [`Days`] to the date part of the `DateTime`
+ ///
+ /// Returns `None` if the resulting date would be out of range.
+ pub fn checked_add_days(self, days: Days) -> Option<Self> {
+ self.naive_local()
+ .checked_add_days(days)?
+ .and_local_timezone(TimeZone::from_offset(&self.offset))
+ .single()
+ }
+
+ /// Subtract a duration in [`Days`] from the date part of the `DateTime`
+ ///
+ /// Returns `None` if the resulting date would be out of range.
+ pub fn checked_sub_days(self, days: Days) -> Option<Self> {
+ self.naive_local()
+ .checked_sub_days(days)?
+ .and_local_timezone(TimeZone::from_offset(&self.offset))
+ .single()
+ }
+
+ /// Subtracts another `DateTime` from the current date and time.
+ /// This does not overflow or underflow at all.
+ #[inline]
+ 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]
+ pub fn naive_utc(&self) -> NaiveDateTime {
+ self.datetime
+ }
+
+ /// Returns a view to the naive local datetime.
+ #[inline]
+ pub fn naive_local(&self) -> NaiveDateTime {
+ self.datetime + self.offset.fix()
+ }
+
+ /// Retrieve the elapsed years from now to the given [`DateTime`].
+ pub fn years_since(&self, base: Self) -> Option<u32> {
+ let mut years = self.year() - base.year();
+ let earlier_time =
+ (self.month(), self.day(), self.time()) < (base.month(), base.day(), base.time());
+
+ years -= match earlier_time {
+ true => 1,
+ false => 0,
+ };
+
+ match years >= 0 {
+ true => Some(years as u32),
+ false => None,
+ }
+ }
+
+ /// The minimum possible `DateTime<Utc>`.
+ pub const MIN_UTC: DateTime<Utc> = DateTime { datetime: NaiveDateTime::MIN, offset: Utc };
+ /// The maximum possible `DateTime<Utc>`.
+ pub const MAX_UTC: DateTime<Utc> = DateTime { datetime: NaiveDateTime::MAX, offset: Utc };
+}
+
+impl Default for DateTime<Utc> {
+ fn default() -> Self {
+ Utc.from_utc_datetime(&NaiveDateTime::default())
+ }
+}
+
+#[cfg(feature = "clock")]
+#[cfg_attr(docsrs, doc(cfg(feature = "clock")))]
+impl Default for DateTime<Local> {
+ fn default() -> Self {
+ Local.from_utc_datetime(&NaiveDateTime::default())
+ }
+}
+
+impl Default for DateTime<FixedOffset> {
+ fn default() -> Self {
+ FixedOffset::west_opt(0).unwrap().from_utc_datetime(&NaiveDateTime::default())
+ }
+}
+
+/// Convert a `DateTime<Utc>` instance into a `DateTime<FixedOffset>` instance.
+impl From<DateTime<Utc>> for DateTime<FixedOffset> {
+ /// Convert this `DateTime<Utc>` instance into a `DateTime<FixedOffset>` instance.
+ ///
+ /// Conversion is done via [`DateTime::with_timezone`]. Note that the converted value returned by
+ /// this will be created with a fixed timezone offset of 0.
+ fn from(src: DateTime<Utc>) -> Self {
+ src.with_timezone(&FixedOffset::east_opt(0).unwrap())
+ }
+}
+
+/// Convert a `DateTime<Utc>` instance into a `DateTime<Local>` instance.
+#[cfg(feature = "clock")]
+#[cfg_attr(docsrs, doc(cfg(feature = "clock")))]
+impl From<DateTime<Utc>> for DateTime<Local> {
+ /// Convert this `DateTime<Utc>` instance into a `DateTime<Local>` instance.
+ ///
+ /// Conversion is performed via [`DateTime::with_timezone`], accounting for the difference in timezones.
+ fn from(src: DateTime<Utc>) -> Self {
+ src.with_timezone(&Local)
+ }
+}
+
+/// Convert a `DateTime<FixedOffset>` instance into a `DateTime<Utc>` instance.
+impl From<DateTime<FixedOffset>> for DateTime<Utc> {
+ /// Convert this `DateTime<FixedOffset>` instance into a `DateTime<Utc>` instance.
+ ///
+ /// Conversion is performed via [`DateTime::with_timezone`], accounting for the timezone
+ /// difference.
+ fn from(src: DateTime<FixedOffset>) -> Self {
+ src.with_timezone(&Utc)
+ }
+}
+
+/// Convert a `DateTime<FixedOffset>` instance into a `DateTime<Local>` instance.
+#[cfg(feature = "clock")]
+#[cfg_attr(docsrs, doc(cfg(feature = "clock")))]
+impl From<DateTime<FixedOffset>> for DateTime<Local> {
+ /// Convert this `DateTime<FixedOffset>` instance into a `DateTime<Local>` instance.
+ ///
+ /// Conversion is performed via [`DateTime::with_timezone`]. Returns the equivalent value in local
+ /// time.
+ fn from(src: DateTime<FixedOffset>) -> Self {
+ src.with_timezone(&Local)
+ }
+}
+
+/// Convert a `DateTime<Local>` instance into a `DateTime<Utc>` instance.
+#[cfg(feature = "clock")]
+#[cfg_attr(docsrs, doc(cfg(feature = "clock")))]
+impl From<DateTime<Local>> for DateTime<Utc> {
+ /// Convert this `DateTime<Local>` instance into a `DateTime<Utc>` instance.
+ ///
+ /// Conversion is performed via [`DateTime::with_timezone`], accounting for the difference in
+ /// timezones.
+ fn from(src: DateTime<Local>) -> Self {
+ src.with_timezone(&Utc)
+ }
+}
+
+/// Convert a `DateTime<Local>` instance into a `DateTime<FixedOffset>` instance.
+#[cfg(feature = "clock")]
+#[cfg_attr(docsrs, doc(cfg(feature = "clock")))]
+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.
+ fn from(src: DateTime<Local>) -> Self {
+ src.with_timezone(&FixedOffset::east_opt(0).unwrap())
+ }
+}
+
+/// Maps the local datetime to other datetime with given conversion function.
+fn map_local<Tz: TimeZone, F>(dt: &DateTime<Tz>, mut f: F) -> Option<DateTime<Tz>>
+where
+ F: FnMut(NaiveDateTime) -> Option<NaiveDateTime>,
+{
+ f(dt.naive_local()).and_then(|datetime| dt.timezone().from_local_datetime(&datetime).single())
+}
+
+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`].
+ ///
+ /// RFC 2822 is the internet message standard that specifies the
+ /// representation of times in HTTP and email headers.
+ ///
+ /// ```
+ /// # use chrono::{DateTime, FixedOffset, TimeZone, NaiveDate};
+ /// 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()
+ /// );
+ /// ```
+ pub fn parse_from_rfc2822(s: &str) -> ParseResult<DateTime<FixedOffset>> {
+ const ITEMS: &[Item<'static>] = &[Item::Fixed(Fixed::RFC2822)];
+ let mut parsed = Parsed::new();
+ parse(&mut parsed, s, ITEMS.iter())?;
+ 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`].
+ ///
+ /// 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.
+ pub fn parse_from_rfc3339(s: &str) -> ParseResult<DateTime<FixedOffset>> {
+ const ITEMS: &[Item<'static>] = &[Item::Fixed(Fixed::RFC3339)];
+ let mut parsed = Parsed::new();
+ parse(&mut parsed, s, ITEMS.iter())?;
+ parsed.to_datetime()
+ }
+
+ /// Parses a string with the specified format string and returns a new
+ /// [`DateTime`] with a parsed [`FixedOffset`].
+ ///
+ /// 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 string. See
+ /// [`NaiveDateTime::parse_from_str`]
+ /// for a version that does not require a timezone in the to-be-parsed str.
+ ///
+ /// # Example
+ ///
+ /// ```rust
+ /// use chrono::{DateTime, FixedOffset, TimeZone, NaiveDate};
+ ///
+ /// let dt = DateTime::parse_from_str(
+ /// "1983 Apr 13 12:09:14.274 +0000", "%Y %b %d %H:%M:%S%.3f %z");
+ /// assert_eq!(dt, Ok(FixedOffset::east_opt(0).unwrap().from_local_datetime(&NaiveDate::from_ymd_opt(1983, 4, 13).unwrap().and_hms_milli_opt(12, 9, 14, 274).unwrap()).unwrap()));
+ /// ```
+ pub fn parse_from_str(s: &str, fmt: &str) -> ParseResult<DateTime<FixedOffset>> {
+ let mut parsed = Parsed::new();
+ parse(&mut parsed, s, StrftimeItems::new(fmt))?;
+ parsed.to_datetime()
+ }
+}
+
+impl<Tz: TimeZone> DateTime<Tz>
+where
+ Tz::Offset: fmt::Display,
+{
+ /// 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"))))]
+ 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())
+ .expect("writing rfc2822 datetime to string should never fail");
+ result
+ }
+
+ /// 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"))))]
+ 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())
+ .expect("writing rfc3339 datetime to string should never fail");
+ result
+ }
+
+ /// Return an RFC 3339 and ISO 8601 date and time string with subseconds
+ /// formatted as per a `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
+ /// [`Fixed::TimezoneOffsetColon`]
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use chrono::{DateTime, 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");
+ /// assert_eq!(dt.to_rfc3339_opts(SecondsFormat::Millis, true),
+ /// "2018-01-26T18:30:09.453Z");
+ /// assert_eq!(dt.to_rfc3339_opts(SecondsFormat::Secs, true),
+ /// "2018-01-26T18:30:09Z");
+ ///
+ /// let pst = FixedOffset::east_opt(8 * 60 * 60).unwrap();
+ /// let dt = pst.from_local_datetime(&NaiveDate::from_ymd_opt(2018, 1, 26).unwrap().and_hms_micro_opt(10, 30, 9, 453_829).unwrap()).unwrap();
+ /// assert_eq!(dt.to_rfc3339_opts(SecondsFormat::Secs, true),
+ /// "2018-01-26T10:30:09+08:00");
+ /// ```
+ #[cfg(any(feature = "alloc", feature = "std", test))]
+ #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))]
+ pub fn to_rfc3339_opts(&self, secform: SecondsFormat, use_z: bool) -> String {
+ use crate::format::Numeric::*;
+ use crate::format::Pad::Zero;
+ use crate::SecondsFormat::*;
+
+ debug_assert!(secform != __NonExhaustive, "Do not use __NonExhaustive!");
+
+ const PREFIX: &[Item<'static>] = &[
+ Item::Numeric(Year, Zero),
+ Item::Literal("-"),
+ Item::Numeric(Month, Zero),
+ Item::Literal("-"),
+ Item::Numeric(Day, Zero),
+ Item::Literal("T"),
+ Item::Numeric(Hour, Zero),
+ Item::Literal(":"),
+ Item::Numeric(Minute, Zero),
+ Item::Literal(":"),
+ Item::Numeric(Second, Zero),
+ ];
+
+ let ssitem = match secform {
+ Secs => None,
+ Millis => Some(Item::Fixed(Fixed::Nanosecond3)),
+ Micros => Some(Item::Fixed(Fixed::Nanosecond6)),
+ Nanos => Some(Item::Fixed(Fixed::Nanosecond9)),
+ AutoSi => Some(Item::Fixed(Fixed::Nanosecond)),
+ __NonExhaustive => unreachable!(),
+ };
+
+ let tzitem = Item::Fixed(if use_z {
+ Fixed::TimezoneOffsetColonZ
+ } else {
+ Fixed::TimezoneOffsetColon
+ });
+
+ match ssitem {
+ None => self.format_with_items(PREFIX.iter().chain([tzitem].iter())).to_string(),
+ Some(s) => self.format_with_items(PREFIX.iter().chain([s, tzitem].iter())).to_string(),
+ }
+ }
+
+ /// Formats the combined date and time with the specified formatting items.
+ #[cfg(any(feature = "alloc", feature = "std", test))]
+ #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))]
+ #[inline]
+ pub fn format_with_items<'a, I, B>(&self, items: I) -> DelayedFormat<I>
+ where
+ I: Iterator<Item = B> + Clone,
+ B: Borrow<Item<'a>>,
+ {
+ let local = self.naive_local();
+ 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.
+ ///
+ /// # Example
+ /// ```rust
+ /// use chrono::prelude::*;
+ ///
+ /// let date_time: DateTime<Utc> = Utc.with_ymd_and_hms(2017, 04, 02, 12, 50, 32).unwrap();
+ /// let formatted = format!("{}", date_time.format("%d/%m/%Y %H:%M"));
+ /// assert_eq!(formatted, "02/04/2017 12:50");
+ /// ```
+ #[cfg(any(feature = "alloc", feature = "std", test))]
+ #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))]
+ #[inline]
+ pub fn format<'a>(&self, fmt: &'a str) -> DelayedFormat<StrftimeItems<'a>> {
+ self.format_with_items(StrftimeItems::new(fmt))
+ }
+
+ /// Formats the combined date and time with the specified formatting items and locale.
+ #[cfg(feature = "unstable-locales")]
+ #[cfg_attr(docsrs, doc(cfg(feature = "unstable-locales")))]
+ #[inline]
+ pub fn format_localized_with_items<'a, I, B>(
+ &self,
+ items: I,
+ locale: Locale,
+ ) -> DelayedFormat<I>
+ where
+ I: Iterator<Item = B> + Clone,
+ B: Borrow<Item<'a>>,
+ {
+ let local = self.naive_local();
+ DelayedFormat::new_with_offset_and_locale(
+ Some(local.date()),
+ Some(local.time()),
+ &self.offset,
+ items,
+ locale,
+ )
+ }
+
+ /// Formats the combined date and time with the specified format string and
+ /// locale.
+ ///
+ /// See the [`crate::format::strftime`] module on the supported escape
+ /// sequences.
+ #[cfg(feature = "unstable-locales")]
+ #[cfg_attr(docsrs, doc(cfg(feature = "unstable-locales")))]
+ #[inline]
+ pub fn format_localized<'a>(
+ &self,
+ fmt: &'a str,
+ locale: Locale,
+ ) -> DelayedFormat<StrftimeItems<'a>> {
+ self.format_localized_with_items(StrftimeItems::new_with_locale(fmt, locale), locale)
+ }
+}
+
+impl<Tz: TimeZone> Datelike for DateTime<Tz> {
+ #[inline]
+ fn year(&self) -> i32 {
+ self.naive_local().year()
+ }
+ #[inline]
+ fn month(&self) -> u32 {
+ self.naive_local().month()
+ }
+ #[inline]
+ fn month0(&self) -> u32 {
+ self.naive_local().month0()
+ }
+ #[inline]
+ fn day(&self) -> u32 {
+ self.naive_local().day()
+ }
+ #[inline]
+ fn day0(&self) -> u32 {
+ self.naive_local().day0()
+ }
+ #[inline]
+ fn ordinal(&self) -> u32 {
+ self.naive_local().ordinal()
+ }
+ #[inline]
+ fn ordinal0(&self) -> u32 {
+ self.naive_local().ordinal0()
+ }
+ #[inline]
+ fn weekday(&self) -> Weekday {
+ self.naive_local().weekday()
+ }
+ #[inline]
+ fn iso_week(&self) -> IsoWeek {
+ self.naive_local().iso_week()
+ }
+
+ #[inline]
+ fn with_year(&self, year: i32) -> Option<DateTime<Tz>> {
+ map_local(self, |datetime| datetime.with_year(year))
+ }
+
+ #[inline]
+ fn with_month(&self, month: u32) -> Option<DateTime<Tz>> {
+ map_local(self, |datetime| datetime.with_month(month))
+ }
+
+ #[inline]
+ fn with_month0(&self, month0: u32) -> Option<DateTime<Tz>> {
+ map_local(self, |datetime| datetime.with_month0(month0))
+ }
+
+ #[inline]
+ fn with_day(&self, day: u32) -> Option<DateTime<Tz>> {
+ map_local(self, |datetime| datetime.with_day(day))
+ }
+
+ #[inline]
+ fn with_day0(&self, day0: u32) -> Option<DateTime<Tz>> {
+ map_local(self, |datetime| datetime.with_day0(day0))
+ }
+
+ #[inline]
+ fn with_ordinal(&self, ordinal: u32) -> Option<DateTime<Tz>> {
+ map_local(self, |datetime| datetime.with_ordinal(ordinal))
+ }
+
+ #[inline]
+ fn with_ordinal0(&self, ordinal0: u32) -> Option<DateTime<Tz>> {
+ map_local(self, |datetime| datetime.with_ordinal0(ordinal0))
+ }
+}
+
+impl<Tz: TimeZone> Timelike for DateTime<Tz> {
+ #[inline]
+ fn hour(&self) -> u32 {
+ self.naive_local().hour()
+ }
+ #[inline]
+ fn minute(&self) -> u32 {
+ self.naive_local().minute()
+ }
+ #[inline]
+ fn second(&self) -> u32 {
+ self.naive_local().second()
+ }
+ #[inline]
+ fn nanosecond(&self) -> u32 {
+ self.naive_local().nanosecond()
+ }
+
+ #[inline]
+ fn with_hour(&self, hour: u32) -> Option<DateTime<Tz>> {
+ map_local(self, |datetime| datetime.with_hour(hour))
+ }
+
+ #[inline]
+ fn with_minute(&self, min: u32) -> Option<DateTime<Tz>> {
+ map_local(self, |datetime| datetime.with_minute(min))
+ }
+
+ #[inline]
+ fn with_second(&self, sec: u32) -> Option<DateTime<Tz>> {
+ map_local(self, |datetime| datetime.with_second(sec))
+ }
+
+ #[inline]
+ fn with_nanosecond(&self, nano: u32) -> Option<DateTime<Tz>> {
+ map_local(self, |datetime| datetime.with_nanosecond(nano))
+ }
+}
+
+// we need them as automatic impls cannot handle associated types
+impl<Tz: TimeZone> Copy for DateTime<Tz> where <Tz as TimeZone>::Offset: Copy {}
+unsafe impl<Tz: TimeZone> Send for DateTime<Tz> where <Tz as TimeZone>::Offset: Send {}
+
+impl<Tz: TimeZone, Tz2: TimeZone> PartialEq<DateTime<Tz2>> for DateTime<Tz> {
+ fn eq(&self, other: &DateTime<Tz2>) -> bool {
+ self.datetime == other.datetime
+ }
+}
+
+impl<Tz: TimeZone> Eq for DateTime<Tz> {}
+
+impl<Tz: TimeZone, Tz2: TimeZone> PartialOrd<DateTime<Tz2>> for DateTime<Tz> {
+ /// Compare two DateTimes based on their true time, ignoring time zones
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use chrono::prelude::*;
+ ///
+ /// let earlier = Utc.with_ymd_and_hms(2015, 5, 15, 2, 0, 0).unwrap().with_timezone(&FixedOffset::west_opt(1 * 3600).unwrap());
+ /// let later = Utc.with_ymd_and_hms(2015, 5, 15, 3, 0, 0).unwrap().with_timezone(&FixedOffset::west_opt(5 * 3600).unwrap());
+ ///
+ /// assert_eq!(earlier.to_string(), "2015-05-15 01:00:00 -01:00");
+ /// assert_eq!(later.to_string(), "2015-05-14 22:00:00 -05:00");
+ ///
+ /// assert!(later > earlier);
+ /// ```
+ fn partial_cmp(&self, other: &DateTime<Tz2>) -> Option<Ordering> {
+ self.datetime.partial_cmp(&other.datetime)
+ }
+}
+
+impl<Tz: TimeZone> Ord for DateTime<Tz> {
+ fn cmp(&self, other: &DateTime<Tz>) -> Ordering {
+ self.datetime.cmp(&other.datetime)
+ }
+}
+
+impl<Tz: TimeZone> hash::Hash for DateTime<Tz> {
+ fn hash<H: hash::Hasher>(&self, state: &mut H) {
+ self.datetime.hash(state)
+ }
+}
+
+impl<Tz: TimeZone> Add<OldDuration> for DateTime<Tz> {
+ type Output = DateTime<Tz>;
+
+ #[inline]
+ fn add(self, rhs: OldDuration) -> DateTime<Tz> {
+ self.checked_add_signed(rhs).expect("`DateTime + Duration` overflowed")
+ }
+}
+
+impl<Tz: TimeZone> AddAssign<OldDuration> for DateTime<Tz> {
+ #[inline]
+ fn add_assign(&mut self, rhs: OldDuration) {
+ let datetime =
+ self.datetime.checked_add_signed(rhs).expect("`DateTime + Duration` overflowed");
+ let tz = self.timezone();
+ *self = tz.from_utc_datetime(&datetime);
+ }
+}
+
+impl<Tz: TimeZone> Add<Months> for DateTime<Tz> {
+ type Output = DateTime<Tz>;
+
+ fn add(self, rhs: Months) -> Self::Output {
+ self.checked_add_months(rhs).unwrap()
+ }
+}
+
+impl<Tz: TimeZone> Sub<OldDuration> for DateTime<Tz> {
+ type Output = DateTime<Tz>;
+
+ #[inline]
+ fn sub(self, rhs: OldDuration) -> DateTime<Tz> {
+ self.checked_sub_signed(rhs).expect("`DateTime - Duration` overflowed")
+ }
+}
+
+impl<Tz: TimeZone> SubAssign<OldDuration> for DateTime<Tz> {
+ #[inline]
+ fn sub_assign(&mut self, rhs: OldDuration) {
+ let datetime =
+ self.datetime.checked_sub_signed(rhs).expect("`DateTime - Duration` overflowed");
+ let tz = self.timezone();
+ *self = tz.from_utc_datetime(&datetime)
+ }
+}
+
+impl<Tz: TimeZone> Sub<Months> for DateTime<Tz> {
+ type Output = DateTime<Tz>;
+
+ fn sub(self, rhs: Months) -> Self::Output {
+ self.checked_sub_months(rhs).unwrap()
+ }
+}
+
+impl<Tz: TimeZone> Sub<DateTime<Tz>> for DateTime<Tz> {
+ type Output = OldDuration;
+
+ #[inline]
+ fn sub(self, rhs: DateTime<Tz>) -> OldDuration {
+ self.signed_duration_since(rhs)
+ }
+}
+
+impl<Tz: TimeZone> Add<Days> for DateTime<Tz> {
+ type Output = DateTime<Tz>;
+
+ fn add(self, days: Days) -> Self::Output {
+ self.checked_add_days(days).unwrap()
+ }
+}
+
+impl<Tz: TimeZone> Sub<Days> for DateTime<Tz> {
+ type Output = DateTime<Tz>;
+
+ fn sub(self, days: Days) -> Self::Output {
+ self.checked_sub_days(days).unwrap()
+ }
+}
+
+impl<Tz: TimeZone> fmt::Debug for DateTime<Tz> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ self.naive_local().fmt(f)?;
+ self.offset.fmt(f)
+ }
+}
+
+impl<Tz: TimeZone> fmt::Display for DateTime<Tz>
+where
+ Tz::Offset: fmt::Display,
+{
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ self.naive_local().fmt(f)?;
+ f.write_char(' ')?;
+ self.offset.fmt(f)
+ }
+}
+
+/// 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.
+///
+/// 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>>();
+/// ```
+impl str::FromStr for DateTime<Utc> {
+ type Err = ParseError;
+
+ fn from_str(s: &str) -> ParseResult<DateTime<Utc>> {
+ s.parse::<DateTime<FixedOffset>>().map(|dt| dt.with_timezone(&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.
+///
+/// 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>>();
+/// ```
+#[cfg(feature = "clock")]
+#[cfg_attr(docsrs, doc(cfg(feature = "clock")))]
+impl str::FromStr for DateTime<Local> {
+ type Err = ParseError;
+
+ fn from_str(s: &str) -> ParseResult<DateTime<Local>> {
+ s.parse::<DateTime<FixedOffset>>().map(|dt| dt.with_timezone(&Local))
+ }
+}
+
+#[cfg(any(feature = "std", test))]
+#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
+impl From<SystemTime> for DateTime<Utc> {
+ fn from(t: SystemTime) -> DateTime<Utc> {
+ let (sec, nsec) = match t.duration_since(UNIX_EPOCH) {
+ Ok(dur) => (dur.as_secs() as i64, dur.subsec_nanos()),
+ Err(e) => {
+ // unlikely but should be handled
+ let dur = e.duration();
+ let (sec, nsec) = (dur.as_secs() as i64, dur.subsec_nanos());
+ if nsec == 0 {
+ (-sec, 0)
+ } else {
+ (-sec - 1, 1_000_000_000 - nsec)
+ }
+ }
+ };
+ Utc.timestamp_opt(sec, nsec).unwrap()
+ }
+}
+
+#[cfg(feature = "clock")]
+#[cfg_attr(docsrs, doc(cfg(feature = "clock")))]
+impl From<SystemTime> for DateTime<Local> {
+ fn from(t: SystemTime) -> DateTime<Local> {
+ DateTime::<Utc>::from(t).with_timezone(&Local)
+ }
+}
+
+#[cfg(any(feature = "std", test))]
+#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
+impl<Tz: TimeZone> From<DateTime<Tz>> for SystemTime {
+ fn from(dt: DateTime<Tz>) -> SystemTime {
+ use std::time::Duration;
+
+ let sec = dt.timestamp();
+ let nsec = dt.timestamp_subsec_nanos();
+ if sec < 0 {
+ // unlikely but should be handled
+ UNIX_EPOCH - Duration::new(-sec as u64, 0) + Duration::new(0, nsec)
+ } else {
+ UNIX_EPOCH + Duration::new(sec as u64, nsec)
+ }
+ }
+}
+
+#[cfg(all(
+ target_arch = "wasm32",
+ feature = "wasmbind",
+ not(any(target_os = "emscripten", target_os = "wasi"))
+))]
+#[cfg_attr(
+ docsrs,
+ doc(cfg(all(
+ target_arch = "wasm32",
+ feature = "wasmbind",
+ not(any(target_os = "emscripten", target_os = "wasi"))
+ )))
+)]
+impl From<js_sys::Date> for DateTime<Utc> {
+ fn from(date: js_sys::Date) -> DateTime<Utc> {
+ DateTime::<Utc>::from(&date)
+ }
+}
+
+#[cfg(all(
+ target_arch = "wasm32",
+ feature = "wasmbind",
+ not(any(target_os = "emscripten", target_os = "wasi"))
+))]
+#[cfg_attr(
+ docsrs,
+ doc(cfg(all(
+ target_arch = "wasm32",
+ feature = "wasmbind",
+ not(any(target_os = "emscripten", target_os = "wasi"))
+ )))
+)]
+impl From<&js_sys::Date> for DateTime<Utc> {
+ fn from(date: &js_sys::Date) -> DateTime<Utc> {
+ Utc.timestamp_millis_opt(date.get_time() as i64).unwrap()
+ }
+}
+
+#[cfg(all(
+ target_arch = "wasm32",
+ feature = "wasmbind",
+ not(any(target_os = "emscripten", target_os = "wasi"))
+))]
+#[cfg_attr(
+ docsrs,
+ doc(cfg(all(
+ target_arch = "wasm32",
+ feature = "wasmbind",
+ not(any(target_os = "emscripten", target_os = "wasi"))
+ )))
+)]
+impl From<DateTime<Utc>> for js_sys::Date {
+ /// Converts a `DateTime<Utc>` to a JS `Date`. The resulting value may be lossy,
+ /// any values that have a millisecond timestamp value greater/less than ±8,640,000,000,000,000
+ /// (April 20, 271821 BCE ~ September 13, 275760 CE) will become invalid dates in JS.
+ fn from(date: DateTime<Utc>) -> js_sys::Date {
+ let js_millis = wasm_bindgen::JsValue::from_f64(date.timestamp_millis() as f64);
+ js_sys::Date::new(&js_millis)
+ }
+}
+
+// Note that implementation of Arbitrary cannot be simply derived for DateTime<Tz>, due to
+// the nontrivial bound <Tz as TimeZone>::Offset: Arbitrary.
+#[cfg(feature = "arbitrary")]
+impl<'a, Tz> arbitrary::Arbitrary<'a> for DateTime<Tz>
+where
+ Tz: TimeZone,
+ <Tz as TimeZone>::Offset: arbitrary::Arbitrary<'a>,
+{
+ fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<DateTime<Tz>> {
+ let datetime = NaiveDateTime::arbitrary(u)?;
+ let offset = <Tz as TimeZone>::Offset::arbitrary(u)?;
+ Ok(DateTime::from_utc(datetime, offset))
+ }
+}
+
+#[test]
+fn test_add_sub_months() {
+ let utc_dt = Utc.with_ymd_and_hms(2018, 9, 5, 23, 58, 0).unwrap();
+ assert_eq!(utc_dt + Months::new(15), Utc.with_ymd_and_hms(2019, 12, 5, 23, 58, 0).unwrap());
+
+ let utc_dt = Utc.with_ymd_and_hms(2020, 1, 31, 23, 58, 0).unwrap();
+ assert_eq!(utc_dt + Months::new(1), Utc.with_ymd_and_hms(2020, 2, 29, 23, 58, 0).unwrap());
+ assert_eq!(utc_dt + Months::new(2), Utc.with_ymd_and_hms(2020, 3, 31, 23, 58, 0).unwrap());
+
+ let utc_dt = Utc.with_ymd_and_hms(2018, 9, 5, 23, 58, 0).unwrap();
+ assert_eq!(utc_dt - Months::new(15), Utc.with_ymd_and_hms(2017, 6, 5, 23, 58, 0).unwrap());
+
+ let utc_dt = Utc.with_ymd_and_hms(2020, 3, 31, 23, 58, 0).unwrap();
+ assert_eq!(utc_dt - Months::new(1), Utc.with_ymd_and_hms(2020, 2, 29, 23, 58, 0).unwrap());
+ assert_eq!(utc_dt - Months::new(2), Utc.with_ymd_and_hms(2020, 1, 31, 23, 58, 0).unwrap());
+}
+
+#[test]
+fn test_auto_conversion() {
+ let utc_dt = Utc.with_ymd_and_hms(2018, 9, 5, 23, 58, 0).unwrap();
+ let cdt_dt = FixedOffset::west_opt(5 * 60 * 60)
+ .unwrap()
+ .with_ymd_and_hms(2018, 9, 5, 18, 58, 0)
+ .unwrap();
+ let utc_dt2: DateTime<Utc> = cdt_dt.into();
+ assert_eq!(utc_dt, utc_dt2);
+}
+
+#[cfg(all(test, any(feature = "rustc-serialize", feature = "serde")))]
+fn test_encodable_json<FUtc, FFixed, E>(to_string_utc: FUtc, to_string_fixed: FFixed)
+where
+ FUtc: Fn(&DateTime<Utc>) -> Result<String, E>,
+ FFixed: Fn(&DateTime<FixedOffset>) -> Result<String, E>,
+ E: ::core::fmt::Debug,
+{
+ assert_eq!(
+ to_string_utc(&Utc.with_ymd_and_hms(2014, 7, 24, 12, 34, 6).unwrap()).ok(),
+ Some(r#""2014-07-24T12:34:06Z""#.into())
+ );
+
+ assert_eq!(
+ to_string_fixed(
+ &FixedOffset::east_opt(3660).unwrap().with_ymd_and_hms(2014, 7, 24, 12, 34, 6).unwrap()
+ )
+ .ok(),
+ Some(r#""2014-07-24T12:34:06+01:01""#.into())
+ );
+ assert_eq!(
+ to_string_fixed(
+ &FixedOffset::east_opt(3650).unwrap().with_ymd_and_hms(2014, 7, 24, 12, 34, 6).unwrap()
+ )
+ .ok(),
+ Some(r#""2014-07-24T12:34:06+01:00:50""#.into())
+ );
+}
+
+#[cfg(all(test, feature = "clock", any(feature = "rustc-serialize", feature = "serde")))]
+fn test_decodable_json<FUtc, FFixed, FLocal, E>(
+ utc_from_str: FUtc,
+ fixed_from_str: FFixed,
+ local_from_str: FLocal,
+) where
+ FUtc: Fn(&str) -> Result<DateTime<Utc>, E>,
+ FFixed: Fn(&str) -> Result<DateTime<FixedOffset>, E>,
+ FLocal: Fn(&str) -> Result<DateTime<Local>, E>,
+ E: ::core::fmt::Debug,
+{
+ // should check against the offset as well (the normal DateTime comparison will ignore them)
+ fn norm<Tz: TimeZone>(dt: &Option<DateTime<Tz>>) -> Option<(&DateTime<Tz>, &Tz::Offset)> {
+ dt.as_ref().map(|dt| (dt, dt.offset()))
+ }
+
+ assert_eq!(
+ norm(&utc_from_str(r#""2014-07-24T12:34:06Z""#).ok()),
+ norm(&Some(Utc.with_ymd_and_hms(2014, 7, 24, 12, 34, 6).unwrap()))
+ );
+ assert_eq!(
+ norm(&utc_from_str(r#""2014-07-24T13:57:06+01:23""#).ok()),
+ norm(&Some(Utc.with_ymd_and_hms(2014, 7, 24, 12, 34, 6).unwrap()))
+ );
+
+ assert_eq!(
+ norm(&fixed_from_str(r#""2014-07-24T12:34:06Z""#).ok()),
+ norm(&Some(
+ FixedOffset::east_opt(0).unwrap().with_ymd_and_hms(2014, 7, 24, 12, 34, 6).unwrap()
+ ))
+ );
+ assert_eq!(
+ norm(&fixed_from_str(r#""2014-07-24T13:57:06+01:23""#).ok()),
+ norm(&Some(
+ FixedOffset::east_opt(60 * 60 + 23 * 60)
+ .unwrap()
+ .with_ymd_and_hms(2014, 7, 24, 13, 57, 6)
+ .unwrap()
+ ))
+ );
+
+ // we don't know the exact local offset but we can check that
+ // the conversion didn't change the instant itself
+ assert_eq!(
+ local_from_str(r#""2014-07-24T12:34:06Z""#).expect("local shouuld parse"),
+ Utc.with_ymd_and_hms(2014, 7, 24, 12, 34, 6).unwrap()
+ );
+ assert_eq!(
+ local_from_str(r#""2014-07-24T13:57:06+01:23""#).expect("local should parse with offset"),
+ Utc.with_ymd_and_hms(2014, 7, 24, 12, 34, 6).unwrap()
+ );
+
+ assert!(utc_from_str(r#""2014-07-32T12:34:06Z""#).is_err());
+ assert!(fixed_from_str(r#""2014-07-32T12:34:06Z""#).is_err());
+}
+
+#[cfg(all(test, feature = "clock", feature = "rustc-serialize"))]
+fn test_decodable_json_timestamps<FUtc, FFixed, FLocal, E>(
+ utc_from_str: FUtc,
+ fixed_from_str: FFixed,
+ local_from_str: FLocal,
+) where
+ FUtc: Fn(&str) -> Result<rustc_serialize::TsSeconds<Utc>, E>,
+ FFixed: Fn(&str) -> Result<rustc_serialize::TsSeconds<FixedOffset>, E>,
+ FLocal: Fn(&str) -> Result<rustc_serialize::TsSeconds<Local>, E>,
+ E: ::core::fmt::Debug,
+{
+ fn norm<Tz: TimeZone>(dt: &Option<DateTime<Tz>>) -> Option<(&DateTime<Tz>, &Tz::Offset)> {
+ dt.as_ref().map(|dt| (dt, dt.offset()))
+ }
+
+ assert_eq!(
+ norm(&utc_from_str("0").ok().map(DateTime::from)),
+ norm(&Some(Utc.with_ymd_and_hms(1970, 1, 1, 0, 0, 0).unwrap()))
+ );
+ assert_eq!(
+ norm(&utc_from_str("-1").ok().map(DateTime::from)),
+ norm(&Some(Utc.with_ymd_and_hms(1969, 12, 31, 23, 59, 59).unwrap()))
+ );
+
+ assert_eq!(
+ norm(&fixed_from_str("0").ok().map(DateTime::from)),
+ norm(&Some(
+ FixedOffset::east_opt(0).unwrap().with_ymd_and_hms(1970, 1, 1, 0, 0, 0).unwrap()
+ ))
+ );
+ assert_eq!(
+ norm(&fixed_from_str("-1").ok().map(DateTime::from)),
+ norm(&Some(
+ FixedOffset::east_opt(0).unwrap().with_ymd_and_hms(1969, 12, 31, 23, 59, 59).unwrap()
+ ))
+ );
+
+ assert_eq!(
+ *fixed_from_str("0").expect("0 timestamp should parse"),
+ Utc.with_ymd_and_hms(1970, 1, 1, 0, 0, 0).unwrap()
+ );
+ assert_eq!(
+ *local_from_str("-1").expect("-1 timestamp should parse"),
+ Utc.with_ymd_and_hms(1969, 12, 31, 23, 59, 59).unwrap()
+ );
+}
diff --git a/vendor/chrono/src/datetime/rustc_serialize.rs b/vendor/chrono/src/datetime/rustc_serialize.rs
new file mode 100644
index 000000000..18a67d622
--- /dev/null
+++ b/vendor/chrono/src/datetime/rustc_serialize.rs
@@ -0,0 +1,123 @@
+#![cfg_attr(docsrs, doc(cfg(feature = "rustc-serialize")))]
+
+use super::DateTime;
+#[cfg(feature = "clock")]
+use crate::offset::Local;
+use crate::offset::{FixedOffset, LocalResult, TimeZone, Utc};
+use core::fmt;
+use core::ops::Deref;
+use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
+
+impl<Tz: TimeZone> Encodable for DateTime<Tz> {
+ fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
+ format!("{:?}", self).encode(s)
+ }
+}
+
+// lik? function to convert a LocalResult into a serde-ish Result
+fn from<T, D>(me: LocalResult<T>, d: &mut D) -> Result<T, D::Error>
+where
+ D: Decoder,
+ T: fmt::Display,
+{
+ match me {
+ LocalResult::None => Err(d.error("value is not a legal timestamp")),
+ LocalResult::Ambiguous(..) => Err(d.error("value is an ambiguous timestamp")),
+ LocalResult::Single(val) => Ok(val),
+ }
+}
+
+impl Decodable for DateTime<FixedOffset> {
+ fn decode<D: Decoder>(d: &mut D) -> Result<DateTime<FixedOffset>, D::Error> {
+ d.read_str()?.parse::<DateTime<FixedOffset>>().map_err(|_| d.error("invalid date and time"))
+ }
+}
+
+#[allow(deprecated)]
+impl Decodable for TsSeconds<FixedOffset> {
+ #[allow(deprecated)]
+ fn decode<D: Decoder>(d: &mut D) -> Result<TsSeconds<FixedOffset>, D::Error> {
+ from(FixedOffset::east_opt(0).unwrap().timestamp_opt(d.read_i64()?, 0), d).map(TsSeconds)
+ }
+}
+
+impl Decodable for DateTime<Utc> {
+ fn decode<D: Decoder>(d: &mut D) -> Result<DateTime<Utc>, D::Error> {
+ d.read_str()?
+ .parse::<DateTime<FixedOffset>>()
+ .map(|dt| dt.with_timezone(&Utc))
+ .map_err(|_| d.error("invalid date and time"))
+ }
+}
+
+/// A [`DateTime`] that can be deserialized from a timestamp
+///
+/// A timestamp here is seconds since the epoch
+#[derive(Debug)]
+pub struct TsSeconds<Tz: TimeZone>(DateTime<Tz>);
+
+#[allow(deprecated)]
+impl<Tz: TimeZone> From<TsSeconds<Tz>> for DateTime<Tz> {
+ /// Pull the inner `DateTime<Tz>` out
+ #[allow(deprecated)]
+ fn from(obj: TsSeconds<Tz>) -> DateTime<Tz> {
+ obj.0
+ }
+}
+
+#[allow(deprecated)]
+impl<Tz: TimeZone> Deref for TsSeconds<Tz> {
+ type Target = DateTime<Tz>;
+
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+}
+
+#[allow(deprecated)]
+impl Decodable for TsSeconds<Utc> {
+ fn decode<D: Decoder>(d: &mut D) -> Result<TsSeconds<Utc>, D::Error> {
+ from(Utc.timestamp_opt(d.read_i64()?, 0), d).map(TsSeconds)
+ }
+}
+
+#[cfg(feature = "clock")]
+#[cfg_attr(docsrs, doc(cfg(feature = "clock")))]
+impl Decodable for DateTime<Local> {
+ fn decode<D: Decoder>(d: &mut D) -> Result<DateTime<Local>, D::Error> {
+ match d.read_str()?.parse::<DateTime<FixedOffset>>() {
+ Ok(dt) => Ok(dt.with_timezone(&Local)),
+ Err(_) => Err(d.error("invalid date and time")),
+ }
+ }
+}
+
+#[cfg(feature = "clock")]
+#[cfg_attr(docsrs, doc(cfg(feature = "clock")))]
+#[allow(deprecated)]
+impl Decodable for TsSeconds<Local> {
+ #[allow(deprecated)]
+ fn decode<D: Decoder>(d: &mut D) -> Result<TsSeconds<Local>, D::Error> {
+ from(Utc.timestamp_opt(d.read_i64()?, 0), d).map(|dt| TsSeconds(dt.with_timezone(&Local)))
+ }
+}
+
+#[cfg(test)]
+use rustc_serialize::json;
+
+#[test]
+fn test_encodable() {
+ super::test_encodable_json(json::encode, json::encode);
+}
+
+#[cfg(feature = "clock")]
+#[test]
+fn test_decodable() {
+ super::test_decodable_json(json::decode, json::decode, json::decode);
+}
+
+#[cfg(feature = "clock")]
+#[test]
+fn test_decodable_timestamps() {
+ super::test_decodable_json_timestamps(json::decode, json::decode, json::decode);
+}
diff --git a/vendor/chrono/src/datetime/serde.rs b/vendor/chrono/src/datetime/serde.rs
new file mode 100644
index 000000000..ab0126e2b
--- /dev/null
+++ b/vendor/chrono/src/datetime/serde.rs
@@ -0,0 +1,1150 @@
+#![cfg_attr(docsrs, doc(cfg(feature = "serde")))]
+
+use core::fmt;
+use serde::{de, ser};
+
+use super::DateTime;
+use crate::naive::datetime::serde::serde_from;
+#[cfg(feature = "clock")]
+use crate::offset::Local;
+use crate::offset::{FixedOffset, TimeZone, Utc};
+
+#[doc(hidden)]
+#[derive(Debug)]
+pub struct SecondsTimestampVisitor;
+
+#[doc(hidden)]
+#[derive(Debug)]
+pub struct NanoSecondsTimestampVisitor;
+
+#[doc(hidden)]
+#[derive(Debug)]
+pub struct MicroSecondsTimestampVisitor;
+
+#[doc(hidden)]
+#[derive(Debug)]
+pub struct MilliSecondsTimestampVisitor;
+
+/// Serialize into a rfc3339 time string
+///
+/// See [the `serde` module](./serde/index.html) for alternate
+/// serializations.
+impl<Tz: TimeZone> ser::Serialize for DateTime<Tz> {
+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: ser::Serializer,
+ {
+ struct FormatWrapped<'a, D: 'a> {
+ inner: &'a D,
+ }
+
+ impl<'a, D: fmt::Debug> fmt::Display for FormatWrapped<'a, D> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ self.inner.fmt(f)
+ }
+ }
+
+ // Debug formatting is correct RFC3339, and it allows Zulu.
+ serializer.collect_str(&FormatWrapped { inner: &self })
+ }
+}
+
+struct DateTimeVisitor;
+
+impl<'de> de::Visitor<'de> for DateTimeVisitor {
+ type Value = DateTime<FixedOffset>;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("a formatted date and time string or a unix timestamp")
+ }
+
+ fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
+ where
+ E: de::Error,
+ {
+ value.parse().map_err(E::custom)
+ }
+}
+
+/// Deserialize a value that optionally includes a timezone offset in its
+/// string representation
+///
+/// The value to be deserialized must be an rfc3339 string.
+///
+/// See [the `serde` module](./serde/index.html) for alternate
+/// deserialization formats.
+impl<'de> de::Deserialize<'de> for DateTime<FixedOffset> {
+ fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+ where
+ D: de::Deserializer<'de>,
+ {
+ deserializer.deserialize_str(DateTimeVisitor)
+ }
+}
+
+/// Deserialize into a UTC value
+///
+/// The value to be deserialized must be an rfc3339 string.
+///
+/// See [the `serde` module](./serde/index.html) for alternate
+/// deserialization formats.
+impl<'de> de::Deserialize<'de> for DateTime<Utc> {
+ fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+ where
+ D: de::Deserializer<'de>,
+ {
+ deserializer.deserialize_str(DateTimeVisitor).map(|dt| dt.with_timezone(&Utc))
+ }
+}
+
+/// Deserialize a value that includes no timezone in its string
+/// representation
+///
+/// The value to be deserialized must be an rfc3339 string.
+///
+/// See [the `serde` module](./serde/index.html) for alternate
+/// serialization formats.
+#[cfg(feature = "clock")]
+#[cfg_attr(docsrs, doc(cfg(feature = "clock")))]
+impl<'de> de::Deserialize<'de> for DateTime<Local> {
+ fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+ where
+ D: de::Deserializer<'de>,
+ {
+ deserializer.deserialize_str(DateTimeVisitor).map(|dt| dt.with_timezone(&Local))
+ }
+}
+
+/// Ser/de to/from timestamps in nanoseconds
+///
+/// Intended for use with `serde`'s `with` attribute.
+///
+/// # Example:
+///
+/// ```rust
+/// # use chrono::{TimeZone, DateTime, Utc, NaiveDate};
+/// # use serde_derive::{Deserialize, Serialize};
+/// use chrono::serde::ts_nanoseconds;
+/// #[derive(Deserialize, Serialize)]
+/// struct S {
+/// #[serde(with = "ts_nanoseconds")]
+/// time: DateTime<Utc>
+/// }
+///
+/// let time = NaiveDate::from_ymd_opt(2018, 5, 17).unwrap().and_hms_nano_opt(02, 04, 59, 918355733).unwrap().and_local_timezone(Utc).unwrap();
+/// let my_s = S {
+/// time: time.clone(),
+/// };
+///
+/// let as_string = serde_json::to_string(&my_s)?;
+/// assert_eq!(as_string, r#"{"time":1526522699918355733}"#);
+/// let my_s: S = serde_json::from_str(&as_string)?;
+/// assert_eq!(my_s.time, time);
+/// # Ok::<(), serde_json::Error>(())
+/// ```
+pub mod ts_nanoseconds {
+ use core::fmt;
+ use serde::{de, ser};
+
+ use crate::offset::TimeZone;
+ use crate::{DateTime, Utc};
+
+ use super::{serde_from, NanoSecondsTimestampVisitor};
+
+ /// Serialize a UTC datetime into an integer number of nanoseconds since the epoch
+ ///
+ /// Intended for use with `serde`s `serialize_with` attribute.
+ ///
+ /// # Example:
+ ///
+ /// ```rust
+ /// # use chrono::{TimeZone, DateTime, Utc, NaiveDate};
+ /// # use serde_derive::Serialize;
+ /// use chrono::serde::ts_nanoseconds::serialize as to_nano_ts;
+ /// #[derive(Serialize)]
+ /// struct S {
+ /// #[serde(serialize_with = "to_nano_ts")]
+ /// time: DateTime<Utc>
+ /// }
+ ///
+ /// let my_s = S {
+ /// time: NaiveDate::from_ymd_opt(2018, 5, 17).unwrap().and_hms_nano_opt(02, 04, 59, 918355733).unwrap().and_local_timezone(Utc).unwrap(),
+ /// };
+ /// let as_string = serde_json::to_string(&my_s)?;
+ /// assert_eq!(as_string, r#"{"time":1526522699918355733}"#);
+ /// # Ok::<(), serde_json::Error>(())
+ /// ```
+ pub fn serialize<S>(dt: &DateTime<Utc>, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: ser::Serializer,
+ {
+ serializer.serialize_i64(dt.timestamp_nanos())
+ }
+
+ /// Deserialize a [`DateTime`] from a nanosecond timestamp
+ ///
+ /// Intended for use with `serde`s `deserialize_with` attribute.
+ ///
+ /// # Example:
+ ///
+ /// ```rust
+ /// # use chrono::{DateTime, Utc};
+ /// # use serde_derive::Deserialize;
+ /// use chrono::serde::ts_nanoseconds::deserialize as from_nano_ts;
+ /// #[derive(Deserialize)]
+ /// struct S {
+ /// #[serde(deserialize_with = "from_nano_ts")]
+ /// time: DateTime<Utc>
+ /// }
+ ///
+ /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918355733 }"#)?;
+ /// # Ok::<(), serde_json::Error>(())
+ /// ```
+ pub fn deserialize<'de, D>(d: D) -> Result<DateTime<Utc>, D::Error>
+ where
+ D: de::Deserializer<'de>,
+ {
+ d.deserialize_i64(NanoSecondsTimestampVisitor)
+ }
+
+ impl<'de> de::Visitor<'de> for NanoSecondsTimestampVisitor {
+ type Value = DateTime<Utc>;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("a unix timestamp in nanoseconds")
+ }
+
+ /// Deserialize a timestamp in nanoseconds since the epoch
+ fn visit_i64<E>(self, value: i64) -> Result<Self::Value, E>
+ where
+ E: de::Error,
+ {
+ serde_from(
+ Utc.timestamp_opt(value / 1_000_000_000, (value % 1_000_000_000) as u32),
+ &value,
+ )
+ }
+
+ /// Deserialize a timestamp in nanoseconds since the epoch
+ fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
+ where
+ E: de::Error,
+ {
+ serde_from(
+ Utc.timestamp_opt((value / 1_000_000_000) as i64, (value % 1_000_000_000) as u32),
+ &value,
+ )
+ }
+ }
+}
+
+/// Ser/de to/from optional timestamps in nanoseconds
+///
+/// Intended for use with `serde`'s `with` attribute.
+///
+/// # Example:
+///
+/// ```rust
+/// # use chrono::{TimeZone, DateTime, Utc, NaiveDate};
+/// # use serde_derive::{Deserialize, Serialize};
+/// use chrono::serde::ts_nanoseconds_option;
+/// #[derive(Deserialize, Serialize)]
+/// struct S {
+/// #[serde(with = "ts_nanoseconds_option")]
+/// time: Option<DateTime<Utc>>
+/// }
+///
+/// let time = Some(NaiveDate::from_ymd_opt(2018, 5, 17).unwrap().and_hms_nano_opt(02, 04, 59, 918355733).unwrap().and_local_timezone(Utc).unwrap());
+/// let my_s = S {
+/// time: time.clone(),
+/// };
+///
+/// let as_string = serde_json::to_string(&my_s)?;
+/// assert_eq!(as_string, r#"{"time":1526522699918355733}"#);
+/// let my_s: S = serde_json::from_str(&as_string)?;
+/// assert_eq!(my_s.time, time);
+/// # Ok::<(), serde_json::Error>(())
+/// ```
+pub mod ts_nanoseconds_option {
+ use core::fmt;
+ use serde::{de, ser};
+
+ use crate::{DateTime, Utc};
+
+ use super::NanoSecondsTimestampVisitor;
+
+ /// Serialize a UTC datetime into an integer number of nanoseconds since the epoch or none
+ ///
+ /// Intended for use with `serde`s `serialize_with` attribute.
+ ///
+ /// # Example:
+ ///
+ /// ```rust
+ /// # use chrono::{TimeZone, DateTime, Utc, NaiveDate};
+ /// # use serde_derive::Serialize;
+ /// use chrono::serde::ts_nanoseconds_option::serialize as to_nano_tsopt;
+ /// #[derive(Serialize)]
+ /// struct S {
+ /// #[serde(serialize_with = "to_nano_tsopt")]
+ /// time: Option<DateTime<Utc>>
+ /// }
+ ///
+ /// let my_s = S {
+ /// time: Some(NaiveDate::from_ymd_opt(2018, 5, 17).unwrap().and_hms_nano_opt(02, 04, 59, 918355733).unwrap().and_local_timezone(Utc).unwrap()),
+ /// };
+ /// let as_string = serde_json::to_string(&my_s)?;
+ /// assert_eq!(as_string, r#"{"time":1526522699918355733}"#);
+ /// # Ok::<(), serde_json::Error>(())
+ /// ```
+ pub fn serialize<S>(opt: &Option<DateTime<Utc>>, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: ser::Serializer,
+ {
+ match *opt {
+ Some(ref dt) => serializer.serialize_some(&dt.timestamp_nanos()),
+ None => serializer.serialize_none(),
+ }
+ }
+
+ /// Deserialize a `DateTime` from a nanosecond timestamp or none
+ ///
+ /// Intended for use with `serde`s `deserialize_with` attribute.
+ ///
+ /// # Example:
+ ///
+ /// ```rust
+ /// # use chrono::{DateTime, Utc};
+ /// # use serde_derive::Deserialize;
+ /// use chrono::serde::ts_nanoseconds_option::deserialize as from_nano_tsopt;
+ /// #[derive(Deserialize)]
+ /// struct S {
+ /// #[serde(deserialize_with = "from_nano_tsopt")]
+ /// time: Option<DateTime<Utc>>
+ /// }
+ ///
+ /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918355733 }"#)?;
+ /// # Ok::<(), serde_json::Error>(())
+ /// ```
+ pub fn deserialize<'de, D>(d: D) -> Result<Option<DateTime<Utc>>, D::Error>
+ where
+ D: de::Deserializer<'de>,
+ {
+ d.deserialize_option(OptionNanoSecondsTimestampVisitor)
+ }
+
+ struct OptionNanoSecondsTimestampVisitor;
+
+ impl<'de> de::Visitor<'de> for OptionNanoSecondsTimestampVisitor {
+ type Value = Option<DateTime<Utc>>;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("a unix timestamp in nanoseconds or none")
+ }
+
+ /// Deserialize a timestamp in nanoseconds since the epoch
+ fn visit_some<D>(self, d: D) -> Result<Self::Value, D::Error>
+ where
+ D: de::Deserializer<'de>,
+ {
+ d.deserialize_i64(NanoSecondsTimestampVisitor).map(Some)
+ }
+
+ /// Deserialize a timestamp in nanoseconds since the epoch
+ fn visit_none<E>(self) -> Result<Self::Value, E>
+ where
+ E: de::Error,
+ {
+ Ok(None)
+ }
+
+ /// Deserialize a timestamp in nanoseconds since the epoch
+ fn visit_unit<E>(self) -> Result<Self::Value, E>
+ where
+ E: de::Error,
+ {
+ Ok(None)
+ }
+ }
+}
+
+/// Ser/de to/from timestamps in microseconds
+///
+/// Intended for use with `serde`'s `with` attribute.
+///
+/// # Example:
+///
+/// ```rust
+/// # use chrono::{TimeZone, DateTime, Utc, NaiveDate};
+/// # use serde_derive::{Deserialize, Serialize};
+/// use chrono::serde::ts_microseconds;
+/// #[derive(Deserialize, Serialize)]
+/// struct S {
+/// #[serde(with = "ts_microseconds")]
+/// time: DateTime<Utc>
+/// }
+///
+/// let time = NaiveDate::from_ymd_opt(2018, 5, 17).unwrap().and_hms_micro_opt(02, 04, 59, 918355).unwrap().and_local_timezone(Utc).unwrap();
+/// let my_s = S {
+/// time: time.clone(),
+/// };
+///
+/// let as_string = serde_json::to_string(&my_s)?;
+/// assert_eq!(as_string, r#"{"time":1526522699918355}"#);
+/// let my_s: S = serde_json::from_str(&as_string)?;
+/// assert_eq!(my_s.time, time);
+/// # Ok::<(), serde_json::Error>(())
+/// ```
+pub mod ts_microseconds {
+ use core::fmt;
+ use serde::{de, ser};
+
+ use super::{serde_from, MicroSecondsTimestampVisitor};
+ use crate::offset::TimeZone;
+ use crate::{DateTime, Utc};
+
+ /// Serialize a UTC datetime into an integer number of microseconds since the epoch
+ ///
+ /// Intended for use with `serde`s `serialize_with` attribute.
+ ///
+ /// # Example:
+ ///
+ /// ```rust
+ /// # use chrono::{TimeZone, DateTime, Utc, NaiveDate};
+ /// # use serde_derive::Serialize;
+ /// use chrono::serde::ts_microseconds::serialize as to_micro_ts;
+ /// #[derive(Serialize)]
+ /// struct S {
+ /// #[serde(serialize_with = "to_micro_ts")]
+ /// time: DateTime<Utc>
+ /// }
+ ///
+ /// let my_s = S {
+ /// time: NaiveDate::from_ymd_opt(2018, 5, 17).unwrap().and_hms_micro_opt(02, 04, 59, 918355).unwrap().and_local_timezone(Utc).unwrap(),
+ /// };
+ /// let as_string = serde_json::to_string(&my_s)?;
+ /// assert_eq!(as_string, r#"{"time":1526522699918355}"#);
+ /// # Ok::<(), serde_json::Error>(())
+ /// ```
+ pub fn serialize<S>(dt: &DateTime<Utc>, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: ser::Serializer,
+ {
+ serializer.serialize_i64(dt.timestamp_micros())
+ }
+
+ /// Deserialize a `DateTime` from a microsecond timestamp
+ ///
+ /// Intended for use with `serde`s `deserialize_with` attribute.
+ ///
+ /// # Example:
+ ///
+ /// ```rust
+ /// # use chrono::{DateTime, Utc};
+ /// # use serde_derive::Deserialize;
+ /// use chrono::serde::ts_microseconds::deserialize as from_micro_ts;
+ /// #[derive(Deserialize)]
+ /// struct S {
+ /// #[serde(deserialize_with = "from_micro_ts")]
+ /// time: DateTime<Utc>
+ /// }
+ ///
+ /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918355 }"#)?;
+ /// # Ok::<(), serde_json::Error>(())
+ /// ```
+ pub fn deserialize<'de, D>(d: D) -> Result<DateTime<Utc>, D::Error>
+ where
+ D: de::Deserializer<'de>,
+ {
+ d.deserialize_i64(MicroSecondsTimestampVisitor)
+ }
+
+ impl<'de> de::Visitor<'de> for MicroSecondsTimestampVisitor {
+ type Value = DateTime<Utc>;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("a unix timestamp in microseconds")
+ }
+
+ /// Deserialize a timestamp in milliseconds since the epoch
+ fn visit_i64<E>(self, value: i64) -> Result<Self::Value, E>
+ where
+ E: de::Error,
+ {
+ serde_from(
+ Utc.timestamp_opt(value / 1_000_000, ((value % 1_000_000) * 1_000) as u32),
+ &value,
+ )
+ }
+
+ /// Deserialize a timestamp in milliseconds since the epoch
+ fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
+ where
+ E: de::Error,
+ {
+ serde_from(
+ Utc.timestamp_opt((value / 1_000_000) as i64, ((value % 1_000_000) * 1_000) as u32),
+ &value,
+ )
+ }
+ }
+}
+
+/// Ser/de to/from optional timestamps in microseconds
+///
+/// Intended for use with `serde`'s `with` attribute.
+///
+/// # Example:
+///
+/// ```rust
+/// # use chrono::{TimeZone, DateTime, Utc, NaiveDate};
+/// # use serde_derive::{Deserialize, Serialize};
+/// use chrono::serde::ts_microseconds_option;
+/// #[derive(Deserialize, Serialize)]
+/// struct S {
+/// #[serde(with = "ts_microseconds_option")]
+/// time: Option<DateTime<Utc>>
+/// }
+///
+/// let time = Some(NaiveDate::from_ymd_opt(2018, 5, 17).unwrap().and_hms_micro_opt(02, 04, 59, 918355).unwrap().and_local_timezone(Utc).unwrap());
+/// let my_s = S {
+/// time: time.clone(),
+/// };
+///
+/// let as_string = serde_json::to_string(&my_s)?;
+/// assert_eq!(as_string, r#"{"time":1526522699918355}"#);
+/// let my_s: S = serde_json::from_str(&as_string)?;
+/// assert_eq!(my_s.time, time);
+/// # Ok::<(), serde_json::Error>(())
+/// ```
+pub mod ts_microseconds_option {
+ use core::fmt;
+ use serde::{de, ser};
+
+ use super::MicroSecondsTimestampVisitor;
+ use crate::{DateTime, Utc};
+
+ /// Serialize a UTC datetime into an integer number of microseconds since the epoch or none
+ ///
+ /// Intended for use with `serde`s `serialize_with` attribute.
+ ///
+ /// # Example:
+ ///
+ /// ```rust
+ /// # use chrono::{TimeZone, DateTime, Utc, NaiveDate};
+ /// # use serde_derive::Serialize;
+ /// use chrono::serde::ts_microseconds_option::serialize as to_micro_tsopt;
+ /// #[derive(Serialize)]
+ /// struct S {
+ /// #[serde(serialize_with = "to_micro_tsopt")]
+ /// time: Option<DateTime<Utc>>
+ /// }
+ ///
+ /// let my_s = S {
+ /// time: Some(NaiveDate::from_ymd_opt(2018, 5, 17).unwrap().and_hms_micro_opt(02, 04, 59, 918355).unwrap().and_local_timezone(Utc).unwrap()),
+ /// };
+ /// let as_string = serde_json::to_string(&my_s)?;
+ /// assert_eq!(as_string, r#"{"time":1526522699918355}"#);
+ /// # Ok::<(), serde_json::Error>(())
+ /// ```
+ pub fn serialize<S>(opt: &Option<DateTime<Utc>>, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: ser::Serializer,
+ {
+ match *opt {
+ Some(ref dt) => serializer.serialize_some(&dt.timestamp_micros()),
+ None => serializer.serialize_none(),
+ }
+ }
+
+ /// Deserialize a `DateTime` from a microsecond timestamp or none
+ ///
+ /// Intended for use with `serde`s `deserialize_with` attribute.
+ ///
+ /// # Example:
+ ///
+ /// ```rust
+ /// # use chrono::{DateTime, Utc};
+ /// # use serde_derive::Deserialize;
+ /// use chrono::serde::ts_microseconds_option::deserialize as from_micro_tsopt;
+ /// #[derive(Deserialize)]
+ /// struct S {
+ /// #[serde(deserialize_with = "from_micro_tsopt")]
+ /// time: Option<DateTime<Utc>>
+ /// }
+ ///
+ /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918355 }"#)?;
+ /// # Ok::<(), serde_json::Error>(())
+ /// ```
+ pub fn deserialize<'de, D>(d: D) -> Result<Option<DateTime<Utc>>, D::Error>
+ where
+ D: de::Deserializer<'de>,
+ {
+ d.deserialize_option(OptionMicroSecondsTimestampVisitor)
+ }
+
+ struct OptionMicroSecondsTimestampVisitor;
+
+ impl<'de> de::Visitor<'de> for OptionMicroSecondsTimestampVisitor {
+ type Value = Option<DateTime<Utc>>;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("a unix timestamp in microseconds or none")
+ }
+
+ /// Deserialize a timestamp in microseconds since the epoch
+ fn visit_some<D>(self, d: D) -> Result<Self::Value, D::Error>
+ where
+ D: de::Deserializer<'de>,
+ {
+ d.deserialize_i64(MicroSecondsTimestampVisitor).map(Some)
+ }
+
+ /// Deserialize a timestamp in microseconds since the epoch
+ fn visit_none<E>(self) -> Result<Self::Value, E>
+ where
+ E: de::Error,
+ {
+ Ok(None)
+ }
+
+ /// Deserialize a timestamp in microseconds since the epoch
+ fn visit_unit<E>(self) -> Result<Self::Value, E>
+ where
+ E: de::Error,
+ {
+ Ok(None)
+ }
+ }
+}
+
+/// Ser/de to/from timestamps in milliseconds
+///
+/// Intended for use with `serde`s `with` attribute.
+///
+/// # Example
+///
+/// ```rust
+/// # use chrono::{TimeZone, DateTime, Utc, NaiveDate};
+/// # use serde_derive::{Deserialize, Serialize};
+/// use chrono::serde::ts_milliseconds;
+/// #[derive(Deserialize, Serialize)]
+/// struct S {
+/// #[serde(with = "ts_milliseconds")]
+/// time: DateTime<Utc>
+/// }
+///
+/// let time = NaiveDate::from_ymd_opt(2018, 5, 17).unwrap().and_hms_milli_opt(02, 04, 59, 918).unwrap().and_local_timezone(Utc).unwrap();
+/// let my_s = S {
+/// time: time.clone(),
+/// };
+///
+/// let as_string = serde_json::to_string(&my_s)?;
+/// assert_eq!(as_string, r#"{"time":1526522699918}"#);
+/// let my_s: S = serde_json::from_str(&as_string)?;
+/// assert_eq!(my_s.time, time);
+/// # Ok::<(), serde_json::Error>(())
+/// ```
+pub mod ts_milliseconds {
+ use core::fmt;
+ use serde::{de, ser};
+
+ use super::{serde_from, MilliSecondsTimestampVisitor};
+ use crate::offset::TimeZone;
+ use crate::{DateTime, Utc};
+
+ /// Serialize a UTC datetime into an integer number of milliseconds since the epoch
+ ///
+ /// Intended for use with `serde`s `serialize_with` attribute.
+ ///
+ /// # Example:
+ ///
+ /// ```rust
+ /// # use chrono::{TimeZone, DateTime, Utc, NaiveDate};
+ /// # use serde_derive::Serialize;
+ /// use chrono::serde::ts_milliseconds::serialize as to_milli_ts;
+ /// #[derive(Serialize)]
+ /// struct S {
+ /// #[serde(serialize_with = "to_milli_ts")]
+ /// time: DateTime<Utc>
+ /// }
+ ///
+ /// let my_s = S {
+ /// time: NaiveDate::from_ymd_opt(2018, 5, 17).unwrap().and_hms_milli_opt(02, 04, 59, 918).unwrap().and_local_timezone(Utc).unwrap(),
+ /// };
+ /// let as_string = serde_json::to_string(&my_s)?;
+ /// assert_eq!(as_string, r#"{"time":1526522699918}"#);
+ /// # Ok::<(), serde_json::Error>(())
+ /// ```
+ pub fn serialize<S>(dt: &DateTime<Utc>, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: ser::Serializer,
+ {
+ serializer.serialize_i64(dt.timestamp_millis())
+ }
+
+ /// Deserialize a `DateTime` from a millisecond timestamp
+ ///
+ /// Intended for use with `serde`s `deserialize_with` attribute.
+ ///
+ /// # Example:
+ ///
+ /// ```rust
+ /// # use chrono::{DateTime, Utc};
+ /// # use serde_derive::Deserialize;
+ /// use chrono::serde::ts_milliseconds::deserialize as from_milli_ts;
+ /// #[derive(Deserialize)]
+ /// struct S {
+ /// #[serde(deserialize_with = "from_milli_ts")]
+ /// time: DateTime<Utc>
+ /// }
+ ///
+ /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918 }"#)?;
+ /// # Ok::<(), serde_json::Error>(())
+ /// ```
+ pub fn deserialize<'de, D>(d: D) -> Result<DateTime<Utc>, D::Error>
+ where
+ D: de::Deserializer<'de>,
+ {
+ d.deserialize_i64(MilliSecondsTimestampVisitor).map(|dt| dt.with_timezone(&Utc))
+ }
+
+ impl<'de> de::Visitor<'de> for MilliSecondsTimestampVisitor {
+ type Value = DateTime<Utc>;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("a unix timestamp in milliseconds")
+ }
+
+ /// Deserialize a timestamp in milliseconds since the epoch
+ fn visit_i64<E>(self, value: i64) -> Result<Self::Value, E>
+ where
+ E: de::Error,
+ {
+ serde_from(Utc.timestamp_opt(value / 1000, ((value % 1000) * 1_000_000) as u32), &value)
+ }
+
+ /// Deserialize a timestamp in milliseconds since the epoch
+ fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
+ where
+ E: de::Error,
+ {
+ serde_from(
+ Utc.timestamp_opt((value / 1000) as i64, ((value % 1000) * 1_000_000) as u32),
+ &value,
+ )
+ }
+ }
+}
+
+/// Ser/de to/from optional timestamps in milliseconds
+///
+/// Intended for use with `serde`s `with` attribute.
+///
+/// # Example
+///
+/// ```rust
+/// # use chrono::{TimeZone, DateTime, Utc, NaiveDate};
+/// # use serde_derive::{Deserialize, Serialize};
+/// use chrono::serde::ts_milliseconds_option;
+/// #[derive(Deserialize, Serialize)]
+/// struct S {
+/// #[serde(with = "ts_milliseconds_option")]
+/// time: Option<DateTime<Utc>>
+/// }
+///
+/// let time = Some(NaiveDate::from_ymd_opt(2018, 5, 17).unwrap().and_hms_milli_opt(02, 04, 59, 918).unwrap().and_local_timezone(Utc).unwrap());
+/// let my_s = S {
+/// time: time.clone(),
+/// };
+///
+/// let as_string = serde_json::to_string(&my_s)?;
+/// assert_eq!(as_string, r#"{"time":1526522699918}"#);
+/// let my_s: S = serde_json::from_str(&as_string)?;
+/// assert_eq!(my_s.time, time);
+/// # Ok::<(), serde_json::Error>(())
+/// ```
+pub mod ts_milliseconds_option {
+ use core::fmt;
+ use serde::{de, ser};
+
+ use super::MilliSecondsTimestampVisitor;
+ use crate::{DateTime, Utc};
+
+ /// Serialize a UTC datetime into an integer number of milliseconds since the epoch or none
+ ///
+ /// Intended for use with `serde`s `serialize_with` attribute.
+ ///
+ /// # Example:
+ ///
+ /// ```rust
+ /// # use chrono::{TimeZone, DateTime, Utc, NaiveDate};
+ /// # use serde_derive::Serialize;
+ /// use chrono::serde::ts_milliseconds_option::serialize as to_milli_tsopt;
+ /// #[derive(Serialize)]
+ /// struct S {
+ /// #[serde(serialize_with = "to_milli_tsopt")]
+ /// time: Option<DateTime<Utc>>
+ /// }
+ ///
+ /// let my_s = S {
+ /// time: Some(NaiveDate::from_ymd_opt(2018, 5, 17).unwrap().and_hms_milli_opt(02, 04, 59, 918).unwrap().and_local_timezone(Utc).unwrap()),
+ /// };
+ /// let as_string = serde_json::to_string(&my_s)?;
+ /// assert_eq!(as_string, r#"{"time":1526522699918}"#);
+ /// # Ok::<(), serde_json::Error>(())
+ /// ```
+ pub fn serialize<S>(opt: &Option<DateTime<Utc>>, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: ser::Serializer,
+ {
+ match *opt {
+ Some(ref dt) => serializer.serialize_some(&dt.timestamp_millis()),
+ None => serializer.serialize_none(),
+ }
+ }
+
+ /// Deserialize a `DateTime` from a millisecond timestamp or none
+ ///
+ /// Intended for use with `serde`s `deserialize_with` attribute.
+ ///
+ /// # Example:
+ ///
+ /// ```rust
+ /// # use chrono::{TimeZone, DateTime, Utc};
+ /// # use serde_derive::Deserialize;
+ /// use chrono::serde::ts_milliseconds_option::deserialize as from_milli_tsopt;
+ ///
+ /// #[derive(Deserialize, PartialEq, Debug)]
+ /// #[serde(untagged)]
+ /// enum E<T> {
+ /// V(T),
+ /// }
+ ///
+ /// #[derive(Deserialize, PartialEq, Debug)]
+ /// struct S {
+ /// #[serde(default, deserialize_with = "from_milli_tsopt")]
+ /// time: Option<DateTime<Utc>>
+ /// }
+ ///
+ /// 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)) }));
+ /// 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>(())
+ /// ```
+ pub fn deserialize<'de, D>(d: D) -> Result<Option<DateTime<Utc>>, D::Error>
+ where
+ D: de::Deserializer<'de>,
+ {
+ d.deserialize_option(OptionMilliSecondsTimestampVisitor)
+ .map(|opt| opt.map(|dt| dt.with_timezone(&Utc)))
+ }
+
+ struct OptionMilliSecondsTimestampVisitor;
+
+ impl<'de> de::Visitor<'de> for OptionMilliSecondsTimestampVisitor {
+ type Value = Option<DateTime<Utc>>;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("a unix timestamp in milliseconds or none")
+ }
+
+ /// Deserialize a timestamp in milliseconds since the epoch
+ fn visit_some<D>(self, d: D) -> Result<Self::Value, D::Error>
+ where
+ D: de::Deserializer<'de>,
+ {
+ d.deserialize_i64(MilliSecondsTimestampVisitor).map(Some)
+ }
+
+ /// Deserialize a timestamp in milliseconds since the epoch
+ fn visit_none<E>(self) -> Result<Self::Value, E>
+ where
+ E: de::Error,
+ {
+ Ok(None)
+ }
+
+ /// Deserialize a timestamp in milliseconds since the epoch
+ fn visit_unit<E>(self) -> Result<Self::Value, E>
+ where
+ E: de::Error,
+ {
+ Ok(None)
+ }
+ }
+}
+
+/// Ser/de to/from timestamps in seconds
+///
+/// Intended for use with `serde`'s `with` attribute.
+///
+/// # Example:
+///
+/// ```rust
+/// # use chrono::{TimeZone, DateTime, Utc};
+/// # use serde_derive::{Deserialize, Serialize};
+/// use chrono::serde::ts_seconds;
+/// #[derive(Deserialize, Serialize)]
+/// struct S {
+/// #[serde(with = "ts_seconds")]
+/// time: DateTime<Utc>
+/// }
+///
+/// let time = Utc.with_ymd_and_hms(2015, 5, 15, 10, 0, 0).unwrap();
+/// let my_s = S {
+/// time: time.clone(),
+/// };
+///
+/// let as_string = serde_json::to_string(&my_s)?;
+/// assert_eq!(as_string, r#"{"time":1431684000}"#);
+/// let my_s: S = serde_json::from_str(&as_string)?;
+/// assert_eq!(my_s.time, time);
+/// # Ok::<(), serde_json::Error>(())
+/// ```
+pub mod ts_seconds {
+ use core::fmt;
+ use serde::{de, ser};
+
+ use super::{serde_from, SecondsTimestampVisitor};
+ use crate::offset::TimeZone;
+ use crate::{DateTime, Utc};
+
+ /// Serialize a UTC datetime into an integer number of seconds since the epoch
+ ///
+ /// Intended for use with `serde`s `serialize_with` attribute.
+ ///
+ /// # Example:
+ ///
+ /// ```rust
+ /// # use chrono::{TimeZone, DateTime, Utc};
+ /// # use serde_derive::Serialize;
+ /// use chrono::serde::ts_seconds::serialize as to_ts;
+ /// #[derive(Serialize)]
+ /// struct S {
+ /// #[serde(serialize_with = "to_ts")]
+ /// time: DateTime<Utc>
+ /// }
+ ///
+ /// let my_s = S {
+ /// time: Utc.with_ymd_and_hms(2015, 5, 15, 10, 0, 0).unwrap(),
+ /// };
+ /// let as_string = serde_json::to_string(&my_s)?;
+ /// assert_eq!(as_string, r#"{"time":1431684000}"#);
+ /// # Ok::<(), serde_json::Error>(())
+ /// ```
+ pub fn serialize<S>(dt: &DateTime<Utc>, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: ser::Serializer,
+ {
+ serializer.serialize_i64(dt.timestamp())
+ }
+
+ /// Deserialize a `DateTime` from a seconds timestamp
+ ///
+ /// Intended for use with `serde`s `deserialize_with` attribute.
+ ///
+ /// # Example:
+ ///
+ /// ```rust
+ /// # use chrono::{DateTime, Utc};
+ /// # use serde_derive::Deserialize;
+ /// use chrono::serde::ts_seconds::deserialize as from_ts;
+ /// #[derive(Deserialize)]
+ /// struct S {
+ /// #[serde(deserialize_with = "from_ts")]
+ /// time: DateTime<Utc>
+ /// }
+ ///
+ /// let my_s: S = serde_json::from_str(r#"{ "time": 1431684000 }"#)?;
+ /// # Ok::<(), serde_json::Error>(())
+ /// ```
+ pub fn deserialize<'de, D>(d: D) -> Result<DateTime<Utc>, D::Error>
+ where
+ D: de::Deserializer<'de>,
+ {
+ d.deserialize_i64(SecondsTimestampVisitor)
+ }
+
+ impl<'de> de::Visitor<'de> for SecondsTimestampVisitor {
+ type Value = DateTime<Utc>;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("a unix timestamp in seconds")
+ }
+
+ /// Deserialize a timestamp in seconds since the epoch
+ fn visit_i64<E>(self, value: i64) -> Result<Self::Value, E>
+ where
+ E: de::Error,
+ {
+ serde_from(Utc.timestamp_opt(value, 0), &value)
+ }
+
+ /// Deserialize a timestamp in seconds since the epoch
+ fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
+ where
+ E: de::Error,
+ {
+ serde_from(Utc.timestamp_opt(value as i64, 0), &value)
+ }
+ }
+}
+
+/// Ser/de to/from optional timestamps in seconds
+///
+/// Intended for use with `serde`'s `with` attribute.
+///
+/// # Example:
+///
+/// ```rust
+/// # use chrono::{TimeZone, DateTime, Utc};
+/// # use serde_derive::{Deserialize, Serialize};
+/// use chrono::serde::ts_seconds_option;
+/// #[derive(Deserialize, Serialize)]
+/// struct S {
+/// #[serde(with = "ts_seconds_option")]
+/// time: Option<DateTime<Utc>>
+/// }
+///
+/// let time = Some(Utc.with_ymd_and_hms(2015, 5, 15, 10, 0, 0).unwrap());
+/// let my_s = S {
+/// time: time.clone(),
+/// };
+///
+/// let as_string = serde_json::to_string(&my_s)?;
+/// assert_eq!(as_string, r#"{"time":1431684000}"#);
+/// let my_s: S = serde_json::from_str(&as_string)?;
+/// assert_eq!(my_s.time, time);
+/// # Ok::<(), serde_json::Error>(())
+/// ```
+pub mod ts_seconds_option {
+ use core::fmt;
+ use serde::{de, ser};
+
+ use super::SecondsTimestampVisitor;
+ use crate::{DateTime, Utc};
+
+ /// Serialize a UTC datetime into an integer number of seconds since the epoch or none
+ ///
+ /// Intended for use with `serde`s `serialize_with` attribute.
+ ///
+ /// # Example:
+ ///
+ /// ```rust
+ /// # use chrono::{TimeZone, DateTime, Utc};
+ /// # use serde_derive::Serialize;
+ /// use chrono::serde::ts_seconds_option::serialize as to_tsopt;
+ /// #[derive(Serialize)]
+ /// struct S {
+ /// #[serde(serialize_with = "to_tsopt")]
+ /// time: Option<DateTime<Utc>>
+ /// }
+ ///
+ /// let my_s = S {
+ /// time: Some(Utc.with_ymd_and_hms(2015, 5, 15, 10, 0, 0).unwrap()),
+ /// };
+ /// let as_string = serde_json::to_string(&my_s)?;
+ /// assert_eq!(as_string, r#"{"time":1431684000}"#);
+ /// # Ok::<(), serde_json::Error>(())
+ /// ```
+ pub fn serialize<S>(opt: &Option<DateTime<Utc>>, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: ser::Serializer,
+ {
+ match *opt {
+ Some(ref dt) => serializer.serialize_some(&dt.timestamp()),
+ None => serializer.serialize_none(),
+ }
+ }
+
+ /// Deserialize a `DateTime` from a seconds timestamp or none
+ ///
+ /// Intended for use with `serde`s `deserialize_with` attribute.
+ ///
+ /// # Example:
+ ///
+ /// ```rust
+ /// # use chrono::{DateTime, Utc};
+ /// # use serde_derive::Deserialize;
+ /// use chrono::serde::ts_seconds_option::deserialize as from_tsopt;
+ /// #[derive(Deserialize)]
+ /// struct S {
+ /// #[serde(deserialize_with = "from_tsopt")]
+ /// time: Option<DateTime<Utc>>
+ /// }
+ ///
+ /// let my_s: S = serde_json::from_str(r#"{ "time": 1431684000 }"#)?;
+ /// # Ok::<(), serde_json::Error>(())
+ /// ```
+ pub fn deserialize<'de, D>(d: D) -> Result<Option<DateTime<Utc>>, D::Error>
+ where
+ D: de::Deserializer<'de>,
+ {
+ d.deserialize_option(OptionSecondsTimestampVisitor)
+ }
+
+ struct OptionSecondsTimestampVisitor;
+
+ impl<'de> de::Visitor<'de> for OptionSecondsTimestampVisitor {
+ type Value = Option<DateTime<Utc>>;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("a unix timestamp in seconds or none")
+ }
+
+ /// Deserialize a timestamp in seconds since the epoch
+ fn visit_some<D>(self, d: D) -> Result<Self::Value, D::Error>
+ where
+ D: de::Deserializer<'de>,
+ {
+ d.deserialize_i64(SecondsTimestampVisitor).map(Some)
+ }
+
+ /// Deserialize a timestamp in seconds since the epoch
+ fn visit_none<E>(self) -> Result<Self::Value, E>
+ where
+ E: de::Error,
+ {
+ Ok(None)
+ }
+
+ /// Deserialize a timestamp in seconds since the epoch
+ fn visit_unit<E>(self) -> Result<Self::Value, E>
+ where
+ E: de::Error,
+ {
+ Ok(None)
+ }
+ }
+}
+
+#[test]
+fn test_serde_serialize() {
+ super::test_encodable_json(serde_json::to_string, serde_json::to_string);
+}
+
+#[cfg(feature = "clock")]
+#[test]
+fn test_serde_deserialize() {
+ super::test_decodable_json(
+ |input| serde_json::from_str(input),
+ |input| serde_json::from_str(input),
+ |input| serde_json::from_str(input),
+ );
+}
+
+#[test]
+fn test_serde_bincode() {
+ // Bincode is relevant to test separately from JSON because
+ // it is not self-describing.
+ use bincode::{deserialize, serialize};
+
+ let dt = Utc.with_ymd_and_hms(2014, 7, 24, 12, 34, 6).unwrap();
+ let encoded = serialize(&dt).unwrap();
+ let decoded: DateTime<Utc> = deserialize(&encoded).unwrap();
+ assert_eq!(dt, decoded);
+ assert_eq!(dt.offset(), decoded.offset());
+}
diff --git a/vendor/chrono/src/datetime/tests.rs b/vendor/chrono/src/datetime/tests.rs
new file mode 100644
index 000000000..ebd32cae9
--- /dev/null
+++ b/vendor/chrono/src/datetime/tests.rs
@@ -0,0 +1,952 @@
+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};
+
+#[derive(Clone)]
+struct DstTester;
+
+impl DstTester {
+ fn winter_offset() -> FixedOffset {
+ FixedOffset::east_opt(8 * 60 * 60).unwrap()
+ }
+ fn summer_offset() -> FixedOffset {
+ FixedOffset::east_opt(9 * 60 * 60).unwrap()
+ }
+
+ const TO_WINTER_MONTH_DAY: (u32, u32) = (4, 15);
+ const TO_SUMMER_MONTH_DAY: (u32, u32) = (9, 15);
+
+ fn transition_start_local() -> NaiveTime {
+ NaiveTime::from_hms_opt(2, 0, 0).unwrap()
+ }
+}
+
+impl TimeZone for DstTester {
+ type Offset = FixedOffset;
+
+ fn from_offset(_: &Self::Offset) -> Self {
+ DstTester
+ }
+
+ fn offset_from_local_date(&self, _: &NaiveDate) -> crate::LocalResult<Self::Offset> {
+ unimplemented!()
+ }
+
+ fn offset_from_local_datetime(
+ &self,
+ local: &NaiveDateTime,
+ ) -> crate::LocalResult<Self::Offset> {
+ let local_to_winter_transition_start = NaiveDate::from_ymd_opt(
+ local.year(),
+ DstTester::TO_WINTER_MONTH_DAY.0,
+ DstTester::TO_WINTER_MONTH_DAY.1,
+ )
+ .unwrap()
+ .and_time(DstTester::transition_start_local());
+
+ let local_to_winter_transition_end = NaiveDate::from_ymd_opt(
+ local.year(),
+ DstTester::TO_WINTER_MONTH_DAY.0,
+ DstTester::TO_WINTER_MONTH_DAY.1,
+ )
+ .unwrap()
+ .and_time(DstTester::transition_start_local() - Duration::hours(1));
+
+ let local_to_summer_transition_start = NaiveDate::from_ymd_opt(
+ local.year(),
+ DstTester::TO_SUMMER_MONTH_DAY.0,
+ DstTester::TO_SUMMER_MONTH_DAY.1,
+ )
+ .unwrap()
+ .and_time(DstTester::transition_start_local());
+
+ let local_to_summer_transition_end = NaiveDate::from_ymd_opt(
+ local.year(),
+ DstTester::TO_SUMMER_MONTH_DAY.0,
+ DstTester::TO_SUMMER_MONTH_DAY.1,
+ )
+ .unwrap()
+ .and_time(DstTester::transition_start_local() + Duration::hours(1));
+
+ if *local < local_to_winter_transition_end || *local >= local_to_summer_transition_end {
+ LocalResult::Single(DstTester::summer_offset())
+ } else if *local >= local_to_winter_transition_start
+ && *local < local_to_summer_transition_start
+ {
+ LocalResult::Single(DstTester::winter_offset())
+ } else if *local >= local_to_winter_transition_end
+ && *local < local_to_winter_transition_start
+ {
+ LocalResult::Ambiguous(DstTester::winter_offset(), DstTester::summer_offset())
+ } else if *local >= local_to_summer_transition_start
+ && *local < local_to_summer_transition_end
+ {
+ LocalResult::None
+ } else {
+ panic!("Unexpected local time {}", local)
+ }
+ }
+
+ fn offset_from_utc_date(&self, _: &NaiveDate) -> Self::Offset {
+ unimplemented!()
+ }
+
+ fn offset_from_utc_datetime(&self, utc: &NaiveDateTime) -> Self::Offset {
+ let utc_to_winter_transition = NaiveDate::from_ymd_opt(
+ utc.year(),
+ DstTester::TO_WINTER_MONTH_DAY.0,
+ DstTester::TO_WINTER_MONTH_DAY.1,
+ )
+ .unwrap()
+ .and_time(DstTester::transition_start_local())
+ - DstTester::summer_offset();
+
+ let utc_to_summer_transition = NaiveDate::from_ymd_opt(
+ utc.year(),
+ DstTester::TO_SUMMER_MONTH_DAY.0,
+ DstTester::TO_SUMMER_MONTH_DAY.1,
+ )
+ .unwrap()
+ .and_time(DstTester::transition_start_local())
+ - DstTester::winter_offset();
+
+ if *utc < utc_to_winter_transition || *utc >= utc_to_summer_transition {
+ DstTester::summer_offset()
+ } else if *utc >= utc_to_winter_transition && *utc < utc_to_summer_transition {
+ DstTester::winter_offset()
+ } else {
+ panic!("Unexpected utc time {}", utc)
+ }
+ }
+}
+
+#[test]
+fn test_datetime_add_days() {
+ let est = FixedOffset::west_opt(5 * 60 * 60).unwrap();
+ let kst = FixedOffset::east_opt(9 * 60 * 60).unwrap();
+
+ assert_eq!(
+ format!("{}", est.with_ymd_and_hms(2014, 5, 6, 7, 8, 9).unwrap() + Days::new(5)),
+ "2014-05-11 07:08:09 -05:00"
+ );
+ assert_eq!(
+ format!("{}", kst.with_ymd_and_hms(2014, 5, 6, 7, 8, 9).unwrap() + Days::new(5)),
+ "2014-05-11 07:08:09 +09:00"
+ );
+
+ assert_eq!(
+ format!("{}", est.with_ymd_and_hms(2014, 5, 6, 7, 8, 9).unwrap() + Days::new(35)),
+ "2014-06-10 07:08:09 -05:00"
+ );
+ assert_eq!(
+ format!("{}", kst.with_ymd_and_hms(2014, 5, 6, 7, 8, 9).unwrap() + Days::new(35)),
+ "2014-06-10 07:08:09 +09:00"
+ );
+
+ assert_eq!(
+ format!("{}", DstTester.with_ymd_and_hms(2014, 4, 6, 7, 8, 9).unwrap() + Days::new(5)),
+ "2014-04-11 07:08:09 +09:00"
+ );
+ assert_eq!(
+ format!("{}", DstTester.with_ymd_and_hms(2014, 4, 6, 7, 8, 9).unwrap() + Days::new(10)),
+ "2014-04-16 07:08:09 +08:00"
+ );
+
+ assert_eq!(
+ format!("{}", DstTester.with_ymd_and_hms(2014, 9, 6, 7, 8, 9).unwrap() + Days::new(5)),
+ "2014-09-11 07:08:09 +08:00"
+ );
+ assert_eq!(
+ format!("{}", DstTester.with_ymd_and_hms(2014, 9, 6, 7, 8, 9).unwrap() + Days::new(10)),
+ "2014-09-16 07:08:09 +09:00"
+ );
+}
+
+#[test]
+fn test_datetime_sub_days() {
+ let est = FixedOffset::west_opt(5 * 60 * 60).unwrap();
+ let kst = FixedOffset::east_opt(9 * 60 * 60).unwrap();
+
+ assert_eq!(
+ format!("{}", est.with_ymd_and_hms(2014, 5, 6, 7, 8, 9).unwrap() - Days::new(5)),
+ "2014-05-01 07:08:09 -05:00"
+ );
+ assert_eq!(
+ format!("{}", kst.with_ymd_and_hms(2014, 5, 6, 7, 8, 9).unwrap() - Days::new(5)),
+ "2014-05-01 07:08:09 +09:00"
+ );
+
+ assert_eq!(
+ format!("{}", est.with_ymd_and_hms(2014, 5, 6, 7, 8, 9).unwrap() - Days::new(35)),
+ "2014-04-01 07:08:09 -05:00"
+ );
+ assert_eq!(
+ format!("{}", kst.with_ymd_and_hms(2014, 5, 6, 7, 8, 9).unwrap() - Days::new(35)),
+ "2014-04-01 07:08:09 +09:00"
+ );
+}
+
+#[test]
+fn test_datetime_add_months() {
+ let est = FixedOffset::west_opt(5 * 60 * 60).unwrap();
+ let kst = FixedOffset::east_opt(9 * 60 * 60).unwrap();
+
+ assert_eq!(
+ format!("{}", est.with_ymd_and_hms(2014, 5, 6, 7, 8, 9).unwrap() + Months::new(1)),
+ "2014-06-06 07:08:09 -05:00"
+ );
+ assert_eq!(
+ format!("{}", kst.with_ymd_and_hms(2014, 5, 6, 7, 8, 9).unwrap() + Months::new(1)),
+ "2014-06-06 07:08:09 +09:00"
+ );
+
+ assert_eq!(
+ format!("{}", est.with_ymd_and_hms(2014, 5, 6, 7, 8, 9).unwrap() + Months::new(5)),
+ "2014-10-06 07:08:09 -05:00"
+ );
+ assert_eq!(
+ format!("{}", kst.with_ymd_and_hms(2014, 5, 6, 7, 8, 9).unwrap() + Months::new(5)),
+ "2014-10-06 07:08:09 +09:00"
+ );
+}
+
+#[test]
+fn test_datetime_sub_months() {
+ let est = FixedOffset::west_opt(5 * 60 * 60).unwrap();
+ let kst = FixedOffset::east_opt(9 * 60 * 60).unwrap();
+
+ assert_eq!(
+ format!("{}", est.with_ymd_and_hms(2014, 5, 6, 7, 8, 9).unwrap() - Months::new(1)),
+ "2014-04-06 07:08:09 -05:00"
+ );
+ assert_eq!(
+ format!("{}", kst.with_ymd_and_hms(2014, 5, 6, 7, 8, 9).unwrap() - Months::new(1)),
+ "2014-04-06 07:08:09 +09:00"
+ );
+
+ assert_eq!(
+ format!("{}", est.with_ymd_and_hms(2014, 5, 6, 7, 8, 9).unwrap() - Months::new(5)),
+ "2013-12-06 07:08:09 -05:00"
+ );
+ assert_eq!(
+ format!("{}", kst.with_ymd_and_hms(2014, 5, 6, 7, 8, 9).unwrap() - Months::new(5)),
+ "2013-12-06 07:08:09 +09:00"
+ );
+}
+
+#[test]
+fn test_datetime_offset() {
+ let est = FixedOffset::west_opt(5 * 60 * 60).unwrap();
+ let edt = FixedOffset::west_opt(4 * 60 * 60).unwrap();
+ let kst = FixedOffset::east_opt(9 * 60 * 60).unwrap();
+
+ assert_eq!(
+ format!("{}", Utc.with_ymd_and_hms(2014, 5, 6, 7, 8, 9).unwrap()),
+ "2014-05-06 07:08:09 UTC"
+ );
+ assert_eq!(
+ format!("{}", edt.with_ymd_and_hms(2014, 5, 6, 7, 8, 9).unwrap()),
+ "2014-05-06 07:08:09 -04:00"
+ );
+ assert_eq!(
+ format!("{}", kst.with_ymd_and_hms(2014, 5, 6, 7, 8, 9).unwrap()),
+ "2014-05-06 07:08:09 +09:00"
+ );
+ assert_eq!(
+ format!("{:?}", Utc.with_ymd_and_hms(2014, 5, 6, 7, 8, 9).unwrap()),
+ "2014-05-06T07:08:09Z"
+ );
+ assert_eq!(
+ format!("{:?}", edt.with_ymd_and_hms(2014, 5, 6, 7, 8, 9).unwrap()),
+ "2014-05-06T07:08:09-04:00"
+ );
+ assert_eq!(
+ format!("{:?}", kst.with_ymd_and_hms(2014, 5, 6, 7, 8, 9).unwrap()),
+ "2014-05-06T07:08:09+09:00"
+ );
+
+ // edge cases
+ assert_eq!(
+ format!("{:?}", Utc.with_ymd_and_hms(2014, 5, 6, 0, 0, 0).unwrap()),
+ "2014-05-06T00:00:00Z"
+ );
+ assert_eq!(
+ format!("{:?}", edt.with_ymd_and_hms(2014, 5, 6, 0, 0, 0).unwrap()),
+ "2014-05-06T00:00:00-04:00"
+ );
+ assert_eq!(
+ format!("{:?}", kst.with_ymd_and_hms(2014, 5, 6, 0, 0, 0).unwrap()),
+ "2014-05-06T00:00:00+09:00"
+ );
+ assert_eq!(
+ format!("{:?}", Utc.with_ymd_and_hms(2014, 5, 6, 23, 59, 59).unwrap()),
+ "2014-05-06T23:59:59Z"
+ );
+ assert_eq!(
+ format!("{:?}", edt.with_ymd_and_hms(2014, 5, 6, 23, 59, 59).unwrap()),
+ "2014-05-06T23:59:59-04:00"
+ );
+ assert_eq!(
+ format!("{:?}", kst.with_ymd_and_hms(2014, 5, 6, 23, 59, 59).unwrap()),
+ "2014-05-06T23:59:59+09:00"
+ );
+
+ let dt = Utc.with_ymd_and_hms(2014, 5, 6, 7, 8, 9).unwrap();
+ assert_eq!(dt, edt.with_ymd_and_hms(2014, 5, 6, 3, 8, 9).unwrap());
+ assert_eq!(
+ dt + Duration::seconds(3600 + 60 + 1),
+ Utc.with_ymd_and_hms(2014, 5, 6, 8, 9, 10).unwrap()
+ );
+ assert_eq!(
+ dt.signed_duration_since(edt.with_ymd_and_hms(2014, 5, 6, 10, 11, 12).unwrap()),
+ Duration::seconds(-7 * 3600 - 3 * 60 - 3)
+ );
+
+ assert_eq!(*Utc.with_ymd_and_hms(2014, 5, 6, 7, 8, 9).unwrap().offset(), Utc);
+ assert_eq!(*edt.with_ymd_and_hms(2014, 5, 6, 7, 8, 9).unwrap().offset(), edt);
+ assert!(*edt.with_ymd_and_hms(2014, 5, 6, 7, 8, 9).unwrap().offset() != est);
+}
+
+#[test]
+fn test_datetime_date_and_time() {
+ let tz = FixedOffset::east_opt(5 * 60 * 60).unwrap();
+ let d = tz.with_ymd_and_hms(2014, 5, 6, 7, 8, 9).unwrap();
+ assert_eq!(d.time(), NaiveTime::from_hms_opt(7, 8, 9).unwrap());
+ assert_eq!(d.date_naive(), NaiveDate::from_ymd_opt(2014, 5, 6).unwrap());
+
+ let tz = FixedOffset::east_opt(4 * 60 * 60).unwrap();
+ let d = tz.with_ymd_and_hms(2016, 5, 4, 3, 2, 1).unwrap();
+ assert_eq!(d.time(), NaiveTime::from_hms_opt(3, 2, 1).unwrap());
+ assert_eq!(d.date_naive(), NaiveDate::from_ymd_opt(2016, 5, 4).unwrap());
+
+ let tz = FixedOffset::west_opt(13 * 60 * 60).unwrap();
+ let d = tz.with_ymd_and_hms(2017, 8, 9, 12, 34, 56).unwrap();
+ assert_eq!(d.time(), NaiveTime::from_hms_opt(12, 34, 56).unwrap());
+ assert_eq!(d.date_naive(), NaiveDate::from_ymd_opt(2017, 8, 9).unwrap());
+
+ let utc_d = Utc.with_ymd_and_hms(2017, 8, 9, 12, 34, 56).unwrap();
+ assert!(utc_d < d);
+}
+
+#[test]
+#[cfg(feature = "clock")]
+fn test_datetime_with_timezone() {
+ let local_now = Local::now();
+ let utc_now = local_now.with_timezone(&Utc);
+ let local_now2 = utc_now.with_timezone(&Local);
+ assert_eq!(local_now, local_now2);
+}
+
+#[test]
+fn test_datetime_rfc2822_and_rfc3339() {
+ let edt = FixedOffset::east_opt(5 * 60 * 60).unwrap();
+ assert_eq!(
+ Utc.with_ymd_and_hms(2015, 2, 18, 23, 16, 9).unwrap().to_rfc2822(),
+ "Wed, 18 Feb 2015 23:16:09 +0000"
+ );
+ assert_eq!(
+ Utc.with_ymd_and_hms(2015, 2, 18, 23, 16, 9).unwrap().to_rfc3339(),
+ "2015-02-18T23:16:09+00:00"
+ );
+ assert_eq!(
+ edt.from_local_datetime(
+ &NaiveDate::from_ymd_opt(2015, 2, 18)
+ .unwrap()
+ .and_hms_milli_opt(23, 16, 9, 150)
+ .unwrap()
+ )
+ .unwrap()
+ .to_rfc2822(),
+ "Wed, 18 Feb 2015 23:16:09 +0500"
+ );
+ assert_eq!(
+ edt.from_local_datetime(
+ &NaiveDate::from_ymd_opt(2015, 2, 18)
+ .unwrap()
+ .and_hms_milli_opt(23, 16, 9, 150)
+ .unwrap()
+ )
+ .unwrap()
+ .to_rfc3339(),
+ "2015-02-18T23:16:09.150+05:00"
+ );
+ assert_eq!(
+ edt.from_local_datetime(
+ &NaiveDate::from_ymd_opt(2015, 2, 18)
+ .unwrap()
+ .and_hms_micro_opt(23, 59, 59, 1_234_567)
+ .unwrap()
+ )
+ .unwrap()
+ .to_rfc2822(),
+ "Wed, 18 Feb 2015 23:59:60 +0500"
+ );
+ assert_eq!(
+ edt.from_local_datetime(
+ &NaiveDate::from_ymd_opt(2015, 2, 18)
+ .unwrap()
+ .and_hms_micro_opt(23, 59, 59, 1_234_567)
+ .unwrap()
+ )
+ .unwrap()
+ .to_rfc3339(),
+ "2015-02-18T23:59:60.234567+05:00"
+ );
+
+ assert_eq!(
+ DateTime::parse_from_rfc2822("Wed, 18 Feb 2015 23:16:09 +0000"),
+ Ok(FixedOffset::east_opt(0).unwrap().with_ymd_and_hms(2015, 2, 18, 23, 16, 9).unwrap())
+ );
+ assert_eq!(
+ DateTime::parse_from_rfc2822("Wed, 18 Feb 2015 23:16:09 -0000"),
+ Ok(FixedOffset::east_opt(0).unwrap().with_ymd_and_hms(2015, 2, 18, 23, 16, 9).unwrap())
+ );
+ assert_eq!(
+ DateTime::parse_from_rfc3339("2015-02-18T23:16:09Z"),
+ Ok(FixedOffset::east_opt(0).unwrap().with_ymd_and_hms(2015, 2, 18, 23, 16, 9).unwrap())
+ );
+ assert_eq!(
+ DateTime::parse_from_rfc2822("Wed, 18 Feb 2015 23:59:60 +0500"),
+ Ok(edt
+ .from_local_datetime(
+ &NaiveDate::from_ymd_opt(2015, 2, 18)
+ .unwrap()
+ .and_hms_milli_opt(23, 59, 59, 1_000)
+ .unwrap()
+ )
+ .unwrap())
+ );
+ assert!(DateTime::parse_from_rfc2822("31 DEC 262143 23:59 -2359").is_err());
+ assert_eq!(
+ DateTime::parse_from_rfc3339("2015-02-18T23:59:60.234567+05:00"),
+ Ok(edt
+ .from_local_datetime(
+ &NaiveDate::from_ymd_opt(2015, 2, 18)
+ .unwrap()
+ .and_hms_micro_opt(23, 59, 59, 1_234_567)
+ .unwrap()
+ )
+ .unwrap())
+ );
+}
+
+#[test]
+fn test_rfc3339_opts() {
+ use crate::SecondsFormat::*;
+ let pst = FixedOffset::east_opt(8 * 60 * 60).unwrap();
+ let dt = pst
+ .from_local_datetime(
+ &NaiveDate::from_ymd_opt(2018, 1, 11)
+ .unwrap()
+ .and_hms_nano_opt(10, 5, 13, 84_660_000)
+ .unwrap(),
+ )
+ .unwrap();
+ assert_eq!(dt.to_rfc3339_opts(Secs, false), "2018-01-11T10:05:13+08:00");
+ assert_eq!(dt.to_rfc3339_opts(Secs, true), "2018-01-11T10:05:13+08:00");
+ assert_eq!(dt.to_rfc3339_opts(Millis, false), "2018-01-11T10:05:13.084+08:00");
+ assert_eq!(dt.to_rfc3339_opts(Micros, false), "2018-01-11T10:05:13.084660+08:00");
+ assert_eq!(dt.to_rfc3339_opts(Nanos, false), "2018-01-11T10:05:13.084660000+08:00");
+ assert_eq!(dt.to_rfc3339_opts(AutoSi, false), "2018-01-11T10:05:13.084660+08:00");
+
+ let ut = DateTime::<Utc>::from_utc(dt.naive_utc(), Utc);
+ assert_eq!(ut.to_rfc3339_opts(Secs, false), "2018-01-11T02:05:13+00:00");
+ assert_eq!(ut.to_rfc3339_opts(Secs, true), "2018-01-11T02:05:13Z");
+ assert_eq!(ut.to_rfc3339_opts(Millis, false), "2018-01-11T02:05:13.084+00:00");
+ assert_eq!(ut.to_rfc3339_opts(Millis, true), "2018-01-11T02:05:13.084Z");
+ assert_eq!(ut.to_rfc3339_opts(Micros, true), "2018-01-11T02:05:13.084660Z");
+ assert_eq!(ut.to_rfc3339_opts(Nanos, true), "2018-01-11T02:05:13.084660000Z");
+ assert_eq!(ut.to_rfc3339_opts(AutoSi, true), "2018-01-11T02:05:13.084660Z");
+}
+
+#[test]
+#[should_panic]
+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);
+}
+
+#[test]
+fn test_datetime_from_str() {
+ assert_eq!(
+ "2015-02-18T23:16:9.15Z".parse::<DateTime<FixedOffset>>(),
+ Ok(FixedOffset::east_opt(0)
+ .unwrap()
+ .from_local_datetime(
+ &NaiveDate::from_ymd_opt(2015, 2, 18)
+ .unwrap()
+ .and_hms_milli_opt(23, 16, 9, 150)
+ .unwrap()
+ )
+ .unwrap())
+ );
+ assert_eq!(
+ "2015-02-18T23:16:9.15Z".parse::<DateTime<Utc>>(),
+ Ok(Utc
+ .from_local_datetime(
+ &NaiveDate::from_ymd_opt(2015, 2, 18)
+ .unwrap()
+ .and_hms_milli_opt(23, 16, 9, 150)
+ .unwrap()
+ )
+ .unwrap())
+ );
+ assert_eq!(
+ "2015-02-18T23:16:9.15 UTC".parse::<DateTime<Utc>>(),
+ Ok(Utc
+ .from_local_datetime(
+ &NaiveDate::from_ymd_opt(2015, 2, 18)
+ .unwrap()
+ .and_hms_milli_opt(23, 16, 9, 150)
+ .unwrap()
+ )
+ .unwrap())
+ );
+ assert_eq!(
+ "2015-02-18T23:16:9.15UTC".parse::<DateTime<Utc>>(),
+ Ok(Utc
+ .from_local_datetime(
+ &NaiveDate::from_ymd_opt(2015, 2, 18)
+ .unwrap()
+ .and_hms_milli_opt(23, 16, 9, 150)
+ .unwrap()
+ )
+ .unwrap())
+ );
+
+ assert_eq!(
+ "2015-2-18T23:16:9.15Z".parse::<DateTime<FixedOffset>>(),
+ Ok(FixedOffset::east_opt(0)
+ .unwrap()
+ .from_local_datetime(
+ &NaiveDate::from_ymd_opt(2015, 2, 18)
+ .unwrap()
+ .and_hms_milli_opt(23, 16, 9, 150)
+ .unwrap()
+ )
+ .unwrap())
+ );
+ assert_eq!(
+ "2015-2-18T13:16:9.15-10:00".parse::<DateTime<FixedOffset>>(),
+ Ok(FixedOffset::west_opt(10 * 3600)
+ .unwrap()
+ .from_local_datetime(
+ &NaiveDate::from_ymd_opt(2015, 2, 18)
+ .unwrap()
+ .and_hms_milli_opt(13, 16, 9, 150)
+ .unwrap()
+ )
+ .unwrap())
+ );
+ assert!("2015-2-18T23:16:9.15".parse::<DateTime<FixedOffset>>().is_err());
+
+ assert_eq!(
+ "2015-2-18T23:16:9.15Z".parse::<DateTime<Utc>>(),
+ Ok(Utc
+ .from_local_datetime(
+ &NaiveDate::from_ymd_opt(2015, 2, 18)
+ .unwrap()
+ .and_hms_milli_opt(23, 16, 9, 150)
+ .unwrap()
+ )
+ .unwrap())
+ );
+ assert_eq!(
+ "2015-2-18T13:16:9.15-10:00".parse::<DateTime<Utc>>(),
+ Ok(Utc
+ .from_local_datetime(
+ &NaiveDate::from_ymd_opt(2015, 2, 18)
+ .unwrap()
+ .and_hms_milli_opt(23, 16, 9, 150)
+ .unwrap()
+ )
+ .unwrap())
+ );
+ assert!("2015-2-18T23:16:9.15".parse::<DateTime<Utc>>().is_err());
+
+ // no test for `DateTime<Local>`, we cannot verify that much.
+}
+
+#[test]
+fn test_datetime_parse_from_str() {
+ let ymdhms = |y, m, d, h, n, s, off| {
+ FixedOffset::east_opt(off).unwrap().with_ymd_and_hms(y, m, d, h, n, s).unwrap()
+ };
+ assert_eq!(
+ DateTime::parse_from_str("2014-5-7T12:34:56+09:30", "%Y-%m-%dT%H:%M:%S%z"),
+ Ok(ymdhms(2014, 5, 7, 12, 34, 56, 570 * 60))
+ ); // ignore offset
+ assert!(DateTime::parse_from_str("20140507000000", "%Y%m%d%H%M%S").is_err()); // no offset
+ assert!(DateTime::parse_from_str("Fri, 09 Aug 2013 23:54:35 GMT", "%a, %d %b %Y %H:%M:%S GMT")
+ .is_err());
+ assert_eq!(
+ Utc.datetime_from_str("Fri, 09 Aug 2013 23:54:35 GMT", "%a, %d %b %Y %H:%M:%S GMT"),
+ Ok(Utc.with_ymd_and_hms(2013, 8, 9, 23, 54, 35).unwrap())
+ );
+}
+
+#[test]
+fn test_to_string_round_trip() {
+ let dt = Utc.with_ymd_and_hms(2000, 1, 1, 0, 0, 0).unwrap();
+ let _dt: DateTime<Utc> = dt.to_string().parse().unwrap();
+
+ let ndt_fixed = dt.with_timezone(&FixedOffset::east_opt(3600).unwrap());
+ let _dt: DateTime<FixedOffset> = ndt_fixed.to_string().parse().unwrap();
+
+ let ndt_fixed = dt.with_timezone(&FixedOffset::east_opt(0).unwrap());
+ let _dt: DateTime<FixedOffset> = ndt_fixed.to_string().parse().unwrap();
+}
+
+#[test]
+#[cfg(feature = "clock")]
+fn test_to_string_round_trip_with_local() {
+ let ndt = Local::now();
+ let _dt: DateTime<FixedOffset> = ndt.to_string().parse().unwrap();
+}
+
+#[test]
+#[cfg(feature = "clock")]
+fn test_datetime_format_with_local() {
+ // if we are not around the year boundary, local and UTC date should have the same year
+ let dt = Local::now().with_month(5).unwrap();
+ assert_eq!(dt.format("%Y").to_string(), dt.with_timezone(&Utc).format("%Y").to_string());
+}
+
+#[test]
+#[cfg(feature = "clock")]
+fn test_datetime_is_copy() {
+ // UTC is known to be `Copy`.
+ let a = Utc::now();
+ let b = a;
+ assert_eq!(a, b);
+}
+
+#[test]
+#[cfg(feature = "clock")]
+fn test_datetime_is_send() {
+ use std::thread;
+
+ // UTC is known to be `Send`.
+ let a = Utc::now();
+ thread::spawn(move || {
+ let _ = a;
+ })
+ .join()
+ .unwrap();
+}
+
+#[test]
+fn test_subsecond_part() {
+ let datetime = Utc
+ .from_local_datetime(
+ &NaiveDate::from_ymd_opt(2014, 7, 8)
+ .unwrap()
+ .and_hms_nano_opt(9, 10, 11, 1234567)
+ .unwrap(),
+ )
+ .unwrap();
+
+ assert_eq!(1, datetime.timestamp_subsec_millis());
+ assert_eq!(1234, datetime.timestamp_subsec_micros());
+ assert_eq!(1234567, datetime.timestamp_subsec_nanos());
+}
+
+#[test]
+#[cfg(not(target_os = "windows"))]
+fn test_from_system_time() {
+ use std::time::Duration;
+
+ let epoch = Utc.with_ymd_and_hms(1970, 1, 1, 0, 0, 0).unwrap();
+ let nanos = 999_999_999;
+
+ // SystemTime -> DateTime<Utc>
+ assert_eq!(DateTime::<Utc>::from(UNIX_EPOCH), epoch);
+ assert_eq!(
+ DateTime::<Utc>::from(UNIX_EPOCH + Duration::new(999_999_999, nanos)),
+ Utc.from_local_datetime(
+ &NaiveDate::from_ymd_opt(2001, 9, 9)
+ .unwrap()
+ .and_hms_nano_opt(1, 46, 39, nanos)
+ .unwrap()
+ )
+ .unwrap()
+ );
+ assert_eq!(
+ DateTime::<Utc>::from(UNIX_EPOCH - Duration::new(999_999_999, nanos)),
+ Utc.from_local_datetime(
+ &NaiveDate::from_ymd_opt(1938, 4, 24).unwrap().and_hms_nano_opt(22, 13, 20, 1).unwrap()
+ )
+ .unwrap()
+ );
+
+ // DateTime<Utc> -> SystemTime
+ assert_eq!(SystemTime::from(epoch), UNIX_EPOCH);
+ assert_eq!(
+ SystemTime::from(
+ Utc.from_local_datetime(
+ &NaiveDate::from_ymd_opt(2001, 9, 9)
+ .unwrap()
+ .and_hms_nano_opt(1, 46, 39, nanos)
+ .unwrap()
+ )
+ .unwrap()
+ ),
+ UNIX_EPOCH + Duration::new(999_999_999, nanos)
+ );
+ assert_eq!(
+ SystemTime::from(
+ Utc.from_local_datetime(
+ &NaiveDate::from_ymd_opt(1938, 4, 24)
+ .unwrap()
+ .and_hms_nano_opt(22, 13, 20, 1)
+ .unwrap()
+ )
+ .unwrap()
+ ),
+ UNIX_EPOCH - Duration::new(999_999_999, 999_999_999)
+ );
+
+ // DateTime<any tz> -> SystemTime (via `with_timezone`)
+ #[cfg(feature = "clock")]
+ {
+ assert_eq!(SystemTime::from(epoch.with_timezone(&Local)), UNIX_EPOCH);
+ }
+ assert_eq!(
+ SystemTime::from(epoch.with_timezone(&FixedOffset::east_opt(32400).unwrap())),
+ UNIX_EPOCH
+ );
+ assert_eq!(
+ SystemTime::from(epoch.with_timezone(&FixedOffset::west_opt(28800).unwrap())),
+ UNIX_EPOCH
+ );
+}
+
+#[test]
+#[cfg(target_os = "windows")]
+fn test_from_system_time() {
+ use std::time::Duration;
+
+ let nanos = 999_999_000;
+
+ let epoch = Utc.with_ymd_and_hms(1970, 1, 1, 0, 0, 0).unwrap();
+
+ // SystemTime -> DateTime<Utc>
+ assert_eq!(DateTime::<Utc>::from(UNIX_EPOCH), epoch);
+ assert_eq!(
+ DateTime::<Utc>::from(UNIX_EPOCH + Duration::new(999_999_999, nanos)),
+ Utc.from_local_datetime(
+ &NaiveDate::from_ymd_opt(2001, 9, 9)
+ .unwrap()
+ .and_hms_nano_opt(1, 46, 39, nanos)
+ .unwrap()
+ )
+ .unwrap()
+ );
+ assert_eq!(
+ DateTime::<Utc>::from(UNIX_EPOCH - Duration::new(999_999_999, nanos)),
+ Utc.from_local_datetime(
+ &NaiveDate::from_ymd_opt(1938, 4, 24)
+ .unwrap()
+ .and_hms_nano_opt(22, 13, 20, 1_000)
+ .unwrap()
+ )
+ .unwrap()
+ );
+
+ // DateTime<Utc> -> SystemTime
+ assert_eq!(SystemTime::from(epoch), UNIX_EPOCH);
+ assert_eq!(
+ SystemTime::from(
+ Utc.from_local_datetime(
+ &NaiveDate::from_ymd_opt(2001, 9, 9)
+ .unwrap()
+ .and_hms_nano_opt(1, 46, 39, nanos)
+ .unwrap()
+ )
+ .unwrap()
+ ),
+ UNIX_EPOCH + Duration::new(999_999_999, nanos)
+ );
+ assert_eq!(
+ SystemTime::from(
+ Utc.from_local_datetime(
+ &NaiveDate::from_ymd_opt(1938, 4, 24)
+ .unwrap()
+ .and_hms_nano_opt(22, 13, 20, 1_000)
+ .unwrap()
+ )
+ .unwrap()
+ ),
+ UNIX_EPOCH - Duration::new(999_999_999, nanos)
+ );
+
+ // DateTime<any tz> -> SystemTime (via `with_timezone`)
+ #[cfg(feature = "clock")]
+ {
+ assert_eq!(SystemTime::from(epoch.with_timezone(&Local)), UNIX_EPOCH);
+ }
+ assert_eq!(
+ SystemTime::from(epoch.with_timezone(&FixedOffset::east_opt(32400).unwrap())),
+ UNIX_EPOCH
+ );
+ assert_eq!(
+ SystemTime::from(epoch.with_timezone(&FixedOffset::west_opt(28800).unwrap())),
+ UNIX_EPOCH
+ );
+}
+
+#[test]
+fn test_datetime_format_alignment() {
+ let datetime = Utc.with_ymd_and_hms(2007, 1, 2, 0, 0, 0).unwrap();
+
+ // Item::Literal
+ let percent = datetime.format("%%");
+ assert_eq!(" %", format!("{:>3}", percent));
+ assert_eq!("% ", format!("{:<3}", percent));
+ assert_eq!(" % ", format!("{:^3}", percent));
+
+ // Item::Numeric
+ let year = datetime.format("%Y");
+ assert_eq!(" 2007", format!("{:>6}", year));
+ assert_eq!("2007 ", format!("{:<6}", year));
+ assert_eq!(" 2007 ", format!("{:^6}", year));
+
+ // Item::Fixed
+ let tz = datetime.format("%Z");
+ assert_eq!(" UTC", format!("{:>5}", tz));
+ assert_eq!("UTC ", format!("{:<5}", tz));
+ assert_eq!(" UTC ", format!("{:^5}", tz));
+
+ // [Item::Numeric, Item::Space, Item::Literal, Item::Space, Item::Numeric]
+ let ymd = datetime.format("%Y %B %d");
+ let ymd_formatted = "2007 January 02";
+ assert_eq!(format!(" {}", ymd_formatted), format!("{:>17}", ymd));
+ assert_eq!(format!("{} ", ymd_formatted), format!("{:<17}", ymd));
+ assert_eq!(format!(" {} ", ymd_formatted), format!("{:^17}", ymd));
+}
+
+#[test]
+fn test_datetime_from_local() {
+ // 2000-01-12T02:00:00Z
+ let naivedatetime_utc =
+ NaiveDate::from_ymd_opt(2000, 1, 12).unwrap().and_hms_opt(2, 0, 0).unwrap();
+ let datetime_utc = DateTime::<Utc>::from_utc(naivedatetime_utc, Utc);
+
+ // 2000-01-12T10:00:00+8:00:00
+ let timezone_east = FixedOffset::east_opt(8 * 60 * 60).unwrap();
+ let naivedatetime_east =
+ NaiveDate::from_ymd_opt(2000, 1, 12).unwrap().and_hms_opt(10, 0, 0).unwrap();
+ let datetime_east = DateTime::<FixedOffset>::from_local(naivedatetime_east, timezone_east);
+
+ // 2000-01-11T19:00:00-7:00:00
+ let timezone_west = FixedOffset::west_opt(7 * 60 * 60).unwrap();
+ let naivedatetime_west =
+ NaiveDate::from_ymd_opt(2000, 1, 11).unwrap().and_hms_opt(19, 0, 0).unwrap();
+ let datetime_west = DateTime::<FixedOffset>::from_local(naivedatetime_west, timezone_west);
+
+ assert_eq!(datetime_east, datetime_utc.with_timezone(&timezone_east));
+ assert_eq!(datetime_west, datetime_utc.with_timezone(&timezone_west));
+}
+
+#[test]
+#[cfg(feature = "clock")]
+fn test_years_elapsed() {
+ const WEEKS_PER_YEAR: f32 = 52.1775;
+
+ // This is always at least one year because 1 year = 52.1775 weeks.
+ let one_year_ago =
+ Utc::now().date_naive() - Duration::weeks((WEEKS_PER_YEAR * 1.5).ceil() as i64);
+ // A bit more than 2 years.
+ let two_year_ago =
+ Utc::now().date_naive() - Duration::weeks((WEEKS_PER_YEAR * 2.5).ceil() as i64);
+
+ assert_eq!(Utc::now().date_naive().years_since(one_year_ago), Some(1));
+ assert_eq!(Utc::now().date_naive().years_since(two_year_ago), Some(2));
+
+ // If the given DateTime is later than now, the function will always return 0.
+ let future = Utc::now().date_naive() + Duration::weeks(12);
+ assert_eq!(Utc::now().date_naive().years_since(future), None);
+}
+
+#[test]
+fn test_datetime_add_assign() {
+ let naivedatetime = NaiveDate::from_ymd_opt(2000, 1, 1).unwrap().and_hms_opt(0, 0, 0).unwrap();
+ let datetime = DateTime::<Utc>::from_utc(naivedatetime, Utc);
+ let mut datetime_add = datetime;
+
+ datetime_add += Duration::seconds(60);
+ assert_eq!(datetime_add, datetime + Duration::seconds(60));
+
+ let timezone = FixedOffset::east_opt(60 * 60).unwrap();
+ let datetime = datetime.with_timezone(&timezone);
+ let datetime_add = datetime_add.with_timezone(&timezone);
+
+ assert_eq!(datetime_add, datetime + Duration::seconds(60));
+
+ let timezone = FixedOffset::west_opt(2 * 60 * 60).unwrap();
+ let datetime = datetime.with_timezone(&timezone);
+ let datetime_add = datetime_add.with_timezone(&timezone);
+
+ assert_eq!(datetime_add, datetime + Duration::seconds(60));
+}
+
+#[test]
+#[cfg(feature = "clock")]
+fn test_datetime_add_assign_local() {
+ let naivedatetime = NaiveDate::from_ymd_opt(2022, 1, 1).unwrap().and_hms_opt(0, 0, 0).unwrap();
+
+ let datetime = Local.from_utc_datetime(&naivedatetime);
+ let mut datetime_add = Local.from_utc_datetime(&naivedatetime);
+
+ // ensure we cross a DST transition
+ for i in 1..=365 {
+ datetime_add += Duration::days(1);
+ assert_eq!(datetime_add, datetime + Duration::days(i))
+ }
+}
+
+#[test]
+fn test_datetime_sub_assign() {
+ let naivedatetime = NaiveDate::from_ymd_opt(2000, 1, 1).unwrap().and_hms_opt(12, 0, 0).unwrap();
+ let datetime = DateTime::<Utc>::from_utc(naivedatetime, Utc);
+ let mut datetime_sub = datetime;
+
+ datetime_sub -= Duration::minutes(90);
+ assert_eq!(datetime_sub, datetime - Duration::minutes(90));
+
+ let timezone = FixedOffset::east_opt(60 * 60).unwrap();
+ let datetime = datetime.with_timezone(&timezone);
+ let datetime_sub = datetime_sub.with_timezone(&timezone);
+
+ assert_eq!(datetime_sub, datetime - Duration::minutes(90));
+
+ let timezone = FixedOffset::west_opt(2 * 60 * 60).unwrap();
+ let datetime = datetime.with_timezone(&timezone);
+ let datetime_sub = datetime_sub.with_timezone(&timezone);
+
+ assert_eq!(datetime_sub, datetime - Duration::minutes(90));
+}
+
+#[test]
+#[cfg(feature = "clock")]
+fn test_datetime_sub_assign_local() {
+ let naivedatetime = NaiveDate::from_ymd_opt(2022, 1, 1).unwrap().and_hms_opt(0, 0, 0).unwrap();
+
+ let datetime = Local.from_utc_datetime(&naivedatetime);
+ let mut datetime_sub = Local.from_utc_datetime(&naivedatetime);
+
+ // ensure we cross a DST transition
+ for i in 1..=365 {
+ datetime_sub -= Duration::days(1);
+ assert_eq!(datetime_sub, datetime - Duration::days(i))
+ }
+}
diff --git a/vendor/chrono/src/div.rs b/vendor/chrono/src/div.rs
deleted file mode 100644
index 64b8e4bce..000000000
--- a/vendor/chrono/src/div.rs
+++ /dev/null
@@ -1,41 +0,0 @@
-// This is a part of Chrono.
-// Portions Copyright 2013-2014 The Rust Project Developers.
-// See README.md and LICENSE.txt for details.
-
-//! Integer division utilities. (Shamelessly copied from [num](https://github.com/rust-lang/num/))
-
-// Algorithm from [Daan Leijen. _Division and Modulus for Computer Scientists_,
-// December 2001](http://research.microsoft.com/pubs/151917/divmodnote-letter.pdf)
-
-pub use num_integer::{div_floor, div_mod_floor, div_rem, mod_floor};
-
-#[cfg(test)]
-mod tests {
- use super::{div_mod_floor, mod_floor};
-
- #[test]
- fn test_mod_floor() {
- assert_eq!(mod_floor(8, 3), 2);
- assert_eq!(mod_floor(8, -3), -1);
- assert_eq!(mod_floor(-8, 3), 1);
- assert_eq!(mod_floor(-8, -3), -2);
-
- assert_eq!(mod_floor(1, 2), 1);
- assert_eq!(mod_floor(1, -2), -1);
- assert_eq!(mod_floor(-1, 2), 1);
- assert_eq!(mod_floor(-1, -2), -1);
- }
-
- #[test]
- fn test_div_mod_floor() {
- assert_eq!(div_mod_floor(8, 3), (2, 2));
- assert_eq!(div_mod_floor(8, -3), (-3, -1));
- assert_eq!(div_mod_floor(-8, 3), (-3, 1));
- assert_eq!(div_mod_floor(-8, -3), (2, -2));
-
- assert_eq!(div_mod_floor(1, 2), (0, 1));
- assert_eq!(div_mod_floor(1, -2), (-1, -1));
- assert_eq!(div_mod_floor(-1, 2), (-1, 1));
- assert_eq!(div_mod_floor(-1, -2), (0, -1));
- }
-}
diff --git a/vendor/chrono/src/format/mod.rs b/vendor/chrono/src/format/mod.rs
index a641f196d..c05ba4d04 100644
--- a/vendor/chrono/src/format/mod.rs
+++ b/vendor/chrono/src/format/mod.rs
@@ -12,10 +12,26 @@
//! which are just an [`Iterator`](https://doc.rust-lang.org/std/iter/trait.Iterator.html) of
//! the [`Item`](./enum.Item.html) type.
//! They are generated from more readable **format strings**;
-//! currently Chrono supports [one built-in syntax closely resembling
-//! C's `strftime` format](./strftime/index.html).
+//! currently Chrono supports a built-in syntax closely resembling
+//! C's `strftime` format. The available options can be found [here](./strftime/index.html).
+//!
+//! # Example
+//! ```rust
+//! # use std::error::Error;
+//! use chrono::prelude::*;
+//!
+//! let date_time = Utc.with_ymd_and_hms(2020, 11, 10, 0, 1, 32).unwrap();
+//!
+//! let formatted = format!("{}", date_time.format("%Y-%m-%d %H:%M:%S"));
+//! assert_eq!(formatted, "2020-11-10 00:01:32");
+//!
+//! let parsed = Utc.datetime_from_str(&formatted, "%Y-%m-%d %H:%M:%S")?;
+//! assert_eq!(parsed, date_time);
+//! # Ok::<(), chrono::ParseError>(())
+//! ```
-#![allow(ellipsis_inclusive_range_patterns)]
+#[cfg(feature = "alloc")]
+extern crate alloc;
#[cfg(feature = "alloc")]
use alloc::boxed::Box;
@@ -24,38 +40,40 @@ use alloc::string::{String, ToString};
#[cfg(any(feature = "alloc", feature = "std", test))]
use core::borrow::Borrow;
use core::fmt;
+use core::fmt::Write;
use core::str::FromStr;
#[cfg(any(feature = "std", test))]
use std::error::Error;
#[cfg(any(feature = "alloc", feature = "std", test))]
-use naive::{NaiveDate, NaiveTime};
+use crate::naive::{NaiveDate, NaiveTime};
#[cfg(any(feature = "alloc", feature = "std", test))]
-use offset::{FixedOffset, Offset};
+use crate::offset::{FixedOffset, Offset};
#[cfg(any(feature = "alloc", feature = "std", test))]
-use {Datelike, Timelike};
-use {Month, ParseMonthError, ParseWeekdayError, Weekday};
+use crate::{Datelike, Timelike};
+use crate::{Month, ParseMonthError, ParseWeekdayError, Weekday};
#[cfg(feature = "unstable-locales")]
pub(crate) mod locales;
-pub use self::parse::parse;
-pub use self::parsed::Parsed;
-pub use self::strftime::StrftimeItems;
+pub use parse::parse;
+pub use parsed::Parsed;
/// L10n locales.
#[cfg(feature = "unstable-locales")]
pub use pure_rust_locales::Locale;
+pub use strftime::StrftimeItems;
#[cfg(not(feature = "unstable-locales"))]
+#[allow(dead_code)]
#[derive(Debug)]
struct Locale;
/// An uninhabited type used for `InternalNumeric` and `InternalFixed` below.
-#[derive(Clone, PartialEq, Eq)]
+#[derive(Clone, PartialEq, Eq, Hash)]
enum Void {}
/// Padding characters for numeric items.
-#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
pub enum Pad {
/// No padding.
None,
@@ -78,10 +96,10 @@ pub enum Pad {
/// It also trims the preceding whitespace if any.
/// It cannot parse the negative number, so some date and time cannot be formatted then
/// parsed with the same formatting items.
-#[derive(Clone, PartialEq, Eq, Debug)]
+#[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub enum Numeric {
/// Full Gregorian year (FW=4, PW=∞).
- /// May accept years before 1 BCE or after 9999 CE, given an initial sign.
+ /// May accept years before 1 BCE or after 9999 CE, given an initial sign (+/-).
Year,
/// Gregorian year divided by 100 (century number; FW=PW=2). Implies the non-negative year.
YearDiv100,
@@ -134,24 +152,11 @@ pub enum Numeric {
}
/// An opaque type representing numeric item types for internal uses only.
+#[derive(Clone, Eq, Hash, PartialEq)]
pub struct InternalNumeric {
_dummy: Void,
}
-impl Clone for InternalNumeric {
- fn clone(&self) -> Self {
- match self._dummy {}
- }
-}
-
-impl PartialEq for InternalNumeric {
- fn eq(&self, _other: &InternalNumeric) -> bool {
- match self._dummy {}
- }
-}
-
-impl Eq for InternalNumeric {}
-
impl fmt::Debug for InternalNumeric {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "<InternalNumeric>")
@@ -162,7 +167,7 @@ impl fmt::Debug for InternalNumeric {
///
/// They have their own rules of formatting and parsing.
/// Otherwise noted, they print in the specified cases but parse case-insensitively.
-#[derive(Clone, PartialEq, Eq, Debug)]
+#[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub enum Fixed {
/// Abbreviated month names.
///
@@ -208,6 +213,18 @@ pub enum Fixed {
/// The offset is limited from `-24:00` to `+24:00`,
/// which is the same as [`FixedOffset`](../offset/struct.FixedOffset.html)'s range.
TimezoneOffsetColon,
+ /// Offset from the local time to UTC with seconds (`+09:00:00` or `-04:00:00` or `+00:00:00`).
+ ///
+ /// In the parser, the colon can be omitted and/or surrounded with any amount of whitespace.
+ /// The offset is limited from `-24:00:00` to `+24:00:00`,
+ /// which is the same as [`FixedOffset`](../offset/struct.FixedOffset.html)'s range.
+ TimezoneOffsetDoubleColon,
+ /// Offset from the local time to UTC without minutes (`+09` or `-04` or `+00`).
+ ///
+ /// In the parser, the colon can be omitted and/or surrounded with any amount of whitespace.
+ /// The offset is limited from `-24` to `+24`,
+ /// which is the same as [`FixedOffset`](../offset/struct.FixedOffset.html)'s range.
+ TimezoneOffsetTripleColon,
/// Offset from the local time to UTC (`+09:00` or `-04:00` or `Z`).
///
/// In the parser, the colon can be omitted and/or surrounded with any amount of whitespace,
@@ -234,12 +251,12 @@ pub enum Fixed {
}
/// An opaque type representing fixed-format item types for internal uses only.
-#[derive(Debug, Clone, PartialEq, Eq)]
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct InternalFixed {
val: InternalInternal,
}
-#[derive(Debug, Clone, PartialEq, Eq)]
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
enum InternalInternal {
/// Same as [`TimezoneOffsetColonZ`](#variant.TimezoneOffsetColonZ), but
/// allows missing minutes (per [ISO 8601][iso8601]).
@@ -258,18 +275,29 @@ enum InternalInternal {
Nanosecond9NoDot,
}
+#[cfg(any(feature = "alloc", feature = "std", test))]
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+enum Colons {
+ None,
+ Single,
+ Double,
+ Triple,
+}
+
/// A single formatting item. This is used for both formatting and parsing.
-#[derive(Clone, PartialEq, Eq, Debug)]
+#[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub enum Item<'a> {
/// A literally printed and parsed text.
Literal(&'a str),
/// Same as `Literal` but with the string owned by the item.
#[cfg(any(feature = "alloc", feature = "std", test))]
+ #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))]
OwnedLiteral(Box<str>),
/// Whitespace. Prints literally but reads zero or more whitespace.
Space(&'a str),
/// Same as `Space` but with the string owned by the item.
#[cfg(any(feature = "alloc", feature = "std", test))]
+ #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))]
OwnedSpace(Box<str>),
/// Numeric item. Can be optionally padded to the maximal length (if any) when formatting;
/// the parser simply ignores any padded whitespace and zeroes.
@@ -317,12 +345,19 @@ macro_rules! internal_fix {
}
/// An error from the `parse` function.
-#[derive(Debug, Clone, PartialEq, Eq, Copy)]
+#[derive(Debug, Clone, PartialEq, Eq, Copy, Hash)]
pub struct ParseError(ParseErrorKind);
+impl ParseError {
+ /// The category of parse error
+ pub const fn kind(&self) -> ParseErrorKind {
+ self.0
+ }
+}
+
/// The category of parse error
-#[derive(Debug, Clone, PartialEq, Eq, Copy)]
-enum ParseErrorKind {
+#[derive(Debug, Clone, PartialEq, Eq, Copy, Hash)]
+pub enum ParseErrorKind {
/// Given field is out of permitted range.
OutOfRange,
@@ -350,6 +385,10 @@ 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
+ #[doc(hidden)]
+ __Nonexhaustive,
}
/// Same as `Result<T, ParseError>`.
@@ -365,11 +404,13 @@ impl fmt::Display for ParseError {
ParseErrorKind::TooShort => write!(f, "premature end of input"),
ParseErrorKind::TooLong => write!(f, "trailing input"),
ParseErrorKind::BadFormat => write!(f, "bad or unsupported format string"),
+ _ => unreachable!(),
}
}
}
#[cfg(any(feature = "std", test))]
+#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
impl Error for ParseError {
#[allow(deprecated)]
fn description(&self) -> &str {
@@ -386,14 +427,72 @@ const TOO_SHORT: ParseError = ParseError(ParseErrorKind::TooShort);
const TOO_LONG: ParseError = ParseError(ParseErrorKind::TooLong);
const BAD_FORMAT: ParseError = ParseError(ParseErrorKind::BadFormat);
+#[cfg(any(feature = "alloc", feature = "std", test))]
+struct Locales {
+ short_months: &'static [&'static str],
+ long_months: &'static [&'static str],
+ short_weekdays: &'static [&'static str],
+ long_weekdays: &'static [&'static str],
+ am_pm: &'static [&'static str],
+}
+
+#[cfg(any(feature = "alloc", feature = "std", test))]
+impl Locales {
+ fn new(_locale: Option<Locale>) -> Self {
+ #[cfg(feature = "unstable-locales")]
+ {
+ let locale = _locale.unwrap_or(Locale::POSIX);
+ Self {
+ short_months: locales::short_months(locale),
+ long_months: locales::long_months(locale),
+ short_weekdays: locales::short_weekdays(locale),
+ long_weekdays: locales::long_weekdays(locale),
+ am_pm: locales::am_pm(locale),
+ }
+ }
+ #[cfg(not(feature = "unstable-locales"))]
+ Self {
+ short_months: &[
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
+ ],
+ long_months: &[
+ "January",
+ "February",
+ "March",
+ "April",
+ "May",
+ "June",
+ "July",
+ "August",
+ "September",
+ "October",
+ "November",
+ "December",
+ ],
+ short_weekdays: &["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
+ long_weekdays: &[
+ "Sunday",
+ "Monday",
+ "Tuesday",
+ "Wednesday",
+ "Thursday",
+ "Friday",
+ "Saturday",
+ ],
+ am_pm: &["AM", "PM"],
+ }
+ }
+}
+
/// Formats single formatting item
#[cfg(any(feature = "alloc", feature = "std", test))]
-pub fn format_item<'a>(
+#[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))]
+pub fn format_item(
w: &mut fmt::Formatter,
date: Option<&NaiveDate>,
time: Option<&NaiveTime>,
off: Option<&(String, FixedOffset)>,
- item: &Item<'a>,
+ item: &Item<'_>,
) -> fmt::Result {
let mut result = String::new();
format_inner(&mut result, date, time, off, item, None)?;
@@ -401,54 +500,17 @@ pub fn format_item<'a>(
}
#[cfg(any(feature = "alloc", feature = "std", test))]
-fn format_inner<'a>(
+fn format_inner(
result: &mut String,
date: Option<&NaiveDate>,
time: Option<&NaiveTime>,
off: Option<&(String, FixedOffset)>,
- item: &Item<'a>,
- _locale: Option<Locale>,
+ item: &Item<'_>,
+ locale: Option<Locale>,
) -> fmt::Result {
- #[cfg(feature = "unstable-locales")]
- let (short_months, long_months, short_weekdays, long_weekdays, am_pm, am_pm_lowercase) = {
- let locale = _locale.unwrap_or(Locale::POSIX);
- let am_pm = locales::am_pm(locale);
- (
- locales::short_months(locale),
- locales::long_months(locale),
- locales::short_weekdays(locale),
- locales::long_weekdays(locale),
- am_pm,
- &[am_pm[0].to_lowercase(), am_pm[1].to_lowercase()],
- )
- };
- #[cfg(not(feature = "unstable-locales"))]
- let (short_months, long_months, short_weekdays, long_weekdays, am_pm, am_pm_lowercase) = {
- (
- &["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
- &[
- "January",
- "February",
- "March",
- "April",
- "May",
- "June",
- "July",
- "August",
- "September",
- "October",
- "November",
- "December",
- ],
- &["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
- &["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
- &["AM", "PM"],
- &["am", "pm"],
- )
- };
+ let locale = Locales::new(locale);
- use core::fmt::Write;
- use div::{div_floor, mod_floor};
+ use num_integer::{div_floor, mod_floor};
match *item {
Item::Literal(s) | Item::Space(s) => result.push_str(s),
@@ -458,12 +520,8 @@ fn format_inner<'a>(
Item::Numeric(ref spec, ref pad) => {
use self::Numeric::*;
- let week_from_sun = |d: &NaiveDate| {
- (d.ordinal() as i32 - d.weekday().num_days_from_sunday() as i32 + 7) / 7
- };
- let week_from_mon = |d: &NaiveDate| {
- (d.ordinal() as i32 - d.weekday().num_days_from_monday() as i32 + 7) / 7
- };
+ let week_from_sun = |d: &NaiveDate| d.weeks_from(Weekday::Sun);
+ let week_from_mon = |d: &NaiveDate| d.weeks_from(Weekday::Mon);
let (width, v) = match *spec {
Year => (4, date.map(|d| i64::from(d.year()))),
@@ -501,7 +559,7 @@ fn format_inner<'a>(
};
if let Some(v) = v {
- if (spec == &Year || spec == &IsoYear) && !(0 <= v && v < 10_000) {
+ if (spec == &Year || spec == &IsoYear) && !(0..10_000).contains(&v) {
// non-four-digit years require an explicit sign as per ISO 8601
match *pad {
Pad::None => write!(result, "{:+}", v),
@@ -523,60 +581,41 @@ fn format_inner<'a>(
Item::Fixed(ref spec) => {
use self::Fixed::*;
- /// Prints an offset from UTC in the format of `+HHMM` or `+HH:MM`.
- /// `Z` instead of `+00[:]00` is allowed when `allow_zulu` is true.
- fn write_local_minus_utc(
- result: &mut String,
- off: FixedOffset,
- allow_zulu: bool,
- use_colon: bool,
- ) -> fmt::Result {
- let off = off.local_minus_utc();
- if !allow_zulu || off != 0 {
- let (sign, off) = if off < 0 { ('-', -off) } else { ('+', off) };
- if use_colon {
- write!(result, "{}{:02}:{:02}", sign, off / 3600, off / 60 % 60)
- } else {
- write!(result, "{}{:02}{:02}", sign, off / 3600, off / 60 % 60)
- }
- } else {
- result.push_str("Z");
- Ok(())
- }
- }
-
let ret =
match *spec {
ShortMonthName => date.map(|d| {
- result.push_str(short_months[d.month0() as usize]);
+ result.push_str(locale.short_months[d.month0() as usize]);
Ok(())
}),
LongMonthName => date.map(|d| {
- result.push_str(long_months[d.month0() as usize]);
+ result.push_str(locale.long_months[d.month0() as usize]);
Ok(())
}),
ShortWeekdayName => date.map(|d| {
- result
- .push_str(short_weekdays[d.weekday().num_days_from_sunday() as usize]);
+ result.push_str(
+ locale.short_weekdays[d.weekday().num_days_from_sunday() as usize],
+ );
Ok(())
}),
LongWeekdayName => date.map(|d| {
- result.push_str(long_weekdays[d.weekday().num_days_from_sunday() as usize]);
+ result.push_str(
+ locale.long_weekdays[d.weekday().num_days_from_sunday() as usize],
+ );
Ok(())
}),
LowerAmPm => time.map(|t| {
- #[cfg_attr(feature = "cargo-clippy", allow(useless_asref))]
- {
- result.push_str(if t.hour12().0 {
- am_pm_lowercase[1].as_ref()
- } else {
- am_pm_lowercase[0].as_ref()
- });
+ let ampm = if t.hour12().0 { locale.am_pm[1] } else { locale.am_pm[0] };
+ for char in ampm.chars() {
+ result.extend(char.to_lowercase())
}
Ok(())
}),
UpperAmPm => time.map(|t| {
- result.push_str(if t.hour12().0 { am_pm[1] } else { am_pm[0] });
+ result.push_str(if t.hour12().0 {
+ locale.am_pm[1]
+ } else {
+ locale.am_pm[0]
+ });
Ok(())
}),
Nanosecond => time.map(|t| {
@@ -618,21 +657,23 @@ fn format_inner<'a>(
let nano = t.nanosecond() % 1_000_000_000;
write!(result, "{:09}", nano)
}),
- TimezoneName => off.map(|&(ref name, _)| {
+ TimezoneName => off.map(|(name, _)| {
result.push_str(name);
Ok(())
}),
- TimezoneOffsetColon => {
- off.map(|&(_, off)| write_local_minus_utc(result, off, false, true))
- }
- TimezoneOffsetColonZ => {
- off.map(|&(_, off)| write_local_minus_utc(result, off, true, true))
- }
+ TimezoneOffsetColon => off
+ .map(|&(_, off)| write_local_minus_utc(result, off, false, Colons::Single)),
+ TimezoneOffsetDoubleColon => off
+ .map(|&(_, off)| write_local_minus_utc(result, off, false, Colons::Double)),
+ TimezoneOffsetTripleColon => off
+ .map(|&(_, off)| write_local_minus_utc(result, off, false, Colons::Triple)),
+ TimezoneOffsetColonZ => off
+ .map(|&(_, off)| write_local_minus_utc(result, off, true, Colons::Single)),
TimezoneOffset => {
- off.map(|&(_, off)| write_local_minus_utc(result, off, false, false))
+ off.map(|&(_, off)| write_local_minus_utc(result, off, false, Colons::None))
}
TimezoneOffsetZ => {
- off.map(|&(_, off)| write_local_minus_utc(result, off, true, false))
+ off.map(|&(_, off)| write_local_minus_utc(result, off, true, Colons::None))
}
Internal(InternalFixed { val: InternalInternal::TimezoneOffsetPermissive }) => {
panic!("Do not try to write %#z it is undefined")
@@ -641,19 +682,7 @@ fn format_inner<'a>(
// same as `%a, %d %b %Y %H:%M:%S %z`
{
if let (Some(d), Some(t), Some(&(_, off))) = (date, time, off) {
- let sec = t.second() + t.nanosecond() / 1_000_000_000;
- write!(
- result,
- "{}, {:02} {} {:04} {:02}:{:02}:{:02} ",
- short_weekdays[d.weekday().num_days_from_sunday() as usize],
- d.day(),
- short_months[d.month0() as usize],
- d.year(),
- t.hour(),
- t.minute(),
- sec
- )?;
- Some(write_local_minus_utc(result, off, false, false))
+ Some(write_rfc2822_inner(result, d, t, off, locale))
} else {
None
}
@@ -662,10 +691,7 @@ fn format_inner<'a>(
// same as `%Y-%m-%dT%H:%M:%S%.f%:z`
{
if let (Some(d), Some(t), Some(&(_, off))) = (date, time, off) {
- // reuse `Debug` impls which already print ISO 8601 format.
- // this is faster in this way.
- write!(result, "{:?}T{:?}", d, t)?;
- Some(write_local_minus_utc(result, off, false, true))
+ Some(write_rfc3339(result, crate::NaiveDateTime::new(*d, *t), off))
} else {
None
}
@@ -683,9 +709,114 @@ fn format_inner<'a>(
Ok(())
}
+/// Prints an offset from UTC in the format of `+HHMM` or `+HH:MM`.
+/// `Z` instead of `+00[:]00` is allowed when `allow_zulu` is true.
+#[cfg(any(feature = "alloc", feature = "std", test))]
+fn write_local_minus_utc(
+ result: &mut String,
+ off: FixedOffset,
+ allow_zulu: bool,
+ colon_type: Colons,
+) -> fmt::Result {
+ let off = off.local_minus_utc();
+ if allow_zulu && off == 0 {
+ result.push('Z');
+ return Ok(());
+ }
+ let (sign, off) = if off < 0 { ('-', -off) } else { ('+', off) };
+ result.push(sign);
+
+ write_hundreds(result, (off / 3600) as u8)?;
+
+ match colon_type {
+ Colons::None => write_hundreds(result, (off / 60 % 60) as u8),
+ Colons::Single => {
+ result.push(':');
+ write_hundreds(result, (off / 60 % 60) as u8)
+ }
+ Colons::Double => {
+ result.push(':');
+ write_hundreds(result, (off / 60 % 60) as u8)?;
+ result.push(':');
+ write_hundreds(result, (off % 60) as u8)
+ }
+ Colons::Triple => Ok(()),
+ }
+}
+
+/// Writes the date, time and offset to the string. same as `%Y-%m-%dT%H:%M:%S%.f%:z`
+#[cfg(any(feature = "alloc", feature = "std", test))]
+pub(crate) fn write_rfc3339(
+ result: &mut String,
+ dt: crate::NaiveDateTime,
+ off: FixedOffset,
+) -> fmt::Result {
+ // reuse `Debug` impls which already print ISO 8601 format.
+ // this is faster in this way.
+ write!(result, "{:?}", dt)?;
+ write_local_minus_utc(result, off, false, Colons::Single)
+}
+
+#[cfg(any(feature = "alloc", feature = "std", test))]
+/// write datetimes like `Tue, 1 Jul 2003 10:52:37 +0200`, same as `%a, %d %b %Y %H:%M:%S %z`
+pub(crate) fn write_rfc2822(
+ result: &mut String,
+ dt: crate::NaiveDateTime,
+ off: FixedOffset,
+) -> fmt::Result {
+ write_rfc2822_inner(result, &dt.date(), &dt.time(), off, Locales::new(None))
+}
+
+#[cfg(any(feature = "alloc", feature = "std", test))]
+/// write datetimes like `Tue, 1 Jul 2003 10:52:37 +0200`, same as `%a, %d %b %Y %H:%M:%S %z`
+fn write_rfc2822_inner(
+ result: &mut String,
+ d: &NaiveDate,
+ t: &NaiveTime,
+ off: FixedOffset,
+ locale: Locales,
+) -> fmt::Result {
+ let year = d.year();
+ // RFC2822 is only defined on years 0 through 9999
+ if !(0..=9999).contains(&year) {
+ return Err(fmt::Error);
+ }
+
+ result.push_str(locale.short_weekdays[d.weekday().num_days_from_sunday() as usize]);
+ result.push_str(", ");
+ write_hundreds(result, d.day() as u8)?;
+ result.push(' ');
+ result.push_str(locale.short_months[d.month0() as usize]);
+ result.push(' ');
+ write_hundreds(result, (year / 100) as u8)?;
+ write_hundreds(result, (year % 100) as u8)?;
+ result.push(' ');
+ write_hundreds(result, t.hour() as u8)?;
+ result.push(':');
+ write_hundreds(result, t.minute() as u8)?;
+ result.push(':');
+ let sec = t.second() + t.nanosecond() / 1_000_000_000;
+ write_hundreds(result, sec as u8)?;
+ result.push(' ');
+ write_local_minus_utc(result, off, false, Colons::None)
+}
+
+/// Equivalent to `{:02}` formatting for n < 100.
+pub(crate) fn write_hundreds(w: &mut impl Write, n: u8) -> fmt::Result {
+ if n >= 100 {
+ return Err(fmt::Error);
+ }
+
+ let tens = b'0' + n / 10;
+ let ones = b'0' + n % 10;
+ w.write_char(tens as char)?;
+ w.write_char(ones as char)
+}
+
/// Tries to format given arguments with given formatting items.
/// Internally used by `DelayedFormat`.
#[cfg(any(feature = "alloc", feature = "std", test))]
+#[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))]
pub fn format<'a, I, B>(
w: &mut fmt::Formatter,
date: Option<&NaiveDate>,
@@ -715,6 +846,7 @@ pub mod strftime;
/// A *temporary* object which can be used as an argument to `format!` or others.
/// This is normally constructed via `format` methods of each date and time type.
#[cfg(any(feature = "alloc", feature = "std", test))]
+#[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))]
#[derive(Debug)]
pub struct DelayedFormat<I> {
/// The date view, if any.
@@ -726,6 +858,9 @@ pub struct DelayedFormat<I> {
/// An iterator returning formatting items.
items: I,
/// Locale used for text.
+ // TODO: Only used with the locale feature. We should make this property
+ // only present when the feature is enabled.
+ #[cfg(feature = "unstable-locales")]
locale: Option<Locale>,
}
@@ -733,7 +868,14 @@ pub struct DelayedFormat<I> {
impl<'a, I: Iterator<Item = B> + Clone, B: Borrow<Item<'a>>> DelayedFormat<I> {
/// Makes a new `DelayedFormat` value out of local date and time.
pub fn new(date: Option<NaiveDate>, time: Option<NaiveTime>, items: I) -> DelayedFormat<I> {
- DelayedFormat { date: date, time: time, off: None, items: items, locale: None }
+ DelayedFormat {
+ date,
+ time,
+ off: None,
+ items,
+ #[cfg(feature = "unstable-locales")]
+ locale: None,
+ }
}
/// Makes a new `DelayedFormat` value out of local date and time and UTC offset.
@@ -748,27 +890,30 @@ impl<'a, I: Iterator<Item = B> + Clone, B: Borrow<Item<'a>>> DelayedFormat<I> {
{
let name_and_diff = (offset.to_string(), offset.fix());
DelayedFormat {
- date: date,
- time: time,
+ date,
+ time,
off: Some(name_and_diff),
- items: items,
+ items,
+ #[cfg(feature = "unstable-locales")]
locale: None,
}
}
/// 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")))]
pub fn new_with_locale(
date: Option<NaiveDate>,
time: Option<NaiveTime>,
items: I,
locale: Locale,
) -> DelayedFormat<I> {
- DelayedFormat { date: date, time: time, off: None, items: items, locale: Some(locale) }
+ DelayedFormat { date, time, off: None, items, locale: Some(locale) }
}
/// 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")))]
pub fn new_with_offset_and_locale<Off>(
date: Option<NaiveDate>,
time: Option<NaiveTime>,
@@ -780,13 +925,7 @@ impl<'a, I: Iterator<Item = B> + Clone, B: Borrow<Item<'a>>> DelayedFormat<I> {
Off: Offset + fmt::Display,
{
let name_and_diff = (offset.to_string(), offset.fix());
- DelayedFormat {
- date: date,
- time: time,
- off: Some(name_and_diff),
- items: items,
- locale: Some(locale),
- }
+ DelayedFormat { date, time, off: Some(name_and_diff), items, locale: Some(locale) }
}
}
@@ -817,26 +956,26 @@ impl<'a, I: Iterator<Item = B> + Clone, B: Borrow<Item<'a>>> fmt::Display for De
///
/// # Example
///
-/// ~~~~
+/// ```
/// use chrono::Weekday;
///
/// assert_eq!("Sunday".parse::<Weekday>(), Ok(Weekday::Sun));
/// assert!("any day".parse::<Weekday>().is_err());
-/// ~~~~
+/// ```
///
/// The parsing is case-insensitive.
///
-/// ~~~~
+/// ```
/// # use chrono::Weekday;
/// assert_eq!("mON".parse::<Weekday>(), Ok(Weekday::Mon));
-/// ~~~~
+/// ```
///
/// Only the shortest form (e.g. `sun`) and the longest form (e.g. `sunday`) is accepted.
///
-/// ~~~~
+/// ```
/// # use chrono::Weekday;
/// assert!("thurs".parse::<Weekday>().is_err());
-/// ~~~~
+/// ```
impl FromStr for Weekday {
type Err = ParseWeekdayError;
@@ -851,6 +990,7 @@ impl FromStr for Weekday {
/// Formats single formatting item
#[cfg(feature = "unstable-locales")]
+#[cfg_attr(docsrs, doc(cfg(feature = "unstable-locales")))]
pub fn format_item_localized<'a>(
w: &mut fmt::Formatter,
date: Option<&NaiveDate>,
@@ -867,6 +1007,7 @@ pub fn format_item_localized<'a>(
/// Tries to format given arguments with given formatting items.
/// Internally used by `DelayedFormat`.
#[cfg(feature = "unstable-locales")]
+#[cfg_attr(docsrs, doc(cfg(feature = "unstable-locales")))]
pub fn format_localized<'a, I, B>(
w: &mut fmt::Formatter,
date: Option<&NaiveDate>,
@@ -890,27 +1031,27 @@ where
///
/// # Example
///
-/// ~~~~
+/// ```
/// use chrono::Month;
///
/// assert_eq!("January".parse::<Month>(), Ok(Month::January));
/// assert!("any day".parse::<Month>().is_err());
-/// ~~~~
+/// ```
///
/// The parsing is case-insensitive.
///
-/// ~~~~
+/// ```
/// # use chrono::Month;
/// assert_eq!("fEbruARy".parse::<Month>(), Ok(Month::February));
-/// ~~~~
+/// ```
///
/// Only the shortest form (e.g. `jan`) and the longest form (e.g. `january`) is accepted.
///
-/// ~~~~
+/// ```
/// # use chrono::Month;
/// assert!("septem".parse::<Month>().is_err());
/// assert!("Augustin".parse::<Month>().is_err());
-/// ~~~~
+/// ```
impl FromStr for Month {
type Err = ParseMonthError;
diff --git a/vendor/chrono/src/format/parse.rs b/vendor/chrono/src/format/parse.rs
index 2fce8277b..69204d2e9 100644
--- a/vendor/chrono/src/format/parse.rs
+++ b/vendor/chrono/src/format/parse.rs
@@ -14,7 +14,7 @@ use super::scan;
use super::{Fixed, InternalFixed, InternalInternal, Item, Numeric, Pad, Parsed};
use super::{ParseError, ParseErrorKind, ParseResult};
use super::{BAD_FORMAT, INVALID, NOT_ENOUGH, OUT_OF_RANGE, TOO_LONG, TOO_SHORT};
-use {DateTime, FixedOffset, Weekday};
+use crate::{DateTime, FixedOffset, Weekday};
fn set_weekday_with_num_days_from_sunday(p: &mut Parsed, v: i64) -> ParseResult<()> {
p.set_weekday(match v {
@@ -53,7 +53,10 @@ fn parse_rfc2822<'a>(parsed: &mut Parsed, mut s: &'a str) -> ParseResult<(&'a st
// an adapted RFC 2822 syntax from Section 3.3 and 4.3:
//
- // date-time = [ day-of-week "," ] date 1*S time *S
+ // c-char = <any char except '(', ')' and '\\'>
+ // c-escape = "\" <any char>
+ // comment = "(" *(comment / c-char / c-escape) ")" *S
+ // date-time = [ day-of-week "," ] date 1*S time *S *comment
// day-of-week = *S day-name *S
// day-name = "Mon" / "Tue" / "Wed" / "Thu" / "Fri" / "Sat" / "Sun"
// date = day month year
@@ -79,9 +82,10 @@ fn parse_rfc2822<'a>(parsed: &mut Parsed, mut s: &'a str) -> ParseResult<(&'a st
//
// - we do not recognize a folding white space (FWS) or comment (CFWS).
// for our purposes, instead, we accept any sequence of Unicode
- // white space characters (denoted here to `S`). any actual RFC 2822
- // parser is expected to parse FWS and/or CFWS themselves and replace
- // it with a single SP (`%x20`); this is legitimate.
+ // white space characters (denoted here to `S`). For comments, we accept
+ // any text within parentheses while respecting escaped parentheses.
+ // Any actual RFC 2822 parser is expected to parse FWS and/or CFWS themselves
+ // and replace it with a single SP (`%x20`); this is legitimate.
//
// - two-digit year < 50 should be interpreted by adding 2000.
// two-digit year >= 50 or three-digit year should be interpreted
@@ -117,10 +121,10 @@ fn parse_rfc2822<'a>(parsed: &mut Parsed, mut s: &'a str) -> ParseResult<(&'a st
let mut year = try_consume!(scan::number(s, 2, usize::MAX));
let yearlen = prevlen - s.len();
match (yearlen, year) {
- (2, 0...49) => {
+ (2, 0..=49) => {
year += 2000;
} // 47 -> 2047, 05 -> 2005
- (2, 50...99) => {
+ (2, 50..=99) => {
year += 1900;
} // 79 -> 1979
(3, _) => {
@@ -145,6 +149,11 @@ fn parse_rfc2822<'a>(parsed: &mut Parsed, mut s: &'a str) -> ParseResult<(&'a st
parsed.set_offset(i64::from(offset))?;
}
+ // optional comments
+ while let Ok((s_out, ())) = scan::comment_2822(s) {
+ s = s_out;
+ }
+
Ok((s, ()))
}
@@ -411,7 +420,10 @@ where
try_consume!(scan::timezone_name_skip(s));
}
- &TimezoneOffsetColon | &TimezoneOffset => {
+ &TimezoneOffsetColon
+ | &TimezoneOffsetDoubleColon
+ | &TimezoneOffsetTripleColon
+ | &TimezoneOffset => {
let offset = try_consume!(scan::timezone_offset(
s.trim_left(),
scan::colon_or_space
@@ -455,11 +467,22 @@ 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.
+///
+/// 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>>();
+/// ```
impl str::FromStr for DateTime<FixedOffset> {
type Err = ParseError;
fn from_str(s: &str) -> ParseResult<DateTime<FixedOffset>> {
- const DATE_ITEMS: &'static [Item<'static>] = &[
+ const DATE_ITEMS: &[Item<'static>] = &[
Item::Numeric(Numeric::Year, Pad::Zero),
Item::Space(""),
Item::Literal("-"),
@@ -468,7 +491,7 @@ impl str::FromStr for DateTime<FixedOffset> {
Item::Literal("-"),
Item::Numeric(Numeric::Day, Pad::Zero),
];
- const TIME_ITEMS: &'static [Item<'static>] = &[
+ const TIME_ITEMS: &[Item<'static>] = &[
Item::Numeric(Numeric::Hour, Pad::Zero),
Item::Space(""),
Item::Literal(":"),
@@ -488,11 +511,11 @@ impl str::FromStr for DateTime<FixedOffset> {
if remainder.starts_with('T') || remainder.starts_with(' ') {
parse(&mut parsed, &remainder[1..], TIME_ITEMS.iter())?;
} else {
- Err(INVALID)?;
+ return Err(INVALID);
}
}
- Err((_s, e)) => Err(e)?,
- Ok(_) => Err(NOT_ENOUGH)?,
+ Err((_s, e)) => return Err(e),
+ Ok(_) => return Err(NOT_ENOUGH),
};
parsed.to_datetime()
}
@@ -557,7 +580,7 @@ fn test_parse() {
check!(" \t987", [num!(Year)]; year: 987);
check!("5", [num!(Year)]; year: 5);
check!("5\0", [num!(Year)]; TOO_LONG);
- check!("\05", [num!(Year)]; INVALID);
+ check!("\x005", [num!(Year)]; INVALID);
check!("", [num!(Year)]; TOO_SHORT);
check!("12345", [num!(Year), lit!("5")]; year: 1234);
check!("12345", [nums!(Year), lit!("5")]; year: 1234);
@@ -798,14 +821,25 @@ fn test_parse() {
fn test_rfc2822() {
use super::NOT_ENOUGH;
use super::*;
- use offset::FixedOffset;
- use DateTime;
+ use crate::offset::FixedOffset;
+ use crate::DateTime;
// Test data - (input, Ok(expected result after parse and format) or Err(error code))
let testdates = [
("Tue, 20 Jan 2015 17:35:20 -0800", Ok("Tue, 20 Jan 2015 17:35:20 -0800")), // normal case
("Fri, 2 Jan 2015 17:35:20 -0800", Ok("Fri, 02 Jan 2015 17:35:20 -0800")), // folding whitespace
("Fri, 02 Jan 2015 17:35:20 -0800", Ok("Fri, 02 Jan 2015 17:35:20 -0800")), // leading zero
+ ("Tue, 20 Jan 2015 17:35:20 -0800 (UTC)", Ok("Tue, 20 Jan 2015 17:35:20 -0800")), // trailing comment
+ (
+ r"Tue, 20 Jan 2015 17:35:20 -0800 ( (UTC ) (\( (a)\(( \t ) ) \\( \) ))",
+ Ok("Tue, 20 Jan 2015 17:35:20 -0800"),
+ ), // complex trailing comment
+ (r"Tue, 20 Jan 2015 17:35:20 -0800 (UTC\)", Err(TOO_LONG)), // incorrect comment, not enough closing parentheses
+ (
+ "Tue, 20 Jan 2015 17:35:20 -0800 (UTC)\t \r\n(Anothercomment)",
+ Ok("Tue, 20 Jan 2015 17:35:20 -0800"),
+ ), // multiple comments
+ ("Tue, 20 Jan 2015 17:35:20 -0800 (UTC) ", Err(TOO_LONG)), // trailing whitespace after comment
("20 Jan 2015 17:35:20 -0800", Ok("Tue, 20 Jan 2015 17:35:20 -0800")), // no day of week
("20 JAN 2015 17:35:20 -0800", Ok("Tue, 20 Jan 2015 17:35:20 -0800")), // upper case month
("Tue, 20 Jan 2015 17:35 -0800", Ok("Tue, 20 Jan 2015 17:35:00 -0800")), // no second
@@ -853,12 +887,12 @@ fn test_rfc2822() {
#[cfg(test)]
#[test]
fn parse_rfc850() {
- use {TimeZone, Utc};
+ use crate::{TimeZone, Utc};
- static RFC850_FMT: &'static str = "%A, %d-%b-%y %T GMT";
+ static RFC850_FMT: &str = "%A, %d-%b-%y %T GMT";
let dt_str = "Sunday, 06-Nov-94 08:49:37 GMT";
- let dt = Utc.ymd(1994, 11, 6).and_hms(8, 49, 37);
+ let dt = Utc.with_ymd_and_hms(1994, 11, 6, 8, 49, 37).unwrap();
// Check that the format is what we expect
assert_eq!(dt.format(RFC850_FMT).to_string(), dt_str);
@@ -869,12 +903,21 @@ fn parse_rfc850() {
// Check that the rest of the weekdays parse correctly (this test originally failed because
// Sunday parsed incorrectly).
let testdates = [
- (Utc.ymd(1994, 11, 7).and_hms(8, 49, 37), "Monday, 07-Nov-94 08:49:37 GMT"),
- (Utc.ymd(1994, 11, 8).and_hms(8, 49, 37), "Tuesday, 08-Nov-94 08:49:37 GMT"),
- (Utc.ymd(1994, 11, 9).and_hms(8, 49, 37), "Wednesday, 09-Nov-94 08:49:37 GMT"),
- (Utc.ymd(1994, 11, 10).and_hms(8, 49, 37), "Thursday, 10-Nov-94 08:49:37 GMT"),
- (Utc.ymd(1994, 11, 11).and_hms(8, 49, 37), "Friday, 11-Nov-94 08:49:37 GMT"),
- (Utc.ymd(1994, 11, 12).and_hms(8, 49, 37), "Saturday, 12-Nov-94 08:49:37 GMT"),
+ (Utc.with_ymd_and_hms(1994, 11, 7, 8, 49, 37).unwrap(), "Monday, 07-Nov-94 08:49:37 GMT"),
+ (Utc.with_ymd_and_hms(1994, 11, 8, 8, 49, 37).unwrap(), "Tuesday, 08-Nov-94 08:49:37 GMT"),
+ (
+ Utc.with_ymd_and_hms(1994, 11, 9, 8, 49, 37).unwrap(),
+ "Wednesday, 09-Nov-94 08:49:37 GMT",
+ ),
+ (
+ Utc.with_ymd_and_hms(1994, 11, 10, 8, 49, 37).unwrap(),
+ "Thursday, 10-Nov-94 08:49:37 GMT",
+ ),
+ (Utc.with_ymd_and_hms(1994, 11, 11, 8, 49, 37).unwrap(), "Friday, 11-Nov-94 08:49:37 GMT"),
+ (
+ Utc.with_ymd_and_hms(1994, 11, 12, 8, 49, 37).unwrap(),
+ "Saturday, 12-Nov-94 08:49:37 GMT",
+ ),
];
for val in &testdates {
@@ -886,8 +929,8 @@ fn parse_rfc850() {
#[test]
fn test_rfc3339() {
use super::*;
- use offset::FixedOffset;
- use DateTime;
+ use crate::offset::FixedOffset;
+ use crate::DateTime;
// Test data - (input, Ok(expected result after parse and format) or Err(error code))
let testdates = [
diff --git a/vendor/chrono/src/format/parsed.rs b/vendor/chrono/src/format/parsed.rs
index b8ed2d90f..6cc29e9d4 100644
--- a/vendor/chrono/src/format/parsed.rs
+++ b/vendor/chrono/src/format/parsed.rs
@@ -4,16 +4,16 @@
//! 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 oldtime::Duration as OldDuration;
use super::{ParseResult, IMPOSSIBLE, NOT_ENOUGH, OUT_OF_RANGE};
-use div::div_rem;
-use naive::{NaiveDate, NaiveDateTime, NaiveTime};
-use offset::{FixedOffset, LocalResult, Offset, TimeZone};
-use DateTime;
-use Weekday;
-use {Datelike, Timelike};
+use crate::naive::{NaiveDate, NaiveDateTime, NaiveTime};
+use crate::offset::{FixedOffset, LocalResult, Offset, TimeZone};
+use crate::oldtime::Duration as OldDuration;
+use crate::DateTime;
+use crate::Weekday;
+use crate::{Datelike, Timelike};
/// Parsed parts of date and time. There are two classes of methods:
///
@@ -22,8 +22,7 @@ use {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(missing_copy_implementations)]
-#[derive(Clone, PartialEq, Debug)]
+#[derive(Clone, PartialEq, Eq, Debug, Default, Hash)]
pub struct Parsed {
/// Year.
///
@@ -126,34 +125,6 @@ fn set_if_consistent<T: PartialEq>(old: &mut Option<T>, new: T) -> ParseResult<(
}
}
-impl Default for Parsed {
- fn default() -> Parsed {
- Parsed {
- year: None,
- year_div_100: None,
- year_mod_100: None,
- isoyear: None,
- isoyear_div_100: None,
- isoyear_mod_100: None,
- month: None,
- week_from_sun: None,
- week_from_mon: None,
- isoweek: None,
- weekday: None,
- ordinal: None,
- day: None,
- hour_div_12: None,
- hour_mod_12: None,
- minute: None,
- second: None,
- nanosecond: None,
- timestamp: None,
- offset: None,
- _dummy: (),
- }
- }
-}
-
impl Parsed {
/// Returns the initial value of parsed parts.
pub fn new() -> Parsed {
@@ -254,14 +225,14 @@ impl Parsed {
/// (`false` for AM, `true` for PM)
#[inline]
pub fn set_ampm(&mut self, value: bool) -> ParseResult<()> {
- set_if_consistent(&mut self.hour_div_12, if value { 1 } else { 0 })
+ set_if_consistent(&mut self.hour_div_12, u32::from(value))
}
/// Tries to set the [`hour_mod_12`](#structfield.hour_mod_12) field from
/// given hour number in 12-hour clocks.
#[inline]
pub fn set_hour12(&mut self, value: i64) -> ParseResult<()> {
- if value < 1 || value > 12 {
+ if !(1..=12).contains(&value) {
return Err(OUT_OF_RANGE);
}
set_if_consistent(&mut self.hour_mod_12, value as u32 % 12)
@@ -333,7 +304,7 @@ impl Parsed {
// check if present quotient and/or modulo is consistent to the full year.
// since the presence of those fields means a positive full year,
// we should filter a negative full year first.
- (Some(y), q, r @ Some(0...99)) | (Some(y), q, r @ None) => {
+ (Some(y), q, r @ Some(0..=99)) | (Some(y), q, r @ None) => {
if y < 0 {
return Err(OUT_OF_RANGE);
}
@@ -347,7 +318,7 @@ impl Parsed {
// the full year is missing but we have quotient and modulo.
// reconstruct the full year. make sure that the result is always positive.
- (None, Some(q), Some(r @ 0...99)) => {
+ (None, Some(q), Some(r @ 0..=99)) => {
if q < 0 {
return Err(OUT_OF_RANGE);
}
@@ -357,7 +328,7 @@ impl Parsed {
// we only have modulo. try to interpret a modulo as a conventional two-digit year.
// note: we are affected by Rust issue #18060. avoid multiple range patterns.
- (None, None, Some(r @ 0...99)) => Ok(Some(r + if r < 70 { 2000 } else { 1900 })),
+ (None, None, Some(r @ 0..=99)) => Ok(Some(r + if r < 70 { 2000 } else { 1900 })),
// otherwise it is an out-of-bound or insufficient condition.
(None, Some(_), None) => Err(NOT_ENOUGH),
@@ -408,9 +379,8 @@ impl Parsed {
// verify the ordinal and other (non-ISO) week dates.
let verify_ordinal = |date: NaiveDate| {
let ordinal = date.ordinal();
- let weekday = date.weekday();
- let week_from_sun = (ordinal as i32 - weekday.num_days_from_sunday() as i32 + 7) / 7;
- let week_from_mon = (ordinal as i32 - weekday.num_days_from_monday() as i32 + 7) / 7;
+ let week_from_sun = date.weeks_from(Weekday::Sun);
+ let week_from_mon = date.weeks_from(Weekday::Mon);
self.ordinal.unwrap_or(ordinal) == ordinal
&& self.week_from_sun.map_or(week_from_sun, |v| v as i32) == week_from_sun
&& self.week_from_mon.map_or(week_from_mon, |v| v as i32) == week_from_mon
@@ -528,32 +498,32 @@ impl Parsed {
/// It is able to handle leap seconds when given second is 60.
pub fn to_naive_time(&self) -> ParseResult<NaiveTime> {
let hour_div_12 = match self.hour_div_12 {
- Some(v @ 0...1) => v,
+ Some(v @ 0..=1) => v,
Some(_) => return Err(OUT_OF_RANGE),
None => return Err(NOT_ENOUGH),
};
let hour_mod_12 = match self.hour_mod_12 {
- Some(v @ 0...11) => v,
+ Some(v @ 0..=11) => v,
Some(_) => return Err(OUT_OF_RANGE),
None => return Err(NOT_ENOUGH),
};
let hour = hour_div_12 * 12 + hour_mod_12;
let minute = match self.minute {
- Some(v @ 0...59) => v,
+ Some(v @ 0..=59) => v,
Some(_) => return Err(OUT_OF_RANGE),
None => return Err(NOT_ENOUGH),
};
// we allow omitting seconds or nanoseconds, but they should be in the range.
let (second, mut nano) = match self.second.unwrap_or(0) {
- v @ 0...59 => (v, 0),
+ v @ 0..=59 => (v, 0),
60 => (59, 1_000_000_000),
_ => return Err(OUT_OF_RANGE),
};
nano += match self.nanosecond {
- Some(v @ 0...999_999_999) if self.second.is_some() => v,
- Some(0...999_999_999) => return Err(NOT_ENOUGH), // second is missing
+ Some(v @ 0..=999_999_999) if self.second.is_some() => v,
+ Some(0..=999_999_999) => return Err(NOT_ENOUGH), // second is missing
Some(_) => return Err(OUT_OF_RANGE),
None => 0,
};
@@ -655,6 +625,12 @@ impl Parsed {
let offset = self.offset.ok_or(NOT_ENOUGH)?;
let datetime = self.to_naive_datetime_with_offset(offset)?;
let offset = FixedOffset::east_opt(offset).ok_or(OUT_OF_RANGE)?;
+
+ // this is used to prevent an overflow when calling FixedOffset::from_local_datetime
+ datetime
+ .checked_sub_signed(OldDuration::seconds(i64::from(offset.local_minus_utc())))
+ .ok_or(OUT_OF_RANGE)?;
+
match offset.from_local_datetime(&datetime) {
LocalResult::None => Err(IMPOSSIBLE),
LocalResult::Single(t) => Ok(t),
@@ -721,10 +697,10 @@ impl Parsed {
mod tests {
use super::super::{IMPOSSIBLE, NOT_ENOUGH, OUT_OF_RANGE};
use super::Parsed;
- use naive::{NaiveDate, NaiveTime, MAX_DATE, MIN_DATE};
- use offset::{FixedOffset, TimeZone, Utc};
- use Datelike;
- use Weekday::*;
+ use crate::naive::{NaiveDate, NaiveTime};
+ use crate::offset::{FixedOffset, TimeZone, Utc};
+ use crate::Datelike;
+ use crate::Weekday::*;
#[test]
fn test_parsed_set_fields() {
@@ -805,7 +781,7 @@ mod tests {
)
}
- let ymd = |y, m, d| Ok(NaiveDate::from_ymd(y, m, d));
+ let ymd = |y, m, d| Ok(NaiveDate::from_ymd_opt(y, m, d).unwrap());
// ymd: omission of fields
assert_eq!(parse!(), Err(NOT_ENOUGH));
@@ -851,7 +827,7 @@ mod tests {
assert_eq!(parse!(year_div_100: 19, year_mod_100: -1, month: 1, day: 1), Err(OUT_OF_RANGE));
assert_eq!(parse!(year_div_100: 0, year_mod_100: 0, month: 1, day: 1), ymd(0, 1, 1));
assert_eq!(parse!(year_div_100: -1, year_mod_100: 42, month: 1, day: 1), Err(OUT_OF_RANGE));
- let max_year = MAX_DATE.year();
+ let max_year = NaiveDate::MAX.year();
assert_eq!(
parse!(year_div_100: max_year / 100,
year_mod_100: max_year % 100, month: 1, day: 1),
@@ -992,8 +968,8 @@ mod tests {
)
}
- let hms = |h, m, s| Ok(NaiveTime::from_hms(h, m, s));
- let hmsn = |h, m, s, n| Ok(NaiveTime::from_hms_nano(h, m, s, n));
+ let hms = |h, m, s| Ok(NaiveTime::from_hms_opt(h, m, s).unwrap());
+ let hmsn = |h, m, s, n| Ok(NaiveTime::from_hms_nano_opt(h, m, s, n).unwrap());
// omission of fields
assert_eq!(parse!(), Err(NOT_ENOUGH));
@@ -1048,9 +1024,12 @@ mod tests {
($($k:ident: $v:expr),*) => (parse!(offset = 0; $($k: $v),*))
}
- let ymdhms = |y, m, d, h, n, s| Ok(NaiveDate::from_ymd(y, m, d).and_hms(h, n, s));
- let ymdhmsn =
- |y, m, d, h, n, s, nano| Ok(NaiveDate::from_ymd(y, m, d).and_hms_nano(h, n, s, nano));
+ let ymdhms = |y, m, d, h, n, s| {
+ Ok(NaiveDate::from_ymd_opt(y, m, d).unwrap().and_hms_opt(h, n, s).unwrap())
+ };
+ let ymdhmsn = |y, m, d, h, n, s, nano| {
+ Ok(NaiveDate::from_ymd_opt(y, m, d).unwrap().and_hms_nano_opt(h, n, s, nano).unwrap())
+ };
// omission of fields
assert_eq!(parse!(), Err(NOT_ENOUGH));
@@ -1104,14 +1083,15 @@ mod tests {
// more timestamps
let max_days_from_year_1970 =
- MAX_DATE.signed_duration_since(NaiveDate::from_ymd(1970, 1, 1));
- let year_0_from_year_1970 =
- NaiveDate::from_ymd(0, 1, 1).signed_duration_since(NaiveDate::from_ymd(1970, 1, 1));
+ NaiveDate::MAX.signed_duration_since(NaiveDate::from_ymd_opt(1970, 1, 1).unwrap());
+ let year_0_from_year_1970 = NaiveDate::from_ymd_opt(0, 1, 1)
+ .unwrap()
+ .signed_duration_since(NaiveDate::from_ymd_opt(1970, 1, 1).unwrap());
let min_days_from_year_1970 =
- MIN_DATE.signed_duration_since(NaiveDate::from_ymd(1970, 1, 1));
+ NaiveDate::MIN.signed_duration_since(NaiveDate::from_ymd_opt(1970, 1, 1).unwrap());
assert_eq!(
parse!(timestamp: min_days_from_year_1970.num_seconds()),
- ymdhms(MIN_DATE.year(), 1, 1, 0, 0, 0)
+ ymdhms(NaiveDate::MIN.year(), 1, 1, 0, 0, 0)
);
assert_eq!(
parse!(timestamp: year_0_from_year_1970.num_seconds()),
@@ -1119,7 +1099,7 @@ mod tests {
);
assert_eq!(
parse!(timestamp: max_days_from_year_1970.num_seconds() + 86399),
- ymdhms(MAX_DATE.year(), 12, 31, 23, 59, 59)
+ ymdhms(NaiveDate::MAX.year(), 12, 31, 23, 59, 59)
);
// leap seconds #1: partial fields
@@ -1198,7 +1178,15 @@ mod tests {
}
let ymdhmsn = |y, m, d, h, n, s, nano, off| {
- Ok(FixedOffset::east(off).ymd(y, m, d).and_hms_nano(h, n, s, nano))
+ Ok(FixedOffset::east_opt(off)
+ .unwrap()
+ .from_local_datetime(
+ &NaiveDate::from_ymd_opt(y, m, d)
+ .unwrap()
+ .and_hms_nano_opt(h, n, s, nano)
+ .unwrap(),
+ )
+ .unwrap())
};
assert_eq!(parse!(offset: 0), Err(NOT_ENOUGH));
@@ -1242,7 +1230,14 @@ mod tests {
parse!(Utc;
year: 2014, ordinal: 365, hour_div_12: 0, hour_mod_12: 4,
minute: 26, second: 40, nanosecond: 12_345_678, offset: 0),
- Ok(Utc.ymd(2014, 12, 31).and_hms_nano(4, 26, 40, 12_345_678))
+ Ok(Utc
+ .from_local_datetime(
+ &NaiveDate::from_ymd_opt(2014, 12, 31)
+ .unwrap()
+ .and_hms_nano_opt(4, 26, 40, 12_345_678)
+ .unwrap()
+ )
+ .unwrap())
);
assert_eq!(
parse!(Utc;
@@ -1251,31 +1246,42 @@ mod tests {
Err(IMPOSSIBLE)
);
assert_eq!(
- parse!(FixedOffset::east(32400);
+ parse!(FixedOffset::east_opt(32400).unwrap();
year: 2014, ordinal: 365, hour_div_12: 0, hour_mod_12: 4,
minute: 26, second: 40, nanosecond: 12_345_678, offset: 0),
Err(IMPOSSIBLE)
);
assert_eq!(
- parse!(FixedOffset::east(32400);
+ parse!(FixedOffset::east_opt(32400).unwrap();
year: 2014, ordinal: 365, hour_div_12: 1, hour_mod_12: 1,
minute: 26, second: 40, nanosecond: 12_345_678, offset: 32400),
- Ok(FixedOffset::east(32400).ymd(2014, 12, 31).and_hms_nano(13, 26, 40, 12_345_678))
+ Ok(FixedOffset::east_opt(32400)
+ .unwrap()
+ .from_local_datetime(
+ &NaiveDate::from_ymd_opt(2014, 12, 31)
+ .unwrap()
+ .and_hms_nano_opt(13, 26, 40, 12_345_678)
+ .unwrap()
+ )
+ .unwrap())
);
// single result from timestamp
assert_eq!(
parse!(Utc; timestamp: 1_420_000_000, offset: 0),
- Ok(Utc.ymd(2014, 12, 31).and_hms(4, 26, 40))
+ Ok(Utc.with_ymd_and_hms(2014, 12, 31, 4, 26, 40).unwrap())
);
assert_eq!(parse!(Utc; timestamp: 1_420_000_000, offset: 32400), Err(IMPOSSIBLE));
assert_eq!(
- parse!(FixedOffset::east(32400); timestamp: 1_420_000_000, offset: 0),
+ parse!(FixedOffset::east_opt(32400).unwrap(); timestamp: 1_420_000_000, offset: 0),
Err(IMPOSSIBLE)
);
assert_eq!(
- parse!(FixedOffset::east(32400); timestamp: 1_420_000_000, offset: 32400),
- Ok(FixedOffset::east(32400).ymd(2014, 12, 31).and_hms(13, 26, 40))
+ parse!(FixedOffset::east_opt(32400).unwrap(); timestamp: 1_420_000_000, offset: 32400),
+ Ok(FixedOffset::east_opt(32400)
+ .unwrap()
+ .with_ymd_and_hms(2014, 12, 31, 13, 26, 40)
+ .unwrap())
);
// TODO test with a variable time zone (for None and Ambiguous cases)
diff --git a/vendor/chrono/src/format/scan.rs b/vendor/chrono/src/format/scan.rs
index 0efb1ee3d..263fec556 100644
--- a/vendor/chrono/src/format/scan.rs
+++ b/vendor/chrono/src/format/scan.rs
@@ -8,13 +8,13 @@
#![allow(deprecated)]
use super::{ParseResult, INVALID, OUT_OF_RANGE, TOO_SHORT};
-use Weekday;
+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 {
- b'A'...b'Z' => c + 32,
+ b'A'..=b'Z' => c + 32,
_ => c,
});
let mut ys = pattern.as_bytes().iter().cloned();
@@ -34,7 +34,7 @@ fn equals(s: &str, pattern: &str) -> bool {
/// More than `max` digits are consumed up to the first `max` digits.
/// Any number that does not fit in `i64` is an error.
#[inline]
-pub fn number(s: &str, min: usize, max: usize) -> ParseResult<(&str, i64)> {
+pub(super) fn number(s: &str, min: usize, max: usize) -> ParseResult<(&str, i64)> {
assert!(min <= max);
// We are only interested in ascii numbers, so we can work with the `str` as bytes. We stop on
@@ -48,7 +48,7 @@ pub 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 c < b'0' || b'9' < c {
+ if !(b'0'..=b'9').contains(&c) {
if i < min {
return Err(INVALID);
} else {
@@ -62,12 +62,12 @@ pub fn number(s: &str, min: usize, max: usize) -> ParseResult<(&str, i64)> {
};
}
- Ok((&s[::core::cmp::min(max, bytes.len())..], n))
+ Ok((&s[core::cmp::min(max, bytes.len())..], n))
}
/// Tries to consume at least one digits as a fractional second.
/// Returns the number of whole nanoseconds (0--999,999,999).
-pub fn nanosecond(s: &str) -> ParseResult<(&str, i64)> {
+pub(super) fn nanosecond(s: &str) -> ParseResult<(&str, i64)> {
// record the number of digits consumed for later scaling.
let origlen = s.len();
let (s, v) = number(s, 1, 9)?;
@@ -79,14 +79,14 @@ pub 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' <= c && c <= '9');
+ let s = s.trim_left_matches(|c: char| ('0'..='9').contains(&c));
Ok((s, v))
}
/// Tries to consume a fixed number of digits as a fractional second.
/// Returns the number of whole nanoseconds (0--999,999,999).
-pub fn nanosecond_fixed(s: &str, digits: usize) -> ParseResult<(&str, i64)> {
+pub(super) fn nanosecond_fixed(s: &str, digits: usize) -> ParseResult<(&str, i64)> {
// record the number of digits consumed for later scaling.
let (s, v) = number(s, digits, digits)?;
@@ -99,7 +99,7 @@ pub fn nanosecond_fixed(s: &str, digits: usize) -> ParseResult<(&str, i64)> {
}
/// Tries to parse the month index (0 through 11) with the first three ASCII letters.
-pub fn short_month0(s: &str) -> ParseResult<(&str, u8)> {
+pub(super) fn short_month0(s: &str) -> ParseResult<(&str, u8)> {
if s.len() < 3 {
return Err(TOO_SHORT);
}
@@ -123,7 +123,7 @@ pub fn short_month0(s: &str) -> ParseResult<(&str, u8)> {
}
/// Tries to parse the weekday with the first three ASCII letters.
-pub fn short_weekday(s: &str) -> ParseResult<(&str, Weekday)> {
+pub(super) fn short_weekday(s: &str) -> ParseResult<(&str, Weekday)> {
if s.len() < 3 {
return Err(TOO_SHORT);
}
@@ -143,9 +143,9 @@ pub fn short_weekday(s: &str) -> ParseResult<(&str, Weekday)> {
/// Tries to parse the month index (0 through 11) with short or long month names.
/// It prefers long month names to short month names when both are possible.
-pub fn short_or_long_month0(s: &str) -> ParseResult<(&str, u8)> {
+pub(super) fn short_or_long_month0(s: &str) -> ParseResult<(&str, u8)> {
// lowercased month names, minus first three chars
- static LONG_MONTH_SUFFIXES: [&'static str; 12] =
+ static LONG_MONTH_SUFFIXES: [&str; 12] =
["uary", "ruary", "ch", "il", "", "e", "y", "ust", "tember", "ober", "ember", "ember"];
let (mut s, month0) = short_month0(s)?;
@@ -161,9 +161,9 @@ pub fn short_or_long_month0(s: &str) -> ParseResult<(&str, u8)> {
/// Tries to parse the weekday with short or long weekday names.
/// It prefers long weekday names to short weekday names when both are possible.
-pub fn short_or_long_weekday(s: &str) -> ParseResult<(&str, Weekday)> {
+pub(super) fn short_or_long_weekday(s: &str) -> ParseResult<(&str, Weekday)> {
// lowercased weekday names, minus first three chars
- static LONG_WEEKDAY_SUFFIXES: [&'static str; 7] =
+ static LONG_WEEKDAY_SUFFIXES: [&str; 7] =
["day", "sday", "nesday", "rsday", "day", "urday", "day"];
let (mut s, weekday) = short_weekday(s)?;
@@ -178,7 +178,7 @@ pub fn short_or_long_weekday(s: &str) -> ParseResult<(&str, Weekday)> {
}
/// Tries to consume exactly one given character.
-pub fn char(s: &str, c1: u8) -> ParseResult<&str> {
+pub(super) fn char(s: &str, c1: u8) -> ParseResult<&str> {
match s.as_bytes().first() {
Some(&c) if c == c1 => Ok(&s[1..]),
Some(_) => Err(INVALID),
@@ -187,7 +187,7 @@ pub fn char(s: &str, c1: u8) -> ParseResult<&str> {
}
/// Tries to consume one or more whitespace.
-pub fn space(s: &str) -> ParseResult<&str> {
+pub(super) fn space(s: &str) -> ParseResult<&str> {
let s_ = s.trim_left();
if s_.len() < s.len() {
Ok(s_)
@@ -199,7 +199,7 @@ pub fn space(s: &str) -> ParseResult<&str> {
}
/// Consumes any number (including zero) of colon or spaces.
-pub fn colon_or_space(s: &str) -> ParseResult<&str> {
+pub(super) fn colon_or_space(s: &str) -> ParseResult<&str> {
Ok(s.trim_left_matches(|c: char| c == ':' || c.is_whitespace()))
}
@@ -207,7 +207,7 @@ pub fn colon_or_space(s: &str) -> ParseResult<&str> {
///
/// The additional `colon` may be used to parse a mandatory or optional `:`
/// between hours and minutes, and should return either a new suffix or `Err` when parsing fails.
-pub fn timezone_offset<F>(s: &str, consume_colon: F) -> ParseResult<(&str, i32)>
+pub(super) fn timezone_offset<F>(s: &str, consume_colon: F) -> ParseResult<(&str, i32)>
where
F: FnMut(&str) -> ParseResult<&str>,
{
@@ -240,7 +240,7 @@ where
// hours (00--99)
let hours = match digits(s)? {
- (h1 @ b'0'...b'9', h2 @ b'0'...b'9') => i32::from((h1 - b'0') * 10 + (h2 - b'0')),
+ (h1 @ b'0'..=b'9', h2 @ b'0'..=b'9') => i32::from((h1 - b'0') * 10 + (h2 - b'0')),
_ => return Err(INVALID),
};
s = &s[2..];
@@ -252,8 +252,8 @@ where
// if the next two items are digits then we have to add minutes
let minutes = if let Ok(ds) = digits(s) {
match ds {
- (m1 @ b'0'...b'5', m2 @ b'0'...b'9') => i32::from((m1 - b'0') * 10 + (m2 - b'0')),
- (b'6'...b'9', b'0'...b'9') => return Err(OUT_OF_RANGE),
+ (m1 @ b'0'..=b'5', m2 @ b'0'..=b'9') => i32::from((m1 - b'0') * 10 + (m2 - b'0')),
+ (b'6'..=b'9', b'0'..=b'9') => return Err(OUT_OF_RANGE),
_ => return Err(INVALID),
}
} else if allow_missing_minutes {
@@ -272,7 +272,7 @@ where
}
/// Same as `timezone_offset` but also allows for `z`/`Z` which is the same as `+00:00`.
-pub fn timezone_offset_zulu<F>(s: &str, colon: F) -> ParseResult<(&str, i32)>
+pub(super) fn timezone_offset_zulu<F>(s: &str, colon: F) -> ParseResult<(&str, i32)>
where
F: FnMut(&str) -> ParseResult<&str>,
{
@@ -296,7 +296,7 @@ where
/// Same as `timezone_offset` but also allows for `z`/`Z` which is the same as
/// `+00:00`, and allows missing minutes entirely.
-pub fn timezone_offset_permissive<F>(s: &str, colon: F) -> ParseResult<(&str, i32)>
+pub(super) fn timezone_offset_permissive<F>(s: &str, colon: F) -> ParseResult<(&str, i32)>
where
F: FnMut(&str) -> ParseResult<&str>,
{
@@ -308,16 +308,16 @@ 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`).
-pub fn timezone_offset_2822(s: &str) -> ParseResult<(&str, Option<i32>)> {
+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,
+ b'a'..=b'z' | b'A'..=b'Z' => false,
_ => true,
})
- .unwrap_or_else(|| s.len());
+ .unwrap_or(s.len());
if upto > 0 {
let name = &s[..upto];
let s = &s[upto..];
@@ -343,8 +343,73 @@ pub fn timezone_offset_2822(s: &str) -> ParseResult<(&str, Option<i32>)> {
}
}
-/// Tries to consume everyting until next whitespace-like symbol.
+/// Tries to consume everything until next whitespace-like symbol.
/// Does not provide any offset information from the consumed data.
-pub fn timezone_name_skip(s: &str) -> ParseResult<(&str, ())> {
+pub(super) fn timezone_name_skip(s: &str) -> ParseResult<(&str, ())> {
Ok((s.trim_left_matches(|c: char| !c.is_whitespace()), ()))
}
+
+/// Tries to consume an RFC2822 comment including preceding ` `.
+///
+/// Returns the remaining string after the closing parenthesis.
+pub(super) fn comment_2822(s: &str) -> ParseResult<(&str, ())> {
+ use CommentState::*;
+
+ let s = s.trim_start();
+
+ let mut state = Start;
+ for (i, c) in s.bytes().enumerate() {
+ state = match (state, c) {
+ (Start, b'(') => Next(1),
+ (Next(1), b')') => return Ok((&s[i + 1..], ())),
+ (Next(depth), b'\\') => Escape(depth),
+ (Next(depth), b'(') => Next(depth + 1),
+ (Next(depth), b')') => Next(depth - 1),
+ (Next(depth), _) | (Escape(depth), _) => Next(depth),
+ _ => return Err(INVALID),
+ };
+ }
+
+ Err(TOO_SHORT)
+}
+
+enum CommentState {
+ Start,
+ Next(usize),
+ Escape(usize),
+}
+
+#[cfg(test)]
+#[test]
+fn test_rfc2822_comments() {
+ let testdata = [
+ ("", Err(TOO_SHORT)),
+ (" ", Err(TOO_SHORT)),
+ ("x", Err(INVALID)),
+ ("(", Err(TOO_SHORT)),
+ ("()", Ok("")),
+ (" \r\n\t()", Ok("")),
+ ("() ", Ok(" ")),
+ ("()z", Ok("z")),
+ ("(x)", Ok("")),
+ ("(())", Ok("")),
+ ("((()))", Ok("")),
+ ("(x(x(x)x)x)", Ok("")),
+ ("( x ( x ( x ) x ) x )", Ok("")),
+ (r"(\)", Err(TOO_SHORT)),
+ (r"(\()", Ok("")),
+ (r"(\))", Ok("")),
+ (r"(\\)", Ok("")),
+ ("(()())", Ok("")),
+ ("( x ( x ) x ( x ) x )", Ok("")),
+ ];
+
+ for (test_in, expected) in testdata.iter() {
+ let actual = comment_2822(test_in).map(|(s, _)| s);
+ assert_eq!(
+ *expected, actual,
+ "{:?} expected to produce {:?}, but produced {:?}.",
+ test_in, expected, actual
+ );
+ }
+}
diff --git a/vendor/chrono/src/format/strftime.rs b/vendor/chrono/src/format/strftime.rs
index 93820a232..dcaabe49f 100644
--- a/vendor/chrono/src/format/strftime.rs
+++ b/vendor/chrono/src/format/strftime.rs
@@ -11,9 +11,9 @@ The following specifiers are available both to formatting and parsing.
| Spec. | Example | Description |
|-------|----------|----------------------------------------------------------------------------|
| | | **DATE SPECIFIERS:** |
-| `%Y` | `2001` | The full proleptic Gregorian year, zero-padded to 4 digits. [^1] |
-| `%C` | `20` | The proleptic Gregorian year divided by 100, zero-padded to 2 digits. [^2] |
-| `%y` | `01` | The proleptic Gregorian year modulo 100, zero-padded to 2 digits. [^2] |
+| `%Y` | `2001` | The full proleptic Gregorian year, zero-padded to 4 digits. chrono supports years from -262144 to 262143. Note: years before 1 BCE or after 9999 CE, require an initial sign (+/-).|
+| `%C` | `20` | The proleptic Gregorian year divided by 100, zero-padded to 2 digits. [^1] |
+| `%y` | `01` | The proleptic Gregorian year modulo 100, zero-padded to 2 digits. [^1] |
| | | |
| `%m` | `07` | Month number (01--12), zero-padded to 2 digits. |
| `%b` | `Jul` | Abbreviated month name. Always 3 letters. |
@@ -28,12 +28,12 @@ The following specifiers are available both to formatting and parsing.
| `%w` | `0` | Sunday = 0, Monday = 1, ..., Saturday = 6. |
| `%u` | `7` | Monday = 1, Tuesday = 2, ..., Sunday = 7. (ISO 8601) |
| | | |
-| `%U` | `28` | Week number starting with Sunday (00--53), zero-padded to 2 digits. [^3] |
+| `%U` | `28` | Week number starting with Sunday (00--53), zero-padded to 2 digits. [^2] |
| `%W` | `27` | Same as `%U`, but week 1 starts with the first Monday in that year instead.|
| | | |
-| `%G` | `2001` | Same as `%Y` but uses the year number in ISO 8601 week date. [^4] |
-| `%g` | `01` | Same as `%y` but uses the year number in ISO 8601 week date. [^4] |
-| `%V` | `27` | Same as `%U` but uses the week number in ISO 8601 week date (01--53). [^4] |
+| `%G` | `2001` | Same as `%Y` but uses the year number in ISO 8601 week date. [^3] |
+| `%g` | `01` | Same as `%y` but uses the year number in ISO 8601 week date. [^3] |
+| `%V` | `27` | Same as `%U` but uses the week number in ISO 8601 week date (01--53). [^3] |
| | | |
| `%j` | `189` | Day of the year (001--366), zero-padded to 3 digits. |
| | | |
@@ -52,15 +52,15 @@ The following specifiers are available both to formatting and parsing.
| `%p` | `AM` | `AM` or `PM` in 12-hour clocks. |
| | | |
| `%M` | `34` | Minute number (00--59), zero-padded to 2 digits. |
-| `%S` | `60` | Second number (00--60), zero-padded to 2 digits. [^5] |
-| `%f` | `026490000` | The fractional seconds (in nanoseconds) since last whole second. [^8] |
-| `%.f` | `.026490`| Similar to `.%f` but left-aligned. These all consume the leading dot. [^8] |
-| `%.3f`| `.026` | Similar to `.%f` but left-aligned but fixed to a length of 3. [^8] |
-| `%.6f`| `.026490` | Similar to `.%f` but left-aligned but fixed to a length of 6. [^8] |
-| `%.9f`| `.026490000` | Similar to `.%f` but left-aligned but fixed to a length of 9. [^8] |
-| `%3f` | `026` | Similar to `%.3f` but without the leading dot. [^8] |
-| `%6f` | `026490` | Similar to `%.6f` but without the leading dot. [^8] |
-| `%9f` | `026490000` | Similar to `%.9f` but without the leading dot. [^8] |
+| `%S` | `60` | Second number (00--60), zero-padded to 2 digits. [^4] |
+| `%f` | `026490000` | The fractional seconds (in nanoseconds) since last whole second. [^7] |
+| `%.f` | `.026490`| Similar to `.%f` but left-aligned. These all consume the leading dot. [^7] |
+| `%.3f`| `.026` | Similar to `.%f` but left-aligned but fixed to a length of 3. [^7] |
+| `%.6f`| `.026490` | Similar to `.%f` but left-aligned but fixed to a length of 6. [^7] |
+| `%.9f`| `.026490000` | Similar to `.%f` but left-aligned but fixed to a length of 9. [^7] |
+| `%3f` | `026` | Similar to `%.3f` but without the leading dot. [^7] |
+| `%6f` | `026490` | Similar to `%.6f` but without the leading dot. [^7] |
+| `%9f` | `026490000` | Similar to `%.9f` but without the leading dot. [^7] |
| | | |
| `%R` | `00:34` | Hour-minute format. Same as `%H:%M`. |
| `%T` | `00:34:60` | Hour-minute-second format. Same as `%H:%M:%S`. |
@@ -68,16 +68,18 @@ 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. [^9] |
+| `%Z` | `ACST` | Local time zone name. Skips all non-whitespace characters during parsing. [^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. |
+|`%:::z`| `+09` | Offset from the local time to UTC without minutes. |
| `%#z` | `+09` | *Parsing only:* Same as `%z` but allows minutes to be missing or present. |
| | | |
| | | **DATE & TIME SPECIFIERS:** |
|`%c`|`Sun Jul 8 00:34:60 2001`|Locale's date and time (e.g., Thu Mar 3 23:05:25 2005). |
-| `%+` | `2001-07-08T00:34:60.026490+09:30` | ISO 8601 / RFC 3339 date & time format. [^6] |
+| `%+` | `2001-07-08T00:34:60.026490+09:30` | ISO 8601 / RFC 3339 date & time format. [^5] |
| | | |
-| `%s` | `994518299` | UNIX timestamp, the number of seconds since 1970-01-01 00:00 UTC. [^7]|
+| `%s` | `994518299` | UNIX timestamp, the number of seconds since 1970-01-01 00:00 UTC. [^6]|
| | | |
| | | **SPECIAL SPECIFIERS:** |
| `%t` | | Literal tab (`\t`). |
@@ -95,38 +97,42 @@ Modifier | Description
Notes:
-[^1]: `%Y`:
- Negative years are allowed in formatting but not in parsing.
-
-[^2]: `%C`, `%y`:
+[^1]: `%C`, `%y`:
This is floor division, so 100 BCE (year number -99) will print `-1` and `99` respectively.
-[^3]: `%U`:
+[^2]: `%U`:
Week 1 starts with the first Sunday in that year.
It is possible to have week 0 for days before the first Sunday.
-[^4]: `%G`, `%g`, `%V`:
+[^3]: `%G`, `%g`, `%V`:
Week 1 is the first week with at least 4 days in that year.
Week 0 does not exist, so this should be used with `%G` or `%g`.
-[^5]: `%S`:
+[^4]: `%S`:
It accounts for leap seconds, so `60` is possible.
-[^6]: `%+`: Same as `%Y-%m-%dT%H:%M:%S%.f%:z`, i.e. 0, 3, 6 or 9 fractional
+[^5]: `%+`: Same as `%Y-%m-%dT%H:%M:%S%.f%:z`, i.e. 0, 3, 6 or 9 fractional
digits for seconds and colons in the time zone offset.
<br>
<br>
+ This format also supports having a `Z` or `UTC` in place of `%:z`. They
+ are equivalent to `+00:00`.
+ <br>
+ <br>
+ Note that all `T`, `Z`, and `UTC` are parsed case-insensitively.
+ <br>
+ <br>
The typical `strftime` implementations have different (and locale-dependent)
formats for this specifier. While Chrono's format for `%+` is far more
stable, it is best to avoid this specifier if you want to control the exact
output.
-[^7]: `%s`:
+[^6]: `%s`:
This is not padded and can be negative.
For the purpose of Chrono, it only accounts for non-leap seconds
so it slightly differs from ISO C `strftime` behavior.
-[^8]: `%f`, `%.f`, `%.3f`, `%.6f`, `%.9f`, `%3f`, `%6f`, `%9f`:
+[^7]: `%f`, `%.f`, `%.3f`, `%.6f`, `%.9f`, `%3f`, `%6f`, `%9f`:
<br>
The default `%f` is right-aligned and always zero-padded to 9 digits
for the compatibility with glibc and others,
@@ -157,7 +163,7 @@ Notes:
and parsing `07`, `070000` etc. will yield the same.
Note that they can read nothing if the fractional part is zero.
-[^9]: `%Z`:
+[^8]: `%Z`:
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.
@@ -169,6 +175,12 @@ Notes:
*/
#[cfg(feature = "unstable-locales")]
+extern crate alloc;
+
+#[cfg(feature = "unstable-locales")]
+use alloc::vec::Vec;
+
+#[cfg(feature = "unstable-locales")]
use super::{locales, Locale};
use super::{Fixed, InternalFixed, InternalInternal, Item, Numeric, Pad};
@@ -177,9 +189,9 @@ type Fmt<'a> = Vec<Item<'a>>;
#[cfg(not(feature = "unstable-locales"))]
type Fmt<'a> = &'static [Item<'static>];
-static D_FMT: &'static [Item<'static>] =
+static D_FMT: &[Item<'static>] =
&[num0!(Month), lit!("/"), num0!(Day), lit!("/"), num0!(YearMod100)];
-static D_T_FMT: &'static [Item<'static>] = &[
+static D_T_FMT: &[Item<'static>] = &[
fix!(ShortWeekdayName),
sp!(" "),
fix!(ShortMonthName),
@@ -194,8 +206,7 @@ static D_T_FMT: &'static [Item<'static>] = &[
sp!(" "),
num0!(Year),
];
-static T_FMT: &'static [Item<'static>] =
- &[num0!(Hour), lit!(":"), num0!(Minute), lit!(":"), num0!(Second)];
+static T_FMT: &[Item<'static>] = &[num0!(Hour), lit!(":"), num0!(Minute), lit!(":"), num0!(Second)];
/// Parsing iterator for `strftime`-like format strings.
#[derive(Clone, Debug)]
@@ -222,23 +233,18 @@ 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")))]
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();
let t_fmt = StrftimeItems::new(locales::t_fmt(locale)).collect();
- StrftimeItems {
- remainder: s,
- recons: Vec::new(),
- d_fmt: d_fmt,
- d_t_fmt: d_t_fmt,
- t_fmt: t_fmt,
- }
+ StrftimeItems { remainder: s, recons: Vec::new(), d_fmt, d_t_fmt, t_fmt }
}
#[cfg(not(feature = "unstable-locales"))]
fn with_remainer(s: &'a str) -> StrftimeItems<'a> {
- static FMT_NONE: &'static [Item<'static>; 0] = &[];
+ static FMT_NONE: &[Item<'static>; 0] = &[];
StrftimeItems {
remainder: s,
@@ -261,7 +267,7 @@ impl<'a> StrftimeItems<'a> {
}
}
-const HAVE_ALTERNATES: &'static str = "z";
+const HAVE_ALTERNATES: &str = "z";
impl<'a> Iterator for StrftimeItems<'a> {
type Item = Item<'a>;
@@ -407,10 +413,20 @@ impl<'a> Iterator for StrftimeItems<'a> {
}
}
'+' => fix!(RFC3339),
- ':' => match next!() {
- 'z' => fix!(TimezoneOffsetColon),
- _ => Item::Error,
- },
+ ':' => {
+ if self.remainder.starts_with("::z") {
+ self.remainder = &self.remainder[3..];
+ fix!(TimezoneOffsetTripleColon)
+ } else if self.remainder.starts_with(":z") {
+ self.remainder = &self.remainder[2..];
+ fix!(TimezoneOffsetDoubleColon)
+ } else if self.remainder.starts_with('z') {
+ self.remainder = &self.remainder[1..];
+ fix!(TimezoneOffsetColon)
+ } else {
+ Item::Error
+ }
+ }
'.' => match next!() {
'3' => match next!() {
'f' => fix!(Nanosecond3),
@@ -462,7 +478,7 @@ impl<'a> Iterator for StrftimeItems<'a> {
let nextspec = self
.remainder
.find(|c: char| !c.is_whitespace())
- .unwrap_or_else(|| self.remainder.len());
+ .unwrap_or(self.remainder.len());
assert!(nextspec > 0);
let item = sp!(&self.remainder[..nextspec]);
self.remainder = &self.remainder[nextspec..];
@@ -474,7 +490,7 @@ impl<'a> Iterator for StrftimeItems<'a> {
let nextspec = self
.remainder
.find(|c: char| c.is_whitespace() || c == '%')
- .unwrap_or_else(|| self.remainder.len());
+ .unwrap_or(self.remainder.len());
assert!(nextspec > 0);
let item = lit!(&self.remainder[..nextspec]);
self.remainder = &self.remainder[nextspec..];
@@ -487,11 +503,11 @@ impl<'a> Iterator for StrftimeItems<'a> {
#[cfg(test)]
#[test]
fn test_strftime_items() {
- fn parse_and_collect<'a>(s: &'a str) -> Vec<Item<'a>> {
+ fn parse_and_collect(s: &str) -> Vec<Item<'_>> {
// map any error into `[Item::Error]`. useful for easy testing.
let items = StrftimeItems::new(s);
let items = items.map(|spec| if spec == Item::Error { None } else { Some(spec) });
- items.collect::<Option<Vec<_>>>().unwrap_or(vec![Item::Error])
+ items.collect::<Option<Vec<_>>>().unwrap_or_else(|| vec![Item::Error])
}
assert_eq!(parse_and_collect(""), []);
@@ -540,9 +556,18 @@ fn test_strftime_items() {
#[cfg(test)]
#[test]
fn test_strftime_docs() {
- use {FixedOffset, TimeZone, Timelike};
-
- let dt = FixedOffset::east(34200).ymd(2001, 7, 8).and_hms_nano(0, 34, 59, 1_026_490_708);
+ use crate::NaiveDate;
+ use crate::{DateTime, FixedOffset, TimeZone, Timelike, Utc};
+
+ let dt = FixedOffset::east_opt(34200)
+ .unwrap()
+ .from_local_datetime(
+ &NaiveDate::from_ymd_opt(2001, 7, 8)
+ .unwrap()
+ .and_hms_nano_opt(0, 34, 59, 1_026_490_708)
+ .unwrap(),
+ )
+ .unwrap();
// date specifiers
assert_eq!(dt.format("%Y").to_string(), "2001");
@@ -559,7 +584,7 @@ fn test_strftime_docs() {
assert_eq!(dt.format("%A").to_string(), "Sunday");
assert_eq!(dt.format("%w").to_string(), "0");
assert_eq!(dt.format("%u").to_string(), "7");
- assert_eq!(dt.format("%U").to_string(), "28");
+ assert_eq!(dt.format("%U").to_string(), "27");
assert_eq!(dt.format("%W").to_string(), "27");
assert_eq!(dt.format("%G").to_string(), "2001");
assert_eq!(dt.format("%g").to_string(), "01");
@@ -599,10 +624,30 @@ fn test_strftime_docs() {
//assert_eq!(dt.format("%Z").to_string(), "ACST");
assert_eq!(dt.format("%z").to_string(), "+0930");
assert_eq!(dt.format("%:z").to_string(), "+09:30");
+ assert_eq!(dt.format("%::z").to_string(), "+09:30:00");
+ assert_eq!(dt.format("%:::z").to_string(), "+09");
// date & time specifiers
assert_eq!(dt.format("%c").to_string(), "Sun Jul 8 00:34:60 2001");
assert_eq!(dt.format("%+").to_string(), "2001-07-08T00:34:60.026490708+09:30");
+
+ assert_eq!(
+ dt.with_timezone(&Utc).format("%+").to_string(),
+ "2001-07-07T15:04:60.026490708+00:00"
+ );
+ assert_eq!(
+ dt.with_timezone(&Utc),
+ DateTime::parse_from_str("2001-07-07T15:04:60.026490708Z", "%+").unwrap()
+ );
+ assert_eq!(
+ dt.with_timezone(&Utc),
+ DateTime::parse_from_str("2001-07-07T15:04:60.026490708UTC", "%+").unwrap()
+ );
+ assert_eq!(
+ dt.with_timezone(&Utc),
+ DateTime::parse_from_str("2001-07-07t15:04:60.026490708utc", "%+").unwrap()
+ );
+
assert_eq!(
dt.with_nanosecond(1_026_490_000).unwrap().format("%+").to_string(),
"2001-07-08T00:34:60.026490+09:30"
@@ -618,9 +663,14 @@ fn test_strftime_docs() {
#[cfg(feature = "unstable-locales")]
#[test]
fn test_strftime_docs_localized() {
- use {FixedOffset, TimeZone};
+ use crate::{FixedOffset, NaiveDate, TimeZone};
- let dt = FixedOffset::east(34200).ymd(2001, 7, 8).and_hms_nano(0, 34, 59, 1_026_490_708);
+ let dt = FixedOffset::east_opt(34200).unwrap().ymd_opt(2001, 7, 8).unwrap().and_hms_nano(
+ 0,
+ 34,
+ 59,
+ 1_026_490_708,
+ );
// date specifiers
assert_eq!(dt.format_localized("%b", Locale::fr_BE).to_string(), "jui");
@@ -646,4 +696,17 @@ fn test_strftime_docs_localized() {
dt.format_localized("%c", Locale::fr_BE).to_string(),
"dim 08 jui 2001 00:34:60 +09:30"
);
+
+ let nd = NaiveDate::from_ymd_opt(2001, 7, 8).unwrap();
+
+ // date specifiers
+ assert_eq!(nd.format_localized("%b", Locale::de_DE).to_string(), "Jul");
+ assert_eq!(nd.format_localized("%B", Locale::de_DE).to_string(), "Juli");
+ assert_eq!(nd.format_localized("%h", Locale::de_DE).to_string(), "Jul");
+ assert_eq!(nd.format_localized("%a", Locale::de_DE).to_string(), "So");
+ assert_eq!(nd.format_localized("%A", Locale::de_DE).to_string(), "Sonntag");
+ assert_eq!(nd.format_localized("%D", Locale::de_DE).to_string(), "07/08/01");
+ assert_eq!(nd.format_localized("%x", Locale::de_DE).to_string(), "08.07.2001");
+ assert_eq!(nd.format_localized("%F", Locale::de_DE).to_string(), "2001-07-08");
+ assert_eq!(nd.format_localized("%v", Locale::de_DE).to_string(), " 8-Jul-2001");
}
diff --git a/vendor/chrono/src/lib.rs b/vendor/chrono/src/lib.rs
index 9d66ae324..861ee1059 100644
--- a/vendor/chrono/src/lib.rs
+++ b/vendor/chrono/src/lib.rs
@@ -1,6 +1,3 @@
-// This is a part of Chrono.
-// See README.md and LICENSE.txt for details.
-
//! # Chrono: Date and Time for Rust
//!
//! It aims to be a feature-complete superset of
@@ -19,18 +16,6 @@
//! * Dietrich Epp's [datetime-rs](https://github.com/depp/datetime-rs)
//! * Luis de Bethencourt's [rust-datetime](https://github.com/luisbg/rust-datetime)
//!
-//! Any significant changes to Chrono are documented in
-//! the [`CHANGELOG.md`](https://github.com/chronotope/chrono/blob/main/CHANGELOG.md) file.
-//!
-//! ## Usage
-//!
-//! Put this in your `Cargo.toml`:
-//!
-//! ```toml
-//! [dependencies]
-//! chrono = "0.4"
-//! ```
-//!
//! ### Features
//!
//! Chrono supports various runtime environments and operating systems, and has
@@ -42,12 +27,11 @@
//! - `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`), independent of whether
-//! `std::time::SystemTime` is present, depends on having a libc.
+//! - `clock`: Enables reading the system time (`now`) that depends on the standard library for
+//! UNIX-like operating systems and the Windows API (`winapi`) for Windows.
//!
//! Optional features:
//!
-//! - `wasmbind`: Enable integration with [wasm-bindgen][] and its `js-sys` project
//! - [`serde`][]: Enable serialization/deserialization via serde.
//! - `unstable-locales`: Enable localization. This adds various methods with a
//! `_localized` suffix. The implementation and API may change or even be
@@ -142,26 +126,26 @@
//! use chrono::prelude::*;
//! use chrono::offset::LocalResult;
//!
-//! let dt = Utc.ymd(2014, 7, 8).and_hms(9, 10, 11); // `2014-07-08T09:10:11Z`
+//! let dt = Utc.with_ymd_and_hms(2014, 7, 8, 9, 10, 11).unwrap(); // `2014-07-08T09:10:11Z`
//! // July 8 is 188th day of the year 2014 (`o` for "ordinal")
-//! assert_eq!(dt, Utc.yo(2014, 189).and_hms(9, 10, 11));
+//! assert_eq!(dt, Utc.yo(2014, 189).and_hms_opt(9, 10, 11).unwrap());
//! // July 8 is Tuesday in ISO week 28 of the year 2014.
-//! assert_eq!(dt, Utc.isoywd(2014, 28, Weekday::Tue).and_hms(9, 10, 11));
+//! assert_eq!(dt, Utc.isoywd(2014, 28, Weekday::Tue).and_hms_opt(9, 10, 11).unwrap());
//!
-//! let dt = Utc.ymd(2014, 7, 8).and_hms_milli(9, 10, 11, 12); // `2014-07-08T09:10:11.012Z`
-//! assert_eq!(dt, Utc.ymd(2014, 7, 8).and_hms_micro(9, 10, 11, 12_000));
-//! assert_eq!(dt, Utc.ymd(2014, 7, 8).and_hms_nano(9, 10, 11, 12_000_000));
+//! 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());
//!
//! // dynamic verification
//! assert_eq!(Utc.ymd_opt(2014, 7, 8).and_hms_opt(21, 15, 33),
-//! LocalResult::Single(Utc.ymd(2014, 7, 8).and_hms(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);
//!
//! // 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.
-//! let local_dt = Local.ymd(2014, 7, 8).and_hms_milli(9, 10, 11, 12);
-//! let fixed_dt = FixedOffset::east(9 * 3600).ymd(2014, 7, 8).and_hms_milli(18, 10, 11, 12);
+//! let local_dt = Local.from_local_datetime(&NaiveDate::from_ymd_opt(2014, 7, 8).unwrap().and_hms_milli_opt(9, 10, 11, 12).unwrap()).unwrap();
+//! 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;
//! ```
@@ -173,14 +157,11 @@
//! The following illustrates most supported operations to the date and time:
//!
//! ```rust
-//! # extern crate chrono;
-//!
-//! # fn main() {
//! use chrono::prelude::*;
//! use chrono::Duration;
//!
//! // assume this returned `2014-11-28T21:45:59.324310806+09:00`:
-//! let dt = FixedOffset::east(9*3600).ymd(2014, 11, 28).and_hms_nano(21, 45, 59, 324310806);
+//! let dt = FixedOffset::east_opt(9*3600).unwrap().from_local_datetime(&NaiveDate::from_ymd_opt(2014, 11, 28).unwrap().and_hms_nano_opt(21, 45, 59, 324310806).unwrap()).unwrap();
//!
//! // property accessors
//! assert_eq!((dt.year(), dt.month(), dt.day()), (2014, 11, 28));
@@ -193,8 +174,8 @@
//!
//! // time zone accessor and manipulation
//! assert_eq!(dt.offset().fix().local_minus_utc(), 9 * 3600);
-//! assert_eq!(dt.timezone(), FixedOffset::east(9 * 3600));
-//! assert_eq!(dt.with_timezone(&Utc), Utc.ymd(2014, 11, 28).and_hms_nano(12, 45, 59, 324310806));
+//! assert_eq!(dt.timezone(), FixedOffset::east_opt(9 * 3600).unwrap());
+//! assert_eq!(dt.with_timezone(&Utc), NaiveDate::from_ymd_opt(2014, 11, 28).unwrap().and_hms_nano_opt(12, 45, 59, 324310806).unwrap().and_local_timezone(Utc).unwrap());
//!
//! // a sample of property manipulations (validates dynamically)
//! assert_eq!(dt.with_day(29).unwrap().weekday(), Weekday::Sat); // 2014-11-29 is Saturday
@@ -202,15 +183,14 @@
//! assert_eq!(dt.with_year(-300).unwrap().num_days_from_ce(), -109606); // November 29, 301 BCE
//!
//! // arithmetic operations
-//! let dt1 = Utc.ymd(2014, 11, 14).and_hms(8, 9, 10);
-//! let dt2 = Utc.ymd(2014, 11, 14).and_hms(10, 9, 8);
+//! let dt1 = Utc.with_ymd_and_hms(2014, 11, 14, 8, 9, 10).unwrap();
+//! let dt2 = Utc.with_ymd_and_hms(2014, 11, 14, 10, 9, 8).unwrap();
//! assert_eq!(dt1.signed_duration_since(dt2), Duration::seconds(-2 * 3600 + 2));
//! assert_eq!(dt2.signed_duration_since(dt1), Duration::seconds(2 * 3600 - 2));
-//! assert_eq!(Utc.ymd(1970, 1, 1).and_hms(0, 0, 0) + Duration::seconds(1_000_000_000),
-//! Utc.ymd(2001, 9, 9).and_hms(1, 46, 40));
-//! assert_eq!(Utc.ymd(1970, 1, 1).and_hms(0, 0, 0) - Duration::seconds(1_000_000_000),
-//! Utc.ymd(1938, 4, 24).and_hms(22, 13, 20));
-//! # }
+//! assert_eq!(Utc.with_ymd_and_hms(1970, 1, 1, 0, 0, 0).unwrap() + Duration::seconds(1_000_000_000),
+//! Utc.with_ymd_and_hms(2001, 9, 9, 1, 46, 40).unwrap());
+//! assert_eq!(Utc.with_ymd_and_hms(1970, 1, 1, 0, 0, 0).unwrap() - Duration::seconds(1_000_000_000),
+//! Utc.with_ymd_and_hms(1938, 4, 24, 22, 13, 20).unwrap());
//! ```
//!
//! ### Formatting and Parsing
@@ -230,8 +210,8 @@
//! help of an additional C library. This functionality is under the feature
//! `unstable-locales`:
//!
-//! ```text
-//! chrono { version = "0.4", features = ["unstable-locales"]
+//! ```toml
+//! chrono = { version = "0.4", features = ["unstable-locales"] }
//! ```
//!
//! The `unstable-locales` feature requires and implies at least the `alloc` feature.
@@ -239,20 +219,28 @@
//! ```rust
//! use chrono::prelude::*;
//!
-//! let dt = Utc.ymd(2014, 11, 28).and_hms(12, 0, 9);
+//! # #[cfg(feature = "unstable-locales")]
+//! # fn test() {
+//! let dt = Utc.with_ymd_and_hms(2014, 11, 28, 12, 0, 9).unwrap();
//! assert_eq!(dt.format("%Y-%m-%d %H:%M:%S").to_string(), "2014-11-28 12:00:09");
//! assert_eq!(dt.format("%a %b %e %T %Y").to_string(), "Fri Nov 28 12:00:09 2014");
//! assert_eq!(dt.format_localized("%A %e %B %Y, %T", Locale::fr_BE).to_string(), "vendredi 28 novembre 2014, 12:00:09");
-//! assert_eq!(dt.format("%a %b %e %T %Y").to_string(), dt.format("%c").to_string());
//!
+//! assert_eq!(dt.format("%a %b %e %T %Y").to_string(), dt.format("%c").to_string());
//! assert_eq!(dt.to_string(), "2014-11-28 12:00:09 UTC");
//! assert_eq!(dt.to_rfc2822(), "Fri, 28 Nov 2014 12:00:09 +0000");
//! assert_eq!(dt.to_rfc3339(), "2014-11-28T12:00:09+00:00");
//! assert_eq!(format!("{:?}", dt), "2014-11-28T12:00:09Z");
//!
//! // Note that milli/nanoseconds are only printed if they are non-zero
-//! let dt_nano = Utc.ymd(2014, 11, 28).and_hms_nano(12, 0, 9, 1);
+//! let dt_nano = NaiveDate::from_ymd_opt(2014, 11, 28).unwrap().and_hms_nano_opt(12, 0, 9, 1).unwrap().and_local_timezone(Utc).unwrap();
//! assert_eq!(format!("{:?}", dt_nano), "2014-11-28T12:00:09.000000001Z");
+//! # }
+//! # #[cfg(not(feature = "unstable-locales"))]
+//! # fn test() {}
+//! # if cfg!(feature = "unstable-locales") {
+//! # test();
+//! # }
//! ```
//!
//! Parsing can be done with three methods:
@@ -285,8 +273,8 @@
//! ```rust
//! use chrono::prelude::*;
//!
-//! let dt = Utc.ymd(2014, 11, 28).and_hms(12, 0, 9);
-//! let fixed_dt = dt.with_timezone(&FixedOffset::east(9*3600));
+//! let dt = Utc.with_ymd_and_hms(2014, 11, 28, 12, 0, 9).unwrap();
+//! let fixed_dt = dt.with_timezone(&FixedOffset::east_opt(9*3600).unwrap());
//!
//! // method 1
//! assert_eq!("2014-11-28T12:00:09Z".parse::<DateTime<Utc>>(), Ok(dt.clone()));
@@ -353,9 +341,9 @@
//! assert_eq!(Utc::today(), Utc::now().date());
//! assert_eq!(Local::today(), Local::now().date());
//!
-//! assert_eq!(Utc.ymd(2014, 11, 28).weekday(), Weekday::Fri);
+//! assert_eq!(Utc.ymd_opt(2014, 11, 28).unwrap().weekday(), Weekday::Fri);
//! assert_eq!(Utc.ymd_opt(2014, 11, 31), LocalResult::None);
-//! assert_eq!(Utc.ymd(2014, 11, 28).and_hms_milli(7, 8, 9, 10).format("%H%M%S").to_string(),
+//! 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");
//! ```
//!
@@ -401,7 +389,7 @@
//! 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(2014, 1, 30).with_month(2)` returns `None`.
+//! and consequently `Utc.ymd_opt(2014, 1, 30).unwrap().with_month(2)` returns `None`.
//!
//! Non ISO week handling is not yet supported.
//! For now you can use the [chrono_ext](https://crates.io/crates/chrono_ext)
@@ -414,1122 +402,126 @@
#![cfg_attr(feature = "bench", feature(test))] // lib stability features as per RFC #507
#![deny(missing_docs)]
#![deny(missing_debug_implementations)]
+#![warn(unreachable_pub)]
#![deny(dead_code)]
-// lints are added all the time, we test on 1.13
-#![allow(unknown_lints)]
#![cfg_attr(not(any(feature = "std", test)), no_std)]
-#![cfg_attr(feature = "cargo-clippy", allow(
- renamed_and_removed_lints,
- // The explicit 'static lifetimes are still needed for rustc 1.13-16
- // backward compatibility, and this appeases clippy. If minimum rustc
- // becomes 1.17, should be able to remove this, those 'static lifetimes,
- // and use `static` in a lot of places `const` is used now.
- redundant_static_lifetimes,
- // Similarly, redundant_field_names lints on not using the
- // field-init-shorthand, which was stabilized in rust 1.17.
- redundant_field_names,
- // Changing trivially_copy_pass_by_ref would require an incompatible version
- // bump.
- trivially_copy_pass_by_ref,
- try_err,
- // Currently deprecated, we use the separate implementation to add docs
- // warning that putting a time in a hash table is probably a bad idea
- derive_hash_xor_eq,
-))]
-
-#[cfg(feature = "alloc")]
-extern crate alloc;
-#[cfg(all(feature = "std", not(feature = "alloc")))]
-extern crate std as alloc;
-#[cfg(any(feature = "std", test))]
-extern crate std as core;
+// can remove this if/when rustc-serialize support is removed
+// keeps clippy happy in the meantime
+#![cfg_attr(feature = "rustc-serialize", allow(deprecated))]
+#![cfg_attr(docsrs, feature(doc_cfg))]
#[cfg(feature = "oldtime")]
+#[cfg_attr(docsrs, doc(cfg(feature = "oldtime")))]
extern crate time as oldtime;
#[cfg(not(feature = "oldtime"))]
mod oldtime;
+// this reexport is to aid the transition and should not be in the prelude!
+pub use oldtime::{Duration, OutOfRangeError};
-#[cfg(feature = "clock")]
-extern crate libc;
-#[cfg(all(feature = "clock", windows))]
-extern crate winapi;
-#[cfg(all(
- feature = "clock",
- not(all(target_arch = "wasm32", not(target_os = "wasi"), feature = "wasmbind"))
-))]
-mod sys;
-
-extern crate num_integer;
-extern crate num_traits;
-#[cfg(feature = "rustc-serialize")]
-extern crate rustc_serialize;
-#[cfg(feature = "serde")]
-extern crate serde as serdelib;
#[cfg(feature = "__doctest")]
#[cfg_attr(feature = "__doctest", cfg(doctest))]
-#[macro_use]
-extern crate doc_comment;
-#[cfg(all(target_arch = "wasm32", not(target_os = "wasi"), feature = "wasmbind"))]
-extern crate js_sys;
-#[cfg(feature = "unstable-locales")]
-extern crate pure_rust_locales;
-#[cfg(feature = "bench")]
-extern crate test;
-#[cfg(all(target_arch = "wasm32", not(target_os = "wasi"), feature = "wasmbind"))]
-extern crate wasm_bindgen;
+use doc_comment::doctest;
#[cfg(feature = "__doctest")]
#[cfg_attr(feature = "__doctest", cfg(doctest))]
doctest!("../README.md");
-// this reexport is to aid the transition and should not be in the prelude!
-pub use oldtime::Duration;
-
-pub use date::{Date, MAX_DATE, MIN_DATE};
-#[cfg(feature = "rustc-serialize")]
-pub use datetime::rustc_serialize::TsSeconds;
-pub use datetime::{DateTime, SecondsFormat, MAX_DATETIME, MIN_DATETIME};
-/// L10n locales.
-#[cfg(feature = "unstable-locales")]
-pub use format::Locale;
-pub use format::{ParseError, ParseResult};
-#[doc(no_inline)]
-pub use naive::{IsoWeek, NaiveDate, NaiveDateTime, NaiveTime};
-#[cfg(feature = "clock")]
-#[doc(no_inline)]
-pub use offset::Local;
-#[doc(no_inline)]
-pub use offset::{FixedOffset, LocalResult, Offset, TimeZone, Utc};
-pub use round::{DurationRound, RoundingError, SubsecRound};
-
/// A convenience module appropriate for glob imports (`use chrono::prelude::*;`).
pub mod prelude {
#[doc(no_inline)]
- pub use Date;
+ #[allow(deprecated)]
+ pub use crate::Date;
#[cfg(feature = "clock")]
+ #[cfg_attr(docsrs, doc(cfg(feature = "clock")))]
#[doc(no_inline)]
- pub use Local;
+ pub use crate::Local;
#[cfg(feature = "unstable-locales")]
+ #[cfg_attr(docsrs, doc(cfg(feature = "unstable-locales")))]
#[doc(no_inline)]
- pub use Locale;
+ pub use crate::Locale;
#[doc(no_inline)]
- pub use SubsecRound;
+ pub use crate::SubsecRound;
#[doc(no_inline)]
- pub use {DateTime, SecondsFormat};
+ pub use crate::{DateTime, SecondsFormat};
#[doc(no_inline)]
- pub use {Datelike, Month, Timelike, Weekday};
+ pub use crate::{Datelike, Month, Timelike, Weekday};
#[doc(no_inline)]
- pub use {FixedOffset, Utc};
+ pub use crate::{FixedOffset, Utc};
#[doc(no_inline)]
- pub use {NaiveDate, NaiveDateTime, NaiveTime};
+ pub use crate::{NaiveDate, NaiveDateTime, NaiveTime};
#[doc(no_inline)]
- pub use {Offset, TimeZone};
+ pub use crate::{Offset, TimeZone};
}
-// useful throughout the codebase
-macro_rules! try_opt {
- ($e:expr) => {
- match $e {
- Some(v) => v,
- None => return None,
- }
- };
-}
+mod date;
+#[allow(deprecated)]
+pub use date::{Date, MAX_DATE, MIN_DATE};
-mod div;
-pub mod offset;
-pub mod naive {
- //! Date and time types unconcerned with timezones.
- //!
- //! They are primarily building blocks for other types
- //! (e.g. [`TimeZone`](../offset/trait.TimeZone.html)),
- //! but can be also used for the simpler date and time handling.
+mod datetime;
+#[cfg(feature = "rustc-serialize")]
+#[cfg_attr(docsrs, doc(cfg(feature = "rustc-serialize")))]
+pub use datetime::rustc_serialize::TsSeconds;
+#[allow(deprecated)]
+pub use datetime::{DateTime, SecondsFormat, MAX_DATETIME, MIN_DATETIME};
- mod date;
- mod datetime;
- mod internals;
- mod isoweek;
- mod time;
+pub mod format;
+/// L10n locales.
+#[cfg(feature = "unstable-locales")]
+#[cfg_attr(docsrs, doc(cfg(feature = "unstable-locales")))]
+pub use format::Locale;
+pub use format::{ParseError, ParseResult};
- pub use self::date::{NaiveDate, MAX_DATE, MIN_DATE};
- #[cfg(feature = "rustc-serialize")]
- #[allow(deprecated)]
- pub use self::datetime::rustc_serialize::TsSeconds;
- pub use self::datetime::{NaiveDateTime, MAX_DATETIME, MIN_DATETIME};
- pub use self::isoweek::IsoWeek;
- pub use self::time::NaiveTime;
+pub mod naive;
+#[doc(no_inline)]
+pub use naive::{Days, IsoWeek, NaiveDate, NaiveDateTime, NaiveTime, NaiveWeek};
- #[cfg(feature = "__internal_bench")]
- #[doc(hidden)]
- pub use self::internals::YearFlags as __BenchYearFlags;
+pub mod offset;
+#[cfg(feature = "clock")]
+#[cfg_attr(docsrs, doc(cfg(feature = "clock")))]
+#[doc(no_inline)]
+pub use offset::Local;
+#[doc(no_inline)]
+pub use offset::{FixedOffset, LocalResult, Offset, TimeZone, Utc};
- /// Serialization/Deserialization of naive types in alternate formats
- ///
- /// The various modules in here are intended to be used with serde's [`with`
- /// annotation][1] to serialize as something other than the default [RFC
- /// 3339][2] format.
- ///
- /// [1]: https://serde.rs/attributes.html#field-attributes
- /// [2]: https://tools.ietf.org/html/rfc3339
- #[cfg(feature = "serde")]
- pub mod serde {
- pub use super::datetime::serde::*;
- }
-}
-mod date;
-mod datetime;
-pub mod format;
mod round;
+pub use round::{DurationRound, RoundingError, SubsecRound};
+
+mod weekday;
+pub use weekday::{ParseWeekdayError, Weekday};
+
+mod month;
+pub use month::{Month, Months, ParseMonthError};
+
+mod traits;
+pub use traits::{Datelike, Timelike};
#[cfg(feature = "__internal_bench")]
#[doc(hidden)]
pub use naive::__BenchYearFlags;
-/// Serialization/Deserialization in alternate formats
+/// 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].
///
-/// The various modules in here are intended to be used with serde's [`with`
-/// annotation][1] to serialize as something other than the default [RFC
-/// 3339][2] format.
+/// *Available on crate feature 'serde' only.*
///
-/// [1]: https://serde.rs/attributes.html#field-attributes
-/// [2]: https://tools.ietf.org/html/rfc3339
+/// [1]: https://tools.ietf.org/html/rfc3339
+/// [2]: https://serde.rs/attributes.html#field-attributes
#[cfg(feature = "serde")]
+#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
pub mod serde {
pub use super::datetime::serde::*;
}
-// Until rust 1.18 there is no "pub(crate)" so to share this we need it in the root
-
-#[cfg(feature = "serde")]
-enum SerdeError<V: fmt::Display, D: fmt::Display> {
- NonExistent { timestamp: V },
- Ambiguous { timestamp: V, min: D, max: D },
-}
-
-/// Construct a [`SerdeError::NonExistent`]
-#[cfg(feature = "serde")]
-fn ne_timestamp<T: fmt::Display>(ts: T) -> SerdeError<T, u8> {
- SerdeError::NonExistent::<T, u8> { timestamp: ts }
-}
-
-#[cfg(feature = "serde")]
-impl<V: fmt::Display, D: fmt::Display> fmt::Debug for SerdeError<V, D> {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "ChronoSerdeError({})", self)
- }
-}
-
-// impl<V: fmt::Display, D: fmt::Debug> core::error::Error for SerdeError<V, D> {}
-#[cfg(feature = "serde")]
-impl<V: fmt::Display, D: fmt::Display> fmt::Display for SerdeError<V, D> {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- match self {
- &SerdeError::NonExistent { ref timestamp } => {
- write!(f, "value is not a legal timestamp: {}", timestamp)
- }
- &SerdeError::Ambiguous { ref timestamp, ref min, ref max } => write!(
- f,
- "value is an ambiguous timestamp: {}, could be either of {}, {}",
- timestamp, min, max
- ),
- }
- }
-}
-
-/// 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.
-#[derive(PartialEq, Eq, Copy, Clone, Debug, Hash)]
-#[cfg_attr(feature = "rustc-serialize", derive(RustcEncodable, RustcDecodable))]
-pub enum Weekday {
- /// Monday.
- Mon = 0,
- /// Tuesday.
- Tue = 1,
- /// Wednesday.
- Wed = 2,
- /// Thursday.
- Thu = 3,
- /// Friday.
- Fri = 4,
- /// Saturday.
- Sat = 5,
- /// Sunday.
- Sun = 6,
-}
-
-impl Weekday {
- /// The next day in the week.
- ///
- /// `w`: | `Mon` | `Tue` | `Wed` | `Thu` | `Fri` | `Sat` | `Sun`
- /// ----------- | ----- | ----- | ----- | ----- | ----- | ----- | -----
- /// `w.succ()`: | `Tue` | `Wed` | `Thu` | `Fri` | `Sat` | `Sun` | `Mon`
- #[inline]
- pub fn succ(&self) -> Weekday {
- match *self {
- Weekday::Mon => Weekday::Tue,
- Weekday::Tue => Weekday::Wed,
- Weekday::Wed => Weekday::Thu,
- Weekday::Thu => Weekday::Fri,
- Weekday::Fri => Weekday::Sat,
- Weekday::Sat => Weekday::Sun,
- Weekday::Sun => Weekday::Mon,
- }
- }
-
- /// The previous day in the week.
- ///
- /// `w`: | `Mon` | `Tue` | `Wed` | `Thu` | `Fri` | `Sat` | `Sun`
- /// ----------- | ----- | ----- | ----- | ----- | ----- | ----- | -----
- /// `w.pred()`: | `Sun` | `Mon` | `Tue` | `Wed` | `Thu` | `Fri` | `Sat`
- #[inline]
- pub fn pred(&self) -> Weekday {
- match *self {
- Weekday::Mon => Weekday::Sun,
- Weekday::Tue => Weekday::Mon,
- Weekday::Wed => Weekday::Tue,
- Weekday::Thu => Weekday::Wed,
- Weekday::Fri => Weekday::Thu,
- Weekday::Sat => Weekday::Fri,
- Weekday::Sun => Weekday::Sat,
- }
- }
-
- /// Returns a day-of-week number starting from Monday = 1. (ISO 8601 weekday number)
- ///
- /// `w`: | `Mon` | `Tue` | `Wed` | `Thu` | `Fri` | `Sat` | `Sun`
- /// ------------------------- | ----- | ----- | ----- | ----- | ----- | ----- | -----
- /// `w.number_from_monday()`: | 1 | 2 | 3 | 4 | 5 | 6 | 7
- #[inline]
- pub fn number_from_monday(&self) -> u32 {
- match *self {
- Weekday::Mon => 1,
- Weekday::Tue => 2,
- Weekday::Wed => 3,
- Weekday::Thu => 4,
- Weekday::Fri => 5,
- Weekday::Sat => 6,
- Weekday::Sun => 7,
- }
- }
-
- /// Returns a day-of-week number starting from Sunday = 1.
- ///
- /// `w`: | `Mon` | `Tue` | `Wed` | `Thu` | `Fri` | `Sat` | `Sun`
- /// ------------------------- | ----- | ----- | ----- | ----- | ----- | ----- | -----
- /// `w.number_from_sunday()`: | 2 | 3 | 4 | 5 | 6 | 7 | 1
- #[inline]
- pub fn number_from_sunday(&self) -> u32 {
- match *self {
- Weekday::Mon => 2,
- Weekday::Tue => 3,
- Weekday::Wed => 4,
- Weekday::Thu => 5,
- Weekday::Fri => 6,
- Weekday::Sat => 7,
- Weekday::Sun => 1,
- }
- }
-
- /// Returns a day-of-week number starting from Monday = 0.
- ///
- /// `w`: | `Mon` | `Tue` | `Wed` | `Thu` | `Fri` | `Sat` | `Sun`
- /// --------------------------- | ----- | ----- | ----- | ----- | ----- | ----- | -----
- /// `w.num_days_from_monday()`: | 0 | 1 | 2 | 3 | 4 | 5 | 6
- #[inline]
- pub fn num_days_from_monday(&self) -> u32 {
- match *self {
- Weekday::Mon => 0,
- Weekday::Tue => 1,
- Weekday::Wed => 2,
- Weekday::Thu => 3,
- Weekday::Fri => 4,
- Weekday::Sat => 5,
- Weekday::Sun => 6,
- }
- }
-
- /// Returns a day-of-week number starting from Sunday = 0.
- ///
- /// `w`: | `Mon` | `Tue` | `Wed` | `Thu` | `Fri` | `Sat` | `Sun`
- /// --------------------------- | ----- | ----- | ----- | ----- | ----- | ----- | -----
- /// `w.num_days_from_sunday()`: | 1 | 2 | 3 | 4 | 5 | 6 | 0
- #[inline]
- pub fn num_days_from_sunday(&self) -> u32 {
- match *self {
- Weekday::Mon => 1,
- Weekday::Tue => 2,
- Weekday::Wed => 3,
- Weekday::Thu => 4,
- Weekday::Fri => 5,
- Weekday::Sat => 6,
- Weekday::Sun => 0,
- }
- }
-}
-
-impl fmt::Display for Weekday {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- f.write_str(match *self {
- Weekday::Mon => "Mon",
- Weekday::Tue => "Tue",
- Weekday::Wed => "Wed",
- Weekday::Thu => "Thu",
- Weekday::Fri => "Fri",
- Weekday::Sat => "Sat",
- Weekday::Sun => "Sun",
- })
- }
-}
-
-/// 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> {
- match n {
- 0 => Some(Weekday::Mon),
- 1 => Some(Weekday::Tue),
- 2 => Some(Weekday::Wed),
- 3 => Some(Weekday::Thu),
- 4 => Some(Weekday::Fri),
- 5 => Some(Weekday::Sat),
- 6 => Some(Weekday::Sun),
- _ => None,
- }
- }
-
- #[inline]
- fn from_u64(n: u64) -> Option<Weekday> {
- match n {
- 0 => Some(Weekday::Mon),
- 1 => Some(Weekday::Tue),
- 2 => Some(Weekday::Wed),
- 3 => Some(Weekday::Thu),
- 4 => Some(Weekday::Fri),
- 5 => Some(Weekday::Sat),
- 6 => Some(Weekday::Sun),
- _ => None,
- }
- }
-}
-
-use core::fmt;
-
-/// An error resulting from reading `Weekday` value with `FromStr`.
-#[derive(Clone, PartialEq)]
-pub struct ParseWeekdayError {
- _dummy: (),
-}
-
-impl fmt::Debug for ParseWeekdayError {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "ParseWeekdayError {{ .. }}")
- }
-}
-
-// the actual `FromStr` implementation is in the `format` module to leverage the existing code
-
-#[cfg(feature = "serde")]
-mod weekday_serde {
- use super::Weekday;
- use core::fmt;
- use serdelib::{de, ser};
-
- impl ser::Serialize for Weekday {
- fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
- where
- S: ser::Serializer,
- {
- serializer.collect_str(&self)
- }
- }
-
- struct WeekdayVisitor;
-
- impl<'de> de::Visitor<'de> for WeekdayVisitor {
- type Value = Weekday;
-
- fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "Weekday")
- }
-
- fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
- where
- E: de::Error,
- {
- value.parse().map_err(|_| E::custom("short or long weekday names expected"))
- }
- }
-
- impl<'de> de::Deserialize<'de> for Weekday {
- fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
- where
- D: de::Deserializer<'de>,
- {
- deserializer.deserialize_str(WeekdayVisitor)
- }
- }
-
- #[cfg(test)]
- extern crate serde_json;
-
- #[test]
- fn test_serde_serialize() {
- use self::serde_json::to_string;
- use Weekday::*;
-
- let cases: Vec<(Weekday, &str)> = vec![
- (Mon, "\"Mon\""),
- (Tue, "\"Tue\""),
- (Wed, "\"Wed\""),
- (Thu, "\"Thu\""),
- (Fri, "\"Fri\""),
- (Sat, "\"Sat\""),
- (Sun, "\"Sun\""),
- ];
-
- for (weekday, expected_str) in cases {
- let string = to_string(&weekday).unwrap();
- assert_eq!(string, expected_str);
- }
- }
-
- #[test]
- fn test_serde_deserialize() {
- use self::serde_json::from_str;
- use Weekday::*;
-
- let cases: Vec<(&str, Weekday)> = vec![
- ("\"mon\"", Mon),
- ("\"MONDAY\"", Mon),
- ("\"MonDay\"", Mon),
- ("\"mOn\"", Mon),
- ("\"tue\"", Tue),
- ("\"tuesday\"", Tue),
- ("\"wed\"", Wed),
- ("\"wednesday\"", Wed),
- ("\"thu\"", Thu),
- ("\"thursday\"", Thu),
- ("\"fri\"", Fri),
- ("\"friday\"", Fri),
- ("\"sat\"", Sat),
- ("\"saturday\"", Sat),
- ("\"sun\"", Sun),
- ("\"sunday\"", Sun),
- ];
-
- for (str, expected_weekday) in cases {
- let weekday = from_str::<Weekday>(str).unwrap();
- assert_eq!(weekday, expected_weekday);
- }
-
- let errors: Vec<&str> =
- vec!["\"not a weekday\"", "\"monDAYs\"", "\"mond\"", "mon", "\"thur\"", "\"thurs\""];
-
- for str in errors {
- from_str::<Weekday>(str).unwrap_err();
- }
- }
-}
-
-/// The month of the year.
-///
-/// This enum is just a convenience implementation.
-/// The month in dates created by DateLike objects does not return this enum.
-///
-/// It is possible to convert from a date to a month independently
-/// ```
-/// # extern crate num_traits;
-/// use num_traits::FromPrimitive;
-/// use chrono::prelude::*;
-/// let date = Utc.ymd(2019, 10, 28).and_hms(9, 10, 11);
-/// // `2019-10-28T09:10:11Z`
-/// let month = Month::from_u32(date.month());
-/// assert_eq!(month, Some(Month::October))
-/// ```
-/// Or from a Month to an integer usable by dates
-/// ```
-/// # use chrono::prelude::*;
-/// let month = Month::January;
-/// let dt = Utc.ymd(2019, month.number_from_month(), 28).and_hms(9, 10, 11);
-/// assert_eq!((dt.year(), dt.month(), dt.day()), (2019, 1, 28));
-/// ```
-/// 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)]
-#[cfg_attr(feature = "rustc-serialize", derive(RustcEncodable, RustcDecodable))]
-pub enum Month {
- /// January
- January = 0,
- /// February
- February = 1,
- /// March
- March = 2,
- /// April
- April = 3,
- /// May
- May = 4,
- /// June
- June = 5,
- /// July
- July = 6,
- /// August
- August = 7,
- /// September
- September = 8,
- /// October
- October = 9,
- /// November
- November = 10,
- /// December
- December = 11,
-}
-
-impl Month {
- /// The next month.
- ///
- /// `m`: | `January` | `February` | `...` | `December`
- /// ----------- | --------- | ---------- | --- | ---------
- /// `m.succ()`: | `February` | `March` | `...` | `January`
- #[inline]
- pub fn succ(&self) -> Month {
- match *self {
- Month::January => Month::February,
- Month::February => Month::March,
- Month::March => Month::April,
- Month::April => Month::May,
- Month::May => Month::June,
- Month::June => Month::July,
- Month::July => Month::August,
- Month::August => Month::September,
- Month::September => Month::October,
- Month::October => Month::November,
- Month::November => Month::December,
- Month::December => Month::January,
- }
- }
-
- /// The previous month.
- ///
- /// `m`: | `January` | `February` | `...` | `December`
- /// ----------- | --------- | ---------- | --- | ---------
- /// `m.succ()`: | `December` | `January` | `...` | `November`
- #[inline]
- pub fn pred(&self) -> Month {
- match *self {
- Month::January => Month::December,
- Month::February => Month::January,
- Month::March => Month::February,
- Month::April => Month::March,
- Month::May => Month::April,
- Month::June => Month::May,
- Month::July => Month::June,
- Month::August => Month::July,
- Month::September => Month::August,
- Month::October => Month::September,
- Month::November => Month::October,
- Month::December => Month::November,
- }
- }
-
- /// Returns a month-of-year number starting from January = 1.
- ///
- /// `m`: | `January` | `February` | `...` | `December`
- /// -------------------------| --------- | ---------- | --- | -----
- /// `m.number_from_month()`: | 1 | 2 | `...` | 12
- #[inline]
- pub fn number_from_month(&self) -> u32 {
- match *self {
- Month::January => 1,
- Month::February => 2,
- Month::March => 3,
- Month::April => 4,
- Month::May => 5,
- Month::June => 6,
- Month::July => 7,
- Month::August => 8,
- Month::September => 9,
- Month::October => 10,
- Month::November => 11,
- Month::December => 12,
- }
- }
-
- /// Get the name of the month
- ///
- /// ```
- /// use chrono::Month;
- ///
- /// assert_eq!(Month::January.name(), "January")
- /// ```
- pub fn name(&self) -> &'static str {
- match *self {
- Month::January => "January",
- Month::February => "February",
- Month::March => "March",
- Month::April => "April",
- Month::May => "May",
- Month::June => "June",
- Month::July => "July",
- Month::August => "August",
- Month::September => "September",
- Month::October => "October",
- Month::November => "November",
- Month::December => "December",
- }
- }
-}
-
-impl num_traits::FromPrimitive for Month {
- /// Returns an Option<Month> from a i64, assuming a 1-index, January = 1.
- ///
- /// `Month::from_i64(n: i64)`: | `1` | `2` | ... | `12`
- /// ---------------------------| -------------------- | --------------------- | ... | -----
- /// ``: | Some(Month::January) | Some(Month::February) | ... | Some(Month::December)
-
- #[inline]
- fn from_u64(n: u64) -> Option<Month> {
- Self::from_u32(n as u32)
- }
-
- #[inline]
- fn from_i64(n: i64) -> Option<Month> {
- Self::from_u32(n as u32)
- }
-
- #[inline]
- fn from_u32(n: u32) -> Option<Month> {
- match n {
- 1 => Some(Month::January),
- 2 => Some(Month::February),
- 3 => Some(Month::March),
- 4 => Some(Month::April),
- 5 => Some(Month::May),
- 6 => Some(Month::June),
- 7 => Some(Month::July),
- 8 => Some(Month::August),
- 9 => Some(Month::September),
- 10 => Some(Month::October),
- 11 => Some(Month::November),
- 12 => Some(Month::December),
- _ => None,
- }
- }
-}
-
-/// An error resulting from reading `<Month>` value with `FromStr`.
-#[derive(Clone, PartialEq)]
-pub struct ParseMonthError {
- _dummy: (),
-}
-
-impl fmt::Debug for ParseMonthError {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "ParseMonthError {{ .. }}")
- }
-}
-
-#[cfg(feature = "serde")]
-mod month_serde {
- use super::Month;
- use serdelib::{de, ser};
-
- use core::fmt;
-
- impl ser::Serialize for Month {
- fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
- where
- S: ser::Serializer,
- {
- serializer.collect_str(self.name())
- }
- }
-
- struct MonthVisitor;
-
- impl<'de> de::Visitor<'de> for MonthVisitor {
- type Value = Month;
-
- fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "Month")
- }
-
- fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
- where
- E: de::Error,
- {
- value.parse().map_err(|_| E::custom("short (3-letter) or full month names expected"))
- }
- }
-
- impl<'de> de::Deserialize<'de> for Month {
- fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
- where
- D: de::Deserializer<'de>,
- {
- deserializer.deserialize_str(MonthVisitor)
- }
- }
-
- #[cfg(test)]
- extern crate serde_json;
-
- #[test]
- fn test_serde_serialize() {
- use self::serde_json::to_string;
- use Month::*;
-
- let cases: Vec<(Month, &str)> = vec![
- (January, "\"January\""),
- (February, "\"February\""),
- (March, "\"March\""),
- (April, "\"April\""),
- (May, "\"May\""),
- (June, "\"June\""),
- (July, "\"July\""),
- (August, "\"August\""),
- (September, "\"September\""),
- (October, "\"October\""),
- (November, "\"November\""),
- (December, "\"December\""),
- ];
-
- for (month, expected_str) in cases {
- let string = to_string(&month).unwrap();
- assert_eq!(string, expected_str);
- }
- }
-
- #[test]
- fn test_serde_deserialize() {
- use self::serde_json::from_str;
- use Month::*;
-
- let cases: Vec<(&str, Month)> = vec![
- ("\"january\"", January),
- ("\"jan\"", January),
- ("\"FeB\"", February),
- ("\"MAR\"", March),
- ("\"mar\"", March),
- ("\"april\"", April),
- ("\"may\"", May),
- ("\"june\"", June),
- ("\"JULY\"", July),
- ("\"august\"", August),
- ("\"september\"", September),
- ("\"October\"", October),
- ("\"November\"", November),
- ("\"DECEmbEr\"", December),
- ];
-
- for (string, expected_month) in cases {
- let month = from_str::<Month>(string).unwrap();
- assert_eq!(month, expected_month);
- }
-
- let errors: Vec<&str> =
- vec!["\"not a month\"", "\"ja\"", "\"Dece\"", "Dec", "\"Augustin\""];
-
- for string in errors {
- from_str::<Month>(string).unwrap_err();
- }
- }
-}
-
-/// The common set of methods for date component.
-pub trait Datelike: Sized {
- /// Returns the year number in the [calendar date](./naive/struct.NaiveDate.html#calendar-date).
- fn year(&self) -> i32;
-
- /// Returns the absolute year number starting from 1 with a boolean flag,
- /// which is false when the year predates the epoch (BCE/BC) and true otherwise (CE/AD).
- #[inline]
- fn year_ce(&self) -> (bool, u32) {
- let year = self.year();
- if year < 1 {
- (false, (1 - year) as u32)
- } else {
- (true, year as u32)
- }
- }
-
- /// Returns the month number starting from 1.
- ///
- /// The return value ranges from 1 to 12.
- fn month(&self) -> u32;
-
- /// Returns the month number starting from 0.
- ///
- /// The return value ranges from 0 to 11.
- fn month0(&self) -> u32;
-
- /// Returns the day of month starting from 1.
- ///
- /// The return value ranges from 1 to 31. (The last day of month differs by months.)
- fn day(&self) -> u32;
-
- /// Returns the day of month starting from 0.
- ///
- /// The return value ranges from 0 to 30. (The last day of month differs by months.)
- fn day0(&self) -> u32;
-
- /// Returns the day of year starting from 1.
- ///
- /// The return value ranges from 1 to 366. (The last day of year differs by years.)
- fn ordinal(&self) -> u32;
-
- /// Returns the day of year starting from 0.
- ///
- /// The return value ranges from 0 to 365. (The last day of year differs by years.)
- fn ordinal0(&self) -> u32;
-
- /// Returns the day of week.
- fn weekday(&self) -> Weekday;
-
- /// Returns the ISO week.
- fn iso_week(&self) -> IsoWeek;
-
- /// Makes a new value with the year number changed.
- ///
- /// Returns `None` when the resulting value would be invalid.
- fn with_year(&self, year: i32) -> Option<Self>;
-
- /// Makes a new value with the month number (starting from 1) changed.
- ///
- /// Returns `None` when the resulting value would be invalid.
- fn with_month(&self, month: u32) -> Option<Self>;
-
- /// Makes a new value with the month number (starting from 0) changed.
- ///
- /// Returns `None` when the resulting value would be invalid.
- fn with_month0(&self, month0: u32) -> Option<Self>;
-
- /// Makes a new value with the day of month (starting from 1) changed.
- ///
- /// Returns `None` when the resulting value would be invalid.
- fn with_day(&self, day: u32) -> Option<Self>;
-
- /// Makes a new value with the day of month (starting from 0) changed.
- ///
- /// Returns `None` when the resulting value would be invalid.
- fn with_day0(&self, day0: u32) -> Option<Self>;
-
- /// Makes a new value with the day of year (starting from 1) changed.
- ///
- /// Returns `None` when the resulting value would be invalid.
- fn with_ordinal(&self, ordinal: u32) -> Option<Self>;
-
- /// Makes a new value with the day of year (starting from 0) changed.
- ///
- /// Returns `None` when the resulting value would be invalid.
- fn with_ordinal0(&self, ordinal0: u32) -> Option<Self>;
-
- /// Counts the days in the proleptic Gregorian calendar, with January 1, Year 1 (CE) as day 1.
- ///
- /// # Examples
- ///
- /// ```
- /// use chrono::{NaiveDate, Datelike};
- ///
- /// assert_eq!(NaiveDate::from_ymd(1970, 1, 1).num_days_from_ce(), 719_163);
- /// assert_eq!(NaiveDate::from_ymd(2, 1, 1).num_days_from_ce(), 366);
- /// assert_eq!(NaiveDate::from_ymd(1, 1, 1).num_days_from_ce(), 1);
- /// assert_eq!(NaiveDate::from_ymd(0, 1, 1).num_days_from_ce(), -365);
- /// ```
- fn num_days_from_ce(&self) -> i32 {
- // See test_num_days_from_ce_against_alternative_impl below for a more straightforward
- // implementation.
-
- // we know this wouldn't overflow since year is limited to 1/2^13 of i32's full range.
- let mut year = self.year() - 1;
- let mut ndays = 0;
- if year < 0 {
- let excess = 1 + (-year) / 400;
- year += excess * 400;
- ndays -= excess * 146_097;
- }
- let div_100 = year / 100;
- ndays += ((year * 1461) >> 2) - div_100 + (div_100 >> 2);
- ndays + self.ordinal() as i32
- }
-}
-
-/// The common set of methods for time component.
-pub trait Timelike: Sized {
- /// Returns the hour number from 0 to 23.
- fn hour(&self) -> u32;
-
- /// Returns the hour number from 1 to 12 with a boolean flag,
- /// which is false for AM and true for PM.
- #[inline]
- fn hour12(&self) -> (bool, u32) {
- let hour = self.hour();
- let mut hour12 = hour % 12;
- if hour12 == 0 {
- hour12 = 12;
- }
- (hour >= 12, hour12)
- }
-
- /// Returns the minute number from 0 to 59.
- fn minute(&self) -> u32;
-
- /// Returns the second number from 0 to 59.
- fn second(&self) -> u32;
-
- /// Returns the number of nanoseconds since the whole non-leap second.
- /// The range from 1,000,000,000 to 1,999,999,999 represents
- /// the [leap second](./naive/struct.NaiveTime.html#leap-second-handling).
- fn nanosecond(&self) -> u32;
-
- /// Makes a new value with the hour number changed.
- ///
- /// Returns `None` when the resulting value would be invalid.
- fn with_hour(&self, hour: u32) -> Option<Self>;
-
- /// Makes a new value with the minute number changed.
- ///
- /// Returns `None` when the resulting value would be invalid.
- fn with_minute(&self, min: u32) -> Option<Self>;
-
- /// Makes a new value with the second number changed.
- ///
- /// Returns `None` when the resulting value would be invalid.
- /// As with the [`second`](#tymethod.second) method,
- /// the input range is restricted to 0 through 59.
- fn with_second(&self, sec: u32) -> Option<Self>;
-
- /// Makes a new value with nanoseconds since the whole non-leap second changed.
- ///
- /// Returns `None` when the resulting value would be invalid.
- /// As with the [`nanosecond`](#tymethod.nanosecond) method,
- /// the input range can exceed 1,000,000,000 for leap seconds.
- fn with_nanosecond(&self, nano: u32) -> Option<Self>;
-
- /// Returns the number of non-leap seconds past the last midnight.
- #[inline]
- fn num_seconds_from_midnight(&self) -> u32 {
- self.hour() * 3600 + self.minute() * 60 + self.second()
- }
-}
-
+/// MSRV 1.42
#[cfg(test)]
-extern crate num_iter;
-
-mod test {
- #[allow(unused_imports)]
- use super::*;
-
- #[test]
- fn test_readme_doomsday() {
- use num_iter::range_inclusive;
-
- for y in range_inclusive(naive::MIN_DATE.year(), naive::MAX_DATE.year()) {
- // even months
- let d4 = NaiveDate::from_ymd(y, 4, 4);
- let d6 = NaiveDate::from_ymd(y, 6, 6);
- let d8 = NaiveDate::from_ymd(y, 8, 8);
- let d10 = NaiveDate::from_ymd(y, 10, 10);
- let d12 = NaiveDate::from_ymd(y, 12, 12);
-
- // nine to five, seven-eleven
- let d59 = NaiveDate::from_ymd(y, 5, 9);
- let d95 = NaiveDate::from_ymd(y, 9, 5);
- let d711 = NaiveDate::from_ymd(y, 7, 11);
- let d117 = NaiveDate::from_ymd(y, 11, 7);
-
- // "March 0"
- let d30 = NaiveDate::from_ymd(y, 3, 1).pred();
-
- let weekday = d30.weekday();
- let other_dates = [d4, d6, d8, d10, d12, d59, d95, d711, d117];
- assert!(other_dates.iter().all(|d| d.weekday() == weekday));
+#[macro_export]
+macro_rules! matches {
+ ($expression:expr, $(|)? $( $pattern:pat )|+ $( if $guard: expr )? $(,)?) => {
+ match $expression {
+ $( $pattern )|+ $( if $guard )? => true,
+ _ => false
}
}
-
- #[test]
- fn test_month_enum_primitive_parse() {
- use num_traits::FromPrimitive;
-
- let jan_opt = Month::from_u32(1);
- let feb_opt = Month::from_u64(2);
- let dec_opt = Month::from_i64(12);
- let no_month = Month::from_u32(13);
- assert_eq!(jan_opt, Some(Month::January));
- assert_eq!(feb_opt, Some(Month::February));
- assert_eq!(dec_opt, Some(Month::December));
- assert_eq!(no_month, None);
-
- let date = Utc.ymd(2019, 10, 28).and_hms(9, 10, 11);
- assert_eq!(Month::from_u32(date.month()), Some(Month::October));
-
- let month = Month::January;
- let dt = Utc.ymd(2019, month.number_from_month(), 28).and_hms(9, 10, 11);
- assert_eq!((dt.year(), dt.month(), dt.day()), (2019, 1, 28));
- }
-}
-
-/// Tests `Datelike::num_days_from_ce` against an alternative implementation.
-///
-/// The alternative implementation is not as short as the current one but it is simpler to
-/// understand, with less unexplained magic constants.
-#[test]
-fn test_num_days_from_ce_against_alternative_impl() {
- /// Returns the number of multiples of `div` in the range `start..end`.
- ///
- /// If the range `start..end` is back-to-front, i.e. `start` is greater than `end`, the
- /// behaviour is defined by the following equation:
- /// `in_between(start, end, div) == - in_between(end, start, div)`.
- ///
- /// When `div` is 1, this is equivalent to `end - start`, i.e. the length of `start..end`.
- ///
- /// # Panics
- ///
- /// Panics if `div` is not positive.
- fn in_between(start: i32, end: i32, div: i32) -> i32 {
- assert!(div > 0, "in_between: nonpositive div = {}", div);
- let start = (start.div_euclid(div), start.rem_euclid(div));
- let end = (end.div_euclid(div), end.rem_euclid(div));
- // The lowest multiple of `div` greater than or equal to `start`, divided.
- let start = start.0 + (start.1 != 0) as i32;
- // The lowest multiple of `div` greater than or equal to `end`, divided.
- let end = end.0 + (end.1 != 0) as i32;
- end - start
- }
-
- /// Alternative implementation to `Datelike::num_days_from_ce`
- fn num_days_from_ce<Date: Datelike>(date: &Date) -> i32 {
- let year = date.year();
- let diff = move |div| in_between(1, year, div);
- // 365 days a year, one more in leap years. In the gregorian calendar, leap years are all
- // the multiples of 4 except multiples of 100 but including multiples of 400.
- date.ordinal() as i32 + 365 * diff(1) + diff(4) - diff(100) + diff(400)
- }
-
- use num_iter::range_inclusive;
-
- for year in range_inclusive(naive::MIN_DATE.year(), naive::MAX_DATE.year()) {
- let jan1_year = NaiveDate::from_ymd(year, 1, 1);
- assert_eq!(
- jan1_year.num_days_from_ce(),
- num_days_from_ce(&jan1_year),
- "on {:?}",
- jan1_year
- );
- let mid_year = jan1_year + Duration::days(133);
- assert_eq!(mid_year.num_days_from_ce(), num_days_from_ce(&mid_year), "on {:?}", mid_year);
- }
-}
-
-#[test]
-fn test_month_enum_succ_pred() {
- assert_eq!(Month::January.succ(), Month::February);
- assert_eq!(Month::December.succ(), Month::January);
- assert_eq!(Month::January.pred(), Month::December);
- assert_eq!(Month::February.pred(), Month::January);
}
diff --git a/vendor/chrono/src/month.rs b/vendor/chrono/src/month.rs
new file mode 100644
index 000000000..46f09d0fb
--- /dev/null
+++ b/vendor/chrono/src/month.rs
@@ -0,0 +1,355 @@
+use core::fmt;
+
+#[cfg(feature = "rkyv")]
+use rkyv::{Archive, Deserialize, Serialize};
+
+/// The month of the year.
+///
+/// This enum is just a convenience implementation.
+/// The month in dates created by DateLike objects does not return this enum.
+///
+/// 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());
+/// assert_eq!(month, Some(Month::October))
+/// ```
+/// Or from a Month to an integer usable by dates
+/// ```
+/// # use chrono::prelude::*;
+/// 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));
+/// ```
+/// 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)]
+#[cfg_attr(feature = "rustc-serialize", derive(RustcEncodable, RustcDecodable))]
+#[cfg_attr(feature = "rkyv", derive(Archive, Deserialize, Serialize))]
+#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
+pub enum Month {
+ /// January
+ January = 0,
+ /// February
+ February = 1,
+ /// March
+ March = 2,
+ /// April
+ April = 3,
+ /// May
+ May = 4,
+ /// June
+ June = 5,
+ /// July
+ July = 6,
+ /// August
+ August = 7,
+ /// September
+ September = 8,
+ /// October
+ October = 9,
+ /// November
+ November = 10,
+ /// December
+ December = 11,
+}
+
+impl Month {
+ /// The next month.
+ ///
+ /// `m`: | `January` | `February` | `...` | `December`
+ /// ----------- | --------- | ---------- | --- | ---------
+ /// `m.succ()`: | `February` | `March` | `...` | `January`
+ #[inline]
+ pub fn succ(&self) -> Month {
+ match *self {
+ Month::January => Month::February,
+ Month::February => Month::March,
+ Month::March => Month::April,
+ Month::April => Month::May,
+ Month::May => Month::June,
+ Month::June => Month::July,
+ Month::July => Month::August,
+ Month::August => Month::September,
+ Month::September => Month::October,
+ Month::October => Month::November,
+ Month::November => Month::December,
+ Month::December => Month::January,
+ }
+ }
+
+ /// The previous month.
+ ///
+ /// `m`: | `January` | `February` | `...` | `December`
+ /// ----------- | --------- | ---------- | --- | ---------
+ /// `m.pred()`: | `December` | `January` | `...` | `November`
+ #[inline]
+ pub fn pred(&self) -> Month {
+ match *self {
+ Month::January => Month::December,
+ Month::February => Month::January,
+ Month::March => Month::February,
+ Month::April => Month::March,
+ Month::May => Month::April,
+ Month::June => Month::May,
+ Month::July => Month::June,
+ Month::August => Month::July,
+ Month::September => Month::August,
+ Month::October => Month::September,
+ Month::November => Month::October,
+ Month::December => Month::November,
+ }
+ }
+
+ /// Returns a month-of-year number starting from January = 1.
+ ///
+ /// `m`: | `January` | `February` | `...` | `December`
+ /// -------------------------| --------- | ---------- | --- | -----
+ /// `m.number_from_month()`: | 1 | 2 | `...` | 12
+ #[inline]
+ pub fn number_from_month(&self) -> u32 {
+ match *self {
+ Month::January => 1,
+ Month::February => 2,
+ Month::March => 3,
+ Month::April => 4,
+ Month::May => 5,
+ Month::June => 6,
+ Month::July => 7,
+ Month::August => 8,
+ Month::September => 9,
+ Month::October => 10,
+ Month::November => 11,
+ Month::December => 12,
+ }
+ }
+
+ /// Get the name of the month
+ ///
+ /// ```
+ /// use chrono::Month;
+ ///
+ /// assert_eq!(Month::January.name(), "January")
+ /// ```
+ pub fn name(&self) -> &'static str {
+ match *self {
+ Month::January => "January",
+ Month::February => "February",
+ Month::March => "March",
+ Month::April => "April",
+ Month::May => "May",
+ Month::June => "June",
+ Month::July => "July",
+ Month::August => "August",
+ Month::September => "September",
+ Month::October => "October",
+ Month::November => "November",
+ Month::December => "December",
+ }
+ }
+}
+
+impl num_traits::FromPrimitive for Month {
+ /// Returns an `Option<Month>` from a i64, assuming a 1-index, January = 1.
+ ///
+ /// `Month::from_i64(n: i64)`: | `1` | `2` | ... | `12`
+ /// ---------------------------| -------------------- | --------------------- | ... | -----
+ /// ``: | Some(Month::January) | Some(Month::February) | ... | Some(Month::December)
+
+ #[inline]
+ fn from_u64(n: u64) -> Option<Month> {
+ Self::from_u32(n as u32)
+ }
+
+ #[inline]
+ fn from_i64(n: i64) -> Option<Month> {
+ Self::from_u32(n as u32)
+ }
+
+ #[inline]
+ fn from_u32(n: u32) -> Option<Month> {
+ match n {
+ 1 => Some(Month::January),
+ 2 => Some(Month::February),
+ 3 => Some(Month::March),
+ 4 => Some(Month::April),
+ 5 => Some(Month::May),
+ 6 => Some(Month::June),
+ 7 => Some(Month::July),
+ 8 => Some(Month::August),
+ 9 => Some(Month::September),
+ 10 => Some(Month::October),
+ 11 => Some(Month::November),
+ 12 => Some(Month::December),
+ _ => None,
+ }
+ }
+}
+
+/// A duration in calendar months
+#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd)]
+#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
+pub struct Months(pub(crate) u32);
+
+impl Months {
+ /// Construct a new `Months` from a number of months
+ pub const fn new(num: u32) -> Self {
+ Self(num)
+ }
+}
+
+/// An error resulting from reading `<Month>` value with `FromStr`.
+#[derive(Clone, PartialEq, Eq)]
+pub struct ParseMonthError {
+ pub(crate) _dummy: (),
+}
+
+impl fmt::Debug for ParseMonthError {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "ParseMonthError {{ .. }}")
+ }
+}
+
+#[cfg(feature = "serde")]
+#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
+mod month_serde {
+ use super::Month;
+ use serde::{de, ser};
+
+ use core::fmt;
+
+ impl ser::Serialize for Month {
+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: ser::Serializer,
+ {
+ serializer.collect_str(self.name())
+ }
+ }
+
+ struct MonthVisitor;
+
+ impl<'de> de::Visitor<'de> for MonthVisitor {
+ type Value = Month;
+
+ fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.write_str("Month")
+ }
+
+ fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
+ where
+ E: de::Error,
+ {
+ value.parse().map_err(|_| E::custom("short (3-letter) or full month names expected"))
+ }
+ }
+
+ impl<'de> de::Deserialize<'de> for Month {
+ fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+ where
+ D: de::Deserializer<'de>,
+ {
+ deserializer.deserialize_str(MonthVisitor)
+ }
+ }
+
+ #[test]
+ fn test_serde_serialize() {
+ use serde_json::to_string;
+ use Month::*;
+
+ let cases: Vec<(Month, &str)> = vec![
+ (January, "\"January\""),
+ (February, "\"February\""),
+ (March, "\"March\""),
+ (April, "\"April\""),
+ (May, "\"May\""),
+ (June, "\"June\""),
+ (July, "\"July\""),
+ (August, "\"August\""),
+ (September, "\"September\""),
+ (October, "\"October\""),
+ (November, "\"November\""),
+ (December, "\"December\""),
+ ];
+
+ for (month, expected_str) in cases {
+ let string = to_string(&month).unwrap();
+ assert_eq!(string, expected_str);
+ }
+ }
+
+ #[test]
+ fn test_serde_deserialize() {
+ use serde_json::from_str;
+ use Month::*;
+
+ let cases: Vec<(&str, Month)> = vec![
+ ("\"january\"", January),
+ ("\"jan\"", January),
+ ("\"FeB\"", February),
+ ("\"MAR\"", March),
+ ("\"mar\"", March),
+ ("\"april\"", April),
+ ("\"may\"", May),
+ ("\"june\"", June),
+ ("\"JULY\"", July),
+ ("\"august\"", August),
+ ("\"september\"", September),
+ ("\"October\"", October),
+ ("\"November\"", November),
+ ("\"DECEmbEr\"", December),
+ ];
+
+ for (string, expected_month) in cases {
+ let month = from_str::<Month>(string).unwrap();
+ assert_eq!(month, expected_month);
+ }
+
+ let errors: Vec<&str> =
+ vec!["\"not a month\"", "\"ja\"", "\"Dece\"", "Dec", "\"Augustin\""];
+
+ for string in errors {
+ from_str::<Month>(string).unwrap_err();
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::Month;
+ use crate::{Datelike, TimeZone, Utc};
+
+ #[test]
+ fn test_month_enum_primitive_parse() {
+ use num_traits::FromPrimitive;
+
+ let jan_opt = Month::from_u32(1);
+ let feb_opt = Month::from_u64(2);
+ let dec_opt = Month::from_i64(12);
+ let no_month = Month::from_u32(13);
+ assert_eq!(jan_opt, Some(Month::January));
+ assert_eq!(feb_opt, Some(Month::February));
+ assert_eq!(dec_opt, Some(Month::December));
+ assert_eq!(no_month, None);
+
+ let date = Utc.with_ymd_and_hms(2019, 10, 28, 9, 10, 11).unwrap();
+ assert_eq!(Month::from_u32(date.month()), Some(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_succ_pred() {
+ assert_eq!(Month::January.succ(), Month::February);
+ assert_eq!(Month::December.succ(), Month::January);
+ assert_eq!(Month::January.pred(), Month::December);
+ assert_eq!(Month::February.pred(), Month::January);
+ }
+}
diff --git a/vendor/chrono/src/naive/date.rs b/vendor/chrono/src/naive/date.rs
index 3e34e2074..64af978f3 100644
--- a/vendor/chrono/src/naive/date.rs
+++ b/vendor/chrono/src/naive/date.rs
@@ -5,18 +5,27 @@
#[cfg(any(feature = "alloc", feature = "std", test))]
use core::borrow::Borrow;
-use core::ops::{Add, AddAssign, Sub, SubAssign};
+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;
-use oldtime::Duration as OldDuration;
+#[cfg(feature = "rkyv")]
+use rkyv::{Archive, Deserialize, Serialize};
+
+/// L10n locales.
+#[cfg(feature = "unstable-locales")]
+use pure_rust_locales::Locale;
-use div::div_mod_floor;
#[cfg(any(feature = "alloc", feature = "std", test))]
-use format::DelayedFormat;
-use format::{parse, ParseError, ParseResult, Parsed, StrftimeItems};
-use format::{Item, Numeric, Pad};
-use naive::{IsoWeek, NaiveDateTime, NaiveTime};
-use {Datelike, Weekday};
+use crate::format::DelayedFormat;
+use crate::format::{parse, write_hundreds, ParseError, ParseResult, Parsed, StrftimeItems};
+use crate::format::{Item, Numeric, Pad};
+use crate::month::Months;
+use crate::naive::{IsoWeek, NaiveDateTime, NaiveTime};
+use crate::oldtime::Duration as OldDuration;
+use crate::{Datelike, Duration, Weekday};
use super::internals::{self, DateImpl, Mdf, Of, YearFlags};
use super::isoweek;
@@ -42,11 +51,91 @@ const MAX_DAYS_FROM_YEAR_0: i32 =
const MIN_DAYS_FROM_YEAR_0: i32 = (MIN_YEAR + 400_000) * 365 + (MIN_YEAR + 400_000) / 4
- (MIN_YEAR + 400_000) / 100
+ (MIN_YEAR + 400_000) / 400
- - 146097_000;
+ - 146_097_000;
#[cfg(test)] // only used for testing, but duplicated in naive::datetime
const MAX_BITS: usize = 44;
+/// A week represented by a [`NaiveDate`] and a [`Weekday`] which is the first
+/// day of the week.
+#[derive(Debug)]
+pub struct NaiveWeek {
+ date: NaiveDate,
+ start: Weekday,
+}
+
+impl NaiveWeek {
+ /// Returns a date representing the first day of the week.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use chrono::{NaiveDate, Weekday};
+ ///
+ /// let date = NaiveDate::from_ymd_opt(2022, 4, 18).unwrap();
+ /// let week = date.week(Weekday::Mon);
+ /// assert!(week.first_day() <= date);
+ /// ```
+ #[inline]
+ 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())
+ }
+
+ /// Returns a date representing the last day of the week.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use chrono::{NaiveDate, Weekday};
+ ///
+ /// let date = NaiveDate::from_ymd_opt(2022, 4, 18).unwrap();
+ /// let week = date.week(Weekday::Mon);
+ /// assert!(week.last_day() >= date);
+ /// ```
+ #[inline]
+ pub fn last_day(&self) -> NaiveDate {
+ self.first_day() + Duration::days(6)
+ }
+
+ /// Returns a [`RangeInclusive<T>`] representing the whole week bounded by
+ /// [first_day](./struct.NaiveWeek.html#method.first_day) and
+ /// [last_day](./struct.NaiveWeek.html#method.last_day) functions.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use chrono::{NaiveDate, Weekday};
+ ///
+ /// let date = NaiveDate::from_ymd_opt(2022, 4, 18).unwrap();
+ /// let week = date.week(Weekday::Mon);
+ /// let days = week.days();
+ /// assert!(days.contains(&date));
+ /// ```
+ #[inline]
+ pub fn days(&self) -> RangeInclusive<NaiveDate> {
+ self.first_day()..=self.last_day()
+ }
+}
+
+/// A duration in calendar days.
+///
+/// This is useful because when using `Duration` it is possible
+/// that adding `Duration::days(1)` doesn't increment the day value as expected due to it being a
+/// fixed number of seconds. This difference applies only when dealing with `DateTime<TimeZone>` data types
+/// and in other cases `Duration::days(n)` and `Days::new(n)` are equivalent.
+#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd)]
+pub struct Days(pub(crate) u64);
+
+impl Days {
+ /// Construct a new `Days` from a number of days
+ pub const fn new(num: u64) -> Self {
+ Self(num)
+ }
+}
+
/// ISO 8601 calendar date without timezone.
/// Allows for every [proleptic Gregorian date](#calendar-date)
/// from Jan 1, 262145 BCE to Dec 31, 262143 CE.
@@ -96,35 +185,48 @@ const MAX_BITS: usize = 44;
///
/// This is currently the internal format of Chrono's date types.
#[derive(PartialEq, Eq, Hash, PartialOrd, Ord, Copy, Clone)]
+#[cfg_attr(feature = "rkyv", derive(Archive, Deserialize, Serialize))]
pub struct NaiveDate {
ymdf: DateImpl, // (year << 13) | of
}
/// The minimum possible `NaiveDate` (January 1, 262145 BCE).
-pub const MIN_DATE: NaiveDate = NaiveDate { ymdf: (MIN_YEAR << 13) | (1 << 4) | 0o07 /*FE*/ };
+#[deprecated(since = "0.4.20", note = "Use NaiveDate::MIN instead")]
+pub const MIN_DATE: NaiveDate = NaiveDate::MIN;
/// The maximum possible `NaiveDate` (December 31, 262143 CE).
-pub const MAX_DATE: NaiveDate = NaiveDate { ymdf: (MAX_YEAR << 13) | (365 << 4) | 0o17 /*F*/ };
+#[deprecated(since = "0.4.20", note = "Use NaiveDate::MAX instead")]
+pub const MAX_DATE: NaiveDate = NaiveDate::MAX;
+
+#[cfg(feature = "arbitrary")]
+impl arbitrary::Arbitrary<'_> for NaiveDate {
+ fn arbitrary(u: &mut arbitrary::Unstructured) -> arbitrary::Result<NaiveDate> {
+ let year = u.int_in_range(MIN_YEAR..=MAX_YEAR)?;
+ let max_days = YearFlags::from_year(year).ndays();
+ let ord = u.int_in_range(1..=max_days)?;
+ NaiveDate::from_yo_opt(year, ord).ok_or(arbitrary::Error::IncorrectFormat)
+ }
+}
-// as it is hard to verify year flags in `MIN_DATE` and `MAX_DATE`,
+// as it is hard to verify year flags in `NaiveDate::MIN` and `NaiveDate::MAX`,
// we use a separate run-time test.
#[test]
fn test_date_bounds() {
- let calculated_min = NaiveDate::from_ymd(MIN_YEAR, 1, 1);
- let calculated_max = NaiveDate::from_ymd(MAX_YEAR, 12, 31);
+ let calculated_min = NaiveDate::from_ymd_opt(MIN_YEAR, 1, 1).unwrap();
+ let calculated_max = NaiveDate::from_ymd_opt(MAX_YEAR, 12, 31).unwrap();
assert!(
- MIN_DATE == calculated_min,
- "`MIN_DATE` should have a year flag {:?}",
+ NaiveDate::MIN == calculated_min,
+ "`NaiveDate::MIN` should have a year flag {:?}",
calculated_min.of().flags()
);
assert!(
- MAX_DATE == calculated_max,
- "`MAX_DATE` should have a year flag {:?}",
+ NaiveDate::MAX == calculated_max,
+ "`NaiveDate::MAX` should have a year flag {:?}",
calculated_max.of().flags()
);
// let's also check that the entire range do not exceed 2^44 seconds
// (sometimes used for bounding `Duration` against overflow)
- let maxsecs = MAX_DATE.signed_duration_since(MIN_DATE).num_seconds();
+ let maxsecs = NaiveDate::MAX.signed_duration_since(NaiveDate::MIN).num_seconds();
let maxsecs = maxsecs + 86401; // also take care of DateTime
assert!(
maxsecs < (1 << MAX_BITS),
@@ -134,9 +236,12 @@ fn test_date_bounds() {
}
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 year >= MIN_YEAR && year <= MAX_YEAR && of.valid() {
+ if (MIN_YEAR..=MAX_YEAR).contains(&year) && of.valid() {
let Of(of) = of;
Some(NaiveDate { ymdf: (year << 13) | (of as DateImpl) })
} else {
@@ -153,22 +258,7 @@ impl NaiveDate {
/// (year, month and day).
///
/// Panics on the out-of-range date, invalid month and/or day.
- ///
- /// # Example
- ///
- /// ~~~~
- /// use chrono::{NaiveDate, Datelike, Weekday};
- ///
- /// let d = NaiveDate::from_ymd(2015, 3, 14);
- /// assert_eq!(d.year(), 2015);
- /// assert_eq!(d.month(), 3);
- /// assert_eq!(d.day(), 14);
- /// assert_eq!(d.ordinal(), 73); // day of year
- /// assert_eq!(d.iso_week().year(), 2015);
- /// assert_eq!(d.iso_week().week(), 11);
- /// assert_eq!(d.weekday(), Weekday::Sat);
- /// assert_eq!(d.num_days_from_ce(), 735671); // days since January 1, 1 CE
- /// ~~~~
+ #[deprecated(since = "0.4.23", note = "use `from_ymd_opt()` instead")]
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")
}
@@ -180,7 +270,7 @@ impl NaiveDate {
///
/// # Example
///
- /// ~~~~
+ /// ```
/// use chrono::NaiveDate;
///
/// let from_ymd_opt = NaiveDate::from_ymd_opt;
@@ -191,32 +281,17 @@ impl NaiveDate {
/// assert!(from_ymd_opt(-4, 2, 29).is_some()); // 5 BCE is a leap year
/// assert!(from_ymd_opt(400000, 1, 1).is_none());
/// assert!(from_ymd_opt(-400000, 1, 1).is_none());
- /// ~~~~
+ /// ```
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))
+ NaiveDate::from_mdf(year, Mdf::new(month, day, flags)?)
}
/// Makes a new `NaiveDate` from the [ordinal date](#ordinal-date)
/// (year and day of the year).
///
/// Panics on the out-of-range date and/or invalid day of year.
- ///
- /// # Example
- ///
- /// ~~~~
- /// use chrono::{NaiveDate, Datelike, Weekday};
- ///
- /// let d = NaiveDate::from_yo(2015, 73);
- /// assert_eq!(d.ordinal(), 73);
- /// assert_eq!(d.year(), 2015);
- /// assert_eq!(d.month(), 3);
- /// assert_eq!(d.day(), 14);
- /// assert_eq!(d.iso_week().year(), 2015);
- /// assert_eq!(d.iso_week().week(), 11);
- /// assert_eq!(d.weekday(), Weekday::Sat);
- /// assert_eq!(d.num_days_from_ce(), 735671); // days since January 1, 1 CE
- /// ~~~~
+ #[deprecated(since = "0.4.23", note = "use `from_yo_opt()` instead")]
pub fn from_yo(year: i32, ordinal: u32) -> NaiveDate {
NaiveDate::from_yo_opt(year, ordinal).expect("invalid or out-of-range date")
}
@@ -228,7 +303,7 @@ impl NaiveDate {
///
/// # Example
///
- /// ~~~~
+ /// ```
/// use chrono::NaiveDate;
///
/// let from_yo_opt = NaiveDate::from_yo_opt;
@@ -240,10 +315,10 @@ impl NaiveDate {
/// assert!(from_yo_opt(-4, 366).is_some()); // 5 BCE is a leap year
/// assert!(from_yo_opt(400000, 1).is_none());
/// assert!(from_yo_opt(-400000, 1).is_none());
- /// ~~~~
+ /// ```
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_of(year, Of::new(ordinal, flags)?)
}
/// Makes a new `NaiveDate` from the [ISO week date](#week-date)
@@ -251,22 +326,7 @@ impl NaiveDate {
/// The resulting `NaiveDate` may have a different year from the input year.
///
/// Panics on the out-of-range date and/or invalid week number.
- ///
- /// # Example
- ///
- /// ~~~~
- /// use chrono::{NaiveDate, Datelike, Weekday};
- ///
- /// let d = NaiveDate::from_isoywd(2015, 11, Weekday::Sat);
- /// assert_eq!(d.iso_week().year(), 2015);
- /// assert_eq!(d.iso_week().week(), 11);
- /// assert_eq!(d.weekday(), Weekday::Sat);
- /// assert_eq!(d.year(), 2015);
- /// assert_eq!(d.month(), 3);
- /// assert_eq!(d.day(), 14);
- /// assert_eq!(d.ordinal(), 73); // day of year
- /// assert_eq!(d.num_days_from_ce(), 735671); // days since January 1, 1 CE
- /// ~~~~
+ #[deprecated(since = "0.4.23", note = "use `from_isoywd_opt()` instead")]
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")
}
@@ -279,7 +339,7 @@ impl NaiveDate {
///
/// # Example
///
- /// ~~~~
+ /// ```
/// use chrono::{NaiveDate, Weekday};
///
/// let from_ymd = NaiveDate::from_ymd;
@@ -292,11 +352,11 @@ impl NaiveDate {
///
/// assert_eq!(from_isoywd_opt(400000, 10, Weekday::Fri), None);
/// assert_eq!(from_isoywd_opt(-400000, 10, Weekday::Sat), None);
- /// ~~~~
+ /// ```
///
/// The year number of ISO week date may differ from that of the calendar date.
///
- /// ~~~~
+ /// ```
/// # use chrono::{NaiveDate, Weekday};
/// # let from_ymd = NaiveDate::from_ymd;
/// # let from_isoywd_opt = NaiveDate::from_isoywd_opt;
@@ -314,7 +374,7 @@ impl NaiveDate {
/// assert_eq!(from_isoywd_opt(2015, 53, Weekday::Sun), Some(from_ymd(2016, 1, 3)));
/// 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)));
- /// ~~~~
+ /// ```
pub fn from_isoywd_opt(year: i32, week: u32, weekday: Weekday) -> Option<NaiveDate> {
let flags = YearFlags::from_year(year);
let nweeks = flags.nisoweeks();
@@ -327,18 +387,18 @@ impl NaiveDate {
let prevflags = YearFlags::from_year(year - 1);
NaiveDate::from_of(
year - 1,
- Of::new(weekord + prevflags.ndays() - delta, prevflags),
+ Of::new(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_of(year, Of::new(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_of(year + 1, Of::new(ordinal - ndays, nextflags)?)
}
}
} else {
@@ -350,45 +410,7 @@ impl NaiveDate {
/// January 1, 1 being day 1.
///
/// Panics if the date is out of range.
- ///
- /// # Example
- ///
- /// ~~~~
- /// use chrono::{NaiveDate, Datelike, Weekday};
- ///
- /// let d = NaiveDate::from_num_days_from_ce(735671);
- /// assert_eq!(d.num_days_from_ce(), 735671); // days since January 1, 1 CE
- /// assert_eq!(d.year(), 2015);
- /// assert_eq!(d.month(), 3);
- /// assert_eq!(d.day(), 14);
- /// assert_eq!(d.ordinal(), 73); // day of year
- /// assert_eq!(d.iso_week().year(), 2015);
- /// assert_eq!(d.iso_week().week(), 11);
- /// assert_eq!(d.weekday(), Weekday::Sat);
- /// ~~~~
- ///
- /// While not directly supported by Chrono,
- /// it is easy to convert from the Julian day number
- /// (January 1, 4713 BCE in the *Julian* calendar being Day 0)
- /// to Gregorian with this method.
- /// (Note that this panics when `jd` is out of range.)
- ///
- /// ~~~~
- /// use chrono::NaiveDate;
- ///
- /// fn jd_to_date(jd: i32) -> NaiveDate {
- /// // keep in mind that the Julian day number is 0-based
- /// // while this method requires an 1-based number.
- /// NaiveDate::from_num_days_from_ce(jd - 1721425)
- /// }
- ///
- /// // January 1, 4713 BCE in Julian = November 24, 4714 BCE in Gregorian
- /// assert_eq!(jd_to_date(0), NaiveDate::from_ymd(-4713, 11, 24));
- ///
- /// assert_eq!(jd_to_date(1721426), NaiveDate::from_ymd(1, 1, 1));
- /// assert_eq!(jd_to_date(2450000), NaiveDate::from_ymd(1995, 10, 9));
- /// assert_eq!(jd_to_date(2451545), NaiveDate::from_ymd(2000, 1, 1));
- /// ~~~~
+ #[deprecated(since = "0.4.23", note = "use `from_num_days_from_ce_opt()` instead")]
#[inline]
pub fn from_num_days_from_ce(days: i32) -> NaiveDate {
NaiveDate::from_num_days_from_ce_opt(days).expect("out-of-range date")
@@ -401,11 +423,11 @@ impl NaiveDate {
///
/// # Example
///
- /// ~~~~
+ /// ```
/// use chrono::NaiveDate;
///
/// let from_ndays_opt = NaiveDate::from_num_days_from_ce_opt;
- /// let from_ymd = NaiveDate::from_ymd;
+ /// let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap();
///
/// assert_eq!(from_ndays_opt(730_000), Some(from_ymd(1999, 9, 3)));
/// assert_eq!(from_ndays_opt(1), Some(from_ymd(1, 1, 1)));
@@ -413,13 +435,13 @@ impl NaiveDate {
/// assert_eq!(from_ndays_opt(-1), Some(from_ymd(0, 12, 30)));
/// assert_eq!(from_ndays_opt(100_000_000), None);
/// assert_eq!(from_ndays_opt(-100_000_000), None);
- /// ~~~~
+ /// ```
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 (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_of(year_div_400 * 400 + year_mod_400 as i32, Of::new(ordinal, flags)?)
}
/// Makes a new `NaiveDate` by counting the number of occurrences of a particular day-of-week
@@ -432,21 +454,7 @@ impl NaiveDate {
/// of `weekday` in `month` (eg. the 6th Friday of March 2017) then this function will panic.
///
/// `n` is 1-indexed. Passing `n=0` will cause a panic.
- ///
- /// # Example
- ///
- /// ~~~~
- /// use chrono::{NaiveDate, Weekday};
- ///
- /// let from_weekday_of_month = NaiveDate::from_weekday_of_month;
- /// let from_ymd = NaiveDate::from_ymd;
- ///
- /// assert_eq!(from_weekday_of_month(2018, 8, Weekday::Wed, 1), from_ymd(2018, 8, 1));
- /// assert_eq!(from_weekday_of_month(2018, 8, Weekday::Fri, 1), from_ymd(2018, 8, 3));
- /// assert_eq!(from_weekday_of_month(2018, 8, Weekday::Tue, 2), from_ymd(2018, 8, 14));
- /// assert_eq!(from_weekday_of_month(2018, 8, Weekday::Fri, 4), from_ymd(2018, 8, 24));
- /// assert_eq!(from_weekday_of_month(2018, 8, Weekday::Fri, 5), from_ymd(2018, 8, 31));
- /// ~~~~
+ #[deprecated(since = "0.4.23", note = "use `from_weekday_of_month_opt()` instead")]
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")
}
@@ -455,11 +463,11 @@ impl NaiveDate {
/// since the beginning of the given month. For instance, if you want the 2nd Friday of March
/// 2017, you would use `NaiveDate::from_weekday_of_month(2017, 3, Weekday::Fri, 2)`. `n` is 1-indexed.
///
- /// ~~~~
+ /// ```
/// use chrono::{NaiveDate, Weekday};
/// assert_eq!(NaiveDate::from_weekday_of_month_opt(2017, 3, Weekday::Fri, 2),
/// NaiveDate::from_ymd_opt(2017, 3, 10))
- /// ~~~~
+ /// ```
///
/// 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`.
@@ -472,7 +480,7 @@ impl NaiveDate {
if n == 0 {
return None;
}
- let first = NaiveDate::from_ymd(year, month, 1).weekday();
+ let first = NaiveDate::from_ymd_opt(year, month, 1)?.weekday();
let first_to_dow = (7 + weekday.number_from_monday() - first.number_from_monday()) % 7;
let day = (u32::from(n) - 1) * 7 + first_to_dow + 1;
NaiveDate::from_ymd_opt(year, month, day)
@@ -484,64 +492,223 @@ impl NaiveDate {
///
/// # Example
///
- /// ~~~~
+ /// ```
/// use chrono::NaiveDate;
///
/// let parse_from_str = NaiveDate::parse_from_str;
///
/// assert_eq!(parse_from_str("2015-09-05", "%Y-%m-%d"),
- /// Ok(NaiveDate::from_ymd(2015, 9, 5)));
+ /// Ok(NaiveDate::from_ymd_opt(2015, 9, 5).unwrap()));
/// assert_eq!(parse_from_str("5sep2015", "%d%b%Y"),
- /// Ok(NaiveDate::from_ymd(2015, 9, 5)));
- /// ~~~~
+ /// Ok(NaiveDate::from_ymd_opt(2015, 9, 5).unwrap()));
+ /// ```
///
/// Time and offset is ignored for the purpose of parsing.
///
- /// ~~~~
+ /// ```
/// # use chrono::NaiveDate;
/// # let parse_from_str = NaiveDate::parse_from_str;
/// assert_eq!(parse_from_str("2014-5-17T12:34:56+09:30", "%Y-%m-%dT%H:%M:%S%z"),
- /// Ok(NaiveDate::from_ymd(2014, 5, 17)));
- /// ~~~~
+ /// Ok(NaiveDate::from_ymd_opt(2014, 5, 17).unwrap()));
+ /// ```
///
/// Out-of-bound dates or insufficient fields are errors.
///
- /// ~~~~
+ /// ```
/// # use chrono::NaiveDate;
/// # let parse_from_str = NaiveDate::parse_from_str;
/// assert!(parse_from_str("2015/9", "%Y/%m").is_err());
/// assert!(parse_from_str("2015/9/31", "%Y/%m/%d").is_err());
- /// ~~~~
+ /// ```
///
/// All parsed fields should be consistent to each other, otherwise it's an error.
///
- /// ~~~~
+ /// ```
/// # use chrono::NaiveDate;
/// # let parse_from_str = NaiveDate::parse_from_str;
/// assert!(parse_from_str("Sat, 09 Aug 2013", "%a, %d %b %Y").is_err());
- /// ~~~~
+ /// ```
pub fn parse_from_str(s: &str, fmt: &str) -> ParseResult<NaiveDate> {
let mut parsed = Parsed::new();
parse(&mut parsed, s, StrftimeItems::new(fmt))?;
parsed.to_naive_date()
}
+ /// 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.
+ ///
+ /// Returns `None` if the resulting date would be out of range.
+ ///
+ /// ```
+ /// # use chrono::{NaiveDate, Months};
+ /// assert_eq!(
+ /// NaiveDate::from_ymd_opt(2022, 2, 20).unwrap().checked_add_months(Months::new(6)),
+ /// Some(NaiveDate::from_ymd_opt(2022, 8, 20).unwrap())
+ /// );
+ /// assert_eq!(
+ /// NaiveDate::from_ymd_opt(2022, 7, 31).unwrap().checked_add_months(Months::new(2)),
+ /// Some(NaiveDate::from_ymd_opt(2022, 9, 30).unwrap())
+ /// );
+ /// ```
+ pub fn checked_add_months(self, months: Months) -> Option<Self> {
+ if months.0 == 0 {
+ return Some(self);
+ }
+
+ match months.0 <= core::i32::MAX as u32 {
+ true => self.diff_months(months.0 as i32),
+ false => None,
+ }
+ }
+
+ /// Subtract a duration in [`Months`] from the date
+ ///
+ /// If the day would be out of range for the resulting month, use the last day for that month.
+ ///
+ /// Returns `None` if the resulting date would be out of range.
+ ///
+ /// ```
+ /// # use chrono::{NaiveDate, Months};
+ /// assert_eq!(
+ /// NaiveDate::from_ymd_opt(2022, 2, 20).unwrap().checked_sub_months(Months::new(6)),
+ /// Some(NaiveDate::from_ymd_opt(2021, 8, 20).unwrap())
+ /// );
+ ///
+ /// assert_eq!(
+ /// NaiveDate::from_ymd_opt(2014, 1, 1).unwrap()
+ /// .checked_sub_months(Months::new(core::i32::MAX as u32 + 1)),
+ /// None
+ /// );
+ /// ```
+ pub fn checked_sub_months(self, months: Months) -> Option<Self> {
+ if months.0 == 0 {
+ return Some(self);
+ }
+
+ // Copy `i32::MAX` here so we don't have to do a complicated cast
+ match months.0 <= 2_147_483_647 {
+ true => self.diff_months(-(months.0 as i32)),
+ false => None,
+ }
+ }
+
+ fn diff_months(self, months: i32) -> Option<Self> {
+ let (years, left) = ((months / 12), (months % 12));
+
+ // Determine new year (without taking months into account for now
+
+ let year = if (years > 0 && years > (MAX_YEAR - self.year()))
+ || (years < 0 && years < (MIN_YEAR - self.year()))
+ {
+ return None;
+ } else {
+ self.year() + years
+ };
+
+ // Determine new month
+
+ let month = self.month() as i32 + left;
+ let (year, month) = if month <= 0 {
+ if year == MIN_YEAR {
+ return None;
+ }
+
+ (year - 1, month + 12)
+ } else if month > 12 {
+ if year == MAX_YEAR {
+ return None;
+ }
+
+ (year + 1, month - 12)
+ } else {
+ (year, month)
+ };
+
+ // Clamp original day in case new month is shorter
+
+ let flags = YearFlags::from_year(year);
+ let feb_days = if flags.ndays() == 366 { 29 } else { 28 };
+ let days = [31, feb_days, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
+ let day = Ord::min(self.day(), days[(month - 1) as usize]);
+
+ NaiveDate::from_mdf(year, Mdf::new(month as u32, day, flags)?)
+ }
+
+ /// Add a duration in [`Days`] to the date
+ ///
+ /// Returns `None` if the resulting date would be out of range.
+ ///
+ /// ```
+ /// # use chrono::{NaiveDate, Days};
+ /// assert_eq!(
+ /// NaiveDate::from_ymd_opt(2022, 2, 20).unwrap().checked_add_days(Days::new(9)),
+ /// Some(NaiveDate::from_ymd_opt(2022, 3, 1).unwrap())
+ /// );
+ /// assert_eq!(
+ /// NaiveDate::from_ymd_opt(2022, 7, 31).unwrap().checked_add_days(Days::new(2)),
+ /// Some(NaiveDate::from_ymd_opt(2022, 8, 2).unwrap())
+ /// );
+ /// assert_eq!(
+ /// NaiveDate::from_ymd_opt(2022, 7, 31).unwrap().checked_add_days(Days::new(1000000000000)),
+ /// None
+ /// );
+ /// ```
+ pub fn checked_add_days(self, days: Days) -> Option<Self> {
+ if days.0 == 0 {
+ return Some(self);
+ }
+
+ i64::try_from(days.0).ok().and_then(|d| self.diff_days(d))
+ }
+
+ /// Subtract a duration in [`Days`] from the date
+ ///
+ /// Returns `None` if the resulting date would be out of range.
+ ///
+ /// ```
+ /// # use chrono::{NaiveDate, Days};
+ /// assert_eq!(
+ /// NaiveDate::from_ymd_opt(2022, 2, 20).unwrap().checked_sub_days(Days::new(6)),
+ /// Some(NaiveDate::from_ymd_opt(2022, 2, 14).unwrap())
+ /// );
+ /// assert_eq!(
+ /// NaiveDate::from_ymd_opt(2022, 2, 20).unwrap().checked_sub_days(Days::new(1000000000000)),
+ /// None
+ /// );
+ /// ```
+ pub fn checked_sub_days(self, days: Days) -> Option<Self> {
+ if days.0 == 0 {
+ return Some(self);
+ }
+
+ i64::try_from(days.0).ok().and_then(|d| self.diff_days(-d))
+ }
+
+ fn diff_days(self, days: i64) -> Option<Self> {
+ let secs = days.checked_mul(86400)?; // 86400 seconds in one day
+ if secs >= core::i64::MAX / 1000 || secs <= core::i64::MIN / 1000 {
+ return None; // See the `time` 0.1 crate. Outside these bounds, `Duration::seconds` will panic
+ }
+ self.checked_add_signed(Duration::seconds(secs))
+ }
+
/// Makes a new `NaiveDateTime` from the current date and given `NaiveTime`.
///
/// # Example
///
- /// ~~~~
+ /// ```
/// use chrono::{NaiveDate, NaiveTime, NaiveDateTime};
///
- /// let d = NaiveDate::from_ymd(2015, 6, 3);
- /// let t = NaiveTime::from_hms_milli(12, 34, 56, 789);
+ /// let d = NaiveDate::from_ymd_opt(2015, 6, 3).unwrap();
+ /// let t = NaiveTime::from_hms_milli_opt(12, 34, 56, 789).unwrap();
///
/// let dt: NaiveDateTime = d.and_time(t);
/// assert_eq!(dt.date(), d);
/// assert_eq!(dt.time(), t);
- /// ~~~~
+ /// ```
#[inline]
- pub fn and_time(&self, time: NaiveTime) -> NaiveDateTime {
+ pub const fn and_time(&self, time: NaiveTime) -> NaiveDateTime {
NaiveDateTime::new(*self, time)
}
@@ -551,19 +718,7 @@ impl NaiveDate {
/// use `NaiveDate::and_hms_*` methods with a subsecond parameter instead.
///
/// Panics on invalid hour, minute and/or second.
- ///
- /// # Example
- ///
- /// ~~~~
- /// use chrono::{NaiveDate, NaiveDateTime, Datelike, Timelike, Weekday};
- ///
- /// let d = NaiveDate::from_ymd(2015, 6, 3);
- ///
- /// let dt: NaiveDateTime = d.and_hms(12, 34, 56);
- /// assert_eq!(dt.year(), 2015);
- /// assert_eq!(dt.weekday(), Weekday::Wed);
- /// assert_eq!(dt.second(), 56);
- /// ~~~~
+ #[deprecated(since = "0.4.23", note = "use `and_hms_opt()` instead")]
#[inline]
pub fn and_hms(&self, hour: u32, min: u32, sec: u32) -> NaiveDateTime {
self.and_hms_opt(hour, min, sec).expect("invalid time")
@@ -578,15 +733,15 @@ impl NaiveDate {
///
/// # Example
///
- /// ~~~~
+ /// ```
/// use chrono::NaiveDate;
///
- /// let d = NaiveDate::from_ymd(2015, 6, 3);
+ /// let d = NaiveDate::from_ymd_opt(2015, 6, 3).unwrap();
/// assert!(d.and_hms_opt(12, 34, 56).is_some());
/// assert!(d.and_hms_opt(12, 34, 60).is_none()); // use `and_hms_milli_opt` instead
/// assert!(d.and_hms_opt(12, 60, 56).is_none());
/// assert!(d.and_hms_opt(24, 34, 56).is_none());
- /// ~~~~
+ /// ```
#[inline]
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))
@@ -598,20 +753,7 @@ impl NaiveDate {
/// in order to represent the [leap second](./struct.NaiveTime.html#leap-second-handling).
///
/// Panics on invalid hour, minute, second and/or millisecond.
- ///
- /// # Example
- ///
- /// ~~~~
- /// use chrono::{NaiveDate, NaiveDateTime, Datelike, Timelike, Weekday};
- ///
- /// let d = NaiveDate::from_ymd(2015, 6, 3);
- ///
- /// let dt: NaiveDateTime = d.and_hms_milli(12, 34, 56, 789);
- /// assert_eq!(dt.year(), 2015);
- /// assert_eq!(dt.weekday(), Weekday::Wed);
- /// assert_eq!(dt.second(), 56);
- /// assert_eq!(dt.nanosecond(), 789_000_000);
- /// ~~~~
+ #[deprecated(since = "0.4.23", note = "use `and_hms_milli_opt()` instead")]
#[inline]
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")
@@ -626,17 +768,17 @@ impl NaiveDate {
///
/// # Example
///
- /// ~~~~
+ /// ```
/// use chrono::NaiveDate;
///
- /// let d = NaiveDate::from_ymd(2015, 6, 3);
+ /// let d = NaiveDate::from_ymd_opt(2015, 6, 3).unwrap();
/// assert!(d.and_hms_milli_opt(12, 34, 56, 789).is_some());
/// assert!(d.and_hms_milli_opt(12, 34, 59, 1_789).is_some()); // leap second
/// assert!(d.and_hms_milli_opt(12, 34, 59, 2_789).is_none());
/// assert!(d.and_hms_milli_opt(12, 34, 60, 789).is_none());
/// assert!(d.and_hms_milli_opt(12, 60, 56, 789).is_none());
/// assert!(d.and_hms_milli_opt(24, 34, 56, 789).is_none());
- /// ~~~~
+ /// ```
#[inline]
pub fn and_hms_milli_opt(
&self,
@@ -657,17 +799,18 @@ impl NaiveDate {
///
/// # Example
///
- /// ~~~~
+ /// ```
/// use chrono::{NaiveDate, NaiveDateTime, Datelike, Timelike, Weekday};
///
- /// let d = NaiveDate::from_ymd(2015, 6, 3);
+ /// let d = NaiveDate::from_ymd_opt(2015, 6, 3).unwrap();
///
/// let dt: NaiveDateTime = d.and_hms_micro(12, 34, 56, 789_012);
/// assert_eq!(dt.year(), 2015);
/// assert_eq!(dt.weekday(), Weekday::Wed);
/// assert_eq!(dt.second(), 56);
/// assert_eq!(dt.nanosecond(), 789_012_000);
- /// ~~~~
+ /// ```
+ #[deprecated(since = "0.4.23", note = "use `and_hms_micro_opt()` instead")]
#[inline]
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")
@@ -682,17 +825,17 @@ impl NaiveDate {
///
/// # Example
///
- /// ~~~~
+ /// ```
/// use chrono::NaiveDate;
///
- /// let d = NaiveDate::from_ymd(2015, 6, 3);
+ /// let d = NaiveDate::from_ymd_opt(2015, 6, 3).unwrap();
/// assert!(d.and_hms_micro_opt(12, 34, 56, 789_012).is_some());
/// assert!(d.and_hms_micro_opt(12, 34, 59, 1_789_012).is_some()); // leap second
/// assert!(d.and_hms_micro_opt(12, 34, 59, 2_789_012).is_none());
/// assert!(d.and_hms_micro_opt(12, 34, 60, 789_012).is_none());
/// assert!(d.and_hms_micro_opt(12, 60, 56, 789_012).is_none());
/// assert!(d.and_hms_micro_opt(24, 34, 56, 789_012).is_none());
- /// ~~~~
+ /// ```
#[inline]
pub fn and_hms_micro_opt(
&self,
@@ -710,20 +853,7 @@ impl NaiveDate {
/// in order to represent the [leap second](./struct.NaiveTime.html#leap-second-handling).
///
/// Panics on invalid hour, minute, second and/or nanosecond.
- ///
- /// # Example
- ///
- /// ~~~~
- /// use chrono::{NaiveDate, NaiveDateTime, Datelike, Timelike, Weekday};
- ///
- /// let d = NaiveDate::from_ymd(2015, 6, 3);
- ///
- /// let dt: NaiveDateTime = d.and_hms_nano(12, 34, 56, 789_012_345);
- /// assert_eq!(dt.year(), 2015);
- /// assert_eq!(dt.weekday(), Weekday::Wed);
- /// assert_eq!(dt.second(), 56);
- /// assert_eq!(dt.nanosecond(), 789_012_345);
- /// ~~~~
+ #[deprecated(since = "0.4.23", note = "use `and_hms_nano_opt()` instead")]
#[inline]
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")
@@ -738,17 +868,17 @@ impl NaiveDate {
///
/// # Example
///
- /// ~~~~
+ /// ```
/// use chrono::NaiveDate;
///
- /// let d = NaiveDate::from_ymd(2015, 6, 3);
+ /// let d = NaiveDate::from_ymd_opt(2015, 6, 3).unwrap();
/// assert!(d.and_hms_nano_opt(12, 34, 56, 789_012_345).is_some());
/// assert!(d.and_hms_nano_opt(12, 34, 59, 1_789_012_345).is_some()); // leap second
/// assert!(d.and_hms_nano_opt(12, 34, 59, 2_789_012_345).is_none());
/// assert!(d.and_hms_nano_opt(12, 34, 60, 789_012_345).is_none());
/// assert!(d.and_hms_nano_opt(12, 60, 56, 789_012_345).is_none());
/// assert!(d.and_hms_nano_opt(24, 34, 56, 789_012_345).is_none());
- /// ~~~~
+ /// ```
#[inline]
pub fn and_hms_nano_opt(
&self,
@@ -768,7 +898,7 @@ impl NaiveDate {
/// Returns the packed ordinal-flags.
#[inline]
- fn of(&self) -> Of {
+ const fn of(&self) -> Of {
Of((self.ymdf & 0b1_1111_1111_1111) as u32)
}
@@ -796,16 +926,7 @@ impl NaiveDate {
/// Makes a new `NaiveDate` for the next calendar date.
///
/// Panics when `self` is the last representable date.
- ///
- /// # Example
- ///
- /// ~~~~
- /// use chrono::NaiveDate;
- ///
- /// assert_eq!(NaiveDate::from_ymd(2015, 6, 3).succ(), NaiveDate::from_ymd(2015, 6, 4));
- /// assert_eq!(NaiveDate::from_ymd(2015, 6, 30).succ(), NaiveDate::from_ymd(2015, 7, 1));
- /// assert_eq!(NaiveDate::from_ymd(2015, 12, 31).succ(), NaiveDate::from_ymd(2016, 1, 1));
- /// ~~~~
+ #[deprecated(since = "0.4.23", note = "use `succ_opt()` instead")]
#[inline]
pub fn succ(&self) -> NaiveDate {
self.succ_opt().expect("out of bound")
@@ -817,14 +938,13 @@ impl NaiveDate {
///
/// # Example
///
- /// ~~~~
+ /// ```
/// use chrono::NaiveDate;
- /// use chrono::naive::MAX_DATE;
///
- /// assert_eq!(NaiveDate::from_ymd(2015, 6, 3).succ_opt(),
- /// Some(NaiveDate::from_ymd(2015, 6, 4)));
- /// assert_eq!(MAX_DATE.succ_opt(), None);
- /// ~~~~
+ /// assert_eq!(NaiveDate::from_ymd_opt(2015, 6, 3).unwrap().succ_opt(),
+ /// Some(NaiveDate::from_ymd_opt(2015, 6, 4).unwrap()));
+ /// assert_eq!(NaiveDate::MAX.succ_opt(), None);
+ /// ```
#[inline]
pub fn succ_opt(&self) -> Option<NaiveDate> {
self.with_of(self.of().succ()).or_else(|| NaiveDate::from_ymd_opt(self.year() + 1, 1, 1))
@@ -833,16 +953,7 @@ impl NaiveDate {
/// Makes a new `NaiveDate` for the previous calendar date.
///
/// Panics when `self` is the first representable date.
- ///
- /// # Example
- ///
- /// ~~~~
- /// use chrono::NaiveDate;
- ///
- /// assert_eq!(NaiveDate::from_ymd(2015, 6, 3).pred(), NaiveDate::from_ymd(2015, 6, 2));
- /// assert_eq!(NaiveDate::from_ymd(2015, 6, 1).pred(), NaiveDate::from_ymd(2015, 5, 31));
- /// assert_eq!(NaiveDate::from_ymd(2015, 1, 1).pred(), NaiveDate::from_ymd(2014, 12, 31));
- /// ~~~~
+ #[deprecated(since = "0.4.23", note = "use `pred_opt()` instead")]
#[inline]
pub fn pred(&self) -> NaiveDate {
self.pred_opt().expect("out of bound")
@@ -854,14 +965,13 @@ impl NaiveDate {
///
/// # Example
///
- /// ~~~~
+ /// ```
/// use chrono::NaiveDate;
- /// use chrono::naive::MIN_DATE;
///
- /// assert_eq!(NaiveDate::from_ymd(2015, 6, 3).pred_opt(),
- /// Some(NaiveDate::from_ymd(2015, 6, 2)));
- /// assert_eq!(MIN_DATE.pred_opt(), None);
- /// ~~~~
+ /// assert_eq!(NaiveDate::from_ymd_opt(2015, 6, 3).unwrap().pred_opt(),
+ /// Some(NaiveDate::from_ymd_opt(2015, 6, 2).unwrap()));
+ /// assert_eq!(NaiveDate::MIN.pred_opt(), None);
+ /// ```
#[inline]
pub fn pred_opt(&self) -> Option<NaiveDate> {
self.with_of(self.of().pred()).or_else(|| NaiveDate::from_ymd_opt(self.year() - 1, 12, 31))
@@ -873,32 +983,29 @@ impl NaiveDate {
///
/// # Example
///
- /// ~~~~
- /// # extern crate chrono; fn main() {
+ /// ```
/// use chrono::{Duration, NaiveDate};
- /// use chrono::naive::MAX_DATE;
///
- /// let d = NaiveDate::from_ymd(2015, 9, 5);
+ /// let d = NaiveDate::from_ymd_opt(2015, 9, 5).unwrap();
/// assert_eq!(d.checked_add_signed(Duration::days(40)),
- /// Some(NaiveDate::from_ymd(2015, 10, 15)));
+ /// Some(NaiveDate::from_ymd_opt(2015, 10, 15).unwrap()));
/// assert_eq!(d.checked_add_signed(Duration::days(-40)),
- /// Some(NaiveDate::from_ymd(2015, 7, 27)));
+ /// Some(NaiveDate::from_ymd_opt(2015, 7, 27).unwrap()));
/// assert_eq!(d.checked_add_signed(Duration::days(1_000_000_000)), None);
/// assert_eq!(d.checked_add_signed(Duration::days(-1_000_000_000)), None);
- /// assert_eq!(MAX_DATE.checked_add_signed(Duration::days(1)), None);
- /// # }
- /// ~~~~
+ /// assert_eq!(NaiveDate::MAX.checked_add_signed(Duration::days(1)), None);
+ /// ```
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 = try_opt!((cycle as i32).checked_add(try_opt!(rhs.num_days().to_i32())));
+ let cycle = (cycle as i32).checked_add(rhs.num_days().to_i32()?)?;
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_of(year_div_400 * 400 + year_mod_400 as i32, Of::new(ordinal, flags)?)
}
/// Subtracts the `days` part of given `Duration` from the current date.
@@ -907,32 +1014,29 @@ impl NaiveDate {
///
/// # Example
///
- /// ~~~~
- /// # extern crate chrono; fn main() {
+ /// ```
/// use chrono::{Duration, NaiveDate};
- /// use chrono::naive::MIN_DATE;
///
- /// let d = NaiveDate::from_ymd(2015, 9, 5);
+ /// let d = NaiveDate::from_ymd_opt(2015, 9, 5).unwrap();
/// assert_eq!(d.checked_sub_signed(Duration::days(40)),
- /// Some(NaiveDate::from_ymd(2015, 7, 27)));
+ /// Some(NaiveDate::from_ymd_opt(2015, 7, 27).unwrap()));
/// assert_eq!(d.checked_sub_signed(Duration::days(-40)),
- /// Some(NaiveDate::from_ymd(2015, 10, 15)));
+ /// Some(NaiveDate::from_ymd_opt(2015, 10, 15).unwrap()));
/// assert_eq!(d.checked_sub_signed(Duration::days(1_000_000_000)), None);
/// assert_eq!(d.checked_sub_signed(Duration::days(-1_000_000_000)), None);
- /// assert_eq!(MIN_DATE.checked_sub_signed(Duration::days(1)), None);
- /// # }
- /// ~~~~
+ /// assert_eq!(NaiveDate::MIN.checked_sub_signed(Duration::days(1)), None);
+ /// ```
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 = try_opt!((cycle as i32).checked_sub(try_opt!(rhs.num_days().to_i32())));
+ let cycle = (cycle as i32).checked_sub(rhs.num_days().to_i32()?)?;
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_of(year_div_400 * 400 + year_mod_400 as i32, Of::new(ordinal, flags)?)
}
/// Subtracts another `NaiveDate` from the current date.
@@ -943,8 +1047,7 @@ impl NaiveDate {
///
/// # Example
///
- /// ~~~~
- /// # extern crate chrono; fn main() {
+ /// ```
/// use chrono::{Duration, NaiveDate};
///
/// let from_ymd = NaiveDate::from_ymd;
@@ -957,8 +1060,7 @@ impl NaiveDate {
/// assert_eq!(since(from_ymd(2014, 1, 1), from_ymd(2013, 1, 1)), Duration::days(365));
/// 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));
- /// # }
- /// ~~~~
+ /// ```
pub fn signed_duration_since(self, rhs: NaiveDate) -> OldDuration {
let year1 = self.year();
let year2 = rhs.year();
@@ -971,6 +1073,19 @@ impl NaiveDate {
)
}
+ /// Returns the number of whole years from the given `base` until `self`.
+ 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()) {
+ years -= 1;
+ }
+
+ match years >= 0 {
+ true => Some(years as u32),
+ false => None,
+ }
+ }
+
/// Formats the date with the specified formatting items.
/// Otherwise it is the same as the ordinary `format` method.
///
@@ -979,26 +1094,27 @@ impl NaiveDate {
///
/// # Example
///
- /// ~~~~
+ /// ```
/// use chrono::NaiveDate;
/// use chrono::format::strftime::StrftimeItems;
///
/// let fmt = StrftimeItems::new("%Y-%m-%d");
- /// let d = NaiveDate::from_ymd(2015, 9, 5);
+ /// let d = NaiveDate::from_ymd_opt(2015, 9, 5).unwrap();
/// assert_eq!(d.format_with_items(fmt.clone()).to_string(), "2015-09-05");
/// assert_eq!(d.format("%Y-%m-%d").to_string(), "2015-09-05");
- /// ~~~~
+ /// ```
///
/// The resulting `DelayedFormat` can be formatted directly via the `Display` trait.
///
- /// ~~~~
+ /// ```
/// # use chrono::NaiveDate;
/// # use chrono::format::strftime::StrftimeItems;
/// # let fmt = StrftimeItems::new("%Y-%m-%d").clone();
- /// # let d = NaiveDate::from_ymd(2015, 9, 5);
+ /// # let d = NaiveDate::from_ymd_opt(2015, 9, 5).unwrap();
/// assert_eq!(format!("{}", d.format_with_items(fmt)), "2015-09-05");
- /// ~~~~
+ /// ```
#[cfg(any(feature = "alloc", feature = "std", test))]
+ #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))]
#[inline]
pub fn format_with_items<'a, I, B>(&self, items: I) -> DelayedFormat<I>
where
@@ -1024,29 +1140,61 @@ impl NaiveDate {
///
/// # Example
///
- /// ~~~~
+ /// ```
/// use chrono::NaiveDate;
///
- /// let d = NaiveDate::from_ymd(2015, 9, 5);
+ /// let d = NaiveDate::from_ymd_opt(2015, 9, 5).unwrap();
/// assert_eq!(d.format("%Y-%m-%d").to_string(), "2015-09-05");
/// assert_eq!(d.format("%A, %-d %B, %C%y").to_string(), "Saturday, 5 September, 2015");
- /// ~~~~
+ /// ```
///
/// The resulting `DelayedFormat` can be formatted directly via the `Display` trait.
///
- /// ~~~~
+ /// ```
/// # use chrono::NaiveDate;
- /// # let d = NaiveDate::from_ymd(2015, 9, 5);
+ /// # let d = NaiveDate::from_ymd_opt(2015, 9, 5).unwrap();
/// assert_eq!(format!("{}", d.format("%Y-%m-%d")), "2015-09-05");
/// assert_eq!(format!("{}", d.format("%A, %-d %B, %C%y")), "Saturday, 5 September, 2015");
- /// ~~~~
+ /// ```
#[cfg(any(feature = "alloc", feature = "std", test))]
+ #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))]
#[inline]
pub fn format<'a>(&self, fmt: &'a str) -> DelayedFormat<StrftimeItems<'a>> {
self.format_with_items(StrftimeItems::new(fmt))
}
- /// Returns an iterator that steps by days until the last representable date.
+ /// Formats the date with the specified formatting items and locale.
+ #[cfg(feature = "unstable-locales")]
+ #[cfg_attr(docsrs, doc(cfg(feature = "unstable-locales")))]
+ #[inline]
+ pub fn format_localized_with_items<'a, I, B>(
+ &self,
+ items: I,
+ locale: Locale,
+ ) -> DelayedFormat<I>
+ where
+ I: Iterator<Item = B> + Clone,
+ B: Borrow<Item<'a>>,
+ {
+ DelayedFormat::new_with_locale(Some(*self), None, items, locale)
+ }
+
+ /// Formats the date with the specified format string and locale.
+ ///
+ /// See the [`crate::format::strftime`] module on the supported escape
+ /// sequences.
+ #[cfg(feature = "unstable-locales")]
+ #[cfg_attr(docsrs, doc(cfg(feature = "unstable-locales")))]
+ #[inline]
+ pub fn format_localized<'a>(
+ &self,
+ fmt: &'a str,
+ locale: Locale,
+ ) -> DelayedFormat<StrftimeItems<'a>> {
+ self.format_localized_with_items(StrftimeItems::new_with_locale(fmt, locale), locale)
+ }
+
+ /// Returns an iterator that steps by days across all representable dates.
///
/// # Example
///
@@ -1054,25 +1202,30 @@ impl NaiveDate {
/// # use chrono::NaiveDate;
///
/// let expected = [
- /// NaiveDate::from_ymd(2016, 2, 27),
- /// NaiveDate::from_ymd(2016, 2, 28),
- /// NaiveDate::from_ymd(2016, 2, 29),
- /// NaiveDate::from_ymd(2016, 3, 1),
+ /// NaiveDate::from_ymd_opt(2016, 2, 27).unwrap(),
+ /// NaiveDate::from_ymd_opt(2016, 2, 28).unwrap(),
+ /// NaiveDate::from_ymd_opt(2016, 2, 29).unwrap(),
+ /// NaiveDate::from_ymd_opt(2016, 3, 1).unwrap(),
/// ];
///
/// let mut count = 0;
- /// for (idx, d) in NaiveDate::from_ymd(2016, 2, 27).iter_days().take(4).enumerate() {
+ /// for (idx, d) in NaiveDate::from_ymd_opt(2016, 2, 27).unwrap().iter_days().take(4).enumerate() {
/// assert_eq!(d, expected[idx]);
/// count += 1;
/// }
/// assert_eq!(count, 4);
+ ///
+ /// for d in NaiveDate::from_ymd_opt(2016, 3, 1).unwrap().iter_days().rev().take(4) {
+ /// count -= 1;
+ /// assert_eq!(d, expected[count]);
+ /// }
/// ```
#[inline]
- pub fn iter_days(&self) -> NaiveDateDaysIterator {
+ pub const fn iter_days(&self) -> NaiveDateDaysIterator {
NaiveDateDaysIterator { value: *self }
}
- /// Returns an iterator that steps by weeks until the last representable date.
+ /// Returns an iterator that steps by weeks across all representable dates.
///
/// # Example
///
@@ -1080,23 +1233,40 @@ impl NaiveDate {
/// # use chrono::NaiveDate;
///
/// let expected = [
- /// NaiveDate::from_ymd(2016, 2, 27),
- /// NaiveDate::from_ymd(2016, 3, 5),
- /// NaiveDate::from_ymd(2016, 3, 12),
- /// NaiveDate::from_ymd(2016, 3, 19),
+ /// NaiveDate::from_ymd_opt(2016, 2, 27).unwrap(),
+ /// NaiveDate::from_ymd_opt(2016, 3, 5).unwrap(),
+ /// NaiveDate::from_ymd_opt(2016, 3, 12).unwrap(),
+ /// NaiveDate::from_ymd_opt(2016, 3, 19).unwrap(),
/// ];
///
/// let mut count = 0;
- /// for (idx, d) in NaiveDate::from_ymd(2016, 2, 27).iter_weeks().take(4).enumerate() {
+ /// for (idx, d) in NaiveDate::from_ymd_opt(2016, 2, 27).unwrap().iter_weeks().take(4).enumerate() {
/// assert_eq!(d, expected[idx]);
/// count += 1;
/// }
/// assert_eq!(count, 4);
+ ///
+ /// for d in NaiveDate::from_ymd_opt(2016, 3, 19).unwrap().iter_weeks().rev().take(4) {
+ /// count -= 1;
+ /// assert_eq!(d, expected[count]);
+ /// }
/// ```
#[inline]
- pub fn iter_weeks(&self) -> NaiveDateWeeksIterator {
+ pub const fn iter_weeks(&self) -> NaiveDateWeeksIterator {
NaiveDateWeeksIterator { value: *self }
}
+
+ /// Returns the [`NaiveWeek`] that the date belongs to, starting with the [`Weekday`]
+ /// specified.
+ #[inline]
+ pub const fn week(&self, start: Weekday) -> NaiveWeek {
+ NaiveWeek { date: *self, start }
+ }
+
+ /// The minimum possible `NaiveDate` (January 1, 262145 BCE).
+ pub const MIN: NaiveDate = NaiveDate { ymdf: (MIN_YEAR << 13) | (1 << 4) | 0o07 /*FE*/ };
+ /// The maximum possible `NaiveDate` (December 31, 262143 CE).
+ pub const MAX: NaiveDate = NaiveDate { ymdf: (MAX_YEAR << 13) | (365 << 4) | 0o17 /*F*/ };
}
impl Datelike for NaiveDate {
@@ -1104,12 +1274,12 @@ impl Datelike for NaiveDate {
///
/// # Example
///
- /// ~~~~
+ /// ```
/// use chrono::{NaiveDate, Datelike};
///
- /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).year(), 2015);
- /// assert_eq!(NaiveDate::from_ymd(-308, 3, 14).year(), -308); // 309 BCE
- /// ~~~~
+ /// assert_eq!(NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().year(), 2015);
+ /// assert_eq!(NaiveDate::from_ymd_opt(-308, 3, 14).unwrap().year(), -308); // 309 BCE
+ /// ```
#[inline]
fn year(&self) -> i32 {
self.ymdf >> 13
@@ -1121,12 +1291,12 @@ impl Datelike for NaiveDate {
///
/// # Example
///
- /// ~~~~
+ /// ```
/// use chrono::{NaiveDate, Datelike};
///
- /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).month(), 9);
- /// assert_eq!(NaiveDate::from_ymd(-308, 3, 14).month(), 3);
- /// ~~~~
+ /// assert_eq!(NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().month(), 9);
+ /// assert_eq!(NaiveDate::from_ymd_opt(-308, 3, 14).unwrap().month(), 3);
+ /// ```
#[inline]
fn month(&self) -> u32 {
self.mdf().month()
@@ -1138,12 +1308,12 @@ impl Datelike for NaiveDate {
///
/// # Example
///
- /// ~~~~
+ /// ```
/// use chrono::{NaiveDate, Datelike};
///
- /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).month0(), 8);
- /// assert_eq!(NaiveDate::from_ymd(-308, 3, 14).month0(), 2);
- /// ~~~~
+ /// assert_eq!(NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().month0(), 8);
+ /// assert_eq!(NaiveDate::from_ymd_opt(-308, 3, 14).unwrap().month0(), 2);
+ /// ```
#[inline]
fn month0(&self) -> u32 {
self.mdf().month() - 1
@@ -1155,24 +1325,24 @@ impl Datelike for NaiveDate {
///
/// # Example
///
- /// ~~~~
+ /// ```
/// use chrono::{NaiveDate, Datelike};
///
- /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).day(), 8);
- /// assert_eq!(NaiveDate::from_ymd(-308, 3, 14).day(), 14);
- /// ~~~~
+ /// assert_eq!(NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().day(), 8);
+ /// assert_eq!(NaiveDate::from_ymd_opt(-308, 3, 14).unwrap().day(), 14);
+ /// ```
///
/// Combined with [`NaiveDate::pred`](#method.pred),
/// one can determine the number of days in a particular month.
/// (Note that this panics when `year` is out of range.)
///
- /// ~~~~
+ /// ```
/// use chrono::{NaiveDate, Datelike};
///
/// fn ndays_in_month(year: i32, month: u32) -> u32 {
/// // the first day of the next month...
/// let (y, m) = if month == 12 { (year + 1, 1) } else { (year, month + 1) };
- /// let d = NaiveDate::from_ymd(y, m, 1);
+ /// let d = NaiveDate::from_ymd_opt(y, m, 1).unwrap();
///
/// // ...is preceded by the last day of the original month
/// d.pred().day()
@@ -1183,7 +1353,7 @@ impl Datelike for NaiveDate {
/// assert_eq!(ndays_in_month(2015, 12), 31);
/// assert_eq!(ndays_in_month(2016, 2), 29);
/// assert_eq!(ndays_in_month(2017, 2), 28);
- /// ~~~~
+ /// ```
#[inline]
fn day(&self) -> u32 {
self.mdf().day()
@@ -1195,12 +1365,12 @@ impl Datelike for NaiveDate {
///
/// # Example
///
- /// ~~~~
+ /// ```
/// use chrono::{NaiveDate, Datelike};
///
- /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).day0(), 7);
- /// assert_eq!(NaiveDate::from_ymd(-308, 3, 14).day0(), 13);
- /// ~~~~
+ /// assert_eq!(NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().day0(), 7);
+ /// assert_eq!(NaiveDate::from_ymd_opt(-308, 3, 14).unwrap().day0(), 13);
+ /// ```
#[inline]
fn day0(&self) -> u32 {
self.mdf().day() - 1
@@ -1212,23 +1382,23 @@ impl Datelike for NaiveDate {
///
/// # Example
///
- /// ~~~~
+ /// ```
/// use chrono::{NaiveDate, Datelike};
///
- /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).ordinal(), 251);
- /// assert_eq!(NaiveDate::from_ymd(-308, 3, 14).ordinal(), 74);
- /// ~~~~
+ /// assert_eq!(NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().ordinal(), 251);
+ /// assert_eq!(NaiveDate::from_ymd_opt(-308, 3, 14).unwrap().ordinal(), 74);
+ /// ```
///
/// Combined with [`NaiveDate::pred`](#method.pred),
/// one can determine the number of days in a particular year.
/// (Note that this panics when `year` is out of range.)
///
- /// ~~~~
+ /// ```
/// use chrono::{NaiveDate, Datelike};
///
/// fn ndays_in_year(year: i32) -> u32 {
/// // the first day of the next year...
- /// let d = NaiveDate::from_ymd(year + 1, 1, 1);
+ /// let d = NaiveDate::from_ymd_opt(year + 1, 1, 1).unwrap();
///
/// // ...is preceded by the last day of the original year
/// d.pred().ordinal()
@@ -1239,7 +1409,7 @@ impl Datelike for NaiveDate {
/// assert_eq!(ndays_in_year(2017), 365);
/// assert_eq!(ndays_in_year(2000), 366);
/// assert_eq!(ndays_in_year(2100), 365);
- /// ~~~~
+ /// ```
#[inline]
fn ordinal(&self) -> u32 {
self.of().ordinal()
@@ -1251,12 +1421,12 @@ impl Datelike for NaiveDate {
///
/// # Example
///
- /// ~~~~
+ /// ```
/// use chrono::{NaiveDate, Datelike};
///
- /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).ordinal0(), 250);
- /// assert_eq!(NaiveDate::from_ymd(-308, 3, 14).ordinal0(), 73);
- /// ~~~~
+ /// assert_eq!(NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().ordinal0(), 250);
+ /// assert_eq!(NaiveDate::from_ymd_opt(-308, 3, 14).unwrap().ordinal0(), 73);
+ /// ```
#[inline]
fn ordinal0(&self) -> u32 {
self.of().ordinal() - 1
@@ -1266,12 +1436,12 @@ impl Datelike for NaiveDate {
///
/// # Example
///
- /// ~~~~
+ /// ```
/// use chrono::{NaiveDate, Datelike, Weekday};
///
- /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).weekday(), Weekday::Tue);
- /// assert_eq!(NaiveDate::from_ymd(-308, 3, 14).weekday(), Weekday::Fri);
- /// ~~~~
+ /// assert_eq!(NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().weekday(), Weekday::Tue);
+ /// assert_eq!(NaiveDate::from_ymd_opt(-308, 3, 14).unwrap().weekday(), Weekday::Fri);
+ /// ```
#[inline]
fn weekday(&self) -> Weekday {
self.of().weekday()
@@ -1288,22 +1458,22 @@ impl Datelike for NaiveDate {
///
/// # Example
///
- /// ~~~~
+ /// ```
/// use chrono::{NaiveDate, Datelike};
///
- /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).with_year(2016),
- /// Some(NaiveDate::from_ymd(2016, 9, 8)));
- /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).with_year(-308),
- /// Some(NaiveDate::from_ymd(-308, 9, 8)));
- /// ~~~~
+ /// assert_eq!(NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().with_year(2016),
+ /// Some(NaiveDate::from_ymd_opt(2016, 9, 8).unwrap()));
+ /// assert_eq!(NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().with_year(-308),
+ /// Some(NaiveDate::from_ymd_opt(-308, 9, 8).unwrap()));
+ /// ```
///
/// A leap day (February 29) is a good example that this method can return `None`.
///
- /// ~~~~
+ /// ```
/// # use chrono::{NaiveDate, Datelike};
- /// assert!(NaiveDate::from_ymd(2016, 2, 29).with_year(2015).is_none());
- /// assert!(NaiveDate::from_ymd(2016, 2, 29).with_year(2020).is_some());
- /// ~~~~
+ /// assert!(NaiveDate::from_ymd_opt(2016, 2, 29).unwrap().with_year(2015).is_none());
+ /// assert!(NaiveDate::from_ymd_opt(2016, 2, 29).unwrap().with_year(2020).is_some());
+ /// ```
#[inline]
fn with_year(&self, year: i32) -> Option<NaiveDate> {
// we need to operate with `mdf` since we should keep the month and day number as is
@@ -1322,17 +1492,17 @@ impl Datelike for NaiveDate {
///
/// # Example
///
- /// ~~~~
+ /// ```
/// use chrono::{NaiveDate, Datelike};
///
- /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).with_month(10),
- /// Some(NaiveDate::from_ymd(2015, 10, 8)));
- /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).with_month(13), None); // no month 13
- /// assert_eq!(NaiveDate::from_ymd(2015, 9, 30).with_month(2), None); // no February 30
- /// ~~~~
+ /// assert_eq!(NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().with_month(10),
+ /// Some(NaiveDate::from_ymd_opt(2015, 10, 8).unwrap()));
+ /// assert_eq!(NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().with_month(13), None); // no month 13
+ /// assert_eq!(NaiveDate::from_ymd_opt(2015, 9, 30).unwrap().with_month(2), None); // no February 30
+ /// ```
#[inline]
fn with_month(&self, month: u32) -> Option<NaiveDate> {
- self.with_mdf(self.mdf().with_month(month))
+ self.with_mdf(self.mdf().with_month(month)?)
}
/// Makes a new `NaiveDate` with the month number (starting from 0) changed.
@@ -1341,17 +1511,17 @@ impl Datelike for NaiveDate {
///
/// # Example
///
- /// ~~~~
+ /// ```
/// use chrono::{NaiveDate, Datelike};
///
- /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).with_month0(9),
- /// Some(NaiveDate::from_ymd(2015, 10, 8)));
- /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).with_month0(12), None); // no month 13
- /// assert_eq!(NaiveDate::from_ymd(2015, 9, 30).with_month0(1), None); // no February 30
- /// ~~~~
+ /// assert_eq!(NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().with_month0(9),
+ /// Some(NaiveDate::from_ymd_opt(2015, 10, 8).unwrap()));
+ /// assert_eq!(NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().with_month0(12), None); // no month 13
+ /// assert_eq!(NaiveDate::from_ymd_opt(2015, 9, 30).unwrap().with_month0(1), None); // no February 30
+ /// ```
#[inline]
fn with_month0(&self, month0: u32) -> Option<NaiveDate> {
- self.with_mdf(self.mdf().with_month(month0 + 1))
+ self.with_mdf(self.mdf().with_month(month0 + 1)?)
}
/// Makes a new `NaiveDate` with the day of month (starting from 1) changed.
@@ -1360,17 +1530,17 @@ impl Datelike for NaiveDate {
///
/// # Example
///
- /// ~~~~
+ /// ```
/// use chrono::{NaiveDate, Datelike};
///
- /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).with_day(30),
- /// Some(NaiveDate::from_ymd(2015, 9, 30)));
- /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).with_day(31),
+ /// assert_eq!(NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().with_day(30),
+ /// Some(NaiveDate::from_ymd_opt(2015, 9, 30).unwrap()));
+ /// assert_eq!(NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().with_day(31),
/// None); // no September 31
- /// ~~~~
+ /// ```
#[inline]
fn with_day(&self, day: u32) -> Option<NaiveDate> {
- self.with_mdf(self.mdf().with_day(day))
+ self.with_mdf(self.mdf().with_day(day)?)
}
/// Makes a new `NaiveDate` with the day of month (starting from 0) changed.
@@ -1379,17 +1549,17 @@ impl Datelike for NaiveDate {
///
/// # Example
///
- /// ~~~~
+ /// ```
/// use chrono::{NaiveDate, Datelike};
///
- /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).with_day0(29),
- /// Some(NaiveDate::from_ymd(2015, 9, 30)));
- /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).with_day0(30),
+ /// assert_eq!(NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().with_day0(29),
+ /// Some(NaiveDate::from_ymd_opt(2015, 9, 30).unwrap()));
+ /// assert_eq!(NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().with_day0(30),
/// None); // no September 31
- /// ~~~~
+ /// ```
#[inline]
fn with_day0(&self, day0: u32) -> Option<NaiveDate> {
- self.with_mdf(self.mdf().with_day(day0 + 1))
+ self.with_mdf(self.mdf().with_day(day0 + 1)?)
}
/// Makes a new `NaiveDate` with the day of year (starting from 1) changed.
@@ -1398,22 +1568,22 @@ impl Datelike for NaiveDate {
///
/// # Example
///
- /// ~~~~
+ /// ```
/// use chrono::{NaiveDate, Datelike};
///
- /// assert_eq!(NaiveDate::from_ymd(2015, 1, 1).with_ordinal(60),
- /// Some(NaiveDate::from_ymd(2015, 3, 1)));
- /// assert_eq!(NaiveDate::from_ymd(2015, 1, 1).with_ordinal(366),
+ /// assert_eq!(NaiveDate::from_ymd_opt(2015, 1, 1).unwrap().with_ordinal(60),
+ /// Some(NaiveDate::from_ymd_opt(2015, 3, 1).unwrap()));
+ /// assert_eq!(NaiveDate::from_ymd_opt(2015, 1, 1).unwrap().with_ordinal(366),
/// None); // 2015 had only 365 days
///
- /// assert_eq!(NaiveDate::from_ymd(2016, 1, 1).with_ordinal(60),
- /// Some(NaiveDate::from_ymd(2016, 2, 29)));
- /// assert_eq!(NaiveDate::from_ymd(2016, 1, 1).with_ordinal(366),
- /// Some(NaiveDate::from_ymd(2016, 12, 31)));
- /// ~~~~
+ /// assert_eq!(NaiveDate::from_ymd_opt(2016, 1, 1).unwrap().with_ordinal(60),
+ /// Some(NaiveDate::from_ymd_opt(2016, 2, 29).unwrap()));
+ /// assert_eq!(NaiveDate::from_ymd_opt(2016, 1, 1).unwrap().with_ordinal(366),
+ /// Some(NaiveDate::from_ymd_opt(2016, 12, 31).unwrap()));
+ /// ```
#[inline]
fn with_ordinal(&self, ordinal: u32) -> Option<NaiveDate> {
- self.with_of(self.of().with_ordinal(ordinal))
+ self.with_of(self.of().with_ordinal(ordinal)?)
}
/// Makes a new `NaiveDate` with the day of year (starting from 0) changed.
@@ -1422,22 +1592,22 @@ impl Datelike for NaiveDate {
///
/// # Example
///
- /// ~~~~
+ /// ```
/// use chrono::{NaiveDate, Datelike};
///
- /// assert_eq!(NaiveDate::from_ymd(2015, 1, 1).with_ordinal0(59),
- /// Some(NaiveDate::from_ymd(2015, 3, 1)));
- /// assert_eq!(NaiveDate::from_ymd(2015, 1, 1).with_ordinal0(365),
+ /// assert_eq!(NaiveDate::from_ymd_opt(2015, 1, 1).unwrap().with_ordinal0(59),
+ /// Some(NaiveDate::from_ymd_opt(2015, 3, 1).unwrap()));
+ /// assert_eq!(NaiveDate::from_ymd_opt(2015, 1, 1).unwrap().with_ordinal0(365),
/// None); // 2015 had only 365 days
///
- /// assert_eq!(NaiveDate::from_ymd(2016, 1, 1).with_ordinal0(59),
- /// Some(NaiveDate::from_ymd(2016, 2, 29)));
- /// assert_eq!(NaiveDate::from_ymd(2016, 1, 1).with_ordinal0(365),
- /// Some(NaiveDate::from_ymd(2016, 12, 31)));
- /// ~~~~
+ /// assert_eq!(NaiveDate::from_ymd_opt(2016, 1, 1).unwrap().with_ordinal0(59),
+ /// Some(NaiveDate::from_ymd_opt(2016, 2, 29).unwrap()));
+ /// assert_eq!(NaiveDate::from_ymd_opt(2016, 1, 1).unwrap().with_ordinal0(365),
+ /// Some(NaiveDate::from_ymd_opt(2016, 12, 31).unwrap()));
+ /// ```
#[inline]
fn with_ordinal0(&self, ordinal0: u32) -> Option<NaiveDate> {
- self.with_of(self.of().with_ordinal(ordinal0 + 1))
+ self.with_of(self.of().with_ordinal(ordinal0 + 1)?)
}
}
@@ -1449,8 +1619,7 @@ impl Datelike for NaiveDate {
///
/// # Example
///
-/// ~~~~
-/// # extern crate chrono; fn main() {
+/// ```
/// use chrono::{Duration, NaiveDate};
///
/// let from_ymd = NaiveDate::from_ymd;
@@ -1463,8 +1632,7 @@ impl Datelike for NaiveDate {
/// assert_eq!(from_ymd(2014, 1, 1) + Duration::days(364), from_ymd(2014, 12, 31));
/// 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));
-/// # }
-/// ~~~~
+/// ```
impl Add<OldDuration> for NaiveDate {
type Output = NaiveDate;
@@ -1481,6 +1649,75 @@ impl AddAssign<OldDuration> for NaiveDate {
}
}
+impl Add<Months> for NaiveDate {
+ type Output = NaiveDate;
+
+ /// An addition of months to `NaiveDate` clamped to valid days in resulting month.
+ ///
+ /// # Panics
+ ///
+ /// Panics if the resulting date would be out of range.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use chrono::{Duration, NaiveDate, Months};
+ ///
+ /// let from_ymd = NaiveDate::from_ymd;
+ ///
+ /// 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));
+ /// assert_eq!(from_ymd(2014, 1, 1) + Months::new(12), from_ymd(2015, 1, 1));
+ /// assert_eq!(from_ymd(2014, 1, 1) + Months::new(13), from_ymd(2015, 2, 1));
+ /// assert_eq!(from_ymd(2014, 1, 31) + Months::new(1), from_ymd(2014, 2, 28));
+ /// assert_eq!(from_ymd(2020, 1, 31) + Months::new(1), from_ymd(2020, 2, 29));
+ /// ```
+ fn add(self, months: Months) -> Self::Output {
+ self.checked_add_months(months).unwrap()
+ }
+}
+
+impl Sub<Months> for NaiveDate {
+ type Output = NaiveDate;
+
+ /// A subtraction of Months from `NaiveDate` clamped to valid days in resulting month.
+ ///
+ /// # Panics
+ ///
+ /// Panics if the resulting date would be out of range.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use chrono::{Duration, NaiveDate, Months};
+ ///
+ /// let from_ymd = NaiveDate::from_ymd;
+ ///
+ /// 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));
+ /// assert_eq!(from_ymd(2014, 1, 1) - Months::new(13), from_ymd(2012, 12, 1));
+ /// ```
+ fn sub(self, months: Months) -> Self::Output {
+ self.checked_sub_months(months).unwrap()
+ }
+}
+
+impl Add<Days> for NaiveDate {
+ type Output = NaiveDate;
+
+ fn add(self, days: Days) -> Self::Output {
+ self.checked_add_days(days).unwrap()
+ }
+}
+
+impl Sub<Days> for NaiveDate {
+ type Output = NaiveDate;
+
+ fn sub(self, days: Days) -> Self::Output {
+ self.checked_sub_days(days).unwrap()
+ }
+}
+
/// A subtraction of `Duration` from `NaiveDate` discards the fractional days,
/// rounding to the closest integral number of days towards `Duration::zero()`.
/// It is the same as the addition with a negated `Duration`.
@@ -1490,8 +1727,7 @@ impl AddAssign<OldDuration> for NaiveDate {
///
/// # Example
///
-/// ~~~~
-/// # extern crate chrono; fn main() {
+/// ```
/// use chrono::{Duration, NaiveDate};
///
/// let from_ymd = NaiveDate::from_ymd;
@@ -1504,8 +1740,7 @@ impl AddAssign<OldDuration> for NaiveDate {
/// assert_eq!(from_ymd(2014, 1, 1) - Duration::days(364), from_ymd(2013, 1, 2));
/// 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));
-/// # }
-/// ~~~~
+/// ```
impl Sub<OldDuration> for NaiveDate {
type Output = NaiveDate;
@@ -1533,8 +1768,7 @@ impl SubAssign<OldDuration> for NaiveDate {
///
/// # Example
///
-/// ~~~~
-/// # extern crate chrono; fn main() {
+/// ```
/// use chrono::{Duration, NaiveDate};
///
/// let from_ymd = NaiveDate::from_ymd;
@@ -1546,8 +1780,7 @@ impl SubAssign<OldDuration> for NaiveDate {
/// assert_eq!(from_ymd(2014, 1, 1) - from_ymd(2013, 1, 1), Duration::days(365));
/// assert_eq!(from_ymd(2014, 1, 1) - from_ymd(2010, 1, 1), Duration::days(365*4 + 1));
/// assert_eq!(from_ymd(2014, 1, 1) - from_ymd(1614, 1, 1), Duration::days(365*400 + 97));
-/// # }
-/// ~~~~
+/// ```
impl Sub<NaiveDate> for NaiveDate {
type Output = OldDuration;
@@ -1567,24 +1800,35 @@ impl Iterator for NaiveDateDaysIterator {
type Item = NaiveDate;
fn next(&mut self) -> Option<Self::Item> {
- if self.value == MAX_DATE {
+ if self.value == NaiveDate::MAX {
return None;
}
- // current < MAX_DATE from here on:
+ // current < NaiveDate::MAX from here on:
let current = self.value;
- // This can't panic because current is < MAX_DATE:
- self.value = current.succ();
+ // This can't panic because current is < NaiveDate::MAX:
+ self.value = current.succ_opt().unwrap();
Some(current)
}
fn size_hint(&self) -> (usize, Option<usize>) {
- let exact_size = MAX_DATE.signed_duration_since(self.value).num_days();
+ let exact_size = NaiveDate::MAX.signed_duration_since(self.value).num_days();
(exact_size as usize, Some(exact_size as usize))
}
}
impl ExactSizeIterator for NaiveDateDaysIterator {}
+impl DoubleEndedIterator for NaiveDateDaysIterator {
+ fn next_back(&mut self) -> Option<Self::Item> {
+ if self.value == NaiveDate::MIN {
+ return None;
+ }
+ let current = self.value;
+ self.value = current.pred_opt().unwrap();
+ Some(current)
+ }
+}
+
#[derive(Debug, Copy, Clone, Hash, PartialEq, PartialOrd, Eq, Ord)]
pub struct NaiveDateWeeksIterator {
value: NaiveDate,
@@ -1594,7 +1838,7 @@ impl Iterator for NaiveDateWeeksIterator {
type Item = NaiveDate;
fn next(&mut self) -> Option<Self::Item> {
- if MAX_DATE - self.value < OldDuration::weeks(1) {
+ if NaiveDate::MAX - self.value < OldDuration::weeks(1) {
return None;
}
let current = self.value;
@@ -1603,13 +1847,24 @@ impl Iterator for NaiveDateWeeksIterator {
}
fn size_hint(&self) -> (usize, Option<usize>) {
- let exact_size = MAX_DATE.signed_duration_since(self.value).num_weeks();
+ let exact_size = NaiveDate::MAX.signed_duration_since(self.value).num_weeks();
(exact_size as usize, Some(exact_size as usize))
}
}
impl ExactSizeIterator for NaiveDateWeeksIterator {}
+impl DoubleEndedIterator for NaiveDateWeeksIterator {
+ fn next_back(&mut self) -> Option<Self::Item> {
+ if self.value - NaiveDate::MIN < OldDuration::weeks(1) {
+ return None;
+ }
+ let current = self.value;
+ self.value = current - OldDuration::weeks(1);
+ Some(current)
+ }
+}
+
// TODO: NaiveDateDaysIterator and NaiveDateWeeksIterator should implement FusedIterator,
// TrustedLen, and Step once they becomes stable.
// See: https://github.com/chronotope/chrono/issues/208
@@ -1621,31 +1876,39 @@ impl ExactSizeIterator for NaiveDateWeeksIterator {}
///
/// # Example
///
-/// ~~~~
+/// ```
/// use chrono::NaiveDate;
///
-/// assert_eq!(format!("{:?}", NaiveDate::from_ymd(2015, 9, 5)), "2015-09-05");
-/// assert_eq!(format!("{:?}", NaiveDate::from_ymd( 0, 1, 1)), "0000-01-01");
-/// assert_eq!(format!("{:?}", NaiveDate::from_ymd(9999, 12, 31)), "9999-12-31");
-/// ~~~~
+/// assert_eq!(format!("{:?}", NaiveDate::from_ymd_opt(2015, 9, 5).unwrap()), "2015-09-05");
+/// assert_eq!(format!("{:?}", NaiveDate::from_ymd_opt( 0, 1, 1).unwrap()), "0000-01-01");
+/// assert_eq!(format!("{:?}", NaiveDate::from_ymd_opt(9999, 12, 31).unwrap()), "9999-12-31");
+/// ```
///
/// ISO 8601 requires an explicit sign for years before 1 BCE or after 9999 CE.
///
-/// ~~~~
+/// ```
/// # use chrono::NaiveDate;
-/// assert_eq!(format!("{:?}", NaiveDate::from_ymd( -1, 1, 1)), "-0001-01-01");
-/// assert_eq!(format!("{:?}", NaiveDate::from_ymd(10000, 12, 31)), "+10000-12-31");
-/// ~~~~
+/// assert_eq!(format!("{:?}", NaiveDate::from_ymd_opt( -1, 1, 1).unwrap()), "-0001-01-01");
+/// assert_eq!(format!("{:?}", NaiveDate::from_ymd_opt(10000, 12, 31).unwrap()), "+10000-12-31");
+/// ```
impl fmt::Debug for NaiveDate {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ use core::fmt::Write;
+
let year = self.year();
let mdf = self.mdf();
- if 0 <= year && year <= 9999 {
- write!(f, "{:04}-{:02}-{:02}", year, mdf.month(), mdf.day())
+ if (0..=9999).contains(&year) {
+ write_hundreds(f, (year / 100) as u8)?;
+ write_hundreds(f, (year % 100) as u8)?;
} else {
// ISO 8601 requires the explicit sign for out-of-range years
- write!(f, "{:+05}-{:02}-{:02}", year, mdf.month(), mdf.day())
+ write!(f, "{:+05}", year)?;
}
+
+ f.write_char('-')?;
+ write_hundreds(f, mdf.month() as u8)?;
+ f.write_char('-')?;
+ write_hundreds(f, mdf.day() as u8)
}
}
@@ -1656,21 +1919,21 @@ impl fmt::Debug for NaiveDate {
///
/// # Example
///
-/// ~~~~
+/// ```
/// use chrono::NaiveDate;
///
-/// assert_eq!(format!("{}", NaiveDate::from_ymd(2015, 9, 5)), "2015-09-05");
-/// assert_eq!(format!("{}", NaiveDate::from_ymd( 0, 1, 1)), "0000-01-01");
-/// assert_eq!(format!("{}", NaiveDate::from_ymd(9999, 12, 31)), "9999-12-31");
-/// ~~~~
+/// assert_eq!(format!("{}", NaiveDate::from_ymd_opt(2015, 9, 5).unwrap()), "2015-09-05");
+/// assert_eq!(format!("{}", NaiveDate::from_ymd_opt( 0, 1, 1).unwrap()), "0000-01-01");
+/// assert_eq!(format!("{}", NaiveDate::from_ymd_opt(9999, 12, 31).unwrap()), "9999-12-31");
+/// ```
///
/// ISO 8601 requires an explicit sign for years before 1 BCE or after 9999 CE.
///
-/// ~~~~
+/// ```
/// # use chrono::NaiveDate;
-/// assert_eq!(format!("{}", NaiveDate::from_ymd( -1, 1, 1)), "-0001-01-01");
-/// assert_eq!(format!("{}", NaiveDate::from_ymd(10000, 12, 31)), "+10000-12-31");
-/// ~~~~
+/// assert_eq!(format!("{}", NaiveDate::from_ymd_opt( -1, 1, 1).unwrap()), "-0001-01-01");
+/// assert_eq!(format!("{}", NaiveDate::from_ymd_opt(10000, 12, 31).unwrap()), "+10000-12-31");
+/// ```
impl fmt::Display for NaiveDate {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(self, f)
@@ -1682,22 +1945,22 @@ impl fmt::Display for NaiveDate {
///
/// # Example
///
-/// ~~~~
+/// ```
/// use chrono::NaiveDate;
///
-/// let d = NaiveDate::from_ymd(2015, 9, 18);
+/// let d = NaiveDate::from_ymd_opt(2015, 9, 18).unwrap();
/// assert_eq!("2015-09-18".parse::<NaiveDate>(), Ok(d));
///
-/// let d = NaiveDate::from_ymd(12345, 6, 7);
+/// let d = NaiveDate::from_ymd_opt(12345, 6, 7).unwrap();
/// assert_eq!("+12345-6-7".parse::<NaiveDate>(), Ok(d));
///
/// assert!("foo".parse::<NaiveDate>().is_err());
-/// ~~~~
+/// ```
impl str::FromStr for NaiveDate {
type Err = ParseError;
fn from_str(s: &str) -> ParseResult<NaiveDate> {
- const ITEMS: &'static [Item<'static>] = &[
+ const ITEMS: &[Item<'static>] = &[
Item::Numeric(Numeric::Year, Pad::Zero),
Item::Space(""),
Item::Literal("-"),
@@ -1714,17 +1977,42 @@ impl str::FromStr for NaiveDate {
}
}
+/// The default value for a NaiveDate is 1st of January 1970.
+///
+/// # Example
+///
+/// ```rust
+/// use chrono::NaiveDate;
+///
+/// let default_date = NaiveDate::default();
+/// assert_eq!(default_date, NaiveDate::from_ymd_opt(1970, 1, 1).unwrap());
+/// ```
+impl Default for NaiveDate {
+ fn default() -> Self {
+ NaiveDate::from_ymd_opt(1970, 1, 1).unwrap()
+ }
+}
+
#[cfg(all(test, any(feature = "rustc-serialize", feature = "serde")))]
fn test_encodable_json<F, E>(to_string: F)
where
F: Fn(&NaiveDate) -> Result<String, E>,
E: ::std::fmt::Debug,
{
- assert_eq!(to_string(&NaiveDate::from_ymd(2014, 7, 24)).ok(), Some(r#""2014-07-24""#.into()));
- assert_eq!(to_string(&NaiveDate::from_ymd(0, 1, 1)).ok(), Some(r#""0000-01-01""#.into()));
- assert_eq!(to_string(&NaiveDate::from_ymd(-1, 12, 31)).ok(), Some(r#""-0001-12-31""#.into()));
- assert_eq!(to_string(&MIN_DATE).ok(), Some(r#""-262144-01-01""#.into()));
- assert_eq!(to_string(&MAX_DATE).ok(), Some(r#""+262143-12-31""#.into()));
+ assert_eq!(
+ to_string(&NaiveDate::from_ymd_opt(2014, 7, 24).unwrap()).ok(),
+ Some(r#""2014-07-24""#.into())
+ );
+ assert_eq!(
+ to_string(&NaiveDate::from_ymd_opt(0, 1, 1).unwrap()).ok(),
+ Some(r#""0000-01-01""#.into())
+ );
+ assert_eq!(
+ to_string(&NaiveDate::from_ymd_opt(-1, 12, 31).unwrap()).ok(),
+ Some(r#""-0001-12-31""#.into())
+ );
+ assert_eq!(to_string(&NaiveDate::MIN).ok(), Some(r#""-262144-01-01""#.into()));
+ assert_eq!(to_string(&NaiveDate::MAX).ok(), Some(r#""+262143-12-31""#.into()));
}
#[cfg(all(test, any(feature = "rustc-serialize", feature = "serde")))]
@@ -1735,14 +2023,20 @@ where
{
use std::{i32, i64};
- assert_eq!(from_str(r#""2016-07-08""#).ok(), Some(NaiveDate::from_ymd(2016, 7, 8)));
- assert_eq!(from_str(r#""2016-7-8""#).ok(), Some(NaiveDate::from_ymd(2016, 7, 8)));
- assert_eq!(from_str(r#""+002016-07-08""#).ok(), Some(NaiveDate::from_ymd(2016, 7, 8)));
- assert_eq!(from_str(r#""0000-01-01""#).ok(), Some(NaiveDate::from_ymd(0, 1, 1)));
- assert_eq!(from_str(r#""0-1-1""#).ok(), Some(NaiveDate::from_ymd(0, 1, 1)));
- assert_eq!(from_str(r#""-0001-12-31""#).ok(), Some(NaiveDate::from_ymd(-1, 12, 31)));
- assert_eq!(from_str(r#""-262144-01-01""#).ok(), Some(MIN_DATE));
- assert_eq!(from_str(r#""+262143-12-31""#).ok(), Some(MAX_DATE));
+ assert_eq!(
+ from_str(r#""2016-07-08""#).ok(),
+ Some(NaiveDate::from_ymd_opt(2016, 7, 8).unwrap())
+ );
+ assert_eq!(from_str(r#""2016-7-8""#).ok(), Some(NaiveDate::from_ymd_opt(2016, 7, 8).unwrap()));
+ assert_eq!(from_str(r#""+002016-07-08""#).ok(), NaiveDate::from_ymd_opt(2016, 7, 8));
+ assert_eq!(from_str(r#""0000-01-01""#).ok(), Some(NaiveDate::from_ymd_opt(0, 1, 1).unwrap()));
+ assert_eq!(from_str(r#""0-1-1""#).ok(), Some(NaiveDate::from_ymd_opt(0, 1, 1).unwrap()));
+ assert_eq!(
+ from_str(r#""-0001-12-31""#).ok(),
+ Some(NaiveDate::from_ymd_opt(-1, 12, 31).unwrap())
+ );
+ assert_eq!(from_str(r#""-262144-01-01""#).ok(), Some(NaiveDate::MIN));
+ assert_eq!(from_str(r#""+262143-12-31""#).ok(), Some(NaiveDate::MAX));
// bad formats
assert!(from_str(r#""""#).is_err());
@@ -1765,6 +2059,7 @@ where
}
#[cfg(feature = "rustc-serialize")]
+#[cfg_attr(docsrs, doc(cfg(feature = "rustc-serialize")))]
mod rustc_serialize {
use super::NaiveDate;
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
@@ -1796,10 +2091,11 @@ mod rustc_serialize {
}
#[cfg(feature = "serde")]
+#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
mod serde {
use super::NaiveDate;
use core::fmt;
- use serdelib::{de, ser};
+ use serde::{de, ser};
// TODO not very optimized for space (binary formats would want something better)
@@ -1828,11 +2124,11 @@ mod serde {
type Value = NaiveDate;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
- write!(formatter, "a formatted date string")
+ formatter.write_str("a formatted date string")
}
#[cfg(any(feature = "std", test))]
- fn visit_str<E>(self, value: &str) -> Result<NaiveDate, E>
+ fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
where
E: de::Error,
{
@@ -1840,7 +2136,7 @@ mod serde {
}
#[cfg(not(any(feature = "std", test)))]
- fn visit_str<E>(self, value: &str) -> Result<NaiveDate, E>
+ fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
where
E: de::Error,
{
@@ -1857,29 +2153,24 @@ mod serde {
}
}
- #[cfg(test)]
- extern crate bincode;
- #[cfg(test)]
- extern crate serde_json;
-
#[test]
fn test_serde_serialize() {
- super::test_encodable_json(self::serde_json::to_string);
+ super::test_encodable_json(serde_json::to_string);
}
#[test]
fn test_serde_deserialize() {
- super::test_decodable_json(|input| self::serde_json::from_str(&input));
+ super::test_decodable_json(|input| serde_json::from_str(input));
}
#[test]
fn test_serde_bincode() {
// Bincode is relevant to test separately from JSON because
// it is not self-describing.
- use self::bincode::{deserialize, serialize, Infinite};
+ use bincode::{deserialize, serialize};
- let d = NaiveDate::from_ymd(2014, 7, 24);
- let encoded = serialize(&d, Infinite).unwrap();
+ let d = NaiveDate::from_ymd_opt(2014, 7, 24).unwrap();
+ let encoded = serialize(&d).unwrap();
let decoded: NaiveDate = deserialize(&encoded).unwrap();
assert_eq!(d, decoded);
}
@@ -1887,16 +2178,131 @@ mod serde {
#[cfg(test)]
mod tests {
- use super::NaiveDate;
- use super::{MAX_DATE, MAX_DAYS_FROM_YEAR_0, MAX_YEAR};
- use super::{MIN_DATE, MIN_DAYS_FROM_YEAR_0, MIN_YEAR};
- use oldtime::Duration;
- use std::{i32, u32};
- use {Datelike, Weekday};
+ use super::{
+ Days, Months, NaiveDate, MAX_DAYS_FROM_YEAR_0, MAX_YEAR, MIN_DAYS_FROM_YEAR_0, MIN_YEAR,
+ };
+ use crate::oldtime::Duration;
+ use crate::{Datelike, Weekday};
+ use std::{
+ convert::{TryFrom, TryInto},
+ i32, u32,
+ };
+
+ #[test]
+ fn diff_months() {
+ // identity
+ assert_eq!(
+ NaiveDate::from_ymd_opt(2022, 8, 3).unwrap().checked_add_months(Months::new(0)),
+ Some(NaiveDate::from_ymd_opt(2022, 8, 3).unwrap())
+ );
+
+ // add with months exceeding `i32::MAX`
+ assert_eq!(
+ NaiveDate::from_ymd_opt(2022, 8, 3)
+ .unwrap()
+ .checked_add_months(Months::new(i32::MAX as u32 + 1)),
+ None
+ );
+
+ // sub with months exceeding `i32::MIN`
+ assert_eq!(
+ NaiveDate::from_ymd_opt(2022, 8, 3)
+ .unwrap()
+ .checked_sub_months(Months::new((i32::MIN as i64).abs() as u32 + 1)),
+ None
+ );
+
+ // add overflowing year
+ assert_eq!(NaiveDate::MAX.checked_add_months(Months::new(1)), None);
+
+ // add underflowing year
+ assert_eq!(NaiveDate::MIN.checked_sub_months(Months::new(1)), None);
+
+ // sub crossing year 0 boundary
+ assert_eq!(
+ NaiveDate::from_ymd_opt(2022, 8, 3).unwrap().checked_sub_months(Months::new(2050 * 12)),
+ Some(NaiveDate::from_ymd_opt(-28, 8, 3).unwrap())
+ );
+
+ // add crossing year boundary
+ assert_eq!(
+ NaiveDate::from_ymd_opt(2022, 8, 3).unwrap().checked_add_months(Months::new(6)),
+ Some(NaiveDate::from_ymd_opt(2023, 2, 3).unwrap())
+ );
+
+ // sub crossing year boundary
+ assert_eq!(
+ NaiveDate::from_ymd_opt(2022, 8, 3).unwrap().checked_sub_months(Months::new(10)),
+ Some(NaiveDate::from_ymd_opt(2021, 10, 3).unwrap())
+ );
+
+ // add clamping day, non-leap year
+ assert_eq!(
+ NaiveDate::from_ymd_opt(2022, 1, 29).unwrap().checked_add_months(Months::new(1)),
+ Some(NaiveDate::from_ymd_opt(2022, 2, 28).unwrap())
+ );
+
+ // add to leap day
+ assert_eq!(
+ NaiveDate::from_ymd_opt(2022, 10, 29).unwrap().checked_add_months(Months::new(16)),
+ Some(NaiveDate::from_ymd_opt(2024, 2, 29).unwrap())
+ );
+
+ // add into december
+ assert_eq!(
+ NaiveDate::from_ymd_opt(2022, 10, 31).unwrap().checked_add_months(Months::new(2)),
+ Some(NaiveDate::from_ymd_opt(2022, 12, 31).unwrap())
+ );
+
+ // sub into december
+ assert_eq!(
+ NaiveDate::from_ymd_opt(2022, 10, 31).unwrap().checked_sub_months(Months::new(10)),
+ Some(NaiveDate::from_ymd_opt(2021, 12, 31).unwrap())
+ );
+
+ // add into january
+ assert_eq!(
+ NaiveDate::from_ymd_opt(2022, 8, 3).unwrap().checked_add_months(Months::new(5)),
+ Some(NaiveDate::from_ymd_opt(2023, 1, 3).unwrap())
+ );
+
+ // sub into january
+ assert_eq!(
+ NaiveDate::from_ymd_opt(2022, 8, 3).unwrap().checked_sub_months(Months::new(7)),
+ Some(NaiveDate::from_ymd_opt(2022, 1, 3).unwrap())
+ );
+ }
+
+ #[test]
+ fn test_readme_doomsday() {
+ use num_iter::range_inclusive;
+
+ for y in range_inclusive(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();
+ let d8 = NaiveDate::from_ymd_opt(y, 8, 8).unwrap();
+ let d10 = NaiveDate::from_ymd_opt(y, 10, 10).unwrap();
+ let d12 = NaiveDate::from_ymd_opt(y, 12, 12).unwrap();
+
+ // nine to five, seven-eleven
+ let d59 = NaiveDate::from_ymd_opt(y, 5, 9).unwrap();
+ let d95 = NaiveDate::from_ymd_opt(y, 9, 5).unwrap();
+ let d711 = NaiveDate::from_ymd_opt(y, 7, 11).unwrap();
+ let d117 = NaiveDate::from_ymd_opt(y, 11, 7).unwrap();
+
+ // "March 0"
+ let d30 = NaiveDate::from_ymd_opt(y, 3, 1).unwrap().pred_opt().unwrap();
+
+ let weekday = d30.weekday();
+ let other_dates = [d4, d6, d8, d10, d12, d59, d95, d711, d117];
+ assert!(other_dates.iter().all(|d| d.weekday() == weekday));
+ }
+ }
#[test]
fn test_date_from_ymd() {
- let ymd_opt = |y, m, d| NaiveDate::from_ymd_opt(y, m, d);
+ let ymd_opt = NaiveDate::from_ymd_opt;
assert!(ymd_opt(2012, 0, 1).is_none());
assert!(ymd_opt(2012, 1, 1).is_some());
@@ -1912,8 +2318,8 @@ mod tests {
#[test]
fn test_date_from_yo() {
- let yo_opt = |y, o| NaiveDate::from_yo_opt(y, o);
- let ymd = |y, m, d| NaiveDate::from_ymd(y, m, d);
+ let yo_opt = NaiveDate::from_yo_opt;
+ let ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap();
assert_eq!(yo_opt(2012, 0), None);
assert_eq!(yo_opt(2012, 1), Some(ymd(2012, 1, 1)));
@@ -1942,8 +2348,8 @@ mod tests {
#[test]
fn test_date_from_isoywd() {
- let isoywd_opt = |y, w, d| NaiveDate::from_isoywd_opt(y, w, d);
- let ymd = |y, m, d| NaiveDate::from_ymd(y, m, d);
+ let isoywd_opt = NaiveDate::from_isoywd_opt;
+ let ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap();
assert_eq!(isoywd_opt(2004, 0, Weekday::Sun), None);
assert_eq!(isoywd_opt(2004, 1, Weekday::Mon), Some(ymd(2003, 12, 29)));
@@ -1985,8 +2391,7 @@ mod tests {
.iter()
{
let d = NaiveDate::from_isoywd_opt(year, week, weekday);
- if d.is_some() {
- let d = d.unwrap();
+ if let Some(d) = d {
assert_eq!(d.weekday(), weekday);
let w = d.iso_week();
assert_eq!(w.year(), year);
@@ -2000,11 +2405,10 @@ mod tests {
for month in 1..13 {
for day in 1..32 {
let d = NaiveDate::from_ymd_opt(year, month, day);
- if d.is_some() {
- let d = d.unwrap();
+ if let Some(d) = d {
let w = d.iso_week();
- let d_ = NaiveDate::from_isoywd(w.year(), w.week(), d.weekday());
- assert_eq!(d, d_);
+ let d_ = NaiveDate::from_isoywd_opt(w.year(), w.week(), d.weekday());
+ assert_eq!(d, d_.unwrap());
}
}
}
@@ -2013,63 +2417,111 @@ mod tests {
#[test]
fn test_date_from_num_days_from_ce() {
- let from_ndays_from_ce = |days| NaiveDate::from_num_days_from_ce_opt(days);
- assert_eq!(from_ndays_from_ce(1), Some(NaiveDate::from_ymd(1, 1, 1)));
- assert_eq!(from_ndays_from_ce(2), Some(NaiveDate::from_ymd(1, 1, 2)));
- assert_eq!(from_ndays_from_ce(31), Some(NaiveDate::from_ymd(1, 1, 31)));
- assert_eq!(from_ndays_from_ce(32), Some(NaiveDate::from_ymd(1, 2, 1)));
- assert_eq!(from_ndays_from_ce(59), Some(NaiveDate::from_ymd(1, 2, 28)));
- assert_eq!(from_ndays_from_ce(60), Some(NaiveDate::from_ymd(1, 3, 1)));
- assert_eq!(from_ndays_from_ce(365), Some(NaiveDate::from_ymd(1, 12, 31)));
- assert_eq!(from_ndays_from_ce(365 * 1 + 1), Some(NaiveDate::from_ymd(2, 1, 1)));
- assert_eq!(from_ndays_from_ce(365 * 2 + 1), Some(NaiveDate::from_ymd(3, 1, 1)));
- assert_eq!(from_ndays_from_ce(365 * 3 + 1), Some(NaiveDate::from_ymd(4, 1, 1)));
- assert_eq!(from_ndays_from_ce(365 * 4 + 2), Some(NaiveDate::from_ymd(5, 1, 1)));
- assert_eq!(from_ndays_from_ce(146097 + 1), Some(NaiveDate::from_ymd(401, 1, 1)));
- assert_eq!(from_ndays_from_ce(146097 * 5 + 1), Some(NaiveDate::from_ymd(2001, 1, 1)));
- assert_eq!(from_ndays_from_ce(719163), Some(NaiveDate::from_ymd(1970, 1, 1)));
- assert_eq!(from_ndays_from_ce(0), Some(NaiveDate::from_ymd(0, 12, 31))); // 1 BCE
- assert_eq!(from_ndays_from_ce(-365), Some(NaiveDate::from_ymd(0, 1, 1)));
- assert_eq!(from_ndays_from_ce(-366), Some(NaiveDate::from_ymd(-1, 12, 31))); // 2 BCE
+ let from_ndays_from_ce = NaiveDate::from_num_days_from_ce_opt;
+ assert_eq!(from_ndays_from_ce(1), Some(NaiveDate::from_ymd_opt(1, 1, 1).unwrap()));
+ assert_eq!(from_ndays_from_ce(2), Some(NaiveDate::from_ymd_opt(1, 1, 2).unwrap()));
+ assert_eq!(from_ndays_from_ce(31), Some(NaiveDate::from_ymd_opt(1, 1, 31).unwrap()));
+ assert_eq!(from_ndays_from_ce(32), Some(NaiveDate::from_ymd_opt(1, 2, 1).unwrap()));
+ assert_eq!(from_ndays_from_ce(59), Some(NaiveDate::from_ymd_opt(1, 2, 28).unwrap()));
+ assert_eq!(from_ndays_from_ce(60), Some(NaiveDate::from_ymd_opt(1, 3, 1).unwrap()));
+ assert_eq!(from_ndays_from_ce(365), Some(NaiveDate::from_ymd_opt(1, 12, 31).unwrap()));
+ assert_eq!(from_ndays_from_ce(365 + 1), Some(NaiveDate::from_ymd_opt(2, 1, 1).unwrap()));
+ assert_eq!(
+ from_ndays_from_ce(365 * 2 + 1),
+ Some(NaiveDate::from_ymd_opt(3, 1, 1).unwrap())
+ );
+ assert_eq!(
+ from_ndays_from_ce(365 * 3 + 1),
+ Some(NaiveDate::from_ymd_opt(4, 1, 1).unwrap())
+ );
+ assert_eq!(
+ from_ndays_from_ce(365 * 4 + 2),
+ Some(NaiveDate::from_ymd_opt(5, 1, 1).unwrap())
+ );
+ assert_eq!(
+ from_ndays_from_ce(146097 + 1),
+ Some(NaiveDate::from_ymd_opt(401, 1, 1).unwrap())
+ );
+ assert_eq!(
+ from_ndays_from_ce(146097 * 5 + 1),
+ Some(NaiveDate::from_ymd_opt(2001, 1, 1).unwrap())
+ );
+ assert_eq!(from_ndays_from_ce(719163), Some(NaiveDate::from_ymd_opt(1970, 1, 1).unwrap()));
+ assert_eq!(from_ndays_from_ce(0), Some(NaiveDate::from_ymd_opt(0, 12, 31).unwrap())); // 1 BCE
+ assert_eq!(from_ndays_from_ce(-365), Some(NaiveDate::from_ymd_opt(0, 1, 1).unwrap()));
+ assert_eq!(from_ndays_from_ce(-366), Some(NaiveDate::from_ymd_opt(-1, 12, 31).unwrap())); // 2 BCE
for days in (-9999..10001).map(|x| x * 100) {
assert_eq!(from_ndays_from_ce(days).map(|d| d.num_days_from_ce()), Some(days));
}
- assert_eq!(from_ndays_from_ce(MIN_DATE.num_days_from_ce()), Some(MIN_DATE));
- assert_eq!(from_ndays_from_ce(MIN_DATE.num_days_from_ce() - 1), None);
- assert_eq!(from_ndays_from_ce(MAX_DATE.num_days_from_ce()), Some(MAX_DATE));
- assert_eq!(from_ndays_from_ce(MAX_DATE.num_days_from_ce() + 1), None);
+ assert_eq!(from_ndays_from_ce(NaiveDate::MIN.num_days_from_ce()), Some(NaiveDate::MIN));
+ 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);
}
#[test]
fn test_date_from_weekday_of_month_opt() {
- let ymwd = |y, m, w, n| NaiveDate::from_weekday_of_month_opt(y, m, w, n);
+ let ymwd = NaiveDate::from_weekday_of_month_opt;
assert_eq!(ymwd(2018, 8, Weekday::Tue, 0), None);
- assert_eq!(ymwd(2018, 8, Weekday::Wed, 1), Some(NaiveDate::from_ymd(2018, 8, 1)));
- assert_eq!(ymwd(2018, 8, Weekday::Thu, 1), Some(NaiveDate::from_ymd(2018, 8, 2)));
- assert_eq!(ymwd(2018, 8, Weekday::Sun, 1), Some(NaiveDate::from_ymd(2018, 8, 5)));
- assert_eq!(ymwd(2018, 8, Weekday::Mon, 1), Some(NaiveDate::from_ymd(2018, 8, 6)));
- assert_eq!(ymwd(2018, 8, Weekday::Tue, 1), Some(NaiveDate::from_ymd(2018, 8, 7)));
- assert_eq!(ymwd(2018, 8, Weekday::Wed, 2), Some(NaiveDate::from_ymd(2018, 8, 8)));
- assert_eq!(ymwd(2018, 8, Weekday::Sun, 2), Some(NaiveDate::from_ymd(2018, 8, 12)));
- assert_eq!(ymwd(2018, 8, Weekday::Thu, 3), Some(NaiveDate::from_ymd(2018, 8, 16)));
- assert_eq!(ymwd(2018, 8, Weekday::Thu, 4), Some(NaiveDate::from_ymd(2018, 8, 23)));
- assert_eq!(ymwd(2018, 8, Weekday::Thu, 5), Some(NaiveDate::from_ymd(2018, 8, 30)));
- assert_eq!(ymwd(2018, 8, Weekday::Fri, 5), Some(NaiveDate::from_ymd(2018, 8, 31)));
+ assert_eq!(
+ ymwd(2018, 8, Weekday::Wed, 1),
+ Some(NaiveDate::from_ymd_opt(2018, 8, 1).unwrap())
+ );
+ assert_eq!(
+ ymwd(2018, 8, Weekday::Thu, 1),
+ Some(NaiveDate::from_ymd_opt(2018, 8, 2).unwrap())
+ );
+ assert_eq!(
+ ymwd(2018, 8, Weekday::Sun, 1),
+ Some(NaiveDate::from_ymd_opt(2018, 8, 5).unwrap())
+ );
+ assert_eq!(
+ ymwd(2018, 8, Weekday::Mon, 1),
+ Some(NaiveDate::from_ymd_opt(2018, 8, 6).unwrap())
+ );
+ assert_eq!(
+ ymwd(2018, 8, Weekday::Tue, 1),
+ Some(NaiveDate::from_ymd_opt(2018, 8, 7).unwrap())
+ );
+ assert_eq!(
+ ymwd(2018, 8, Weekday::Wed, 2),
+ Some(NaiveDate::from_ymd_opt(2018, 8, 8).unwrap())
+ );
+ assert_eq!(
+ ymwd(2018, 8, Weekday::Sun, 2),
+ Some(NaiveDate::from_ymd_opt(2018, 8, 12).unwrap())
+ );
+ assert_eq!(
+ ymwd(2018, 8, Weekday::Thu, 3),
+ Some(NaiveDate::from_ymd_opt(2018, 8, 16).unwrap())
+ );
+ assert_eq!(
+ ymwd(2018, 8, Weekday::Thu, 4),
+ Some(NaiveDate::from_ymd_opt(2018, 8, 23).unwrap())
+ );
+ assert_eq!(
+ ymwd(2018, 8, Weekday::Thu, 5),
+ Some(NaiveDate::from_ymd_opt(2018, 8, 30).unwrap())
+ );
+ assert_eq!(
+ ymwd(2018, 8, Weekday::Fri, 5),
+ Some(NaiveDate::from_ymd_opt(2018, 8, 31).unwrap())
+ );
assert_eq!(ymwd(2018, 8, Weekday::Sat, 5), None);
}
#[test]
fn test_date_fields() {
fn check(year: i32, month: u32, day: u32, ordinal: u32) {
- let d1 = NaiveDate::from_ymd(year, month, day);
+ let d1 = NaiveDate::from_ymd_opt(year, month, day).unwrap();
assert_eq!(d1.year(), year);
assert_eq!(d1.month(), month);
assert_eq!(d1.day(), day);
assert_eq!(d1.ordinal(), ordinal);
- let d2 = NaiveDate::from_yo(year, ordinal);
+ let d2 = NaiveDate::from_yo_opt(year, ordinal).unwrap();
assert_eq!(d2.year(), year);
assert_eq!(d2.month(), month);
assert_eq!(d2.day(), day);
@@ -2101,88 +2553,88 @@ mod tests {
#[test]
fn test_date_weekday() {
- assert_eq!(NaiveDate::from_ymd(1582, 10, 15).weekday(), Weekday::Fri);
+ assert_eq!(NaiveDate::from_ymd_opt(1582, 10, 15).unwrap().weekday(), Weekday::Fri);
// May 20, 1875 = ISO 8601 reference date
- assert_eq!(NaiveDate::from_ymd(1875, 5, 20).weekday(), Weekday::Thu);
- assert_eq!(NaiveDate::from_ymd(2000, 1, 1).weekday(), Weekday::Sat);
+ assert_eq!(NaiveDate::from_ymd_opt(1875, 5, 20).unwrap().weekday(), Weekday::Thu);
+ assert_eq!(NaiveDate::from_ymd_opt(2000, 1, 1).unwrap().weekday(), Weekday::Sat);
}
#[test]
fn test_date_with_fields() {
- let d = NaiveDate::from_ymd(2000, 2, 29);
- assert_eq!(d.with_year(-400), Some(NaiveDate::from_ymd(-400, 2, 29)));
+ let d = NaiveDate::from_ymd_opt(2000, 2, 29).unwrap();
+ assert_eq!(d.with_year(-400), Some(NaiveDate::from_ymd_opt(-400, 2, 29).unwrap()));
assert_eq!(d.with_year(-100), None);
- assert_eq!(d.with_year(1600), Some(NaiveDate::from_ymd(1600, 2, 29)));
+ assert_eq!(d.with_year(1600), Some(NaiveDate::from_ymd_opt(1600, 2, 29).unwrap()));
assert_eq!(d.with_year(1900), None);
- assert_eq!(d.with_year(2000), Some(NaiveDate::from_ymd(2000, 2, 29)));
+ assert_eq!(d.with_year(2000), Some(NaiveDate::from_ymd_opt(2000, 2, 29).unwrap()));
assert_eq!(d.with_year(2001), None);
- assert_eq!(d.with_year(2004), Some(NaiveDate::from_ymd(2004, 2, 29)));
+ assert_eq!(d.with_year(2004), Some(NaiveDate::from_ymd_opt(2004, 2, 29).unwrap()));
assert_eq!(d.with_year(i32::MAX), None);
- let d = NaiveDate::from_ymd(2000, 4, 30);
+ let d = NaiveDate::from_ymd_opt(2000, 4, 30).unwrap();
assert_eq!(d.with_month(0), None);
- assert_eq!(d.with_month(1), Some(NaiveDate::from_ymd(2000, 1, 30)));
+ assert_eq!(d.with_month(1), Some(NaiveDate::from_ymd_opt(2000, 1, 30).unwrap()));
assert_eq!(d.with_month(2), None);
- assert_eq!(d.with_month(3), Some(NaiveDate::from_ymd(2000, 3, 30)));
- assert_eq!(d.with_month(4), Some(NaiveDate::from_ymd(2000, 4, 30)));
- assert_eq!(d.with_month(12), Some(NaiveDate::from_ymd(2000, 12, 30)));
+ assert_eq!(d.with_month(3), Some(NaiveDate::from_ymd_opt(2000, 3, 30).unwrap()));
+ assert_eq!(d.with_month(4), Some(NaiveDate::from_ymd_opt(2000, 4, 30).unwrap()));
+ assert_eq!(d.with_month(12), Some(NaiveDate::from_ymd_opt(2000, 12, 30).unwrap()));
assert_eq!(d.with_month(13), None);
assert_eq!(d.with_month(u32::MAX), None);
- let d = NaiveDate::from_ymd(2000, 2, 8);
+ let d = NaiveDate::from_ymd_opt(2000, 2, 8).unwrap();
assert_eq!(d.with_day(0), None);
- assert_eq!(d.with_day(1), Some(NaiveDate::from_ymd(2000, 2, 1)));
- assert_eq!(d.with_day(29), Some(NaiveDate::from_ymd(2000, 2, 29)));
+ assert_eq!(d.with_day(1), Some(NaiveDate::from_ymd_opt(2000, 2, 1).unwrap()));
+ assert_eq!(d.with_day(29), Some(NaiveDate::from_ymd_opt(2000, 2, 29).unwrap()));
assert_eq!(d.with_day(30), None);
assert_eq!(d.with_day(u32::MAX), None);
- let d = NaiveDate::from_ymd(2000, 5, 5);
+ let d = NaiveDate::from_ymd_opt(2000, 5, 5).unwrap();
assert_eq!(d.with_ordinal(0), None);
- assert_eq!(d.with_ordinal(1), Some(NaiveDate::from_ymd(2000, 1, 1)));
- assert_eq!(d.with_ordinal(60), Some(NaiveDate::from_ymd(2000, 2, 29)));
- assert_eq!(d.with_ordinal(61), Some(NaiveDate::from_ymd(2000, 3, 1)));
- assert_eq!(d.with_ordinal(366), Some(NaiveDate::from_ymd(2000, 12, 31)));
+ assert_eq!(d.with_ordinal(1), Some(NaiveDate::from_ymd_opt(2000, 1, 1).unwrap()));
+ assert_eq!(d.with_ordinal(60), Some(NaiveDate::from_ymd_opt(2000, 2, 29).unwrap()));
+ assert_eq!(d.with_ordinal(61), Some(NaiveDate::from_ymd_opt(2000, 3, 1).unwrap()));
+ assert_eq!(d.with_ordinal(366), Some(NaiveDate::from_ymd_opt(2000, 12, 31).unwrap()));
assert_eq!(d.with_ordinal(367), None);
assert_eq!(d.with_ordinal(u32::MAX), None);
}
#[test]
fn test_date_num_days_from_ce() {
- assert_eq!(NaiveDate::from_ymd(1, 1, 1).num_days_from_ce(), 1);
+ assert_eq!(NaiveDate::from_ymd_opt(1, 1, 1).unwrap().num_days_from_ce(), 1);
for year in -9999..10001 {
assert_eq!(
- NaiveDate::from_ymd(year, 1, 1).num_days_from_ce(),
- NaiveDate::from_ymd(year - 1, 12, 31).num_days_from_ce() + 1
+ NaiveDate::from_ymd_opt(year, 1, 1).unwrap().num_days_from_ce(),
+ NaiveDate::from_ymd_opt(year - 1, 12, 31).unwrap().num_days_from_ce() + 1
);
}
}
#[test]
fn test_date_succ() {
- let ymd = |y, m, d| NaiveDate::from_ymd(y, m, d);
+ let ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap();
assert_eq!(ymd(2014, 5, 6).succ_opt(), Some(ymd(2014, 5, 7)));
assert_eq!(ymd(2014, 5, 31).succ_opt(), Some(ymd(2014, 6, 1)));
assert_eq!(ymd(2014, 12, 31).succ_opt(), Some(ymd(2015, 1, 1)));
assert_eq!(ymd(2016, 2, 28).succ_opt(), Some(ymd(2016, 2, 29)));
- assert_eq!(ymd(MAX_DATE.year(), 12, 31).succ_opt(), None);
+ assert_eq!(ymd(NaiveDate::MAX.year(), 12, 31).succ_opt(), None);
}
#[test]
fn test_date_pred() {
- let ymd = |y, m, d| NaiveDate::from_ymd(y, m, d);
+ let ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap();
assert_eq!(ymd(2016, 3, 1).pred_opt(), Some(ymd(2016, 2, 29)));
assert_eq!(ymd(2015, 1, 1).pred_opt(), Some(ymd(2014, 12, 31)));
assert_eq!(ymd(2014, 6, 1).pred_opt(), Some(ymd(2014, 5, 31)));
assert_eq!(ymd(2014, 5, 7).pred_opt(), Some(ymd(2014, 5, 6)));
- assert_eq!(ymd(MIN_DATE.year(), 1, 1).pred_opt(), None);
+ assert_eq!(ymd(NaiveDate::MIN.year(), 1, 1).pred_opt(), None);
}
#[test]
fn test_date_add() {
fn check((y1, m1, d1): (i32, u32, u32), rhs: Duration, ymd: Option<(i32, u32, u32)>) {
- let lhs = NaiveDate::from_ymd(y1, m1, d1);
- let sum = ymd.map(|(y, m, d)| NaiveDate::from_ymd(y, m, d));
+ let lhs = NaiveDate::from_ymd_opt(y1, m1, d1).unwrap();
+ let sum = ymd.map(|(y, m, d)| NaiveDate::from_ymd_opt(y, m, d).unwrap());
assert_eq!(lhs.checked_add_signed(rhs), sum);
assert_eq!(lhs.checked_sub_signed(-rhs), sum);
}
@@ -2211,8 +2663,8 @@ mod tests {
#[test]
fn test_date_sub() {
fn check((y1, m1, d1): (i32, u32, u32), (y2, m2, d2): (i32, u32, u32), diff: Duration) {
- let lhs = NaiveDate::from_ymd(y1, m1, d1);
- let rhs = NaiveDate::from_ymd(y2, m2, d2);
+ let lhs = NaiveDate::from_ymd_opt(y1, m1, d1).unwrap();
+ let rhs = NaiveDate::from_ymd_opt(y2, m2, d2).unwrap();
assert_eq!(lhs.signed_duration_since(rhs), diff);
assert_eq!(rhs.signed_duration_since(lhs), -diff);
}
@@ -2229,8 +2681,53 @@ mod tests {
}
#[test]
+ fn test_date_add_days() {
+ fn check((y1, m1, d1): (i32, u32, u32), rhs: Days, ymd: Option<(i32, u32, u32)>) {
+ let lhs = NaiveDate::from_ymd_opt(y1, m1, d1).unwrap();
+ let sum = ymd.map(|(y, m, d)| NaiveDate::from_ymd_opt(y, m, d).unwrap());
+ assert_eq!(lhs.checked_add_days(rhs), sum);
+ }
+
+ check((2014, 1, 1), Days::new(0), Some((2014, 1, 1)));
+ // always round towards zero
+ check((2014, 1, 1), Days::new(1), Some((2014, 1, 2)));
+ check((2014, 1, 1), Days::new(364), Some((2014, 12, 31)));
+ check((2014, 1, 1), Days::new(365 * 4 + 1), Some((2018, 1, 1)));
+ check((2014, 1, 1), Days::new(365 * 400 + 97), Some((2414, 1, 1)));
+
+ check((-7, 1, 1), Days::new(365 * 12 + 3), Some((5, 1, 1)));
+
+ // overflow check
+ check(
+ (0, 1, 1),
+ Days::new(MAX_DAYS_FROM_YEAR_0.try_into().unwrap()),
+ Some((MAX_YEAR, 12, 31)),
+ );
+ check((0, 1, 1), Days::new(u64::try_from(MAX_DAYS_FROM_YEAR_0).unwrap() + 1), None);
+ }
+
+ #[test]
+ fn test_date_sub_days() {
+ fn check((y1, m1, d1): (i32, u32, u32), (y2, m2, d2): (i32, u32, u32), diff: Days) {
+ let lhs = NaiveDate::from_ymd_opt(y1, m1, d1).unwrap();
+ let rhs = NaiveDate::from_ymd_opt(y2, m2, d2).unwrap();
+ assert_eq!(lhs - diff, rhs);
+ }
+
+ check((2014, 1, 1), (2014, 1, 1), Days::new(0));
+ check((2014, 1, 2), (2014, 1, 1), Days::new(1));
+ check((2014, 12, 31), (2014, 1, 1), Days::new(364));
+ check((2015, 1, 3), (2014, 1, 1), Days::new(365 + 2));
+ check((2018, 1, 1), (2014, 1, 1), Days::new(365 * 4 + 1));
+ check((2414, 1, 1), (2014, 1, 1), Days::new(365 * 400 + 97));
+
+ check((MAX_YEAR, 12, 31), (0, 1, 1), Days::new(MAX_DAYS_FROM_YEAR_0.try_into().unwrap()));
+ check((0, 1, 1), (MIN_YEAR, 1, 1), Days::new((-MIN_DAYS_FROM_YEAR_0).try_into().unwrap()));
+ }
+
+ #[test]
fn test_date_addassignment() {
- let ymd = NaiveDate::from_ymd;
+ let ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap();
let mut date = ymd(2016, 10, 1);
date += Duration::days(10);
assert_eq!(date, ymd(2016, 10, 11));
@@ -2240,7 +2737,7 @@ mod tests {
#[test]
fn test_date_subassignment() {
- let ymd = NaiveDate::from_ymd;
+ let ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap();
let mut date = ymd(2016, 10, 11);
date -= Duration::days(10);
assert_eq!(date, ymd(2016, 10, 1));
@@ -2250,19 +2747,22 @@ mod tests {
#[test]
fn test_date_fmt() {
- assert_eq!(format!("{:?}", NaiveDate::from_ymd(2012, 3, 4)), "2012-03-04");
- assert_eq!(format!("{:?}", NaiveDate::from_ymd(0, 3, 4)), "0000-03-04");
- assert_eq!(format!("{:?}", NaiveDate::from_ymd(-307, 3, 4)), "-0307-03-04");
- assert_eq!(format!("{:?}", NaiveDate::from_ymd(12345, 3, 4)), "+12345-03-04");
+ assert_eq!(format!("{:?}", NaiveDate::from_ymd_opt(2012, 3, 4).unwrap()), "2012-03-04");
+ assert_eq!(format!("{:?}", NaiveDate::from_ymd_opt(0, 3, 4).unwrap()), "0000-03-04");
+ assert_eq!(format!("{:?}", NaiveDate::from_ymd_opt(-307, 3, 4).unwrap()), "-0307-03-04");
+ assert_eq!(format!("{:?}", NaiveDate::from_ymd_opt(12345, 3, 4).unwrap()), "+12345-03-04");
- assert_eq!(NaiveDate::from_ymd(2012, 3, 4).to_string(), "2012-03-04");
- assert_eq!(NaiveDate::from_ymd(0, 3, 4).to_string(), "0000-03-04");
- assert_eq!(NaiveDate::from_ymd(-307, 3, 4).to_string(), "-0307-03-04");
- assert_eq!(NaiveDate::from_ymd(12345, 3, 4).to_string(), "+12345-03-04");
+ assert_eq!(NaiveDate::from_ymd_opt(2012, 3, 4).unwrap().to_string(), "2012-03-04");
+ assert_eq!(NaiveDate::from_ymd_opt(0, 3, 4).unwrap().to_string(), "0000-03-04");
+ assert_eq!(NaiveDate::from_ymd_opt(-307, 3, 4).unwrap().to_string(), "-0307-03-04");
+ assert_eq!(NaiveDate::from_ymd_opt(12345, 3, 4).unwrap().to_string(), "+12345-03-04");
// the format specifier should have no effect on `NaiveTime`
- assert_eq!(format!("{:+30?}", NaiveDate::from_ymd(1234, 5, 6)), "1234-05-06");
- assert_eq!(format!("{:30?}", NaiveDate::from_ymd(12345, 6, 7)), "+12345-06-07");
+ assert_eq!(format!("{:+30?}", NaiveDate::from_ymd_opt(1234, 5, 6).unwrap()), "1234-05-06");
+ assert_eq!(
+ format!("{:30?}", NaiveDate::from_ymd_opt(12345, 6, 7).unwrap()),
+ "+12345-06-07"
+ );
}
#[test]
@@ -2318,7 +2818,7 @@ mod tests {
#[test]
fn test_date_parse_from_str() {
- let ymd = |y, m, d| NaiveDate::from_ymd(y, m, d);
+ let ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap();
assert_eq!(
NaiveDate::parse_from_str("2014-5-7T12:34:56+09:30", "%Y-%m-%dT%H:%M:%S%z"),
Ok(ymd(2014, 5, 7))
@@ -2334,11 +2834,21 @@ mod tests {
assert!(NaiveDate::parse_from_str("Sat, 09 Aug 2013", "%a, %d %b %Y").is_err());
assert!(NaiveDate::parse_from_str("2014-57", "%Y-%m-%d").is_err());
assert!(NaiveDate::parse_from_str("2014", "%Y").is_err()); // insufficient
+
+ assert_eq!(
+ NaiveDate::parse_from_str("2020-01-0", "%Y-%W-%w").ok(),
+ NaiveDate::from_ymd_opt(2020, 1, 12),
+ );
+
+ assert_eq!(
+ NaiveDate::parse_from_str("2019-01-0", "%Y-%W-%w").ok(),
+ NaiveDate::from_ymd_opt(2019, 1, 13),
+ );
}
#[test]
fn test_date_format() {
- let d = NaiveDate::from_ymd(2012, 3, 4);
+ let d = NaiveDate::from_ymd_opt(2012, 3, 4).unwrap();
assert_eq!(d.format("%Y,%C,%y,%G,%g").to_string(), "2012,20,12,2012,12");
assert_eq!(d.format("%m,%b,%h,%B").to_string(), "03,Mar,Mar,March");
assert_eq!(d.format("%d,%e").to_string(), "04, 4");
@@ -2351,33 +2861,40 @@ mod tests {
assert_eq!(d.format("%t%n%%%n%t").to_string(), "\t\n%\n\t");
// non-four-digit years
- assert_eq!(NaiveDate::from_ymd(12345, 1, 1).format("%Y").to_string(), "+12345");
- assert_eq!(NaiveDate::from_ymd(1234, 1, 1).format("%Y").to_string(), "1234");
- assert_eq!(NaiveDate::from_ymd(123, 1, 1).format("%Y").to_string(), "0123");
- assert_eq!(NaiveDate::from_ymd(12, 1, 1).format("%Y").to_string(), "0012");
- assert_eq!(NaiveDate::from_ymd(1, 1, 1).format("%Y").to_string(), "0001");
- assert_eq!(NaiveDate::from_ymd(0, 1, 1).format("%Y").to_string(), "0000");
- assert_eq!(NaiveDate::from_ymd(-1, 1, 1).format("%Y").to_string(), "-0001");
- assert_eq!(NaiveDate::from_ymd(-12, 1, 1).format("%Y").to_string(), "-0012");
- assert_eq!(NaiveDate::from_ymd(-123, 1, 1).format("%Y").to_string(), "-0123");
- assert_eq!(NaiveDate::from_ymd(-1234, 1, 1).format("%Y").to_string(), "-1234");
- assert_eq!(NaiveDate::from_ymd(-12345, 1, 1).format("%Y").to_string(), "-12345");
+ assert_eq!(
+ NaiveDate::from_ymd_opt(12345, 1, 1).unwrap().format("%Y").to_string(),
+ "+12345"
+ );
+ assert_eq!(NaiveDate::from_ymd_opt(1234, 1, 1).unwrap().format("%Y").to_string(), "1234");
+ assert_eq!(NaiveDate::from_ymd_opt(123, 1, 1).unwrap().format("%Y").to_string(), "0123");
+ assert_eq!(NaiveDate::from_ymd_opt(12, 1, 1).unwrap().format("%Y").to_string(), "0012");
+ assert_eq!(NaiveDate::from_ymd_opt(1, 1, 1).unwrap().format("%Y").to_string(), "0001");
+ assert_eq!(NaiveDate::from_ymd_opt(0, 1, 1).unwrap().format("%Y").to_string(), "0000");
+ assert_eq!(NaiveDate::from_ymd_opt(-1, 1, 1).unwrap().format("%Y").to_string(), "-0001");
+ assert_eq!(NaiveDate::from_ymd_opt(-12, 1, 1).unwrap().format("%Y").to_string(), "-0012");
+ assert_eq!(NaiveDate::from_ymd_opt(-123, 1, 1).unwrap().format("%Y").to_string(), "-0123");
+ assert_eq!(NaiveDate::from_ymd_opt(-1234, 1, 1).unwrap().format("%Y").to_string(), "-1234");
+ assert_eq!(
+ NaiveDate::from_ymd_opt(-12345, 1, 1).unwrap().format("%Y").to_string(),
+ "-12345"
+ );
// corner cases
assert_eq!(
- NaiveDate::from_ymd(2007, 12, 31).format("%G,%g,%U,%W,%V").to_string(),
- "2008,08,53,53,01"
+ NaiveDate::from_ymd_opt(2007, 12, 31).unwrap().format("%G,%g,%U,%W,%V").to_string(),
+ "2008,08,52,53,01"
);
assert_eq!(
- NaiveDate::from_ymd(2010, 1, 3).format("%G,%g,%U,%W,%V").to_string(),
+ NaiveDate::from_ymd_opt(2010, 1, 3).unwrap().format("%G,%g,%U,%W,%V").to_string(),
"2009,09,01,00,53"
);
}
#[test]
fn test_day_iterator_limit() {
+ assert_eq!(NaiveDate::from_ymd_opt(262143, 12, 29).unwrap().iter_days().take(4).count(), 2);
assert_eq!(
- NaiveDate::from_ymd(262143, 12, 29).iter_days().take(4).collect::<Vec<_>>().len(),
+ NaiveDate::from_ymd_opt(-262144, 1, 3).unwrap().iter_days().rev().take(4).count(),
2
);
}
@@ -2385,8 +2902,96 @@ mod tests {
#[test]
fn test_week_iterator_limit() {
assert_eq!(
- NaiveDate::from_ymd(262143, 12, 12).iter_weeks().take(4).collect::<Vec<_>>().len(),
+ NaiveDate::from_ymd_opt(262143, 12, 12).unwrap().iter_weeks().take(4).count(),
+ 2
+ );
+ assert_eq!(
+ NaiveDate::from_ymd_opt(-262144, 1, 15).unwrap().iter_weeks().rev().take(4).count(),
2
);
}
+
+ #[test]
+ 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"),
+ ];
+ 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!(days.contains(&date));
+ }
+ }
+
+ #[test]
+ fn test_weeks_from() {
+ // tests per: https://github.com/chronotope/chrono/issues/961
+ // these internally use `weeks_from` via the parsing infrastructure
+ assert_eq!(
+ NaiveDate::parse_from_str("2020-01-0", "%Y-%W-%w").ok(),
+ NaiveDate::from_ymd_opt(2020, 1, 12),
+ );
+ assert_eq!(
+ NaiveDate::parse_from_str("2019-01-0", "%Y-%W-%w").ok(),
+ NaiveDate::from_ymd_opt(2019, 1, 13),
+ );
+
+ // direct tests
+ for (y, starts_on) in &[
+ (2019, Weekday::Tue),
+ (2020, Weekday::Wed),
+ (2021, Weekday::Fri),
+ (2022, Weekday::Sat),
+ (2023, Weekday::Sun),
+ (2024, Weekday::Mon),
+ (2025, Weekday::Wed),
+ (2026, Weekday::Thu),
+ ] {
+ for day in &[
+ Weekday::Mon,
+ Weekday::Tue,
+ Weekday::Wed,
+ Weekday::Thu,
+ Weekday::Fri,
+ Weekday::Sat,
+ Weekday::Sun,
+ ] {
+ assert_eq!(
+ NaiveDate::from_ymd_opt(*y, 1, 1).map(|d| d.weeks_from(*day)),
+ Some(if day == starts_on { 1 } else { 0 })
+ );
+
+ // last day must always be in week 52 or 53
+ assert!([52, 53]
+ .contains(&NaiveDate::from_ymd_opt(*y, 12, 31).unwrap().weeks_from(*day)),);
+ }
+ }
+
+ let base = NaiveDate::from_ymd_opt(2019, 1, 1).unwrap();
+
+ // 400 years covers all year types
+ for day in &[
+ Weekday::Mon,
+ Weekday::Tue,
+ Weekday::Wed,
+ Weekday::Thu,
+ Weekday::Fri,
+ Weekday::Sat,
+ Weekday::Sun,
+ ] {
+ // must always be below 54
+ for dplus in 1..(400 * 366) {
+ assert!((base + Days::new(dplus)).weeks_from(*day) < 54)
+ }
+ }
+ }
}
diff --git a/vendor/chrono/src/naive/datetime.rs b/vendor/chrono/src/naive/datetime.rs
deleted file mode 100644
index 92d6c2855..000000000
--- a/vendor/chrono/src/naive/datetime.rs
+++ /dev/null
@@ -1,2507 +0,0 @@
-// This is a part of Chrono.
-// See README.md and LICENSE.txt for details.
-
-//! ISO 8601 date and time without timezone.
-
-#[cfg(any(feature = "alloc", feature = "std", test))]
-use core::borrow::Borrow;
-use core::ops::{Add, AddAssign, Sub, SubAssign};
-use core::{fmt, hash, str};
-use num_traits::ToPrimitive;
-use oldtime::Duration as OldDuration;
-
-use div::div_mod_floor;
-#[cfg(any(feature = "alloc", feature = "std", test))]
-use format::DelayedFormat;
-use format::{parse, ParseError, ParseResult, Parsed, StrftimeItems};
-use format::{Fixed, Item, Numeric, Pad};
-use naive::date::{MAX_DATE, MIN_DATE};
-use naive::time::{MAX_TIME, MIN_TIME};
-use naive::{IsoWeek, NaiveDate, NaiveTime};
-use {Datelike, Timelike, Weekday};
-
-/// The tight upper bound guarantees that a duration with `|Duration| >= 2^MAX_SECS_BITS`
-/// will always overflow the addition with any date and time type.
-///
-/// So why is this needed? `Duration::seconds(rhs)` may overflow, and we don't have
-/// an alternative returning `Option` or `Result`. Thus we need some early bound to avoid
-/// touching that call when we are already sure that it WILL overflow...
-const MAX_SECS_BITS: usize = 44;
-
-/// The minimum possible `NaiveDateTime`.
-pub const MIN_DATETIME: NaiveDateTime = NaiveDateTime { date: MIN_DATE, time: MIN_TIME };
-/// The maximum possible `NaiveDateTime`.
-pub const MAX_DATETIME: NaiveDateTime = NaiveDateTime { date: MAX_DATE, time: MAX_TIME };
-
-/// ISO 8601 combined date and time without timezone.
-///
-/// # Example
-///
-/// `NaiveDateTime` is commonly created from [`NaiveDate`](./struct.NaiveDate.html).
-///
-/// ~~~~
-/// use chrono::{NaiveDate, NaiveDateTime};
-///
-/// let dt: NaiveDateTime = NaiveDate::from_ymd(2016, 7, 8).and_hms(9, 10, 11);
-/// # let _ = dt;
-/// ~~~~
-///
-/// You can use typical [date-like](../trait.Datelike.html) and
-/// [time-like](../trait.Timelike.html) methods,
-/// provided that relevant traits are in the scope.
-///
-/// ~~~~
-/// # use chrono::{NaiveDate, NaiveDateTime};
-/// # let dt: NaiveDateTime = NaiveDate::from_ymd(2016, 7, 8).and_hms(9, 10, 11);
-/// use chrono::{Datelike, Timelike, Weekday};
-///
-/// assert_eq!(dt.weekday(), Weekday::Fri);
-/// assert_eq!(dt.num_seconds_from_midnight(), 33011);
-/// ~~~~
-#[derive(PartialEq, Eq, PartialOrd, Ord, Copy, Clone)]
-pub struct NaiveDateTime {
- date: NaiveDate,
- time: NaiveTime,
-}
-
-impl NaiveDateTime {
- /// Makes a new `NaiveDateTime` from date and time components.
- /// Equivalent to [`date.and_time(time)`](./struct.NaiveDate.html#method.and_time)
- /// and many other helper constructors on `NaiveDate`.
- ///
- /// # Example
- ///
- /// ~~~~
- /// use chrono::{NaiveDate, NaiveTime, NaiveDateTime};
- ///
- /// let d = NaiveDate::from_ymd(2015, 6, 3);
- /// let t = NaiveTime::from_hms_milli(12, 34, 56, 789);
- ///
- /// let dt = NaiveDateTime::new(d, t);
- /// assert_eq!(dt.date(), d);
- /// assert_eq!(dt.time(), t);
- /// ~~~~
- #[inline]
- pub fn new(date: NaiveDate, time: NaiveTime) -> NaiveDateTime {
- NaiveDateTime { date: date, time: time }
- }
-
- /// Makes a new `NaiveDateTime` corresponding to a UTC date and time,
- /// from the number of non-leap seconds
- /// since the midnight UTC on January 1, 1970 (aka "UNIX timestamp")
- /// and the number of nanoseconds since the last whole non-leap second.
- ///
- /// For a non-naive version of this function see
- /// [`TimeZone::timestamp`](../offset/trait.TimeZone.html#method.timestamp).
- ///
- /// The nanosecond part can exceed 1,000,000,000 in order to represent the
- /// [leap second](./struct.NaiveTime.html#leap-second-handling). (The true "UNIX
- /// timestamp" cannot represent a leap second unambiguously.)
- ///
- /// Panics on the out-of-range number of seconds and/or invalid nanosecond.
- ///
- /// # Example
- ///
- /// ~~~~
- /// use chrono::{NaiveDateTime, NaiveDate};
- ///
- /// let dt = NaiveDateTime::from_timestamp(0, 42_000_000);
- /// assert_eq!(dt, NaiveDate::from_ymd(1970, 1, 1).and_hms_milli(0, 0, 0, 42));
- ///
- /// let dt = NaiveDateTime::from_timestamp(1_000_000_000, 0);
- /// assert_eq!(dt, NaiveDate::from_ymd(2001, 9, 9).and_hms(1, 46, 40));
- /// ~~~~
- #[inline]
- 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")
- }
-
- /// Makes a new `NaiveDateTime` corresponding to a UTC date and time,
- /// from the number of non-leap seconds
- /// since the midnight UTC on January 1, 1970 (aka "UNIX timestamp")
- /// and the number of nanoseconds since the last whole non-leap second.
- ///
- /// The nanosecond part can exceed 1,000,000,000
- /// in order to represent the [leap second](./struct.NaiveTime.html#leap-second-handling).
- /// (The true "UNIX timestamp" cannot represent a leap second unambiguously.)
- ///
- /// Returns `None` on the out-of-range number of seconds and/or invalid nanosecond.
- ///
- /// # Example
- ///
- /// ~~~~
- /// use chrono::{NaiveDateTime, NaiveDate};
- /// use std::i64;
- ///
- /// let from_timestamp_opt = NaiveDateTime::from_timestamp_opt;
- ///
- /// assert!(from_timestamp_opt(0, 0).is_some());
- /// assert!(from_timestamp_opt(0, 999_999_999).is_some());
- /// assert!(from_timestamp_opt(0, 1_500_000_000).is_some()); // leap second
- /// assert!(from_timestamp_opt(0, 2_000_000_000).is_none());
- /// assert!(from_timestamp_opt(i64::MAX, 0).is_none());
- /// ~~~~
- #[inline]
- 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()
- .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);
- match (date, time) {
- (Some(date), Some(time)) => Some(NaiveDateTime { date: date, time: time }),
- (_, _) => None,
- }
- }
-
- /// Parses a string with the specified format string and returns a new `NaiveDateTime`.
- /// See the [`format::strftime` module](../format/strftime/index.html)
- /// on the supported escape sequences.
- ///
- /// # Example
- ///
- /// ~~~~
- /// use chrono::{NaiveDateTime, NaiveDate};
- ///
- /// let parse_from_str = NaiveDateTime::parse_from_str;
- ///
- /// assert_eq!(parse_from_str("2015-09-05 23:56:04", "%Y-%m-%d %H:%M:%S"),
- /// Ok(NaiveDate::from_ymd(2015, 9, 5).and_hms(23, 56, 4)));
- /// assert_eq!(parse_from_str("5sep2015pm012345.6789", "%d%b%Y%p%I%M%S%.f"),
- /// Ok(NaiveDate::from_ymd(2015, 9, 5).and_hms_micro(13, 23, 45, 678_900)));
- /// ~~~~
- ///
- /// Offset is ignored for the purpose of parsing.
- ///
- /// ~~~~
- /// # use chrono::{NaiveDateTime, NaiveDate};
- /// # let parse_from_str = NaiveDateTime::parse_from_str;
- /// assert_eq!(parse_from_str("2014-5-17T12:34:56+09:30", "%Y-%m-%dT%H:%M:%S%z"),
- /// Ok(NaiveDate::from_ymd(2014, 5, 17).and_hms(12, 34, 56)));
- /// ~~~~
- ///
- /// [Leap seconds](./struct.NaiveTime.html#leap-second-handling) are correctly handled by
- /// treating any time of the form `hh:mm:60` as a leap second.
- /// (This equally applies to the formatting, so the round trip is possible.)
- ///
- /// ~~~~
- /// # use chrono::{NaiveDateTime, NaiveDate};
- /// # let parse_from_str = NaiveDateTime::parse_from_str;
- /// assert_eq!(parse_from_str("2015-07-01 08:59:60.123", "%Y-%m-%d %H:%M:%S%.f"),
- /// Ok(NaiveDate::from_ymd(2015, 7, 1).and_hms_milli(8, 59, 59, 1_123)));
- /// ~~~~
- ///
- /// Missing seconds are assumed to be zero,
- /// but out-of-bound times or insufficient fields are errors otherwise.
- ///
- /// ~~~~
- /// # use chrono::{NaiveDateTime, NaiveDate};
- /// # let parse_from_str = NaiveDateTime::parse_from_str;
- /// assert_eq!(parse_from_str("94/9/4 7:15", "%y/%m/%d %H:%M"),
- /// Ok(NaiveDate::from_ymd(1994, 9, 4).and_hms(7, 15, 0)));
- ///
- /// assert!(parse_from_str("04m33s", "%Mm%Ss").is_err());
- /// assert!(parse_from_str("94/9/4 12", "%y/%m/%d %H").is_err());
- /// assert!(parse_from_str("94/9/4 17:60", "%y/%m/%d %H:%M").is_err());
- /// assert!(parse_from_str("94/9/4 24:00:00", "%y/%m/%d %H:%M:%S").is_err());
- /// ~~~~
- ///
- /// All parsed fields should be consistent to each other, otherwise it's an error.
- ///
- /// ~~~~
- /// # use chrono::NaiveDateTime;
- /// # let parse_from_str = NaiveDateTime::parse_from_str;
- /// let fmt = "%Y-%m-%d %H:%M:%S = UNIX timestamp %s";
- /// assert!(parse_from_str("2001-09-09 01:46:39 = UNIX timestamp 999999999", fmt).is_ok());
- /// assert!(parse_from_str("1970-01-01 00:00:00 = UNIX timestamp 1", fmt).is_err());
- /// ~~~~
- 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
- }
-
- /// Retrieves a date component.
- ///
- /// # Example
- ///
- /// ~~~~
- /// use chrono::NaiveDate;
- ///
- /// let dt = NaiveDate::from_ymd(2016, 7, 8).and_hms(9, 10, 11);
- /// assert_eq!(dt.date(), NaiveDate::from_ymd(2016, 7, 8));
- /// ~~~~
- #[inline]
- pub fn date(&self) -> NaiveDate {
- self.date
- }
-
- /// Retrieves a time component.
- ///
- /// # Example
- ///
- /// ~~~~
- /// use chrono::{NaiveDate, NaiveTime};
- ///
- /// let dt = NaiveDate::from_ymd(2016, 7, 8).and_hms(9, 10, 11);
- /// assert_eq!(dt.time(), NaiveTime::from_hms(9, 10, 11));
- /// ~~~~
- #[inline]
- pub fn time(&self) -> NaiveTime {
- self.time
- }
-
- /// Returns the number of non-leap seconds since the midnight on January 1, 1970.
- ///
- /// Note that this does *not* account for the timezone!
- /// The true "UNIX timestamp" would count seconds since the midnight *UTC* on the epoch.
- ///
- /// # Example
- ///
- /// ~~~~
- /// use chrono::NaiveDate;
- ///
- /// let dt = NaiveDate::from_ymd(1970, 1, 1).and_hms_milli(0, 0, 1, 980);
- /// assert_eq!(dt.timestamp(), 1);
- ///
- /// let dt = NaiveDate::from_ymd(2001, 9, 9).and_hms(1, 46, 40);
- /// assert_eq!(dt.timestamp(), 1_000_000_000);
- ///
- /// let dt = NaiveDate::from_ymd(1969, 12, 31).and_hms(23, 59, 59);
- /// assert_eq!(dt.timestamp(), -1);
- ///
- /// let dt = NaiveDate::from_ymd(-1, 1, 1).and_hms(0, 0, 0);
- /// assert_eq!(dt.timestamp(), -62198755200);
- /// ~~~~
- #[inline]
- pub fn timestamp(&self) -> i64 {
- const UNIX_EPOCH_DAY: i64 = 719_163;
- let gregorian_day = i64::from(self.date.num_days_from_ce());
- let seconds_from_midnight = i64::from(self.time.num_seconds_from_midnight());
- (gregorian_day - UNIX_EPOCH_DAY) * 86_400 + seconds_from_midnight
- }
-
- /// Returns the number of non-leap *milliseconds* since midnight on January 1, 1970.
- ///
- /// Note that this does *not* account for the timezone!
- /// The true "UNIX timestamp" would count seconds since the midnight *UTC* on the epoch.
- ///
- /// Note also that this does reduce the number of years that can be
- /// represented from ~584 Billion to ~584 Million. (If this is a problem,
- /// please file an issue to let me know what domain needs millisecond
- /// precision over billions of years, I'm curious.)
- ///
- /// # Example
- ///
- /// ~~~~
- /// use chrono::NaiveDate;
- ///
- /// let dt = NaiveDate::from_ymd(1970, 1, 1).and_hms_milli(0, 0, 1, 444);
- /// assert_eq!(dt.timestamp_millis(), 1_444);
- ///
- /// let dt = NaiveDate::from_ymd(2001, 9, 9).and_hms_milli(1, 46, 40, 555);
- /// assert_eq!(dt.timestamp_millis(), 1_000_000_000_555);
- ///
- /// let dt = NaiveDate::from_ymd(1969, 12, 31).and_hms_milli(23, 59, 59, 100);
- /// assert_eq!(dt.timestamp_millis(), -900);
- /// ~~~~
- #[inline]
- pub fn timestamp_millis(&self) -> i64 {
- let as_ms = self.timestamp() * 1000;
- as_ms + i64::from(self.timestamp_subsec_millis())
- }
-
- /// Returns the number of non-leap *nanoseconds* since midnight on January 1, 1970.
- ///
- /// Note that this does *not* account for the timezone!
- /// The true "UNIX timestamp" would count seconds since the midnight *UTC* on the epoch.
- ///
- /// # Panics
- ///
- /// Note also that this does reduce the number of years that can be
- /// represented from ~584 Billion to ~584 years. The dates that can be
- /// represented as nanoseconds are between 1677-09-21T00:12:44.0 and
- /// 2262-04-11T23:47:16.854775804.
- ///
- /// (If this is a problem, please file an issue to let me know what domain
- /// needs nanosecond precision over millennia, I'm curious.)
- ///
- /// # Example
- ///
- /// ~~~~
- /// use chrono::{NaiveDate, NaiveDateTime};
- ///
- /// let dt = NaiveDate::from_ymd(1970, 1, 1).and_hms_nano(0, 0, 1, 444);
- /// assert_eq!(dt.timestamp_nanos(), 1_000_000_444);
- ///
- /// let dt = NaiveDate::from_ymd(2001, 9, 9).and_hms_nano(1, 46, 40, 555);
- ///
- /// const A_BILLION: i64 = 1_000_000_000;
- /// 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)
- /// );
- /// ~~~~
- #[inline]
- pub fn timestamp_nanos(&self) -> i64 {
- let as_ns = self.timestamp() * 1_000_000_000;
- as_ns + i64::from(self.timestamp_subsec_nanos())
- }
-
- /// Returns the number of milliseconds since the last whole non-leap second.
- ///
- /// The return value ranges from 0 to 999,
- /// or for [leap seconds](./struct.NaiveTime.html#leap-second-handling), to 1,999.
- ///
- /// # Example
- ///
- /// ~~~~
- /// use chrono::NaiveDate;
- ///
- /// let dt = NaiveDate::from_ymd(2016, 7, 8).and_hms_nano(9, 10, 11, 123_456_789);
- /// assert_eq!(dt.timestamp_subsec_millis(), 123);
- ///
- /// let dt = NaiveDate::from_ymd(2015, 7, 1).and_hms_nano(8, 59, 59, 1_234_567_890);
- /// assert_eq!(dt.timestamp_subsec_millis(), 1_234);
- /// ~~~~
- #[inline]
- pub fn timestamp_subsec_millis(&self) -> u32 {
- self.timestamp_subsec_nanos() / 1_000_000
- }
-
- /// Returns the number of microseconds since the last whole non-leap second.
- ///
- /// The return value ranges from 0 to 999,999,
- /// or for [leap seconds](./struct.NaiveTime.html#leap-second-handling), to 1,999,999.
- ///
- /// # Example
- ///
- /// ~~~~
- /// use chrono::NaiveDate;
- ///
- /// let dt = NaiveDate::from_ymd(2016, 7, 8).and_hms_nano(9, 10, 11, 123_456_789);
- /// assert_eq!(dt.timestamp_subsec_micros(), 123_456);
- ///
- /// let dt = NaiveDate::from_ymd(2015, 7, 1).and_hms_nano(8, 59, 59, 1_234_567_890);
- /// assert_eq!(dt.timestamp_subsec_micros(), 1_234_567);
- /// ~~~~
- #[inline]
- pub fn timestamp_subsec_micros(&self) -> u32 {
- self.timestamp_subsec_nanos() / 1_000
- }
-
- /// Returns the number of nanoseconds since the last whole non-leap second.
- ///
- /// The return value ranges from 0 to 999,999,999,
- /// or for [leap seconds](./struct.NaiveTime.html#leap-second-handling), to 1,999,999,999.
- ///
- /// # Example
- ///
- /// ~~~~
- /// use chrono::NaiveDate;
- ///
- /// let dt = NaiveDate::from_ymd(2016, 7, 8).and_hms_nano(9, 10, 11, 123_456_789);
- /// assert_eq!(dt.timestamp_subsec_nanos(), 123_456_789);
- ///
- /// let dt = NaiveDate::from_ymd(2015, 7, 1).and_hms_nano(8, 59, 59, 1_234_567_890);
- /// assert_eq!(dt.timestamp_subsec_nanos(), 1_234_567_890);
- /// ~~~~
- #[inline]
- pub fn timestamp_subsec_nanos(&self) -> u32 {
- self.time.nanosecond()
- }
-
- /// Adds given `Duration` to the current date and time.
- ///
- /// 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**.
- ///
- /// Returns `None` when it will result in overflow.
- ///
- /// # Example
- ///
- /// ~~~~
- /// # extern crate chrono; fn main() {
- /// use chrono::{Duration, NaiveDate};
- ///
- /// let from_ymd = NaiveDate::from_ymd;
- ///
- /// let d = from_ymd(2016, 7, 8);
- /// let hms = |h, m, s| d.and_hms(h, m, s);
- /// assert_eq!(hms(3, 5, 7).checked_add_signed(Duration::zero()),
- /// Some(hms(3, 5, 7)));
- /// assert_eq!(hms(3, 5, 7).checked_add_signed(Duration::seconds(1)),
- /// Some(hms(3, 5, 8)));
- /// assert_eq!(hms(3, 5, 7).checked_add_signed(Duration::seconds(-1)),
- /// Some(hms(3, 5, 6)));
- /// assert_eq!(hms(3, 5, 7).checked_add_signed(Duration::seconds(3600 + 60)),
- /// Some(hms(4, 6, 7)));
- /// assert_eq!(hms(3, 5, 7).checked_add_signed(Duration::seconds(86_400)),
- /// Some(from_ymd(2016, 7, 9).and_hms(3, 5, 7)));
- ///
- /// let hmsm = |h, m, s, milli| d.and_hms_milli(h, m, s, milli);
- /// assert_eq!(hmsm(3, 5, 7, 980).checked_add_signed(Duration::milliseconds(450)),
- /// Some(hmsm(3, 5, 8, 430)));
- /// # }
- /// ~~~~
- ///
- /// Overflow returns `None`.
- ///
- /// ~~~~
- /// # extern crate chrono; fn main() {
- /// # use chrono::{Duration, NaiveDate};
- /// # let hms = |h, m, s| NaiveDate::from_ymd(2016, 7, 8).and_hms(h, m, s);
- /// assert_eq!(hms(3, 5, 7).checked_add_signed(Duration::days(1_000_000_000)), None);
- /// # }
- /// ~~~~
- ///
- /// Leap seconds are handled,
- /// but the addition assumes that it is the only leap second happened.
- ///
- /// ~~~~
- /// # extern crate chrono; fn main() {
- /// # use chrono::{Duration, NaiveDate};
- /// # let from_ymd = NaiveDate::from_ymd;
- /// # let hmsm = |h, m, s, milli| from_ymd(2016, 7, 8).and_hms_milli(h, m, s, milli);
- /// let leap = hmsm(3, 5, 59, 1_300);
- /// assert_eq!(leap.checked_add_signed(Duration::zero()),
- /// Some(hmsm(3, 5, 59, 1_300)));
- /// assert_eq!(leap.checked_add_signed(Duration::milliseconds(-500)),
- /// Some(hmsm(3, 5, 59, 800)));
- /// assert_eq!(leap.checked_add_signed(Duration::milliseconds(500)),
- /// Some(hmsm(3, 5, 59, 1_800)));
- /// assert_eq!(leap.checked_add_signed(Duration::milliseconds(800)),
- /// Some(hmsm(3, 6, 0, 100)));
- /// assert_eq!(leap.checked_add_signed(Duration::seconds(10)),
- /// Some(hmsm(3, 6, 9, 300)));
- /// assert_eq!(leap.checked_add_signed(Duration::seconds(-10)),
- /// Some(hmsm(3, 5, 50, 300)));
- /// assert_eq!(leap.checked_add_signed(Duration::days(1)),
- /// Some(from_ymd(2016, 7, 9).and_hms_milli(3, 5, 59, 300)));
- /// # }
- /// ~~~~
- pub fn checked_add_signed(self, rhs: OldDuration) -> Option<NaiveDateTime> {
- let (time, rhs) = self.time.overflowing_add_signed(rhs);
-
- // early checking to avoid overflow in OldDuration::seconds
- if rhs <= (-1 << MAX_SECS_BITS) || rhs >= (1 << MAX_SECS_BITS) {
- return None;
- }
-
- let date = try_opt!(self.date.checked_add_signed(OldDuration::seconds(rhs)));
- Some(NaiveDateTime { date: date, time: time })
- }
-
- /// Subtracts given `Duration` from the current date and time.
- ///
- /// As a part of Chrono's [leap second handling](./struct.NaiveTime.html#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**.
- ///
- /// Returns `None` when it will result in overflow.
- ///
- /// # Example
- ///
- /// ~~~~
- /// # extern crate chrono; fn main() {
- /// use chrono::{Duration, NaiveDate};
- ///
- /// let from_ymd = NaiveDate::from_ymd;
- ///
- /// let d = from_ymd(2016, 7, 8);
- /// let hms = |h, m, s| d.and_hms(h, m, s);
- /// assert_eq!(hms(3, 5, 7).checked_sub_signed(Duration::zero()),
- /// Some(hms(3, 5, 7)));
- /// assert_eq!(hms(3, 5, 7).checked_sub_signed(Duration::seconds(1)),
- /// Some(hms(3, 5, 6)));
- /// assert_eq!(hms(3, 5, 7).checked_sub_signed(Duration::seconds(-1)),
- /// Some(hms(3, 5, 8)));
- /// assert_eq!(hms(3, 5, 7).checked_sub_signed(Duration::seconds(3600 + 60)),
- /// Some(hms(2, 4, 7)));
- /// assert_eq!(hms(3, 5, 7).checked_sub_signed(Duration::seconds(86_400)),
- /// Some(from_ymd(2016, 7, 7).and_hms(3, 5, 7)));
- ///
- /// let hmsm = |h, m, s, milli| d.and_hms_milli(h, m, s, milli);
- /// assert_eq!(hmsm(3, 5, 7, 450).checked_sub_signed(Duration::milliseconds(670)),
- /// Some(hmsm(3, 5, 6, 780)));
- /// # }
- /// ~~~~
- ///
- /// Overflow returns `None`.
- ///
- /// ~~~~
- /// # extern crate chrono; fn main() {
- /// # use chrono::{Duration, NaiveDate};
- /// # let hms = |h, m, s| NaiveDate::from_ymd(2016, 7, 8).and_hms(h, m, s);
- /// assert_eq!(hms(3, 5, 7).checked_sub_signed(Duration::days(1_000_000_000)), None);
- /// # }
- /// ~~~~
- ///
- /// Leap seconds are handled,
- /// but the subtraction assumes that it is the only leap second happened.
- ///
- /// ~~~~
- /// # extern crate chrono; fn main() {
- /// # use chrono::{Duration, NaiveDate};
- /// # let from_ymd = NaiveDate::from_ymd;
- /// # let hmsm = |h, m, s, milli| from_ymd(2016, 7, 8).and_hms_milli(h, m, s, milli);
- /// let leap = hmsm(3, 5, 59, 1_300);
- /// assert_eq!(leap.checked_sub_signed(Duration::zero()),
- /// Some(hmsm(3, 5, 59, 1_300)));
- /// assert_eq!(leap.checked_sub_signed(Duration::milliseconds(200)),
- /// Some(hmsm(3, 5, 59, 1_100)));
- /// assert_eq!(leap.checked_sub_signed(Duration::milliseconds(500)),
- /// Some(hmsm(3, 5, 59, 800)));
- /// assert_eq!(leap.checked_sub_signed(Duration::seconds(60)),
- /// Some(hmsm(3, 5, 0, 300)));
- /// assert_eq!(leap.checked_sub_signed(Duration::days(1)),
- /// Some(from_ymd(2016, 7, 7).and_hms_milli(3, 6, 0, 300)));
- /// # }
- /// ~~~~
- pub fn checked_sub_signed(self, rhs: OldDuration) -> Option<NaiveDateTime> {
- let (time, rhs) = self.time.overflowing_sub_signed(rhs);
-
- // early checking to avoid overflow in OldDuration::seconds
- if rhs <= (-1 << MAX_SECS_BITS) || rhs >= (1 << MAX_SECS_BITS) {
- return None;
- }
-
- let date = try_opt!(self.date.checked_sub_signed(OldDuration::seconds(rhs)));
- Some(NaiveDateTime { date: date, time: time })
- }
-
- /// Subtracts another `NaiveDateTime` from the current date and time.
- /// This does not overflow or underflow at all.
- ///
- /// As a part of Chrono's [leap second handling](./struct.NaiveTime.html#leap-second-handling),
- /// the subtraction assumes that **there is no leap second ever**,
- /// except when any of the `NaiveDateTime`s themselves represents a leap second
- /// in which case the assumption becomes that
- /// **there are exactly one (or two) leap second(s) ever**.
- ///
- /// # Example
- ///
- /// ~~~~
- /// # extern crate chrono; fn main() {
- /// use chrono::{Duration, NaiveDate};
- ///
- /// let from_ymd = NaiveDate::from_ymd;
- ///
- /// let d = from_ymd(2016, 7, 8);
- /// assert_eq!(d.and_hms(3, 5, 7).signed_duration_since(d.and_hms(2, 4, 6)),
- /// Duration::seconds(3600 + 60 + 1));
- ///
- /// // July 8 is 190th day in the year 2016
- /// let d0 = from_ymd(2016, 1, 1);
- /// assert_eq!(d.and_hms_milli(0, 7, 6, 500).signed_duration_since(d0.and_hms(0, 0, 0)),
- /// Duration::seconds(189 * 86_400 + 7 * 60 + 6) + Duration::milliseconds(500));
- /// # }
- /// ~~~~
- ///
- /// Leap seconds are handled, but the subtraction assumes that
- /// there were no other leap seconds happened.
- ///
- /// ~~~~
- /// # extern crate chrono; fn main() {
- /// # use chrono::{Duration, NaiveDate};
- /// # let from_ymd = NaiveDate::from_ymd;
- /// let leap = from_ymd(2015, 6, 30).and_hms_milli(23, 59, 59, 1_500);
- /// assert_eq!(leap.signed_duration_since(from_ymd(2015, 6, 30).and_hms(23, 0, 0)),
- /// Duration::seconds(3600) + Duration::milliseconds(500));
- /// assert_eq!(from_ymd(2015, 7, 1).and_hms(1, 0, 0).signed_duration_since(leap),
- /// Duration::seconds(3600) - Duration::milliseconds(500));
- /// # }
- /// ~~~~
- pub fn signed_duration_since(self, rhs: NaiveDateTime) -> OldDuration {
- self.date.signed_duration_since(rhs.date) + self.time.signed_duration_since(rhs.time)
- }
-
- /// Formats the combined date and time with the specified formatting items.
- /// Otherwise it is the same as the ordinary [`format`](#method.format) method.
- ///
- /// The `Iterator` of items should be `Clone`able,
- /// since the resulting `DelayedFormat` value may be formatted multiple times.
- ///
- /// # Example
- ///
- /// ~~~~
- /// use chrono::NaiveDate;
- /// use chrono::format::strftime::StrftimeItems;
- ///
- /// let fmt = StrftimeItems::new("%Y-%m-%d %H:%M:%S");
- /// let dt = NaiveDate::from_ymd(2015, 9, 5).and_hms(23, 56, 4);
- /// assert_eq!(dt.format_with_items(fmt.clone()).to_string(), "2015-09-05 23:56:04");
- /// assert_eq!(dt.format("%Y-%m-%d %H:%M:%S").to_string(), "2015-09-05 23:56:04");
- /// ~~~~
- ///
- /// The resulting `DelayedFormat` can be formatted directly via the `Display` trait.
- ///
- /// ~~~~
- /// # use chrono::NaiveDate;
- /// # use chrono::format::strftime::StrftimeItems;
- /// # let fmt = StrftimeItems::new("%Y-%m-%d %H:%M:%S").clone();
- /// # let dt = NaiveDate::from_ymd(2015, 9, 5).and_hms(23, 56, 4);
- /// assert_eq!(format!("{}", dt.format_with_items(fmt)), "2015-09-05 23:56:04");
- /// ~~~~
- #[cfg(any(feature = "alloc", feature = "std", test))]
- #[inline]
- pub fn format_with_items<'a, I, B>(&self, items: I) -> DelayedFormat<I>
- where
- I: Iterator<Item = B> + Clone,
- B: Borrow<Item<'a>>,
- {
- DelayedFormat::new(Some(self.date), Some(self.time), items)
- }
-
- /// Formats the combined date and time with the specified format string.
- /// See the [`format::strftime` module](../format/strftime/index.html)
- /// on the supported escape sequences.
- ///
- /// This returns a `DelayedFormat`,
- /// which gets converted to a string only when actual formatting happens.
- /// You may use the `to_string` method to get a `String`,
- /// or just feed it into `print!` and other formatting macros.
- /// (In this way it avoids the redundant memory allocation.)
- ///
- /// A wrong format string does *not* issue an error immediately.
- /// Rather, converting or formatting the `DelayedFormat` fails.
- /// You are recommended to immediately use `DelayedFormat` for this reason.
- ///
- /// # Example
- ///
- /// ~~~~
- /// use chrono::NaiveDate;
- ///
- /// let dt = NaiveDate::from_ymd(2015, 9, 5).and_hms(23, 56, 4);
- /// assert_eq!(dt.format("%Y-%m-%d %H:%M:%S").to_string(), "2015-09-05 23:56:04");
- /// assert_eq!(dt.format("around %l %p on %b %-d").to_string(), "around 11 PM on Sep 5");
- /// ~~~~
- ///
- /// The resulting `DelayedFormat` can be formatted directly via the `Display` trait.
- ///
- /// ~~~~
- /// # use chrono::NaiveDate;
- /// # let dt = NaiveDate::from_ymd(2015, 9, 5).and_hms(23, 56, 4);
- /// assert_eq!(format!("{}", dt.format("%Y-%m-%d %H:%M:%S")), "2015-09-05 23:56:04");
- /// assert_eq!(format!("{}", dt.format("around %l %p on %b %-d")), "around 11 PM on Sep 5");
- /// ~~~~
- #[cfg(any(feature = "alloc", feature = "std", test))]
- #[inline]
- pub fn format<'a>(&self, fmt: &'a str) -> DelayedFormat<StrftimeItems<'a>> {
- self.format_with_items(StrftimeItems::new(fmt))
- }
-}
-
-impl Datelike for NaiveDateTime {
- /// Returns the year number in the [calendar date](./index.html#calendar-date).
- ///
- /// See also the [`NaiveDate::year`](./struct.NaiveDate.html#method.year) method.
- ///
- /// # Example
- ///
- /// ~~~~
- /// use chrono::{NaiveDate, NaiveDateTime, Datelike};
- ///
- /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 25).and_hms(12, 34, 56);
- /// assert_eq!(dt.year(), 2015);
- /// ~~~~
- #[inline]
- fn year(&self) -> i32 {
- self.date.year()
- }
-
- /// Returns the month number starting from 1.
- ///
- /// The return value ranges from 1 to 12.
- ///
- /// See also the [`NaiveDate::month`](./struct.NaiveDate.html#method.month) method.
- ///
- /// # Example
- ///
- /// ~~~~
- /// use chrono::{NaiveDate, NaiveDateTime, Datelike};
- ///
- /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 25).and_hms(12, 34, 56);
- /// assert_eq!(dt.month(), 9);
- /// ~~~~
- #[inline]
- fn month(&self) -> u32 {
- self.date.month()
- }
-
- /// Returns the month number starting from 0.
- ///
- /// The return value ranges from 0 to 11.
- ///
- /// See also the [`NaiveDate::month0`](./struct.NaiveDate.html#method.month0) method.
- ///
- /// # Example
- ///
- /// ~~~~
- /// use chrono::{NaiveDate, NaiveDateTime, Datelike};
- ///
- /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 25).and_hms(12, 34, 56);
- /// assert_eq!(dt.month0(), 8);
- /// ~~~~
- #[inline]
- fn month0(&self) -> u32 {
- self.date.month0()
- }
-
- /// Returns the day of month starting from 1.
- ///
- /// The return value ranges from 1 to 31. (The last day of month differs by months.)
- ///
- /// See also the [`NaiveDate::day`](./struct.NaiveDate.html#method.day) method.
- ///
- /// # Example
- ///
- /// ~~~~
- /// use chrono::{NaiveDate, NaiveDateTime, Datelike};
- ///
- /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 25).and_hms(12, 34, 56);
- /// assert_eq!(dt.day(), 25);
- /// ~~~~
- #[inline]
- fn day(&self) -> u32 {
- self.date.day()
- }
-
- /// Returns the day of month starting from 0.
- ///
- /// The return value ranges from 0 to 30. (The last day of month differs by months.)
- ///
- /// See also the [`NaiveDate::day0`](./struct.NaiveDate.html#method.day0) method.
- ///
- /// # Example
- ///
- /// ~~~~
- /// use chrono::{NaiveDate, NaiveDateTime, Datelike};
- ///
- /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 25).and_hms(12, 34, 56);
- /// assert_eq!(dt.day0(), 24);
- /// ~~~~
- #[inline]
- fn day0(&self) -> u32 {
- self.date.day0()
- }
-
- /// Returns the day of year starting from 1.
- ///
- /// The return value ranges from 1 to 366. (The last day of year differs by years.)
- ///
- /// See also the [`NaiveDate::ordinal`](./struct.NaiveDate.html#method.ordinal) method.
- ///
- /// # Example
- ///
- /// ~~~~
- /// use chrono::{NaiveDate, NaiveDateTime, Datelike};
- ///
- /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 25).and_hms(12, 34, 56);
- /// assert_eq!(dt.ordinal(), 268);
- /// ~~~~
- #[inline]
- fn ordinal(&self) -> u32 {
- self.date.ordinal()
- }
-
- /// Returns the day of year starting from 0.
- ///
- /// The return value ranges from 0 to 365. (The last day of year differs by years.)
- ///
- /// See also the [`NaiveDate::ordinal0`](./struct.NaiveDate.html#method.ordinal0) method.
- ///
- /// # Example
- ///
- /// ~~~~
- /// use chrono::{NaiveDate, NaiveDateTime, Datelike};
- ///
- /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 25).and_hms(12, 34, 56);
- /// assert_eq!(dt.ordinal0(), 267);
- /// ~~~~
- #[inline]
- fn ordinal0(&self) -> u32 {
- self.date.ordinal0()
- }
-
- /// Returns the day of week.
- ///
- /// See also the [`NaiveDate::weekday`](./struct.NaiveDate.html#method.weekday) method.
- ///
- /// # Example
- ///
- /// ~~~~
- /// use chrono::{NaiveDate, NaiveDateTime, Datelike, Weekday};
- ///
- /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 25).and_hms(12, 34, 56);
- /// assert_eq!(dt.weekday(), Weekday::Fri);
- /// ~~~~
- #[inline]
- fn weekday(&self) -> Weekday {
- self.date.weekday()
- }
-
- #[inline]
- fn iso_week(&self) -> IsoWeek {
- self.date.iso_week()
- }
-
- /// Makes a new `NaiveDateTime` with the year number changed.
- ///
- /// Returns `None` when the resulting `NaiveDateTime` would be invalid.
- ///
- /// See also the
- /// [`NaiveDate::with_year`](./struct.NaiveDate.html#method.with_year) method.
- ///
- /// # Example
- ///
- /// ~~~~
- /// use chrono::{NaiveDate, NaiveDateTime, Datelike};
- ///
- /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 25).and_hms(12, 34, 56);
- /// assert_eq!(dt.with_year(2016), Some(NaiveDate::from_ymd(2016, 9, 25).and_hms(12, 34, 56)));
- /// assert_eq!(dt.with_year(-308), Some(NaiveDate::from_ymd(-308, 9, 25).and_hms(12, 34, 56)));
- /// ~~~~
- #[inline]
- fn with_year(&self, year: i32) -> Option<NaiveDateTime> {
- self.date.with_year(year).map(|d| NaiveDateTime { date: d, ..*self })
- }
-
- /// Makes a new `NaiveDateTime` with the month number (starting from 1) changed.
- ///
- /// Returns `None` when the resulting `NaiveDateTime` would be invalid.
- ///
- /// See also the
- /// [`NaiveDate::with_month`](./struct.NaiveDate.html#method.with_month) method.
- ///
- /// # Example
- ///
- /// ~~~~
- /// use chrono::{NaiveDate, NaiveDateTime, Datelike};
- ///
- /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 30).and_hms(12, 34, 56);
- /// assert_eq!(dt.with_month(10), Some(NaiveDate::from_ymd(2015, 10, 30).and_hms(12, 34, 56)));
- /// assert_eq!(dt.with_month(13), None); // no month 13
- /// assert_eq!(dt.with_month(2), None); // no February 30
- /// ~~~~
- #[inline]
- fn with_month(&self, month: u32) -> Option<NaiveDateTime> {
- self.date.with_month(month).map(|d| NaiveDateTime { date: d, ..*self })
- }
-
- /// Makes a new `NaiveDateTime` with the month number (starting from 0) changed.
- ///
- /// Returns `None` when the resulting `NaiveDateTime` would be invalid.
- ///
- /// See also the
- /// [`NaiveDate::with_month0`](./struct.NaiveDate.html#method.with_month0) method.
- ///
- /// # Example
- ///
- /// ~~~~
- /// use chrono::{NaiveDate, NaiveDateTime, Datelike};
- ///
- /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 30).and_hms(12, 34, 56);
- /// assert_eq!(dt.with_month0(9), Some(NaiveDate::from_ymd(2015, 10, 30).and_hms(12, 34, 56)));
- /// assert_eq!(dt.with_month0(12), None); // no month 13
- /// assert_eq!(dt.with_month0(1), None); // no February 30
- /// ~~~~
- #[inline]
- fn with_month0(&self, month0: u32) -> Option<NaiveDateTime> {
- self.date.with_month0(month0).map(|d| NaiveDateTime { date: d, ..*self })
- }
-
- /// Makes a new `NaiveDateTime` with the day of month (starting from 1) changed.
- ///
- /// Returns `None` when the resulting `NaiveDateTime` would be invalid.
- ///
- /// See also the
- /// [`NaiveDate::with_day`](./struct.NaiveDate.html#method.with_day) method.
- ///
- /// # Example
- ///
- /// ~~~~
- /// use chrono::{NaiveDate, NaiveDateTime, Datelike};
- ///
- /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 8).and_hms(12, 34, 56);
- /// assert_eq!(dt.with_day(30), Some(NaiveDate::from_ymd(2015, 9, 30).and_hms(12, 34, 56)));
- /// assert_eq!(dt.with_day(31), None); // no September 31
- /// ~~~~
- #[inline]
- fn with_day(&self, day: u32) -> Option<NaiveDateTime> {
- self.date.with_day(day).map(|d| NaiveDateTime { date: d, ..*self })
- }
-
- /// Makes a new `NaiveDateTime` with the day of month (starting from 0) changed.
- ///
- /// Returns `None` when the resulting `NaiveDateTime` would be invalid.
- ///
- /// See also the
- /// [`NaiveDate::with_day0`](./struct.NaiveDate.html#method.with_day0) method.
- ///
- /// # Example
- ///
- /// ~~~~
- /// use chrono::{NaiveDate, NaiveDateTime, Datelike};
- ///
- /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 8).and_hms(12, 34, 56);
- /// assert_eq!(dt.with_day0(29), Some(NaiveDate::from_ymd(2015, 9, 30).and_hms(12, 34, 56)));
- /// assert_eq!(dt.with_day0(30), None); // no September 31
- /// ~~~~
- #[inline]
- fn with_day0(&self, day0: u32) -> Option<NaiveDateTime> {
- self.date.with_day0(day0).map(|d| NaiveDateTime { date: d, ..*self })
- }
-
- /// Makes a new `NaiveDateTime` with the day of year (starting from 1) changed.
- ///
- /// Returns `None` when the resulting `NaiveDateTime` would be invalid.
- ///
- /// See also the
- /// [`NaiveDate::with_ordinal`](./struct.NaiveDate.html#method.with_ordinal) method.
- ///
- /// # Example
- ///
- /// ~~~~
- /// use chrono::{NaiveDate, NaiveDateTime, Datelike};
- ///
- /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 8).and_hms(12, 34, 56);
- /// assert_eq!(dt.with_ordinal(60),
- /// Some(NaiveDate::from_ymd(2015, 3, 1).and_hms(12, 34, 56)));
- /// assert_eq!(dt.with_ordinal(366), None); // 2015 had only 365 days
- ///
- /// let dt: NaiveDateTime = NaiveDate::from_ymd(2016, 9, 8).and_hms(12, 34, 56);
- /// assert_eq!(dt.with_ordinal(60),
- /// Some(NaiveDate::from_ymd(2016, 2, 29).and_hms(12, 34, 56)));
- /// assert_eq!(dt.with_ordinal(366),
- /// Some(NaiveDate::from_ymd(2016, 12, 31).and_hms(12, 34, 56)));
- /// ~~~~
- #[inline]
- fn with_ordinal(&self, ordinal: u32) -> Option<NaiveDateTime> {
- self.date.with_ordinal(ordinal).map(|d| NaiveDateTime { date: d, ..*self })
- }
-
- /// Makes a new `NaiveDateTime` with the day of year (starting from 0) changed.
- ///
- /// Returns `None` when the resulting `NaiveDateTime` would be invalid.
- ///
- /// See also the
- /// [`NaiveDate::with_ordinal0`](./struct.NaiveDate.html#method.with_ordinal0) method.
- ///
- /// # Example
- ///
- /// ~~~~
- /// use chrono::{NaiveDate, NaiveDateTime, Datelike};
- ///
- /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 8).and_hms(12, 34, 56);
- /// assert_eq!(dt.with_ordinal0(59),
- /// Some(NaiveDate::from_ymd(2015, 3, 1).and_hms(12, 34, 56)));
- /// assert_eq!(dt.with_ordinal0(365), None); // 2015 had only 365 days
- ///
- /// let dt: NaiveDateTime = NaiveDate::from_ymd(2016, 9, 8).and_hms(12, 34, 56);
- /// assert_eq!(dt.with_ordinal0(59),
- /// Some(NaiveDate::from_ymd(2016, 2, 29).and_hms(12, 34, 56)));
- /// assert_eq!(dt.with_ordinal0(365),
- /// Some(NaiveDate::from_ymd(2016, 12, 31).and_hms(12, 34, 56)));
- /// ~~~~
- #[inline]
- fn with_ordinal0(&self, ordinal0: u32) -> Option<NaiveDateTime> {
- self.date.with_ordinal0(ordinal0).map(|d| NaiveDateTime { date: d, ..*self })
- }
-}
-
-impl Timelike for NaiveDateTime {
- /// Returns the hour number from 0 to 23.
- ///
- /// See also the [`NaiveTime::hour`](./struct.NaiveTime.html#method.hour) method.
- ///
- /// # Example
- ///
- /// ~~~~
- /// use chrono::{NaiveDate, NaiveDateTime, Timelike};
- ///
- /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 8).and_hms_milli(12, 34, 56, 789);
- /// assert_eq!(dt.hour(), 12);
- /// ~~~~
- #[inline]
- fn hour(&self) -> u32 {
- self.time.hour()
- }
-
- /// Returns the minute number from 0 to 59.
- ///
- /// See also the [`NaiveTime::minute`](./struct.NaiveTime.html#method.minute) method.
- ///
- /// # Example
- ///
- /// ~~~~
- /// use chrono::{NaiveDate, NaiveDateTime, Timelike};
- ///
- /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 8).and_hms_milli(12, 34, 56, 789);
- /// assert_eq!(dt.minute(), 34);
- /// ~~~~
- #[inline]
- fn minute(&self) -> u32 {
- self.time.minute()
- }
-
- /// Returns the second number from 0 to 59.
- ///
- /// See also the [`NaiveTime::second`](./struct.NaiveTime.html#method.second) method.
- ///
- /// # Example
- ///
- /// ~~~~
- /// use chrono::{NaiveDate, NaiveDateTime, Timelike};
- ///
- /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 8).and_hms_milli(12, 34, 56, 789);
- /// assert_eq!(dt.second(), 56);
- /// ~~~~
- #[inline]
- fn second(&self) -> u32 {
- self.time.second()
- }
-
- /// Returns the number of nanoseconds since the whole non-leap second.
- /// The range from 1,000,000,000 to 1,999,999,999 represents
- /// the [leap second](./struct.NaiveTime.html#leap-second-handling).
- ///
- /// See also the
- /// [`NaiveTime::nanosecond`](./struct.NaiveTime.html#method.nanosecond) method.
- ///
- /// # Example
- ///
- /// ~~~~
- /// use chrono::{NaiveDate, NaiveDateTime, Timelike};
- ///
- /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 8).and_hms_milli(12, 34, 56, 789);
- /// assert_eq!(dt.nanosecond(), 789_000_000);
- /// ~~~~
- #[inline]
- fn nanosecond(&self) -> u32 {
- self.time.nanosecond()
- }
-
- /// Makes a new `NaiveDateTime` with the hour number changed.
- ///
- /// Returns `None` when the resulting `NaiveDateTime` would be invalid.
- ///
- /// See also the
- /// [`NaiveTime::with_hour`](./struct.NaiveTime.html#method.with_hour) method.
- ///
- /// # Example
- ///
- /// ~~~~
- /// use chrono::{NaiveDate, NaiveDateTime, Timelike};
- ///
- /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 8).and_hms_milli(12, 34, 56, 789);
- /// assert_eq!(dt.with_hour(7),
- /// Some(NaiveDate::from_ymd(2015, 9, 8).and_hms_milli(7, 34, 56, 789)));
- /// assert_eq!(dt.with_hour(24), None);
- /// ~~~~
- #[inline]
- fn with_hour(&self, hour: u32) -> Option<NaiveDateTime> {
- self.time.with_hour(hour).map(|t| NaiveDateTime { time: t, ..*self })
- }
-
- /// Makes a new `NaiveDateTime` with the minute number changed.
- ///
- /// Returns `None` when the resulting `NaiveDateTime` would be invalid.
- ///
- /// See also the
- /// [`NaiveTime::with_minute`](./struct.NaiveTime.html#method.with_minute) method.
- ///
- /// # Example
- ///
- /// ~~~~
- /// use chrono::{NaiveDate, NaiveDateTime, Timelike};
- ///
- /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 8).and_hms_milli(12, 34, 56, 789);
- /// assert_eq!(dt.with_minute(45),
- /// Some(NaiveDate::from_ymd(2015, 9, 8).and_hms_milli(12, 45, 56, 789)));
- /// assert_eq!(dt.with_minute(60), None);
- /// ~~~~
- #[inline]
- fn with_minute(&self, min: u32) -> Option<NaiveDateTime> {
- self.time.with_minute(min).map(|t| NaiveDateTime { time: t, ..*self })
- }
-
- /// Makes a new `NaiveDateTime` with the second number changed.
- ///
- /// Returns `None` when the resulting `NaiveDateTime` would be invalid.
- /// As with the [`second`](#method.second) method,
- /// the input range is restricted to 0 through 59.
- ///
- /// See also the
- /// [`NaiveTime::with_second`](./struct.NaiveTime.html#method.with_second) method.
- ///
- /// # Example
- ///
- /// ~~~~
- /// use chrono::{NaiveDate, NaiveDateTime, Timelike};
- ///
- /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 8).and_hms_milli(12, 34, 56, 789);
- /// assert_eq!(dt.with_second(17),
- /// Some(NaiveDate::from_ymd(2015, 9, 8).and_hms_milli(12, 34, 17, 789)));
- /// assert_eq!(dt.with_second(60), None);
- /// ~~~~
- #[inline]
- fn with_second(&self, sec: u32) -> Option<NaiveDateTime> {
- self.time.with_second(sec).map(|t| NaiveDateTime { time: t, ..*self })
- }
-
- /// Makes a new `NaiveDateTime` with nanoseconds since the whole non-leap second changed.
- ///
- /// Returns `None` when the resulting `NaiveDateTime` would be invalid.
- /// As with the [`nanosecond`](#method.nanosecond) method,
- /// the input range can exceed 1,000,000,000 for leap seconds.
- ///
- /// See also the
- /// [`NaiveTime::with_nanosecond`](./struct.NaiveTime.html#method.with_nanosecond)
- /// method.
- ///
- /// # Example
- ///
- /// ~~~~
- /// use chrono::{NaiveDate, NaiveDateTime, Timelike};
- ///
- /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 8).and_hms_milli(12, 34, 56, 789);
- /// assert_eq!(dt.with_nanosecond(333_333_333),
- /// Some(NaiveDate::from_ymd(2015, 9, 8).and_hms_nano(12, 34, 56, 333_333_333)));
- /// assert_eq!(dt.with_nanosecond(1_333_333_333), // leap second
- /// Some(NaiveDate::from_ymd(2015, 9, 8).and_hms_nano(12, 34, 56, 1_333_333_333)));
- /// assert_eq!(dt.with_nanosecond(2_000_000_000), None);
- /// ~~~~
- #[inline]
- fn with_nanosecond(&self, nano: u32) -> Option<NaiveDateTime> {
- self.time.with_nanosecond(nano).map(|t| NaiveDateTime { time: t, ..*self })
- }
-}
-
-/// `NaiveDateTime` can be used as a key to the hash maps (in principle).
-///
-/// Practically this also takes account of fractional seconds, so it is not recommended.
-/// (For the obvious reason this also distinguishes leap seconds from non-leap seconds.)
-impl hash::Hash for NaiveDateTime {
- fn hash<H: hash::Hasher>(&self, state: &mut H) {
- self.date.hash(state);
- self.time.hash(state);
- }
-}
-
-/// 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**.
-///
-/// Panics on underflow or overflow.
-/// Use [`NaiveDateTime::checked_add_signed`](#method.checked_add_signed) to detect that.
-///
-/// # Example
-///
-/// ~~~~
-/// # extern crate chrono; fn main() {
-/// use chrono::{Duration, NaiveDate};
-///
-/// let from_ymd = NaiveDate::from_ymd;
-///
-/// let d = from_ymd(2016, 7, 8);
-/// let hms = |h, m, s| d.and_hms(h, m, s);
-/// assert_eq!(hms(3, 5, 7) + Duration::zero(), hms(3, 5, 7));
-/// assert_eq!(hms(3, 5, 7) + Duration::seconds(1), hms(3, 5, 8));
-/// assert_eq!(hms(3, 5, 7) + Duration::seconds(-1), hms(3, 5, 6));
-/// assert_eq!(hms(3, 5, 7) + Duration::seconds(3600 + 60), hms(4, 6, 7));
-/// assert_eq!(hms(3, 5, 7) + Duration::seconds(86_400),
-/// from_ymd(2016, 7, 9).and_hms(3, 5, 7));
-/// assert_eq!(hms(3, 5, 7) + Duration::days(365),
-/// from_ymd(2017, 7, 8).and_hms(3, 5, 7));
-///
-/// let hmsm = |h, m, s, milli| d.and_hms_milli(h, m, s, milli);
-/// assert_eq!(hmsm(3, 5, 7, 980) + Duration::milliseconds(450), hmsm(3, 5, 8, 430));
-/// # }
-/// ~~~~
-///
-/// Leap seconds are handled,
-/// but the addition assumes that it is the only leap second happened.
-///
-/// ~~~~
-/// # extern crate chrono; fn main() {
-/// # use chrono::{Duration, NaiveDate};
-/// # let from_ymd = NaiveDate::from_ymd;
-/// # let hmsm = |h, m, s, milli| from_ymd(2016, 7, 8).and_hms_milli(h, m, s, milli);
-/// let leap = hmsm(3, 5, 59, 1_300);
-/// assert_eq!(leap + Duration::zero(), hmsm(3, 5, 59, 1_300));
-/// assert_eq!(leap + Duration::milliseconds(-500), hmsm(3, 5, 59, 800));
-/// assert_eq!(leap + Duration::milliseconds(500), hmsm(3, 5, 59, 1_800));
-/// assert_eq!(leap + Duration::milliseconds(800), hmsm(3, 6, 0, 100));
-/// assert_eq!(leap + Duration::seconds(10), hmsm(3, 6, 9, 300));
-/// assert_eq!(leap + Duration::seconds(-10), hmsm(3, 5, 50, 300));
-/// assert_eq!(leap + Duration::days(1),
-/// from_ymd(2016, 7, 9).and_hms_milli(3, 5, 59, 300));
-/// # }
-/// ~~~~
-impl Add<OldDuration> for NaiveDateTime {
- type Output = NaiveDateTime;
-
- #[inline]
- fn add(self, rhs: OldDuration) -> NaiveDateTime {
- self.checked_add_signed(rhs).expect("`NaiveDateTime + Duration` overflowed")
- }
-}
-
-impl AddAssign<OldDuration> for NaiveDateTime {
- #[inline]
- fn add_assign(&mut self, rhs: OldDuration) {
- *self = self.add(rhs);
- }
-}
-
-/// 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**.
-///
-/// Panics on underflow or overflow.
-/// Use [`NaiveDateTime::checked_sub_signed`](#method.checked_sub_signed) to detect that.
-///
-/// # Example
-///
-/// ~~~~
-/// # extern crate chrono; fn main() {
-/// use chrono::{Duration, NaiveDate};
-///
-/// let from_ymd = NaiveDate::from_ymd;
-///
-/// let d = from_ymd(2016, 7, 8);
-/// let hms = |h, m, s| d.and_hms(h, m, s);
-/// assert_eq!(hms(3, 5, 7) - Duration::zero(), hms(3, 5, 7));
-/// assert_eq!(hms(3, 5, 7) - Duration::seconds(1), hms(3, 5, 6));
-/// assert_eq!(hms(3, 5, 7) - Duration::seconds(-1), hms(3, 5, 8));
-/// assert_eq!(hms(3, 5, 7) - Duration::seconds(3600 + 60), hms(2, 4, 7));
-/// assert_eq!(hms(3, 5, 7) - Duration::seconds(86_400),
-/// from_ymd(2016, 7, 7).and_hms(3, 5, 7));
-/// assert_eq!(hms(3, 5, 7) - Duration::days(365),
-/// from_ymd(2015, 7, 9).and_hms(3, 5, 7));
-///
-/// let hmsm = |h, m, s, milli| d.and_hms_milli(h, m, s, milli);
-/// assert_eq!(hmsm(3, 5, 7, 450) - Duration::milliseconds(670), hmsm(3, 5, 6, 780));
-/// # }
-/// ~~~~
-///
-/// Leap seconds are handled,
-/// but the subtraction assumes that it is the only leap second happened.
-///
-/// ~~~~
-/// # extern crate chrono; fn main() {
-/// # use chrono::{Duration, NaiveDate};
-/// # let from_ymd = NaiveDate::from_ymd;
-/// # let hmsm = |h, m, s, milli| from_ymd(2016, 7, 8).and_hms_milli(h, m, s, milli);
-/// let leap = hmsm(3, 5, 59, 1_300);
-/// assert_eq!(leap - Duration::zero(), hmsm(3, 5, 59, 1_300));
-/// assert_eq!(leap - Duration::milliseconds(200), hmsm(3, 5, 59, 1_100));
-/// assert_eq!(leap - Duration::milliseconds(500), hmsm(3, 5, 59, 800));
-/// assert_eq!(leap - Duration::seconds(60), hmsm(3, 5, 0, 300));
-/// assert_eq!(leap - Duration::days(1),
-/// from_ymd(2016, 7, 7).and_hms_milli(3, 6, 0, 300));
-/// # }
-/// ~~~~
-impl Sub<OldDuration> for NaiveDateTime {
- type Output = NaiveDateTime;
-
- #[inline]
- fn sub(self, rhs: OldDuration) -> NaiveDateTime {
- self.checked_sub_signed(rhs).expect("`NaiveDateTime - Duration` overflowed")
- }
-}
-
-impl SubAssign<OldDuration> for NaiveDateTime {
- #[inline]
- fn sub_assign(&mut self, rhs: OldDuration) {
- *self = self.sub(rhs);
- }
-}
-
-/// Subtracts another `NaiveDateTime` from the current date and time.
-/// This does not overflow or underflow at all.
-///
-/// As a part of Chrono's [leap second handling](./struct.NaiveTime.html#leap-second-handling),
-/// the subtraction assumes that **there is no leap second ever**,
-/// except when any of the `NaiveDateTime`s themselves represents a leap second
-/// in which case the assumption becomes that
-/// **there are exactly one (or two) leap second(s) ever**.
-///
-/// The implementation is a wrapper around
-/// [`NaiveDateTime::signed_duration_since`](#method.signed_duration_since).
-///
-/// # Example
-///
-/// ~~~~
-/// # extern crate chrono; fn main() {
-/// use chrono::{Duration, NaiveDate};
-///
-/// let from_ymd = NaiveDate::from_ymd;
-///
-/// let d = from_ymd(2016, 7, 8);
-/// assert_eq!(d.and_hms(3, 5, 7) - d.and_hms(2, 4, 6), Duration::seconds(3600 + 60 + 1));
-///
-/// // July 8 is 190th day in the year 2016
-/// let d0 = from_ymd(2016, 1, 1);
-/// assert_eq!(d.and_hms_milli(0, 7, 6, 500) - d0.and_hms(0, 0, 0),
-/// Duration::seconds(189 * 86_400 + 7 * 60 + 6) + Duration::milliseconds(500));
-/// # }
-/// ~~~~
-///
-/// Leap seconds are handled, but the subtraction assumes that
-/// there were no other leap seconds happened.
-///
-/// ~~~~
-/// # extern crate chrono; fn main() {
-/// # use chrono::{Duration, NaiveDate};
-/// # let from_ymd = NaiveDate::from_ymd;
-/// let leap = from_ymd(2015, 6, 30).and_hms_milli(23, 59, 59, 1_500);
-/// assert_eq!(leap - from_ymd(2015, 6, 30).and_hms(23, 0, 0),
-/// Duration::seconds(3600) + Duration::milliseconds(500));
-/// assert_eq!(from_ymd(2015, 7, 1).and_hms(1, 0, 0) - leap,
-/// Duration::seconds(3600) - Duration::milliseconds(500));
-/// # }
-/// ~~~~
-impl Sub<NaiveDateTime> for NaiveDateTime {
- type Output = OldDuration;
-
- #[inline]
- fn sub(self, rhs: NaiveDateTime) -> OldDuration {
- self.signed_duration_since(rhs)
- }
-}
-
-/// The `Debug` output of the naive date and time `dt` is the same as
-/// [`dt.format("%Y-%m-%dT%H:%M:%S%.f")`](../format/strftime/index.html).
-///
-/// The string printed can be readily parsed via the `parse` method on `str`.
-///
-/// It should be noted that, for leap seconds not on the minute boundary,
-/// it may print a representation not distinguishable from non-leap seconds.
-/// This doesn't matter in practice, since such leap seconds never happened.
-/// (By the time of the first leap second on 1972-06-30,
-/// every time zone offset around the world has standardized to the 5-minute alignment.)
-///
-/// # Example
-///
-/// ~~~~
-/// use chrono::NaiveDate;
-///
-/// let dt = NaiveDate::from_ymd(2016, 11, 15).and_hms(7, 39, 24);
-/// assert_eq!(format!("{:?}", dt), "2016-11-15T07:39:24");
-/// ~~~~
-///
-/// Leap seconds may also be used.
-///
-/// ~~~~
-/// # use chrono::NaiveDate;
-/// let dt = NaiveDate::from_ymd(2015, 6, 30).and_hms_milli(23, 59, 59, 1_500);
-/// assert_eq!(format!("{:?}", dt), "2015-06-30T23:59:60.500");
-/// ~~~~
-impl fmt::Debug for NaiveDateTime {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "{:?}T{:?}", self.date, self.time)
- }
-}
-
-/// The `Display` output of the naive date and time `dt` is the same as
-/// [`dt.format("%Y-%m-%d %H:%M:%S%.f")`](../format/strftime/index.html).
-///
-/// It should be noted that, for leap seconds not on the minute boundary,
-/// it may print a representation not distinguishable from non-leap seconds.
-/// This doesn't matter in practice, since such leap seconds never happened.
-/// (By the time of the first leap second on 1972-06-30,
-/// every time zone offset around the world has standardized to the 5-minute alignment.)
-///
-/// # Example
-///
-/// ~~~~
-/// use chrono::NaiveDate;
-///
-/// let dt = NaiveDate::from_ymd(2016, 11, 15).and_hms(7, 39, 24);
-/// assert_eq!(format!("{}", dt), "2016-11-15 07:39:24");
-/// ~~~~
-///
-/// Leap seconds may also be used.
-///
-/// ~~~~
-/// # use chrono::NaiveDate;
-/// let dt = NaiveDate::from_ymd(2015, 6, 30).and_hms_milli(23, 59, 59, 1_500);
-/// assert_eq!(format!("{}", dt), "2015-06-30 23:59:60.500");
-/// ~~~~
-impl fmt::Display for NaiveDateTime {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "{} {}", self.date, self.time)
- }
-}
-
-/// Parsing a `str` into a `NaiveDateTime` uses the same format,
-/// [`%Y-%m-%dT%H:%M:%S%.f`](../format/strftime/index.html), as in `Debug`.
-///
-/// # Example
-///
-/// ~~~~
-/// use chrono::{NaiveDateTime, NaiveDate};
-///
-/// let dt = NaiveDate::from_ymd(2015, 9, 18).and_hms(23, 56, 4);
-/// assert_eq!("2015-09-18T23:56:04".parse::<NaiveDateTime>(), Ok(dt));
-///
-/// let dt = NaiveDate::from_ymd(12345, 6, 7).and_hms_milli(7, 59, 59, 1_500); // leap second
-/// assert_eq!("+12345-6-7T7:59:60.5".parse::<NaiveDateTime>(), Ok(dt));
-///
-/// assert!("foo".parse::<NaiveDateTime>().is_err());
-/// ~~~~
-impl str::FromStr for NaiveDateTime {
- type Err = ParseError;
-
- fn from_str(s: &str) -> ParseResult<NaiveDateTime> {
- const ITEMS: &'static [Item<'static>] = &[
- Item::Numeric(Numeric::Year, Pad::Zero),
- Item::Space(""),
- Item::Literal("-"),
- Item::Numeric(Numeric::Month, Pad::Zero),
- Item::Space(""),
- Item::Literal("-"),
- Item::Numeric(Numeric::Day, Pad::Zero),
- Item::Space(""),
- Item::Literal("T"), // XXX shouldn't this be case-insensitive?
- Item::Numeric(Numeric::Hour, Pad::Zero),
- Item::Space(""),
- Item::Literal(":"),
- Item::Numeric(Numeric::Minute, Pad::Zero),
- Item::Space(""),
- Item::Literal(":"),
- Item::Numeric(Numeric::Second, Pad::Zero),
- Item::Fixed(Fixed::Nanosecond),
- Item::Space(""),
- ];
-
- let mut parsed = Parsed::new();
- parse(&mut parsed, s, ITEMS.iter())?;
- parsed.to_naive_datetime_with_offset(0)
- }
-}
-
-#[cfg(all(test, any(feature = "rustc-serialize", feature = "serde")))]
-fn test_encodable_json<F, E>(to_string: F)
-where
- F: Fn(&NaiveDateTime) -> Result<String, E>,
- E: ::std::fmt::Debug,
-{
- use naive::{MAX_DATE, MIN_DATE};
-
- assert_eq!(
- to_string(&NaiveDate::from_ymd(2016, 7, 8).and_hms_milli(9, 10, 48, 90)).ok(),
- Some(r#""2016-07-08T09:10:48.090""#.into())
- );
- assert_eq!(
- to_string(&NaiveDate::from_ymd(2014, 7, 24).and_hms(12, 34, 6)).ok(),
- Some(r#""2014-07-24T12:34:06""#.into())
- );
- assert_eq!(
- to_string(&NaiveDate::from_ymd(0, 1, 1).and_hms_milli(0, 0, 59, 1_000)).ok(),
- Some(r#""0000-01-01T00:00:60""#.into())
- );
- assert_eq!(
- to_string(&NaiveDate::from_ymd(-1, 12, 31).and_hms_nano(23, 59, 59, 7)).ok(),
- Some(r#""-0001-12-31T23:59:59.000000007""#.into())
- );
- assert_eq!(
- to_string(&MIN_DATE.and_hms(0, 0, 0)).ok(),
- Some(r#""-262144-01-01T00:00:00""#.into())
- );
- assert_eq!(
- to_string(&MAX_DATE.and_hms_nano(23, 59, 59, 1_999_999_999)).ok(),
- Some(r#""+262143-12-31T23:59:60.999999999""#.into())
- );
-}
-
-#[cfg(all(test, any(feature = "rustc-serialize", feature = "serde")))]
-fn test_decodable_json<F, E>(from_str: F)
-where
- F: Fn(&str) -> Result<NaiveDateTime, E>,
- E: ::std::fmt::Debug,
-{
- use naive::{MAX_DATE, MIN_DATE};
-
- assert_eq!(
- from_str(r#""2016-07-08T09:10:48.090""#).ok(),
- Some(NaiveDate::from_ymd(2016, 7, 8).and_hms_milli(9, 10, 48, 90))
- );
- assert_eq!(
- from_str(r#""2016-7-8T9:10:48.09""#).ok(),
- Some(NaiveDate::from_ymd(2016, 7, 8).and_hms_milli(9, 10, 48, 90))
- );
- assert_eq!(
- from_str(r#""2014-07-24T12:34:06""#).ok(),
- Some(NaiveDate::from_ymd(2014, 7, 24).and_hms(12, 34, 6))
- );
- assert_eq!(
- from_str(r#""0000-01-01T00:00:60""#).ok(),
- Some(NaiveDate::from_ymd(0, 1, 1).and_hms_milli(0, 0, 59, 1_000))
- );
- assert_eq!(
- from_str(r#""0-1-1T0:0:60""#).ok(),
- Some(NaiveDate::from_ymd(0, 1, 1).and_hms_milli(0, 0, 59, 1_000))
- );
- assert_eq!(
- from_str(r#""-0001-12-31T23:59:59.000000007""#).ok(),
- Some(NaiveDate::from_ymd(-1, 12, 31).and_hms_nano(23, 59, 59, 7))
- );
- assert_eq!(from_str(r#""-262144-01-01T00:00:00""#).ok(), Some(MIN_DATE.and_hms(0, 0, 0)));
- assert_eq!(
- from_str(r#""+262143-12-31T23:59:60.999999999""#).ok(),
- Some(MAX_DATE.and_hms_nano(23, 59, 59, 1_999_999_999))
- );
- assert_eq!(
- from_str(r#""+262143-12-31T23:59:60.9999999999997""#).ok(), // excess digits are ignored
- Some(MAX_DATE.and_hms_nano(23, 59, 59, 1_999_999_999))
- );
-
- // bad formats
- assert!(from_str(r#""""#).is_err());
- assert!(from_str(r#""2016-07-08""#).is_err());
- assert!(from_str(r#""09:10:48.090""#).is_err());
- assert!(from_str(r#""20160708T091048.090""#).is_err());
- assert!(from_str(r#""2000-00-00T00:00:00""#).is_err());
- assert!(from_str(r#""2000-02-30T00:00:00""#).is_err());
- assert!(from_str(r#""2001-02-29T00:00:00""#).is_err());
- assert!(from_str(r#""2002-02-28T24:00:00""#).is_err());
- assert!(from_str(r#""2002-02-28T23:60:00""#).is_err());
- assert!(from_str(r#""2002-02-28T23:59:61""#).is_err());
- assert!(from_str(r#""2016-07-08T09:10:48,090""#).is_err());
- assert!(from_str(r#""2016-07-08 09:10:48.090""#).is_err());
- assert!(from_str(r#""2016-007-08T09:10:48.090""#).is_err());
- assert!(from_str(r#""yyyy-mm-ddThh:mm:ss.fffffffff""#).is_err());
- assert!(from_str(r#"20160708000000"#).is_err());
- assert!(from_str(r#"{}"#).is_err());
- // pre-0.3.0 rustc-serialize format is now invalid
- assert!(from_str(r#"{"date":{"ymdf":20},"time":{"secs":0,"frac":0}}"#).is_err());
- assert!(from_str(r#"null"#).is_err());
-}
-
-#[cfg(all(test, feature = "rustc-serialize"))]
-fn test_decodable_json_timestamp<F, E>(from_str: F)
-where
- F: Fn(&str) -> Result<rustc_serialize::TsSeconds, E>,
- E: ::std::fmt::Debug,
-{
- assert_eq!(
- *from_str("0").unwrap(),
- NaiveDate::from_ymd(1970, 1, 1).and_hms(0, 0, 0),
- "should parse integers as timestamps"
- );
- assert_eq!(
- *from_str("-1").unwrap(),
- NaiveDate::from_ymd(1969, 12, 31).and_hms(23, 59, 59),
- "should parse integers as timestamps"
- );
-}
-
-#[cfg(feature = "rustc-serialize")]
-pub mod rustc_serialize {
- use super::NaiveDateTime;
- use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
- use std::ops::Deref;
-
- impl Encodable for NaiveDateTime {
- fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
- format!("{:?}", self).encode(s)
- }
- }
-
- impl Decodable for NaiveDateTime {
- fn decode<D: Decoder>(d: &mut D) -> Result<NaiveDateTime, D::Error> {
- d.read_str()?.parse().map_err(|_| d.error("invalid date time string"))
- }
- }
-
- /// A `DateTime` that can be deserialized from a seconds-based timestamp
- #[derive(Debug)]
- #[deprecated(
- since = "1.4.2",
- note = "RustcSerialize will be removed before chrono 1.0, use Serde instead"
- )]
- pub struct TsSeconds(NaiveDateTime);
-
- #[allow(deprecated)]
- impl From<TsSeconds> for NaiveDateTime {
- /// Pull the internal NaiveDateTime out
- #[allow(deprecated)]
- fn from(obj: TsSeconds) -> NaiveDateTime {
- obj.0
- }
- }
-
- #[allow(deprecated)]
- impl Deref for TsSeconds {
- type Target = NaiveDateTime;
-
- #[allow(deprecated)]
- fn deref(&self) -> &Self::Target {
- &self.0
- }
- }
-
- #[allow(deprecated)]
- impl Decodable for TsSeconds {
- #[allow(deprecated)]
- fn decode<D: Decoder>(d: &mut D) -> Result<TsSeconds, D::Error> {
- Ok(TsSeconds(
- NaiveDateTime::from_timestamp_opt(d.read_i64()?, 0)
- .ok_or_else(|| d.error("invalid timestamp"))?,
- ))
- }
- }
-
- #[cfg(test)]
- use rustc_serialize::json;
-
- #[test]
- fn test_encodable() {
- super::test_encodable_json(json::encode);
- }
-
- #[test]
- fn test_decodable() {
- super::test_decodable_json(json::decode);
- }
-
- #[test]
- fn test_decodable_timestamps() {
- super::test_decodable_json_timestamp(json::decode);
- }
-}
-
-/// Tools to help serializing/deserializing `NaiveDateTime`s
-#[cfg(feature = "serde")]
-pub mod serde {
- use super::NaiveDateTime;
- use core::fmt;
- use serdelib::{de, ser};
-
- /// Serialize a `NaiveDateTime` as an RFC 3339 string
- ///
- /// See [the `serde` module](./serde/index.html) for alternate
- /// serialization formats.
- impl ser::Serialize for NaiveDateTime {
- fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
- where
- S: ser::Serializer,
- {
- struct FormatWrapped<'a, D: 'a> {
- inner: &'a D,
- }
-
- impl<'a, D: fmt::Debug> fmt::Display for FormatWrapped<'a, D> {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- self.inner.fmt(f)
- }
- }
-
- serializer.collect_str(&FormatWrapped { inner: &self })
- }
- }
-
- struct NaiveDateTimeVisitor;
-
- impl<'de> de::Visitor<'de> for NaiveDateTimeVisitor {
- type Value = NaiveDateTime;
-
- fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
- write!(formatter, "a formatted date and time string")
- }
-
- fn visit_str<E>(self, value: &str) -> Result<NaiveDateTime, E>
- where
- E: de::Error,
- {
- value.parse().map_err(E::custom)
- }
- }
-
- impl<'de> de::Deserialize<'de> for NaiveDateTime {
- fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
- where
- D: de::Deserializer<'de>,
- {
- deserializer.deserialize_str(NaiveDateTimeVisitor)
- }
- }
-
- /// Used to serialize/deserialize from nanosecond-precision timestamps
- ///
- /// # Example:
- ///
- /// ```rust
- /// # // We mark this ignored so that we can test on 1.13 (which does not
- /// # // support custom derive), and run tests with --ignored on beta and
- /// # // nightly to actually trigger these.
- /// #
- /// # #[macro_use] extern crate serde_derive;
- /// # extern crate serde_json;
- /// # extern crate serde;
- /// # extern crate chrono;
- /// # use chrono::{TimeZone, NaiveDate, NaiveDateTime, Utc};
- /// use chrono::naive::serde::ts_nanoseconds;
- /// #[derive(Deserialize, Serialize)]
- /// struct S {
- /// #[serde(with = "ts_nanoseconds")]
- /// time: NaiveDateTime
- /// }
- ///
- /// # fn example() -> Result<S, serde_json::Error> {
- /// let time = NaiveDate::from_ymd(2018, 5, 17).and_hms_nano(02, 04, 59, 918355733);
- /// let my_s = S {
- /// time: time.clone(),
- /// };
- ///
- /// let as_string = serde_json::to_string(&my_s)?;
- /// assert_eq!(as_string, r#"{"time":1526522699918355733}"#);
- /// let my_s: S = serde_json::from_str(&as_string)?;
- /// assert_eq!(my_s.time, time);
- /// # Ok(my_s)
- /// # }
- /// # fn main() { example().unwrap(); }
- /// ```
- pub mod ts_nanoseconds {
- use core::fmt;
- use serdelib::{de, ser};
-
- use {ne_timestamp, NaiveDateTime};
-
- /// Serialize a UTC datetime into an integer number of nanoseconds since the epoch
- ///
- /// Intended for use with `serde`s `serialize_with` attribute.
- ///
- /// # Example:
- ///
- /// ```rust
- /// # // We mark this ignored so that we can test on 1.13 (which does not
- /// # // support custom derive), and run tests with --ignored on beta and
- /// # // nightly to actually trigger these.
- /// #
- /// # #[macro_use] extern crate serde_derive;
- /// # #[macro_use] extern crate serde_json;
- /// # #[macro_use] extern crate serde;
- /// # extern crate chrono;
- /// # use chrono::{TimeZone, NaiveDate, NaiveDateTime, Utc};
- /// # use serde::Serialize;
- /// use chrono::naive::serde::ts_nanoseconds::serialize as to_nano_ts;
- /// #[derive(Serialize)]
- /// struct S {
- /// #[serde(serialize_with = "to_nano_ts")]
- /// time: NaiveDateTime
- /// }
- ///
- /// # fn example() -> Result<String, serde_json::Error> {
- /// let my_s = S {
- /// time: NaiveDate::from_ymd(2018, 5, 17).and_hms_nano(02, 04, 59, 918355733),
- /// };
- /// let as_string = serde_json::to_string(&my_s)?;
- /// assert_eq!(as_string, r#"{"time":1526522699918355733}"#);
- /// # Ok(as_string)
- /// # }
- /// # fn main() { example().unwrap(); }
- /// ```
- pub fn serialize<S>(dt: &NaiveDateTime, serializer: S) -> Result<S::Ok, S::Error>
- where
- S: ser::Serializer,
- {
- serializer.serialize_i64(dt.timestamp_nanos())
- }
-
- /// Deserialize a `DateTime` from a nanoseconds timestamp
- ///
- /// Intended for use with `serde`s `deserialize_with` attribute.
- ///
- /// # Example:
- ///
- /// ```rust
- /// # // We mark this ignored so that we can test on 1.13 (which does not
- /// # // support custom derive), and run tests with --ignored on beta and
- /// # // nightly to actually trigger these.
- /// #
- /// # #[macro_use] extern crate serde_derive;
- /// # #[macro_use] extern crate serde_json;
- /// # extern crate serde;
- /// # extern crate chrono;
- /// # use chrono::{NaiveDateTime, Utc};
- /// # use serde::Deserialize;
- /// use chrono::naive::serde::ts_nanoseconds::deserialize as from_nano_ts;
- /// #[derive(Deserialize)]
- /// struct S {
- /// #[serde(deserialize_with = "from_nano_ts")]
- /// time: NaiveDateTime
- /// }
- ///
- /// # fn example() -> Result<S, serde_json::Error> {
- /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918355733 }"#)?;
- /// # Ok(my_s)
- /// # }
- /// # fn main() { example().unwrap(); }
- /// ```
- pub fn deserialize<'de, D>(d: D) -> Result<NaiveDateTime, D::Error>
- where
- D: de::Deserializer<'de>,
- {
- Ok(d.deserialize_i64(NaiveDateTimeFromNanoSecondsVisitor)?)
- }
-
- struct NaiveDateTimeFromNanoSecondsVisitor;
-
- impl<'de> de::Visitor<'de> for NaiveDateTimeFromNanoSecondsVisitor {
- type Value = NaiveDateTime;
-
- fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
- formatter.write_str("a unix timestamp")
- }
-
- fn visit_i64<E>(self, value: i64) -> Result<NaiveDateTime, E>
- where
- E: de::Error,
- {
- NaiveDateTime::from_timestamp_opt(
- value / 1_000_000_000,
- (value % 1_000_000_000) as u32,
- )
- .ok_or_else(|| E::custom(ne_timestamp(value)))
- }
-
- fn visit_u64<E>(self, value: u64) -> Result<NaiveDateTime, E>
- where
- E: de::Error,
- {
- NaiveDateTime::from_timestamp_opt(
- value as i64 / 1_000_000_000,
- (value as i64 % 1_000_000_000) as u32,
- )
- .ok_or_else(|| E::custom(ne_timestamp(value)))
- }
- }
- }
-
- /// Used to serialize/deserialize from millisecond-precision timestamps
- ///
- /// # Example:
- ///
- /// ```rust
- /// # // We mark this ignored so that we can test on 1.13 (which does not
- /// # // support custom derive), and run tests with --ignored on beta and
- /// # // nightly to actually trigger these.
- /// #
- /// # #[macro_use] extern crate serde_derive;
- /// # extern crate serde_json;
- /// # extern crate serde;
- /// # extern crate chrono;
- /// # use chrono::{TimeZone, NaiveDate, NaiveDateTime, Utc};
- /// use chrono::naive::serde::ts_milliseconds;
- /// #[derive(Deserialize, Serialize)]
- /// struct S {
- /// #[serde(with = "ts_milliseconds")]
- /// time: NaiveDateTime
- /// }
- ///
- /// # fn example() -> Result<S, serde_json::Error> {
- /// let time = NaiveDate::from_ymd(2018, 5, 17).and_hms_milli(02, 04, 59, 918);
- /// let my_s = S {
- /// time: time.clone(),
- /// };
- ///
- /// let as_string = serde_json::to_string(&my_s)?;
- /// assert_eq!(as_string, r#"{"time":1526522699918}"#);
- /// let my_s: S = serde_json::from_str(&as_string)?;
- /// assert_eq!(my_s.time, time);
- /// # Ok(my_s)
- /// # }
- /// # fn main() { example().unwrap(); }
- /// ```
- pub mod ts_milliseconds {
- use core::fmt;
- use serdelib::{de, ser};
-
- use {ne_timestamp, NaiveDateTime};
-
- /// Serialize a UTC datetime into an integer number of milliseconds since the epoch
- ///
- /// Intended for use with `serde`s `serialize_with` attribute.
- ///
- /// # Example:
- ///
- /// ```rust
- /// # // We mark this ignored so that we can test on 1.13 (which does not
- /// # // support custom derive), and run tests with --ignored on beta and
- /// # // nightly to actually trigger these.
- /// #
- /// # #[macro_use] extern crate serde_derive;
- /// # #[macro_use] extern crate serde_json;
- /// # #[macro_use] extern crate serde;
- /// # extern crate chrono;
- /// # use chrono::{TimeZone, NaiveDate, NaiveDateTime, Utc};
- /// # use serde::Serialize;
- /// use chrono::naive::serde::ts_milliseconds::serialize as to_milli_ts;
- /// #[derive(Serialize)]
- /// struct S {
- /// #[serde(serialize_with = "to_milli_ts")]
- /// time: NaiveDateTime
- /// }
- ///
- /// # fn example() -> Result<String, serde_json::Error> {
- /// let my_s = S {
- /// time: NaiveDate::from_ymd(2018, 5, 17).and_hms_milli(02, 04, 59, 918),
- /// };
- /// let as_string = serde_json::to_string(&my_s)?;
- /// assert_eq!(as_string, r#"{"time":1526522699918}"#);
- /// # Ok(as_string)
- /// # }
- /// # fn main() { example().unwrap(); }
- /// ```
- pub fn serialize<S>(dt: &NaiveDateTime, serializer: S) -> Result<S::Ok, S::Error>
- where
- S: ser::Serializer,
- {
- serializer.serialize_i64(dt.timestamp_millis())
- }
-
- /// Deserialize a `DateTime` from a milliseconds timestamp
- ///
- /// Intended for use with `serde`s `deserialize_with` attribute.
- ///
- /// # Example:
- ///
- /// ```rust
- /// # // We mark this ignored so that we can test on 1.13 (which does not
- /// # // support custom derive), and run tests with --ignored on beta and
- /// # // nightly to actually trigger these.
- /// #
- /// # #[macro_use] extern crate serde_derive;
- /// # #[macro_use] extern crate serde_json;
- /// # extern crate serde;
- /// # extern crate chrono;
- /// # use chrono::{NaiveDateTime, Utc};
- /// # use serde::Deserialize;
- /// use chrono::naive::serde::ts_milliseconds::deserialize as from_milli_ts;
- /// #[derive(Deserialize)]
- /// struct S {
- /// #[serde(deserialize_with = "from_milli_ts")]
- /// time: NaiveDateTime
- /// }
- ///
- /// # fn example() -> Result<S, serde_json::Error> {
- /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918 }"#)?;
- /// # Ok(my_s)
- /// # }
- /// # fn main() { example().unwrap(); }
- /// ```
- pub fn deserialize<'de, D>(d: D) -> Result<NaiveDateTime, D::Error>
- where
- D: de::Deserializer<'de>,
- {
- Ok(d.deserialize_i64(NaiveDateTimeFromMilliSecondsVisitor)?)
- }
-
- struct NaiveDateTimeFromMilliSecondsVisitor;
-
- impl<'de> de::Visitor<'de> for NaiveDateTimeFromMilliSecondsVisitor {
- type Value = NaiveDateTime;
-
- fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
- formatter.write_str("a unix timestamp")
- }
-
- fn visit_i64<E>(self, value: i64) -> Result<NaiveDateTime, E>
- where
- E: de::Error,
- {
- NaiveDateTime::from_timestamp_opt(value / 1000, ((value % 1000) * 1_000_000) as u32)
- .ok_or_else(|| E::custom(ne_timestamp(value)))
- }
-
- fn visit_u64<E>(self, value: u64) -> Result<NaiveDateTime, E>
- where
- E: de::Error,
- {
- NaiveDateTime::from_timestamp_opt(
- (value / 1000) as i64,
- ((value % 1000) * 1_000_000) as u32,
- )
- .ok_or_else(|| E::custom(ne_timestamp(value)))
- }
- }
- }
-
- /// Used to serialize/deserialize from second-precision timestamps
- ///
- /// # Example:
- ///
- /// ```rust
- /// # // We mark this ignored so that we can test on 1.13 (which does not
- /// # // support custom derive), and run tests with --ignored on beta and
- /// # // nightly to actually trigger these.
- /// #
- /// # #[macro_use] extern crate serde_derive;
- /// # extern crate serde_json;
- /// # extern crate serde;
- /// # extern crate chrono;
- /// # use chrono::{TimeZone, NaiveDate, NaiveDateTime, Utc};
- /// use chrono::naive::serde::ts_seconds;
- /// #[derive(Deserialize, Serialize)]
- /// struct S {
- /// #[serde(with = "ts_seconds")]
- /// time: NaiveDateTime
- /// }
- ///
- /// # fn example() -> Result<S, serde_json::Error> {
- /// let time = NaiveDate::from_ymd(2015, 5, 15).and_hms(10, 0, 0);
- /// let my_s = S {
- /// time: time.clone(),
- /// };
- ///
- /// let as_string = serde_json::to_string(&my_s)?;
- /// assert_eq!(as_string, r#"{"time":1431684000}"#);
- /// let my_s: S = serde_json::from_str(&as_string)?;
- /// assert_eq!(my_s.time, time);
- /// # Ok(my_s)
- /// # }
- /// # fn main() { example().unwrap(); }
- /// ```
- pub mod ts_seconds {
- use core::fmt;
- use serdelib::{de, ser};
-
- use {ne_timestamp, NaiveDateTime};
-
- /// Serialize a UTC datetime into an integer number of seconds since the epoch
- ///
- /// Intended for use with `serde`s `serialize_with` attribute.
- ///
- /// # Example:
- ///
- /// ```rust
- /// # // We mark this ignored so that we can test on 1.13 (which does not
- /// # // support custom derive), and run tests with --ignored on beta and
- /// # // nightly to actually trigger these.
- /// #
- /// # #[macro_use] extern crate serde_derive;
- /// # #[macro_use] extern crate serde_json;
- /// # #[macro_use] extern crate serde;
- /// # extern crate chrono;
- /// # use chrono::{TimeZone, NaiveDate, NaiveDateTime, Utc};
- /// # use serde::Serialize;
- /// use chrono::naive::serde::ts_seconds::serialize as to_ts;
- /// #[derive(Serialize)]
- /// struct S {
- /// #[serde(serialize_with = "to_ts")]
- /// time: NaiveDateTime
- /// }
- ///
- /// # fn example() -> Result<String, serde_json::Error> {
- /// let my_s = S {
- /// time: NaiveDate::from_ymd(2015, 5, 15).and_hms(10, 0, 0),
- /// };
- /// let as_string = serde_json::to_string(&my_s)?;
- /// assert_eq!(as_string, r#"{"time":1431684000}"#);
- /// # Ok(as_string)
- /// # }
- /// # fn main() { example().unwrap(); }
- /// ```
- pub fn serialize<S>(dt: &NaiveDateTime, serializer: S) -> Result<S::Ok, S::Error>
- where
- S: ser::Serializer,
- {
- serializer.serialize_i64(dt.timestamp())
- }
-
- /// Deserialize a `DateTime` from a seconds timestamp
- ///
- /// Intended for use with `serde`s `deserialize_with` attribute.
- ///
- /// # Example:
- ///
- /// ```rust
- /// # // We mark this ignored so that we can test on 1.13 (which does not
- /// # // support custom derive), and run tests with --ignored on beta and
- /// # // nightly to actually trigger these.
- /// #
- /// # #[macro_use] extern crate serde_derive;
- /// # #[macro_use] extern crate serde_json;
- /// # extern crate serde;
- /// # extern crate chrono;
- /// # use chrono::{NaiveDateTime, Utc};
- /// # use serde::Deserialize;
- /// use chrono::naive::serde::ts_seconds::deserialize as from_ts;
- /// #[derive(Deserialize)]
- /// struct S {
- /// #[serde(deserialize_with = "from_ts")]
- /// time: NaiveDateTime
- /// }
- ///
- /// # fn example() -> Result<S, serde_json::Error> {
- /// let my_s: S = serde_json::from_str(r#"{ "time": 1431684000 }"#)?;
- /// # Ok(my_s)
- /// # }
- /// # fn main() { example().unwrap(); }
- /// ```
- pub fn deserialize<'de, D>(d: D) -> Result<NaiveDateTime, D::Error>
- where
- D: de::Deserializer<'de>,
- {
- Ok(d.deserialize_i64(NaiveDateTimeFromSecondsVisitor)?)
- }
-
- struct NaiveDateTimeFromSecondsVisitor;
-
- impl<'de> de::Visitor<'de> for NaiveDateTimeFromSecondsVisitor {
- type Value = NaiveDateTime;
-
- fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
- formatter.write_str("a unix timestamp")
- }
-
- fn visit_i64<E>(self, value: i64) -> Result<NaiveDateTime, E>
- where
- E: de::Error,
- {
- NaiveDateTime::from_timestamp_opt(value, 0)
- .ok_or_else(|| E::custom(ne_timestamp(value)))
- }
-
- fn visit_u64<E>(self, value: u64) -> Result<NaiveDateTime, E>
- where
- E: de::Error,
- {
- NaiveDateTime::from_timestamp_opt(value as i64, 0)
- .ok_or_else(|| E::custom(ne_timestamp(value)))
- }
- }
- }
-
- #[cfg(test)]
- extern crate bincode;
- #[cfg(test)]
- extern crate serde_derive;
- #[cfg(test)]
- extern crate serde_json;
-
- #[test]
- fn test_serde_serialize() {
- super::test_encodable_json(self::serde_json::to_string);
- }
-
- #[test]
- fn test_serde_deserialize() {
- super::test_decodable_json(|input| self::serde_json::from_str(&input));
- }
-
- // Bincode is relevant to test separately from JSON because
- // it is not self-describing.
- #[test]
- fn test_serde_bincode() {
- use self::bincode::{deserialize, serialize, Infinite};
- use naive::NaiveDate;
-
- let dt = NaiveDate::from_ymd(2016, 7, 8).and_hms_milli(9, 10, 48, 90);
- let encoded = serialize(&dt, Infinite).unwrap();
- let decoded: NaiveDateTime = deserialize(&encoded).unwrap();
- assert_eq!(dt, decoded);
- }
-
- #[test]
- fn test_serde_bincode_optional() {
- use self::bincode::{deserialize, serialize, Infinite};
- use self::serde_derive::{Deserialize, Serialize};
- use prelude::*;
- use serde::ts_nanoseconds_option;
-
- #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
- struct Test {
- one: Option<i64>,
- #[serde(with = "ts_nanoseconds_option")]
- two: Option<DateTime<Utc>>,
- }
-
- let expected = Test { one: Some(1), two: Some(Utc.ymd(1970, 1, 1).and_hms(0, 1, 1)) };
- let bytes: Vec<u8> = serialize(&expected, Infinite).unwrap();
- let actual = deserialize::<Test>(&(bytes)).unwrap();
-
- assert_eq!(expected, actual);
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::NaiveDateTime;
- use naive::{NaiveDate, MAX_DATE, MIN_DATE};
- use oldtime::Duration;
- use std::i64;
- use Datelike;
-
- #[test]
- fn test_datetime_from_timestamp() {
- let from_timestamp = |secs| NaiveDateTime::from_timestamp_opt(secs, 0);
- let ymdhms = |y, m, d, h, n, s| NaiveDate::from_ymd(y, m, d).and_hms(h, n, s);
- assert_eq!(from_timestamp(-1), Some(ymdhms(1969, 12, 31, 23, 59, 59)));
- assert_eq!(from_timestamp(0), Some(ymdhms(1970, 1, 1, 0, 0, 0)));
- assert_eq!(from_timestamp(1), Some(ymdhms(1970, 1, 1, 0, 0, 1)));
- assert_eq!(from_timestamp(1_000_000_000), Some(ymdhms(2001, 9, 9, 1, 46, 40)));
- assert_eq!(from_timestamp(0x7fffffff), Some(ymdhms(2038, 1, 19, 3, 14, 7)));
- assert_eq!(from_timestamp(i64::MIN), None);
- assert_eq!(from_timestamp(i64::MAX), None);
- }
-
- #[test]
- fn test_datetime_add() {
- fn check(
- (y, m, d, h, n, s): (i32, u32, u32, u32, u32, u32),
- rhs: Duration,
- result: Option<(i32, u32, u32, u32, u32, u32)>,
- ) {
- let lhs = NaiveDate::from_ymd(y, m, d).and_hms(h, n, s);
- let sum =
- result.map(|(y, m, d, h, n, s)| NaiveDate::from_ymd(y, m, d).and_hms(h, n, s));
- assert_eq!(lhs.checked_add_signed(rhs), sum);
- assert_eq!(lhs.checked_sub_signed(-rhs), sum);
- };
-
- check(
- (2014, 5, 6, 7, 8, 9),
- Duration::seconds(3600 + 60 + 1),
- Some((2014, 5, 6, 8, 9, 10)),
- );
- check(
- (2014, 5, 6, 7, 8, 9),
- Duration::seconds(-(3600 + 60 + 1)),
- Some((2014, 5, 6, 6, 7, 8)),
- );
- check((2014, 5, 6, 7, 8, 9), Duration::seconds(86399), Some((2014, 5, 7, 7, 8, 8)));
- check((2014, 5, 6, 7, 8, 9), Duration::seconds(86_400 * 10), Some((2014, 5, 16, 7, 8, 9)));
- check((2014, 5, 6, 7, 8, 9), Duration::seconds(-86_400 * 10), Some((2014, 4, 26, 7, 8, 9)));
- check((2014, 5, 6, 7, 8, 9), Duration::seconds(86_400 * 10), Some((2014, 5, 16, 7, 8, 9)));
-
- // overflow check
- // assumes that we have correct values for MAX/MIN_DAYS_FROM_YEAR_0 from `naive::date`.
- // (they are private constants, but the equivalence is tested in that module.)
- let max_days_from_year_0 = MAX_DATE.signed_duration_since(NaiveDate::from_ymd(0, 1, 1));
- check((0, 1, 1, 0, 0, 0), max_days_from_year_0, Some((MAX_DATE.year(), 12, 31, 0, 0, 0)));
- check(
- (0, 1, 1, 0, 0, 0),
- max_days_from_year_0 + Duration::seconds(86399),
- Some((MAX_DATE.year(), 12, 31, 23, 59, 59)),
- );
- check((0, 1, 1, 0, 0, 0), max_days_from_year_0 + Duration::seconds(86_400), None);
- check((0, 1, 1, 0, 0, 0), Duration::max_value(), None);
-
- let min_days_from_year_0 = MIN_DATE.signed_duration_since(NaiveDate::from_ymd(0, 1, 1));
- check((0, 1, 1, 0, 0, 0), min_days_from_year_0, Some((MIN_DATE.year(), 1, 1, 0, 0, 0)));
- check((0, 1, 1, 0, 0, 0), min_days_from_year_0 - Duration::seconds(1), None);
- check((0, 1, 1, 0, 0, 0), Duration::min_value(), None);
- }
-
- #[test]
- fn test_datetime_sub() {
- let ymdhms = |y, m, d, h, n, s| NaiveDate::from_ymd(y, m, d).and_hms(h, n, s);
- let since = NaiveDateTime::signed_duration_since;
- assert_eq!(
- since(ymdhms(2014, 5, 6, 7, 8, 9), ymdhms(2014, 5, 6, 7, 8, 9)),
- Duration::zero()
- );
- assert_eq!(
- since(ymdhms(2014, 5, 6, 7, 8, 10), ymdhms(2014, 5, 6, 7, 8, 9)),
- Duration::seconds(1)
- );
- assert_eq!(
- since(ymdhms(2014, 5, 6, 7, 8, 9), ymdhms(2014, 5, 6, 7, 8, 10)),
- Duration::seconds(-1)
- );
- assert_eq!(
- since(ymdhms(2014, 5, 7, 7, 8, 9), ymdhms(2014, 5, 6, 7, 8, 10)),
- Duration::seconds(86399)
- );
- assert_eq!(
- since(ymdhms(2001, 9, 9, 1, 46, 39), ymdhms(1970, 1, 1, 0, 0, 0)),
- Duration::seconds(999_999_999)
- );
- }
-
- #[test]
- fn test_datetime_addassignment() {
- let ymdhms = |y, m, d, h, n, s| NaiveDate::from_ymd(y, m, d).and_hms(h, n, s);
- let mut date = ymdhms(2016, 10, 1, 10, 10, 10);
- date += Duration::minutes(10_000_000);
- assert_eq!(date, ymdhms(2035, 10, 6, 20, 50, 10));
- date += Duration::days(10);
- assert_eq!(date, ymdhms(2035, 10, 16, 20, 50, 10));
- }
-
- #[test]
- fn test_datetime_subassignment() {
- let ymdhms = |y, m, d, h, n, s| NaiveDate::from_ymd(y, m, d).and_hms(h, n, s);
- let mut date = ymdhms(2016, 10, 1, 10, 10, 10);
- date -= Duration::minutes(10_000_000);
- assert_eq!(date, ymdhms(1997, 9, 26, 23, 30, 10));
- date -= Duration::days(10);
- assert_eq!(date, ymdhms(1997, 9, 16, 23, 30, 10));
- }
-
- #[test]
- fn test_datetime_timestamp() {
- let to_timestamp =
- |y, m, d, h, n, s| NaiveDate::from_ymd(y, m, d).and_hms(h, n, s).timestamp();
- assert_eq!(to_timestamp(1969, 12, 31, 23, 59, 59), -1);
- assert_eq!(to_timestamp(1970, 1, 1, 0, 0, 0), 0);
- assert_eq!(to_timestamp(1970, 1, 1, 0, 0, 1), 1);
- assert_eq!(to_timestamp(2001, 9, 9, 1, 46, 40), 1_000_000_000);
- assert_eq!(to_timestamp(2038, 1, 19, 3, 14, 7), 0x7fffffff);
- }
-
- #[test]
- fn test_datetime_from_str() {
- // valid cases
- let valid = [
- "2015-2-18T23:16:9.15",
- "-77-02-18T23:16:09",
- " +82701 - 05 - 6 T 15 : 9 : 60.898989898989 ",
- ];
- for &s in &valid {
- let d = match s.parse::<NaiveDateTime>() {
- Ok(d) => d,
- Err(e) => panic!("parsing `{}` has failed: {}", s, e),
- };
- let s_ = format!("{:?}", d);
- // `s` and `s_` may differ, but `s.parse()` and `s_.parse()` must be same
- let d_ = match s_.parse::<NaiveDateTime>() {
- Ok(d) => d,
- Err(e) => {
- panic!("`{}` is parsed into `{:?}`, but reparsing that has failed: {}", s, d, e)
- }
- };
- assert!(
- d == d_,
- "`{}` is parsed into `{:?}`, but reparsed result \
- `{:?}` does not match",
- s,
- d,
- d_
- );
- }
-
- // some invalid cases
- // since `ParseErrorKind` is private, all we can do is to check if there was an error
- assert!("".parse::<NaiveDateTime>().is_err());
- assert!("x".parse::<NaiveDateTime>().is_err());
- assert!("15".parse::<NaiveDateTime>().is_err());
- assert!("15:8:9".parse::<NaiveDateTime>().is_err());
- assert!("15-8-9".parse::<NaiveDateTime>().is_err());
- assert!("2015-15-15T15:15:15".parse::<NaiveDateTime>().is_err());
- assert!("2012-12-12T12:12:12x".parse::<NaiveDateTime>().is_err());
- assert!("2012-123-12T12:12:12".parse::<NaiveDateTime>().is_err());
- assert!("+ 82701-123-12T12:12:12".parse::<NaiveDateTime>().is_err());
- assert!("+802701-123-12T12:12:12".parse::<NaiveDateTime>().is_err()); // out-of-bound
- }
-
- #[test]
- fn test_datetime_parse_from_str() {
- let ymdhms = |y, m, d, h, n, s| NaiveDate::from_ymd(y, m, d).and_hms(h, n, s);
- let ymdhmsn =
- |y, m, d, h, n, s, nano| NaiveDate::from_ymd(y, m, d).and_hms_nano(h, n, s, nano);
- assert_eq!(
- NaiveDateTime::parse_from_str("2014-5-7T12:34:56+09:30", "%Y-%m-%dT%H:%M:%S%z"),
- Ok(ymdhms(2014, 5, 7, 12, 34, 56))
- ); // ignore offset
- assert_eq!(
- NaiveDateTime::parse_from_str("2015-W06-1 000000", "%G-W%V-%u%H%M%S"),
- Ok(ymdhms(2015, 2, 2, 0, 0, 0))
- );
- assert_eq!(
- NaiveDateTime::parse_from_str(
- "Fri, 09 Aug 2013 23:54:35 GMT",
- "%a, %d %b %Y %H:%M:%S GMT"
- ),
- Ok(ymdhms(2013, 8, 9, 23, 54, 35))
- );
- assert!(NaiveDateTime::parse_from_str(
- "Sat, 09 Aug 2013 23:54:35 GMT",
- "%a, %d %b %Y %H:%M:%S GMT"
- )
- .is_err());
- assert!(NaiveDateTime::parse_from_str("2014-5-7 12:3456", "%Y-%m-%d %H:%M:%S").is_err());
- assert!(NaiveDateTime::parse_from_str("12:34:56", "%H:%M:%S").is_err()); // insufficient
- assert_eq!(
- NaiveDateTime::parse_from_str("1441497364", "%s"),
- Ok(ymdhms(2015, 9, 5, 23, 56, 4))
- );
- assert_eq!(
- NaiveDateTime::parse_from_str("1283929614.1234", "%s.%f"),
- Ok(ymdhmsn(2010, 9, 8, 7, 6, 54, 1234))
- );
- assert_eq!(
- NaiveDateTime::parse_from_str("1441497364.649", "%s%.3f"),
- Ok(ymdhmsn(2015, 9, 5, 23, 56, 4, 649000000))
- );
- assert_eq!(
- NaiveDateTime::parse_from_str("1497854303.087654", "%s%.6f"),
- Ok(ymdhmsn(2017, 6, 19, 6, 38, 23, 87654000))
- );
- assert_eq!(
- NaiveDateTime::parse_from_str("1437742189.918273645", "%s%.9f"),
- Ok(ymdhmsn(2015, 7, 24, 12, 49, 49, 918273645))
- );
- }
-
- #[test]
- fn test_datetime_format() {
- let dt = NaiveDate::from_ymd(2010, 9, 8).and_hms_milli(7, 6, 54, 321);
- assert_eq!(dt.format("%c").to_string(), "Wed Sep 8 07:06:54 2010");
- assert_eq!(dt.format("%s").to_string(), "1283929614");
- assert_eq!(dt.format("%t%n%%%n%t").to_string(), "\t\n%\n\t");
-
- // a horror of leap second: coming near to you.
- let dt = NaiveDate::from_ymd(2012, 6, 30).and_hms_milli(23, 59, 59, 1_000);
- assert_eq!(dt.format("%c").to_string(), "Sat Jun 30 23:59:60 2012");
- assert_eq!(dt.format("%s").to_string(), "1341100799"); // not 1341100800, it's intentional.
- }
-
- #[test]
- fn test_datetime_add_sub_invariant() {
- // issue #37
- let base = NaiveDate::from_ymd(2000, 1, 1).and_hms(0, 0, 0);
- let t = -946684799990000;
- let time = base + Duration::microseconds(t);
- assert_eq!(t, time.signed_duration_since(base).num_microseconds().unwrap());
- }
-
- #[test]
- fn test_nanosecond_range() {
- const A_BILLION: i64 = 1_000_000_000;
- let maximum = "2262-04-11T23:47:16.854775804";
- let parsed: NaiveDateTime = maximum.parse().unwrap();
- let nanos = parsed.timestamp_nanos();
- assert_eq!(
- parsed,
- NaiveDateTime::from_timestamp(nanos / A_BILLION, (nanos % A_BILLION) as u32)
- );
-
- let minimum = "1677-09-21T00:12:44.000000000";
- let parsed: NaiveDateTime = minimum.parse().unwrap();
- let nanos = parsed.timestamp_nanos();
- assert_eq!(
- parsed,
- NaiveDateTime::from_timestamp(nanos / A_BILLION, (nanos % A_BILLION) as u32)
- );
- }
-}
diff --git a/vendor/chrono/src/naive/datetime/mod.rs b/vendor/chrono/src/naive/datetime/mod.rs
new file mode 100644
index 000000000..ec0d842c0
--- /dev/null
+++ b/vendor/chrono/src/naive/datetime/mod.rs
@@ -0,0 +1,1946 @@
+// This is a part of Chrono.
+// See README.md and LICENSE.txt for details.
+
+//! ISO 8601 date and time without timezone.
+
+#[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::{Fixed, Item, Numeric, Pad};
+use crate::naive::{Days, IsoWeek, NaiveDate, NaiveTime};
+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;
+
+/// Tools to help serializing/deserializing `NaiveDateTime`s
+#[cfg(feature = "serde")]
+pub(crate) mod serde;
+
+#[cfg(test)]
+mod tests;
+
+/// The tight upper bound guarantees that a duration with `|Duration| >= 2^MAX_SECS_BITS`
+/// will always overflow the addition with any date and time type.
+///
+/// So why is this needed? `Duration::seconds(rhs)` may overflow, and we don't have
+/// an alternative returning `Option` or `Result`. Thus we need some early bound to avoid
+/// 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;
+/// The maximum possible `NaiveDateTime`.
+#[deprecated(since = "0.4.20", note = "Use NaiveDateTime::MAX instead")]
+pub const MAX_DATETIME: NaiveDateTime = NaiveDateTime::MAX;
+
+/// ISO 8601 combined date and time without timezone.
+///
+/// # Example
+///
+/// `NaiveDateTime` is commonly created from [`NaiveDate`](./struct.NaiveDate.html).
+///
+/// ```
+/// use chrono::{NaiveDate, NaiveDateTime};
+///
+/// let dt: NaiveDateTime = NaiveDate::from_ymd_opt(2016, 7, 8).unwrap().and_hms_opt(9, 10, 11).unwrap();
+/// # let _ = dt;
+/// ```
+///
+/// You can use typical [date-like](../trait.Datelike.html) and
+/// [time-like](../trait.Timelike.html) methods,
+/// provided that relevant traits are in the scope.
+///
+/// ```
+/// # use chrono::{NaiveDate, NaiveDateTime};
+/// # let dt: NaiveDateTime = NaiveDate::from_ymd_opt(2016, 7, 8).unwrap().and_hms_opt(9, 10, 11).unwrap();
+/// use chrono::{Datelike, Timelike, Weekday};
+///
+/// assert_eq!(dt.weekday(), Weekday::Fri);
+/// assert_eq!(dt.num_seconds_from_midnight(), 33011);
+/// ```
+#[derive(PartialEq, Eq, Hash, PartialOrd, Ord, Copy, Clone)]
+#[cfg_attr(feature = "rkyv", derive(Archive, Deserialize, Serialize))]
+#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
+pub struct NaiveDateTime {
+ date: NaiveDate,
+ 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)
+ /// and many other helper constructors on `NaiveDate`.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use chrono::{NaiveDate, NaiveTime, NaiveDateTime};
+ ///
+ /// let d = NaiveDate::from_ymd_opt(2015, 6, 3).unwrap();
+ /// let t = NaiveTime::from_hms_milli_opt(12, 34, 56, 789).unwrap();
+ ///
+ /// let dt = NaiveDateTime::new(d, t);
+ /// assert_eq!(dt.date(), d);
+ /// assert_eq!(dt.time(), t);
+ /// ```
+ #[inline]
+ pub const fn new(date: NaiveDate, time: NaiveTime) -> NaiveDateTime {
+ NaiveDateTime { date, time }
+ }
+
+ /// Makes a new `NaiveDateTime` corresponding to a UTC date and time,
+ /// from the number of non-leap seconds
+ /// since the midnight UTC on January 1, 1970 (aka "UNIX timestamp")
+ /// and the number of nanoseconds since the last whole non-leap second.
+ ///
+ /// For a non-naive version of this function see
+ /// [`TimeZone::timestamp`](../offset/trait.TimeZone.html#method.timestamp).
+ ///
+ /// The nanosecond part can exceed 1,000,000,000 in order to represent the
+ /// [leap second](./struct.NaiveTime.html#leap-second-handling). (The true "UNIX
+ /// timestamp" cannot represent a leap second unambiguously.)
+ ///
+ /// 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]
+ 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")
+ }
+
+ /// Creates a new [NaiveDateTime] from milliseconds since the UNIX epoch.
+ ///
+ /// The UNIX epoch starts on midnight, January 1, 1970, UTC.
+ ///
+ /// Returns `None` on an out-of-range number of milliseconds.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use chrono::NaiveDateTime;
+ /// let timestamp_millis: i64 = 1662921288000; //Sunday, September 11, 2022 6:34:48 PM
+ /// let naive_datetime = NaiveDateTime::from_timestamp_millis(timestamp_millis);
+ /// assert!(naive_datetime.is_some());
+ /// assert_eq!(timestamp_millis, naive_datetime.unwrap().timestamp_millis());
+ ///
+ /// // Negative timestamps (before the UNIX epoch) are supported as well.
+ /// let timestamp_millis: i64 = -2208936075000; //Mon Jan 01 1900 14:38:45 GMT+0000
+ /// let naive_datetime = NaiveDateTime::from_timestamp_millis(timestamp_millis);
+ /// assert!(naive_datetime.is_some());
+ /// assert_eq!(timestamp_millis, naive_datetime.unwrap().timestamp_millis());
+ /// ```
+ #[inline]
+ pub fn from_timestamp_millis(millis: i64) -> Option<NaiveDateTime> {
+ Self::from_timestamp_unit(millis, TimestampUnit::Millis)
+ }
+
+ /// Creates a new [NaiveDateTime] from microseconds since the UNIX epoch.
+ ///
+ /// The UNIX epoch starts on midnight, January 1, 1970, UTC.
+ ///
+ /// Returns `None` on an out-of-range number of microseconds.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use chrono::NaiveDateTime;
+ /// let timestamp_micros: i64 = 1662921288000000; //Sunday, September 11, 2022 6:34:48 PM
+ /// let naive_datetime = NaiveDateTime::from_timestamp_micros(timestamp_micros);
+ /// assert!(naive_datetime.is_some());
+ /// assert_eq!(timestamp_micros, naive_datetime.unwrap().timestamp_micros());
+ ///
+ /// // Negative timestamps (before the UNIX epoch) are supported as well.
+ /// let timestamp_micros: i64 = -2208936075000000; //Mon Jan 01 1900 14:38:45 GMT+0000
+ /// let naive_datetime = NaiveDateTime::from_timestamp_micros(timestamp_micros);
+ /// assert!(naive_datetime.is_some());
+ /// assert_eq!(timestamp_micros, naive_datetime.unwrap().timestamp_micros());
+ /// ```
+ #[inline]
+ pub fn from_timestamp_micros(micros: i64) -> Option<NaiveDateTime> {
+ Self::from_timestamp_unit(micros, TimestampUnit::Micros)
+ }
+
+ /// Makes a new `NaiveDateTime` corresponding to a UTC date and time,
+ /// from the number of non-leap seconds
+ /// since the midnight UTC on January 1, 1970 (aka "UNIX timestamp")
+ /// and the number of nanoseconds since the last whole non-leap second.
+ ///
+ /// The nanosecond part can exceed 1,000,000,000
+ /// in order to represent the [leap second](./struct.NaiveTime.html#leap-second-handling).
+ /// (The true "UNIX timestamp" cannot represent a leap second unambiguously.)
+ ///
+ /// Returns `None` on the out-of-range number of seconds (more than 262 000 years away
+ /// from common era) and/or invalid nanosecond (2 seconds or more).
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use chrono::{NaiveDateTime, NaiveDate};
+ /// use std::i64;
+ ///
+ /// let from_timestamp_opt = NaiveDateTime::from_timestamp_opt;
+ ///
+ /// assert!(from_timestamp_opt(0, 0).is_some());
+ /// assert!(from_timestamp_opt(0, 999_999_999).is_some());
+ /// assert!(from_timestamp_opt(0, 1_500_000_000).is_some()); // leap second
+ /// assert!(from_timestamp_opt(0, 2_000_000_000).is_none());
+ /// assert!(from_timestamp_opt(i64::MAX, 0).is_none());
+ /// ```
+ #[inline]
+ 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()
+ .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);
+ match (date, time) {
+ (Some(date), Some(time)) => Some(NaiveDateTime { date, time }),
+ (_, _) => None,
+ }
+ }
+
+ /// Parses a string with the specified format string and returns a new `NaiveDateTime`.
+ /// See the [`format::strftime` module](../format/strftime/index.html)
+ /// on the supported escape sequences.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use chrono::{NaiveDateTime, NaiveDate};
+ ///
+ /// let parse_from_str = NaiveDateTime::parse_from_str;
+ ///
+ /// assert_eq!(parse_from_str("2015-09-05 23:56:04", "%Y-%m-%d %H:%M:%S"),
+ /// Ok(NaiveDate::from_ymd_opt(2015, 9, 5).unwrap().and_hms_opt(23, 56, 4).unwrap()));
+ /// assert_eq!(parse_from_str("5sep2015pm012345.6789", "%d%b%Y%p%I%M%S%.f"),
+ /// Ok(NaiveDate::from_ymd_opt(2015, 9, 5).unwrap().and_hms_micro_opt(13, 23, 45, 678_900).unwrap()));
+ /// ```
+ ///
+ /// Offset is ignored for the purpose of parsing.
+ ///
+ /// ```
+ /// # use chrono::{NaiveDateTime, NaiveDate};
+ /// # let parse_from_str = NaiveDateTime::parse_from_str;
+ /// assert_eq!(parse_from_str("2014-5-17T12:34:56+09:30", "%Y-%m-%dT%H:%M:%S%z"),
+ /// Ok(NaiveDate::from_ymd_opt(2014, 5, 17).unwrap().and_hms_opt(12, 34, 56).unwrap()));
+ /// ```
+ ///
+ /// [Leap seconds](./struct.NaiveTime.html#leap-second-handling) are correctly handled by
+ /// treating any time of the form `hh:mm:60` as a leap second.
+ /// (This equally applies to the formatting, so the round trip is possible.)
+ ///
+ /// ```
+ /// # use chrono::{NaiveDateTime, NaiveDate};
+ /// # let parse_from_str = NaiveDateTime::parse_from_str;
+ /// assert_eq!(parse_from_str("2015-07-01 08:59:60.123", "%Y-%m-%d %H:%M:%S%.f"),
+ /// Ok(NaiveDate::from_ymd_opt(2015, 7, 1).unwrap().and_hms_milli_opt(8, 59, 59, 1_123).unwrap()));
+ /// ```
+ ///
+ /// Missing seconds are assumed to be zero,
+ /// but out-of-bound times or insufficient fields are errors otherwise.
+ ///
+ /// ```
+ /// # use chrono::{NaiveDateTime, NaiveDate};
+ /// # let parse_from_str = NaiveDateTime::parse_from_str;
+ /// assert_eq!(parse_from_str("94/9/4 7:15", "%y/%m/%d %H:%M"),
+ /// Ok(NaiveDate::from_ymd_opt(1994, 9, 4).unwrap().and_hms_opt(7, 15, 0).unwrap()));
+ ///
+ /// assert!(parse_from_str("04m33s", "%Mm%Ss").is_err());
+ /// assert!(parse_from_str("94/9/4 12", "%y/%m/%d %H").is_err());
+ /// assert!(parse_from_str("94/9/4 17:60", "%y/%m/%d %H:%M").is_err());
+ /// assert!(parse_from_str("94/9/4 24:00:00", "%y/%m/%d %H:%M:%S").is_err());
+ /// ```
+ ///
+ /// All parsed fields should be consistent to each other, otherwise it's an error.
+ ///
+ /// ```
+ /// # use chrono::NaiveDateTime;
+ /// # let parse_from_str = NaiveDateTime::parse_from_str;
+ /// let fmt = "%Y-%m-%d %H:%M:%S = UNIX timestamp %s";
+ /// assert!(parse_from_str("2001-09-09 01:46:39 = UNIX timestamp 999999999", fmt).is_ok());
+ /// assert!(parse_from_str("1970-01-01 00:00:00 = UNIX timestamp 1", fmt).is_err());
+ /// ```
+ ///
+ /// Years before 1 BCE or after 9999 CE, require an initial sign
+ ///
+ ///```
+ /// # use chrono::{NaiveDate, 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
+ }
+
+ /// Retrieves a date component.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use chrono::NaiveDate;
+ ///
+ /// let dt = NaiveDate::from_ymd_opt(2016, 7, 8).unwrap().and_hms_opt(9, 10, 11).unwrap();
+ /// assert_eq!(dt.date(), NaiveDate::from_ymd_opt(2016, 7, 8).unwrap());
+ /// ```
+ #[inline]
+ pub const fn date(&self) -> NaiveDate {
+ self.date
+ }
+
+ /// Retrieves a time component.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use chrono::{NaiveDate, NaiveTime};
+ ///
+ /// let dt = NaiveDate::from_ymd_opt(2016, 7, 8).unwrap().and_hms_opt(9, 10, 11).unwrap();
+ /// assert_eq!(dt.time(), NaiveTime::from_hms_opt(9, 10, 11).unwrap());
+ /// ```
+ #[inline]
+ pub const fn time(&self) -> NaiveTime {
+ self.time
+ }
+
+ /// Returns the number of non-leap seconds since the midnight on January 1, 1970.
+ ///
+ /// Note that this does *not* account for the timezone!
+ /// The true "UNIX timestamp" would count seconds since the midnight *UTC* on the epoch.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use chrono::NaiveDate;
+ ///
+ /// let dt = NaiveDate::from_ymd_opt(1970, 1, 1).unwrap().and_hms_milli_opt(0, 0, 1, 980).unwrap();
+ /// assert_eq!(dt.timestamp(), 1);
+ ///
+ /// let dt = NaiveDate::from_ymd_opt(2001, 9, 9).unwrap().and_hms_opt(1, 46, 40).unwrap();
+ /// assert_eq!(dt.timestamp(), 1_000_000_000);
+ ///
+ /// let dt = NaiveDate::from_ymd_opt(1969, 12, 31).unwrap().and_hms_opt(23, 59, 59).unwrap();
+ /// assert_eq!(dt.timestamp(), -1);
+ ///
+ /// let dt = NaiveDate::from_ymd_opt(-1, 1, 1).unwrap().and_hms_opt(0, 0, 0).unwrap();
+ /// assert_eq!(dt.timestamp(), -62198755200);
+ /// ```
+ #[inline]
+ pub fn timestamp(&self) -> i64 {
+ const UNIX_EPOCH_DAY: i64 = 719_163;
+ let gregorian_day = i64::from(self.date.num_days_from_ce());
+ let seconds_from_midnight = i64::from(self.time.num_seconds_from_midnight());
+ (gregorian_day - UNIX_EPOCH_DAY) * 86_400 + seconds_from_midnight
+ }
+
+ /// Returns the number of non-leap *milliseconds* since midnight on January 1, 1970.
+ ///
+ /// Note that this does *not* account for the timezone!
+ /// The true "UNIX timestamp" would count seconds since the midnight *UTC* on the epoch.
+ ///
+ /// Note also that this does reduce the number of years that can be
+ /// represented from ~584 Billion to ~584 Million. (If this is a problem,
+ /// please file an issue to let me know what domain needs millisecond
+ /// precision over billions of years, I'm curious.)
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use chrono::NaiveDate;
+ ///
+ /// let dt = NaiveDate::from_ymd_opt(1970, 1, 1).unwrap().and_hms_milli_opt(0, 0, 1, 444).unwrap();
+ /// assert_eq!(dt.timestamp_millis(), 1_444);
+ ///
+ /// let dt = NaiveDate::from_ymd_opt(2001, 9, 9).unwrap().and_hms_milli_opt(1, 46, 40, 555).unwrap();
+ /// assert_eq!(dt.timestamp_millis(), 1_000_000_000_555);
+ ///
+ /// let dt = NaiveDate::from_ymd_opt(1969, 12, 31).unwrap().and_hms_milli_opt(23, 59, 59, 100).unwrap();
+ /// assert_eq!(dt.timestamp_millis(), -900);
+ /// ```
+ #[inline]
+ pub fn timestamp_millis(&self) -> i64 {
+ let as_ms = self.timestamp() * 1000;
+ as_ms + i64::from(self.timestamp_subsec_millis())
+ }
+
+ /// Returns the number of non-leap *microseconds* since midnight on January 1, 1970.
+ ///
+ /// Note that this does *not* account for the timezone!
+ /// The true "UNIX timestamp" would count seconds since the midnight *UTC* on the epoch.
+ ///
+ /// Note also that this does reduce the number of years that can be
+ /// represented from ~584 Billion to ~584 Thousand. (If this is a problem,
+ /// please file an issue to let me know what domain needs microsecond
+ /// precision over millennia, I'm curious.)
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use chrono::NaiveDate;
+ ///
+ /// let dt = NaiveDate::from_ymd_opt(1970, 1, 1).unwrap().and_hms_micro_opt(0, 0, 1, 444).unwrap();
+ /// assert_eq!(dt.timestamp_micros(), 1_000_444);
+ ///
+ /// let dt = NaiveDate::from_ymd_opt(2001, 9, 9).unwrap().and_hms_micro_opt(1, 46, 40, 555).unwrap();
+ /// assert_eq!(dt.timestamp_micros(), 1_000_000_000_000_555);
+ /// ```
+ #[inline]
+ pub fn timestamp_micros(&self) -> i64 {
+ let as_us = self.timestamp() * 1_000_000;
+ as_us + i64::from(self.timestamp_subsec_micros())
+ }
+
+ /// Returns the number of non-leap *nanoseconds* since midnight on January 1, 1970.
+ ///
+ /// Note that this does *not* account for the timezone!
+ /// The true "UNIX timestamp" would count seconds since the midnight *UTC* on the epoch.
+ ///
+ /// # Panics
+ ///
+ /// Note also that this does reduce the number of years that can be
+ /// represented from ~584 Billion to ~584 years. The dates that can be
+ /// represented as nanoseconds are between 1677-09-21T00:12:44.0 and
+ /// 2262-04-11T23:47:16.854775804.
+ ///
+ /// (If this is a problem, please file an issue to let me know what domain
+ /// needs nanosecond precision over millennia, I'm curious.)
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use chrono::{NaiveDate, NaiveDateTime};
+ ///
+ /// let dt = NaiveDate::from_ymd_opt(1970, 1, 1).unwrap().and_hms_nano_opt(0, 0, 1, 444).unwrap();
+ /// assert_eq!(dt.timestamp_nanos(), 1_000_000_444);
+ ///
+ /// let dt = NaiveDate::from_ymd_opt(2001, 9, 9).unwrap().and_hms_nano_opt(1, 46, 40, 555).unwrap();
+ ///
+ /// const A_BILLION: i64 = 1_000_000_000;
+ /// 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)
+ /// );
+ /// ```
+ #[inline]
+ pub fn timestamp_nanos(&self) -> i64 {
+ let as_ns = self.timestamp() * 1_000_000_000;
+ as_ns + i64::from(self.timestamp_subsec_nanos())
+ }
+
+ /// Returns the number of milliseconds since the last whole non-leap second.
+ ///
+ /// The return value ranges from 0 to 999,
+ /// or for [leap seconds](./struct.NaiveTime.html#leap-second-handling), to 1,999.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use chrono::NaiveDate;
+ ///
+ /// let dt = NaiveDate::from_ymd_opt(2016, 7, 8).unwrap().and_hms_nano_opt(9, 10, 11, 123_456_789).unwrap();
+ /// assert_eq!(dt.timestamp_subsec_millis(), 123);
+ ///
+ /// let dt = NaiveDate::from_ymd_opt(2015, 7, 1).unwrap().and_hms_nano_opt(8, 59, 59, 1_234_567_890).unwrap();
+ /// assert_eq!(dt.timestamp_subsec_millis(), 1_234);
+ /// ```
+ #[inline]
+ pub fn timestamp_subsec_millis(&self) -> u32 {
+ self.timestamp_subsec_nanos() / 1_000_000
+ }
+
+ /// Returns the number of microseconds since the last whole non-leap second.
+ ///
+ /// The return value ranges from 0 to 999,999,
+ /// or for [leap seconds](./struct.NaiveTime.html#leap-second-handling), to 1,999,999.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use chrono::NaiveDate;
+ ///
+ /// let dt = NaiveDate::from_ymd_opt(2016, 7, 8).unwrap().and_hms_nano_opt(9, 10, 11, 123_456_789).unwrap();
+ /// assert_eq!(dt.timestamp_subsec_micros(), 123_456);
+ ///
+ /// let dt = NaiveDate::from_ymd_opt(2015, 7, 1).unwrap().and_hms_nano_opt(8, 59, 59, 1_234_567_890).unwrap();
+ /// assert_eq!(dt.timestamp_subsec_micros(), 1_234_567);
+ /// ```
+ #[inline]
+ pub fn timestamp_subsec_micros(&self) -> u32 {
+ self.timestamp_subsec_nanos() / 1_000
+ }
+
+ /// Returns the number of nanoseconds since the last whole non-leap second.
+ ///
+ /// The return value ranges from 0 to 999,999,999,
+ /// or for [leap seconds](./struct.NaiveTime.html#leap-second-handling), to 1,999,999,999.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use chrono::NaiveDate;
+ ///
+ /// let dt = NaiveDate::from_ymd_opt(2016, 7, 8).unwrap().and_hms_nano_opt(9, 10, 11, 123_456_789).unwrap();
+ /// assert_eq!(dt.timestamp_subsec_nanos(), 123_456_789);
+ ///
+ /// let dt = NaiveDate::from_ymd_opt(2015, 7, 1).unwrap().and_hms_nano_opt(8, 59, 59, 1_234_567_890).unwrap();
+ /// assert_eq!(dt.timestamp_subsec_nanos(), 1_234_567_890);
+ /// ```
+ #[inline]
+ pub fn timestamp_subsec_nanos(&self) -> u32 {
+ self.time.nanosecond()
+ }
+
+ /// Adds given `Duration` to the current date and time.
+ ///
+ /// 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**.
+ ///
+ /// Returns `None` when it will result in overflow.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use chrono::{Duration, NaiveDate};
+ ///
+ /// let from_ymd = NaiveDate::from_ymd;
+ ///
+ /// let d = from_ymd(2016, 7, 8);
+ /// let hms = |h, m, s| d.and_hms_opt(h, m, s).unwrap();
+ /// assert_eq!(hms(3, 5, 7).checked_add_signed(Duration::zero()),
+ /// Some(hms(3, 5, 7)));
+ /// assert_eq!(hms(3, 5, 7).checked_add_signed(Duration::seconds(1)),
+ /// Some(hms(3, 5, 8)));
+ /// assert_eq!(hms(3, 5, 7).checked_add_signed(Duration::seconds(-1)),
+ /// Some(hms(3, 5, 6)));
+ /// assert_eq!(hms(3, 5, 7).checked_add_signed(Duration::seconds(3600 + 60)),
+ /// Some(hms(4, 6, 7)));
+ /// assert_eq!(hms(3, 5, 7).checked_add_signed(Duration::seconds(86_400)),
+ /// Some(from_ymd(2016, 7, 9).and_hms_opt(3, 5, 7).unwrap()));
+ ///
+ /// let hmsm = |h, m, s, milli| d.and_hms_milli_opt(h, m, s, milli).unwrap();
+ /// assert_eq!(hmsm(3, 5, 7, 980).checked_add_signed(Duration::milliseconds(450)),
+ /// Some(hmsm(3, 5, 8, 430)));
+ /// ```
+ ///
+ /// Overflow returns `None`.
+ ///
+ /// ```
+ /// # use chrono::{Duration, NaiveDate};
+ /// # let hms = |h, m, s| NaiveDate::from_ymd_opt(2016, 7, 8).unwrap().and_hms_opt(h, m, s).unwrap();
+ /// assert_eq!(hms(3, 5, 7).checked_add_signed(Duration::days(1_000_000_000)), None);
+ /// ```
+ ///
+ /// Leap seconds are handled,
+ /// but the addition assumes that it is the only leap second happened.
+ ///
+ /// ```
+ /// # use chrono::{Duration, NaiveDate};
+ /// # let from_ymd = NaiveDate::from_ymd;
+ /// # 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()),
+ /// Some(hmsm(3, 5, 59, 1_300)));
+ /// assert_eq!(leap.checked_add_signed(Duration::milliseconds(-500)),
+ /// Some(hmsm(3, 5, 59, 800)));
+ /// assert_eq!(leap.checked_add_signed(Duration::milliseconds(500)),
+ /// Some(hmsm(3, 5, 59, 1_800)));
+ /// assert_eq!(leap.checked_add_signed(Duration::milliseconds(800)),
+ /// Some(hmsm(3, 6, 0, 100)));
+ /// assert_eq!(leap.checked_add_signed(Duration::seconds(10)),
+ /// Some(hmsm(3, 6, 9, 300)));
+ /// assert_eq!(leap.checked_add_signed(Duration::seconds(-10)),
+ /// Some(hmsm(3, 5, 50, 300)));
+ /// assert_eq!(leap.checked_add_signed(Duration::days(1)),
+ /// Some(from_ymd(2016, 7, 9).and_hms_milli_opt(3, 5, 59, 300).unwrap()));
+ /// ```
+ pub fn checked_add_signed(self, rhs: OldDuration) -> Option<NaiveDateTime> {
+ let (time, rhs) = self.time.overflowing_add_signed(rhs);
+
+ // early checking to avoid overflow in OldDuration::seconds
+ if rhs <= (-1 << MAX_SECS_BITS) || rhs >= (1 << MAX_SECS_BITS) {
+ return None;
+ }
+
+ let date = self.date.checked_add_signed(OldDuration::seconds(rhs))?;
+ Some(NaiveDateTime { date, time })
+ }
+
+ /// Adds given `Months` to the current date and time.
+ ///
+ /// Returns `None` when it will result in overflow.
+ ///
+ /// Overflow returns `None`.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use std::str::FromStr;
+ /// use chrono::{Months, NaiveDate, NaiveDateTime};
+ ///
+ /// assert_eq!(
+ /// NaiveDate::from_ymd_opt(2014, 1, 1).unwrap().and_hms_opt(1, 0, 0).unwrap()
+ /// .checked_add_months(Months::new(1)),
+ /// Some(NaiveDate::from_ymd_opt(2014, 2, 1).unwrap().and_hms_opt(1, 0, 0).unwrap())
+ /// );
+ ///
+ /// assert_eq!(
+ /// NaiveDate::from_ymd_opt(2014, 1, 1).unwrap().and_hms_opt(1, 0, 0).unwrap()
+ /// .checked_add_months(Months::new(core::i32::MAX as u32 + 1)),
+ /// None
+ /// );
+ /// ```
+ pub fn checked_add_months(self, rhs: Months) -> Option<NaiveDateTime> {
+ Some(Self { date: self.date.checked_add_months(rhs)?, time: self.time })
+ }
+
+ /// Subtracts given `Duration` from the current date and time.
+ ///
+ /// As a part of Chrono's [leap second handling](./struct.NaiveTime.html#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**.
+ ///
+ /// Returns `None` when it will result in overflow.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use chrono::{Duration, NaiveDate};
+ ///
+ /// let from_ymd = NaiveDate::from_ymd;
+ ///
+ /// let d = from_ymd(2016, 7, 8);
+ /// let hms = |h, m, s| d.and_hms_opt(h, m, s).unwrap();
+ /// assert_eq!(hms(3, 5, 7).checked_sub_signed(Duration::zero()),
+ /// Some(hms(3, 5, 7)));
+ /// assert_eq!(hms(3, 5, 7).checked_sub_signed(Duration::seconds(1)),
+ /// Some(hms(3, 5, 6)));
+ /// assert_eq!(hms(3, 5, 7).checked_sub_signed(Duration::seconds(-1)),
+ /// Some(hms(3, 5, 8)));
+ /// assert_eq!(hms(3, 5, 7).checked_sub_signed(Duration::seconds(3600 + 60)),
+ /// Some(hms(2, 4, 7)));
+ /// assert_eq!(hms(3, 5, 7).checked_sub_signed(Duration::seconds(86_400)),
+ /// Some(from_ymd(2016, 7, 7).and_hms_opt(3, 5, 7).unwrap()));
+ ///
+ /// let hmsm = |h, m, s, milli| d.and_hms_milli_opt(h, m, s, milli).unwrap();
+ /// assert_eq!(hmsm(3, 5, 7, 450).checked_sub_signed(Duration::milliseconds(670)),
+ /// Some(hmsm(3, 5, 6, 780)));
+ /// ```
+ ///
+ /// Overflow returns `None`.
+ ///
+ /// ```
+ /// # use chrono::{Duration, NaiveDate};
+ /// # let hms = |h, m, s| NaiveDate::from_ymd_opt(2016, 7, 8).unwrap().and_hms_opt(h, m, s).unwrap();
+ /// assert_eq!(hms(3, 5, 7).checked_sub_signed(Duration::days(1_000_000_000)), None);
+ /// ```
+ ///
+ /// Leap seconds are handled,
+ /// but the subtraction assumes that it is the only leap second happened.
+ ///
+ /// ```
+ /// # use chrono::{Duration, NaiveDate};
+ /// # let from_ymd = NaiveDate::from_ymd;
+ /// # 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()),
+ /// Some(hmsm(3, 5, 59, 1_300)));
+ /// assert_eq!(leap.checked_sub_signed(Duration::milliseconds(200)),
+ /// Some(hmsm(3, 5, 59, 1_100)));
+ /// assert_eq!(leap.checked_sub_signed(Duration::milliseconds(500)),
+ /// Some(hmsm(3, 5, 59, 800)));
+ /// assert_eq!(leap.checked_sub_signed(Duration::seconds(60)),
+ /// Some(hmsm(3, 5, 0, 300)));
+ /// assert_eq!(leap.checked_sub_signed(Duration::days(1)),
+ /// Some(from_ymd(2016, 7, 7).and_hms_milli_opt(3, 6, 0, 300).unwrap()));
+ /// ```
+ pub fn checked_sub_signed(self, rhs: OldDuration) -> Option<NaiveDateTime> {
+ let (time, rhs) = self.time.overflowing_sub_signed(rhs);
+
+ // early checking to avoid overflow in OldDuration::seconds
+ if rhs <= (-1 << MAX_SECS_BITS) || rhs >= (1 << MAX_SECS_BITS) {
+ return None;
+ }
+
+ let date = self.date.checked_sub_signed(OldDuration::seconds(rhs))?;
+ Some(NaiveDateTime { date, time })
+ }
+
+ /// Subtracts given `Months` from the current date and time.
+ ///
+ /// Returns `None` when it will result in overflow.
+ ///
+ /// Overflow returns `None`.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use std::str::FromStr;
+ /// use chrono::{Months, NaiveDate, NaiveDateTime};
+ ///
+ /// assert_eq!(
+ /// NaiveDate::from_ymd_opt(2014, 1, 1).unwrap().and_hms_opt(1, 0, 0).unwrap()
+ /// .checked_sub_months(Months::new(1)),
+ /// Some(NaiveDate::from_ymd_opt(2013, 12, 1).unwrap().and_hms_opt(1, 0, 0).unwrap())
+ /// );
+ ///
+ /// assert_eq!(
+ /// NaiveDate::from_ymd_opt(2014, 1, 1).unwrap().and_hms_opt(1, 0, 0).unwrap()
+ /// .checked_sub_months(Months::new(core::i32::MAX as u32 + 1)),
+ /// None
+ /// );
+ /// ```
+ pub fn checked_sub_months(self, rhs: Months) -> Option<NaiveDateTime> {
+ Some(Self { date: self.date.checked_sub_months(rhs)?, time: self.time })
+ }
+
+ /// Add a duration in [`Days`] to the date part of the `NaiveDateTime`
+ ///
+ /// Returns `None` if the resulting date would be out of range.
+ pub fn checked_add_days(self, days: Days) -> Option<Self> {
+ Some(Self { date: self.date.checked_add_days(days)?, ..self })
+ }
+
+ /// Subtract a duration in [`Days`] from the date part of the `NaiveDateTime`
+ ///
+ /// Returns `None` if the resulting date would be out of range.
+ pub fn checked_sub_days(self, days: Days) -> Option<Self> {
+ Some(Self { date: self.date.checked_sub_days(days)?, ..self })
+ }
+
+ /// Subtracts another `NaiveDateTime` from the current date and time.
+ /// This does not overflow or underflow at all.
+ ///
+ /// As a part of Chrono's [leap second handling](./struct.NaiveTime.html#leap-second-handling),
+ /// the subtraction assumes that **there is no leap second ever**,
+ /// except when any of the `NaiveDateTime`s themselves represents a leap second
+ /// in which case the assumption becomes that
+ /// **there are exactly one (or two) leap second(s) ever**.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use chrono::{Duration, NaiveDate};
+ ///
+ /// let from_ymd = NaiveDate::from_ymd;
+ ///
+ /// 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()),
+ /// Duration::seconds(3600 + 60 + 1));
+ ///
+ /// // July 8 is 190th day in the year 2016
+ /// let d0 = from_ymd(2016, 1, 1);
+ /// assert_eq!(d.and_hms_milli_opt(0, 7, 6, 500).unwrap().signed_duration_since(d0.and_hms_opt(0, 0, 0).unwrap()),
+ /// Duration::seconds(189 * 86_400 + 7 * 60 + 6) + Duration::milliseconds(500));
+ /// ```
+ ///
+ /// Leap seconds are handled, but the subtraction assumes that
+ /// there were no other leap seconds happened.
+ ///
+ /// ```
+ /// # use chrono::{Duration, NaiveDate};
+ /// # let from_ymd = NaiveDate::from_ymd;
+ /// 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));
+ /// ```
+ pub fn signed_duration_since(self, rhs: NaiveDateTime) -> OldDuration {
+ self.date.signed_duration_since(rhs.date) + self.time.signed_duration_since(rhs.time)
+ }
+
+ /// Formats the combined date and time with the specified formatting items.
+ /// Otherwise it is the same as the ordinary [`format`](#method.format) method.
+ ///
+ /// The `Iterator` of items should be `Clone`able,
+ /// since the resulting `DelayedFormat` value may be formatted multiple times.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use chrono::NaiveDate;
+ /// use chrono::format::strftime::StrftimeItems;
+ ///
+ /// let fmt = StrftimeItems::new("%Y-%m-%d %H:%M:%S");
+ /// let dt = NaiveDate::from_ymd_opt(2015, 9, 5).unwrap().and_hms_opt(23, 56, 4).unwrap();
+ /// assert_eq!(dt.format_with_items(fmt.clone()).to_string(), "2015-09-05 23:56:04");
+ /// assert_eq!(dt.format("%Y-%m-%d %H:%M:%S").to_string(), "2015-09-05 23:56:04");
+ /// ```
+ ///
+ /// The resulting `DelayedFormat` can be formatted directly via the `Display` trait.
+ ///
+ /// ```
+ /// # use chrono::NaiveDate;
+ /// # use chrono::format::strftime::StrftimeItems;
+ /// # let fmt = StrftimeItems::new("%Y-%m-%d %H:%M:%S").clone();
+ /// # let dt = NaiveDate::from_ymd_opt(2015, 9, 5).unwrap().and_hms_opt(23, 56, 4).unwrap();
+ /// assert_eq!(format!("{}", dt.format_with_items(fmt)), "2015-09-05 23:56:04");
+ /// ```
+ #[cfg(any(feature = "alloc", feature = "std", test))]
+ #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))]
+ #[inline]
+ pub fn format_with_items<'a, I, B>(&self, items: I) -> DelayedFormat<I>
+ where
+ I: Iterator<Item = B> + Clone,
+ B: Borrow<Item<'a>>,
+ {
+ DelayedFormat::new(Some(self.date), Some(self.time), items)
+ }
+
+ /// Formats the combined date and time with the specified format string.
+ /// See the [`format::strftime` module](../format/strftime/index.html)
+ /// on the supported escape sequences.
+ ///
+ /// This returns a `DelayedFormat`,
+ /// which gets converted to a string only when actual formatting happens.
+ /// You may use the `to_string` method to get a `String`,
+ /// or just feed it into `print!` and other formatting macros.
+ /// (In this way it avoids the redundant memory allocation.)
+ ///
+ /// A wrong format string does *not* issue an error immediately.
+ /// Rather, converting or formatting the `DelayedFormat` fails.
+ /// You are recommended to immediately use `DelayedFormat` for this reason.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use chrono::NaiveDate;
+ ///
+ /// let dt = NaiveDate::from_ymd_opt(2015, 9, 5).unwrap().and_hms_opt(23, 56, 4).unwrap();
+ /// assert_eq!(dt.format("%Y-%m-%d %H:%M:%S").to_string(), "2015-09-05 23:56:04");
+ /// assert_eq!(dt.format("around %l %p on %b %-d").to_string(), "around 11 PM on Sep 5");
+ /// ```
+ ///
+ /// The resulting `DelayedFormat` can be formatted directly via the `Display` trait.
+ ///
+ /// ```
+ /// # use chrono::NaiveDate;
+ /// # let dt = NaiveDate::from_ymd_opt(2015, 9, 5).unwrap().and_hms_opt(23, 56, 4).unwrap();
+ /// assert_eq!(format!("{}", dt.format("%Y-%m-%d %H:%M:%S")), "2015-09-05 23:56:04");
+ /// assert_eq!(format!("{}", dt.format("around %l %p on %b %-d")), "around 11 PM on Sep 5");
+ /// ```
+ #[cfg(any(feature = "alloc", feature = "std", test))]
+ #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))]
+ #[inline]
+ pub fn format<'a>(&self, fmt: &'a str) -> DelayedFormat<StrftimeItems<'a>> {
+ self.format_with_items(StrftimeItems::new(fmt))
+ }
+
+ /// Converts the `NaiveDateTime` into the timezone-aware `DateTime<Tz>`
+ /// with the provided timezone, if possible.
+ ///
+ /// This can fail in cases where the local time represented by the `NaiveDateTime`
+ /// is not a valid local timestamp in the target timezone due to an offset transition
+ /// for example if the target timezone had a change from +00:00 to +01:00
+ /// occuring at 2015-09-05 22:59:59, then a local time of 2015-09-05 23:56:04
+ /// could never occur. Similarly, if the offset transitioned in the opposite direction
+ /// then there would be two local times of 2015-09-05 23:56:04, one at +00:00 and one
+ /// at +01:00.
+ ///
+ /// # 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);
+ pub fn and_local_timezone<Tz: TimeZone>(&self, tz: Tz) -> LocalResult<DateTime<Tz>> {
+ tz.from_local_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).
+ ///
+ /// See also the [`NaiveDate::year`] method.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use chrono::{NaiveDate, NaiveDateTime, Datelike};
+ ///
+ /// let dt: NaiveDateTime = NaiveDate::from_ymd_opt(2015, 9, 25).unwrap().and_hms_opt(12, 34, 56).unwrap();
+ /// assert_eq!(dt.year(), 2015);
+ /// ```
+ #[inline]
+ fn year(&self) -> i32 {
+ self.date.year()
+ }
+
+ /// Returns the month number starting from 1.
+ ///
+ /// The return value ranges from 1 to 12.
+ ///
+ /// See also the [`NaiveDate::month`](./struct.NaiveDate.html#method.month) method.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use chrono::{NaiveDate, NaiveDateTime, Datelike};
+ ///
+ /// let dt: NaiveDateTime = NaiveDate::from_ymd_opt(2015, 9, 25).unwrap().and_hms_opt(12, 34, 56).unwrap();
+ /// assert_eq!(dt.month(), 9);
+ /// ```
+ #[inline]
+ fn month(&self) -> u32 {
+ self.date.month()
+ }
+
+ /// Returns the month number starting from 0.
+ ///
+ /// The return value ranges from 0 to 11.
+ ///
+ /// See also the [`NaiveDate::month0`](./struct.NaiveDate.html#method.month0) method.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use chrono::{NaiveDate, NaiveDateTime, Datelike};
+ ///
+ /// let dt: NaiveDateTime = NaiveDate::from_ymd_opt(2015, 9, 25).unwrap().and_hms_opt(12, 34, 56).unwrap();
+ /// assert_eq!(dt.month0(), 8);
+ /// ```
+ #[inline]
+ fn month0(&self) -> u32 {
+ self.date.month0()
+ }
+
+ /// Returns the day of month starting from 1.
+ ///
+ /// The return value ranges from 1 to 31. (The last day of month differs by months.)
+ ///
+ /// See also the [`NaiveDate::day`](./struct.NaiveDate.html#method.day) method.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use chrono::{NaiveDate, NaiveDateTime, Datelike};
+ ///
+ /// let dt: NaiveDateTime = NaiveDate::from_ymd_opt(2015, 9, 25).unwrap().and_hms_opt(12, 34, 56).unwrap();
+ /// assert_eq!(dt.day(), 25);
+ /// ```
+ #[inline]
+ fn day(&self) -> u32 {
+ self.date.day()
+ }
+
+ /// Returns the day of month starting from 0.
+ ///
+ /// The return value ranges from 0 to 30. (The last day of month differs by months.)
+ ///
+ /// See also the [`NaiveDate::day0`](./struct.NaiveDate.html#method.day0) method.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use chrono::{NaiveDate, NaiveDateTime, Datelike};
+ ///
+ /// let dt: NaiveDateTime = NaiveDate::from_ymd_opt(2015, 9, 25).unwrap().and_hms_opt(12, 34, 56).unwrap();
+ /// assert_eq!(dt.day0(), 24);
+ /// ```
+ #[inline]
+ fn day0(&self) -> u32 {
+ self.date.day0()
+ }
+
+ /// Returns the day of year starting from 1.
+ ///
+ /// The return value ranges from 1 to 366. (The last day of year differs by years.)
+ ///
+ /// See also the [`NaiveDate::ordinal`](./struct.NaiveDate.html#method.ordinal) method.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use chrono::{NaiveDate, NaiveDateTime, Datelike};
+ ///
+ /// let dt: NaiveDateTime = NaiveDate::from_ymd_opt(2015, 9, 25).unwrap().and_hms_opt(12, 34, 56).unwrap();
+ /// assert_eq!(dt.ordinal(), 268);
+ /// ```
+ #[inline]
+ fn ordinal(&self) -> u32 {
+ self.date.ordinal()
+ }
+
+ /// Returns the day of year starting from 0.
+ ///
+ /// The return value ranges from 0 to 365. (The last day of year differs by years.)
+ ///
+ /// See also the [`NaiveDate::ordinal0`](./struct.NaiveDate.html#method.ordinal0) method.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use chrono::{NaiveDate, NaiveDateTime, Datelike};
+ ///
+ /// let dt: NaiveDateTime = NaiveDate::from_ymd_opt(2015, 9, 25).unwrap().and_hms_opt(12, 34, 56).unwrap();
+ /// assert_eq!(dt.ordinal0(), 267);
+ /// ```
+ #[inline]
+ fn ordinal0(&self) -> u32 {
+ self.date.ordinal0()
+ }
+
+ /// Returns the day of week.
+ ///
+ /// See also the [`NaiveDate::weekday`](./struct.NaiveDate.html#method.weekday) method.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use chrono::{NaiveDate, NaiveDateTime, Datelike, Weekday};
+ ///
+ /// let dt: NaiveDateTime = NaiveDate::from_ymd_opt(2015, 9, 25).unwrap().and_hms_opt(12, 34, 56).unwrap();
+ /// assert_eq!(dt.weekday(), Weekday::Fri);
+ /// ```
+ #[inline]
+ fn weekday(&self) -> Weekday {
+ self.date.weekday()
+ }
+
+ #[inline]
+ fn iso_week(&self) -> IsoWeek {
+ self.date.iso_week()
+ }
+
+ /// Makes a new `NaiveDateTime` with the year number changed.
+ ///
+ /// Returns `None` when the resulting `NaiveDateTime` would be invalid.
+ ///
+ /// See also the [`NaiveDate::with_year`] method.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use chrono::{NaiveDate, NaiveDateTime, Datelike};
+ ///
+ /// let dt: NaiveDateTime = NaiveDate::from_ymd_opt(2015, 9, 25).unwrap().and_hms_opt(12, 34, 56).unwrap();
+ /// assert_eq!(dt.with_year(2016), Some(NaiveDate::from_ymd_opt(2016, 9, 25).unwrap().and_hms_opt(12, 34, 56).unwrap()));
+ /// assert_eq!(dt.with_year(-308), Some(NaiveDate::from_ymd_opt(-308, 9, 25).unwrap().and_hms_opt(12, 34, 56).unwrap()));
+ /// ```
+ #[inline]
+ fn with_year(&self, year: i32) -> Option<NaiveDateTime> {
+ self.date.with_year(year).map(|d| NaiveDateTime { date: d, ..*self })
+ }
+
+ /// Makes a new `NaiveDateTime` with the month number (starting from 1) changed.
+ ///
+ /// Returns `None` when the resulting `NaiveDateTime` would be invalid.
+ ///
+ /// See also the [`NaiveDate::with_month`] method.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use chrono::{NaiveDate, NaiveDateTime, Datelike};
+ ///
+ /// let dt: NaiveDateTime = NaiveDate::from_ymd_opt(2015, 9, 30).unwrap().and_hms_opt(12, 34, 56).unwrap();
+ /// assert_eq!(dt.with_month(10), Some(NaiveDate::from_ymd_opt(2015, 10, 30).unwrap().and_hms_opt(12, 34, 56).unwrap()));
+ /// assert_eq!(dt.with_month(13), None); // no month 13
+ /// assert_eq!(dt.with_month(2), None); // no February 30
+ /// ```
+ #[inline]
+ fn with_month(&self, month: u32) -> Option<NaiveDateTime> {
+ self.date.with_month(month).map(|d| NaiveDateTime { date: d, ..*self })
+ }
+
+ /// Makes a new `NaiveDateTime` with the month number (starting from 0) changed.
+ ///
+ /// Returns `None` when the resulting `NaiveDateTime` would be invalid.
+ ///
+ /// See also the [`NaiveDate::with_month0`] method.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use chrono::{NaiveDate, NaiveDateTime, Datelike};
+ ///
+ /// let dt: NaiveDateTime = NaiveDate::from_ymd_opt(2015, 9, 30).unwrap().and_hms_opt(12, 34, 56).unwrap();
+ /// assert_eq!(dt.with_month0(9), Some(NaiveDate::from_ymd_opt(2015, 10, 30).unwrap().and_hms_opt(12, 34, 56).unwrap()));
+ /// assert_eq!(dt.with_month0(12), None); // no month 13
+ /// assert_eq!(dt.with_month0(1), None); // no February 30
+ /// ```
+ #[inline]
+ fn with_month0(&self, month0: u32) -> Option<NaiveDateTime> {
+ self.date.with_month0(month0).map(|d| NaiveDateTime { date: d, ..*self })
+ }
+
+ /// Makes a new `NaiveDateTime` with the day of month (starting from 1) changed.
+ ///
+ /// Returns `None` when the resulting `NaiveDateTime` would be invalid.
+ ///
+ /// See also the [`NaiveDate::with_day`] method.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use chrono::{NaiveDate, NaiveDateTime, Datelike};
+ ///
+ /// let dt: NaiveDateTime = NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().and_hms_opt(12, 34, 56).unwrap();
+ /// assert_eq!(dt.with_day(30), Some(NaiveDate::from_ymd_opt(2015, 9, 30).unwrap().and_hms_opt(12, 34, 56).unwrap()));
+ /// assert_eq!(dt.with_day(31), None); // no September 31
+ /// ```
+ #[inline]
+ fn with_day(&self, day: u32) -> Option<NaiveDateTime> {
+ self.date.with_day(day).map(|d| NaiveDateTime { date: d, ..*self })
+ }
+
+ /// Makes a new `NaiveDateTime` with the day of month (starting from 0) changed.
+ ///
+ /// Returns `None` when the resulting `NaiveDateTime` would be invalid.
+ ///
+ /// See also the [`NaiveDate::with_day0`] method.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use chrono::{NaiveDate, NaiveDateTime, Datelike};
+ ///
+ /// let dt: NaiveDateTime = NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().and_hms_opt(12, 34, 56).unwrap();
+ /// assert_eq!(dt.with_day0(29), Some(NaiveDate::from_ymd_opt(2015, 9, 30).unwrap().and_hms_opt(12, 34, 56).unwrap()));
+ /// assert_eq!(dt.with_day0(30), None); // no September 31
+ /// ```
+ #[inline]
+ fn with_day0(&self, day0: u32) -> Option<NaiveDateTime> {
+ self.date.with_day0(day0).map(|d| NaiveDateTime { date: d, ..*self })
+ }
+
+ /// Makes a new `NaiveDateTime` with the day of year (starting from 1) changed.
+ ///
+ /// Returns `None` when the resulting `NaiveDateTime` would be invalid.
+ ///
+ /// See also the [`NaiveDate::with_ordinal`] method.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use chrono::{NaiveDate, NaiveDateTime, Datelike};
+ ///
+ /// let dt: NaiveDateTime = NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().and_hms_opt(12, 34, 56).unwrap();
+ /// assert_eq!(dt.with_ordinal(60),
+ /// Some(NaiveDate::from_ymd_opt(2015, 3, 1).unwrap().and_hms_opt(12, 34, 56).unwrap()));
+ /// assert_eq!(dt.with_ordinal(366), None); // 2015 had only 365 days
+ ///
+ /// let dt: NaiveDateTime = NaiveDate::from_ymd_opt(2016, 9, 8).unwrap().and_hms_opt(12, 34, 56).unwrap();
+ /// assert_eq!(dt.with_ordinal(60),
+ /// Some(NaiveDate::from_ymd_opt(2016, 2, 29).unwrap().and_hms_opt(12, 34, 56).unwrap()));
+ /// assert_eq!(dt.with_ordinal(366),
+ /// Some(NaiveDate::from_ymd_opt(2016, 12, 31).unwrap().and_hms_opt(12, 34, 56).unwrap()));
+ /// ```
+ #[inline]
+ fn with_ordinal(&self, ordinal: u32) -> Option<NaiveDateTime> {
+ self.date.with_ordinal(ordinal).map(|d| NaiveDateTime { date: d, ..*self })
+ }
+
+ /// Makes a new `NaiveDateTime` with the day of year (starting from 0) changed.
+ ///
+ /// Returns `None` when the resulting `NaiveDateTime` would be invalid.
+ ///
+ /// See also the [`NaiveDate::with_ordinal0`] method.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use chrono::{NaiveDate, NaiveDateTime, Datelike};
+ ///
+ /// let dt: NaiveDateTime = NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().and_hms_opt(12, 34, 56).unwrap();
+ /// assert_eq!(dt.with_ordinal0(59),
+ /// Some(NaiveDate::from_ymd_opt(2015, 3, 1).unwrap().and_hms_opt(12, 34, 56).unwrap()));
+ /// assert_eq!(dt.with_ordinal0(365), None); // 2015 had only 365 days
+ ///
+ /// let dt: NaiveDateTime = NaiveDate::from_ymd_opt(2016, 9, 8).unwrap().and_hms_opt(12, 34, 56).unwrap();
+ /// assert_eq!(dt.with_ordinal0(59),
+ /// Some(NaiveDate::from_ymd_opt(2016, 2, 29).unwrap().and_hms_opt(12, 34, 56).unwrap()));
+ /// assert_eq!(dt.with_ordinal0(365),
+ /// Some(NaiveDate::from_ymd_opt(2016, 12, 31).unwrap().and_hms_opt(12, 34, 56).unwrap()));
+ /// ```
+ #[inline]
+ fn with_ordinal0(&self, ordinal0: u32) -> Option<NaiveDateTime> {
+ self.date.with_ordinal0(ordinal0).map(|d| NaiveDateTime { date: d, ..*self })
+ }
+}
+
+impl Timelike for NaiveDateTime {
+ /// Returns the hour number from 0 to 23.
+ ///
+ /// See also the [`NaiveTime::hour`] method.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use chrono::{NaiveDate, NaiveDateTime, Timelike};
+ ///
+ /// let dt: NaiveDateTime = NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().and_hms_milli_opt(12, 34, 56, 789).unwrap();
+ /// assert_eq!(dt.hour(), 12);
+ /// ```
+ #[inline]
+ fn hour(&self) -> u32 {
+ self.time.hour()
+ }
+
+ /// Returns the minute number from 0 to 59.
+ ///
+ /// See also the [`NaiveTime::minute`] method.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use chrono::{NaiveDate, NaiveDateTime, Timelike};
+ ///
+ /// let dt: NaiveDateTime = NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().and_hms_milli_opt(12, 34, 56, 789).unwrap();
+ /// assert_eq!(dt.minute(), 34);
+ /// ```
+ #[inline]
+ fn minute(&self) -> u32 {
+ self.time.minute()
+ }
+
+ /// Returns the second number from 0 to 59.
+ ///
+ /// See also the [`NaiveTime::second`] method.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use chrono::{NaiveDate, NaiveDateTime, Timelike};
+ ///
+ /// let dt: NaiveDateTime = NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().and_hms_milli_opt(12, 34, 56, 789).unwrap();
+ /// assert_eq!(dt.second(), 56);
+ /// ```
+ #[inline]
+ fn second(&self) -> u32 {
+ self.time.second()
+ }
+
+ /// Returns the number of nanoseconds since the whole non-leap second.
+ /// The range from 1,000,000,000 to 1,999,999,999 represents
+ /// the [leap second](./struct.NaiveTime.html#leap-second-handling).
+ ///
+ /// See also the [`NaiveTime::nanosecond`] method.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use chrono::{NaiveDate, NaiveDateTime, Timelike};
+ ///
+ /// let dt: NaiveDateTime = NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().and_hms_milli_opt(12, 34, 56, 789).unwrap();
+ /// assert_eq!(dt.nanosecond(), 789_000_000);
+ /// ```
+ #[inline]
+ fn nanosecond(&self) -> u32 {
+ self.time.nanosecond()
+ }
+
+ /// Makes a new `NaiveDateTime` with the hour number changed.
+ ///
+ /// Returns `None` when the resulting `NaiveDateTime` would be invalid.
+ ///
+ /// See also the [`NaiveTime::with_hour`] method.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use chrono::{NaiveDate, NaiveDateTime, Timelike};
+ ///
+ /// let dt: NaiveDateTime = NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().and_hms_milli_opt(12, 34, 56, 789).unwrap();
+ /// assert_eq!(dt.with_hour(7),
+ /// Some(NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().and_hms_milli_opt(7, 34, 56, 789).unwrap()));
+ /// assert_eq!(dt.with_hour(24), None);
+ /// ```
+ #[inline]
+ fn with_hour(&self, hour: u32) -> Option<NaiveDateTime> {
+ self.time.with_hour(hour).map(|t| NaiveDateTime { time: t, ..*self })
+ }
+
+ /// Makes a new `NaiveDateTime` with the minute number changed.
+ ///
+ /// Returns `None` when the resulting `NaiveDateTime` would be invalid.
+ ///
+ /// See also the
+ /// [`NaiveTime::with_minute`] method.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use chrono::{NaiveDate, NaiveDateTime, Timelike};
+ ///
+ /// let dt: NaiveDateTime = NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().and_hms_milli_opt(12, 34, 56, 789).unwrap();
+ /// assert_eq!(dt.with_minute(45),
+ /// Some(NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().and_hms_milli_opt(12, 45, 56, 789).unwrap()));
+ /// assert_eq!(dt.with_minute(60), None);
+ /// ```
+ #[inline]
+ fn with_minute(&self, min: u32) -> Option<NaiveDateTime> {
+ self.time.with_minute(min).map(|t| NaiveDateTime { time: t, ..*self })
+ }
+
+ /// Makes a new `NaiveDateTime` with the second number changed.
+ ///
+ /// Returns `None` when the resulting `NaiveDateTime` would be invalid. As
+ /// with the [`NaiveDateTime::second`] method, the input range is
+ /// restricted to 0 through 59.
+ ///
+ /// See also the [`NaiveTime::with_second`] method.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use chrono::{NaiveDate, NaiveDateTime, Timelike};
+ ///
+ /// let dt: NaiveDateTime = NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().and_hms_milli_opt(12, 34, 56, 789).unwrap();
+ /// assert_eq!(dt.with_second(17),
+ /// Some(NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().and_hms_milli_opt(12, 34, 17, 789).unwrap()));
+ /// assert_eq!(dt.with_second(60), None);
+ /// ```
+ #[inline]
+ fn with_second(&self, sec: u32) -> Option<NaiveDateTime> {
+ self.time.with_second(sec).map(|t| NaiveDateTime { time: t, ..*self })
+ }
+
+ /// Makes a new `NaiveDateTime` with nanoseconds since the whole non-leap second changed.
+ ///
+ /// Returns `None` when the resulting `NaiveDateTime` would be invalid.
+ /// As with the [`NaiveDateTime::nanosecond`] method,
+ /// the input range can exceed 1,000,000,000 for leap seconds.
+ ///
+ /// See also the [`NaiveTime::with_nanosecond`] method.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use chrono::{NaiveDate, NaiveDateTime, Timelike};
+ ///
+ /// let dt: NaiveDateTime = NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().and_hms_milli_opt(12, 34, 56, 789).unwrap();
+ /// assert_eq!(dt.with_nanosecond(333_333_333),
+ /// Some(NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().and_hms_nano_opt(12, 34, 56, 333_333_333).unwrap()));
+ /// assert_eq!(dt.with_nanosecond(1_333_333_333), // leap second
+ /// Some(NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().and_hms_nano_opt(12, 34, 56, 1_333_333_333).unwrap()));
+ /// assert_eq!(dt.with_nanosecond(2_000_000_000), None);
+ /// ```
+ #[inline]
+ fn with_nanosecond(&self, nano: u32) -> Option<NaiveDateTime> {
+ self.time.with_nanosecond(nano).map(|t| NaiveDateTime { time: t, ..*self })
+ }
+}
+
+/// 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**.
+///
+/// Panics on underflow or overflow. Use [`NaiveDateTime::checked_add_signed`]
+/// to detect that.
+///
+/// # Example
+///
+/// ```
+/// use chrono::{Duration, NaiveDate};
+///
+/// let from_ymd = NaiveDate::from_ymd;
+///
+/// let d = from_ymd(2016, 7, 8);
+/// let hms = |h, m, s| d.and_hms_opt(h, m, s).unwrap();
+/// assert_eq!(hms(3, 5, 7) + Duration::zero(), hms(3, 5, 7));
+/// assert_eq!(hms(3, 5, 7) + Duration::seconds(1), hms(3, 5, 8));
+/// assert_eq!(hms(3, 5, 7) + Duration::seconds(-1), hms(3, 5, 6));
+/// assert_eq!(hms(3, 5, 7) + Duration::seconds(3600 + 60), hms(4, 6, 7));
+/// assert_eq!(hms(3, 5, 7) + Duration::seconds(86_400),
+/// from_ymd(2016, 7, 9).and_hms_opt(3, 5, 7).unwrap());
+/// assert_eq!(hms(3, 5, 7) + Duration::days(365),
+/// from_ymd(2017, 7, 8).and_hms_opt(3, 5, 7).unwrap());
+///
+/// let hmsm = |h, m, s, milli| d.and_hms_milli_opt(h, m, s, milli).unwrap();
+/// assert_eq!(hmsm(3, 5, 7, 980) + Duration::milliseconds(450), hmsm(3, 5, 8, 430));
+/// ```
+///
+/// Leap seconds are handled,
+/// but the addition assumes that it is the only leap second happened.
+///
+/// ```
+/// # use chrono::{Duration, NaiveDate};
+/// # let from_ymd = NaiveDate::from_ymd;
+/// # 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));
+/// assert_eq!(leap + Duration::milliseconds(-500), hmsm(3, 5, 59, 800));
+/// assert_eq!(leap + Duration::milliseconds(500), hmsm(3, 5, 59, 1_800));
+/// assert_eq!(leap + Duration::milliseconds(800), hmsm(3, 6, 0, 100));
+/// assert_eq!(leap + Duration::seconds(10), hmsm(3, 6, 9, 300));
+/// assert_eq!(leap + Duration::seconds(-10), hmsm(3, 5, 50, 300));
+/// assert_eq!(leap + Duration::days(1),
+/// from_ymd(2016, 7, 9).and_hms_milli_opt(3, 5, 59, 300).unwrap());
+/// ```
+impl Add<OldDuration> for NaiveDateTime {
+ type Output = NaiveDateTime;
+
+ #[inline]
+ fn add(self, rhs: OldDuration) -> NaiveDateTime {
+ self.checked_add_signed(rhs).expect("`NaiveDateTime + Duration` overflowed")
+ }
+}
+
+impl AddAssign<OldDuration> for NaiveDateTime {
+ #[inline]
+ fn add_assign(&mut self, rhs: OldDuration) {
+ *self = self.add(rhs);
+ }
+}
+
+impl Add<Months> for NaiveDateTime {
+ type Output = NaiveDateTime;
+
+ /// An addition of months to `NaiveDateTime` clamped to valid days in resulting month.
+ ///
+ /// # Panics
+ ///
+ /// Panics if the resulting date would be out of range.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use chrono::{Duration, NaiveDateTime, Months, NaiveDate};
+ /// use std::str::FromStr;
+ ///
+ /// assert_eq!(
+ /// NaiveDate::from_ymd_opt(2014, 1, 1).unwrap().and_hms_opt(1, 0, 0).unwrap() + Months::new(1),
+ /// NaiveDate::from_ymd_opt(2014, 2, 1).unwrap().and_hms_opt(1, 0, 0).unwrap()
+ /// );
+ /// assert_eq!(
+ /// NaiveDate::from_ymd_opt(2014, 1, 1).unwrap().and_hms_opt(0, 2, 0).unwrap() + Months::new(11),
+ /// NaiveDate::from_ymd_opt(2014, 12, 1).unwrap().and_hms_opt(0, 2, 0).unwrap()
+ /// );
+ /// assert_eq!(
+ /// NaiveDate::from_ymd_opt(2014, 1, 1).unwrap().and_hms_opt(0, 0, 3).unwrap() + Months::new(12),
+ /// NaiveDate::from_ymd_opt(2015, 1, 1).unwrap().and_hms_opt(0, 0, 3).unwrap()
+ /// );
+ /// assert_eq!(
+ /// NaiveDate::from_ymd_opt(2014, 1, 1).unwrap().and_hms_opt(0, 0, 4).unwrap() + Months::new(13),
+ /// NaiveDate::from_ymd_opt(2015, 2, 1).unwrap().and_hms_opt(0, 0, 4).unwrap()
+ /// );
+ /// assert_eq!(
+ /// NaiveDate::from_ymd_opt(2014, 1, 31).unwrap().and_hms_opt(0, 5, 0).unwrap() + Months::new(1),
+ /// NaiveDate::from_ymd_opt(2014, 2, 28).unwrap().and_hms_opt(0, 5, 0).unwrap()
+ /// );
+ /// assert_eq!(
+ /// NaiveDate::from_ymd_opt(2020, 1, 31).unwrap().and_hms_opt(6, 0, 0).unwrap() + Months::new(1),
+ /// NaiveDate::from_ymd_opt(2020, 2, 29).unwrap().and_hms_opt(6, 0, 0).unwrap()
+ /// );
+ /// ```
+ fn add(self, rhs: Months) -> Self::Output {
+ Self { date: self.date.checked_add_months(rhs).unwrap(), time: self.time }
+ }
+}
+
+/// 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**.
+///
+/// Panics on underflow or overflow. Use [`NaiveDateTime::checked_sub_signed`]
+/// to detect that.
+///
+/// # Example
+///
+/// ```
+/// use chrono::{Duration, NaiveDate};
+///
+/// let from_ymd = NaiveDate::from_ymd;
+///
+/// let d = from_ymd(2016, 7, 8);
+/// let hms = |h, m, s| d.and_hms_opt(h, m, s).unwrap();
+/// assert_eq!(hms(3, 5, 7) - Duration::zero(), hms(3, 5, 7));
+/// assert_eq!(hms(3, 5, 7) - Duration::seconds(1), hms(3, 5, 6));
+/// assert_eq!(hms(3, 5, 7) - Duration::seconds(-1), hms(3, 5, 8));
+/// assert_eq!(hms(3, 5, 7) - Duration::seconds(3600 + 60), hms(2, 4, 7));
+/// assert_eq!(hms(3, 5, 7) - Duration::seconds(86_400),
+/// from_ymd(2016, 7, 7).and_hms_opt(3, 5, 7).unwrap());
+/// assert_eq!(hms(3, 5, 7) - Duration::days(365),
+/// from_ymd(2015, 7, 9).and_hms_opt(3, 5, 7).unwrap());
+///
+/// let hmsm = |h, m, s, milli| d.and_hms_milli_opt(h, m, s, milli).unwrap();
+/// assert_eq!(hmsm(3, 5, 7, 450) - Duration::milliseconds(670), hmsm(3, 5, 6, 780));
+/// ```
+///
+/// Leap seconds are handled,
+/// but the subtraction assumes that it is the only leap second happened.
+///
+/// ```
+/// # use chrono::{Duration, NaiveDate};
+/// # let from_ymd = NaiveDate::from_ymd;
+/// # 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));
+/// assert_eq!(leap - Duration::milliseconds(200), hmsm(3, 5, 59, 1_100));
+/// assert_eq!(leap - Duration::milliseconds(500), hmsm(3, 5, 59, 800));
+/// assert_eq!(leap - Duration::seconds(60), hmsm(3, 5, 0, 300));
+/// assert_eq!(leap - Duration::days(1),
+/// from_ymd(2016, 7, 7).and_hms_milli_opt(3, 6, 0, 300).unwrap());
+/// ```
+impl Sub<OldDuration> for NaiveDateTime {
+ type Output = NaiveDateTime;
+
+ #[inline]
+ fn sub(self, rhs: OldDuration) -> NaiveDateTime {
+ self.checked_sub_signed(rhs).expect("`NaiveDateTime - Duration` overflowed")
+ }
+}
+
+impl SubAssign<OldDuration> for NaiveDateTime {
+ #[inline]
+ fn sub_assign(&mut self, rhs: OldDuration) {
+ *self = self.sub(rhs);
+ }
+}
+
+/// A subtraction of Months from `NaiveDateTime` clamped to valid days in resulting month.
+///
+/// # Panics
+///
+/// Panics if the resulting date would be out of range.
+///
+/// # Example
+///
+/// ```
+/// use chrono::{Duration, NaiveDateTime, Months, NaiveDate};
+/// use std::str::FromStr;
+///
+/// assert_eq!(
+/// NaiveDate::from_ymd_opt(2014, 01, 01).unwrap().and_hms_opt(01, 00, 00).unwrap() - Months::new(11),
+/// NaiveDate::from_ymd_opt(2013, 02, 01).unwrap().and_hms_opt(01, 00, 00).unwrap()
+/// );
+/// assert_eq!(
+/// NaiveDate::from_ymd_opt(2014, 01, 01).unwrap().and_hms_opt(00, 02, 00).unwrap() - Months::new(12),
+/// NaiveDate::from_ymd_opt(2013, 01, 01).unwrap().and_hms_opt(00, 02, 00).unwrap()
+/// );
+/// assert_eq!(
+/// NaiveDate::from_ymd_opt(2014, 01, 01).unwrap().and_hms_opt(00, 00, 03).unwrap() - Months::new(13),
+/// NaiveDate::from_ymd_opt(2012, 12, 01).unwrap().and_hms_opt(00, 00, 03).unwrap()
+/// );
+/// ```
+impl Sub<Months> for NaiveDateTime {
+ type Output = NaiveDateTime;
+
+ fn sub(self, rhs: Months) -> Self::Output {
+ Self { date: self.date.checked_sub_months(rhs).unwrap(), time: self.time }
+ }
+}
+
+/// Subtracts another `NaiveDateTime` from the current date and time.
+/// This does not overflow or underflow at all.
+///
+/// As a part of Chrono's [leap second handling](./struct.NaiveTime.html#leap-second-handling),
+/// the subtraction assumes that **there is no leap second ever**,
+/// except when any of the `NaiveDateTime`s themselves represents a leap second
+/// in which case the assumption becomes that
+/// **there are exactly one (or two) leap second(s) ever**.
+///
+/// The implementation is a wrapper around [`NaiveDateTime::signed_duration_since`].
+///
+/// # Example
+///
+/// ```
+/// use chrono::{Duration, NaiveDate};
+///
+/// let from_ymd = NaiveDate::from_ymd;
+///
+/// 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));
+///
+/// // July 8 is 190th day in the year 2016
+/// let d0 = from_ymd(2016, 1, 1);
+/// assert_eq!(d.and_hms_milli_opt(0, 7, 6, 500).unwrap() - d0.and_hms_opt(0, 0, 0).unwrap(),
+/// Duration::seconds(189 * 86_400 + 7 * 60 + 6) + Duration::milliseconds(500));
+/// ```
+///
+/// Leap seconds are handled, but the subtraction assumes that no other leap
+/// seconds happened.
+///
+/// ```
+/// # use chrono::{Duration, NaiveDate};
+/// # let from_ymd = NaiveDate::from_ymd;
+/// 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));
+/// assert_eq!(from_ymd(2015, 7, 1).and_hms_opt(1, 0, 0).unwrap() - leap,
+/// Duration::seconds(3600) - Duration::milliseconds(500));
+/// ```
+impl Sub<NaiveDateTime> for NaiveDateTime {
+ type Output = OldDuration;
+
+ #[inline]
+ fn sub(self, rhs: NaiveDateTime) -> OldDuration {
+ self.signed_duration_since(rhs)
+ }
+}
+
+impl Add<Days> for NaiveDateTime {
+ type Output = NaiveDateTime;
+
+ fn add(self, days: Days) -> Self::Output {
+ self.checked_add_days(days).unwrap()
+ }
+}
+
+impl Sub<Days> for NaiveDateTime {
+ type Output = NaiveDateTime;
+
+ fn sub(self, days: Days) -> Self::Output {
+ self.checked_sub_days(days).unwrap()
+ }
+}
+
+/// The `Debug` output of the naive date and time `dt` is the same as
+/// [`dt.format("%Y-%m-%dT%H:%M:%S%.f")`](crate::format::strftime).
+///
+/// The string printed can be readily parsed via the `parse` method on `str`.
+///
+/// It should be noted that, for leap seconds not on the minute boundary,
+/// it may print a representation not distinguishable from non-leap seconds.
+/// This doesn't matter in practice, since such leap seconds never happened.
+/// (By the time of the first leap second on 1972-06-30,
+/// every time zone offset around the world has standardized to the 5-minute alignment.)
+///
+/// # Example
+///
+/// ```
+/// use chrono::NaiveDate;
+///
+/// let dt = NaiveDate::from_ymd_opt(2016, 11, 15).unwrap().and_hms_opt(7, 39, 24).unwrap();
+/// assert_eq!(format!("{:?}", dt), "2016-11-15T07:39:24");
+/// ```
+///
+/// Leap seconds may also be used.
+///
+/// ```
+/// # use chrono::NaiveDate;
+/// let dt = NaiveDate::from_ymd_opt(2015, 6, 30).unwrap().and_hms_milli_opt(23, 59, 59, 1_500).unwrap();
+/// assert_eq!(format!("{:?}", dt), "2015-06-30T23:59:60.500");
+/// ```
+impl fmt::Debug for NaiveDateTime {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ self.date.fmt(f)?;
+ f.write_char('T')?;
+ self.time.fmt(f)
+ }
+}
+
+/// The `Display` output of the naive date and time `dt` is the same as
+/// [`dt.format("%Y-%m-%d %H:%M:%S%.f")`](crate::format::strftime).
+///
+/// It should be noted that, for leap seconds not on the minute boundary,
+/// it may print a representation not distinguishable from non-leap seconds.
+/// This doesn't matter in practice, since such leap seconds never happened.
+/// (By the time of the first leap second on 1972-06-30,
+/// every time zone offset around the world has standardized to the 5-minute alignment.)
+///
+/// # Example
+///
+/// ```
+/// use chrono::NaiveDate;
+///
+/// let dt = NaiveDate::from_ymd_opt(2016, 11, 15).unwrap().and_hms_opt(7, 39, 24).unwrap();
+/// assert_eq!(format!("{}", dt), "2016-11-15 07:39:24");
+/// ```
+///
+/// Leap seconds may also be used.
+///
+/// ```
+/// # use chrono::NaiveDate;
+/// let dt = NaiveDate::from_ymd_opt(2015, 6, 30).unwrap().and_hms_milli_opt(23, 59, 59, 1_500).unwrap();
+/// assert_eq!(format!("{}", dt), "2015-06-30 23:59:60.500");
+/// ```
+impl fmt::Display for NaiveDateTime {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ self.date.fmt(f)?;
+ f.write_char(' ')?;
+ self.time.fmt(f)
+ }
+}
+
+/// Parsing a `str` into a `NaiveDateTime` uses the same format,
+/// [`%Y-%m-%dT%H:%M:%S%.f`](crate::format::strftime), as in `Debug`.
+///
+/// # Example
+///
+/// ```
+/// use chrono::{NaiveDateTime, NaiveDate};
+///
+/// let dt = NaiveDate::from_ymd_opt(2015, 9, 18).unwrap().and_hms_opt(23, 56, 4).unwrap();
+/// assert_eq!("2015-09-18T23:56:04".parse::<NaiveDateTime>(), Ok(dt));
+///
+/// let dt = NaiveDate::from_ymd_opt(12345, 6, 7).unwrap().and_hms_milli_opt(7, 59, 59, 1_500).unwrap(); // leap second
+/// assert_eq!("+12345-6-7T7:59:60.5".parse::<NaiveDateTime>(), Ok(dt));
+///
+/// assert!("foo".parse::<NaiveDateTime>().is_err());
+/// ```
+impl str::FromStr for NaiveDateTime {
+ type Err = ParseError;
+
+ fn from_str(s: &str) -> ParseResult<NaiveDateTime> {
+ const ITEMS: &[Item<'static>] = &[
+ Item::Numeric(Numeric::Year, Pad::Zero),
+ Item::Space(""),
+ Item::Literal("-"),
+ Item::Numeric(Numeric::Month, Pad::Zero),
+ Item::Space(""),
+ Item::Literal("-"),
+ Item::Numeric(Numeric::Day, Pad::Zero),
+ Item::Space(""),
+ Item::Literal("T"), // XXX shouldn't this be case-insensitive?
+ Item::Numeric(Numeric::Hour, Pad::Zero),
+ Item::Space(""),
+ Item::Literal(":"),
+ Item::Numeric(Numeric::Minute, Pad::Zero),
+ Item::Space(""),
+ Item::Literal(":"),
+ Item::Numeric(Numeric::Second, Pad::Zero),
+ Item::Fixed(Fixed::Nanosecond),
+ Item::Space(""),
+ ];
+
+ let mut parsed = Parsed::new();
+ parse(&mut parsed, s, ITEMS.iter())?;
+ parsed.to_naive_datetime_with_offset(0)
+ }
+}
+
+/// The default value for a NaiveDateTime is one with epoch 0
+/// that is, 1st of January 1970 at 00:00:00.
+///
+/// # Example
+///
+/// ```rust
+/// use chrono::NaiveDateTime;
+///
+/// let default_date = NaiveDateTime::default();
+/// assert_eq!(default_date, NaiveDateTime::from_timestamp(0, 0));
+/// ```
+impl Default for NaiveDateTime {
+ fn default() -> Self {
+ NaiveDateTime::from_timestamp_opt(0, 0).unwrap()
+ }
+}
+
+#[cfg(all(test, any(feature = "rustc-serialize", feature = "serde")))]
+fn test_encodable_json<F, E>(to_string: F)
+where
+ F: Fn(&NaiveDateTime) -> Result<String, E>,
+ E: ::std::fmt::Debug,
+{
+ assert_eq!(
+ to_string(
+ &NaiveDate::from_ymd_opt(2016, 7, 8).unwrap().and_hms_milli_opt(9, 10, 48, 90).unwrap()
+ )
+ .ok(),
+ Some(r#""2016-07-08T09:10:48.090""#.into())
+ );
+ assert_eq!(
+ to_string(&NaiveDate::from_ymd_opt(2014, 7, 24).unwrap().and_hms_opt(12, 34, 6).unwrap())
+ .ok(),
+ Some(r#""2014-07-24T12:34:06""#.into())
+ );
+ assert_eq!(
+ to_string(
+ &NaiveDate::from_ymd_opt(0, 1, 1).unwrap().and_hms_milli_opt(0, 0, 59, 1_000).unwrap()
+ )
+ .ok(),
+ Some(r#""0000-01-01T00:00:60""#.into())
+ );
+ assert_eq!(
+ to_string(
+ &NaiveDate::from_ymd_opt(-1, 12, 31).unwrap().and_hms_nano_opt(23, 59, 59, 7).unwrap()
+ )
+ .ok(),
+ Some(r#""-0001-12-31T23:59:59.000000007""#.into())
+ );
+ assert_eq!(
+ to_string(&NaiveDate::MIN.and_hms_opt(0, 0, 0).unwrap()).ok(),
+ Some(r#""-262144-01-01T00:00:00""#.into())
+ );
+ assert_eq!(
+ to_string(&NaiveDate::MAX.and_hms_nano_opt(23, 59, 59, 1_999_999_999).unwrap()).ok(),
+ Some(r#""+262143-12-31T23:59:60.999999999""#.into())
+ );
+}
+
+#[cfg(all(test, any(feature = "rustc-serialize", feature = "serde")))]
+fn test_decodable_json<F, E>(from_str: F)
+where
+ F: Fn(&str) -> Result<NaiveDateTime, E>,
+ E: ::std::fmt::Debug,
+{
+ assert_eq!(
+ from_str(r#""2016-07-08T09:10:48.090""#).ok(),
+ Some(
+ NaiveDate::from_ymd_opt(2016, 7, 8).unwrap().and_hms_milli_opt(9, 10, 48, 90).unwrap()
+ )
+ );
+ assert_eq!(
+ from_str(r#""2016-7-8T9:10:48.09""#).ok(),
+ Some(
+ NaiveDate::from_ymd_opt(2016, 7, 8).unwrap().and_hms_milli_opt(9, 10, 48, 90).unwrap()
+ )
+ );
+ assert_eq!(
+ from_str(r#""2014-07-24T12:34:06""#).ok(),
+ Some(NaiveDate::from_ymd_opt(2014, 7, 24).unwrap().and_hms_opt(12, 34, 6).unwrap())
+ );
+ assert_eq!(
+ from_str(r#""0000-01-01T00:00:60""#).ok(),
+ Some(NaiveDate::from_ymd_opt(0, 1, 1).unwrap().and_hms_milli_opt(0, 0, 59, 1_000).unwrap())
+ );
+ assert_eq!(
+ from_str(r#""0-1-1T0:0:60""#).ok(),
+ Some(NaiveDate::from_ymd_opt(0, 1, 1).unwrap().and_hms_milli_opt(0, 0, 59, 1_000).unwrap())
+ );
+ assert_eq!(
+ from_str(r#""-0001-12-31T23:59:59.000000007""#).ok(),
+ Some(NaiveDate::from_ymd_opt(-1, 12, 31).unwrap().and_hms_nano_opt(23, 59, 59, 7).unwrap())
+ );
+ assert_eq!(
+ from_str(r#""-262144-01-01T00:00:00""#).ok(),
+ Some(NaiveDate::MIN.and_hms_opt(0, 0, 0).unwrap())
+ );
+ assert_eq!(
+ from_str(r#""+262143-12-31T23:59:60.999999999""#).ok(),
+ Some(NaiveDate::MAX.and_hms_nano_opt(23, 59, 59, 1_999_999_999).unwrap())
+ );
+ assert_eq!(
+ from_str(r#""+262143-12-31T23:59:60.9999999999997""#).ok(), // excess digits are ignored
+ Some(NaiveDate::MAX.and_hms_nano_opt(23, 59, 59, 1_999_999_999).unwrap())
+ );
+
+ // bad formats
+ assert!(from_str(r#""""#).is_err());
+ assert!(from_str(r#""2016-07-08""#).is_err());
+ assert!(from_str(r#""09:10:48.090""#).is_err());
+ assert!(from_str(r#""20160708T091048.090""#).is_err());
+ assert!(from_str(r#""2000-00-00T00:00:00""#).is_err());
+ assert!(from_str(r#""2000-02-30T00:00:00""#).is_err());
+ assert!(from_str(r#""2001-02-29T00:00:00""#).is_err());
+ assert!(from_str(r#""2002-02-28T24:00:00""#).is_err());
+ assert!(from_str(r#""2002-02-28T23:60:00""#).is_err());
+ assert!(from_str(r#""2002-02-28T23:59:61""#).is_err());
+ assert!(from_str(r#""2016-07-08T09:10:48,090""#).is_err());
+ assert!(from_str(r#""2016-07-08 09:10:48.090""#).is_err());
+ assert!(from_str(r#""2016-007-08T09:10:48.090""#).is_err());
+ assert!(from_str(r#""yyyy-mm-ddThh:mm:ss.fffffffff""#).is_err());
+ assert!(from_str(r#"20160708000000"#).is_err());
+ assert!(from_str(r#"{}"#).is_err());
+ // pre-0.3.0 rustc-serialize format is now invalid
+ assert!(from_str(r#"{"date":{"ymdf":20},"time":{"secs":0,"frac":0}}"#).is_err());
+ assert!(from_str(r#"null"#).is_err());
+}
+
+#[cfg(all(test, feature = "rustc-serialize"))]
+fn test_decodable_json_timestamp<F, E>(from_str: F)
+where
+ F: Fn(&str) -> Result<rustc_serialize::TsSeconds, E>,
+ E: ::std::fmt::Debug,
+{
+ assert_eq!(
+ *from_str("0").unwrap(),
+ NaiveDate::from_ymd_opt(1970, 1, 1).unwrap().and_hms_opt(0, 0, 0).unwrap(),
+ "should parse integers as timestamps"
+ );
+ assert_eq!(
+ *from_str("-1").unwrap(),
+ NaiveDate::from_ymd_opt(1969, 12, 31).unwrap().and_hms_opt(23, 59, 59).unwrap(),
+ "should parse integers as timestamps"
+ );
+}
diff --git a/vendor/chrono/src/naive/datetime/rustc_serialize.rs b/vendor/chrono/src/naive/datetime/rustc_serialize.rs
new file mode 100644
index 000000000..6e33829e0
--- /dev/null
+++ b/vendor/chrono/src/naive/datetime/rustc_serialize.rs
@@ -0,0 +1,73 @@
+#![cfg_attr(docsrs, doc(cfg(feature = "rustc-serialize")))]
+
+use super::NaiveDateTime;
+use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
+use std::ops::Deref;
+
+impl Encodable for NaiveDateTime {
+ fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
+ format!("{:?}", self).encode(s)
+ }
+}
+
+impl Decodable for NaiveDateTime {
+ fn decode<D: Decoder>(d: &mut D) -> Result<NaiveDateTime, D::Error> {
+ d.read_str()?.parse().map_err(|_| d.error("invalid date time string"))
+ }
+}
+
+/// A `DateTime` that can be deserialized from a seconds-based timestamp
+#[derive(Debug)]
+#[deprecated(
+ since = "1.4.2",
+ note = "RustcSerialize will be removed before chrono 1.0, use Serde instead"
+)]
+pub struct TsSeconds(NaiveDateTime);
+
+#[allow(deprecated)]
+impl From<TsSeconds> for NaiveDateTime {
+ /// Pull the internal NaiveDateTime out
+ #[allow(deprecated)]
+ fn from(obj: TsSeconds) -> NaiveDateTime {
+ obj.0
+ }
+}
+
+#[allow(deprecated)]
+impl Deref for TsSeconds {
+ type Target = NaiveDateTime;
+
+ #[allow(deprecated)]
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+}
+
+#[allow(deprecated)]
+impl Decodable for TsSeconds {
+ #[allow(deprecated)]
+ fn decode<D: Decoder>(d: &mut D) -> Result<TsSeconds, D::Error> {
+ Ok(TsSeconds(
+ NaiveDateTime::from_timestamp_opt(d.read_i64()?, 0)
+ .ok_or_else(|| d.error("invalid timestamp"))?,
+ ))
+ }
+}
+
+#[cfg(test)]
+use rustc_serialize::json;
+
+#[test]
+fn test_encodable() {
+ super::test_encodable_json(json::encode);
+}
+
+#[test]
+fn test_decodable() {
+ super::test_decodable_json(json::decode);
+}
+
+#[test]
+fn test_decodable_timestamps() {
+ super::test_decodable_json_timestamp(json::decode);
+}
diff --git a/vendor/chrono/src/naive/datetime/serde.rs b/vendor/chrono/src/naive/datetime/serde.rs
new file mode 100644
index 000000000..40695fa74
--- /dev/null
+++ b/vendor/chrono/src/naive/datetime/serde.rs
@@ -0,0 +1,1133 @@
+#![cfg_attr(docsrs, doc(cfg(feature = "serde")))]
+
+use core::fmt;
+use serde::{de, ser};
+
+use super::NaiveDateTime;
+use crate::offset::LocalResult;
+
+/// Serialize a `NaiveDateTime` as an RFC 3339 string
+///
+/// See [the `serde` module](./serde/index.html) for alternate
+/// serialization formats.
+impl ser::Serialize for NaiveDateTime {
+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: ser::Serializer,
+ {
+ struct FormatWrapped<'a, D: 'a> {
+ inner: &'a D,
+ }
+
+ impl<'a, D: fmt::Debug> fmt::Display for FormatWrapped<'a, D> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ self.inner.fmt(f)
+ }
+ }
+
+ serializer.collect_str(&FormatWrapped { inner: &self })
+ }
+}
+
+struct NaiveDateTimeVisitor;
+
+impl<'de> de::Visitor<'de> for NaiveDateTimeVisitor {
+ type Value = NaiveDateTime;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("a formatted date and time string")
+ }
+
+ fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
+ where
+ E: de::Error,
+ {
+ value.parse().map_err(E::custom)
+ }
+}
+
+impl<'de> de::Deserialize<'de> for NaiveDateTime {
+ fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+ where
+ D: de::Deserializer<'de>,
+ {
+ deserializer.deserialize_str(NaiveDateTimeVisitor)
+ }
+}
+
+/// Used to serialize/deserialize from nanosecond-precision timestamps
+///
+/// # Example:
+///
+/// ```rust
+/// # use chrono::{NaiveDate, NaiveDateTime};
+/// # use serde_derive::{Deserialize, Serialize};
+/// use chrono::naive::serde::ts_nanoseconds;
+/// #[derive(Deserialize, Serialize)]
+/// struct S {
+/// #[serde(with = "ts_nanoseconds")]
+/// time: NaiveDateTime
+/// }
+///
+/// let time = NaiveDate::from_ymd_opt(2018, 5, 17).unwrap().and_hms_nano_opt(02, 04, 59, 918355733).unwrap();
+/// let my_s = S {
+/// time: time.clone(),
+/// };
+///
+/// let as_string = serde_json::to_string(&my_s)?;
+/// assert_eq!(as_string, r#"{"time":1526522699918355733}"#);
+/// let my_s: S = serde_json::from_str(&as_string)?;
+/// assert_eq!(my_s.time, time);
+/// # Ok::<(), serde_json::Error>(())
+/// ```
+pub mod ts_nanoseconds {
+ use core::fmt;
+ use serde::{de, ser};
+
+ use super::ne_timestamp;
+ use crate::NaiveDateTime;
+
+ /// Serialize a datetime into an integer number of nanoseconds since the epoch
+ ///
+ /// Intended for use with `serde`s `serialize_with` attribute.
+ ///
+ /// # Example:
+ ///
+ /// ```rust
+ /// # use chrono::{NaiveDate, NaiveDateTime};
+ /// # use serde_derive::Serialize;
+ /// use chrono::naive::serde::ts_nanoseconds::serialize as to_nano_ts;
+ /// #[derive(Serialize)]
+ /// struct S {
+ /// #[serde(serialize_with = "to_nano_ts")]
+ /// time: NaiveDateTime
+ /// }
+ ///
+ /// let my_s = S {
+ /// time: NaiveDate::from_ymd_opt(2018, 5, 17).unwrap().and_hms_nano_opt(02, 04, 59, 918355733).unwrap(),
+ /// };
+ /// let as_string = serde_json::to_string(&my_s)?;
+ /// assert_eq!(as_string, r#"{"time":1526522699918355733}"#);
+ /// # Ok::<(), serde_json::Error>(())
+ /// ```
+ pub fn serialize<S>(dt: &NaiveDateTime, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: ser::Serializer,
+ {
+ serializer.serialize_i64(dt.timestamp_nanos())
+ }
+
+ /// Deserialize a `NaiveDateTime` from a nanoseconds timestamp
+ ///
+ /// Intended for use with `serde`s `deserialize_with` attribute.
+ ///
+ /// # Example:
+ ///
+ /// ```rust
+ /// # use chrono::NaiveDateTime;
+ /// # use serde_derive::Deserialize;
+ /// use chrono::naive::serde::ts_nanoseconds::deserialize as from_nano_ts;
+ /// #[derive(Deserialize)]
+ /// struct S {
+ /// #[serde(deserialize_with = "from_nano_ts")]
+ /// time: NaiveDateTime
+ /// }
+ ///
+ /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918355733 }"#)?;
+ /// # Ok::<(), serde_json::Error>(())
+ /// ```
+ pub fn deserialize<'de, D>(d: D) -> Result<NaiveDateTime, D::Error>
+ where
+ D: de::Deserializer<'de>,
+ {
+ d.deserialize_i64(NanoSecondsTimestampVisitor)
+ }
+
+ pub(super) struct NanoSecondsTimestampVisitor;
+
+ impl<'de> de::Visitor<'de> for NanoSecondsTimestampVisitor {
+ type Value = NaiveDateTime;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("a unix timestamp")
+ }
+
+ fn visit_i64<E>(self, value: i64) -> Result<Self::Value, E>
+ where
+ E: de::Error,
+ {
+ NaiveDateTime::from_timestamp_opt(value / 1_000_000_000, (value % 1_000_000_000) as u32)
+ .ok_or_else(|| E::custom(ne_timestamp(value)))
+ }
+
+ fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
+ where
+ E: de::Error,
+ {
+ NaiveDateTime::from_timestamp_opt(
+ value as i64 / 1_000_000_000,
+ (value as i64 % 1_000_000_000) as u32,
+ )
+ .ok_or_else(|| E::custom(ne_timestamp(value)))
+ }
+ }
+}
+
+/// Ser/de to/from optional timestamps in nanoseconds
+///
+/// Intended for use with `serde`'s `with` attribute.
+///
+/// # Example:
+///
+/// ```rust
+/// # use chrono::naive::{NaiveDate, NaiveDateTime};
+/// # use serde_derive::{Deserialize, Serialize};
+/// use chrono::naive::serde::ts_nanoseconds_option;
+/// #[derive(Deserialize, Serialize)]
+/// struct S {
+/// #[serde(with = "ts_nanoseconds_option")]
+/// time: Option<NaiveDateTime>
+/// }
+///
+/// let time = Some(NaiveDate::from_ymd_opt(2018, 5, 17).unwrap().and_hms_nano_opt(02, 04, 59, 918355733).unwrap());
+/// let my_s = S {
+/// time: time.clone(),
+/// };
+///
+/// let as_string = serde_json::to_string(&my_s)?;
+/// assert_eq!(as_string, r#"{"time":1526522699918355733}"#);
+/// let my_s: S = serde_json::from_str(&as_string)?;
+/// assert_eq!(my_s.time, time);
+/// # Ok::<(), serde_json::Error>(())
+/// ```
+pub mod ts_nanoseconds_option {
+ use core::fmt;
+ use serde::{de, ser};
+
+ use super::ts_nanoseconds::NanoSecondsTimestampVisitor;
+ use crate::NaiveDateTime;
+
+ /// Serialize a datetime into an integer number of nanoseconds since the epoch or none
+ ///
+ /// Intended for use with `serde`s `serialize_with` attribute.
+ ///
+ /// # Example:
+ ///
+ /// ```rust
+ /// # use chrono::naive::{NaiveDate, NaiveDateTime};
+ /// # use serde_derive::Serialize;
+ /// use chrono::naive::serde::ts_nanoseconds_option::serialize as to_nano_tsopt;
+ /// #[derive(Serialize)]
+ /// struct S {
+ /// #[serde(serialize_with = "to_nano_tsopt")]
+ /// time: Option<NaiveDateTime>
+ /// }
+ ///
+ /// let my_s = S {
+ /// time: Some(NaiveDate::from_ymd_opt(2018, 5, 17).unwrap().and_hms_nano_opt(02, 04, 59, 918355733).unwrap()),
+ /// };
+ /// let as_string = serde_json::to_string(&my_s)?;
+ /// assert_eq!(as_string, r#"{"time":1526522699918355733}"#);
+ /// # Ok::<(), serde_json::Error>(())
+ /// ```
+ pub fn serialize<S>(opt: &Option<NaiveDateTime>, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: ser::Serializer,
+ {
+ match *opt {
+ Some(ref dt) => serializer.serialize_some(&dt.timestamp_nanos()),
+ None => serializer.serialize_none(),
+ }
+ }
+
+ /// Deserialize a `NaiveDateTime` from a nanosecond timestamp or none
+ ///
+ /// Intended for use with `serde`s `deserialize_with` attribute.
+ ///
+ /// # Example:
+ ///
+ /// ```rust
+ /// # use chrono::naive::{NaiveDate, NaiveDateTime};
+ /// # use serde_derive::Deserialize;
+ /// use chrono::naive::serde::ts_nanoseconds_option::deserialize as from_nano_tsopt;
+ /// #[derive(Deserialize)]
+ /// struct S {
+ /// #[serde(deserialize_with = "from_nano_tsopt")]
+ /// time: Option<NaiveDateTime>
+ /// }
+ ///
+ /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918355733 }"#)?;
+ /// # Ok::<(), serde_json::Error>(())
+ /// ```
+ pub fn deserialize<'de, D>(d: D) -> Result<Option<NaiveDateTime>, D::Error>
+ where
+ D: de::Deserializer<'de>,
+ {
+ d.deserialize_option(OptionNanoSecondsTimestampVisitor)
+ }
+
+ struct OptionNanoSecondsTimestampVisitor;
+
+ impl<'de> de::Visitor<'de> for OptionNanoSecondsTimestampVisitor {
+ type Value = Option<NaiveDateTime>;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("a unix timestamp in nanoseconds or none")
+ }
+
+ /// Deserialize a timestamp in nanoseconds since the epoch
+ fn visit_some<D>(self, d: D) -> Result<Self::Value, D::Error>
+ where
+ D: de::Deserializer<'de>,
+ {
+ d.deserialize_i64(NanoSecondsTimestampVisitor).map(Some)
+ }
+
+ /// Deserialize a timestamp in nanoseconds since the epoch
+ fn visit_none<E>(self) -> Result<Self::Value, E>
+ where
+ E: de::Error,
+ {
+ Ok(None)
+ }
+
+ /// Deserialize a timestamp in nanoseconds since the epoch
+ fn visit_unit<E>(self) -> Result<Self::Value, E>
+ where
+ E: de::Error,
+ {
+ Ok(None)
+ }
+ }
+}
+
+/// Used to serialize/deserialize from microsecond-precision timestamps
+///
+/// # Example:
+///
+/// ```rust
+/// # use chrono::{NaiveDate, NaiveDateTime};
+/// # use serde_derive::{Deserialize, Serialize};
+/// use chrono::naive::serde::ts_microseconds;
+/// #[derive(Deserialize, Serialize)]
+/// struct S {
+/// #[serde(with = "ts_microseconds")]
+/// time: NaiveDateTime
+/// }
+///
+/// let time = NaiveDate::from_ymd_opt(2018, 5, 17).unwrap().and_hms_micro_opt(02, 04, 59, 918355).unwrap();
+/// let my_s = S {
+/// time: time.clone(),
+/// };
+///
+/// let as_string = serde_json::to_string(&my_s)?;
+/// assert_eq!(as_string, r#"{"time":1526522699918355}"#);
+/// let my_s: S = serde_json::from_str(&as_string)?;
+/// assert_eq!(my_s.time, time);
+/// # Ok::<(), serde_json::Error>(())
+/// ```
+pub mod ts_microseconds {
+ use core::fmt;
+ use serde::{de, ser};
+
+ use super::ne_timestamp;
+ use crate::NaiveDateTime;
+
+ /// Serialize a datetime into an integer number of microseconds since the epoch
+ ///
+ /// Intended for use with `serde`s `serialize_with` attribute.
+ ///
+ /// # Example:
+ ///
+ /// ```rust
+ /// # use chrono::{NaiveDate, NaiveDateTime};
+ /// # use serde_derive::Serialize;
+ /// use chrono::naive::serde::ts_microseconds::serialize as to_micro_ts;
+ /// #[derive(Serialize)]
+ /// struct S {
+ /// #[serde(serialize_with = "to_micro_ts")]
+ /// time: NaiveDateTime
+ /// }
+ ///
+ /// let my_s = S {
+ /// time: NaiveDate::from_ymd_opt(2018, 5, 17).unwrap().and_hms_micro_opt(02, 04, 59, 918355).unwrap(),
+ /// };
+ /// let as_string = serde_json::to_string(&my_s)?;
+ /// assert_eq!(as_string, r#"{"time":1526522699918355}"#);
+ /// # Ok::<(), serde_json::Error>(())
+ /// ```
+ pub fn serialize<S>(dt: &NaiveDateTime, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: ser::Serializer,
+ {
+ serializer.serialize_i64(dt.timestamp_micros())
+ }
+
+ /// Deserialize a `NaiveDateTime` from a microseconds timestamp
+ ///
+ /// Intended for use with `serde`s `deserialize_with` attribute.
+ ///
+ /// # Example:
+ ///
+ /// ```rust
+ /// # use chrono::NaiveDateTime;
+ /// # use serde_derive::Deserialize;
+ /// use chrono::naive::serde::ts_microseconds::deserialize as from_micro_ts;
+ /// #[derive(Deserialize)]
+ /// struct S {
+ /// #[serde(deserialize_with = "from_micro_ts")]
+ /// time: NaiveDateTime
+ /// }
+ ///
+ /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918355 }"#)?;
+ /// # Ok::<(), serde_json::Error>(())
+ /// ```
+ pub fn deserialize<'de, D>(d: D) -> Result<NaiveDateTime, D::Error>
+ where
+ D: de::Deserializer<'de>,
+ {
+ d.deserialize_i64(MicroSecondsTimestampVisitor)
+ }
+
+ pub(super) struct MicroSecondsTimestampVisitor;
+
+ impl<'de> de::Visitor<'de> for MicroSecondsTimestampVisitor {
+ type Value = NaiveDateTime;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("a unix timestamp")
+ }
+
+ fn visit_i64<E>(self, value: i64) -> Result<Self::Value, E>
+ where
+ E: de::Error,
+ {
+ NaiveDateTime::from_timestamp_opt(
+ value / 1_000_000,
+ ((value % 1_000_000) * 1000) as u32,
+ )
+ .ok_or_else(|| E::custom(ne_timestamp(value)))
+ }
+
+ fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
+ where
+ E: de::Error,
+ {
+ NaiveDateTime::from_timestamp_opt(
+ (value / 1_000_000) as i64,
+ ((value % 1_000_000) * 1_000) as u32,
+ )
+ .ok_or_else(|| E::custom(ne_timestamp(value)))
+ }
+ }
+}
+
+/// Ser/de to/from optional timestamps in microseconds
+///
+/// Intended for use with `serde`'s `with` attribute.
+///
+/// # Example:
+///
+/// ```rust
+/// # use chrono::naive::{NaiveDate, NaiveDateTime};
+/// # use serde_derive::{Deserialize, Serialize};
+/// use chrono::naive::serde::ts_microseconds_option;
+/// #[derive(Deserialize, Serialize)]
+/// struct S {
+/// #[serde(with = "ts_microseconds_option")]
+/// time: Option<NaiveDateTime>
+/// }
+///
+/// let time = Some(NaiveDate::from_ymd_opt(2018, 5, 17).unwrap().and_hms_micro_opt(02, 04, 59, 918355).unwrap());
+/// let my_s = S {
+/// time: time.clone(),
+/// };
+///
+/// let as_string = serde_json::to_string(&my_s)?;
+/// assert_eq!(as_string, r#"{"time":1526522699918355}"#);
+/// let my_s: S = serde_json::from_str(&as_string)?;
+/// assert_eq!(my_s.time, time);
+/// # Ok::<(), serde_json::Error>(())
+/// ```
+pub mod ts_microseconds_option {
+ use core::fmt;
+ use serde::{de, ser};
+
+ use super::ts_microseconds::MicroSecondsTimestampVisitor;
+ use crate::NaiveDateTime;
+
+ /// Serialize a datetime into an integer number of microseconds since the epoch or none
+ ///
+ /// Intended for use with `serde`s `serialize_with` attribute.
+ ///
+ /// # Example:
+ ///
+ /// ```rust
+ /// # use chrono::naive::{NaiveDate, NaiveDateTime};
+ /// # use serde_derive::Serialize;
+ /// use chrono::naive::serde::ts_microseconds_option::serialize as to_micro_tsopt;
+ /// #[derive(Serialize)]
+ /// struct S {
+ /// #[serde(serialize_with = "to_micro_tsopt")]
+ /// time: Option<NaiveDateTime>
+ /// }
+ ///
+ /// let my_s = S {
+ /// time: Some(NaiveDate::from_ymd_opt(2018, 5, 17).unwrap().and_hms_micro_opt(02, 04, 59, 918355).unwrap()),
+ /// };
+ /// let as_string = serde_json::to_string(&my_s)?;
+ /// assert_eq!(as_string, r#"{"time":1526522699918355}"#);
+ /// # Ok::<(), serde_json::Error>(())
+ /// ```
+ pub fn serialize<S>(opt: &Option<NaiveDateTime>, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: ser::Serializer,
+ {
+ match *opt {
+ Some(ref dt) => serializer.serialize_some(&dt.timestamp_micros()),
+ None => serializer.serialize_none(),
+ }
+ }
+
+ /// Deserialize a `NaiveDateTime` from a nanosecond timestamp or none
+ ///
+ /// Intended for use with `serde`s `deserialize_with` attribute.
+ ///
+ /// # Example:
+ ///
+ /// ```rust
+ /// # use chrono::naive::{NaiveDate, NaiveDateTime};
+ /// # use serde_derive::Deserialize;
+ /// use chrono::naive::serde::ts_microseconds_option::deserialize as from_micro_tsopt;
+ /// #[derive(Deserialize)]
+ /// struct S {
+ /// #[serde(deserialize_with = "from_micro_tsopt")]
+ /// time: Option<NaiveDateTime>
+ /// }
+ ///
+ /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918355 }"#)?;
+ /// # Ok::<(), serde_json::Error>(())
+ /// ```
+ pub fn deserialize<'de, D>(d: D) -> Result<Option<NaiveDateTime>, D::Error>
+ where
+ D: de::Deserializer<'de>,
+ {
+ d.deserialize_option(OptionMicroSecondsTimestampVisitor)
+ }
+
+ struct OptionMicroSecondsTimestampVisitor;
+
+ impl<'de> de::Visitor<'de> for OptionMicroSecondsTimestampVisitor {
+ type Value = Option<NaiveDateTime>;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("a unix timestamp in microseconds or none")
+ }
+
+ /// Deserialize a timestamp in microseconds since the epoch
+ fn visit_some<D>(self, d: D) -> Result<Self::Value, D::Error>
+ where
+ D: de::Deserializer<'de>,
+ {
+ d.deserialize_i64(MicroSecondsTimestampVisitor).map(Some)
+ }
+
+ /// Deserialize a timestamp in microseconds since the epoch
+ fn visit_none<E>(self) -> Result<Self::Value, E>
+ where
+ E: de::Error,
+ {
+ Ok(None)
+ }
+
+ /// Deserialize a timestamp in microseconds since the epoch
+ fn visit_unit<E>(self) -> Result<Self::Value, E>
+ where
+ E: de::Error,
+ {
+ Ok(None)
+ }
+ }
+}
+
+/// Used to serialize/deserialize from millisecond-precision timestamps
+///
+/// # Example:
+///
+/// ```rust
+/// # use chrono::{NaiveDate, NaiveDateTime};
+/// # use serde_derive::{Deserialize, Serialize};
+/// use chrono::naive::serde::ts_milliseconds;
+/// #[derive(Deserialize, Serialize)]
+/// struct S {
+/// #[serde(with = "ts_milliseconds")]
+/// time: NaiveDateTime
+/// }
+///
+/// let time = NaiveDate::from_ymd_opt(2018, 5, 17).unwrap().and_hms_milli_opt(02, 04, 59, 918).unwrap();
+/// let my_s = S {
+/// time: time.clone(),
+/// };
+///
+/// let as_string = serde_json::to_string(&my_s)?;
+/// assert_eq!(as_string, r#"{"time":1526522699918}"#);
+/// let my_s: S = serde_json::from_str(&as_string)?;
+/// assert_eq!(my_s.time, time);
+/// # Ok::<(), serde_json::Error>(())
+/// ```
+pub mod ts_milliseconds {
+ use core::fmt;
+ use serde::{de, ser};
+
+ use super::ne_timestamp;
+ use crate::NaiveDateTime;
+
+ /// Serialize a datetime into an integer number of milliseconds since the epoch
+ ///
+ /// Intended for use with `serde`s `serialize_with` attribute.
+ ///
+ /// # Example:
+ ///
+ /// ```rust
+ /// # use chrono::{NaiveDate, NaiveDateTime};
+ /// # use serde_derive::Serialize;
+ /// use chrono::naive::serde::ts_milliseconds::serialize as to_milli_ts;
+ /// #[derive(Serialize)]
+ /// struct S {
+ /// #[serde(serialize_with = "to_milli_ts")]
+ /// time: NaiveDateTime
+ /// }
+ ///
+ /// let my_s = S {
+ /// time: NaiveDate::from_ymd_opt(2018, 5, 17).unwrap().and_hms_milli_opt(02, 04, 59, 918).unwrap(),
+ /// };
+ /// let as_string = serde_json::to_string(&my_s)?;
+ /// assert_eq!(as_string, r#"{"time":1526522699918}"#);
+ /// # Ok::<(), serde_json::Error>(())
+ /// ```
+ pub fn serialize<S>(dt: &NaiveDateTime, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: ser::Serializer,
+ {
+ serializer.serialize_i64(dt.timestamp_millis())
+ }
+
+ /// Deserialize a `NaiveDateTime` from a milliseconds timestamp
+ ///
+ /// Intended for use with `serde`s `deserialize_with` attribute.
+ ///
+ /// # Example:
+ ///
+ /// ```rust
+ /// # use chrono::NaiveDateTime;
+ /// # use serde_derive::Deserialize;
+ /// use chrono::naive::serde::ts_milliseconds::deserialize as from_milli_ts;
+ /// #[derive(Deserialize)]
+ /// struct S {
+ /// #[serde(deserialize_with = "from_milli_ts")]
+ /// time: NaiveDateTime
+ /// }
+ ///
+ /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918 }"#)?;
+ /// # Ok::<(), serde_json::Error>(())
+ /// ```
+ pub fn deserialize<'de, D>(d: D) -> Result<NaiveDateTime, D::Error>
+ where
+ D: de::Deserializer<'de>,
+ {
+ d.deserialize_i64(MilliSecondsTimestampVisitor)
+ }
+
+ pub(super) struct MilliSecondsTimestampVisitor;
+
+ impl<'de> de::Visitor<'de> for MilliSecondsTimestampVisitor {
+ type Value = NaiveDateTime;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("a unix timestamp")
+ }
+
+ fn visit_i64<E>(self, value: i64) -> Result<Self::Value, E>
+ where
+ E: de::Error,
+ {
+ NaiveDateTime::from_timestamp_opt(value / 1000, ((value % 1000) * 1_000_000) as u32)
+ .ok_or_else(|| E::custom(ne_timestamp(value)))
+ }
+
+ fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
+ where
+ E: de::Error,
+ {
+ NaiveDateTime::from_timestamp_opt(
+ (value / 1000) as i64,
+ ((value % 1000) * 1_000_000) as u32,
+ )
+ .ok_or_else(|| E::custom(ne_timestamp(value)))
+ }
+ }
+}
+
+/// Ser/de to/from optional timestamps in milliseconds
+///
+/// Intended for use with `serde`'s `with` attribute.
+///
+/// # Example:
+///
+/// ```rust
+/// # use chrono::naive::{NaiveDate, NaiveDateTime};
+/// # use serde_derive::{Deserialize, Serialize};
+/// use chrono::naive::serde::ts_milliseconds_option;
+/// #[derive(Deserialize, Serialize)]
+/// struct S {
+/// #[serde(with = "ts_milliseconds_option")]
+/// time: Option<NaiveDateTime>
+/// }
+///
+/// let time = Some(NaiveDate::from_ymd_opt(2018, 5, 17).unwrap().and_hms_milli_opt(02, 04, 59, 918).unwrap());
+/// let my_s = S {
+/// time: time.clone(),
+/// };
+///
+/// let as_string = serde_json::to_string(&my_s)?;
+/// assert_eq!(as_string, r#"{"time":1526522699918}"#);
+/// let my_s: S = serde_json::from_str(&as_string)?;
+/// assert_eq!(my_s.time, time);
+/// # Ok::<(), serde_json::Error>(())
+/// ```
+pub mod ts_milliseconds_option {
+ use core::fmt;
+ use serde::{de, ser};
+
+ use super::ts_milliseconds::MilliSecondsTimestampVisitor;
+ use crate::NaiveDateTime;
+
+ /// Serialize a datetime into an integer number of milliseconds since the epoch or none
+ ///
+ /// Intended for use with `serde`s `serialize_with` attribute.
+ ///
+ /// # Example:
+ ///
+ /// ```rust
+ /// # use chrono::naive::{NaiveDate, NaiveDateTime};
+ /// # use serde_derive::Serialize;
+ /// use chrono::naive::serde::ts_milliseconds_option::serialize as to_milli_tsopt;
+ /// #[derive(Serialize)]
+ /// struct S {
+ /// #[serde(serialize_with = "to_milli_tsopt")]
+ /// time: Option<NaiveDateTime>
+ /// }
+ ///
+ /// let my_s = S {
+ /// time: Some(NaiveDate::from_ymd_opt(2018, 5, 17).unwrap().and_hms_milli_opt(02, 04, 59, 918).unwrap()),
+ /// };
+ /// let as_string = serde_json::to_string(&my_s)?;
+ /// assert_eq!(as_string, r#"{"time":1526522699918}"#);
+ /// # Ok::<(), serde_json::Error>(())
+ /// ```
+ pub fn serialize<S>(opt: &Option<NaiveDateTime>, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: ser::Serializer,
+ {
+ match *opt {
+ Some(ref dt) => serializer.serialize_some(&dt.timestamp_millis()),
+ None => serializer.serialize_none(),
+ }
+ }
+
+ /// Deserialize a `NaiveDateTime` from a nanosecond timestamp or none
+ ///
+ /// Intended for use with `serde`s `deserialize_with` attribute.
+ ///
+ /// # Example:
+ ///
+ /// ```rust
+ /// # use chrono::naive::{NaiveDate, NaiveDateTime};
+ /// # use serde_derive::Deserialize;
+ /// use chrono::naive::serde::ts_milliseconds_option::deserialize as from_milli_tsopt;
+ /// #[derive(Deserialize)]
+ /// struct S {
+ /// #[serde(deserialize_with = "from_milli_tsopt")]
+ /// time: Option<NaiveDateTime>
+ /// }
+ ///
+ /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918355 }"#)?;
+ /// # Ok::<(), serde_json::Error>(())
+ /// ```
+ pub fn deserialize<'de, D>(d: D) -> Result<Option<NaiveDateTime>, D::Error>
+ where
+ D: de::Deserializer<'de>,
+ {
+ d.deserialize_option(OptionMilliSecondsTimestampVisitor)
+ }
+
+ struct OptionMilliSecondsTimestampVisitor;
+
+ impl<'de> de::Visitor<'de> for OptionMilliSecondsTimestampVisitor {
+ type Value = Option<NaiveDateTime>;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("a unix timestamp in milliseconds or none")
+ }
+
+ /// Deserialize a timestamp in milliseconds since the epoch
+ fn visit_some<D>(self, d: D) -> Result<Self::Value, D::Error>
+ where
+ D: de::Deserializer<'de>,
+ {
+ d.deserialize_i64(MilliSecondsTimestampVisitor).map(Some)
+ }
+
+ /// Deserialize a timestamp in milliseconds since the epoch
+ fn visit_none<E>(self) -> Result<Self::Value, E>
+ where
+ E: de::Error,
+ {
+ Ok(None)
+ }
+
+ /// Deserialize a timestamp in milliseconds since the epoch
+ fn visit_unit<E>(self) -> Result<Self::Value, E>
+ where
+ E: de::Error,
+ {
+ Ok(None)
+ }
+ }
+}
+
+/// Used to serialize/deserialize from second-precision timestamps
+///
+/// # Example:
+///
+/// ```rust
+/// # use chrono::{NaiveDate, NaiveDateTime};
+/// # use serde_derive::{Deserialize, Serialize};
+/// use chrono::naive::serde::ts_seconds;
+/// #[derive(Deserialize, Serialize)]
+/// struct S {
+/// #[serde(with = "ts_seconds")]
+/// time: NaiveDateTime
+/// }
+///
+/// let time = NaiveDate::from_ymd_opt(2015, 5, 15).unwrap().and_hms_opt(10, 0, 0).unwrap();
+/// let my_s = S {
+/// time: time.clone(),
+/// };
+///
+/// let as_string = serde_json::to_string(&my_s)?;
+/// assert_eq!(as_string, r#"{"time":1431684000}"#);
+/// let my_s: S = serde_json::from_str(&as_string)?;
+/// assert_eq!(my_s.time, time);
+/// # Ok::<(), serde_json::Error>(())
+/// ```
+pub mod ts_seconds {
+ use core::fmt;
+ use serde::{de, ser};
+
+ use super::ne_timestamp;
+ use crate::NaiveDateTime;
+
+ /// Serialize a datetime into an integer number of seconds since the epoch
+ ///
+ /// Intended for use with `serde`s `serialize_with` attribute.
+ ///
+ /// # Example:
+ ///
+ /// ```rust
+ /// # use chrono::{NaiveDate, NaiveDateTime};
+ /// # use serde_derive::Serialize;
+ /// use chrono::naive::serde::ts_seconds::serialize as to_ts;
+ /// #[derive(Serialize)]
+ /// struct S {
+ /// #[serde(serialize_with = "to_ts")]
+ /// time: NaiveDateTime
+ /// }
+ ///
+ /// let my_s = S {
+ /// time: NaiveDate::from_ymd_opt(2015, 5, 15).unwrap().and_hms_opt(10, 0, 0).unwrap(),
+ /// };
+ /// let as_string = serde_json::to_string(&my_s)?;
+ /// assert_eq!(as_string, r#"{"time":1431684000}"#);
+ /// # Ok::<(), serde_json::Error>(())
+ /// ```
+ pub fn serialize<S>(dt: &NaiveDateTime, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: ser::Serializer,
+ {
+ serializer.serialize_i64(dt.timestamp())
+ }
+
+ /// Deserialize a `NaiveDateTime` from a seconds timestamp
+ ///
+ /// Intended for use with `serde`s `deserialize_with` attribute.
+ ///
+ /// # Example:
+ ///
+ /// ```rust
+ /// # use chrono::NaiveDateTime;
+ /// # use serde_derive::Deserialize;
+ /// use chrono::naive::serde::ts_seconds::deserialize as from_ts;
+ /// #[derive(Deserialize)]
+ /// struct S {
+ /// #[serde(deserialize_with = "from_ts")]
+ /// time: NaiveDateTime
+ /// }
+ ///
+ /// let my_s: S = serde_json::from_str(r#"{ "time": 1431684000 }"#)?;
+ /// # Ok::<(), serde_json::Error>(())
+ /// ```
+ pub fn deserialize<'de, D>(d: D) -> Result<NaiveDateTime, D::Error>
+ where
+ D: de::Deserializer<'de>,
+ {
+ d.deserialize_i64(SecondsTimestampVisitor)
+ }
+
+ pub(super) struct SecondsTimestampVisitor;
+
+ impl<'de> de::Visitor<'de> for SecondsTimestampVisitor {
+ type Value = NaiveDateTime;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("a unix timestamp")
+ }
+
+ fn visit_i64<E>(self, value: i64) -> Result<Self::Value, E>
+ where
+ E: de::Error,
+ {
+ NaiveDateTime::from_timestamp_opt(value, 0)
+ .ok_or_else(|| E::custom(ne_timestamp(value)))
+ }
+
+ fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
+ where
+ E: de::Error,
+ {
+ NaiveDateTime::from_timestamp_opt(value as i64, 0)
+ .ok_or_else(|| E::custom(ne_timestamp(value)))
+ }
+ }
+}
+
+/// Ser/de to/from optional timestamps in seconds
+///
+/// Intended for use with `serde`'s `with` attribute.
+///
+/// # Example:
+///
+/// ```rust
+/// # use chrono::naive::{NaiveDate, NaiveDateTime};
+/// # use serde_derive::{Deserialize, Serialize};
+/// use chrono::naive::serde::ts_seconds_option;
+/// #[derive(Deserialize, Serialize)]
+/// struct S {
+/// #[serde(with = "ts_seconds_option")]
+/// time: Option<NaiveDateTime>
+/// }
+///
+/// let time = Some(NaiveDate::from_ymd_opt(2018, 5, 17).unwrap().and_hms_opt(02, 04, 59).unwrap());
+/// let my_s = S {
+/// time: time.clone(),
+/// };
+///
+/// let as_string = serde_json::to_string(&my_s)?;
+/// assert_eq!(as_string, r#"{"time":1526522699}"#);
+/// let my_s: S = serde_json::from_str(&as_string)?;
+/// assert_eq!(my_s.time, time);
+/// # Ok::<(), serde_json::Error>(())
+/// ```
+pub mod ts_seconds_option {
+ use core::fmt;
+ use serde::{de, ser};
+
+ use super::ts_seconds::SecondsTimestampVisitor;
+ use crate::NaiveDateTime;
+
+ /// Serialize a datetime into an integer number of seconds since the epoch or none
+ ///
+ /// Intended for use with `serde`s `serialize_with` attribute.
+ ///
+ /// # Example:
+ ///
+ /// ```rust
+ /// # use chrono::naive::{NaiveDate, NaiveDateTime};
+ /// # use serde_derive::Serialize;
+ /// use chrono::naive::serde::ts_seconds_option::serialize as to_tsopt;
+ /// #[derive(Serialize)]
+ /// struct S {
+ /// #[serde(serialize_with = "to_tsopt")]
+ /// time: Option<NaiveDateTime>
+ /// }
+ ///
+ /// let my_s = S {
+ /// time: Some(NaiveDate::from_ymd_opt(2018, 5, 17).unwrap().and_hms_opt(02, 04, 59).unwrap()),
+ /// };
+ /// let as_string = serde_json::to_string(&my_s)?;
+ /// assert_eq!(as_string, r#"{"time":1526522699}"#);
+ /// # Ok::<(), serde_json::Error>(())
+ /// ```
+ pub fn serialize<S>(opt: &Option<NaiveDateTime>, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: ser::Serializer,
+ {
+ match *opt {
+ Some(ref dt) => serializer.serialize_some(&dt.timestamp()),
+ None => serializer.serialize_none(),
+ }
+ }
+
+ /// Deserialize a `NaiveDateTime` from a second timestamp or none
+ ///
+ /// Intended for use with `serde`s `deserialize_with` attribute.
+ ///
+ /// # Example:
+ ///
+ /// ```rust
+ /// # use chrono::naive::{NaiveDate, NaiveDateTime};
+ /// # use serde_derive::Deserialize;
+ /// use chrono::naive::serde::ts_seconds_option::deserialize as from_tsopt;
+ /// #[derive(Deserialize)]
+ /// struct S {
+ /// #[serde(deserialize_with = "from_tsopt")]
+ /// time: Option<NaiveDateTime>
+ /// }
+ ///
+ /// let my_s: S = serde_json::from_str(r#"{ "time": 1431684000 }"#)?;
+ /// # Ok::<(), serde_json::Error>(())
+ /// ```
+ pub fn deserialize<'de, D>(d: D) -> Result<Option<NaiveDateTime>, D::Error>
+ where
+ D: de::Deserializer<'de>,
+ {
+ d.deserialize_option(OptionSecondsTimestampVisitor)
+ }
+
+ struct OptionSecondsTimestampVisitor;
+
+ impl<'de> de::Visitor<'de> for OptionSecondsTimestampVisitor {
+ type Value = Option<NaiveDateTime>;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("a unix timestamp in seconds or none")
+ }
+
+ /// Deserialize a timestamp in seconds since the epoch
+ fn visit_some<D>(self, d: D) -> Result<Self::Value, D::Error>
+ where
+ D: de::Deserializer<'de>,
+ {
+ d.deserialize_i64(SecondsTimestampVisitor).map(Some)
+ }
+
+ /// Deserialize a timestamp in seconds since the epoch
+ fn visit_none<E>(self) -> Result<Self::Value, E>
+ where
+ E: de::Error,
+ {
+ Ok(None)
+ }
+
+ /// Deserialize a timestamp in seconds since the epoch
+ fn visit_unit<E>(self) -> Result<Self::Value, E>
+ where
+ E: de::Error,
+ {
+ Ok(None)
+ }
+ }
+}
+
+#[test]
+fn test_serde_serialize() {
+ super::test_encodable_json(serde_json::to_string);
+}
+
+#[test]
+fn test_serde_deserialize() {
+ super::test_decodable_json(|input| serde_json::from_str(input));
+}
+
+// Bincode is relevant to test separately from JSON because
+// it is not self-describing.
+#[test]
+fn test_serde_bincode() {
+ use crate::NaiveDate;
+ use bincode::{deserialize, serialize};
+
+ let dt = NaiveDate::from_ymd_opt(2016, 7, 8).unwrap().and_hms_milli_opt(9, 10, 48, 90).unwrap();
+ let encoded = serialize(&dt).unwrap();
+ let decoded: NaiveDateTime = deserialize(&encoded).unwrap();
+ assert_eq!(dt, decoded);
+}
+
+#[test]
+fn test_serde_bincode_optional() {
+ use crate::prelude::*;
+ use crate::serde::ts_nanoseconds_option;
+ use bincode::{deserialize, serialize};
+ use serde_derive::{Deserialize, Serialize};
+
+ #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
+ struct Test {
+ one: Option<i64>,
+ #[serde(with = "ts_nanoseconds_option")]
+ two: Option<DateTime<Utc>>,
+ }
+
+ let expected =
+ Test { one: Some(1), two: Some(Utc.with_ymd_and_hms(1970, 1, 1, 0, 1, 1).unwrap()) };
+ let bytes: Vec<u8> = serialize(&expected).unwrap();
+ let actual = deserialize::<Test>(&(bytes)).unwrap();
+
+ assert_eq!(expected, actual);
+}
+
+// lik? function to convert a LocalResult into a serde-ish Result
+pub(crate) fn serde_from<T, E, V>(me: LocalResult<T>, ts: &V) -> Result<T, E>
+where
+ E: de::Error,
+ V: fmt::Display,
+ T: fmt::Display,
+{
+ match me {
+ LocalResult::None => Err(E::custom(ne_timestamp(ts))),
+ LocalResult::Ambiguous(min, max) => {
+ Err(E::custom(SerdeError::Ambiguous { timestamp: ts, min, max }))
+ }
+ LocalResult::Single(val) => Ok(val),
+ }
+}
+
+enum SerdeError<V: fmt::Display, D: fmt::Display> {
+ NonExistent { timestamp: V },
+ Ambiguous { timestamp: V, min: D, max: D },
+}
+
+/// Construct a [`SerdeError::NonExistent`]
+fn ne_timestamp<T: fmt::Display>(ts: T) -> SerdeError<T, u8> {
+ SerdeError::NonExistent::<T, u8> { timestamp: ts }
+}
+
+impl<V: fmt::Display, D: fmt::Display> fmt::Debug for SerdeError<V, D> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "ChronoSerdeError({})", self)
+ }
+}
+
+// impl<V: fmt::Display, D: fmt::Debug> core::error::Error for SerdeError<V, D> {}
+impl<V: fmt::Display, D: fmt::Display> fmt::Display for SerdeError<V, D> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match self {
+ SerdeError::NonExistent { timestamp } => {
+ write!(f, "value is not a legal timestamp: {}", timestamp)
+ }
+ SerdeError::Ambiguous { timestamp, min, max } => write!(
+ f,
+ "value is an ambiguous timestamp: {}, could be either of {}, {}",
+ timestamp, min, max
+ ),
+ }
+ }
+}
diff --git a/vendor/chrono/src/naive/datetime/tests.rs b/vendor/chrono/src/naive/datetime/tests.rs
new file mode 100644
index 000000000..202bdb34d
--- /dev/null
+++ b/vendor/chrono/src/naive/datetime/tests.rs
@@ -0,0 +1,343 @@
+use super::NaiveDateTime;
+use crate::oldtime::Duration;
+use crate::NaiveDate;
+use crate::{Datelike, FixedOffset, Utc};
+use std::i64;
+
+#[test]
+fn test_datetime_from_timestamp_millis() {
+ let valid_map = [
+ (1662921288000, "2022-09-11 18:34:48.000000000"),
+ (1662921288123, "2022-09-11 18:34:48.123000000"),
+ (1662921287890, "2022-09-11 18:34:47.890000000"),
+ (-2208936075000, "1900-01-01 14:38:45.000000000"),
+ (0, "1970-01-01 00:00:00.000000000"),
+ (119731017000, "1973-10-17 18:36:57.000000000"),
+ (1234567890000, "2009-02-13 23:31:30.000000000"),
+ (2034061609000, "2034-06-16 09:06:49.000000000"),
+ ];
+
+ for (timestamp_millis, formatted) in valid_map.iter().copied() {
+ let naive_datetime = NaiveDateTime::from_timestamp_millis(timestamp_millis);
+ assert_eq!(timestamp_millis, naive_datetime.unwrap().timestamp_millis());
+ assert_eq!(naive_datetime.unwrap().format("%F %T%.9f").to_string(), formatted);
+ }
+
+ let invalid = [i64::MAX, i64::MIN];
+
+ for timestamp_millis in invalid.iter().copied() {
+ let naive_datetime = NaiveDateTime::from_timestamp_millis(timestamp_millis);
+ assert!(naive_datetime.is_none());
+ }
+
+ // Test that the result of `from_timestamp_millis` compares equal to
+ // that of `from_timestamp_opt`.
+ let secs_test = [0, 1, 2, 1000, 1234, 12345678, -1, -2, -1000, -12345678];
+ for secs in secs_test.iter().cloned() {
+ assert_eq!(
+ NaiveDateTime::from_timestamp_millis(secs * 1000),
+ NaiveDateTime::from_timestamp_opt(secs, 0)
+ );
+ }
+}
+
+#[test]
+fn test_datetime_from_timestamp_micros() {
+ let valid_map = [
+ (1662921288000000, "2022-09-11 18:34:48.000000000"),
+ (1662921288123456, "2022-09-11 18:34:48.123456000"),
+ (1662921287890000, "2022-09-11 18:34:47.890000000"),
+ (-2208936075000000, "1900-01-01 14:38:45.000000000"),
+ (0, "1970-01-01 00:00:00.000000000"),
+ (119731017000000, "1973-10-17 18:36:57.000000000"),
+ (1234567890000000, "2009-02-13 23:31:30.000000000"),
+ (2034061609000000, "2034-06-16 09:06:49.000000000"),
+ ];
+
+ for (timestamp_micros, formatted) in valid_map.iter().copied() {
+ let naive_datetime = NaiveDateTime::from_timestamp_micros(timestamp_micros);
+ assert_eq!(timestamp_micros, naive_datetime.unwrap().timestamp_micros());
+ assert_eq!(naive_datetime.unwrap().format("%F %T%.9f").to_string(), formatted);
+ }
+
+ let invalid = [i64::MAX, i64::MIN];
+
+ for timestamp_micros in invalid.iter().copied() {
+ let naive_datetime = NaiveDateTime::from_timestamp_micros(timestamp_micros);
+ assert!(naive_datetime.is_none());
+ }
+
+ // Test that the result of `from_timestamp_micros` compares equal to
+ // that of `from_timestamp_opt`.
+ let secs_test = [0, 1, 2, 1000, 1234, 12345678, -1, -2, -1000, -12345678];
+ for secs in secs_test.iter().copied() {
+ assert_eq!(
+ NaiveDateTime::from_timestamp_micros(secs * 1_000_000),
+ NaiveDateTime::from_timestamp_opt(secs, 0)
+ );
+ }
+}
+
+#[test]
+fn test_datetime_from_timestamp() {
+ let from_timestamp = |secs| NaiveDateTime::from_timestamp_opt(secs, 0);
+ let ymdhms =
+ |y, m, d, h, n, s| NaiveDate::from_ymd_opt(y, m, d).unwrap().and_hms_opt(h, n, s).unwrap();
+ assert_eq!(from_timestamp(-1), Some(ymdhms(1969, 12, 31, 23, 59, 59)));
+ assert_eq!(from_timestamp(0), Some(ymdhms(1970, 1, 1, 0, 0, 0)));
+ assert_eq!(from_timestamp(1), Some(ymdhms(1970, 1, 1, 0, 0, 1)));
+ assert_eq!(from_timestamp(1_000_000_000), Some(ymdhms(2001, 9, 9, 1, 46, 40)));
+ assert_eq!(from_timestamp(0x7fffffff), Some(ymdhms(2038, 1, 19, 3, 14, 7)));
+ assert_eq!(from_timestamp(i64::MIN), None);
+ assert_eq!(from_timestamp(i64::MAX), None);
+}
+
+#[test]
+fn test_datetime_add() {
+ fn check(
+ (y, m, d, h, n, s): (i32, u32, u32, u32, u32, u32),
+ rhs: Duration,
+ result: Option<(i32, u32, u32, u32, u32, u32)>,
+ ) {
+ let lhs = NaiveDate::from_ymd_opt(y, m, d).unwrap().and_hms_opt(h, n, s).unwrap();
+ let sum = result.map(|(y, m, d, h, n, s)| {
+ NaiveDate::from_ymd_opt(y, m, d).unwrap().and_hms_opt(h, n, s).unwrap()
+ });
+ assert_eq!(lhs.checked_add_signed(rhs), sum);
+ assert_eq!(lhs.checked_sub_signed(-rhs), sum);
+ }
+
+ check((2014, 5, 6, 7, 8, 9), Duration::seconds(3600 + 60 + 1), Some((2014, 5, 6, 8, 9, 10)));
+ check((2014, 5, 6, 7, 8, 9), Duration::seconds(-(3600 + 60 + 1)), Some((2014, 5, 6, 6, 7, 8)));
+ check((2014, 5, 6, 7, 8, 9), Duration::seconds(86399), Some((2014, 5, 7, 7, 8, 8)));
+ check((2014, 5, 6, 7, 8, 9), Duration::seconds(86_400 * 10), Some((2014, 5, 16, 7, 8, 9)));
+ check((2014, 5, 6, 7, 8, 9), Duration::seconds(-86_400 * 10), Some((2014, 4, 26, 7, 8, 9)));
+ check((2014, 5, 6, 7, 8, 9), Duration::seconds(86_400 * 10), Some((2014, 5, 16, 7, 8, 9)));
+
+ // overflow check
+ // assumes that we have correct values for MAX/MIN_DAYS_FROM_YEAR_0 from `naive::date`.
+ // (they are private constants, but the equivalence is tested in that module.)
+ let max_days_from_year_0 =
+ NaiveDate::MAX.signed_duration_since(NaiveDate::from_ymd_opt(0, 1, 1).unwrap());
+ check((0, 1, 1, 0, 0, 0), max_days_from_year_0, Some((NaiveDate::MAX.year(), 12, 31, 0, 0, 0)));
+ check(
+ (0, 1, 1, 0, 0, 0),
+ max_days_from_year_0 + Duration::seconds(86399),
+ Some((NaiveDate::MAX.year(), 12, 31, 23, 59, 59)),
+ );
+ check((0, 1, 1, 0, 0, 0), max_days_from_year_0 + Duration::seconds(86_400), None);
+ check((0, 1, 1, 0, 0, 0), Duration::max_value(), None);
+
+ let min_days_from_year_0 =
+ NaiveDate::MIN.signed_duration_since(NaiveDate::from_ymd_opt(0, 1, 1).unwrap());
+ check((0, 1, 1, 0, 0, 0), min_days_from_year_0, Some((NaiveDate::MIN.year(), 1, 1, 0, 0, 0)));
+ check((0, 1, 1, 0, 0, 0), min_days_from_year_0 - Duration::seconds(1), None);
+ check((0, 1, 1, 0, 0, 0), Duration::min_value(), None);
+}
+
+#[test]
+fn test_datetime_sub() {
+ let ymdhms =
+ |y, m, d, h, n, s| NaiveDate::from_ymd_opt(y, m, d).unwrap().and_hms_opt(h, n, s).unwrap();
+ let since = NaiveDateTime::signed_duration_since;
+ assert_eq!(since(ymdhms(2014, 5, 6, 7, 8, 9), ymdhms(2014, 5, 6, 7, 8, 9)), Duration::zero());
+ assert_eq!(
+ since(ymdhms(2014, 5, 6, 7, 8, 10), ymdhms(2014, 5, 6, 7, 8, 9)),
+ Duration::seconds(1)
+ );
+ assert_eq!(
+ since(ymdhms(2014, 5, 6, 7, 8, 9), ymdhms(2014, 5, 6, 7, 8, 10)),
+ Duration::seconds(-1)
+ );
+ assert_eq!(
+ since(ymdhms(2014, 5, 7, 7, 8, 9), ymdhms(2014, 5, 6, 7, 8, 10)),
+ Duration::seconds(86399)
+ );
+ assert_eq!(
+ since(ymdhms(2001, 9, 9, 1, 46, 39), ymdhms(1970, 1, 1, 0, 0, 0)),
+ Duration::seconds(999_999_999)
+ );
+}
+
+#[test]
+fn test_datetime_addassignment() {
+ let ymdhms =
+ |y, m, d, h, n, s| NaiveDate::from_ymd_opt(y, m, d).unwrap().and_hms_opt(h, n, s).unwrap();
+ let mut date = ymdhms(2016, 10, 1, 10, 10, 10);
+ date += Duration::minutes(10_000_000);
+ assert_eq!(date, ymdhms(2035, 10, 6, 20, 50, 10));
+ date += Duration::days(10);
+ assert_eq!(date, ymdhms(2035, 10, 16, 20, 50, 10));
+}
+
+#[test]
+fn test_datetime_subassignment() {
+ let ymdhms =
+ |y, m, d, h, n, s| NaiveDate::from_ymd_opt(y, m, d).unwrap().and_hms_opt(h, n, s).unwrap();
+ let mut date = ymdhms(2016, 10, 1, 10, 10, 10);
+ date -= Duration::minutes(10_000_000);
+ assert_eq!(date, ymdhms(1997, 9, 26, 23, 30, 10));
+ date -= Duration::days(10);
+ assert_eq!(date, ymdhms(1997, 9, 16, 23, 30, 10));
+}
+
+#[test]
+fn test_datetime_timestamp() {
+ let to_timestamp = |y, m, d, h, n, s| {
+ NaiveDate::from_ymd_opt(y, m, d).unwrap().and_hms_opt(h, n, s).unwrap().timestamp()
+ };
+ assert_eq!(to_timestamp(1969, 12, 31, 23, 59, 59), -1);
+ assert_eq!(to_timestamp(1970, 1, 1, 0, 0, 0), 0);
+ assert_eq!(to_timestamp(1970, 1, 1, 0, 0, 1), 1);
+ assert_eq!(to_timestamp(2001, 9, 9, 1, 46, 40), 1_000_000_000);
+ assert_eq!(to_timestamp(2038, 1, 19, 3, 14, 7), 0x7fffffff);
+}
+
+#[test]
+fn test_datetime_from_str() {
+ // valid cases
+ let valid = [
+ "2015-2-18T23:16:9.15",
+ "-77-02-18T23:16:09",
+ " +82701 - 05 - 6 T 15 : 9 : 60.898989898989 ",
+ ];
+ for &s in &valid {
+ let d = match s.parse::<NaiveDateTime>() {
+ Ok(d) => d,
+ Err(e) => panic!("parsing `{}` has failed: {}", s, e),
+ };
+ let s_ = format!("{:?}", d);
+ // `s` and `s_` may differ, but `s.parse()` and `s_.parse()` must be same
+ let d_ = match s_.parse::<NaiveDateTime>() {
+ Ok(d) => d,
+ Err(e) => {
+ panic!("`{}` is parsed into `{:?}`, but reparsing that has failed: {}", s, d, e)
+ }
+ };
+ assert!(
+ d == d_,
+ "`{}` is parsed into `{:?}`, but reparsed result \
+ `{:?}` does not match",
+ s,
+ d,
+ d_
+ );
+ }
+
+ // some invalid cases
+ // since `ParseErrorKind` is private, all we can do is to check if there was an error
+ assert!("".parse::<NaiveDateTime>().is_err());
+ assert!("x".parse::<NaiveDateTime>().is_err());
+ assert!("15".parse::<NaiveDateTime>().is_err());
+ assert!("15:8:9".parse::<NaiveDateTime>().is_err());
+ assert!("15-8-9".parse::<NaiveDateTime>().is_err());
+ assert!("2015-15-15T15:15:15".parse::<NaiveDateTime>().is_err());
+ assert!("2012-12-12T12:12:12x".parse::<NaiveDateTime>().is_err());
+ assert!("2012-123-12T12:12:12".parse::<NaiveDateTime>().is_err());
+ assert!("+ 82701-123-12T12:12:12".parse::<NaiveDateTime>().is_err());
+ assert!("+802701-123-12T12:12:12".parse::<NaiveDateTime>().is_err()); // out-of-bound
+}
+
+#[test]
+fn test_datetime_parse_from_str() {
+ let ymdhms =
+ |y, m, d, h, n, s| NaiveDate::from_ymd_opt(y, m, d).unwrap().and_hms_opt(h, n, s).unwrap();
+ let ymdhmsn = |y, m, d, h, n, s, nano| {
+ NaiveDate::from_ymd_opt(y, m, d).unwrap().and_hms_nano_opt(h, n, s, nano).unwrap()
+ };
+ assert_eq!(
+ NaiveDateTime::parse_from_str("2014-5-7T12:34:56+09:30", "%Y-%m-%dT%H:%M:%S%z"),
+ Ok(ymdhms(2014, 5, 7, 12, 34, 56))
+ ); // ignore offset
+ assert_eq!(
+ NaiveDateTime::parse_from_str("2015-W06-1 000000", "%G-W%V-%u%H%M%S"),
+ Ok(ymdhms(2015, 2, 2, 0, 0, 0))
+ );
+ assert_eq!(
+ NaiveDateTime::parse_from_str("Fri, 09 Aug 2013 23:54:35 GMT", "%a, %d %b %Y %H:%M:%S GMT"),
+ Ok(ymdhms(2013, 8, 9, 23, 54, 35))
+ );
+ assert!(NaiveDateTime::parse_from_str(
+ "Sat, 09 Aug 2013 23:54:35 GMT",
+ "%a, %d %b %Y %H:%M:%S GMT"
+ )
+ .is_err());
+ assert!(NaiveDateTime::parse_from_str("2014-5-7 12:3456", "%Y-%m-%d %H:%M:%S").is_err());
+ assert!(NaiveDateTime::parse_from_str("12:34:56", "%H:%M:%S").is_err()); // insufficient
+ assert_eq!(
+ NaiveDateTime::parse_from_str("1441497364", "%s"),
+ Ok(ymdhms(2015, 9, 5, 23, 56, 4))
+ );
+ assert_eq!(
+ NaiveDateTime::parse_from_str("1283929614.1234", "%s.%f"),
+ Ok(ymdhmsn(2010, 9, 8, 7, 6, 54, 1234))
+ );
+ assert_eq!(
+ NaiveDateTime::parse_from_str("1441497364.649", "%s%.3f"),
+ Ok(ymdhmsn(2015, 9, 5, 23, 56, 4, 649000000))
+ );
+ assert_eq!(
+ NaiveDateTime::parse_from_str("1497854303.087654", "%s%.6f"),
+ Ok(ymdhmsn(2017, 6, 19, 6, 38, 23, 87654000))
+ );
+ assert_eq!(
+ NaiveDateTime::parse_from_str("1437742189.918273645", "%s%.9f"),
+ Ok(ymdhmsn(2015, 7, 24, 12, 49, 49, 918273645))
+ );
+}
+
+#[test]
+fn test_datetime_format() {
+ let dt = NaiveDate::from_ymd_opt(2010, 9, 8).unwrap().and_hms_milli_opt(7, 6, 54, 321).unwrap();
+ assert_eq!(dt.format("%c").to_string(), "Wed Sep 8 07:06:54 2010");
+ assert_eq!(dt.format("%s").to_string(), "1283929614");
+ assert_eq!(dt.format("%t%n%%%n%t").to_string(), "\t\n%\n\t");
+
+ // a horror of leap second: coming near to you.
+ let dt =
+ NaiveDate::from_ymd_opt(2012, 6, 30).unwrap().and_hms_milli_opt(23, 59, 59, 1_000).unwrap();
+ assert_eq!(dt.format("%c").to_string(), "Sat Jun 30 23:59:60 2012");
+ assert_eq!(dt.format("%s").to_string(), "1341100799"); // not 1341100800, it's intentional.
+}
+
+#[test]
+fn test_datetime_add_sub_invariant() {
+ // issue #37
+ let base = NaiveDate::from_ymd_opt(2000, 1, 1).unwrap().and_hms_opt(0, 0, 0).unwrap();
+ let t = -946684799990000;
+ let time = base + Duration::microseconds(t);
+ assert_eq!(t, time.signed_duration_since(base).num_microseconds().unwrap());
+}
+
+#[test]
+fn test_nanosecond_range() {
+ const A_BILLION: i64 = 1_000_000_000;
+ let maximum = "2262-04-11T23:47:16.854775804";
+ let parsed: NaiveDateTime = maximum.parse().unwrap();
+ let nanos = parsed.timestamp_nanos();
+ assert_eq!(
+ parsed,
+ NaiveDateTime::from_timestamp_opt(nanos / A_BILLION, (nanos % A_BILLION) as u32).unwrap()
+ );
+
+ let minimum = "1677-09-21T00:12:44.000000000";
+ let parsed: NaiveDateTime = minimum.parse().unwrap();
+ let nanos = parsed.timestamp_nanos();
+ assert_eq!(
+ parsed,
+ NaiveDateTime::from_timestamp_opt(nanos / A_BILLION, (nanos % A_BILLION) as u32).unwrap()
+ );
+}
+
+#[test]
+fn test_and_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);
+ assert_eq!(dt_utc.timezone(), Utc);
+
+ let offset_tz = FixedOffset::west_opt(4 * 3600).unwrap();
+ let dt_offset = ndt.and_local_timezone(offset_tz).unwrap();
+ assert_eq!(dt_offset.naive_local(), ndt);
+ assert_eq!(dt_offset.timezone(), offset_tz);
+}
diff --git a/vendor/chrono/src/naive/internals.rs b/vendor/chrono/src/naive/internals.rs
index 346063c37..05305b506 100644
--- a/vendor/chrono/src/naive/internals.rs
+++ b/vendor/chrono/src/naive/internals.rs
@@ -13,19 +13,18 @@
//! but the conversion keeps the valid value valid and the invalid value invalid
//! so that the user-facing `NaiveDate` can validate the input as late as possible.
-#![allow(dead_code)] // some internal methods have been left for consistency
#![cfg_attr(feature = "__internal_bench", allow(missing_docs))]
+use crate::Weekday;
use core::{fmt, i32};
-use div::{div_rem, mod_floor};
+use num_integer::{div_rem, mod_floor};
use num_traits::FromPrimitive;
-use Weekday;
/// The internal date representation. This also includes the packed `Mdf` value.
-pub type DateImpl = i32;
+pub(super) type DateImpl = i32;
-pub const MAX_YEAR: DateImpl = i32::MAX >> 13;
-pub const MIN_YEAR: DateImpl = i32::MIN >> 13;
+pub(super) const MAX_YEAR: DateImpl = i32::MAX >> 13;
+pub(super) const MIN_YEAR: DateImpl = i32::MIN >> 13;
/// The year flags (aka the dominical letter).
///
@@ -35,23 +34,24 @@ pub const MIN_YEAR: DateImpl = i32::MIN >> 13;
/// where `a` is `1` for the common year (simplifies the `Of` validation)
/// and `bbb` is a non-zero `Weekday` (mapping `Mon` to 7) of the last day in the past year
/// (simplifies the day of week calculation from the 1-based ordinal).
-#[derive(PartialEq, Eq, Copy, Clone)]
-pub struct YearFlags(pub u8);
-
-pub const A: YearFlags = YearFlags(0o15);
-pub const AG: YearFlags = YearFlags(0o05);
-pub const B: YearFlags = YearFlags(0o14);
-pub const BA: YearFlags = YearFlags(0o04);
-pub const C: YearFlags = YearFlags(0o13);
-pub const CB: YearFlags = YearFlags(0o03);
-pub const D: YearFlags = YearFlags(0o12);
-pub const DC: YearFlags = YearFlags(0o02);
-pub const E: YearFlags = YearFlags(0o11);
-pub const ED: YearFlags = YearFlags(0o01);
-pub const F: YearFlags = YearFlags(0o17);
-pub const FE: YearFlags = YearFlags(0o07);
-pub const G: YearFlags = YearFlags(0o16);
-pub const GF: YearFlags = YearFlags(0o06);
+#[allow(unreachable_pub)] // public as an alias for benchmarks only
+#[derive(PartialEq, Eq, Copy, Clone, Hash)]
+pub struct YearFlags(pub(super) u8);
+
+pub(super) const A: YearFlags = YearFlags(0o15);
+pub(super) const AG: YearFlags = YearFlags(0o05);
+pub(super) const B: YearFlags = YearFlags(0o14);
+pub(super) const BA: YearFlags = YearFlags(0o04);
+pub(super) const C: YearFlags = YearFlags(0o13);
+pub(super) const CB: YearFlags = YearFlags(0o03);
+pub(super) const D: YearFlags = YearFlags(0o12);
+pub(super) const DC: YearFlags = YearFlags(0o02);
+pub(super) const E: YearFlags = YearFlags(0o11);
+pub(super) const ED: YearFlags = YearFlags(0o01);
+pub(super) const F: YearFlags = YearFlags(0o17);
+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] = [
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,
@@ -94,7 +94,7 @@ static YEAR_DELTAS: [u8; 401] = [
96, 97, 97, 97, 97, // 400+1
];
-pub fn cycle_to_yo(cycle: u32) -> (u32, u32) {
+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]);
if ordinal0 < delta {
@@ -106,11 +106,13 @@ pub fn cycle_to_yo(cycle: u32) -> (u32, u32) {
(year_mod_400, ordinal0 + 1)
}
-pub fn yo_to_cycle(year_mod_400: u32, ordinal: u32) -> u32 {
+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
}
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);
@@ -118,18 +120,18 @@ impl YearFlags {
}
#[inline]
- pub fn from_year_mod_400(year: i32) -> YearFlags {
+ pub(super) fn from_year_mod_400(year: i32) -> YearFlags {
YEAR_TO_FLAGS[year as usize]
}
#[inline]
- pub fn ndays(&self) -> u32 {
+ pub(super) fn ndays(&self) -> u32 {
let YearFlags(flags) = *self;
366 - u32::from(flags >> 3)
}
#[inline]
- pub fn isoweek_delta(&self) -> u32 {
+ pub(super) fn isoweek_delta(&self) -> u32 {
let YearFlags(flags) = *self;
let mut delta = u32::from(flags) & 0b0111;
if delta < 3 {
@@ -139,7 +141,7 @@ impl YearFlags {
}
#[inline]
- pub fn nisoweeks(&self) -> u32 {
+ pub(super) const fn nisoweeks(&self) -> u32 {
let YearFlags(flags) = *self;
52 + ((0b0000_0100_0000_0110 >> flags as usize) & 1)
}
@@ -170,10 +172,9 @@ impl fmt::Debug for YearFlags {
}
}
-pub const MIN_OL: u32 = 1 << 1;
-pub const MAX_OL: u32 = 366 << 1; // larger than the non-leap last day `(365 << 1) | 1`
-pub const MIN_MDL: u32 = (1 << 6) | (1 << 1);
-pub const MAX_MDL: u32 = (12 << 6) | (31 << 1) | 1;
+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_MDL: u32 = (12 << 6) | (31 << 1) | 1;
const XX: i8 = -128;
static MDL_TO_OL: [i8; MAX_MDL as usize + 1] = [
@@ -265,26 +266,19 @@ 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.
#[derive(PartialEq, PartialOrd, Copy, Clone)]
-pub struct Of(pub u32);
+pub(super) struct Of(pub(crate) u32);
impl Of {
#[inline]
- fn clamp_ordinal(ordinal: u32) -> u32 {
- if ordinal > 366 {
- 0
- } else {
- ordinal
+ pub(super) fn new(ordinal: u32, YearFlags(flags): YearFlags) -> Option<Of> {
+ match ordinal <= 366 {
+ true => Some(Of((ordinal << 4) | u32::from(flags))),
+ false => None,
}
}
#[inline]
- pub fn new(ordinal: u32, YearFlags(flags): YearFlags) -> Of {
- let ordinal = Of::clamp_ordinal(ordinal);
- Of((ordinal << 4) | u32::from(flags))
- }
-
- #[inline]
- pub fn from_mdf(Mdf(mdf): Mdf) -> Of {
+ pub(super) fn from_mdf(Mdf(mdf): Mdf) -> 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)),
@@ -293,64 +287,62 @@ impl Of {
}
#[inline]
- pub fn valid(&self) -> bool {
+ pub(super) fn valid(&self) -> bool {
let Of(of) = *self;
let ol = of >> 3;
- MIN_OL <= ol && ol <= MAX_OL
+ (MIN_OL..=MAX_OL).contains(&ol)
}
#[inline]
- pub fn ordinal(&self) -> u32 {
+ pub(super) const fn ordinal(&self) -> u32 {
let Of(of) = *self;
of >> 4
}
#[inline]
- pub fn with_ordinal(&self, ordinal: u32) -> Of {
- let ordinal = Of::clamp_ordinal(ordinal);
- let Of(of) = *self;
- Of((of & 0b1111) | (ordinal << 4))
- }
+ pub(super) fn with_ordinal(&self, ordinal: u32) -> Option<Of> {
+ if ordinal > 366 {
+ return None;
+ }
- #[inline]
- pub fn flags(&self) -> YearFlags {
let Of(of) = *self;
- YearFlags((of & 0b1111) as u8)
+ Some(Of((of & 0b1111) | (ordinal << 4)))
}
#[inline]
- pub fn with_flags(&self, YearFlags(flags): YearFlags) -> Of {
+ pub(super) const fn flags(&self) -> YearFlags {
let Of(of) = *self;
- Of((of & !0b1111) | u32::from(flags))
+ YearFlags((of & 0b1111) as u8)
}
#[inline]
- pub fn weekday(&self) -> Weekday {
+ pub(super) fn weekday(&self) -> Weekday {
let Of(of) = *self;
Weekday::from_u32(((of >> 4) + (of & 0b111)) % 7).unwrap()
}
#[inline]
- pub fn isoweekdate_raw(&self) -> (u32, Weekday) {
+ pub(super) fn isoweekdate_raw(&self) -> (u32, Weekday) {
// 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())
}
+ #[cfg_attr(feature = "cargo-clippy", allow(clippy::wrong_self_convention))]
#[inline]
- pub fn to_mdf(&self) -> Mdf {
+ pub(super) fn to_mdf(&self) -> Mdf {
Mdf::from_of(*self)
}
#[inline]
- pub fn succ(&self) -> Of {
+ pub(super) const fn succ(&self) -> Of {
let Of(of) = *self;
Of(of + (1 << 4))
}
#[inline]
- pub fn pred(&self) -> Of {
+ pub(super) const fn pred(&self) -> Of {
let Of(of) = *self;
Of(of - (1 << 4))
}
@@ -375,36 +367,19 @@ impl fmt::Debug for Of {
/// (month, day of month and leap flag),
/// which is an index to the `MDL_TO_OL` lookup table.
#[derive(PartialEq, PartialOrd, Copy, Clone)]
-pub struct Mdf(pub u32);
+pub(super) struct Mdf(pub(super) u32);
impl Mdf {
#[inline]
- fn clamp_month(month: u32) -> u32 {
- if month > 12 {
- 0
- } else {
- month
- }
- }
-
- #[inline]
- fn clamp_day(day: u32) -> u32 {
- if day > 31 {
- 0
- } else {
- day
+ 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))),
+ false => None,
}
}
#[inline]
- pub fn new(month: u32, day: u32, YearFlags(flags): YearFlags) -> Mdf {
- let month = Mdf::clamp_month(month);
- let day = Mdf::clamp_day(day);
- Mdf((month << 9) | (day << 4) | u32::from(flags))
- }
-
- #[inline]
- pub fn from_of(Of(of): Of) -> Mdf {
+ pub(super) 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)),
@@ -412,8 +387,8 @@ impl Mdf {
}
}
- #[inline]
- pub fn valid(&self) -> bool {
+ #[cfg(test)]
+ pub(super) fn valid(&self) -> bool {
let Mdf(mdf) = *self;
let mdl = mdf >> 3;
match MDL_TO_OL.get(mdl as usize) {
@@ -423,45 +398,46 @@ impl Mdf {
}
#[inline]
- pub fn month(&self) -> u32 {
+ pub(super) const fn month(&self) -> u32 {
let Mdf(mdf) = *self;
mdf >> 9
}
#[inline]
- pub fn with_month(&self, month: u32) -> Mdf {
- let month = Mdf::clamp_month(month);
+ pub(super) fn with_month(&self, month: u32) -> Option<Mdf> {
+ if month > 12 {
+ return None;
+ }
+
let Mdf(mdf) = *self;
- Mdf((mdf & 0b1_1111_1111) | (month << 9))
+ Some(Mdf((mdf & 0b1_1111_1111) | (month << 9)))
}
#[inline]
- pub fn day(&self) -> u32 {
+ pub(super) const fn day(&self) -> u32 {
let Mdf(mdf) = *self;
(mdf >> 4) & 0b1_1111
}
#[inline]
- pub fn with_day(&self, day: u32) -> Mdf {
- let day = Mdf::clamp_day(day);
- let Mdf(mdf) = *self;
- Mdf((mdf & !0b1_1111_0000) | (day << 4))
- }
+ pub(super) fn with_day(&self, day: u32) -> Option<Mdf> {
+ if day > 31 {
+ return None;
+ }
- #[inline]
- pub fn flags(&self) -> YearFlags {
let Mdf(mdf) = *self;
- YearFlags((mdf & 0b1111) as u8)
+ Some(Mdf((mdf & !0b1_1111_0000) | (day << 4)))
}
#[inline]
- pub fn with_flags(&self, YearFlags(flags): YearFlags) -> Mdf {
+ pub(super) fn with_flags(&self, YearFlags(flags): YearFlags) -> Mdf {
let Mdf(mdf) = *self;
Mdf((mdf & !0b1111) | u32::from(flags))
}
+ #[cfg_attr(feature = "cargo-clippy", allow(clippy::wrong_self_convention))]
#[inline]
- pub fn to_of(&self) -> Of {
+ pub(super) fn to_of(&self) -> Of {
Of::from_mdf(*self)
}
}
@@ -482,14 +458,12 @@ impl fmt::Debug for Mdf {
#[cfg(test)]
mod tests {
- #[cfg(test)]
- extern crate num_iter;
+ use num_iter::range_inclusive;
+ use std::u32;
- use self::num_iter::range_inclusive;
use super::{Mdf, Of};
use super::{YearFlags, A, AG, B, BA, C, CB, D, DC, E, ED, F, FE, G, GF};
- use std::u32;
- use Weekday;
+ use crate::Weekday;
const NONLEAP_FLAGS: [YearFlags; 7] = [A, B, C, D, E, F, G];
const LEAP_FLAGS: [YearFlags; 7] = [AG, BA, CB, DC, ED, FE, GF];
@@ -534,7 +508,12 @@ mod tests {
fn test_of() {
fn check(expected: bool, flags: YearFlags, ordinal1: u32, ordinal2: u32) {
for ordinal in range_inclusive(ordinal1, ordinal2) {
- let of = Of::new(ordinal, flags);
+ let of = match Of::new(ordinal, flags) {
+ Some(of) => of,
+ None if !expected => continue,
+ None => panic!("Of::new({}, {:?}) returned None", ordinal, flags),
+ };
+
assert!(
of.valid() == expected,
"ordinal {} = {:?} should be {} for dominical year {:?}",
@@ -566,7 +545,12 @@ mod tests {
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) {
- let mdf = Mdf::new(month, day, flags);
+ let mdf = match Mdf::new(month, day, flags) {
+ Some(mdf) => mdf,
+ None if !expected => continue,
+ None => panic!("Mdf::new({}, {}, {:?}) returned None", month, day, flags),
+ };
+
assert!(
mdf.valid() == expected,
"month {} day {} = {:?} should be {} for dominical year {:?}",
@@ -651,7 +635,7 @@ mod tests {
fn test_of_fields() {
for &flags in FLAGS.iter() {
for ordinal in range_inclusive(1u32, 366) {
- let of = Of::new(ordinal, flags);
+ let of = Of::new(ordinal, flags).unwrap();
if of.valid() {
assert_eq!(of.ordinal(), ordinal);
}
@@ -662,11 +646,16 @@ mod tests {
#[test]
fn test_of_with_fields() {
fn check(flags: YearFlags, ordinal: u32) {
- let of = Of::new(ordinal, flags);
+ let of = Of::new(ordinal, flags).unwrap();
for ordinal in range_inclusive(0u32, 1024) {
- let of = of.with_ordinal(ordinal);
- assert_eq!(of.valid(), Of::new(ordinal, flags).valid());
+ 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() {
assert_eq!(of.ordinal(), ordinal);
}
@@ -685,25 +674,25 @@ mod tests {
#[test]
fn test_of_weekday() {
- assert_eq!(Of::new(1, A).weekday(), Weekday::Sun);
- assert_eq!(Of::new(1, B).weekday(), Weekday::Sat);
- assert_eq!(Of::new(1, C).weekday(), Weekday::Fri);
- assert_eq!(Of::new(1, D).weekday(), Weekday::Thu);
- assert_eq!(Of::new(1, E).weekday(), Weekday::Wed);
- assert_eq!(Of::new(1, F).weekday(), Weekday::Tue);
- assert_eq!(Of::new(1, G).weekday(), Weekday::Mon);
- assert_eq!(Of::new(1, AG).weekday(), Weekday::Sun);
- assert_eq!(Of::new(1, BA).weekday(), Weekday::Sat);
- assert_eq!(Of::new(1, CB).weekday(), Weekday::Fri);
- assert_eq!(Of::new(1, DC).weekday(), Weekday::Thu);
- assert_eq!(Of::new(1, ED).weekday(), Weekday::Wed);
- assert_eq!(Of::new(1, FE).weekday(), Weekday::Tue);
- assert_eq!(Of::new(1, GF).weekday(), Weekday::Mon);
+ assert_eq!(Of::new(1, A).unwrap().weekday(), Weekday::Sun);
+ assert_eq!(Of::new(1, B).unwrap().weekday(), Weekday::Sat);
+ assert_eq!(Of::new(1, C).unwrap().weekday(), Weekday::Fri);
+ assert_eq!(Of::new(1, D).unwrap().weekday(), Weekday::Thu);
+ assert_eq!(Of::new(1, E).unwrap().weekday(), Weekday::Wed);
+ assert_eq!(Of::new(1, F).unwrap().weekday(), Weekday::Tue);
+ assert_eq!(Of::new(1, G).unwrap().weekday(), Weekday::Mon);
+ assert_eq!(Of::new(1, AG).unwrap().weekday(), Weekday::Sun);
+ assert_eq!(Of::new(1, BA).unwrap().weekday(), Weekday::Sat);
+ assert_eq!(Of::new(1, CB).unwrap().weekday(), Weekday::Fri);
+ assert_eq!(Of::new(1, DC).unwrap().weekday(), Weekday::Thu);
+ assert_eq!(Of::new(1, ED).unwrap().weekday(), Weekday::Wed);
+ assert_eq!(Of::new(1, FE).unwrap().weekday(), Weekday::Tue);
+ assert_eq!(Of::new(1, GF).unwrap().weekday(), Weekday::Mon);
for &flags in FLAGS.iter() {
- let mut prev = Of::new(1, flags).weekday();
+ let mut prev = Of::new(1, flags).unwrap().weekday();
for ordinal in range_inclusive(2u32, flags.ndays()) {
- let of = Of::new(ordinal, flags);
+ let of = Of::new(ordinal, flags).unwrap();
let expected = prev.succ();
assert_eq!(of.weekday(), expected);
prev = expected;
@@ -716,7 +705,11 @@ mod tests {
for &flags in FLAGS.iter() {
for month in range_inclusive(1u32, 12) {
for day in range_inclusive(1u32, 31) {
- let mdf = Mdf::new(month, day, flags);
+ let mdf = match Mdf::new(month, day, flags) {
+ Some(mdf) => mdf,
+ None => continue,
+ };
+
if mdf.valid() {
assert_eq!(mdf.month(), month);
assert_eq!(mdf.day(), day);
@@ -729,11 +722,15 @@ mod tests {
#[test]
fn test_mdf_with_fields() {
fn check(flags: YearFlags, month: u32, day: u32) {
- let mdf = Mdf::new(month, day, flags);
+ let mdf = Mdf::new(month, day, flags).unwrap();
for month in range_inclusive(0u32, 16) {
- let mdf = mdf.with_month(month);
- assert_eq!(mdf.valid(), Mdf::new(month, day, flags).valid());
+ let mdf = match mdf.with_month(month) {
+ Some(mdf) => mdf,
+ None if month > 12 => continue,
+ None => panic!("failed to create Mdf with month {}", month),
+ };
+
if mdf.valid() {
assert_eq!(mdf.month(), month);
assert_eq!(mdf.day(), day);
@@ -741,8 +738,12 @@ mod tests {
}
for day in range_inclusive(0u32, 1024) {
- let mdf = mdf.with_day(day);
- assert_eq!(mdf.valid(), Mdf::new(month, day, flags).valid());
+ let mdf = match mdf.with_day(day) {
+ Some(mdf) => mdf,
+ None if day > 31 => continue,
+ None => panic!("failed to create Mdf with month {}", month),
+ };
+
if mdf.valid() {
assert_eq!(mdf.month(), month);
assert_eq!(mdf.day(), day);
@@ -772,7 +773,7 @@ mod tests {
fn test_of_isoweekdate_raw() {
for &flags in FLAGS.iter() {
// January 4 should be in the first week
- let (week, _) = Of::new(4 /* January 4 */, flags).isoweekdate_raw();
+ let (week, _) = Of::new(4 /* January 4 */, flags).unwrap().isoweekdate_raw();
assert_eq!(week, 1);
}
}
diff --git a/vendor/chrono/src/naive/isoweek.rs b/vendor/chrono/src/naive/isoweek.rs
index ece10f250..6a4fcfd11 100644
--- a/vendor/chrono/src/naive/isoweek.rs
+++ b/vendor/chrono/src/naive/isoweek.rs
@@ -7,13 +7,17 @@ use core::fmt;
use super::internals::{DateImpl, Of, YearFlags};
+#[cfg(feature = "rkyv")]
+use rkyv::{Archive, Deserialize, Serialize};
+
/// ISO 8601 week.
///
/// This type, combined with [`Weekday`](../enum.Weekday.html),
-/// constitues the ISO 8601 [week date](./struct.NaiveDate.html#week-date).
+/// constitutes the ISO 8601 [week date](./struct.NaiveDate.html#week-date).
/// One can retrieve this type from the existing [`Datelike`](../trait.Datelike.html) types
/// via the [`Datelike::iso_week`](../trait.Datelike.html#tymethod.iso_week) method.
-#[derive(PartialEq, Eq, PartialOrd, Ord, Copy, Clone)]
+#[derive(PartialEq, Eq, PartialOrd, Ord, Copy, Clone, Hash)]
+#[cfg_attr(feature = "rkyv", derive(Archive, Deserialize, Serialize))]
pub struct IsoWeek {
// note that this allows for larger year range than `NaiveDate`.
// this is crucial because we have an edge case for the first and last week supported,
@@ -27,7 +31,7 @@ pub struct IsoWeek {
// because the year range for the week date and the calendar date do not match and
// it is confusing to have a date that is out of range in one and not in another.
// currently we sidestep this issue by making `IsoWeek` fully dependent of `Datelike`.
-pub fn iso_week_from_yof(year: i32, of: Of) -> IsoWeek {
+pub(super) fn iso_week_from_yof(year: i32, of: Of) -> IsoWeek {
let (rawweek, _) = of.isoweekdate_raw();
let (year, week) = if rawweek < 1 {
// previous year
@@ -50,24 +54,24 @@ impl IsoWeek {
///
/// # Example
///
- /// ~~~~
+ /// ```
/// use chrono::{NaiveDate, Datelike, Weekday};
///
/// let d = NaiveDate::from_isoywd(2015, 1, Weekday::Mon);
/// assert_eq!(d.iso_week().year(), 2015);
- /// ~~~~
+ /// ```
///
/// This year number might not match the calendar year number.
/// Continuing the example...
///
- /// ~~~~
+ /// ```
/// # use chrono::{NaiveDate, Datelike, Weekday};
/// # let d = NaiveDate::from_isoywd(2015, 1, Weekday::Mon);
/// assert_eq!(d.year(), 2014);
- /// assert_eq!(d, NaiveDate::from_ymd(2014, 12, 29));
- /// ~~~~
+ /// assert_eq!(d, NaiveDate::from_ymd_opt(2014, 12, 29).unwrap());
+ /// ```
#[inline]
- pub fn year(&self) -> i32 {
+ pub const fn year(&self) -> i32 {
self.ywf >> 10
}
@@ -77,14 +81,14 @@ impl IsoWeek {
///
/// # Example
///
- /// ~~~~
+ /// ```
/// use chrono::{NaiveDate, Datelike, Weekday};
///
/// let d = NaiveDate::from_isoywd(2015, 15, Weekday::Mon);
/// assert_eq!(d.iso_week().week(), 15);
- /// ~~~~
+ /// ```
#[inline]
- pub fn week(&self) -> u32 {
+ pub const fn week(&self) -> u32 {
((self.ywf >> 4) & 0x3f) as u32
}
@@ -94,14 +98,14 @@ impl IsoWeek {
///
/// # Example
///
- /// ~~~~
+ /// ```
/// use chrono::{NaiveDate, Datelike, Weekday};
///
/// let d = NaiveDate::from_isoywd(2015, 15, Weekday::Mon);
/// assert_eq!(d.iso_week().week0(), 14);
- /// ~~~~
+ /// ```
#[inline]
- pub fn week0(&self) -> u32 {
+ pub const fn week0(&self) -> u32 {
((self.ywf >> 4) & 0x3f) as u32 - 1
}
}
@@ -112,26 +116,26 @@ impl IsoWeek {
///
/// # Example
///
-/// ~~~~
+/// ```
/// use chrono::{NaiveDate, Datelike};
///
-/// assert_eq!(format!("{:?}", NaiveDate::from_ymd(2015, 9, 5).iso_week()), "2015-W36");
-/// assert_eq!(format!("{:?}", NaiveDate::from_ymd( 0, 1, 3).iso_week()), "0000-W01");
-/// assert_eq!(format!("{:?}", NaiveDate::from_ymd(9999, 12, 31).iso_week()), "9999-W52");
-/// ~~~~
+/// assert_eq!(format!("{:?}", NaiveDate::from_ymd_opt(2015, 9, 5).unwrap().iso_week()), "2015-W36");
+/// assert_eq!(format!("{:?}", NaiveDate::from_ymd_opt( 0, 1, 3).unwrap().iso_week()), "0000-W01");
+/// assert_eq!(format!("{:?}", NaiveDate::from_ymd_opt(9999, 12, 31).unwrap().iso_week()), "9999-W52");
+/// ```
///
/// ISO 8601 requires an explicit sign for years before 1 BCE or after 9999 CE.
///
-/// ~~~~
+/// ```
/// # use chrono::{NaiveDate, Datelike};
-/// assert_eq!(format!("{:?}", NaiveDate::from_ymd( 0, 1, 2).iso_week()), "-0001-W52");
-/// assert_eq!(format!("{:?}", NaiveDate::from_ymd(10000, 12, 31).iso_week()), "+10000-W52");
-/// ~~~~
+/// assert_eq!(format!("{:?}", NaiveDate::from_ymd_opt( 0, 1, 2).unwrap().iso_week()), "-0001-W52");
+/// assert_eq!(format!("{:?}", NaiveDate::from_ymd_opt(10000, 12, 31).unwrap().iso_week()), "+10000-W52");
+/// ```
impl fmt::Debug for IsoWeek {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let year = self.year();
let week = self.week();
- if 0 <= year && year <= 9999 {
+ if (0..=9999).contains(&year) {
write!(f, "{:04}-W{:02}", year, week)
} else {
// ISO 8601 requires the explicit sign for out-of-range years
@@ -142,22 +146,22 @@ impl fmt::Debug for IsoWeek {
#[cfg(test)]
mod tests {
- use naive::{internals, MAX_DATE, MIN_DATE};
- use Datelike;
+ use crate::naive::{internals, NaiveDate};
+ use crate::Datelike;
#[test]
fn test_iso_week_extremes() {
- let minweek = MIN_DATE.iso_week();
- let maxweek = MAX_DATE.iso_week();
+ let minweek = NaiveDate::MIN.iso_week();
+ let maxweek = NaiveDate::MAX.iso_week();
assert_eq!(minweek.year(), internals::MIN_YEAR);
assert_eq!(minweek.week(), 1);
assert_eq!(minweek.week0(), 0);
- assert_eq!(format!("{:?}", minweek), MIN_DATE.format("%G-W%V").to_string());
+ assert_eq!(format!("{:?}", minweek), NaiveDate::MIN.format("%G-W%V").to_string());
assert_eq!(maxweek.year(), internals::MAX_YEAR + 1);
assert_eq!(maxweek.week(), 1);
assert_eq!(maxweek.week0(), 0);
- assert_eq!(format!("{:?}", maxweek), MAX_DATE.format("%G-W%V").to_string());
+ assert_eq!(format!("{:?}", maxweek), NaiveDate::MAX.format("%G-W%V").to_string());
}
}
diff --git a/vendor/chrono/src/naive/mod.rs b/vendor/chrono/src/naive/mod.rs
new file mode 100644
index 000000000..c41acba8d
--- /dev/null
+++ b/vendor/chrono/src/naive/mod.rs
@@ -0,0 +1,39 @@
+//! Date and time types unconcerned with timezones.
+//!
+//! They are primarily building blocks for other types
+//! (e.g. [`TimeZone`](../offset/trait.TimeZone.html)),
+//! but can be also used for the simpler date and time handling.
+
+mod date;
+pub(crate) mod datetime;
+mod internals;
+mod isoweek;
+mod time;
+
+#[allow(deprecated)]
+pub use self::date::{Days, NaiveDate, NaiveWeek, MAX_DATE, MIN_DATE};
+#[cfg(feature = "rustc-serialize")]
+#[allow(deprecated)]
+pub use self::datetime::rustc_serialize::TsSeconds;
+#[allow(deprecated)]
+pub use self::datetime::{NaiveDateTime, MAX_DATETIME, MIN_DATETIME};
+pub use self::isoweek::IsoWeek;
+pub use self::time::NaiveTime;
+
+#[cfg(feature = "__internal_bench")]
+#[doc(hidden)]
+pub use self::internals::YearFlags as __BenchYearFlags;
+
+/// Serialization/Deserialization of naive types in alternate formats
+///
+/// The various modules in here are intended to be used with serde's [`with`
+/// annotation][1] to serialize as something other than the default [RFC
+/// 3339][2] format.
+///
+/// [1]: https://serde.rs/attributes.html#field-attributes
+/// [2]: https://tools.ietf.org/html/rfc3339
+#[cfg(feature = "serde")]
+#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
+pub mod serde {
+ pub use super::datetime::serde::*;
+}
diff --git a/vendor/chrono/src/naive/time.rs b/vendor/chrono/src/naive/time/mod.rs
index 1ddc9fbed..1d36583aa 100644
--- a/vendor/chrono/src/naive/time.rs
+++ b/vendor/chrono/src/naive/time/mod.rs
@@ -6,18 +6,27 @@
#[cfg(any(feature = "alloc", feature = "std", test))]
use core::borrow::Borrow;
use core::ops::{Add, AddAssign, Sub, SubAssign};
-use core::{fmt, hash, str};
-use oldtime::Duration as OldDuration;
+use core::{fmt, str};
+
+use num_integer::div_mod_floor;
+#[cfg(feature = "rkyv")]
+use rkyv::{Archive, Deserialize, Serialize};
-use div::div_mod_floor;
#[cfg(any(feature = "alloc", feature = "std", test))]
-use format::DelayedFormat;
-use format::{parse, ParseError, ParseResult, Parsed, StrftimeItems};
-use format::{Fixed, Item, Numeric, Pad};
-use Timelike;
+use crate::format::DelayedFormat;
+use crate::format::{parse, write_hundreds, ParseError, ParseResult, Parsed, StrftimeItems};
+use crate::format::{Fixed, Item, Numeric, Pad};
+use crate::oldtime::Duration as OldDuration;
+use crate::Timelike;
-pub const MIN_TIME: NaiveTime = NaiveTime { secs: 0, frac: 0 };
-pub const MAX_TIME: NaiveTime = NaiveTime { secs: 23 * 3600 + 59 * 60 + 59, frac: 999_999_999 };
+#[cfg(feature = "rustc-serialize")]
+mod rustc_serialize;
+
+#[cfg(feature = "serde")]
+mod serde;
+
+#[cfg(test)]
+mod tests;
/// ISO 8601 time without timezone.
/// Allows for the nanosecond precision and optional leap second representation.
@@ -64,16 +73,16 @@ pub const MAX_TIME: NaiveTime = NaiveTime { secs: 23 * 3600 + 59 * 60 + 59, frac
///
/// All methods accepting fractional seconds will accept such values.
///
-/// ~~~~
+/// ```
/// use chrono::{NaiveDate, NaiveTime, Utc, TimeZone};
///
-/// let t = NaiveTime::from_hms_milli(8, 59, 59, 1_000);
+/// let t = NaiveTime::from_hms_milli_opt(8, 59, 59, 1_000).unwrap();
///
-/// let dt1 = NaiveDate::from_ymd(2015, 7, 1).and_hms_micro(8, 59, 59, 1_000_000);
+/// let dt1 = NaiveDate::from_ymd_opt(2015, 7, 1).unwrap().and_hms_micro_opt(8, 59, 59, 1_000_000).unwrap();
///
-/// let dt2 = Utc.ymd(2015, 6, 30).and_hms_nano(23, 59, 59, 1_000_000_000);
+/// let dt2 = NaiveDate::from_ymd_opt(2015, 6, 30).unwrap().and_hms_nano_opt(23, 59, 59, 1_000_000_000).unwrap().and_local_timezone(Utc).unwrap();
/// # let _ = (t, dt1, dt2);
-/// ~~~~
+/// ```
///
/// Note that the leap second can happen anytime given an appropriate time zone;
/// 2015-07-01 01:23:60 would be a proper leap second if UTC+01:24 had existed.
@@ -151,12 +160,12 @@ pub const MAX_TIME: NaiveTime = NaiveTime { secs: 23 * 3600 + 59 * 60 + 59, frac
/// The leap second in the human-readable representation
/// will be represented as the second part being 60, as required by ISO 8601.
///
-/// ~~~~
-/// use chrono::{Utc, TimeZone};
+/// ```
+/// use chrono::{Utc, TimeZone, NaiveDate};
///
-/// let dt = Utc.ymd(2015, 6, 30).and_hms_milli(23, 59, 59, 1_000);
+/// 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");
-/// ~~~~
+/// ```
///
/// There are hypothetical leap seconds not on the minute boundary
/// nevertheless supported by Chrono.
@@ -165,25 +174,37 @@ pub const MAX_TIME: NaiveTime = NaiveTime { secs: 23 * 3600 + 59 * 60 + 59, frac
/// For such cases the human-readable representation is ambiguous
/// and would be read back to the next non-leap second.
///
-/// ~~~~
-/// use chrono::{DateTime, Utc, TimeZone};
+/// ```
+/// use chrono::{DateTime, Utc, TimeZone, NaiveDate};
///
-/// let dt = Utc.ymd(2015, 6, 30).and_hms_milli(23, 56, 4, 1_000);
+/// let dt = NaiveDate::from_ymd_opt(2015, 6, 30).unwrap().and_hms_milli_opt(23, 56, 4, 1_000).unwrap().and_local_timezone(Utc).unwrap();
/// assert_eq!(format!("{:?}", dt), "2015-06-30T23:56:05Z");
///
-/// let dt = Utc.ymd(2015, 6, 30).and_hms(23, 56, 5);
+/// let dt = Utc.with_ymd_and_hms(2015, 6, 30, 23, 56, 5).unwrap();
/// assert_eq!(format!("{:?}", dt), "2015-06-30T23:56:05Z");
/// assert_eq!(DateTime::parse_from_rfc3339("2015-06-30T23:56:05Z").unwrap(), dt);
-/// ~~~~
+/// ```
///
/// Since Chrono alone cannot determine any existence of leap seconds,
/// **there is absolutely no guarantee that the leap second read has actually happened**.
-#[derive(PartialEq, Eq, PartialOrd, Ord, Copy, Clone)]
+#[derive(PartialEq, Eq, Hash, PartialOrd, Ord, Copy, Clone)]
+#[cfg_attr(feature = "rkyv", derive(Archive, Deserialize, Serialize))]
pub struct NaiveTime {
secs: u32,
frac: u32,
}
+#[cfg(feature = "arbitrary")]
+impl arbitrary::Arbitrary<'_> for NaiveTime {
+ fn arbitrary(u: &mut arbitrary::Unstructured) -> arbitrary::Result<NaiveTime> {
+ let secs = u.int_in_range(0..=86_399)?;
+ let nano = u.int_in_range(0..=1_999_999_999)?;
+ let time = NaiveTime::from_num_seconds_from_midnight_opt(secs, nano)
+ .expect("Could not generate a valid chrono::NaiveTime. It looks like implementation of Arbitrary for NaiveTime is erroneous.");
+ Ok(time)
+ }
+}
+
impl NaiveTime {
/// Makes a new `NaiveTime` from hour, minute and second.
///
@@ -191,18 +212,7 @@ impl NaiveTime {
/// use `NaiveTime::from_hms_*` methods with a subsecond parameter instead.
///
/// Panics on invalid hour, minute and/or second.
- ///
- /// # Example
- ///
- /// ~~~~
- /// use chrono::{NaiveTime, Timelike};
- ///
- /// let t = NaiveTime::from_hms(23, 56, 4);
- /// assert_eq!(t.hour(), 23);
- /// assert_eq!(t.minute(), 56);
- /// assert_eq!(t.second(), 4);
- /// assert_eq!(t.nanosecond(), 0);
- /// ~~~~
+ #[deprecated(since = "0.4.23", note = "use `from_hms_opt()` instead")]
#[inline]
pub fn from_hms(hour: u32, min: u32, sec: u32) -> NaiveTime {
NaiveTime::from_hms_opt(hour, min, sec).expect("invalid time")
@@ -217,7 +227,7 @@ impl NaiveTime {
///
/// # Example
///
- /// ~~~~
+ /// ```
/// use chrono::NaiveTime;
///
/// let from_hms_opt = NaiveTime::from_hms_opt;
@@ -227,7 +237,7 @@ impl NaiveTime {
/// assert!(from_hms_opt(24, 0, 0).is_none());
/// assert!(from_hms_opt(23, 60, 0).is_none());
/// assert!(from_hms_opt(23, 59, 60).is_none());
- /// ~~~~
+ /// ```
#[inline]
pub fn from_hms_opt(hour: u32, min: u32, sec: u32) -> Option<NaiveTime> {
NaiveTime::from_hms_nano_opt(hour, min, sec, 0)
@@ -239,18 +249,7 @@ impl NaiveTime {
/// in order to represent the [leap second](#leap-second-handling).
///
/// Panics on invalid hour, minute, second and/or millisecond.
- ///
- /// # Example
- ///
- /// ~~~~
- /// use chrono::{NaiveTime, Timelike};
- ///
- /// let t = NaiveTime::from_hms_milli(23, 56, 4, 12);
- /// assert_eq!(t.hour(), 23);
- /// assert_eq!(t.minute(), 56);
- /// assert_eq!(t.second(), 4);
- /// assert_eq!(t.nanosecond(), 12_000_000);
- /// ~~~~
+ #[deprecated(since = "0.4.23", note = "use `from_hms_milli_opt()` instead")]
#[inline]
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")
@@ -265,7 +264,7 @@ impl NaiveTime {
///
/// # Example
///
- /// ~~~~
+ /// ```
/// use chrono::NaiveTime;
///
/// let from_hmsm_opt = NaiveTime::from_hms_milli_opt;
@@ -277,7 +276,7 @@ impl NaiveTime {
/// assert!(from_hmsm_opt(23, 60, 0, 0).is_none());
/// assert!(from_hmsm_opt(23, 59, 60, 0).is_none());
/// assert!(from_hmsm_opt(23, 59, 59, 2_000).is_none());
- /// ~~~~
+ /// ```
#[inline]
pub fn from_hms_milli_opt(hour: u32, min: u32, sec: u32, milli: u32) -> Option<NaiveTime> {
milli
@@ -291,18 +290,7 @@ impl NaiveTime {
/// in order to represent the [leap second](#leap-second-handling).
///
/// Panics on invalid hour, minute, second and/or microsecond.
- ///
- /// # Example
- ///
- /// ~~~~
- /// use chrono::{NaiveTime, Timelike};
- ///
- /// let t = NaiveTime::from_hms_micro(23, 56, 4, 12_345);
- /// assert_eq!(t.hour(), 23);
- /// assert_eq!(t.minute(), 56);
- /// assert_eq!(t.second(), 4);
- /// assert_eq!(t.nanosecond(), 12_345_000);
- /// ~~~~
+ #[deprecated(since = "0.4.23", note = "use `from_hms_micro_opt()` instead")]
#[inline]
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")
@@ -317,7 +305,7 @@ impl NaiveTime {
///
/// # Example
///
- /// ~~~~
+ /// ```
/// use chrono::NaiveTime;
///
/// let from_hmsu_opt = NaiveTime::from_hms_micro_opt;
@@ -329,7 +317,7 @@ impl NaiveTime {
/// assert!(from_hmsu_opt(23, 60, 0, 0).is_none());
/// assert!(from_hmsu_opt(23, 59, 60, 0).is_none());
/// assert!(from_hmsu_opt(23, 59, 59, 2_000_000).is_none());
- /// ~~~~
+ /// ```
#[inline]
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))
@@ -341,18 +329,7 @@ impl NaiveTime {
/// in order to represent the [leap second](#leap-second-handling).
///
/// Panics on invalid hour, minute, second and/or nanosecond.
- ///
- /// # Example
- ///
- /// ~~~~
- /// use chrono::{NaiveTime, Timelike};
- ///
- /// let t = NaiveTime::from_hms_nano(23, 56, 4, 12_345_678);
- /// assert_eq!(t.hour(), 23);
- /// assert_eq!(t.minute(), 56);
- /// assert_eq!(t.second(), 4);
- /// assert_eq!(t.nanosecond(), 12_345_678);
- /// ~~~~
+ #[deprecated(since = "0.4.23", note = "use `from_hms_nano_opt()` instead")]
#[inline]
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")
@@ -367,7 +344,7 @@ impl NaiveTime {
///
/// # Example
///
- /// ~~~~
+ /// ```
/// use chrono::NaiveTime;
///
/// let from_hmsn_opt = NaiveTime::from_hms_nano_opt;
@@ -379,14 +356,14 @@ impl NaiveTime {
/// assert!(from_hmsn_opt(23, 60, 0, 0).is_none());
/// assert!(from_hmsn_opt(23, 59, 60, 0).is_none());
/// 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> {
if hour >= 24 || min >= 60 || sec >= 60 || nano >= 2_000_000_000 {
return None;
}
let secs = hour * 3600 + min * 60 + sec;
- Some(NaiveTime { secs: secs, frac: nano })
+ Some(NaiveTime { secs, frac: nano })
}
/// Makes a new `NaiveTime` from the number of seconds since midnight and nanosecond.
@@ -395,18 +372,7 @@ impl NaiveTime {
/// in order to represent the [leap second](#leap-second-handling).
///
/// Panics on invalid number of seconds and/or nanosecond.
- ///
- /// # Example
- ///
- /// ~~~~
- /// use chrono::{NaiveTime, Timelike};
- ///
- /// let t = NaiveTime::from_num_seconds_from_midnight(86164, 12_345_678);
- /// assert_eq!(t.hour(), 23);
- /// assert_eq!(t.minute(), 56);
- /// assert_eq!(t.second(), 4);
- /// assert_eq!(t.nanosecond(), 12_345_678);
- /// ~~~~
+ #[deprecated(since = "0.4.23", note = "use `from_num_seconds_from_midnight_opt()` instead")]
#[inline]
pub fn from_num_seconds_from_midnight(secs: u32, nano: u32) -> NaiveTime {
NaiveTime::from_num_seconds_from_midnight_opt(secs, nano).expect("invalid time")
@@ -421,7 +387,7 @@ impl NaiveTime {
///
/// # Example
///
- /// ~~~~
+ /// ```
/// use chrono::NaiveTime;
///
/// let from_nsecs_opt = NaiveTime::from_num_seconds_from_midnight_opt;
@@ -431,13 +397,13 @@ impl NaiveTime {
/// assert!(from_nsecs_opt(86399, 1_999_999_999).is_some()); // a leap second after 23:59:59
/// assert!(from_nsecs_opt(86_400, 0).is_none());
/// 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> {
if secs >= 86_400 || nano >= 2_000_000_000 {
return None;
}
- Some(NaiveTime { secs: secs, frac: nano })
+ Some(NaiveTime { secs, frac: nano })
}
/// Parses a string with the specified format string and returns a new `NaiveTime`.
@@ -446,61 +412,61 @@ impl NaiveTime {
///
/// # Example
///
- /// ~~~~
+ /// ```
/// use chrono::NaiveTime;
///
/// let parse_from_str = NaiveTime::parse_from_str;
///
/// assert_eq!(parse_from_str("23:56:04", "%H:%M:%S"),
- /// Ok(NaiveTime::from_hms(23, 56, 4)));
+ /// Ok(NaiveTime::from_hms_opt(23, 56, 4).unwrap()));
/// assert_eq!(parse_from_str("pm012345.6789", "%p%I%M%S%.f"),
- /// Ok(NaiveTime::from_hms_micro(13, 23, 45, 678_900)));
- /// ~~~~
+ /// Ok(NaiveTime::from_hms_micro_opt(13, 23, 45, 678_900).unwrap()));
+ /// ```
///
/// Date and offset is ignored for the purpose of parsing.
///
- /// ~~~~
+ /// ```
/// # use chrono::NaiveTime;
/// # let parse_from_str = NaiveTime::parse_from_str;
/// assert_eq!(parse_from_str("2014-5-17T12:34:56+09:30", "%Y-%m-%dT%H:%M:%S%z"),
- /// Ok(NaiveTime::from_hms(12, 34, 56)));
- /// ~~~~
+ /// Ok(NaiveTime::from_hms_opt(12, 34, 56).unwrap()));
+ /// ```
///
/// [Leap seconds](#leap-second-handling) are correctly handled by
/// treating any time of the form `hh:mm:60` as a leap second.
/// (This equally applies to the formatting, so the round trip is possible.)
///
- /// ~~~~
+ /// ```
/// # use chrono::NaiveTime;
/// # let parse_from_str = NaiveTime::parse_from_str;
/// assert_eq!(parse_from_str("08:59:60.123", "%H:%M:%S%.f"),
- /// Ok(NaiveTime::from_hms_milli(8, 59, 59, 1_123)));
- /// ~~~~
+ /// Ok(NaiveTime::from_hms_milli_opt(8, 59, 59, 1_123).unwrap()));
+ /// ```
///
/// Missing seconds are assumed to be zero,
/// but out-of-bound times or insufficient fields are errors otherwise.
///
- /// ~~~~
+ /// ```
/// # use chrono::NaiveTime;
/// # let parse_from_str = NaiveTime::parse_from_str;
/// assert_eq!(parse_from_str("7:15", "%H:%M"),
- /// Ok(NaiveTime::from_hms(7, 15, 0)));
+ /// Ok(NaiveTime::from_hms_opt(7, 15, 0).unwrap()));
///
/// assert!(parse_from_str("04m33s", "%Mm%Ss").is_err());
/// assert!(parse_from_str("12", "%H").is_err());
/// assert!(parse_from_str("17:60", "%H:%M").is_err());
/// assert!(parse_from_str("24:00:00", "%H:%M:%S").is_err());
- /// ~~~~
+ /// ```
///
/// All parsed fields should be consistent to each other, otherwise it's an error.
/// Here `%H` is for 24-hour clocks, unlike `%I`,
/// and thus can be independently determined without AM/PM.
///
- /// ~~~~
+ /// ```
/// # use chrono::NaiveTime;
/// # let parse_from_str = NaiveTime::parse_from_str;
/// assert!(parse_from_str("13:07 AM", "%H:%M %p").is_err());
- /// ~~~~
+ /// ```
pub fn parse_from_str(s: &str, fmt: &str) -> ParseResult<NaiveTime> {
let mut parsed = Parsed::new();
parse(&mut parsed, s, StrftimeItems::new(fmt))?;
@@ -514,8 +480,7 @@ impl NaiveTime {
///
/// # Example
///
- /// ~~~~
- /// # extern crate chrono; fn main() {
+ /// ```
/// use chrono::{Duration, NaiveTime};
///
/// let from_hms = NaiveTime::from_hms;
@@ -526,9 +491,7 @@ impl NaiveTime {
/// (from_hms(2, 4, 5), 86_400));
/// assert_eq!(from_hms(3, 4, 5).overflowing_add_signed(Duration::hours(-7)),
/// (from_hms(20, 4, 5), -86_400));
- /// # }
- /// ~~~~
- #[cfg_attr(feature = "cargo-clippy", allow(cyclomatic_complexity))]
+ /// ```
pub fn overflowing_add_signed(&self, mut rhs: OldDuration) -> (NaiveTime, i64) {
let mut secs = self.secs;
let mut frac = self.frac;
@@ -548,7 +511,7 @@ impl NaiveTime {
} else {
frac = (i64::from(frac) + rhs.num_nanoseconds().unwrap()) as u32;
debug_assert!(frac < 2_000_000_000);
- return (NaiveTime { secs: secs, frac: frac }, 0);
+ return (NaiveTime { secs, frac }, 0);
}
}
debug_assert!(secs <= 86_400);
@@ -577,8 +540,8 @@ impl NaiveTime {
frac -= 1_000_000_000;
secs += 1;
}
- debug_assert!(-86_400 <= secs && secs < 2 * 86_400);
- debug_assert!(0 <= frac && frac < 1_000_000_000);
+ debug_assert!((-86_400..2 * 86_400).contains(&secs));
+ debug_assert!((0..1_000_000_000).contains(&frac));
if secs < 0 {
secs += 86_400;
@@ -587,7 +550,7 @@ impl NaiveTime {
secs -= 86_400;
morerhssecs += 86_400;
}
- debug_assert!(0 <= secs && secs < 86_400);
+ debug_assert!((0..86_400).contains(&secs));
(NaiveTime { secs: secs as u32, frac: frac as u32 }, morerhssecs)
}
@@ -599,8 +562,7 @@ impl NaiveTime {
///
/// # Example
///
- /// ~~~~
- /// # extern crate chrono; fn main() {
+ /// ```
/// use chrono::{Duration, NaiveTime};
///
/// let from_hms = NaiveTime::from_hms;
@@ -611,8 +573,7 @@ impl NaiveTime {
/// (from_hms(10, 4, 5), 86_400));
/// assert_eq!(from_hms(3, 4, 5).overflowing_sub_signed(Duration::hours(-22)),
/// (from_hms(1, 4, 5), -86_400));
- /// # }
- /// ~~~~
+ /// ```
#[inline]
pub fn overflowing_sub_signed(&self, rhs: OldDuration) -> (NaiveTime, i64) {
let (time, rhs) = self.overflowing_add_signed(-rhs);
@@ -631,8 +592,7 @@ impl NaiveTime {
///
/// # Example
///
- /// ~~~~
- /// # extern crate chrono; fn main() {
+ /// ```
/// use chrono::{Duration, NaiveTime};
///
/// let from_hmsm = NaiveTime::from_hms_milli;
@@ -654,14 +614,12 @@ impl NaiveTime {
/// Duration::seconds(-3600));
/// assert_eq!(since(from_hmsm(3, 5, 7, 900), from_hmsm(2, 4, 6, 800)),
/// Duration::seconds(3600 + 60 + 1) + Duration::milliseconds(100));
- /// # }
- /// ~~~~
+ /// ```
///
/// Leap seconds are handled, but the subtraction assumes that
/// there were no other leap seconds happened.
///
- /// ~~~~
- /// # extern crate chrono; fn main() {
+ /// ```
/// # use chrono::{Duration, NaiveTime};
/// # let from_hmsm = NaiveTime::from_hms_milli;
/// # let since = NaiveTime::signed_duration_since;
@@ -675,8 +633,7 @@ impl NaiveTime {
/// Duration::seconds(1));
/// assert_eq!(since(from_hmsm(3, 0, 59, 1_000), from_hmsm(2, 59, 59, 1_000)),
/// Duration::seconds(61));
- /// # }
- /// ~~~~
+ /// ```
pub fn signed_duration_since(self, rhs: NaiveTime) -> OldDuration {
// | | :leap| | | | | | | :leap| |
// | | : | | | | | | | : | |
@@ -695,13 +652,7 @@ impl NaiveTime {
// `secs` may contain a leap second yet to be counted
let adjust = match self.secs.cmp(&rhs.secs) {
- Ordering::Greater => {
- if rhs.frac >= 1_000_000_000 {
- 1
- } else {
- 0
- }
- }
+ Ordering::Greater => i64::from(rhs.frac >= 1_000_000_000),
Ordering::Equal => 0,
Ordering::Less => {
if self.frac >= 1_000_000_000 {
@@ -723,26 +674,27 @@ impl NaiveTime {
///
/// # Example
///
- /// ~~~~
+ /// ```
/// use chrono::NaiveTime;
/// use chrono::format::strftime::StrftimeItems;
///
/// let fmt = StrftimeItems::new("%H:%M:%S");
- /// let t = NaiveTime::from_hms(23, 56, 4);
+ /// let t = NaiveTime::from_hms_opt(23, 56, 4).unwrap();
/// assert_eq!(t.format_with_items(fmt.clone()).to_string(), "23:56:04");
/// assert_eq!(t.format("%H:%M:%S").to_string(), "23:56:04");
- /// ~~~~
+ /// ```
///
/// The resulting `DelayedFormat` can be formatted directly via the `Display` trait.
///
- /// ~~~~
+ /// ```
/// # use chrono::NaiveTime;
/// # use chrono::format::strftime::StrftimeItems;
/// # let fmt = StrftimeItems::new("%H:%M:%S").clone();
- /// # let t = NaiveTime::from_hms(23, 56, 4);
+ /// # let t = NaiveTime::from_hms_opt(23, 56, 4).unwrap();
/// assert_eq!(format!("{}", t.format_with_items(fmt)), "23:56:04");
- /// ~~~~
+ /// ```
#[cfg(any(feature = "alloc", feature = "std", test))]
+ #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))]
#[inline]
pub fn format_with_items<'a, I, B>(&self, items: I) -> DelayedFormat<I>
where
@@ -768,25 +720,26 @@ impl NaiveTime {
///
/// # Example
///
- /// ~~~~
+ /// ```
/// use chrono::NaiveTime;
///
- /// let t = NaiveTime::from_hms_nano(23, 56, 4, 12_345_678);
+ /// let t = NaiveTime::from_hms_nano_opt(23, 56, 4, 12_345_678).unwrap();
/// assert_eq!(t.format("%H:%M:%S").to_string(), "23:56:04");
/// assert_eq!(t.format("%H:%M:%S%.6f").to_string(), "23:56:04.012345");
/// assert_eq!(t.format("%-I:%M %p").to_string(), "11:56 PM");
- /// ~~~~
+ /// ```
///
/// The resulting `DelayedFormat` can be formatted directly via the `Display` trait.
///
- /// ~~~~
+ /// ```
/// # use chrono::NaiveTime;
- /// # let t = NaiveTime::from_hms_nano(23, 56, 4, 12_345_678);
+ /// # let t = NaiveTime::from_hms_nano_opt(23, 56, 4, 12_345_678).unwrap();
/// assert_eq!(format!("{}", t.format("%H:%M:%S")), "23:56:04");
/// assert_eq!(format!("{}", t.format("%H:%M:%S%.6f")), "23:56:04.012345");
/// assert_eq!(format!("{}", t.format("%-I:%M %p")), "11:56 PM");
- /// ~~~~
+ /// ```
#[cfg(any(feature = "alloc", feature = "std", test))]
+ #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))]
#[inline]
pub fn format<'a>(&self, fmt: &'a str) -> DelayedFormat<StrftimeItems<'a>> {
self.format_with_items(StrftimeItems::new(fmt))
@@ -798,6 +751,10 @@ impl NaiveTime {
let (hour, min) = div_mod_floor(mins, 60);
(hour, min, sec)
}
+
+ /// The earliest possible `NaiveTime`
+ pub const MIN: Self = Self { secs: 0, frac: 0 };
+ pub(super) const MAX: Self = Self { secs: 23 * 3600 + 59 * 60 + 59, frac: 999_999_999 };
}
impl Timelike for NaiveTime {
@@ -805,12 +762,12 @@ impl Timelike for NaiveTime {
///
/// # Example
///
- /// ~~~~
+ /// ```
/// use chrono::{NaiveTime, Timelike};
///
- /// assert_eq!(NaiveTime::from_hms(0, 0, 0).hour(), 0);
- /// assert_eq!(NaiveTime::from_hms_nano(23, 56, 4, 12_345_678).hour(), 23);
- /// ~~~~
+ /// assert_eq!(NaiveTime::from_hms_opt(0, 0, 0).unwrap().hour(), 0);
+ /// assert_eq!(NaiveTime::from_hms_nano_opt(23, 56, 4, 12_345_678).unwrap().hour(), 23);
+ /// ```
#[inline]
fn hour(&self) -> u32 {
self.hms().0
@@ -820,12 +777,12 @@ impl Timelike for NaiveTime {
///
/// # Example
///
- /// ~~~~
+ /// ```
/// use chrono::{NaiveTime, Timelike};
///
- /// assert_eq!(NaiveTime::from_hms(0, 0, 0).minute(), 0);
- /// assert_eq!(NaiveTime::from_hms_nano(23, 56, 4, 12_345_678).minute(), 56);
- /// ~~~~
+ /// assert_eq!(NaiveTime::from_hms_opt(0, 0, 0).unwrap().minute(), 0);
+ /// assert_eq!(NaiveTime::from_hms_nano_opt(23, 56, 4, 12_345_678).unwrap().minute(), 56);
+ /// ```
#[inline]
fn minute(&self) -> u32 {
self.hms().1
@@ -835,23 +792,23 @@ impl Timelike for NaiveTime {
///
/// # Example
///
- /// ~~~~
+ /// ```
/// use chrono::{NaiveTime, Timelike};
///
- /// assert_eq!(NaiveTime::from_hms(0, 0, 0).second(), 0);
- /// assert_eq!(NaiveTime::from_hms_nano(23, 56, 4, 12_345_678).second(), 4);
- /// ~~~~
+ /// assert_eq!(NaiveTime::from_hms_opt(0, 0, 0).unwrap().second(), 0);
+ /// assert_eq!(NaiveTime::from_hms_nano_opt(23, 56, 4, 12_345_678).unwrap().second(), 4);
+ /// ```
///
/// This method never returns 60 even when it is a leap second.
/// ([Why?](#leap-second-handling))
/// Use the proper [formatting method](#method.format) to get a human-readable representation.
///
- /// ~~~~
+ /// ```
/// # use chrono::{NaiveTime, Timelike};
- /// let leap = NaiveTime::from_hms_milli(23, 59, 59, 1_000);
+ /// let leap = NaiveTime::from_hms_milli_opt(23, 59, 59, 1_000).unwrap();
/// assert_eq!(leap.second(), 59);
/// assert_eq!(leap.format("%H:%M:%S").to_string(), "23:59:60");
- /// ~~~~
+ /// ```
#[inline]
fn second(&self) -> u32 {
self.hms().2
@@ -863,23 +820,23 @@ impl Timelike for NaiveTime {
///
/// # Example
///
- /// ~~~~
+ /// ```
/// use chrono::{NaiveTime, Timelike};
///
- /// assert_eq!(NaiveTime::from_hms(0, 0, 0).nanosecond(), 0);
- /// assert_eq!(NaiveTime::from_hms_nano(23, 56, 4, 12_345_678).nanosecond(), 12_345_678);
- /// ~~~~
+ /// assert_eq!(NaiveTime::from_hms_opt(0, 0, 0).unwrap().nanosecond(), 0);
+ /// assert_eq!(NaiveTime::from_hms_nano_opt(23, 56, 4, 12_345_678).unwrap().nanosecond(), 12_345_678);
+ /// ```
///
/// Leap seconds may have seemingly out-of-range return values.
/// 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.
///
- /// ~~~~
+ /// ```
/// # use chrono::{NaiveTime, Timelike};
- /// let leap = NaiveTime::from_hms_milli(23, 59, 59, 1_000);
+ /// let leap = NaiveTime::from_hms_milli_opt(23, 59, 59, 1_000).unwrap();
/// assert_eq!(leap.nanosecond(), 1_000_000_000);
/// assert_eq!(leap.format("%H:%M:%S%.9f").to_string(), "23:59:60.000000000");
- /// ~~~~
+ /// ```
#[inline]
fn nanosecond(&self) -> u32 {
self.frac
@@ -891,20 +848,20 @@ impl Timelike for NaiveTime {
///
/// # Example
///
- /// ~~~~
+ /// ```
/// use chrono::{NaiveTime, Timelike};
///
- /// let dt = NaiveTime::from_hms_nano(23, 56, 4, 12_345_678);
- /// assert_eq!(dt.with_hour(7), Some(NaiveTime::from_hms_nano(7, 56, 4, 12_345_678)));
+ /// let dt = NaiveTime::from_hms_nano_opt(23, 56, 4, 12_345_678).unwrap();
+ /// assert_eq!(dt.with_hour(7), Some(NaiveTime::from_hms_nano_opt(7, 56, 4, 12_345_678).unwrap()));
/// assert_eq!(dt.with_hour(24), None);
- /// ~~~~
+ /// ```
#[inline]
fn with_hour(&self, hour: u32) -> Option<NaiveTime> {
if hour >= 24 {
return None;
}
let secs = hour * 3600 + self.secs % 3600;
- Some(NaiveTime { secs: secs, ..*self })
+ Some(NaiveTime { secs, ..*self })
}
/// Makes a new `NaiveTime` with the minute number changed.
@@ -913,20 +870,20 @@ impl Timelike for NaiveTime {
///
/// # Example
///
- /// ~~~~
+ /// ```
/// use chrono::{NaiveTime, Timelike};
///
- /// let dt = NaiveTime::from_hms_nano(23, 56, 4, 12_345_678);
- /// assert_eq!(dt.with_minute(45), Some(NaiveTime::from_hms_nano(23, 45, 4, 12_345_678)));
+ /// let dt = NaiveTime::from_hms_nano_opt(23, 56, 4, 12_345_678).unwrap();
+ /// assert_eq!(dt.with_minute(45), Some(NaiveTime::from_hms_nano_opt(23, 45, 4, 12_345_678).unwrap()));
/// assert_eq!(dt.with_minute(60), None);
- /// ~~~~
+ /// ```
#[inline]
fn with_minute(&self, min: u32) -> Option<NaiveTime> {
if min >= 60 {
return None;
}
let secs = self.secs / 3600 * 3600 + min * 60 + self.secs % 60;
- Some(NaiveTime { secs: secs, ..*self })
+ Some(NaiveTime { secs, ..*self })
}
/// Makes a new `NaiveTime` with the second number changed.
@@ -937,20 +894,20 @@ impl Timelike for NaiveTime {
///
/// # Example
///
- /// ~~~~
+ /// ```
/// use chrono::{NaiveTime, Timelike};
///
- /// let dt = NaiveTime::from_hms_nano(23, 56, 4, 12_345_678);
- /// assert_eq!(dt.with_second(17), Some(NaiveTime::from_hms_nano(23, 56, 17, 12_345_678)));
+ /// let dt = NaiveTime::from_hms_nano_opt(23, 56, 4, 12_345_678).unwrap();
+ /// assert_eq!(dt.with_second(17), Some(NaiveTime::from_hms_nano_opt(23, 56, 17, 12_345_678).unwrap()));
/// assert_eq!(dt.with_second(60), None);
- /// ~~~~
+ /// ```
#[inline]
fn with_second(&self, sec: u32) -> Option<NaiveTime> {
if sec >= 60 {
return None;
}
let secs = self.secs / 60 * 60 + sec;
- Some(NaiveTime { secs: secs, ..*self })
+ Some(NaiveTime { secs, ..*self })
}
/// Makes a new `NaiveTime` with nanoseconds since the whole non-leap second changed.
@@ -961,26 +918,26 @@ impl Timelike for NaiveTime {
///
/// # Example
///
- /// ~~~~
+ /// ```
/// use chrono::{NaiveTime, Timelike};
///
- /// let dt = NaiveTime::from_hms_nano(23, 56, 4, 12_345_678);
+ /// let dt = NaiveTime::from_hms_nano_opt(23, 56, 4, 12_345_678).unwrap();
/// assert_eq!(dt.with_nanosecond(333_333_333),
- /// Some(NaiveTime::from_hms_nano(23, 56, 4, 333_333_333)));
+ /// Some(NaiveTime::from_hms_nano_opt(23, 56, 4, 333_333_333).unwrap()));
/// assert_eq!(dt.with_nanosecond(2_000_000_000), None);
- /// ~~~~
+ /// ```
///
/// Leap seconds can theoretically follow *any* whole second.
/// The following would be a proper leap second at the time zone offset of UTC-00:03:57
/// (there are several historical examples comparable to this "non-sense" offset),
/// and therefore is allowed.
///
- /// ~~~~
+ /// ```
/// # use chrono::{NaiveTime, Timelike};
- /// # let dt = NaiveTime::from_hms_nano(23, 56, 4, 12_345_678);
+ /// # let dt = NaiveTime::from_hms_nano_opt(23, 56, 4, 12_345_678).unwrap();
/// assert_eq!(dt.with_nanosecond(1_333_333_333),
- /// Some(NaiveTime::from_hms_nano(23, 56, 4, 1_333_333_333)));
- /// ~~~~
+ /// Some(NaiveTime::from_hms_nano_opt(23, 56, 4, 1_333_333_333).unwrap()));
+ /// ```
#[inline]
fn with_nanosecond(&self, nano: u32) -> Option<NaiveTime> {
if nano >= 2_000_000_000 {
@@ -993,33 +950,22 @@ impl Timelike for NaiveTime {
///
/// # Example
///
- /// ~~~~
+ /// ```
/// use chrono::{NaiveTime, Timelike};
///
- /// assert_eq!(NaiveTime::from_hms(1, 2, 3).num_seconds_from_midnight(),
+ /// assert_eq!(NaiveTime::from_hms_opt(1, 2, 3).unwrap().num_seconds_from_midnight(),
/// 3723);
- /// assert_eq!(NaiveTime::from_hms_nano(23, 56, 4, 12_345_678).num_seconds_from_midnight(),
+ /// assert_eq!(NaiveTime::from_hms_nano_opt(23, 56, 4, 12_345_678).unwrap().num_seconds_from_midnight(),
/// 86164);
- /// assert_eq!(NaiveTime::from_hms_milli(23, 59, 59, 1_000).num_seconds_from_midnight(),
+ /// assert_eq!(NaiveTime::from_hms_milli_opt(23, 59, 59, 1_000).unwrap().num_seconds_from_midnight(),
/// 86399);
- /// ~~~~
+ /// ```
#[inline]
fn num_seconds_from_midnight(&self) -> u32 {
self.secs // do not repeat the calculation!
}
}
-/// `NaiveTime` can be used as a key to the hash maps (in principle).
-///
-/// Practically this also takes account of fractional seconds, so it is not recommended.
-/// (For the obvious reason this also distinguishes leap seconds from non-leap seconds.)
-impl hash::Hash for NaiveTime {
- fn hash<H: hash::Hasher>(&self, state: &mut H) {
- self.secs.hash(state);
- self.frac.hash(state);
- }
-}
-
/// An addition of `Duration` to `NaiveTime` wraps around and never overflows or underflows.
/// In particular the addition ignores integral number of days.
///
@@ -1030,8 +976,7 @@ impl hash::Hash for NaiveTime {
///
/// # Example
///
-/// ~~~~
-/// # extern crate chrono; fn main() {
+/// ```
/// use chrono::{Duration, NaiveTime};
///
/// let from_hmsm = NaiveTime::from_hms_milli;
@@ -1044,25 +989,21 @@ impl hash::Hash for NaiveTime {
/// assert_eq!(from_hmsm(3, 5, 7, 0) + Duration::milliseconds(80), from_hmsm(3, 5, 7, 80));
/// assert_eq!(from_hmsm(3, 5, 7, 950) + Duration::milliseconds(280), from_hmsm(3, 5, 8, 230));
/// assert_eq!(from_hmsm(3, 5, 7, 950) + Duration::milliseconds(-980), from_hmsm(3, 5, 6, 970));
-/// # }
-/// ~~~~
+/// ```
///
/// The addition wraps around.
///
-/// ~~~~
-/// # extern crate chrono; fn main() {
+/// ```
/// # use chrono::{Duration, NaiveTime};
/// # let from_hmsm = NaiveTime::from_hms_milli;
/// 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));
-/// # }
-/// ~~~~
+/// ```
///
/// Leap seconds are handled, but the addition assumes that it is the only leap second happened.
///
-/// ~~~~
-/// # extern crate chrono; fn main() {
+/// ```
/// # use chrono::{Duration, NaiveTime};
/// # let from_hmsm = NaiveTime::from_hms_milli;
/// let leap = from_hmsm(3, 5, 59, 1_300);
@@ -1073,8 +1014,7 @@ impl hash::Hash for NaiveTime {
/// assert_eq!(leap + Duration::seconds(10), from_hmsm(3, 6, 9, 300));
/// assert_eq!(leap + Duration::seconds(-10), from_hmsm(3, 5, 50, 300));
/// assert_eq!(leap + Duration::days(1), from_hmsm(3, 5, 59, 300));
-/// # }
-/// ~~~~
+/// ```
impl Add<OldDuration> for NaiveTime {
type Output = NaiveTime;
@@ -1102,8 +1042,7 @@ impl AddAssign<OldDuration> for NaiveTime {
///
/// # Example
///
-/// ~~~~
-/// # extern crate chrono; fn main() {
+/// ```
/// use chrono::{Duration, NaiveTime};
///
/// let from_hmsm = NaiveTime::from_hms_milli;
@@ -1114,24 +1053,20 @@ impl AddAssign<OldDuration> for NaiveTime {
/// assert_eq!(from_hmsm(3, 5, 7, 0) - Duration::seconds(2*60*60 + 6*60), from_hmsm(0, 59, 7, 0));
/// assert_eq!(from_hmsm(3, 5, 7, 0) - Duration::milliseconds(80), from_hmsm(3, 5, 6, 920));
/// assert_eq!(from_hmsm(3, 5, 7, 950) - Duration::milliseconds(280), from_hmsm(3, 5, 7, 670));
-/// # }
-/// ~~~~
+/// ```
///
/// The subtraction wraps around.
///
-/// ~~~~
-/// # extern crate chrono; fn main() {
+/// ```
/// # use chrono::{Duration, NaiveTime};
/// # let from_hmsm = NaiveTime::from_hms_milli;
/// 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));
-/// # }
-/// ~~~~
+/// ```
///
/// Leap seconds are handled, but the subtraction assumes that it is the only leap second happened.
///
-/// ~~~~
-/// # extern crate chrono; fn main() {
+/// ```
/// # use chrono::{Duration, NaiveTime};
/// # let from_hmsm = NaiveTime::from_hms_milli;
/// let leap = from_hmsm(3, 5, 59, 1_300);
@@ -1140,8 +1075,7 @@ impl AddAssign<OldDuration> for NaiveTime {
/// assert_eq!(leap - Duration::milliseconds(500), from_hmsm(3, 5, 59, 800));
/// assert_eq!(leap - Duration::seconds(60), from_hmsm(3, 5, 0, 300));
/// assert_eq!(leap - Duration::days(1), from_hmsm(3, 6, 0, 300));
-/// # }
-/// ~~~~
+/// ```
impl Sub<OldDuration> for NaiveTime {
type Output = NaiveTime;
@@ -1173,8 +1107,7 @@ impl SubAssign<OldDuration> for NaiveTime {
///
/// # Example
///
-/// ~~~~
-/// # extern crate chrono; fn main() {
+/// ```
/// use chrono::{Duration, NaiveTime};
///
/// let from_hmsm = NaiveTime::from_hms_milli;
@@ -1188,14 +1121,12 @@ impl SubAssign<OldDuration> for NaiveTime {
/// assert_eq!(from_hmsm(3, 5, 7, 900) - from_hmsm(4, 5, 7, 900), Duration::seconds(-3600));
/// assert_eq!(from_hmsm(3, 5, 7, 900) - from_hmsm(2, 4, 6, 800),
/// Duration::seconds(3600 + 60 + 1) + Duration::milliseconds(100));
-/// # }
-/// ~~~~
+/// ```
///
/// Leap seconds are handled, but the subtraction assumes that
/// there were no other leap seconds happened.
///
-/// ~~~~
-/// # extern crate chrono; fn main() {
+/// ```
/// # use chrono::{Duration, NaiveTime};
/// # let from_hmsm = NaiveTime::from_hms_milli;
/// assert_eq!(from_hmsm(3, 0, 59, 1_000) - from_hmsm(3, 0, 59, 0), Duration::seconds(1));
@@ -1205,8 +1136,7 @@ impl SubAssign<OldDuration> for NaiveTime {
/// assert_eq!(from_hmsm(3, 0, 0, 0) - from_hmsm(2, 59, 59, 1_000), Duration::seconds(1));
/// assert_eq!(from_hmsm(3, 0, 59, 1_000) - from_hmsm(2, 59, 59, 1_000),
/// Duration::seconds(61));
-/// # }
-/// ~~~~
+/// ```
impl Sub<NaiveTime> for NaiveTime {
type Output = OldDuration;
@@ -1229,21 +1159,21 @@ impl Sub<NaiveTime> for NaiveTime {
///
/// # Example
///
-/// ~~~~
+/// ```
/// use chrono::NaiveTime;
///
-/// assert_eq!(format!("{:?}", NaiveTime::from_hms(23, 56, 4)), "23:56:04");
-/// assert_eq!(format!("{:?}", NaiveTime::from_hms_milli(23, 56, 4, 12)), "23:56:04.012");
-/// assert_eq!(format!("{:?}", NaiveTime::from_hms_micro(23, 56, 4, 1234)), "23:56:04.001234");
-/// assert_eq!(format!("{:?}", NaiveTime::from_hms_nano(23, 56, 4, 123456)), "23:56:04.000123456");
-/// ~~~~
+/// assert_eq!(format!("{:?}", NaiveTime::from_hms_opt(23, 56, 4).unwrap()), "23:56:04");
+/// assert_eq!(format!("{:?}", NaiveTime::from_hms_milli_opt(23, 56, 4, 12).unwrap()), "23:56:04.012");
+/// assert_eq!(format!("{:?}", NaiveTime::from_hms_micro_opt(23, 56, 4, 1234).unwrap()), "23:56:04.001234");
+/// assert_eq!(format!("{:?}", NaiveTime::from_hms_nano_opt(23, 56, 4, 123456).unwrap()), "23:56:04.000123456");
+/// ```
///
/// Leap seconds may also be used.
///
-/// ~~~~
+/// ```
/// # use chrono::NaiveTime;
-/// assert_eq!(format!("{:?}", NaiveTime::from_hms_milli(6, 59, 59, 1_500)), "06:59:60.500");
-/// ~~~~
+/// assert_eq!(format!("{:?}", NaiveTime::from_hms_milli_opt(6, 59, 59, 1_500).unwrap()), "06:59:60.500");
+/// ```
impl fmt::Debug for NaiveTime {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let (hour, min, sec) = self.hms();
@@ -1253,7 +1183,13 @@ impl fmt::Debug for NaiveTime {
(sec, self.frac)
};
- write!(f, "{:02}:{:02}:{:02}", hour, min, sec)?;
+ use core::fmt::Write;
+ write_hundreds(f, hour as u8)?;
+ f.write_char(':')?;
+ write_hundreds(f, min as u8)?;
+ f.write_char(':')?;
+ write_hundreds(f, sec as u8)?;
+
if nano == 0 {
Ok(())
} else if nano % 1_000_000 == 0 {
@@ -1279,21 +1215,21 @@ impl fmt::Debug for NaiveTime {
///
/// # Example
///
-/// ~~~~
+/// ```
/// use chrono::NaiveTime;
///
-/// assert_eq!(format!("{}", NaiveTime::from_hms(23, 56, 4)), "23:56:04");
-/// assert_eq!(format!("{}", NaiveTime::from_hms_milli(23, 56, 4, 12)), "23:56:04.012");
-/// assert_eq!(format!("{}", NaiveTime::from_hms_micro(23, 56, 4, 1234)), "23:56:04.001234");
-/// assert_eq!(format!("{}", NaiveTime::from_hms_nano(23, 56, 4, 123456)), "23:56:04.000123456");
-/// ~~~~
+/// assert_eq!(format!("{}", NaiveTime::from_hms_opt(23, 56, 4).unwrap()), "23:56:04");
+/// assert_eq!(format!("{}", NaiveTime::from_hms_milli_opt(23, 56, 4, 12).unwrap()), "23:56:04.012");
+/// assert_eq!(format!("{}", NaiveTime::from_hms_micro_opt(23, 56, 4, 1234).unwrap()), "23:56:04.001234");
+/// assert_eq!(format!("{}", NaiveTime::from_hms_nano_opt(23, 56, 4, 123456).unwrap()), "23:56:04.000123456");
+/// ```
///
/// Leap seconds may also be used.
///
-/// ~~~~
+/// ```
/// # use chrono::NaiveTime;
-/// assert_eq!(format!("{}", NaiveTime::from_hms_milli(6, 59, 59, 1_500)), "06:59:60.500");
-/// ~~~~
+/// assert_eq!(format!("{}", NaiveTime::from_hms_milli_opt(6, 59, 59, 1_500).unwrap()), "06:59:60.500");
+/// ```
impl fmt::Display for NaiveTime {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(self, f)
@@ -1305,25 +1241,25 @@ impl fmt::Display for NaiveTime {
///
/// # Example
///
-/// ~~~~
+/// ```
/// use chrono::NaiveTime;
///
-/// let t = NaiveTime::from_hms(23, 56, 4);
+/// let t = NaiveTime::from_hms_opt(23, 56, 4).unwrap();
/// assert_eq!("23:56:04".parse::<NaiveTime>(), Ok(t));
///
-/// let t = NaiveTime::from_hms_nano(23, 56, 4, 12_345_678);
+/// let t = NaiveTime::from_hms_nano_opt(23, 56, 4, 12_345_678).unwrap();
/// assert_eq!("23:56:4.012345678".parse::<NaiveTime>(), Ok(t));
///
-/// let t = NaiveTime::from_hms_nano(23, 59, 59, 1_234_567_890); // leap second
+/// let t = NaiveTime::from_hms_nano_opt(23, 59, 59, 1_234_567_890).unwrap(); // leap second
/// assert_eq!("23:59:60.23456789".parse::<NaiveTime>(), Ok(t));
///
/// assert!("foo".parse::<NaiveTime>().is_err());
-/// ~~~~
+/// ```
impl str::FromStr for NaiveTime {
type Err = ParseError;
fn from_str(s: &str) -> ParseResult<NaiveTime> {
- const ITEMS: &'static [Item<'static>] = &[
+ const ITEMS: &[Item<'static>] = &[
Item::Numeric(Numeric::Hour, Pad::Zero),
Item::Space(""),
Item::Literal(":"),
@@ -1341,33 +1277,58 @@ impl str::FromStr for NaiveTime {
}
}
+/// The default value for a NaiveTime is midnight, 00:00:00 exactly.
+///
+/// # Example
+///
+/// ```rust
+/// use chrono::NaiveTime;
+///
+/// let default_time = NaiveTime::default();
+/// assert_eq!(default_time, NaiveTime::from_hms_opt(0, 0, 0).unwrap());
+/// ```
+impl Default for NaiveTime {
+ fn default() -> Self {
+ NaiveTime::from_hms_opt(0, 0, 0).unwrap()
+ }
+}
+
#[cfg(all(test, any(feature = "rustc-serialize", feature = "serde")))]
fn test_encodable_json<F, E>(to_string: F)
where
F: Fn(&NaiveTime) -> Result<String, E>,
E: ::std::fmt::Debug,
{
- assert_eq!(to_string(&NaiveTime::from_hms(0, 0, 0)).ok(), Some(r#""00:00:00""#.into()));
assert_eq!(
- to_string(&NaiveTime::from_hms_milli(0, 0, 0, 950)).ok(),
+ to_string(&NaiveTime::from_hms_opt(0, 0, 0).unwrap()).ok(),
+ Some(r#""00:00:00""#.into())
+ );
+ assert_eq!(
+ to_string(&NaiveTime::from_hms_milli_opt(0, 0, 0, 950).unwrap()).ok(),
Some(r#""00:00:00.950""#.into())
);
assert_eq!(
- to_string(&NaiveTime::from_hms_milli(0, 0, 59, 1_000)).ok(),
+ to_string(&NaiveTime::from_hms_milli_opt(0, 0, 59, 1_000).unwrap()).ok(),
Some(r#""00:00:60""#.into())
);
- assert_eq!(to_string(&NaiveTime::from_hms(0, 1, 2)).ok(), Some(r#""00:01:02""#.into()));
assert_eq!(
- to_string(&NaiveTime::from_hms_nano(3, 5, 7, 98765432)).ok(),
+ to_string(&NaiveTime::from_hms_opt(0, 1, 2).unwrap()).ok(),
+ Some(r#""00:01:02""#.into())
+ );
+ assert_eq!(
+ to_string(&NaiveTime::from_hms_nano_opt(3, 5, 7, 98765432).unwrap()).ok(),
Some(r#""03:05:07.098765432""#.into())
);
- assert_eq!(to_string(&NaiveTime::from_hms(7, 8, 9)).ok(), Some(r#""07:08:09""#.into()));
assert_eq!(
- to_string(&NaiveTime::from_hms_micro(12, 34, 56, 789)).ok(),
+ to_string(&NaiveTime::from_hms_opt(7, 8, 9).unwrap()).ok(),
+ Some(r#""07:08:09""#.into())
+ );
+ assert_eq!(
+ to_string(&NaiveTime::from_hms_micro_opt(12, 34, 56, 789).unwrap()).ok(),
Some(r#""12:34:56.000789""#.into())
);
assert_eq!(
- to_string(&NaiveTime::from_hms_nano(23, 59, 59, 1_999_999_999)).ok(),
+ to_string(&NaiveTime::from_hms_nano_opt(23, 59, 59, 1_999_999_999).unwrap()).ok(),
Some(r#""23:59:60.999999999""#.into())
);
}
@@ -1378,28 +1339,37 @@ where
F: Fn(&str) -> Result<NaiveTime, E>,
E: ::std::fmt::Debug,
{
- assert_eq!(from_str(r#""00:00:00""#).ok(), Some(NaiveTime::from_hms(0, 0, 0)));
- assert_eq!(from_str(r#""0:0:0""#).ok(), Some(NaiveTime::from_hms(0, 0, 0)));
- assert_eq!(from_str(r#""00:00:00.950""#).ok(), Some(NaiveTime::from_hms_milli(0, 0, 0, 950)));
- assert_eq!(from_str(r#""0:0:0.95""#).ok(), Some(NaiveTime::from_hms_milli(0, 0, 0, 950)));
- assert_eq!(from_str(r#""00:00:60""#).ok(), Some(NaiveTime::from_hms_milli(0, 0, 59, 1_000)));
- assert_eq!(from_str(r#""00:01:02""#).ok(), Some(NaiveTime::from_hms(0, 1, 2)));
+ assert_eq!(from_str(r#""00:00:00""#).ok(), Some(NaiveTime::from_hms_opt(0, 0, 0).unwrap()));
+ assert_eq!(from_str(r#""0:0:0""#).ok(), Some(NaiveTime::from_hms_opt(0, 0, 0).unwrap()));
+ assert_eq!(
+ from_str(r#""00:00:00.950""#).ok(),
+ Some(NaiveTime::from_hms_milli_opt(0, 0, 0, 950).unwrap())
+ );
+ assert_eq!(
+ from_str(r#""0:0:0.95""#).ok(),
+ Some(NaiveTime::from_hms_milli_opt(0, 0, 0, 950).unwrap())
+ );
+ assert_eq!(
+ from_str(r#""00:00:60""#).ok(),
+ Some(NaiveTime::from_hms_milli_opt(0, 0, 59, 1_000).unwrap())
+ );
+ assert_eq!(from_str(r#""00:01:02""#).ok(), Some(NaiveTime::from_hms_opt(0, 1, 2).unwrap()));
assert_eq!(
from_str(r#""03:05:07.098765432""#).ok(),
- Some(NaiveTime::from_hms_nano(3, 5, 7, 98765432))
+ Some(NaiveTime::from_hms_nano_opt(3, 5, 7, 98765432).unwrap())
);
- assert_eq!(from_str(r#""07:08:09""#).ok(), Some(NaiveTime::from_hms(7, 8, 9)));
+ assert_eq!(from_str(r#""07:08:09""#).ok(), Some(NaiveTime::from_hms_opt(7, 8, 9).unwrap()));
assert_eq!(
from_str(r#""12:34:56.000789""#).ok(),
- Some(NaiveTime::from_hms_micro(12, 34, 56, 789))
+ Some(NaiveTime::from_hms_micro_opt(12, 34, 56, 789).unwrap())
);
assert_eq!(
from_str(r#""23:59:60.999999999""#).ok(),
- Some(NaiveTime::from_hms_nano(23, 59, 59, 1_999_999_999))
+ Some(NaiveTime::from_hms_nano_opt(23, 59, 59, 1_999_999_999).unwrap())
);
assert_eq!(
from_str(r#""23:59:60.9999999999997""#).ok(), // excess digits are ignored
- Some(NaiveTime::from_hms_nano(23, 59, 59, 1_999_999_999))
+ Some(NaiveTime::from_hms_nano_opt(23, 59, 59, 1_999_999_999).unwrap())
);
// bad formats
@@ -1418,397 +1388,3 @@ where
assert!(from_str(r#"{"secs":0,"frac":0}"#).is_err());
assert!(from_str(r#"null"#).is_err());
}
-
-#[cfg(feature = "rustc-serialize")]
-mod rustc_serialize {
- use super::NaiveTime;
- use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
-
- impl Encodable for NaiveTime {
- fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
- format!("{:?}", self).encode(s)
- }
- }
-
- impl Decodable for NaiveTime {
- fn decode<D: Decoder>(d: &mut D) -> Result<NaiveTime, D::Error> {
- d.read_str()?.parse().map_err(|_| d.error("invalid time"))
- }
- }
-
- #[cfg(test)]
- use rustc_serialize::json;
-
- #[test]
- fn test_encodable() {
- super::test_encodable_json(json::encode);
- }
-
- #[test]
- fn test_decodable() {
- super::test_decodable_json(json::decode);
- }
-}
-
-#[cfg(feature = "serde")]
-mod serde {
- use super::NaiveTime;
- use core::fmt;
- use serdelib::{de, ser};
-
- // TODO not very optimized for space (binary formats would want something better)
- // TODO round-trip for general leap seconds (not just those with second = 60)
-
- impl ser::Serialize for NaiveTime {
- fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
- where
- S: ser::Serializer,
- {
- serializer.collect_str(&self)
- }
- }
-
- struct NaiveTimeVisitor;
-
- impl<'de> de::Visitor<'de> for NaiveTimeVisitor {
- type Value = NaiveTime;
-
- fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
- write!(formatter, "a formatted time string")
- }
-
- fn visit_str<E>(self, value: &str) -> Result<NaiveTime, E>
- where
- E: de::Error,
- {
- value.parse().map_err(E::custom)
- }
- }
-
- impl<'de> de::Deserialize<'de> for NaiveTime {
- fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
- where
- D: de::Deserializer<'de>,
- {
- deserializer.deserialize_str(NaiveTimeVisitor)
- }
- }
-
- #[cfg(test)]
- extern crate bincode;
- #[cfg(test)]
- extern crate serde_json;
-
- #[test]
- fn test_serde_serialize() {
- super::test_encodable_json(self::serde_json::to_string);
- }
-
- #[test]
- fn test_serde_deserialize() {
- super::test_decodable_json(|input| self::serde_json::from_str(&input));
- }
-
- #[test]
- fn test_serde_bincode() {
- // Bincode is relevant to test separately from JSON because
- // it is not self-describing.
- use self::bincode::{deserialize, serialize, Infinite};
-
- let t = NaiveTime::from_hms_nano(3, 5, 7, 98765432);
- let encoded = serialize(&t, Infinite).unwrap();
- let decoded: NaiveTime = deserialize(&encoded).unwrap();
- assert_eq!(t, decoded);
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::NaiveTime;
- use oldtime::Duration;
- use std::u32;
- use Timelike;
-
- #[test]
- fn test_time_from_hms_milli() {
- assert_eq!(
- NaiveTime::from_hms_milli_opt(3, 5, 7, 0),
- Some(NaiveTime::from_hms_nano(3, 5, 7, 0))
- );
- assert_eq!(
- NaiveTime::from_hms_milli_opt(3, 5, 7, 777),
- Some(NaiveTime::from_hms_nano(3, 5, 7, 777_000_000))
- );
- assert_eq!(
- NaiveTime::from_hms_milli_opt(3, 5, 7, 1_999),
- Some(NaiveTime::from_hms_nano(3, 5, 7, 1_999_000_000))
- );
- assert_eq!(NaiveTime::from_hms_milli_opt(3, 5, 7, 2_000), None);
- assert_eq!(NaiveTime::from_hms_milli_opt(3, 5, 7, 5_000), None); // overflow check
- assert_eq!(NaiveTime::from_hms_milli_opt(3, 5, 7, u32::MAX), None);
- }
-
- #[test]
- fn test_time_from_hms_micro() {
- assert_eq!(
- NaiveTime::from_hms_micro_opt(3, 5, 7, 0),
- Some(NaiveTime::from_hms_nano(3, 5, 7, 0))
- );
- assert_eq!(
- NaiveTime::from_hms_micro_opt(3, 5, 7, 333),
- Some(NaiveTime::from_hms_nano(3, 5, 7, 333_000))
- );
- assert_eq!(
- NaiveTime::from_hms_micro_opt(3, 5, 7, 777_777),
- Some(NaiveTime::from_hms_nano(3, 5, 7, 777_777_000))
- );
- assert_eq!(
- NaiveTime::from_hms_micro_opt(3, 5, 7, 1_999_999),
- Some(NaiveTime::from_hms_nano(3, 5, 7, 1_999_999_000))
- );
- assert_eq!(NaiveTime::from_hms_micro_opt(3, 5, 7, 2_000_000), None);
- assert_eq!(NaiveTime::from_hms_micro_opt(3, 5, 7, 5_000_000), None); // overflow check
- assert_eq!(NaiveTime::from_hms_micro_opt(3, 5, 7, u32::MAX), None);
- }
-
- #[test]
- fn test_time_hms() {
- assert_eq!(NaiveTime::from_hms(3, 5, 7).hour(), 3);
- assert_eq!(NaiveTime::from_hms(3, 5, 7).with_hour(0), Some(NaiveTime::from_hms(0, 5, 7)));
- assert_eq!(NaiveTime::from_hms(3, 5, 7).with_hour(23), Some(NaiveTime::from_hms(23, 5, 7)));
- assert_eq!(NaiveTime::from_hms(3, 5, 7).with_hour(24), None);
- assert_eq!(NaiveTime::from_hms(3, 5, 7).with_hour(u32::MAX), None);
-
- assert_eq!(NaiveTime::from_hms(3, 5, 7).minute(), 5);
- assert_eq!(NaiveTime::from_hms(3, 5, 7).with_minute(0), Some(NaiveTime::from_hms(3, 0, 7)));
- assert_eq!(
- NaiveTime::from_hms(3, 5, 7).with_minute(59),
- Some(NaiveTime::from_hms(3, 59, 7))
- );
- assert_eq!(NaiveTime::from_hms(3, 5, 7).with_minute(60), None);
- assert_eq!(NaiveTime::from_hms(3, 5, 7).with_minute(u32::MAX), None);
-
- assert_eq!(NaiveTime::from_hms(3, 5, 7).second(), 7);
- assert_eq!(NaiveTime::from_hms(3, 5, 7).with_second(0), Some(NaiveTime::from_hms(3, 5, 0)));
- assert_eq!(
- NaiveTime::from_hms(3, 5, 7).with_second(59),
- Some(NaiveTime::from_hms(3, 5, 59))
- );
- assert_eq!(NaiveTime::from_hms(3, 5, 7).with_second(60), None);
- assert_eq!(NaiveTime::from_hms(3, 5, 7).with_second(u32::MAX), None);
- }
-
- #[test]
- fn test_time_add() {
- macro_rules! check {
- ($lhs:expr, $rhs:expr, $sum:expr) => {{
- assert_eq!($lhs + $rhs, $sum);
- //assert_eq!($rhs + $lhs, $sum);
- }};
- }
-
- let hmsm = |h, m, s, mi| NaiveTime::from_hms_milli(h, m, s, mi);
-
- check!(hmsm(3, 5, 7, 900), Duration::zero(), hmsm(3, 5, 7, 900));
- check!(hmsm(3, 5, 7, 900), Duration::milliseconds(100), hmsm(3, 5, 8, 0));
- check!(hmsm(3, 5, 7, 1_300), Duration::milliseconds(-1800), hmsm(3, 5, 6, 500));
- check!(hmsm(3, 5, 7, 1_300), Duration::milliseconds(-800), hmsm(3, 5, 7, 500));
- check!(hmsm(3, 5, 7, 1_300), Duration::milliseconds(-100), hmsm(3, 5, 7, 1_200));
- check!(hmsm(3, 5, 7, 1_300), Duration::milliseconds(100), hmsm(3, 5, 7, 1_400));
- check!(hmsm(3, 5, 7, 1_300), Duration::milliseconds(800), hmsm(3, 5, 8, 100));
- check!(hmsm(3, 5, 7, 1_300), Duration::milliseconds(1800), hmsm(3, 5, 9, 100));
- check!(hmsm(3, 5, 7, 900), Duration::seconds(86399), hmsm(3, 5, 6, 900)); // overwrap
- check!(hmsm(3, 5, 7, 900), Duration::seconds(-86399), hmsm(3, 5, 8, 900));
- check!(hmsm(3, 5, 7, 900), Duration::days(12345), hmsm(3, 5, 7, 900));
- check!(hmsm(3, 5, 7, 1_300), Duration::days(1), hmsm(3, 5, 7, 300));
- check!(hmsm(3, 5, 7, 1_300), Duration::days(-1), hmsm(3, 5, 8, 300));
-
- // regression tests for #37
- check!(hmsm(0, 0, 0, 0), Duration::milliseconds(-990), hmsm(23, 59, 59, 10));
- check!(hmsm(0, 0, 0, 0), Duration::milliseconds(-9990), hmsm(23, 59, 50, 10));
- }
-
- #[test]
- fn test_time_overflowing_add() {
- let hmsm = NaiveTime::from_hms_milli;
-
- assert_eq!(
- hmsm(3, 4, 5, 678).overflowing_add_signed(Duration::hours(11)),
- (hmsm(14, 4, 5, 678), 0)
- );
- assert_eq!(
- hmsm(3, 4, 5, 678).overflowing_add_signed(Duration::hours(23)),
- (hmsm(2, 4, 5, 678), 86_400)
- );
- assert_eq!(
- hmsm(3, 4, 5, 678).overflowing_add_signed(Duration::hours(-7)),
- (hmsm(20, 4, 5, 678), -86_400)
- );
-
- // overflowing_add_signed with leap seconds may be counter-intuitive
- assert_eq!(
- hmsm(3, 4, 5, 1_678).overflowing_add_signed(Duration::days(1)),
- (hmsm(3, 4, 5, 678), 86_400)
- );
- assert_eq!(
- hmsm(3, 4, 5, 1_678).overflowing_add_signed(Duration::days(-1)),
- (hmsm(3, 4, 6, 678), -86_400)
- );
- }
-
- #[test]
- fn test_time_addassignment() {
- let hms = NaiveTime::from_hms;
- let mut time = hms(12, 12, 12);
- time += Duration::hours(10);
- assert_eq!(time, hms(22, 12, 12));
- time += Duration::hours(10);
- assert_eq!(time, hms(8, 12, 12));
- }
-
- #[test]
- fn test_time_subassignment() {
- let hms = NaiveTime::from_hms;
- let mut time = hms(12, 12, 12);
- time -= Duration::hours(10);
- assert_eq!(time, hms(2, 12, 12));
- time -= Duration::hours(10);
- assert_eq!(time, hms(16, 12, 12));
- }
-
- #[test]
- fn test_time_sub() {
- macro_rules! check {
- ($lhs:expr, $rhs:expr, $diff:expr) => {{
- // `time1 - time2 = duration` is equivalent to `time2 - time1 = -duration`
- assert_eq!($lhs.signed_duration_since($rhs), $diff);
- assert_eq!($rhs.signed_duration_since($lhs), -$diff);
- }};
- }
-
- let hmsm = |h, m, s, mi| NaiveTime::from_hms_milli(h, m, s, mi);
-
- check!(hmsm(3, 5, 7, 900), hmsm(3, 5, 7, 900), Duration::zero());
- check!(hmsm(3, 5, 7, 900), hmsm(3, 5, 7, 600), Duration::milliseconds(300));
- check!(hmsm(3, 5, 7, 200), hmsm(2, 4, 6, 200), Duration::seconds(3600 + 60 + 1));
- check!(
- hmsm(3, 5, 7, 200),
- hmsm(2, 4, 6, 300),
- Duration::seconds(3600 + 60) + Duration::milliseconds(900)
- );
-
- // treats the leap second as if it coincides with the prior non-leap second,
- // as required by `time1 - time2 = duration` and `time2 - time1 = -duration` equivalence.
- check!(hmsm(3, 5, 7, 200), hmsm(3, 5, 6, 1_800), Duration::milliseconds(400));
- check!(hmsm(3, 5, 7, 1_200), hmsm(3, 5, 6, 1_800), Duration::milliseconds(1400));
- check!(hmsm(3, 5, 7, 1_200), hmsm(3, 5, 6, 800), Duration::milliseconds(1400));
-
- // additional equality: `time1 + duration = time2` is equivalent to
- // `time2 - time1 = duration` IF AND ONLY IF `time2` represents a non-leap second.
- assert_eq!(hmsm(3, 5, 6, 800) + Duration::milliseconds(400), hmsm(3, 5, 7, 200));
- assert_eq!(hmsm(3, 5, 6, 1_800) + Duration::milliseconds(400), hmsm(3, 5, 7, 200));
- }
-
- #[test]
- fn test_time_fmt() {
- assert_eq!(format!("{}", NaiveTime::from_hms_milli(23, 59, 59, 999)), "23:59:59.999");
- assert_eq!(format!("{}", NaiveTime::from_hms_milli(23, 59, 59, 1_000)), "23:59:60");
- assert_eq!(format!("{}", NaiveTime::from_hms_milli(23, 59, 59, 1_001)), "23:59:60.001");
- assert_eq!(format!("{}", NaiveTime::from_hms_micro(0, 0, 0, 43210)), "00:00:00.043210");
- assert_eq!(format!("{}", NaiveTime::from_hms_nano(0, 0, 0, 6543210)), "00:00:00.006543210");
-
- // the format specifier should have no effect on `NaiveTime`
- assert_eq!(format!("{:30}", NaiveTime::from_hms_milli(3, 5, 7, 9)), "03:05:07.009");
- }
-
- #[test]
- fn test_date_from_str() {
- // valid cases
- let valid = [
- "0:0:0",
- "0:0:0.0000000",
- "0:0:0.0000003",
- " 4 : 3 : 2.1 ",
- " 09:08:07 ",
- " 9:8:07 ",
- "23:59:60.373929310237",
- ];
- for &s in &valid {
- let d = match s.parse::<NaiveTime>() {
- Ok(d) => d,
- Err(e) => panic!("parsing `{}` has failed: {}", s, e),
- };
- let s_ = format!("{:?}", d);
- // `s` and `s_` may differ, but `s.parse()` and `s_.parse()` must be same
- let d_ = match s_.parse::<NaiveTime>() {
- Ok(d) => d,
- Err(e) => {
- panic!("`{}` is parsed into `{:?}`, but reparsing that has failed: {}", s, d, e)
- }
- };
- assert!(
- d == d_,
- "`{}` is parsed into `{:?}`, but reparsed result \
- `{:?}` does not match",
- s,
- d,
- d_
- );
- }
-
- // some invalid cases
- // since `ParseErrorKind` is private, all we can do is to check if there was an error
- assert!("".parse::<NaiveTime>().is_err());
- assert!("x".parse::<NaiveTime>().is_err());
- assert!("15".parse::<NaiveTime>().is_err());
- assert!("15:8".parse::<NaiveTime>().is_err());
- assert!("15:8:x".parse::<NaiveTime>().is_err());
- assert!("15:8:9x".parse::<NaiveTime>().is_err());
- assert!("23:59:61".parse::<NaiveTime>().is_err());
- assert!("12:34:56.x".parse::<NaiveTime>().is_err());
- assert!("12:34:56. 0".parse::<NaiveTime>().is_err());
- }
-
- #[test]
- fn test_time_parse_from_str() {
- let hms = |h, m, s| NaiveTime::from_hms(h, m, s);
- assert_eq!(
- NaiveTime::parse_from_str("2014-5-7T12:34:56+09:30", "%Y-%m-%dT%H:%M:%S%z"),
- Ok(hms(12, 34, 56))
- ); // ignore date and offset
- assert_eq!(NaiveTime::parse_from_str("PM 12:59", "%P %H:%M"), Ok(hms(12, 59, 0)));
- assert!(NaiveTime::parse_from_str("12:3456", "%H:%M:%S").is_err());
- }
-
- #[test]
- fn test_time_format() {
- let t = NaiveTime::from_hms_nano(3, 5, 7, 98765432);
- assert_eq!(t.format("%H,%k,%I,%l,%P,%p").to_string(), "03, 3,03, 3,am,AM");
- assert_eq!(t.format("%M").to_string(), "05");
- assert_eq!(t.format("%S,%f,%.f").to_string(), "07,098765432,.098765432");
- assert_eq!(t.format("%.3f,%.6f,%.9f").to_string(), ".098,.098765,.098765432");
- assert_eq!(t.format("%R").to_string(), "03:05");
- assert_eq!(t.format("%T,%X").to_string(), "03:05:07,03:05:07");
- assert_eq!(t.format("%r").to_string(), "03:05:07 AM");
- assert_eq!(t.format("%t%n%%%n%t").to_string(), "\t\n%\n\t");
-
- let t = NaiveTime::from_hms_micro(3, 5, 7, 432100);
- assert_eq!(t.format("%S,%f,%.f").to_string(), "07,432100000,.432100");
- assert_eq!(t.format("%.3f,%.6f,%.9f").to_string(), ".432,.432100,.432100000");
-
- let t = NaiveTime::from_hms_milli(3, 5, 7, 210);
- assert_eq!(t.format("%S,%f,%.f").to_string(), "07,210000000,.210");
- assert_eq!(t.format("%.3f,%.6f,%.9f").to_string(), ".210,.210000,.210000000");
-
- let t = NaiveTime::from_hms(3, 5, 7);
- assert_eq!(t.format("%S,%f,%.f").to_string(), "07,000000000,");
- assert_eq!(t.format("%.3f,%.6f,%.9f").to_string(), ".000,.000000,.000000000");
-
- // corner cases
- assert_eq!(NaiveTime::from_hms(13, 57, 9).format("%r").to_string(), "01:57:09 PM");
- assert_eq!(
- NaiveTime::from_hms_milli(23, 59, 59, 1_000).format("%X").to_string(),
- "23:59:60"
- );
- }
-}
diff --git a/vendor/chrono/src/naive/time/rustc_serialize.rs b/vendor/chrono/src/naive/time/rustc_serialize.rs
new file mode 100644
index 000000000..9eaf68219
--- /dev/null
+++ b/vendor/chrono/src/naive/time/rustc_serialize.rs
@@ -0,0 +1,29 @@
+#![cfg_attr(docsrs, doc(cfg(feature = "rustc-serialize")))]
+
+use super::NaiveTime;
+use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
+
+impl Encodable for NaiveTime {
+ fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
+ format!("{:?}", self).encode(s)
+ }
+}
+
+impl Decodable for NaiveTime {
+ fn decode<D: Decoder>(d: &mut D) -> Result<NaiveTime, D::Error> {
+ d.read_str()?.parse().map_err(|_| d.error("invalid time"))
+ }
+}
+
+#[cfg(test)]
+use rustc_serialize::json;
+
+#[test]
+fn test_encodable() {
+ super::test_encodable_json(json::encode);
+}
+
+#[test]
+fn test_decodable() {
+ super::test_decodable_json(json::decode);
+}
diff --git a/vendor/chrono/src/naive/time/serde.rs b/vendor/chrono/src/naive/time/serde.rs
new file mode 100644
index 000000000..c7394fb57
--- /dev/null
+++ b/vendor/chrono/src/naive/time/serde.rs
@@ -0,0 +1,65 @@
+#![cfg_attr(docsrs, doc(cfg(feature = "serde")))]
+
+use super::NaiveTime;
+use core::fmt;
+use serde::{de, ser};
+
+// TODO not very optimized for space (binary formats would want something better)
+// TODO round-trip for general leap seconds (not just those with second = 60)
+
+impl ser::Serialize for NaiveTime {
+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: ser::Serializer,
+ {
+ serializer.collect_str(&self)
+ }
+}
+
+struct NaiveTimeVisitor;
+
+impl<'de> de::Visitor<'de> for NaiveTimeVisitor {
+ type Value = NaiveTime;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("a formatted time string")
+ }
+
+ fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
+ where
+ E: de::Error,
+ {
+ value.parse().map_err(E::custom)
+ }
+}
+
+impl<'de> de::Deserialize<'de> for NaiveTime {
+ fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+ where
+ D: de::Deserializer<'de>,
+ {
+ deserializer.deserialize_str(NaiveTimeVisitor)
+ }
+}
+
+#[test]
+fn test_serde_serialize() {
+ super::test_encodable_json(serde_json::to_string);
+}
+
+#[test]
+fn test_serde_deserialize() {
+ super::test_decodable_json(|input| serde_json::from_str(input));
+}
+
+#[test]
+fn test_serde_bincode() {
+ // Bincode is relevant to test separately from JSON because
+ // it is not self-describing.
+ use bincode::{deserialize, serialize};
+
+ let t = NaiveTime::from_hms_nano_opt(3, 5, 7, 98765432).unwrap();
+ let encoded = serialize(&t).unwrap();
+ let decoded: NaiveTime = deserialize(&encoded).unwrap();
+ assert_eq!(t, decoded);
+}
diff --git a/vendor/chrono/src/naive/time/tests.rs b/vendor/chrono/src/naive/time/tests.rs
new file mode 100644
index 000000000..62c46a247
--- /dev/null
+++ b/vendor/chrono/src/naive/time/tests.rs
@@ -0,0 +1,317 @@
+use super::NaiveTime;
+use crate::oldtime::Duration;
+use crate::Timelike;
+use std::u32;
+
+#[test]
+fn test_time_from_hms_milli() {
+ assert_eq!(
+ NaiveTime::from_hms_milli_opt(3, 5, 7, 0),
+ Some(NaiveTime::from_hms_nano_opt(3, 5, 7, 0).unwrap())
+ );
+ assert_eq!(
+ NaiveTime::from_hms_milli_opt(3, 5, 7, 777),
+ Some(NaiveTime::from_hms_nano_opt(3, 5, 7, 777_000_000).unwrap())
+ );
+ assert_eq!(
+ NaiveTime::from_hms_milli_opt(3, 5, 7, 1_999),
+ Some(NaiveTime::from_hms_nano_opt(3, 5, 7, 1_999_000_000).unwrap())
+ );
+ assert_eq!(NaiveTime::from_hms_milli_opt(3, 5, 7, 2_000), None);
+ assert_eq!(NaiveTime::from_hms_milli_opt(3, 5, 7, 5_000), None); // overflow check
+ assert_eq!(NaiveTime::from_hms_milli_opt(3, 5, 7, u32::MAX), None);
+}
+
+#[test]
+fn test_time_from_hms_micro() {
+ assert_eq!(
+ NaiveTime::from_hms_micro_opt(3, 5, 7, 0),
+ Some(NaiveTime::from_hms_nano_opt(3, 5, 7, 0).unwrap())
+ );
+ assert_eq!(
+ NaiveTime::from_hms_micro_opt(3, 5, 7, 333),
+ Some(NaiveTime::from_hms_nano_opt(3, 5, 7, 333_000).unwrap())
+ );
+ assert_eq!(
+ NaiveTime::from_hms_micro_opt(3, 5, 7, 777_777),
+ Some(NaiveTime::from_hms_nano_opt(3, 5, 7, 777_777_000).unwrap())
+ );
+ assert_eq!(
+ NaiveTime::from_hms_micro_opt(3, 5, 7, 1_999_999),
+ Some(NaiveTime::from_hms_nano_opt(3, 5, 7, 1_999_999_000).unwrap())
+ );
+ assert_eq!(NaiveTime::from_hms_micro_opt(3, 5, 7, 2_000_000), None);
+ assert_eq!(NaiveTime::from_hms_micro_opt(3, 5, 7, 5_000_000), None); // overflow check
+ assert_eq!(NaiveTime::from_hms_micro_opt(3, 5, 7, u32::MAX), None);
+}
+
+#[test]
+fn test_time_hms() {
+ assert_eq!(NaiveTime::from_hms_opt(3, 5, 7).unwrap().hour(), 3);
+ assert_eq!(
+ NaiveTime::from_hms_opt(3, 5, 7).unwrap().with_hour(0),
+ Some(NaiveTime::from_hms_opt(0, 5, 7).unwrap())
+ );
+ assert_eq!(
+ NaiveTime::from_hms_opt(3, 5, 7).unwrap().with_hour(23),
+ Some(NaiveTime::from_hms_opt(23, 5, 7).unwrap())
+ );
+ assert_eq!(NaiveTime::from_hms_opt(3, 5, 7).unwrap().with_hour(24), None);
+ assert_eq!(NaiveTime::from_hms_opt(3, 5, 7).unwrap().with_hour(u32::MAX), None);
+
+ assert_eq!(NaiveTime::from_hms_opt(3, 5, 7).unwrap().minute(), 5);
+ assert_eq!(
+ NaiveTime::from_hms_opt(3, 5, 7).unwrap().with_minute(0),
+ Some(NaiveTime::from_hms_opt(3, 0, 7).unwrap())
+ );
+ assert_eq!(
+ NaiveTime::from_hms_opt(3, 5, 7).unwrap().with_minute(59),
+ Some(NaiveTime::from_hms_opt(3, 59, 7).unwrap())
+ );
+ assert_eq!(NaiveTime::from_hms_opt(3, 5, 7).unwrap().with_minute(60), None);
+ assert_eq!(NaiveTime::from_hms_opt(3, 5, 7).unwrap().with_minute(u32::MAX), None);
+
+ assert_eq!(NaiveTime::from_hms_opt(3, 5, 7).unwrap().second(), 7);
+ assert_eq!(
+ NaiveTime::from_hms_opt(3, 5, 7).unwrap().with_second(0),
+ Some(NaiveTime::from_hms_opt(3, 5, 0).unwrap())
+ );
+ assert_eq!(
+ NaiveTime::from_hms_opt(3, 5, 7).unwrap().with_second(59),
+ Some(NaiveTime::from_hms_opt(3, 5, 59).unwrap())
+ );
+ assert_eq!(NaiveTime::from_hms_opt(3, 5, 7).unwrap().with_second(60), None);
+ assert_eq!(NaiveTime::from_hms_opt(3, 5, 7).unwrap().with_second(u32::MAX), None);
+}
+
+#[test]
+fn test_time_add() {
+ macro_rules! check {
+ ($lhs:expr, $rhs:expr, $sum:expr) => {{
+ assert_eq!($lhs + $rhs, $sum);
+ //assert_eq!($rhs + $lhs, $sum);
+ }};
+ }
+
+ let hmsm = |h, m, s, ms| NaiveTime::from_hms_milli_opt(h, m, s, ms).unwrap();
+
+ check!(hmsm(3, 5, 7, 900), Duration::zero(), hmsm(3, 5, 7, 900));
+ check!(hmsm(3, 5, 7, 900), Duration::milliseconds(100), hmsm(3, 5, 8, 0));
+ check!(hmsm(3, 5, 7, 1_300), Duration::milliseconds(-1800), hmsm(3, 5, 6, 500));
+ check!(hmsm(3, 5, 7, 1_300), Duration::milliseconds(-800), hmsm(3, 5, 7, 500));
+ check!(hmsm(3, 5, 7, 1_300), Duration::milliseconds(-100), hmsm(3, 5, 7, 1_200));
+ check!(hmsm(3, 5, 7, 1_300), Duration::milliseconds(100), hmsm(3, 5, 7, 1_400));
+ check!(hmsm(3, 5, 7, 1_300), Duration::milliseconds(800), hmsm(3, 5, 8, 100));
+ check!(hmsm(3, 5, 7, 1_300), Duration::milliseconds(1800), hmsm(3, 5, 9, 100));
+ check!(hmsm(3, 5, 7, 900), Duration::seconds(86399), hmsm(3, 5, 6, 900)); // overwrap
+ check!(hmsm(3, 5, 7, 900), Duration::seconds(-86399), hmsm(3, 5, 8, 900));
+ check!(hmsm(3, 5, 7, 900), Duration::days(12345), hmsm(3, 5, 7, 900));
+ check!(hmsm(3, 5, 7, 1_300), Duration::days(1), hmsm(3, 5, 7, 300));
+ check!(hmsm(3, 5, 7, 1_300), Duration::days(-1), hmsm(3, 5, 8, 300));
+
+ // regression tests for #37
+ check!(hmsm(0, 0, 0, 0), Duration::milliseconds(-990), hmsm(23, 59, 59, 10));
+ check!(hmsm(0, 0, 0, 0), Duration::milliseconds(-9990), hmsm(23, 59, 50, 10));
+}
+
+#[test]
+fn test_time_overflowing_add() {
+ let hmsm = |h, m, s, ms| NaiveTime::from_hms_milli_opt(h, m, s, ms).unwrap();
+
+ assert_eq!(
+ hmsm(3, 4, 5, 678).overflowing_add_signed(Duration::hours(11)),
+ (hmsm(14, 4, 5, 678), 0)
+ );
+ assert_eq!(
+ hmsm(3, 4, 5, 678).overflowing_add_signed(Duration::hours(23)),
+ (hmsm(2, 4, 5, 678), 86_400)
+ );
+ assert_eq!(
+ hmsm(3, 4, 5, 678).overflowing_add_signed(Duration::hours(-7)),
+ (hmsm(20, 4, 5, 678), -86_400)
+ );
+
+ // overflowing_add_signed with leap seconds may be counter-intuitive
+ assert_eq!(
+ hmsm(3, 4, 5, 1_678).overflowing_add_signed(Duration::days(1)),
+ (hmsm(3, 4, 5, 678), 86_400)
+ );
+ assert_eq!(
+ hmsm(3, 4, 5, 1_678).overflowing_add_signed(Duration::days(-1)),
+ (hmsm(3, 4, 6, 678), -86_400)
+ );
+}
+
+#[test]
+fn test_time_addassignment() {
+ let hms = |h, m, s| NaiveTime::from_hms_opt(h, m, s).unwrap();
+ let mut time = hms(12, 12, 12);
+ time += Duration::hours(10);
+ assert_eq!(time, hms(22, 12, 12));
+ time += Duration::hours(10);
+ assert_eq!(time, hms(8, 12, 12));
+}
+
+#[test]
+fn test_time_subassignment() {
+ let hms = |h, m, s| NaiveTime::from_hms_opt(h, m, s).unwrap();
+ let mut time = hms(12, 12, 12);
+ time -= Duration::hours(10);
+ assert_eq!(time, hms(2, 12, 12));
+ time -= Duration::hours(10);
+ assert_eq!(time, hms(16, 12, 12));
+}
+
+#[test]
+fn test_time_sub() {
+ macro_rules! check {
+ ($lhs:expr, $rhs:expr, $diff:expr) => {{
+ // `time1 - time2 = duration` is equivalent to `time2 - time1 = -duration`
+ assert_eq!($lhs.signed_duration_since($rhs), $diff);
+ assert_eq!($rhs.signed_duration_since($lhs), -$diff);
+ }};
+ }
+
+ let hmsm = |h, m, s, ms| NaiveTime::from_hms_milli_opt(h, m, s, ms).unwrap();
+
+ check!(hmsm(3, 5, 7, 900), hmsm(3, 5, 7, 900), Duration::zero());
+ check!(hmsm(3, 5, 7, 900), hmsm(3, 5, 7, 600), Duration::milliseconds(300));
+ check!(hmsm(3, 5, 7, 200), hmsm(2, 4, 6, 200), Duration::seconds(3600 + 60 + 1));
+ check!(
+ hmsm(3, 5, 7, 200),
+ hmsm(2, 4, 6, 300),
+ Duration::seconds(3600 + 60) + Duration::milliseconds(900)
+ );
+
+ // treats the leap second as if it coincides with the prior non-leap second,
+ // as required by `time1 - time2 = duration` and `time2 - time1 = -duration` equivalence.
+ check!(hmsm(3, 5, 7, 200), hmsm(3, 5, 6, 1_800), Duration::milliseconds(400));
+ check!(hmsm(3, 5, 7, 1_200), hmsm(3, 5, 6, 1_800), Duration::milliseconds(1400));
+ check!(hmsm(3, 5, 7, 1_200), hmsm(3, 5, 6, 800), Duration::milliseconds(1400));
+
+ // additional equality: `time1 + duration = time2` is equivalent to
+ // `time2 - time1 = duration` IF AND ONLY IF `time2` represents a non-leap second.
+ assert_eq!(hmsm(3, 5, 6, 800) + Duration::milliseconds(400), hmsm(3, 5, 7, 200));
+ assert_eq!(hmsm(3, 5, 6, 1_800) + Duration::milliseconds(400), hmsm(3, 5, 7, 200));
+}
+
+#[test]
+fn test_time_fmt() {
+ assert_eq!(
+ format!("{}", NaiveTime::from_hms_milli_opt(23, 59, 59, 999).unwrap()),
+ "23:59:59.999"
+ );
+ assert_eq!(
+ format!("{}", NaiveTime::from_hms_milli_opt(23, 59, 59, 1_000).unwrap()),
+ "23:59:60"
+ );
+ assert_eq!(
+ format!("{}", NaiveTime::from_hms_milli_opt(23, 59, 59, 1_001).unwrap()),
+ "23:59:60.001"
+ );
+ assert_eq!(
+ format!("{}", NaiveTime::from_hms_micro_opt(0, 0, 0, 43210).unwrap()),
+ "00:00:00.043210"
+ );
+ assert_eq!(
+ format!("{}", NaiveTime::from_hms_nano_opt(0, 0, 0, 6543210).unwrap()),
+ "00:00:00.006543210"
+ );
+
+ // the format specifier should have no effect on `NaiveTime`
+ assert_eq!(
+ format!("{:30}", NaiveTime::from_hms_milli_opt(3, 5, 7, 9).unwrap()),
+ "03:05:07.009"
+ );
+}
+
+#[test]
+fn test_date_from_str() {
+ // valid cases
+ let valid = [
+ "0:0:0",
+ "0:0:0.0000000",
+ "0:0:0.0000003",
+ " 4 : 3 : 2.1 ",
+ " 09:08:07 ",
+ " 9:8:07 ",
+ "23:59:60.373929310237",
+ ];
+ for &s in &valid {
+ let d = match s.parse::<NaiveTime>() {
+ Ok(d) => d,
+ Err(e) => panic!("parsing `{}` has failed: {}", s, e),
+ };
+ let s_ = format!("{:?}", d);
+ // `s` and `s_` may differ, but `s.parse()` and `s_.parse()` must be same
+ let d_ = match s_.parse::<NaiveTime>() {
+ Ok(d) => d,
+ Err(e) => {
+ panic!("`{}` is parsed into `{:?}`, but reparsing that has failed: {}", s, d, e)
+ }
+ };
+ assert!(
+ d == d_,
+ "`{}` is parsed into `{:?}`, but reparsed result \
+ `{:?}` does not match",
+ s,
+ d,
+ d_
+ );
+ }
+
+ // some invalid cases
+ // since `ParseErrorKind` is private, all we can do is to check if there was an error
+ assert!("".parse::<NaiveTime>().is_err());
+ assert!("x".parse::<NaiveTime>().is_err());
+ assert!("15".parse::<NaiveTime>().is_err());
+ assert!("15:8".parse::<NaiveTime>().is_err());
+ assert!("15:8:x".parse::<NaiveTime>().is_err());
+ assert!("15:8:9x".parse::<NaiveTime>().is_err());
+ assert!("23:59:61".parse::<NaiveTime>().is_err());
+ assert!("12:34:56.x".parse::<NaiveTime>().is_err());
+ assert!("12:34:56. 0".parse::<NaiveTime>().is_err());
+}
+
+#[test]
+fn test_time_parse_from_str() {
+ let hms = |h, m, s| NaiveTime::from_hms_opt(h, m, s).unwrap();
+ assert_eq!(
+ NaiveTime::parse_from_str("2014-5-7T12:34:56+09:30", "%Y-%m-%dT%H:%M:%S%z"),
+ Ok(hms(12, 34, 56))
+ ); // ignore date and offset
+ assert_eq!(NaiveTime::parse_from_str("PM 12:59", "%P %H:%M"), Ok(hms(12, 59, 0)));
+ assert!(NaiveTime::parse_from_str("12:3456", "%H:%M:%S").is_err());
+}
+
+#[test]
+fn test_time_format() {
+ let t = NaiveTime::from_hms_nano_opt(3, 5, 7, 98765432).unwrap();
+ assert_eq!(t.format("%H,%k,%I,%l,%P,%p").to_string(), "03, 3,03, 3,am,AM");
+ assert_eq!(t.format("%M").to_string(), "05");
+ assert_eq!(t.format("%S,%f,%.f").to_string(), "07,098765432,.098765432");
+ assert_eq!(t.format("%.3f,%.6f,%.9f").to_string(), ".098,.098765,.098765432");
+ assert_eq!(t.format("%R").to_string(), "03:05");
+ assert_eq!(t.format("%T,%X").to_string(), "03:05:07,03:05:07");
+ assert_eq!(t.format("%r").to_string(), "03:05:07 AM");
+ assert_eq!(t.format("%t%n%%%n%t").to_string(), "\t\n%\n\t");
+
+ let t = NaiveTime::from_hms_micro_opt(3, 5, 7, 432100).unwrap();
+ assert_eq!(t.format("%S,%f,%.f").to_string(), "07,432100000,.432100");
+ assert_eq!(t.format("%.3f,%.6f,%.9f").to_string(), ".432,.432100,.432100000");
+
+ let t = NaiveTime::from_hms_milli_opt(3, 5, 7, 210).unwrap();
+ assert_eq!(t.format("%S,%f,%.f").to_string(), "07,210000000,.210");
+ assert_eq!(t.format("%.3f,%.6f,%.9f").to_string(), ".210,.210000,.210000000");
+
+ let t = NaiveTime::from_hms_opt(3, 5, 7).unwrap();
+ assert_eq!(t.format("%S,%f,%.f").to_string(), "07,000000000,");
+ assert_eq!(t.format("%.3f,%.6f,%.9f").to_string(), ".000,.000000,.000000000");
+
+ // corner cases
+ assert_eq!(NaiveTime::from_hms_opt(13, 57, 9).unwrap().format("%r").to_string(), "01:57:09 PM");
+ assert_eq!(
+ NaiveTime::from_hms_milli_opt(23, 59, 59, 1_000).unwrap().format("%X").to_string(),
+ "23:59:60"
+ );
+}
diff --git a/vendor/chrono/src/offset/fixed.rs b/vendor/chrono/src/offset/fixed.rs
index 83f42a1a4..0989dfa5b 100644
--- a/vendor/chrono/src/offset/fixed.rs
+++ b/vendor/chrono/src/offset/fixed.rs
@@ -5,21 +5,25 @@
use core::fmt;
use core::ops::{Add, Sub};
-use oldtime::Duration as OldDuration;
+
+use num_integer::div_mod_floor;
+#[cfg(feature = "rkyv")]
+use rkyv::{Archive, Deserialize, Serialize};
use super::{LocalResult, Offset, TimeZone};
-use div::div_mod_floor;
-use naive::{NaiveDate, NaiveDateTime, NaiveTime};
-use DateTime;
-use Timelike;
+use crate::naive::{NaiveDate, NaiveDateTime, NaiveTime};
+use crate::oldtime::Duration as OldDuration;
+use crate::DateTime;
+use crate::Timelike;
/// The time zone with fixed offset, from UTC-23:59:59 to UTC+23:59:59.
///
/// Using the [`TimeZone`](./trait.TimeZone.html) methods
/// on a `FixedOffset` struct is the preferred way to construct
-/// `DateTime<FixedOffset>` instances. See the [`east`](#method.east) and
-/// [`west`](#method.west) methods for examples.
+/// `DateTime<FixedOffset>` instances. See the [`east_opt`](#method.east_opt) and
+/// [`west_opt`](#method.west_opt) methods for examples.
#[derive(PartialEq, Eq, Hash, Copy, Clone)]
+#[cfg_attr(feature = "rkyv", derive(Archive, Deserialize, Serialize))]
pub struct FixedOffset {
local_minus_utc: i32,
}
@@ -29,16 +33,7 @@ impl FixedOffset {
/// The negative `secs` means the Western Hemisphere.
///
/// Panics on the out-of-bound `secs`.
- ///
- /// # Example
- ///
- /// ~~~~
- /// use chrono::{FixedOffset, TimeZone};
- /// let hour = 3600;
- /// let datetime = FixedOffset::east(5 * hour).ymd(2016, 11, 08)
- /// .and_hms(0, 0, 0);
- /// assert_eq!(&datetime.to_rfc3339(), "2016-11-08T00:00:00+05:00")
- /// ~~~~
+ #[deprecated(since = "0.4.23", note = "use `east_opt()` instead")]
pub fn east(secs: i32) -> FixedOffset {
FixedOffset::east_opt(secs).expect("FixedOffset::east out of bounds")
}
@@ -47,6 +42,16 @@ impl FixedOffset {
/// The negative `secs` means the Western Hemisphere.
///
/// Returns `None` on the out-of-bound `secs`.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// 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();
+ /// assert_eq!(&datetime.to_rfc3339(), "2016-11-08T00:00:00+05:00")
+ /// ```
pub fn east_opt(secs: i32) -> Option<FixedOffset> {
if -86_400 < secs && secs < 86_400 {
Some(FixedOffset { local_minus_utc: secs })
@@ -59,16 +64,7 @@ impl FixedOffset {
/// The negative `secs` means the Eastern Hemisphere.
///
/// Panics on the out-of-bound `secs`.
- ///
- /// # Example
- ///
- /// ~~~~
- /// use chrono::{FixedOffset, TimeZone};
- /// let hour = 3600;
- /// let datetime = FixedOffset::west(5 * hour).ymd(2016, 11, 08)
- /// .and_hms(0, 0, 0);
- /// assert_eq!(&datetime.to_rfc3339(), "2016-11-08T00:00:00-05:00")
- /// ~~~~
+ #[deprecated(since = "0.4.23", note = "use `west_opt()` instead")]
pub fn west(secs: i32) -> FixedOffset {
FixedOffset::west_opt(secs).expect("FixedOffset::west out of bounds")
}
@@ -77,6 +73,16 @@ impl FixedOffset {
/// The negative `secs` means the Eastern Hemisphere.
///
/// Returns `None` on the out-of-bound `secs`.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// 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();
+ /// assert_eq!(&datetime.to_rfc3339(), "2016-11-08T00:00:00-05:00")
+ /// ```
pub fn west_opt(secs: i32) -> Option<FixedOffset> {
if -86_400 < secs && secs < 86_400 {
Some(FixedOffset { local_minus_utc: -secs })
@@ -87,13 +93,13 @@ impl FixedOffset {
/// Returns the number of seconds to add to convert from UTC to the local time.
#[inline]
- pub fn local_minus_utc(&self) -> i32 {
+ pub const fn local_minus_utc(&self) -> i32 {
self.local_minus_utc
}
/// Returns the number of seconds to add to convert from the local time to UTC.
#[inline]
- pub fn utc_minus_local(&self) -> i32 {
+ pub const fn utc_minus_local(&self) -> i32 {
-self.local_minus_utc
}
}
@@ -146,6 +152,16 @@ impl fmt::Display for FixedOffset {
}
}
+#[cfg(feature = "arbitrary")]
+impl arbitrary::Arbitrary<'_> for FixedOffset {
+ fn arbitrary(u: &mut arbitrary::Unstructured) -> arbitrary::Result<FixedOffset> {
+ let secs = u.int_in_range(-86_399..=86_399)?;
+ let fixed_offset = FixedOffset::east_opt(secs)
+ .expect("Could not generate a valid chrono::FixedOffset. It looks like implementation of Arbitrary for FixedOffset is erroneous.");
+ Ok(fixed_offset)
+ }
+}
+
// addition or subtraction of FixedOffset to/from Timelike values is the same as
// adding or subtracting the offset's local_minus_utc value
// but keep keeps the leap second information.
@@ -218,26 +234,50 @@ impl<Tz: TimeZone> Sub<FixedOffset> for DateTime<Tz> {
#[cfg(test)]
mod tests {
use super::FixedOffset;
- use offset::TimeZone;
+ use crate::offset::TimeZone;
#[test]
fn test_date_extreme_offset() {
// starting from 0.3 we don't have an offset exceeding one day.
// this makes everything easier!
assert_eq!(
- format!("{:?}", FixedOffset::east(86399).ymd(2012, 2, 29)),
- "2012-02-29+23:59:59".to_string()
+ format!(
+ "{:?}",
+ FixedOffset::east_opt(86399)
+ .unwrap()
+ .with_ymd_and_hms(2012, 2, 29, 5, 6, 7)
+ .unwrap()
+ ),
+ "2012-02-29T05:06:07+23:59:59".to_string()
);
assert_eq!(
- format!("{:?}", FixedOffset::east(86399).ymd(2012, 2, 29).and_hms(5, 6, 7)),
+ format!(
+ "{:?}",
+ FixedOffset::east_opt(86399)
+ .unwrap()
+ .with_ymd_and_hms(2012, 2, 29, 5, 6, 7)
+ .unwrap()
+ ),
"2012-02-29T05:06:07+23:59:59".to_string()
);
assert_eq!(
- format!("{:?}", FixedOffset::west(86399).ymd(2012, 3, 4)),
- "2012-03-04-23:59:59".to_string()
+ format!(
+ "{:?}",
+ FixedOffset::west_opt(86399)
+ .unwrap()
+ .with_ymd_and_hms(2012, 3, 4, 5, 6, 7)
+ .unwrap()
+ ),
+ "2012-03-04T05:06:07-23:59:59".to_string()
);
assert_eq!(
- format!("{:?}", FixedOffset::west(86399).ymd(2012, 3, 4).and_hms(5, 6, 7)),
+ format!(
+ "{:?}",
+ FixedOffset::west_opt(86399)
+ .unwrap()
+ .with_ymd_and_hms(2012, 3, 4, 5, 6, 7)
+ .unwrap()
+ ),
"2012-03-04T05:06:07-23:59:59".to_string()
);
}
diff --git a/vendor/chrono/src/offset/local.rs b/vendor/chrono/src/offset/local.rs
deleted file mode 100644
index 1abb3a9db..000000000
--- a/vendor/chrono/src/offset/local.rs
+++ /dev/null
@@ -1,227 +0,0 @@
-// This is a part of Chrono.
-// See README.md and LICENSE.txt for details.
-
-//! The local (system) time zone.
-
-#[cfg(not(all(target_arch = "wasm32", not(target_os = "wasi"), feature = "wasmbind")))]
-use sys::{self, Timespec};
-
-use super::fixed::FixedOffset;
-use super::{LocalResult, TimeZone};
-#[cfg(not(all(target_arch = "wasm32", not(target_os = "wasi"), feature = "wasmbind")))]
-use naive::NaiveTime;
-use naive::{NaiveDate, NaiveDateTime};
-use {Date, DateTime};
-#[cfg(not(all(target_arch = "wasm32", not(target_os = "wasi"), feature = "wasmbind")))]
-use {Datelike, Timelike};
-
-/// 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", not(target_os = "wasi"), feature = "wasmbind")))]
-fn tm_to_datetime(mut tm: sys::Tm) -> DateTime<Local> {
- if tm.tm_sec >= 60 {
- tm.tm_nsec += (tm.tm_sec - 59) * 1_000_000_000;
- tm.tm_sec = 59;
- }
-
- #[cfg(not(windows))]
- fn tm_to_naive_date(tm: &sys::Tm) -> NaiveDate {
- // from_yo is more efficient than from_ymd (since it's the internal representation).
- NaiveDate::from_yo(tm.tm_year + 1900, tm.tm_yday as u32 + 1)
- }
-
- #[cfg(windows)]
- fn tm_to_naive_date(tm: &sys::Tm) -> NaiveDate {
- // ...but tm_yday is broken in Windows (issue #85)
- NaiveDate::from_ymd(tm.tm_year + 1900, tm.tm_mon as u32 + 1, tm.tm_mday as u32)
- }
-
- let date = tm_to_naive_date(&tm);
- 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(tm.tm_utcoff);
- DateTime::from_utc(date.and_time(time) - offset, offset)
-}
-
-/// Converts a local `NaiveDateTime` to the `time::Timespec`.
-#[cfg(not(all(target_arch = "wasm32", not(target_os = "wasi"), feature = "wasmbind")))]
-fn datetime_to_timespec(d: &NaiveDateTime, local: bool) -> sys::Timespec {
- // well, this exploits an undocumented `Tm::to_timespec` behavior
- // to get the exact function we want (either `timegm` or `mktime`).
- // the number 1 is arbitrary but should be non-zero to trigger `mktime`.
- let tm_utcoff = if local { 1 } else { 0 };
-
- let tm = sys::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,
- tm_utcoff: tm_utcoff,
- // do not set this, OS APIs are heavily inconsistent in terms of leap second handling
- tm_nsec: 0,
- };
-
- tm.to_timespec()
-}
-
-/// The local timescale. This is implemented via the standard `time` crate.
-///
-/// Using the [`TimeZone`](./trait.TimeZone.html) methods
-/// on the Local struct is the preferred way to construct `DateTime<Local>`
-/// instances.
-///
-/// # Example
-///
-/// ~~~~
-/// use chrono::{Local, DateTime, TimeZone};
-///
-/// let dt: DateTime<Local> = Local::now();
-/// let dt: DateTime<Local> = Local.timestamp(0, 0);
-/// ~~~~
-#[derive(Copy, Clone, Debug)]
-pub struct Local;
-
-impl Local {
- /// Returns a `Date` which corresponds to the current date.
- pub fn today() -> Date<Local> {
- Local::now().date()
- }
-
- /// Returns a `DateTime` which corresponds to the current date.
- #[cfg(not(all(target_arch = "wasm32", not(target_os = "wasi"), feature = "wasmbind")))]
- pub fn now() -> DateTime<Local> {
- tm_to_datetime(Timespec::now().local())
- }
-
- /// Returns a `DateTime` which corresponds to the current date.
- #[cfg(all(target_arch = "wasm32", not(target_os = "wasi"), feature = "wasmbind"))]
- pub fn now() -> DateTime<Local> {
- use super::Utc;
- let now: DateTime<Utc> = super::Utc::now();
-
- // Workaround missing timezone logic in `time` crate
- let offset = FixedOffset::west((js_sys::Date::new_0().get_timezone_offset() as i32) * 60);
- DateTime::from_utc(now.naive_utc(), offset)
- }
-}
-
-impl TimeZone for Local {
- type Offset = FixedOffset;
-
- fn from_offset(_offset: &FixedOffset) -> Local {
- Local
- }
-
- // they are easier to define in terms of the finished date and time unlike other offsets
- fn offset_from_local_date(&self, local: &NaiveDate) -> LocalResult<FixedOffset> {
- self.from_local_date(local).map(|date| *date.offset())
- }
-
- fn offset_from_local_datetime(&self, local: &NaiveDateTime) -> LocalResult<FixedOffset> {
- self.from_local_datetime(local).map(|datetime| *datetime.offset())
- }
-
- fn offset_from_utc_date(&self, utc: &NaiveDate) -> FixedOffset {
- *self.from_utc_date(utc).offset()
- }
-
- fn offset_from_utc_datetime(&self, utc: &NaiveDateTime) -> FixedOffset {
- *self.from_utc_datetime(utc).offset()
- }
-
- // override them for avoiding redundant works
- 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(0, 0, 0));
- midnight.map(|datetime| Date::from_utc(*local, *datetime.offset()))
- }
-
- #[cfg(all(target_arch = "wasm32", not(target_os = "wasi"), feature = "wasmbind"))]
- 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((js_sys::Date::new_0().get_timezone_offset() as i32) * 60);
- local -= ::Duration::seconds(offset.local_minus_utc() as i64);
- LocalResult::Single(DateTime::from_utc(local, offset))
- }
-
- #[cfg(not(all(target_arch = "wasm32", not(target_os = "wasi"), feature = "wasmbind")))]
- fn from_local_datetime(&self, local: &NaiveDateTime) -> LocalResult<DateTime<Local>> {
- let timespec = datetime_to_timespec(local, true);
-
- // datetime_to_timespec completely ignores leap seconds, so we need to adjust for them
- let mut tm = timespec.local();
- assert_eq!(tm.tm_nsec, 0);
- tm.tm_nsec = local.nanosecond() as i32;
-
- LocalResult::Single(tm_to_datetime(tm))
- }
-
- fn from_utc_date(&self, utc: &NaiveDate) -> Date<Local> {
- let midnight = self.from_utc_datetime(&utc.and_hms(0, 0, 0));
- Date::from_utc(*utc, *midnight.offset())
- }
-
- #[cfg(all(target_arch = "wasm32", not(target_os = "wasi"), feature = "wasmbind"))]
- fn from_utc_datetime(&self, utc: &NaiveDateTime) -> DateTime<Local> {
- // Get the offset from the js runtime
- let offset = FixedOffset::west((js_sys::Date::new_0().get_timezone_offset() as i32) * 60);
- DateTime::from_utc(*utc, offset)
- }
-
- #[cfg(not(all(target_arch = "wasm32", not(target_os = "wasi"), feature = "wasmbind")))]
- fn from_utc_datetime(&self, utc: &NaiveDateTime) -> DateTime<Local> {
- let timespec = datetime_to_timespec(utc, false);
-
- // datetime_to_timespec completely ignores leap seconds, so we need to adjust for them
- let mut tm = timespec.local();
- assert_eq!(tm.tm_nsec, 0);
- tm.tm_nsec = utc.nanosecond() as i32;
-
- tm_to_datetime(tm)
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::Local;
- use offset::TimeZone;
- use Datelike;
-
- #[test]
- fn test_local_date_sanity_check() {
- // issue #27
- assert_eq!(Local.ymd(2999, 12, 28).day(), 28);
- }
-
- #[test]
- fn test_leap_second() {
- // issue #123
- let today = Local::today();
-
- let dt = today.and_hms_milli(1, 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 == "01:02:60" || timestr == "01:03:00", "unexpected timestr {:?}", timestr);
-
- let dt = today.and_hms_milli(1, 2, 3, 1234);
- let timestr = dt.time().to_string();
- assert!(
- timestr == "01:02:03.234" || timestr == "01:02:04.234",
- "unexpected timestr {:?}",
- timestr
- );
- }
-}
diff --git a/vendor/chrono/src/offset/local/mod.rs b/vendor/chrono/src/offset/local/mod.rs
new file mode 100644
index 000000000..e280c7800
--- /dev/null
+++ b/vendor/chrono/src/offset/local/mod.rs
@@ -0,0 +1,260 @@
+// This is a part of Chrono.
+// See README.md and LICENSE.txt for details.
+
+//! The local (system) time zone.
+
+#[cfg(feature = "rkyv")]
+use rkyv::{Archive, Deserialize, Serialize};
+
+use super::fixed::FixedOffset;
+use super::{LocalResult, TimeZone};
+use crate::naive::{NaiveDate, NaiveDateTime};
+#[allow(deprecated)]
+use crate::{Date, DateTime};
+
+// 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),
+ not(all(
+ target_arch = "wasm32",
+ feature = "wasmbind",
+ not(any(target_os = "emscripten", target_os = "wasi"))
+ ))
+))]
+#[path = "stub.rs"]
+mod inner;
+
+#[cfg(unix)]
+#[path = "unix.rs"]
+mod inner;
+
+#[cfg(windows)]
+#[path = "windows.rs"]
+mod inner;
+
+#[cfg(unix)]
+mod tz_info;
+
+/// The local timescale. This is implemented via the standard `time` crate.
+///
+/// Using the [`TimeZone`](./trait.TimeZone.html) methods
+/// on the Local struct is the preferred way to construct `DateTime<Local>`
+/// instances.
+///
+/// # Example
+///
+/// ```
+/// use chrono::{Local, DateTime, TimeZone};
+///
+/// let dt: DateTime<Local> = Local::now();
+/// let dt: DateTime<Local> = Local.timestamp(0, 0);
+/// ```
+#[derive(Copy, Clone, Debug)]
+#[cfg_attr(feature = "rkyv", derive(Archive, Deserialize, Serialize))]
+#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
+pub struct Local;
+
+impl Local {
+ /// Returns a `Date` which corresponds to the current date.
+ #[deprecated(since = "0.4.23", note = "use `Local::now()` instead")]
+ #[allow(deprecated)]
+ pub fn today() -> Date<Local> {
+ Local::now().date()
+ }
+
+ /// Returns a `DateTime` which corresponds to the current date and time.
+ #[cfg(not(all(
+ target_arch = "wasm32",
+ feature = "wasmbind",
+ not(any(target_os = "emscripten", target_os = "wasi"))
+ )))]
+ pub fn now() -> DateTime<Local> {
+ inner::now()
+ }
+
+ /// Returns a `DateTime` which corresponds to the current date and time.
+ #[cfg(all(
+ target_arch = "wasm32",
+ feature = "wasmbind",
+ not(any(target_os = "emscripten", target_os = "wasi"))
+ ))]
+ pub fn now() -> DateTime<Local> {
+ use super::Utc;
+ let now: DateTime<Utc> = super::Utc::now();
+
+ // Workaround missing timezone logic in `time` crate
+ let offset =
+ FixedOffset::west_opt((js_sys::Date::new_0().get_timezone_offset() as i32) * 60)
+ .unwrap();
+ DateTime::from_utc(now.naive_utc(), offset)
+ }
+}
+
+impl TimeZone for Local {
+ type Offset = FixedOffset;
+
+ fn from_offset(_offset: &FixedOffset) -> 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())
+ }
+
+ fn offset_from_local_datetime(&self, local: &NaiveDateTime) -> LocalResult<FixedOffset> {
+ self.from_local_datetime(local).map(|datetime| *datetime.offset())
+ }
+
+ #[allow(deprecated)]
+ fn offset_from_utc_date(&self, utc: &NaiveDate) -> FixedOffset {
+ *self.from_utc_date(utc).offset()
+ }
+
+ 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()
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::Local;
+ use crate::offset::TimeZone;
+ use crate::{Datelike, Duration, Utc};
+
+ #[test]
+ fn verify_correct_offsets() {
+ let now = Local::now();
+ let from_local = Local.from_local_datetime(&now.naive_local()).unwrap();
+ let from_utc = Local.from_utc_datetime(&now.naive_utc());
+
+ assert_eq!(now.offset().local_minus_utc(), from_local.offset().local_minus_utc());
+ assert_eq!(now.offset().local_minus_utc(), from_utc.offset().local_minus_utc());
+
+ assert_eq!(now, from_local);
+ assert_eq!(now, from_utc);
+ }
+
+ #[test]
+ fn verify_correct_offsets_distant_past() {
+ // let distant_past = Local::now() - Duration::days(365 * 100);
+ let distant_past = Local::now() - Duration::days(250 * 31);
+ let from_local = Local.from_local_datetime(&distant_past.naive_local()).unwrap();
+ let from_utc = Local.from_utc_datetime(&distant_past.naive_utc());
+
+ assert_eq!(distant_past.offset().local_minus_utc(), from_local.offset().local_minus_utc());
+ assert_eq!(distant_past.offset().local_minus_utc(), from_utc.offset().local_minus_utc());
+
+ assert_eq!(distant_past, from_local);
+ assert_eq!(distant_past, from_utc);
+ }
+
+ #[test]
+ fn verify_correct_offsets_distant_future() {
+ let distant_future = Local::now() + Duration::days(250 * 31);
+ let from_local = Local.from_local_datetime(&distant_future.naive_local()).unwrap();
+ let from_utc = Local.from_utc_datetime(&distant_future.naive_utc());
+
+ assert_eq!(
+ distant_future.offset().local_minus_utc(),
+ from_local.offset().local_minus_utc()
+ );
+ assert_eq!(distant_future.offset().local_minus_utc(), from_utc.offset().local_minus_utc());
+
+ assert_eq!(distant_future, from_local);
+ assert_eq!(distant_future, from_utc);
+ }
+
+ #[test]
+ fn test_local_date_sanity_check() {
+ // issue #27
+ assert_eq!(Local.with_ymd_and_hms(2999, 12, 28, 0, 0, 0).unwrap().day(), 28);
+ }
+
+ #[test]
+ fn test_leap_second() {
+ // 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
+ );
+ }
+}
diff --git a/vendor/chrono/src/offset/local/stub.rs b/vendor/chrono/src/offset/local/stub.rs
new file mode 100644
index 000000000..9ececd3c2
--- /dev/null
+++ b/vendor/chrono/src/offset/local/stub.rs
@@ -0,0 +1,236 @@
+// 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
new file mode 100644
index 000000000..bd2693b6b
--- /dev/null
+++ b/vendor/chrono/src/offset/local/tz_info/mod.rs
@@ -0,0 +1,131 @@
+#![deny(missing_docs)]
+#![allow(dead_code)]
+#![warn(unreachable_pub)]
+
+use std::num::ParseIntError;
+use std::str::Utf8Error;
+use std::time::SystemTimeError;
+use std::{error, fmt, io};
+
+mod timezone;
+pub(crate) use timezone::TimeZone;
+
+mod parser;
+mod rule;
+
+/// Unified error type for everything in the crate
+#[derive(Debug)]
+pub(crate) enum Error {
+ /// Date time error
+ DateTime(&'static str),
+ /// Local time type search error
+ FindLocalTimeType(&'static str),
+ /// Local time type error
+ LocalTimeType(&'static str),
+ /// Invalid slice for integer conversion
+ InvalidSlice(&'static str),
+ /// Invalid Tzif file
+ InvalidTzFile(&'static str),
+ /// Invalid TZ string
+ InvalidTzString(&'static str),
+ /// I/O error
+ Io(io::Error),
+ /// Out of range error
+ OutOfRange(&'static str),
+ /// Integer parsing error
+ ParseInt(ParseIntError),
+ /// Date time projection error
+ ProjectDateTime(&'static str),
+ /// System time error
+ SystemTime(SystemTimeError),
+ /// Time zone error
+ TimeZone(&'static str),
+ /// Transition rule error
+ TransitionRule(&'static str),
+ /// Unsupported Tzif file
+ UnsupportedTzFile(&'static str),
+ /// Unsupported TZ string
+ UnsupportedTzString(&'static str),
+ /// UTF-8 error
+ Utf8(Utf8Error),
+}
+
+impl fmt::Display for Error {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ use Error::*;
+ match self {
+ DateTime(error) => write!(f, "invalid date time: {}", error),
+ FindLocalTimeType(error) => error.fmt(f),
+ LocalTimeType(error) => write!(f, "invalid local time type: {}", error),
+ InvalidSlice(error) => error.fmt(f),
+ InvalidTzString(error) => write!(f, "invalid TZ string: {}", error),
+ InvalidTzFile(error) => error.fmt(f),
+ Io(error) => error.fmt(f),
+ OutOfRange(error) => error.fmt(f),
+ ParseInt(error) => error.fmt(f),
+ ProjectDateTime(error) => error.fmt(f),
+ SystemTime(error) => error.fmt(f),
+ TransitionRule(error) => write!(f, "invalid transition rule: {}", error),
+ TimeZone(error) => write!(f, "invalid time zone: {}", error),
+ UnsupportedTzFile(error) => error.fmt(f),
+ UnsupportedTzString(error) => write!(f, "unsupported TZ string: {}", error),
+ Utf8(error) => error.fmt(f),
+ }
+ }
+}
+
+impl error::Error for Error {}
+
+impl From<io::Error> for Error {
+ fn from(error: io::Error) -> Self {
+ Error::Io(error)
+ }
+}
+
+impl From<ParseIntError> for Error {
+ fn from(error: ParseIntError) -> Self {
+ Error::ParseInt(error)
+ }
+}
+
+impl From<SystemTimeError> for Error {
+ fn from(error: SystemTimeError) -> Self {
+ Error::SystemTime(error)
+ }
+}
+
+impl From<Utf8Error> for Error {
+ fn from(error: Utf8Error) -> Self {
+ Error::Utf8(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
+const SECONDS_PER_HOUR: i64 = 3600;
+/// Number of seconds in one day
+const SECONDS_PER_DAY: i64 = SECONDS_PER_HOUR * HOURS_PER_DAY;
+/// Number of days in one week
+const DAYS_PER_WEEK: i64 = 7;
+
+/// Month days in a normal year
+const DAY_IN_MONTHS_NORMAL_YEAR: [i64; 12] = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
+/// Cumulated month days in a normal year
+const CUMUL_DAY_IN_MONTHS_NORMAL_YEAR: [i64; 12] =
+ [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334];
diff --git a/vendor/chrono/src/offset/local/tz_info/parser.rs b/vendor/chrono/src/offset/local/tz_info/parser.rs
new file mode 100644
index 000000000..5652a0ea9
--- /dev/null
+++ b/vendor/chrono/src/offset/local/tz_info/parser.rs
@@ -0,0 +1,334 @@
+use std::io::{self, ErrorKind};
+use std::iter;
+use std::num::ParseIntError;
+use std::str::{self, FromStr};
+
+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)?;
+ let (state, footer) = match state.header.version {
+ Version::V1 => match cursor.is_empty() {
+ true => (state, None),
+ false => {
+ return Err(Error::InvalidTzFile("remaining data after end of TZif v1 data block"))
+ }
+ },
+ Version::V2 | Version::V3 => {
+ let state = State::new(&mut cursor, false)?;
+ (state, Some(cursor.remaining()))
+ }
+ };
+
+ let mut transitions = Vec::with_capacity(state.header.transition_count);
+ for (arr_time, &local_time_type_index) in
+ state.transition_times.chunks_exact(state.time_size).zip(state.transition_types)
+ {
+ let unix_leap_time =
+ state.parse_time(&arr_time[0..state.time_size], state.header.version)?;
+ let local_time_type_index = local_time_type_index as usize;
+ transitions.push(Transition::new(unix_leap_time, local_time_type_index));
+ }
+
+ let mut local_time_types = Vec::with_capacity(state.header.type_count);
+ for arr in state.local_time_types.chunks_exact(6) {
+ let ut_offset = read_be_i32(&arr[..4])?;
+
+ let is_dst = match arr[4] {
+ 0 => false,
+ 1 => true,
+ _ => return Err(Error::InvalidTzFile("invalid DST indicator")),
+ };
+
+ let char_index = arr[5] as usize;
+ if char_index >= state.header.char_count {
+ return Err(Error::InvalidTzFile("invalid time zone name char index"));
+ }
+
+ let position = match state.names[char_index..].iter().position(|&c| c == b'\0') {
+ Some(position) => position,
+ None => return Err(Error::InvalidTzFile("invalid time zone name char index")),
+ };
+
+ let name = &state.names[char_index..char_index + position];
+ let name = if !name.is_empty() { Some(name) } else { None };
+ local_time_types.push(LocalTimeType::new(ut_offset, is_dst, name)?);
+ }
+
+ let mut leap_seconds = Vec::with_capacity(state.header.leap_count);
+ for arr in state.leap_seconds.chunks_exact(state.time_size + 4) {
+ let unix_leap_time = state.parse_time(&arr[0..state.time_size], state.header.version)?;
+ let correction = read_be_i32(&arr[state.time_size..state.time_size + 4])?;
+ 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));
+ 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",
+ ));
+ }
+
+ let extra_rule = match footer {
+ Some(footer) => {
+ let footer = str::from_utf8(footer)?;
+ if !(footer.starts_with('\n') && footer.ends_with('\n')) {
+ return Err(Error::InvalidTzFile("invalid footer"));
+ }
+
+ let tz_string = footer.trim_matches(|c: char| c.is_ascii_whitespace());
+ if tz_string.starts_with(':') || tz_string.contains('\0') {
+ return Err(Error::InvalidTzFile("invalid footer"));
+ }
+
+ match tz_string.is_empty() {
+ true => None,
+ false => Some(TransitionRule::from_tz_string(
+ tz_string.as_bytes(),
+ state.header.version == Version::V3,
+ )?),
+ }
+ }
+ None => None,
+ };
+
+ TimeZone::new(transitions, local_time_types, leap_seconds, extra_rule)
+}
+
+/// TZif data blocks
+struct State<'a> {
+ header: Header,
+ /// Time size in bytes
+ time_size: usize,
+ /// Transition times data block
+ transition_times: &'a [u8],
+ /// Transition types data block
+ transition_types: &'a [u8],
+ /// Local time types data block
+ local_time_types: &'a [u8],
+ /// Time zone names data block
+ names: &'a [u8],
+ /// Leap seconds data block
+ leap_seconds: &'a [u8],
+ /// UT/local indicators data block
+ std_walls: &'a [u8],
+ /// Standard/wall indicators data block
+ ut_locals: &'a [u8],
+}
+
+impl<'a> State<'a> {
+ /// Read TZif data blocks
+ fn new(cursor: &mut Cursor<'a>, first: bool) -> Result<Self, Error> {
+ let header = Header::new(cursor)?;
+ let time_size = match first {
+ true => 4, // We always parse V1 first
+ false => 8,
+ };
+
+ Ok(Self {
+ time_size,
+ transition_times: cursor.read_exact(header.transition_count * time_size)?,
+ transition_types: cursor.read_exact(header.transition_count)?,
+ local_time_types: cursor.read_exact(header.type_count * 6)?,
+ names: cursor.read_exact(header.char_count)?,
+ leap_seconds: cursor.read_exact(header.leap_count * (time_size + 4))?,
+ std_walls: cursor.read_exact(header.std_wall_count)?,
+ ut_locals: cursor.read_exact(header.ut_local_count)?,
+ header,
+ })
+ }
+
+ /// Parse time values
+ fn parse_time(&self, arr: &[u8], version: Version) -> Result<i64, Error> {
+ match version {
+ Version::V1 => Ok(read_be_i32(&arr[..4])?.into()),
+ Version::V2 | Version::V3 => read_be_i64(arr),
+ }
+ }
+}
+
+/// TZif header
+#[derive(Debug)]
+struct Header {
+ /// TZif version
+ version: Version,
+ /// Number of UT/local indicators
+ ut_local_count: usize,
+ /// Number of standard/wall indicators
+ std_wall_count: usize,
+ /// Number of leap-second records
+ leap_count: usize,
+ /// Number of transition times
+ transition_count: usize,
+ /// Number of local time type records
+ type_count: usize,
+ /// Number of time zone names bytes
+ char_count: usize,
+}
+
+impl Header {
+ fn new(cursor: &mut Cursor) -> Result<Self, Error> {
+ let magic = cursor.read_exact(4)?;
+ if magic != *b"TZif" {
+ return Err(Error::InvalidTzFile("invalid magic number"));
+ }
+
+ let version = match cursor.read_exact(1)? {
+ [0x00] => Version::V1,
+ [0x32] => Version::V2,
+ [0x33] => Version::V3,
+ _ => return Err(Error::UnsupportedTzFile("unsupported TZif version")),
+ };
+
+ cursor.read_exact(15)?;
+ let ut_local_count = cursor.read_be_u32()?;
+ let std_wall_count = cursor.read_be_u32()?;
+ let leap_count = cursor.read_be_u32()?;
+ let transition_count = cursor.read_be_u32()?;
+ let type_count = cursor.read_be_u32()?;
+ let char_count = cursor.read_be_u32()?;
+
+ if !(type_count != 0
+ && char_count != 0
+ && (ut_local_count == 0 || ut_local_count == type_count)
+ && (std_wall_count == 0 || std_wall_count == type_count))
+ {
+ return Err(Error::InvalidTzFile("invalid header"));
+ }
+
+ Ok(Self {
+ version,
+ ut_local_count: ut_local_count as usize,
+ std_wall_count: std_wall_count as usize,
+ leap_count: leap_count as usize,
+ transition_count: transition_count as usize,
+ type_count: type_count as usize,
+ char_count: char_count as usize,
+ })
+ }
+}
+
+/// A `Cursor` contains a slice of a buffer and a read count.
+#[derive(Debug, Eq, PartialEq)]
+pub(crate) struct Cursor<'a> {
+ /// Slice representing the remaining data to be read
+ remaining: &'a [u8],
+ /// Number of already read bytes
+ read_count: usize,
+}
+
+impl<'a> Cursor<'a> {
+ /// Construct a new `Cursor` from remaining data
+ pub(crate) const fn new(remaining: &'a [u8]) -> Self {
+ Self { remaining, read_count: 0 }
+ }
+
+ pub(crate) fn peek(&self) -> Option<&u8> {
+ self.remaining().first()
+ }
+
+ /// Returns remaining data
+ pub(crate) const fn remaining(&self) -> &'a [u8] {
+ self.remaining
+ }
+
+ /// Returns `true` if data is remaining
+ pub(crate) fn is_empty(&self) -> bool {
+ self.remaining.is_empty()
+ }
+
+ pub(crate) fn read_be_u32(&mut self) -> Result<u32, Error> {
+ let mut buf = [0; 4];
+ buf.copy_from_slice(self.read_exact(4)?);
+ Ok(u32::from_be_bytes(buf))
+ }
+
+ /// Read exactly `count` bytes, reducing remaining data and incrementing read count
+ pub(crate) fn read_exact(&mut self, count: usize) -> Result<&'a [u8], io::Error> {
+ match (self.remaining.get(..count), self.remaining.get(count..)) {
+ (Some(result), Some(remaining)) => {
+ self.remaining = remaining;
+ self.read_count += count;
+ Ok(result)
+ }
+ _ => Err(io::Error::from(ErrorKind::UnexpectedEof)),
+ }
+ }
+
+ /// Read bytes and compare them to the provided tag
+ pub(crate) fn read_tag(&mut self, tag: &[u8]) -> Result<(), io::Error> {
+ if self.read_exact(tag.len())? == tag {
+ Ok(())
+ } else {
+ Err(io::Error::from(ErrorKind::InvalidData))
+ }
+ }
+
+ /// Read bytes if the remaining data is prefixed by the provided tag
+ pub(crate) fn read_optional_tag(&mut self, tag: &[u8]) -> Result<bool, io::Error> {
+ if self.remaining.starts_with(tag) {
+ self.read_exact(tag.len())?;
+ Ok(true)
+ } else {
+ Ok(false)
+ }
+ }
+
+ /// Read bytes as long as the provided predicate is true
+ pub(crate) fn read_while<F: Fn(&u8) -> bool>(&mut self, f: F) -> Result<&'a [u8], io::Error> {
+ match self.remaining.iter().position(|x| !f(x)) {
+ None => self.read_exact(self.remaining.len()),
+ Some(position) => self.read_exact(position),
+ }
+ }
+
+ // Parse an integer out of the ASCII digits
+ pub(crate) fn read_int<T: FromStr<Err = ParseIntError>>(&mut self) -> Result<T, Error> {
+ let bytes = self.read_while(u8::is_ascii_digit)?;
+ Ok(str::from_utf8(bytes)?.parse()?)
+ }
+
+ /// Read bytes until the provided predicate is true
+ pub(crate) fn read_until<F: Fn(&u8) -> bool>(&mut self, f: F) -> Result<&'a [u8], io::Error> {
+ match self.remaining.iter().position(f) {
+ None => self.read_exact(self.remaining.len()),
+ Some(position) => self.read_exact(position),
+ }
+ }
+}
+
+pub(crate) fn read_be_i32(bytes: &[u8]) -> Result<i32, Error> {
+ if bytes.len() != 4 {
+ return Err(Error::InvalidSlice("too short for i32"));
+ }
+
+ let mut buf = [0; 4];
+ buf.copy_from_slice(bytes);
+ Ok(i32::from_be_bytes(buf))
+}
+
+pub(crate) fn read_be_i64(bytes: &[u8]) -> Result<i64, Error> {
+ if bytes.len() != 8 {
+ return Err(Error::InvalidSlice("too short for i64"));
+ }
+
+ let mut buf = [0; 8];
+ buf.copy_from_slice(bytes);
+ Ok(i64::from_be_bytes(buf))
+}
+
+/// TZif version
+#[derive(Debug, Copy, Clone, Eq, PartialEq)]
+enum Version {
+ /// Version 1
+ V1,
+ /// Version 2
+ V2,
+ /// Version 3
+ V3,
+}
diff --git a/vendor/chrono/src/offset/local/tz_info/rule.rs b/vendor/chrono/src/offset/local/tz_info/rule.rs
new file mode 100644
index 000000000..7befddb5c
--- /dev/null
+++ b/vendor/chrono/src/offset/local/tz_info/rule.rs
@@ -0,0 +1,1046 @@
+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,
+ SECONDS_PER_DAY,
+};
+
+/// Transition rule
+#[derive(Debug, Copy, Clone, Eq, PartialEq)]
+pub(super) enum TransitionRule {
+ /// Fixed local time type
+ Fixed(LocalTimeType),
+ /// Alternate local time types
+ Alternate(AlternateTime),
+}
+
+impl TransitionRule {
+ /// Parse a POSIX TZ string containing a time zone description, as described in [the POSIX documentation of the `TZ` environment variable](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html).
+ ///
+ /// TZ string extensions from [RFC 8536](https://datatracker.ietf.org/doc/html/rfc8536#section-3.3.1) may be used.
+ ///
+ pub(super) fn from_tz_string(
+ tz_string: &[u8],
+ use_string_extensions: bool,
+ ) -> Result<Self, Error> {
+ let mut cursor = Cursor::new(tz_string);
+
+ let std_time_zone = Some(parse_name(&mut cursor)?);
+ let std_offset = parse_offset(&mut cursor)?;
+
+ if cursor.is_empty() {
+ return Ok(LocalTimeType::new(-std_offset, false, std_time_zone)?.into());
+ }
+
+ let dst_time_zone = Some(parse_name(&mut cursor)?);
+
+ let dst_offset = match cursor.peek() {
+ Some(&b',') => std_offset - 3600,
+ Some(_) => parse_offset(&mut cursor)?,
+ None => {
+ return Err(Error::UnsupportedTzString("DST start and end rules must be provided"))
+ }
+ };
+
+ if cursor.is_empty() {
+ return Err(Error::UnsupportedTzString("DST start and end rules must be provided"));
+ }
+
+ cursor.read_tag(b",")?;
+ let (dst_start, dst_start_time) = RuleDay::parse(&mut cursor, use_string_extensions)?;
+
+ cursor.read_tag(b",")?;
+ let (dst_end, dst_end_time) = RuleDay::parse(&mut cursor, use_string_extensions)?;
+
+ if !cursor.is_empty() {
+ return Err(Error::InvalidTzString("remaining data after parsing TZ string"));
+ }
+
+ Ok(AlternateTime::new(
+ LocalTimeType::new(-std_offset, false, std_time_zone)?,
+ LocalTimeType::new(-dst_offset, true, dst_time_zone)?,
+ dst_start,
+ dst_start_time,
+ dst_end,
+ dst_end_time,
+ )?
+ .into())
+ }
+
+ /// Find the local time type associated to the transition rule at the specified Unix time in seconds
+ pub(super) fn find_local_time_type(&self, unix_time: i64) -> Result<&LocalTimeType, Error> {
+ match self {
+ TransitionRule::Fixed(local_time_type) => Ok(local_time_type),
+ TransitionRule::Alternate(alternate_time) => {
+ alternate_time.find_local_time_type(unix_time)
+ }
+ }
+ }
+
+ /// Find the local time type associated to the transition rule at the specified Unix time in seconds
+ pub(super) fn find_local_time_type_from_local(
+ &self,
+ local_time: i64,
+ year: i32,
+ ) -> Result<crate::LocalResult<LocalTimeType>, Error> {
+ match self {
+ TransitionRule::Fixed(local_time_type) => {
+ Ok(crate::LocalResult::Single(*local_time_type))
+ }
+ TransitionRule::Alternate(alternate_time) => {
+ alternate_time.find_local_time_type_from_local(local_time, year)
+ }
+ }
+ }
+}
+
+impl From<LocalTimeType> for TransitionRule {
+ fn from(inner: LocalTimeType) -> Self {
+ TransitionRule::Fixed(inner)
+ }
+}
+
+impl From<AlternateTime> for TransitionRule {
+ fn from(inner: AlternateTime) -> Self {
+ TransitionRule::Alternate(inner)
+ }
+}
+
+/// Transition rule representing alternate local time types
+#[derive(Debug, Copy, Clone, Eq, PartialEq)]
+pub(super) struct AlternateTime {
+ /// Local time type for standard time
+ pub(super) std: LocalTimeType,
+ /// Local time type for Daylight Saving Time
+ pub(super) dst: LocalTimeType,
+ /// Start day of Daylight Saving Time
+ dst_start: RuleDay,
+ /// Local start day time of Daylight Saving Time, in seconds
+ dst_start_time: i32,
+ /// End day of Daylight Saving Time
+ dst_end: RuleDay,
+ /// Local end day time of Daylight Saving Time, in seconds
+ dst_end_time: i32,
+}
+
+impl AlternateTime {
+ /// Construct a transition rule representing alternate local time types
+ fn new(
+ std: LocalTimeType,
+ dst: LocalTimeType,
+ dst_start: RuleDay,
+ dst_start_time: i32,
+ dst_end: RuleDay,
+ dst_end_time: i32,
+ ) -> Result<Self, Error> {
+ // Overflow is not possible
+ if !((dst_start_time as i64).abs() < SECONDS_PER_WEEK
+ && (dst_end_time as i64).abs() < SECONDS_PER_WEEK)
+ {
+ return Err(Error::TransitionRule("invalid DST start or end time"));
+ }
+
+ Ok(Self { std, dst, dst_start, dst_start_time, dst_end, dst_end_time })
+ }
+
+ /// Find the local time type associated to the alternate transition rule at the specified Unix time in seconds
+ fn find_local_time_type(&self, unix_time: i64) -> Result<&LocalTimeType, Error> {
+ // Overflow is not possible
+ let dst_start_time_in_utc = self.dst_start_time as i64 - self.std.ut_offset as i64;
+ let dst_end_time_in_utc = self.dst_end_time as i64 - self.dst.ut_offset as i64;
+
+ let current_year = match UtcDateTime::from_timespec(unix_time) {
+ Ok(dt) => dt.year,
+ Err(error) => return Err(error),
+ };
+
+ // Check if the current year is valid for the following computations
+ if !(i32::min_value() + 2 <= current_year && current_year <= i32::max_value() - 2) {
+ return Err(Error::OutOfRange("out of range date time"));
+ }
+
+ let current_year_dst_start_unix_time =
+ self.dst_start.unix_time(current_year, dst_start_time_in_utc);
+ let current_year_dst_end_unix_time =
+ self.dst_end.unix_time(current_year, dst_end_time_in_utc);
+
+ // Check DST start/end Unix times for previous/current/next years to support for transition day times outside of [0h, 24h] range
+ let is_dst =
+ match Ord::cmp(&current_year_dst_start_unix_time, &current_year_dst_end_unix_time) {
+ Ordering::Less | Ordering::Equal => {
+ if unix_time < current_year_dst_start_unix_time {
+ let previous_year_dst_end_unix_time =
+ self.dst_end.unix_time(current_year - 1, dst_end_time_in_utc);
+ if unix_time < previous_year_dst_end_unix_time {
+ let previous_year_dst_start_unix_time =
+ self.dst_start.unix_time(current_year - 1, dst_start_time_in_utc);
+ previous_year_dst_start_unix_time <= unix_time
+ } else {
+ false
+ }
+ } else if unix_time < current_year_dst_end_unix_time {
+ true
+ } else {
+ let next_year_dst_start_unix_time =
+ self.dst_start.unix_time(current_year + 1, dst_start_time_in_utc);
+ if next_year_dst_start_unix_time <= unix_time {
+ let next_year_dst_end_unix_time =
+ self.dst_end.unix_time(current_year + 1, dst_end_time_in_utc);
+ unix_time < next_year_dst_end_unix_time
+ } else {
+ false
+ }
+ }
+ }
+ Ordering::Greater => {
+ if unix_time < current_year_dst_end_unix_time {
+ let previous_year_dst_start_unix_time =
+ self.dst_start.unix_time(current_year - 1, dst_start_time_in_utc);
+ if unix_time < previous_year_dst_start_unix_time {
+ let previous_year_dst_end_unix_time =
+ self.dst_end.unix_time(current_year - 1, dst_end_time_in_utc);
+ unix_time < previous_year_dst_end_unix_time
+ } else {
+ true
+ }
+ } else if unix_time < current_year_dst_start_unix_time {
+ false
+ } else {
+ let next_year_dst_end_unix_time =
+ self.dst_end.unix_time(current_year + 1, dst_end_time_in_utc);
+ if next_year_dst_end_unix_time <= unix_time {
+ let next_year_dst_start_unix_time =
+ self.dst_start.unix_time(current_year + 1, dst_start_time_in_utc);
+ next_year_dst_start_unix_time <= unix_time
+ } else {
+ true
+ }
+ }
+ }
+ };
+
+ if is_dst {
+ Ok(&self.dst)
+ } else {
+ Ok(&self.std)
+ }
+ }
+
+ fn find_local_time_type_from_local(
+ &self,
+ local_time: i64,
+ current_year: i32,
+ ) -> Result<crate::LocalResult<LocalTimeType>, Error> {
+ // Check if the current year is valid for the following computations
+ if !(i32::min_value() + 2 <= current_year && current_year <= i32::max_value() - 2) {
+ return Err(Error::OutOfRange("out of range date time"));
+ }
+
+ let dst_start_transition_start =
+ self.dst_start.unix_time(current_year, 0) + i64::from(self.dst_start_time);
+ let dst_start_transition_end = self.dst_start.unix_time(current_year, 0)
+ + i64::from(self.dst_start_time)
+ + i64::from(self.dst.ut_offset)
+ - i64::from(self.std.ut_offset);
+
+ let dst_end_transition_start =
+ self.dst_end.unix_time(current_year, 0) + i64::from(self.dst_end_time);
+ let dst_end_transition_end = self.dst_end.unix_time(current_year, 0)
+ + i64::from(self.dst_end_time)
+ + i64::from(self.std.ut_offset)
+ - i64::from(self.dst.ut_offset);
+
+ match self.std.ut_offset.cmp(&self.dst.ut_offset) {
+ Ordering::Equal => Ok(crate::LocalResult::Single(self.std)),
+ Ordering::Less => {
+ if self.dst_start.transition_date(current_year).0
+ < self.dst_end.transition_date(current_year).0
+ {
+ // northern hemisphere
+ // For the DST END transition, the `start` happens at a later timestamp than the `end`.
+ if local_time <= dst_start_transition_start {
+ Ok(crate::LocalResult::Single(self.std))
+ } else if local_time > dst_start_transition_start
+ && local_time < dst_start_transition_end
+ {
+ Ok(crate::LocalResult::None)
+ } else if local_time >= dst_start_transition_end
+ && local_time < dst_end_transition_end
+ {
+ Ok(crate::LocalResult::Single(self.dst))
+ } else if local_time >= dst_end_transition_end
+ && local_time <= dst_end_transition_start
+ {
+ Ok(crate::LocalResult::Ambiguous(self.std, self.dst))
+ } else {
+ Ok(crate::LocalResult::Single(self.std))
+ }
+ } else {
+ // southern hemisphere regular DST
+ // For the DST END transition, the `start` happens at a later timestamp than the `end`.
+ if local_time < dst_end_transition_end {
+ Ok(crate::LocalResult::Single(self.dst))
+ } else if local_time >= dst_end_transition_end
+ && local_time <= dst_end_transition_start
+ {
+ Ok(crate::LocalResult::Ambiguous(self.std, self.dst))
+ } else if local_time > dst_end_transition_end
+ && local_time < dst_start_transition_start
+ {
+ Ok(crate::LocalResult::Single(self.std))
+ } else if local_time >= dst_start_transition_start
+ && local_time < dst_start_transition_end
+ {
+ Ok(crate::LocalResult::None)
+ } else {
+ Ok(crate::LocalResult::Single(self.dst))
+ }
+ }
+ }
+ Ordering::Greater => {
+ if self.dst_start.transition_date(current_year).0
+ < self.dst_end.transition_date(current_year).0
+ {
+ // southern hemisphere reverse DST
+ // For the DST END transition, the `start` happens at a later timestamp than the `end`.
+ if local_time < dst_start_transition_end {
+ Ok(crate::LocalResult::Single(self.std))
+ } else if local_time >= dst_start_transition_end
+ && local_time <= dst_start_transition_start
+ {
+ Ok(crate::LocalResult::Ambiguous(self.dst, self.std))
+ } else if local_time > dst_start_transition_start
+ && local_time < dst_end_transition_start
+ {
+ Ok(crate::LocalResult::Single(self.dst))
+ } else if local_time >= dst_end_transition_start
+ && local_time < dst_end_transition_end
+ {
+ Ok(crate::LocalResult::None)
+ } else {
+ Ok(crate::LocalResult::Single(self.std))
+ }
+ } else {
+ // northern hemisphere reverse DST
+ // For the DST END transition, the `start` happens at a later timestamp than the `end`.
+ if local_time <= dst_end_transition_start {
+ Ok(crate::LocalResult::Single(self.dst))
+ } else if local_time > dst_end_transition_start
+ && local_time < dst_end_transition_end
+ {
+ Ok(crate::LocalResult::None)
+ } else if local_time >= dst_end_transition_end
+ && local_time < dst_start_transition_end
+ {
+ Ok(crate::LocalResult::Single(self.std))
+ } else if local_time >= dst_start_transition_end
+ && local_time <= dst_start_transition_start
+ {
+ Ok(crate::LocalResult::Ambiguous(self.dst, self.std))
+ } else {
+ Ok(crate::LocalResult::Single(self.dst))
+ }
+ }
+ }
+ }
+ }
+}
+
+/// Parse time zone name
+fn parse_name<'a>(cursor: &mut Cursor<'a>) -> Result<&'a [u8], Error> {
+ match cursor.peek() {
+ Some(b'<') => {}
+ _ => return Ok(cursor.read_while(u8::is_ascii_alphabetic)?),
+ }
+
+ cursor.read_exact(1)?;
+ let unquoted = cursor.read_until(|&x| x == b'>')?;
+ cursor.read_exact(1)?;
+ Ok(unquoted)
+}
+
+/// Parse time zone offset
+fn parse_offset(cursor: &mut Cursor) -> Result<i32, Error> {
+ let (sign, hour, minute, second) = parse_signed_hhmmss(cursor)?;
+
+ if !(0..=24).contains(&hour) {
+ return Err(Error::InvalidTzString("invalid offset hour"));
+ }
+ if !(0..=59).contains(&minute) {
+ return Err(Error::InvalidTzString("invalid offset minute"));
+ }
+ if !(0..=59).contains(&second) {
+ return Err(Error::InvalidTzString("invalid offset second"));
+ }
+
+ Ok(sign * (hour * 3600 + minute * 60 + second))
+}
+
+/// Parse transition rule time
+fn parse_rule_time(cursor: &mut Cursor) -> Result<i32, Error> {
+ let (hour, minute, second) = parse_hhmmss(cursor)?;
+
+ if !(0..=24).contains(&hour) {
+ return Err(Error::InvalidTzString("invalid day time hour"));
+ }
+ if !(0..=59).contains(&minute) {
+ return Err(Error::InvalidTzString("invalid day time minute"));
+ }
+ if !(0..=59).contains(&second) {
+ return Err(Error::InvalidTzString("invalid day time second"));
+ }
+
+ Ok(hour * 3600 + minute * 60 + second)
+}
+
+/// Parse transition rule time with TZ string extensions
+fn parse_rule_time_extended(cursor: &mut Cursor) -> Result<i32, Error> {
+ let (sign, hour, minute, second) = parse_signed_hhmmss(cursor)?;
+
+ if !(-167..=167).contains(&hour) {
+ return Err(Error::InvalidTzString("invalid day time hour"));
+ }
+ if !(0..=59).contains(&minute) {
+ return Err(Error::InvalidTzString("invalid day time minute"));
+ }
+ if !(0..=59).contains(&second) {
+ return Err(Error::InvalidTzString("invalid day time second"));
+ }
+
+ Ok(sign * (hour * 3600 + minute * 60 + second))
+}
+
+/// Parse hours, minutes and seconds
+fn parse_hhmmss(cursor: &mut Cursor) -> Result<(i32, i32, i32), Error> {
+ let hour = cursor.read_int()?;
+
+ let mut minute = 0;
+ let mut second = 0;
+
+ if cursor.read_optional_tag(b":")? {
+ minute = cursor.read_int()?;
+
+ if cursor.read_optional_tag(b":")? {
+ second = cursor.read_int()?;
+ }
+ }
+
+ Ok((hour, minute, second))
+}
+
+/// Parse signed hours, minutes and seconds
+fn parse_signed_hhmmss(cursor: &mut Cursor) -> Result<(i32, i32, i32, i32), Error> {
+ let mut sign = 1;
+ if let Some(&c) = cursor.peek() {
+ if c == b'+' || c == b'-' {
+ cursor.read_exact(1)?;
+ if c == b'-' {
+ sign = -1;
+ }
+ }
+ }
+
+ let (hour, minute, second) = parse_hhmmss(cursor)?;
+ Ok((sign, hour, minute, second))
+}
+
+/// Transition rule day
+#[derive(Debug, Copy, Clone, Eq, PartialEq)]
+enum RuleDay {
+ /// Julian day in `[1, 365]`, without taking occasional Feb 29 into account, which is not referenceable
+ Julian1WithoutLeap(u16),
+ /// Zero-based Julian day in `[0, 365]`, taking occasional Feb 29 into account
+ Julian0WithLeap(u16),
+ /// Day represented by a month, a month week and a week day
+ MonthWeekday {
+ /// Month in `[1, 12]`
+ month: u8,
+ /// Week of the month in `[1, 5]`, with `5` representing the last week of the month
+ week: u8,
+ /// Day of the week in `[0, 6]` from Sunday
+ week_day: u8,
+ },
+}
+
+impl RuleDay {
+ /// Parse transition rule
+ fn parse(cursor: &mut Cursor, use_string_extensions: bool) -> Result<(Self, i32), Error> {
+ let date = match cursor.peek() {
+ Some(b'M') => {
+ cursor.read_exact(1)?;
+ let month = cursor.read_int()?;
+ cursor.read_tag(b".")?;
+ let week = cursor.read_int()?;
+ cursor.read_tag(b".")?;
+ let week_day = cursor.read_int()?;
+ RuleDay::month_weekday(month, week, week_day)?
+ }
+ Some(b'J') => {
+ cursor.read_exact(1)?;
+ RuleDay::julian_1(cursor.read_int()?)?
+ }
+ _ => RuleDay::julian_0(cursor.read_int()?)?,
+ };
+
+ Ok((
+ date,
+ match (cursor.read_optional_tag(b"/")?, use_string_extensions) {
+ (false, _) => 2 * 3600,
+ (true, true) => parse_rule_time_extended(cursor)?,
+ (true, false) => parse_rule_time(cursor)?,
+ },
+ ))
+ }
+
+ /// Construct a transition rule day represented by a Julian day in `[1, 365]`, without taking occasional Feb 29 into account, which is not referenceable
+ fn julian_1(julian_day_1: u16) -> Result<Self, Error> {
+ if !(1..=365).contains(&julian_day_1) {
+ return Err(Error::TransitionRule("invalid rule day julian day"));
+ }
+
+ Ok(RuleDay::Julian1WithoutLeap(julian_day_1))
+ }
+
+ /// 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> {
+ if julian_day_0 > 365 {
+ return Err(Error::TransitionRule("invalid rule day julian day"));
+ }
+
+ Ok(RuleDay::Julian0WithLeap(julian_day_0))
+ }
+
+ /// Construct a transition rule day represented by a month, a month week and a week day
+ fn month_weekday(month: u8, week: u8, week_day: u8) -> Result<Self, Error> {
+ if !(1..=12).contains(&month) {
+ return Err(Error::TransitionRule("invalid rule day month"));
+ }
+
+ if !(1..=5).contains(&week) {
+ return Err(Error::TransitionRule("invalid rule day week"));
+ }
+
+ if week_day > 6 {
+ return Err(Error::TransitionRule("invalid rule day week day"));
+ }
+
+ Ok(RuleDay::MonthWeekday { month, week, week_day })
+ }
+
+ /// Get the transition date for the provided year
+ ///
+ /// ## Outputs
+ ///
+ /// * `month`: Month in `[1, 12]`
+ /// * `month_day`: Day of the month in `[1, 31]`
+ fn transition_date(&self, year: i32) -> (usize, i64) {
+ match *self {
+ RuleDay::Julian1WithoutLeap(year_day) => {
+ let year_day = year_day as i64;
+
+ let month = match CUMUL_DAY_IN_MONTHS_NORMAL_YEAR.binary_search(&(year_day - 1)) {
+ Ok(x) => x + 1,
+ Err(x) => x,
+ };
+
+ let month_day = year_day - CUMUL_DAY_IN_MONTHS_NORMAL_YEAR[month - 1];
+
+ (month, month_day)
+ }
+ RuleDay::Julian0WithLeap(year_day) => {
+ let leap = is_leap_year(year) as i64;
+
+ let cumul_day_in_months = [
+ 0,
+ 31,
+ 59 + leap,
+ 90 + leap,
+ 120 + leap,
+ 151 + leap,
+ 181 + leap,
+ 212 + leap,
+ 243 + leap,
+ 273 + leap,
+ 304 + leap,
+ 334 + leap,
+ ];
+
+ let year_day = year_day as i64;
+
+ let month = match cumul_day_in_months.binary_search(&year_day) {
+ Ok(x) => x + 1,
+ Err(x) => x,
+ };
+
+ let month_day = 1 + year_day - cumul_day_in_months[month - 1];
+
+ (month, month_day)
+ }
+ RuleDay::MonthWeekday { month: rule_month, week, week_day } => {
+ let leap = is_leap_year(year) as i64;
+
+ let month = rule_month as usize;
+
+ let mut day_in_month = DAY_IN_MONTHS_NORMAL_YEAR[month - 1];
+ if month == 2 {
+ day_in_month += leap;
+ }
+
+ let week_day_of_first_month_day =
+ rem_euclid(4 + days_since_unix_epoch(year, month, 1), 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);
+
+ let mut month_day =
+ first_week_day_occurence_in_month + (week as i64 - 1) * DAYS_PER_WEEK;
+ if month_day > day_in_month {
+ month_day -= DAYS_PER_WEEK
+ }
+
+ (month, month_day)
+ }
+ }
+ }
+
+ /// Returns the UTC Unix time in seconds associated to the transition date for the provided year
+ fn unix_time(&self, year: i32, day_time_in_utc: i64) -> i64 {
+ let (month, month_day) = self.transition_date(year);
+ days_since_unix_epoch(year, month, month_day) * SECONDS_PER_DAY + day_time_in_utc
+ }
+}
+
+/// UTC date time exprimed in the [proleptic gregorian calendar](https://en.wikipedia.org/wiki/Proleptic_Gregorian_calendar)
+#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
+pub(crate) struct UtcDateTime {
+ /// Year
+ pub(crate) year: i32,
+ /// Month in `[1, 12]`
+ pub(crate) month: u8,
+ /// Day of the month in `[1, 31]`
+ pub(crate) month_day: u8,
+ /// Hours since midnight in `[0, 23]`
+ pub(crate) hour: u8,
+ /// Minutes in `[0, 59]`
+ pub(crate) minute: u8,
+ /// Seconds in `[0, 60]`, with a possible leap second
+ pub(crate) second: u8,
+}
+
+impl UtcDateTime {
+ /// Construct a UTC date time from a Unix time in seconds and nanoseconds
+ pub(crate) fn from_timespec(unix_time: i64) -> Result<Self, Error> {
+ let seconds = match unix_time.checked_sub(UNIX_OFFSET_SECS) {
+ Some(seconds) => seconds,
+ None => return Err(Error::OutOfRange("out of range operation")),
+ };
+
+ let mut remaining_days = seconds / SECONDS_PER_DAY;
+ let mut remaining_seconds = seconds % SECONDS_PER_DAY;
+ if remaining_seconds < 0 {
+ remaining_seconds += SECONDS_PER_DAY;
+ remaining_days -= 1;
+ }
+
+ let mut cycles_400_years = remaining_days / DAYS_PER_400_YEARS;
+ remaining_days %= DAYS_PER_400_YEARS;
+ if remaining_days < 0 {
+ remaining_days += DAYS_PER_400_YEARS;
+ cycles_400_years -= 1;
+ }
+
+ let cycles_100_years = Ord::min(remaining_days / DAYS_PER_100_YEARS, 3);
+ remaining_days -= cycles_100_years * DAYS_PER_100_YEARS;
+
+ let cycles_4_years = Ord::min(remaining_days / DAYS_PER_4_YEARS, 24);
+ remaining_days -= cycles_4_years * DAYS_PER_4_YEARS;
+
+ let remaining_years = Ord::min(remaining_days / DAYS_PER_NORMAL_YEAR, 3);
+ remaining_days -= remaining_years * DAYS_PER_NORMAL_YEAR;
+
+ let mut year = OFFSET_YEAR
+ + remaining_years
+ + cycles_4_years * 4
+ + cycles_100_years * 100
+ + cycles_400_years * 400;
+
+ let mut month = 0;
+ while month < DAY_IN_MONTHS_LEAP_YEAR_FROM_MARCH.len() {
+ let days = DAY_IN_MONTHS_LEAP_YEAR_FROM_MARCH[month];
+ if remaining_days < days {
+ break;
+ }
+ remaining_days -= days;
+ month += 1;
+ }
+ month += 2;
+
+ if month >= MONTHS_PER_YEAR as usize {
+ month -= MONTHS_PER_YEAR as usize;
+ year += 1;
+ }
+ month += 1;
+
+ let month_day = 1 + remaining_days;
+
+ let hour = remaining_seconds / SECONDS_PER_HOUR;
+ let minute = (remaining_seconds / SECONDS_PER_MINUTE) % MINUTES_PER_HOUR;
+ let second = remaining_seconds % SECONDS_PER_MINUTE;
+
+ let year = match year >= i32::min_value() as i64 && year <= i32::max_value() as i64 {
+ true => year as i32,
+ false => return Err(Error::OutOfRange("i64 is out of range for i32")),
+ };
+
+ Ok(Self {
+ year,
+ month: month as u8,
+ month_day: month_day as u8,
+ hour: hour as u8,
+ minute: minute as u8,
+ second: second as u8,
+ })
+ }
+}
+
+/// Number of nanoseconds in one second
+const NANOSECONDS_PER_SECOND: u32 = 1_000_000_000;
+/// Number of seconds in one minute
+const SECONDS_PER_MINUTE: i64 = 60;
+/// Number of seconds in one hour
+const SECONDS_PER_HOUR: i64 = 3600;
+/// Number of minutes in one hour
+const MINUTES_PER_HOUR: i64 = 60;
+/// Number of months in one year
+const MONTHS_PER_YEAR: i64 = 12;
+/// Number of days in a normal year
+const DAYS_PER_NORMAL_YEAR: i64 = 365;
+/// Number of days in 4 years (including 1 leap year)
+const DAYS_PER_4_YEARS: i64 = DAYS_PER_NORMAL_YEAR * 4 + 1;
+/// Number of days in 100 years (including 24 leap years)
+const DAYS_PER_100_YEARS: i64 = DAYS_PER_NORMAL_YEAR * 100 + 24;
+/// Number of days in 400 years (including 97 leap years)
+const DAYS_PER_400_YEARS: i64 = DAYS_PER_NORMAL_YEAR * 400 + 97;
+/// Unix time at `2000-03-01T00:00:00Z` (Wednesday)
+const UNIX_OFFSET_SECS: i64 = 951868800;
+/// Offset year
+const OFFSET_YEAR: i64 = 2000;
+/// Month days in a leap year from March
+const DAY_IN_MONTHS_LEAP_YEAR_FROM_MARCH: [i64; 12] =
+ [31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 31, 29];
+
+/// Compute the number of days since Unix epoch (`1970-01-01T00:00:00Z`).
+///
+/// ## Inputs
+///
+/// * `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 {
+ let is_leap_year = is_leap_year(year);
+
+ let year = year as i64;
+
+ let mut result = (year - 1970) * 365;
+
+ if year >= 1970 {
+ result += (year - 1968) / 4;
+ result -= (year - 1900) / 100;
+ result += (year - 1600) / 400;
+
+ if is_leap_year && month < 3 {
+ result -= 1;
+ }
+ } else {
+ result += (year - 1972) / 4;
+ result -= (year - 2000) / 100;
+ result += (year - 2000) / 400;
+
+ if is_leap_year && month >= 3 {
+ result += 1;
+ }
+ }
+
+ result += CUMUL_DAY_IN_MONTHS_NORMAL_YEAR[month - 1] + month_day - 1;
+
+ result
+}
+
+/// Check if a year is a leap year
+pub(crate) fn is_leap_year(year: i32) -> bool {
+ year % 400 == 0 || (year % 4 == 0 && year % 100 != 0)
+}
+
+#[cfg(test)]
+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> {
+ let transition_rule = TransitionRule::from_tz_string(b"<-03>+3<+03>-3,J1,J365", false)?;
+ assert_eq!(
+ transition_rule,
+ AlternateTime::new(
+ LocalTimeType::new(-10800, false, Some(b"-03"))?,
+ LocalTimeType::new(10800, true, Some(b"+03"))?,
+ RuleDay::julian_1(1)?,
+ 7200,
+ RuleDay::julian_1(365)?,
+ 7200,
+ )?
+ .into()
+ );
+ Ok(())
+ }
+
+ #[test]
+ fn test_full() -> Result<(), Error> {
+ let tz_string = b"NZST-12:00:00NZDT-13:00:00,M10.1.0/02:00:00,M3.3.0/02:00:00";
+ let transition_rule = TransitionRule::from_tz_string(tz_string, false)?;
+ assert_eq!(
+ transition_rule,
+ AlternateTime::new(
+ LocalTimeType::new(43200, false, Some(b"NZST"))?,
+ LocalTimeType::new(46800, true, Some(b"NZDT"))?,
+ RuleDay::month_weekday(10, 1, 0)?,
+ 7200,
+ RuleDay::month_weekday(3, 3, 0)?,
+ 7200,
+ )?
+ .into()
+ );
+ Ok(())
+ }
+
+ #[test]
+ fn test_negative_dst() -> Result<(), Error> {
+ let tz_string = b"IST-1GMT0,M10.5.0,M3.5.0/1";
+ let transition_rule = TransitionRule::from_tz_string(tz_string, false)?;
+ assert_eq!(
+ transition_rule,
+ AlternateTime::new(
+ LocalTimeType::new(3600, false, Some(b"IST"))?,
+ LocalTimeType::new(0, true, Some(b"GMT"))?,
+ RuleDay::month_weekday(10, 5, 0)?,
+ 7200,
+ RuleDay::month_weekday(3, 5, 0)?,
+ 3600,
+ )?
+ .into()
+ );
+ Ok(())
+ }
+
+ #[test]
+ fn test_negative_hour() -> Result<(), Error> {
+ let tz_string = b"<-03>3<-02>,M3.5.0/-2,M10.5.0/-1";
+ assert!(TransitionRule::from_tz_string(tz_string, false).is_err());
+
+ assert_eq!(
+ TransitionRule::from_tz_string(tz_string, true)?,
+ AlternateTime::new(
+ LocalTimeType::new(-10800, false, Some(b"-03"))?,
+ LocalTimeType::new(-7200, true, Some(b"-02"))?,
+ RuleDay::month_weekday(3, 5, 0)?,
+ -7200,
+ RuleDay::month_weekday(10, 5, 0)?,
+ -3600,
+ )?
+ .into()
+ );
+ Ok(())
+ }
+
+ #[test]
+ fn test_all_year_dst() -> Result<(), Error> {
+ let tz_string = b"EST5EDT,0/0,J365/25";
+ assert!(TransitionRule::from_tz_string(tz_string, false).is_err());
+
+ assert_eq!(
+ TransitionRule::from_tz_string(tz_string, true)?,
+ AlternateTime::new(
+ LocalTimeType::new(-18000, false, Some(b"EST"))?,
+ LocalTimeType::new(-14400, true, Some(b"EDT"))?,
+ RuleDay::julian_0(0)?,
+ 0,
+ RuleDay::julian_1(365)?,
+ 90000,
+ )?
+ .into()
+ );
+ Ok(())
+ }
+
+ #[test]
+ fn test_v3_file() -> Result<(), Error> {
+ let bytes = b"TZif3\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\0\0\0\x04\0\0\x1c\x20\0\0IST\0TZif3\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\0\0\0\x01\0\0\0\0\0\0\0\x01\0\0\0\x01\0\0\0\x04\0\0\0\0\x7f\xe8\x17\x80\0\0\0\x1c\x20\0\0IST\0\x01\x01\x0aIST-2IDT,M3.4.4/26,M10.5.0\x0a";
+
+ let time_zone = TimeZone::from_tz_data(bytes)?;
+
+ let time_zone_result = TimeZone::new(
+ vec![Transition::new(2145916800, 0)],
+ vec![LocalTimeType::new(7200, false, Some(b"IST"))?],
+ Vec::new(),
+ Some(TransitionRule::from(AlternateTime::new(
+ LocalTimeType::new(7200, false, Some(b"IST"))?,
+ LocalTimeType::new(10800, true, Some(b"IDT"))?,
+ RuleDay::month_weekday(3, 4, 4)?,
+ 93600,
+ RuleDay::month_weekday(10, 5, 0)?,
+ 7200,
+ )?)),
+ )?;
+
+ assert_eq!(time_zone, time_zone_result);
+
+ Ok(())
+ }
+
+ #[test]
+ fn test_rule_day() -> Result<(), Error> {
+ let rule_day_j1 = RuleDay::julian_1(60)?;
+ assert_eq!(rule_day_j1.transition_date(2000), (3, 1));
+ assert_eq!(rule_day_j1.transition_date(2001), (3, 1));
+ assert_eq!(rule_day_j1.unix_time(2000, 43200), 951912000);
+
+ let rule_day_j0 = RuleDay::julian_0(59)?;
+ assert_eq!(rule_day_j0.transition_date(2000), (2, 29));
+ assert_eq!(rule_day_j0.transition_date(2001), (3, 1));
+ assert_eq!(rule_day_j0.unix_time(2000, 43200), 951825600);
+
+ let rule_day_mwd = RuleDay::month_weekday(2, 5, 2)?;
+ assert_eq!(rule_day_mwd.transition_date(2000), (2, 29));
+ assert_eq!(rule_day_mwd.transition_date(2001), (2, 27));
+ assert_eq!(rule_day_mwd.unix_time(2000, 43200), 951825600);
+ assert_eq!(rule_day_mwd.unix_time(2001, 43200), 983275200);
+
+ Ok(())
+ }
+
+ #[test]
+ fn test_transition_rule() -> Result<(), Error> {
+ let transition_rule_fixed = TransitionRule::from(LocalTimeType::new(-36000, false, None)?);
+ assert_eq!(transition_rule_fixed.find_local_time_type(0)?.offset(), -36000);
+
+ let transition_rule_dst = TransitionRule::from(AlternateTime::new(
+ LocalTimeType::new(43200, false, Some(b"NZST"))?,
+ LocalTimeType::new(46800, true, Some(b"NZDT"))?,
+ RuleDay::month_weekday(10, 1, 0)?,
+ 7200,
+ RuleDay::month_weekday(3, 3, 0)?,
+ 7200,
+ )?);
+
+ assert_eq!(transition_rule_dst.find_local_time_type(953384399)?.offset(), 46800);
+ assert_eq!(transition_rule_dst.find_local_time_type(953384400)?.offset(), 43200);
+ assert_eq!(transition_rule_dst.find_local_time_type(970322399)?.offset(), 43200);
+ assert_eq!(transition_rule_dst.find_local_time_type(970322400)?.offset(), 46800);
+
+ let transition_rule_negative_dst = TransitionRule::from(AlternateTime::new(
+ LocalTimeType::new(3600, false, Some(b"IST"))?,
+ LocalTimeType::new(0, true, Some(b"GMT"))?,
+ RuleDay::month_weekday(10, 5, 0)?,
+ 7200,
+ RuleDay::month_weekday(3, 5, 0)?,
+ 3600,
+ )?);
+
+ assert_eq!(transition_rule_negative_dst.find_local_time_type(954032399)?.offset(), 0);
+ assert_eq!(transition_rule_negative_dst.find_local_time_type(954032400)?.offset(), 3600);
+ assert_eq!(transition_rule_negative_dst.find_local_time_type(972781199)?.offset(), 3600);
+ assert_eq!(transition_rule_negative_dst.find_local_time_type(972781200)?.offset(), 0);
+
+ let transition_rule_negative_time_1 = TransitionRule::from(AlternateTime::new(
+ LocalTimeType::new(0, false, None)?,
+ LocalTimeType::new(0, true, None)?,
+ RuleDay::julian_0(100)?,
+ 0,
+ RuleDay::julian_0(101)?,
+ -86500,
+ )?);
+
+ assert!(transition_rule_negative_time_1.find_local_time_type(8639899)?.is_dst());
+ assert!(!transition_rule_negative_time_1.find_local_time_type(8639900)?.is_dst());
+ assert!(!transition_rule_negative_time_1.find_local_time_type(8639999)?.is_dst());
+ assert!(transition_rule_negative_time_1.find_local_time_type(8640000)?.is_dst());
+
+ let transition_rule_negative_time_2 = TransitionRule::from(AlternateTime::new(
+ LocalTimeType::new(-10800, false, Some(b"-03"))?,
+ LocalTimeType::new(-7200, true, Some(b"-02"))?,
+ RuleDay::month_weekday(3, 5, 0)?,
+ -7200,
+ RuleDay::month_weekday(10, 5, 0)?,
+ -3600,
+ )?);
+
+ assert_eq!(
+ transition_rule_negative_time_2.find_local_time_type(954032399)?.offset(),
+ -10800
+ );
+ assert_eq!(
+ transition_rule_negative_time_2.find_local_time_type(954032400)?.offset(),
+ -7200
+ );
+ assert_eq!(
+ transition_rule_negative_time_2.find_local_time_type(972781199)?.offset(),
+ -7200
+ );
+ assert_eq!(
+ transition_rule_negative_time_2.find_local_time_type(972781200)?.offset(),
+ -10800
+ );
+
+ let transition_rule_all_year_dst = TransitionRule::from(AlternateTime::new(
+ LocalTimeType::new(-18000, false, Some(b"EST"))?,
+ LocalTimeType::new(-14400, true, Some(b"EDT"))?,
+ RuleDay::julian_0(0)?,
+ 0,
+ RuleDay::julian_1(365)?,
+ 90000,
+ )?);
+
+ assert_eq!(transition_rule_all_year_dst.find_local_time_type(946702799)?.offset(), -14400);
+ assert_eq!(transition_rule_all_year_dst.find_local_time_type(946702800)?.offset(), -14400);
+
+ Ok(())
+ }
+
+ #[test]
+ fn test_transition_rule_overflow() -> Result<(), Error> {
+ let transition_rule_1 = TransitionRule::from(AlternateTime::new(
+ LocalTimeType::new(-1, false, None)?,
+ LocalTimeType::new(-1, true, None)?,
+ RuleDay::julian_1(365)?,
+ 0,
+ RuleDay::julian_1(1)?,
+ 0,
+ )?);
+
+ let transition_rule_2 = TransitionRule::from(AlternateTime::new(
+ LocalTimeType::new(1, false, None)?,
+ LocalTimeType::new(1, true, None)?,
+ RuleDay::julian_1(365)?,
+ 0,
+ RuleDay::julian_1(1)?,
+ 0,
+ )?);
+
+ let min_unix_time = -67768100567971200;
+ let max_unix_time = 67767976233532799;
+
+ assert!(matches!(
+ transition_rule_1.find_local_time_type(min_unix_time),
+ Err(Error::OutOfRange(_))
+ ));
+ assert!(matches!(
+ transition_rule_2.find_local_time_type(max_unix_time),
+ Err(Error::OutOfRange(_))
+ ));
+
+ Ok(())
+ }
+}
diff --git a/vendor/chrono/src/offset/local/tz_info/timezone.rs b/vendor/chrono/src/offset/local/tz_info/timezone.rs
new file mode 100644
index 000000000..8572825a8
--- /dev/null
+++ b/vendor/chrono/src/offset/local/tz_info/timezone.rs
@@ -0,0 +1,904 @@
+//! Types related to a time zone.
+
+use std::fs::{self, File};
+use std::io::{self, Read};
+use std::path::{Path, PathBuf};
+use std::{cmp::Ordering, fmt, str};
+
+use super::rule::{AlternateTime, TransitionRule};
+use super::{parser, Error, DAYS_PER_WEEK, SECONDS_PER_DAY};
+
+/// Time zone
+#[derive(Debug, Clone, Eq, PartialEq)]
+pub(crate) struct TimeZone {
+ /// List of transitions
+ transitions: Vec<Transition>,
+ /// List of local time types (cannot be empty)
+ local_time_types: Vec<LocalTimeType>,
+ /// List of leap seconds
+ leap_seconds: Vec<LeapSecond>,
+ /// Extra transition rule applicable after the last transition
+ extra_rule: Option<TransitionRule>,
+}
+
+impl TimeZone {
+ /// Returns local time zone.
+ ///
+ /// This method in not supported on non-UNIX platforms, and returns the UTC time zone instead.
+ ///
+ pub(crate) fn local(env_tz: Option<&str>) -> Result<Self, Error> {
+ match env_tz {
+ Some(tz) => Self::from_posix_tz(tz),
+ None => Self::from_posix_tz("localtime"),
+ }
+ }
+
+ /// Construct a time zone from a POSIX TZ string, as described in [the POSIX documentation of the `TZ` environment variable](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html).
+ fn from_posix_tz(tz_string: &str) -> Result<Self, Error> {
+ if tz_string.is_empty() {
+ return Err(Error::InvalidTzString("empty TZ string"));
+ }
+
+ if tz_string == "localtime" {
+ return Self::from_tz_data(&fs::read("/etc/localtime")?);
+ }
+
+ let mut chars = tz_string.chars();
+ if chars.next() == Some(':') {
+ return Self::from_file(&mut find_tz_file(chars.as_str())?);
+ }
+
+ if let Ok(mut file) = find_tz_file(tz_string) {
+ return Self::from_file(&mut file);
+ }
+
+ // TZ string extensions are not allowed
+ let tz_string = tz_string.trim_matches(|c: char| c.is_ascii_whitespace());
+ let rule = TransitionRule::from_tz_string(tz_string.as_bytes(), false)?;
+ Self::new(
+ vec![],
+ match rule {
+ TransitionRule::Fixed(local_time_type) => vec![local_time_type],
+ TransitionRule::Alternate(AlternateTime { std, dst, .. }) => vec![std, dst],
+ },
+ vec![],
+ Some(rule),
+ )
+ }
+
+ /// Construct a time zone
+ pub(super) fn new(
+ transitions: Vec<Transition>,
+ local_time_types: Vec<LocalTimeType>,
+ leap_seconds: Vec<LeapSecond>,
+ extra_rule: Option<TransitionRule>,
+ ) -> Result<Self, Error> {
+ let new = Self { transitions, local_time_types, leap_seconds, extra_rule };
+ new.as_ref().validate()?;
+ Ok(new)
+ }
+
+ /// Construct a time zone from the contents of a time zone file
+ fn from_file(file: &mut File) -> Result<Self, Error> {
+ let mut bytes = Vec::new();
+ file.read_to_end(&mut bytes)?;
+ Self::from_tz_data(&bytes)
+ }
+
+ /// Construct a time zone from the contents of a time zone file
+ ///
+ /// Parse TZif data as described in [RFC 8536](https://datatracker.ietf.org/doc/html/rfc8536).
+ pub(crate) fn from_tz_data(bytes: &[u8]) -> Result<Self, Error> {
+ parser::parse(bytes)
+ }
+
+ /// Construct a time zone with the specified UTC offset in seconds
+ fn fixed(ut_offset: i32) -> Result<Self, Error> {
+ Ok(Self {
+ transitions: Vec::new(),
+ local_time_types: vec![LocalTimeType::with_offset(ut_offset)?],
+ leap_seconds: Vec::new(),
+ extra_rule: None,
+ })
+ }
+
+ /// Construct the time zone associated to UTC
+ pub(crate) fn utc() -> Self {
+ Self {
+ transitions: Vec::new(),
+ local_time_types: vec![LocalTimeType::UTC],
+ leap_seconds: Vec::new(),
+ extra_rule: None,
+ }
+ }
+
+ /// Find the local time type associated to the time zone at the specified Unix time in seconds
+ pub(crate) fn find_local_time_type(&self, unix_time: i64) -> Result<&LocalTimeType, Error> {
+ self.as_ref().find_local_time_type(unix_time)
+ }
+
+ // should we pass NaiveDateTime all the way through to this fn?
+ pub(crate) fn find_local_time_type_from_local(
+ &self,
+ local_time: i64,
+ year: i32,
+ ) -> Result<crate::LocalResult<LocalTimeType>, Error> {
+ self.as_ref().find_local_time_type_from_local(local_time, year)
+ }
+
+ /// Returns a reference to the time zone
+ fn as_ref(&self) -> TimeZoneRef {
+ TimeZoneRef {
+ transitions: &self.transitions,
+ local_time_types: &self.local_time_types,
+ leap_seconds: &self.leap_seconds,
+ extra_rule: &self.extra_rule,
+ }
+ }
+}
+
+/// Reference to a time zone
+#[derive(Debug, Copy, Clone, Eq, PartialEq)]
+pub(crate) struct TimeZoneRef<'a> {
+ /// List of transitions
+ transitions: &'a [Transition],
+ /// List of local time types (cannot be empty)
+ local_time_types: &'a [LocalTimeType],
+ /// List of leap seconds
+ leap_seconds: &'a [LeapSecond],
+ /// Extra transition rule applicable after the last transition
+ extra_rule: &'a Option<TransitionRule>,
+}
+
+impl<'a> TimeZoneRef<'a> {
+ /// Find the local time type associated to the time zone at the specified Unix time in seconds
+ pub(crate) fn find_local_time_type(&self, unix_time: i64) -> Result<&'a LocalTimeType, Error> {
+ let extra_rule = match self.transitions.last() {
+ None => match self.extra_rule {
+ Some(extra_rule) => extra_rule,
+ None => return Ok(&self.local_time_types[0]),
+ },
+ Some(last_transition) => {
+ let unix_leap_time = match self.unix_time_to_unix_leap_time(unix_time) {
+ Ok(unix_leap_time) => unix_leap_time,
+ Err(Error::OutOfRange(error)) => return Err(Error::FindLocalTimeType(error)),
+ Err(err) => return Err(err),
+ };
+
+ if unix_leap_time >= last_transition.unix_leap_time {
+ match self.extra_rule {
+ Some(extra_rule) => extra_rule,
+ None => {
+ return Err(Error::FindLocalTimeType(
+ "no local time type is available for the specified timestamp",
+ ))
+ }
+ }
+ } else {
+ let index = match self
+ .transitions
+ .binary_search_by_key(&unix_leap_time, Transition::unix_leap_time)
+ {
+ Ok(x) => x + 1,
+ Err(x) => x,
+ };
+
+ let local_time_type_index = if index > 0 {
+ self.transitions[index - 1].local_time_type_index
+ } else {
+ 0
+ };
+ return Ok(&self.local_time_types[local_time_type_index]);
+ }
+ }
+ };
+
+ match extra_rule.find_local_time_type(unix_time) {
+ Ok(local_time_type) => Ok(local_time_type),
+ Err(Error::OutOfRange(error)) => Err(Error::FindLocalTimeType(error)),
+ err => err,
+ }
+ }
+
+ pub(crate) fn find_local_time_type_from_local(
+ &self,
+ local_time: i64,
+ year: i32,
+ ) -> Result<crate::LocalResult<LocalTimeType>, Error> {
+ // #TODO: this is wrong as we need 'local_time_to_local_leap_time ?
+ // but ... does the local time even include leap seconds ??
+ // let unix_leap_time = match self.unix_time_to_unix_leap_time(local_time) {
+ // Ok(unix_leap_time) => unix_leap_time,
+ // Err(Error::OutOfRange(error)) => return Err(Error::FindLocalTimeType(error)),
+ // Err(err) => return Err(err),
+ // };
+ let local_leap_time = local_time;
+
+ // if we have at least one transition,
+ // we must check _all_ of them, incase of any Overlapping (LocalResult::Ambiguous) or Skipping (LocalResult::None) transitions
+ if !self.transitions.is_empty() {
+ let mut prev = Some(self.local_time_types[0]);
+
+ for transition in self.transitions {
+ let after_ltt = self.local_time_types[transition.local_time_type_index];
+
+ // the end and start here refers to where the time starts prior to the transition
+ // and where it ends up after. not the temporal relationship.
+ let transition_end = transition.unix_leap_time + i64::from(after_ltt.ut_offset);
+ let transition_start =
+ transition.unix_leap_time + i64::from(prev.unwrap().ut_offset);
+
+ match transition_start.cmp(&transition_end) {
+ Ordering::Greater => {
+ // bakwards transition, eg from DST to regular
+ // this means a given local time could have one of two possible offsets
+ if local_leap_time < transition_end {
+ return Ok(crate::LocalResult::Single(prev.unwrap()));
+ } else if local_leap_time >= transition_end
+ && local_leap_time <= transition_start
+ {
+ if prev.unwrap().ut_offset < after_ltt.ut_offset {
+ return Ok(crate::LocalResult::Ambiguous(prev.unwrap(), after_ltt));
+ } else {
+ return Ok(crate::LocalResult::Ambiguous(after_ltt, prev.unwrap()));
+ }
+ }
+ }
+ Ordering::Equal => {
+ // should this ever happen? presumably we have to handle it anyway.
+ if local_leap_time < transition_start {
+ return Ok(crate::LocalResult::Single(prev.unwrap()));
+ } else if local_leap_time == transition_end {
+ if prev.unwrap().ut_offset < after_ltt.ut_offset {
+ return Ok(crate::LocalResult::Ambiguous(prev.unwrap(), after_ltt));
+ } else {
+ return Ok(crate::LocalResult::Ambiguous(after_ltt, prev.unwrap()));
+ }
+ }
+ }
+ Ordering::Less => {
+ // forwards transition, eg from regular to DST
+ // this means that times that are skipped are invalid local times
+ if local_leap_time <= transition_start {
+ return Ok(crate::LocalResult::Single(prev.unwrap()));
+ } else if local_leap_time < transition_end {
+ return Ok(crate::LocalResult::None);
+ } else if local_leap_time == transition_end {
+ return Ok(crate::LocalResult::Single(after_ltt));
+ }
+ }
+ }
+
+ // try the next transition, we are fully after this one
+ prev = Some(after_ltt);
+ }
+ };
+
+ if let Some(extra_rule) = self.extra_rule {
+ match extra_rule.find_local_time_type_from_local(local_time, year) {
+ Ok(local_time_type) => Ok(local_time_type),
+ Err(Error::OutOfRange(error)) => Err(Error::FindLocalTimeType(error)),
+ err => err,
+ }
+ } else {
+ Ok(crate::LocalResult::Single(self.local_time_types[0]))
+ }
+ }
+
+ /// Check time zone inputs
+ fn validate(&self) -> Result<(), Error> {
+ // Check local time types
+ let local_time_types_size = self.local_time_types.len();
+ if local_time_types_size == 0 {
+ return Err(Error::TimeZone("list of local time types must not be empty"));
+ }
+
+ // Check transitions
+ let mut i_transition = 0;
+ while i_transition < self.transitions.len() {
+ if self.transitions[i_transition].local_time_type_index >= local_time_types_size {
+ return Err(Error::TimeZone("invalid local time type index"));
+ }
+
+ if i_transition + 1 < self.transitions.len()
+ && self.transitions[i_transition].unix_leap_time
+ >= self.transitions[i_transition + 1].unix_leap_time
+ {
+ return Err(Error::TimeZone("invalid transition"));
+ }
+
+ i_transition += 1;
+ }
+
+ // Check leap seconds
+ if !(self.leap_seconds.is_empty()
+ || self.leap_seconds[0].unix_leap_time >= 0
+ && saturating_abs(self.leap_seconds[0].correction) == 1)
+ {
+ return Err(Error::TimeZone("invalid leap second"));
+ }
+
+ let min_interval = SECONDS_PER_28_DAYS - 1;
+
+ let mut i_leap_second = 0;
+ while i_leap_second < self.leap_seconds.len() {
+ if i_leap_second + 1 < self.leap_seconds.len() {
+ let x0 = &self.leap_seconds[i_leap_second];
+ let x1 = &self.leap_seconds[i_leap_second + 1];
+
+ let diff_unix_leap_time = x1.unix_leap_time.saturating_sub(x0.unix_leap_time);
+ let abs_diff_correction =
+ saturating_abs(x1.correction.saturating_sub(x0.correction));
+
+ if !(diff_unix_leap_time >= min_interval && abs_diff_correction == 1) {
+ return Err(Error::TimeZone("invalid leap second"));
+ }
+ }
+ i_leap_second += 1;
+ }
+
+ // Check extra rule
+ let (extra_rule, last_transition) = match (&self.extra_rule, self.transitions.last()) {
+ (Some(rule), Some(trans)) => (rule, trans),
+ _ => return Ok(()),
+ };
+
+ let last_local_time_type = &self.local_time_types[last_transition.local_time_type_index];
+ let unix_time = match self.unix_leap_time_to_unix_time(last_transition.unix_leap_time) {
+ Ok(unix_time) => unix_time,
+ Err(Error::OutOfRange(error)) => return Err(Error::TimeZone(error)),
+ Err(err) => return Err(err),
+ };
+
+ let rule_local_time_type = match extra_rule.find_local_time_type(unix_time) {
+ Ok(rule_local_time_type) => rule_local_time_type,
+ Err(Error::OutOfRange(error)) => return Err(Error::TimeZone(error)),
+ Err(err) => return Err(err),
+ };
+
+ let check = last_local_time_type.ut_offset == rule_local_time_type.ut_offset
+ && last_local_time_type.is_dst == rule_local_time_type.is_dst
+ && match (&last_local_time_type.name, &rule_local_time_type.name) {
+ (Some(x), Some(y)) => x.equal(y),
+ (None, None) => true,
+ _ => false,
+ };
+
+ if !check {
+ return Err(Error::TimeZone(
+ "extra transition rule is inconsistent with the last transition",
+ ));
+ }
+
+ Ok(())
+ }
+
+ /// 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> {
+ let mut unix_leap_time = unix_time;
+
+ let mut i = 0;
+ while i < self.leap_seconds.len() {
+ let leap_second = &self.leap_seconds[i];
+
+ if unix_leap_time < leap_second.unix_leap_time {
+ break;
+ }
+
+ unix_leap_time = match unix_time.checked_add(leap_second.correction as i64) {
+ Some(unix_leap_time) => unix_leap_time,
+ None => return Err(Error::OutOfRange("out of range operation")),
+ };
+
+ i += 1;
+ }
+
+ Ok(unix_leap_time)
+ }
+
+ /// Convert Unix leap time to Unix time, from the list of leap seconds in a time zone
+ fn unix_leap_time_to_unix_time(&self, unix_leap_time: i64) -> Result<i64, Error> {
+ if unix_leap_time == i64::min_value() {
+ return Err(Error::OutOfRange("out of range operation"));
+ }
+
+ let index = match self
+ .leap_seconds
+ .binary_search_by_key(&(unix_leap_time - 1), LeapSecond::unix_leap_time)
+ {
+ Ok(x) => x + 1,
+ Err(x) => x,
+ };
+
+ let correction = if index > 0 { self.leap_seconds[index - 1].correction } else { 0 };
+
+ match unix_leap_time.checked_sub(correction as i64) {
+ Some(unix_time) => Ok(unix_time),
+ None => Err(Error::OutOfRange("out of range operation")),
+ }
+ }
+
+ /// The UTC time zone
+ const UTC: TimeZoneRef<'static> = TimeZoneRef {
+ transitions: &[],
+ local_time_types: &[LocalTimeType::UTC],
+ leap_seconds: &[],
+ extra_rule: &None,
+ };
+}
+
+/// Transition of a TZif file
+#[derive(Debug, Copy, Clone, Eq, PartialEq)]
+pub(super) struct Transition {
+ /// Unix leap time
+ unix_leap_time: i64,
+ /// Index specifying the local time type of the transition
+ local_time_type_index: usize,
+}
+
+impl Transition {
+ /// Construct a TZif file transition
+ pub(super) const fn new(unix_leap_time: i64, local_time_type_index: usize) -> Self {
+ Self { unix_leap_time, local_time_type_index }
+ }
+
+ /// Returns Unix leap time
+ const fn unix_leap_time(&self) -> i64 {
+ self.unix_leap_time
+ }
+}
+
+/// Leap second of a TZif file
+#[derive(Debug, Copy, Clone, Eq, PartialEq)]
+pub(super) struct LeapSecond {
+ /// Unix leap time
+ unix_leap_time: i64,
+ /// Leap second correction
+ correction: i32,
+}
+
+impl LeapSecond {
+ /// Construct a TZif file leap second
+ pub(super) const fn new(unix_leap_time: i64, correction: i32) -> Self {
+ Self { unix_leap_time, correction }
+ }
+
+ /// Returns Unix leap time
+ const fn unix_leap_time(&self) -> i64 {
+ self.unix_leap_time
+ }
+}
+
+/// ASCII-encoded fixed-capacity string, used for storing time zone names
+#[derive(Copy, Clone, Eq, PartialEq)]
+struct TimeZoneName {
+ /// Length-prefixed string buffer
+ bytes: [u8; 8],
+}
+
+impl TimeZoneName {
+ /// Construct a time zone name
+ fn new(input: &[u8]) -> Result<Self, Error> {
+ let len = input.len();
+
+ if !(3..=7).contains(&len) {
+ return Err(Error::LocalTimeType(
+ "time zone name must have between 3 and 7 characters",
+ ));
+ }
+
+ let mut bytes = [0; 8];
+ bytes[0] = input.len() as u8;
+
+ let mut i = 0;
+ while i < len {
+ let b = input[i];
+ match b {
+ b'0'..=b'9' | b'A'..=b'Z' | b'a'..=b'z' | b'+' | b'-' => {}
+ _ => return Err(Error::LocalTimeType("invalid characters in time zone name")),
+ }
+
+ bytes[i + 1] = b;
+ i += 1;
+ }
+
+ Ok(Self { bytes })
+ }
+
+ /// Returns time zone name as a byte slice
+ fn as_bytes(&self) -> &[u8] {
+ match self.bytes[0] {
+ 3 => &self.bytes[1..4],
+ 4 => &self.bytes[1..5],
+ 5 => &self.bytes[1..6],
+ 6 => &self.bytes[1..7],
+ 7 => &self.bytes[1..8],
+ _ => unreachable!(),
+ }
+ }
+
+ /// Check if two time zone names are equal
+ fn equal(&self, other: &Self) -> bool {
+ self.bytes == other.bytes
+ }
+}
+
+impl AsRef<str> for TimeZoneName {
+ fn as_ref(&self) -> &str {
+ // SAFETY: ASCII is valid UTF-8
+ unsafe { str::from_utf8_unchecked(self.as_bytes()) }
+ }
+}
+
+impl fmt::Debug for TimeZoneName {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ self.as_ref().fmt(f)
+ }
+}
+
+/// Local time type associated to a time zone
+#[derive(Debug, Copy, Clone, Eq, PartialEq)]
+pub(crate) struct LocalTimeType {
+ /// Offset from UTC in seconds
+ pub(super) ut_offset: i32,
+ /// Daylight Saving Time indicator
+ is_dst: bool,
+ /// Time zone name
+ name: Option<TimeZoneName>,
+}
+
+impl LocalTimeType {
+ /// Construct a local time type
+ pub(super) fn new(ut_offset: i32, is_dst: bool, name: Option<&[u8]>) -> Result<Self, Error> {
+ if ut_offset == i32::min_value() {
+ return Err(Error::LocalTimeType("invalid UTC offset"));
+ }
+
+ let name = match name {
+ Some(name) => TimeZoneName::new(name)?,
+ None => return Ok(Self { ut_offset, is_dst, name: None }),
+ };
+
+ Ok(Self { ut_offset, is_dst, name: Some(name) })
+ }
+
+ /// Construct a local time type with the specified UTC offset in seconds
+ pub(super) fn with_offset(ut_offset: i32) -> Result<Self, Error> {
+ if ut_offset == i32::min_value() {
+ return Err(Error::LocalTimeType("invalid UTC offset"));
+ }
+
+ Ok(Self { ut_offset, is_dst: false, name: None })
+ }
+
+ /// Returns offset from UTC in seconds
+ pub(crate) const fn offset(&self) -> i32 {
+ self.ut_offset
+ }
+
+ /// Returns daylight saving time indicator
+ pub(super) const fn is_dst(&self) -> bool {
+ self.is_dst
+ }
+
+ pub(super) const UTC: LocalTimeType = Self { ut_offset: 0, is_dst: false, name: None };
+}
+
+/// Open the TZif file corresponding to a TZ string
+fn find_tz_file(path: impl AsRef<Path>) -> Result<File, Error> {
+ // Don't check system timezone directories on non-UNIX platforms
+ #[cfg(not(unix))]
+ return Ok(File::open(path)?);
+
+ #[cfg(unix)]
+ {
+ let path = path.as_ref();
+ if path.is_absolute() {
+ return Ok(File::open(path)?);
+ }
+
+ for folder in &ZONE_INFO_DIRECTORIES {
+ if let Ok(file) = File::open(PathBuf::from(folder).join(path)) {
+ return Ok(file);
+ }
+ }
+
+ Err(Error::Io(io::ErrorKind::NotFound.into()))
+ }
+}
+
+#[inline]
+fn saturating_abs(v: i32) -> i32 {
+ if v.is_positive() {
+ v
+ } else if v == i32::min_value() {
+ i32::max_value()
+ } else {
+ -v
+ }
+}
+
+// Possible system timezone directories
+#[cfg(unix)]
+const ZONE_INFO_DIRECTORIES: [&str; 3] =
+ ["/usr/share/zoneinfo", "/share/zoneinfo", "/etc/zoneinfo"];
+
+/// Number of seconds in one week
+pub(crate) const SECONDS_PER_WEEK: i64 = SECONDS_PER_DAY * DAYS_PER_WEEK;
+/// Number of seconds in 28 days
+const SECONDS_PER_28_DAYS: i64 = SECONDS_PER_DAY * 28;
+
+#[cfg(test)]
+mod tests {
+ use super::super::Error;
+ use super::{LeapSecond, LocalTimeType, TimeZone, TimeZoneName, Transition, TransitionRule};
+ use crate::matches;
+
+ #[test]
+ fn test_no_dst() -> Result<(), Error> {
+ let tz_string = b"HST10";
+ let transition_rule = TransitionRule::from_tz_string(tz_string, false)?;
+ assert_eq!(transition_rule, LocalTimeType::new(-36000, false, Some(b"HST"))?.into());
+ Ok(())
+ }
+
+ #[test]
+ fn test_error() -> Result<(), Error> {
+ assert!(matches!(
+ TransitionRule::from_tz_string(b"IST-1GMT0", false),
+ Err(Error::UnsupportedTzString(_))
+ ));
+ assert!(matches!(
+ TransitionRule::from_tz_string(b"EET-2EEST", false),
+ Err(Error::UnsupportedTzString(_))
+ ));
+
+ Ok(())
+ }
+
+ #[test]
+ fn test_v1_file_with_leap_seconds() -> Result<(), Error> {
+ let bytes = b"TZif\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\0\0\0\x01\0\0\0\x1b\0\0\0\0\0\0\0\x01\0\0\0\x04\0\0\0\0\0\0UTC\0\x04\xb2\x58\0\0\0\0\x01\x05\xa4\xec\x01\0\0\0\x02\x07\x86\x1f\x82\0\0\0\x03\x09\x67\x53\x03\0\0\0\x04\x0b\x48\x86\x84\0\0\0\x05\x0d\x2b\x0b\x85\0\0\0\x06\x0f\x0c\x3f\x06\0\0\0\x07\x10\xed\x72\x87\0\0\0\x08\x12\xce\xa6\x08\0\0\0\x09\x15\x9f\xca\x89\0\0\0\x0a\x17\x80\xfe\x0a\0\0\0\x0b\x19\x62\x31\x8b\0\0\0\x0c\x1d\x25\xea\x0c\0\0\0\x0d\x21\xda\xe5\x0d\0\0\0\x0e\x25\x9e\x9d\x8e\0\0\0\x0f\x27\x7f\xd1\x0f\0\0\0\x10\x2a\x50\xf5\x90\0\0\0\x11\x2c\x32\x29\x11\0\0\0\x12\x2e\x13\x5c\x92\0\0\0\x13\x30\xe7\x24\x13\0\0\0\x14\x33\xb8\x48\x94\0\0\0\x15\x36\x8c\x10\x15\0\0\0\x16\x43\xb7\x1b\x96\0\0\0\x17\x49\x5c\x07\x97\0\0\0\x18\x4f\xef\x93\x18\0\0\0\x19\x55\x93\x2d\x99\0\0\0\x1a\x58\x68\x46\x9a\0\0\0\x1b\0\0";
+
+ let time_zone = TimeZone::from_tz_data(bytes)?;
+
+ let time_zone_result = TimeZone::new(
+ Vec::new(),
+ vec![LocalTimeType::new(0, false, Some(b"UTC"))?],
+ vec![
+ LeapSecond::new(78796800, 1),
+ LeapSecond::new(94694401, 2),
+ LeapSecond::new(126230402, 3),
+ LeapSecond::new(157766403, 4),
+ LeapSecond::new(189302404, 5),
+ LeapSecond::new(220924805, 6),
+ LeapSecond::new(252460806, 7),
+ LeapSecond::new(283996807, 8),
+ LeapSecond::new(315532808, 9),
+ LeapSecond::new(362793609, 10),
+ LeapSecond::new(394329610, 11),
+ LeapSecond::new(425865611, 12),
+ LeapSecond::new(489024012, 13),
+ LeapSecond::new(567993613, 14),
+ LeapSecond::new(631152014, 15),
+ LeapSecond::new(662688015, 16),
+ LeapSecond::new(709948816, 17),
+ LeapSecond::new(741484817, 18),
+ LeapSecond::new(773020818, 19),
+ LeapSecond::new(820454419, 20),
+ LeapSecond::new(867715220, 21),
+ LeapSecond::new(915148821, 22),
+ LeapSecond::new(1136073622, 23),
+ LeapSecond::new(1230768023, 24),
+ LeapSecond::new(1341100824, 25),
+ LeapSecond::new(1435708825, 26),
+ LeapSecond::new(1483228826, 27),
+ ],
+ None,
+ )?;
+
+ assert_eq!(time_zone, time_zone_result);
+
+ Ok(())
+ }
+
+ #[test]
+ fn test_v2_file() -> Result<(), Error> {
+ let bytes = b"TZif2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x06\0\0\0\x06\0\0\0\0\0\0\0\x07\0\0\0\x06\0\0\0\x14\x80\0\0\0\xbb\x05\x43\x48\xbb\x21\x71\x58\xcb\x89\x3d\xc8\xd2\x23\xf4\x70\xd2\x61\x49\x38\xd5\x8d\x73\x48\x01\x02\x01\x03\x04\x01\x05\xff\xff\x6c\x02\0\0\xff\xff\x6c\x58\0\x04\xff\xff\x7a\x68\x01\x08\xff\xff\x7a\x68\x01\x0c\xff\xff\x7a\x68\x01\x10\xff\xff\x73\x60\0\x04LMT\0HST\0HDT\0HWT\0HPT\0\0\0\0\0\x01\0\0\0\0\0\x01\0TZif2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x06\0\0\0\x06\0\0\0\0\0\0\0\x07\0\0\0\x06\0\0\0\x14\xff\xff\xff\xff\x74\xe0\x70\xbe\xff\xff\xff\xff\xbb\x05\x43\x48\xff\xff\xff\xff\xbb\x21\x71\x58\xff\xff\xff\xff\xcb\x89\x3d\xc8\xff\xff\xff\xff\xd2\x23\xf4\x70\xff\xff\xff\xff\xd2\x61\x49\x38\xff\xff\xff\xff\xd5\x8d\x73\x48\x01\x02\x01\x03\x04\x01\x05\xff\xff\x6c\x02\0\0\xff\xff\x6c\x58\0\x04\xff\xff\x7a\x68\x01\x08\xff\xff\x7a\x68\x01\x0c\xff\xff\x7a\x68\x01\x10\xff\xff\x73\x60\0\x04LMT\0HST\0HDT\0HWT\0HPT\0\0\0\0\0\x01\0\0\0\0\0\x01\0\x0aHST10\x0a";
+
+ let time_zone = TimeZone::from_tz_data(bytes)?;
+
+ let time_zone_result = TimeZone::new(
+ vec![
+ Transition::new(-2334101314, 1),
+ Transition::new(-1157283000, 2),
+ Transition::new(-1155436200, 1),
+ Transition::new(-880198200, 3),
+ Transition::new(-769395600, 4),
+ Transition::new(-765376200, 1),
+ Transition::new(-712150200, 5),
+ ],
+ vec![
+ LocalTimeType::new(-37886, false, Some(b"LMT"))?,
+ LocalTimeType::new(-37800, false, Some(b"HST"))?,
+ LocalTimeType::new(-34200, true, Some(b"HDT"))?,
+ LocalTimeType::new(-34200, true, Some(b"HWT"))?,
+ LocalTimeType::new(-34200, true, Some(b"HPT"))?,
+ LocalTimeType::new(-36000, false, Some(b"HST"))?,
+ ],
+ Vec::new(),
+ Some(TransitionRule::from(LocalTimeType::new(-36000, false, Some(b"HST"))?)),
+ )?;
+
+ assert_eq!(time_zone, time_zone_result);
+
+ assert_eq!(
+ *time_zone.find_local_time_type(-1156939200)?,
+ LocalTimeType::new(-34200, true, Some(b"HDT"))?
+ );
+ assert_eq!(
+ *time_zone.find_local_time_type(1546300800)?,
+ LocalTimeType::new(-36000, false, Some(b"HST"))?
+ );
+
+ Ok(())
+ }
+
+ #[test]
+ fn test_tz_ascii_str() -> Result<(), Error> {
+ assert!(matches!(TimeZoneName::new(b""), Err(Error::LocalTimeType(_))));
+ assert!(matches!(TimeZoneName::new(b"1"), Err(Error::LocalTimeType(_))));
+ assert!(matches!(TimeZoneName::new(b"12"), Err(Error::LocalTimeType(_))));
+ assert_eq!(TimeZoneName::new(b"123")?.as_bytes(), b"123");
+ assert_eq!(TimeZoneName::new(b"1234")?.as_bytes(), b"1234");
+ assert_eq!(TimeZoneName::new(b"12345")?.as_bytes(), b"12345");
+ assert_eq!(TimeZoneName::new(b"123456")?.as_bytes(), b"123456");
+ assert_eq!(TimeZoneName::new(b"1234567")?.as_bytes(), b"1234567");
+ assert!(matches!(TimeZoneName::new(b"12345678"), Err(Error::LocalTimeType(_))));
+ assert!(matches!(TimeZoneName::new(b"123456789"), Err(Error::LocalTimeType(_))));
+ assert!(matches!(TimeZoneName::new(b"1234567890"), Err(Error::LocalTimeType(_))));
+
+ assert!(matches!(TimeZoneName::new(b"123\0\0\0"), Err(Error::LocalTimeType(_))));
+
+ Ok(())
+ }
+
+ #[test]
+ fn test_time_zone() -> Result<(), Error> {
+ let utc = LocalTimeType::UTC;
+ let cet = LocalTimeType::with_offset(3600)?;
+
+ let utc_local_time_types = vec![utc];
+ let fixed_extra_rule = TransitionRule::from(cet);
+
+ let time_zone_1 = TimeZone::new(vec![], utc_local_time_types.clone(), vec![], None)?;
+ let time_zone_2 =
+ TimeZone::new(vec![], utc_local_time_types.clone(), vec![], Some(fixed_extra_rule))?;
+ let time_zone_3 =
+ TimeZone::new(vec![Transition::new(0, 0)], utc_local_time_types.clone(), vec![], None)?;
+ let time_zone_4 = TimeZone::new(
+ vec![Transition::new(i32::min_value().into(), 0), Transition::new(0, 1)],
+ vec![utc, cet],
+ Vec::new(),
+ Some(fixed_extra_rule),
+ )?;
+
+ assert_eq!(*time_zone_1.find_local_time_type(0)?, utc);
+ assert_eq!(*time_zone_2.find_local_time_type(0)?, cet);
+
+ assert_eq!(*time_zone_3.find_local_time_type(-1)?, utc);
+ assert!(matches!(time_zone_3.find_local_time_type(0), Err(Error::FindLocalTimeType(_))));
+
+ assert_eq!(*time_zone_4.find_local_time_type(-1)?, utc);
+ assert_eq!(*time_zone_4.find_local_time_type(0)?, cet);
+
+ let time_zone_err = TimeZone::new(
+ vec![Transition::new(0, 0)],
+ utc_local_time_types,
+ vec![],
+ Some(fixed_extra_rule),
+ );
+ assert!(time_zone_err.is_err());
+
+ Ok(())
+ }
+
+ #[test]
+ fn test_time_zone_from_posix_tz() -> Result<(), Error> {
+ #[cfg(unix)]
+ {
+ // if the TZ var is set, this essentially _overrides_ the
+ // time set by the localtime symlink
+ // so just ensure that ::local() acts as expected
+ // in this case
+ if let Ok(tz) = std::env::var("TZ") {
+ let time_zone_local = TimeZone::local(Some(tz.as_str()))?;
+ let time_zone_local_1 = TimeZone::from_posix_tz(&tz)?;
+ assert_eq!(time_zone_local, time_zone_local_1);
+ }
+
+ let time_zone_utc = TimeZone::from_posix_tz("UTC")?;
+ assert_eq!(time_zone_utc.find_local_time_type(0)?.offset(), 0);
+ }
+
+ assert!(TimeZone::from_posix_tz("EST5EDT,0/0,J365/25").is_err());
+ assert!(TimeZone::from_posix_tz("").is_err());
+
+ Ok(())
+ }
+
+ #[test]
+ fn test_leap_seconds() -> Result<(), Error> {
+ let time_zone = TimeZone::new(
+ Vec::new(),
+ vec![LocalTimeType::new(0, false, Some(b"UTC"))?],
+ vec![
+ LeapSecond::new(78796800, 1),
+ LeapSecond::new(94694401, 2),
+ LeapSecond::new(126230402, 3),
+ LeapSecond::new(157766403, 4),
+ LeapSecond::new(189302404, 5),
+ LeapSecond::new(220924805, 6),
+ LeapSecond::new(252460806, 7),
+ LeapSecond::new(283996807, 8),
+ LeapSecond::new(315532808, 9),
+ LeapSecond::new(362793609, 10),
+ LeapSecond::new(394329610, 11),
+ LeapSecond::new(425865611, 12),
+ LeapSecond::new(489024012, 13),
+ LeapSecond::new(567993613, 14),
+ LeapSecond::new(631152014, 15),
+ LeapSecond::new(662688015, 16),
+ LeapSecond::new(709948816, 17),
+ LeapSecond::new(741484817, 18),
+ LeapSecond::new(773020818, 19),
+ LeapSecond::new(820454419, 20),
+ LeapSecond::new(867715220, 21),
+ LeapSecond::new(915148821, 22),
+ LeapSecond::new(1136073622, 23),
+ LeapSecond::new(1230768023, 24),
+ LeapSecond::new(1341100824, 25),
+ LeapSecond::new(1435708825, 26),
+ LeapSecond::new(1483228826, 27),
+ ],
+ None,
+ )?;
+
+ let time_zone_ref = time_zone.as_ref();
+
+ assert!(matches!(time_zone_ref.unix_leap_time_to_unix_time(1136073621), Ok(1136073599)));
+ assert!(matches!(time_zone_ref.unix_leap_time_to_unix_time(1136073622), Ok(1136073600)));
+ assert!(matches!(time_zone_ref.unix_leap_time_to_unix_time(1136073623), Ok(1136073600)));
+ assert!(matches!(time_zone_ref.unix_leap_time_to_unix_time(1136073624), Ok(1136073601)));
+
+ assert!(matches!(time_zone_ref.unix_time_to_unix_leap_time(1136073599), Ok(1136073621)));
+ assert!(matches!(time_zone_ref.unix_time_to_unix_leap_time(1136073600), Ok(1136073623)));
+ assert!(matches!(time_zone_ref.unix_time_to_unix_leap_time(1136073601), Ok(1136073624)));
+
+ Ok(())
+ }
+
+ #[test]
+ fn test_leap_seconds_overflow() -> Result<(), Error> {
+ let time_zone_err = TimeZone::new(
+ vec![Transition::new(i64::min_value(), 0)],
+ vec![LocalTimeType::UTC],
+ vec![LeapSecond::new(0, 1)],
+ Some(TransitionRule::from(LocalTimeType::UTC)),
+ );
+ assert!(time_zone_err.is_err());
+
+ let time_zone = TimeZone::new(
+ vec![Transition::new(i64::max_value(), 0)],
+ vec![LocalTimeType::UTC],
+ vec![LeapSecond::new(0, 1)],
+ None,
+ )?;
+ assert!(matches!(
+ time_zone.find_local_time_type(i64::max_value()),
+ Err(Error::FindLocalTimeType(_))
+ ));
+
+ Ok(())
+ }
+}
diff --git a/vendor/chrono/src/offset/local/unix.rs b/vendor/chrono/src/offset/local/unix.rs
new file mode 100644
index 000000000..32aa31618
--- /dev/null
+++ b/vendor/chrono/src/offset/local/unix.rs
@@ -0,0 +1,185 @@
+// 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::{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};
+
+pub(super) fn now() -> DateTime<Local> {
+ let now = Utc::now().naive_utc();
+ naive_to_local(&now, false).unwrap()
+}
+
+pub(super) fn naive_to_local(d: &NaiveDateTime, local: bool) -> LocalResult<DateTime<Local>> {
+ TZ_INFO.with(|maybe_cache| {
+ maybe_cache.borrow_mut().get_or_insert_with(Cache::default).offset(*d, local)
+ })
+}
+
+// we have to store the `Cache` in an option as it can't
+// be initalized in a static context.
+thread_local! {
+ static TZ_INFO: RefCell<Option<Cache>> = Default::default();
+}
+
+enum Source {
+ LocalTime { mtime: SystemTime },
+ Environment { hash: u64 },
+}
+
+impl Source {
+ fn new(env_tz: Option<&str>) -> Source {
+ match env_tz {
+ Some(tz) => {
+ let mut hasher = hash_map::DefaultHasher::new();
+ hasher.write(tz.as_bytes());
+ let hash = hasher.finish();
+ Source::Environment { hash }
+ }
+ None => match fs::symlink_metadata("/etc/localtime") {
+ Ok(data) => Source::LocalTime {
+ // we have to pick a sensible default when the mtime fails
+ // by picking SystemTime::now() we raise the probability of
+ // the cache being invalidated if/when the mtime starts working
+ mtime: data.modified().unwrap_or_else(|_| SystemTime::now()),
+ },
+ Err(_) => {
+ // as above, now() should be a better default than some constant
+ // TODO: see if we can improve caching in the case where the fallback is a valid timezone
+ Source::LocalTime { mtime: SystemTime::now() }
+ }
+ },
+ }
+ }
+}
+
+struct Cache {
+ zone: TimeZone,
+ source: Source,
+ 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()?;
+ let bytes = fs::read(format!("{}/{}", TZDB_LOCATION, tz_name)).ok()?;
+ TimeZone::from_tz_data(&bytes).ok()
+}
+
+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());
+ Cache {
+ last_checked: SystemTime::now(),
+ source: Source::new(env_ref),
+ zone: current_zone(env_ref),
+ }
+ }
+}
+
+fn current_zone(var: Option<&str>) -> TimeZone {
+ TimeZone::local(var).ok().or_else(fallback_timezone).unwrap_or_else(TimeZone::utc)
+}
+
+impl Cache {
+ fn offset(&mut self, d: NaiveDateTime, local: bool) -> LocalResult<DateTime<Local>> {
+ let now = SystemTime::now();
+
+ match now.duration_since(self.last_checked) {
+ // If the cache has been around for less than a second then we reuse it
+ // unconditionally. This is a reasonable tradeoff because the timezone
+ // generally won't be changing _that_ often, but if the time zone does
+ // change, it will reflect sufficiently quickly from an application
+ // user's perspective.
+ 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 new_source = Source::new(env_ref);
+
+ let out_of_date = match (&self.source, &new_source) {
+ // change from env to file or file to env, must recreate the zone
+ (Source::Environment { .. }, Source::LocalTime { .. })
+ | (Source::LocalTime { .. }, Source::Environment { .. }) => true,
+ // stay as file, but mtime has changed
+ (Source::LocalTime { mtime: old_mtime }, Source::LocalTime { mtime })
+ if old_mtime != mtime =>
+ {
+ true
+ }
+ // stay as env, but hash of variable has changed
+ (Source::Environment { hash: old_hash }, Source::Environment { hash })
+ if old_hash != hash =>
+ {
+ true
+ }
+ // cache can be reused
+ _ => false,
+ };
+
+ if out_of_date {
+ self.zone = current_zone(env_ref);
+ }
+
+ self.last_checked = now;
+ self.source = new_source;
+ }
+ }
+
+ if !local {
+ let offset = self
+ .zone
+ .find_local_time_type(d.timestamp())
+ .expect("unable to select local time type")
+ .offset();
+
+ return match FixedOffset::east_opt(offset) {
+ Some(offset) => LocalResult::Single(DateTime::from_utc(d, 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
+ .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))
+ }
+ }
+ }
+}
diff --git a/vendor/chrono/src/offset/local/windows.rs b/vendor/chrono/src/offset/local/windows.rs
new file mode 100644
index 000000000..e6415015c
--- /dev/null
+++ b/vendor/chrono/src/offset/local/windows.rs
@@ -0,0 +1,278 @@
+// 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::io;
+use std::mem;
+use std::time::{SystemTime, UNIX_EPOCH};
+
+use winapi::shared::minwindef::*;
+use winapi::um::minwinbase::SYSTEMTIME;
+use winapi::um::timezoneapi::*;
+
+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`.
+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.
+///
+/// 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)]
+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)
+}
+
+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
+}
+
+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 };
+
+ (month - 1) * 30 + month / 2 + (day - 1) - leap + july
+ }
+}
+
+macro_rules! call {
+ ($name:ident($($arg:expr),*)) => {
+ if $name($($arg),*) == 0 {
+ panic!(concat!(stringify!($name), " failed with: {}"),
+ io::Error::last_os_error());
+ }
+ }
+}
+
+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 };
+ }
+}
+
+fn utc_tm_to_time(tm: &Tm) -> i64 {
+ 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)
+ }
+}
+
+fn local_tm_to_time(tm: &Tm) -> i64 {
+ 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)
+ }
+}
diff --git a/vendor/chrono/src/offset/mod.rs b/vendor/chrono/src/offset/mod.rs
index 0da6bfb42..09d0714e9 100644
--- a/vendor/chrono/src/offset/mod.rs
+++ b/vendor/chrono/src/offset/mod.rs
@@ -20,10 +20,22 @@
use core::fmt;
-use format::{parse, ParseResult, Parsed, StrftimeItems};
-use naive::{NaiveDate, NaiveDateTime, NaiveTime};
-use Weekday;
-use {Date, DateTime};
+use crate::format::{parse, ParseResult, Parsed, StrftimeItems};
+use crate::naive::{NaiveDate, NaiveDateTime, NaiveTime};
+use crate::Weekday;
+#[allow(deprecated)]
+use crate::{Date, DateTime};
+
+mod fixed;
+pub use self::fixed::FixedOffset;
+
+#[cfg(feature = "clock")]
+mod local;
+#[cfg(feature = "clock")]
+pub use self::local::Local;
+
+mod utc;
+pub use self::utc::Utc;
/// The conversion result from the local time to the timezone-aware datetime types.
#[derive(Clone, PartialEq, Debug, Copy, Eq, Hash)]
@@ -73,6 +85,7 @@ impl<T> LocalResult<T> {
}
}
+#[allow(deprecated)]
impl<Tz: TimeZone> LocalResult<Date<Tz>> {
/// Makes a new `DateTime` from the current date and given `NaiveTime`.
/// The offset in the current date is preserved.
@@ -195,6 +208,27 @@ pub trait TimeZone: Sized + Clone {
/// The original `TimeZone` value can be recovered via `TimeZone::from_offset`.
type Offset: Offset;
+ /// Make a new `DateTime` from year, month, day, time components and current time zone.
+ ///
+ /// This assumes the proleptic Gregorian calendar, with the year 0 being 1 BCE.
+ ///
+ /// Returns `LocalResult::None` on invalid input data.
+ fn with_ymd_and_hms(
+ &self,
+ year: i32,
+ month: u32,
+ day: u32,
+ hour: u32,
+ min: u32,
+ sec: u32,
+ ) -> LocalResult<DateTime<Self>> {
+ match NaiveDate::from_ymd_opt(year, month, day).and_then(|d| d.and_hms_opt(hour, min, sec))
+ {
+ Some(dt) => self.from_local_datetime(&dt),
+ None => LocalResult::None,
+ }
+ }
+
/// Makes a new `Date` from year, month, day and the current time zone.
/// This assumes the proleptic Gregorian calendar, with the year 0 being 1 BCE.
///
@@ -202,14 +236,8 @@ pub trait TimeZone: Sized + Clone {
/// but it will propagate to the `DateTime` values constructed via this date.
///
/// Panics on the out-of-range date, invalid month and/or day.
- ///
- /// # Example
- ///
- /// ~~~~
- /// use chrono::{Utc, TimeZone};
- ///
- /// assert_eq!(Utc.ymd(2015, 5, 15).to_string(), "2015-05-15UTC");
- /// ~~~~
+ #[deprecated(since = "0.4.23", note = "use `with_ymd_and_hms()` instead")]
+ #[allow(deprecated)]
fn ymd(&self, year: i32, month: u32, day: u32) -> Date<Self> {
self.ymd_opt(year, month, day).unwrap()
}
@@ -221,15 +249,8 @@ pub trait TimeZone: Sized + Clone {
/// but it will propagate to the `DateTime` values constructed via this date.
///
/// Returns `None` on the out-of-range date, invalid month and/or day.
- ///
- /// # Example
- ///
- /// ~~~~
- /// use chrono::{Utc, LocalResult, TimeZone};
- ///
- /// assert_eq!(Utc.ymd_opt(2015, 5, 15).unwrap().to_string(), "2015-05-15UTC");
- /// assert_eq!(Utc.ymd_opt(2000, 0, 0), LocalResult::None);
- /// ~~~~
+ #[deprecated(since = "0.4.23", note = "use `with_ymd_and_hms()` instead")]
+ #[allow(deprecated)]
fn ymd_opt(&self, year: i32, month: u32, day: u32) -> LocalResult<Date<Self>> {
match NaiveDate::from_ymd_opt(year, month, day) {
Some(d) => self.from_local_date(&d),
@@ -244,14 +265,11 @@ pub trait TimeZone: Sized + Clone {
/// but it will propagate to the `DateTime` values constructed via this date.
///
/// Panics on the out-of-range date and/or invalid DOY.
- ///
- /// # Example
- ///
- /// ~~~~
- /// use chrono::{Utc, TimeZone};
- ///
- /// assert_eq!(Utc.yo(2015, 135).to_string(), "2015-05-15UTC");
- /// ~~~~
+ #[deprecated(
+ since = "0.4.23",
+ note = "use `from_local_datetime()` with a `NaiveDateTime` instead"
+ )]
+ #[allow(deprecated)]
fn yo(&self, year: i32, ordinal: u32) -> Date<Self> {
self.yo_opt(year, ordinal).unwrap()
}
@@ -263,6 +281,11 @@ pub trait TimeZone: Sized + Clone {
/// but it will propagate to the `DateTime` values constructed via this date.
///
/// Returns `None` on the out-of-range date and/or invalid DOY.
+ #[deprecated(
+ since = "0.4.23",
+ note = "use `from_local_datetime()` with a `NaiveDateTime` instead"
+ )]
+ #[allow(deprecated)]
fn yo_opt(&self, year: i32, ordinal: u32) -> LocalResult<Date<Self>> {
match NaiveDate::from_yo_opt(year, ordinal) {
Some(d) => self.from_local_date(&d),
@@ -279,14 +302,11 @@ pub trait TimeZone: Sized + Clone {
/// but it will propagate to the `DateTime` values constructed via this date.
///
/// Panics on the out-of-range date and/or invalid week number.
- ///
- /// # Example
- ///
- /// ~~~~
- /// use chrono::{Utc, Weekday, TimeZone};
- ///
- /// assert_eq!(Utc.isoywd(2015, 20, Weekday::Fri).to_string(), "2015-05-15UTC");
- /// ~~~~
+ #[deprecated(
+ since = "0.4.23",
+ note = "use `from_local_datetime()` with a `NaiveDateTime` instead"
+ )]
+ #[allow(deprecated)]
fn isoywd(&self, year: i32, week: u32, weekday: Weekday) -> Date<Self> {
self.isoywd_opt(year, week, weekday).unwrap()
}
@@ -300,6 +320,11 @@ pub trait TimeZone: Sized + Clone {
/// but it will propagate to the `DateTime` values constructed via this date.
///
/// Returns `None` on the out-of-range date and/or invalid week number.
+ #[deprecated(
+ since = "0.4.23",
+ note = "use `from_local_datetime()` with a `NaiveDateTime` instead"
+ )]
+ #[allow(deprecated)]
fn isoywd_opt(&self, year: i32, week: u32, weekday: Weekday) -> LocalResult<Date<Self>> {
match NaiveDate::from_isoywd_opt(year, week, weekday) {
Some(d) => self.from_local_date(&d),
@@ -313,14 +338,7 @@ pub trait TimeZone: Sized + Clone {
///
/// Panics on the out-of-range number of seconds and/or invalid nanosecond,
/// for a non-panicking version see [`timestamp_opt`](#method.timestamp_opt).
- ///
- /// # Example
- ///
- /// ~~~~
- /// use chrono::{Utc, TimeZone};
- ///
- /// assert_eq!(Utc.timestamp(1431648000, 0).to_string(), "2015-05-15 00:00:00 UTC");
- /// ~~~~
+ #[deprecated(since = "0.4.23", note = "use `timestamp_opt()` instead")]
fn timestamp(&self, secs: i64, nsecs: u32) -> DateTime<Self> {
self.timestamp_opt(secs, nsecs).unwrap()
}
@@ -331,6 +349,14 @@ pub trait TimeZone: Sized + Clone {
///
/// Returns `LocalResult::None` on out-of-range number of seconds and/or
/// invalid nanosecond, otherwise always returns `LocalResult::Single`.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use chrono::{Utc, TimeZone};
+ ///
+ /// assert_eq!(Utc.timestamp_opt(1431648000, 0).unwrap().to_string(), "2015-05-15 00:00:00 UTC");
+ /// ```
fn timestamp_opt(&self, secs: i64, nsecs: u32) -> LocalResult<DateTime<Self>> {
match NaiveDateTime::from_timestamp_opt(secs, nsecs) {
Some(dt) => LocalResult::Single(self.from_utc_datetime(&dt)),
@@ -343,14 +369,7 @@ pub trait TimeZone: Sized + Clone {
///
/// Panics on out-of-range number of milliseconds for a non-panicking
/// version see [`timestamp_millis_opt`](#method.timestamp_millis_opt).
- ///
- /// # Example
- ///
- /// ~~~~
- /// use chrono::{Utc, TimeZone};
- ///
- /// assert_eq!(Utc.timestamp_millis(1431648000).timestamp(), 1431648);
- /// ~~~~
+ #[deprecated(since = "0.4.23", note = "use `timestamp_millis_opt()` instead")]
fn timestamp_millis(&self, millis: i64) -> DateTime<Self> {
self.timestamp_millis_opt(millis).unwrap()
}
@@ -365,13 +384,13 @@ pub trait TimeZone: Sized + Clone {
///
/// # Example
///
- /// ~~~~
+ /// ```
/// use chrono::{Utc, TimeZone, LocalResult};
/// match Utc.timestamp_millis_opt(1431648000) {
/// LocalResult::Single(dt) => assert_eq!(dt.timestamp(), 1431648),
/// _ => panic!("Incorrect timestamp_millis"),
/// };
- /// ~~~~
+ /// ```
fn timestamp_millis_opt(&self, millis: i64) -> LocalResult<DateTime<Self>> {
let (mut secs, mut millis) = (millis / 1000, millis % 1000);
if millis < 0 {
@@ -389,11 +408,11 @@ pub trait TimeZone: Sized + Clone {
///
/// # Example
///
- /// ~~~~
+ /// ```
/// use chrono::{Utc, TimeZone};
///
/// assert_eq!(Utc.timestamp_nanos(1431648000000000).timestamp(), 1431648);
- /// ~~~~
+ /// ```
fn timestamp_nanos(&self, nanos: i64) -> DateTime<Self> {
let (mut secs, mut nanos) = (nanos / 1_000_000_000, nanos % 1_000_000_000);
if nanos < 0 {
@@ -403,16 +422,17 @@ pub trait TimeZone: Sized + Clone {
self.timestamp_opt(secs, nanos as u32).unwrap()
}
- /// Parses a string with the specified format string and
- /// returns a `DateTime` with the current offset.
- /// See the [`format::strftime` module](../format/strftime/index.html)
- /// on the supported escape sequences.
+ /// Parses a string with the specified format string and returns a
+ /// `DateTime` with the current offset.
+ ///
+ /// See the [`crate::format::strftime`] module on the
+ /// supported escape sequences.
///
- /// If the format does not include offsets, the current offset is assumed;
- /// otherwise the input should have a matching UTC offset.
+ /// If the to-be-parsed string includes an offset, it *must* match the
+ /// offset of the TimeZone, otherwise an error will be returned.
///
- /// See also `DateTime::parse_from_str` which gives a local `DateTime`
- /// with parsed `FixedOffset`.
+ /// See also [`DateTime::parse_from_str`] which gives a [`DateTime`] with
+ /// parsed [`FixedOffset`].
fn datetime_from_str(&self, s: &str, fmt: &str) -> ParseResult<DateTime<Self>> {
let mut parsed = Parsed::new();
parse(&mut parsed, s, StrftimeItems::new(fmt))?;
@@ -429,6 +449,9 @@ pub trait TimeZone: Sized + Clone {
fn offset_from_local_datetime(&self, local: &NaiveDateTime) -> LocalResult<Self::Offset>;
/// Converts the local `NaiveDate` to the timezone-aware `Date` if possible.
+ #[allow(clippy::wrong_self_convention)]
+ #[deprecated(since = "0.4.23", note = "use `from_local_datetime()` instead")]
+ #[allow(deprecated)]
fn from_local_date(&self, local: &NaiveDate) -> LocalResult<Date<Self>> {
self.offset_from_local_date(local).map(|offset| {
// since FixedOffset is within +/- 1 day, the date is never affected
@@ -437,6 +460,7 @@ pub trait TimeZone: Sized + Clone {
}
/// Converts the local `NaiveDateTime` to the timezone-aware `DateTime` if possible.
+ #[allow(clippy::wrong_self_convention)]
fn from_local_datetime(&self, local: &NaiveDateTime) -> LocalResult<DateTime<Self>> {
self.offset_from_local_datetime(local)
.map(|offset| DateTime::from_utc(*local - offset.fix(), offset))
@@ -450,48 +474,42 @@ pub trait TimeZone: Sized + Clone {
/// Converts the UTC `NaiveDate` to the local time.
/// The UTC is continuous and thus this cannot fail (but can give the duplicate local time).
+ #[allow(clippy::wrong_self_convention)]
+ #[deprecated(since = "0.4.23", note = "use `from_utc_datetime()` instead")]
+ #[allow(deprecated)]
fn from_utc_date(&self, utc: &NaiveDate) -> Date<Self> {
Date::from_utc(*utc, self.offset_from_utc_date(utc))
}
/// Converts the UTC `NaiveDateTime` to the local time.
/// The UTC is continuous and thus this cannot fail (but can give the duplicate local time).
+ #[allow(clippy::wrong_self_convention)]
fn from_utc_datetime(&self, utc: &NaiveDateTime) -> DateTime<Self> {
DateTime::from_utc(*utc, self.offset_from_utc_datetime(utc))
}
}
-mod fixed;
-#[cfg(feature = "clock")]
-mod local;
-mod utc;
-
-pub use self::fixed::FixedOffset;
-#[cfg(feature = "clock")]
-pub use self::local::Local;
-pub use self::utc::Utc;
-
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_negative_millis() {
- let dt = Utc.timestamp_millis(-1000);
+ let dt = Utc.timestamp_millis_opt(-1000).unwrap();
assert_eq!(dt.to_string(), "1969-12-31 23:59:59 UTC");
- let dt = Utc.timestamp_millis(-7000);
+ let dt = Utc.timestamp_millis_opt(-7000).unwrap();
assert_eq!(dt.to_string(), "1969-12-31 23:59:53 UTC");
- let dt = Utc.timestamp_millis(-7001);
+ let dt = Utc.timestamp_millis_opt(-7001).unwrap();
assert_eq!(dt.to_string(), "1969-12-31 23:59:52.999 UTC");
- let dt = Utc.timestamp_millis(-7003);
+ let dt = Utc.timestamp_millis_opt(-7003).unwrap();
assert_eq!(dt.to_string(), "1969-12-31 23:59:52.997 UTC");
- let dt = Utc.timestamp_millis(-999);
+ let dt = Utc.timestamp_millis_opt(-999).unwrap();
assert_eq!(dt.to_string(), "1969-12-31 23:59:59.001 UTC");
- let dt = Utc.timestamp_millis(-1);
+ let dt = Utc.timestamp_millis_opt(-1).unwrap();
assert_eq!(dt.to_string(), "1969-12-31 23:59:59.999 UTC");
- let dt = Utc.timestamp_millis(-60000);
+ let dt = Utc.timestamp_millis_opt(-60000).unwrap();
assert_eq!(dt.to_string(), "1969-12-31 23:59:00 UTC");
- let dt = Utc.timestamp_millis(-3600000);
+ let dt = Utc.timestamp_millis_opt(-3600000).unwrap();
assert_eq!(dt.to_string(), "1969-12-31 23:00:00 UTC");
for (millis, expected) in &[
diff --git a/vendor/chrono/src/offset/utc.rs b/vendor/chrono/src/offset/utc.rs
index aec6667b0..cfed754b2 100644
--- a/vendor/chrono/src/offset/utc.rs
+++ b/vendor/chrono/src/offset/utc.rs
@@ -4,16 +4,24 @@
//! The UTC (Coordinated Universal Time) time zone.
use core::fmt;
-
-use super::{FixedOffset, LocalResult, Offset, TimeZone};
-use naive::{NaiveDate, NaiveDateTime};
#[cfg(all(
feature = "clock",
- not(all(target_arch = "wasm32", not(target_os = "wasi"), feature = "wasmbind"))
+ not(all(
+ target_arch = "wasm32",
+ feature = "wasmbind",
+ not(any(target_os = "emscripten", target_os = "wasi"))
+ ))
))]
use std::time::{SystemTime, UNIX_EPOCH};
+
+#[cfg(feature = "rkyv")]
+use rkyv::{Archive, Deserialize, Serialize};
+
+use super::{FixedOffset, LocalResult, Offset, TimeZone};
+use crate::naive::{NaiveDate, NaiveDateTime};
#[cfg(feature = "clock")]
-use {Date, DateTime};
+#[allow(deprecated)]
+use crate::{Date, DateTime};
/// The UTC time zone. This is the most efficient time zone when you don't need the local time.
/// It is also used as an offset (which is also a dummy type).
@@ -24,35 +32,52 @@ use {Date, DateTime};
///
/// # Example
///
-/// ~~~~
+/// ```
/// use chrono::{DateTime, TimeZone, NaiveDateTime, Utc};
///
/// let dt = DateTime::<Utc>::from_utc(NaiveDateTime::from_timestamp(61, 0), Utc);
///
/// assert_eq!(Utc.timestamp(61, 0), dt);
-/// assert_eq!(Utc.ymd(1970, 1, 1).and_hms(0, 1, 1), dt);
-/// ~~~~
-#[derive(Copy, Clone, PartialEq, Eq)]
+/// assert_eq!(Utc.with_ymd_and_hms(1970, 1, 1, 0, 1, 1).unwrap(), dt);
+/// ```
+#[derive(Copy, Clone, PartialEq, Eq, Hash)]
+#[cfg_attr(feature = "rkyv", derive(Archive, Deserialize, Serialize))]
+#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct Utc;
#[cfg(feature = "clock")]
+#[cfg_attr(docsrs, doc(cfg(feature = "clock")))]
impl Utc {
/// Returns a `Date` which corresponds to the current date.
+ #[deprecated(
+ since = "0.4.23",
+ note = "use `Utc::now()` instead, potentially with `.date_naive()`"
+ )]
+ #[allow(deprecated)]
pub fn today() -> Date<Utc> {
Utc::now().date()
}
- /// Returns a `DateTime` which corresponds to the current date.
- #[cfg(not(all(target_arch = "wasm32", not(target_os = "wasi"), feature = "wasmbind")))]
+ /// Returns a `DateTime` which corresponds to the current date and time.
+ #[cfg(not(all(
+ target_arch = "wasm32",
+ feature = "wasmbind",
+ not(any(target_os = "emscripten", target_os = "wasi"))
+ )))]
pub fn now() -> DateTime<Utc> {
let now =
SystemTime::now().duration_since(UNIX_EPOCH).expect("system time before Unix epoch");
- let naive = NaiveDateTime::from_timestamp(now.as_secs() as i64, now.subsec_nanos() as u32);
+ let naive =
+ NaiveDateTime::from_timestamp_opt(now.as_secs() as i64, now.subsec_nanos()).unwrap();
DateTime::from_utc(naive, Utc)
}
- /// Returns a `DateTime` which corresponds to the current date.
- #[cfg(all(target_arch = "wasm32", not(target_os = "wasi"), feature = "wasmbind"))]
+ /// Returns a `DateTime` which corresponds to the current date and time.
+ #[cfg(all(
+ target_arch = "wasm32",
+ feature = "wasmbind",
+ not(any(target_os = "emscripten", target_os = "wasi"))
+ ))]
pub fn now() -> DateTime<Utc> {
let now = js_sys::Date::new_0();
DateTime::<Utc>::from(now)
@@ -83,7 +108,7 @@ impl TimeZone for Utc {
impl Offset for Utc {
fn fix(&self) -> FixedOffset {
- FixedOffset::east(0)
+ FixedOffset::east_opt(0).unwrap()
}
}
diff --git a/vendor/chrono/src/oldtime.rs b/vendor/chrono/src/oldtime.rs
index 8656769c5..8e2b3d2c0 100644
--- a/vendor/chrono/src/oldtime.rs
+++ b/vendor/chrono/src/oldtime.rs
@@ -16,6 +16,9 @@ use core::{fmt, i64};
#[cfg(any(feature = "std", test))]
use std::error::Error;
+#[cfg(feature = "rkyv")]
+use rkyv::{Archive, Deserialize, Serialize};
+
/// The number of nanoseconds in a microsecond.
const NANOS_PER_MICRO: i32 = 1000;
/// The number of nanoseconds in a millisecond.
@@ -45,21 +48,23 @@ macro_rules! try_opt {
}
/// ISO 8601 time duration with nanosecond precision.
+///
/// This also allows for the negative duration; see individual methods for details.
-#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
+#[cfg_attr(feature = "rkyv", derive(Archive, Deserialize, Serialize))]
pub struct Duration {
secs: i64,
nanos: i32, // Always 0 <= nanos < NANOS_PER_SEC
}
/// The minimum possible `Duration`: `i64::MIN` milliseconds.
-pub const MIN: Duration = Duration {
+pub(crate) const MIN: Duration = Duration {
secs: i64::MIN / MILLIS_PER_SEC - 1,
nanos: NANOS_PER_SEC + (i64::MIN % MILLIS_PER_SEC) as i32 * NANOS_PER_MILLI,
};
/// The maximum possible `Duration`: `i64::MAX` milliseconds.
-pub const MAX: Duration = Duration {
+pub(crate) const MAX: Duration = Duration {
secs: i64::MAX / MILLIS_PER_SEC,
nanos: (i64::MAX % MILLIS_PER_SEC) as i32 * NANOS_PER_MILLI,
};
@@ -115,7 +120,7 @@ impl Duration {
/// Makes a new `Duration` with given number of milliseconds.
#[inline]
- pub fn milliseconds(milliseconds: i64) -> Duration {
+ pub const fn milliseconds(milliseconds: i64) -> Duration {
let (secs, millis) = div_mod_floor_64(milliseconds, MILLIS_PER_SEC);
let nanos = millis as i32 * NANOS_PER_MILLI;
Duration { secs: secs, nanos: nanos }
@@ -123,7 +128,7 @@ impl Duration {
/// Makes a new `Duration` with given number of microseconds.
#[inline]
- pub fn microseconds(microseconds: i64) -> Duration {
+ pub const fn microseconds(microseconds: i64) -> Duration {
let (secs, micros) = div_mod_floor_64(microseconds, MICROS_PER_SEC);
let nanos = micros as i32 * NANOS_PER_MICRO;
Duration { secs: secs, nanos: nanos }
@@ -131,36 +136,36 @@ impl Duration {
/// Makes a new `Duration` with given number of nanoseconds.
#[inline]
- pub fn nanoseconds(nanos: i64) -> Duration {
+ pub const fn nanoseconds(nanos: i64) -> Duration {
let (secs, nanos) = div_mod_floor_64(nanos, NANOS_PER_SEC as i64);
Duration { secs: secs, nanos: nanos as i32 }
}
/// Returns the total number of whole weeks in the duration.
#[inline]
- pub fn num_weeks(&self) -> i64 {
+ pub const fn num_weeks(&self) -> i64 {
self.num_days() / 7
}
/// Returns the total number of whole days in the duration.
- pub fn num_days(&self) -> i64 {
+ pub const fn num_days(&self) -> i64 {
self.num_seconds() / SECS_PER_DAY
}
/// Returns the total number of whole hours in the duration.
#[inline]
- pub fn num_hours(&self) -> i64 {
+ pub const fn num_hours(&self) -> i64 {
self.num_seconds() / SECS_PER_HOUR
}
/// Returns the total number of whole minutes in the duration.
#[inline]
- pub fn num_minutes(&self) -> i64 {
+ pub const fn num_minutes(&self) -> i64 {
self.num_seconds() / SECS_PER_MINUTE
}
/// Returns the total number of whole seconds in the duration.
- pub fn num_seconds(&self) -> i64 {
+ pub const fn num_seconds(&self) -> i64 {
// If secs is negative, nanos should be subtracted from the duration.
if self.secs < 0 && self.nanos > 0 {
self.secs + 1
@@ -172,7 +177,7 @@ impl Duration {
/// Returns the number of nanoseconds such that
/// `nanos_mod_sec() + num_seconds() * NANOS_PER_SEC` is the total number of
/// nanoseconds in the duration.
- fn nanos_mod_sec(&self) -> i32 {
+ const fn nanos_mod_sec(&self) -> i32 {
if self.secs < 0 && self.nanos > 0 {
self.nanos - NANOS_PER_SEC
} else {
@@ -181,7 +186,7 @@ impl Duration {
}
/// Returns the total number of whole milliseconds in the duration,
- pub fn num_milliseconds(&self) -> i64 {
+ pub const fn num_milliseconds(&self) -> i64 {
// A proper Duration will not overflow, because MIN and MAX are defined
// such that the range is exactly i64 milliseconds.
let secs_part = self.num_seconds() * MILLIS_PER_SEC;
@@ -191,7 +196,7 @@ impl Duration {
/// Returns the total number of whole microseconds in the duration,
/// or `None` on overflow (exceeding 2^63 microseconds in either direction).
- pub fn num_microseconds(&self) -> Option<i64> {
+ pub const fn num_microseconds(&self) -> Option<i64> {
let secs_part = try_opt!(self.num_seconds().checked_mul(MICROS_PER_SEC));
let nanos_part = self.nanos_mod_sec() / NANOS_PER_MICRO;
secs_part.checked_add(nanos_part as i64)
@@ -199,7 +204,7 @@ impl Duration {
/// Returns the total number of whole nanoseconds in the duration,
/// or `None` on overflow (exceeding 2^63 nanoseconds in either direction).
- pub fn num_nanoseconds(&self) -> Option<i64> {
+ pub const fn num_nanoseconds(&self) -> Option<i64> {
let secs_part = try_opt!(self.num_seconds().checked_mul(NANOS_PER_SEC as i64));
let nanos_part = self.nanos_mod_sec();
secs_part.checked_add(nanos_part as i64)
@@ -243,31 +248,35 @@ impl Duration {
/// Returns the duration as an absolute (non-negative) value.
#[inline]
- pub fn abs(&self) -> Duration {
- Duration { secs: self.secs.abs(), nanos: self.nanos }
+ pub const fn abs(&self) -> Duration {
+ if self.secs < 0 && self.nanos != 0 {
+ Duration { secs: (self.secs + 1).abs(), nanos: NANOS_PER_SEC - self.nanos }
+ } else {
+ Duration { secs: self.secs.abs(), nanos: self.nanos }
+ }
}
/// The minimum possible `Duration`: `i64::MIN` milliseconds.
#[inline]
- pub fn min_value() -> Duration {
+ pub const fn min_value() -> Duration {
MIN
}
/// The maximum possible `Duration`: `i64::MAX` milliseconds.
#[inline]
- pub fn max_value() -> Duration {
+ pub const fn max_value() -> Duration {
MAX
}
/// A duration where the stored seconds and nanoseconds are equal to zero.
#[inline]
- pub fn zero() -> Duration {
+ pub const fn zero() -> Duration {
Duration { secs: 0, nanos: 0 }
}
/// Returns `true` if the duration equals `Duration::zero()`.
#[inline]
- pub fn is_zero(&self) -> bool {
+ pub const fn is_zero(&self) -> bool {
self.secs == 0 && self.nanos == 0
}
@@ -372,7 +381,26 @@ impl Div<i32> for Duration {
}
}
+#[cfg(any(feature = "std", test))]
+#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
+impl<'a> std::iter::Sum<&'a Duration> for Duration {
+ fn sum<I: Iterator<Item = &'a Duration>>(iter: I) -> Duration {
+ iter.fold(Duration::zero(), |acc, x| acc + *x)
+ }
+}
+
+#[cfg(any(feature = "std", test))]
+#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
+impl std::iter::Sum<Duration> for Duration {
+ fn sum<I: Iterator<Item = Duration>>(iter: I) -> Duration {
+ iter.fold(Duration::zero(), |acc, x| acc + x)
+ }
+}
+
impl fmt::Display for Duration {
+ /// Format a duration using the [ISO 8601] format
+ ///
+ /// [ISO 8601]: https://en.wikipedia.org/wiki/ISO_8601#Durations
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
// technically speaking, negative duration is not valid ISO 8601,
// but we need to print it anyway.
@@ -419,6 +447,7 @@ impl fmt::Display for OutOfRangeError {
}
#[cfg(any(feature = "std", test))]
+#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
impl Error for OutOfRangeError {
#[allow(deprecated)]
fn description(&self) -> &str {
@@ -428,12 +457,12 @@ impl Error for OutOfRangeError {
// Copied from libnum
#[inline]
-fn div_mod_floor_64(this: i64, other: i64) -> (i64, i64) {
+const fn div_mod_floor_64(this: i64, other: i64) -> (i64, i64) {
(div_floor_64(this, other), mod_floor_64(this, other))
}
#[inline]
-fn div_floor_64(this: i64, other: i64) -> i64 {
+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,
@@ -441,7 +470,7 @@ fn div_floor_64(this: i64, other: i64) -> i64 {
}
#[inline]
-fn mod_floor_64(this: i64, other: i64) -> i64 {
+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,
@@ -449,10 +478,28 @@ fn mod_floor_64(this: i64, other: i64) -> i64 {
}
#[inline]
-fn div_rem_64(this: i64, other: i64) -> (i64, i64) {
+const fn div_rem_64(this: i64, other: i64) -> (i64, i64) {
(this / other, this % other)
}
+#[cfg(feature = "arbitrary")]
+impl arbitrary::Arbitrary<'_> for Duration {
+ fn arbitrary(u: &mut arbitrary::Unstructured) -> arbitrary::Result<Duration> {
+ const MIN_SECS: i64 = i64::MIN / MILLIS_PER_SEC - 1;
+ const MAX_SECS: i64 = i64::MAX / MILLIS_PER_SEC;
+
+ let secs: i64 = u.int_in_range(MIN_SECS..=MAX_SECS)?;
+ let nanos: i32 = u.int_in_range(0..=(NANOS_PER_SEC - 1))?;
+ let duration = Duration { secs, nanos };
+
+ if duration < MIN || duration > MAX {
+ Err(arbitrary::Error::IncorrectFormat)
+ } else {
+ Ok(duration)
+ }
+ }
+}
+
#[cfg(test)]
mod tests {
use super::{Duration, OutOfRangeError, MAX, MIN};
@@ -589,6 +636,19 @@ mod tests {
}
#[test]
+ fn test_duration_abs() {
+ assert_eq!(Duration::milliseconds(1300).abs(), Duration::milliseconds(1300));
+ assert_eq!(Duration::milliseconds(1000).abs(), Duration::milliseconds(1000));
+ assert_eq!(Duration::milliseconds(300).abs(), Duration::milliseconds(300));
+ assert_eq!(Duration::milliseconds(0).abs(), Duration::milliseconds(0));
+ assert_eq!(Duration::milliseconds(-300).abs(), Duration::milliseconds(300));
+ assert_eq!(Duration::milliseconds(-700).abs(), Duration::milliseconds(700));
+ assert_eq!(Duration::milliseconds(-1000).abs(), Duration::milliseconds(1000));
+ assert_eq!(Duration::milliseconds(-1300).abs(), Duration::milliseconds(1300));
+ assert_eq!(Duration::milliseconds(-1700).abs(), Duration::milliseconds(1700));
+ }
+
+ #[test]
fn test_duration_mul() {
assert_eq!(Duration::zero() * i32::MAX, Duration::zero());
assert_eq!(Duration::zero() * i32::MIN, Duration::zero());
@@ -627,6 +687,27 @@ mod tests {
}
#[test]
+ fn test_duration_sum() {
+ let duration_list_1 = [Duration::zero(), Duration::seconds(1)];
+ let sum_1: Duration = duration_list_1.iter().sum();
+ assert_eq!(sum_1, Duration::seconds(1));
+
+ let duration_list_2 =
+ [Duration::zero(), Duration::seconds(1), Duration::seconds(6), Duration::seconds(10)];
+ let sum_2: Duration = duration_list_2.iter().sum();
+ assert_eq!(sum_2, Duration::seconds(17));
+
+ let duration_vec = vec![
+ Duration::zero(),
+ Duration::seconds(1),
+ Duration::seconds(6),
+ Duration::seconds(10),
+ ];
+ let sum_3: Duration = duration_vec.into_iter().sum();
+ assert_eq!(sum_3, Duration::seconds(17));
+ }
+
+ #[test]
fn test_duration_fmt() {
assert_eq!(Duration::zero().to_string(), "PT0S");
assert_eq!(Duration::days(42).to_string(), "P42D");
diff --git a/vendor/chrono/src/round.rs b/vendor/chrono/src/round.rs
index 92d7c3a50..b95f24570 100644
--- a/vendor/chrono/src/round.rs
+++ b/vendor/chrono/src/round.rs
@@ -1,16 +1,15 @@
// This is a part of Chrono.
// See README.md and LICENSE.txt for details.
+use crate::datetime::DateTime;
+use crate::oldtime::Duration;
+use crate::NaiveDateTime;
+use crate::TimeZone;
+use crate::Timelike;
use core::cmp::Ordering;
use core::fmt;
use core::marker::Sized;
use core::ops::{Add, Sub};
-use datetime::DateTime;
-use oldtime::Duration;
-#[cfg(any(feature = "std", test))]
-use std;
-use TimeZone;
-use Timelike;
/// Extension trait for subsecond rounding or truncation to a maximum number
/// of digits. Rounding can be used to decrease the error variance when
@@ -25,8 +24,8 @@ pub trait SubsecRound {
///
/// # Example
/// ``` rust
- /// # use chrono::{DateTime, SubsecRound, Timelike, TimeZone, Utc};
- /// let dt = Utc.ymd(2018, 1, 11).and_hms_milli(12, 0, 0, 154);
+ /// # use chrono::{DateTime, SubsecRound, Timelike, TimeZone, 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);
/// ```
@@ -37,8 +36,8 @@ pub trait SubsecRound {
///
/// # Example
/// ``` rust
- /// # use chrono::{DateTime, SubsecRound, Timelike, TimeZone, Utc};
- /// let dt = Utc.ymd(2018, 1, 11).and_hms_milli(12, 0, 0, 154);
+ /// # use chrono::{DateTime, SubsecRound, Timelike, TimeZone, 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);
/// ```
@@ -112,8 +111,8 @@ pub trait DurationRound: Sized {
///
/// # Example
/// ``` rust
- /// # use chrono::{DateTime, DurationRound, Duration, TimeZone, Utc};
- /// let dt = Utc.ymd(2018, 1, 11).and_hms_milli(12, 0, 0, 154);
+ /// # use chrono::{DateTime, DurationRound, Duration, TimeZone, 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(),
/// "2018-01-11 12:00:00.150 UTC"
@@ -129,8 +128,8 @@ pub trait DurationRound: Sized {
///
/// # Example
/// ``` rust
- /// # use chrono::{DateTime, DurationRound, Duration, TimeZone, Utc};
- /// let dt = Utc.ymd(2018, 1, 11).and_hms_milli(12, 0, 0, 154);
+ /// # use chrono::{DateTime, DurationRound, Duration, TimeZone, 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(),
/// "2018-01-11 12:00:00.150 UTC"
@@ -150,52 +149,89 @@ impl<Tz: TimeZone> DurationRound for DateTime<Tz> {
type Err = RoundingError;
fn duration_round(self, duration: Duration) -> Result<Self, Self::Err> {
- if let Some(span) = duration.num_nanoseconds() {
- if self.timestamp().abs() > MAX_SECONDS_TIMESTAMP_FOR_NANOS {
- return Err(RoundingError::TimestampExceedsLimit);
- }
- let stamp = self.timestamp_nanos();
- if span > stamp.abs() {
- return Err(RoundingError::DurationExceedsTimestamp);
- }
- let delta_down = stamp % span;
- if delta_down == 0 {
- Ok(self)
+ duration_round(self.naive_local(), self, duration)
+ }
+
+ fn duration_trunc(self, duration: Duration) -> Result<Self, Self::Err> {
+ duration_trunc(self.naive_local(), self, duration)
+ }
+}
+
+impl DurationRound for NaiveDateTime {
+ type Err = RoundingError;
+
+ fn duration_round(self, duration: Duration) -> Result<Self, Self::Err> {
+ duration_round(self, self, duration)
+ }
+
+ fn duration_trunc(self, duration: Duration) -> Result<Self, Self::Err> {
+ duration_trunc(self, self, duration)
+ }
+}
+
+fn duration_round<T>(
+ naive: NaiveDateTime,
+ original: T,
+ duration: Duration,
+) -> Result<T, RoundingError>
+where
+ T: Timelike + Add<Duration, Output = T> + Sub<Duration, Output = T>,
+{
+ if let Some(span) = duration.num_nanoseconds() {
+ if naive.timestamp().abs() > MAX_SECONDS_TIMESTAMP_FOR_NANOS {
+ return Err(RoundingError::TimestampExceedsLimit);
+ }
+ let stamp = naive.timestamp_nanos();
+ if span > stamp.abs() {
+ return Err(RoundingError::DurationExceedsTimestamp);
+ }
+ if span == 0 {
+ return Ok(original);
+ }
+ let delta_down = stamp % span;
+ if delta_down == 0 {
+ Ok(original)
+ } else {
+ let (delta_up, delta_down) = if delta_down < 0 {
+ (delta_down.abs(), span - delta_down.abs())
+ } else {
+ (span - delta_down, delta_down)
+ };
+ if delta_up <= delta_down {
+ Ok(original + Duration::nanoseconds(delta_up))
} else {
- let (delta_up, delta_down) = if delta_down < 0 {
- (delta_down.abs(), span - delta_down.abs())
- } else {
- (span - delta_down, delta_down)
- };
- if delta_up <= delta_down {
- Ok(self + Duration::nanoseconds(delta_up))
- } else {
- Ok(self - Duration::nanoseconds(delta_down))
- }
+ Ok(original - Duration::nanoseconds(delta_down))
}
- } else {
- Err(RoundingError::DurationExceedsLimit)
}
+ } else {
+ Err(RoundingError::DurationExceedsLimit)
}
+}
- fn duration_trunc(self, duration: Duration) -> Result<Self, Self::Err> {
- if let Some(span) = duration.num_nanoseconds() {
- if self.timestamp().abs() > MAX_SECONDS_TIMESTAMP_FOR_NANOS {
- return Err(RoundingError::TimestampExceedsLimit);
- }
- let stamp = self.timestamp_nanos();
- if span > stamp.abs() {
- return Err(RoundingError::DurationExceedsTimestamp);
- }
- let delta_down = stamp % span;
- match delta_down.cmp(&0) {
- Ordering::Equal => Ok(self),
- Ordering::Greater => Ok(self - Duration::nanoseconds(delta_down)),
- Ordering::Less => Ok(self - Duration::nanoseconds(span - delta_down.abs())),
- }
- } else {
- Err(RoundingError::DurationExceedsLimit)
+fn duration_trunc<T>(
+ naive: NaiveDateTime,
+ original: T,
+ duration: Duration,
+) -> Result<T, RoundingError>
+where
+ T: Timelike + Add<Duration, Output = T> + Sub<Duration, Output = T>,
+{
+ if let Some(span) = duration.num_nanoseconds() {
+ if naive.timestamp().abs() > MAX_SECONDS_TIMESTAMP_FOR_NANOS {
+ return Err(RoundingError::TimestampExceedsLimit);
+ }
+ let stamp = naive.timestamp_nanos();
+ if span > stamp.abs() {
+ return Err(RoundingError::DurationExceedsTimestamp);
}
+ let delta_down = stamp % span;
+ match delta_down.cmp(&0) {
+ Ordering::Equal => Ok(original),
+ Ordering::Greater => Ok(original - Duration::nanoseconds(delta_down)),
+ Ordering::Less => Ok(original - Duration::nanoseconds(span - delta_down.abs())),
+ }
+ } else {
+ Err(RoundingError::DurationExceedsLimit)
}
}
@@ -208,7 +244,7 @@ pub enum RoundingError {
///
/// ``` rust
/// # use chrono::{DateTime, DurationRound, Duration, RoundingError, TimeZone, Utc};
- /// let dt = Utc.ymd(1970, 12, 12).and_hms(0, 0, 0);
+ /// let dt = Utc.with_ymd_and_hms(1970, 12, 12, 0, 0, 0).unwrap();
///
/// assert_eq!(
/// dt.duration_round(Duration::days(365)),
@@ -220,8 +256,8 @@ pub enum RoundingError {
/// Error when `Duration.num_nanoseconds` exceeds the limit.
///
/// ``` rust
- /// # use chrono::{DateTime, DurationRound, Duration, RoundingError, TimeZone, Utc};
- /// let dt = Utc.ymd(2260, 12, 31).and_hms_nano(23, 59, 59, 1_75_500_000);
+ /// # use chrono::{DateTime, DurationRound, Duration, RoundingError, TimeZone, 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!(
/// dt.duration_round(Duration::days(300 * 365)),
@@ -234,7 +270,7 @@ pub enum RoundingError {
///
/// ``` rust
/// # use chrono::{DateTime, DurationRound, Duration, RoundingError, TimeZone, Utc};
- /// let dt = Utc.ymd(2300, 12, 12).and_hms(0, 0, 0);
+ /// 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),);
/// ```
@@ -258,6 +294,7 @@ impl fmt::Display for RoundingError {
}
#[cfg(any(feature = "std", test))]
+#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
impl std::error::Error for RoundingError {
#[allow(deprecated)]
fn description(&self) -> &str {
@@ -268,29 +305,44 @@ impl std::error::Error for RoundingError {
#[cfg(test)]
mod tests {
use super::{Duration, DurationRound, SubsecRound};
- use offset::{FixedOffset, TimeZone, Utc};
- use Timelike;
+ use crate::offset::{FixedOffset, TimeZone, Utc};
+ use crate::NaiveDate;
+ use crate::Timelike;
#[test]
fn test_round_subsecs() {
- let pst = FixedOffset::east(8 * 60 * 60);
- let dt = pst.ymd(2018, 1, 11).and_hms_nano(10, 5, 13, 084_660_684);
+ let pst = FixedOffset::east_opt(8 * 60 * 60).unwrap();
+ let dt = pst
+ .from_local_datetime(
+ &NaiveDate::from_ymd_opt(2018, 1, 11)
+ .unwrap()
+ .and_hms_nano_opt(10, 5, 13, 84_660_684)
+ .unwrap(),
+ )
+ .unwrap();
assert_eq!(dt.round_subsecs(10), dt);
assert_eq!(dt.round_subsecs(9), dt);
- assert_eq!(dt.round_subsecs(8).nanosecond(), 084_660_680);
- assert_eq!(dt.round_subsecs(7).nanosecond(), 084_660_700);
- assert_eq!(dt.round_subsecs(6).nanosecond(), 084_661_000);
- assert_eq!(dt.round_subsecs(5).nanosecond(), 084_660_000);
- assert_eq!(dt.round_subsecs(4).nanosecond(), 084_700_000);
- assert_eq!(dt.round_subsecs(3).nanosecond(), 085_000_000);
- assert_eq!(dt.round_subsecs(2).nanosecond(), 080_000_000);
+ assert_eq!(dt.round_subsecs(8).nanosecond(), 84_660_680);
+ assert_eq!(dt.round_subsecs(7).nanosecond(), 84_660_700);
+ assert_eq!(dt.round_subsecs(6).nanosecond(), 84_661_000);
+ assert_eq!(dt.round_subsecs(5).nanosecond(), 84_660_000);
+ assert_eq!(dt.round_subsecs(4).nanosecond(), 84_700_000);
+ assert_eq!(dt.round_subsecs(3).nanosecond(), 85_000_000);
+ assert_eq!(dt.round_subsecs(2).nanosecond(), 80_000_000);
assert_eq!(dt.round_subsecs(1).nanosecond(), 100_000_000);
assert_eq!(dt.round_subsecs(0).nanosecond(), 0);
assert_eq!(dt.round_subsecs(0).second(), 13);
- let dt = Utc.ymd(2018, 1, 11).and_hms_nano(10, 5, 27, 750_500_000);
+ let dt = Utc
+ .from_local_datetime(
+ &NaiveDate::from_ymd_opt(2018, 1, 11)
+ .unwrap()
+ .and_hms_nano_opt(10, 5, 27, 750_500_000)
+ .unwrap(),
+ )
+ .unwrap();
assert_eq!(dt.round_subsecs(9), dt);
assert_eq!(dt.round_subsecs(4), dt);
assert_eq!(dt.round_subsecs(3).nanosecond(), 751_000_000);
@@ -303,7 +355,14 @@ mod tests {
#[test]
fn test_round_leap_nanos() {
- let dt = Utc.ymd(2016, 12, 31).and_hms_nano(23, 59, 59, 1_750_500_000);
+ let dt = Utc
+ .from_local_datetime(
+ &NaiveDate::from_ymd_opt(2016, 12, 31)
+ .unwrap()
+ .and_hms_nano_opt(23, 59, 59, 1_750_500_000)
+ .unwrap(),
+ )
+ .unwrap();
assert_eq!(dt.round_subsecs(9), dt);
assert_eq!(dt.round_subsecs(4), dt);
assert_eq!(dt.round_subsecs(2).nanosecond(), 1_750_000_000);
@@ -316,24 +375,38 @@ mod tests {
#[test]
fn test_trunc_subsecs() {
- let pst = FixedOffset::east(8 * 60 * 60);
- let dt = pst.ymd(2018, 1, 11).and_hms_nano(10, 5, 13, 084_660_684);
+ let pst = FixedOffset::east_opt(8 * 60 * 60).unwrap();
+ let dt = pst
+ .from_local_datetime(
+ &NaiveDate::from_ymd_opt(2018, 1, 11)
+ .unwrap()
+ .and_hms_nano_opt(10, 5, 13, 84_660_684)
+ .unwrap(),
+ )
+ .unwrap();
assert_eq!(dt.trunc_subsecs(10), dt);
assert_eq!(dt.trunc_subsecs(9), dt);
- assert_eq!(dt.trunc_subsecs(8).nanosecond(), 084_660_680);
- assert_eq!(dt.trunc_subsecs(7).nanosecond(), 084_660_600);
- assert_eq!(dt.trunc_subsecs(6).nanosecond(), 084_660_000);
- assert_eq!(dt.trunc_subsecs(5).nanosecond(), 084_660_000);
- assert_eq!(dt.trunc_subsecs(4).nanosecond(), 084_600_000);
- assert_eq!(dt.trunc_subsecs(3).nanosecond(), 084_000_000);
- assert_eq!(dt.trunc_subsecs(2).nanosecond(), 080_000_000);
+ assert_eq!(dt.trunc_subsecs(8).nanosecond(), 84_660_680);
+ assert_eq!(dt.trunc_subsecs(7).nanosecond(), 84_660_600);
+ assert_eq!(dt.trunc_subsecs(6).nanosecond(), 84_660_000);
+ assert_eq!(dt.trunc_subsecs(5).nanosecond(), 84_660_000);
+ assert_eq!(dt.trunc_subsecs(4).nanosecond(), 84_600_000);
+ assert_eq!(dt.trunc_subsecs(3).nanosecond(), 84_000_000);
+ assert_eq!(dt.trunc_subsecs(2).nanosecond(), 80_000_000);
assert_eq!(dt.trunc_subsecs(1).nanosecond(), 0);
assert_eq!(dt.trunc_subsecs(0).nanosecond(), 0);
assert_eq!(dt.trunc_subsecs(0).second(), 13);
- let dt = pst.ymd(2018, 1, 11).and_hms_nano(10, 5, 27, 750_500_000);
+ let dt = pst
+ .from_local_datetime(
+ &NaiveDate::from_ymd_opt(2018, 1, 11)
+ .unwrap()
+ .and_hms_nano_opt(10, 5, 27, 750_500_000)
+ .unwrap(),
+ )
+ .unwrap();
assert_eq!(dt.trunc_subsecs(9), dt);
assert_eq!(dt.trunc_subsecs(4), dt);
assert_eq!(dt.trunc_subsecs(3).nanosecond(), 750_000_000);
@@ -346,7 +419,14 @@ mod tests {
#[test]
fn test_trunc_leap_nanos() {
- let dt = Utc.ymd(2016, 12, 31).and_hms_nano(23, 59, 59, 1_750_500_000);
+ let dt = Utc
+ .from_local_datetime(
+ &NaiveDate::from_ymd_opt(2016, 12, 31)
+ .unwrap()
+ .and_hms_nano_opt(23, 59, 59, 1_750_500_000)
+ .unwrap(),
+ )
+ .unwrap();
assert_eq!(dt.trunc_subsecs(9), dt);
assert_eq!(dt.trunc_subsecs(4), dt);
assert_eq!(dt.trunc_subsecs(2).nanosecond(), 1_750_000_000);
@@ -359,7 +439,19 @@ mod tests {
#[test]
fn test_duration_round() {
- let dt = Utc.ymd(2016, 12, 31).and_hms_nano(23, 59, 59, 175_500_000);
+ let dt = Utc
+ .from_local_datetime(
+ &NaiveDate::from_ymd_opt(2016, 12, 31)
+ .unwrap()
+ .and_hms_nano_opt(23, 59, 59, 175_500_000)
+ .unwrap(),
+ )
+ .unwrap();
+
+ assert_eq!(
+ dt.duration_round(Duration::zero()).unwrap().to_string(),
+ "2016-12-31 23:59:59.175500 UTC"
+ );
assert_eq!(
dt.duration_round(Duration::milliseconds(10)).unwrap().to_string(),
@@ -367,13 +459,27 @@ mod tests {
);
// round up
- let dt = Utc.ymd(2012, 12, 12).and_hms_milli(18, 22, 30, 0);
+ let dt = Utc
+ .from_local_datetime(
+ &NaiveDate::from_ymd_opt(2012, 12, 12)
+ .unwrap()
+ .and_hms_milli_opt(18, 22, 30, 0)
+ .unwrap(),
+ )
+ .unwrap();
assert_eq!(
dt.duration_round(Duration::minutes(5)).unwrap().to_string(),
"2012-12-12 18:25:00 UTC"
);
// round down
- let dt = Utc.ymd(2012, 12, 12).and_hms_milli(18, 22, 29, 999);
+ let dt = Utc
+ .from_local_datetime(
+ &NaiveDate::from_ymd_opt(2012, 12, 12)
+ .unwrap()
+ .and_hms_milli_opt(18, 22, 29, 999)
+ .unwrap(),
+ )
+ .unwrap();
assert_eq!(
dt.duration_round(Duration::minutes(5)).unwrap().to_string(),
"2012-12-12 18:20:00 UTC"
@@ -395,11 +501,104 @@ mod tests {
dt.duration_round(Duration::days(1)).unwrap().to_string(),
"2012-12-13 00:00:00 UTC"
);
+
+ // timezone east
+ let dt =
+ FixedOffset::east_opt(3600).unwrap().with_ymd_and_hms(2020, 10, 27, 15, 0, 0).unwrap();
+ assert_eq!(
+ dt.duration_round(Duration::days(1)).unwrap().to_string(),
+ "2020-10-28 00:00:00 +01:00"
+ );
+ assert_eq!(
+ dt.duration_round(Duration::weeks(1)).unwrap().to_string(),
+ "2020-10-29 00:00:00 +01:00"
+ );
+
+ // timezone west
+ let dt =
+ FixedOffset::west_opt(3600).unwrap().with_ymd_and_hms(2020, 10, 27, 15, 0, 0).unwrap();
+ assert_eq!(
+ dt.duration_round(Duration::days(1)).unwrap().to_string(),
+ "2020-10-28 00:00:00 -01:00"
+ );
+ assert_eq!(
+ dt.duration_round(Duration::weeks(1)).unwrap().to_string(),
+ "2020-10-29 00:00:00 -01:00"
+ );
+ }
+
+ #[test]
+ fn test_duration_round_naive() {
+ let dt = Utc
+ .from_local_datetime(
+ &NaiveDate::from_ymd_opt(2016, 12, 31)
+ .unwrap()
+ .and_hms_nano_opt(23, 59, 59, 175_500_000)
+ .unwrap(),
+ )
+ .unwrap()
+ .naive_utc();
+
+ assert_eq!(
+ dt.duration_round(Duration::zero()).unwrap().to_string(),
+ "2016-12-31 23:59:59.175500"
+ );
+
+ assert_eq!(
+ dt.duration_round(Duration::milliseconds(10)).unwrap().to_string(),
+ "2016-12-31 23:59:59.180"
+ );
+
+ // round up
+ let dt = Utc
+ .from_local_datetime(
+ &NaiveDate::from_ymd_opt(2012, 12, 12)
+ .unwrap()
+ .and_hms_milli_opt(18, 22, 30, 0)
+ .unwrap(),
+ )
+ .unwrap()
+ .naive_utc();
+ assert_eq!(
+ dt.duration_round(Duration::minutes(5)).unwrap().to_string(),
+ "2012-12-12 18:25:00"
+ );
+ // round down
+ let dt = Utc
+ .from_local_datetime(
+ &NaiveDate::from_ymd_opt(2012, 12, 12)
+ .unwrap()
+ .and_hms_milli_opt(18, 22, 29, 999)
+ .unwrap(),
+ )
+ .unwrap()
+ .naive_utc();
+ assert_eq!(
+ dt.duration_round(Duration::minutes(5)).unwrap().to_string(),
+ "2012-12-12 18:20:00"
+ );
+
+ assert_eq!(
+ dt.duration_round(Duration::minutes(10)).unwrap().to_string(),
+ "2012-12-12 18:20:00"
+ );
+ assert_eq!(
+ dt.duration_round(Duration::minutes(30)).unwrap().to_string(),
+ "2012-12-12 18:30:00"
+ );
+ assert_eq!(
+ dt.duration_round(Duration::hours(1)).unwrap().to_string(),
+ "2012-12-12 18:00:00"
+ );
+ assert_eq!(
+ dt.duration_round(Duration::days(1)).unwrap().to_string(),
+ "2012-12-13 00:00:00"
+ );
}
#[test]
fn test_duration_round_pre_epoch() {
- let dt = Utc.ymd(1969, 12, 12).and_hms(12, 12, 12);
+ let dt = Utc.with_ymd_and_hms(1969, 12, 12, 12, 12, 12).unwrap();
assert_eq!(
dt.duration_round(Duration::minutes(10)).unwrap().to_string(),
"1969-12-12 12:10:00 UTC"
@@ -408,7 +607,14 @@ mod tests {
#[test]
fn test_duration_trunc() {
- let dt = Utc.ymd(2016, 12, 31).and_hms_nano(23, 59, 59, 1_75_500_000);
+ let dt = Utc
+ .from_local_datetime(
+ &NaiveDate::from_ymd_opt(2016, 12, 31)
+ .unwrap()
+ .and_hms_nano_opt(23, 59, 59, 175_500_000)
+ .unwrap(),
+ )
+ .unwrap();
assert_eq!(
dt.duration_trunc(Duration::milliseconds(10)).unwrap().to_string(),
@@ -416,13 +622,27 @@ mod tests {
);
// would round up
- let dt = Utc.ymd(2012, 12, 12).and_hms_milli(18, 22, 30, 0);
+ let dt = Utc
+ .from_local_datetime(
+ &NaiveDate::from_ymd_opt(2012, 12, 12)
+ .unwrap()
+ .and_hms_milli_opt(18, 22, 30, 0)
+ .unwrap(),
+ )
+ .unwrap();
assert_eq!(
dt.duration_trunc(Duration::minutes(5)).unwrap().to_string(),
"2012-12-12 18:20:00 UTC"
);
// would round down
- let dt = Utc.ymd(2012, 12, 12).and_hms_milli(18, 22, 29, 999);
+ let dt = Utc
+ .from_local_datetime(
+ &NaiveDate::from_ymd_opt(2012, 12, 12)
+ .unwrap()
+ .and_hms_milli_opt(18, 22, 29, 999)
+ .unwrap(),
+ )
+ .unwrap();
assert_eq!(
dt.duration_trunc(Duration::minutes(5)).unwrap().to_string(),
"2012-12-12 18:20:00 UTC"
@@ -443,11 +663,98 @@ mod tests {
dt.duration_trunc(Duration::days(1)).unwrap().to_string(),
"2012-12-12 00:00:00 UTC"
);
+
+ // timezone east
+ let dt =
+ FixedOffset::east_opt(3600).unwrap().with_ymd_and_hms(2020, 10, 27, 15, 0, 0).unwrap();
+ assert_eq!(
+ dt.duration_trunc(Duration::days(1)).unwrap().to_string(),
+ "2020-10-27 00:00:00 +01:00"
+ );
+ assert_eq!(
+ dt.duration_trunc(Duration::weeks(1)).unwrap().to_string(),
+ "2020-10-22 00:00:00 +01:00"
+ );
+
+ // timezone west
+ let dt =
+ FixedOffset::west_opt(3600).unwrap().with_ymd_and_hms(2020, 10, 27, 15, 0, 0).unwrap();
+ assert_eq!(
+ dt.duration_trunc(Duration::days(1)).unwrap().to_string(),
+ "2020-10-27 00:00:00 -01:00"
+ );
+ assert_eq!(
+ dt.duration_trunc(Duration::weeks(1)).unwrap().to_string(),
+ "2020-10-22 00:00:00 -01:00"
+ );
+ }
+
+ #[test]
+ fn test_duration_trunc_naive() {
+ let dt = Utc
+ .from_local_datetime(
+ &NaiveDate::from_ymd_opt(2016, 12, 31)
+ .unwrap()
+ .and_hms_nano_opt(23, 59, 59, 175_500_000)
+ .unwrap(),
+ )
+ .unwrap()
+ .naive_utc();
+
+ assert_eq!(
+ dt.duration_trunc(Duration::milliseconds(10)).unwrap().to_string(),
+ "2016-12-31 23:59:59.170"
+ );
+
+ // would round up
+ let dt = Utc
+ .from_local_datetime(
+ &NaiveDate::from_ymd_opt(2012, 12, 12)
+ .unwrap()
+ .and_hms_milli_opt(18, 22, 30, 0)
+ .unwrap(),
+ )
+ .unwrap()
+ .naive_utc();
+ assert_eq!(
+ dt.duration_trunc(Duration::minutes(5)).unwrap().to_string(),
+ "2012-12-12 18:20:00"
+ );
+ // would round down
+ let dt = Utc
+ .from_local_datetime(
+ &NaiveDate::from_ymd_opt(2012, 12, 12)
+ .unwrap()
+ .and_hms_milli_opt(18, 22, 29, 999)
+ .unwrap(),
+ )
+ .unwrap()
+ .naive_utc();
+ assert_eq!(
+ dt.duration_trunc(Duration::minutes(5)).unwrap().to_string(),
+ "2012-12-12 18:20:00"
+ );
+ assert_eq!(
+ dt.duration_trunc(Duration::minutes(10)).unwrap().to_string(),
+ "2012-12-12 18:20:00"
+ );
+ assert_eq!(
+ dt.duration_trunc(Duration::minutes(30)).unwrap().to_string(),
+ "2012-12-12 18:00:00"
+ );
+ assert_eq!(
+ dt.duration_trunc(Duration::hours(1)).unwrap().to_string(),
+ "2012-12-12 18:00:00"
+ );
+ assert_eq!(
+ dt.duration_trunc(Duration::days(1)).unwrap().to_string(),
+ "2012-12-12 00:00:00"
+ );
}
#[test]
fn test_duration_trunc_pre_epoch() {
- let dt = Utc.ymd(1969, 12, 12).and_hms(12, 12, 12);
+ let dt = Utc.with_ymd_and_hms(1969, 12, 12, 12, 12, 12).unwrap();
assert_eq!(
dt.duration_trunc(Duration::minutes(10)).unwrap().to_string(),
"1969-12-12 12:10:00 UTC"
diff --git a/vendor/chrono/src/sys.rs b/vendor/chrono/src/sys.rs
deleted file mode 100644
index 2e46b7e8e..000000000
--- a/vendor/chrono/src/sys.rs
+++ /dev/null
@@ -1,126 +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.
-
-//! Platform wrappers for converting UTC times to and from the local time zone.
-//!
-//! This code was rescued from v0.1 of the time crate, which is no longer
-//! maintained. It has been substantially stripped down to the bare minimum
-//! required by chrono.
-
-use std::time::{SystemTime, UNIX_EPOCH};
-
-#[cfg(any(target_arch = "wasm32", target_env = "sgx"))]
-#[path = "sys/stub.rs"]
-mod inner;
-
-#[cfg(unix)]
-#[path = "sys/unix.rs"]
-mod inner;
-
-#[cfg(windows)]
-#[path = "sys/windows.rs"]
-mod inner;
-
-/// 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}.
-pub struct Timespec {
- pub sec: i64,
- pub nsec: i32,
-}
-
-impl Timespec {
- /// Constructs a timespec representing the current time in UTC.
- pub 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.
- pub 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,
- };
- inner::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?
-#[cfg(feature = "clock")]
-#[repr(C)]
-pub struct Tm {
- /// Seconds after the minute - [0, 60]
- pub tm_sec: i32,
-
- /// Minutes after the hour - [0, 59]
- pub tm_min: i32,
-
- /// Hours after midnight - [0, 23]
- pub tm_hour: i32,
-
- /// Day of the month - [1, 31]
- pub tm_mday: i32,
-
- /// Months since January - [0, 11]
- pub tm_mon: i32,
-
- /// Years since 1900
- pub tm_year: i32,
-
- /// Days since Sunday - [0, 6]. 0 = Sunday, 1 = Monday, ..., 6 = Saturday.
- pub tm_wday: i32,
-
- /// Days since January 1 - [0, 365]
- pub 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.
- pub 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`.
- pub tm_utcoff: i32,
-
- /// Nanoseconds after the second - [0, 10<sup>9</sup> - 1]
- pub tm_nsec: i32,
-}
-
-impl Tm {
- /// Convert time to the seconds from January 1, 1970
- pub fn to_timespec(&self) -> Timespec {
- let sec = match self.tm_utcoff {
- 0 => inner::utc_tm_to_time(self),
- _ => inner::local_tm_to_time(self),
- };
- Timespec { sec: sec, nsec: self.tm_nsec }
- }
-}
diff --git a/vendor/chrono/src/sys/stub.rs b/vendor/chrono/src/sys/stub.rs
deleted file mode 100644
index 9172a8522..000000000
--- a/vendor/chrono/src/sys/stub.rs
+++ /dev/null
@@ -1,80 +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 super::Tm;
-
-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 fn time_to_local_tm(sec: i64, tm: &mut Tm) {
- // FIXME: Add timezone logic
- time_to_tm(sec, tm);
-}
-
-pub fn utc_tm_to_time(tm: &Tm) -> i64 {
- tm_to_time(tm)
-}
-
-pub fn local_tm_to_time(tm: &Tm) -> i64 {
- // FIXME: Add timezone logic
- tm_to_time(tm)
-}
diff --git a/vendor/chrono/src/sys/unix.rs b/vendor/chrono/src/sys/unix.rs
deleted file mode 100644
index 2f845e745..000000000
--- a/vendor/chrono/src/sys/unix.rs
+++ /dev/null
@@ -1,126 +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 super::Tm;
-use libc::{self, time_t};
-use std::io;
-use std::mem;
-
-#[cfg(any(target_os = "solaris", target_os = "illumos"))]
-extern "C" {
- static timezone: time_t;
- static altzone: time_t;
-}
-
-#[cfg(any(target_os = "solaris", target_os = "illumos"))]
-fn tzset() {
- extern "C" {
- fn tzset();
- }
- unsafe { tzset() }
-}
-
-fn rust_tm_to_tm(rust_tm: &Tm, tm: &mut libc::tm) {
- tm.tm_sec = rust_tm.tm_sec;
- tm.tm_min = rust_tm.tm_min;
- tm.tm_hour = rust_tm.tm_hour;
- tm.tm_mday = rust_tm.tm_mday;
- tm.tm_mon = rust_tm.tm_mon;
- tm.tm_year = rust_tm.tm_year;
- tm.tm_wday = rust_tm.tm_wday;
- tm.tm_yday = rust_tm.tm_yday;
- tm.tm_isdst = rust_tm.tm_isdst;
-}
-
-fn tm_to_rust_tm(tm: &libc::tm, utcoff: i32, rust_tm: &mut Tm) {
- rust_tm.tm_sec = tm.tm_sec;
- rust_tm.tm_min = tm.tm_min;
- rust_tm.tm_hour = tm.tm_hour;
- rust_tm.tm_mday = tm.tm_mday;
- rust_tm.tm_mon = tm.tm_mon;
- rust_tm.tm_year = tm.tm_year;
- rust_tm.tm_wday = tm.tm_wday;
- rust_tm.tm_yday = tm.tm_yday;
- rust_tm.tm_isdst = tm.tm_isdst;
- rust_tm.tm_utcoff = utcoff;
-}
-
-#[cfg(any(target_os = "nacl", target_os = "solaris", target_os = "illumos"))]
-unsafe fn timegm(tm: *mut libc::tm) -> time_t {
- use std::env::{remove_var, set_var, var_os};
- extern "C" {
- fn tzset();
- }
-
- let ret;
-
- let current_tz = var_os("TZ");
- set_var("TZ", "UTC");
- tzset();
-
- ret = libc::mktime(tm);
-
- if let Some(tz) = current_tz {
- set_var("TZ", tz);
- } else {
- remove_var("TZ");
- }
- tzset();
-
- ret
-}
-
-pub fn time_to_local_tm(sec: i64, tm: &mut Tm) {
- unsafe {
- let sec = sec as time_t;
- let mut out = mem::zeroed();
- if libc::localtime_r(&sec, &mut out).is_null() {
- panic!("localtime_r failed: {}", io::Error::last_os_error());
- }
- #[cfg(any(target_os = "solaris", target_os = "illumos"))]
- let gmtoff = {
- tzset();
- // < 0 means we don't know; assume we're not in DST.
- if out.tm_isdst == 0 {
- // timezone is seconds west of UTC, tm_gmtoff is seconds east
- -timezone
- } else if out.tm_isdst > 0 {
- -altzone
- } else {
- -timezone
- }
- };
- #[cfg(not(any(target_os = "solaris", target_os = "illumos")))]
- let gmtoff = out.tm_gmtoff;
- tm_to_rust_tm(&out, gmtoff as i32, tm);
- }
-}
-
-pub fn utc_tm_to_time(rust_tm: &Tm) -> i64 {
- #[cfg(not(any(
- all(target_os = "android", target_pointer_width = "32"),
- target_os = "nacl",
- target_os = "solaris",
- target_os = "illumos"
- )))]
- use libc::timegm;
- #[cfg(all(target_os = "android", target_pointer_width = "32"))]
- use libc::timegm64 as timegm;
-
- let mut tm = unsafe { mem::zeroed() };
- rust_tm_to_tm(rust_tm, &mut tm);
- unsafe { timegm(&mut tm) as i64 }
-}
-
-pub fn local_tm_to_time(rust_tm: &Tm) -> i64 {
- let mut tm = unsafe { mem::zeroed() };
- rust_tm_to_tm(rust_tm, &mut tm);
- unsafe { libc::mktime(&mut tm) as i64 }
-}
diff --git a/vendor/chrono/src/sys/windows.rs b/vendor/chrono/src/sys/windows.rs
deleted file mode 100644
index 3f90338e4..000000000
--- a/vendor/chrono/src/sys/windows.rs
+++ /dev/null
@@ -1,131 +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 super::Tm;
-use std::io;
-use std::mem;
-
-use winapi::shared::minwindef::*;
-use winapi::um::minwinbase::SYSTEMTIME;
-use winapi::um::timezoneapi::*;
-
-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)
-}
-
-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
-}
-
-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 };
-
- (month - 1) * 30 + month / 2 + (day - 1) - leap + july
- }
-}
-
-macro_rules! call {
- ($name:ident($($arg:expr),*)) => {
- if $name($($arg),*) == 0 {
- panic!(concat!(stringify!($name), " failed with: {}"),
- io::Error::last_os_error());
- }
- }
-}
-
-pub 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 };
- }
-}
-
-pub fn utc_tm_to_time(tm: &Tm) -> i64 {
- 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)
- }
-}
-
-pub fn local_tm_to_time(tm: &Tm) -> i64 {
- 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)
- }
-}
diff --git a/vendor/chrono/src/traits.rs b/vendor/chrono/src/traits.rs
new file mode 100644
index 000000000..1b6af6926
--- /dev/null
+++ b/vendor/chrono/src/traits.rs
@@ -0,0 +1,241 @@
+use crate::{IsoWeek, Weekday};
+
+/// The common set of methods for date component.
+pub trait Datelike: Sized {
+ /// Returns the year number in the [calendar date](./naive/struct.NaiveDate.html#calendar-date).
+ fn year(&self) -> i32;
+
+ /// Returns the absolute year number starting from 1 with a boolean flag,
+ /// which is false when the year predates the epoch (BCE/BC) and true otherwise (CE/AD).
+ #[inline]
+ fn year_ce(&self) -> (bool, u32) {
+ let year = self.year();
+ if year < 1 {
+ (false, (1 - year) as u32)
+ } else {
+ (true, year as u32)
+ }
+ }
+
+ /// Returns the month number starting from 1.
+ ///
+ /// The return value ranges from 1 to 12.
+ fn month(&self) -> u32;
+
+ /// Returns the month number starting from 0.
+ ///
+ /// The return value ranges from 0 to 11.
+ fn month0(&self) -> u32;
+
+ /// Returns the day of month starting from 1.
+ ///
+ /// The return value ranges from 1 to 31. (The last day of month differs by months.)
+ fn day(&self) -> u32;
+
+ /// Returns the day of month starting from 0.
+ ///
+ /// The return value ranges from 0 to 30. (The last day of month differs by months.)
+ fn day0(&self) -> u32;
+
+ /// Returns the day of year starting from 1.
+ ///
+ /// The return value ranges from 1 to 366. (The last day of year differs by years.)
+ fn ordinal(&self) -> u32;
+
+ /// Returns the day of year starting from 0.
+ ///
+ /// The return value ranges from 0 to 365. (The last day of year differs by years.)
+ fn ordinal0(&self) -> u32;
+
+ /// Returns the day of week.
+ fn weekday(&self) -> Weekday;
+
+ /// Returns the ISO week.
+ fn iso_week(&self) -> IsoWeek;
+
+ /// Makes a new value with the year number changed.
+ ///
+ /// Returns `None` when the resulting value would be invalid.
+ fn with_year(&self, year: i32) -> Option<Self>;
+
+ /// Makes a new value with the month number (starting from 1) changed.
+ ///
+ /// Returns `None` when the resulting value would be invalid.
+ fn with_month(&self, month: u32) -> Option<Self>;
+
+ /// Makes a new value with the month number (starting from 0) changed.
+ ///
+ /// Returns `None` when the resulting value would be invalid.
+ fn with_month0(&self, month0: u32) -> Option<Self>;
+
+ /// Makes a new value with the day of month (starting from 1) changed.
+ ///
+ /// Returns `None` when the resulting value would be invalid.
+ fn with_day(&self, day: u32) -> Option<Self>;
+
+ /// Makes a new value with the day of month (starting from 0) changed.
+ ///
+ /// Returns `None` when the resulting value would be invalid.
+ fn with_day0(&self, day0: u32) -> Option<Self>;
+
+ /// Makes a new value with the day of year (starting from 1) changed.
+ ///
+ /// Returns `None` when the resulting value would be invalid.
+ fn with_ordinal(&self, ordinal: u32) -> Option<Self>;
+
+ /// Makes a new value with the day of year (starting from 0) changed.
+ ///
+ /// Returns `None` when the resulting value would be invalid.
+ fn with_ordinal0(&self, ordinal0: u32) -> Option<Self>;
+
+ /// Counts the days in the proleptic Gregorian calendar, with January 1, Year 1 (CE) as day 1.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use chrono::{NaiveDate, Datelike};
+ ///
+ /// assert_eq!(NaiveDate::from_ymd_opt(1970, 1, 1).unwrap().num_days_from_ce(), 719_163);
+ /// assert_eq!(NaiveDate::from_ymd_opt(2, 1, 1).unwrap().num_days_from_ce(), 366);
+ /// assert_eq!(NaiveDate::from_ymd_opt(1, 1, 1).unwrap().num_days_from_ce(), 1);
+ /// assert_eq!(NaiveDate::from_ymd_opt(0, 1, 1).unwrap().num_days_from_ce(), -365);
+ /// ```
+ fn num_days_from_ce(&self) -> i32 {
+ // See test_num_days_from_ce_against_alternative_impl below for a more straightforward
+ // implementation.
+
+ // we know this wouldn't overflow since year is limited to 1/2^13 of i32's full range.
+ let mut year = self.year() - 1;
+ let mut ndays = 0;
+ if year < 0 {
+ let excess = 1 + (-year) / 400;
+ year += excess * 400;
+ ndays -= excess * 146_097;
+ }
+ let div_100 = year / 100;
+ ndays += ((year * 1461) >> 2) - div_100 + (div_100 >> 2);
+ ndays + self.ordinal() as i32
+ }
+}
+
+/// The common set of methods for time component.
+pub trait Timelike: Sized {
+ /// Returns the hour number from 0 to 23.
+ fn hour(&self) -> u32;
+
+ /// Returns the hour number from 1 to 12 with a boolean flag,
+ /// which is false for AM and true for PM.
+ #[inline]
+ fn hour12(&self) -> (bool, u32) {
+ let hour = self.hour();
+ let mut hour12 = hour % 12;
+ if hour12 == 0 {
+ hour12 = 12;
+ }
+ (hour >= 12, hour12)
+ }
+
+ /// Returns the minute number from 0 to 59.
+ fn minute(&self) -> u32;
+
+ /// Returns the second number from 0 to 59.
+ fn second(&self) -> u32;
+
+ /// Returns the number of nanoseconds since the whole non-leap second.
+ /// The range from 1,000,000,000 to 1,999,999,999 represents
+ /// the [leap second](./naive/struct.NaiveTime.html#leap-second-handling).
+ fn nanosecond(&self) -> u32;
+
+ /// Makes a new value with the hour number changed.
+ ///
+ /// Returns `None` when the resulting value would be invalid.
+ fn with_hour(&self, hour: u32) -> Option<Self>;
+
+ /// Makes a new value with the minute number changed.
+ ///
+ /// Returns `None` when the resulting value would be invalid.
+ fn with_minute(&self, min: u32) -> Option<Self>;
+
+ /// Makes a new value with the second number changed.
+ ///
+ /// Returns `None` when the resulting value would be invalid.
+ /// As with the [`second`](#tymethod.second) method,
+ /// the input range is restricted to 0 through 59.
+ fn with_second(&self, sec: u32) -> Option<Self>;
+
+ /// Makes a new value with nanoseconds since the whole non-leap second changed.
+ ///
+ /// Returns `None` when the resulting value would be invalid.
+ /// As with the [`nanosecond`](#tymethod.nanosecond) method,
+ /// the input range can exceed 1,000,000,000 for leap seconds.
+ fn with_nanosecond(&self, nano: u32) -> Option<Self>;
+
+ /// Returns the number of non-leap seconds past the last midnight.
+ #[inline]
+ fn num_seconds_from_midnight(&self) -> u32 {
+ self.hour() * 3600 + self.minute() * 60 + self.second()
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::Datelike;
+ use crate::{Duration, NaiveDate};
+
+ /// Tests `Datelike::num_days_from_ce` against an alternative implementation.
+ ///
+ /// The alternative implementation is not as short as the current one but it is simpler to
+ /// understand, with less unexplained magic constants.
+ #[test]
+ fn test_num_days_from_ce_against_alternative_impl() {
+ /// Returns the number of multiples of `div` in the range `start..end`.
+ ///
+ /// If the range `start..end` is back-to-front, i.e. `start` is greater than `end`, the
+ /// behaviour is defined by the following equation:
+ /// `in_between(start, end, div) == - in_between(end, start, div)`.
+ ///
+ /// When `div` is 1, this is equivalent to `end - start`, i.e. the length of `start..end`.
+ ///
+ /// # Panics
+ ///
+ /// Panics if `div` is not positive.
+ fn in_between(start: i32, end: i32, div: i32) -> i32 {
+ assert!(div > 0, "in_between: nonpositive div = {}", div);
+ let start = (start.div_euclid(div), start.rem_euclid(div));
+ let end = (end.div_euclid(div), end.rem_euclid(div));
+ // The lowest multiple of `div` greater than or equal to `start`, divided.
+ let start = start.0 + (start.1 != 0) as i32;
+ // The lowest multiple of `div` greater than or equal to `end`, divided.
+ let end = end.0 + (end.1 != 0) as i32;
+ end - start
+ }
+
+ /// Alternative implementation to `Datelike::num_days_from_ce`
+ fn num_days_from_ce<Date: Datelike>(date: &Date) -> i32 {
+ let year = date.year();
+ let diff = move |div| in_between(1, year, div);
+ // 365 days a year, one more in leap years. In the gregorian calendar, leap years are all
+ // the multiples of 4 except multiples of 100 but including multiples of 400.
+ 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()) {
+ let jan1_year = NaiveDate::from_ymd_opt(year, 1, 1).unwrap();
+ assert_eq!(
+ jan1_year.num_days_from_ce(),
+ num_days_from_ce(&jan1_year),
+ "on {:?}",
+ jan1_year
+ );
+ let mid_year = jan1_year + Duration::days(133);
+ assert_eq!(
+ mid_year.num_days_from_ce(),
+ num_days_from_ce(&mid_year),
+ "on {:?}",
+ mid_year
+ );
+ }
+ }
+}
diff --git a/vendor/chrono/src/weekday.rs b/vendor/chrono/src/weekday.rs
new file mode 100644
index 000000000..72e384673
--- /dev/null
+++ b/vendor/chrono/src/weekday.rs
@@ -0,0 +1,329 @@
+use core::fmt;
+
+#[cfg(feature = "rkyv")]
+use rkyv::{Archive, Deserialize, Serialize};
+
+/// 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.
+#[derive(PartialEq, Eq, Copy, Clone, Debug, Hash)]
+#[cfg_attr(feature = "rustc-serialize", derive(RustcEncodable, RustcDecodable))]
+#[cfg_attr(feature = "rkyv", derive(Archive, Deserialize, Serialize))]
+#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
+pub enum Weekday {
+ /// Monday.
+ Mon = 0,
+ /// Tuesday.
+ Tue = 1,
+ /// Wednesday.
+ Wed = 2,
+ /// Thursday.
+ Thu = 3,
+ /// Friday.
+ Fri = 4,
+ /// Saturday.
+ Sat = 5,
+ /// Sunday.
+ Sun = 6,
+}
+
+impl Weekday {
+ /// The next day in the week.
+ ///
+ /// `w`: | `Mon` | `Tue` | `Wed` | `Thu` | `Fri` | `Sat` | `Sun`
+ /// ----------- | ----- | ----- | ----- | ----- | ----- | ----- | -----
+ /// `w.succ()`: | `Tue` | `Wed` | `Thu` | `Fri` | `Sat` | `Sun` | `Mon`
+ #[inline]
+ pub fn succ(&self) -> Weekday {
+ match *self {
+ Weekday::Mon => Weekday::Tue,
+ Weekday::Tue => Weekday::Wed,
+ Weekday::Wed => Weekday::Thu,
+ Weekday::Thu => Weekday::Fri,
+ Weekday::Fri => Weekday::Sat,
+ Weekday::Sat => Weekday::Sun,
+ Weekday::Sun => Weekday::Mon,
+ }
+ }
+
+ /// The previous day in the week.
+ ///
+ /// `w`: | `Mon` | `Tue` | `Wed` | `Thu` | `Fri` | `Sat` | `Sun`
+ /// ----------- | ----- | ----- | ----- | ----- | ----- | ----- | -----
+ /// `w.pred()`: | `Sun` | `Mon` | `Tue` | `Wed` | `Thu` | `Fri` | `Sat`
+ #[inline]
+ pub fn pred(&self) -> Weekday {
+ match *self {
+ Weekday::Mon => Weekday::Sun,
+ Weekday::Tue => Weekday::Mon,
+ Weekday::Wed => Weekday::Tue,
+ Weekday::Thu => Weekday::Wed,
+ Weekday::Fri => Weekday::Thu,
+ Weekday::Sat => Weekday::Fri,
+ Weekday::Sun => Weekday::Sat,
+ }
+ }
+
+ /// Returns a day-of-week number starting from Monday = 1. (ISO 8601 weekday number)
+ ///
+ /// `w`: | `Mon` | `Tue` | `Wed` | `Thu` | `Fri` | `Sat` | `Sun`
+ /// ------------------------- | ----- | ----- | ----- | ----- | ----- | ----- | -----
+ /// `w.number_from_monday()`: | 1 | 2 | 3 | 4 | 5 | 6 | 7
+ #[inline]
+ pub const fn number_from_monday(&self) -> u32 {
+ self.num_days_from(Weekday::Mon) + 1
+ }
+
+ /// Returns a day-of-week number starting from Sunday = 1.
+ ///
+ /// `w`: | `Mon` | `Tue` | `Wed` | `Thu` | `Fri` | `Sat` | `Sun`
+ /// ------------------------- | ----- | ----- | ----- | ----- | ----- | ----- | -----
+ /// `w.number_from_sunday()`: | 2 | 3 | 4 | 5 | 6 | 7 | 1
+ #[inline]
+ pub const fn number_from_sunday(&self) -> u32 {
+ self.num_days_from(Weekday::Sun) + 1
+ }
+
+ /// Returns a day-of-week number starting from Monday = 0.
+ ///
+ /// `w`: | `Mon` | `Tue` | `Wed` | `Thu` | `Fri` | `Sat` | `Sun`
+ /// --------------------------- | ----- | ----- | ----- | ----- | ----- | ----- | -----
+ /// `w.num_days_from_monday()`: | 0 | 1 | 2 | 3 | 4 | 5 | 6
+ #[inline]
+ pub const fn num_days_from_monday(&self) -> u32 {
+ self.num_days_from(Weekday::Mon)
+ }
+
+ /// Returns a day-of-week number starting from Sunday = 0.
+ ///
+ /// `w`: | `Mon` | `Tue` | `Wed` | `Thu` | `Fri` | `Sat` | `Sun`
+ /// --------------------------- | ----- | ----- | ----- | ----- | ----- | ----- | -----
+ /// `w.num_days_from_sunday()`: | 1 | 2 | 3 | 4 | 5 | 6 | 0
+ #[inline]
+ pub const fn num_days_from_sunday(&self) -> u32 {
+ self.num_days_from(Weekday::Sun)
+ }
+
+ /// 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.num_days_from(wd)`: | 0 | 1 | 2 | 3 | 4 | 5 | 6
+ #[inline]
+ pub(crate) const fn num_days_from(&self, day: Weekday) -> u32 {
+ (*self as u32 + 7 - day as u32) % 7
+ }
+}
+
+impl fmt::Display for Weekday {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.write_str(match *self {
+ Weekday::Mon => "Mon",
+ Weekday::Tue => "Tue",
+ Weekday::Wed => "Wed",
+ Weekday::Thu => "Thu",
+ Weekday::Fri => "Fri",
+ Weekday::Sat => "Sat",
+ Weekday::Sun => "Sun",
+ })
+ }
+}
+
+/// 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> {
+ match n {
+ 0 => Some(Weekday::Mon),
+ 1 => Some(Weekday::Tue),
+ 2 => Some(Weekday::Wed),
+ 3 => Some(Weekday::Thu),
+ 4 => Some(Weekday::Fri),
+ 5 => Some(Weekday::Sat),
+ 6 => Some(Weekday::Sun),
+ _ => None,
+ }
+ }
+
+ #[inline]
+ fn from_u64(n: u64) -> Option<Weekday> {
+ match n {
+ 0 => Some(Weekday::Mon),
+ 1 => Some(Weekday::Tue),
+ 2 => Some(Weekday::Wed),
+ 3 => Some(Weekday::Thu),
+ 4 => Some(Weekday::Fri),
+ 5 => Some(Weekday::Sat),
+ 6 => Some(Weekday::Sun),
+ _ => None,
+ }
+ }
+}
+
+/// An error resulting from reading `Weekday` value with `FromStr`.
+#[derive(Clone, PartialEq, Eq)]
+pub struct ParseWeekdayError {
+ pub(crate) _dummy: (),
+}
+
+#[cfg(feature = "std")]
+#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
+impl std::error::Error for ParseWeekdayError {}
+
+impl fmt::Display for ParseWeekdayError {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.write_fmt(format_args!("{:?}", self))
+ }
+}
+
+impl fmt::Debug for ParseWeekdayError {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "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();
+
+ 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));
+
+ assert_eq!(base_day.num_days_from(base_day), 0);
+
+ assert_eq!(base_day.num_days_from(base_day.pred()), 1);
+ assert_eq!(base_day.num_days_from(base_day.pred().pred()), 2);
+ assert_eq!(base_day.num_days_from(base_day.pred().pred().pred()), 3);
+ assert_eq!(base_day.num_days_from(base_day.pred().pred().pred().pred()), 4);
+ assert_eq!(base_day.num_days_from(base_day.pred().pred().pred().pred().pred()), 5);
+ assert_eq!(
+ base_day.num_days_from(base_day.pred().pred().pred().pred().pred().pred()),
+ 6
+ );
+
+ assert_eq!(base_day.num_days_from(base_day.succ()), 6);
+ assert_eq!(base_day.num_days_from(base_day.succ().succ()), 5);
+ assert_eq!(base_day.num_days_from(base_day.succ().succ().succ()), 4);
+ assert_eq!(base_day.num_days_from(base_day.succ().succ().succ().succ()), 3);
+ assert_eq!(base_day.num_days_from(base_day.succ().succ().succ().succ().succ()), 2);
+ assert_eq!(
+ base_day.num_days_from(base_day.succ().succ().succ().succ().succ().succ()),
+ 1
+ );
+ }
+ }
+}
+
+// the actual `FromStr` implementation is in the `format` module to leverage the existing code
+
+#[cfg(feature = "serde")]
+#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
+mod weekday_serde {
+ use super::Weekday;
+ use core::fmt;
+ use serde::{de, ser};
+
+ impl ser::Serialize for Weekday {
+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: ser::Serializer,
+ {
+ serializer.collect_str(&self)
+ }
+ }
+
+ struct WeekdayVisitor;
+
+ impl<'de> de::Visitor<'de> for WeekdayVisitor {
+ type Value = Weekday;
+
+ fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.write_str("Weekday")
+ }
+
+ fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
+ where
+ E: de::Error,
+ {
+ value.parse().map_err(|_| E::custom("short or long weekday names expected"))
+ }
+ }
+
+ impl<'de> de::Deserialize<'de> for Weekday {
+ fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+ where
+ D: de::Deserializer<'de>,
+ {
+ deserializer.deserialize_str(WeekdayVisitor)
+ }
+ }
+
+ #[test]
+ fn test_serde_serialize() {
+ use serde_json::to_string;
+ use Weekday::*;
+
+ let cases: Vec<(Weekday, &str)> = vec![
+ (Mon, "\"Mon\""),
+ (Tue, "\"Tue\""),
+ (Wed, "\"Wed\""),
+ (Thu, "\"Thu\""),
+ (Fri, "\"Fri\""),
+ (Sat, "\"Sat\""),
+ (Sun, "\"Sun\""),
+ ];
+
+ for (weekday, expected_str) in cases {
+ let string = to_string(&weekday).unwrap();
+ assert_eq!(string, expected_str);
+ }
+ }
+
+ #[test]
+ fn test_serde_deserialize() {
+ use serde_json::from_str;
+ use Weekday::*;
+
+ let cases: Vec<(&str, Weekday)> = vec![
+ ("\"mon\"", Mon),
+ ("\"MONDAY\"", Mon),
+ ("\"MonDay\"", Mon),
+ ("\"mOn\"", Mon),
+ ("\"tue\"", Tue),
+ ("\"tuesday\"", Tue),
+ ("\"wed\"", Wed),
+ ("\"wednesday\"", Wed),
+ ("\"thu\"", Thu),
+ ("\"thursday\"", Thu),
+ ("\"fri\"", Fri),
+ ("\"friday\"", Fri),
+ ("\"sat\"", Sat),
+ ("\"saturday\"", Sat),
+ ("\"sun\"", Sun),
+ ("\"sunday\"", Sun),
+ ];
+
+ for (str, expected_weekday) in cases {
+ let weekday = from_str::<Weekday>(str).unwrap();
+ assert_eq!(weekday, expected_weekday);
+ }
+
+ let errors: Vec<&str> =
+ vec!["\"not a weekday\"", "\"monDAYs\"", "\"mond\"", "mon", "\"thur\"", "\"thurs\""];
+
+ for str in errors {
+ from_str::<Weekday>(str).unwrap_err();
+ }
+ }
+}
diff --git a/vendor/chrono/tests/dateutils.rs b/vendor/chrono/tests/dateutils.rs
new file mode 100644
index 000000000..dec6bfe11
--- /dev/null
+++ b/vendor/chrono/tests/dateutils.rs
@@ -0,0 +1,131 @@
+use chrono::offset::TimeZone;
+use chrono::Local;
+use chrono::{Datelike, NaiveDate, NaiveDateTime, Timelike};
+
+use std::{path, process};
+
+#[cfg(unix)]
+fn verify_against_date_command_local(path: &'static str, dt: NaiveDateTime) {
+ let output = process::Command::new(path)
+ .arg("-d")
+ .arg(format!("{}-{:02}-{:02} {:02}:05:01", dt.year(), dt.month(), dt.day(), dt.hour()))
+ .arg("+%Y-%m-%d %H:%M:%S %:z")
+ .output()
+ .unwrap();
+
+ let date_command_str = String::from_utf8(output.stdout).unwrap();
+
+ // The below would be preferred. At this stage neither earliest() or latest()
+ // seems to be consistent with the output of the `date` command, so we simply
+ // compare both.
+ // let local = Local
+ // .with_ymd_and_hms(year, month, day, hour, 5, 1)
+ // // looks like the "date" command always returns a given time when it is ambiguous
+ // .earliest();
+
+ // if let Some(local) = local {
+ // assert_eq!(format!("{}\n", local), date_command_str);
+ // } else {
+ // // we are in a "Spring forward gap" due to DST, and so date also returns ""
+ // assert_eq!("", date_command_str);
+ // }
+
+ // This is used while a decision is made wheter the `date` output needs to
+ // be exactly matched, or whether LocalResult::Ambigious should be handled
+ // differently
+
+ let date = NaiveDate::from_ymd_opt(dt.year(), dt.month(), dt.day()).unwrap();
+ match Local.from_local_datetime(&date.and_hms_opt(dt.hour(), 5, 1).unwrap()) {
+ chrono::LocalResult::Ambiguous(a, b) => assert!(
+ format!("{}\n", a) == date_command_str || format!("{}\n", b) == date_command_str
+ ),
+ chrono::LocalResult::Single(a) => {
+ assert_eq!(format!("{}\n", a), date_command_str);
+ }
+ chrono::LocalResult::None => {
+ assert_eq!("", date_command_str);
+ }
+ }
+}
+
+#[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.
+ return;
+ }
+
+ let mut date = NaiveDate::from_ymd_opt(1975, 1, 1).unwrap().and_hms_opt(0, 0, 0).unwrap();
+
+ 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);
+ }
+
+ date += chrono::Duration::hours(1);
+ }
+}
+
+#[cfg(target_os = "linux")]
+fn verify_against_date_command_format_local(path: &'static str, dt: NaiveDateTime) {
+ let required_format =
+ "d%d D%D F%F H%H I%I j%j k%k l%l m%m M%M S%S T%T u%u U%U w%w W%W X%X y%y Y%Y z%:z";
+ // a%a - depends from localization
+ // A%A - depends from localization
+ // b%b - depends from localization
+ // B%B - depends from localization
+ // h%h - depends from localization
+ // c%c - depends from localization
+ // p%p - depends from localization
+ // r%r - depends from localization
+ // x%x - fails, date is dd/mm/yyyy, chrono is dd/mm/yy, same as %D
+ // Z%Z - too many ways to represent it, will most likely fail
+
+ let output = process::Command::new(path)
+ .arg("-d")
+ .arg(format!(
+ "{}-{:02}-{:02} {:02}:{:02}:{:02}",
+ dt.year(),
+ dt.month(),
+ dt.day(),
+ dt.hour(),
+ dt.minute(),
+ dt.second()
+ ))
+ .arg(format!("+{}", required_format))
+ .output()
+ .unwrap();
+
+ let date_command_str = String::from_utf8(output.stdout).unwrap();
+ let date = NaiveDate::from_ymd_opt(dt.year(), dt.month(), dt.day()).unwrap();
+ let ldt = Local
+ .from_local_datetime(&date.and_hms_opt(dt.hour(), dt.minute(), dt.second()).unwrap())
+ .unwrap();
+ let formated_date = format!("{}\n", ldt.format(required_format));
+ assert_eq!(date_command_str, formated_date);
+}
+
+#[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
+ return;
+ }
+ 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);
+ date += chrono::Duration::days(55);
+ }
+}
diff --git a/vendor/chrono/tests/wasm.rs b/vendor/chrono/tests/wasm.rs
index 275d120d3..f003d4db9 100644
--- a/vendor/chrono/tests/wasm.rs
+++ b/vendor/chrono/tests/wasm.rs
@@ -1,67 +1,81 @@
-#[cfg(all(test, feature = "wasmbind"))]
-mod test {
- extern crate chrono;
- extern crate wasm_bindgen_test;
+#![cfg(all(
+ target_arch = "wasm32",
+ feature = "wasmbind",
+ not(any(target_os = "emscripten", target_os = "wasi"))
+))]
- use self::chrono::prelude::*;
- use self::wasm_bindgen_test::*;
+use self::chrono::prelude::*;
+use self::wasm_bindgen_test::*;
- #[wasm_bindgen_test]
- fn now() {
- let utc: DateTime<Utc> = Utc::now();
- let local: DateTime<Local> = Local::now();
+#[wasm_bindgen_test]
+fn now() {
+ let utc: DateTime<Utc> = Utc::now();
+ let local: DateTime<Local> = Local::now();
- // Ensure time set by the test script is correct
- let now = env!("NOW");
- let actual = Utc.datetime_from_str(&now, "%s").unwrap();
- let diff = utc - actual;
- assert!(
- diff < chrono::Duration::minutes(5),
- "expected {} - {} == {} < 5m (env var: {})",
- utc,
- actual,
- diff,
- now,
- );
+ // Ensure time set by the test script is correct
+ let now = env!("NOW");
+ let actual = Utc.datetime_from_str(&now, "%s").unwrap();
+ let diff = utc - actual;
+ assert!(
+ diff < chrono::Duration::minutes(5),
+ "expected {} - {} == {} < 5m (env var: {})",
+ utc,
+ actual,
+ diff,
+ now,
+ );
- let tz = env!("TZ");
- eprintln!("testing with tz={}", tz);
+ let tz = env!("TZ");
+ eprintln!("testing with tz={}", tz);
- // Ensure offset retrieved when getting local time is correct
- let expected_offset = match tz {
- "ACST-9:30" => FixedOffset::east(19 * 30 * 60),
- "Asia/Katmandu" => FixedOffset::east(23 * 15 * 60), // No DST thankfully
- "EDT" | "EST4" | "-0400" => FixedOffset::east(-4 * 60 * 60),
- "EST" | "-0500" => FixedOffset::east(-5 * 60 * 60),
- "UTC0" | "+0000" => FixedOffset::east(0),
- tz => panic!("unexpected TZ {}", tz),
- };
- assert_eq!(
- &expected_offset,
- local.offset(),
- "expected: {:?} local: {:?}",
- expected_offset,
- local.offset(),
- );
- }
+ // Ensure offset retrieved when getting local time is correct
+ let expected_offset = match tz {
+ "ACST-9:30" => FixedOffset::east_opt(19 * 30 * 60).unwrap(),
+ "Asia/Katmandu" => FixedOffset::east_opt(23 * 15 * 60).unwrap(), // No DST thankfully
+ "EDT" | "EST4" | "-0400" => FixedOffset::east_opt(-4 * 60 * 60).unwrap(),
+ "EST" | "-0500" => FixedOffset::east_opt(-5 * 60 * 60).unwrap(),
+ "UTC0" | "+0000" => FixedOffset::east_opt(0).unwrap(),
+ tz => panic!("unexpected TZ {}", tz),
+ };
+ assert_eq!(
+ &expected_offset,
+ local.offset(),
+ "expected: {:?} local: {:?}",
+ expected_offset,
+ local.offset(),
+ );
+}
+
+#[wasm_bindgen_test]
+fn from_is_exact() {
+ let now = js_sys::Date::new_0();
- #[wasm_bindgen_test]
- fn from_is_exact() {
- let now = js_sys::Date::new_0();
+ let dt = DateTime::<Utc>::from(now.clone());
- let dt = DateTime::<Utc>::from(now.clone());
+ assert_eq!(now.get_time() as i64, dt.timestamp_millis_opt().unwrap());
+}
+
+#[wasm_bindgen_test]
+fn local_from_local_datetime() {
+ let now = Local::now();
+ let ndt = now.naive_local();
+ let res = match Local.from_local_datetime(&ndt).single() {
+ Some(v) => v,
+ None => panic! {"Required for test!"},
+ };
+ assert_eq!(now, res);
+}
- assert_eq!(now.get_time() as i64, dt.timestamp_millis());
- }
+#[wasm_bindgen_test]
+fn convert_all_parts_with_milliseconds() {
+ let time: DateTime<Utc> = "2020-12-01T03:01:55.974Z".parse().unwrap();
+ let js_date = js_sys::Date::from(time);
- #[wasm_bindgen_test]
- fn local_from_local_datetime() {
- let now = Local::now();
- let ndt = now.naive_local();
- let res = match Local.from_local_datetime(&ndt).single() {
- Some(v) => v,
- None => panic! {"Required for test!"},
- };
- assert_eq!(now, res);
- }
+ assert_eq!(js_date.get_utc_full_year(), 2020);
+ assert_eq!(js_date.get_utc_month(), 12);
+ assert_eq!(js_date.get_utc_date(), 1);
+ assert_eq!(js_date.get_utc_hours(), 3);
+ assert_eq!(js_date.get_utc_minutes(), 1);
+ assert_eq!(js_date.get_utc_seconds(), 55);
+ assert_eq!(js_date.get_utc_milliseconds(), 974);
}