Update chrono to 0.4.39

Test: m
Change-Id: I98fed688517667d953093afd31d8c9c001c258d6
diff --git a/crates/chrono/.android-checksum.json b/crates/chrono/.android-checksum.json
new file mode 100644
index 0000000..ebe340f
--- /dev/null
+++ b/crates/chrono/.android-checksum.json
@@ -0,0 +1 @@
+{"package":null,"files":{"src/naive/datetime/serde.rs":"b95ba199cba50b6c1b78bc6f971834bef1698e3fd4fa1cf8c414d85e5079f3b0","LICENSE":"60d421f113da92de210f41df2ef5020e3cd1afbf0716a6a5f00fec8425639e12","src/format/parse.rs":"e32f3baec7a6ed67bec202159b8c0ec26bed66a651d58e041ab41f164c6abc10","src/format/scan.rs":"3b6ec661c6ef8475e108d9cc97559495823c70b456baa05d8dd610513047bc26","METADATA":"bf19f3ca69fbad0ff0b45143b874785be3238677399d4b0f11e8e4a60be92d15","LICENSE.txt":"60d421f113da92de210f41df2ef5020e3cd1afbf0716a6a5f00fec8425639e12","tests/dateutils.rs":"aa8c902d4ef36c3d6c6035b23e9cd947d823d3509425bbf27b57a0b5accd1784","src/offset/local/unix.rs":"3092f7ac8ce78f997e6dc945f924ef949014ef245835081cab3d8b8e7488f8d8","src/offset/mod.rs":"e0e6317541a834c8d91b296edda2a08cb04f63469e349dbce6f3a1231071d69b","src/round.rs":"35cecf1a5a43e702af5f87b45966e9e691095c927a124fb70ee570ddbfc5fcd4","src/format/formatting.rs":"59da7b077fd66a8f9887d03dd87dc8a819275de22013fd5bf73eb39110549b85","src/naive/internals.rs":"dc59eef76914af046197403c1d4f691a32e0bf46475c8848ff93a481318eeeaf","src/time_delta.rs":"80e4f4372ced4976db2739f2191741ca495577048a3d654840ac09a8e15901d4","src/month.rs":"15398398795bfb576b2a54b97fd8952129ae10e9d9a32aece93ae4993b571332","src/datetime/mod.rs":"58d02cd647da0660dd3860d5af3fc42d8709d46482b652ada36279d581810ccb","src/offset/local/win_bindings.txt":"646777a72d833949149312f18eca7b5041cc0ba7c4c579e7db3895d0cc609895","src/weekday.rs":"0daaa796323367a0defd56aa63cd9d025f424e3db09a5db65ee60de8534098e0","src/offset/utc.rs":"3989e0f2dcbf27c6e492b748513f12554cf325c091771d39774e9eea73af0ef4","src/naive/time/serde.rs":"f0752962eb499b5db01072d2a6d2da6ba2acb72b4a63214e7dcbc7bea929694f","tests/win_bindings.rs":"5e00cfc9d9226264b5848bd235d48ced7a98264edc31dfa52d34c37a3fb62f64","src/offset/local/mod.rs":"49c9592b9bb59c96c4a812326b219b83a598473490ac0cdc205a6691f96d5aa5","src/date.rs":"0760ba27a6ad3d4536412e90698ae2197e04776ee21cfe66a621f844d566482e","src/offset/local/tz_info/parser.rs":"655c0136d8274686df84334910329dba02ecdb958fd3eb337919ea8c02891469","src/offset/local/tz_info/rule.rs":"7f5ed18ddd8ba091b2baa09d02a2e244848dcf539eee799d5307414f5ed770a4","src/format/locales.rs":"9e4890ac865014633c495015f1ccb2751bbbc8365660e364a6037e763a799ed5","Cargo.toml":"cffb09b755c663bee361f08f03a13e67b56e7c96c359c1992e8e682397a09a89","src/naive/isoweek.rs":"1e317b83d8e8ad79b51e1d285c4ddb0c7e5f3f17533ec81f2e723131f9226c27","src/naive/mod.rs":"7000d7d298790aa3eb2fdca5f4237b100d5c530beb715c70bdba3ee9a3362773","src/offset/local/tz_info/mod.rs":"0a39182b6c7027ec45fc05db1a1951de4a55609dbeedae4597432507bb338933","src/format/parsed.rs":"75d859d7a518f8caf28dc6cf6141c58f00ed182f27479709bb8799e232dc9308","src/naive/date/tests.rs":"0d3d4722d594ed71b4bdec9d5153ed1b58af64988c75d23de3e1a56f9fcded7d","src/naive/datetime/tests.rs":"fd9f439ab13744734894bb374bcde7409c58ef028c68eef26278dda5f8ccbeee","src/naive/datetime/mod.rs":"1ff98f0ac101544a031507c5f6513104da260f4e1dfc7dc6d5e1d4239d155744","src/offset/fixed.rs":"7b717e4e3fad0e334a6e153e36ff9c6eef2858bcd0cda6e422e52d041bd4a16a","src/format/mod.rs":"f26ae1077724408080903d22b6219b77bc53136859a7c0f725fd19a4386814d7","tests/wasm.rs":"e4799ba89c17f567757b5798e14597bdf341940049d381590d571a1820c08740","MODULE_LICENSE_APACHE2":"0d6f8afa3940b7f06bebee651376d43bc8b0d5b437337be2696d30377451e93a","TEST_MAPPING":"158a86c6cfb9643813142623368250b67b466e86e6d83b7a9dc19c7781c49b55","src/format/strftime.rs":"7ab2c714968c4ed0b8dd895899f384f4cf0267065f7ac99f730ca5e6a1b1f4a6","src/lib.rs":"1ed9a961fe45217843454257732437a41cf55e5dbedcaa4c498131335819cf55","src/naive/time/tests.rs":"a573b178d474e514faa6fc9693b4bb8138b04d73be6f5b40c4205e29b772fdf5","src/naive/time/mod.rs":"ae6c647bd6fcf8cce2a9142b067d169ca559b7723c92b9d2a1c17adcbe8408ba","cargo_embargo.json":"0015569f32bb5bfe93470021b92aad8b02ea7ad6e34f37e71927de57c7c3726e","src/traits.rs":"b9736a96dbc77102115e1726e16e96b55b1446a732dccb799ae10f1ed91aeb53","src/datetime/serde.rs":"c0d4f35673613512ef19e525351f4dab39d8856f11fac3d84b48bc075b316a6f","src/datetime/tests.rs":"045c6a3c55349fb0e071d5abf9b321da255586e9ccdc2ab6eaec00f7f9f092c1","src/offset/local/win_bindings.rs":"c4187d5417a79295cbd8e559e0fe45b48ecfeacea1d23fbcf6df29b5fd026db8","src/offset/local/tz_info/timezone.rs":"174e2ed2b02fe0e8e62d3ec3d5ed19ae180e1e06ed10ae4e73d229dc61ce1ce5","src/naive/date/mod.rs":"4c1f972d06f3c08c085a49f20a3898e6b83318730949a57f276c5f6c2208f951","Android.bp":"8af4210199bd577b63b8c803891b9aa73aa79b22ec50eefff2be62d17f3b19c8","src/offset/local/windows.rs":"b2f54f8fdf32158952aa67e6a2493864f982e0d5a4bbbb3eab6dccba69e431f7","CITATION.cff":"61469570c85b217c5df6914d985a832bfaa24842673f194812e2b9d35fd00ed0",".cargo-checksum.json":"e82e5facbe972c74727f8205cb910ba946ee396c4c50a9c52b9ace2f80044dee"}}
\ No newline at end of file
diff --git a/crates/chrono/.cargo-checksum.json b/crates/chrono/.cargo-checksum.json
index d613cce..e6e92ae 100644
--- a/crates/chrono/.cargo-checksum.json
+++ b/crates/chrono/.cargo-checksum.json
@@ -1 +1 @@
-{"files":{"CHANGELOG.md":"1cc518c80946bc676a8c691428abe1cdf5a2e4e210b3cacc264b2efc5489d566","CITATION.cff":"e77d50344dced9474fd8aa5365dae75328829e6ac72b13da568b46c2e93af179","Cargo.toml":"790bedd261a51912579eca655bd8b4beea710abb2370afdef6e4e624e6a7fd67","LICENSE.txt":"46610329ff0b38effb9cb05979ff1ef761e465fed96b2eaca39e439d00129fd7","README.md":"79ba2a61ed9433471b06e71b3bd91cfca1114382c3fdd896ee115f3ff1f32432","appveyor.yml":"bcfcff73097a37be373e91934294cfea31fbdfe7a4b01a83bcbc64a8a56c3971","deny.toml":"64e6f7348638d13ea2f87d8fff7654aae7caaff428d4e50671de55ccd989283c","rustfmt.toml":"f74204a6f92aa7422a16ecb2ffe2d5bae0f123b778d08b5db1a398a3c9ca4306","src/date.rs":"10f03590ccab03c3efc076ef55bf218f1e93fdd5f85e4440f46b7590373619b1","src/datetime/mod.rs":"aa7574c6087d967cddf5bfb4950241f10f3b03cf2d83a8958d8498cb37f5934a","src/datetime/rustc_serialize.rs":"1244cb03b64f6f70949feff694bad987ac562b913fcb146e72d93c97f8c5ff3e","src/datetime/serde.rs":"40423f8d4dfd62d4ec532f1f29dc7cb43d233c4dfaa566330f75399bd12d56ef","src/datetime/tests.rs":"71866f75457b32721ece6c3dbae5aa3a7b1b9a567e53350e3756c298de9d8cd0","src/format/formatting.rs":"6f094677df61b795610596355866504f6b7efa2c7745bbe0a985593349203116","src/format/locales.rs":"c35aef701aa077e1b056c9eb7a561241a178207d2f6f748e1b00ee2afcfd8740","src/format/mod.rs":"abc1c6dcef693dbbd4c62275c80810afe29dc676aee9900f10b6b1e91ea54c24","src/format/parse.rs":"337b20497967addb80b517134937b0326bc7335e9c1b9132ef05d036fcec961d","src/format/parsed.rs":"d7506fb4b57bce555140c14230cdedb46e8d58c6ebd28b69dacbe78b82bf37c6","src/format/scan.rs":"be6c765c1916e601eb6274302c619e394aa52d54c5441f26d2fbd9fbf2a08a0a","src/format/strftime.rs":"c478e9be1640dbb12af0e505b85e53a310351fe60f8cc294eb91ae7fe5fe560b","src/lib.rs":"1e24cae615f04e61ab1df6495f4493a7147ab5f2a1c6d5776da992219b587ad5","src/month.rs":"5b75d0da89dafd08d7dc0406ee3fc61bd12055411f46ddbf92296fadb9fc4c22","src/naive/date.rs":"3fcaac41d9dd537ea4120e30412be4ca6e4b6ad9b8078c80762a928e1b9c3afd","src/naive/datetime/mod.rs":"99cbdf6c95d418b7df86449d1a681087afafffb6f31d7fedc355f801fcffdf8f","src/naive/datetime/rustc_serialize.rs":"35e13e1a5ecd84730e0f8c091464ad068cdbc3c54852c0d1dca57ccd9f3b65ee","src/naive/datetime/serde.rs":"b6e65411f38102d0bda3dc5ec67db095732296e6567010e5274d836496cf26a1","src/naive/datetime/tests.rs":"21a4f95666a2626133a308d19e11c9e5bd9e3edb22415817e71017071a8ebbc6","src/naive/internals.rs":"4abb372a9124500746f73bdb99f3b034912984f12b05bc4cd467f88729f16060","src/naive/isoweek.rs":"9b023be1d1e7440508a02168c4fbf7efd694fa7f2f4658fc3b792cbf6239ac27","src/naive/mod.rs":"022e7e9c1e3005d6735daa46b0088836ebbc85044144b8f9cdf049cadd8557c2","src/naive/time/mod.rs":"ba033f12de67c3e44fc939d4083e9d38efbf8119a5a74116d85870091e7ac1c1","src/naive/time/rustc_serialize.rs":"8ef7a5b4eac14662f394b23a3910c104bbb1bc7bcd97baede2ca1bb799c7dc9d","src/naive/time/serde.rs":"1fce0915feec4ddc898847d6b1846b4c2de9b6a789c07f01efacdfccdfd6d9a4","src/naive/time/tests.rs":"127b211d32972f715e9e5049737074bbefb22486f7fa6d7c2091b4171de86e29","src/offset/fixed.rs":"2d8eb8804503ea60b8c8f7212fcb9df7ae0d224949f9a52f0d581f9e690e5738","src/offset/local/mod.rs":"8ca908e94014ec667cff6a030aee343b1af5728ac2e1b38c579a624a720602ce","src/offset/local/tz_info/mod.rs":"c8096637c04687ea396e444c25fdf0008e2b9975ab3c173a41dd63ac213c7877","src/offset/local/tz_info/parser.rs":"4e2f34a6e760833392bc7da038721fb5e266eebb8e4b327a8140e2d8504de4ec","src/offset/local/tz_info/rule.rs":"54df6b45c4517e5442c04654a87c3082dc789b48761237449389802b829acab9","src/offset/local/tz_info/timezone.rs":"12d134c8dff6d37fb1388ab6c49086113d25eae20336693ff752d70ccd181668","src/offset/local/unix.rs":"5a03f58cf5e8efb8046308a88f2fcf36dbd295077071398300e7d7c5da1bfdbf","src/offset/local/win_bindings.rs":"14b7f31e2d7a88f8575bb57ddf758daeca71690244eeebd86b55477529683030","src/offset/local/win_bindings.txt":"e3bae52bc7dcbb6102db41f96b27a2c93a9f3b425eb7195869c99e19c1a354ec","src/offset/local/windows.rs":"35fe2ae74df5e0a1f00cfc20bbce48c2074ce4e4914dabbee99a1a03c77b99b4","src/offset/mod.rs":"c896b77c2b1230c3ad55a3f2f3e336e57e72ee128aba078853f42051dc405a52","src/offset/utc.rs":"4bf5f1ad33133f34fa3ec3f708bbd0a93febd8d5ba359d18cdec68acdb4940cb","src/round.rs":"f7112f14c475ef67182798cf9b1ba8a6b6d19ae746b0545beeb8e2202d56ab9d","src/time_delta.rs":"0f395b36cd4fe3012b90a87816e4524a0a6edf68f4dae3b42279555c6b4412c2","src/traits.rs":"fe301bb63fdc3ee97b8378fefd6e3c6acf3c02e05fdb99637536f5a85857906d","src/weekday.rs":"6f6c179fa23edcbc865cde0e6794a6954548bcb1a4b388ca0e6d8e1da881c74c","taplo.toml":"31cedc3123ed92e506be1f265c2c08cbf8c0b8394aa678fd413ea9dd740f6408","tests/dateutils.rs":"6904c0480ce1a96c46b7c802b2fc89de8cca513974753a55235bd2e6a16f7f78","tests/wasm.rs":"30a023aa9a140d24a7a3c5b2e963a16d17f5001ef09c6a16f04764a79b3277cc","tests/win_bindings.rs":"b23c8d95c724ecf55879229cb20db6bf85d8f76a87221d1e67cb07bb71d29836"},"package":"5bc015644b92d5890fab7489e49d21f879d5c990186827d42ec511919404f38b"}
\ No newline at end of file
+{"files":{"CITATION.cff":"e64b28c9c9202b791045a241c45f001695b017a2d5ce5a2aa8877e0b1cd14196","Cargo.toml":"7eaf24a92bfe51bf8f6fdfb3512966eb69b88532c285e17dbad5531855d83377","LICENSE.txt":"46610329ff0b38effb9cb05979ff1ef761e465fed96b2eaca39e439d00129fd7","src/date.rs":"10f03590ccab03c3efc076ef55bf218f1e93fdd5f85e4440f46b7590373619b1","src/datetime/mod.rs":"b89b4ea25409620fe7cdfa4e0dc566512bbb0a4c82624d30ac39229a4645a730","src/datetime/serde.rs":"6576a9d35dd51bc79fc75eda38904f952b48f74eca1999a9944d9eb454110d0b","src/datetime/tests.rs":"396c4fccb3b6f20eacfb44629f84dff048327689920d7fb702f8620bf62ccaef","src/format/formatting.rs":"0aec20482093fc3511dcd6d16f481de0edba433dc716e8fb9bdab7fd1dd538c3","src/format/locales.rs":"c35aef701aa077e1b056c9eb7a561241a178207d2f6f748e1b00ee2afcfd8740","src/format/mod.rs":"43f82c5956a44871cef2b4b595fe6d9d9843d62ce0f65b289ba29ba063ed6ae2","src/format/parse.rs":"870c3437abca7a7bf1b8d546bbfbb5c5fbecaa2035ae57039af85614586c461d","src/format/parsed.rs":"86f62a8822a80ac9b53f009847f15522345aa848ffc9bedec0bdde01608855d5","src/format/scan.rs":"be6c765c1916e601eb6274302c619e394aa52d54c5441f26d2fbd9fbf2a08a0a","src/format/strftime.rs":"9258a65f1c4e560cd7333ca593007101e9ec3c48e766b9c6bb4db902cbe5a904","src/lib.rs":"ea193c5d2214424137ffeb42fde6024f6003ed952525bcea331f1700bd6fad64","src/month.rs":"609af99ac0e4f8eea5e5983f2e39aa0de41eb1fb6e7f3603200d72d5c7f5a24a","src/naive/date/mod.rs":"947ddb7be90b6f49127ee9e789b0cff9677ce4477cb6fd7e29b2cd0c4965fbbc","src/naive/date/tests.rs":"a2c2fc6e65d1573ed69a07a9dbd5238b55e18bbe66d93d4c3cfd84938963e9df","src/naive/datetime/mod.rs":"aead7ff43214156fbdd9fb6b129318f7edf997a76f109cc4cefd4779855e6494","src/naive/datetime/serde.rs":"eeb8e5a6ea9632799673a6f9e4b72de0ae606ada29b20cbc1b1dbb0f9312b41c","src/naive/datetime/tests.rs":"082eb0adacd87e9034cccce8ca8339febe64567ec6d210220fdea1bdd6428354","src/naive/internals.rs":"7b9fc479602a085a31f81c197f0f4f07be035237555e64b9574edf32ad771678","src/naive/isoweek.rs":"3f586d8de01f2d324ab1dcf94cf50cbfe5071ce71c4849b0e936524d29869776","src/naive/mod.rs":"7057f994aadcc72c9973f92ecf477150a77f0b6c5a4f06bff38e604e4844c0d3","src/naive/time/mod.rs":"f17fd2d76de3b44c6eb12a413fe20b44e5bdfdc9b2d10cc4153aac5b03914dbe","src/naive/time/serde.rs":"6c260c6d0c45dec113f3dcff6056450c524511c37f7c30da9324ad80aff2288b","src/naive/time/tests.rs":"70143375785969ed348fcc1ceab50b670d239209191b938823dd7b25a97ced40","src/offset/fixed.rs":"7a8e7bbe33a67b0dc7614fa2eb7f79a0396360dcaf9967a9f9e5bddb82b7b421","src/offset/local/mod.rs":"6222d8e2fdcd8a97ce64a4eec531288f5739d07066bd1795c872d7e449eb3647","src/offset/local/tz_info/mod.rs":"c8096637c04687ea396e444c25fdf0008e2b9975ab3c173a41dd63ac213c7877","src/offset/local/tz_info/parser.rs":"547f86d077e03d4443ab2ed1f8ada0a7d9d783d1c66823650706ebf7538e1b6e","src/offset/local/tz_info/rule.rs":"ee8c42e001a0ab3b9caf0f18aceeea13ea5f5a285a74c7415bc7f24091bf66d9","src/offset/local/tz_info/timezone.rs":"1993d578315c45f9af58e2d789fb43ea65a31e0469ef0f4d9ea43007d6343062","src/offset/local/unix.rs":"01bd00821db763098e7730dd54e9c951aad112bba75aa01a9f8efb9397310d36","src/offset/local/win_bindings.rs":"ea943f985fbb4a41a88f884214f6ec20856bfa15f59addfdbf9768679724de54","src/offset/local/win_bindings.txt":"3bbbcb90060f20414a9cb2396bfb1d0efc9608dbeabdb08637fe99ea25f473fd","src/offset/local/windows.rs":"4d8a15958c4ac1a8cc238016065e27377dbbebc1702d6d7da87f93bb278b6f7a","src/offset/mod.rs":"be172860c7d02eb75517f7e959abafc48836c82b38baa5e08d7f1a6cebed8856","src/offset/utc.rs":"4b5449427cebf609cb5bbcc07ae70faeb3eab4f742d5a6a521e9118227d6eb2d","src/round.rs":"b1e0a0a2b34ffa354139152e6710a23586f93cfae89c8738b517b943ec6e38ab","src/time_delta.rs":"0cb5db361a8aec0fd54731fa80aa055b89e7f1f463f186ceef4b8bd415bfdf13","src/traits.rs":"1f295008518b45534697049d5ba491100a9cd6e615034d5b3eb068eb1d46bdfb","src/weekday.rs":"69bbe8f458ad1651293aac849fdf332499cf824d97cd4fc6f012db548fa1d5eb","tests/dateutils.rs":"e1294b30268bb70be7fe4b4d9c6a6bbafc9b95d0af5b827f8639ff9b0794df30","tests/wasm.rs":"252f16aeeaacbf26ca268b9a5e53aee3560cd1f071142a7a16d1509a02758a17","tests/win_bindings.rs":"b23c8d95c724ecf55879229cb20db6bf85d8f76a87221d1e67cb07bb71d29836"},"package":"7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825"}
\ No newline at end of file
diff --git a/crates/chrono/Android.bp b/crates/chrono/Android.bp
index 615790c..93ffbcc 100644
--- a/crates/chrono/Android.bp
+++ b/crates/chrono/Android.bp
@@ -18,7 +18,7 @@
     host_supported: true,
     crate_name: "chrono",
     cargo_env_compat: true,
-    cargo_pkg_version: "0.4.34",
+    cargo_pkg_version: "0.4.39",
     crate_root: "src/lib.rs",
     test_suites: ["general-tests"],
     auto_gen_config: true,
@@ -46,7 +46,7 @@
     host_supported: true,
     crate_name: "dateutils",
     cargo_env_compat: true,
-    cargo_pkg_version: "0.4.34",
+    cargo_pkg_version: "0.4.39",
     crate_root: "tests/dateutils.rs",
     test_suites: ["general-tests"],
     auto_gen_config: true,
@@ -75,7 +75,7 @@
     host_supported: true,
     crate_name: "wasm",
     cargo_env_compat: true,
-    cargo_pkg_version: "0.4.34",
+    cargo_pkg_version: "0.4.39",
     crate_root: "tests/wasm.rs",
     test_suites: ["general-tests"],
     auto_gen_config: true,
@@ -104,7 +104,7 @@
     host_supported: true,
     crate_name: "win_bindings",
     cargo_env_compat: true,
-    cargo_pkg_version: "0.4.34",
+    cargo_pkg_version: "0.4.39",
     crate_root: "tests/win_bindings.rs",
     test_suites: ["general-tests"],
     auto_gen_config: true,
@@ -133,7 +133,7 @@
     host_supported: true,
     crate_name: "chrono",
     cargo_env_compat: true,
-    cargo_pkg_version: "0.4.34",
+    cargo_pkg_version: "0.4.39",
     crate_root: "src/lib.rs",
     edition: "2021",
     features: [
diff --git a/crates/chrono/CHANGELOG.md b/crates/chrono/CHANGELOG.md
deleted file mode 100644
index 1e6f6f9..0000000
--- a/crates/chrono/CHANGELOG.md
+++ /dev/null
@@ -1,731 +0,0 @@
-ChangeLog for Chrono
-====================
-
-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
-
-* Correct build on solaris/illumos
-
-## 0.4.18
-
-* Restore support for x86_64-fortanix-unknown-sgx
-
-## 0.4.17
-
-* Fix a name resolution error in wasm-bindgen code introduced by removing the dependency on time
-  v0.1
-
-## 0.4.16
-
-### Features
-
-* Add %Z specifier to the `FromStr`, similar to the glibc strptime
-  (does not set the offset from the timezone name)
-
-* Drop the dependency on time v0.1, which is deprecated, unless the `oldtime`
-  feature is active. This feature is active by default in v0.4.16 for backwards
-  compatibility, but will likely be removed in v0.5. Code that imports
-  `time::Duration` should be switched to import `chrono::Duration` instead to
-  avoid breakage.
-
-## 0.4.15
-
-### Fixes
-
-* Correct usage of vec in specific feature combinations (@quodlibetor)
-
-## 0.4.14 **YANKED**
-
-### Features
-
-* Add day and week iterators for `NaiveDate` (@gnzlbg & @robyoung)
-* Add a `Month` enum (@hhamana)
-* Add `locales`. All format functions can now use locales, see the documentation for the
-  `unstable-locales` feature.
-* Fix `Local.from_local_datetime` method for wasm
-
-### Improvements
-
-* Added MIN and MAX values for `NaiveTime`, `NaiveDateTime` and `DateTime<Utc>`.
-
-## 0.4.13
-
-### Features
-
-* Add `DurationRound` trait that allows rounding and truncating by `Duration` (@robyoung)
-
-### Internal Improvements
-
-* Code improvements to impl `From` for `js_sys` in wasm to reuse code (@schrieveslaach)
-
-## 0.4.12
-
-### New Methods and impls
-
-* `Duration::abs` to ensure that a duration is just a magnitude (#418 @abreis).
-
-### Compatibility improvements
-
-* impl `From` for `js_sys` in wasm (#424 @schrieveslaach)
-* Bump required version of `time` for redox support.
-
-### Bugfixes
-
-* serde modules do a better job with `Option` types (#417 @mwkroening and #429
-  @fx-kirin)
-* Use js runtime when using wasmbind to get the local offset (#412
-  @quodlibetor)
-
-### Internal Improvements
-
-* Migrate to github actions from travis-ci, make the overall CI experience more comprehensible,
-  significantly faster and more correct (#439 @quodlibetor)
-
-## 0.4.11
-
-### Improvements
-
-* Support a space or `T` in `FromStr` for `DateTime<Tz>`, meaning that e.g.
-  `dt.to_string().parse::<DateTime<Utc>>()` now correctly works on round-trip.
-  (@quodlibetor in #378)
-* Support "negative UTC" in `parse_from_rfc2822` (@quodlibetor #368 reported in
-  #102)
-* Support comparisons of DateTimes with different timezones (@dlalic in #375)
-* Many documentation improvements
-
-### Bitrot and external integration fixes
-
-* Don't use wasmbind on wasi (@coolreader18 #365)
-* Avoid deprecation warnings for `Error::description` (@AnderEnder and
-  @quodlibetor #376)
-
-### Internal improvements
-
-* Use Criterion for benchmarks (@quodlibetor)
-
-## 0.4.10
-
-### Compatibility notes
-
-* Putting some functionality behind an `alloc` feature to improve no-std
-  support (in #341) means that if you were relying on chrono with
-  `no-default-features` *and* using any of the functions that require alloc
-  support (i.e. any of the string-generating functions like `to_rfc3339`) you
-  will need to add the `alloc` feature in your Cargo.toml.
-
-### Improvements
-
-* `DateTime::parse_from_str` is more than 2x faster in some cases. (@michalsrb
-  #358)
-* Significant improvements to no-std and alloc support (This should also make
-  many format/serialization operations induce zero unnecessary allocations)
-  (@CryZe #341)
-
-### Features
-
-* Functions that were accepting `Iterator` of `Item`s (for example
-  `format_with_items`) now accept `Iterator` of `Borrow<Item>`, so one can
-  use values or references. (@michalsrb #358)
-* Add built-in support for structs with nested `Option<Datetime>` etc fields
-  (@manifest #302)
-
-### Internal/doc improvements
-
-* Use markdown footnotes on the `strftime` docs page (@qudlibetor #359)
-* Migrate from `try!` -> `?` (question mark) because it is now emitting
-  deprecation warnings and has been stable since rustc 1.13.0
-* Deny dead code
-
-## 0.4.9
-
-### Fixes
-
-* Make Datetime arithmatic adjust their offsets after discovering their new
-  timestamps (@quodlibetor #337)
-* Put wasm-bindgen related code and dependencies behind a `wasmbind` feature
-  gate. (@quodlibetor #335)
-
-## 0.4.8
-
-### Fixes
-
-* Add '0' to single-digit days in rfc2822 date format (@wyhaya #323)
-* Correctly pad DelayedFormat (@SamokhinIlya #320)
-
-### Features
-
-* Support `wasm-unknown-unknown` via wasm-bindgen (in addition to
-  emscripten/`wasm-unknown-emscripten`). (finished by @evq in #331, initial
-  work by @jjpe #287)
-
-## 0.4.7
-
-### Fixes
-
-* Disable libc default features so that CI continues to work on rust 1.13
-* Fix panic on negative inputs to timestamp_millis (@cmars #292)
-* Make `LocalResult` `Copy/Eq/Hash`
-
-### Features
-
-* Add `std::convert::From` conversions between the different timezone formats
-  (@mqudsi #271)
-* Add `timestamp_nanos` methods (@jean-airoldie #308)
-* Documentation improvements
-
-## 0.4.6
-
-### Maintenance
-
-* Doc improvements -- improve README CI verification, external links
-* winapi upgrade to 0.3
-
-## Unreleased
-
-### Features
-
-* Added `NaiveDate::from_weekday_of_month{,_opt}` for getting eg. the 2nd Friday of March 2017.
-
-## 0.4.5
-
-### Features
-
-* Added several more serde deserialization helpers (@novacrazy #258)
-* Enabled all features on the playground (@davidtwco #267)
-* Derive `Hash` on `FixedOffset` (@LuoZijun #254)
-* Improved docs (@storyfeet #261, @quodlibetor #252)
-
-## 0.4.4
-
-### Features
-
-* Added support for parsing nanoseconds without the leading dot (@emschwartz #251)
-
-## 0.4.3
-
-### Features
-
-* Added methods to DateTime/NaiveDateTime to present the stored value as a number
-  of nanoseconds since the UNIX epoch (@harkonenbade #247)
-* Added a serde serialise/deserialise module for nanosecond timestamps. (@harkonenbade #247)
-* Added "Permissive" timezone parsing which allows a numeric timezone to
-  be specified without minutes. (@quodlibetor #242)
-
-## 0.4.2
-
-### Deprecations
-
-* More strongly deprecate RustcSerialize: remove it from documentation unless
-  the feature is enabled, issue a deprecation warning if the rustc-serialize
-  feature is enabled (@quodlibetor #174)
-
-### Features
-
-* Move all uses of the system clock behind a `clock` feature, for use in
-  environments where we don't have access to the current time. (@jethrogb #236)
-* Implement subtraction of two `Date`s, `Time`s, or `DateTime`s, returning a
-  `Duration` (@tobz1000 #237)
-
-## 0.4.1
-
-### Bug Fixes
-
-* Allow parsing timestamps with subsecond precision (@jonasbb)
-* RFC2822 allows times to not include the second (@upsuper)
-
-### Features
-
-* New `timestamp_millis` method on `DateTime` and `NaiveDateTim` that returns
-  number of milliseconds since the epoch. (@quodlibetor)
-* Support exact decimal width on subsecond display for RFC3339 via a new
-  `to_rfc3339_opts` method on `DateTime` (@dekellum)
-* Use no_std-compatible num dependencies (@cuviper)
-* Add `SubsecRound` trait that allows rounding to the nearest second
-  (@dekellum)
-
-### Code Hygiene and Docs
-
-* Docs! (@alatiera @kosta @quodlibetor @kennytm)
-* Run clippy and various fixes (@quodlibetor)
-
-## 0.4.0 (2017-06-22)
-
-This was originally planned as a minor release but was pushed to a major
-release due to the compatibility concern raised.
-
-### Added
-
-- `IsoWeek` has been added for the ISO week without time zone.
-
-- The `+=` and `-=` operators against `time::Duration` are now supported for
-  `NaiveDate`, `NaiveTime` and `NaiveDateTime`. (#99)
-
-  (Note that this does not invalidate the eventual deprecation of `time::Duration`.)
-
-- `SystemTime` and `DateTime<Tz>` types can be now converted to each other via `From`.
-  Due to the obvious lack of time zone information in `SystemTime`,
-  the forward direction is limited to `DateTime<Utc>` and `DateTime<Local>` only.
-
-### Changed
-
-- Intermediate implementation modules have been flattened (#161),
-  and `UTC` has been renamed to `Utc` in accordance with the current convention (#148).
-
-  The full list of changes is as follows:
-
-  Before                                   | After
-  ---------------------------------------- | ----------------------------
-  `chrono::date::Date`                     | `chrono::Date`
-  `chrono::date::MIN`                      | `chrono::MIN_DATE`
-  `chrono::date::MAX`                      | `chrono::MAX_DATE`
-  `chrono::datetime::DateTime`             | `chrono::DateTime`
-  `chrono::naive::time::NaiveTime`         | `chrono::naive::NaiveTime`
-  `chrono::naive::date::NaiveDate`         | `chrono::naive::NaiveDate`
-  `chrono::naive::date::MIN`               | `chrono::naive::MIN_DATE`
-  `chrono::naive::date::MAX`               | `chrono::naive::MAX_DATE`
-  `chrono::naive::datetime::NaiveDateTime` | `chrono::naive::NaiveDateTime`
-  `chrono::offset::utc::UTC`               | `chrono::offset::Utc`
-  `chrono::offset::fixed::FixedOffset`     | `chrono::offset::FixedOffset`
-  `chrono::offset::local::Local`           | `chrono::offset::Local`
-  `chrono::format::parsed::Parsed`         | `chrono::format::Parsed`
-
-  With an exception of `Utc`, this change does not affect any direct usage of
-  `chrono::*` or `chrono::prelude::*` types.
-
-- `Datelike::isoweekdate` is replaced by `Datelike::iso_week` which only returns the ISO week.
-
-  The original method used to return a tuple of year number, week number and day of the week,
-  but this duplicated the `Datelike::weekday` method and it had been hard to deal with
-  the raw year and week number for the ISO week date.
-  This change isolates any logic and API for the week date into a separate type.
-
-- `NaiveDateTime` and `DateTime` can now be deserialized from an integral UNIX timestamp. (#125)
-
-  This turns out to be very common input for web-related usages.
-  The existing string representation is still supported as well.
-
-- `chrono::serde` and `chrono::naive::serde` modules have been added
-  for the serialization utilities. (#125)
-
-  Currently they contain the `ts_seconds` modules that can be used to
-  serialize `NaiveDateTime` and `DateTime` values into an integral UNIX timestamp.
-  This can be combined with Serde's `[de]serialize_with` attributes
-  to fully support the (de)serialization to/from the timestamp.
-
-  For rustc-serialize, there are separate `chrono::TsSeconds` and `chrono::naive::TsSeconds` types
-  that are newtype wrappers implementing different (de)serialization logics.
-  This is a suboptimal API, however, and it is strongly recommended to migrate to Serde.
-
-### Fixed
-
-- The major version was made to fix the broken Serde dependency issues. (#146, #156, #158, #159)
-
-  The original intention to technically break the dependency was
-  to facilitate the use of Serde 1.0 at the expense of temporary breakage.
-  Whether this was appropriate or not is quite debatable,
-  but it became clear that there are several high-profile crates requiring Serde 0.9
-  and it is not feasible to force them to use Serde 1.0 anyway.
-
-  To the end, the new major release was made with some known lower-priority breaking changes.
-  0.3.1 is now yanked and any remaining 0.3 users can safely roll back to 0.3.0.
-
-- Various documentation fixes and goodies. (#92, #131, #136)
-
-## 0.3.1 (2017-05-02)
-
-### Added
-
-- `Weekday` now implements `FromStr`, `Serialize` and `Deserialize`. (#113)
-
-  The syntax is identical to `%A`, i.e. either the shortest or the longest form of English names.
-
-### Changed
-
-- Serde 1.0 is now supported. (#142)
-
-  This is technically a breaking change because Serde 0.9 and 1.0 are not compatible,
-  but this time we decided not to issue a minor version because
-  we have already seen Serde 0.8 and 0.9 compatibility problems even after 0.3.0 and
-  a new minor version turned out to be not very helpful for this kind of issues.
-
-### Fixed
-
-- Fixed a bug that the leap second can be mapped wrongly in the local time zone.
-  Only occurs when the local time zone is behind UTC. (#130)
-
-## 0.3.0 (2017-02-07)
-
-The project has moved to the [Chronotope](https://github.com/chronotope/) organization.
-
-### Added
-
-- `chrono::prelude` module has been added. All other glob imports are now discouraged.
-
-- `FixedOffset` can be added to or subtracted from any timelike types.
-
-    - `FixedOffset::local_minus_utc` and `FixedOffset::utc_minus_local` methods have been added.
-      Note that the old `Offset::local_minus_utc` method is gone; see below.
-
-- Serde support for non-self-describing formats like Bincode is added. (#89)
-
-- Added `Item::Owned{Literal,Space}` variants for owned formatting items. (#76)
-
-- Formatting items and the `Parsed` type have been slightly adjusted so that
-  they can be internally extended without breaking any compatibility.
-
-- `Weekday` is now `Hash`able. (#109)
-
-- `ParseError` now implements `Eq` as well as `PartialEq`. (#114)
-
-- More documentation improvements. (#101, #108, #112)
-
-### Changed
-
-- Chrono now only supports Rust 1.13.0 or later (previously: Rust 1.8.0 or later).
-
-- Serde 0.9 is now supported.
-  Due to the API difference, support for 0.8 or older is discontinued. (#122)
-
-- Rustc-serialize implementations are now on par with corresponding Serde implementations.
-  They both standardize on the `std::fmt::Debug` textual output.
-
-  **This is a silent breaking change (hopefully the last though).**
-  You should be prepared for the format change if you depended on rustc-serialize.
-
-- `Offset::local_minus_utc` is now `Offset::fix`, and returns `FixedOffset` instead of a duration.
-
-  This makes every time zone operation operate within a bias less than one day,
-  and vastly simplifies many logics.
-
-- `chrono::format::format` now receives `FixedOffset` instead of `time::Duration`.
-
-- The following methods and implementations have been renamed and older names have been *removed*.
-  The older names will be reused for the same methods with `std::time::Duration` in the future.
-
-    - `checked_*` → `checked_*_signed` in `Date`, `DateTime`, `NaiveDate` and `NaiveDateTime` types
-
-    - `overflowing_*` → `overflowing_*_signed` in the `NaiveTime` type
-
-    - All subtraction implementations between two time instants have been moved to
-      `signed_duration_since`, following the naming in `std::time`.
-
-### Fixed
-
-- Fixed a panic when the `Local` offset receives a leap second. (#123)
-
-### Removed
-
-- Rustc-serialize support for `Date<Tz>` types and all offset types has been dropped.
-
-  These implementations were automatically derived and never had been in a good shape.
-  Moreover there are no corresponding Serde implementations, limiting their usefulness.
-  In the future they may be revived with more complete implementations.
-
-- The following method aliases deprecated in the 0.2 branch have been removed.
-
-    - `DateTime::num_seconds_from_unix_epoch` (→ `DateTime::timestamp`)
-    - `NaiveDateTime::from_num_seconds_from_unix_epoch` (→ `NaiveDateTime::from_timestamp`)
-    - `NaiveDateTime::from_num_seconds_from_unix_epoch_opt` (→ `NaiveDateTime::from_timestamp_opt`)
-    - `NaiveDateTime::num_seconds_unix_epoch` (→ `NaiveDateTime::timestamp`)
-
-- Formatting items are no longer `Copy`, except for `chrono::format::Pad`.
-
-- `chrono::offset::add_with_leapsecond` has been removed.
-  Use a direct addition with `FixedOffset` instead.
-
-## 0.2.25 (2016-08-04)
-
-This is the last version officially supports Rust 1.12.0 or older.
-
-(0.2.24 was accidentally uploaded without a proper check for warnings in the default state,
-and replaced by 0.2.25 very shortly. Duh.)
-
-### Added
-
-- Serde 0.8 is now supported. 0.7 also remains supported. (#86)
-
-### Fixed
-
-- The deserialization implementation for rustc-serialize now properly verifies the input.
-  All serialization codes are also now thoroughly tested. (#42)
-
-## 0.2.23 (2016-08-03)
-
-### Added
-
-- The documentation was greatly improved for several types,
-  and tons of cross-references have been added. (#77, #78, #80, #82)
-
-- `DateTime::timestamp_subsec_{millis,micros,nanos}` methods have been added. (#81)
-
-### Fixed
-
-- When the system time records a leap second,
-  the nanosecond component was mistakenly reset to zero. (#84)
-
-- `Local` offset misbehaves in Windows for August and later,
-  due to the long-standing libtime bug (dates back to mid-2015).
-  Workaround has been implemented. (#85)
-
-## 0.2.22 (2016-04-22)
-
-### Fixed
-
-- `%.6f` and `%.9f` used to print only three digits when the nanosecond part is zero. (#71)
-- The documentation for `%+` has been updated to reflect the current status. (#71)
-
-## 0.2.21 (2016-03-29)
-
-### Fixed
-
-- `Fixed::LongWeekdayName` was unable to recognize `"sunday"` (whoops). (#66)
-
-## 0.2.20 (2016-03-06)
-
-### Changed
-
-- `serde` dependency has been updated to 0.7. (#63, #64)
-
-## 0.2.19 (2016-02-05)
-
-### Added
-
-- The documentation for `Date` is made clear about its ambiguity and guarantees.
-
-### Fixed
-
-- `DateTime::date` had been wrong when the local date and the UTC date is in disagreement. (#61)
-
-## 0.2.18 (2016-01-23)
-
-### Fixed
-
-- Chrono no longer pulls a superfluous `rand` dependency. (#57)
-
-## 0.2.17 (2015-11-22)
-
-### Added
-
-- Naive date and time types and `DateTime` now have a `serde` support.
-  They serialize as an ISO 8601 / RFC 3339 string just like `Debug`. (#51)
-
-## 0.2.16 (2015-09-06)
-
-### Added
-
-- Added `%.3f`, `%.6f` and `%.9f` specifier for formatting fractional seconds
-  up to 3, 6 or 9 decimal digits. This is a natural extension to the existing `%f`.
-  Note that this is (not yet) generic, no other value of precision is supported. (#45)
-
-### Changed
-
-- Forbade unsized types from implementing `Datelike` and `Timelike`.
-  This does not make a big harm as any type implementing them should be already sized
-  to be practical, but this change still can break highly generic codes. (#46)
-
-### Fixed
-
-- Fixed a broken link in the `README.md`. (#41)
-
-## 0.2.15 (2015-07-05)
-
-### Added
-
-- Padding modifiers `%_?`, `%-?` and `%0?` are implemented.
-  They are glibc extensions which seem to be reasonably widespread (e.g. Ruby).
-
-- Added `%:z` specifier and corresponding formatting items
-  which is essentially the same as `%z` but with a colon.
-
-- Added a new specifier `%.f` which precision adapts from the input.
-  This was added as a response to the UX problems in the original nanosecond specifier `%f`.
-
-### Fixed
-
-- `Numeric::Timestamp` specifier (`%s`) was ignoring the time zone offset when provided.
-
-- Improved the documentation and associated tests for `strftime`.
-
-## 0.2.14 (2015-05-15)
-
-### Fixed
-
-- `NaiveDateTime +/- Duration` or `NaiveTime +/- Duration` could have gone wrong
-  when the `Duration` to be added is negative and has a fractional second part.
-  This was caused by an underflow in the conversion from `Duration` to the parts;
-  the lack of tests for this case allowed a bug. (#37)
-
-## 0.2.13 (2015-04-29)
-
-### Added
-
-- The optional dependency on `rustc_serialize` and
-  relevant `Rustc{En,De}codable` implementations for supported types has been added.
-  This is enabled by the `rustc-serialize` Cargo feature. (#34)
-
-### Changed
-
-- `chrono::Duration` reexport is changed to that of crates.io `time` crate.
-  This enables Rust 1.0 beta compatibility.
-
-## 0.2.4 (2015-03-03)
-
-### Fixed
-
-- Clarified the meaning of `Date<Tz>` and fixed unwanted conversion problem
-  that only occurs with positive UTC offsets. (#27)
-
-## 0.2.3 (2015-02-27)
-
-### Added
-
-- `DateTime<Tz>` and `Date<Tz>` is now `Copy`/`Send` when `Tz::Offset` is `Copy`/`Send`.
-  The implementations for them were mistakenly omitted. (#25)
-
-### Fixed
-
-- `Local::from_utc_datetime` didn't set a correct offset. (#26)
-
-## 0.2.1 (2015-02-21)
-
-### Changed
-
-- `DelayedFormat` no longer conveys a redundant lifetime.
-
-## 0.2.0 (2015-02-19)
-
-### Added
-
-- `Offset` is splitted into `TimeZone` (constructor) and `Offset` (storage) types.
-  You would normally see only the former, as the latter is mostly an implementation detail.
-  Most importantly, `Local` now can be used to directly construct timezone-aware values.
-
-  Some types (currently, `UTC` and `FixedOffset`) are both `TimeZone` and `Offset`,
-  but others aren't (e.g. `Local` is not what is being stored to each `DateTime` values).
-
-- `LocalResult::map` convenience method has been added.
-
-- `TimeZone` now allows a construction of `DateTime` values from UNIX timestamp,
-  via `timestamp` and `timestamp_opt` methods.
-
-- `TimeZone` now also has a method for parsing `DateTime`, namely `datetime_from_str`.
-
-- The following methods have been added to all date and time types:
-
-    - `checked_add`
-    - `checked_sub`
-    - `format_with_items`
-
-- The following methods have been added to all timezone-aware types:
-
-    - `timezone`
-    - `with_timezone`
-    - `naive_utc`
-    - `naive_local`
-
-- `parse_from_str` method has been added to all naive types and `DateTime<FixedOffset>`.
-
-- All naive types and instances of `DateTime` with time zones `UTC`, `Local` and `FixedOffset`
-  implement the `FromStr` trait. They parse what `std::fmt::Debug` would print.
-
-- `chrono::format` has been greatly rewritten.
-
-    - The formatting syntax parser is modular now, available at `chrono::format::strftime`.
-
-    - The parser and resolution algorithm is also modular, the former is available at
-      `chrono::format::parse` while the latter is available at `chrono::format::parsed`.
-
-    - Explicit support for RFC 2822 and 3339 syntaxes is landed.
-
-    - There is a minor formatting difference with atypical values,
-      e.g. for years not between 1 BCE and 9999 CE.
-
-### Changed
-
-- Most uses of `Offset` are converted to `TimeZone`.
-  In fact, *all* user-facing code is expected to be `Offset`-free.
-
-- `[Naive]DateTime::*num_seconds_from_unix_epoch*` methods have been renamed to
-  simply `timestamp` or `from_timestamp*`. The original names have been deprecated.
-
-### Removed
-
-- `Time` has been removed. This also prompts a related set of methods in `TimeZone`.
-
-  This is in principle possible, but in practice has seen a little use
-  because it can only be meaningfully constructed via an existing `DateTime` value.
-  This made many operations to `Time` unintuitive or ambiguous,
-  so we simply let it go.
-
-  In the case that `Time` is really required, one can use a simpler `NaiveTime`.
-  `NaiveTime` and `NaiveDate` can be freely combined and splitted,
-  and `TimeZone::from_{local,utc}_datetime` can be used to convert from/to the local time.
-
-- `with_offset` method has been removed. Use `with_timezone` method instead.
-  (This is not deprecated since it is an integral part of offset reform.)
-
-## 0.1.14 (2015-01-10)
-
-### Added
-
-- Added a missing `std::fmt::String` impl for `Local`.
-
-## 0.1.13 (2015-01-10)
-
-### Changed
-
-- Most types now implement both `std::fmt::Show` and `std::fmt::String`,
-  with the former used for the stricter output and the latter used for more casual output.
-
-### Removed
-
-- `Offset::name` has been replaced by a `std::fmt::String` implementation to `Offset`.
-
-## 0.1.12 (2015-01-08)
-
-### Removed
-
-- `Duration + T` no longer works due to the updated impl reachability rules.
-  Use `T + Duration` as a workaround.
-
-## 0.1.4 (2014-12-13)
-
-### Fixed
-
-- Fixed a bug that `Date::and_*` methods with an offset that can change the date are
-  off by one day.
-
-## 0.1.3 (2014-11-28)
-
-### Added
-
-- `{Date,Time,DateTime}::with_offset` methods have been added.
-
-- `LocalResult` now implements a common set of traits.
-
-- `LocalResult::and_*` methods have been added.
-  They are useful for safely chaining `LocalResult<Date<Off>>` methods
-  to make `LocalResult<DateTime<Off>>`.
-
-### Changed
-
-- `Offset::name` now returns `SendStr`.
-
-- `{Date,Time} - Duration` overloadings are now allowed.
-
-## 0.1.2 (2014-11-24)
-
-### Added
-
-- `Duration + Date` overloading is now allowed.
-
-### Changed
-
-- Chrono no longer needs `num` dependency.
-
-## 0.1.0 (2014-11-20)
-
-The initial version that was available to `crates.io`.
diff --git a/crates/chrono/CITATION.cff b/crates/chrono/CITATION.cff
index 904009d..96cbf16 100644
--- a/crates/chrono/CITATION.cff
+++ b/crates/chrono/CITATION.cff
@@ -3,8 +3,8 @@
 message: Please cite this crate using these information.
 
 # Version information.
-date-released: 2024-02-11
-version: 0.4.34
+date-released: 2024-04-15
+version: 0.4.38
 
 # Project information.
 abstract: Date and time library for Rust
diff --git a/crates/chrono/Cargo.toml b/crates/chrono/Cargo.toml
index 9f0f82f..6ccd2ac 100644
--- a/crates/chrono/Cargo.toml
+++ b/crates/chrono/Cargo.toml
@@ -13,8 +13,19 @@
 edition = "2021"
 rust-version = "1.61.0"
 name = "chrono"
-version = "0.4.34"
-exclude = ["/ci/*"]
+version = "0.4.39"
+build = false
+include = [
+    "src/*",
+    "tests/*.rs",
+    "LICENSE.txt",
+    "CITATION.cff",
+]
+autolib = false
+autobins = false
+autoexamples = false
+autotests = false
+autobenches = false
 description = "Date and time library for Rust"
 homepage = "https://github.com/chronotope/chrono"
 documentation = "https://docs.rs/chrono/"
@@ -45,6 +56,19 @@
 
 [lib]
 name = "chrono"
+path = "src/lib.rs"
+
+[[test]]
+name = "dateutils"
+path = "tests/dateutils.rs"
+
+[[test]]
+name = "wasm"
+path = "tests/wasm.rs"
+
+[[test]]
+name = "win_bindings"
+path = "tests/win_bindings.rs"
 
 [dependencies.arbitrary]
 version = "1.0.0"
@@ -64,10 +88,6 @@
 optional = true
 default-features = false
 
-[dependencies.rustc-serialize]
-version = "0.3.20"
-optional = true
-
 [dependencies.serde]
 version = "1.0.99"
 optional = true
@@ -126,18 +146,18 @@
 ]
 winapi = ["windows-targets"]
 
-[target."cfg(all(target_arch = \"wasm32\", not(any(target_os = \"emscripten\", target_os = \"wasi\"))))".dependencies.js-sys]
+[target.'cfg(all(target_arch = "wasm32", not(any(target_os = "emscripten", target_os = "wasi"))))'.dependencies.js-sys]
 version = "0.3"
 optional = true
 
-[target."cfg(all(target_arch = \"wasm32\", not(any(target_os = \"emscripten\", target_os = \"wasi\"))))".dependencies.wasm-bindgen]
+[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]
+[target.'cfg(all(target_arch = "wasm32", not(any(target_os = "emscripten", target_os = "wasi"))))'.dev-dependencies.wasm-bindgen-test]
 version = "0.3"
 
-[target."cfg(target_os = \"android\")".dependencies.android-tzdata]
+[target.'cfg(target_os = "android")'.dependencies.android-tzdata]
 version = "0.1.1"
 optional = true
 
@@ -151,4 +171,4 @@
 optional = true
 
 [target."cfg(windows)".dev-dependencies.windows-bindgen]
-version = "0.52"
+version = "0.58"
diff --git a/crates/chrono/METADATA b/crates/chrono/METADATA
index 0e90364..90d7590 100644
--- a/crates/chrono/METADATA
+++ b/crates/chrono/METADATA
@@ -1,17 +1,17 @@
 name: "chrono"
 description: "Date and time library for Rust"
 third_party {
-  version: "0.4.34"
+  version: "0.4.39"
   license_type: NOTICE
   last_upgrade_date {
     year: 2024
-    month: 2
-    day: 21
+    month: 12
+    day: 19
   }
   homepage: "https://crates.io/crates/chrono"
   identifier {
     type: "Archive"
-    value: "https://static.crates.io/crates/chrono/chrono-0.4.34.crate"
-    version: "0.4.34"
+    value: "https://static.crates.io/crates/chrono/chrono-0.4.39.crate"
+    version: "0.4.39"
   }
 }
diff --git a/crates/chrono/README.md b/crates/chrono/README.md
deleted file mode 100644
index 0558d88..0000000
--- a/crates/chrono/README.md
+++ /dev/null
@@ -1,83 +0,0 @@
-[Chrono][docsrs]: Timezone-aware date and time handling
-========================================
-
-[![Chrono GitHub Actions][gh-image]][gh-checks]
-[![Chrono on crates.io][cratesio-image]][cratesio]
-[![Chrono on docs.rs][docsrs-image]][docsrs]
-[![Chat][discord-image]][discord]
-[![codecov.io][codecov-img]][codecov-link]
-
-[gh-image]: https://github.com/chronotope/chrono/actions/workflows/test.yml/badge.svg?branch=main
-[gh-checks]: https://github.com/chronotope/chrono/actions/workflows/test.yml?query=branch%3Amain
-[cratesio-image]: https://img.shields.io/crates/v/chrono.svg
-[cratesio]: https://crates.io/crates/chrono
-[docsrs-image]: https://docs.rs/chrono/badge.svg
-[docsrs]: https://docs.rs/chrono
-[discord-image]: https://img.shields.io/discord/976380008299917365?logo=discord
-[discord]: https://discord.gg/sXpav4PS7M
-[codecov-img]: https://img.shields.io/codecov/c/github/chronotope/chrono?logo=codecov
-[codecov-link]: https://codecov.io/gh/chronotope/chrono
-
-Chrono aims to provide all functionality needed to do correct operations on dates and times in the
-[proleptic Gregorian calendar](https://en.wikipedia.org/wiki/Proleptic_Gregorian_calendar):
-
-* The [`DateTime`](https://docs.rs/chrono/latest/chrono/struct.DateTime.html) type is timezone-aware
-  by default, with separate timezone-naive types.
-* Operations that may produce an invalid or ambiguous date and time return `Option` or
-  [`LocalResult`](https://docs.rs/chrono/latest/chrono/offset/enum.LocalResult.html).
-* Configurable parsing and formatting with an `strftime` inspired date and time formatting syntax.
-* The [`Local`](https://docs.rs/chrono/latest/chrono/offset/struct.Local.html) timezone works with
-  the current timezone of the OS.
-* Types and operations are implemented to be reasonably efficient.
-
-Timezone data is not shipped with chrono by default to limit binary sizes. Use the companion crate
-[Chrono-TZ](https://crates.io/crates/chrono-tz) or [`tzfile`](https://crates.io/crates/tzfile) for
-full timezone support.
-
-## Documentation
-
-See [docs.rs](https://docs.rs/chrono/latest/chrono/) for the API reference.
-
-## Limitations
-
-* Only the proleptic Gregorian calendar (i.e. extended to support older dates) is supported.
-* Date types are limited to about +/- 262,000 years from the common epoch.
-* Time types are limited to nanosecond accuracy.
-* Leap seconds can be represented, but Chrono does not fully support them.
-  See [Leap Second Handling](https://docs.rs/chrono/latest/chrono/naive/struct.NaiveTime.html#leap-second-handling).
-
-## Crate features
-
-Default features:
-
-* `alloc`: Enable features that depend on allocation (primarily string formatting)
-* `std`: Enables functionality that depends on the standard library. This is a superset of `alloc`
-  and adds interoperation with standard library types and traits.
-* `clock`: Enables reading the local timezone (`Local`). This is a superset of `now`.
-* `now`: Enables reading the system time (`now`)
-* `wasmbind`: Interface with the JS Date API for the `wasm32` target.
-
-Optional features:
-
-* `serde`: Enable serialization/deserialization via serde.
-* `rkyv`: Enable serialization/deserialization via rkyv.
-* `rustc-serialize`: Enable serialization/deserialization via rustc-serialize (deprecated).
-* `arbitrary`: construct arbitrary instances of a type with the Arbitrary crate.
-* `unstable-locales`: Enable localization. This adds various methods with a `_localized` suffix.
-  The implementation and API may change or even be removed in a patch release. Feedback welcome.
-
-## Rust version requirements
-
-The Minimum Supported Rust Version (MSRV) is currently **Rust 1.61.0**.
-
-The MSRV is explicitly tested in CI. It may be bumped in minor releases, but this is not done
-lightly.
-
-## License
-
-This project is licensed under either of
-
-* [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0)
-* [MIT License](https://opensource.org/licenses/MIT)
-
-at your option.
diff --git a/crates/chrono/appveyor.yml b/crates/chrono/appveyor.yml
deleted file mode 100644
index 6057e85..0000000
--- a/crates/chrono/appveyor.yml
+++ /dev/null
@@ -1,12 +0,0 @@
-# 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/crates/chrono/deny.toml b/crates/chrono/deny.toml
deleted file mode 100644
index 186290e..0000000
--- a/crates/chrono/deny.toml
+++ /dev/null
@@ -1,11 +0,0 @@
-[licenses]
-allow-osi-fsf-free = "either"
-copyleft = "deny"
-
-[advisories]
-ignore = [
-  "RUSTSEC-2022-0004", # rustc_serialize, cannot remove due to compatibility
-]
-unmaintained = "deny"
-unsound = "deny"
-yanked = "deny"
diff --git a/crates/chrono/rustfmt.toml b/crates/chrono/rustfmt.toml
deleted file mode 100644
index 2a35f02..0000000
--- a/crates/chrono/rustfmt.toml
+++ /dev/null
@@ -1 +0,0 @@
-use_small_heuristics = "Max"
diff --git a/crates/chrono/src/datetime/mod.rs b/crates/chrono/src/datetime/mod.rs
index e4e460b..db91561 100644
--- a/crates/chrono/src/datetime/mod.rs
+++ b/crates/chrono/src/datetime/mod.rs
@@ -3,7 +3,7 @@
 
 //! ISO 8601 date and time with time zone.
 
-#[cfg(all(not(feature = "std"), feature = "alloc"))]
+#[cfg(all(feature = "alloc", not(feature = "std"), not(test)))]
 use alloc::string::String;
 use core::borrow::Borrow;
 use core::cmp::Ordering;
@@ -25,18 +25,15 @@
 use crate::naive::{Days, IsoWeek, NaiveDate, NaiveDateTime, NaiveTime};
 #[cfg(feature = "clock")]
 use crate::offset::Local;
-use crate::offset::{FixedOffset, Offset, TimeZone, Utc};
-use crate::try_opt;
+use crate::offset::{FixedOffset, LocalResult, Offset, TimeZone, Utc};
 #[allow(deprecated)]
 use crate::Date;
+use crate::{expect, try_opt};
 use crate::{Datelike, Months, TimeDelta, Timelike, Weekday};
 
 #[cfg(any(feature = "rkyv", feature = "rkyv-16", feature = "rkyv-32", feature = "rkyv-64"))]
 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;
@@ -79,9 +76,9 @@
     ///
     /// # Example
     ///
-    #[cfg_attr(not(feature = "clock"), doc = "```ignore")]
-    #[cfg_attr(feature = "clock", doc = "```rust")]
-    /// use chrono::{Local, DateTime};
+    /// ```
+    /// # #[cfg(feature = "clock")] {
+    /// use chrono::{DateTime, Local};
     ///
     /// let dt = Local::now();
     /// // Get components
@@ -90,6 +87,7 @@
     /// // Serialize, pass through FFI... and recreate the `DateTime`:
     /// let dt_new = DateTime::<Local>::from_naive_utc_and_offset(naive_utc, offset);
     /// assert_eq!(dt, dt_new);
+    /// # }
     /// ```
     #[inline]
     #[must_use]
@@ -166,14 +164,14 @@
     /// 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();
+    /// 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]
     #[must_use]
     pub fn date_naive(&self) -> NaiveDate {
-        let local = self.naive_local();
-        NaiveDate::from_ymd_opt(local.year(), local.month(), local.day()).unwrap()
+        self.naive_local().date()
     }
 
     /// Retrieves the time component.
@@ -200,7 +198,9 @@
     #[inline]
     #[must_use]
     pub const fn timestamp(&self) -> i64 {
-        self.datetime.timestamp()
+        let gregorian_day = self.datetime.date().num_days_from_ce() as i64;
+        let seconds_from_midnight = self.datetime.time().num_seconds_from_midnight() as i64;
+        (gregorian_day - UNIX_EPOCH_DAY) * 86_400 + seconds_from_midnight
     }
 
     /// Returns the number of non-leap-milliseconds since January 1, 1970 UTC.
@@ -208,18 +208,29 @@
     /// # Example
     ///
     /// ```
-    /// use chrono::{Utc, NaiveDate};
+    /// use chrono::{NaiveDate, Utc};
     ///
-    /// let dt = NaiveDate::from_ymd_opt(1970, 1, 1).unwrap().and_hms_milli_opt(0, 0, 1, 444).unwrap().and_local_timezone(Utc).unwrap();
+    /// 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();
+    /// 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]
     #[must_use]
     pub const fn timestamp_millis(&self) -> i64 {
-        self.datetime.timestamp_millis()
+        let as_ms = self.timestamp() * 1000;
+        as_ms + self.timestamp_subsec_millis() as i64
     }
 
     /// Returns the number of non-leap-microseconds since January 1, 1970 UTC.
@@ -227,18 +238,29 @@
     /// # Example
     ///
     /// ```
-    /// use chrono::{Utc, NaiveDate};
+    /// use chrono::{NaiveDate, Utc};
     ///
-    /// let dt = NaiveDate::from_ymd_opt(1970, 1, 1).unwrap().and_hms_micro_opt(0, 0, 1, 444).unwrap().and_local_timezone(Utc).unwrap();
+    /// 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();
+    /// 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]
     #[must_use]
     pub const fn timestamp_micros(&self) -> i64 {
-        self.datetime.timestamp_micros()
+        let as_us = self.timestamp() * 1_000_000;
+        as_us + self.timestamp_subsec_micros() as i64
     }
 
     /// Returns the number of non-leap-nanoseconds since January 1, 1970 UTC.
@@ -253,9 +275,11 @@
     #[deprecated(since = "0.4.31", note = "use `timestamp_nanos_opt()` instead")]
     #[inline]
     #[must_use]
-    #[allow(deprecated)]
     pub const fn timestamp_nanos(&self) -> i64 {
-        self.datetime.timestamp_nanos()
+        expect(
+            self.timestamp_nanos_opt(),
+            "value can not be represented in a timestamp with nanosecond precision.",
+        )
     }
 
     /// Returns the number of non-leap-nanoseconds since January 1, 1970 UTC.
@@ -271,30 +295,72 @@
     /// # Example
     ///
     /// ```
-    /// use chrono::{Utc, NaiveDate};
+    /// use chrono::{NaiveDate, Utc};
     ///
-    /// let dt = NaiveDate::from_ymd_opt(1970, 1, 1).unwrap().and_hms_nano_opt(0, 0, 1, 444).unwrap().and_local_timezone(Utc).unwrap();
+    /// 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_opt(), Some(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();
+    /// 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_opt(), Some(1_000_000_000_000_000_555));
     ///
-    /// let dt = NaiveDate::from_ymd_opt(1677, 9, 21).unwrap().and_hms_nano_opt(0, 12, 43, 145_224_192).unwrap().and_local_timezone(Utc).unwrap();
+    /// let dt = NaiveDate::from_ymd_opt(1677, 9, 21)
+    ///     .unwrap()
+    ///     .and_hms_nano_opt(0, 12, 43, 145_224_192)
+    ///     .unwrap()
+    ///     .and_local_timezone(Utc)
+    ///     .unwrap();
     /// assert_eq!(dt.timestamp_nanos_opt(), Some(-9_223_372_036_854_775_808));
     ///
-    /// let dt = NaiveDate::from_ymd_opt(2262, 4, 11).unwrap().and_hms_nano_opt(23, 47, 16, 854_775_807).unwrap().and_local_timezone(Utc).unwrap();
+    /// let dt = NaiveDate::from_ymd_opt(2262, 4, 11)
+    ///     .unwrap()
+    ///     .and_hms_nano_opt(23, 47, 16, 854_775_807)
+    ///     .unwrap()
+    ///     .and_local_timezone(Utc)
+    ///     .unwrap();
     /// assert_eq!(dt.timestamp_nanos_opt(), Some(9_223_372_036_854_775_807));
     ///
-    /// let dt = NaiveDate::from_ymd_opt(1677, 9, 21).unwrap().and_hms_nano_opt(0, 12, 43, 145_224_191).unwrap().and_local_timezone(Utc).unwrap();
+    /// let dt = NaiveDate::from_ymd_opt(1677, 9, 21)
+    ///     .unwrap()
+    ///     .and_hms_nano_opt(0, 12, 43, 145_224_191)
+    ///     .unwrap()
+    ///     .and_local_timezone(Utc)
+    ///     .unwrap();
     /// assert_eq!(dt.timestamp_nanos_opt(), None);
     ///
-    /// let dt = NaiveDate::from_ymd_opt(2262, 4, 11).unwrap().and_hms_nano_opt(23, 47, 16, 854_775_808).unwrap().and_local_timezone(Utc).unwrap();
+    /// let dt = NaiveDate::from_ymd_opt(2262, 4, 11)
+    ///     .unwrap()
+    ///     .and_hms_nano_opt(23, 47, 16, 854_775_808)
+    ///     .unwrap()
+    ///     .and_local_timezone(Utc)
+    ///     .unwrap();
     /// assert_eq!(dt.timestamp_nanos_opt(), None);
     /// ```
     #[inline]
     #[must_use]
     pub const fn timestamp_nanos_opt(&self) -> Option<i64> {
-        self.datetime.timestamp_nanos_opt()
+        let mut timestamp = self.timestamp();
+        let mut subsec_nanos = self.timestamp_subsec_nanos() as i64;
+        // `(timestamp * 1_000_000_000) + subsec_nanos` may create a temporary that underflows while
+        // the final value can be represented as an `i64`.
+        // As workaround we converting the negative case to:
+        // `((timestamp + 1) * 1_000_000_000) + (ns - 1_000_000_000)``
+        //
+        // Also see <https://github.com/chronotope/chrono/issues/1289>.
+        if timestamp < 0 {
+            subsec_nanos -= 1_000_000_000;
+            timestamp += 1;
+        }
+        try_opt!(timestamp.checked_mul(1_000_000_000)).checked_add(subsec_nanos)
     }
 
     /// Returns the number of milliseconds since the last second boundary.
@@ -303,7 +369,7 @@
     #[inline]
     #[must_use]
     pub const fn timestamp_subsec_millis(&self) -> u32 {
-        self.datetime.timestamp_subsec_millis()
+        self.timestamp_subsec_nanos() / 1_000_000
     }
 
     /// Returns the number of microseconds since the last second boundary.
@@ -312,7 +378,7 @@
     #[inline]
     #[must_use]
     pub const fn timestamp_subsec_micros(&self) -> u32 {
-        self.datetime.timestamp_subsec_micros()
+        self.timestamp_subsec_nanos() / 1_000
     }
 
     /// Returns the number of nanoseconds since the last second boundary
@@ -321,7 +387,7 @@
     #[inline]
     #[must_use]
     pub const fn timestamp_subsec_nanos(&self) -> u32 {
-        self.datetime.timestamp_subsec_nanos()
+        self.datetime.time().nanosecond()
     }
 
     /// Retrieves an associated offset from UTC.
@@ -385,13 +451,17 @@
     /// # Errors
     ///
     /// Returns `None` if:
-    /// - The resulting date would be out of range.
     /// - The local time at the resulting date does not exist or is ambiguous, for example during a
     ///   daylight saving time transition.
+    /// - The resulting UTC datetime would be out of range.
+    /// - The resulting local datetime would be out of range (unless `months` is zero).
     #[must_use]
-    pub fn checked_add_months(self, rhs: Months) -> Option<DateTime<Tz>> {
-        self.naive_local()
-            .checked_add_months(rhs)?
+    pub fn checked_add_months(self, months: Months) -> Option<DateTime<Tz>> {
+        // `NaiveDate::checked_add_months` has a fast path for `Months(0)` that does not validate
+        // the resulting date, with which we can return `Some` even for an out of range local
+        // datetime.
+        self.overflowing_naive_local()
+            .checked_add_months(months)?
             .and_local_timezone(Tz::from_offset(&self.offset))
             .single()
     }
@@ -418,13 +488,17 @@
     /// # Errors
     ///
     /// Returns `None` if:
-    /// - The resulting date would be out of range.
     /// - The local time at the resulting date does not exist or is ambiguous, for example during a
     ///   daylight saving time transition.
+    /// - The resulting UTC datetime would be out of range.
+    /// - The resulting local datetime would be out of range (unless `months` is zero).
     #[must_use]
-    pub fn checked_sub_months(self, rhs: Months) -> Option<DateTime<Tz>> {
-        self.naive_local()
-            .checked_sub_months(rhs)?
+    pub fn checked_sub_months(self, months: Months) -> Option<DateTime<Tz>> {
+        // `NaiveDate::checked_sub_months` has a fast path for `Months(0)` that does not validate
+        // the resulting date, with which we can return `Some` even for an out of range local
+        // datetime.
+        self.overflowing_naive_local()
+            .checked_sub_months(months)?
             .and_local_timezone(Tz::from_offset(&self.offset))
             .single()
     }
@@ -434,15 +508,22 @@
     /// # Errors
     ///
     /// Returns `None` if:
-    /// - The resulting date would be out of range.
     /// - The local time at the resulting date does not exist or is ambiguous, for example during a
     ///   daylight saving time transition.
+    /// - The resulting UTC datetime would be out of range.
+    /// - The resulting local datetime would be out of range (unless `days` is zero).
     #[must_use]
     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()
+        if days == Days::new(0) {
+            return Some(self);
+        }
+        // `NaiveDate::add_days` has a fast path if the result remains within the same year, that
+        // does not validate the resulting date. This allows us to return `Some` even for an out of
+        // range local datetime when adding `Days(0)`.
+        self.overflowing_naive_local()
+            .checked_add_days(days)
+            .and_then(|dt| self.timezone().from_local_datetime(&dt).single())
+            .filter(|dt| dt <= &DateTime::<Utc>::MAX_UTC)
     }
 
     /// Subtract a duration in [`Days`] from the date part of the `DateTime`.
@@ -450,15 +531,19 @@
     /// # Errors
     ///
     /// Returns `None` if:
-    /// - The resulting date would be out of range.
     /// - The local time at the resulting date does not exist or is ambiguous, for example during a
     ///   daylight saving time transition.
+    /// - The resulting UTC datetime would be out of range.
+    /// - The resulting local datetime would be out of range (unless `days` is zero).
     #[must_use]
     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()
+        // `NaiveDate::add_days` has a fast path if the result remains within the same year, that
+        // does not validate the resulting date. This allows us to return `Some` even for an out of
+        // range local datetime when adding `Days(0)`.
+        self.overflowing_naive_local()
+            .checked_sub_days(days)
+            .and_then(|dt| self.timezone().from_local_datetime(&dt).single())
+            .filter(|dt| dt >= &DateTime::<Utc>::MIN_UTC)
     }
 
     /// Subtracts another `DateTime` from the current date and time.
@@ -509,7 +594,7 @@
     ///
     /// # Errors
     ///
-    /// Returns `None` if `base < self`.
+    /// Returns `None` if `base > self`.
     #[must_use]
     pub fn years_since(&self, base: Self) -> Option<u32> {
         let mut years = self.year() - base.year();
@@ -565,19 +650,26 @@
     /// # Examples
     ///
     /// ```rust
-    /// # use chrono::{FixedOffset, SecondsFormat, TimeZone, Utc, NaiveDate};
-    /// let dt = NaiveDate::from_ymd_opt(2018, 1, 26).unwrap().and_hms_micro_opt(18, 30, 9, 453_829).unwrap().and_local_timezone(Utc).unwrap();
-    /// assert_eq!(dt.to_rfc3339_opts(SecondsFormat::Millis, false),
-    ///            "2018-01-26T18:30:09.453+00:00");
-    /// 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");
+    /// # use chrono::{FixedOffset, SecondsFormat, TimeZone, NaiveDate};
+    /// let dt = NaiveDate::from_ymd_opt(2018, 1, 26)
+    ///     .unwrap()
+    ///     .and_hms_micro_opt(18, 30, 9, 453_829)
+    ///     .unwrap()
+    ///     .and_utc();
+    /// 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");
+    /// 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(feature = "alloc")]
     #[must_use]
@@ -588,6 +680,32 @@
         result
     }
 
+    /// Set the time to a new fixed time on the existing date.
+    ///
+    /// # Errors
+    ///
+    /// Returns `LocalResult::None` if the datetime is at the edge of the representable range for a
+    /// `DateTime`, and `with_time` would push the value in UTC out of range.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// # #[cfg(feature = "clock")] {
+    /// use chrono::{Local, NaiveTime};
+    ///
+    /// let noon = NaiveTime::from_hms_opt(12, 0, 0).unwrap();
+    /// let today_noon = Local::now().with_time(noon);
+    /// let today_midnight = Local::now().with_time(NaiveTime::MIN);
+    ///
+    /// assert_eq!(today_noon.single().unwrap().time(), noon);
+    /// assert_eq!(today_midnight.single().unwrap().time(), NaiveTime::MIN);
+    /// # }
+    /// ```
+    #[must_use]
+    pub fn with_time(&self, time: NaiveTime) -> LocalResult<Self> {
+        self.timezone().from_local_datetime(&self.overflowing_naive_local().date().and_time(time))
+    }
+
     /// The minimum possible `DateTime<Utc>`.
     pub const MIN_UTC: DateTime<Utc> = DateTime { datetime: NaiveDateTime::MIN, offset: Utc };
     /// The maximum possible `DateTime<Utc>`.
@@ -595,7 +713,7 @@
 }
 
 impl DateTime<Utc> {
-    /// Makes a new [`DateTime<Utc>`] from the number of non-leap seconds
+    /// Makes a new `DateTime<Utc>` from the number of non-leap seconds
     /// since January 1, 1970 0:00:00 UTC (aka "UNIX timestamp")
     /// and the number of nanoseconds since the last whole non-leap second.
     ///
@@ -617,9 +735,9 @@
     /// # Example
     ///
     /// ```
-    /// use chrono::{DateTime, Utc};
+    /// use chrono::DateTime;
     ///
-    /// let dt: DateTime<Utc> = DateTime::<Utc>::from_timestamp(1431648000, 0).expect("invalid timestamp");
+    /// let dt = DateTime::from_timestamp(1431648000, 0).expect("invalid timestamp");
     ///
     /// assert_eq!(dt.to_string(), "2015-05-15 00:00:00 UTC");
     /// assert_eq!(DateTime::from_timestamp(dt.timestamp(), dt.timestamp_subsec_nanos()).unwrap(), dt);
@@ -627,16 +745,20 @@
     #[inline]
     #[must_use]
     pub const fn from_timestamp(secs: i64, nsecs: u32) -> Option<Self> {
-        Some(DateTime {
-            datetime: try_opt!(NaiveDateTime::from_timestamp_opt(secs, nsecs)),
-            offset: Utc,
-        })
+        let days = secs.div_euclid(86_400) + UNIX_EPOCH_DAY;
+        let secs = secs.rem_euclid(86_400);
+        if days < i32::MIN as i64 || days > i32::MAX as i64 {
+            return None;
+        }
+        let date = try_opt!(NaiveDate::from_num_days_from_ce_opt(days as i32));
+        let time = try_opt!(NaiveTime::from_num_seconds_from_midnight_opt(secs as u32, nsecs));
+        Some(date.and_time(time).and_utc())
     }
 
-    /// Makes a new [`DateTime<Utc>`] from the number of non-leap milliseconds
+    /// Makes a new `DateTime<Utc>` from the number of non-leap milliseconds
     /// since January 1, 1970 0:00:00.000 UTC (aka "UNIX timestamp").
     ///
-    /// This is guaranteed to round-trip with regard to [`timestamp_millis`](DateTime::timestamp_millis).
+    /// This is guaranteed to round-trip with [`timestamp_millis`](DateTime::timestamp_millis).
     ///
     /// If you need to create a `DateTime` with a [`TimeZone`] different from [`Utc`], use
     /// [`TimeZone::timestamp_millis_opt`] or [`DateTime::with_timezone`].
@@ -648,9 +770,9 @@
     /// # Example
     ///
     /// ```
-    /// use chrono::{DateTime, Utc};
+    /// use chrono::DateTime;
     ///
-    /// let dt: DateTime<Utc> = DateTime::<Utc>::from_timestamp_millis(947638923004).expect("invalid timestamp");
+    /// let dt = DateTime::from_timestamp_millis(947638923004).expect("invalid timestamp");
     ///
     /// assert_eq!(dt.to_string(), "2000-01-12 01:02:03.004 UTC");
     /// assert_eq!(DateTime::from_timestamp_millis(dt.timestamp_millis()).unwrap(), dt);
@@ -658,7 +780,81 @@
     #[inline]
     #[must_use]
     pub const fn from_timestamp_millis(millis: i64) -> Option<Self> {
-        Some(try_opt!(NaiveDateTime::from_timestamp_millis(millis)).and_utc())
+        let secs = millis.div_euclid(1000);
+        let nsecs = millis.rem_euclid(1000) as u32 * 1_000_000;
+        Self::from_timestamp(secs, nsecs)
+    }
+
+    /// Creates a new `DateTime<Utc>` from the number of non-leap microseconds
+    /// since January 1, 1970 0:00:00.000 UTC (aka "UNIX timestamp").
+    ///
+    /// This is guaranteed to round-trip with [`timestamp_micros`](DateTime::timestamp_micros).
+    ///
+    /// If you need to create a `DateTime` with a [`TimeZone`] different from [`Utc`], use
+    /// [`TimeZone::timestamp_micros`] or [`DateTime::with_timezone`].
+    ///
+    /// # Errors
+    ///
+    /// Returns `None` if the number of microseconds would be out of range for a `NaiveDateTime`
+    /// (more than ca. 262,000 years away from common era)
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use chrono::DateTime;
+    ///
+    /// let timestamp_micros: i64 = 1662921288000000; // Sun, 11 Sep 2022 18:34:48 UTC
+    /// let dt = DateTime::from_timestamp_micros(timestamp_micros);
+    /// assert!(dt.is_some());
+    /// assert_eq!(timestamp_micros, dt.expect("invalid timestamp").timestamp_micros());
+    ///
+    /// // Negative timestamps (before the UNIX epoch) are supported as well.
+    /// let timestamp_micros: i64 = -2208936075000000; // Mon, 1 Jan 1900 14:38:45 UTC
+    /// let dt = DateTime::from_timestamp_micros(timestamp_micros);
+    /// assert!(dt.is_some());
+    /// assert_eq!(timestamp_micros, dt.expect("invalid timestamp").timestamp_micros());
+    /// ```
+    #[inline]
+    #[must_use]
+    pub const fn from_timestamp_micros(micros: i64) -> Option<Self> {
+        let secs = micros.div_euclid(1_000_000);
+        let nsecs = micros.rem_euclid(1_000_000) as u32 * 1000;
+        Self::from_timestamp(secs, nsecs)
+    }
+
+    /// Creates a new [`DateTime<Utc>`] from the number of non-leap nanoseconds
+    /// since January 1, 1970 0:00:00.000 UTC (aka "UNIX timestamp").
+    ///
+    /// This is guaranteed to round-trip with [`timestamp_nanos`](DateTime::timestamp_nanos).
+    ///
+    /// If you need to create a `DateTime` with a [`TimeZone`] different from [`Utc`], use
+    /// [`TimeZone::timestamp_nanos`] or [`DateTime::with_timezone`].
+    ///
+    /// The UNIX epoch starts on midnight, January 1, 1970, UTC.
+    ///
+    /// An `i64` with nanosecond precision can span a range of ~584 years. Because all values can
+    /// be represented as a `DateTime` this method never fails.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use chrono::DateTime;
+    ///
+    /// let timestamp_nanos: i64 = 1662921288_000_000_000; // Sun, 11 Sep 2022 18:34:48 UTC
+    /// let dt = DateTime::from_timestamp_nanos(timestamp_nanos);
+    /// assert_eq!(timestamp_nanos, dt.timestamp_nanos_opt().unwrap());
+    ///
+    /// // Negative timestamps (before the UNIX epoch) are supported as well.
+    /// let timestamp_nanos: i64 = -2208936075_000_000_000; // Mon, 1 Jan 1900 14:38:45 UTC
+    /// let dt = DateTime::from_timestamp_nanos(timestamp_nanos);
+    /// assert_eq!(timestamp_nanos, dt.timestamp_nanos_opt().unwrap());
+    /// ```
+    #[inline]
+    #[must_use]
+    pub const fn from_timestamp_nanos(nanos: i64) -> Self {
+        let secs = nanos.div_euclid(1_000_000_000);
+        let nsecs = nanos.rem_euclid(1_000_000_000) as u32;
+        expect(Self::from_timestamp(secs, nsecs), "timestamp in nanos is always in range")
     }
 
     /// The Unix Epoch, 1970-01-01 00:00:00 UTC.
@@ -831,17 +1027,27 @@
     /// for a version that does not require a timezone in the to-be-parsed str. The returned
     /// [`DateTime`] value will have a [`FixedOffset`] reflecting the parsed timezone.
     ///
-    /// See the [`format::strftime` module](./format/strftime/index.html) for supported format
+    /// See the [`format::strftime` module](crate::format::strftime) for supported format
     /// sequences.
     ///
     /// # Example
     ///
     /// ```rust
-    /// use chrono::{DateTime, FixedOffset, TimeZone, NaiveDate};
+    /// use chrono::{DateTime, FixedOffset, NaiveDate, 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_opt(0).unwrap().from_local_datetime(&NaiveDate::from_ymd_opt(1983, 4, 13).unwrap().and_hms_milli_opt(12, 9, 14, 274).unwrap()).unwrap()));
+    /// 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();
@@ -867,10 +1073,13 @@
     /// ```rust
     /// # use chrono::{DateTime, FixedOffset, TimeZone};
     /// let (datetime, remainder) = DateTime::parse_and_remainder(
-    ///     "2015-02-18 23:16:09 +0200 trailing text", "%Y-%m-%d %H:%M:%S %z").unwrap();
+    ///     "2015-02-18 23:16:09 +0200 trailing text",
+    ///     "%Y-%m-%d %H:%M:%S %z",
+    /// )
+    /// .unwrap();
     /// assert_eq!(
     ///     datetime,
-    ///     FixedOffset::east_opt(2*3600).unwrap().with_ymd_and_hms(2015, 2, 18, 23, 16, 9).unwrap()
+    ///     FixedOffset::east_opt(2 * 3600).unwrap().with_ymd_and_hms(2015, 2, 18, 23, 16, 9).unwrap()
     /// );
     /// assert_eq!(remainder, " trailing text");
     /// ```
@@ -1006,22 +1215,28 @@
     /// # Errors
     ///
     /// Returns `None` if:
-    /// - The resulting date does not exist.
-    /// - When the `NaiveDateTime` would be out of range.
+    /// - The resulting date does not exist (February 29 in a non-leap year).
     /// - The local time at the resulting date does not exist or is ambiguous, for example during a
     ///   daylight saving time transition.
+    /// - The resulting UTC datetime would be out of range.
+    /// - The resulting local datetime would be out of range (unless the year remains the same).
     fn with_year(&self, year: i32) -> Option<DateTime<Tz>> {
-        map_local(self, |datetime| datetime.with_year(year))
+        map_local(self, |dt| match dt.year() == year {
+            true => Some(dt),
+            false => dt.with_year(year),
+        })
     }
 
     /// Makes a new `DateTime` with the month number (starting from 1) changed.
     ///
+    /// Don't combine multiple `Datelike::with_*` methods. The intermediate value may not exist.
+    ///
     /// See also the [`NaiveDate::with_month`] method.
     ///
     /// # Errors
     ///
     /// Returns `None` if:
-    /// - The resulting date does not exist.
+    /// - The resulting date does not exist (for example `month(4)` when day of the month is 31).
     /// - The value for `month` is invalid.
     /// - The local time at the resulting date does not exist or is ambiguous, for example during a
     ///   daylight saving time transition.
@@ -1037,7 +1252,7 @@
     /// # Errors
     ///
     /// Returns `None` if:
-    /// - The resulting date does not exist.
+    /// - The resulting date does not exist (for example `month0(3)` when day of the month is 31).
     /// - The value for `month0` is invalid.
     /// - The local time at the resulting date does not exist or is ambiguous, for example during a
     ///   daylight saving time transition.
@@ -1053,7 +1268,7 @@
     /// # Errors
     ///
     /// Returns `None` if:
-    /// - The resulting date does not exist.
+    /// - The resulting date does not exist (for example `day(31)` in April).
     /// - The value for `day` is invalid.
     /// - The local time at the resulting date does not exist or is ambiguous, for example during a
     ///   daylight saving time transition.
@@ -1069,7 +1284,7 @@
     /// # Errors
     ///
     /// Returns `None` if:
-    /// - The resulting date does not exist.
+    /// - The resulting date does not exist (for example `day(30)` in April).
     /// - The value for `day0` is invalid.
     /// - The local time at the resulting date does not exist or is ambiguous, for example during a
     ///   daylight saving time transition.
@@ -1085,7 +1300,7 @@
     /// # Errors
     ///
     /// Returns `None` if:
-    /// - The resulting date does not exist.
+    /// - The resulting date does not exist (`with_ordinal(366)` in a non-leap year).
     /// - The value for `ordinal` is invalid.
     /// - The local time at the resulting date does not exist or is ambiguous, for example during a
     ///   daylight saving time transition.
@@ -1101,7 +1316,7 @@
     /// # Errors
     ///
     /// Returns `None` if:
-    /// - The resulting date does not exist.
+    /// - The resulting date does not exist (`with_ordinal0(365)` in a non-leap year).
     /// - The value for `ordinal0` is invalid.
     /// - The local time at the resulting date does not exist or is ambiguous, for example during a
     ///   daylight saving time transition.
@@ -1193,9 +1408,14 @@
     }
 }
 
-// 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 {}
+// We don't store a field with the `Tz` type, so it doesn't need to influence whether `DateTime` can
+// be `Copy`. Implement it manually if the two types we do have are `Copy`.
+impl<Tz: TimeZone> Copy for DateTime<Tz>
+where
+    <Tz as TimeZone>::Offset: Copy,
+    NaiveDateTime: Copy,
+{
+}
 
 impl<Tz: TimeZone, Tz2: TimeZone> PartialEq<DateTime<Tz2>> for DateTime<Tz> {
     fn eq(&self, other: &DateTime<Tz2>) -> bool {
@@ -1213,8 +1433,14 @@
     /// ```
     /// 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());
+    /// 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");
@@ -1501,7 +1727,7 @@
 /// - The local time at the resulting date does not exist or is ambiguous, for example during a
 ///   daylight saving time transition.
 ///
-/// Strongly consider using `DateTime<Tz>::checked_sub_days` to get an `Option` instead.
+/// Strongly consider using `DateTime<Tz>::checked_add_days` to get an `Option` instead.
 impl<Tz: TimeZone> Add<Days> for DateTime<Tz> {
     type Output = DateTime<Tz>;
 
@@ -1707,135 +1933,12 @@
     }
 }
 
-#[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(),
-        // An offset with seconds is not allowed by RFC 3339, so we round it to the nearest minute.
-        // In this case `+01:00:50` becomes `+01:01`
-        Some(r#""2014-07-24T12:34:06+01:01""#.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 should 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()
-    );
-}
+/// Number of days between Januari 1, 1970 and December 31, 1 BCE which we define to be day 0.
+/// 4 full leap year cycles until December 31, 1600     4 * 146097 = 584388
+/// 1 day until January 1, 1601                                           1
+/// 369 years until Januari 1, 1970                      369 * 365 = 134685
+/// of which floor(369 / 4) are leap years          floor(369 / 4) =     92
+/// except for 1700, 1800 and 1900                                       -3 +
+///                                                                  --------
+///                                                                  719163
+const UNIX_EPOCH_DAY: i64 = 719_163;
diff --git a/crates/chrono/src/datetime/rustc_serialize.rs b/crates/chrono/src/datetime/rustc_serialize.rs
deleted file mode 100644
index f704b2f..0000000
--- a/crates/chrono/src/datetime/rustc_serialize.rs
+++ /dev/null
@@ -1,124 +0,0 @@
-use super::DateTime;
-use crate::format::SecondsFormat;
-#[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> {
-        self.to_rfc3339_opts(SecondsFormat::AutoSi, true).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")]
-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)]
-mod tests {
-    use crate::datetime::test_encodable_json;
-    use crate::datetime::{test_decodable_json, test_decodable_json_timestamps};
-    use rustc_serialize::json;
-
-    #[test]
-    fn test_encodable() {
-        test_encodable_json(json::encode, json::encode);
-    }
-
-    #[cfg(feature = "clock")]
-    #[test]
-    fn test_decodable() {
-        test_decodable_json(json::decode, json::decode, json::decode);
-    }
-
-    #[cfg(feature = "clock")]
-    #[test]
-    fn test_decodable_timestamps() {
-        test_decodable_json_timestamps(json::decode, json::decode, json::decode);
-    }
-}
diff --git a/crates/chrono/src/datetime/serde.rs b/crates/chrono/src/datetime/serde.rs
index dcdb36d..e3c6bf5 100644
--- a/crates/chrono/src/datetime/serde.rs
+++ b/crates/chrono/src/datetime/serde.rs
@@ -3,7 +3,6 @@
 
 use super::DateTime;
 use crate::format::{write_rfc3339, SecondsFormat};
-use crate::naive::datetime::serde::serde_from;
 #[cfg(feature = "clock")]
 use crate::offset::Local;
 use crate::offset::{FixedOffset, Offset, TimeZone, Utc};
@@ -24,10 +23,12 @@
 #[derive(Debug)]
 pub struct MilliSecondsTimestampVisitor;
 
-/// Serialize into an ISO 8601 formatted string.
+/// Serialize to an RFC 3339 formatted string
 ///
-/// See [the `serde` module](./serde/index.html) for alternate
-/// serializations.
+/// As an extension to RFC 3339 this can serialize `DateTime`s outside the range of 0-9999 years
+/// using an ISO 8601 syntax (which prepends an `-` or `+`).
+///
+/// See [the `serde` module](crate::serde) for alternate serializations.
 impl<Tz: TimeZone> ser::Serialize for DateTime<Tz> {
     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
     where
@@ -37,7 +38,7 @@
             inner: &'a DateTime<Tz>,
         }
 
-        impl<'a, Tz: TimeZone> fmt::Display for FormatIso8601<'a, Tz> {
+        impl<Tz: TimeZone> fmt::Display for FormatIso8601<'_, Tz> {
             fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                 let naive = self.inner.naive_local();
                 let offset = self.inner.offset.fix();
@@ -51,11 +52,11 @@
 
 struct DateTimeVisitor;
 
-impl<'de> de::Visitor<'de> for DateTimeVisitor {
+impl de::Visitor<'_> 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")
+        formatter.write_str("an RFC 3339 formatted date and time string")
     }
 
     fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
@@ -66,13 +67,12 @@
     }
 }
 
-/// Deserialize a value that optionally includes a timezone offset in its
-/// string representation
+/// Deserialize an RFC 3339 formatted string into a `DateTime<FixedOffset>`
 ///
-/// The value to be deserialized must be an rfc3339 string.
+/// As an extension to RFC 3339 this can deserialize to `DateTime`s outside the range of 0-9999
+/// years using an ISO 8601 syntax (which prepends an `-` or `+`).
 ///
-/// See [the `serde` module](./serde/index.html) for alternate
-/// deserialization formats.
+/// See [the `serde` module](crate::serde) for alternate deserialization formats.
 impl<'de> de::Deserialize<'de> for DateTime<FixedOffset> {
     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
     where
@@ -82,12 +82,14 @@
     }
 }
 
-/// Deserialize into a UTC value
+/// Deserialize an RFC 3339 formatted string into a `DateTime<Utc>`
 ///
-/// The value to be deserialized must be an rfc3339 string.
+/// If the value contains an offset from UTC that is not zero, the value will be converted to UTC.
 ///
-/// See [the `serde` module](./serde/index.html) for alternate
-/// deserialization formats.
+/// As an extension to RFC 3339 this can deserialize to `DateTime`s outside the range of 0-9999
+/// years using an ISO 8601 syntax (which prepends an `-` or `+`).
+///
+/// See [the `serde` module](crate::serde) for alternate deserialization formats.
 impl<'de> de::Deserialize<'de> for DateTime<Utc> {
     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
     where
@@ -97,13 +99,15 @@
     }
 }
 
-/// Deserialize a value that includes no timezone in its string
-/// representation
+/// Deserialize an RFC 3339 formatted string into a `DateTime<Local>`
 ///
-/// The value to be deserialized must be an rfc3339 string.
+/// The value will remain the same instant in UTC, but the offset will be recalculated to match
+/// that of the `Local` platform time zone.
 ///
-/// See [the `serde` module](./serde/index.html) for alternate
-/// serialization formats.
+/// As an extension to RFC 3339 this can deserialize to `DateTime`s outside the range of 0-9999
+/// years using an ISO 8601 syntax (which prepends an `-` or `+`).
+///
+/// See [the `serde` module](crate::serde) for alternate deserialization formats.
 #[cfg(feature = "clock")]
 impl<'de> de::Deserialize<'de> for DateTime<Local> {
     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
@@ -127,13 +131,15 @@
 /// #[derive(Deserialize, Serialize)]
 /// struct S {
 ///     #[serde(with = "ts_nanoseconds")]
-///     time: DateTime<Utc>
+///     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 time = NaiveDate::from_ymd_opt(2018, 5, 17)
+///     .unwrap()
+///     .and_hms_nano_opt(02, 04, 59, 918355733)
+///     .unwrap()
+///     .and_utc();
+/// let my_s = S { time: time.clone() };
 ///
 /// let as_string = serde_json::to_string(&my_s)?;
 /// assert_eq!(as_string, r#"{"time":1526522699918355733}"#);
@@ -145,10 +151,10 @@
     use core::fmt;
     use serde::{de, ser};
 
-    use crate::offset::TimeZone;
+    use crate::serde::invalid_ts;
     use crate::{DateTime, Utc};
 
-    use super::{serde_from, NanoSecondsTimestampVisitor};
+    use super::NanoSecondsTimestampVisitor;
 
     /// Serialize a UTC datetime into an integer number of nanoseconds since the epoch
     ///
@@ -171,11 +177,15 @@
     /// #[derive(Serialize)]
     /// struct S {
     ///     #[serde(serialize_with = "to_nano_ts")]
-    ///     time: DateTime<Utc>
+    ///     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(),
+    ///     time: NaiveDate::from_ymd_opt(2018, 5, 17)
+    ///         .unwrap()
+    ///         .and_hms_nano_opt(02, 04, 59, 918355733)
+    ///         .unwrap()
+    ///         .and_utc(),
     /// };
     /// let as_string = serde_json::to_string(&my_s)?;
     /// assert_eq!(as_string, r#"{"time":1526522699918355733}"#);
@@ -203,7 +213,7 @@
     /// #[derive(Debug, PartialEq, Deserialize)]
     /// struct S {
     ///     #[serde(deserialize_with = "from_nano_ts")]
-    ///     time: DateTime<Utc>
+    ///     time: DateTime<Utc>,
     /// }
     ///
     /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918355733 }"#)?;
@@ -220,7 +230,7 @@
         d.deserialize_i64(NanoSecondsTimestampVisitor)
     }
 
-    impl<'de> de::Visitor<'de> for NanoSecondsTimestampVisitor {
+    impl de::Visitor<'_> for NanoSecondsTimestampVisitor {
         type Value = DateTime<Utc>;
 
         fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
@@ -232,13 +242,11 @@
         where
             E: de::Error,
         {
-            serde_from(
-                Utc.timestamp_opt(
-                    value.div_euclid(1_000_000_000),
-                    (value.rem_euclid(1_000_000_000)) as u32,
-                ),
-                &value,
+            DateTime::from_timestamp(
+                value.div_euclid(1_000_000_000),
+                (value.rem_euclid(1_000_000_000)) as u32,
             )
+            .ok_or_else(|| invalid_ts(value))
         }
 
         /// Deserialize a timestamp in nanoseconds since the epoch
@@ -246,10 +254,8 @@
         where
             E: de::Error,
         {
-            serde_from(
-                Utc.timestamp_opt((value / 1_000_000_000) as i64, (value % 1_000_000_000) as u32),
-                &value,
-            )
+            DateTime::from_timestamp((value / 1_000_000_000) as i64, (value % 1_000_000_000) as u32)
+                .ok_or_else(|| invalid_ts(value))
         }
     }
 }
@@ -267,13 +273,17 @@
 /// #[derive(Deserialize, Serialize)]
 /// struct S {
 ///     #[serde(with = "ts_nanoseconds_option")]
-///     time: Option<DateTime<Utc>>
+///     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 time = Some(
+///     NaiveDate::from_ymd_opt(2018, 5, 17)
+///         .unwrap()
+///         .and_hms_nano_opt(02, 04, 59, 918355733)
+///         .unwrap()
+///         .and_utc(),
+/// );
+/// let my_s = S { time: time.clone() };
 ///
 /// let as_string = serde_json::to_string(&my_s)?;
 /// assert_eq!(as_string, r#"{"time":1526522699918355733}"#);
@@ -310,11 +320,17 @@
     /// #[derive(Serialize)]
     /// struct S {
     ///     #[serde(serialize_with = "to_nano_tsopt")]
-    ///     time: Option<DateTime<Utc>>
+    ///     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()),
+    ///     time: Some(
+    ///         NaiveDate::from_ymd_opt(2018, 5, 17)
+    ///             .unwrap()
+    ///             .and_hms_nano_opt(02, 04, 59, 918355733)
+    ///             .unwrap()
+    ///             .and_utc(),
+    ///     ),
     /// };
     /// let as_string = serde_json::to_string(&my_s)?;
     /// assert_eq!(as_string, r#"{"time":1526522699918355733}"#);
@@ -345,7 +361,7 @@
     /// #[derive(Debug, PartialEq, Deserialize)]
     /// struct S {
     ///     #[serde(deserialize_with = "from_nano_tsopt")]
-    ///     time: Option<DateTime<Utc>>
+    ///     time: Option<DateTime<Utc>>,
     /// }
     ///
     /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918355733 }"#)?;
@@ -407,13 +423,15 @@
 /// #[derive(Deserialize, Serialize)]
 /// struct S {
 ///     #[serde(with = "ts_microseconds")]
-///     time: DateTime<Utc>
+///     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 time = NaiveDate::from_ymd_opt(2018, 5, 17)
+///     .unwrap()
+///     .and_hms_micro_opt(02, 04, 59, 918355)
+///     .unwrap()
+///     .and_utc();
+/// let my_s = S { time: time.clone() };
 ///
 /// let as_string = serde_json::to_string(&my_s)?;
 /// assert_eq!(as_string, r#"{"time":1526522699918355}"#);
@@ -425,10 +443,11 @@
     use core::fmt;
     use serde::{de, ser};
 
-    use super::{serde_from, MicroSecondsTimestampVisitor};
-    use crate::offset::TimeZone;
+    use crate::serde::invalid_ts;
     use crate::{DateTime, Utc};
 
+    use super::MicroSecondsTimestampVisitor;
+
     /// Serialize a UTC datetime into an integer number of microseconds since the epoch
     ///
     /// Intended for use with `serde`s `serialize_with` attribute.
@@ -442,11 +461,15 @@
     /// #[derive(Serialize)]
     /// struct S {
     ///     #[serde(serialize_with = "to_micro_ts")]
-    ///     time: DateTime<Utc>
+    ///     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(),
+    ///     time: NaiveDate::from_ymd_opt(2018, 5, 17)
+    ///         .unwrap()
+    ///         .and_hms_micro_opt(02, 04, 59, 918355)
+    ///         .unwrap()
+    ///         .and_utc(),
     /// };
     /// let as_string = serde_json::to_string(&my_s)?;
     /// assert_eq!(as_string, r#"{"time":1526522699918355}"#);
@@ -472,7 +495,7 @@
     /// #[derive(Debug, PartialEq, Deserialize)]
     /// struct S {
     ///     #[serde(deserialize_with = "from_micro_ts")]
-    ///     time: DateTime<Utc>
+    ///     time: DateTime<Utc>,
     /// }
     ///
     /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918355 }"#)?;
@@ -489,7 +512,7 @@
         d.deserialize_i64(MicroSecondsTimestampVisitor)
     }
 
-    impl<'de> de::Visitor<'de> for MicroSecondsTimestampVisitor {
+    impl de::Visitor<'_> for MicroSecondsTimestampVisitor {
         type Value = DateTime<Utc>;
 
         fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
@@ -501,13 +524,11 @@
         where
             E: de::Error,
         {
-            serde_from(
-                Utc.timestamp_opt(
-                    value.div_euclid(1_000_000),
-                    (value.rem_euclid(1_000_000) * 1_000) as u32,
-                ),
-                &value,
+            DateTime::from_timestamp(
+                value.div_euclid(1_000_000),
+                (value.rem_euclid(1_000_000) * 1000) as u32,
             )
+            .ok_or_else(|| invalid_ts(value))
         }
 
         /// Deserialize a timestamp in milliseconds since the epoch
@@ -515,10 +536,11 @@
         where
             E: de::Error,
         {
-            serde_from(
-                Utc.timestamp_opt((value / 1_000_000) as i64, ((value % 1_000_000) * 1_000) as u32),
-                &value,
+            DateTime::from_timestamp(
+                (value / 1_000_000) as i64,
+                ((value % 1_000_000) * 1_000) as u32,
             )
+            .ok_or_else(|| invalid_ts(value))
         }
     }
 }
@@ -536,13 +558,17 @@
 /// #[derive(Deserialize, Serialize)]
 /// struct S {
 ///     #[serde(with = "ts_microseconds_option")]
-///     time: Option<DateTime<Utc>>
+///     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 time = Some(
+///     NaiveDate::from_ymd_opt(2018, 5, 17)
+///         .unwrap()
+///         .and_hms_micro_opt(02, 04, 59, 918355)
+///         .unwrap()
+///         .and_utc(),
+/// );
+/// let my_s = S { time: time.clone() };
 ///
 /// let as_string = serde_json::to_string(&my_s)?;
 /// assert_eq!(as_string, r#"{"time":1526522699918355}"#);
@@ -570,11 +596,17 @@
     /// #[derive(Serialize)]
     /// struct S {
     ///     #[serde(serialize_with = "to_micro_tsopt")]
-    ///     time: Option<DateTime<Utc>>
+    ///     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()),
+    ///     time: Some(
+    ///         NaiveDate::from_ymd_opt(2018, 5, 17)
+    ///             .unwrap()
+    ///             .and_hms_micro_opt(02, 04, 59, 918355)
+    ///             .unwrap()
+    ///             .and_utc(),
+    ///     ),
     /// };
     /// let as_string = serde_json::to_string(&my_s)?;
     /// assert_eq!(as_string, r#"{"time":1526522699918355}"#);
@@ -603,7 +635,7 @@
     /// #[derive(Debug, PartialEq, Deserialize)]
     /// struct S {
     ///     #[serde(deserialize_with = "from_micro_tsopt")]
-    ///     time: Option<DateTime<Utc>>
+    ///     time: Option<DateTime<Utc>>,
     /// }
     ///
     /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918355 }"#)?;
@@ -665,13 +697,15 @@
 /// #[derive(Deserialize, Serialize)]
 /// struct S {
 ///     #[serde(with = "ts_milliseconds")]
-///     time: DateTime<Utc>
+///     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 time = NaiveDate::from_ymd_opt(2018, 5, 17)
+///     .unwrap()
+///     .and_hms_milli_opt(02, 04, 59, 918)
+///     .unwrap()
+///     .and_utc();
+/// let my_s = S { time: time.clone() };
 ///
 /// let as_string = serde_json::to_string(&my_s)?;
 /// assert_eq!(as_string, r#"{"time":1526522699918}"#);
@@ -683,10 +717,11 @@
     use core::fmt;
     use serde::{de, ser};
 
-    use super::{serde_from, MilliSecondsTimestampVisitor};
-    use crate::offset::TimeZone;
+    use crate::serde::invalid_ts;
     use crate::{DateTime, Utc};
 
+    use super::MilliSecondsTimestampVisitor;
+
     /// Serialize a UTC datetime into an integer number of milliseconds since the epoch
     ///
     /// Intended for use with `serde`s `serialize_with` attribute.
@@ -700,11 +735,15 @@
     /// #[derive(Serialize)]
     /// struct S {
     ///     #[serde(serialize_with = "to_milli_ts")]
-    ///     time: DateTime<Utc>
+    ///     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(),
+    ///     time: NaiveDate::from_ymd_opt(2018, 5, 17)
+    ///         .unwrap()
+    ///         .and_hms_milli_opt(02, 04, 59, 918)
+    ///         .unwrap()
+    ///         .and_utc(),
     /// };
     /// let as_string = serde_json::to_string(&my_s)?;
     /// assert_eq!(as_string, r#"{"time":1526522699918}"#);
@@ -730,7 +769,7 @@
     /// #[derive(Debug, PartialEq, Deserialize)]
     /// struct S {
     ///     #[serde(deserialize_with = "from_milli_ts")]
-    ///     time: DateTime<Utc>
+    ///     time: DateTime<Utc>,
     /// }
     ///
     /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918 }"#)?;
@@ -747,7 +786,7 @@
         d.deserialize_i64(MilliSecondsTimestampVisitor).map(|dt| dt.with_timezone(&Utc))
     }
 
-    impl<'de> de::Visitor<'de> for MilliSecondsTimestampVisitor {
+    impl de::Visitor<'_> for MilliSecondsTimestampVisitor {
         type Value = DateTime<Utc>;
 
         fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
@@ -759,7 +798,7 @@
         where
             E: de::Error,
         {
-            serde_from(Utc.timestamp_millis_opt(value), &value)
+            DateTime::from_timestamp_millis(value).ok_or_else(|| invalid_ts(value))
         }
 
         /// Deserialize a timestamp in milliseconds since the epoch
@@ -767,10 +806,8 @@
         where
             E: de::Error,
         {
-            serde_from(
-                Utc.timestamp_opt((value / 1000) as i64, ((value % 1000) * 1_000_000) as u32),
-                &value,
-            )
+            DateTime::from_timestamp((value / 1000) as i64, ((value % 1000) * 1_000_000) as u32)
+                .ok_or_else(|| invalid_ts(value))
         }
     }
 }
@@ -788,13 +825,17 @@
 /// #[derive(Deserialize, Serialize)]
 /// struct S {
 ///     #[serde(with = "ts_milliseconds_option")]
-///     time: Option<DateTime<Utc>>
+///     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 time = Some(
+///     NaiveDate::from_ymd_opt(2018, 5, 17)
+///         .unwrap()
+///         .and_hms_milli_opt(02, 04, 59, 918)
+///         .unwrap()
+///         .and_utc(),
+/// );
+/// let my_s = S { time: time.clone() };
 ///
 /// let as_string = serde_json::to_string(&my_s)?;
 /// assert_eq!(as_string, r#"{"time":1526522699918}"#);
@@ -822,11 +863,17 @@
     /// #[derive(Serialize)]
     /// struct S {
     ///     #[serde(serialize_with = "to_milli_tsopt")]
-    ///     time: Option<DateTime<Utc>>
+    ///     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()),
+    ///     time: Some(
+    ///         NaiveDate::from_ymd_opt(2018, 5, 17)
+    ///             .unwrap()
+    ///             .and_hms_milli_opt(02, 04, 59, 918)
+    ///             .unwrap()
+    ///             .and_utc(),
+    ///     ),
     /// };
     /// let as_string = serde_json::to_string(&my_s)?;
     /// assert_eq!(as_string, r#"{"time":1526522699918}"#);
@@ -862,7 +909,7 @@
     /// #[derive(Deserialize, PartialEq, Debug)]
     /// struct S {
     ///     #[serde(default, deserialize_with = "from_milli_tsopt")]
-    ///     time: Option<DateTime<Utc>>
+    ///     time: Option<DateTime<Utc>>,
     /// }
     ///
     /// let my_s: E<S> = serde_json::from_str(r#"{ "time": 1526522699918 }"#)?;
@@ -929,13 +976,11 @@
 /// #[derive(Deserialize, Serialize)]
 /// struct S {
 ///     #[serde(with = "ts_seconds")]
-///     time: DateTime<Utc>
+///     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 my_s = S { time: time.clone() };
 ///
 /// let as_string = serde_json::to_string(&my_s)?;
 /// assert_eq!(as_string, r#"{"time":1431684000}"#);
@@ -947,8 +992,10 @@
     use core::fmt;
     use serde::{de, ser};
 
-    use super::{serde_from, SecondsTimestampVisitor};
-    use crate::{DateTime, LocalResult, TimeZone, Utc};
+    use crate::serde::invalid_ts;
+    use crate::{DateTime, Utc};
+
+    use super::SecondsTimestampVisitor;
 
     /// Serialize a UTC datetime into an integer number of seconds since the epoch
     ///
@@ -963,12 +1010,10 @@
     /// #[derive(Serialize)]
     /// struct S {
     ///     #[serde(serialize_with = "to_ts")]
-    ///     time: DateTime<Utc>
+    ///     time: DateTime<Utc>,
     /// }
     ///
-    /// let my_s = S {
-    ///     time: Utc.with_ymd_and_hms(2015, 5, 15, 10, 0, 0).unwrap(),
-    /// };
+    /// 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>(())
@@ -993,7 +1038,7 @@
     /// #[derive(Debug, PartialEq, Deserialize)]
     /// struct S {
     ///     #[serde(deserialize_with = "from_ts")]
-    ///     time: DateTime<Utc>
+    ///     time: DateTime<Utc>,
     /// }
     ///
     /// let my_s: S = serde_json::from_str(r#"{ "time": 1431684000 }"#)?;
@@ -1007,7 +1052,7 @@
         d.deserialize_i64(SecondsTimestampVisitor)
     }
 
-    impl<'de> de::Visitor<'de> for SecondsTimestampVisitor {
+    impl de::Visitor<'_> for SecondsTimestampVisitor {
         type Value = DateTime<Utc>;
 
         fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
@@ -1019,7 +1064,7 @@
         where
             E: de::Error,
         {
-            serde_from(Utc.timestamp_opt(value, 0), &value)
+            DateTime::from_timestamp(value, 0).ok_or_else(|| invalid_ts(value))
         }
 
         /// Deserialize a timestamp in seconds since the epoch
@@ -1027,14 +1072,11 @@
         where
             E: de::Error,
         {
-            serde_from(
-                if value > i64::MAX as u64 {
-                    LocalResult::None
-                } else {
-                    Utc.timestamp_opt(value as i64, 0)
-                },
-                &value,
-            )
+            if value > i64::MAX as u64 {
+                Err(invalid_ts(value))
+            } else {
+                DateTime::from_timestamp(value as i64, 0).ok_or_else(|| invalid_ts(value))
+            }
         }
     }
 }
@@ -1052,13 +1094,11 @@
 /// #[derive(Deserialize, Serialize)]
 /// struct S {
 ///     #[serde(with = "ts_seconds_option")]
-///     time: Option<DateTime<Utc>>
+///     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 my_s = S { time: time.clone() };
 ///
 /// let as_string = serde_json::to_string(&my_s)?;
 /// assert_eq!(as_string, r#"{"time":1431684000}"#);
@@ -1086,12 +1126,10 @@
     /// #[derive(Serialize)]
     /// struct S {
     ///     #[serde(serialize_with = "to_tsopt")]
-    ///     time: Option<DateTime<Utc>>
+    ///     time: Option<DateTime<Utc>>,
     /// }
     ///
-    /// let my_s = S {
-    ///     time: Some(Utc.with_ymd_and_hms(2015, 5, 15, 10, 0, 0).unwrap()),
-    /// };
+    /// 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>(())
@@ -1119,7 +1157,7 @@
     /// #[derive(Debug, PartialEq, Deserialize)]
     /// struct S {
     ///     #[serde(deserialize_with = "from_tsopt")]
-    ///     time: Option<DateTime<Utc>>
+    ///     time: Option<DateTime<Utc>>,
     /// }
     ///
     /// let my_s: S = serde_json::from_str(r#"{ "time": 1431684000 }"#)?;
@@ -1171,24 +1209,87 @@
 #[cfg(test)]
 mod tests {
     #[cfg(feature = "clock")]
-    use crate::datetime::test_decodable_json;
-    use crate::datetime::test_encodable_json;
+    use crate::Local;
     use crate::{DateTime, FixedOffset, TimeZone, Utc};
     use core::fmt;
 
     #[test]
     fn test_serde_serialize() {
-        test_encodable_json(serde_json::to_string, serde_json::to_string);
+        assert_eq!(
+            serde_json::to_string(&Utc.with_ymd_and_hms(2014, 7, 24, 12, 34, 6).unwrap()).ok(),
+            Some(r#""2014-07-24T12:34:06Z""#.to_owned())
+        );
+        assert_eq!(
+            serde_json::to_string(
+                &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""#.to_owned())
+        );
+        assert_eq!(
+            serde_json::to_string(
+                &FixedOffset::east_opt(3650)
+                    .unwrap()
+                    .with_ymd_and_hms(2014, 7, 24, 12, 34, 6)
+                    .unwrap()
+            )
+            .ok(),
+            // An offset with seconds is not allowed by RFC 3339, so we round it to the nearest minute.
+            // In this case `+01:00:50` becomes `+01:01`
+            Some(r#""2014-07-24T12:34:06+01:01""#.to_owned())
+        );
     }
 
-    #[cfg(feature = "clock")]
     #[test]
     fn test_serde_deserialize() {
-        test_decodable_json(
-            |input| serde_json::from_str(input),
-            |input| serde_json::from_str(input),
-            |input| serde_json::from_str(input),
+        // 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()))
+        }
+
+        let dt: Option<DateTime<Utc>> = serde_json::from_str(r#""2014-07-24T12:34:06Z""#).ok();
+        assert_eq!(norm(&dt), norm(&Some(Utc.with_ymd_and_hms(2014, 7, 24, 12, 34, 6).unwrap())));
+        let dt: Option<DateTime<Utc>> = serde_json::from_str(r#""2014-07-24T13:57:06+01:23""#).ok();
+        assert_eq!(norm(&dt), norm(&Some(Utc.with_ymd_and_hms(2014, 7, 24, 12, 34, 6).unwrap())));
+
+        let dt: Option<DateTime<FixedOffset>> =
+            serde_json::from_str(r#""2014-07-24T12:34:06Z""#).ok();
+        assert_eq!(
+            norm(&dt),
+            norm(&Some(
+                FixedOffset::east_opt(0).unwrap().with_ymd_and_hms(2014, 7, 24, 12, 34, 6).unwrap()
+            ))
         );
+        let dt: Option<DateTime<FixedOffset>> =
+            serde_json::from_str(r#""2014-07-24T13:57:06+01:23""#).ok();
+        assert_eq!(
+            norm(&dt),
+            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
+        #[cfg(feature = "clock")]
+        {
+            let dt: DateTime<Local> =
+                serde_json::from_str(r#""2014-07-24T12:34:06Z""#).expect("local should parse");
+            assert_eq!(dt, Utc.with_ymd_and_hms(2014, 7, 24, 12, 34, 6).unwrap());
+
+            let dt: DateTime<Local> = serde_json::from_str(r#""2014-07-24T13:57:06+01:23""#)
+                .expect("local should parse with offset");
+            assert_eq!(dt, Utc.with_ymd_and_hms(2014, 7, 24, 12, 34, 6).unwrap());
+        }
+
+        assert!(serde_json::from_str::<DateTime<Utc>>(r#""2014-07-32T12:34:06Z""#).is_err());
+        assert!(serde_json::from_str::<DateTime<FixedOffset>>(r#""2014-07-32T12:34:06Z""#).is_err());
     }
 
     #[test]
@@ -1206,7 +1307,7 @@
 
     #[test]
     fn test_serde_no_offset_debug() {
-        use crate::{LocalResult, NaiveDate, NaiveDateTime, Offset};
+        use crate::{MappedLocalTime, NaiveDate, NaiveDateTime, Offset};
         use core::fmt::Debug;
 
         #[derive(Clone)]
@@ -1221,14 +1322,14 @@
             fn from_offset(_state: &TestTimeZone) -> TestTimeZone {
                 TestTimeZone
             }
-            fn offset_from_local_date(&self, _local: &NaiveDate) -> LocalResult<TestTimeZone> {
-                LocalResult::Single(TestTimeZone)
+            fn offset_from_local_date(&self, _local: &NaiveDate) -> MappedLocalTime<TestTimeZone> {
+                MappedLocalTime::Single(TestTimeZone)
             }
             fn offset_from_local_datetime(
                 &self,
                 _local: &NaiveDateTime,
-            ) -> LocalResult<TestTimeZone> {
-                LocalResult::Single(TestTimeZone)
+            ) -> MappedLocalTime<TestTimeZone> {
+                MappedLocalTime::Single(TestTimeZone)
             }
             fn offset_from_utc_date(&self, _utc: &NaiveDate) -> TestTimeZone {
                 TestTimeZone
diff --git a/crates/chrono/src/datetime/tests.rs b/crates/chrono/src/datetime/tests.rs
index be83955..c890863 100644
--- a/crates/chrono/src/datetime/tests.rs
+++ b/crates/chrono/src/datetime/tests.rs
@@ -1,9 +1,9 @@
 use super::DateTime;
 use crate::naive::{NaiveDate, NaiveTime};
-use crate::offset::{FixedOffset, TimeZone, Utc};
 #[cfg(feature = "clock")]
-use crate::offset::{Local, Offset};
-use crate::{Datelike, Days, LocalResult, Months, NaiveDateTime, TimeDelta, Timelike, Weekday};
+use crate::offset::Local;
+use crate::offset::{FixedOffset, Offset, TimeZone, Utc};
+use crate::{Datelike, Days, MappedLocalTime, Months, NaiveDateTime, TimeDelta, Timelike, Weekday};
 
 #[derive(Clone)]
 struct DstTester;
@@ -31,14 +31,14 @@
         DstTester
     }
 
-    fn offset_from_local_date(&self, _: &NaiveDate) -> crate::LocalResult<Self::Offset> {
+    fn offset_from_local_date(&self, _: &NaiveDate) -> crate::MappedLocalTime<Self::Offset> {
         unimplemented!()
     }
 
     fn offset_from_local_datetime(
         &self,
         local: &NaiveDateTime,
-    ) -> crate::LocalResult<Self::Offset> {
+    ) -> crate::MappedLocalTime<Self::Offset> {
         let local_to_winter_transition_start = NaiveDate::from_ymd_opt(
             local.year(),
             DstTester::TO_WINTER_MONTH_DAY.0,
@@ -53,7 +53,7 @@
             DstTester::TO_WINTER_MONTH_DAY.1,
         )
         .unwrap()
-        .and_time(DstTester::transition_start_local() - TimeDelta::hours(1));
+        .and_time(DstTester::transition_start_local() - TimeDelta::try_hours(1).unwrap());
 
         let local_to_summer_transition_start = NaiveDate::from_ymd_opt(
             local.year(),
@@ -69,22 +69,22 @@
             DstTester::TO_SUMMER_MONTH_DAY.1,
         )
         .unwrap()
-        .and_time(DstTester::transition_start_local() + TimeDelta::hours(1));
+        .and_time(DstTester::transition_start_local() + TimeDelta::try_hours(1).unwrap());
 
         if *local < local_to_winter_transition_end || *local >= local_to_summer_transition_end {
-            LocalResult::Single(DstTester::summer_offset())
+            MappedLocalTime::Single(DstTester::summer_offset())
         } else if *local >= local_to_winter_transition_start
             && *local < local_to_summer_transition_start
         {
-            LocalResult::Single(DstTester::winter_offset())
+            MappedLocalTime::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())
+            MappedLocalTime::Ambiguous(DstTester::winter_offset(), DstTester::summer_offset())
         } else if *local >= local_to_summer_transition_start
             && *local < local_to_summer_transition_end
         {
-            LocalResult::None
+            MappedLocalTime::None
         } else {
             panic!("Unexpected local time {}", local)
         }
@@ -124,6 +124,194 @@
 }
 
 #[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 datetime = DateTime::from_timestamp_millis(timestamp_millis).unwrap();
+        assert_eq!(timestamp_millis, datetime.timestamp_millis());
+        #[cfg(feature = "alloc")]
+        assert_eq!(datetime.format("%F %T%.9f").to_string(), _formatted);
+    }
+
+    let invalid = [i64::MAX, i64::MIN];
+
+    for timestamp_millis in invalid.iter().copied() {
+        let datetime = DateTime::from_timestamp_millis(timestamp_millis);
+        assert!(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!(DateTime::from_timestamp_millis(secs * 1000), DateTime::from_timestamp(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 datetime = DateTime::from_timestamp_micros(timestamp_micros).unwrap();
+        assert_eq!(timestamp_micros, datetime.timestamp_micros());
+        #[cfg(feature = "alloc")]
+        assert_eq!(datetime.format("%F %T%.9f").to_string(), _formatted);
+    }
+
+    let invalid = [i64::MAX, i64::MIN];
+
+    for timestamp_micros in invalid.iter().copied() {
+        let datetime = DateTime::from_timestamp_micros(timestamp_micros);
+        assert!(datetime.is_none());
+    }
+
+    // Test that the result of `TimeZone::timestamp_micros` compares equal to
+    // that of `TimeZone::timestamp_opt`.
+    let secs_test = [0, 1, 2, 1000, 1234, 12345678, -1, -2, -1000, -12345678];
+    for secs in secs_test.iter().copied() {
+        assert_eq!(
+            DateTime::from_timestamp_micros(secs * 1_000_000),
+            DateTime::from_timestamp(secs, 0)
+        );
+    }
+}
+
+#[test]
+fn test_datetime_from_timestamp_nanos() {
+    let valid_map = [
+        (1662921288000000000, "2022-09-11 18:34:48.000000000"),
+        (1662921288123456000, "2022-09-11 18:34:48.123456000"),
+        (1662921288123456789, "2022-09-11 18:34:48.123456789"),
+        (1662921287890000000, "2022-09-11 18:34:47.890000000"),
+        (-2208936075000000000, "1900-01-01 14:38:45.000000000"),
+        (-5337182663000000000, "1800-11-15 01:15:37.000000000"),
+        (0, "1970-01-01 00:00:00.000000000"),
+        (119731017000000000, "1973-10-17 18:36:57.000000000"),
+        (1234567890000000000, "2009-02-13 23:31:30.000000000"),
+        (2034061609000000000, "2034-06-16 09:06:49.000000000"),
+    ];
+
+    for (timestamp_nanos, _formatted) in valid_map.iter().copied() {
+        let datetime = DateTime::from_timestamp_nanos(timestamp_nanos);
+        assert_eq!(timestamp_nanos, datetime.timestamp_nanos_opt().unwrap());
+        #[cfg(feature = "alloc")]
+        assert_eq!(datetime.format("%F %T%.9f").to_string(), _formatted);
+    }
+
+    const A_BILLION: i64 = 1_000_000_000;
+    // Maximum datetime in nanoseconds
+    let maximum = "2262-04-11T23:47:16.854775804UTC";
+    let parsed: DateTime<Utc> = maximum.parse().unwrap();
+    let nanos = parsed.timestamp_nanos_opt().unwrap();
+    assert_eq!(
+        Some(DateTime::from_timestamp_nanos(nanos)),
+        DateTime::from_timestamp(nanos / A_BILLION, (nanos % A_BILLION) as u32)
+    );
+    // Minimum datetime in nanoseconds
+    let minimum = "1677-09-21T00:12:44.000000000UTC";
+    let parsed: DateTime<Utc> = minimum.parse().unwrap();
+    let nanos = parsed.timestamp_nanos_opt().unwrap();
+    assert_eq!(
+        Some(DateTime::from_timestamp_nanos(nanos)),
+        DateTime::from_timestamp(nanos / A_BILLION, (nanos % A_BILLION) as u32)
+    );
+
+    // Test that the result of `TimeZone::timestamp_nanos` compares equal to
+    // that of `TimeZone::timestamp_opt`.
+    let secs_test = [0, 1, 2, 1000, 1234, 12345678, -1, -2, -1000, -12345678];
+    for secs in secs_test.iter().copied() {
+        assert_eq!(
+            Some(DateTime::from_timestamp_nanos(secs * 1_000_000_000)),
+            DateTime::from_timestamp(secs, 0)
+        );
+    }
+}
+
+#[test]
+fn test_datetime_from_timestamp() {
+    let from_timestamp = |secs| DateTime::from_timestamp(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().and_utc()
+    };
+    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_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()
+            .and_utc()
+            .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_nanosecond_range() {
+    const A_BILLION: i64 = 1_000_000_000;
+    let maximum = "2262-04-11T23:47:16.854775804UTC";
+    let parsed: DateTime<Utc> = maximum.parse().unwrap();
+    let nanos = parsed.timestamp_nanos_opt().unwrap();
+    assert_eq!(
+        parsed,
+        DateTime::<Utc>::from_timestamp(nanos / A_BILLION, (nanos % A_BILLION) as u32).unwrap()
+    );
+
+    let minimum = "1677-09-21T00:12:44.000000000UTC";
+    let parsed: DateTime<Utc> = minimum.parse().unwrap();
+    let nanos = parsed.timestamp_nanos_opt().unwrap();
+    assert_eq!(
+        parsed,
+        DateTime::<Utc>::from_timestamp(nanos / A_BILLION, (nanos % A_BILLION) as u32).unwrap()
+    );
+
+    // Just beyond range
+    let maximum = "2262-04-11T23:47:16.854775804UTC";
+    let parsed: DateTime<Utc> = maximum.parse().unwrap();
+    let beyond_max = parsed + TimeDelta::try_milliseconds(300).unwrap();
+    assert!(beyond_max.timestamp_nanos_opt().is_none());
+
+    // Far beyond range
+    let maximum = "2262-04-11T23:47:16.854775804UTC";
+    let parsed: DateTime<Utc> = maximum.parse().unwrap();
+    let beyond_max = parsed + Days::new(365);
+    assert!(beyond_max.timestamp_nanos_opt().is_none());
+}
+
+#[test]
 fn test_datetime_add_days() {
     let est = FixedOffset::west_opt(5 * 60 * 60).unwrap();
     let kst = FixedOffset::east_opt(9 * 60 * 60).unwrap();
@@ -392,12 +580,12 @@
     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 + TimeDelta::seconds(3600 + 60 + 1),
+        dt + TimeDelta::try_seconds(3600 + 60 + 1).unwrap(),
         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()),
-        TimeDelta::seconds(-7 * 3600 - 3 * 60 - 3)
+        TimeDelta::try_seconds(-7 * 3600 - 3 * 60 - 3).unwrap()
     );
 
     assert_eq!(*Utc.with_ymd_and_hms(2014, 5, 6, 7, 8, 9).unwrap().offset(), Utc);
@@ -415,7 +603,7 @@
     let diff2 = dt2.signed_duration_since(&dt1); // Take by reference
     assert_eq!(diff1, -diff2);
 
-    let diff1 = dt1 - &dt2; // We can choose to substract rhs by reference
+    let diff1 = dt1 - &dt2; // We can choose to subtract rhs by reference
     let diff2 = dt2 - dt1; // Or consume rhs
     assert_eq!(diff1, -diff2);
 }
@@ -915,7 +1103,7 @@
         .is_err());
     assert_eq!(
         DateTime::parse_from_str("0", "%s").unwrap(),
-        NaiveDateTime::from_timestamp_opt(0, 0).unwrap().and_utc().fixed_offset()
+        DateTime::from_timestamp(0, 0).unwrap().fixed_offset()
     );
 
     assert_eq!(
@@ -1130,9 +1318,44 @@
 
 #[test]
 fn test_datetime_is_send_and_copy() {
+    #[derive(Clone)]
+    struct Tz {
+        _not_send: *const i32,
+    }
+    impl TimeZone for Tz {
+        type Offset = Off;
+
+        fn from_offset(_: &Self::Offset) -> Self {
+            unimplemented!()
+        }
+        fn offset_from_local_date(&self, _: &NaiveDate) -> crate::MappedLocalTime<Self::Offset> {
+            unimplemented!()
+        }
+        fn offset_from_local_datetime(
+            &self,
+            _: &NaiveDateTime,
+        ) -> crate::MappedLocalTime<Self::Offset> {
+            unimplemented!()
+        }
+        fn offset_from_utc_date(&self, _: &NaiveDate) -> Self::Offset {
+            unimplemented!()
+        }
+        fn offset_from_utc_datetime(&self, _: &NaiveDateTime) -> Self::Offset {
+            unimplemented!()
+        }
+    }
+
+    #[derive(Copy, Clone, Debug)]
+    struct Off(());
+    impl Offset for Off {
+        fn fix(&self) -> FixedOffset {
+            unimplemented!()
+        }
+    }
+
     fn _assert_send_copy<T: Send + Copy>() {}
-    // UTC is known to be `Send + Copy`.
-    _assert_send_copy::<DateTime<Utc>>();
+    // `DateTime` is `Send + Copy` if the offset is.
+    _assert_send_copy::<DateTime<Tz>>();
 }
 
 #[test]
@@ -1253,18 +1476,6 @@
 }
 
 #[test]
-fn test_datetime_from_timestamp_millis() {
-    // 2000-01-12T01:02:03:004Z
-    let naive_dt =
-        NaiveDate::from_ymd_opt(2000, 1, 12).unwrap().and_hms_milli_opt(1, 2, 3, 4).unwrap();
-    let datetime_utc = DateTime::<Utc>::from_naive_utc_and_offset(naive_dt, Utc);
-    assert_eq!(
-        datetime_utc,
-        DateTime::<Utc>::from_timestamp_millis(datetime_utc.timestamp_millis()).unwrap()
-    );
-}
-
-#[test]
 #[cfg(feature = "clock")]
 fn test_datetime_before_windows_api_limits() {
     // dt corresponds to `FILETIME = 147221225472` from issue 651.
@@ -1279,20 +1490,16 @@
 #[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() - TimeDelta::weeks((WEEKS_PER_YEAR * 1.5).ceil() as i64);
-    // A bit more than 2 years.
-    let two_year_ago =
-        Utc::now().date_naive() - TimeDelta::weeks((WEEKS_PER_YEAR * 2.5).ceil() as i64);
+    // A bit more than 1 year
+    let one_year_ago = Utc::now().date_naive() - Days::new(400);
+    // A bit more than 2 years
+    let two_year_ago = Utc::now().date_naive() - Days::new(750);
 
     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() + TimeDelta::weeks(12);
+    let future = Utc::now().date_naive() + Days(100);
     assert_eq!(Utc::now().date_naive().years_since(future), None);
 }
 
@@ -1302,20 +1509,20 @@
     let datetime = naivedatetime.and_utc();
     let mut datetime_add = datetime;
 
-    datetime_add += TimeDelta::seconds(60);
-    assert_eq!(datetime_add, datetime + TimeDelta::seconds(60));
+    datetime_add += TimeDelta::try_seconds(60).unwrap();
+    assert_eq!(datetime_add, datetime + TimeDelta::try_seconds(60).unwrap());
 
     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 + TimeDelta::seconds(60));
+    assert_eq!(datetime_add, datetime + TimeDelta::try_seconds(60).unwrap());
 
     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 + TimeDelta::seconds(60));
+    assert_eq!(datetime_add, datetime + TimeDelta::try_seconds(60).unwrap());
 }
 
 #[test]
@@ -1328,8 +1535,8 @@
 
     // ensure we cross a DST transition
     for i in 1..=365 {
-        datetime_add += TimeDelta::days(1);
-        assert_eq!(datetime_add, datetime + TimeDelta::days(i))
+        datetime_add += TimeDelta::try_days(1).unwrap();
+        assert_eq!(datetime_add, datetime + TimeDelta::try_days(i).unwrap())
     }
 }
 
@@ -1339,20 +1546,20 @@
     let datetime = naivedatetime.and_utc();
     let mut datetime_sub = datetime;
 
-    datetime_sub -= TimeDelta::minutes(90);
-    assert_eq!(datetime_sub, datetime - TimeDelta::minutes(90));
+    datetime_sub -= TimeDelta::try_minutes(90).unwrap();
+    assert_eq!(datetime_sub, datetime - TimeDelta::try_minutes(90).unwrap());
 
     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 - TimeDelta::minutes(90));
+    assert_eq!(datetime_sub, datetime - TimeDelta::try_minutes(90).unwrap());
 
     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 - TimeDelta::minutes(90));
+    assert_eq!(datetime_sub, datetime - TimeDelta::try_minutes(90).unwrap());
 }
 
 #[test]
@@ -1421,6 +1628,7 @@
     let beyond_max = offset_max.from_utc_datetime(&NaiveDateTime::MAX);
 
     assert_eq!(beyond_min.with_year(2020).unwrap().year(), 2020);
+    assert_eq!(beyond_min.with_year(beyond_min.year()), Some(beyond_min));
     assert_eq!(beyond_min.with_month(beyond_min.month()), Some(beyond_min));
     assert_eq!(beyond_min.with_month(3), None);
     assert_eq!(beyond_min.with_month0(beyond_min.month0()), Some(beyond_min));
@@ -1434,13 +1642,17 @@
     assert_eq!(beyond_min.with_ordinal0(beyond_min.ordinal0()), Some(beyond_min));
     assert_eq!(beyond_min.with_ordinal0(200), None);
     assert_eq!(beyond_min.with_hour(beyond_min.hour()), Some(beyond_min));
-    assert_eq!(beyond_min.with_hour(23), beyond_min.checked_add_signed(TimeDelta::hours(1)));
+    assert_eq!(
+        beyond_min.with_hour(23),
+        beyond_min.checked_add_signed(TimeDelta::try_hours(1).unwrap())
+    );
     assert_eq!(beyond_min.with_hour(5), None);
     assert_eq!(beyond_min.with_minute(0), Some(beyond_min));
     assert_eq!(beyond_min.with_second(0), Some(beyond_min));
     assert_eq!(beyond_min.with_nanosecond(0), Some(beyond_min));
 
     assert_eq!(beyond_max.with_year(2020).unwrap().year(), 2020);
+    assert_eq!(beyond_max.with_year(beyond_max.year()), Some(beyond_max));
     assert_eq!(beyond_max.with_month(beyond_max.month()), Some(beyond_max));
     assert_eq!(beyond_max.with_month(3), None);
     assert_eq!(beyond_max.with_month0(beyond_max.month0()), Some(beyond_max));
@@ -1454,7 +1666,10 @@
     assert_eq!(beyond_max.with_ordinal0(beyond_max.ordinal0()), Some(beyond_max));
     assert_eq!(beyond_max.with_ordinal0(200), None);
     assert_eq!(beyond_max.with_hour(beyond_max.hour()), Some(beyond_max));
-    assert_eq!(beyond_max.with_hour(0), beyond_max.checked_sub_signed(TimeDelta::hours(1)));
+    assert_eq!(
+        beyond_max.with_hour(0),
+        beyond_max.checked_sub_signed(TimeDelta::try_hours(1).unwrap())
+    );
     assert_eq!(beyond_max.with_hour(5), None);
     assert_eq!(beyond_max.with_minute(beyond_max.minute()), Some(beyond_max));
     assert_eq!(beyond_max.with_second(beyond_max.second()), Some(beyond_max));
@@ -1462,6 +1677,56 @@
 }
 
 #[test]
+fn test_min_max_add_days() {
+    let offset_min = FixedOffset::west_opt(2 * 60 * 60).unwrap();
+    let beyond_min = offset_min.from_utc_datetime(&NaiveDateTime::MIN);
+    let offset_max = FixedOffset::east_opt(2 * 60 * 60).unwrap();
+    let beyond_max = offset_max.from_utc_datetime(&NaiveDateTime::MAX);
+    let max_time = NaiveTime::from_hms_nano_opt(23, 59, 59, 999_999_999).unwrap();
+
+    assert_eq!(beyond_min.checked_add_days(Days::new(0)), Some(beyond_min));
+    assert_eq!(
+        beyond_min.checked_add_days(Days::new(1)),
+        Some(offset_min.from_utc_datetime(&(NaiveDate::MIN + Days(1)).and_time(NaiveTime::MIN)))
+    );
+    assert_eq!(beyond_min.checked_sub_days(Days::new(0)), Some(beyond_min));
+    assert_eq!(beyond_min.checked_sub_days(Days::new(1)), None);
+
+    assert_eq!(beyond_max.checked_add_days(Days::new(0)), Some(beyond_max));
+    assert_eq!(beyond_max.checked_add_days(Days::new(1)), None);
+    assert_eq!(beyond_max.checked_sub_days(Days::new(0)), Some(beyond_max));
+    assert_eq!(
+        beyond_max.checked_sub_days(Days::new(1)),
+        Some(offset_max.from_utc_datetime(&(NaiveDate::MAX - Days(1)).and_time(max_time)))
+    );
+}
+
+#[test]
+fn test_min_max_add_months() {
+    let offset_min = FixedOffset::west_opt(2 * 60 * 60).unwrap();
+    let beyond_min = offset_min.from_utc_datetime(&NaiveDateTime::MIN);
+    let offset_max = FixedOffset::east_opt(2 * 60 * 60).unwrap();
+    let beyond_max = offset_max.from_utc_datetime(&NaiveDateTime::MAX);
+    let max_time = NaiveTime::from_hms_nano_opt(23, 59, 59, 999_999_999).unwrap();
+
+    assert_eq!(beyond_min.checked_add_months(Months::new(0)), Some(beyond_min));
+    assert_eq!(
+        beyond_min.checked_add_months(Months::new(1)),
+        Some(offset_min.from_utc_datetime(&(NaiveDate::MIN + Months(1)).and_time(NaiveTime::MIN)))
+    );
+    assert_eq!(beyond_min.checked_sub_months(Months::new(0)), Some(beyond_min));
+    assert_eq!(beyond_min.checked_sub_months(Months::new(1)), None);
+
+    assert_eq!(beyond_max.checked_add_months(Months::new(0)), Some(beyond_max));
+    assert_eq!(beyond_max.checked_add_months(Months::new(1)), None);
+    assert_eq!(beyond_max.checked_sub_months(Months::new(0)), Some(beyond_max));
+    assert_eq!(
+        beyond_max.checked_sub_months(Months::new(1)),
+        Some(offset_max.from_utc_datetime(&(NaiveDate::MAX - Months(1)).and_time(max_time)))
+    );
+}
+
+#[test]
 #[should_panic]
 fn test_local_beyond_min_datetime() {
     let min = FixedOffset::west_opt(2 * 60 * 60).unwrap().from_utc_datetime(&NaiveDateTime::MIN);
@@ -1485,8 +1750,8 @@
 
     // ensure we cross a DST transition
     for i in 1..=365 {
-        datetime_sub -= TimeDelta::days(1);
-        assert_eq!(datetime_sub, datetime - TimeDelta::days(i))
+        datetime_sub -= TimeDelta::try_days(1).unwrap();
+        assert_eq!(datetime_sub, datetime - TimeDelta::try_days(i).unwrap())
     }
 }
 
diff --git a/crates/chrono/src/format/formatting.rs b/crates/chrono/src/format/formatting.rs
index 9b05528..967f2d3 100644
--- a/crates/chrono/src/format/formatting.rs
+++ b/crates/chrono/src/format/formatting.rs
@@ -3,7 +3,7 @@
 
 //! Date and time formatting routines.
 
-#[cfg(all(not(feature = "std"), feature = "alloc"))]
+#[cfg(all(feature = "alloc", not(feature = "std"), not(test)))]
 use alloc::string::{String, ToString};
 #[cfg(feature = "alloc")]
 use core::borrow::Borrow;
@@ -13,16 +13,14 @@
 
 #[cfg(feature = "alloc")]
 use crate::offset::Offset;
-#[cfg(any(feature = "alloc", feature = "serde", feature = "rustc-serialize"))]
+#[cfg(any(feature = "alloc", feature = "serde"))]
 use crate::{Datelike, FixedOffset, NaiveDateTime, Timelike};
 #[cfg(feature = "alloc")]
 use crate::{NaiveDate, NaiveTime, Weekday};
 
 #[cfg(feature = "alloc")]
 use super::locales;
-#[cfg(all(feature = "unstable-locales", feature = "alloc"))]
-use super::Locale;
-#[cfg(any(feature = "alloc", feature = "serde", feature = "rustc-serialize"))]
+#[cfg(any(feature = "alloc", feature = "serde"))]
 use super::{Colons, OffsetFormat, OffsetPrecision, Pad};
 #[cfg(feature = "alloc")]
 use super::{Fixed, InternalFixed, InternalInternal, Item, Numeric};
@@ -43,10 +41,8 @@
     /// 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>,
+    /// ZST if the `unstable-locales` feature is not enabled.
+    locale: Locale,
 }
 
 #[cfg(feature = "alloc")]
@@ -54,14 +50,7 @@
     /// Makes a new `DelayedFormat` value out of local date and time.
     #[must_use]
     pub fn new(date: Option<NaiveDate>, time: Option<NaiveTime>, items: I) -> DelayedFormat<I> {
-        DelayedFormat {
-            date,
-            time,
-            off: None,
-            items,
-            #[cfg(feature = "unstable-locales")]
-            locale: None,
-        }
+        DelayedFormat { date, time, off: None, items, locale: default_locale() }
     }
 
     /// Makes a new `DelayedFormat` value out of local date and time and UTC offset.
@@ -76,14 +65,7 @@
         Off: Offset + Display,
     {
         let name_and_diff = (offset.to_string(), offset.fix());
-        DelayedFormat {
-            date,
-            time,
-            off: Some(name_and_diff),
-            items,
-            #[cfg(feature = "unstable-locales")]
-            locale: None,
-        }
+        DelayedFormat { date, time, off: Some(name_and_diff), items, locale: default_locale() }
     }
 
     /// Makes a new `DelayedFormat` value out of local date and time and locale.
@@ -95,7 +77,7 @@
         items: I,
         locale: Locale,
     ) -> DelayedFormat<I> {
-        DelayedFormat { date, time, off: None, items, locale: Some(locale) }
+        DelayedFormat { date, time, off: None, items, locale }
     }
 
     /// Makes a new `DelayedFormat` value out of local date and time, UTC offset and locale.
@@ -112,29 +94,234 @@
         Off: Offset + Display,
     {
         let name_and_diff = (offset.to_string(), offset.fix());
-        DelayedFormat { date, time, off: Some(name_and_diff), items, locale: Some(locale) }
+        DelayedFormat { date, time, off: Some(name_and_diff), items, locale }
+    }
+
+    fn format(&self, w: &mut impl Write) -> fmt::Result {
+        for item in self.items.clone() {
+            match *item.borrow() {
+                Item::Literal(s) | Item::Space(s) => w.write_str(s),
+                #[cfg(feature = "alloc")]
+                Item::OwnedLiteral(ref s) | Item::OwnedSpace(ref s) => w.write_str(s),
+                Item::Numeric(ref spec, pad) => self.format_numeric(w, spec, pad),
+                Item::Fixed(ref spec) => self.format_fixed(w, spec),
+                Item::Error => Err(fmt::Error),
+            }?;
+        }
+        Ok(())
+    }
+
+    #[cfg(feature = "alloc")]
+    fn format_numeric(&self, w: &mut impl Write, spec: &Numeric, pad: Pad) -> fmt::Result {
+        use self::Numeric::*;
+
+        fn write_one(w: &mut impl Write, v: u8) -> fmt::Result {
+            w.write_char((b'0' + v) as char)
+        }
+
+        fn write_two(w: &mut impl Write, v: u8, pad: Pad) -> fmt::Result {
+            let ones = b'0' + v % 10;
+            match (v / 10, pad) {
+                (0, Pad::None) => {}
+                (0, Pad::Space) => w.write_char(' ')?,
+                (tens, _) => w.write_char((b'0' + tens) as char)?,
+            }
+            w.write_char(ones as char)
+        }
+
+        #[inline]
+        fn write_year(w: &mut impl Write, year: i32, pad: Pad) -> fmt::Result {
+            if (1000..=9999).contains(&year) {
+                // fast path
+                write_hundreds(w, (year / 100) as u8)?;
+                write_hundreds(w, (year % 100) as u8)
+            } else {
+                write_n(w, 4, year as i64, pad, !(0..10_000).contains(&year))
+            }
+        }
+
+        fn write_n(
+            w: &mut impl Write,
+            n: usize,
+            v: i64,
+            pad: Pad,
+            always_sign: bool,
+        ) -> fmt::Result {
+            if always_sign {
+                match pad {
+                    Pad::None => write!(w, "{:+}", v),
+                    Pad::Zero => write!(w, "{:+01$}", v, n + 1),
+                    Pad::Space => write!(w, "{:+1$}", v, n + 1),
+                }
+            } else {
+                match pad {
+                    Pad::None => write!(w, "{}", v),
+                    Pad::Zero => write!(w, "{:01$}", v, n),
+                    Pad::Space => write!(w, "{:1$}", v, n),
+                }
+            }
+        }
+
+        match (spec, self.date, self.time) {
+            (Year, Some(d), _) => write_year(w, d.year(), pad),
+            (YearDiv100, Some(d), _) => write_two(w, d.year().div_euclid(100) as u8, pad),
+            (YearMod100, Some(d), _) => write_two(w, d.year().rem_euclid(100) as u8, pad),
+            (IsoYear, Some(d), _) => write_year(w, d.iso_week().year(), pad),
+            (IsoYearDiv100, Some(d), _) => {
+                write_two(w, d.iso_week().year().div_euclid(100) as u8, pad)
+            }
+            (IsoYearMod100, Some(d), _) => {
+                write_two(w, d.iso_week().year().rem_euclid(100) as u8, pad)
+            }
+            (Month, Some(d), _) => write_two(w, d.month() as u8, pad),
+            (Day, Some(d), _) => write_two(w, d.day() as u8, pad),
+            (WeekFromSun, Some(d), _) => write_two(w, d.weeks_from(Weekday::Sun) as u8, pad),
+            (WeekFromMon, Some(d), _) => write_two(w, d.weeks_from(Weekday::Mon) as u8, pad),
+            (IsoWeek, Some(d), _) => write_two(w, d.iso_week().week() as u8, pad),
+            (NumDaysFromSun, Some(d), _) => write_one(w, d.weekday().num_days_from_sunday() as u8),
+            (WeekdayFromMon, Some(d), _) => write_one(w, d.weekday().number_from_monday() as u8),
+            (Ordinal, Some(d), _) => write_n(w, 3, d.ordinal() as i64, pad, false),
+            (Hour, _, Some(t)) => write_two(w, t.hour() as u8, pad),
+            (Hour12, _, Some(t)) => write_two(w, t.hour12().1 as u8, pad),
+            (Minute, _, Some(t)) => write_two(w, t.minute() as u8, pad),
+            (Second, _, Some(t)) => {
+                write_two(w, (t.second() + t.nanosecond() / 1_000_000_000) as u8, pad)
+            }
+            (Nanosecond, _, Some(t)) => {
+                write_n(w, 9, (t.nanosecond() % 1_000_000_000) as i64, pad, false)
+            }
+            (Timestamp, Some(d), Some(t)) => {
+                let offset = self.off.as_ref().map(|(_, o)| i64::from(o.local_minus_utc()));
+                let timestamp = d.and_time(t).and_utc().timestamp() - offset.unwrap_or(0);
+                write_n(w, 9, timestamp, pad, false)
+            }
+            (Internal(_), _, _) => Ok(()), // for future expansion
+            _ => Err(fmt::Error),          // insufficient arguments for given format
+        }
+    }
+
+    #[cfg(feature = "alloc")]
+    fn format_fixed(&self, w: &mut impl Write, spec: &Fixed) -> fmt::Result {
+        use Fixed::*;
+        use InternalInternal::*;
+
+        match (spec, self.date, self.time, self.off.as_ref()) {
+            (ShortMonthName, Some(d), _, _) => {
+                w.write_str(short_months(self.locale)[d.month0() as usize])
+            }
+            (LongMonthName, Some(d), _, _) => {
+                w.write_str(long_months(self.locale)[d.month0() as usize])
+            }
+            (ShortWeekdayName, Some(d), _, _) => w.write_str(
+                short_weekdays(self.locale)[d.weekday().num_days_from_sunday() as usize],
+            ),
+            (LongWeekdayName, Some(d), _, _) => {
+                w.write_str(long_weekdays(self.locale)[d.weekday().num_days_from_sunday() as usize])
+            }
+            (LowerAmPm, _, Some(t), _) => {
+                let ampm = if t.hour12().0 { am_pm(self.locale)[1] } else { am_pm(self.locale)[0] };
+                for c in ampm.chars().flat_map(|c| c.to_lowercase()) {
+                    w.write_char(c)?
+                }
+                Ok(())
+            }
+            (UpperAmPm, _, Some(t), _) => {
+                let ampm = if t.hour12().0 { am_pm(self.locale)[1] } else { am_pm(self.locale)[0] };
+                w.write_str(ampm)
+            }
+            (Nanosecond, _, Some(t), _) => {
+                let nano = t.nanosecond() % 1_000_000_000;
+                if nano == 0 {
+                    Ok(())
+                } else {
+                    w.write_str(decimal_point(self.locale))?;
+                    if nano % 1_000_000 == 0 {
+                        write!(w, "{:03}", nano / 1_000_000)
+                    } else if nano % 1_000 == 0 {
+                        write!(w, "{:06}", nano / 1_000)
+                    } else {
+                        write!(w, "{:09}", nano)
+                    }
+                }
+            }
+            (Nanosecond3, _, Some(t), _) => {
+                w.write_str(decimal_point(self.locale))?;
+                write!(w, "{:03}", t.nanosecond() / 1_000_000 % 1000)
+            }
+            (Nanosecond6, _, Some(t), _) => {
+                w.write_str(decimal_point(self.locale))?;
+                write!(w, "{:06}", t.nanosecond() / 1_000 % 1_000_000)
+            }
+            (Nanosecond9, _, Some(t), _) => {
+                w.write_str(decimal_point(self.locale))?;
+                write!(w, "{:09}", t.nanosecond() % 1_000_000_000)
+            }
+            (Internal(InternalFixed { val: Nanosecond3NoDot }), _, Some(t), _) => {
+                write!(w, "{:03}", t.nanosecond() / 1_000_000 % 1_000)
+            }
+            (Internal(InternalFixed { val: Nanosecond6NoDot }), _, Some(t), _) => {
+                write!(w, "{:06}", t.nanosecond() / 1_000 % 1_000_000)
+            }
+            (Internal(InternalFixed { val: Nanosecond9NoDot }), _, Some(t), _) => {
+                write!(w, "{:09}", t.nanosecond() % 1_000_000_000)
+            }
+            (TimezoneName, _, _, Some((tz_name, _))) => write!(w, "{}", tz_name),
+            (TimezoneOffset | TimezoneOffsetZ, _, _, Some((_, off))) => {
+                let offset_format = OffsetFormat {
+                    precision: OffsetPrecision::Minutes,
+                    colons: Colons::Maybe,
+                    allow_zulu: *spec == TimezoneOffsetZ,
+                    padding: Pad::Zero,
+                };
+                offset_format.format(w, *off)
+            }
+            (TimezoneOffsetColon | TimezoneOffsetColonZ, _, _, Some((_, off))) => {
+                let offset_format = OffsetFormat {
+                    precision: OffsetPrecision::Minutes,
+                    colons: Colons::Colon,
+                    allow_zulu: *spec == TimezoneOffsetColonZ,
+                    padding: Pad::Zero,
+                };
+                offset_format.format(w, *off)
+            }
+            (TimezoneOffsetDoubleColon, _, _, Some((_, off))) => {
+                let offset_format = OffsetFormat {
+                    precision: OffsetPrecision::Seconds,
+                    colons: Colons::Colon,
+                    allow_zulu: false,
+                    padding: Pad::Zero,
+                };
+                offset_format.format(w, *off)
+            }
+            (TimezoneOffsetTripleColon, _, _, Some((_, off))) => {
+                let offset_format = OffsetFormat {
+                    precision: OffsetPrecision::Hours,
+                    colons: Colons::None,
+                    allow_zulu: false,
+                    padding: Pad::Zero,
+                };
+                offset_format.format(w, *off)
+            }
+            (RFC2822, Some(d), Some(t), Some((_, off))) => {
+                write_rfc2822(w, crate::NaiveDateTime::new(d, t), *off)
+            }
+            (RFC3339, Some(d), Some(t), Some((_, off))) => write_rfc3339(
+                w,
+                crate::NaiveDateTime::new(d, t),
+                *off,
+                SecondsFormat::AutoSi,
+                false,
+            ),
+            _ => Err(fmt::Error), // insufficient arguments for given format
+        }
     }
 }
 
 #[cfg(feature = "alloc")]
 impl<'a, I: Iterator<Item = B> + Clone, B: Borrow<Item<'a>>> Display for DelayedFormat<I> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        #[cfg(feature = "unstable-locales")]
-        let locale = self.locale;
-        #[cfg(not(feature = "unstable-locales"))]
-        let locale = None;
-
         let mut result = String::new();
-        for item in self.items.clone() {
-            format_inner(
-                &mut result,
-                self.date.as_ref(),
-                self.time.as_ref(),
-                self.off.as_ref(),
-                item.borrow(),
-                locale,
-            )?;
-        }
+        self.format(&mut result)?;
         f.pad(&result)
     }
 }
@@ -159,8 +346,7 @@
         time: time.copied(),
         off: off.cloned(),
         items,
-        #[cfg(feature = "unstable-locales")]
-        locale: None,
+        locale: default_locale(),
     }
     .fmt(w)
 }
@@ -180,249 +366,12 @@
         time: time.copied(),
         off: off.cloned(),
         items: [item].into_iter(),
-        #[cfg(feature = "unstable-locales")]
-        locale: None,
+        locale: default_locale(),
     }
     .fmt(w)
 }
 
-#[cfg(feature = "alloc")]
-fn format_inner(
-    w: &mut impl Write,
-    date: Option<&NaiveDate>,
-    time: Option<&NaiveTime>,
-    off: Option<&(String, FixedOffset)>,
-    item: &Item<'_>,
-    locale: Option<Locale>,
-) -> fmt::Result {
-    let locale = locale.unwrap_or(default_locale());
-
-    match *item {
-        Item::Literal(s) | Item::Space(s) => w.write_str(s),
-        #[cfg(feature = "alloc")]
-        Item::OwnedLiteral(ref s) | Item::OwnedSpace(ref s) => w.write_str(s),
-
-        Item::Numeric(ref spec, ref pad) => {
-            use self::Numeric::*;
-
-            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()))),
-                YearDiv100 => (2, date.map(|d| i64::from(d.year()).div_euclid(100))),
-                YearMod100 => (2, date.map(|d| i64::from(d.year()).rem_euclid(100))),
-                IsoYear => (4, date.map(|d| i64::from(d.iso_week().year()))),
-                IsoYearDiv100 => (2, date.map(|d| i64::from(d.iso_week().year()).div_euclid(100))),
-                IsoYearMod100 => (2, date.map(|d| i64::from(d.iso_week().year()).rem_euclid(100))),
-                Month => (2, date.map(|d| i64::from(d.month()))),
-                Day => (2, date.map(|d| i64::from(d.day()))),
-                WeekFromSun => (2, date.map(|d| i64::from(week_from_sun(d)))),
-                WeekFromMon => (2, date.map(|d| i64::from(week_from_mon(d)))),
-                IsoWeek => (2, date.map(|d| i64::from(d.iso_week().week()))),
-                NumDaysFromSun => (1, date.map(|d| i64::from(d.weekday().num_days_from_sunday()))),
-                WeekdayFromMon => (1, date.map(|d| i64::from(d.weekday().number_from_monday()))),
-                Ordinal => (3, date.map(|d| i64::from(d.ordinal()))),
-                Hour => (2, time.map(|t| i64::from(t.hour()))),
-                Hour12 => (2, time.map(|t| i64::from(t.hour12().1))),
-                Minute => (2, time.map(|t| i64::from(t.minute()))),
-                Second => (2, time.map(|t| i64::from(t.second() + t.nanosecond() / 1_000_000_000))),
-                Nanosecond => (9, time.map(|t| i64::from(t.nanosecond() % 1_000_000_000))),
-                Timestamp => (
-                    1,
-                    match (date, time, off) {
-                        (Some(d), Some(t), None) => Some(d.and_time(*t).timestamp()),
-                        (Some(d), Some(t), Some(&(_, off))) => {
-                            Some(d.and_time(*t).timestamp() - i64::from(off.local_minus_utc()))
-                        }
-                        (_, _, _) => None,
-                    },
-                ),
-
-                // for the future expansion
-                Internal(ref int) => match int._dummy {},
-            };
-
-            if let Some(v) = v {
-                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!(w, "{:+}", v),
-                        Pad::Zero => write!(w, "{:+01$}", v, width + 1),
-                        Pad::Space => write!(w, "{:+1$}", v, width + 1),
-                    }
-                } else {
-                    match *pad {
-                        Pad::None => write!(w, "{}", v),
-                        Pad::Zero => write!(w, "{:01$}", v, width),
-                        Pad::Space => write!(w, "{:1$}", v, width),
-                    }
-                }
-            } else {
-                Err(fmt::Error) // insufficient arguments for given format
-            }
-        }
-
-        Item::Fixed(ref spec) => {
-            use self::Fixed::*;
-
-            let ret = match *spec {
-                ShortMonthName => date.map(|d| {
-                    w.write_str(short_months(locale)[d.month0() as usize])?;
-                    Ok(())
-                }),
-                LongMonthName => date.map(|d| {
-                    w.write_str(long_months(locale)[d.month0() as usize])?;
-                    Ok(())
-                }),
-                ShortWeekdayName => date.map(|d| {
-                    w.write_str(
-                        short_weekdays(locale)[d.weekday().num_days_from_sunday() as usize],
-                    )?;
-                    Ok(())
-                }),
-                LongWeekdayName => date.map(|d| {
-                    w.write_str(
-                        long_weekdays(locale)[d.weekday().num_days_from_sunday() as usize],
-                    )?;
-                    Ok(())
-                }),
-                LowerAmPm => time.map(|t| {
-                    let ampm = if t.hour12().0 { am_pm(locale)[1] } else { am_pm(locale)[0] };
-                    for c in ampm.chars().flat_map(|c| c.to_lowercase()) {
-                        w.write_char(c)?
-                    }
-                    Ok(())
-                }),
-                UpperAmPm => time.map(|t| {
-                    w.write_str(if t.hour12().0 { am_pm(locale)[1] } else { am_pm(locale)[0] })?;
-                    Ok(())
-                }),
-                Nanosecond => time.map(|t| {
-                    let nano = t.nanosecond() % 1_000_000_000;
-                    if nano == 0 {
-                        Ok(())
-                    } else {
-                        w.write_str(decimal_point(locale))?;
-                        if nano % 1_000_000 == 0 {
-                            write!(w, "{:03}", nano / 1_000_000)
-                        } else if nano % 1_000 == 0 {
-                            write!(w, "{:06}", nano / 1_000)
-                        } else {
-                            write!(w, "{:09}", nano)
-                        }
-                    }
-                }),
-                Nanosecond3 => time.map(|t| {
-                    let nano = t.nanosecond() % 1_000_000_000;
-                    w.write_str(decimal_point(locale))?;
-                    write!(w, "{:03}", nano / 1_000_000)
-                }),
-                Nanosecond6 => time.map(|t| {
-                    let nano = t.nanosecond() % 1_000_000_000;
-                    w.write_str(decimal_point(locale))?;
-                    write!(w, "{:06}", nano / 1_000)
-                }),
-                Nanosecond9 => time.map(|t| {
-                    let nano = t.nanosecond() % 1_000_000_000;
-                    w.write_str(decimal_point(locale))?;
-                    write!(w, "{:09}", nano)
-                }),
-                Internal(InternalFixed { val: InternalInternal::Nanosecond3NoDot }) => {
-                    time.map(|t| {
-                        let nano = t.nanosecond() % 1_000_000_000;
-                        write!(w, "{:03}", nano / 1_000_000)
-                    })
-                }
-                Internal(InternalFixed { val: InternalInternal::Nanosecond6NoDot }) => {
-                    time.map(|t| {
-                        let nano = t.nanosecond() % 1_000_000_000;
-                        write!(w, "{:06}", nano / 1_000)
-                    })
-                }
-                Internal(InternalFixed { val: InternalInternal::Nanosecond9NoDot }) => {
-                    time.map(|t| {
-                        let nano = t.nanosecond() % 1_000_000_000;
-                        write!(w, "{:09}", nano)
-                    })
-                }
-                TimezoneName => off.map(|(name, _)| {
-                    w.write_str(name)?;
-                    Ok(())
-                }),
-                TimezoneOffset | TimezoneOffsetZ => off.map(|&(_, off)| {
-                    OffsetFormat {
-                        precision: OffsetPrecision::Minutes,
-                        colons: Colons::Maybe,
-                        allow_zulu: *spec == TimezoneOffsetZ,
-                        padding: Pad::Zero,
-                    }
-                    .format(w, off)
-                }),
-                TimezoneOffsetColon | TimezoneOffsetColonZ => off.map(|&(_, off)| {
-                    OffsetFormat {
-                        precision: OffsetPrecision::Minutes,
-                        colons: Colons::Colon,
-                        allow_zulu: *spec == TimezoneOffsetColonZ,
-                        padding: Pad::Zero,
-                    }
-                    .format(w, off)
-                }),
-                TimezoneOffsetDoubleColon => off.map(|&(_, off)| {
-                    OffsetFormat {
-                        precision: OffsetPrecision::Seconds,
-                        colons: Colons::Colon,
-                        allow_zulu: false,
-                        padding: Pad::Zero,
-                    }
-                    .format(w, off)
-                }),
-                TimezoneOffsetTripleColon => off.map(|&(_, off)| {
-                    OffsetFormat {
-                        precision: OffsetPrecision::Hours,
-                        colons: Colons::None,
-                        allow_zulu: false,
-                        padding: Pad::Zero,
-                    }
-                    .format(w, off)
-                }),
-                Internal(InternalFixed { val: InternalInternal::TimezoneOffsetPermissive }) => {
-                    return Err(fmt::Error);
-                }
-                RFC2822 =>
-                // same as `%a, %d %b %Y %H:%M:%S %z`
-                {
-                    if let (Some(d), Some(t), Some(&(_, off))) = (date, time, off) {
-                        Some(write_rfc2822(w, crate::NaiveDateTime::new(*d, *t), off))
-                    } else {
-                        None
-                    }
-                }
-                RFC3339 =>
-                // same as `%Y-%m-%dT%H:%M:%S%.f%:z`
-                {
-                    if let (Some(d), Some(t), Some(&(_, off))) = (date, time, off) {
-                        Some(write_rfc3339(
-                            w,
-                            crate::NaiveDateTime::new(*d, *t),
-                            off.fix(),
-                            SecondsFormat::AutoSi,
-                            false,
-                        ))
-                    } else {
-                        None
-                    }
-                }
-            };
-
-            ret.unwrap_or(Err(fmt::Error)) // insufficient arguments for given format
-        }
-
-        Item::Error => Err(fmt::Error),
-    }
-}
-
-#[cfg(any(feature = "alloc", feature = "serde", feature = "rustc-serialize"))]
+#[cfg(any(feature = "alloc", feature = "serde"))]
 impl OffsetFormat {
     /// Writes an offset from UTC with the format defined by `self`.
     fn format(&self, w: &mut impl Write, off: FixedOffset) -> fmt::Result {
@@ -532,7 +481,7 @@
 
 /// Writes the date, time and offset to the string. same as `%Y-%m-%dT%H:%M:%S%.f%:z`
 #[inline]
-#[cfg(any(feature = "alloc", feature = "serde", feature = "rustc-serialize"))]
+#[cfg(any(feature = "alloc", feature = "serde"))]
 pub(crate) fn write_rfc3339(
     w: &mut impl Write,
     dt: NaiveDateTime,
diff --git a/crates/chrono/src/format/mod.rs b/crates/chrono/src/format/mod.rs
index a822882..cd4520c 100644
--- a/crates/chrono/src/format/mod.rs
+++ b/crates/chrono/src/format/mod.rs
@@ -16,8 +16,8 @@
 //! C's `strftime` format. The available options can be found [here](./strftime/index.html).
 //!
 //! # Example
-#![cfg_attr(not(feature = "std"), doc = "```ignore")]
-#![cfg_attr(feature = "std", doc = "```rust")]
+//! ```
+//! # #[cfg(feature = "alloc")] {
 //! use chrono::{NaiveDateTime, TimeZone, Utc};
 //!
 //! let date_time = Utc.with_ymd_and_hms(2020, 11, 10, 0, 1, 32).unwrap();
@@ -27,10 +27,11 @@
 //!
 //! let parsed = NaiveDateTime::parse_from_str(&formatted, "%Y-%m-%d %H:%M:%S")?.and_utc();
 //! assert_eq!(parsed, date_time);
+//! # }
 //! # Ok::<(), chrono::ParseError>(())
 //! ```
 
-#[cfg(all(not(feature = "std"), feature = "alloc"))]
+#[cfg(all(feature = "alloc", not(feature = "std"), not(test)))]
 use alloc::boxed::Box;
 use core::fmt;
 use core::str::FromStr;
@@ -56,7 +57,7 @@
 pub(crate) use formatting::write_hundreds;
 #[cfg(feature = "alloc")]
 pub(crate) use formatting::write_rfc2822;
-#[cfg(any(feature = "alloc", feature = "serde", feature = "rustc-serialize"))]
+#[cfg(any(feature = "alloc", feature = "serde"))]
 pub(crate) use formatting::write_rfc3339;
 pub use formatting::SecondsFormat;
 #[cfg(feature = "alloc")]
@@ -97,6 +98,7 @@
 /// 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.
+#[non_exhaustive]
 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
 pub enum Numeric {
     /// Full Gregorian year (FW=4, PW=∞).
@@ -168,6 +170,7 @@
 ///
 /// They have their own rules of formatting and parsing.
 /// Otherwise noted, they print in the specified cases but parse case-insensitively.
+#[non_exhaustive]
 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
 pub enum Fixed {
     /// Abbreviated month names.
@@ -363,7 +366,7 @@
     Item::Fixed(Fixed::Internal(InternalFixed { val }))
 }
 
-impl<'a> Item<'a> {
+impl Item<'_> {
     /// Convert items that contain a reference to the format string into an owned variant.
     #[cfg(any(feature = "alloc", feature = "std"))]
     pub fn to_owned(self) -> Item<'static> {
@@ -419,7 +422,7 @@
     /// All formatting items have been read but there is a remaining input.
     TooLong,
 
-    /// There was an error on the formatting string, or there were non-supported formating items.
+    /// There was an error on the formatting string, or there were non-supported formatting items.
     BadFormat,
 
     // TODO: Change this to `#[non_exhaustive]` (on the enum) with the next breaking release.
diff --git a/crates/chrono/src/format/parse.rs b/crates/chrono/src/format/parse.rs
index 26340d3..5a3a702 100644
--- a/crates/chrono/src/format/parse.rs
+++ b/crates/chrono/src/format/parse.rs
@@ -6,7 +6,6 @@
 
 use core::borrow::Borrow;
 use core::str;
-use core::usize;
 
 use super::scan;
 use super::{Fixed, InternalFixed, InternalInternal, Item, Numeric, Pad, Parsed};
@@ -250,7 +249,7 @@
     match parse_internal(parsed, s, items) {
         Ok("") => Ok(()),
         Ok(_) => Err(TOO_LONG), // if there are trailing chars it is an error
-        Err((_, e)) => Err(e),
+        Err(e) => Err(e),
     }
 }
 
@@ -277,14 +276,14 @@
     I: Iterator<Item = B>,
     B: Borrow<Item<'a>>,
 {
-    parse_internal(parsed, s, items).map_err(|(_s, e)| e)
+    parse_internal(parsed, s, items)
 }
 
 fn parse_internal<'a, 'b, I, B>(
     parsed: &mut Parsed,
     mut s: &'b str,
     items: I,
-) -> Result<&'b str, (&'b str, ParseError)>
+) -> Result<&'b str, ParseError>
 where
     I: Iterator<Item = B>,
     B: Borrow<Item<'a>>,
@@ -296,7 +295,7 @@
                     s = s_;
                     v
                 }
-                Err(e) => return Err((s, e)),
+                Err(e) => return Err(e),
             }
         }};
     }
@@ -305,10 +304,10 @@
         match *item.borrow() {
             Item::Literal(prefix) => {
                 if s.len() < prefix.len() {
-                    return Err((s, TOO_SHORT));
+                    return Err(TOO_SHORT);
                 }
                 if !s.starts_with(prefix) {
-                    return Err((s, INVALID));
+                    return Err(INVALID);
                 }
                 s = &s[prefix.len()..];
             }
@@ -316,10 +315,10 @@
             #[cfg(feature = "alloc")]
             Item::OwnedLiteral(ref prefix) => {
                 if s.len() < prefix.len() {
-                    return Err((s, TOO_SHORT));
+                    return Err(TOO_SHORT);
                 }
                 if !s.starts_with(&prefix[..]) {
-                    return Err((s, INVALID));
+                    return Err(INVALID);
                 }
                 s = &s[prefix.len()..];
             }
@@ -367,7 +366,7 @@
                 let v = if signed {
                     if s.starts_with('-') {
                         let v = try_consume!(scan::number(&s[1..], 1, usize::MAX));
-                        0i64.checked_sub(v).ok_or((s, OUT_OF_RANGE))?
+                        0i64.checked_sub(v).ok_or(OUT_OF_RANGE)?
                     } else if s.starts_with('+') {
                         try_consume!(scan::number(&s[1..], 1, usize::MAX))
                     } else {
@@ -377,7 +376,7 @@
                 } else {
                     try_consume!(scan::number(s, 1, width))
                 };
-                set(parsed, v).map_err(|e| (s, e))?;
+                set(parsed, v)?;
             }
 
             Item::Fixed(ref spec) => {
@@ -386,66 +385,66 @@
                 match spec {
                     &ShortMonthName => {
                         let month0 = try_consume!(scan::short_month0(s));
-                        parsed.set_month(i64::from(month0) + 1).map_err(|e| (s, e))?;
+                        parsed.set_month(i64::from(month0) + 1)?;
                     }
 
                     &LongMonthName => {
                         let month0 = try_consume!(scan::short_or_long_month0(s));
-                        parsed.set_month(i64::from(month0) + 1).map_err(|e| (s, e))?;
+                        parsed.set_month(i64::from(month0) + 1)?;
                     }
 
                     &ShortWeekdayName => {
                         let weekday = try_consume!(scan::short_weekday(s));
-                        parsed.set_weekday(weekday).map_err(|e| (s, e))?;
+                        parsed.set_weekday(weekday)?;
                     }
 
                     &LongWeekdayName => {
                         let weekday = try_consume!(scan::short_or_long_weekday(s));
-                        parsed.set_weekday(weekday).map_err(|e| (s, e))?;
+                        parsed.set_weekday(weekday)?;
                     }
 
                     &LowerAmPm | &UpperAmPm => {
                         if s.len() < 2 {
-                            return Err((s, TOO_SHORT));
+                            return Err(TOO_SHORT);
                         }
                         let ampm = match (s.as_bytes()[0] | 32, s.as_bytes()[1] | 32) {
                             (b'a', b'm') => false,
                             (b'p', b'm') => true,
-                            _ => return Err((s, INVALID)),
+                            _ => return Err(INVALID),
                         };
-                        parsed.set_ampm(ampm).map_err(|e| (s, e))?;
+                        parsed.set_ampm(ampm)?;
                         s = &s[2..];
                     }
 
                     &Nanosecond | &Nanosecond3 | &Nanosecond6 | &Nanosecond9 => {
                         if s.starts_with('.') {
                             let nano = try_consume!(scan::nanosecond(&s[1..]));
-                            parsed.set_nanosecond(nano).map_err(|e| (s, e))?;
+                            parsed.set_nanosecond(nano)?;
                         }
                     }
 
                     &Internal(InternalFixed { val: InternalInternal::Nanosecond3NoDot }) => {
                         if s.len() < 3 {
-                            return Err((s, TOO_SHORT));
+                            return Err(TOO_SHORT);
                         }
                         let nano = try_consume!(scan::nanosecond_fixed(s, 3));
-                        parsed.set_nanosecond(nano).map_err(|e| (s, e))?;
+                        parsed.set_nanosecond(nano)?;
                     }
 
                     &Internal(InternalFixed { val: InternalInternal::Nanosecond6NoDot }) => {
                         if s.len() < 6 {
-                            return Err((s, TOO_SHORT));
+                            return Err(TOO_SHORT);
                         }
                         let nano = try_consume!(scan::nanosecond_fixed(s, 6));
-                        parsed.set_nanosecond(nano).map_err(|e| (s, e))?;
+                        parsed.set_nanosecond(nano)?;
                     }
 
                     &Internal(InternalFixed { val: InternalInternal::Nanosecond9NoDot }) => {
                         if s.len() < 9 {
-                            return Err((s, TOO_SHORT));
+                            return Err(TOO_SHORT);
                         }
                         let nano = try_consume!(scan::nanosecond_fixed(s, 9));
-                        parsed.set_nanosecond(nano).map_err(|e| (s, e))?;
+                        parsed.set_nanosecond(nano)?;
                     }
 
                     &TimezoneName => {
@@ -463,7 +462,7 @@
                             false,
                             true,
                         ));
-                        parsed.set_offset(i64::from(offset)).map_err(|e| (s, e))?;
+                        parsed.set_offset(i64::from(offset))?;
                     }
 
                     &TimezoneOffsetColonZ | &TimezoneOffsetZ => {
@@ -474,7 +473,7 @@
                             false,
                             true,
                         ));
-                        parsed.set_offset(i64::from(offset)).map_err(|e| (s, e))?;
+                        parsed.set_offset(i64::from(offset))?;
                     }
                     &Internal(InternalFixed {
                         val: InternalInternal::TimezoneOffsetPermissive,
@@ -486,7 +485,7 @@
                             true,
                             true,
                         ));
-                        parsed.set_offset(i64::from(offset)).map_err(|e| (s, e))?;
+                        parsed.set_offset(i64::from(offset))?;
                     }
 
                     &RFC2822 => try_consume!(parse_rfc2822(parsed, s)),
@@ -501,7 +500,7 @@
             }
 
             Item::Error => {
-                return Err((s, BAD_FORMAT));
+                return Err(BAD_FORMAT);
             }
         }
     }
@@ -509,7 +508,7 @@
 }
 
 /// Accepts a relaxed form of RFC3339.
-/// A space or a 'T' are acepted as the separator between the date and time
+/// A space or a 'T' are accepted as the separator between the date and time
 /// parts. Additional spaces are allowed between each component.
 ///
 /// All of these examples are equivalent:
@@ -564,7 +563,7 @@
         Item::Space(""),
     ];
 
-    s = parse_internal(parsed, s, DATE_ITEMS.iter()).map_err(|(_s, e)| e)?;
+    s = parse_internal(parsed, s, DATE_ITEMS.iter())?;
 
     s = match s.as_bytes().first() {
         Some(&b't' | &b'T' | &b' ') => &s[1..],
@@ -572,7 +571,7 @@
         None => return Err(TOO_SHORT),
     };
 
-    s = parse_internal(parsed, s, TIME_ITEMS.iter()).map_err(|(_s, e)| e)?;
+    s = parse_internal(parsed, s, TIME_ITEMS.iter())?;
     s = s.trim_start();
     let (s, offset) = if s.len() >= 3 && "UTC".as_bytes().eq_ignore_ascii_case(&s.as_bytes()[..3]) {
         (&s[3..], 0)
diff --git a/crates/chrono/src/format/parsed.rs b/crates/chrono/src/format/parsed.rs
index 19f7f81..e14f03f 100644
--- a/crates/chrono/src/format/parsed.rs
+++ b/crates/chrono/src/format/parsed.rs
@@ -6,102 +6,168 @@
 
 use super::{ParseResult, IMPOSSIBLE, NOT_ENOUGH, OUT_OF_RANGE};
 use crate::naive::{NaiveDate, NaiveDateTime, NaiveTime};
-use crate::offset::{FixedOffset, LocalResult, Offset, TimeZone};
+use crate::offset::{FixedOffset, MappedLocalTime, Offset, TimeZone};
 use crate::{DateTime, Datelike, TimeDelta, Timelike, Weekday};
 
-/// Parsed parts of date and time. There are two classes of methods:
+/// A type to hold parsed fields of date and time that can check all fields are consistent.
 ///
-/// - `set_*` methods try to set given field(s) while checking for the consistency.
-///   It may or may not check for the range constraint immediately (for efficiency reasons).
+/// There are three classes of methods:
+///
+/// - `set_*` methods to set fields you have available. They do a basic range check, and if the
+///   same field is set more than once it is checked for consistency.
 ///
 /// - `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.
+///   They fully check that all fields are consistent and whether the date/datetime exists.
+///
+/// - Methods to inspect the parsed fields.
+///
+/// `Parsed` is used internally by all parsing functions in chrono. It is a public type so that it
+/// can be used to write custom parsers that reuse the resolving algorithm, or to inspect the
+/// results of a string parsed with chrono without converting it to concrete types.
+///
+/// # Resolving algorithm
+///
+/// Resolving date/time parts is littered with lots of corner cases, which is why common date/time
+/// parsers do not implement it correctly.
+///
+/// Chrono provides a complete resolution algorithm that checks all fields for consistency via the
+/// `Parsed` type.
+///
+/// As an easy example, consider RFC 2822. The [RFC 2822 date and time format] has a day of the week
+/// part, which should be consistent with the other date parts. But a `strptime`-based parse would
+/// happily accept inconsistent input:
+///
+/// ```python
+/// >>> import time
+/// >>> time.strptime('Wed, 31 Dec 2014 04:26:40 +0000',
+///                   '%a, %d %b %Y %H:%M:%S +0000')
+/// time.struct_time(tm_year=2014, tm_mon=12, tm_mday=31,
+///                  tm_hour=4, tm_min=26, tm_sec=40,
+///                  tm_wday=2, tm_yday=365, tm_isdst=-1)
+/// >>> time.strptime('Thu, 31 Dec 2014 04:26:40 +0000',
+///                   '%a, %d %b %Y %H:%M:%S +0000')
+/// time.struct_time(tm_year=2014, tm_mon=12, tm_mday=31,
+///                  tm_hour=4, tm_min=26, tm_sec=40,
+///                  tm_wday=3, tm_yday=365, tm_isdst=-1)
+/// ```
+///
+/// [RFC 2822 date and time format]: https://tools.ietf.org/html/rfc2822#section-3.3
+///
+/// # Example
+///
+/// Let's see how `Parsed` correctly detects the second RFC 2822 string from before is inconsistent.
+///
+/// ```
+/// # #[cfg(feature = "alloc")] {
+/// use chrono::format::{ParseErrorKind, Parsed};
+/// use chrono::Weekday;
+///
+/// let mut parsed = Parsed::new();
+/// parsed.set_weekday(Weekday::Wed)?;
+/// parsed.set_day(31)?;
+/// parsed.set_month(12)?;
+/// parsed.set_year(2014)?;
+/// parsed.set_hour(4)?;
+/// parsed.set_minute(26)?;
+/// parsed.set_second(40)?;
+/// parsed.set_offset(0)?;
+/// let dt = parsed.to_datetime()?;
+/// assert_eq!(dt.to_rfc2822(), "Wed, 31 Dec 2014 04:26:40 +0000");
+///
+/// let mut parsed = Parsed::new();
+/// parsed.set_weekday(Weekday::Thu)?; // changed to the wrong day
+/// parsed.set_day(31)?;
+/// parsed.set_month(12)?;
+/// parsed.set_year(2014)?;
+/// parsed.set_hour(4)?;
+/// parsed.set_minute(26)?;
+/// parsed.set_second(40)?;
+/// parsed.set_offset(0)?;
+/// let result = parsed.to_datetime();
+///
+/// assert!(result.is_err());
+/// if let Err(error) = result {
+///     assert_eq!(error.kind(), ParseErrorKind::Impossible);
+/// }
+/// # }
+/// # Ok::<(), chrono::ParseError>(())
+/// ```
+///
+/// The same using chrono's build-in parser for RFC 2822 (the [RFC2822 formatting item]) and
+/// [`format::parse()`] showing how to inspect a field on failure.
+///
+/// [RFC2822 formatting item]: crate::format::Fixed::RFC2822
+/// [`format::parse()`]: crate::format::parse()
+///
+/// ```
+/// # #[cfg(feature = "alloc")] {
+/// use chrono::format::{parse, Fixed, Item, Parsed};
+/// use chrono::Weekday;
+///
+/// let rfc_2822 = [Item::Fixed(Fixed::RFC2822)];
+///
+/// let mut parsed = Parsed::new();
+/// parse(&mut parsed, "Wed, 31 Dec 2014 04:26:40 +0000", rfc_2822.iter())?;
+/// let dt = parsed.to_datetime()?;
+///
+/// assert_eq!(dt.to_rfc2822(), "Wed, 31 Dec 2014 04:26:40 +0000");
+///
+/// let mut parsed = Parsed::new();
+/// parse(&mut parsed, "Thu, 31 Dec 2014 04:26:40 +0000", rfc_2822.iter())?;
+/// let result = parsed.to_datetime();
+///
+/// assert!(result.is_err());
+/// if result.is_err() {
+///     // What is the weekday?
+///     assert_eq!(parsed.weekday(), Some(Weekday::Thu));
+/// }
+/// # }
+/// # Ok::<(), chrono::ParseError>(())
+/// ```
 #[allow(clippy::manual_non_exhaustive)]
 #[derive(Clone, PartialEq, Eq, Debug, Default, Hash)]
 pub struct Parsed {
-    /// Year.
-    ///
-    /// This can be negative unlike [`year_div_100`](#structfield.year_div_100)
-    /// and [`year_mod_100`](#structfield.year_mod_100) fields.
+    #[doc(hidden)]
     pub year: Option<i32>,
-
-    /// Year divided by 100. Implies that the year is >= 1 BCE when set.
-    ///
-    /// Due to the common usage, if this field is missing but
-    /// [`year_mod_100`](#structfield.year_mod_100) is present,
-    /// it is inferred to 19 when `year_mod_100 >= 70` and 20 otherwise.
+    #[doc(hidden)]
     pub year_div_100: Option<i32>,
-
-    /// Year modulo 100. Implies that the year is >= 1 BCE when set.
+    #[doc(hidden)]
     pub year_mod_100: Option<i32>,
-
-    /// Year in the [ISO week date](../naive/struct.NaiveDate.html#week-date).
-    ///
-    /// This can be negative unlike [`isoyear_div_100`](#structfield.isoyear_div_100) and
-    /// [`isoyear_mod_100`](#structfield.isoyear_mod_100) fields.
+    #[doc(hidden)]
     pub isoyear: Option<i32>,
-
-    /// Year in the [ISO week date](../naive/struct.NaiveDate.html#week-date), divided by 100.
-    /// Implies that the year is >= 1 BCE when set.
-    ///
-    /// Due to the common usage, if this field is missing but
-    /// [`isoyear_mod_100`](#structfield.isoyear_mod_100) is present,
-    /// it is inferred to 19 when `isoyear_mod_100 >= 70` and 20 otherwise.
+    #[doc(hidden)]
     pub isoyear_div_100: Option<i32>,
-
-    /// Year in the [ISO week date](../naive/struct.NaiveDate.html#week-date), modulo 100.
-    /// Implies that the year is >= 1 BCE when set.
+    #[doc(hidden)]
     pub isoyear_mod_100: Option<i32>,
-
-    /// Month (1--12).
+    #[doc(hidden)]
     pub month: Option<u32>,
-
-    /// Week number, where the week 1 starts at the first Sunday of January
-    /// (0--53, 1--53 or 1--52 depending on the year).
+    #[doc(hidden)]
     pub week_from_sun: Option<u32>,
-
-    /// Week number, where the week 1 starts at the first Monday of January
-    /// (0--53, 1--53 or 1--52 depending on the year).
+    #[doc(hidden)]
     pub week_from_mon: Option<u32>,
-
-    /// [ISO week number](../naive/struct.NaiveDate.html#week-date)
-    /// (1--52 or 1--53 depending on the year).
+    #[doc(hidden)]
     pub isoweek: Option<u32>,
-
-    /// Day of the week.
+    #[doc(hidden)]
     pub weekday: Option<Weekday>,
-
-    /// Day of the year (1--365 or 1--366 depending on the year).
+    #[doc(hidden)]
     pub ordinal: Option<u32>,
-
-    /// Day of the month (1--28, 1--29, 1--30 or 1--31 depending on the month).
+    #[doc(hidden)]
     pub day: Option<u32>,
-
-    /// Hour number divided by 12 (0--1). 0 indicates AM and 1 indicates PM.
+    #[doc(hidden)]
     pub hour_div_12: Option<u32>,
-
-    /// Hour number modulo 12 (0--11).
+    #[doc(hidden)]
     pub hour_mod_12: Option<u32>,
-
-    /// Minute number (0--59).
+    #[doc(hidden)]
     pub minute: Option<u32>,
-
-    /// Second number (0--60, accounting for leap seconds).
+    #[doc(hidden)]
     pub second: Option<u32>,
-
-    /// The number of nanoseconds since the whole second (0--999,999,999).
+    #[doc(hidden)]
     pub nanosecond: Option<u32>,
-
-    /// The number of non-leap seconds since the midnight UTC on January 1, 1970.
-    ///
-    /// This can be off by one if [`second`](#structfield.second) is 60 (a leap second).
+    #[doc(hidden)]
     pub timestamp: Option<i64>,
-
-    /// Offset from the local time to UTC, in seconds.
+    #[doc(hidden)]
     pub offset: Option<i32>,
-
-    /// A dummy field to make this type not fully destructible (required for API stability).
-    // TODO: Change this to `#[non_exhaustive]` (on the enum) with the next breaking release.
+    #[doc(hidden)]
     _dummy: (),
 }
 
@@ -128,154 +194,351 @@
         Parsed::default()
     }
 
-    /// Tries to set the [`year`](#structfield.year) field from given value.
+    /// Set the [`year`](Parsed::year) field to the given value.
+    ///
+    /// The value can be negative, unlike the [`year_div_100`](Parsed::year_div_100) and
+    /// [`year_mod_100`](Parsed::year_mod_100) fields.
+    ///
+    /// # Errors
+    ///
+    /// Returns `OUT_OF_RANGE` if `value` is outside the range of an `i32`.
+    ///
+    /// Returns `IMPOSSIBLE` if this field was already set to a different value.
     #[inline]
     pub fn set_year(&mut self, value: i64) -> ParseResult<()> {
         set_if_consistent(&mut self.year, i32::try_from(value).map_err(|_| OUT_OF_RANGE)?)
     }
 
-    /// Tries to set the [`year_div_100`](#structfield.year_div_100) field from given value.
+    /// Set the [`year_div_100`](Parsed::year_div_100) field to the given value.
+    ///
+    /// # Errors
+    ///
+    /// Returns `OUT_OF_RANGE` if `value` is negative or if it is greater than `i32::MAX`.
+    ///
+    /// Returns `IMPOSSIBLE` if this field was already set to a different value.
     #[inline]
     pub fn set_year_div_100(&mut self, value: i64) -> ParseResult<()> {
-        if value < 0 {
+        if !(0..=i32::MAX as i64).contains(&value) {
             return Err(OUT_OF_RANGE);
         }
-        set_if_consistent(&mut self.year_div_100, i32::try_from(value).map_err(|_| OUT_OF_RANGE)?)
+        set_if_consistent(&mut self.year_div_100, value as i32)
     }
 
-    /// Tries to set the [`year_mod_100`](#structfield.year_mod_100) field from given value.
+    /// Set the [`year_mod_100`](Parsed::year_mod_100) field to the given value.
+    ///
+    /// When set it implies that the year is not negative.
+    ///
+    /// If this field is set while the [`year_div_100`](Parsed::year_div_100) field is missing (and
+    /// the full [`year`](Parsed::year) field is also not set), it assumes a default value for the
+    /// [`year_div_100`](Parsed::year_div_100) field.
+    /// The default is 19 when `year_mod_100 >= 70` and 20 otherwise.
+    ///
+    /// # Errors
+    ///
+    /// Returns `OUT_OF_RANGE` if `value` is negative or if it is greater than 99.
+    ///
+    /// Returns `IMPOSSIBLE` if this field was already set to a different value.
     #[inline]
     pub fn set_year_mod_100(&mut self, value: i64) -> ParseResult<()> {
-        if value < 0 {
+        if !(0..100).contains(&value) {
             return Err(OUT_OF_RANGE);
         }
-        set_if_consistent(&mut self.year_mod_100, i32::try_from(value).map_err(|_| OUT_OF_RANGE)?)
+        set_if_consistent(&mut self.year_mod_100, value as i32)
     }
 
-    /// Tries to set the [`isoyear`](#structfield.isoyear) field from given value.
+    /// Set the [`isoyear`](Parsed::isoyear) field, that is part of an [ISO 8601 week date], to the
+    /// given value.
+    ///
+    /// The value can be negative, unlike the [`isoyear_div_100`](Parsed::isoyear_div_100) and
+    /// [`isoyear_mod_100`](Parsed::isoyear_mod_100) fields.
+    ///
+    /// [ISO 8601 week date]: crate::NaiveDate#week-date
+    ///
+    /// # Errors
+    ///
+    /// Returns `OUT_OF_RANGE` if `value` is outside the range of an `i32`.
+    ///
+    /// Returns `IMPOSSIBLE` if this field was already set to a different value.
     #[inline]
     pub fn set_isoyear(&mut self, value: i64) -> ParseResult<()> {
         set_if_consistent(&mut self.isoyear, i32::try_from(value).map_err(|_| OUT_OF_RANGE)?)
     }
 
-    /// Tries to set the [`isoyear_div_100`](#structfield.isoyear_div_100) field from given value.
+    /// Set the [`isoyear_div_100`](Parsed::isoyear_div_100) field, that is part of an
+    /// [ISO 8601 week date], to the given value.
+    ///
+    /// [ISO 8601 week date]: crate::NaiveDate#week-date
+    ///
+    /// # Errors
+    ///
+    /// Returns `OUT_OF_RANGE` if `value` is negative or if it is greater than `i32::MAX`.
+    ///
+    /// Returns `IMPOSSIBLE` if this field was already set to a different value.
     #[inline]
     pub fn set_isoyear_div_100(&mut self, value: i64) -> ParseResult<()> {
-        if value < 0 {
+        if !(0..=i32::MAX as i64).contains(&value) {
             return Err(OUT_OF_RANGE);
         }
-        set_if_consistent(
-            &mut self.isoyear_div_100,
-            i32::try_from(value).map_err(|_| OUT_OF_RANGE)?,
-        )
+        set_if_consistent(&mut self.isoyear_div_100, value as i32)
     }
 
-    /// Tries to set the [`isoyear_mod_100`](#structfield.isoyear_mod_100) field from given value.
+    /// Set the [`isoyear_mod_100`](Parsed::isoyear_mod_100) field, that is part of an
+    /// [ISO 8601 week date], to the given value.
+    ///
+    /// When set it implies that the year is not negative.
+    ///
+    /// If this field is set while the [`isoyear_div_100`](Parsed::isoyear_div_100) field is missing
+    /// (and the full [`isoyear`](Parsed::isoyear) field is also not set), it assumes a default
+    /// value for the [`isoyear_div_100`](Parsed::isoyear_div_100) field.
+    /// The default is 19 when `year_mod_100 >= 70` and 20 otherwise.
+    ///
+    /// [ISO 8601 week date]: crate::NaiveDate#week-date
+    ///
+    /// # Errors
+    ///
+    /// Returns `OUT_OF_RANGE` if `value` is negative or if it is greater than 99.
+    ///
+    /// Returns `IMPOSSIBLE` if this field was already set to a different value.
     #[inline]
     pub fn set_isoyear_mod_100(&mut self, value: i64) -> ParseResult<()> {
-        if value < 0 {
+        if !(0..100).contains(&value) {
             return Err(OUT_OF_RANGE);
         }
-        set_if_consistent(
-            &mut self.isoyear_mod_100,
-            i32::try_from(value).map_err(|_| OUT_OF_RANGE)?,
-        )
+        set_if_consistent(&mut self.isoyear_mod_100, value as i32)
     }
 
-    /// Tries to set the [`month`](#structfield.month) field from given value.
+    /// Set the [`month`](Parsed::month) field to the given value.
+    ///
+    /// # Errors
+    ///
+    /// Returns `OUT_OF_RANGE` if `value` is not in the range 1-12.
+    ///
+    /// Returns `IMPOSSIBLE` if this field was already set to a different value.
     #[inline]
     pub fn set_month(&mut self, value: i64) -> ParseResult<()> {
-        set_if_consistent(&mut self.month, u32::try_from(value).map_err(|_| OUT_OF_RANGE)?)
+        if !(1..=12).contains(&value) {
+            return Err(OUT_OF_RANGE);
+        }
+        set_if_consistent(&mut self.month, value as u32)
     }
 
-    /// Tries to set the [`week_from_sun`](#structfield.week_from_sun) field from given value.
+    /// Set the [`week_from_sun`](Parsed::week_from_sun) week number field to the given value.
+    ///
+    /// Week 1 starts at the first Sunday of January.
+    ///
+    /// # Errors
+    ///
+    /// Returns `OUT_OF_RANGE` if `value` is not in the range 0-53.
+    ///
+    /// Returns `IMPOSSIBLE` if this field was already set to a different value.
     #[inline]
     pub fn set_week_from_sun(&mut self, value: i64) -> ParseResult<()> {
-        set_if_consistent(&mut self.week_from_sun, u32::try_from(value).map_err(|_| OUT_OF_RANGE)?)
+        if !(0..=53).contains(&value) {
+            return Err(OUT_OF_RANGE);
+        }
+        set_if_consistent(&mut self.week_from_sun, value as u32)
     }
 
-    /// Tries to set the [`week_from_mon`](#structfield.week_from_mon) field from given value.
+    /// Set the [`week_from_mon`](Parsed::week_from_mon) week number field to the given value.
+    /// Set the 'week number starting with Monday' field to the given value.
+    ///
+    /// Week 1 starts at the first Monday of January.
+    ///
+    /// # Errors
+    ///
+    /// Returns `OUT_OF_RANGE` if `value` is not in the range 0-53.
+    ///
+    /// Returns `IMPOSSIBLE` if this field was already set to a different value.
     #[inline]
     pub fn set_week_from_mon(&mut self, value: i64) -> ParseResult<()> {
-        set_if_consistent(&mut self.week_from_mon, u32::try_from(value).map_err(|_| OUT_OF_RANGE)?)
+        if !(0..=53).contains(&value) {
+            return Err(OUT_OF_RANGE);
+        }
+        set_if_consistent(&mut self.week_from_mon, value as u32)
     }
 
-    /// Tries to set the [`isoweek`](#structfield.isoweek) field from given value.
+    /// Set the [`isoweek`](Parsed::isoweek) field for an [ISO 8601 week date] to the given value.
+    ///
+    /// [ISO 8601 week date]: crate::NaiveDate#week-date
+    ///
+    /// # Errors
+    ///
+    /// Returns `OUT_OF_RANGE` if `value` is not in the range 1-53.
+    ///
+    /// Returns `IMPOSSIBLE` if this field was already set to a different value.
     #[inline]
     pub fn set_isoweek(&mut self, value: i64) -> ParseResult<()> {
-        set_if_consistent(&mut self.isoweek, u32::try_from(value).map_err(|_| OUT_OF_RANGE)?)
+        if !(1..=53).contains(&value) {
+            return Err(OUT_OF_RANGE);
+        }
+        set_if_consistent(&mut self.isoweek, value as u32)
     }
 
-    /// Tries to set the [`weekday`](#structfield.weekday) field from given value.
+    /// Set the [`weekday`](Parsed::weekday) field to the given value.
+    ///
+    /// # Errors
+    ///
+    /// Returns `IMPOSSIBLE` if this field was already set to a different value.
     #[inline]
     pub fn set_weekday(&mut self, value: Weekday) -> ParseResult<()> {
         set_if_consistent(&mut self.weekday, value)
     }
 
-    /// Tries to set the [`ordinal`](#structfield.ordinal) field from given value.
+    /// Set the [`ordinal`](Parsed::ordinal) (day of the year) field to the given value.
+    ///
+    /// # Errors
+    ///
+    /// Returns `OUT_OF_RANGE` if `value` is not in the range 1-366.
+    ///
+    /// Returns `IMPOSSIBLE` if this field was already set to a different value.
     #[inline]
     pub fn set_ordinal(&mut self, value: i64) -> ParseResult<()> {
-        set_if_consistent(&mut self.ordinal, u32::try_from(value).map_err(|_| OUT_OF_RANGE)?)
+        if !(1..=366).contains(&value) {
+            return Err(OUT_OF_RANGE);
+        }
+        set_if_consistent(&mut self.ordinal, value as u32)
     }
 
-    /// Tries to set the [`day`](#structfield.day) field from given value.
+    /// Set the [`day`](Parsed::day) of the month field to the given value.
+    ///
+    /// # Errors
+    ///
+    /// Returns `OUT_OF_RANGE` if `value` is not in the range 1-31.
+    ///
+    /// Returns `IMPOSSIBLE` if this field was already set to a different value.
     #[inline]
     pub fn set_day(&mut self, value: i64) -> ParseResult<()> {
-        set_if_consistent(&mut self.day, u32::try_from(value).map_err(|_| OUT_OF_RANGE)?)
+        if !(1..=31).contains(&value) {
+            return Err(OUT_OF_RANGE);
+        }
+        set_if_consistent(&mut self.day, value as u32)
     }
 
-    /// Tries to set the [`hour_div_12`](#structfield.hour_div_12) field from given value.
-    /// (`false` for AM, `true` for PM)
+    /// Set the [`hour_div_12`](Parsed::hour_div_12) am/pm field to the given value.
+    ///
+    /// `false` indicates AM and `true` indicates PM.
+    ///
+    /// # Errors
+    ///
+    /// Returns `IMPOSSIBLE` if this field was already set to a different value.
     #[inline]
     pub fn set_ampm(&mut self, value: bool) -> ParseResult<()> {
-        set_if_consistent(&mut self.hour_div_12, u32::from(value))
+        set_if_consistent(&mut self.hour_div_12, value as u32)
     }
 
-    /// Tries to set the [`hour_mod_12`](#structfield.hour_mod_12) field from
-    /// given hour number in 12-hour clocks.
+    /// Set the [`hour_mod_12`](Parsed::hour_mod_12) field, for the hour number in 12-hour clocks,
+    /// to the given value.
+    ///
+    /// Value must be in the canonical range of 1-12.
+    /// It will internally be stored as 0-11 (`value % 12`).
+    ///
+    /// # Errors
+    ///
+    /// Returns `OUT_OF_RANGE` if `value` is not in the range 1-12.
+    ///
+    /// Returns `IMPOSSIBLE` if this field was already set to a different value.
     #[inline]
-    pub fn set_hour12(&mut self, value: i64) -> ParseResult<()> {
+    pub fn set_hour12(&mut self, mut value: i64) -> ParseResult<()> {
         if !(1..=12).contains(&value) {
             return Err(OUT_OF_RANGE);
         }
-        set_if_consistent(&mut self.hour_mod_12, value as u32 % 12)
+        if value == 12 {
+            value = 0
+        }
+        set_if_consistent(&mut self.hour_mod_12, value as u32)
     }
 
-    /// Tries to set both [`hour_div_12`](#structfield.hour_div_12) and
-    /// [`hour_mod_12`](#structfield.hour_mod_12) fields from given value.
+    /// Set the [`hour_div_12`](Parsed::hour_div_12) and [`hour_mod_12`](Parsed::hour_mod_12)
+    /// fields to the given value for a 24-hour clock.
+    ///
+    /// # Errors
+    ///
+    /// May return `OUT_OF_RANGE` if `value` is not in the range 0-23.
+    /// Currently only checks the value is not out of range for a `u32`.
+    ///
+    /// Returns `IMPOSSIBLE` one of the fields was already set to a different value.
     #[inline]
     pub fn set_hour(&mut self, value: i64) -> ParseResult<()> {
-        let v = u32::try_from(value).map_err(|_| OUT_OF_RANGE)?;
-        set_if_consistent(&mut self.hour_div_12, v / 12)?;
-        set_if_consistent(&mut self.hour_mod_12, v % 12)?;
-        Ok(())
+        let (hour_div_12, hour_mod_12) = match value {
+            hour @ 0..=11 => (0, hour as u32),
+            hour @ 12..=23 => (1, hour as u32 - 12),
+            _ => return Err(OUT_OF_RANGE),
+        };
+        set_if_consistent(&mut self.hour_div_12, hour_div_12)?;
+        set_if_consistent(&mut self.hour_mod_12, hour_mod_12)
     }
 
-    /// Tries to set the [`minute`](#structfield.minute) field from given value.
+    /// Set the [`minute`](Parsed::minute) field to the given value.
+    ///
+    /// # Errors
+    ///
+    /// Returns `OUT_OF_RANGE` if `value` is not in the range 0-59.
+    ///
+    /// Returns `IMPOSSIBLE` if this field was already set to a different value.
     #[inline]
     pub fn set_minute(&mut self, value: i64) -> ParseResult<()> {
-        set_if_consistent(&mut self.minute, u32::try_from(value).map_err(|_| OUT_OF_RANGE)?)
+        if !(0..=59).contains(&value) {
+            return Err(OUT_OF_RANGE);
+        }
+        set_if_consistent(&mut self.minute, value as u32)
     }
 
-    /// Tries to set the [`second`](#structfield.second) field from given value.
+    /// Set the [`second`](Parsed::second) field to the given value.
+    ///
+    /// The value can be 60 in the case of a leap second.
+    ///
+    /// # Errors
+    ///
+    /// Returns `OUT_OF_RANGE` if `value` is not in the range 0-60.
+    ///
+    /// Returns `IMPOSSIBLE` if this field was already set to a different value.
     #[inline]
     pub fn set_second(&mut self, value: i64) -> ParseResult<()> {
-        set_if_consistent(&mut self.second, u32::try_from(value).map_err(|_| OUT_OF_RANGE)?)
+        if !(0..=60).contains(&value) {
+            return Err(OUT_OF_RANGE);
+        }
+        set_if_consistent(&mut self.second, value as u32)
     }
 
-    /// Tries to set the [`nanosecond`](#structfield.nanosecond) field from given value.
+    /// Set the [`nanosecond`](Parsed::nanosecond) field to the given value.
+    ///
+    /// This is the number of nanoseconds since the whole second.
+    ///
+    /// # Errors
+    ///
+    /// Returns `OUT_OF_RANGE` if `value` is not in the range 0-999,999,999.
+    ///
+    /// Returns `IMPOSSIBLE` if this field was already set to a different value.
     #[inline]
     pub fn set_nanosecond(&mut self, value: i64) -> ParseResult<()> {
-        set_if_consistent(&mut self.nanosecond, u32::try_from(value).map_err(|_| OUT_OF_RANGE)?)
+        if !(0..=999_999_999).contains(&value) {
+            return Err(OUT_OF_RANGE);
+        }
+        set_if_consistent(&mut self.nanosecond, value as u32)
     }
 
-    /// Tries to set the [`timestamp`](#structfield.timestamp) field from given value.
+    /// Set the [`timestamp`](Parsed::timestamp) field to the given value.
+    ///
+    /// A Unix timestamp is defined as the number of non-leap seconds since midnight UTC on
+    /// January 1, 1970.
+    ///
+    /// # Errors
+    ///
+    /// Returns `IMPOSSIBLE` if this field was already set to a different value.
     #[inline]
     pub fn set_timestamp(&mut self, value: i64) -> ParseResult<()> {
         set_if_consistent(&mut self.timestamp, value)
     }
 
-    /// Tries to set the [`offset`](#structfield.offset) field from given value.
+    /// Set the [`offset`](Parsed::offset) field to the given value.
+    ///
+    /// The offset is in seconds from local time to UTC.
+    ///
+    /// # Errors
+    ///
+    /// Returns `OUT_OF_RANGE` if `value` is outside the range of an `i32`.
+    ///
+    /// Returns `IMPOSSIBLE` if this field was already set to a different value.
     #[inline]
     pub fn set_offset(&mut self, value: i64) -> ParseResult<()> {
         set_if_consistent(&mut self.offset, i32::try_from(value).map_err(|_| OUT_OF_RANGE)?)
@@ -292,6 +555,18 @@
     ///
     /// Gregorian year and ISO week date year can have their century number (`*_div_100`) omitted,
     /// the two-digit year is used to guess the century number then.
+    ///
+    /// It checks all given date fields are consistent with each other.
+    ///
+    /// # Errors
+    ///
+    /// This method returns:
+    /// - `IMPOSSIBLE` if any of the date fields conflict.
+    /// - `NOT_ENOUGH` if there are not enough fields set in `Parsed` for a complete date.
+    /// - `OUT_OF_RANGE`
+    ///   - if any of the date fields of `Parsed` are set to a value beyond their acceptable range.
+    ///   - if the value would be outside the range of a [`NaiveDate`].
+    ///   - if the date does not exist.
     pub fn to_naive_date(&self) -> ParseResult<NaiveDate> {
         fn resolve_year(
             y: Option<i32>,
@@ -309,7 +584,7 @@
                 // we should filter a negative full year first.
                 (Some(y), q, r @ Some(0..=99)) | (Some(y), q, r @ None) => {
                     if y < 0 {
-                        return Err(OUT_OF_RANGE);
+                        return Err(IMPOSSIBLE);
                     }
                     let q_ = y / 100;
                     let r_ = y % 100;
@@ -324,7 +599,7 @@
                 // reconstruct the full year. make sure that the result is always positive.
                 (None, Some(q), Some(r @ 0..=99)) => {
                     if q < 0 {
-                        return Err(OUT_OF_RANGE);
+                        return Err(IMPOSSIBLE);
                     }
                     let y = q.checked_mul(100).and_then(|v| v.checked_add(r));
                     Ok(Some(y.ok_or(OUT_OF_RANGE)?))
@@ -404,71 +679,15 @@
                 (verify_ymd(date) && verify_isoweekdate(date) && verify_ordinal(date), date)
             }
 
-            (
-                Some(year),
-                _,
-                &Parsed { week_from_sun: Some(week_from_sun), weekday: Some(weekday), .. },
-            ) => {
+            (Some(year), _, &Parsed { week_from_sun: Some(week), weekday: Some(weekday), .. }) => {
                 // year, week (starting at 1st Sunday), day of the week
-                let newyear = NaiveDate::from_yo_opt(year, 1).ok_or(OUT_OF_RANGE)?;
-                let firstweek = match newyear.weekday() {
-                    Weekday::Sun => 0,
-                    Weekday::Mon => 6,
-                    Weekday::Tue => 5,
-                    Weekday::Wed => 4,
-                    Weekday::Thu => 3,
-                    Weekday::Fri => 2,
-                    Weekday::Sat => 1,
-                };
-
-                // `firstweek+1`-th day of January is the beginning of the week 1.
-                if week_from_sun > 53 {
-                    return Err(OUT_OF_RANGE);
-                } // can it overflow?
-                let ndays = firstweek
-                    + (week_from_sun as i32 - 1) * 7
-                    + weekday.num_days_from_sunday() as i32;
-                let date = newyear
-                    .checked_add_signed(TimeDelta::days(i64::from(ndays)))
-                    .ok_or(OUT_OF_RANGE)?;
-                if date.year() != year {
-                    return Err(OUT_OF_RANGE);
-                } // early exit for correct error
-
+                let date = resolve_week_date(year, week, weekday, Weekday::Sun)?;
                 (verify_ymd(date) && verify_isoweekdate(date) && verify_ordinal(date), date)
             }
 
-            (
-                Some(year),
-                _,
-                &Parsed { week_from_mon: Some(week_from_mon), weekday: Some(weekday), .. },
-            ) => {
+            (Some(year), _, &Parsed { week_from_mon: Some(week), weekday: Some(weekday), .. }) => {
                 // year, week (starting at 1st Monday), day of the week
-                let newyear = NaiveDate::from_yo_opt(year, 1).ok_or(OUT_OF_RANGE)?;
-                let firstweek = match newyear.weekday() {
-                    Weekday::Sun => 1,
-                    Weekday::Mon => 0,
-                    Weekday::Tue => 6,
-                    Weekday::Wed => 5,
-                    Weekday::Thu => 4,
-                    Weekday::Fri => 3,
-                    Weekday::Sat => 2,
-                };
-
-                // `firstweek+1`-th day of January is the beginning of the week 1.
-                if week_from_mon > 53 {
-                    return Err(OUT_OF_RANGE);
-                } // can it overflow?
-                let ndays = firstweek
-                    + (week_from_mon as i32 - 1) * 7
-                    + weekday.num_days_from_monday() as i32;
-                let date = newyear
-                    .checked_add_signed(TimeDelta::days(i64::from(ndays)))
-                    .ok_or(OUT_OF_RANGE)?;
-                if date.year() != year {
-                    return Err(OUT_OF_RANGE);
-                } // early exit for correct error
-
+                let date = resolve_week_date(year, week, weekday, Weekday::Mon)?;
                 (verify_ymd(date) && verify_isoweekdate(date) && verify_ordinal(date), date)
             }
 
@@ -498,6 +717,14 @@
     /// - Hour, minute, second, nanosecond.
     ///
     /// It is able to handle leap seconds when given second is 60.
+    ///
+    /// # Errors
+    ///
+    /// This method returns:
+    /// - `OUT_OF_RANGE` if any of the time fields of `Parsed` are set to a value beyond
+    ///   their acceptable range.
+    /// - `NOT_ENOUGH` if an hour field is missing, if AM/PM is missing in a 12-hour clock,
+    ///   if minutes are missing, or if seconds are missing while the nanosecond field is present.
     pub fn to_naive_time(&self) -> ParseResult<NaiveTime> {
         let hour_div_12 = match self.hour_div_12 {
             Some(v @ 0..=1) => v,
@@ -533,13 +760,25 @@
         NaiveTime::from_hms_nano_opt(hour, minute, second, nano).ok_or(OUT_OF_RANGE)
     }
 
-    /// Returns a parsed naive date and time out of given fields,
-    /// except for the [`offset`](#structfield.offset) field (assumed to have a given value).
-    /// This is required for parsing a local time or other known-timezone inputs.
+    /// Returns a parsed naive date and time out of given fields, except for the offset field.
     ///
-    /// This method is able to determine the combined date and time
-    /// from date and time fields or a single [`timestamp`](#structfield.timestamp) field.
-    /// Either way those fields have to be consistent to each other.
+    /// The offset is assumed to have a given value. It is not compared against the offset field set
+    /// in the `Parsed` type, so it is allowed to be inconsistent.
+    ///
+    /// This method is able to determine the combined date and time from date and time fields or
+    /// from a single timestamp field. It checks all fields are consistent with each other.
+    ///
+    /// # Errors
+    ///
+    /// This method returns:
+    /// - `IMPOSSIBLE`  if any of the date fields conflict, or if a timestamp conflicts with any of
+    ///   the other fields.
+    /// - `NOT_ENOUGH` if there are not enough fields set in `Parsed` for a complete datetime.
+    /// - `OUT_OF_RANGE`
+    ///   - if any of the date or time fields of `Parsed` are set to a value beyond their acceptable
+    ///     range.
+    ///   - if the value would be outside the range of a [`NaiveDateTime`].
+    ///   - if the date does not exist.
     pub fn to_naive_datetime_with_offset(&self, offset: i32) -> ParseResult<NaiveDateTime> {
         let date = self.to_naive_date();
         let time = self.to_naive_time();
@@ -548,7 +787,7 @@
 
             // verify the timestamp field if any
             // the following is safe, `timestamp` is very limited in range
-            let timestamp = datetime.timestamp() - i64::from(offset);
+            let timestamp = datetime.and_utc().timestamp() - i64::from(offset);
             if let Some(given_timestamp) = self.timestamp {
                 // if `datetime` represents a leap second, it might be off by one second.
                 if given_timestamp != timestamp
@@ -573,8 +812,7 @@
 
             // reconstruct date and time fields from timestamp
             let ts = timestamp.checked_add(i64::from(offset)).ok_or(OUT_OF_RANGE)?;
-            let datetime = NaiveDateTime::from_timestamp_opt(ts, 0);
-            let mut datetime = datetime.ok_or(OUT_OF_RANGE)?;
+            let mut datetime = DateTime::from_timestamp(ts, 0).ok_or(OUT_OF_RANGE)?.naive_utc();
 
             // fill year, ordinal, hour, minute and second fields from timestamp.
             // if existing fields are consistent, this will allow the full date/time reconstruction.
@@ -586,7 +824,7 @@
                     59 => {}
                     // `datetime` is known to be off by one second.
                     0 => {
-                        datetime -= TimeDelta::seconds(1);
+                        datetime -= TimeDelta::try_seconds(1).unwrap();
                     }
                     // otherwise it is impossible.
                     _ => return Err(IMPOSSIBLE),
@@ -613,16 +851,34 @@
     }
 
     /// Returns a parsed fixed time zone offset out of given fields.
+    ///
+    /// # Errors
+    ///
+    /// This method returns:
+    /// - `OUT_OF_RANGE` if the offset is out of range for a `FixedOffset`.
+    /// - `NOT_ENOUGH` if the offset field is not set.
     pub fn to_fixed_offset(&self) -> ParseResult<FixedOffset> {
-        self.offset.and_then(FixedOffset::east_opt).ok_or(OUT_OF_RANGE)
+        FixedOffset::east_opt(self.offset.ok_or(NOT_ENOUGH)?).ok_or(OUT_OF_RANGE)
     }
 
     /// Returns a parsed timezone-aware date and time out of given fields.
     ///
-    /// This method is able to determine the combined date and time
-    /// from date and time fields or a single [`timestamp`](#structfield.timestamp) field,
-    /// plus a time zone offset.
-    /// Either way those fields have to be consistent to each other.
+    /// This method is able to determine the combined date and time from date, time and offset
+    /// fields, and/or from a single timestamp field. It checks all fields are consistent with each
+    /// other.
+    ///
+    /// # Errors
+    ///
+    /// This method returns:
+    /// - `IMPOSSIBLE`  if any of the date fields conflict, or if a timestamp conflicts with any of
+    ///   the other fields.
+    /// - `NOT_ENOUGH` if there are not enough fields set in `Parsed` for a complete datetime
+    ///   including offset from UTC.
+    /// - `OUT_OF_RANGE`
+    ///   - if any of the fields of `Parsed` are set to a value beyond their acceptable
+    ///     range.
+    ///   - if the value would be outside the range of a [`NaiveDateTime`] or [`FixedOffset`].
+    ///   - if the date does not exist.
     pub fn to_datetime(&self) -> ParseResult<DateTime<FixedOffset>> {
         // If there is no explicit offset, consider a timestamp value as indication of a UTC value.
         let offset = match (self.offset, self.timestamp) {
@@ -634,21 +890,37 @@
         let offset = FixedOffset::east_opt(offset).ok_or(OUT_OF_RANGE)?;
 
         match offset.from_local_datetime(&datetime) {
-            LocalResult::None => Err(IMPOSSIBLE),
-            LocalResult::Single(t) => Ok(t),
-            LocalResult::Ambiguous(..) => Err(NOT_ENOUGH),
+            MappedLocalTime::None => Err(IMPOSSIBLE),
+            MappedLocalTime::Single(t) => Ok(t),
+            MappedLocalTime::Ambiguous(..) => Err(NOT_ENOUGH),
         }
     }
 
     /// Returns a parsed timezone-aware date and time out of given fields,
-    /// with an additional `TimeZone` used to interpret and validate the local date.
+    /// with an additional [`TimeZone`] used to interpret and validate the local date.
     ///
-    /// This method is able to determine the combined date and time
-    /// from date and time fields or a single [`timestamp`](#structfield.timestamp) field,
-    /// plus a time zone offset.
-    /// Either way those fields have to be consistent to each other.
-    /// If parsed fields include an UTC offset, it also has to be consistent to
-    /// [`offset`](#structfield.offset).
+    /// This method is able to determine the combined date and time from date and time, and/or from
+    /// a single timestamp field. It checks all fields are consistent with each other.
+    ///
+    /// If the parsed fields include an UTC offset, it also has to be consistent with the offset in
+    /// the provided `tz` time zone for that datetime.
+    ///
+    /// # Errors
+    ///
+    /// This method returns:
+    /// - `IMPOSSIBLE`
+    ///   - if any of the date fields conflict, if a timestamp conflicts with any of the other
+    ///     fields, or if the offset field is set but differs from the offset at that time in the
+    ///     `tz` time zone.
+    ///   - if the local datetime does not exists in the provided time zone (because it falls in a
+    ///     transition due to for example DST).
+    /// - `NOT_ENOUGH` if there are not enough fields set in `Parsed` for a complete datetime, or if
+    ///   the local time in the provided time zone is ambiguous (because it falls in a transition
+    ///   due to for example DST) while there is no offset field or timestamp field set.
+    /// - `OUT_OF_RANGE`
+    ///   - if the value would be outside the range of a [`NaiveDateTime`] or [`FixedOffset`].
+    ///   - if any of the fields of `Parsed` are set to a value beyond their acceptable range.
+    ///   - if the date does not exist.
     pub fn to_datetime_with_timezone<Tz: TimeZone>(&self, tz: &Tz) -> ParseResult<DateTime<Tz>> {
         // if we have `timestamp` specified, guess an offset from that.
         let mut guessed_offset = 0;
@@ -656,8 +928,8 @@
             // make a naive `DateTime` from given timestamp and (if any) nanosecond.
             // an empty `nanosecond` is always equal to zero, so missing nanosecond is fine.
             let nanosecond = self.nanosecond.unwrap_or(0);
-            let dt = NaiveDateTime::from_timestamp_opt(timestamp, nanosecond);
-            let dt = dt.ok_or(OUT_OF_RANGE)?;
+            let dt =
+                DateTime::from_timestamp(timestamp, nanosecond).ok_or(OUT_OF_RANGE)?.naive_utc();
             guessed_offset = tz.offset_from_utc_datetime(&dt).fix().local_minus_utc();
         }
 
@@ -674,15 +946,15 @@
         // it will be 0 otherwise, but this is fine as the algorithm ignores offset for that case.
         let datetime = self.to_naive_datetime_with_offset(guessed_offset)?;
         match tz.from_local_datetime(&datetime) {
-            LocalResult::None => Err(IMPOSSIBLE),
-            LocalResult::Single(t) => {
+            MappedLocalTime::None => Err(IMPOSSIBLE),
+            MappedLocalTime::Single(t) => {
                 if check_offset(&t) {
                     Ok(t)
                 } else {
                     Err(IMPOSSIBLE)
                 }
             }
-            LocalResult::Ambiguous(min, max) => {
+            MappedLocalTime::Ambiguous(min, max) => {
                 // try to disambiguate two possible local dates by offset.
                 match (check_offset(&min), check_offset(&max)) {
                     (false, false) => Err(IMPOSSIBLE),
@@ -693,6 +965,201 @@
             }
         }
     }
+
+    /// Get the `year` field if set.
+    ///
+    /// See also [`set_year()`](Parsed::set_year).
+    #[inline]
+    pub fn year(&self) -> Option<i32> {
+        self.year
+    }
+
+    /// Get the `year_div_100` field if set.
+    ///
+    /// See also [`set_year_div_100()`](Parsed::set_year_div_100).
+    #[inline]
+    pub fn year_div_100(&self) -> Option<i32> {
+        self.year_div_100
+    }
+
+    /// Get the `year_mod_100` field if set.
+    ///
+    /// See also [`set_year_mod_100()`](Parsed::set_year_mod_100).
+    #[inline]
+    pub fn year_mod_100(&self) -> Option<i32> {
+        self.year_mod_100
+    }
+
+    /// Get the `isoyear` field that is part of an [ISO 8601 week date] if set.
+    ///
+    /// See also [`set_isoyear()`](Parsed::set_isoyear).
+    ///
+    /// [ISO 8601 week date]: crate::NaiveDate#week-date
+    #[inline]
+    pub fn isoyear(&self) -> Option<i32> {
+        self.isoyear
+    }
+
+    /// Get the `isoyear_div_100` field that is part of an [ISO 8601 week date] if set.
+    ///
+    /// See also [`set_isoyear_div_100()`](Parsed::set_isoyear_div_100).
+    ///
+    /// [ISO 8601 week date]: crate::NaiveDate#week-date
+    #[inline]
+    pub fn isoyear_div_100(&self) -> Option<i32> {
+        self.isoyear_div_100
+    }
+
+    /// Get the `isoyear_mod_100` field that is part of an [ISO 8601 week date] if set.
+    ///
+    /// See also [`set_isoyear_mod_100()`](Parsed::set_isoyear_mod_100).
+    ///
+    /// [ISO 8601 week date]: crate::NaiveDate#week-date
+    #[inline]
+    pub fn isoyear_mod_100(&self) -> Option<i32> {
+        self.isoyear_mod_100
+    }
+
+    /// Get the `month` field if set.
+    ///
+    /// See also [`set_month()`](Parsed::set_month).
+    #[inline]
+    pub fn month(&self) -> Option<u32> {
+        self.month
+    }
+
+    /// Get the `week_from_sun` field if set.
+    ///
+    /// See also [`set_week_from_sun()`](Parsed::set_week_from_sun).
+    #[inline]
+    pub fn week_from_sun(&self) -> Option<u32> {
+        self.week_from_sun
+    }
+
+    /// Get the `week_from_mon` field if set.
+    ///
+    /// See also [`set_week_from_mon()`](Parsed::set_week_from_mon).
+    #[inline]
+    pub fn week_from_mon(&self) -> Option<u32> {
+        self.week_from_mon
+    }
+
+    /// Get the `isoweek` field that is part of an [ISO 8601 week date] if set.
+    ///
+    /// See also [`set_isoweek()`](Parsed::set_isoweek).
+    ///
+    /// [ISO 8601 week date]: crate::NaiveDate#week-date
+    #[inline]
+    pub fn isoweek(&self) -> Option<u32> {
+        self.isoweek
+    }
+
+    /// Get the `weekday` field if set.
+    ///
+    /// See also [`set_weekday()`](Parsed::set_weekday).
+    #[inline]
+    pub fn weekday(&self) -> Option<Weekday> {
+        self.weekday
+    }
+
+    /// Get the `ordinal` (day of the year) field if set.
+    ///
+    /// See also [`set_ordinal()`](Parsed::set_ordinal).
+    #[inline]
+    pub fn ordinal(&self) -> Option<u32> {
+        self.ordinal
+    }
+
+    /// Get the `day` of the month field if set.
+    ///
+    /// See also [`set_day()`](Parsed::set_day).
+    #[inline]
+    pub fn day(&self) -> Option<u32> {
+        self.day
+    }
+
+    /// Get the `hour_div_12` field (am/pm) if set.
+    ///
+    /// 0 indicates AM and 1 indicates PM.
+    ///
+    /// See also [`set_ampm()`](Parsed::set_ampm) and [`set_hour()`](Parsed::set_hour).
+    #[inline]
+    pub fn hour_div_12(&self) -> Option<u32> {
+        self.hour_div_12
+    }
+
+    /// Get the `hour_mod_12` field if set.
+    ///
+    /// See also [`set_hour12()`](Parsed::set_hour12) and [`set_hour()`](Parsed::set_hour).
+    pub fn hour_mod_12(&self) -> Option<u32> {
+        self.hour_mod_12
+    }
+
+    /// Get the `minute` field if set.
+    ///
+    /// See also [`set_minute()`](Parsed::set_minute).
+    #[inline]
+    pub fn minute(&self) -> Option<u32> {
+        self.minute
+    }
+
+    /// Get the `second` field if set.
+    ///
+    /// See also [`set_second()`](Parsed::set_second).
+    #[inline]
+    pub fn second(&self) -> Option<u32> {
+        self.second
+    }
+
+    /// Get the `nanosecond` field if set.
+    ///
+    /// See also [`set_nanosecond()`](Parsed::set_nanosecond).
+    #[inline]
+    pub fn nanosecond(&self) -> Option<u32> {
+        self.nanosecond
+    }
+
+    /// Get the `timestamp` field if set.
+    ///
+    /// See also [`set_timestamp()`](Parsed::set_timestamp).
+    #[inline]
+    pub fn timestamp(&self) -> Option<i64> {
+        self.timestamp
+    }
+
+    /// Get the `offset` field if set.
+    ///
+    /// See also [`set_offset()`](Parsed::set_offset).
+    #[inline]
+    pub fn offset(&self) -> Option<i32> {
+        self.offset
+    }
+}
+
+/// Create a `NaiveDate` when given a year, week, weekday, and the definition at which day of the
+/// week a week starts.
+///
+/// Returns `IMPOSSIBLE` if `week` is `0` or `53` and the `weekday` falls outside the year.
+fn resolve_week_date(
+    year: i32,
+    week: u32,
+    weekday: Weekday,
+    week_start_day: Weekday,
+) -> ParseResult<NaiveDate> {
+    if week > 53 {
+        return Err(OUT_OF_RANGE);
+    }
+
+    let first_day_of_year = NaiveDate::from_yo_opt(year, 1).ok_or(OUT_OF_RANGE)?;
+    // Ordinal of the day at which week 1 starts.
+    let first_week_start = 1 + week_start_day.days_since(first_day_of_year.weekday()) as i32;
+    // Number of the `weekday`, which is 0 for the first day of the week.
+    let weekday = weekday.days_since(week_start_day) as i32;
+    let ordinal = first_week_start + (week as i32 - 1) * 7 + weekday;
+    if ordinal <= 0 {
+        return Err(IMPOSSIBLE);
+    }
+    first_day_of_year.with_ordinal(ordinal as u32).ok_or(IMPOSSIBLE)
 }
 
 #[cfg(test)]
@@ -776,6 +1243,102 @@
     }
 
     #[test]
+    fn test_parsed_set_range() {
+        assert_eq!(Parsed::new().set_year(i32::MIN as i64 - 1), Err(OUT_OF_RANGE));
+        assert!(Parsed::new().set_year(i32::MIN as i64).is_ok());
+        assert!(Parsed::new().set_year(i32::MAX as i64).is_ok());
+        assert_eq!(Parsed::new().set_year(i32::MAX as i64 + 1), Err(OUT_OF_RANGE));
+
+        assert_eq!(Parsed::new().set_year_div_100(-1), Err(OUT_OF_RANGE));
+        assert!(Parsed::new().set_year_div_100(0).is_ok());
+        assert!(Parsed::new().set_year_div_100(i32::MAX as i64).is_ok());
+        assert_eq!(Parsed::new().set_year_div_100(i32::MAX as i64 + 1), Err(OUT_OF_RANGE));
+
+        assert_eq!(Parsed::new().set_year_mod_100(-1), Err(OUT_OF_RANGE));
+        assert!(Parsed::new().set_year_mod_100(0).is_ok());
+        assert!(Parsed::new().set_year_mod_100(99).is_ok());
+        assert_eq!(Parsed::new().set_year_mod_100(100), Err(OUT_OF_RANGE));
+
+        assert_eq!(Parsed::new().set_isoyear(i32::MIN as i64 - 1), Err(OUT_OF_RANGE));
+        assert!(Parsed::new().set_isoyear(i32::MIN as i64).is_ok());
+        assert!(Parsed::new().set_isoyear(i32::MAX as i64).is_ok());
+        assert_eq!(Parsed::new().set_isoyear(i32::MAX as i64 + 1), Err(OUT_OF_RANGE));
+
+        assert_eq!(Parsed::new().set_isoyear_div_100(-1), Err(OUT_OF_RANGE));
+        assert!(Parsed::new().set_isoyear_div_100(0).is_ok());
+        assert!(Parsed::new().set_isoyear_div_100(99).is_ok());
+        assert_eq!(Parsed::new().set_isoyear_div_100(i32::MAX as i64 + 1), Err(OUT_OF_RANGE));
+
+        assert_eq!(Parsed::new().set_isoyear_mod_100(-1), Err(OUT_OF_RANGE));
+        assert!(Parsed::new().set_isoyear_mod_100(0).is_ok());
+        assert!(Parsed::new().set_isoyear_mod_100(99).is_ok());
+        assert_eq!(Parsed::new().set_isoyear_mod_100(100), Err(OUT_OF_RANGE));
+
+        assert_eq!(Parsed::new().set_month(0), Err(OUT_OF_RANGE));
+        assert!(Parsed::new().set_month(1).is_ok());
+        assert!(Parsed::new().set_month(12).is_ok());
+        assert_eq!(Parsed::new().set_month(13), Err(OUT_OF_RANGE));
+
+        assert_eq!(Parsed::new().set_week_from_sun(-1), Err(OUT_OF_RANGE));
+        assert!(Parsed::new().set_week_from_sun(0).is_ok());
+        assert!(Parsed::new().set_week_from_sun(53).is_ok());
+        assert_eq!(Parsed::new().set_week_from_sun(54), Err(OUT_OF_RANGE));
+
+        assert_eq!(Parsed::new().set_week_from_mon(-1), Err(OUT_OF_RANGE));
+        assert!(Parsed::new().set_week_from_mon(0).is_ok());
+        assert!(Parsed::new().set_week_from_mon(53).is_ok());
+        assert_eq!(Parsed::new().set_week_from_mon(54), Err(OUT_OF_RANGE));
+
+        assert_eq!(Parsed::new().set_isoweek(0), Err(OUT_OF_RANGE));
+        assert!(Parsed::new().set_isoweek(1).is_ok());
+        assert!(Parsed::new().set_isoweek(53).is_ok());
+        assert_eq!(Parsed::new().set_isoweek(54), Err(OUT_OF_RANGE));
+
+        assert_eq!(Parsed::new().set_ordinal(0), Err(OUT_OF_RANGE));
+        assert!(Parsed::new().set_ordinal(1).is_ok());
+        assert!(Parsed::new().set_ordinal(366).is_ok());
+        assert_eq!(Parsed::new().set_ordinal(367), Err(OUT_OF_RANGE));
+
+        assert_eq!(Parsed::new().set_day(0), Err(OUT_OF_RANGE));
+        assert!(Parsed::new().set_day(1).is_ok());
+        assert!(Parsed::new().set_day(31).is_ok());
+        assert_eq!(Parsed::new().set_day(32), Err(OUT_OF_RANGE));
+
+        assert_eq!(Parsed::new().set_hour12(0), Err(OUT_OF_RANGE));
+        assert!(Parsed::new().set_hour12(1).is_ok());
+        assert!(Parsed::new().set_hour12(12).is_ok());
+        assert_eq!(Parsed::new().set_hour12(13), Err(OUT_OF_RANGE));
+
+        assert_eq!(Parsed::new().set_hour(-1), Err(OUT_OF_RANGE));
+        assert!(Parsed::new().set_hour(0).is_ok());
+        assert!(Parsed::new().set_hour(23).is_ok());
+        assert_eq!(Parsed::new().set_hour(24), Err(OUT_OF_RANGE));
+
+        assert_eq!(Parsed::new().set_minute(-1), Err(OUT_OF_RANGE));
+        assert!(Parsed::new().set_minute(0).is_ok());
+        assert!(Parsed::new().set_minute(59).is_ok());
+        assert_eq!(Parsed::new().set_minute(60), Err(OUT_OF_RANGE));
+
+        assert_eq!(Parsed::new().set_second(-1), Err(OUT_OF_RANGE));
+        assert!(Parsed::new().set_second(0).is_ok());
+        assert!(Parsed::new().set_second(60).is_ok());
+        assert_eq!(Parsed::new().set_second(61), Err(OUT_OF_RANGE));
+
+        assert_eq!(Parsed::new().set_nanosecond(-1), Err(OUT_OF_RANGE));
+        assert!(Parsed::new().set_nanosecond(0).is_ok());
+        assert!(Parsed::new().set_nanosecond(999_999_999).is_ok());
+        assert_eq!(Parsed::new().set_nanosecond(1_000_000_000), Err(OUT_OF_RANGE));
+
+        assert!(Parsed::new().set_timestamp(i64::MIN).is_ok());
+        assert!(Parsed::new().set_timestamp(i64::MAX).is_ok());
+
+        assert_eq!(Parsed::new().set_offset(i32::MIN as i64 - 1), Err(OUT_OF_RANGE));
+        assert!(Parsed::new().set_offset(i32::MIN as i64).is_ok());
+        assert!(Parsed::new().set_offset(i32::MAX as i64).is_ok());
+        assert_eq!(Parsed::new().set_offset(i32::MAX as i64 + 1), Err(OUT_OF_RANGE));
+    }
+
+    #[test]
     fn test_parsed_to_naive_date() {
         macro_rules! parse {
             ($($k:ident: $v:expr),*) => (
@@ -828,7 +1391,7 @@
         );
         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));
+        assert_eq!(parse!(year_div_100: -1, year_mod_100: 42, month: 1, day: 1), Err(IMPOSSIBLE));
         let max_year = NaiveDate::MAX.year();
         assert_eq!(
             parse!(year_div_100: max_year / 100,
@@ -864,17 +1427,17 @@
         );
         assert_eq!(
             parse!(year: -1, year_div_100: -1, year_mod_100: 99, month: 1, day: 1),
-            Err(OUT_OF_RANGE)
+            Err(IMPOSSIBLE)
         );
-        assert_eq!(parse!(year: -1, year_div_100: 0, month: 1, day: 1), Err(OUT_OF_RANGE));
-        assert_eq!(parse!(year: -1, year_mod_100: 99, month: 1, day: 1), Err(OUT_OF_RANGE));
+        assert_eq!(parse!(year: -1, year_div_100: 0, month: 1, day: 1), Err(IMPOSSIBLE));
+        assert_eq!(parse!(year: -1, year_mod_100: 99, month: 1, day: 1), Err(IMPOSSIBLE));
 
         // weekdates
         assert_eq!(parse!(year: 2000, week_from_mon: 0), Err(NOT_ENOUGH));
         assert_eq!(parse!(year: 2000, week_from_sun: 0), Err(NOT_ENOUGH));
         assert_eq!(parse!(year: 2000, weekday: Sun), Err(NOT_ENOUGH));
-        assert_eq!(parse!(year: 2000, week_from_mon: 0, weekday: Fri), Err(OUT_OF_RANGE));
-        assert_eq!(parse!(year: 2000, week_from_sun: 0, weekday: Fri), Err(OUT_OF_RANGE));
+        assert_eq!(parse!(year: 2000, week_from_mon: 0, weekday: Fri), Err(IMPOSSIBLE));
+        assert_eq!(parse!(year: 2000, week_from_sun: 0, weekday: Fri), Err(IMPOSSIBLE));
         assert_eq!(parse!(year: 2000, week_from_mon: 0, weekday: Sat), ymd(2000, 1, 1));
         assert_eq!(parse!(year: 2000, week_from_sun: 0, weekday: Sat), ymd(2000, 1, 1));
         assert_eq!(parse!(year: 2000, week_from_mon: 0, weekday: Sun), ymd(2000, 1, 2));
@@ -888,9 +1451,9 @@
         assert_eq!(parse!(year: 2000, week_from_mon: 2, weekday: Mon), ymd(2000, 1, 10));
         assert_eq!(parse!(year: 2000, week_from_sun: 52, weekday: Sat), ymd(2000, 12, 30));
         assert_eq!(parse!(year: 2000, week_from_sun: 53, weekday: Sun), ymd(2000, 12, 31));
-        assert_eq!(parse!(year: 2000, week_from_sun: 53, weekday: Mon), Err(OUT_OF_RANGE));
+        assert_eq!(parse!(year: 2000, week_from_sun: 53, weekday: Mon), Err(IMPOSSIBLE));
         assert_eq!(parse!(year: 2000, week_from_sun: 0xffffffff, weekday: Mon), Err(OUT_OF_RANGE));
-        assert_eq!(parse!(year: 2006, week_from_sun: 0, weekday: Sat), Err(OUT_OF_RANGE));
+        assert_eq!(parse!(year: 2006, week_from_sun: 0, weekday: Sat), Err(IMPOSSIBLE));
         assert_eq!(parse!(year: 2006, week_from_sun: 1, weekday: Sun), ymd(2006, 1, 1));
 
         // weekdates: conflicting inputs
diff --git a/crates/chrono/src/format/strftime.rs b/crates/chrono/src/format/strftime.rs
index 26fa391..e446c68 100644
--- a/crates/chrono/src/format/strftime.rs
+++ b/crates/chrono/src/format/strftime.rs
@@ -99,6 +99,8 @@
 
 [^1]: `%C`, `%y`:
    This is floor division, so 100 BCE (year number -99) will print `-1` and `99` respectively.
+   For `%y`, values greater or equal to 70 are interpreted as being in the 20th century,
+   values smaller than 70 in the 21st century.
 
 [^2]: `%U`:
    Week 1 starts with the first Sunday in that year.
@@ -165,7 +167,7 @@
 use super::{Fixed, InternalInternal, Item, Numeric, Pad};
 #[cfg(any(feature = "alloc", feature = "std"))]
 use super::{ParseError, BAD_FORMAT};
-#[cfg(feature = "alloc")]
+#[cfg(all(feature = "alloc", not(feature = "std"), not(test)))]
 use alloc::vec::Vec;
 
 /// Parsing iterator for `strftime`-like format strings.
@@ -208,8 +210,7 @@
     ///
     /// # Example
     ///
-    #[cfg_attr(not(any(feature = "alloc", feature = "std")), doc = "```ignore")]
-    #[cfg_attr(any(feature = "alloc", feature = "std"), doc = "```rust")]
+    /// ```
     /// use chrono::format::*;
     ///
     /// let strftime_parser = StrftimeItems::new("%F"); // %F: year-month-day (ISO 8601)
@@ -259,8 +260,8 @@
     ///
     /// # Example
     ///
-    #[cfg_attr(not(any(feature = "alloc", feature = "std")), doc = "```ignore")]
-    #[cfg_attr(any(feature = "alloc", feature = "std"), doc = "```rust")]
+    /// ```
+    /// # #[cfg(feature = "alloc")] {
     /// use chrono::format::{Locale, StrftimeItems};
     /// use chrono::{FixedOffset, TimeZone};
     ///
@@ -279,6 +280,7 @@
     /// assert_eq!(fmtr.to_string(), "2023년 07월 11일");
     /// let fmtr = dt.format_with_items(StrftimeItems::new_with_locale("%x", Locale::ja_JP));
     /// assert_eq!(fmtr.to_string(), "2023年07月11日");
+    /// # }
     /// ```
     #[cfg(feature = "unstable-locales")]
     #[must_use]
diff --git a/crates/chrono/src/lib.rs b/crates/chrono/src/lib.rs
index 18d1faa..a7c603a 100644
--- a/crates/chrono/src/lib.rs
+++ b/crates/chrono/src/lib.rs
@@ -1,158 +1,193 @@
 //! # Chrono: Date and Time for Rust
 //!
-
-//! Chrono aims to provide all functionality needed to do correct operations on dates and times in the
-//! [proleptic Gregorian calendar](https://en.wikipedia.org/wiki/Proleptic_Gregorian_calendar):
+//! Chrono aims to provide all functionality needed to do correct operations on dates and times in
+//! the [proleptic Gregorian calendar]:
 //!
-//! * The [`DateTime`](https://docs.rs/chrono/latest/chrono/struct.DateTime.html) type is timezone-aware
-//!   by default, with separate timezone-naive types.
+//! * The [`DateTime`] type is timezone-aware by default, with separate timezone-naive types.
 //! * Operations that may produce an invalid or ambiguous date and time return `Option` or
-//!   [`LocalResult`](https://docs.rs/chrono/latest/chrono/offset/enum.LocalResult.html).
-//! * Configurable parsing and formatting with a `strftime` inspired date and time formatting syntax.
-//! * The [`Local`](https://docs.rs/chrono/latest/chrono/offset/struct.Local.html) timezone works with
-//!   the current timezone of the OS.
+//!   [`MappedLocalTime`].
+//! * Configurable parsing and formatting with a `strftime` inspired date and time formatting
+//!   syntax.
+//! * The [`Local`] timezone works with the current timezone of the OS.
 //! * Types and operations are implemented to be reasonably efficient.
 //!
-//! Timezone data is not shipped with chrono by default to limit binary sizes. Use the companion crate
-//! [Chrono-TZ](https://crates.io/crates/chrono-tz) or [`tzfile`](https://crates.io/crates/tzfile) for
-//! full timezone support.
+//! Timezone data is not shipped with chrono by default to limit binary sizes. Use the companion
+//! crate [Chrono-TZ] or [`tzfile`] for full timezone support.
+//!
+//! [proleptic Gregorian calendar]: https://en.wikipedia.org/wiki/Proleptic_Gregorian_calendar
+//! [Chrono-TZ]: https://crates.io/crates/chrono-tz
+//! [`tzfile`]: https://crates.io/crates/tzfile
 //!
 //! ### Features
 //!
-//! Chrono supports various runtime environments and operating systems, and has
-//! several features that may be enabled or disabled.
+//! 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`) that depends on the standard library for
-//! UNIX-like operating systems and the Windows API (`winapi`) for Windows.
+//! - `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 local timezone (`Local`). This is a superset of `now`.
+//! - `now`: Enables reading the system time (`now`).
 //! - `wasmbind`: Interface with the JS Date API for the `wasm32` target.
 //!
 //! Optional features:
 //!
-//! - [`serde`][]: Enable serialization/deserialization via serde.
-//! - `rkyv`: Enable serialization/deserialization via rkyv.
-//! - `arbitrary`: construct arbitrary instances of a type with the Arbitrary crate.
-//! - `unstable-locales`: Enable localization. This adds various methods with a
-//!   `_localized` suffix. The implementation and API may change or even be
-//!   removed in a patch release. Feedback welcome.
-//! - `oldtime`: this feature no langer has a function, but once offered compatibility with the
+//! - `serde`: Enable serialization/deserialization via [serde].
+//! - `rkyv`: Deprecated, use the `rkyv-*` features.
+//! - `rkyv-16`: Enable serialization/deserialization via [rkyv],
+//!    using 16-bit integers for integral `*size` types.
+//! - `rkyv-32`: Enable serialization/deserialization via [rkyv],
+//!    using 32-bit integers for integral `*size` types.
+//! - `rkyv-64`: Enable serialization/deserialization via [rkyv],
+//!    using 64-bit integers for integral `*size` types.
+//! - `rkyv-validation`: Enable rkyv validation support using `bytecheck`.
+//! - `arbitrary`: Construct arbitrary instances of a type with the Arbitrary crate.
+//! - `unstable-locales`: Enable localization. This adds various methods with a `_localized` suffix.
+//!   The implementation and API may change or even be removed in a patch release. Feedback welcome.
+//! - `oldtime`: This feature no longer has any effect; it used to offer compatibility with the
 //!   `time` 0.1 crate.
 //!
-//! [`serde`]: https://github.com/serde-rs/serde
-//! [wasm-bindgen]: https://github.com/rustwasm/wasm-bindgen
+//! Note: The `rkyv{,-16,-32,-64}` features are mutually exclusive.
 //!
-//! See the [cargo docs][] for examples of specifying features.
+//! See the [cargo docs] for examples of specifying features.
 //!
+//! [serde]: https://github.com/serde-rs/serde
+//! [rkyv]: https://github.com/rkyv/rkyv
 //! [cargo docs]: https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#choosing-features
 //!
 //! ## Overview
 //!
 //! ### Time delta / Duration
 //!
-//! Chrono has a [`TimeDelta`] type to represent the magnitude of a time span. This is an
-//! "accurate" duration represented as seconds and nanoseconds, and does not represent "nominal"
-//! components such as days or months.
+//! Chrono has a [`TimeDelta`] type to represent the magnitude of a time span. This is an "accurate"
+//! duration represented as seconds and nanoseconds, and does not represent "nominal" components
+//! such as days or months.
 //!
 //! The [`TimeDelta`] type was previously named `Duration` (and is still available as a type alias
 //! with that name). A notable difference with the similar [`core::time::Duration`] is that it is a
 //! signed value instead of unsigned.
 //!
-//! Chrono currently only supports a small number of operations with [`core::time::Duration`] .
+//! Chrono currently only supports a small number of operations with [`core::time::Duration`].
 //! You can convert between both types with the [`TimeDelta::from_std`] and [`TimeDelta::to_std`]
 //! methods.
 //!
 //! ### Date and Time
 //!
-//! Chrono provides a
-//! [**`DateTime`**](./struct.DateTime.html)
-//! type to represent a date and a time in a timezone.
+//! Chrono provides a [`DateTime`] 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.
+//! For more abstract moment-in-time tracking such as internal timekeeping that is unconcerned with
+//! timezones, consider [`std::time::SystemTime`], which tracks your system clock, or
+//! [`std::time::Instant`], which is an opaque but monotonically-increasing representation of a
+//! moment in time.
 //!
-//! `DateTime` is timezone-aware and must be constructed from
-//! the [**`TimeZone`**](./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:
+//! [`DateTime`] is timezone-aware and must be constructed from a [`TimeZone`] object, which defines
+//! how the local date is converted to and back from the UTC date.
+//! There are three well-known [`TimeZone`] implementations:
 //!
-//! * [**`Utc`**](./offset/struct.Utc.html) specifies the UTC time zone. It is most efficient.
+//! * [`Utc`] specifies the UTC time zone. It is most efficient.
 //!
-//! * [**`Local`**](./offset/struct.Local.html) specifies the system local time zone.
+//! * [`Local`] specifies the system local time zone.
 //!
-//! * [**`FixedOffset`**](./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.
+//! * [`FixedOffset`] 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`](./struct.DateTime.html#method.with_timezone) method.
+//! [`DateTime`]s with different [`TimeZone`] types are distinct and do not mix, but can be
+//! converted to each other using the [`DateTime::with_timezone`] method.
 //!
-//! You can get the current date and time in the UTC time zone
-//! ([`Utc::now()`](./offset/struct.Utc.html#method.now))
-//! or in the local time zone
-//! ([`Local::now()`](./offset/struct.Local.html#method.now)).
+//! You can get the current date and time in the UTC time zone ([`Utc::now()`]) or in the local time
+//! zone ([`Local::now()`]).
 //!
-#![cfg_attr(not(feature = "now"), doc = "```ignore")]
-#![cfg_attr(feature = "now", doc = "```rust")]
+//! ```
+//! # #[cfg(feature = "now")] {
 //! use chrono::prelude::*;
 //!
-//! let utc: DateTime<Utc> = Utc::now();       // e.g. `2014-11-28T12:45:59.324310806Z`
+//! let utc: DateTime<Utc> = Utc::now(); // e.g. `2014-11-28T12:45:59.324310806Z`
 //! # let _ = utc;
+//! # }
 //! ```
 //!
-#![cfg_attr(not(feature = "clock"), doc = "```ignore")]
-#![cfg_attr(feature = "clock", doc = "```rust")]
+//! ```
+//! # #[cfg(feature = "clock")] {
 //! use chrono::prelude::*;
 //!
 //! let local: DateTime<Local> = Local::now(); // e.g. `2014-11-28T21:45:59.324310806+09:00`
 //! # let _ = local;
+//! # }
 //! ```
 //!
-//! 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.
+//! 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.
 //!
-#![cfg_attr(not(feature = "now"), doc = "```ignore")]
-#![cfg_attr(feature = "now", doc = "```rust")]
+//! ```
+//! use chrono::offset::MappedLocalTime;
 //! use chrono::prelude::*;
-//! use chrono::offset::LocalResult;
 //!
 //! # fn doctest() -> Option<()> {
 //!
 //! let dt = Utc.with_ymd_and_hms(2014, 7, 8, 9, 10, 11).unwrap(); // `2014-07-08T09:10:11Z`
-//! assert_eq!(dt, NaiveDate::from_ymd_opt(2014, 7, 8)?.and_hms_opt(9, 10, 11)?.and_local_timezone(Utc).unwrap());
+//! assert_eq!(
+//!     dt,
+//!     NaiveDate::from_ymd_opt(2014, 7, 8)?
+//!         .and_hms_opt(9, 10, 11)?
+//!         .and_utc()
+//! );
 //!
 //! // July 8 is 188th day of the year 2014 (`o` for "ordinal")
 //! assert_eq!(dt, NaiveDate::from_yo_opt(2014, 189)?.and_hms_opt(9, 10, 11)?.and_utc());
 //! // July 8 is Tuesday in ISO week 28 of the year 2014.
-//! assert_eq!(dt, NaiveDate::from_isoywd_opt(2014, 28, Weekday::Tue)?.and_hms_opt(9, 10, 11)?.and_utc());
+//! assert_eq!(
+//!     dt,
+//!     NaiveDate::from_isoywd_opt(2014, 28, Weekday::Tue)?.and_hms_opt(9, 10, 11)?.and_utc()
+//! );
 //!
-//! let dt = NaiveDate::from_ymd_opt(2014, 7, 8)?.and_hms_milli_opt(9, 10, 11, 12)?.and_local_timezone(Utc).unwrap(); // `2014-07-08T09:10:11.012Z`
-//! assert_eq!(dt, NaiveDate::from_ymd_opt(2014, 7, 8)?.and_hms_micro_opt(9, 10, 11, 12_000)?.and_local_timezone(Utc).unwrap());
-//! assert_eq!(dt, NaiveDate::from_ymd_opt(2014, 7, 8)?.and_hms_nano_opt(9, 10, 11, 12_000_000)?.and_local_timezone(Utc).unwrap());
+//! let dt = NaiveDate::from_ymd_opt(2014, 7, 8)?
+//!     .and_hms_milli_opt(9, 10, 11, 12)?
+//!     .and_utc(); // `2014-07-08T09:10:11.012Z`
+//! assert_eq!(
+//!     dt,
+//!     NaiveDate::from_ymd_opt(2014, 7, 8)?
+//!         .and_hms_micro_opt(9, 10, 11, 12_000)?
+//!         .and_utc()
+//! );
+//! assert_eq!(
+//!     dt,
+//!     NaiveDate::from_ymd_opt(2014, 7, 8)?
+//!         .and_hms_nano_opt(9, 10, 11, 12_000_000)?
+//!         .and_utc()
+//! );
 //!
 //! // dynamic verification
-//! assert_eq!(Utc.with_ymd_and_hms(2014, 7, 8, 21, 15, 33),
-//!            LocalResult::Single(NaiveDate::from_ymd_opt(2014, 7, 8)?.and_hms_opt(21, 15, 33)?.and_utc()));
-//! assert_eq!(Utc.with_ymd_and_hms(2014, 7, 8, 80, 15, 33), LocalResult::None);
-//! assert_eq!(Utc.with_ymd_and_hms(2014, 7, 38, 21, 15, 33), LocalResult::None);
+//! assert_eq!(
+//!     Utc.with_ymd_and_hms(2014, 7, 8, 21, 15, 33),
+//!     MappedLocalTime::Single(
+//!         NaiveDate::from_ymd_opt(2014, 7, 8)?.and_hms_opt(21, 15, 33)?.and_utc()
+//!     )
+//! );
+//! assert_eq!(Utc.with_ymd_and_hms(2014, 7, 8, 80, 15, 33), MappedLocalTime::None);
+//! assert_eq!(Utc.with_ymd_and_hms(2014, 7, 38, 21, 15, 33), MappedLocalTime::None);
 //!
 //! # #[cfg(feature = "clock")] {
 //! // 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.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();
+//! 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;
 //! # }
@@ -161,9 +196,8 @@
 //! # doctest().unwrap();
 //! ```
 //!
-//! Various properties are available to the date and time, and can be altered individually.
-//! Most of them are defined in the traits [`Datelike`](./trait.Datelike.html) and
-//! [`Timelike`](./trait.Timelike.html) which you should `use` before.
+//! Various properties are available to the date and time, and can be altered individually. Most of
+//! them are defined in the traits [`Datelike`] and [`Timelike`] which you should `use` before.
 //! Addition and subtraction is also supported.
 //! The following illustrates most supported operations to the date and time:
 //!
@@ -172,7 +206,15 @@
 //! use chrono::TimeDelta;
 //!
 //! // assume this returned `2014-11-28T21:45:59.324310806+09:00`:
-//! 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();
+//! 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));
@@ -186,7 +228,14 @@
 //! // time zone accessor and manipulation
 //! assert_eq!(dt.offset().fix().local_minus_utc(), 9 * 3600);
 //! 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());
+//! assert_eq!(
+//!     dt.with_timezone(&Utc),
+//!     NaiveDate::from_ymd_opt(2014, 11, 28)
+//!         .unwrap()
+//!         .and_hms_nano_opt(12, 45, 59, 324310806)
+//!         .unwrap()
+//!         .and_utc()
+//! );
 //!
 //! // a sample of property manipulations (validates dynamically)
 //! assert_eq!(dt.with_day(29).unwrap().weekday(), Weekday::Sat); // 2014-11-29 is Saturday
@@ -196,30 +245,34 @@
 //! // arithmetic operations
 //! 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), TimeDelta::seconds(-2 * 3600 + 2));
-//! assert_eq!(dt2.signed_duration_since(dt1), TimeDelta::seconds(2 * 3600 - 2));
-//! assert_eq!(Utc.with_ymd_and_hms(1970, 1, 1, 0, 0, 0).unwrap() + TimeDelta::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() - TimeDelta::seconds(1_000_000_000),
-//!            Utc.with_ymd_and_hms(1938, 4, 24, 22, 13, 20).unwrap());
+//! assert_eq!(dt1.signed_duration_since(dt2), TimeDelta::try_seconds(-2 * 3600 + 2).unwrap());
+//! assert_eq!(dt2.signed_duration_since(dt1), TimeDelta::try_seconds(2 * 3600 - 2).unwrap());
+//! assert_eq!(
+//!     Utc.with_ymd_and_hms(1970, 1, 1, 0, 0, 0).unwrap()
+//!         + TimeDelta::try_seconds(1_000_000_000).unwrap(),
+//!     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()
+//!         - TimeDelta::try_seconds(1_000_000_000).unwrap(),
+//!     Utc.with_ymd_and_hms(1938, 4, 24, 22, 13, 20).unwrap()
+//! );
 //! ```
 //!
 //! ### Formatting and Parsing
 //!
-//! Formatting is done via the [`format`](./struct.DateTime.html#method.format) method,
-//! which format is equivalent to the familiar `strftime` format.
+//! Formatting is done via the [`format`](DateTime::format()) method, which format is equivalent to
+//! the familiar `strftime` format.
 //!
-//! See [`format::strftime`](./format/strftime/index.html#specifiers)
-//! documentation for full syntax and list of specifiers.
+//! See [`format::strftime`](format::strftime#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`](./struct.DateTime.html#method.to_rfc2822) and
-//! [`to_rfc3339`](./struct.DateTime.html#method.to_rfc3339) methods
-//! for well-known formats.
+//! Chrono also provides [`to_rfc2822`](DateTime::to_rfc2822) and
+//! [`to_rfc3339`](DateTime::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`:
+//! 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`:
 //!
 //! ```toml
 //! chrono = { version = "0.4", features = ["unstable-locales"] }
@@ -236,7 +289,10 @@
 //! 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_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");
@@ -245,7 +301,11 @@
 //! assert_eq!(format!("{:?}", dt), "2014-11-28T12:00:09Z");
 //!
 //! // Note that milli/nanoseconds are only printed if they are non-zero
-//! 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();
+//! let dt_nano = NaiveDate::from_ymd_opt(2014, 11, 28)
+//!     .unwrap()
+//!     .and_hms_nano_opt(12, 0, 9, 1)
+//!     .unwrap()
+//!     .and_utc();
 //! assert_eq!(format!("{:?}", dt_nano), "2014-11-28T12:00:09.000000001Z");
 //! # }
 //! # #[cfg(not(all(feature = "unstable-locales", feature = "alloc")))]
@@ -257,30 +317,24 @@
 //!
 //! Parsing can be done with two 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.
+//! 1. The standard [`FromStr`](std::str::FromStr) trait (and [`parse`](str::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`] format specifier
+//!    prints, and requires the offset to be present.
 //!
-//! 2. [`DateTime::parse_from_str`](./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`](./struct.DateTime.html#method.parse_from_rfc2822)
-//!    and
-//!    [`DateTime::parse_from_rfc3339`](./struct.DateTime.html#method.parse_from_rfc3339)
-//!    are similar but for well-known formats.
+//! 2. [`DateTime::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`] and [`DateTime::parse_from_rfc3339`] are similar but for
+//!    well-known formats.
 //!
-//! More detailed control over the parsing process is available via
-//! [`format`](./format/index.html) module.
+//! More detailed control over the parsing process is available via [`format`](mod@format) module.
 //!
 //! ```rust
 //! use chrono::prelude::*;
 //!
 //! 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());
+//! 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()));
@@ -288,10 +342,14 @@
 //! 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_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()));
 //!
 //! // oops, the year is missing!
@@ -302,8 +360,8 @@
 //! assert!(DateTime::parse_from_str("Sat Nov 28 12:00:09 2014", "%a %b %e %T %Y").is_err());
 //! ```
 //!
-//! Again : See [`format::strftime`](./format/strftime/index.html#specifiers)
-//! documentation for full syntax and list of specifiers.
+//! Again: See [`format::strftime`](format::strftime#specifiers) documentation for full syntax and
+//! list of specifiers.
 //!
 //! ### Conversion from and to EPOCH timestamps
 //!
@@ -316,8 +374,8 @@
 //! [`DateTime.timestamp_subsec_nanos`](DateTime::timestamp_subsec_nanos)
 //! to get the number of additional number of nanoseconds.
 //!
-#![cfg_attr(not(feature = "std"), doc = "```ignore")]
-#![cfg_attr(feature = "std", doc = "```rust")]
+//! ```
+//! # #[cfg(feature = "alloc")] {
 //! // We need the trait in scope to use Utc::timestamp().
 //! use chrono::{DateTime, Utc};
 //!
@@ -328,24 +386,21 @@
 //! // 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);
+//! # }
 //! ```
 //!
 //! ### Naive date and time
 //!
-//! Chrono provides naive counterparts to `Date`, (non-existent) `Time` and `DateTime`
-//! as [**`NaiveDate`**](./naive/struct.NaiveDate.html),
-//! [**`NaiveTime`**](./naive/struct.NaiveTime.html) and
-//! [**`NaiveDateTime`**](./naive/struct.NaiveDateTime.html) respectively.
+//! Chrono provides naive counterparts to `Date`, (non-existent) `Time` and `DateTime` as
+//! [`NaiveDate`], [`NaiveTime`] and [`NaiveDateTime`] 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.
+//! 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`](./struct.DateTime.html#method.naive_local) returns
-//! a view to the naive local time,
-//! and [`naive_utc`](./struct.DateTime.html#method.naive_utc) returns
-//! a view to the naive UTC time.
+//! [`naive_local`](DateTime::naive_local) returns a view to the naive local time,
+//! and [`naive_utc`](DateTime::naive_utc) returns a view to the naive UTC time.
 //!
 //! ## Limitations
 //!
@@ -353,7 +408,7 @@
 //! * Date types are limited to about +/- 262,000 years from the common epoch.
 //! * Time types are limited to nanosecond accuracy.
 //! * Leap seconds can be represented, but Chrono does not fully support them.
-//!   See [Leap Second Handling](https://docs.rs/chrono/latest/chrono/naive/struct.NaiveTime.html#leap-second-handling).
+//!   See [Leap Second Handling](NaiveTime#leap-second-handling).
 //!
 //! ## Rust version requirements
 //!
@@ -446,15 +501,11 @@
 //! [chrono#1095]: https://github.com/chronotope/chrono/pull/1095
 
 #![doc(html_root_url = "https://docs.rs/chrono/latest/", test(attr(deny(warnings))))]
-#![cfg_attr(feature = "bench", feature(test))] // lib stability features as per RFC #507
 #![deny(missing_docs)]
 #![deny(missing_debug_implementations)]
 #![warn(unreachable_pub)]
 #![deny(clippy::tests_outside_test_module)]
 #![cfg_attr(not(any(feature = "std", test)), no_std)]
-// 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_auto_cfg))]
 
 #[cfg(feature = "alloc")]
@@ -495,8 +546,6 @@
 pub use date::{MAX_DATE, MIN_DATE};
 
 mod datetime;
-#[cfg(feature = "rustc-serialize")]
-pub use datetime::rustc_serialize::TsSeconds;
 pub use datetime::DateTime;
 #[allow(deprecated)]
 #[doc(no_inline)]
@@ -517,7 +566,9 @@
 #[cfg(feature = "clock")]
 #[doc(inline)]
 pub use offset::Local;
+#[doc(hidden)]
 pub use offset::LocalResult;
+pub use offset::MappedLocalTime;
 #[doc(inline)]
 pub use offset::{FixedOffset, Offset, TimeZone, Utc};
 
@@ -541,18 +592,50 @@
 #[doc(hidden)]
 pub use naive::__BenchYearFlags;
 
-/// Serialization/Deserialization with serde.
+/// 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][2].
+/// The [`DateTime`] type has default implementations for (de)serializing to/from the [RFC 3339]
+/// format. This module provides alternatives for serializing to timestamps.
+///
+/// The alternatives are for use with serde's [`with` annotation] combined with the module name.
+/// Alternatively the individual `serialize` and `deserialize` functions in each module can be used
+/// with serde's [`serialize_with`] and [`deserialize_with`] annotations.
 ///
 /// *Available on crate feature 'serde' only.*
 ///
-/// [1]: https://tools.ietf.org/html/rfc3339
-/// [2]: https://serde.rs/field-attrs.html#with
+/// [RFC 3339]: https://tools.ietf.org/html/rfc3339
+/// [`with` annotation]: https://serde.rs/field-attrs.html#with
+/// [`serialize_with`]: https://serde.rs/field-attrs.html#serialize_with
+/// [`deserialize_with`]: https://serde.rs/field-attrs.html#deserialize_with
 #[cfg(feature = "serde")]
 pub mod serde {
+    use core::fmt;
+    use serde::de;
+
     pub use super::datetime::serde::*;
+
+    /// Create a custom `de::Error` with `SerdeError::InvalidTimestamp`.
+    pub(crate) fn invalid_ts<E, T>(value: T) -> E
+    where
+        E: de::Error,
+        T: fmt::Display,
+    {
+        E::custom(SerdeError::InvalidTimestamp(value))
+    }
+
+    enum SerdeError<T: fmt::Display> {
+        InvalidTimestamp(T),
+    }
+
+    impl<T: fmt::Display> fmt::Display for SerdeError<T> {
+        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+            match self {
+                SerdeError::InvalidTimestamp(ts) => {
+                    write!(f, "value is not a legal timestamp: {}", ts)
+                }
+            }
+        }
+    }
 }
 
 /// Zero-copy serialization/deserialization with rkyv.
@@ -617,13 +700,33 @@
 }
 
 /// Workaround because `.expect()` is not (yet) available in const context.
-#[macro_export]
-#[doc(hidden)]
-macro_rules! expect {
-    ($e:expr, $m:literal) => {
-        match $e {
-            Some(v) => v,
-            None => panic!($m),
-        }
-    };
+pub(crate) const fn expect<T: Copy>(opt: Option<T>, msg: &str) -> T {
+    match opt {
+        Some(val) => val,
+        None => panic!("{}", msg),
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    #[cfg(feature = "clock")]
+    use crate::{DateTime, FixedOffset, Local, NaiveDate, NaiveDateTime, NaiveTime, Utc};
+
+    #[test]
+    #[allow(deprecated)]
+    #[cfg(feature = "clock")]
+    fn test_type_sizes() {
+        use core::mem::size_of;
+        assert_eq!(size_of::<NaiveDate>(), 4);
+        assert_eq!(size_of::<Option<NaiveDate>>(), 4);
+        assert_eq!(size_of::<NaiveTime>(), 8);
+        assert_eq!(size_of::<Option<NaiveTime>>(), 12);
+        assert_eq!(size_of::<NaiveDateTime>(), 12);
+        assert_eq!(size_of::<Option<NaiveDateTime>>(), 12);
+
+        assert_eq!(size_of::<DateTime<Utc>>(), 12);
+        assert_eq!(size_of::<DateTime<FixedOffset>>(), 16);
+        assert_eq!(size_of::<DateTime<Local>>(), 16);
+        assert_eq!(size_of::<Option<DateTime<FixedOffset>>>(), 16);
+    }
 }
diff --git a/crates/chrono/src/month.rs b/crates/chrono/src/month.rs
index 4353dda..f964f85 100644
--- a/crates/chrono/src/month.rs
+++ b/crates/chrono/src/month.rs
@@ -29,7 +29,6 @@
 /// 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, PartialOrd, Ord)]
-#[cfg_attr(feature = "rustc-serialize", derive(RustcEncodable, RustcDecodable))]
 #[cfg_attr(
     any(feature = "rkyv", feature = "rkyv-16", feature = "rkyv-32", feature = "rkyv-64"),
     derive(Archive, Deserialize, Serialize),
@@ -192,7 +191,6 @@
     /// `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)
@@ -280,7 +278,7 @@
 
     struct MonthVisitor;
 
-    impl<'de> de::Visitor<'de> for MonthVisitor {
+    impl de::Visitor<'_> for MonthVisitor {
         type Value = Month;
 
         fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
diff --git a/crates/chrono/src/naive/date.rs b/crates/chrono/src/naive/date.rs
deleted file mode 100644
index 190a6ba..0000000
--- a/crates/chrono/src/naive/date.rs
+++ /dev/null
@@ -1,3357 +0,0 @@
-// This is a part of Chrono.
-// See README.md and LICENSE.txt for details.
-
-//! ISO 8601 calendar date without timezone.
-
-#[cfg(feature = "alloc")]
-use core::borrow::Borrow;
-use core::iter::FusedIterator;
-use core::ops::{Add, AddAssign, RangeInclusive, Sub, SubAssign};
-use core::{fmt, str};
-
-#[cfg(any(feature = "rkyv", feature = "rkyv-16", feature = "rkyv-32", feature = "rkyv-64"))]
-use rkyv::{Archive, Deserialize, Serialize};
-
-/// L10n locales.
-#[cfg(all(feature = "unstable-locales", feature = "alloc"))]
-use pure_rust_locales::Locale;
-
-#[cfg(feature = "alloc")]
-use crate::format::DelayedFormat;
-use crate::format::{
-    parse, parse_and_remainder, write_hundreds, Item, Numeric, Pad, ParseError, ParseResult,
-    Parsed, StrftimeItems,
-};
-use crate::month::Months;
-use crate::naive::{IsoWeek, NaiveDateTime, NaiveTime};
-use crate::{expect, try_opt};
-use crate::{Datelike, TimeDelta, Weekday};
-
-use super::internals::{self, DateImpl, Mdf, Of, YearFlags};
-use super::isoweek;
-
-const MAX_YEAR: i32 = internals::MAX_YEAR;
-const MIN_YEAR: i32 = internals::MIN_YEAR;
-
-/// 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.
-    ///
-    /// # Panics
-    ///
-    /// Panics if the first day of the week happens to fall just out of range of `NaiveDate`
-    /// (more than ca. 262,000 years away from common era).
-    ///
-    /// # 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]
-    #[must_use]
-    pub const fn first_day(&self) -> NaiveDate {
-        let start = self.start.num_days_from_monday() as i32;
-        let ref_day = self.date.weekday().num_days_from_monday() as i32;
-        // Calculate the number of days to subtract from `self.date`.
-        // Do not construct an intermediate date beyond `self.date`, because that may be out of
-        // range if `date` is close to `NaiveDate::MAX`.
-        let days = start - ref_day - if start > ref_day { 7 } else { 0 };
-        expect!(self.date.add_days(days), "first weekday out of range for `NaiveDate`")
-    }
-
-    /// Returns a date representing the last day of the week.
-    ///
-    /// # Panics
-    ///
-    /// Panics if the last day of the week happens to fall just out of range of `NaiveDate`
-    /// (more than ca. 262,000 years away from common era).
-    ///
-    /// # 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]
-    #[must_use]
-    pub const fn last_day(&self) -> NaiveDate {
-        let end = self.start.pred().num_days_from_monday() as i32;
-        let ref_day = self.date.weekday().num_days_from_monday() as i32;
-        // Calculate the number of days to add to `self.date`.
-        // Do not construct an intermediate date before `self.date` (like with `first_day()`),
-        // because that may be out of range if `date` is close to `NaiveDate::MIN`.
-        let days = end - ref_day + if end < ref_day { 7 } else { 0 };
-        expect!(self.date.add_days(days), "last weekday out of range for `NaiveDate`")
-    }
-
-    /// Returns a [`RangeInclusive<T>`] representing the whole week bounded by
-    /// [first_day](NaiveWeek::first_day) and [last_day](NaiveWeek::last_day) functions.
-    ///
-    /// # Panics
-    ///
-    /// Panics if the either the first or last day of the week happens to fall just out of range of
-    /// `NaiveDate` (more than ca. 262,000 years away from common era).
-    ///
-    /// # 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]
-    #[must_use]
-    pub const fn days(&self) -> RangeInclusive<NaiveDate> {
-        self.first_day()..=self.last_day()
-    }
-}
-
-/// A duration in calendar days.
-///
-/// This is useful because when using `TimeDelta` it is possible that adding `TimeDelta::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
-/// `TimeDelta::days(n)` and `Days::new(n)` are equivalent.
-#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
-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] from Jan 1, 262145 BCE to Dec 31, 262143 CE.
-/// Also supports the conversion from ISO 8601 ordinal and week date.
-///
-/// # Calendar Date
-///
-/// The ISO 8601 **calendar date** follows the proleptic Gregorian calendar.
-/// It is like a normal civil calendar but note some slight differences:
-///
-/// * Dates before the Gregorian calendar's inception in 1582 are defined via the extrapolation.
-///   Be careful, as historical dates are often noted in the Julian calendar and others
-///   and the transition to Gregorian may differ across countries (as late as early 20C).
-///
-///   (Some example: Both Shakespeare from Britain and Cervantes from Spain seemingly died
-///   on the same calendar date---April 23, 1616---but in the different calendar.
-///   Britain used the Julian calendar at that time, so Shakespeare's death is later.)
-///
-/// * ISO 8601 calendars has the year 0, which is 1 BCE (a year before 1 CE).
-///   If you need a typical BCE/BC and CE/AD notation for year numbers,
-///   use the [`Datelike::year_ce`] method.
-///
-/// # Week Date
-///
-/// The ISO 8601 **week date** is a triple of year number, week number
-/// and [day of the week](Weekday) with the following rules:
-///
-/// * A week consists of Monday through Sunday, and is always numbered within some year.
-///   The week number ranges from 1 to 52 or 53 depending on the year.
-///
-/// * The week 1 of given year is defined as the first week containing January 4 of that year,
-///   or equivalently, the first week containing four or more days in that year.
-///
-/// * The year number in the week date may *not* correspond to the actual Gregorian year.
-///   For example, January 3, 2016 (Sunday) was on the last (53rd) week of 2015.
-///
-/// Chrono's date types default to the ISO 8601 [calendar date](#calendar-date), but
-/// [`Datelike::iso_week`] and [`Datelike::weekday`] methods can be used to get the corresponding
-/// week date.
-///
-/// # Ordinal Date
-///
-/// The ISO 8601 **ordinal date** is a pair of year number and day of the year ("ordinal").
-/// The ordinal number ranges from 1 to 365 or 366 depending on the year.
-/// The year number is the same as that of the [calendar date](#calendar-date).
-///
-/// This is currently the internal format of Chrono's date types.
-///
-/// [proleptic Gregorian date]: crate::NaiveDate#calendar-date
-#[derive(PartialEq, Eq, Hash, PartialOrd, Ord, Copy, Clone)]
-#[cfg_attr(
-    any(feature = "rkyv", feature = "rkyv-16", feature = "rkyv-32", feature = "rkyv-64"),
-    derive(Archive, Deserialize, Serialize),
-    archive(compare(PartialEq, PartialOrd)),
-    archive_attr(derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash))
-)]
-#[cfg_attr(feature = "rkyv-validation", archive(check_bytes))]
-pub struct NaiveDate {
-    ymdf: DateImpl, // (year << 13) | of
-}
-
-/// The minimum possible `NaiveDate` (January 1, 262145 BCE).
-#[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).
-#[deprecated(since = "0.4.20", note = "Use NaiveDate::MAX instead")]
-pub const MAX_DATE: NaiveDate = NaiveDate::MAX;
-
-#[cfg(all(feature = "arbitrary", feature = "std"))]
-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)
-    }
-}
-
-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, ordinal and flags.
-    /// Does not check whether the flags are correct for the provided year.
-    const fn from_ordinal_and_flags(
-        year: i32,
-        ordinal: u32,
-        flags: YearFlags,
-    ) -> Option<NaiveDate> {
-        if year < MIN_YEAR || year > MAX_YEAR {
-            return None; // Out-of-range
-        }
-        debug_assert!(YearFlags::from_year(year).0 == flags.0);
-        match Of::new(ordinal, flags) {
-            Some(of) => Some(NaiveDate { ymdf: (year << 13) | (of.inner() as DateImpl) }),
-            None => None, // Invalid: Ordinal outside of the nr of days in a year with those flags.
-        }
-    }
-
-    /// Makes a new `NaiveDate` from year and packed month-day-flags.
-    /// Does not check whether the flags are correct for the provided year.
-    const fn from_mdf(year: i32, mdf: Mdf) -> Option<NaiveDate> {
-        if year < MIN_YEAR || year > MAX_YEAR {
-            return None; // Out-of-range
-        }
-        match mdf.to_of() {
-            Some(of) => Some(NaiveDate { ymdf: (year << 13) | (of.inner() as DateImpl) }),
-            None => None, // Non-existing date
-        }
-    }
-
-    /// Makes a new `NaiveDate` from the [calendar date](#calendar-date)
-    /// (year, month and day).
-    ///
-    /// # Panics
-    ///
-    /// Panics if the specified calendar day does not exist, on invalid values for `month` or `day`,
-    /// or if `year` is out of range for `NaiveDate`.
-    #[deprecated(since = "0.4.23", note = "use `from_ymd_opt()` instead")]
-    #[must_use]
-    pub const fn from_ymd(year: i32, month: u32, day: u32) -> NaiveDate {
-        expect!(NaiveDate::from_ymd_opt(year, month, day), "invalid or out-of-range date")
-    }
-
-    /// Makes a new `NaiveDate` from the [calendar date](#calendar-date)
-    /// (year, month and day).
-    ///
-    /// # Errors
-    ///
-    /// Returns `None` if:
-    /// - The specified calendar day does not exist (for example 2023-04-31).
-    /// - The value for `month` or `day` is invalid.
-    /// - `year` is out of range for `NaiveDate`.
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// use chrono::NaiveDate;
-    ///
-    /// let from_ymd_opt = NaiveDate::from_ymd_opt;
-    ///
-    /// assert!(from_ymd_opt(2015, 3, 14).is_some());
-    /// assert!(from_ymd_opt(2015, 0, 14).is_none());
-    /// assert!(from_ymd_opt(2015, 2, 29).is_none());
-    /// 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());
-    /// ```
-    #[must_use]
-    pub const fn from_ymd_opt(year: i32, month: u32, day: u32) -> Option<NaiveDate> {
-        let flags = YearFlags::from_year(year);
-
-        if let Some(mdf) = Mdf::new(month, day, flags) {
-            NaiveDate::from_mdf(year, mdf)
-        } else {
-            None
-        }
-    }
-
-    /// Makes a new `NaiveDate` from the [ordinal date](#ordinal-date)
-    /// (year and day of the year).
-    ///
-    /// # Panics
-    ///
-    /// Panics if the specified ordinal day does not exist, on invalid values for `ordinal`, or if
-    /// `year` is out of range for `NaiveDate`.
-    #[deprecated(since = "0.4.23", note = "use `from_yo_opt()` instead")]
-    #[must_use]
-    pub const fn from_yo(year: i32, ordinal: u32) -> NaiveDate {
-        expect!(NaiveDate::from_yo_opt(year, ordinal), "invalid or out-of-range date")
-    }
-
-    /// Makes a new `NaiveDate` from the [ordinal date](#ordinal-date)
-    /// (year and day of the year).
-    ///
-    /// # Errors
-    ///
-    /// Returns `None` if:
-    /// - The specified ordinal day does not exist (for example 2023-366).
-    /// - The value for `ordinal` is invalid (for example: `0`, `400`).
-    /// - `year` is out of range for `NaiveDate`.
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// use chrono::NaiveDate;
-    ///
-    /// let from_yo_opt = NaiveDate::from_yo_opt;
-    ///
-    /// assert!(from_yo_opt(2015, 100).is_some());
-    /// assert!(from_yo_opt(2015, 0).is_none());
-    /// assert!(from_yo_opt(2015, 365).is_some());
-    /// assert!(from_yo_opt(2015, 366).is_none());
-    /// 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());
-    /// ```
-    #[must_use]
-    pub const fn from_yo_opt(year: i32, ordinal: u32) -> Option<NaiveDate> {
-        let flags = YearFlags::from_year(year);
-        NaiveDate::from_ordinal_and_flags(year, ordinal, flags)
-    }
-
-    /// Makes a new `NaiveDate` from the [ISO week date](#week-date)
-    /// (year, week number and day of the week).
-    /// The resulting `NaiveDate` may have a different year from the input year.
-    ///
-    /// # Panics
-    ///
-    /// Panics if the specified week does not exist in that year, on invalid values for `week`, or
-    /// if the resulting date is out of range for `NaiveDate`.
-    #[deprecated(since = "0.4.23", note = "use `from_isoywd_opt()` instead")]
-    #[must_use]
-    pub const fn from_isoywd(year: i32, week: u32, weekday: Weekday) -> NaiveDate {
-        expect!(NaiveDate::from_isoywd_opt(year, week, weekday), "invalid or out-of-range date")
-    }
-
-    /// Makes a new `NaiveDate` from the [ISO week date](#week-date)
-    /// (year, week number and day of the week).
-    /// The resulting `NaiveDate` may have a different year from the input year.
-    ///
-    /// # Errors
-    ///
-    /// Returns `None` if:
-    /// - The specified week does not exist in that year (for example 2023 week 53).
-    /// - The value for `week` is invalid (for example: `0`, `60`).
-    /// - If the resulting date is out of range for `NaiveDate`.
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// use chrono::{NaiveDate, Weekday};
-    ///
-    /// let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap();
-    /// let from_isoywd_opt = NaiveDate::from_isoywd_opt;
-    ///
-    /// assert_eq!(from_isoywd_opt(2015, 0, Weekday::Sun), None);
-    /// assert_eq!(from_isoywd_opt(2015, 10, Weekday::Sun), Some(from_ymd(2015, 3, 8)));
-    /// assert_eq!(from_isoywd_opt(2015, 30, Weekday::Mon), Some(from_ymd(2015, 7, 20)));
-    /// assert_eq!(from_isoywd_opt(2015, 60, Weekday::Mon), None);
-    ///
-    /// 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 = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap();
-    /// # let from_isoywd_opt = NaiveDate::from_isoywd_opt;
-    /// //           Mo Tu We Th Fr Sa Su
-    /// // 2014-W52  22 23 24 25 26 27 28    has 4+ days of new year,
-    /// // 2015-W01  29 30 31  1  2  3  4 <- so this is the first week
-    /// assert_eq!(from_isoywd_opt(2014, 52, Weekday::Sun), Some(from_ymd(2014, 12, 28)));
-    /// assert_eq!(from_isoywd_opt(2014, 53, Weekday::Mon), None);
-    /// assert_eq!(from_isoywd_opt(2015, 1, Weekday::Mon), Some(from_ymd(2014, 12, 29)));
-    ///
-    /// // 2015-W52  21 22 23 24 25 26 27    has 4+ days of old year,
-    /// // 2015-W53  28 29 30 31  1  2  3 <- so this is the last week
-    /// // 2016-W01   4  5  6  7  8  9 10
-    /// assert_eq!(from_isoywd_opt(2015, 52, Weekday::Sun), Some(from_ymd(2015, 12, 27)));
-    /// 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)));
-    /// ```
-    #[must_use]
-    pub const fn from_isoywd_opt(year: i32, week: u32, weekday: Weekday) -> Option<NaiveDate> {
-        let flags = YearFlags::from_year(year);
-        let nweeks = flags.nisoweeks();
-        if 1 <= week && week <= nweeks {
-            // ordinal = week ordinal - delta
-            let weekord = week * 7 + weekday as u32;
-            let delta = flags.isoweek_delta();
-            if weekord <= delta {
-                // ordinal < 1, previous year
-                let prevflags = YearFlags::from_year(year - 1);
-                NaiveDate::from_ordinal_and_flags(
-                    year - 1,
-                    weekord + prevflags.ndays() - delta,
-                    prevflags,
-                )
-            } else {
-                let ordinal = weekord - delta;
-                let ndays = flags.ndays();
-                if ordinal <= ndays {
-                    // this year
-                    NaiveDate::from_ordinal_and_flags(year, ordinal, flags)
-                } else {
-                    // ordinal > ndays, next year
-                    let nextflags = YearFlags::from_year(year + 1);
-                    NaiveDate::from_ordinal_and_flags(year + 1, ordinal - ndays, nextflags)
-                }
-            }
-        } else {
-            None
-        }
-    }
-
-    /// Makes a new `NaiveDate` from a day's number in the proleptic Gregorian calendar, with
-    /// January 1, 1 being day 1.
-    ///
-    /// # Panics
-    ///
-    /// Panics if the date is out of range.
-    #[deprecated(since = "0.4.23", note = "use `from_num_days_from_ce_opt()` instead")]
-    #[inline]
-    #[must_use]
-    pub const fn from_num_days_from_ce(days: i32) -> NaiveDate {
-        expect!(NaiveDate::from_num_days_from_ce_opt(days), "out-of-range date")
-    }
-
-    /// Makes a new `NaiveDate` from a day's number in the proleptic Gregorian calendar, with
-    /// January 1, 1 being day 1.
-    ///
-    /// # Errors
-    ///
-    /// Returns `None` if the date is out of range.
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// use chrono::NaiveDate;
-    ///
-    /// let from_ndays_opt = NaiveDate::from_num_days_from_ce_opt;
-    /// 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)));
-    /// assert_eq!(from_ndays_opt(0),            Some(from_ymd(0, 12, 31)));
-    /// 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);
-    /// ```
-    #[must_use]
-    pub const fn from_num_days_from_ce_opt(days: i32) -> Option<NaiveDate> {
-        let days = try_opt!(days.checked_add(365)); // make December 31, 1 BCE equal to day 0
-        let year_div_400 = days.div_euclid(146_097);
-        let cycle = days.rem_euclid(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_ordinal_and_flags(year_div_400 * 400 + year_mod_400 as i32, ordinal, flags)
-    }
-
-    /// Makes a new `NaiveDate` by counting the number of occurrences of a particular day-of-week
-    /// 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.
-    ///
-    /// # Panics
-    ///
-    /// Panics if the specified day does not exist in that month, on invalid values for `month` or
-    /// `n`, or if `year` is out of range for `NaiveDate`.
-    #[deprecated(since = "0.4.23", note = "use `from_weekday_of_month_opt()` instead")]
-    #[must_use]
-    pub const fn from_weekday_of_month(
-        year: i32,
-        month: u32,
-        weekday: Weekday,
-        n: u8,
-    ) -> NaiveDate {
-        expect!(NaiveDate::from_weekday_of_month_opt(year, month, weekday, n), "out-of-range date")
-    }
-
-    /// Makes a new `NaiveDate` by counting the number of occurrences of a particular day-of-week
-    /// 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.
-    ///
-    /// # Errors
-    ///
-    /// Returns `None` if:
-    /// - The specified day does not exist in that month (for example the 5th Monday of Apr. 2023).
-    /// - The value for `month` or `n` is invalid.
-    /// - `year` is out of range for `NaiveDate`.
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// use chrono::{NaiveDate, Weekday};
-    /// assert_eq!(NaiveDate::from_weekday_of_month_opt(2017, 3, Weekday::Fri, 2),
-    ///            NaiveDate::from_ymd_opt(2017, 3, 10))
-    /// ```
-    #[must_use]
-    pub const fn from_weekday_of_month_opt(
-        year: i32,
-        month: u32,
-        weekday: Weekday,
-        n: u8,
-    ) -> Option<NaiveDate> {
-        if n == 0 {
-            return None;
-        }
-        let first = try_opt!(NaiveDate::from_ymd_opt(year, month, 1)).weekday();
-        let first_to_dow = (7 + weekday.number_from_monday() - first.number_from_monday()) % 7;
-        let day = (n - 1) as u32 * 7 + first_to_dow + 1;
-        NaiveDate::from_ymd_opt(year, month, day)
-    }
-
-    /// Parses a string with the specified format string and returns a new `NaiveDate`.
-    /// See the [`format::strftime` module](crate::format::strftime)
-    /// on the supported escape sequences.
-    ///
-    /// # 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_opt(2015, 9, 5).unwrap()));
-    /// assert_eq!(parse_from_str("5sep2015", "%d%b%Y"),
-    ///            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_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()
-    }
-
-    /// Parses a string from a user-specified format into a new `NaiveDate` value, and a slice with
-    /// the remaining portion of the string.
-    /// See the [`format::strftime` module](crate::format::strftime)
-    /// on the supported escape sequences.
-    ///
-    /// Similar to [`parse_from_str`](#method.parse_from_str).
-    ///
-    /// # Example
-    ///
-    /// ```rust
-    /// # use chrono::{NaiveDate};
-    /// let (date, remainder) = NaiveDate::parse_and_remainder(
-    ///     "2015-02-18 trailing text", "%Y-%m-%d").unwrap();
-    /// assert_eq!(date, NaiveDate::from_ymd_opt(2015, 2, 18).unwrap());
-    /// assert_eq!(remainder, " trailing text");
-    /// ```
-    pub fn parse_and_remainder<'a>(s: &'a str, fmt: &str) -> ParseResult<(NaiveDate, &'a str)> {
-        let mut parsed = Parsed::new();
-        let remainder = parse_and_remainder(&mut parsed, s, StrftimeItems::new(fmt))?;
-        parsed.to_naive_date().map(|d| (d, remainder))
-    }
-
-    /// Add a duration in [`Months`] to the date
-    ///
-    /// Uses the last day of the month if the day does not exist in the resulting month.
-    ///
-    /// # Errors
-    ///
-    /// Returns `None` if the resulting date would be out of range.
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// # 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())
-    /// );
-    /// ```
-    #[must_use]
-    pub const 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
-    ///
-    /// Uses the last day of the month if the day does not exist in the resulting month.
-    ///
-    /// # Errors
-    ///
-    /// Returns `None` if the resulting date would be out of range.
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// # 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
-    /// );
-    /// ```
-    #[must_use]
-    pub const 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,
-        }
-    }
-
-    const 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_max = days[(month - 1) as usize];
-        let mut day = self.day();
-        if day > day_max {
-            day = day_max;
-        };
-
-        NaiveDate::from_mdf(year, try_opt!(Mdf::new(month as u32, day, flags)))
-    }
-
-    /// Add a duration in [`Days`] to the date
-    ///
-    /// # Errors
-    ///
-    /// Returns `None` if the resulting date would be out of range.
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// # 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
-    /// );
-    /// ```
-    #[must_use]
-    pub const fn checked_add_days(self, days: Days) -> Option<Self> {
-        match days.0 <= i32::MAX as u64 {
-            true => self.add_days(days.0 as i32),
-            false => None,
-        }
-    }
-
-    /// Subtract a duration in [`Days`] from the date
-    ///
-    /// # Errors
-    ///
-    /// Returns `None` if the resulting date would be out of range.
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// # 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
-    /// );
-    /// ```
-    #[must_use]
-    pub const fn checked_sub_days(self, days: Days) -> Option<Self> {
-        match days.0 <= i32::MAX as u64 {
-            true => self.add_days(-(days.0 as i32)),
-            false => None,
-        }
-    }
-
-    /// Add a duration of `i32` days to the date.
-    pub(crate) const fn add_days(self, days: i32) -> Option<Self> {
-        // fast path if the result is within the same year
-        const ORDINAL_MASK: i32 = 0b1_1111_1111_0000;
-        if let Some(ordinal) = ((self.ymdf & ORDINAL_MASK) >> 4).checked_add(days) {
-            if ordinal > 0 && ordinal <= 365 {
-                let year_and_flags = self.ymdf & !ORDINAL_MASK;
-                return Some(NaiveDate { ymdf: year_and_flags | (ordinal << 4) });
-            }
-        }
-        // do the full check
-        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(days));
-        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_ordinal_and_flags(year_div_400 * 400 + year_mod_400 as i32, ordinal, flags)
-    }
-
-    /// Makes a new `NaiveDateTime` from the current date and given `NaiveTime`.
-    ///
-    /// # 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 = d.and_time(t);
-    /// assert_eq!(dt.date(), d);
-    /// assert_eq!(dt.time(), t);
-    /// ```
-    #[inline]
-    #[must_use]
-    pub const fn and_time(&self, time: NaiveTime) -> NaiveDateTime {
-        NaiveDateTime::new(*self, time)
-    }
-
-    /// Makes a new `NaiveDateTime` from the current date, hour, minute and second.
-    ///
-    /// No [leap second](./struct.NaiveTime.html#leap-second-handling) is allowed here;
-    /// use `NaiveDate::and_hms_*` methods with a subsecond parameter instead.
-    ///
-    /// # Panics
-    ///
-    /// Panics on invalid hour, minute and/or second.
-    #[deprecated(since = "0.4.23", note = "use `and_hms_opt()` instead")]
-    #[inline]
-    #[must_use]
-    pub const fn and_hms(&self, hour: u32, min: u32, sec: u32) -> NaiveDateTime {
-        expect!(self.and_hms_opt(hour, min, sec), "invalid time")
-    }
-
-    /// Makes a new `NaiveDateTime` from the current date, hour, minute and second.
-    ///
-    /// No [leap second](./struct.NaiveTime.html#leap-second-handling) is allowed here;
-    /// use `NaiveDate::and_hms_*_opt` methods with a subsecond parameter instead.
-    ///
-    /// # Errors
-    ///
-    /// Returns `None` on invalid hour, minute and/or second.
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// use chrono::NaiveDate;
-    ///
-    /// 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]
-    #[must_use]
-    pub const fn and_hms_opt(&self, hour: u32, min: u32, sec: u32) -> Option<NaiveDateTime> {
-        let time = try_opt!(NaiveTime::from_hms_opt(hour, min, sec));
-        Some(self.and_time(time))
-    }
-
-    /// Makes a new `NaiveDateTime` from the current date, hour, minute, second and millisecond.
-    ///
-    /// The millisecond part is allowed to exceed 1,000,000,000 in order to represent a [leap second](
-    /// ./struct.NaiveTime.html#leap-second-handling), but only when `sec == 59`.
-    ///
-    /// # Panics
-    ///
-    /// Panics on invalid hour, minute, second and/or millisecond.
-    #[deprecated(since = "0.4.23", note = "use `and_hms_milli_opt()` instead")]
-    #[inline]
-    #[must_use]
-    pub const fn and_hms_milli(&self, hour: u32, min: u32, sec: u32, milli: u32) -> NaiveDateTime {
-        expect!(self.and_hms_milli_opt(hour, min, sec, milli), "invalid time")
-    }
-
-    /// Makes a new `NaiveDateTime` from the current date, hour, minute, second and millisecond.
-    ///
-    /// The millisecond part is allowed to exceed 1,000,000,000 in order to represent a [leap second](
-    /// ./struct.NaiveTime.html#leap-second-handling), but only when `sec == 59`.
-    ///
-    /// # Errors
-    ///
-    /// Returns `None` on invalid hour, minute, second and/or millisecond.
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// use chrono::NaiveDate;
-    ///
-    /// 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]
-    #[must_use]
-    pub const fn and_hms_milli_opt(
-        &self,
-        hour: u32,
-        min: u32,
-        sec: u32,
-        milli: u32,
-    ) -> Option<NaiveDateTime> {
-        let time = try_opt!(NaiveTime::from_hms_milli_opt(hour, min, sec, milli));
-        Some(self.and_time(time))
-    }
-
-    /// Makes a new `NaiveDateTime` from the current date, hour, minute, second and microsecond.
-    ///
-    /// The microsecond part is allowed to exceed 1,000,000,000 in order to represent a [leap second](
-    /// ./struct.NaiveTime.html#leap-second-handling), but only when `sec == 59`.
-    ///
-    /// # Panics
-    ///
-    /// Panics on invalid hour, minute, second and/or microsecond.
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// use chrono::{NaiveDate, NaiveDateTime, Datelike, Timelike, Weekday};
-    ///
-    /// let d = NaiveDate::from_ymd_opt(2015, 6, 3).unwrap();
-    ///
-    /// let dt: NaiveDateTime = d.and_hms_micro_opt(12, 34, 56, 789_012).unwrap();
-    /// assert_eq!(dt.year(), 2015);
-    /// assert_eq!(dt.weekday(), Weekday::Wed);
-    /// assert_eq!(dt.second(), 56);
-    /// assert_eq!(dt.nanosecond(), 789_012_000);
-    /// ```
-    #[deprecated(since = "0.4.23", note = "use `and_hms_micro_opt()` instead")]
-    #[inline]
-    #[must_use]
-    pub const fn and_hms_micro(&self, hour: u32, min: u32, sec: u32, micro: u32) -> NaiveDateTime {
-        expect!(self.and_hms_micro_opt(hour, min, sec, micro), "invalid time")
-    }
-
-    /// Makes a new `NaiveDateTime` from the current date, hour, minute, second and microsecond.
-    ///
-    /// The microsecond part is allowed to exceed 1,000,000,000 in order to represent a [leap second](
-    /// ./struct.NaiveTime.html#leap-second-handling), but only when `sec == 59`.
-    ///
-    /// # Errors
-    ///
-    /// Returns `None` on invalid hour, minute, second and/or microsecond.
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// use chrono::NaiveDate;
-    ///
-    /// 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]
-    #[must_use]
-    pub const fn and_hms_micro_opt(
-        &self,
-        hour: u32,
-        min: u32,
-        sec: u32,
-        micro: u32,
-    ) -> Option<NaiveDateTime> {
-        let time = try_opt!(NaiveTime::from_hms_micro_opt(hour, min, sec, micro));
-        Some(self.and_time(time))
-    }
-
-    /// Makes a new `NaiveDateTime` from the current date, hour, minute, second and nanosecond.
-    ///
-    /// The nanosecond part is allowed to exceed 1,000,000,000 in order to represent a [leap second](
-    /// ./struct.NaiveTime.html#leap-second-handling), but only when `sec == 59`.
-    ///
-    /// # Panics
-    ///
-    /// Panics on invalid hour, minute, second and/or nanosecond.
-    #[deprecated(since = "0.4.23", note = "use `and_hms_nano_opt()` instead")]
-    #[inline]
-    #[must_use]
-    pub const fn and_hms_nano(&self, hour: u32, min: u32, sec: u32, nano: u32) -> NaiveDateTime {
-        expect!(self.and_hms_nano_opt(hour, min, sec, nano), "invalid time")
-    }
-
-    /// Makes a new `NaiveDateTime` from the current date, hour, minute, second and nanosecond.
-    ///
-    /// The nanosecond part is allowed to exceed 1,000,000,000 in order to represent a [leap second](
-    /// ./struct.NaiveTime.html#leap-second-handling), but only when `sec == 59`.
-    ///
-    /// # Errors
-    ///
-    /// Returns `None` on invalid hour, minute, second and/or nanosecond.
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// use chrono::NaiveDate;
-    ///
-    /// 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]
-    #[must_use]
-    pub const fn and_hms_nano_opt(
-        &self,
-        hour: u32,
-        min: u32,
-        sec: u32,
-        nano: u32,
-    ) -> Option<NaiveDateTime> {
-        let time = try_opt!(NaiveTime::from_hms_nano_opt(hour, min, sec, nano));
-        Some(self.and_time(time))
-    }
-
-    /// Returns the packed month-day-flags.
-    #[inline]
-    const fn mdf(&self) -> Mdf {
-        self.of().to_mdf()
-    }
-
-    /// Returns the packed ordinal-flags.
-    #[inline]
-    const fn of(&self) -> Of {
-        Of::from_date_impl(self.ymdf)
-    }
-
-    /// Makes a new `NaiveDate` with the packed month-day-flags changed.
-    ///
-    /// Returns `None` when the resulting `NaiveDate` would be invalid.
-    #[inline]
-    const fn with_mdf(&self, mdf: Mdf) -> Option<NaiveDate> {
-        Some(self.with_of(try_opt!(mdf.to_of())))
-    }
-
-    /// Makes a new `NaiveDate` with the packed ordinal-flags changed.
-    ///
-    /// Returns `None` when the resulting `NaiveDate` would be invalid.
-    /// Does not check if the year flags match the year.
-    #[inline]
-    const fn with_of(&self, of: Of) -> NaiveDate {
-        NaiveDate { ymdf: (self.ymdf & !0b1_1111_1111_1111) | of.inner() as DateImpl }
-    }
-
-    /// Makes a new `NaiveDate` for the next calendar date.
-    ///
-    /// # Panics
-    ///
-    /// Panics when `self` is the last representable date.
-    #[deprecated(since = "0.4.23", note = "use `succ_opt()` instead")]
-    #[inline]
-    #[must_use]
-    pub const fn succ(&self) -> NaiveDate {
-        expect!(self.succ_opt(), "out of bound")
-    }
-
-    /// Makes a new `NaiveDate` for the next calendar date.
-    ///
-    /// # Errors
-    ///
-    /// Returns `None` when `self` is the last representable date.
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// use chrono::NaiveDate;
-    ///
-    /// 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]
-    #[must_use]
-    pub const fn succ_opt(&self) -> Option<NaiveDate> {
-        match self.of().succ() {
-            Some(of) => Some(self.with_of(of)),
-            None => NaiveDate::from_ymd_opt(self.year() + 1, 1, 1),
-        }
-    }
-
-    /// Makes a new `NaiveDate` for the previous calendar date.
-    ///
-    /// # Panics
-    ///
-    /// Panics when `self` is the first representable date.
-    #[deprecated(since = "0.4.23", note = "use `pred_opt()` instead")]
-    #[inline]
-    #[must_use]
-    pub const fn pred(&self) -> NaiveDate {
-        expect!(self.pred_opt(), "out of bound")
-    }
-
-    /// Makes a new `NaiveDate` for the previous calendar date.
-    ///
-    /// # Errors
-    ///
-    /// Returns `None` when `self` is the first representable date.
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// use chrono::NaiveDate;
-    ///
-    /// 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]
-    #[must_use]
-    pub const fn pred_opt(&self) -> Option<NaiveDate> {
-        match self.of().pred() {
-            Some(of) => Some(self.with_of(of)),
-            None => NaiveDate::from_ymd_opt(self.year() - 1, 12, 31),
-        }
-    }
-
-    /// Adds the number of whole days in the given `TimeDelta` to the current date.
-    ///
-    /// # Errors
-    ///
-    /// Returns `None` if the resulting date would be out of range.
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// use chrono::{TimeDelta, NaiveDate};
-    ///
-    /// let d = NaiveDate::from_ymd_opt(2015, 9, 5).unwrap();
-    /// assert_eq!(d.checked_add_signed(TimeDelta::days(40)),
-    ///            Some(NaiveDate::from_ymd_opt(2015, 10, 15).unwrap()));
-    /// assert_eq!(d.checked_add_signed(TimeDelta::days(-40)),
-    ///            Some(NaiveDate::from_ymd_opt(2015, 7, 27).unwrap()));
-    /// assert_eq!(d.checked_add_signed(TimeDelta::days(1_000_000_000)), None);
-    /// assert_eq!(d.checked_add_signed(TimeDelta::days(-1_000_000_000)), None);
-    /// assert_eq!(NaiveDate::MAX.checked_add_signed(TimeDelta::days(1)), None);
-    /// ```
-    #[must_use]
-    pub const fn checked_add_signed(self, rhs: TimeDelta) -> Option<NaiveDate> {
-        let days = rhs.num_days();
-        if days < i32::MIN as i64 || days > i32::MAX as i64 {
-            return None;
-        }
-        self.add_days(days as i32)
-    }
-
-    /// Subtracts the number of whole days in the given `TimeDelta` from the current date.
-    ///
-    /// # Errors
-    ///
-    /// Returns `None` if the resulting date would be out of range.
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// use chrono::{TimeDelta, NaiveDate};
-    ///
-    /// let d = NaiveDate::from_ymd_opt(2015, 9, 5).unwrap();
-    /// assert_eq!(d.checked_sub_signed(TimeDelta::days(40)),
-    ///            Some(NaiveDate::from_ymd_opt(2015, 7, 27).unwrap()));
-    /// assert_eq!(d.checked_sub_signed(TimeDelta::days(-40)),
-    ///            Some(NaiveDate::from_ymd_opt(2015, 10, 15).unwrap()));
-    /// assert_eq!(d.checked_sub_signed(TimeDelta::days(1_000_000_000)), None);
-    /// assert_eq!(d.checked_sub_signed(TimeDelta::days(-1_000_000_000)), None);
-    /// assert_eq!(NaiveDate::MIN.checked_sub_signed(TimeDelta::days(1)), None);
-    /// ```
-    #[must_use]
-    pub const fn checked_sub_signed(self, rhs: TimeDelta) -> Option<NaiveDate> {
-        let days = -rhs.num_days();
-        if days < i32::MIN as i64 || days > i32::MAX as i64 {
-            return None;
-        }
-        self.add_days(days as i32)
-    }
-
-    /// Subtracts another `NaiveDate` from the current date.
-    /// Returns a `TimeDelta` of integral numbers.
-    ///
-    /// This does not overflow or underflow at all,
-    /// as all possible output fits in the range of `TimeDelta`.
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// use chrono::{TimeDelta, NaiveDate};
-    ///
-    /// let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap();
-    /// let since = NaiveDate::signed_duration_since;
-    ///
-    /// assert_eq!(since(from_ymd(2014, 1, 1), from_ymd(2014, 1, 1)), TimeDelta::zero());
-    /// assert_eq!(since(from_ymd(2014, 1, 1), from_ymd(2013, 12, 31)), TimeDelta::days(1));
-    /// assert_eq!(since(from_ymd(2014, 1, 1), from_ymd(2014, 1, 2)), TimeDelta::days(-1));
-    /// assert_eq!(since(from_ymd(2014, 1, 1), from_ymd(2013, 9, 23)), TimeDelta::days(100));
-    /// assert_eq!(since(from_ymd(2014, 1, 1), from_ymd(2013, 1, 1)), TimeDelta::days(365));
-    /// assert_eq!(since(from_ymd(2014, 1, 1), from_ymd(2010, 1, 1)), TimeDelta::days(365*4 + 1));
-    /// assert_eq!(since(from_ymd(2014, 1, 1), from_ymd(1614, 1, 1)), TimeDelta::days(365*400 + 97));
-    /// ```
-    #[must_use]
-    pub const fn signed_duration_since(self, rhs: NaiveDate) -> TimeDelta {
-        let year1 = self.year();
-        let year2 = rhs.year();
-        let (year1_div_400, year1_mod_400) = div_mod_floor(year1, 400);
-        let (year2_div_400, year2_mod_400) = div_mod_floor(year2, 400);
-        let cycle1 = internals::yo_to_cycle(year1_mod_400 as u32, self.of().ordinal()) as i64;
-        let cycle2 = internals::yo_to_cycle(year2_mod_400 as u32, rhs.of().ordinal()) as i64;
-        TimeDelta::days((year1_div_400 as i64 - year2_div_400 as i64) * 146_097 + (cycle1 - cycle2))
-    }
-
-    /// Returns the number of whole years from the given `base` until `self`.
-    ///
-    /// # Errors
-    ///
-    /// Returns `None` if `base < self`.
-    #[must_use]
-    pub const fn years_since(&self, base: Self) -> Option<u32> {
-        let mut years = self.year() - base.year();
-        // Comparing tuples is not (yet) possible in const context. Instead we combine month and
-        // day into one `u32` for easy comparison.
-        if (self.month() << 5 | self.day()) < (base.month() << 5 | 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.
-    ///
-    /// 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");
-    /// 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_opt(2015, 9, 5).unwrap();
-    /// assert_eq!(format!("{}", d.format_with_items(fmt)), "2015-09-05");
-    /// ```
-    #[cfg(feature = "alloc")]
-    #[inline]
-    #[must_use]
-    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), None, items)
-    }
-
-    /// Formats the date with the specified format string.
-    /// See the [`format::strftime` module](crate::format::strftime)
-    /// 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 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_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(feature = "alloc")]
-    #[inline]
-    #[must_use]
-    pub fn format<'a>(&self, fmt: &'a str) -> DelayedFormat<StrftimeItems<'a>> {
-        self.format_with_items(StrftimeItems::new(fmt))
-    }
-
-    /// Formats the date with the specified formatting items and locale.
-    #[cfg(all(feature = "unstable-locales", feature = "alloc"))]
-    #[inline]
-    #[must_use]
-    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(all(feature = "unstable-locales", feature = "alloc"))]
-    #[inline]
-    #[must_use]
-    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
-    ///
-    /// ```
-    /// # use chrono::NaiveDate;
-    ///
-    /// let expected = [
-    ///     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_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 const fn iter_days(&self) -> NaiveDateDaysIterator {
-        NaiveDateDaysIterator { value: *self }
-    }
-
-    /// Returns an iterator that steps by weeks across all representable dates.
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// # use chrono::NaiveDate;
-    ///
-    /// let expected = [
-    ///     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_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 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 }
-    }
-
-    /// Returns `true` if this is a leap year.
-    ///
-    /// ```
-    /// # use chrono::NaiveDate;
-    /// assert_eq!(NaiveDate::from_ymd_opt(2000, 1, 1).unwrap().leap_year(), true);
-    /// assert_eq!(NaiveDate::from_ymd_opt(2001, 1, 1).unwrap().leap_year(), false);
-    /// assert_eq!(NaiveDate::from_ymd_opt(2002, 1, 1).unwrap().leap_year(), false);
-    /// assert_eq!(NaiveDate::from_ymd_opt(2003, 1, 1).unwrap().leap_year(), false);
-    /// assert_eq!(NaiveDate::from_ymd_opt(2004, 1, 1).unwrap().leap_year(), true);
-    /// assert_eq!(NaiveDate::from_ymd_opt(2100, 1, 1).unwrap().leap_year(), false);
-    /// ```
-    pub const fn leap_year(&self) -> bool {
-        self.ymdf & (0b1000) == 0
-    }
-
-    // This duplicates `Datelike::year()`, because trait methods can't be const yet.
-    #[inline]
-    const fn year(&self) -> i32 {
-        self.ymdf >> 13
-    }
-
-    /// Returns the day of year starting from 1.
-    // This duplicates `Datelike::ordinal()`, because trait methods can't be const yet.
-    #[inline]
-    const fn ordinal(&self) -> u32 {
-        self.of().ordinal()
-    }
-
-    // This duplicates `Datelike::month()`, because trait methods can't be const yet.
-    #[inline]
-    const fn month(&self) -> u32 {
-        self.mdf().month()
-    }
-
-    // This duplicates `Datelike::day()`, because trait methods can't be const yet.
-    #[inline]
-    const fn day(&self) -> u32 {
-        self.mdf().day()
-    }
-
-    // This duplicates `Datelike::weekday()`, because trait methods can't be const yet.
-    #[inline]
-    const fn weekday(&self) -> Weekday {
-        self.of().weekday()
-    }
-
-    /// Counts the days in the proleptic Gregorian calendar, with January 1, Year 1 (CE) as day 1.
-    // This duplicates `Datelike::num_days_from_ce()`, because trait methods can't be const yet.
-    pub(crate) const fn num_days_from_ce(&self) -> i32 {
-        // 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 minimum possible `NaiveDate` (January 1, 262144 BCE).
-    pub const MIN: NaiveDate = NaiveDate { ymdf: (MIN_YEAR << 13) | (1 << 4) | 0o12 /*D*/ };
-    /// The maximum possible `NaiveDate` (December 31, 262142 CE).
-    pub const MAX: NaiveDate = NaiveDate { ymdf: (MAX_YEAR << 13) | (365 << 4) | 0o16 /*G*/ };
-
-    /// One day before the minimum possible `NaiveDate` (December 31, 262145 BCE).
-    pub(crate) const BEFORE_MIN: NaiveDate =
-        NaiveDate { ymdf: ((MIN_YEAR - 1) << 13) | (366 << 4) | 0o07 /*FE*/ };
-    /// One day after the maximum possible `NaiveDate` (January 1, 262143 CE).
-    pub(crate) const AFTER_MAX: NaiveDate =
-        NaiveDate { ymdf: ((MAX_YEAR + 1) << 13) | (1 << 4) | 0o17 /*F*/ };
-}
-
-impl Datelike for NaiveDate {
-    /// Returns the year number in the [calendar date](#calendar-date).
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// use chrono::{NaiveDate, Datelike};
-    ///
-    /// 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.year()
-    }
-
-    /// Returns the month number starting from 1.
-    ///
-    /// The return value ranges from 1 to 12.
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// use chrono::{NaiveDate, Datelike};
-    ///
-    /// 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.month()
-    }
-
-    /// Returns the month number starting from 0.
-    ///
-    /// The return value ranges from 0 to 11.
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// use chrono::{NaiveDate, Datelike};
-    ///
-    /// 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.month() - 1
-    }
-
-    /// Returns the day of month starting from 1.
-    ///
-    /// The return value ranges from 1 to 31. (The last day of month differs by months.)
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// use chrono::{NaiveDate, Datelike};
-    ///
-    /// 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_opt`](#method.pred_opt),
-    /// 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_opt(y, m, 1).unwrap();
-    ///
-    ///     // ...is preceded by the last day of the original month
-    ///     d.pred_opt().unwrap().day()
-    /// }
-    ///
-    /// assert_eq!(ndays_in_month(2015, 8), 31);
-    /// assert_eq!(ndays_in_month(2015, 9), 30);
-    /// 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.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.)
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// use chrono::{NaiveDate, Datelike};
-    ///
-    /// 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
-    }
-
-    /// Returns the day of year starting from 1.
-    ///
-    /// The return value ranges from 1 to 366. (The last day of year differs by years.)
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// use chrono::{NaiveDate, Datelike};
-    ///
-    /// 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_opt`](#method.pred_opt),
-    /// 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_opt(year + 1, 1, 1).unwrap();
-    ///
-    ///     // ...is preceded by the last day of the original year
-    ///     d.pred_opt().unwrap().ordinal()
-    /// }
-    ///
-    /// assert_eq!(ndays_in_year(2015), 365);
-    /// assert_eq!(ndays_in_year(2016), 366);
-    /// 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()
-    }
-
-    /// Returns the day of year starting from 0.
-    ///
-    /// The return value ranges from 0 to 365. (The last day of year differs by years.)
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// use chrono::{NaiveDate, Datelike};
-    ///
-    /// 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
-    }
-
-    /// Returns the day of week.
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// use chrono::{NaiveDate, Datelike, Weekday};
-    ///
-    /// 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.weekday()
-    }
-
-    #[inline]
-    fn iso_week(&self) -> IsoWeek {
-        isoweek::iso_week_from_yof(self.year(), self.of())
-    }
-
-    /// Makes a new `NaiveDate` with the year number changed, while keeping the same month and day.
-    ///
-    /// # Errors
-    ///
-    /// Returns `None` if the resulting date does not exist, or when the `NaiveDate` would be
-    /// out of range.
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// use chrono::{NaiveDate, Datelike};
-    ///
-    /// 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_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
-        let mdf = self.mdf();
-
-        // adjust the flags as needed
-        let flags = YearFlags::from_year(year);
-        let mdf = mdf.with_flags(flags);
-
-        NaiveDate::from_mdf(year, mdf)
-    }
-
-    /// Makes a new `NaiveDate` with the month number (starting from 1) changed.
-    ///
-    /// # Errors
-    ///
-    /// Returns `None` if the resulting date does not exist, or if the value for `month` is invalid.
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// use chrono::{NaiveDate, Datelike};
-    ///
-    /// 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)?)
-    }
-
-    /// Makes a new `NaiveDate` with the month number (starting from 0) changed.
-    ///
-    /// # Errors
-    ///
-    /// Returns `None` if the resulting date does not exist, or if the value for `month0` is
-    /// invalid.
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// use chrono::{NaiveDate, Datelike};
-    ///
-    /// 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> {
-        let month = month0.checked_add(1)?;
-        self.with_mdf(self.mdf().with_month(month)?)
-    }
-
-    /// Makes a new `NaiveDate` with the day of month (starting from 1) changed.
-    ///
-    /// # Errors
-    ///
-    /// Returns `None` if the resulting date does not exist, or if the value for `day` is invalid.
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// use chrono::{NaiveDate, Datelike};
-    ///
-    /// 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)?)
-    }
-
-    /// Makes a new `NaiveDate` with the day of month (starting from 0) changed.
-    ///
-    /// # Errors
-    ///
-    /// Returns `None` if the resulting date does not exist, or if the value for `day0` is invalid.
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// use chrono::{NaiveDate, Datelike};
-    ///
-    /// 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> {
-        let day = day0.checked_add(1)?;
-        self.with_mdf(self.mdf().with_day(day)?)
-    }
-
-    /// Makes a new `NaiveDate` with the day of year (starting from 1) changed.
-    ///
-    /// # Errors
-    ///
-    /// Returns `None` if the resulting date does not exist, or if the value for `ordinal` is
-    /// invalid.
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// use chrono::{NaiveDate, Datelike};
-    ///
-    /// 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_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.of().with_ordinal(ordinal).map(|of| self.with_of(of))
-    }
-
-    /// Makes a new `NaiveDate` with the day of year (starting from 0) changed.
-    ///
-    /// # Errors
-    ///
-    /// Returns `None` if the resulting date does not exist, or if the value for `ordinal0` is
-    /// invalid.
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// use chrono::{NaiveDate, Datelike};
-    ///
-    /// 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_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> {
-        let ordinal = ordinal0.checked_add(1)?;
-        self.with_ordinal(ordinal)
-    }
-}
-
-/// Add `TimeDelta` to `NaiveDate`.
-///
-/// This discards the fractional days in `TimeDelta`, rounding to the closest integral number of
-/// days towards `TimeDelta::zero()`.
-///
-/// # Panics
-///
-/// Panics if the resulting date would be out of range.
-/// Consider using [`NaiveDate::checked_add_signed`] to get an `Option` instead.
-///
-/// # Example
-///
-/// ```
-/// use chrono::{TimeDelta, NaiveDate};
-///
-/// let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap();
-///
-/// assert_eq!(from_ymd(2014, 1, 1) + TimeDelta::zero(),             from_ymd(2014, 1, 1));
-/// assert_eq!(from_ymd(2014, 1, 1) + TimeDelta::seconds(86399),     from_ymd(2014, 1, 1));
-/// assert_eq!(from_ymd(2014, 1, 1) + TimeDelta::seconds(-86399),    from_ymd(2014, 1, 1));
-/// assert_eq!(from_ymd(2014, 1, 1) + TimeDelta::days(1),            from_ymd(2014, 1, 2));
-/// assert_eq!(from_ymd(2014, 1, 1) + TimeDelta::days(-1),           from_ymd(2013, 12, 31));
-/// assert_eq!(from_ymd(2014, 1, 1) + TimeDelta::days(364),          from_ymd(2014, 12, 31));
-/// assert_eq!(from_ymd(2014, 1, 1) + TimeDelta::days(365*4 + 1),    from_ymd(2018, 1, 1));
-/// assert_eq!(from_ymd(2014, 1, 1) + TimeDelta::days(365*400 + 97), from_ymd(2414, 1, 1));
-/// ```
-///
-/// [`NaiveDate::checked_add_signed`]: crate::NaiveDate::checked_add_signed
-impl Add<TimeDelta> for NaiveDate {
-    type Output = NaiveDate;
-
-    #[inline]
-    fn add(self, rhs: TimeDelta) -> NaiveDate {
-        self.checked_add_signed(rhs).expect("`NaiveDate + TimeDelta` overflowed")
-    }
-}
-
-/// Add-assign of `TimeDelta` to `NaiveDate`.
-///
-/// This discards the fractional days in `TimeDelta`, rounding to the closest integral number of days
-/// towards `TimeDelta::zero()`.
-///
-/// # Panics
-///
-/// Panics if the resulting date would be out of range.
-/// Consider using [`NaiveDate::checked_add_signed`] to get an `Option` instead.
-impl AddAssign<TimeDelta> for NaiveDate {
-    #[inline]
-    fn add_assign(&mut self, rhs: TimeDelta) {
-        *self = self.add(rhs);
-    }
-}
-
-/// Add `Months` to `NaiveDate`.
-///
-/// The result will be clamped to valid days in the resulting month, see `checked_add_months` for
-/// details.
-///
-/// # Panics
-///
-/// Panics if the resulting date would be out of range.
-/// Consider using `NaiveDate::checked_add_months` to get an `Option` instead.
-///
-/// # Example
-///
-/// ```
-/// use chrono::{NaiveDate, Months};
-///
-/// let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap();
-///
-/// assert_eq!(from_ymd(2014, 1, 1) + Months::new(1), from_ymd(2014, 2, 1));
-/// assert_eq!(from_ymd(2014, 1, 1) + Months::new(11), from_ymd(2014, 12, 1));
-/// 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));
-/// ```
-impl Add<Months> for NaiveDate {
-    type Output = NaiveDate;
-
-    fn add(self, months: Months) -> Self::Output {
-        self.checked_add_months(months).expect("`NaiveDate + Months` out of range")
-    }
-}
-
-/// Subtract `Months` from `NaiveDate`.
-///
-/// The result will be clamped to valid days in the resulting month, see `checked_sub_months` for
-/// details.
-///
-/// # Panics
-///
-/// Panics if the resulting date would be out of range.
-/// Consider using `NaiveDate::checked_sub_months` to get an `Option` instead.
-///
-/// # Example
-///
-/// ```
-/// use chrono::{NaiveDate, Months};
-///
-/// let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap();
-///
-/// assert_eq!(from_ymd(2014, 1, 1) - Months::new(11), from_ymd(2013, 2, 1));
-/// assert_eq!(from_ymd(2014, 1, 1) - Months::new(12), from_ymd(2013, 1, 1));
-/// assert_eq!(from_ymd(2014, 1, 1) - Months::new(13), from_ymd(2012, 12, 1));
-/// ```
-impl Sub<Months> for NaiveDate {
-    type Output = NaiveDate;
-
-    fn sub(self, months: Months) -> Self::Output {
-        self.checked_sub_months(months).expect("`NaiveDate - Months` out of range")
-    }
-}
-
-/// Add `Days` to `NaiveDate`.
-///
-/// # Panics
-///
-/// Panics if the resulting date would be out of range.
-/// Consider using `NaiveDate::checked_add_days` to get an `Option` instead.
-impl Add<Days> for NaiveDate {
-    type Output = NaiveDate;
-
-    fn add(self, days: Days) -> Self::Output {
-        self.checked_add_days(days).expect("`NaiveDate + Days` out of range")
-    }
-}
-
-/// Subtract `Days` from `NaiveDate`.
-///
-/// # Panics
-///
-/// Panics if the resulting date would be out of range.
-/// Consider using `NaiveDate::checked_sub_days` to get an `Option` instead.
-impl Sub<Days> for NaiveDate {
-    type Output = NaiveDate;
-
-    fn sub(self, days: Days) -> Self::Output {
-        self.checked_sub_days(days).expect("`NaiveDate - Days` out of range")
-    }
-}
-
-/// Subtract `TimeDelta` from `NaiveDate`.
-///
-/// This discards the fractional days in `TimeDelta`, rounding to the closest integral number of
-/// days towards `TimeDelta::zero()`.
-/// It is the same as the addition with a negated `TimeDelta`.
-///
-/// # Panics
-///
-/// Panics if the resulting date would be out of range.
-/// Consider using [`NaiveDate::checked_sub_signed`] to get an `Option` instead.
-///
-/// # Example
-///
-/// ```
-/// use chrono::{TimeDelta, NaiveDate};
-///
-/// let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap();
-///
-/// assert_eq!(from_ymd(2014, 1, 1) - TimeDelta::zero(),             from_ymd(2014, 1, 1));
-/// assert_eq!(from_ymd(2014, 1, 1) - TimeDelta::seconds(86399),     from_ymd(2014, 1, 1));
-/// assert_eq!(from_ymd(2014, 1, 1) - TimeDelta::seconds(-86399),    from_ymd(2014, 1, 1));
-/// assert_eq!(from_ymd(2014, 1, 1) - TimeDelta::days(1),            from_ymd(2013, 12, 31));
-/// assert_eq!(from_ymd(2014, 1, 1) - TimeDelta::days(-1),           from_ymd(2014, 1, 2));
-/// assert_eq!(from_ymd(2014, 1, 1) - TimeDelta::days(364),          from_ymd(2013, 1, 2));
-/// assert_eq!(from_ymd(2014, 1, 1) - TimeDelta::days(365*4 + 1),    from_ymd(2010, 1, 1));
-/// assert_eq!(from_ymd(2014, 1, 1) - TimeDelta::days(365*400 + 97), from_ymd(1614, 1, 1));
-/// ```
-///
-/// [`NaiveDate::checked_sub_signed`]: crate::NaiveDate::checked_sub_signed
-impl Sub<TimeDelta> for NaiveDate {
-    type Output = NaiveDate;
-
-    #[inline]
-    fn sub(self, rhs: TimeDelta) -> NaiveDate {
-        self.checked_sub_signed(rhs).expect("`NaiveDate - TimeDelta` overflowed")
-    }
-}
-
-/// Subtract-assign `TimeDelta` from `NaiveDate`.
-///
-/// This discards the fractional days in `TimeDelta`, rounding to the closest integral number of
-/// days towards `TimeDelta::zero()`.
-/// It is the same as the addition with a negated `TimeDelta`.
-///
-/// # Panics
-///
-/// Panics if the resulting date would be out of range.
-/// Consider using [`NaiveDate::checked_sub_signed`] to get an `Option` instead.
-impl SubAssign<TimeDelta> for NaiveDate {
-    #[inline]
-    fn sub_assign(&mut self, rhs: TimeDelta) {
-        *self = self.sub(rhs);
-    }
-}
-
-/// Subtracts another `NaiveDate` from the current date.
-/// Returns a `TimeDelta` of integral numbers.
-///
-/// This does not overflow or underflow at all,
-/// as all possible output fits in the range of `TimeDelta`.
-///
-/// The implementation is a wrapper around
-/// [`NaiveDate::signed_duration_since`](#method.signed_duration_since).
-///
-/// # Example
-///
-/// ```
-/// use chrono::{TimeDelta, NaiveDate};
-///
-/// let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap();
-///
-/// assert_eq!(from_ymd(2014, 1, 1) - from_ymd(2014, 1, 1), TimeDelta::zero());
-/// assert_eq!(from_ymd(2014, 1, 1) - from_ymd(2013, 12, 31), TimeDelta::days(1));
-/// assert_eq!(from_ymd(2014, 1, 1) - from_ymd(2014, 1, 2), TimeDelta::days(-1));
-/// assert_eq!(from_ymd(2014, 1, 1) - from_ymd(2013, 9, 23), TimeDelta::days(100));
-/// assert_eq!(from_ymd(2014, 1, 1) - from_ymd(2013, 1, 1), TimeDelta::days(365));
-/// assert_eq!(from_ymd(2014, 1, 1) - from_ymd(2010, 1, 1), TimeDelta::days(365*4 + 1));
-/// assert_eq!(from_ymd(2014, 1, 1) - from_ymd(1614, 1, 1), TimeDelta::days(365*400 + 97));
-/// ```
-impl Sub<NaiveDate> for NaiveDate {
-    type Output = TimeDelta;
-
-    #[inline]
-    fn sub(self, rhs: NaiveDate) -> TimeDelta {
-        self.signed_duration_since(rhs)
-    }
-}
-
-impl From<NaiveDateTime> for NaiveDate {
-    fn from(naive_datetime: NaiveDateTime) -> Self {
-        naive_datetime.date()
-    }
-}
-
-/// Iterator over `NaiveDate` with a step size of one day.
-#[derive(Debug, Copy, Clone, Hash, PartialEq, PartialOrd, Eq, Ord)]
-pub struct NaiveDateDaysIterator {
-    value: NaiveDate,
-}
-
-impl Iterator for NaiveDateDaysIterator {
-    type Item = NaiveDate;
-
-    fn next(&mut self) -> Option<Self::Item> {
-        // We return the current value, and have no way to return `NaiveDate::MAX`.
-        let current = self.value;
-        // This can't panic because current is < NaiveDate::MAX:
-        self.value = current.succ_opt()?;
-        Some(current)
-    }
-
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        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> {
-        // We return the current value, and have no way to return `NaiveDate::MIN`.
-        let current = self.value;
-        self.value = current.pred_opt()?;
-        Some(current)
-    }
-}
-
-impl FusedIterator for NaiveDateDaysIterator {}
-
-/// Iterator over `NaiveDate` with a step size of one week.
-#[derive(Debug, Copy, Clone, Hash, PartialEq, PartialOrd, Eq, Ord)]
-pub struct NaiveDateWeeksIterator {
-    value: NaiveDate,
-}
-
-impl Iterator for NaiveDateWeeksIterator {
-    type Item = NaiveDate;
-
-    fn next(&mut self) -> Option<Self::Item> {
-        let current = self.value;
-        self.value = current.checked_add_signed(TimeDelta::weeks(1))?;
-        Some(current)
-    }
-
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        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> {
-        let current = self.value;
-        self.value = current.checked_sub_signed(TimeDelta::weeks(1))?;
-        Some(current)
-    }
-}
-
-impl FusedIterator for NaiveDateWeeksIterator {}
-
-/// The `Debug` output of the naive date `d` is the same as
-/// [`d.format("%Y-%m-%d")`](crate::format::strftime).
-///
-/// The string printed can be readily parsed via the `parse` method on `str`.
-///
-/// # Example
-///
-/// ```
-/// use chrono::NaiveDate;
-///
-/// 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_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..=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}", year)?;
-        }
-
-        f.write_char('-')?;
-        write_hundreds(f, mdf.month() as u8)?;
-        f.write_char('-')?;
-        write_hundreds(f, mdf.day() as u8)
-    }
-}
-
-/// The `Display` output of the naive date `d` is the same as
-/// [`d.format("%Y-%m-%d")`](crate::format::strftime).
-///
-/// The string printed can be readily parsed via the `parse` method on `str`.
-///
-/// # Example
-///
-/// ```
-/// use chrono::NaiveDate;
-///
-/// 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_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)
-    }
-}
-
-/// Parsing a `str` into a `NaiveDate` uses the same format,
-/// [`%Y-%m-%d`](crate::format::strftime), as in `Debug` and `Display`.
-///
-/// # Example
-///
-/// ```
-/// use chrono::NaiveDate;
-///
-/// let d = NaiveDate::from_ymd_opt(2015, 9, 18).unwrap();
-/// assert_eq!("2015-09-18".parse::<NaiveDate>(), Ok(d));
-///
-/// 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: &[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(""),
-        ];
-
-        let mut parsed = Parsed::new();
-        parse(&mut parsed, s, ITEMS.iter())?;
-        parsed.to_naive_date()
-    }
-}
-
-/// 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()
-    }
-}
-
-const fn div_mod_floor(val: i32, div: i32) -> (i32, i32) {
-    (val.div_euclid(div), val.rem_euclid(div))
-}
-
-#[cfg(all(test, any(feature = "rustc-serialize", feature = "serde")))]
-fn test_encodable_json<F, E>(to_string: F)
-where
-    F: Fn(&NaiveDate) -> Result<String, E>,
-    E: ::std::fmt::Debug,
-{
-    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#""-262143-01-01""#.into()));
-    assert_eq!(to_string(&NaiveDate::MAX).ok(), Some(r#""+262142-12-31""#.into()));
-}
-
-#[cfg(all(test, any(feature = "rustc-serialize", feature = "serde")))]
-fn test_decodable_json<F, E>(from_str: F)
-where
-    F: Fn(&str) -> Result<NaiveDate, E>,
-    E: ::std::fmt::Debug,
-{
-    use std::{i32, i64};
-
-    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#""-262143-01-01""#).ok(), Some(NaiveDate::MIN));
-    assert_eq!(from_str(r#""+262142-12-31""#).ok(), Some(NaiveDate::MAX));
-
-    // bad formats
-    assert!(from_str(r#""""#).is_err());
-    assert!(from_str(r#""20001231""#).is_err());
-    assert!(from_str(r#""2000-00-00""#).is_err());
-    assert!(from_str(r#""2000-02-30""#).is_err());
-    assert!(from_str(r#""2001-02-29""#).is_err());
-    assert!(from_str(r#""2002-002-28""#).is_err());
-    assert!(from_str(r#""yyyy-mm-dd""#).is_err());
-    assert!(from_str(r#"0"#).is_err());
-    assert!(from_str(r#"20.01"#).is_err());
-    assert!(from_str(&i32::MIN.to_string()).is_err());
-    assert!(from_str(&i32::MAX.to_string()).is_err());
-    assert!(from_str(&i64::MIN.to_string()).is_err());
-    assert!(from_str(&i64::MAX.to_string()).is_err());
-    assert!(from_str(r#"{}"#).is_err());
-    // pre-0.3.0 rustc-serialize format is now invalid
-    assert!(from_str(r#"{"ymdf":20}"#).is_err());
-    assert!(from_str(r#"null"#).is_err());
-}
-
-#[cfg(feature = "rustc-serialize")]
-mod rustc_serialize {
-    use super::NaiveDate;
-    use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
-
-    impl Encodable for NaiveDate {
-        fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
-            format!("{:?}", self).encode(s)
-        }
-    }
-
-    impl Decodable for NaiveDate {
-        fn decode<D: Decoder>(d: &mut D) -> Result<NaiveDate, D::Error> {
-            d.read_str()?.parse().map_err(|_| d.error("invalid date"))
-        }
-    }
-
-    #[cfg(test)]
-    mod tests {
-        use crate::naive::date::{test_decodable_json, test_encodable_json};
-        use rustc_serialize::json;
-
-        #[test]
-        fn test_encodable() {
-            test_encodable_json(json::encode);
-        }
-
-        #[test]
-        fn test_decodable() {
-            test_decodable_json(json::decode);
-        }
-    }
-}
-
-#[cfg(feature = "serde")]
-mod serde {
-    use super::NaiveDate;
-    use core::fmt;
-    use serde::{de, ser};
-
-    // TODO not very optimized for space (binary formats would want something better)
-
-    impl ser::Serialize for NaiveDate {
-        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 NaiveDateVisitor;
-
-    impl<'de> de::Visitor<'de> for NaiveDateVisitor {
-        type Value = NaiveDate;
-
-        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
-            formatter.write_str("a formatted date 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 NaiveDate {
-        fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
-        where
-            D: de::Deserializer<'de>,
-        {
-            deserializer.deserialize_str(NaiveDateVisitor)
-        }
-    }
-
-    #[cfg(test)]
-    mod tests {
-        use crate::naive::date::{test_decodable_json, test_encodable_json};
-        use crate::NaiveDate;
-
-        #[test]
-        fn test_serde_serialize() {
-            test_encodable_json(serde_json::to_string);
-        }
-
-        #[test]
-        fn test_serde_deserialize() {
-            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 d = NaiveDate::from_ymd_opt(2014, 7, 24).unwrap();
-            let encoded = serialize(&d).unwrap();
-            let decoded: NaiveDate = deserialize(&encoded).unwrap();
-            assert_eq!(d, decoded);
-        }
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use super::{Days, Months, NaiveDate, MAX_YEAR, MIN_YEAR};
-    use crate::naive::internals::YearFlags;
-    use crate::{Datelike, TimeDelta, Weekday};
-
-    // 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_opt(MIN_YEAR, 1, 1).unwrap();
-        let calculated_max = NaiveDate::from_ymd_opt(MAX_YEAR, 12, 31).unwrap();
-        assert!(
-            NaiveDate::MIN == calculated_min,
-            "`NaiveDate::MIN` should have year flag {:?}",
-            calculated_min.of().flags()
-        );
-        assert!(
-            NaiveDate::MAX == calculated_max,
-            "`NaiveDate::MAX` should have year flag {:?} and ordinal {}",
-            calculated_max.of().flags(),
-            calculated_max.of().ordinal()
-        );
-
-        // let's also check that the entire range do not exceed 2^44 seconds
-        // (sometimes used for bounding `TimeDelta` against overflow)
-        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),
-            "The entire `NaiveDate` range somehow exceeds 2^{} seconds",
-            MAX_BITS
-        );
-
-        const BEFORE_MIN: NaiveDate = NaiveDate::BEFORE_MIN;
-        assert_eq!(BEFORE_MIN.of().flags(), YearFlags::from_year(BEFORE_MIN.year()));
-        assert_eq!((BEFORE_MIN.month(), BEFORE_MIN.day()), (12, 31));
-
-        const AFTER_MAX: NaiveDate = NaiveDate::AFTER_MAX;
-        assert_eq!(AFTER_MAX.of().flags(), YearFlags::from_year(AFTER_MAX.year()));
-        assert_eq!((AFTER_MAX.month(), AFTER_MAX.day()), (1, 1));
-    }
-
-    #[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.unsigned_abs() + 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() {
-        for y in NaiveDate::MIN.year()..=NaiveDate::MAX.year() {
-            // even months
-            let d4 = NaiveDate::from_ymd_opt(y, 4, 4).unwrap();
-            let d6 = NaiveDate::from_ymd_opt(y, 6, 6).unwrap();
-            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 = NaiveDate::from_ymd_opt;
-
-        assert!(ymd_opt(2012, 0, 1).is_none());
-        assert!(ymd_opt(2012, 1, 1).is_some());
-        assert!(ymd_opt(2012, 2, 29).is_some());
-        assert!(ymd_opt(2014, 2, 29).is_none());
-        assert!(ymd_opt(2014, 3, 0).is_none());
-        assert!(ymd_opt(2014, 3, 1).is_some());
-        assert!(ymd_opt(2014, 3, 31).is_some());
-        assert!(ymd_opt(2014, 3, 32).is_none());
-        assert!(ymd_opt(2014, 12, 31).is_some());
-        assert!(ymd_opt(2014, 13, 1).is_none());
-    }
-
-    #[test]
-    fn test_date_from_yo() {
-        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)));
-        assert_eq!(yo_opt(2012, 2), Some(ymd(2012, 1, 2)));
-        assert_eq!(yo_opt(2012, 32), Some(ymd(2012, 2, 1)));
-        assert_eq!(yo_opt(2012, 60), Some(ymd(2012, 2, 29)));
-        assert_eq!(yo_opt(2012, 61), Some(ymd(2012, 3, 1)));
-        assert_eq!(yo_opt(2012, 100), Some(ymd(2012, 4, 9)));
-        assert_eq!(yo_opt(2012, 200), Some(ymd(2012, 7, 18)));
-        assert_eq!(yo_opt(2012, 300), Some(ymd(2012, 10, 26)));
-        assert_eq!(yo_opt(2012, 366), Some(ymd(2012, 12, 31)));
-        assert_eq!(yo_opt(2012, 367), None);
-
-        assert_eq!(yo_opt(2014, 0), None);
-        assert_eq!(yo_opt(2014, 1), Some(ymd(2014, 1, 1)));
-        assert_eq!(yo_opt(2014, 2), Some(ymd(2014, 1, 2)));
-        assert_eq!(yo_opt(2014, 32), Some(ymd(2014, 2, 1)));
-        assert_eq!(yo_opt(2014, 59), Some(ymd(2014, 2, 28)));
-        assert_eq!(yo_opt(2014, 60), Some(ymd(2014, 3, 1)));
-        assert_eq!(yo_opt(2014, 100), Some(ymd(2014, 4, 10)));
-        assert_eq!(yo_opt(2014, 200), Some(ymd(2014, 7, 19)));
-        assert_eq!(yo_opt(2014, 300), Some(ymd(2014, 10, 27)));
-        assert_eq!(yo_opt(2014, 365), Some(ymd(2014, 12, 31)));
-        assert_eq!(yo_opt(2014, 366), None);
-    }
-
-    #[test]
-    fn test_date_from_isoywd() {
-        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)));
-        assert_eq!(isoywd_opt(2004, 1, Weekday::Sun), Some(ymd(2004, 1, 4)));
-        assert_eq!(isoywd_opt(2004, 2, Weekday::Mon), Some(ymd(2004, 1, 5)));
-        assert_eq!(isoywd_opt(2004, 2, Weekday::Sun), Some(ymd(2004, 1, 11)));
-        assert_eq!(isoywd_opt(2004, 52, Weekday::Mon), Some(ymd(2004, 12, 20)));
-        assert_eq!(isoywd_opt(2004, 52, Weekday::Sun), Some(ymd(2004, 12, 26)));
-        assert_eq!(isoywd_opt(2004, 53, Weekday::Mon), Some(ymd(2004, 12, 27)));
-        assert_eq!(isoywd_opt(2004, 53, Weekday::Sun), Some(ymd(2005, 1, 2)));
-        assert_eq!(isoywd_opt(2004, 54, Weekday::Mon), None);
-
-        assert_eq!(isoywd_opt(2011, 0, Weekday::Sun), None);
-        assert_eq!(isoywd_opt(2011, 1, Weekday::Mon), Some(ymd(2011, 1, 3)));
-        assert_eq!(isoywd_opt(2011, 1, Weekday::Sun), Some(ymd(2011, 1, 9)));
-        assert_eq!(isoywd_opt(2011, 2, Weekday::Mon), Some(ymd(2011, 1, 10)));
-        assert_eq!(isoywd_opt(2011, 2, Weekday::Sun), Some(ymd(2011, 1, 16)));
-
-        assert_eq!(isoywd_opt(2018, 51, Weekday::Mon), Some(ymd(2018, 12, 17)));
-        assert_eq!(isoywd_opt(2018, 51, Weekday::Sun), Some(ymd(2018, 12, 23)));
-        assert_eq!(isoywd_opt(2018, 52, Weekday::Mon), Some(ymd(2018, 12, 24)));
-        assert_eq!(isoywd_opt(2018, 52, Weekday::Sun), Some(ymd(2018, 12, 30)));
-        assert_eq!(isoywd_opt(2018, 53, Weekday::Mon), None);
-    }
-
-    #[test]
-    fn test_date_from_isoywd_and_iso_week() {
-        for year in 2000..2401 {
-            for week in 1..54 {
-                for &weekday in [
-                    Weekday::Mon,
-                    Weekday::Tue,
-                    Weekday::Wed,
-                    Weekday::Thu,
-                    Weekday::Fri,
-                    Weekday::Sat,
-                    Weekday::Sun,
-                ]
-                .iter()
-                {
-                    let d = NaiveDate::from_isoywd_opt(year, week, weekday);
-                    if let Some(d) = d {
-                        assert_eq!(d.weekday(), weekday);
-                        let w = d.iso_week();
-                        assert_eq!(w.year(), year);
-                        assert_eq!(w.week(), week);
-                    }
-                }
-            }
-        }
-
-        for year in 2000..2401 {
-            for month in 1..13 {
-                for day in 1..32 {
-                    let d = NaiveDate::from_ymd_opt(year, month, day);
-                    if let Some(d) = d {
-                        let w = d.iso_week();
-                        let d_ = NaiveDate::from_isoywd_opt(w.year(), w.week(), d.weekday());
-                        assert_eq!(d, d_.unwrap());
-                    }
-                }
-            }
-        }
-    }
-
-    #[test]
-    fn test_date_from_num_days_from_ce() {
-        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(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);
-
-        assert_eq!(from_ndays_from_ce(i32::MIN), None);
-        assert_eq!(from_ndays_from_ce(i32::MAX), None);
-    }
-
-    #[test]
-    fn test_date_from_weekday_of_month_opt() {
-        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_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_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_opt(year, ordinal).unwrap();
-            assert_eq!(d2.year(), year);
-            assert_eq!(d2.month(), month);
-            assert_eq!(d2.day(), day);
-            assert_eq!(d2.ordinal(), ordinal);
-
-            assert_eq!(d1, d2);
-        }
-
-        check(2012, 1, 1, 1);
-        check(2012, 1, 2, 2);
-        check(2012, 2, 1, 32);
-        check(2012, 2, 29, 60);
-        check(2012, 3, 1, 61);
-        check(2012, 4, 9, 100);
-        check(2012, 7, 18, 200);
-        check(2012, 10, 26, 300);
-        check(2012, 12, 31, 366);
-
-        check(2014, 1, 1, 1);
-        check(2014, 1, 2, 2);
-        check(2014, 2, 1, 32);
-        check(2014, 2, 28, 59);
-        check(2014, 3, 1, 60);
-        check(2014, 4, 10, 100);
-        check(2014, 7, 19, 200);
-        check(2014, 10, 27, 300);
-        check(2014, 12, 31, 365);
-    }
-
-    #[test]
-    fn test_date_weekday() {
-        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_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_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_opt(1600, 2, 29).unwrap()));
-        assert_eq!(d.with_year(1900), None);
-        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_opt(2004, 2, 29).unwrap()));
-        assert_eq!(d.with_year(i32::MAX), None);
-
-        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_opt(2000, 1, 30).unwrap()));
-        assert_eq!(d.with_month(2), None);
-        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_opt(2000, 2, 8).unwrap();
-        assert_eq!(d.with_day(0), None);
-        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_opt(2000, 5, 5).unwrap();
-        assert_eq!(d.with_ordinal(0), None);
-        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_opt(1, 1, 1).unwrap().num_days_from_ce(), 1);
-
-        for year in -9999..10001 {
-            assert_eq!(
-                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_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(NaiveDate::MAX.year(), 12, 31).succ_opt(), None);
-    }
-
-    #[test]
-    fn test_date_pred() {
-        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(NaiveDate::MIN.year(), 1, 1).pred_opt(), None);
-    }
-
-    #[test]
-    fn test_date_add() {
-        fn check((y1, m1, d1): (i32, u32, u32), rhs: TimeDelta, 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_signed(rhs), sum);
-            assert_eq!(lhs.checked_sub_signed(-rhs), sum);
-        }
-
-        check((2014, 1, 1), TimeDelta::zero(), Some((2014, 1, 1)));
-        check((2014, 1, 1), TimeDelta::seconds(86399), Some((2014, 1, 1)));
-        // always round towards zero
-        check((2014, 1, 1), TimeDelta::seconds(-86399), Some((2014, 1, 1)));
-        check((2014, 1, 1), TimeDelta::days(1), Some((2014, 1, 2)));
-        check((2014, 1, 1), TimeDelta::days(-1), Some((2013, 12, 31)));
-        check((2014, 1, 1), TimeDelta::days(364), Some((2014, 12, 31)));
-        check((2014, 1, 1), TimeDelta::days(365 * 4 + 1), Some((2018, 1, 1)));
-        check((2014, 1, 1), TimeDelta::days(365 * 400 + 97), Some((2414, 1, 1)));
-
-        check((-7, 1, 1), TimeDelta::days(365 * 12 + 3), Some((5, 1, 1)));
-
-        // overflow check
-        check((0, 1, 1), TimeDelta::days(MAX_DAYS_FROM_YEAR_0 as i64), Some((MAX_YEAR, 12, 31)));
-        check((0, 1, 1), TimeDelta::days(MAX_DAYS_FROM_YEAR_0 as i64 + 1), None);
-        check((0, 1, 1), TimeDelta::max_value(), None);
-        check((0, 1, 1), TimeDelta::days(MIN_DAYS_FROM_YEAR_0 as i64), Some((MIN_YEAR, 1, 1)));
-        check((0, 1, 1), TimeDelta::days(MIN_DAYS_FROM_YEAR_0 as i64 - 1), None);
-        check((0, 1, 1), TimeDelta::min_value(), None);
-    }
-
-    #[test]
-    fn test_date_sub() {
-        fn check((y1, m1, d1): (i32, u32, u32), (y2, m2, d2): (i32, u32, u32), diff: TimeDelta) {
-            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);
-        }
-
-        check((2014, 1, 1), (2014, 1, 1), TimeDelta::zero());
-        check((2014, 1, 2), (2014, 1, 1), TimeDelta::days(1));
-        check((2014, 12, 31), (2014, 1, 1), TimeDelta::days(364));
-        check((2015, 1, 3), (2014, 1, 1), TimeDelta::days(365 + 2));
-        check((2018, 1, 1), (2014, 1, 1), TimeDelta::days(365 * 4 + 1));
-        check((2414, 1, 1), (2014, 1, 1), TimeDelta::days(365 * 400 + 97));
-
-        check((MAX_YEAR, 12, 31), (0, 1, 1), TimeDelta::days(MAX_DAYS_FROM_YEAR_0 as i64));
-        check((MIN_YEAR, 1, 1), (0, 1, 1), TimeDelta::days(MIN_DAYS_FROM_YEAR_0 as i64));
-    }
-
-    #[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 = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap();
-        let mut date = ymd(2016, 10, 1);
-        date += TimeDelta::days(10);
-        assert_eq!(date, ymd(2016, 10, 11));
-        date += TimeDelta::days(30);
-        assert_eq!(date, ymd(2016, 11, 10));
-    }
-
-    #[test]
-    fn test_date_subassignment() {
-        let ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap();
-        let mut date = ymd(2016, 10, 11);
-        date -= TimeDelta::days(10);
-        assert_eq!(date, ymd(2016, 10, 1));
-        date -= TimeDelta::days(2);
-        assert_eq!(date, ymd(2016, 9, 29));
-    }
-
-    #[test]
-    fn test_date_fmt() {
-        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_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_opt(1234, 5, 6).unwrap()), "1234-05-06");
-        assert_eq!(
-            format!("{:30?}", NaiveDate::from_ymd_opt(12345, 6, 7).unwrap()),
-            "+12345-06-07"
-        );
-    }
-
-    #[test]
-    fn test_date_from_str() {
-        // valid cases
-        let valid = [
-            "-0000000123456-1-2",
-            "    -123456 - 1 - 2    ",
-            "-12345-1-2",
-            "-1234-12-31",
-            "-7-6-5",
-            "350-2-28",
-            "360-02-29",
-            "0360-02-29",
-            "2015-2 -18",
-            "2015-02-18",
-            "+70-2-18",
-            "+70000-2-18",
-            "+00007-2-18",
-        ];
-        for &s in &valid {
-            eprintln!("test_date_from_str valid {:?}", s);
-            let d = match s.parse::<NaiveDate>() {
-                Ok(d) => d,
-                Err(e) => panic!("parsing `{}` has failed: {}", s, e),
-            };
-            eprintln!("d {:?} (NaiveDate)", d);
-            let s_ = format!("{:?}", d);
-            eprintln!("s_ {:?}", s_);
-            // `s` and `s_` may differ, but `s.parse()` and `s_.parse()` must be same
-            let d_ = match s_.parse::<NaiveDate>() {
-                Ok(d) => d,
-                Err(e) => {
-                    panic!("`{}` is parsed into `{:?}`, but reparsing that has failed: {}", s, d, e)
-                }
-            };
-            eprintln!("d_ {:?} (NaiveDate)", d_);
-            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
-        let invalid = [
-            "",                     // empty
-            "x",                    // invalid
-            "Fri, 09 Aug 2013 GMT", // valid date, wrong format
-            "Sat Jun 30 2012",      // valid date, wrong format
-            "1441497364.649",       // valid datetime, wrong format
-            "+1441497364.649",      // valid datetime, wrong format
-            "+1441497364",          // valid datetime, wrong format
-            "2014/02/03",           // valid date, wrong format
-            "2014",                 // datetime missing data
-            "2014-01",              // datetime missing data
-            "2014-01-00",           // invalid day
-            "2014-11-32",           // invalid day
-            "2014-13-01",           // invalid month
-            "2014-13-57",           // invalid month, day
-            "9999999-9-9",          // invalid year (out of bounds)
-        ];
-        for &s in &invalid {
-            eprintln!("test_date_from_str invalid {:?}", s);
-            assert!(s.parse::<NaiveDate>().is_err());
-        }
-    }
-
-    #[test]
-    fn test_date_parse_from_str() {
-        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))
-        ); // ignore time and offset
-        assert_eq!(
-            NaiveDate::parse_from_str("2015-W06-1=2015-033", "%G-W%V-%u = %Y-%j"),
-            Ok(ymd(2015, 2, 2))
-        );
-        assert_eq!(
-            NaiveDate::parse_from_str("Fri, 09 Aug 13", "%a, %d %b %y"),
-            Ok(ymd(2013, 8, 9))
-        );
-        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_day_iterator_limit() {
-        assert_eq!(
-            NaiveDate::from_ymd_opt(MAX_YEAR, 12, 29).unwrap().iter_days().take(4).count(),
-            2
-        );
-        assert_eq!(
-            NaiveDate::from_ymd_opt(MIN_YEAR, 1, 3).unwrap().iter_days().rev().take(4).count(),
-            2
-        );
-    }
-
-    #[test]
-    fn test_week_iterator_limit() {
-        assert_eq!(
-            NaiveDate::from_ymd_opt(MAX_YEAR, 12, 12).unwrap().iter_weeks().take(4).count(),
-            2
-        );
-        assert_eq!(
-            NaiveDate::from_ymd_opt(MIN_YEAR, 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 = [
-            (Weekday::Mon, "Mon 2022-05-16", "Sun 2022-05-22"),
-            (Weekday::Tue, "Tue 2022-05-17", "Mon 2022-05-23"),
-            (Weekday::Wed, "Wed 2022-05-18", "Tue 2022-05-24"),
-            (Weekday::Thu, "Thu 2022-05-12", "Wed 2022-05-18"),
-            (Weekday::Fri, "Fri 2022-05-13", "Thu 2022-05-19"),
-            (Weekday::Sat, "Sat 2022-05-14", "Fri 2022-05-20"),
-            (Weekday::Sun, "Sun 2022-05-15", "Sat 2022-05-21"),
-        ];
-        for (start, first_day, last_day) in asserts {
-            let week = date.week(start);
-            let days = week.days();
-            assert_eq!(Ok(week.first_day()), NaiveDate::parse_from_str(first_day, "%a %Y-%m-%d"));
-            assert_eq!(Ok(week.last_day()), NaiveDate::parse_from_str(last_day, "%a %Y-%m-%d"));
-            assert!(days.contains(&date));
-        }
-    }
-
-    #[test]
-    fn test_naiveweek_min_max() {
-        let date_max = NaiveDate::MAX;
-        assert!(date_max.week(Weekday::Mon).first_day() <= date_max);
-        let date_min = NaiveDate::MIN;
-        assert!(date_min.week(Weekday::Mon).last_day() >= date_min);
-    }
-
-    #[test]
-    fn test_weeks_from() {
-        // tests per: https://github.com/chronotope/chrono/issues/961
-        // these internally use `weeks_from` via the parsing infrastructure
-        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)
-            }
-        }
-    }
-
-    #[test]
-    fn test_with_0_overflow() {
-        let dt = NaiveDate::from_ymd_opt(2023, 4, 18).unwrap();
-        assert!(dt.with_month0(4294967295).is_none());
-        assert!(dt.with_day0(4294967295).is_none());
-        assert!(dt.with_ordinal0(4294967295).is_none());
-    }
-
-    #[test]
-    fn test_leap_year() {
-        for year in 0..=MAX_YEAR {
-            let date = NaiveDate::from_ymd_opt(year, 1, 1).unwrap();
-            let is_leap = year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
-            assert_eq!(date.leap_year(), is_leap);
-            assert_eq!(date.leap_year(), date.with_ordinal(366).is_some());
-        }
-    }
-
-    #[test]
-    #[cfg(feature = "rkyv-validation")]
-    fn test_rkyv_validation() {
-        let date_min = NaiveDate::MIN;
-        let bytes = rkyv::to_bytes::<_, 4>(&date_min).unwrap();
-        assert_eq!(rkyv::from_bytes::<NaiveDate>(&bytes).unwrap(), date_min);
-
-        let date_max = NaiveDate::MAX;
-        let bytes = rkyv::to_bytes::<_, 4>(&date_max).unwrap();
-        assert_eq!(rkyv::from_bytes::<NaiveDate>(&bytes).unwrap(), date_max);
-    }
-
-    //   MAX_YEAR-12-31 minus 0000-01-01
-    // = (MAX_YEAR-12-31 minus 0000-12-31) + (0000-12-31 - 0000-01-01)
-    // = MAX_YEAR * 365 + (# of leap years from 0001 to MAX_YEAR) + 365
-    // = (MAX_YEAR + 1) * 365 + (# of leap years from 0001 to MAX_YEAR)
-    const MAX_DAYS_FROM_YEAR_0: i32 =
-        (MAX_YEAR + 1) * 365 + MAX_YEAR / 4 - MAX_YEAR / 100 + MAX_YEAR / 400;
-
-    //   MIN_YEAR-01-01 minus 0000-01-01
-    // = MIN_YEAR * 365 + (# of leap years from MIN_YEAR to 0000)
-    const MIN_DAYS_FROM_YEAR_0: i32 =
-        MIN_YEAR * 365 + MIN_YEAR / 4 - MIN_YEAR / 100 + MIN_YEAR / 400;
-
-    // only used for testing, but duplicated in naive::datetime
-    const MAX_BITS: usize = 44;
-}
diff --git a/crates/chrono/src/naive/date/mod.rs b/crates/chrono/src/naive/date/mod.rs
new file mode 100644
index 0000000..1514518
--- /dev/null
+++ b/crates/chrono/src/naive/date/mod.rs
@@ -0,0 +1,2534 @@
+// This is a part of Chrono.
+// See README.md and LICENSE.txt for details.
+
+//! ISO 8601 calendar date without timezone.
+//!
+//! The implementation is optimized for determining year, month, day and day of week.
+//!
+//! Format of `NaiveDate`:
+//! `YYYY_YYYY_YYYY_YYYY_YYYO_OOOO_OOOO_LWWW`
+//! `Y`: Year
+//! `O`: Ordinal
+//! `L`: leap year flag (1 = common year, 0 is leap year)
+//! `W`: weekday before the first day of the year
+//! `LWWW`: will also be referred to as the year flags (`F`)
+
+#[cfg(feature = "alloc")]
+use core::borrow::Borrow;
+use core::iter::FusedIterator;
+use core::num::NonZeroI32;
+use core::ops::{Add, AddAssign, Sub, SubAssign};
+use core::{fmt, str};
+
+#[cfg(any(feature = "rkyv", feature = "rkyv-16", feature = "rkyv-32", feature = "rkyv-64"))]
+use rkyv::{Archive, Deserialize, Serialize};
+
+/// L10n locales.
+#[cfg(all(feature = "unstable-locales", feature = "alloc"))]
+use pure_rust_locales::Locale;
+
+#[cfg(feature = "alloc")]
+use crate::format::DelayedFormat;
+use crate::format::{
+    parse, parse_and_remainder, write_hundreds, Item, Numeric, Pad, ParseError, ParseResult,
+    Parsed, StrftimeItems,
+};
+use crate::month::Months;
+use crate::naive::{Days, IsoWeek, NaiveDateTime, NaiveTime, NaiveWeek};
+use crate::{expect, try_opt};
+use crate::{Datelike, TimeDelta, Weekday};
+
+use super::internals::{Mdf, YearFlags};
+
+#[cfg(test)]
+mod tests;
+
+/// ISO 8601 calendar date without timezone.
+/// Allows for every [proleptic Gregorian date] from Jan 1, 262145 BCE to Dec 31, 262143 CE.
+/// Also supports the conversion from ISO 8601 ordinal and week date.
+///
+/// # Calendar Date
+///
+/// The ISO 8601 **calendar date** follows the proleptic Gregorian calendar.
+/// It is like a normal civil calendar but note some slight differences:
+///
+/// * Dates before the Gregorian calendar's inception in 1582 are defined via the extrapolation.
+///   Be careful, as historical dates are often noted in the Julian calendar and others
+///   and the transition to Gregorian may differ across countries (as late as early 20C).
+///
+///   (Some example: Both Shakespeare from Britain and Cervantes from Spain seemingly died
+///   on the same calendar date---April 23, 1616---but in the different calendar.
+///   Britain used the Julian calendar at that time, so Shakespeare's death is later.)
+///
+/// * ISO 8601 calendars has the year 0, which is 1 BCE (a year before 1 CE).
+///   If you need a typical BCE/BC and CE/AD notation for year numbers,
+///   use the [`Datelike::year_ce`] method.
+///
+/// # Week Date
+///
+/// The ISO 8601 **week date** is a triple of year number, week number
+/// and [day of the week](Weekday) with the following rules:
+///
+/// * A week consists of Monday through Sunday, and is always numbered within some year.
+///   The week number ranges from 1 to 52 or 53 depending on the year.
+///
+/// * The week 1 of given year is defined as the first week containing January 4 of that year,
+///   or equivalently, the first week containing four or more days in that year.
+///
+/// * The year number in the week date may *not* correspond to the actual Gregorian year.
+///   For example, January 3, 2016 (Sunday) was on the last (53rd) week of 2015.
+///
+/// Chrono's date types default to the ISO 8601 [calendar date](#calendar-date), but
+/// [`Datelike::iso_week`] and [`Datelike::weekday`] methods can be used to get the corresponding
+/// week date.
+///
+/// # Ordinal Date
+///
+/// The ISO 8601 **ordinal date** is a pair of year number and day of the year ("ordinal").
+/// The ordinal number ranges from 1 to 365 or 366 depending on the year.
+/// The year number is the same as that of the [calendar date](#calendar-date).
+///
+/// This is currently the internal format of Chrono's date types.
+///
+/// [proleptic Gregorian date]: crate::NaiveDate#calendar-date
+#[derive(PartialEq, Eq, Hash, PartialOrd, Ord, Copy, Clone)]
+#[cfg_attr(
+    any(feature = "rkyv", feature = "rkyv-16", feature = "rkyv-32", feature = "rkyv-64"),
+    derive(Archive, Deserialize, Serialize),
+    archive(compare(PartialEq, PartialOrd)),
+    archive_attr(derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash))
+)]
+#[cfg_attr(feature = "rkyv-validation", archive(check_bytes))]
+pub struct NaiveDate {
+    yof: NonZeroI32, // (year << 13) | of
+}
+
+/// The minimum possible `NaiveDate` (January 1, 262145 BCE).
+#[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).
+#[deprecated(since = "0.4.20", note = "Use NaiveDate::MAX instead")]
+pub const MAX_DATE: NaiveDate = NaiveDate::MAX;
+
+#[cfg(all(feature = "arbitrary", feature = "std"))]
+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)
+    }
+}
+
+impl NaiveDate {
+    pub(crate) fn weeks_from(&self, day: Weekday) -> i32 {
+        (self.ordinal() as i32 - self.weekday().days_since(day) as i32 + 6) / 7
+    }
+
+    /// Makes a new `NaiveDate` from year, ordinal and flags.
+    /// Does not check whether the flags are correct for the provided year.
+    const fn from_ordinal_and_flags(
+        year: i32,
+        ordinal: u32,
+        flags: YearFlags,
+    ) -> Option<NaiveDate> {
+        if year < MIN_YEAR || year > MAX_YEAR {
+            return None; // Out-of-range
+        }
+        if ordinal == 0 || ordinal > 366 {
+            return None; // Invalid
+        }
+        debug_assert!(YearFlags::from_year(year).0 == flags.0);
+        let yof = (year << 13) | (ordinal << 4) as i32 | flags.0 as i32;
+        match yof & OL_MASK <= MAX_OL {
+            true => Some(NaiveDate::from_yof(yof)),
+            false => None, // Does not exist: Ordinal 366 in a common year.
+        }
+    }
+
+    /// Makes a new `NaiveDate` from year and packed month-day-flags.
+    /// Does not check whether the flags are correct for the provided year.
+    const fn from_mdf(year: i32, mdf: Mdf) -> Option<NaiveDate> {
+        if year < MIN_YEAR || year > MAX_YEAR {
+            return None; // Out-of-range
+        }
+        Some(NaiveDate::from_yof((year << 13) | try_opt!(mdf.ordinal_and_flags())))
+    }
+
+    /// Makes a new `NaiveDate` from the [calendar date](#calendar-date)
+    /// (year, month and day).
+    ///
+    /// # Panics
+    ///
+    /// Panics if the specified calendar day does not exist, on invalid values for `month` or `day`,
+    /// or if `year` is out of range for `NaiveDate`.
+    #[deprecated(since = "0.4.23", note = "use `from_ymd_opt()` instead")]
+    #[must_use]
+    pub const fn from_ymd(year: i32, month: u32, day: u32) -> NaiveDate {
+        expect(NaiveDate::from_ymd_opt(year, month, day), "invalid or out-of-range date")
+    }
+
+    /// Makes a new `NaiveDate` from the [calendar date](#calendar-date)
+    /// (year, month and day).
+    ///
+    /// # Errors
+    ///
+    /// Returns `None` if:
+    /// - The specified calendar day does not exist (for example 2023-04-31).
+    /// - The value for `month` or `day` is invalid.
+    /// - `year` is out of range for `NaiveDate`.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use chrono::NaiveDate;
+    ///
+    /// let from_ymd_opt = NaiveDate::from_ymd_opt;
+    ///
+    /// assert!(from_ymd_opt(2015, 3, 14).is_some());
+    /// assert!(from_ymd_opt(2015, 0, 14).is_none());
+    /// assert!(from_ymd_opt(2015, 2, 29).is_none());
+    /// 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());
+    /// ```
+    #[must_use]
+    pub const fn from_ymd_opt(year: i32, month: u32, day: u32) -> Option<NaiveDate> {
+        let flags = YearFlags::from_year(year);
+
+        if let Some(mdf) = Mdf::new(month, day, flags) {
+            NaiveDate::from_mdf(year, mdf)
+        } else {
+            None
+        }
+    }
+
+    /// Makes a new `NaiveDate` from the [ordinal date](#ordinal-date)
+    /// (year and day of the year).
+    ///
+    /// # Panics
+    ///
+    /// Panics if the specified ordinal day does not exist, on invalid values for `ordinal`, or if
+    /// `year` is out of range for `NaiveDate`.
+    #[deprecated(since = "0.4.23", note = "use `from_yo_opt()` instead")]
+    #[must_use]
+    pub const fn from_yo(year: i32, ordinal: u32) -> NaiveDate {
+        expect(NaiveDate::from_yo_opt(year, ordinal), "invalid or out-of-range date")
+    }
+
+    /// Makes a new `NaiveDate` from the [ordinal date](#ordinal-date)
+    /// (year and day of the year).
+    ///
+    /// # Errors
+    ///
+    /// Returns `None` if:
+    /// - The specified ordinal day does not exist (for example 2023-366).
+    /// - The value for `ordinal` is invalid (for example: `0`, `400`).
+    /// - `year` is out of range for `NaiveDate`.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use chrono::NaiveDate;
+    ///
+    /// let from_yo_opt = NaiveDate::from_yo_opt;
+    ///
+    /// assert!(from_yo_opt(2015, 100).is_some());
+    /// assert!(from_yo_opt(2015, 0).is_none());
+    /// assert!(from_yo_opt(2015, 365).is_some());
+    /// assert!(from_yo_opt(2015, 366).is_none());
+    /// 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());
+    /// ```
+    #[must_use]
+    pub const fn from_yo_opt(year: i32, ordinal: u32) -> Option<NaiveDate> {
+        let flags = YearFlags::from_year(year);
+        NaiveDate::from_ordinal_and_flags(year, ordinal, flags)
+    }
+
+    /// Makes a new `NaiveDate` from the [ISO week date](#week-date)
+    /// (year, week number and day of the week).
+    /// The resulting `NaiveDate` may have a different year from the input year.
+    ///
+    /// # Panics
+    ///
+    /// Panics if the specified week does not exist in that year, on invalid values for `week`, or
+    /// if the resulting date is out of range for `NaiveDate`.
+    #[deprecated(since = "0.4.23", note = "use `from_isoywd_opt()` instead")]
+    #[must_use]
+    pub const fn from_isoywd(year: i32, week: u32, weekday: Weekday) -> NaiveDate {
+        expect(NaiveDate::from_isoywd_opt(year, week, weekday), "invalid or out-of-range date")
+    }
+
+    /// Makes a new `NaiveDate` from the [ISO week date](#week-date)
+    /// (year, week number and day of the week).
+    /// The resulting `NaiveDate` may have a different year from the input year.
+    ///
+    /// # Errors
+    ///
+    /// Returns `None` if:
+    /// - The specified week does not exist in that year (for example 2023 week 53).
+    /// - The value for `week` is invalid (for example: `0`, `60`).
+    /// - If the resulting date is out of range for `NaiveDate`.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use chrono::{NaiveDate, Weekday};
+    ///
+    /// let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap();
+    /// let from_isoywd_opt = NaiveDate::from_isoywd_opt;
+    ///
+    /// assert_eq!(from_isoywd_opt(2015, 0, Weekday::Sun), None);
+    /// assert_eq!(from_isoywd_opt(2015, 10, Weekday::Sun), Some(from_ymd(2015, 3, 8)));
+    /// assert_eq!(from_isoywd_opt(2015, 30, Weekday::Mon), Some(from_ymd(2015, 7, 20)));
+    /// assert_eq!(from_isoywd_opt(2015, 60, Weekday::Mon), None);
+    ///
+    /// 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 = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap();
+    /// # let from_isoywd_opt = NaiveDate::from_isoywd_opt;
+    /// //           Mo Tu We Th Fr Sa Su
+    /// // 2014-W52  22 23 24 25 26 27 28    has 4+ days of new year,
+    /// // 2015-W01  29 30 31  1  2  3  4 <- so this is the first week
+    /// assert_eq!(from_isoywd_opt(2014, 52, Weekday::Sun), Some(from_ymd(2014, 12, 28)));
+    /// assert_eq!(from_isoywd_opt(2014, 53, Weekday::Mon), None);
+    /// assert_eq!(from_isoywd_opt(2015, 1, Weekday::Mon), Some(from_ymd(2014, 12, 29)));
+    ///
+    /// // 2015-W52  21 22 23 24 25 26 27    has 4+ days of old year,
+    /// // 2015-W53  28 29 30 31  1  2  3 <- so this is the last week
+    /// // 2016-W01   4  5  6  7  8  9 10
+    /// assert_eq!(from_isoywd_opt(2015, 52, Weekday::Sun), Some(from_ymd(2015, 12, 27)));
+    /// 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)));
+    /// ```
+    #[must_use]
+    pub const fn from_isoywd_opt(year: i32, week: u32, weekday: Weekday) -> Option<NaiveDate> {
+        let flags = YearFlags::from_year(year);
+        let nweeks = flags.nisoweeks();
+        if week == 0 || week > nweeks {
+            return None;
+        }
+        // ordinal = week ordinal - delta
+        let weekord = week * 7 + weekday as u32;
+        let delta = flags.isoweek_delta();
+        let (year, ordinal, flags) = if weekord <= delta {
+            // ordinal < 1, previous year
+            let prevflags = YearFlags::from_year(year - 1);
+            (year - 1, weekord + prevflags.ndays() - delta, prevflags)
+        } else {
+            let ordinal = weekord - delta;
+            let ndays = flags.ndays();
+            if ordinal <= ndays {
+                // this year
+                (year, ordinal, flags)
+            } else {
+                // ordinal > ndays, next year
+                let nextflags = YearFlags::from_year(year + 1);
+                (year + 1, ordinal - ndays, nextflags)
+            }
+        };
+        NaiveDate::from_ordinal_and_flags(year, ordinal, flags)
+    }
+
+    /// Makes a new `NaiveDate` from a day's number in the proleptic Gregorian calendar, with
+    /// January 1, 1 being day 1.
+    ///
+    /// # Panics
+    ///
+    /// Panics if the date is out of range.
+    #[deprecated(since = "0.4.23", note = "use `from_num_days_from_ce_opt()` instead")]
+    #[inline]
+    #[must_use]
+    pub const fn from_num_days_from_ce(days: i32) -> NaiveDate {
+        expect(NaiveDate::from_num_days_from_ce_opt(days), "out-of-range date")
+    }
+
+    /// Makes a new `NaiveDate` from a day's number in the proleptic Gregorian calendar, with
+    /// January 1, 1 being day 1.
+    ///
+    /// # Errors
+    ///
+    /// Returns `None` if the date is out of range.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use chrono::NaiveDate;
+    ///
+    /// let from_ndays_opt = NaiveDate::from_num_days_from_ce_opt;
+    /// 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)));
+    /// assert_eq!(from_ndays_opt(0), Some(from_ymd(0, 12, 31)));
+    /// 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);
+    /// ```
+    #[must_use]
+    pub const fn from_num_days_from_ce_opt(days: i32) -> Option<NaiveDate> {
+        let days = try_opt!(days.checked_add(365)); // make December 31, 1 BCE equal to day 0
+        let year_div_400 = days.div_euclid(146_097);
+        let cycle = days.rem_euclid(146_097);
+        let (year_mod_400, ordinal) = cycle_to_yo(cycle as u32);
+        let flags = YearFlags::from_year_mod_400(year_mod_400 as i32);
+        NaiveDate::from_ordinal_and_flags(year_div_400 * 400 + year_mod_400 as i32, ordinal, flags)
+    }
+
+    /// Makes a new `NaiveDate` by counting the number of occurrences of a particular day-of-week
+    /// 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.
+    ///
+    /// # Panics
+    ///
+    /// Panics if the specified day does not exist in that month, on invalid values for `month` or
+    /// `n`, or if `year` is out of range for `NaiveDate`.
+    #[deprecated(since = "0.4.23", note = "use `from_weekday_of_month_opt()` instead")]
+    #[must_use]
+    pub const fn from_weekday_of_month(
+        year: i32,
+        month: u32,
+        weekday: Weekday,
+        n: u8,
+    ) -> NaiveDate {
+        expect(NaiveDate::from_weekday_of_month_opt(year, month, weekday, n), "out-of-range date")
+    }
+
+    /// Makes a new `NaiveDate` by counting the number of occurrences of a particular day-of-week
+    /// 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.
+    ///
+    /// # Errors
+    ///
+    /// Returns `None` if:
+    /// - The specified day does not exist in that month (for example the 5th Monday of Apr. 2023).
+    /// - The value for `month` or `n` is invalid.
+    /// - `year` is out of range for `NaiveDate`.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use chrono::{NaiveDate, Weekday};
+    /// assert_eq!(
+    ///     NaiveDate::from_weekday_of_month_opt(2017, 3, Weekday::Fri, 2),
+    ///     NaiveDate::from_ymd_opt(2017, 3, 10)
+    /// )
+    /// ```
+    #[must_use]
+    pub const fn from_weekday_of_month_opt(
+        year: i32,
+        month: u32,
+        weekday: Weekday,
+        n: u8,
+    ) -> Option<NaiveDate> {
+        if n == 0 {
+            return None;
+        }
+        let first = try_opt!(NaiveDate::from_ymd_opt(year, month, 1)).weekday();
+        let first_to_dow = (7 + weekday.number_from_monday() - first.number_from_monday()) % 7;
+        let day = (n - 1) as u32 * 7 + first_to_dow + 1;
+        NaiveDate::from_ymd_opt(year, month, day)
+    }
+
+    /// Parses a string with the specified format string and returns a new `NaiveDate`.
+    /// See the [`format::strftime` module](crate::format::strftime)
+    /// on the supported escape sequences.
+    ///
+    /// # 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_opt(2015, 9, 5).unwrap())
+    /// );
+    /// assert_eq!(
+    ///     parse_from_str("5sep2015", "%d%b%Y"),
+    ///     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_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()
+    }
+
+    /// Parses a string from a user-specified format into a new `NaiveDate` value, and a slice with
+    /// the remaining portion of the string.
+    /// See the [`format::strftime` module](crate::format::strftime)
+    /// on the supported escape sequences.
+    ///
+    /// Similar to [`parse_from_str`](#method.parse_from_str).
+    ///
+    /// # Example
+    ///
+    /// ```rust
+    /// # use chrono::{NaiveDate};
+    /// let (date, remainder) =
+    ///     NaiveDate::parse_and_remainder("2015-02-18 trailing text", "%Y-%m-%d").unwrap();
+    /// assert_eq!(date, NaiveDate::from_ymd_opt(2015, 2, 18).unwrap());
+    /// assert_eq!(remainder, " trailing text");
+    /// ```
+    pub fn parse_and_remainder<'a>(s: &'a str, fmt: &str) -> ParseResult<(NaiveDate, &'a str)> {
+        let mut parsed = Parsed::new();
+        let remainder = parse_and_remainder(&mut parsed, s, StrftimeItems::new(fmt))?;
+        parsed.to_naive_date().map(|d| (d, remainder))
+    }
+
+    /// Add a duration in [`Months`] to the date
+    ///
+    /// Uses the last day of the month if the day does not exist in the resulting month.
+    ///
+    /// # Errors
+    ///
+    /// Returns `None` if the resulting date would be out of range.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// # 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())
+    /// );
+    /// ```
+    #[must_use]
+    pub const fn checked_add_months(self, months: Months) -> Option<Self> {
+        if months.0 == 0 {
+            return Some(self);
+        }
+
+        match months.0 <= i32::MAX as u32 {
+            true => self.diff_months(months.0 as i32),
+            false => None,
+        }
+    }
+
+    /// Subtract a duration in [`Months`] from the date
+    ///
+    /// Uses the last day of the month if the day does not exist in the resulting month.
+    ///
+    /// # Errors
+    ///
+    /// Returns `None` if the resulting date would be out of range.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// # 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
+    /// );
+    /// ```
+    #[must_use]
+    pub const fn checked_sub_months(self, months: Months) -> Option<Self> {
+        if months.0 == 0 {
+            return Some(self);
+        }
+
+        match months.0 <= i32::MAX as u32 {
+            true => self.diff_months(-(months.0 as i32)),
+            false => None,
+        }
+    }
+
+    const fn diff_months(self, months: i32) -> Option<Self> {
+        let months = try_opt!((self.year() * 12 + self.month() as i32 - 1).checked_add(months));
+        let year = months.div_euclid(12);
+        let month = months.rem_euclid(12) as u32 + 1;
+
+        // 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_max = days[(month - 1) as usize];
+        let mut day = self.day();
+        if day > day_max {
+            day = day_max;
+        };
+
+        NaiveDate::from_ymd_opt(year, month, day)
+    }
+
+    /// Add a duration in [`Days`] to the date
+    ///
+    /// # Errors
+    ///
+    /// Returns `None` if the resulting date would be out of range.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// # 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
+    /// );
+    /// ```
+    #[must_use]
+    pub const fn checked_add_days(self, days: Days) -> Option<Self> {
+        match days.0 <= i32::MAX as u64 {
+            true => self.add_days(days.0 as i32),
+            false => None,
+        }
+    }
+
+    /// Subtract a duration in [`Days`] from the date
+    ///
+    /// # Errors
+    ///
+    /// Returns `None` if the resulting date would be out of range.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// # 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
+    /// );
+    /// ```
+    #[must_use]
+    pub const fn checked_sub_days(self, days: Days) -> Option<Self> {
+        match days.0 <= i32::MAX as u64 {
+            true => self.add_days(-(days.0 as i32)),
+            false => None,
+        }
+    }
+
+    /// Add a duration of `i32` days to the date.
+    pub(crate) const fn add_days(self, days: i32) -> Option<Self> {
+        // Fast path if the result is within the same year.
+        // Also `DateTime::checked_(add|sub)_days` relies on this path, because if the value remains
+        // within the year it doesn't do a check if the year is in range.
+        // This way `DateTime:checked_(add|sub)_days(Days::new(0))` can be a no-op on dates were the
+        // local datetime is beyond `NaiveDate::{MIN, MAX}.
+        const ORDINAL_MASK: i32 = 0b1_1111_1111_0000;
+        if let Some(ordinal) = ((self.yof() & ORDINAL_MASK) >> 4).checked_add(days) {
+            if ordinal > 0 && ordinal <= (365 + self.leap_year() as i32) {
+                let year_and_flags = self.yof() & !ORDINAL_MASK;
+                return Some(NaiveDate::from_yof(year_and_flags | (ordinal << 4)));
+            }
+        }
+        // do the full check
+        let year = self.year();
+        let (mut year_div_400, year_mod_400) = div_mod_floor(year, 400);
+        let cycle = yo_to_cycle(year_mod_400 as u32, self.ordinal());
+        let cycle = try_opt!((cycle as i32).checked_add(days));
+        let (cycle_div_400y, cycle) = div_mod_floor(cycle, 146_097);
+        year_div_400 += cycle_div_400y;
+
+        let (year_mod_400, ordinal) = cycle_to_yo(cycle as u32);
+        let flags = YearFlags::from_year_mod_400(year_mod_400 as i32);
+        NaiveDate::from_ordinal_and_flags(year_div_400 * 400 + year_mod_400 as i32, ordinal, flags)
+    }
+
+    /// Makes a new `NaiveDateTime` from the current date and given `NaiveTime`.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use chrono::{NaiveDate, NaiveDateTime, NaiveTime};
+    ///
+    /// 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]
+    #[must_use]
+    pub const fn and_time(&self, time: NaiveTime) -> NaiveDateTime {
+        NaiveDateTime::new(*self, time)
+    }
+
+    /// Makes a new `NaiveDateTime` from the current date, hour, minute and second.
+    ///
+    /// No [leap second](./struct.NaiveTime.html#leap-second-handling) is allowed here;
+    /// use `NaiveDate::and_hms_*` methods with a subsecond parameter instead.
+    ///
+    /// # Panics
+    ///
+    /// Panics on invalid hour, minute and/or second.
+    #[deprecated(since = "0.4.23", note = "use `and_hms_opt()` instead")]
+    #[inline]
+    #[must_use]
+    pub const fn and_hms(&self, hour: u32, min: u32, sec: u32) -> NaiveDateTime {
+        expect(self.and_hms_opt(hour, min, sec), "invalid time")
+    }
+
+    /// Makes a new `NaiveDateTime` from the current date, hour, minute and second.
+    ///
+    /// No [leap second](./struct.NaiveTime.html#leap-second-handling) is allowed here;
+    /// use `NaiveDate::and_hms_*_opt` methods with a subsecond parameter instead.
+    ///
+    /// # Errors
+    ///
+    /// Returns `None` on invalid hour, minute and/or second.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use chrono::NaiveDate;
+    ///
+    /// 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]
+    #[must_use]
+    pub const fn and_hms_opt(&self, hour: u32, min: u32, sec: u32) -> Option<NaiveDateTime> {
+        let time = try_opt!(NaiveTime::from_hms_opt(hour, min, sec));
+        Some(self.and_time(time))
+    }
+
+    /// Makes a new `NaiveDateTime` from the current date, hour, minute, second and millisecond.
+    ///
+    /// The millisecond part is allowed to exceed 1,000,000,000 in order to represent a [leap second](
+    /// ./struct.NaiveTime.html#leap-second-handling), but only when `sec == 59`.
+    ///
+    /// # Panics
+    ///
+    /// Panics on invalid hour, minute, second and/or millisecond.
+    #[deprecated(since = "0.4.23", note = "use `and_hms_milli_opt()` instead")]
+    #[inline]
+    #[must_use]
+    pub const fn and_hms_milli(&self, hour: u32, min: u32, sec: u32, milli: u32) -> NaiveDateTime {
+        expect(self.and_hms_milli_opt(hour, min, sec, milli), "invalid time")
+    }
+
+    /// Makes a new `NaiveDateTime` from the current date, hour, minute, second and millisecond.
+    ///
+    /// The millisecond part is allowed to exceed 1,000,000,000 in order to represent a [leap second](
+    /// ./struct.NaiveTime.html#leap-second-handling), but only when `sec == 59`.
+    ///
+    /// # Errors
+    ///
+    /// Returns `None` on invalid hour, minute, second and/or millisecond.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use chrono::NaiveDate;
+    ///
+    /// 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]
+    #[must_use]
+    pub const fn and_hms_milli_opt(
+        &self,
+        hour: u32,
+        min: u32,
+        sec: u32,
+        milli: u32,
+    ) -> Option<NaiveDateTime> {
+        let time = try_opt!(NaiveTime::from_hms_milli_opt(hour, min, sec, milli));
+        Some(self.and_time(time))
+    }
+
+    /// Makes a new `NaiveDateTime` from the current date, hour, minute, second and microsecond.
+    ///
+    /// The microsecond part is allowed to exceed 1,000,000,000 in order to represent a [leap second](
+    /// ./struct.NaiveTime.html#leap-second-handling), but only when `sec == 59`.
+    ///
+    /// # Panics
+    ///
+    /// Panics on invalid hour, minute, second and/or microsecond.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use chrono::{Datelike, NaiveDate, NaiveDateTime, Timelike, Weekday};
+    ///
+    /// let d = NaiveDate::from_ymd_opt(2015, 6, 3).unwrap();
+    ///
+    /// let dt: NaiveDateTime = d.and_hms_micro_opt(12, 34, 56, 789_012).unwrap();
+    /// assert_eq!(dt.year(), 2015);
+    /// assert_eq!(dt.weekday(), Weekday::Wed);
+    /// assert_eq!(dt.second(), 56);
+    /// assert_eq!(dt.nanosecond(), 789_012_000);
+    /// ```
+    #[deprecated(since = "0.4.23", note = "use `and_hms_micro_opt()` instead")]
+    #[inline]
+    #[must_use]
+    pub const fn and_hms_micro(&self, hour: u32, min: u32, sec: u32, micro: u32) -> NaiveDateTime {
+        expect(self.and_hms_micro_opt(hour, min, sec, micro), "invalid time")
+    }
+
+    /// Makes a new `NaiveDateTime` from the current date, hour, minute, second and microsecond.
+    ///
+    /// The microsecond part is allowed to exceed 1,000,000 in order to represent a [leap second](
+    /// ./struct.NaiveTime.html#leap-second-handling), but only when `sec == 59`.
+    ///
+    /// # Errors
+    ///
+    /// Returns `None` on invalid hour, minute, second and/or microsecond.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use chrono::NaiveDate;
+    ///
+    /// 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]
+    #[must_use]
+    pub const fn and_hms_micro_opt(
+        &self,
+        hour: u32,
+        min: u32,
+        sec: u32,
+        micro: u32,
+    ) -> Option<NaiveDateTime> {
+        let time = try_opt!(NaiveTime::from_hms_micro_opt(hour, min, sec, micro));
+        Some(self.and_time(time))
+    }
+
+    /// Makes a new `NaiveDateTime` from the current date, hour, minute, second and nanosecond.
+    ///
+    /// The nanosecond part is allowed to exceed 1,000,000,000 in order to represent a [leap second](
+    /// ./struct.NaiveTime.html#leap-second-handling), but only when `sec == 59`.
+    ///
+    /// # Panics
+    ///
+    /// Panics on invalid hour, minute, second and/or nanosecond.
+    #[deprecated(since = "0.4.23", note = "use `and_hms_nano_opt()` instead")]
+    #[inline]
+    #[must_use]
+    pub const fn and_hms_nano(&self, hour: u32, min: u32, sec: u32, nano: u32) -> NaiveDateTime {
+        expect(self.and_hms_nano_opt(hour, min, sec, nano), "invalid time")
+    }
+
+    /// Makes a new `NaiveDateTime` from the current date, hour, minute, second and nanosecond.
+    ///
+    /// The nanosecond part is allowed to exceed 1,000,000,000 in order to represent a [leap second](
+    /// ./struct.NaiveTime.html#leap-second-handling), but only when `sec == 59`.
+    ///
+    /// # Errors
+    ///
+    /// Returns `None` on invalid hour, minute, second and/or nanosecond.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use chrono::NaiveDate;
+    ///
+    /// 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]
+    #[must_use]
+    pub const fn and_hms_nano_opt(
+        &self,
+        hour: u32,
+        min: u32,
+        sec: u32,
+        nano: u32,
+    ) -> Option<NaiveDateTime> {
+        let time = try_opt!(NaiveTime::from_hms_nano_opt(hour, min, sec, nano));
+        Some(self.and_time(time))
+    }
+
+    /// Returns the packed month-day-flags.
+    #[inline]
+    const fn mdf(&self) -> Mdf {
+        Mdf::from_ol((self.yof() & OL_MASK) >> 3, self.year_flags())
+    }
+
+    /// Makes a new `NaiveDate` with the packed month-day-flags changed.
+    ///
+    /// Returns `None` when the resulting `NaiveDate` would be invalid.
+    #[inline]
+    const fn with_mdf(&self, mdf: Mdf) -> Option<NaiveDate> {
+        debug_assert!(self.year_flags().0 == mdf.year_flags().0);
+        match mdf.ordinal() {
+            Some(ordinal) => {
+                Some(NaiveDate::from_yof((self.yof() & !ORDINAL_MASK) | (ordinal << 4) as i32))
+            }
+            None => None, // Non-existing date
+        }
+    }
+
+    /// Makes a new `NaiveDate` for the next calendar date.
+    ///
+    /// # Panics
+    ///
+    /// Panics when `self` is the last representable date.
+    #[deprecated(since = "0.4.23", note = "use `succ_opt()` instead")]
+    #[inline]
+    #[must_use]
+    pub const fn succ(&self) -> NaiveDate {
+        expect(self.succ_opt(), "out of bound")
+    }
+
+    /// Makes a new `NaiveDate` for the next calendar date.
+    ///
+    /// # Errors
+    ///
+    /// Returns `None` when `self` is the last representable date.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use chrono::NaiveDate;
+    ///
+    /// 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]
+    #[must_use]
+    pub const fn succ_opt(&self) -> Option<NaiveDate> {
+        let new_ol = (self.yof() & OL_MASK) + (1 << 4);
+        match new_ol <= MAX_OL {
+            true => Some(NaiveDate::from_yof(self.yof() & !OL_MASK | new_ol)),
+            false => NaiveDate::from_yo_opt(self.year() + 1, 1),
+        }
+    }
+
+    /// Makes a new `NaiveDate` for the previous calendar date.
+    ///
+    /// # Panics
+    ///
+    /// Panics when `self` is the first representable date.
+    #[deprecated(since = "0.4.23", note = "use `pred_opt()` instead")]
+    #[inline]
+    #[must_use]
+    pub const fn pred(&self) -> NaiveDate {
+        expect(self.pred_opt(), "out of bound")
+    }
+
+    /// Makes a new `NaiveDate` for the previous calendar date.
+    ///
+    /// # Errors
+    ///
+    /// Returns `None` when `self` is the first representable date.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use chrono::NaiveDate;
+    ///
+    /// 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]
+    #[must_use]
+    pub const fn pred_opt(&self) -> Option<NaiveDate> {
+        let new_shifted_ordinal = (self.yof() & ORDINAL_MASK) - (1 << 4);
+        match new_shifted_ordinal > 0 {
+            true => Some(NaiveDate::from_yof(self.yof() & !ORDINAL_MASK | new_shifted_ordinal)),
+            false => NaiveDate::from_ymd_opt(self.year() - 1, 12, 31),
+        }
+    }
+
+    /// Adds the number of whole days in the given `TimeDelta` to the current date.
+    ///
+    /// # Errors
+    ///
+    /// Returns `None` if the resulting date would be out of range.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use chrono::{NaiveDate, TimeDelta};
+    ///
+    /// let d = NaiveDate::from_ymd_opt(2015, 9, 5).unwrap();
+    /// assert_eq!(
+    ///     d.checked_add_signed(TimeDelta::try_days(40).unwrap()),
+    ///     Some(NaiveDate::from_ymd_opt(2015, 10, 15).unwrap())
+    /// );
+    /// assert_eq!(
+    ///     d.checked_add_signed(TimeDelta::try_days(-40).unwrap()),
+    ///     Some(NaiveDate::from_ymd_opt(2015, 7, 27).unwrap())
+    /// );
+    /// assert_eq!(d.checked_add_signed(TimeDelta::try_days(1_000_000_000).unwrap()), None);
+    /// assert_eq!(d.checked_add_signed(TimeDelta::try_days(-1_000_000_000).unwrap()), None);
+    /// assert_eq!(NaiveDate::MAX.checked_add_signed(TimeDelta::try_days(1).unwrap()), None);
+    /// ```
+    #[must_use]
+    pub const fn checked_add_signed(self, rhs: TimeDelta) -> Option<NaiveDate> {
+        let days = rhs.num_days();
+        if days < i32::MIN as i64 || days > i32::MAX as i64 {
+            return None;
+        }
+        self.add_days(days as i32)
+    }
+
+    /// Subtracts the number of whole days in the given `TimeDelta` from the current date.
+    ///
+    /// # Errors
+    ///
+    /// Returns `None` if the resulting date would be out of range.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use chrono::{NaiveDate, TimeDelta};
+    ///
+    /// let d = NaiveDate::from_ymd_opt(2015, 9, 5).unwrap();
+    /// assert_eq!(
+    ///     d.checked_sub_signed(TimeDelta::try_days(40).unwrap()),
+    ///     Some(NaiveDate::from_ymd_opt(2015, 7, 27).unwrap())
+    /// );
+    /// assert_eq!(
+    ///     d.checked_sub_signed(TimeDelta::try_days(-40).unwrap()),
+    ///     Some(NaiveDate::from_ymd_opt(2015, 10, 15).unwrap())
+    /// );
+    /// assert_eq!(d.checked_sub_signed(TimeDelta::try_days(1_000_000_000).unwrap()), None);
+    /// assert_eq!(d.checked_sub_signed(TimeDelta::try_days(-1_000_000_000).unwrap()), None);
+    /// assert_eq!(NaiveDate::MIN.checked_sub_signed(TimeDelta::try_days(1).unwrap()), None);
+    /// ```
+    #[must_use]
+    pub const fn checked_sub_signed(self, rhs: TimeDelta) -> Option<NaiveDate> {
+        let days = -rhs.num_days();
+        if days < i32::MIN as i64 || days > i32::MAX as i64 {
+            return None;
+        }
+        self.add_days(days as i32)
+    }
+
+    /// Subtracts another `NaiveDate` from the current date.
+    /// Returns a `TimeDelta` of integral numbers.
+    ///
+    /// This does not overflow or underflow at all,
+    /// as all possible output fits in the range of `TimeDelta`.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use chrono::{NaiveDate, TimeDelta};
+    ///
+    /// let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap();
+    /// let since = NaiveDate::signed_duration_since;
+    ///
+    /// assert_eq!(since(from_ymd(2014, 1, 1), from_ymd(2014, 1, 1)), TimeDelta::zero());
+    /// assert_eq!(
+    ///     since(from_ymd(2014, 1, 1), from_ymd(2013, 12, 31)),
+    ///     TimeDelta::try_days(1).unwrap()
+    /// );
+    /// assert_eq!(since(from_ymd(2014, 1, 1), from_ymd(2014, 1, 2)), TimeDelta::try_days(-1).unwrap());
+    /// assert_eq!(
+    ///     since(from_ymd(2014, 1, 1), from_ymd(2013, 9, 23)),
+    ///     TimeDelta::try_days(100).unwrap()
+    /// );
+    /// assert_eq!(
+    ///     since(from_ymd(2014, 1, 1), from_ymd(2013, 1, 1)),
+    ///     TimeDelta::try_days(365).unwrap()
+    /// );
+    /// assert_eq!(
+    ///     since(from_ymd(2014, 1, 1), from_ymd(2010, 1, 1)),
+    ///     TimeDelta::try_days(365 * 4 + 1).unwrap()
+    /// );
+    /// assert_eq!(
+    ///     since(from_ymd(2014, 1, 1), from_ymd(1614, 1, 1)),
+    ///     TimeDelta::try_days(365 * 400 + 97).unwrap()
+    /// );
+    /// ```
+    #[must_use]
+    pub const fn signed_duration_since(self, rhs: NaiveDate) -> TimeDelta {
+        let year1 = self.year();
+        let year2 = rhs.year();
+        let (year1_div_400, year1_mod_400) = div_mod_floor(year1, 400);
+        let (year2_div_400, year2_mod_400) = div_mod_floor(year2, 400);
+        let cycle1 = yo_to_cycle(year1_mod_400 as u32, self.ordinal()) as i64;
+        let cycle2 = yo_to_cycle(year2_mod_400 as u32, rhs.ordinal()) as i64;
+        let days = (year1_div_400 as i64 - year2_div_400 as i64) * 146_097 + (cycle1 - cycle2);
+        // The range of `TimeDelta` is ca. 585 million years, the range of `NaiveDate` ca. 525.000
+        // years.
+        expect(TimeDelta::try_days(days), "always in range")
+    }
+
+    /// Returns the number of whole years from the given `base` until `self`.
+    ///
+    /// # Errors
+    ///
+    /// Returns `None` if `base > self`.
+    #[must_use]
+    pub const fn years_since(&self, base: Self) -> Option<u32> {
+        let mut years = self.year() - base.year();
+        // Comparing tuples is not (yet) possible in const context. Instead we combine month and
+        // day into one `u32` for easy comparison.
+        if (self.month() << 5 | self.day()) < (base.month() << 5 | 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.
+    ///
+    /// The `Iterator` of items should be `Clone`able,
+    /// since the resulting `DelayedFormat` value may be formatted multiple times.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use chrono::format::strftime::StrftimeItems;
+    /// use chrono::NaiveDate;
+    ///
+    /// let fmt = StrftimeItems::new("%Y-%m-%d");
+    /// 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_opt(2015, 9, 5).unwrap();
+    /// assert_eq!(format!("{}", d.format_with_items(fmt)), "2015-09-05");
+    /// ```
+    #[cfg(feature = "alloc")]
+    #[inline]
+    #[must_use]
+    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), None, items)
+    }
+
+    /// Formats the date with the specified format string.
+    /// See the [`format::strftime` module](crate::format::strftime)
+    /// 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.)
+    ///
+    /// # Panics
+    ///
+    /// Converting or formatting the returned `DelayedFormat` panics if the format string is wrong.
+    /// Because of this delayed failure, you are recommended to immediately use the `DelayedFormat`
+    /// value.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use chrono::NaiveDate;
+    ///
+    /// 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_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(feature = "alloc")]
+    #[inline]
+    #[must_use]
+    pub fn format<'a>(&self, fmt: &'a str) -> DelayedFormat<StrftimeItems<'a>> {
+        self.format_with_items(StrftimeItems::new(fmt))
+    }
+
+    /// Formats the date with the specified formatting items and locale.
+    #[cfg(all(feature = "unstable-locales", feature = "alloc"))]
+    #[inline]
+    #[must_use]
+    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(all(feature = "unstable-locales", feature = "alloc"))]
+    #[inline]
+    #[must_use]
+    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
+    ///
+    /// ```
+    /// # use chrono::NaiveDate;
+    ///
+    /// let expected = [
+    ///     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_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 const fn iter_days(&self) -> NaiveDateDaysIterator {
+        NaiveDateDaysIterator { value: *self }
+    }
+
+    /// Returns an iterator that steps by weeks across all representable dates.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// # use chrono::NaiveDate;
+    ///
+    /// let expected = [
+    ///     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_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 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::new(*self, start)
+    }
+
+    /// Returns `true` if this is a leap year.
+    ///
+    /// ```
+    /// # use chrono::NaiveDate;
+    /// assert_eq!(NaiveDate::from_ymd_opt(2000, 1, 1).unwrap().leap_year(), true);
+    /// assert_eq!(NaiveDate::from_ymd_opt(2001, 1, 1).unwrap().leap_year(), false);
+    /// assert_eq!(NaiveDate::from_ymd_opt(2002, 1, 1).unwrap().leap_year(), false);
+    /// assert_eq!(NaiveDate::from_ymd_opt(2003, 1, 1).unwrap().leap_year(), false);
+    /// assert_eq!(NaiveDate::from_ymd_opt(2004, 1, 1).unwrap().leap_year(), true);
+    /// assert_eq!(NaiveDate::from_ymd_opt(2100, 1, 1).unwrap().leap_year(), false);
+    /// ```
+    pub const fn leap_year(&self) -> bool {
+        self.yof() & (0b1000) == 0
+    }
+
+    // This duplicates `Datelike::year()`, because trait methods can't be const yet.
+    #[inline]
+    const fn year(&self) -> i32 {
+        self.yof() >> 13
+    }
+
+    /// Returns the day of year starting from 1.
+    // This duplicates `Datelike::ordinal()`, because trait methods can't be const yet.
+    #[inline]
+    const fn ordinal(&self) -> u32 {
+        ((self.yof() & ORDINAL_MASK) >> 4) as u32
+    }
+
+    // This duplicates `Datelike::month()`, because trait methods can't be const yet.
+    #[inline]
+    const fn month(&self) -> u32 {
+        self.mdf().month()
+    }
+
+    // This duplicates `Datelike::day()`, because trait methods can't be const yet.
+    #[inline]
+    const fn day(&self) -> u32 {
+        self.mdf().day()
+    }
+
+    /// Returns the day of week.
+    // This duplicates `Datelike::weekday()`, because trait methods can't be const yet.
+    #[inline]
+    pub(super) const fn weekday(&self) -> Weekday {
+        match (((self.yof() & ORDINAL_MASK) >> 4) + (self.yof() & WEEKDAY_FLAGS_MASK)) % 7 {
+            0 => Weekday::Mon,
+            1 => Weekday::Tue,
+            2 => Weekday::Wed,
+            3 => Weekday::Thu,
+            4 => Weekday::Fri,
+            5 => Weekday::Sat,
+            _ => Weekday::Sun,
+        }
+    }
+
+    #[inline]
+    const fn year_flags(&self) -> YearFlags {
+        YearFlags((self.yof() & YEAR_FLAGS_MASK) as u8)
+    }
+
+    /// Counts the days in the proleptic Gregorian calendar, with January 1, Year 1 (CE) as day 1.
+    // This duplicates `Datelike::num_days_from_ce()`, because trait methods can't be const yet.
+    pub(crate) const fn num_days_from_ce(&self) -> i32 {
+        // 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
+    }
+
+    /// Create a new `NaiveDate` from a raw year-ordinal-flags `i32`.
+    ///
+    /// In a valid value an ordinal is never `0`, and neither are the year flags. This method
+    /// doesn't do any validation in release builds.
+    #[inline]
+    const fn from_yof(yof: i32) -> NaiveDate {
+        // The following are the invariants our ordinal and flags should uphold for a valid
+        // `NaiveDate`.
+        debug_assert!(((yof & OL_MASK) >> 3) > 1);
+        debug_assert!(((yof & OL_MASK) >> 3) <= MAX_OL);
+        debug_assert!((yof & 0b111) != 000);
+        NaiveDate { yof: unsafe { NonZeroI32::new_unchecked(yof) } }
+    }
+
+    /// Get the raw year-ordinal-flags `i32`.
+    #[inline]
+    const fn yof(&self) -> i32 {
+        self.yof.get()
+    }
+
+    /// The minimum possible `NaiveDate` (January 1, 262144 BCE).
+    pub const MIN: NaiveDate = NaiveDate::from_yof((MIN_YEAR << 13) | (1 << 4) | 0o12 /* D */);
+    /// The maximum possible `NaiveDate` (December 31, 262142 CE).
+    pub const MAX: NaiveDate =
+        NaiveDate::from_yof((MAX_YEAR << 13) | (365 << 4) | 0o16 /* G */);
+
+    /// One day before the minimum possible `NaiveDate` (December 31, 262145 BCE).
+    pub(crate) const BEFORE_MIN: NaiveDate =
+        NaiveDate::from_yof(((MIN_YEAR - 1) << 13) | (366 << 4) | 0o07 /* FE */);
+    /// One day after the maximum possible `NaiveDate` (January 1, 262143 CE).
+    pub(crate) const AFTER_MAX: NaiveDate =
+        NaiveDate::from_yof(((MAX_YEAR + 1) << 13) | (1 << 4) | 0o17 /* F */);
+}
+
+impl Datelike for NaiveDate {
+    /// Returns the year number in the [calendar date](#calendar-date).
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use chrono::{Datelike, NaiveDate};
+    ///
+    /// 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.year()
+    }
+
+    /// Returns the month number starting from 1.
+    ///
+    /// The return value ranges from 1 to 12.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use chrono::{Datelike, NaiveDate};
+    ///
+    /// 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.month()
+    }
+
+    /// Returns the month number starting from 0.
+    ///
+    /// The return value ranges from 0 to 11.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use chrono::{Datelike, NaiveDate};
+    ///
+    /// 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.month() - 1
+    }
+
+    /// Returns the day of month starting from 1.
+    ///
+    /// The return value ranges from 1 to 31. (The last day of month differs by months.)
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use chrono::{Datelike, NaiveDate};
+    ///
+    /// 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_opt`](#method.pred_opt),
+    /// one can determine the number of days in a particular month.
+    /// (Note that this panics when `year` is out of range.)
+    ///
+    /// ```
+    /// use chrono::{Datelike, NaiveDate};
+    ///
+    /// 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_opt(y, m, 1).unwrap();
+    ///
+    ///     // ...is preceded by the last day of the original month
+    ///     d.pred_opt().unwrap().day()
+    /// }
+    ///
+    /// assert_eq!(ndays_in_month(2015, 8), 31);
+    /// assert_eq!(ndays_in_month(2015, 9), 30);
+    /// 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.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.)
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use chrono::{Datelike, NaiveDate};
+    ///
+    /// 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
+    }
+
+    /// Returns the day of year starting from 1.
+    ///
+    /// The return value ranges from 1 to 366. (The last day of year differs by years.)
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use chrono::{Datelike, NaiveDate};
+    ///
+    /// 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_opt`](#method.pred_opt),
+    /// one can determine the number of days in a particular year.
+    /// (Note that this panics when `year` is out of range.)
+    ///
+    /// ```
+    /// use chrono::{Datelike, NaiveDate};
+    ///
+    /// fn ndays_in_year(year: i32) -> u32 {
+    ///     // the first day of the next year...
+    ///     let d = NaiveDate::from_ymd_opt(year + 1, 1, 1).unwrap();
+    ///
+    ///     // ...is preceded by the last day of the original year
+    ///     d.pred_opt().unwrap().ordinal()
+    /// }
+    ///
+    /// assert_eq!(ndays_in_year(2015), 365);
+    /// assert_eq!(ndays_in_year(2016), 366);
+    /// 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.yof() & ORDINAL_MASK) >> 4) as 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.)
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use chrono::{Datelike, NaiveDate};
+    ///
+    /// 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.ordinal() - 1
+    }
+
+    /// Returns the day of week.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use chrono::{Datelike, NaiveDate, Weekday};
+    ///
+    /// 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.weekday()
+    }
+
+    #[inline]
+    fn iso_week(&self) -> IsoWeek {
+        IsoWeek::from_yof(self.year(), self.ordinal(), self.year_flags())
+    }
+
+    /// Makes a new `NaiveDate` with the year number changed, while keeping the same month and day.
+    ///
+    /// This method assumes you want to work on the date as a year-month-day value. Don't use it if
+    /// you want the ordinal to stay the same after changing the year, of if you want the week and
+    /// weekday values to stay the same.
+    ///
+    /// # Errors
+    ///
+    /// Returns `None` if:
+    /// - The resulting date does not exist (February 29 in a non-leap year).
+    /// - The year is out of range for a `NaiveDate`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use chrono::{Datelike, NaiveDate};
+    ///
+    /// 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 case where this method can return `None`.
+    ///
+    /// ```
+    /// # use chrono::{NaiveDate, Datelike};
+    /// 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());
+    /// ```
+    ///
+    /// Don't use `with_year` if you want the ordinal date to stay the same:
+    ///
+    /// ```
+    /// # use chrono::{Datelike, NaiveDate};
+    /// assert_ne!(
+    ///     NaiveDate::from_yo_opt(2020, 100).unwrap().with_year(2023).unwrap(),
+    ///     NaiveDate::from_yo_opt(2023, 100).unwrap() // result is 2023-101
+    /// );
+    /// ```
+    #[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
+        let mdf = self.mdf();
+
+        // adjust the flags as needed
+        let flags = YearFlags::from_year(year);
+        let mdf = mdf.with_flags(flags);
+
+        NaiveDate::from_mdf(year, mdf)
+    }
+
+    /// Makes a new `NaiveDate` with the month number (starting from 1) changed.
+    ///
+    /// # Errors
+    ///
+    /// Returns `None` if:
+    /// - The resulting date does not exist (for example `month(4)` when day of the month is 31).
+    /// - The value for `month` is invalid.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use chrono::{Datelike, NaiveDate};
+    ///
+    /// 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 Feb 30
+    /// ```
+    ///
+    /// Don't combine multiple `Datelike::with_*` methods. The intermediate value may not exist.
+    ///
+    /// ```
+    /// use chrono::{Datelike, NaiveDate};
+    ///
+    /// fn with_year_month(date: NaiveDate, year: i32, month: u32) -> Option<NaiveDate> {
+    ///     date.with_year(year)?.with_month(month)
+    /// }
+    /// let d = NaiveDate::from_ymd_opt(2020, 2, 29).unwrap();
+    /// assert!(with_year_month(d, 2019, 1).is_none()); // fails because of invalid intermediate value
+    ///
+    /// // Correct version:
+    /// fn with_year_month_fixed(date: NaiveDate, year: i32, month: u32) -> Option<NaiveDate> {
+    ///     NaiveDate::from_ymd_opt(year, month, date.day())
+    /// }
+    /// let d = NaiveDate::from_ymd_opt(2020, 2, 29).unwrap();
+    /// assert_eq!(with_year_month_fixed(d, 2019, 1), NaiveDate::from_ymd_opt(2019, 1, 29));
+    /// ```
+    #[inline]
+    fn with_month(&self, month: u32) -> Option<NaiveDate> {
+        self.with_mdf(self.mdf().with_month(month)?)
+    }
+
+    /// Makes a new `NaiveDate` with the month number (starting from 0) changed.
+    ///
+    /// # Errors
+    ///
+    /// Returns `None` if:
+    /// - The resulting date does not exist (for example `month0(3)` when day of the month is 31).
+    /// - The value for `month0` is invalid.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use chrono::{Datelike, NaiveDate};
+    ///
+    /// 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 12
+    /// assert_eq!(NaiveDate::from_ymd_opt(2015, 9, 30).unwrap().with_month0(1), None); // No Feb 30
+    /// ```
+    #[inline]
+    fn with_month0(&self, month0: u32) -> Option<NaiveDate> {
+        let month = month0.checked_add(1)?;
+        self.with_mdf(self.mdf().with_month(month)?)
+    }
+
+    /// Makes a new `NaiveDate` with the day of month (starting from 1) changed.
+    ///
+    /// # Errors
+    ///
+    /// Returns `None` if:
+    /// - The resulting date does not exist (for example `day(31)` in April).
+    /// - The value for `day` is invalid.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use chrono::{Datelike, NaiveDate};
+    ///
+    /// 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)?)
+    }
+
+    /// Makes a new `NaiveDate` with the day of month (starting from 0) changed.
+    ///
+    /// # Errors
+    ///
+    /// Returns `None` if:
+    /// - The resulting date does not exist (for example `day(30)` in April).
+    /// - The value for `day0` is invalid.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use chrono::{Datelike, NaiveDate};
+    ///
+    /// 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> {
+        let day = day0.checked_add(1)?;
+        self.with_mdf(self.mdf().with_day(day)?)
+    }
+
+    /// Makes a new `NaiveDate` with the day of year (starting from 1) changed.
+    ///
+    /// # Errors
+    ///
+    /// Returns `None` if:
+    /// - The resulting date does not exist (`with_ordinal(366)` in a non-leap year).
+    /// - The value for `ordinal` is invalid.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use chrono::{NaiveDate, Datelike};
+    ///
+    /// 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_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> {
+        if ordinal == 0 || ordinal > 366 {
+            return None;
+        }
+        let yof = (self.yof() & !ORDINAL_MASK) | (ordinal << 4) as i32;
+        match yof & OL_MASK <= MAX_OL {
+            true => Some(NaiveDate::from_yof(yof)),
+            false => None, // Does not exist: Ordinal 366 in a common year.
+        }
+    }
+
+    /// Makes a new `NaiveDate` with the day of year (starting from 0) changed.
+    ///
+    /// # Errors
+    ///
+    /// Returns `None` if:
+    /// - The resulting date does not exist (`with_ordinal0(365)` in a non-leap year).
+    /// - The value for `ordinal0` is invalid.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use chrono::{NaiveDate, Datelike};
+    ///
+    /// 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_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> {
+        let ordinal = ordinal0.checked_add(1)?;
+        self.with_ordinal(ordinal)
+    }
+}
+
+/// Add `TimeDelta` to `NaiveDate`.
+///
+/// This discards the fractional days in `TimeDelta`, rounding to the closest integral number of
+/// days towards `TimeDelta::zero()`.
+///
+/// # Panics
+///
+/// Panics if the resulting date would be out of range.
+/// Consider using [`NaiveDate::checked_add_signed`] to get an `Option` instead.
+///
+/// # Example
+///
+/// ```
+/// use chrono::{NaiveDate, TimeDelta};
+///
+/// let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap();
+///
+/// assert_eq!(from_ymd(2014, 1, 1) + TimeDelta::zero(), from_ymd(2014, 1, 1));
+/// assert_eq!(from_ymd(2014, 1, 1) + TimeDelta::try_seconds(86399).unwrap(), from_ymd(2014, 1, 1));
+/// assert_eq!(
+///     from_ymd(2014, 1, 1) + TimeDelta::try_seconds(-86399).unwrap(),
+///     from_ymd(2014, 1, 1)
+/// );
+/// assert_eq!(from_ymd(2014, 1, 1) + TimeDelta::try_days(1).unwrap(), from_ymd(2014, 1, 2));
+/// assert_eq!(from_ymd(2014, 1, 1) + TimeDelta::try_days(-1).unwrap(), from_ymd(2013, 12, 31));
+/// assert_eq!(from_ymd(2014, 1, 1) + TimeDelta::try_days(364).unwrap(), from_ymd(2014, 12, 31));
+/// assert_eq!(
+///     from_ymd(2014, 1, 1) + TimeDelta::try_days(365 * 4 + 1).unwrap(),
+///     from_ymd(2018, 1, 1)
+/// );
+/// assert_eq!(
+///     from_ymd(2014, 1, 1) + TimeDelta::try_days(365 * 400 + 97).unwrap(),
+///     from_ymd(2414, 1, 1)
+/// );
+/// ```
+///
+/// [`NaiveDate::checked_add_signed`]: crate::NaiveDate::checked_add_signed
+impl Add<TimeDelta> for NaiveDate {
+    type Output = NaiveDate;
+
+    #[inline]
+    fn add(self, rhs: TimeDelta) -> NaiveDate {
+        self.checked_add_signed(rhs).expect("`NaiveDate + TimeDelta` overflowed")
+    }
+}
+
+/// Add-assign of `TimeDelta` to `NaiveDate`.
+///
+/// This discards the fractional days in `TimeDelta`, rounding to the closest integral number of days
+/// towards `TimeDelta::zero()`.
+///
+/// # Panics
+///
+/// Panics if the resulting date would be out of range.
+/// Consider using [`NaiveDate::checked_add_signed`] to get an `Option` instead.
+impl AddAssign<TimeDelta> for NaiveDate {
+    #[inline]
+    fn add_assign(&mut self, rhs: TimeDelta) {
+        *self = self.add(rhs);
+    }
+}
+
+/// Add `Months` to `NaiveDate`.
+///
+/// The result will be clamped to valid days in the resulting month, see `checked_add_months` for
+/// details.
+///
+/// # Panics
+///
+/// Panics if the resulting date would be out of range.
+/// Consider using `NaiveDate::checked_add_months` to get an `Option` instead.
+///
+/// # Example
+///
+/// ```
+/// use chrono::{Months, NaiveDate};
+///
+/// let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap();
+///
+/// assert_eq!(from_ymd(2014, 1, 1) + Months::new(1), from_ymd(2014, 2, 1));
+/// assert_eq!(from_ymd(2014, 1, 1) + Months::new(11), from_ymd(2014, 12, 1));
+/// 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));
+/// ```
+impl Add<Months> for NaiveDate {
+    type Output = NaiveDate;
+
+    fn add(self, months: Months) -> Self::Output {
+        self.checked_add_months(months).expect("`NaiveDate + Months` out of range")
+    }
+}
+
+/// Subtract `Months` from `NaiveDate`.
+///
+/// The result will be clamped to valid days in the resulting month, see `checked_sub_months` for
+/// details.
+///
+/// # Panics
+///
+/// Panics if the resulting date would be out of range.
+/// Consider using `NaiveDate::checked_sub_months` to get an `Option` instead.
+///
+/// # Example
+///
+/// ```
+/// use chrono::{Months, NaiveDate};
+///
+/// let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap();
+///
+/// assert_eq!(from_ymd(2014, 1, 1) - Months::new(11), from_ymd(2013, 2, 1));
+/// assert_eq!(from_ymd(2014, 1, 1) - Months::new(12), from_ymd(2013, 1, 1));
+/// assert_eq!(from_ymd(2014, 1, 1) - Months::new(13), from_ymd(2012, 12, 1));
+/// ```
+impl Sub<Months> for NaiveDate {
+    type Output = NaiveDate;
+
+    fn sub(self, months: Months) -> Self::Output {
+        self.checked_sub_months(months).expect("`NaiveDate - Months` out of range")
+    }
+}
+
+/// Add `Days` to `NaiveDate`.
+///
+/// # Panics
+///
+/// Panics if the resulting date would be out of range.
+/// Consider using `NaiveDate::checked_add_days` to get an `Option` instead.
+impl Add<Days> for NaiveDate {
+    type Output = NaiveDate;
+
+    fn add(self, days: Days) -> Self::Output {
+        self.checked_add_days(days).expect("`NaiveDate + Days` out of range")
+    }
+}
+
+/// Subtract `Days` from `NaiveDate`.
+///
+/// # Panics
+///
+/// Panics if the resulting date would be out of range.
+/// Consider using `NaiveDate::checked_sub_days` to get an `Option` instead.
+impl Sub<Days> for NaiveDate {
+    type Output = NaiveDate;
+
+    fn sub(self, days: Days) -> Self::Output {
+        self.checked_sub_days(days).expect("`NaiveDate - Days` out of range")
+    }
+}
+
+/// Subtract `TimeDelta` from `NaiveDate`.
+///
+/// This discards the fractional days in `TimeDelta`, rounding to the closest integral number of
+/// days towards `TimeDelta::zero()`.
+/// It is the same as the addition with a negated `TimeDelta`.
+///
+/// # Panics
+///
+/// Panics if the resulting date would be out of range.
+/// Consider using [`NaiveDate::checked_sub_signed`] to get an `Option` instead.
+///
+/// # Example
+///
+/// ```
+/// use chrono::{NaiveDate, TimeDelta};
+///
+/// let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap();
+///
+/// assert_eq!(from_ymd(2014, 1, 1) - TimeDelta::zero(), from_ymd(2014, 1, 1));
+/// assert_eq!(from_ymd(2014, 1, 1) - TimeDelta::try_seconds(86399).unwrap(), from_ymd(2014, 1, 1));
+/// assert_eq!(
+///     from_ymd(2014, 1, 1) - TimeDelta::try_seconds(-86399).unwrap(),
+///     from_ymd(2014, 1, 1)
+/// );
+/// assert_eq!(from_ymd(2014, 1, 1) - TimeDelta::try_days(1).unwrap(), from_ymd(2013, 12, 31));
+/// assert_eq!(from_ymd(2014, 1, 1) - TimeDelta::try_days(-1).unwrap(), from_ymd(2014, 1, 2));
+/// assert_eq!(from_ymd(2014, 1, 1) - TimeDelta::try_days(364).unwrap(), from_ymd(2013, 1, 2));
+/// assert_eq!(
+///     from_ymd(2014, 1, 1) - TimeDelta::try_days(365 * 4 + 1).unwrap(),
+///     from_ymd(2010, 1, 1)
+/// );
+/// assert_eq!(
+///     from_ymd(2014, 1, 1) - TimeDelta::try_days(365 * 400 + 97).unwrap(),
+///     from_ymd(1614, 1, 1)
+/// );
+/// ```
+///
+/// [`NaiveDate::checked_sub_signed`]: crate::NaiveDate::checked_sub_signed
+impl Sub<TimeDelta> for NaiveDate {
+    type Output = NaiveDate;
+
+    #[inline]
+    fn sub(self, rhs: TimeDelta) -> NaiveDate {
+        self.checked_sub_signed(rhs).expect("`NaiveDate - TimeDelta` overflowed")
+    }
+}
+
+/// Subtract-assign `TimeDelta` from `NaiveDate`.
+///
+/// This discards the fractional days in `TimeDelta`, rounding to the closest integral number of
+/// days towards `TimeDelta::zero()`.
+/// It is the same as the addition with a negated `TimeDelta`.
+///
+/// # Panics
+///
+/// Panics if the resulting date would be out of range.
+/// Consider using [`NaiveDate::checked_sub_signed`] to get an `Option` instead.
+impl SubAssign<TimeDelta> for NaiveDate {
+    #[inline]
+    fn sub_assign(&mut self, rhs: TimeDelta) {
+        *self = self.sub(rhs);
+    }
+}
+
+/// Subtracts another `NaiveDate` from the current date.
+/// Returns a `TimeDelta` of integral numbers.
+///
+/// This does not overflow or underflow at all,
+/// as all possible output fits in the range of `TimeDelta`.
+///
+/// The implementation is a wrapper around
+/// [`NaiveDate::signed_duration_since`](#method.signed_duration_since).
+///
+/// # Example
+///
+/// ```
+/// use chrono::{NaiveDate, TimeDelta};
+///
+/// let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap();
+///
+/// assert_eq!(from_ymd(2014, 1, 1) - from_ymd(2014, 1, 1), TimeDelta::zero());
+/// assert_eq!(from_ymd(2014, 1, 1) - from_ymd(2013, 12, 31), TimeDelta::try_days(1).unwrap());
+/// assert_eq!(from_ymd(2014, 1, 1) - from_ymd(2014, 1, 2), TimeDelta::try_days(-1).unwrap());
+/// assert_eq!(from_ymd(2014, 1, 1) - from_ymd(2013, 9, 23), TimeDelta::try_days(100).unwrap());
+/// assert_eq!(from_ymd(2014, 1, 1) - from_ymd(2013, 1, 1), TimeDelta::try_days(365).unwrap());
+/// assert_eq!(
+///     from_ymd(2014, 1, 1) - from_ymd(2010, 1, 1),
+///     TimeDelta::try_days(365 * 4 + 1).unwrap()
+/// );
+/// assert_eq!(
+///     from_ymd(2014, 1, 1) - from_ymd(1614, 1, 1),
+///     TimeDelta::try_days(365 * 400 + 97).unwrap()
+/// );
+/// ```
+impl Sub<NaiveDate> for NaiveDate {
+    type Output = TimeDelta;
+
+    #[inline]
+    fn sub(self, rhs: NaiveDate) -> TimeDelta {
+        self.signed_duration_since(rhs)
+    }
+}
+
+impl From<NaiveDateTime> for NaiveDate {
+    fn from(naive_datetime: NaiveDateTime) -> Self {
+        naive_datetime.date()
+    }
+}
+
+/// Iterator over `NaiveDate` with a step size of one day.
+#[derive(Debug, Copy, Clone, Hash, PartialEq, PartialOrd, Eq, Ord)]
+pub struct NaiveDateDaysIterator {
+    value: NaiveDate,
+}
+
+impl Iterator for NaiveDateDaysIterator {
+    type Item = NaiveDate;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        // We return the current value, and have no way to return `NaiveDate::MAX`.
+        let current = self.value;
+        // This can't panic because current is < NaiveDate::MAX:
+        self.value = current.succ_opt()?;
+        Some(current)
+    }
+
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        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> {
+        // We return the current value, and have no way to return `NaiveDate::MIN`.
+        let current = self.value;
+        self.value = current.pred_opt()?;
+        Some(current)
+    }
+}
+
+impl FusedIterator for NaiveDateDaysIterator {}
+
+/// Iterator over `NaiveDate` with a step size of one week.
+#[derive(Debug, Copy, Clone, Hash, PartialEq, PartialOrd, Eq, Ord)]
+pub struct NaiveDateWeeksIterator {
+    value: NaiveDate,
+}
+
+impl Iterator for NaiveDateWeeksIterator {
+    type Item = NaiveDate;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        let current = self.value;
+        self.value = current.checked_add_days(Days::new(7))?;
+        Some(current)
+    }
+
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        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> {
+        let current = self.value;
+        self.value = current.checked_sub_days(Days::new(7))?;
+        Some(current)
+    }
+}
+
+impl FusedIterator for NaiveDateWeeksIterator {}
+
+/// The `Debug` output of the naive date `d` is the same as
+/// [`d.format("%Y-%m-%d")`](crate::format::strftime).
+///
+/// The string printed can be readily parsed via the `parse` method on `str`.
+///
+/// # Example
+///
+/// ```
+/// use chrono::NaiveDate;
+///
+/// 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_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..=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}", year)?;
+        }
+
+        f.write_char('-')?;
+        write_hundreds(f, mdf.month() as u8)?;
+        f.write_char('-')?;
+        write_hundreds(f, mdf.day() as u8)
+    }
+}
+
+/// The `Display` output of the naive date `d` is the same as
+/// [`d.format("%Y-%m-%d")`](crate::format::strftime).
+///
+/// The string printed can be readily parsed via the `parse` method on `str`.
+///
+/// # Example
+///
+/// ```
+/// use chrono::NaiveDate;
+///
+/// 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_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)
+    }
+}
+
+/// Parsing a `str` into a `NaiveDate` uses the same format,
+/// [`%Y-%m-%d`](crate::format::strftime), as in `Debug` and `Display`.
+///
+/// # Example
+///
+/// ```
+/// use chrono::NaiveDate;
+///
+/// let d = NaiveDate::from_ymd_opt(2015, 9, 18).unwrap();
+/// assert_eq!("2015-09-18".parse::<NaiveDate>(), Ok(d));
+///
+/// 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: &[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(""),
+        ];
+
+        let mut parsed = Parsed::new();
+        parse(&mut parsed, s, ITEMS.iter())?;
+        parsed.to_naive_date()
+    }
+}
+
+/// 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()
+    }
+}
+
+const fn cycle_to_yo(cycle: u32) -> (u32, u32) {
+    let mut year_mod_400 = cycle / 365;
+    let mut ordinal0 = cycle % 365;
+    let delta = YEAR_DELTAS[year_mod_400 as usize] as u32;
+    if ordinal0 < delta {
+        year_mod_400 -= 1;
+        ordinal0 += 365 - YEAR_DELTAS[year_mod_400 as usize] as u32;
+    } else {
+        ordinal0 -= delta;
+    }
+    (year_mod_400, ordinal0 + 1)
+}
+
+const fn yo_to_cycle(year_mod_400: u32, ordinal: u32) -> u32 {
+    year_mod_400 * 365 + YEAR_DELTAS[year_mod_400 as usize] as u32 + ordinal - 1
+}
+
+const fn div_mod_floor(val: i32, div: i32) -> (i32, i32) {
+    (val.div_euclid(div), val.rem_euclid(div))
+}
+
+/// MAX_YEAR is one year less than the type is capable of representing. Internally we may sometimes
+/// use the headroom, notably to handle cases where the offset of a `DateTime` constructed with
+/// `NaiveDate::MAX` pushes it beyond the valid, representable range.
+pub(super) const MAX_YEAR: i32 = (i32::MAX >> 13) - 1;
+
+/// MIN_YEAR is one year more than the type is capable of representing. Internally we may sometimes
+/// use the headroom, notably to handle cases where the offset of a `DateTime` constructed with
+/// `NaiveDate::MIN` pushes it beyond the valid, representable range.
+pub(super) const MIN_YEAR: i32 = (i32::MIN >> 13) + 1;
+
+const ORDINAL_MASK: i32 = 0b1_1111_1111_0000;
+
+const LEAP_YEAR_MASK: i32 = 0b1000;
+
+// OL: ordinal and leap year flag.
+// With only these parts of the date an ordinal 366 in a common year would be encoded as
+// `((366 << 1) | 1) << 3`, and in a leap year as `((366 << 1) | 0) << 3`, which is less.
+// This allows for efficiently checking the ordinal exists depending on whether this is a leap year.
+const OL_MASK: i32 = ORDINAL_MASK | LEAP_YEAR_MASK;
+const MAX_OL: i32 = 366 << 4;
+
+// Weekday of the last day in the preceding year.
+// Allows for quick day of week calculation from the 1-based ordinal.
+const WEEKDAY_FLAGS_MASK: i32 = 0b111;
+
+const YEAR_FLAGS_MASK: i32 = LEAP_YEAR_MASK | WEEKDAY_FLAGS_MASK;
+
+const YEAR_DELTAS: &[u8; 401] = &[
+    0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8,
+    8, 9, 9, 9, 9, 10, 10, 10, 10, 11, 11, 11, 11, 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14,
+    15, 15, 15, 15, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19, 20, 20, 20, 20,
+    21, 21, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23, 24, 24, 24, 24, 25, 25, 25, // 100
+    25, 25, 25, 25, 25, 26, 26, 26, 26, 27, 27, 27, 27, 28, 28, 28, 28, 29, 29, 29, 29, 30, 30, 30,
+    30, 31, 31, 31, 31, 32, 32, 32, 32, 33, 33, 33, 33, 34, 34, 34, 34, 35, 35, 35, 35, 36, 36, 36,
+    36, 37, 37, 37, 37, 38, 38, 38, 38, 39, 39, 39, 39, 40, 40, 40, 40, 41, 41, 41, 41, 42, 42, 42,
+    42, 43, 43, 43, 43, 44, 44, 44, 44, 45, 45, 45, 45, 46, 46, 46, 46, 47, 47, 47, 47, 48, 48, 48,
+    48, 49, 49, 49, // 200
+    49, 49, 49, 49, 49, 50, 50, 50, 50, 51, 51, 51, 51, 52, 52, 52, 52, 53, 53, 53, 53, 54, 54, 54,
+    54, 55, 55, 55, 55, 56, 56, 56, 56, 57, 57, 57, 57, 58, 58, 58, 58, 59, 59, 59, 59, 60, 60, 60,
+    60, 61, 61, 61, 61, 62, 62, 62, 62, 63, 63, 63, 63, 64, 64, 64, 64, 65, 65, 65, 65, 66, 66, 66,
+    66, 67, 67, 67, 67, 68, 68, 68, 68, 69, 69, 69, 69, 70, 70, 70, 70, 71, 71, 71, 71, 72, 72, 72,
+    72, 73, 73, 73, // 300
+    73, 73, 73, 73, 73, 74, 74, 74, 74, 75, 75, 75, 75, 76, 76, 76, 76, 77, 77, 77, 77, 78, 78, 78,
+    78, 79, 79, 79, 79, 80, 80, 80, 80, 81, 81, 81, 81, 82, 82, 82, 82, 83, 83, 83, 83, 84, 84, 84,
+    84, 85, 85, 85, 85, 86, 86, 86, 86, 87, 87, 87, 87, 88, 88, 88, 88, 89, 89, 89, 89, 90, 90, 90,
+    90, 91, 91, 91, 91, 92, 92, 92, 92, 93, 93, 93, 93, 94, 94, 94, 94, 95, 95, 95, 95, 96, 96, 96,
+    96, 97, 97, 97, 97, // 400+1
+];
+
+#[cfg(feature = "serde")]
+mod serde {
+    use super::NaiveDate;
+    use core::fmt;
+    use serde::{de, ser};
+
+    // TODO not very optimized for space (binary formats would want something better)
+
+    impl ser::Serialize for NaiveDate {
+        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+        where
+            S: ser::Serializer,
+        {
+            struct FormatWrapped<'a, D: 'a> {
+                inner: &'a D,
+            }
+
+            impl<D: fmt::Debug> fmt::Display for FormatWrapped<'_, D> {
+                fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+                    self.inner.fmt(f)
+                }
+            }
+
+            serializer.collect_str(&FormatWrapped { inner: &self })
+        }
+    }
+
+    struct NaiveDateVisitor;
+
+    impl de::Visitor<'_> for NaiveDateVisitor {
+        type Value = NaiveDate;
+
+        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+            formatter.write_str("a formatted date 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 NaiveDate {
+        fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+        where
+            D: de::Deserializer<'de>,
+        {
+            deserializer.deserialize_str(NaiveDateVisitor)
+        }
+    }
+
+    #[cfg(test)]
+    mod tests {
+        use crate::NaiveDate;
+
+        #[test]
+        fn test_serde_serialize() {
+            assert_eq!(
+                serde_json::to_string(&NaiveDate::from_ymd_opt(2014, 7, 24).unwrap()).ok(),
+                Some(r#""2014-07-24""#.into())
+            );
+            assert_eq!(
+                serde_json::to_string(&NaiveDate::from_ymd_opt(0, 1, 1).unwrap()).ok(),
+                Some(r#""0000-01-01""#.into())
+            );
+            assert_eq!(
+                serde_json::to_string(&NaiveDate::from_ymd_opt(-1, 12, 31).unwrap()).ok(),
+                Some(r#""-0001-12-31""#.into())
+            );
+            assert_eq!(
+                serde_json::to_string(&NaiveDate::MIN).ok(),
+                Some(r#""-262143-01-01""#.into())
+            );
+            assert_eq!(
+                serde_json::to_string(&NaiveDate::MAX).ok(),
+                Some(r#""+262142-12-31""#.into())
+            );
+        }
+
+        #[test]
+        fn test_serde_deserialize() {
+            let from_str = serde_json::from_str::<NaiveDate>;
+
+            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#""-262143-01-01""#).ok(), Some(NaiveDate::MIN));
+            assert_eq!(from_str(r#""+262142-12-31""#).ok(), Some(NaiveDate::MAX));
+
+            // bad formats
+            assert!(from_str(r#""""#).is_err());
+            assert!(from_str(r#""20001231""#).is_err());
+            assert!(from_str(r#""2000-00-00""#).is_err());
+            assert!(from_str(r#""2000-02-30""#).is_err());
+            assert!(from_str(r#""2001-02-29""#).is_err());
+            assert!(from_str(r#""2002-002-28""#).is_err());
+            assert!(from_str(r#""yyyy-mm-dd""#).is_err());
+            assert!(from_str(r#"0"#).is_err());
+            assert!(from_str(r#"20.01"#).is_err());
+            let min = i32::MIN.to_string();
+            assert!(from_str(&min).is_err());
+            let max = i32::MAX.to_string();
+            assert!(from_str(&max).is_err());
+            let min = i64::MIN.to_string();
+            assert!(from_str(&min).is_err());
+            let max = i64::MAX.to_string();
+            assert!(from_str(&max).is_err());
+            assert!(from_str(r#"{}"#).is_err());
+        }
+
+        #[test]
+        fn test_serde_bincode() {
+            // Bincode is relevant to test separately from JSON because
+            // it is not self-describing.
+            use bincode::{deserialize, serialize};
+
+            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);
+        }
+    }
+}
diff --git a/crates/chrono/src/naive/date/tests.rs b/crates/chrono/src/naive/date/tests.rs
new file mode 100644
index 0000000..6ae6867
--- /dev/null
+++ b/crates/chrono/src/naive/date/tests.rs
@@ -0,0 +1,877 @@
+use super::{Days, Months, NaiveDate, MAX_YEAR, MIN_YEAR};
+use crate::naive::internals::{YearFlags, A, AG, B, BA, C, CB, D, DC, E, ED, F, FE, G, GF};
+use crate::{Datelike, TimeDelta, Weekday};
+
+// 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_opt(MIN_YEAR, 1, 1).unwrap();
+    let calculated_max = NaiveDate::from_ymd_opt(MAX_YEAR, 12, 31).unwrap();
+    assert!(
+        NaiveDate::MIN == calculated_min,
+        "`NaiveDate::MIN` should have year flag {:?}",
+        calculated_min.year_flags()
+    );
+    assert!(
+        NaiveDate::MAX == calculated_max,
+        "`NaiveDate::MAX` should have year flag {:?} and ordinal {}",
+        calculated_max.year_flags(),
+        calculated_max.ordinal()
+    );
+
+    // let's also check that the entire range do not exceed 2^44 seconds
+    // (sometimes used for bounding `TimeDelta` against overflow)
+    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),
+        "The entire `NaiveDate` range somehow exceeds 2^{} seconds",
+        MAX_BITS
+    );
+
+    const BEFORE_MIN: NaiveDate = NaiveDate::BEFORE_MIN;
+    assert_eq!(BEFORE_MIN.year_flags(), YearFlags::from_year(BEFORE_MIN.year()));
+    assert_eq!((BEFORE_MIN.month(), BEFORE_MIN.day()), (12, 31));
+
+    const AFTER_MAX: NaiveDate = NaiveDate::AFTER_MAX;
+    assert_eq!(AFTER_MAX.year_flags(), YearFlags::from_year(AFTER_MAX.year()));
+    assert_eq!((AFTER_MAX.month(), AFTER_MAX.day()), (1, 1));
+}
+
+#[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.unsigned_abs() + 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() {
+    for y in NaiveDate::MIN.year()..=NaiveDate::MAX.year() {
+        // even months
+        let d4 = NaiveDate::from_ymd_opt(y, 4, 4).unwrap();
+        let d6 = NaiveDate::from_ymd_opt(y, 6, 6).unwrap();
+        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 from_ymd = NaiveDate::from_ymd_opt;
+
+    assert!(from_ymd(2012, 0, 1).is_none());
+    assert!(from_ymd(2012, 1, 1).is_some());
+    assert!(from_ymd(2012, 2, 29).is_some());
+    assert!(from_ymd(2014, 2, 29).is_none());
+    assert!(from_ymd(2014, 3, 0).is_none());
+    assert!(from_ymd(2014, 3, 1).is_some());
+    assert!(from_ymd(2014, 3, 31).is_some());
+    assert!(from_ymd(2014, 3, 32).is_none());
+    assert!(from_ymd(2014, 12, 31).is_some());
+    assert!(from_ymd(2014, 13, 1).is_none());
+}
+
+#[test]
+fn test_date_from_yo() {
+    let from_yo = NaiveDate::from_yo_opt;
+    let ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap();
+
+    assert_eq!(from_yo(2012, 0), None);
+    assert_eq!(from_yo(2012, 1), Some(ymd(2012, 1, 1)));
+    assert_eq!(from_yo(2012, 2), Some(ymd(2012, 1, 2)));
+    assert_eq!(from_yo(2012, 32), Some(ymd(2012, 2, 1)));
+    assert_eq!(from_yo(2012, 60), Some(ymd(2012, 2, 29)));
+    assert_eq!(from_yo(2012, 61), Some(ymd(2012, 3, 1)));
+    assert_eq!(from_yo(2012, 100), Some(ymd(2012, 4, 9)));
+    assert_eq!(from_yo(2012, 200), Some(ymd(2012, 7, 18)));
+    assert_eq!(from_yo(2012, 300), Some(ymd(2012, 10, 26)));
+    assert_eq!(from_yo(2012, 366), Some(ymd(2012, 12, 31)));
+    assert_eq!(from_yo(2012, 367), None);
+    assert_eq!(from_yo(2012, 1 << 28 | 60), None);
+
+    assert_eq!(from_yo(2014, 0), None);
+    assert_eq!(from_yo(2014, 1), Some(ymd(2014, 1, 1)));
+    assert_eq!(from_yo(2014, 2), Some(ymd(2014, 1, 2)));
+    assert_eq!(from_yo(2014, 32), Some(ymd(2014, 2, 1)));
+    assert_eq!(from_yo(2014, 59), Some(ymd(2014, 2, 28)));
+    assert_eq!(from_yo(2014, 60), Some(ymd(2014, 3, 1)));
+    assert_eq!(from_yo(2014, 100), Some(ymd(2014, 4, 10)));
+    assert_eq!(from_yo(2014, 200), Some(ymd(2014, 7, 19)));
+    assert_eq!(from_yo(2014, 300), Some(ymd(2014, 10, 27)));
+    assert_eq!(from_yo(2014, 365), Some(ymd(2014, 12, 31)));
+    assert_eq!(from_yo(2014, 366), None);
+}
+
+#[test]
+fn test_date_from_isoywd() {
+    let from_isoywd = NaiveDate::from_isoywd_opt;
+    let ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap();
+
+    assert_eq!(from_isoywd(2004, 0, Weekday::Sun), None);
+    assert_eq!(from_isoywd(2004, 1, Weekday::Mon), Some(ymd(2003, 12, 29)));
+    assert_eq!(from_isoywd(2004, 1, Weekday::Sun), Some(ymd(2004, 1, 4)));
+    assert_eq!(from_isoywd(2004, 2, Weekday::Mon), Some(ymd(2004, 1, 5)));
+    assert_eq!(from_isoywd(2004, 2, Weekday::Sun), Some(ymd(2004, 1, 11)));
+    assert_eq!(from_isoywd(2004, 52, Weekday::Mon), Some(ymd(2004, 12, 20)));
+    assert_eq!(from_isoywd(2004, 52, Weekday::Sun), Some(ymd(2004, 12, 26)));
+    assert_eq!(from_isoywd(2004, 53, Weekday::Mon), Some(ymd(2004, 12, 27)));
+    assert_eq!(from_isoywd(2004, 53, Weekday::Sun), Some(ymd(2005, 1, 2)));
+    assert_eq!(from_isoywd(2004, 54, Weekday::Mon), None);
+
+    assert_eq!(from_isoywd(2011, 0, Weekday::Sun), None);
+    assert_eq!(from_isoywd(2011, 1, Weekday::Mon), Some(ymd(2011, 1, 3)));
+    assert_eq!(from_isoywd(2011, 1, Weekday::Sun), Some(ymd(2011, 1, 9)));
+    assert_eq!(from_isoywd(2011, 2, Weekday::Mon), Some(ymd(2011, 1, 10)));
+    assert_eq!(from_isoywd(2011, 2, Weekday::Sun), Some(ymd(2011, 1, 16)));
+
+    assert_eq!(from_isoywd(2018, 51, Weekday::Mon), Some(ymd(2018, 12, 17)));
+    assert_eq!(from_isoywd(2018, 51, Weekday::Sun), Some(ymd(2018, 12, 23)));
+    assert_eq!(from_isoywd(2018, 52, Weekday::Mon), Some(ymd(2018, 12, 24)));
+    assert_eq!(from_isoywd(2018, 52, Weekday::Sun), Some(ymd(2018, 12, 30)));
+    assert_eq!(from_isoywd(2018, 53, Weekday::Mon), None);
+}
+
+#[test]
+fn test_date_from_isoywd_and_iso_week() {
+    for year in 2000..2401 {
+        for week in 1..54 {
+            for &weekday in [
+                Weekday::Mon,
+                Weekday::Tue,
+                Weekday::Wed,
+                Weekday::Thu,
+                Weekday::Fri,
+                Weekday::Sat,
+                Weekday::Sun,
+            ]
+            .iter()
+            {
+                let d = NaiveDate::from_isoywd_opt(year, week, weekday);
+                if let Some(d) = d {
+                    assert_eq!(d.weekday(), weekday);
+                    let w = d.iso_week();
+                    assert_eq!(w.year(), year);
+                    assert_eq!(w.week(), week);
+                }
+            }
+        }
+    }
+
+    for year in 2000..2401 {
+        for month in 1..13 {
+            for day in 1..32 {
+                let d = NaiveDate::from_ymd_opt(year, month, day);
+                if let Some(d) = d {
+                    let w = d.iso_week();
+                    let d_ = NaiveDate::from_isoywd_opt(w.year(), w.week(), d.weekday());
+                    assert_eq!(d, d_.unwrap());
+                }
+            }
+        }
+    }
+}
+
+#[test]
+fn test_date_from_num_days_from_ce() {
+    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(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);
+
+    assert_eq!(from_ndays_from_ce(i32::MIN), None);
+    assert_eq!(from_ndays_from_ce(i32::MAX), None);
+}
+
+#[test]
+fn test_date_from_weekday_of_month_opt() {
+    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_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_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_opt(year, ordinal).unwrap();
+        assert_eq!(d2.year(), year);
+        assert_eq!(d2.month(), month);
+        assert_eq!(d2.day(), day);
+        assert_eq!(d2.ordinal(), ordinal);
+
+        assert_eq!(d1, d2);
+    }
+
+    check(2012, 1, 1, 1);
+    check(2012, 1, 2, 2);
+    check(2012, 2, 1, 32);
+    check(2012, 2, 29, 60);
+    check(2012, 3, 1, 61);
+    check(2012, 4, 9, 100);
+    check(2012, 7, 18, 200);
+    check(2012, 10, 26, 300);
+    check(2012, 12, 31, 366);
+
+    check(2014, 1, 1, 1);
+    check(2014, 1, 2, 2);
+    check(2014, 2, 1, 32);
+    check(2014, 2, 28, 59);
+    check(2014, 3, 1, 60);
+    check(2014, 4, 10, 100);
+    check(2014, 7, 19, 200);
+    check(2014, 10, 27, 300);
+    check(2014, 12, 31, 365);
+}
+
+#[test]
+fn test_date_weekday() {
+    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_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_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_opt(1600, 2, 29).unwrap()));
+    assert_eq!(d.with_year(1900), None);
+    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_opt(2004, 2, 29).unwrap()));
+    assert_eq!(d.with_year(i32::MAX), None);
+
+    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_opt(2000, 1, 30).unwrap()));
+    assert_eq!(d.with_month(2), None);
+    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_opt(2000, 2, 8).unwrap();
+    assert_eq!(d.with_day(0), None);
+    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);
+}
+
+#[test]
+fn test_date_with_ordinal() {
+    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_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(1 << 28 | 60), None);
+    let d = NaiveDate::from_ymd_opt(1999, 5, 5).unwrap();
+    assert_eq!(d.with_ordinal(366), None);
+    assert_eq!(d.with_ordinal(u32::MAX), None);
+}
+
+#[test]
+fn test_date_num_days_from_ce() {
+    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_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_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(NaiveDate::MAX.year(), 12, 31).succ_opt(), None);
+}
+
+#[test]
+fn test_date_pred() {
+    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(NaiveDate::MIN.year(), 1, 1).pred_opt(), None);
+}
+
+#[test]
+fn test_date_checked_add_signed() {
+    fn check(lhs: Option<NaiveDate>, delta: TimeDelta, rhs: Option<NaiveDate>) {
+        assert_eq!(lhs.unwrap().checked_add_signed(delta), rhs);
+        assert_eq!(lhs.unwrap().checked_sub_signed(-delta), rhs);
+    }
+    let ymd = NaiveDate::from_ymd_opt;
+
+    check(ymd(2014, 1, 1), TimeDelta::zero(), ymd(2014, 1, 1));
+    check(ymd(2014, 1, 1), TimeDelta::try_seconds(86399).unwrap(), ymd(2014, 1, 1));
+    // always round towards zero
+    check(ymd(2014, 1, 1), TimeDelta::try_seconds(-86399).unwrap(), ymd(2014, 1, 1));
+    check(ymd(2014, 1, 1), TimeDelta::try_days(1).unwrap(), ymd(2014, 1, 2));
+    check(ymd(2014, 1, 1), TimeDelta::try_days(-1).unwrap(), ymd(2013, 12, 31));
+    check(ymd(2014, 1, 1), TimeDelta::try_days(364).unwrap(), ymd(2014, 12, 31));
+    check(ymd(2014, 1, 1), TimeDelta::try_days(365 * 4 + 1).unwrap(), ymd(2018, 1, 1));
+    check(ymd(2014, 1, 1), TimeDelta::try_days(365 * 400 + 97).unwrap(), ymd(2414, 1, 1));
+
+    check(ymd(-7, 1, 1), TimeDelta::try_days(365 * 12 + 3).unwrap(), ymd(5, 1, 1));
+
+    // overflow check
+    check(
+        ymd(0, 1, 1),
+        TimeDelta::try_days(MAX_DAYS_FROM_YEAR_0 as i64).unwrap(),
+        ymd(MAX_YEAR, 12, 31),
+    );
+    check(ymd(0, 1, 1), TimeDelta::try_days(MAX_DAYS_FROM_YEAR_0 as i64 + 1).unwrap(), None);
+    check(ymd(0, 1, 1), TimeDelta::MAX, None);
+    check(
+        ymd(0, 1, 1),
+        TimeDelta::try_days(MIN_DAYS_FROM_YEAR_0 as i64).unwrap(),
+        ymd(MIN_YEAR, 1, 1),
+    );
+    check(ymd(0, 1, 1), TimeDelta::try_days(MIN_DAYS_FROM_YEAR_0 as i64 - 1).unwrap(), None);
+    check(ymd(0, 1, 1), TimeDelta::MIN, None);
+}
+
+#[test]
+fn test_date_signed_duration_since() {
+    fn check(lhs: Option<NaiveDate>, rhs: Option<NaiveDate>, delta: TimeDelta) {
+        assert_eq!(lhs.unwrap().signed_duration_since(rhs.unwrap()), delta);
+        assert_eq!(rhs.unwrap().signed_duration_since(lhs.unwrap()), -delta);
+    }
+    let ymd = NaiveDate::from_ymd_opt;
+
+    check(ymd(2014, 1, 1), ymd(2014, 1, 1), TimeDelta::zero());
+    check(ymd(2014, 1, 2), ymd(2014, 1, 1), TimeDelta::try_days(1).unwrap());
+    check(ymd(2014, 12, 31), ymd(2014, 1, 1), TimeDelta::try_days(364).unwrap());
+    check(ymd(2015, 1, 3), ymd(2014, 1, 1), TimeDelta::try_days(365 + 2).unwrap());
+    check(ymd(2018, 1, 1), ymd(2014, 1, 1), TimeDelta::try_days(365 * 4 + 1).unwrap());
+    check(ymd(2414, 1, 1), ymd(2014, 1, 1), TimeDelta::try_days(365 * 400 + 97).unwrap());
+
+    check(
+        ymd(MAX_YEAR, 12, 31),
+        ymd(0, 1, 1),
+        TimeDelta::try_days(MAX_DAYS_FROM_YEAR_0 as i64).unwrap(),
+    );
+    check(
+        ymd(MIN_YEAR, 1, 1),
+        ymd(0, 1, 1),
+        TimeDelta::try_days(MIN_DAYS_FROM_YEAR_0 as i64).unwrap(),
+    );
+}
+
+#[test]
+fn test_date_add_days() {
+    fn check(lhs: Option<NaiveDate>, days: Days, rhs: Option<NaiveDate>) {
+        assert_eq!(lhs.unwrap().checked_add_days(days), rhs);
+    }
+    let ymd = NaiveDate::from_ymd_opt;
+
+    check(ymd(2014, 1, 1), Days::new(0), ymd(2014, 1, 1));
+    // always round towards zero
+    check(ymd(2014, 1, 1), Days::new(1), ymd(2014, 1, 2));
+    check(ymd(2014, 1, 1), Days::new(364), ymd(2014, 12, 31));
+    check(ymd(2014, 1, 1), Days::new(365 * 4 + 1), ymd(2018, 1, 1));
+    check(ymd(2014, 1, 1), Days::new(365 * 400 + 97), ymd(2414, 1, 1));
+
+    check(ymd(-7, 1, 1), Days::new(365 * 12 + 3), ymd(5, 1, 1));
+
+    // overflow check
+    check(ymd(0, 1, 1), Days::new(MAX_DAYS_FROM_YEAR_0.try_into().unwrap()), ymd(MAX_YEAR, 12, 31));
+    check(ymd(0, 1, 1), Days::new(u64::try_from(MAX_DAYS_FROM_YEAR_0).unwrap() + 1), None);
+}
+
+#[test]
+fn test_date_sub_days() {
+    fn check(lhs: Option<NaiveDate>, days: Days, rhs: Option<NaiveDate>) {
+        assert_eq!(lhs.unwrap().checked_sub_days(days), rhs);
+    }
+    let ymd = NaiveDate::from_ymd_opt;
+
+    check(ymd(2014, 1, 1), Days::new(0), ymd(2014, 1, 1));
+    check(ymd(2014, 1, 2), Days::new(1), ymd(2014, 1, 1));
+    check(ymd(2014, 12, 31), Days::new(364), ymd(2014, 1, 1));
+    check(ymd(2015, 1, 3), Days::new(365 + 2), ymd(2014, 1, 1));
+    check(ymd(2018, 1, 1), Days::new(365 * 4 + 1), ymd(2014, 1, 1));
+    check(ymd(2414, 1, 1), Days::new(365 * 400 + 97), ymd(2014, 1, 1));
+
+    check(ymd(MAX_YEAR, 12, 31), Days::new(MAX_DAYS_FROM_YEAR_0.try_into().unwrap()), ymd(0, 1, 1));
+    check(
+        ymd(0, 1, 1),
+        Days::new((-MIN_DAYS_FROM_YEAR_0).try_into().unwrap()),
+        ymd(MIN_YEAR, 1, 1),
+    );
+}
+
+#[test]
+fn test_date_addassignment() {
+    let ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap();
+    let mut date = ymd(2016, 10, 1);
+    date += TimeDelta::try_days(10).unwrap();
+    assert_eq!(date, ymd(2016, 10, 11));
+    date += TimeDelta::try_days(30).unwrap();
+    assert_eq!(date, ymd(2016, 11, 10));
+}
+
+#[test]
+fn test_date_subassignment() {
+    let ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap();
+    let mut date = ymd(2016, 10, 11);
+    date -= TimeDelta::try_days(10).unwrap();
+    assert_eq!(date, ymd(2016, 10, 1));
+    date -= TimeDelta::try_days(2).unwrap();
+    assert_eq!(date, ymd(2016, 9, 29));
+}
+
+#[test]
+fn test_date_fmt() {
+    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_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_opt(1234, 5, 6).unwrap()), "1234-05-06");
+    assert_eq!(format!("{:30?}", NaiveDate::from_ymd_opt(12345, 6, 7).unwrap()), "+12345-06-07");
+}
+
+#[test]
+fn test_date_from_str() {
+    // valid cases
+    let valid = [
+        "-0000000123456-1-2",
+        "    -123456 - 1 - 2    ",
+        "-12345-1-2",
+        "-1234-12-31",
+        "-7-6-5",
+        "350-2-28",
+        "360-02-29",
+        "0360-02-29",
+        "2015-2 -18",
+        "2015-02-18",
+        "+70-2-18",
+        "+70000-2-18",
+        "+00007-2-18",
+    ];
+    for &s in &valid {
+        eprintln!("test_date_from_str valid {:?}", s);
+        let d = match s.parse::<NaiveDate>() {
+            Ok(d) => d,
+            Err(e) => panic!("parsing `{}` has failed: {}", s, e),
+        };
+        eprintln!("d {:?} (NaiveDate)", d);
+        let s_ = format!("{:?}", d);
+        eprintln!("s_ {:?}", s_);
+        // `s` and `s_` may differ, but `s.parse()` and `s_.parse()` must be same
+        let d_ = match s_.parse::<NaiveDate>() {
+            Ok(d) => d,
+            Err(e) => {
+                panic!("`{}` is parsed into `{:?}`, but reparsing that has failed: {}", s, d, e)
+            }
+        };
+        eprintln!("d_ {:?} (NaiveDate)", d_);
+        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
+    let invalid = [
+        "",                     // empty
+        "x",                    // invalid
+        "Fri, 09 Aug 2013 GMT", // valid date, wrong format
+        "Sat Jun 30 2012",      // valid date, wrong format
+        "1441497364.649",       // valid datetime, wrong format
+        "+1441497364.649",      // valid datetime, wrong format
+        "+1441497364",          // valid datetime, wrong format
+        "2014/02/03",           // valid date, wrong format
+        "2014",                 // datetime missing data
+        "2014-01",              // datetime missing data
+        "2014-01-00",           // invalid day
+        "2014-11-32",           // invalid day
+        "2014-13-01",           // invalid month
+        "2014-13-57",           // invalid month, day
+        "9999999-9-9",          // invalid year (out of bounds)
+    ];
+    for &s in &invalid {
+        eprintln!("test_date_from_str invalid {:?}", s);
+        assert!(s.parse::<NaiveDate>().is_err());
+    }
+}
+
+#[test]
+fn test_date_parse_from_str() {
+    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))
+    ); // ignore time and offset
+    assert_eq!(
+        NaiveDate::parse_from_str("2015-W06-1=2015-033", "%G-W%V-%u = %Y-%j"),
+        Ok(ymd(2015, 2, 2))
+    );
+    assert_eq!(NaiveDate::parse_from_str("Fri, 09 Aug 13", "%a, %d %b %y"), Ok(ymd(2013, 8, 9)));
+    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_day_iterator_limit() {
+    assert_eq!(NaiveDate::from_ymd_opt(MAX_YEAR, 12, 29).unwrap().iter_days().take(4).count(), 2);
+    assert_eq!(
+        NaiveDate::from_ymd_opt(MIN_YEAR, 1, 3).unwrap().iter_days().rev().take(4).count(),
+        2
+    );
+}
+
+#[test]
+fn test_week_iterator_limit() {
+    assert_eq!(NaiveDate::from_ymd_opt(MAX_YEAR, 12, 12).unwrap().iter_weeks().take(4).count(), 2);
+    assert_eq!(
+        NaiveDate::from_ymd_opt(MIN_YEAR, 1, 15).unwrap().iter_weeks().rev().take(4).count(),
+        2
+    );
+}
+
+#[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)
+        }
+    }
+}
+
+#[test]
+fn test_with_0_overflow() {
+    let dt = NaiveDate::from_ymd_opt(2023, 4, 18).unwrap();
+    assert!(dt.with_month0(4294967295).is_none());
+    assert!(dt.with_day0(4294967295).is_none());
+    assert!(dt.with_ordinal0(4294967295).is_none());
+}
+
+#[test]
+fn test_leap_year() {
+    for year in 0..=MAX_YEAR {
+        let date = NaiveDate::from_ymd_opt(year, 1, 1).unwrap();
+        let is_leap = year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
+        assert_eq!(date.leap_year(), is_leap);
+        assert_eq!(date.leap_year(), date.with_ordinal(366).is_some());
+    }
+}
+
+#[test]
+fn test_date_yearflags() {
+    for (year, year_flags, _) in YEAR_FLAGS {
+        assert_eq!(NaiveDate::from_yo_opt(year, 1).unwrap().year_flags(), year_flags);
+    }
+}
+
+#[test]
+fn test_weekday_with_yearflags() {
+    for (year, year_flags, first_weekday) in YEAR_FLAGS {
+        let first_day_of_year = NaiveDate::from_yo_opt(year, 1).unwrap();
+        dbg!(year);
+        assert_eq!(first_day_of_year.year_flags(), year_flags);
+        assert_eq!(first_day_of_year.weekday(), first_weekday);
+
+        let mut prev = first_day_of_year.weekday();
+        for ordinal in 2u32..=year_flags.ndays() {
+            let date = NaiveDate::from_yo_opt(year, ordinal).unwrap();
+            let expected = prev.succ();
+            assert_eq!(date.weekday(), expected);
+            prev = expected;
+        }
+    }
+}
+
+#[test]
+fn test_isoweekdate_with_yearflags() {
+    for (year, year_flags, _) in YEAR_FLAGS {
+        // January 4 should be in the first week
+        let jan4 = NaiveDate::from_ymd_opt(year, 1, 4).unwrap();
+        let iso_week = jan4.iso_week();
+        assert_eq!(jan4.year_flags(), year_flags);
+        assert_eq!(iso_week.week(), 1);
+    }
+}
+
+#[test]
+fn test_date_to_mdf_to_date() {
+    for (year, year_flags, _) in YEAR_FLAGS {
+        for ordinal in 1..=year_flags.ndays() {
+            let date = NaiveDate::from_yo_opt(year, ordinal).unwrap();
+            assert_eq!(date, NaiveDate::from_mdf(date.year(), date.mdf()).unwrap());
+        }
+    }
+}
+
+// Used for testing some methods with all combinations of `YearFlags`.
+// (year, flags, first weekday of year)
+const YEAR_FLAGS: [(i32, YearFlags, Weekday); 14] = [
+    (2006, A, Weekday::Sun),
+    (2005, B, Weekday::Sat),
+    (2010, C, Weekday::Fri),
+    (2009, D, Weekday::Thu),
+    (2003, E, Weekday::Wed),
+    (2002, F, Weekday::Tue),
+    (2001, G, Weekday::Mon),
+    (2012, AG, Weekday::Sun),
+    (2000, BA, Weekday::Sat),
+    (2016, CB, Weekday::Fri),
+    (2004, DC, Weekday::Thu),
+    (2020, ED, Weekday::Wed),
+    (2008, FE, Weekday::Tue),
+    (2024, GF, Weekday::Mon),
+];
+
+#[test]
+#[cfg(feature = "rkyv-validation")]
+fn test_rkyv_validation() {
+    let date_min = NaiveDate::MIN;
+    let bytes = rkyv::to_bytes::<_, 4>(&date_min).unwrap();
+    assert_eq!(rkyv::from_bytes::<NaiveDate>(&bytes).unwrap(), date_min);
+
+    let date_max = NaiveDate::MAX;
+    let bytes = rkyv::to_bytes::<_, 4>(&date_max).unwrap();
+    assert_eq!(rkyv::from_bytes::<NaiveDate>(&bytes).unwrap(), date_max);
+}
+
+//   MAX_YEAR-12-31 minus 0000-01-01
+// = (MAX_YEAR-12-31 minus 0000-12-31) + (0000-12-31 - 0000-01-01)
+// = MAX_YEAR * 365 + (# of leap years from 0001 to MAX_YEAR) + 365
+// = (MAX_YEAR + 1) * 365 + (# of leap years from 0001 to MAX_YEAR)
+const MAX_DAYS_FROM_YEAR_0: i32 =
+    (MAX_YEAR + 1) * 365 + MAX_YEAR / 4 - MAX_YEAR / 100 + MAX_YEAR / 400;
+
+//   MIN_YEAR-01-01 minus 0000-01-01
+// = MIN_YEAR * 365 + (# of leap years from MIN_YEAR to 0000)
+const MIN_DAYS_FROM_YEAR_0: i32 = MIN_YEAR * 365 + MIN_YEAR / 4 - MIN_YEAR / 100 + MIN_YEAR / 400;
+
+// only used for testing, but duplicated in naive::datetime
+const MAX_BITS: usize = 44;
diff --git a/crates/chrono/src/naive/datetime/mod.rs b/crates/chrono/src/naive/datetime/mod.rs
index d767483..a2ffc69 100644
--- a/crates/chrono/src/naive/datetime/mod.rs
+++ b/crates/chrono/src/naive/datetime/mod.rs
@@ -21,11 +21,9 @@
 use crate::offset::Utc;
 use crate::time_delta::NANOS_PER_SEC;
 use crate::{
-    expect, try_opt, DateTime, Datelike, FixedOffset, LocalResult, Months, TimeDelta, TimeZone,
+    expect, try_opt, DateTime, Datelike, FixedOffset, MappedLocalTime, Months, TimeDelta, TimeZone,
     Timelike, Weekday,
 };
-#[cfg(feature = "rustc-serialize")]
-pub(super) mod rustc_serialize;
 
 /// Tools to help serializing/deserializing `NaiveDateTime`s
 #[cfg(feature = "serde")]
@@ -34,14 +32,6 @@
 #[cfg(test)]
 mod tests;
 
-/// The tight upper bound guarantees that a time delta with `|TimeDelta| >= 2^MAX_SECS_BITS`
-/// will always overflow the addition with any date and time type.
-///
-/// So why is this needed? `TimeDelta::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`.
 #[deprecated(since = "0.4.20", note = "Use NaiveDateTime::MIN instead")]
 pub const MIN_DATETIME: NaiveDateTime = NaiveDateTime::MIN;
@@ -58,7 +48,8 @@
 /// ```
 /// use chrono::{NaiveDate, NaiveDateTime};
 ///
-/// let dt: NaiveDateTime = NaiveDate::from_ymd_opt(2016, 7, 8).unwrap().and_hms_opt(9, 10, 11).unwrap();
+/// let dt: NaiveDateTime =
+///     NaiveDate::from_ymd_opt(2016, 7, 8).unwrap().and_hms_opt(9, 10, 11).unwrap();
 /// # let _ = dt;
 /// ```
 ///
@@ -95,7 +86,7 @@
     /// # Example
     ///
     /// ```
-    /// use chrono::{NaiveDate, NaiveTime, NaiveDateTime};
+    /// use chrono::{NaiveDate, NaiveDateTime, NaiveTime};
     ///
     /// let d = NaiveDate::from_ymd_opt(2015, 6, 3).unwrap();
     /// let t = NaiveTime::from_hms_milli_opt(12, 34, 56, 789).unwrap();
@@ -125,12 +116,13 @@
     /// Panics if the number of seconds would be out of range for a `NaiveDateTime` (more than
     /// ca. 262,000 years away from common era), and panics on an invalid nanosecond (2 seconds or
     /// more).
-    #[deprecated(since = "0.4.23", note = "use `from_timestamp_opt()` instead")]
+    #[deprecated(since = "0.4.23", note = "use `DateTime::from_timestamp` instead")]
     #[inline]
     #[must_use]
     pub const fn from_timestamp(secs: i64, nsecs: u32) -> NaiveDateTime {
-        let datetime = NaiveDateTime::from_timestamp_opt(secs, nsecs);
-        expect!(datetime, "invalid or out-of-range datetime")
+        let datetime =
+            expect(DateTime::from_timestamp(secs, nsecs), "invalid or out-of-range datetime");
+        datetime.naive_utc()
     }
 
     /// Creates a new [NaiveDateTime] from milliseconds since the UNIX epoch.
@@ -141,28 +133,11 @@
     ///
     /// Returns `None` if the number of milliseconds would be out of range for a `NaiveDateTime`
     /// (more than ca. 262,000 years away from common era)
-    ///
-    /// # 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());
-    /// ```
+    #[deprecated(since = "0.4.35", note = "use `DateTime::from_timestamp_millis` instead")]
     #[inline]
     #[must_use]
     pub const fn from_timestamp_millis(millis: i64) -> Option<NaiveDateTime> {
-        let secs = millis.div_euclid(1000);
-        let nsecs = millis.rem_euclid(1000) as u32 * 1_000_000;
-        NaiveDateTime::from_timestamp_opt(secs, nsecs)
+        Some(try_opt!(DateTime::from_timestamp_millis(millis)).naive_utc())
     }
 
     /// Creates a new [NaiveDateTime] from microseconds since the UNIX epoch.
@@ -173,28 +148,13 @@
     ///
     /// Returns `None` if the number of microseconds would be out of range for a `NaiveDateTime`
     /// (more than ca. 262,000 years away from common era)
-    ///
-    /// # 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());
-    /// ```
+    #[deprecated(since = "0.4.35", note = "use `DateTime::from_timestamp_micros` instead")]
     #[inline]
     #[must_use]
     pub const fn from_timestamp_micros(micros: i64) -> Option<NaiveDateTime> {
         let secs = micros.div_euclid(1_000_000);
         let nsecs = micros.rem_euclid(1_000_000) as u32 * 1000;
-        NaiveDateTime::from_timestamp_opt(secs, nsecs)
+        Some(try_opt!(DateTime::<Utc>::from_timestamp(secs, nsecs)).naive_utc())
     }
 
     /// Creates a new [NaiveDateTime] from nanoseconds since the UNIX epoch.
@@ -205,29 +165,13 @@
     ///
     /// Returns `None` if the number of nanoseconds would be out of range for a `NaiveDateTime`
     /// (more than ca. 262,000 years away from common era)
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// use chrono::NaiveDateTime;
-    /// let timestamp_nanos: i64 = 1662921288_000_000_000; //Sunday, September 11, 2022 6:34:48 PM
-    /// let naive_datetime = NaiveDateTime::from_timestamp_nanos(timestamp_nanos);
-    /// assert!(naive_datetime.is_some());
-    /// assert_eq!(timestamp_nanos, naive_datetime.unwrap().timestamp_nanos_opt().unwrap());
-    ///
-    /// // Negative timestamps (before the UNIX epoch) are supported as well.
-    /// let timestamp_nanos: i64 = -2208936075_000_000_000; //Mon Jan 01 1900 14:38:45 GMT+0000
-    /// let naive_datetime = NaiveDateTime::from_timestamp_nanos(timestamp_nanos);
-    /// assert!(naive_datetime.is_some());
-    /// assert_eq!(timestamp_nanos, naive_datetime.unwrap().timestamp_nanos_opt().unwrap());
-    /// ```
+    #[deprecated(since = "0.4.35", note = "use `DateTime::from_timestamp_nanos` instead")]
     #[inline]
     #[must_use]
     pub const fn from_timestamp_nanos(nanos: i64) -> Option<NaiveDateTime> {
         let secs = nanos.div_euclid(NANOS_PER_SEC as i64);
         let nsecs = nanos.rem_euclid(NANOS_PER_SEC as i64) as u32;
-
-        NaiveDateTime::from_timestamp_opt(secs, nsecs)
+        Some(try_opt!(DateTime::from_timestamp(secs, nsecs)).naive_utc())
     }
 
     /// Makes a new `NaiveDateTime` corresponding to a UTC date and time,
@@ -244,37 +188,11 @@
     /// Returns `None` if the number of seconds would be out of range for a `NaiveDateTime` (more
     /// than ca. 262,000 years away from common era), and panics on an invalid nanosecond
     /// (2 seconds or more).
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// use chrono::NaiveDateTime;
-    /// 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_none()); // invalid leap second
-    /// assert!(from_timestamp_opt(59, 1_500_000_000).is_some()); // leap second
-    /// assert!(from_timestamp_opt(59, 2_000_000_000).is_none());
-    /// assert!(from_timestamp_opt(i64::MAX, 0).is_none());
-    /// ```
+    #[deprecated(since = "0.4.35", note = "use `DateTime::from_timestamp` instead")]
     #[inline]
     #[must_use]
     pub const fn from_timestamp_opt(secs: i64, nsecs: u32) -> Option<NaiveDateTime> {
-        let days = secs.div_euclid(86_400);
-        let secs = secs.rem_euclid(86_400);
-        if days < i32::MIN as i64 || days > i32::MAX as i64 {
-            return None;
-        }
-        let date =
-            NaiveDate::from_num_days_from_ce_opt(try_opt!((days as i32).checked_add(719_163)));
-        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,
-        }
+        Some(try_opt!(DateTime::from_timestamp(secs, nsecs)).naive_utc())
     }
 
     /// Parses a string with the specified format string and returns a new `NaiveDateTime`.
@@ -284,14 +202,21 @@
     /// # Example
     ///
     /// ```
-    /// use chrono::{NaiveDateTime, NaiveDate};
+    /// use chrono::{NaiveDate, NaiveDateTime};
     ///
     /// 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()));
+    /// 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.
@@ -299,8 +224,10 @@
     /// ```
     /// # 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()));
+    /// 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
@@ -310,8 +237,13 @@
     /// ```
     /// # 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()));
+    /// 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,
@@ -320,8 +252,10 @@
     /// ```
     /// # 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_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());
@@ -347,7 +281,7 @@
     /// 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))?;
@@ -366,7 +300,10 @@
     /// ```rust
     /// # use chrono::{NaiveDate, NaiveDateTime};
     /// let (datetime, remainder) = NaiveDateTime::parse_and_remainder(
-    ///     "2015-02-18 23:16:09 trailing text", "%Y-%m-%d %H:%M:%S").unwrap();
+    ///     "2015-02-18 23:16:09 trailing text",
+    ///     "%Y-%m-%d %H:%M:%S",
+    /// )
+    /// .unwrap();
     /// assert_eq!(
     ///     datetime,
     ///     NaiveDate::from_ymd_opt(2015, 2, 18).unwrap().and_hms_opt(23, 16, 9).unwrap()
@@ -413,80 +350,33 @@
     ///
     /// 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);
-    /// ```
+    #[deprecated(since = "0.4.35", note = "use `.and_utc().timestamp()` instead")]
     #[inline]
     #[must_use]
     pub const fn timestamp(&self) -> i64 {
-        const UNIX_EPOCH_DAY: i64 = 719_163;
-        let gregorian_day = self.date.num_days_from_ce() as i64;
-        let seconds_from_midnight = self.time.num_seconds_from_midnight() as i64;
-        (gregorian_day - UNIX_EPOCH_DAY) * 86_400 + seconds_from_midnight
+        self.and_utc().timestamp()
     }
 
     /// 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.
-    ///
-    /// # 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);
-    /// ```
+    #[deprecated(since = "0.4.35", note = "use `.and_utc().timestamp_millis()` instead")]
     #[inline]
     #[must_use]
     pub const fn timestamp_millis(&self) -> i64 {
-        let as_ms = self.timestamp() * 1000;
-        as_ms + self.timestamp_subsec_millis() as i64
+        self.and_utc().timestamp_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.
-    ///
-    /// # 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);
-    /// ```
+    #[deprecated(since = "0.4.35", note = "use `.and_utc().timestamp_micros()` instead")]
     #[inline]
     #[must_use]
     pub const fn timestamp_micros(&self) -> i64 {
-        let as_us = self.timestamp() * 1_000_000;
-        as_us + self.timestamp_subsec_micros() as i64
+        self.and_utc().timestamp_micros()
     }
 
     /// Returns the number of non-leap *nanoseconds* since midnight on January 1, 1970.
@@ -501,14 +391,12 @@
     ///
     /// The dates that can be represented as nanoseconds are between 1677-09-21T00:12:43.145224192
     /// and 2262-04-11T23:47:16.854775807.
-    #[deprecated(since = "0.4.31", note = "use `timestamp_nanos_opt()` instead")]
+    #[deprecated(since = "0.4.31", note = "use `.and_utc().timestamp_nanos_opt()` instead")]
     #[inline]
     #[must_use]
+    #[allow(deprecated)]
     pub const fn timestamp_nanos(&self) -> i64 {
-        expect!(
-            self.timestamp_nanos_opt(),
-            "value can not be represented in a timestamp with nanosecond precision."
-        )
+        self.and_utc().timestamp_nanos()
     }
 
     /// Returns the number of non-leap *nanoseconds* since midnight on January 1, 1970.
@@ -523,114 +411,42 @@
     ///
     /// The dates that can be represented as nanoseconds are between 1677-09-21T00:12:43.145224192
     /// and 2262-04-11T23:47:16.854775807.
-    ///
-    /// # 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_opt(), Some(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_opt().unwrap();
-    /// assert_eq!(nanos, 1_000_000_000_000_000_555);
-    /// assert_eq!(
-    ///     Some(dt),
-    ///     NaiveDateTime::from_timestamp_opt(nanos / A_BILLION, (nanos % A_BILLION) as u32)
-    /// );
-    /// ```
+    #[deprecated(since = "0.4.35", note = "use `.and_utc().timestamp_nanos_opt()` instead")]
     #[inline]
     #[must_use]
     pub const fn timestamp_nanos_opt(&self) -> Option<i64> {
-        let mut timestamp = self.timestamp();
-        let mut timestamp_subsec_nanos = self.timestamp_subsec_nanos() as i64;
-
-        // subsec nanos are always non-negative, however the timestamp itself (both in seconds and in nanos) can be
-        // negative. Now i64::MIN is NOT dividable by 1_000_000_000, so
-        //
-        //   (timestamp * 1_000_000_000) + nanos
-        //
-        // may underflow (even when in theory we COULD represent the datetime as i64) because we add the non-negative
-        // nanos AFTER the multiplication. This is fixed by converting the negative case to
-        //
-        //   ((timestamp + 1) * 1_000_000_000) + (ns - 1_000_000_000)
-        //
-        // Also see <https://github.com/chronotope/chrono/issues/1289>.
-        if timestamp < 0 && timestamp_subsec_nanos > 0 {
-            timestamp_subsec_nanos -= 1_000_000_000;
-            timestamp += 1;
-        }
-
-        try_opt!(timestamp.checked_mul(1_000_000_000)).checked_add(timestamp_subsec_nanos)
+        self.and_utc().timestamp_nanos_opt()
     }
 
     /// 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);
-    /// ```
+    #[deprecated(since = "0.4.35", note = "use `.and_utc().timestamp_subsec_millis()` instead")]
     #[inline]
     #[must_use]
     pub const fn timestamp_subsec_millis(&self) -> u32 {
-        self.timestamp_subsec_nanos() / 1_000_000
+        self.and_utc().timestamp_subsec_millis()
     }
 
     /// 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);
-    /// ```
+    #[deprecated(since = "0.4.35", note = "use `.and_utc().timestamp_subsec_micros()` instead")]
     #[inline]
     #[must_use]
     pub const fn timestamp_subsec_micros(&self) -> u32 {
-        self.timestamp_subsec_nanos() / 1_000
+        self.and_utc().timestamp_subsec_micros()
     }
 
     /// 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]
-    #[must_use]
+    #[deprecated(since = "0.4.36", note = "use `.and_utc().timestamp_subsec_nanos()` instead")]
     pub const fn timestamp_subsec_nanos(&self) -> u32 {
-        self.time.nanosecond()
+        self.and_utc().timestamp_subsec_nanos()
     }
 
     /// Adds given `TimeDelta` to the current date and time.
@@ -647,26 +463,35 @@
     /// # Example
     ///
     /// ```
-    /// use chrono::{TimeDelta, NaiveDate};
+    /// use chrono::{NaiveDate, TimeDelta};
     ///
     /// let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap();
     ///
     /// let d = from_ymd(2016, 7, 8);
     /// let hms = |h, m, s| d.and_hms_opt(h, m, s).unwrap();
-    /// assert_eq!(hms(3, 5, 7).checked_add_signed(TimeDelta::zero()),
-    ///            Some(hms(3, 5, 7)));
-    /// assert_eq!(hms(3, 5, 7).checked_add_signed(TimeDelta::seconds(1)),
-    ///            Some(hms(3, 5, 8)));
-    /// assert_eq!(hms(3, 5, 7).checked_add_signed(TimeDelta::seconds(-1)),
-    ///            Some(hms(3, 5, 6)));
-    /// assert_eq!(hms(3, 5, 7).checked_add_signed(TimeDelta::seconds(3600 + 60)),
-    ///            Some(hms(4, 6, 7)));
-    /// assert_eq!(hms(3, 5, 7).checked_add_signed(TimeDelta::seconds(86_400)),
-    ///            Some(from_ymd(2016, 7, 9).and_hms_opt(3, 5, 7).unwrap()));
+    /// assert_eq!(hms(3, 5, 7).checked_add_signed(TimeDelta::zero()), Some(hms(3, 5, 7)));
+    /// assert_eq!(
+    ///     hms(3, 5, 7).checked_add_signed(TimeDelta::try_seconds(1).unwrap()),
+    ///     Some(hms(3, 5, 8))
+    /// );
+    /// assert_eq!(
+    ///     hms(3, 5, 7).checked_add_signed(TimeDelta::try_seconds(-1).unwrap()),
+    ///     Some(hms(3, 5, 6))
+    /// );
+    /// assert_eq!(
+    ///     hms(3, 5, 7).checked_add_signed(TimeDelta::try_seconds(3600 + 60).unwrap()),
+    ///     Some(hms(4, 6, 7))
+    /// );
+    /// assert_eq!(
+    ///     hms(3, 5, 7).checked_add_signed(TimeDelta::try_seconds(86_400).unwrap()),
+    ///     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(TimeDelta::milliseconds(450)),
-    ///            Some(hmsm(3, 5, 8, 430)));
+    /// assert_eq!(
+    ///     hmsm(3, 5, 7, 980).checked_add_signed(TimeDelta::try_milliseconds(450).unwrap()),
+    ///     Some(hmsm(3, 5, 8, 430))
+    /// );
     /// ```
     ///
     /// Overflow returns `None`.
@@ -674,7 +499,7 @@
     /// ```
     /// # use chrono::{TimeDelta, 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(TimeDelta::days(1_000_000_000)), None);
+    /// assert_eq!(hms(3, 5, 7).checked_add_signed(TimeDelta::try_days(1_000_000_000).unwrap()), None);
     /// ```
     ///
     /// Leap seconds are handled,
@@ -687,29 +512,24 @@
     /// let leap = hmsm(3, 5, 59, 1_300);
     /// assert_eq!(leap.checked_add_signed(TimeDelta::zero()),
     ///            Some(hmsm(3, 5, 59, 1_300)));
-    /// assert_eq!(leap.checked_add_signed(TimeDelta::milliseconds(-500)),
+    /// assert_eq!(leap.checked_add_signed(TimeDelta::try_milliseconds(-500).unwrap()),
     ///            Some(hmsm(3, 5, 59, 800)));
-    /// assert_eq!(leap.checked_add_signed(TimeDelta::milliseconds(500)),
+    /// assert_eq!(leap.checked_add_signed(TimeDelta::try_milliseconds(500).unwrap()),
     ///            Some(hmsm(3, 5, 59, 1_800)));
-    /// assert_eq!(leap.checked_add_signed(TimeDelta::milliseconds(800)),
+    /// assert_eq!(leap.checked_add_signed(TimeDelta::try_milliseconds(800).unwrap()),
     ///            Some(hmsm(3, 6, 0, 100)));
-    /// assert_eq!(leap.checked_add_signed(TimeDelta::seconds(10)),
+    /// assert_eq!(leap.checked_add_signed(TimeDelta::try_seconds(10).unwrap()),
     ///            Some(hmsm(3, 6, 9, 300)));
-    /// assert_eq!(leap.checked_add_signed(TimeDelta::seconds(-10)),
+    /// assert_eq!(leap.checked_add_signed(TimeDelta::try_seconds(-10).unwrap()),
     ///            Some(hmsm(3, 5, 50, 300)));
-    /// assert_eq!(leap.checked_add_signed(TimeDelta::days(1)),
+    /// assert_eq!(leap.checked_add_signed(TimeDelta::try_days(1).unwrap()),
     ///            Some(from_ymd(2016, 7, 9).and_hms_milli_opt(3, 5, 59, 300).unwrap()));
     /// ```
     #[must_use]
     pub const fn checked_add_signed(self, rhs: TimeDelta) -> Option<NaiveDateTime> {
-        let (time, rhs) = self.time.overflowing_add_signed(rhs);
-
-        // early checking to avoid overflow in TimeDelta::seconds
-        if rhs <= (-1 << MAX_SECS_BITS) || rhs >= (1 << MAX_SECS_BITS) {
-            return None;
-        }
-
-        let date = try_opt!(self.date.checked_add_signed(TimeDelta::seconds(rhs)));
+        let (time, remainder) = self.time.overflowing_add_signed(rhs);
+        let remainder = try_opt!(TimeDelta::try_seconds(remainder));
+        let date = try_opt!(self.date.checked_add_signed(remainder));
         Some(NaiveDateTime { date, time })
     }
 
@@ -727,13 +547,19 @@
     /// use chrono::{Months, NaiveDate};
     ///
     /// assert_eq!(
-    ///     NaiveDate::from_ymd_opt(2014, 1, 1).unwrap().and_hms_opt(1, 0, 0).unwrap()
+    ///     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()
+    ///     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
     /// );
@@ -821,26 +647,35 @@
     /// # Example
     ///
     /// ```
-    /// use chrono::{TimeDelta, NaiveDate};
+    /// use chrono::{NaiveDate, TimeDelta};
     ///
     /// let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap();
     ///
     /// let d = from_ymd(2016, 7, 8);
     /// let hms = |h, m, s| d.and_hms_opt(h, m, s).unwrap();
-    /// assert_eq!(hms(3, 5, 7).checked_sub_signed(TimeDelta::zero()),
-    ///            Some(hms(3, 5, 7)));
-    /// assert_eq!(hms(3, 5, 7).checked_sub_signed(TimeDelta::seconds(1)),
-    ///            Some(hms(3, 5, 6)));
-    /// assert_eq!(hms(3, 5, 7).checked_sub_signed(TimeDelta::seconds(-1)),
-    ///            Some(hms(3, 5, 8)));
-    /// assert_eq!(hms(3, 5, 7).checked_sub_signed(TimeDelta::seconds(3600 + 60)),
-    ///            Some(hms(2, 4, 7)));
-    /// assert_eq!(hms(3, 5, 7).checked_sub_signed(TimeDelta::seconds(86_400)),
-    ///            Some(from_ymd(2016, 7, 7).and_hms_opt(3, 5, 7).unwrap()));
+    /// assert_eq!(hms(3, 5, 7).checked_sub_signed(TimeDelta::zero()), Some(hms(3, 5, 7)));
+    /// assert_eq!(
+    ///     hms(3, 5, 7).checked_sub_signed(TimeDelta::try_seconds(1).unwrap()),
+    ///     Some(hms(3, 5, 6))
+    /// );
+    /// assert_eq!(
+    ///     hms(3, 5, 7).checked_sub_signed(TimeDelta::try_seconds(-1).unwrap()),
+    ///     Some(hms(3, 5, 8))
+    /// );
+    /// assert_eq!(
+    ///     hms(3, 5, 7).checked_sub_signed(TimeDelta::try_seconds(3600 + 60).unwrap()),
+    ///     Some(hms(2, 4, 7))
+    /// );
+    /// assert_eq!(
+    ///     hms(3, 5, 7).checked_sub_signed(TimeDelta::try_seconds(86_400).unwrap()),
+    ///     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(TimeDelta::milliseconds(670)),
-    ///            Some(hmsm(3, 5, 6, 780)));
+    /// assert_eq!(
+    ///     hmsm(3, 5, 7, 450).checked_sub_signed(TimeDelta::try_milliseconds(670).unwrap()),
+    ///     Some(hmsm(3, 5, 6, 780))
+    /// );
     /// ```
     ///
     /// Overflow returns `None`.
@@ -848,7 +683,7 @@
     /// ```
     /// # use chrono::{TimeDelta, 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(TimeDelta::days(1_000_000_000)), None);
+    /// assert_eq!(hms(3, 5, 7).checked_sub_signed(TimeDelta::try_days(1_000_000_000).unwrap()), None);
     /// ```
     ///
     /// Leap seconds are handled,
@@ -861,25 +696,20 @@
     /// let leap = hmsm(3, 5, 59, 1_300);
     /// assert_eq!(leap.checked_sub_signed(TimeDelta::zero()),
     ///            Some(hmsm(3, 5, 59, 1_300)));
-    /// assert_eq!(leap.checked_sub_signed(TimeDelta::milliseconds(200)),
+    /// assert_eq!(leap.checked_sub_signed(TimeDelta::try_milliseconds(200).unwrap()),
     ///            Some(hmsm(3, 5, 59, 1_100)));
-    /// assert_eq!(leap.checked_sub_signed(TimeDelta::milliseconds(500)),
+    /// assert_eq!(leap.checked_sub_signed(TimeDelta::try_milliseconds(500).unwrap()),
     ///            Some(hmsm(3, 5, 59, 800)));
-    /// assert_eq!(leap.checked_sub_signed(TimeDelta::seconds(60)),
+    /// assert_eq!(leap.checked_sub_signed(TimeDelta::try_seconds(60).unwrap()),
     ///            Some(hmsm(3, 5, 0, 300)));
-    /// assert_eq!(leap.checked_sub_signed(TimeDelta::days(1)),
+    /// assert_eq!(leap.checked_sub_signed(TimeDelta::try_days(1).unwrap()),
     ///            Some(from_ymd(2016, 7, 7).and_hms_milli_opt(3, 6, 0, 300).unwrap()));
     /// ```
     #[must_use]
     pub const fn checked_sub_signed(self, rhs: TimeDelta) -> Option<NaiveDateTime> {
-        let (time, rhs) = self.time.overflowing_sub_signed(rhs);
-
-        // early checking to avoid overflow in TimeDelta::seconds
-        if rhs <= (-1 << MAX_SECS_BITS) || rhs >= (1 << MAX_SECS_BITS) {
-            return None;
-        }
-
-        let date = try_opt!(self.date.checked_sub_signed(TimeDelta::seconds(rhs)));
+        let (time, remainder) = self.time.overflowing_sub_signed(rhs);
+        let remainder = try_opt!(TimeDelta::try_seconds(remainder));
+        let date = try_opt!(self.date.checked_sub_signed(remainder));
         Some(NaiveDateTime { date, time })
     }
 
@@ -897,13 +727,19 @@
     /// use chrono::{Months, NaiveDate};
     ///
     /// assert_eq!(
-    ///     NaiveDate::from_ymd_opt(2014, 1, 1).unwrap().and_hms_opt(1, 0, 0).unwrap()
+    ///     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()
+    ///     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
     /// );
@@ -941,18 +777,25 @@
     /// # Example
     ///
     /// ```
-    /// use chrono::{TimeDelta, NaiveDate};
+    /// use chrono::{NaiveDate, TimeDelta};
     ///
     /// let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap();
     ///
     /// let d = from_ymd(2016, 7, 8);
-    /// assert_eq!(d.and_hms_opt(3, 5, 7).unwrap().signed_duration_since(d.and_hms_opt(2, 4, 6).unwrap()),
-    ///            TimeDelta::seconds(3600 + 60 + 1));
+    /// assert_eq!(
+    ///     d.and_hms_opt(3, 5, 7).unwrap().signed_duration_since(d.and_hms_opt(2, 4, 6).unwrap()),
+    ///     TimeDelta::try_seconds(3600 + 60 + 1).unwrap()
+    /// );
     ///
     /// // 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()),
-    ///            TimeDelta::seconds(189 * 86_400 + 7 * 60 + 6) + TimeDelta::milliseconds(500));
+    /// assert_eq!(
+    ///     d.and_hms_milli_opt(0, 7, 6, 500)
+    ///         .unwrap()
+    ///         .signed_duration_since(d0.and_hms_opt(0, 0, 0).unwrap()),
+    ///     TimeDelta::try_seconds(189 * 86_400 + 7 * 60 + 6).unwrap()
+    ///         + TimeDelta::try_milliseconds(500).unwrap()
+    /// );
     /// ```
     ///
     /// Leap seconds are handled, but the subtraction assumes that
@@ -962,18 +805,22 @@
     /// # use chrono::{TimeDelta, NaiveDate};
     /// # let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap();
     /// let leap = from_ymd(2015, 6, 30).and_hms_milli_opt(23, 59, 59, 1_500).unwrap();
-    /// assert_eq!(leap.signed_duration_since(from_ymd(2015, 6, 30).and_hms_opt(23, 0, 0).unwrap()),
-    ///            TimeDelta::seconds(3600) + TimeDelta::milliseconds(500));
-    /// assert_eq!(from_ymd(2015, 7, 1).and_hms_opt(1, 0, 0).unwrap().signed_duration_since(leap),
-    ///            TimeDelta::seconds(3600) - TimeDelta::milliseconds(500));
+    /// assert_eq!(
+    ///     leap.signed_duration_since(from_ymd(2015, 6, 30).and_hms_opt(23, 0, 0).unwrap()),
+    ///     TimeDelta::try_seconds(3600).unwrap() + TimeDelta::try_milliseconds(500).unwrap()
+    /// );
+    /// assert_eq!(
+    ///     from_ymd(2015, 7, 1).and_hms_opt(1, 0, 0).unwrap().signed_duration_since(leap),
+    ///     TimeDelta::try_seconds(3600).unwrap() - TimeDelta::try_milliseconds(500).unwrap()
+    /// );
     /// ```
     #[must_use]
     pub const fn signed_duration_since(self, rhs: NaiveDateTime) -> TimeDelta {
-        expect!(
+        expect(
             self.date
                 .signed_duration_since(rhs.date)
                 .checked_add(&self.time.signed_duration_since(rhs.time)),
-            "always in range"
+            "always in range",
         )
     }
 
@@ -986,13 +833,13 @@
     /// # Example
     ///
     /// ```
-    /// use chrono::NaiveDate;
     /// use chrono::format::strftime::StrftimeItems;
+    /// use chrono::NaiveDate;
     ///
     /// 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");
+    /// 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.
@@ -1054,28 +901,25 @@
         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.
+    /// Converts the `NaiveDateTime` into a timezone-aware `DateTime<Tz>` with the provided
+    /// time zone.
     ///
     /// # Example
     ///
     /// ```
-    /// use chrono::{NaiveDate, FixedOffset};
+    /// use chrono::{FixedOffset, NaiveDate};
     /// let hour = 3600;
     /// let tz = FixedOffset::east_opt(5 * hour).unwrap();
-    /// let dt = NaiveDate::from_ymd_opt(2015, 9, 5).unwrap().and_hms_opt(23, 56, 4).unwrap().and_local_timezone(tz).unwrap();
+    /// let dt = NaiveDate::from_ymd_opt(2015, 9, 5)
+    ///     .unwrap()
+    ///     .and_hms_opt(23, 56, 4)
+    ///     .unwrap()
+    ///     .and_local_timezone(tz)
+    ///     .unwrap();
     /// assert_eq!(dt.timezone(), tz);
     /// ```
     #[must_use]
-    pub fn and_local_timezone<Tz: TimeZone>(&self, tz: Tz) -> LocalResult<DateTime<Tz>> {
+    pub fn and_local_timezone<Tz: TimeZone>(&self, tz: Tz) -> MappedLocalTime<DateTime<Tz>> {
         tz.from_local_datetime(self)
     }
 
@@ -1085,7 +929,8 @@
     ///
     /// ```
     /// use chrono::{NaiveDate, Utc};
-    /// let dt = NaiveDate::from_ymd_opt(2023, 1, 30).unwrap().and_hms_opt(19, 32, 33).unwrap().and_utc();
+    /// let dt =
+    ///     NaiveDate::from_ymd_opt(2023, 1, 30).unwrap().and_hms_opt(19, 32, 33).unwrap().and_utc();
     /// assert_eq!(dt.timezone(), Utc);
     /// ```
     #[must_use]
@@ -1101,7 +946,7 @@
 
     /// The Unix Epoch, 1970-01-01 00:00:00.
     pub const UNIX_EPOCH: Self =
-        expect!(NaiveDate::from_ymd_opt(1970, 1, 1), "").and_time(NaiveTime::MIN);
+        expect(NaiveDate::from_ymd_opt(1970, 1, 1), "").and_time(NaiveTime::MIN);
 }
 
 impl From<NaiveDate> for NaiveDateTime {
@@ -1128,9 +973,10 @@
     /// # Example
     ///
     /// ```
-    /// use chrono::{NaiveDate, NaiveDateTime, Datelike};
+    /// use chrono::{Datelike, NaiveDate, NaiveDateTime};
     ///
-    /// let dt: NaiveDateTime = NaiveDate::from_ymd_opt(2015, 9, 25).unwrap().and_hms_opt(12, 34, 56).unwrap();
+    /// let dt: NaiveDateTime =
+    ///     NaiveDate::from_ymd_opt(2015, 9, 25).unwrap().and_hms_opt(12, 34, 56).unwrap();
     /// assert_eq!(dt.year(), 2015);
     /// ```
     #[inline]
@@ -1147,9 +993,10 @@
     /// # Example
     ///
     /// ```
-    /// use chrono::{NaiveDate, NaiveDateTime, Datelike};
+    /// use chrono::{Datelike, NaiveDate, NaiveDateTime};
     ///
-    /// let dt: NaiveDateTime = NaiveDate::from_ymd_opt(2015, 9, 25).unwrap().and_hms_opt(12, 34, 56).unwrap();
+    /// let dt: NaiveDateTime =
+    ///     NaiveDate::from_ymd_opt(2015, 9, 25).unwrap().and_hms_opt(12, 34, 56).unwrap();
     /// assert_eq!(dt.month(), 9);
     /// ```
     #[inline]
@@ -1166,9 +1013,10 @@
     /// # Example
     ///
     /// ```
-    /// use chrono::{NaiveDate, NaiveDateTime, Datelike};
+    /// use chrono::{Datelike, NaiveDate, NaiveDateTime};
     ///
-    /// let dt: NaiveDateTime = NaiveDate::from_ymd_opt(2015, 9, 25).unwrap().and_hms_opt(12, 34, 56).unwrap();
+    /// let dt: NaiveDateTime =
+    ///     NaiveDate::from_ymd_opt(2015, 9, 25).unwrap().and_hms_opt(12, 34, 56).unwrap();
     /// assert_eq!(dt.month0(), 8);
     /// ```
     #[inline]
@@ -1185,9 +1033,10 @@
     /// # Example
     ///
     /// ```
-    /// use chrono::{NaiveDate, NaiveDateTime, Datelike};
+    /// use chrono::{Datelike, NaiveDate, NaiveDateTime};
     ///
-    /// let dt: NaiveDateTime = NaiveDate::from_ymd_opt(2015, 9, 25).unwrap().and_hms_opt(12, 34, 56).unwrap();
+    /// let dt: NaiveDateTime =
+    ///     NaiveDate::from_ymd_opt(2015, 9, 25).unwrap().and_hms_opt(12, 34, 56).unwrap();
     /// assert_eq!(dt.day(), 25);
     /// ```
     #[inline]
@@ -1204,9 +1053,10 @@
     /// # Example
     ///
     /// ```
-    /// use chrono::{NaiveDate, NaiveDateTime, Datelike};
+    /// use chrono::{Datelike, NaiveDate, NaiveDateTime};
     ///
-    /// let dt: NaiveDateTime = NaiveDate::from_ymd_opt(2015, 9, 25).unwrap().and_hms_opt(12, 34, 56).unwrap();
+    /// let dt: NaiveDateTime =
+    ///     NaiveDate::from_ymd_opt(2015, 9, 25).unwrap().and_hms_opt(12, 34, 56).unwrap();
     /// assert_eq!(dt.day0(), 24);
     /// ```
     #[inline]
@@ -1223,9 +1073,10 @@
     /// # Example
     ///
     /// ```
-    /// use chrono::{NaiveDate, NaiveDateTime, Datelike};
+    /// use chrono::{Datelike, NaiveDate, NaiveDateTime};
     ///
-    /// let dt: NaiveDateTime = NaiveDate::from_ymd_opt(2015, 9, 25).unwrap().and_hms_opt(12, 34, 56).unwrap();
+    /// let dt: NaiveDateTime =
+    ///     NaiveDate::from_ymd_opt(2015, 9, 25).unwrap().and_hms_opt(12, 34, 56).unwrap();
     /// assert_eq!(dt.ordinal(), 268);
     /// ```
     #[inline]
@@ -1242,9 +1093,10 @@
     /// # Example
     ///
     /// ```
-    /// use chrono::{NaiveDate, NaiveDateTime, Datelike};
+    /// use chrono::{Datelike, NaiveDate, NaiveDateTime};
     ///
-    /// let dt: NaiveDateTime = NaiveDate::from_ymd_opt(2015, 9, 25).unwrap().and_hms_opt(12, 34, 56).unwrap();
+    /// let dt: NaiveDateTime =
+    ///     NaiveDate::from_ymd_opt(2015, 9, 25).unwrap().and_hms_opt(12, 34, 56).unwrap();
     /// assert_eq!(dt.ordinal0(), 267);
     /// ```
     #[inline]
@@ -1259,9 +1111,10 @@
     /// # Example
     ///
     /// ```
-    /// use chrono::{NaiveDate, NaiveDateTime, Datelike, Weekday};
+    /// use chrono::{Datelike, NaiveDate, NaiveDateTime, Weekday};
     ///
-    /// let dt: NaiveDateTime = NaiveDate::from_ymd_opt(2015, 9, 25).unwrap().and_hms_opt(12, 34, 56).unwrap();
+    /// 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]
@@ -1281,17 +1134,25 @@
     ///
     /// # Errors
     ///
-    /// Returns `None` if the resulting date does not exist, or when the `NaiveDateTime` would be
-    /// out of range.
+    /// Returns `None` if:
+    /// - The resulting date does not exist (February 29 in a non-leap year).
+    /// - The year is out of range for a `NaiveDate`.
     ///
     /// # Example
     ///
     /// ```
-    /// use chrono::{NaiveDate, NaiveDateTime, Datelike};
+    /// use chrono::{Datelike, NaiveDate, NaiveDateTime};
     ///
-    /// 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()));
+    /// 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> {
@@ -1300,21 +1161,29 @@
 
     /// Makes a new `NaiveDateTime` with the month number (starting from 1) changed.
     ///
+    /// Don't combine multiple `Datelike::with_*` methods. The intermediate value may not exist.
+    ///
     /// See also the [`NaiveDate::with_month`] method.
     ///
     /// # Errors
     ///
-    /// Returns `None` if the resulting date does not exist, or if the value for `month` is invalid.
+    /// Returns `None` if:
+    /// - The resulting date does not exist (for example `month(4)` when day of the month is 31).
+    /// - The value for `month` is invalid.
     ///
     /// # Example
     ///
     /// ```
-    /// use chrono::{NaiveDate, NaiveDateTime, Datelike};
+    /// use chrono::{Datelike, NaiveDate, NaiveDateTime};
     ///
-    /// 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
+    /// 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> {
@@ -1327,18 +1196,23 @@
     ///
     /// # Errors
     ///
-    /// Returns `None` if the resulting date does not exist, or if the value for `month0` is
-    /// invalid.
+    /// Returns `None` if:
+    /// - The resulting date does not exist (for example `month0(3)` when day of the month is 31).
+    /// - The value for `month0` is invalid.
     ///
     /// # Example
     ///
     /// ```
-    /// use chrono::{NaiveDate, NaiveDateTime, Datelike};
+    /// use chrono::{Datelike, NaiveDate, NaiveDateTime};
     ///
-    /// 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
+    /// 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> {
@@ -1351,15 +1225,21 @@
     ///
     /// # Errors
     ///
-    /// Returns `None` if the resulting date does not exist, or if the value for `day` is invalid.
+    /// Returns `None` if:
+    /// - The resulting date does not exist (for example `day(31)` in April).
+    /// - The value for `day` is invalid.
     ///
     /// # Example
     ///
     /// ```
-    /// use chrono::{NaiveDate, NaiveDateTime, Datelike};
+    /// use chrono::{Datelike, NaiveDate, NaiveDateTime};
     ///
-    /// 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()));
+    /// 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]
@@ -1373,15 +1253,21 @@
     ///
     /// # Errors
     ///
-    /// Returns `None` if the resulting date does not exist, or if the value for `day0` is invalid.
+    /// Returns `None` if:
+    /// - The resulting date does not exist (for example `day(30)` in April).
+    /// - The value for `day0` is invalid.
     ///
     /// # Example
     ///
     /// ```
-    /// use chrono::{NaiveDate, NaiveDateTime, Datelike};
+    /// use chrono::{Datelike, NaiveDate, NaiveDateTime};
     ///
-    /// 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()));
+    /// 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]
@@ -1395,24 +1281,33 @@
     ///
     /// # Errors
     ///
-    /// Returns `None` if the resulting date does not exist, or if the value for `ordinal` is
-    /// invalid.
+    /// Returns `None` if:
+    /// - The resulting date does not exist (`with_ordinal(366)` in a non-leap year).
+    /// - The value for `ordinal` is invalid.
     ///
     /// # Example
     ///
     /// ```
-    /// use chrono::{NaiveDate, NaiveDateTime, Datelike};
+    /// use chrono::{Datelike, NaiveDate, NaiveDateTime};
     ///
-    /// 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()));
+    /// 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()));
+    /// 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> {
@@ -1425,24 +1320,33 @@
     ///
     /// # Errors
     ///
-    /// Returns `None` if the resulting date does not exist, or if the value for `ordinal0` is
-    /// invalid.
+    /// Returns `None` if:
+    /// - The resulting date does not exist (`with_ordinal0(365)` in a non-leap year).
+    /// - The value for `ordinal0` is invalid.
     ///
     /// # Example
     ///
     /// ```
-    /// use chrono::{NaiveDate, NaiveDateTime, Datelike};
+    /// use chrono::{Datelike, NaiveDate, NaiveDateTime};
     ///
-    /// 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()));
+    /// 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()));
+    /// 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> {
@@ -1460,7 +1364,8 @@
     /// ```
     /// 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();
+    /// 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]
@@ -1477,7 +1382,8 @@
     /// ```
     /// 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();
+    /// 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]
@@ -1494,7 +1400,8 @@
     /// ```
     /// 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();
+    /// 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]
@@ -1513,7 +1420,8 @@
     /// ```
     /// 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();
+    /// 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]
@@ -1534,9 +1442,14 @@
     /// ```
     /// 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()));
+    /// 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]
@@ -1557,9 +1470,17 @@
     /// ```
     /// 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()));
+    /// 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]
@@ -1583,9 +1504,17 @@
     /// ```
     /// 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()));
+    /// 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]
@@ -1610,11 +1539,26 @@
     /// ```
     /// use chrono::{NaiveDate, NaiveDateTime, Timelike};
     ///
-    /// let dt: NaiveDateTime = NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().and_hms_milli_opt(12, 34, 59, 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, 59, 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, 59, 1_333_333_333).unwrap()));
+    /// let dt: NaiveDateTime =
+    ///     NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().and_hms_milli_opt(12, 34, 59, 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, 59, 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, 59, 1_333_333_333)
+    ///             .unwrap()
+    ///     )
+    /// );
     /// assert_eq!(dt.with_nanosecond(2_000_000_000), None);
     /// ```
     #[inline]
@@ -1637,23 +1581,27 @@
 /// # Example
 ///
 /// ```
-/// use chrono::{TimeDelta, NaiveDate};
+/// use chrono::{NaiveDate, TimeDelta};
 ///
 /// let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap();
 ///
 /// let d = from_ymd(2016, 7, 8);
 /// let hms = |h, m, s| d.and_hms_opt(h, m, s).unwrap();
-/// assert_eq!(hms(3, 5, 7) + TimeDelta::zero(),             hms(3, 5, 7));
-/// assert_eq!(hms(3, 5, 7) + TimeDelta::seconds(1),         hms(3, 5, 8));
-/// assert_eq!(hms(3, 5, 7) + TimeDelta::seconds(-1),        hms(3, 5, 6));
-/// assert_eq!(hms(3, 5, 7) + TimeDelta::seconds(3600 + 60), hms(4, 6, 7));
-/// assert_eq!(hms(3, 5, 7) + TimeDelta::seconds(86_400),
-///            from_ymd(2016, 7, 9).and_hms_opt(3, 5, 7).unwrap());
-/// assert_eq!(hms(3, 5, 7) + TimeDelta::days(365),
-///            from_ymd(2017, 7, 8).and_hms_opt(3, 5, 7).unwrap());
+/// assert_eq!(hms(3, 5, 7) + TimeDelta::zero(), hms(3, 5, 7));
+/// assert_eq!(hms(3, 5, 7) + TimeDelta::try_seconds(1).unwrap(), hms(3, 5, 8));
+/// assert_eq!(hms(3, 5, 7) + TimeDelta::try_seconds(-1).unwrap(), hms(3, 5, 6));
+/// assert_eq!(hms(3, 5, 7) + TimeDelta::try_seconds(3600 + 60).unwrap(), hms(4, 6, 7));
+/// assert_eq!(
+///     hms(3, 5, 7) + TimeDelta::try_seconds(86_400).unwrap(),
+///     from_ymd(2016, 7, 9).and_hms_opt(3, 5, 7).unwrap()
+/// );
+/// assert_eq!(
+///     hms(3, 5, 7) + TimeDelta::try_days(365).unwrap(),
+///     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) + TimeDelta::milliseconds(450), hmsm(3, 5, 8, 430));
+/// assert_eq!(hmsm(3, 5, 7, 980) + TimeDelta::try_milliseconds(450).unwrap(), hmsm(3, 5, 8, 430));
 /// ```
 ///
 /// Leap seconds are handled,
@@ -1664,13 +1612,13 @@
 /// # let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap();
 /// # let hmsm = |h, m, s, milli| from_ymd(2016, 7, 8).and_hms_milli_opt(h, m, s, milli).unwrap();
 /// let leap = hmsm(3, 5, 59, 1_300);
-/// assert_eq!(leap + TimeDelta::zero(),             hmsm(3, 5, 59, 1_300));
-/// assert_eq!(leap + TimeDelta::milliseconds(-500), hmsm(3, 5, 59, 800));
-/// assert_eq!(leap + TimeDelta::milliseconds(500),  hmsm(3, 5, 59, 1_800));
-/// assert_eq!(leap + TimeDelta::milliseconds(800),  hmsm(3, 6, 0, 100));
-/// assert_eq!(leap + TimeDelta::seconds(10),        hmsm(3, 6, 9, 300));
-/// assert_eq!(leap + TimeDelta::seconds(-10),       hmsm(3, 5, 50, 300));
-/// assert_eq!(leap + TimeDelta::days(1),
+/// assert_eq!(leap + TimeDelta::zero(), hmsm(3, 5, 59, 1_300));
+/// assert_eq!(leap + TimeDelta::try_milliseconds(-500).unwrap(), hmsm(3, 5, 59, 800));
+/// assert_eq!(leap + TimeDelta::try_milliseconds(500).unwrap(), hmsm(3, 5, 59, 1_800));
+/// assert_eq!(leap + TimeDelta::try_milliseconds(800).unwrap(), hmsm(3, 6, 0, 100));
+/// assert_eq!(leap + TimeDelta::try_seconds(10).unwrap(), hmsm(3, 6, 9, 300));
+/// assert_eq!(leap + TimeDelta::try_seconds(-10).unwrap(), hmsm(3, 5, 50, 300));
+/// assert_eq!(leap + TimeDelta::try_days(1).unwrap(),
 ///            from_ymd(2016, 7, 9).and_hms_milli_opt(3, 5, 59, 300).unwrap());
 /// ```
 ///
@@ -1774,23 +1722,28 @@
 ///     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, 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(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(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, 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, 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()
 /// );
 /// ```
@@ -1818,23 +1771,27 @@
 /// # Example
 ///
 /// ```
-/// use chrono::{TimeDelta, NaiveDate};
+/// use chrono::{NaiveDate, TimeDelta};
 ///
 /// let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap();
 ///
 /// let d = from_ymd(2016, 7, 8);
 /// let hms = |h, m, s| d.and_hms_opt(h, m, s).unwrap();
-/// assert_eq!(hms(3, 5, 7) - TimeDelta::zero(),             hms(3, 5, 7));
-/// assert_eq!(hms(3, 5, 7) - TimeDelta::seconds(1),         hms(3, 5, 6));
-/// assert_eq!(hms(3, 5, 7) - TimeDelta::seconds(-1),        hms(3, 5, 8));
-/// assert_eq!(hms(3, 5, 7) - TimeDelta::seconds(3600 + 60), hms(2, 4, 7));
-/// assert_eq!(hms(3, 5, 7) - TimeDelta::seconds(86_400),
-///            from_ymd(2016, 7, 7).and_hms_opt(3, 5, 7).unwrap());
-/// assert_eq!(hms(3, 5, 7) - TimeDelta::days(365),
-///            from_ymd(2015, 7, 9).and_hms_opt(3, 5, 7).unwrap());
+/// assert_eq!(hms(3, 5, 7) - TimeDelta::zero(), hms(3, 5, 7));
+/// assert_eq!(hms(3, 5, 7) - TimeDelta::try_seconds(1).unwrap(), hms(3, 5, 6));
+/// assert_eq!(hms(3, 5, 7) - TimeDelta::try_seconds(-1).unwrap(), hms(3, 5, 8));
+/// assert_eq!(hms(3, 5, 7) - TimeDelta::try_seconds(3600 + 60).unwrap(), hms(2, 4, 7));
+/// assert_eq!(
+///     hms(3, 5, 7) - TimeDelta::try_seconds(86_400).unwrap(),
+///     from_ymd(2016, 7, 7).and_hms_opt(3, 5, 7).unwrap()
+/// );
+/// assert_eq!(
+///     hms(3, 5, 7) - TimeDelta::try_days(365).unwrap(),
+///     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) - TimeDelta::milliseconds(670), hmsm(3, 5, 6, 780));
+/// assert_eq!(hmsm(3, 5, 7, 450) - TimeDelta::try_milliseconds(670).unwrap(), hmsm(3, 5, 6, 780));
 /// ```
 ///
 /// Leap seconds are handled,
@@ -1845,11 +1802,11 @@
 /// # let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap();
 /// # let hmsm = |h, m, s, milli| from_ymd(2016, 7, 8).and_hms_milli_opt(h, m, s, milli).unwrap();
 /// let leap = hmsm(3, 5, 59, 1_300);
-/// assert_eq!(leap - TimeDelta::zero(),            hmsm(3, 5, 59, 1_300));
-/// assert_eq!(leap - TimeDelta::milliseconds(200), hmsm(3, 5, 59, 1_100));
-/// assert_eq!(leap - TimeDelta::milliseconds(500), hmsm(3, 5, 59, 800));
-/// assert_eq!(leap - TimeDelta::seconds(60),       hmsm(3, 5, 0, 300));
-/// assert_eq!(leap - TimeDelta::days(1),
+/// assert_eq!(leap - TimeDelta::zero(), hmsm(3, 5, 59, 1_300));
+/// assert_eq!(leap - TimeDelta::try_milliseconds(200).unwrap(), hmsm(3, 5, 59, 1_100));
+/// assert_eq!(leap - TimeDelta::try_milliseconds(500).unwrap(), hmsm(3, 5, 59, 800));
+/// assert_eq!(leap - TimeDelta::try_seconds(60).unwrap(), hmsm(3, 5, 0, 300));
+/// assert_eq!(leap - TimeDelta::try_days(1).unwrap(),
 ///            from_ymd(2016, 7, 7).and_hms_milli_opt(3, 6, 0, 300).unwrap());
 /// ```
 ///
@@ -1951,15 +1908,18 @@
 /// use chrono::{Months, NaiveDate};
 ///
 /// assert_eq!(
-///     NaiveDate::from_ymd_opt(2014, 01, 01).unwrap().and_hms_opt(01, 00, 00).unwrap() - Months::new(11),
+///     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(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(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()
 /// );
 /// ```
@@ -1985,17 +1945,23 @@
 /// # Example
 ///
 /// ```
-/// use chrono::{TimeDelta, NaiveDate};
+/// use chrono::{NaiveDate, TimeDelta};
 ///
 /// let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap();
 ///
 /// let d = from_ymd(2016, 7, 8);
-/// assert_eq!(d.and_hms_opt(3, 5, 7).unwrap() - d.and_hms_opt(2, 4, 6).unwrap(), TimeDelta::seconds(3600 + 60 + 1));
+/// assert_eq!(
+///     d.and_hms_opt(3, 5, 7).unwrap() - d.and_hms_opt(2, 4, 6).unwrap(),
+///     TimeDelta::try_seconds(3600 + 60 + 1).unwrap()
+/// );
 ///
 /// // 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(),
-///            TimeDelta::seconds(189 * 86_400 + 7 * 60 + 6) + TimeDelta::milliseconds(500));
+/// assert_eq!(
+///     d.and_hms_milli_opt(0, 7, 6, 500).unwrap() - d0.and_hms_opt(0, 0, 0).unwrap(),
+///     TimeDelta::try_seconds(189 * 86_400 + 7 * 60 + 6).unwrap()
+///         + TimeDelta::try_milliseconds(500).unwrap()
+/// );
 /// ```
 ///
 /// Leap seconds are handled, but the subtraction assumes that no other leap
@@ -2005,10 +1971,14 @@
 /// # use chrono::{TimeDelta, NaiveDate};
 /// # let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap();
 /// let leap = from_ymd(2015, 6, 30).and_hms_milli_opt(23, 59, 59, 1_500).unwrap();
-/// assert_eq!(leap - from_ymd(2015, 6, 30).and_hms_opt(23, 0, 0).unwrap(),
-///            TimeDelta::seconds(3600) + TimeDelta::milliseconds(500));
-/// assert_eq!(from_ymd(2015, 7, 1).and_hms_opt(1, 0, 0).unwrap() - leap,
-///            TimeDelta::seconds(3600) - TimeDelta::milliseconds(500));
+/// assert_eq!(
+///     leap - from_ymd(2015, 6, 30).and_hms_opt(23, 0, 0).unwrap(),
+///     TimeDelta::try_seconds(3600).unwrap() + TimeDelta::try_milliseconds(500).unwrap()
+/// );
+/// assert_eq!(
+///     from_ymd(2015, 7, 1).and_hms_opt(1, 0, 0).unwrap() - leap,
+///     TimeDelta::try_seconds(3600).unwrap() - TimeDelta::try_milliseconds(500).unwrap()
+/// );
 /// ```
 impl Sub<NaiveDateTime> for NaiveDateTime {
     type Output = TimeDelta;
@@ -2071,7 +2041,8 @@
 ///
 /// ```
 /// # use chrono::NaiveDate;
-/// let dt = NaiveDate::from_ymd_opt(2015, 6, 30).unwrap().and_hms_milli_opt(23, 59, 59, 1_500).unwrap();
+/// 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 {
@@ -2104,7 +2075,8 @@
 ///
 /// ```
 /// # use chrono::NaiveDate;
-/// let dt = NaiveDate::from_ymd_opt(2015, 6, 30).unwrap().and_hms_milli_opt(23, 59, 59, 1_500).unwrap();
+/// 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 {
@@ -2170,140 +2142,10 @@
 /// ```rust
 /// use chrono::NaiveDateTime;
 ///
-/// let default_date = NaiveDateTime::default();
-/// assert_eq!(Some(default_date), NaiveDateTime::from_timestamp_opt(0, 0));
+/// assert_eq!(NaiveDateTime::default(), NaiveDateTime::UNIX_EPOCH);
 /// ```
 impl Default for NaiveDateTime {
     fn default() -> Self {
-        NaiveDateTime::from_timestamp_opt(0, 0).unwrap()
+        Self::UNIX_EPOCH
     }
 }
-
-#[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#""-262143-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#""+262142-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#""-262143-01-01T00:00:00""#).ok(),
-        Some(NaiveDate::MIN.and_hms_opt(0, 0, 0).unwrap())
-    );
-    assert_eq!(
-        from_str(r#""+262142-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#""+262142-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/crates/chrono/src/naive/datetime/rustc_serialize.rs b/crates/chrono/src/naive/datetime/rustc_serialize.rs
deleted file mode 100644
index d2b8a87..0000000
--- a/crates/chrono/src/naive/datetime/rustc_serialize.rs
+++ /dev/null
@@ -1,75 +0,0 @@
-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)]
-mod tests {
-    use crate::naive::datetime::test_encodable_json;
-    use crate::naive::datetime::{test_decodable_json, test_decodable_json_timestamp};
-    use rustc_serialize::json;
-
-    #[test]
-    fn test_encodable() {
-        test_encodable_json(json::encode);
-    }
-
-    #[test]
-    fn test_decodable() {
-        test_decodable_json(json::decode);
-    }
-
-    #[test]
-    fn test_decodable_timestamps() {
-        test_decodable_json_timestamp(json::decode);
-    }
-}
diff --git a/crates/chrono/src/naive/datetime/serde.rs b/crates/chrono/src/naive/datetime/serde.rs
index 0a6cfd9..85fcb94 100644
--- a/crates/chrono/src/naive/datetime/serde.rs
+++ b/crates/chrono/src/naive/datetime/serde.rs
@@ -2,12 +2,10 @@
 use serde::{de, ser};
 
 use super::NaiveDateTime;
-use crate::offset::LocalResult;
 
-/// Serialize a `NaiveDateTime` as an RFC 3339 string
+/// Serialize a `NaiveDateTime` as an ISO 8601 string
 ///
-/// See [the `serde` module](./serde/index.html) for alternate
-/// serialization formats.
+/// See [the `naive::serde` module](crate::naive::serde) for alternate serialization formats.
 impl ser::Serialize for NaiveDateTime {
     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
     where
@@ -17,7 +15,7 @@
             inner: &'a D,
         }
 
-        impl<'a, D: fmt::Debug> fmt::Display for FormatWrapped<'a, D> {
+        impl<D: fmt::Debug> fmt::Display for FormatWrapped<'_, D> {
             fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                 self.inner.fmt(f)
             }
@@ -29,7 +27,7 @@
 
 struct NaiveDateTimeVisitor;
 
-impl<'de> de::Visitor<'de> for NaiveDateTimeVisitor {
+impl de::Visitor<'_> for NaiveDateTimeVisitor {
     type Value = NaiveDateTime;
 
     fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
@@ -64,13 +62,14 @@
 /// #[derive(Deserialize, Serialize)]
 /// struct S {
 ///     #[serde(with = "ts_nanoseconds")]
-///     time: NaiveDateTime
+///     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 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}"#);
@@ -82,8 +81,8 @@
     use core::fmt;
     use serde::{de, ser};
 
-    use super::ne_timestamp;
-    use crate::NaiveDateTime;
+    use crate::serde::invalid_ts;
+    use crate::{DateTime, NaiveDateTime};
 
     /// Serialize a datetime into an integer number of nanoseconds since the epoch
     ///
@@ -106,11 +105,14 @@
     /// #[derive(Serialize)]
     /// struct S {
     ///     #[serde(serialize_with = "to_nano_ts")]
-    ///     time: NaiveDateTime
+    ///     time: NaiveDateTime,
     /// }
     ///
     /// let my_s = S {
-    ///     time: NaiveDate::from_ymd_opt(2018, 5, 17).unwrap().and_hms_nano_opt(02, 04, 59, 918355733).unwrap(),
+    ///     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}"#);
@@ -120,7 +122,7 @@
     where
         S: ser::Serializer,
     {
-        serializer.serialize_i64(dt.timestamp_nanos_opt().ok_or(ser::Error::custom(
+        serializer.serialize_i64(dt.and_utc().timestamp_nanos_opt().ok_or(ser::Error::custom(
             "value out of range for a timestamp with nanosecond precision",
         ))?)
     }
@@ -132,20 +134,22 @@
     /// # Example:
     ///
     /// ```rust
-    /// # use chrono::NaiveDateTime;
+    /// # use chrono::{DateTime, NaiveDateTime};
     /// # use serde_derive::Deserialize;
     /// use chrono::naive::serde::ts_nanoseconds::deserialize as from_nano_ts;
     /// #[derive(Debug, PartialEq, Deserialize)]
     /// struct S {
     ///     #[serde(deserialize_with = "from_nano_ts")]
-    ///     time: NaiveDateTime
+    ///     time: NaiveDateTime,
     /// }
     ///
     /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918355733 }"#)?;
-    /// assert_eq!(my_s, S { time: NaiveDateTime::from_timestamp_opt(1526522699, 918355733).unwrap() });
+    /// let expected = DateTime::from_timestamp(1526522699, 918355733).unwrap().naive_utc();
+    /// assert_eq!(my_s, S { time: expected });
     ///
     /// let my_s: S = serde_json::from_str(r#"{ "time": -1 }"#)?;
-    /// assert_eq!(my_s, S { time: NaiveDateTime::from_timestamp_opt(-1, 999_999_999).unwrap() });
+    /// let expected = DateTime::from_timestamp(-1, 999_999_999).unwrap().naive_utc();
+    /// assert_eq!(my_s, S { time: expected });
     /// # Ok::<(), serde_json::Error>(())
     /// ```
     pub fn deserialize<'de, D>(d: D) -> Result<NaiveDateTime, D::Error>
@@ -157,7 +161,7 @@
 
     pub(super) struct NanoSecondsTimestampVisitor;
 
-    impl<'de> de::Visitor<'de> for NanoSecondsTimestampVisitor {
+    impl de::Visitor<'_> for NanoSecondsTimestampVisitor {
         type Value = NaiveDateTime;
 
         fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
@@ -168,22 +172,21 @@
         where
             E: de::Error,
         {
-            NaiveDateTime::from_timestamp_opt(
+            DateTime::from_timestamp(
                 value.div_euclid(1_000_000_000),
                 (value.rem_euclid(1_000_000_000)) as u32,
             )
-            .ok_or_else(|| E::custom(ne_timestamp(value)))
+            .map(|dt| dt.naive_utc())
+            .ok_or_else(|| invalid_ts(value))
         }
 
         fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
         where
             E: de::Error,
         {
-            NaiveDateTime::from_timestamp_opt(
-                (value / 1_000_000_000) as i64,
-                (value % 1_000_000_000) as u32,
-            )
-            .ok_or_else(|| E::custom(ne_timestamp(value)))
+            DateTime::from_timestamp((value / 1_000_000_000) as i64, (value % 1_000_000_000) as u32)
+                .map(|dt| dt.naive_utc())
+                .ok_or_else(|| invalid_ts(value))
         }
     }
 }
@@ -201,13 +204,16 @@
 /// #[derive(Deserialize, Serialize)]
 /// struct S {
 ///     #[serde(with = "ts_nanoseconds_option")]
-///     time: Option<NaiveDateTime>
+///     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 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}"#);
@@ -243,11 +249,16 @@
     /// #[derive(Serialize)]
     /// struct S {
     ///     #[serde(serialize_with = "to_nano_tsopt")]
-    ///     time: Option<NaiveDateTime>
+    ///     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()),
+    ///     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}"#);
@@ -258,7 +269,7 @@
         S: ser::Serializer,
     {
         match *opt {
-            Some(ref dt) => serializer.serialize_some(&dt.timestamp_nanos_opt().ok_or(
+            Some(ref dt) => serializer.serialize_some(&dt.and_utc().timestamp_nanos_opt().ok_or(
                 ser::Error::custom("value out of range for a timestamp with nanosecond precision"),
             )?),
             None => serializer.serialize_none(),
@@ -272,20 +283,22 @@
     /// # Example:
     ///
     /// ```rust
-    /// # use chrono::naive::NaiveDateTime;
+    /// # use chrono::{DateTime, NaiveDateTime};
     /// # use serde_derive::Deserialize;
     /// use chrono::naive::serde::ts_nanoseconds_option::deserialize as from_nano_tsopt;
     /// #[derive(Debug, PartialEq, Deserialize)]
     /// struct S {
     ///     #[serde(deserialize_with = "from_nano_tsopt")]
-    ///     time: Option<NaiveDateTime>
+    ///     time: Option<NaiveDateTime>,
     /// }
     ///
     /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918355733 }"#)?;
-    /// assert_eq!(my_s, S { time: NaiveDateTime::from_timestamp_opt(1526522699, 918355733) });
+    /// let expected = DateTime::from_timestamp(1526522699, 918355733).unwrap().naive_utc();
+    /// assert_eq!(my_s, S { time: Some(expected) });
     ///
     /// let my_s: S = serde_json::from_str(r#"{ "time": -1 }"#)?;
-    /// assert_eq!(my_s, S { time: NaiveDateTime::from_timestamp_opt(-1, 999_999_999) });
+    /// let expected = DateTime::from_timestamp(-1, 999_999_999).unwrap().naive_utc();
+    /// assert_eq!(my_s, S { time: Some(expected) });
     /// # Ok::<(), serde_json::Error>(())
     /// ```
     pub fn deserialize<'de, D>(d: D) -> Result<Option<NaiveDateTime>, D::Error>
@@ -341,13 +354,14 @@
 /// #[derive(Deserialize, Serialize)]
 /// struct S {
 ///     #[serde(with = "ts_microseconds")]
-///     time: NaiveDateTime
+///     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 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}"#);
@@ -359,8 +373,8 @@
     use core::fmt;
     use serde::{de, ser};
 
-    use super::ne_timestamp;
-    use crate::NaiveDateTime;
+    use crate::serde::invalid_ts;
+    use crate::{DateTime, NaiveDateTime};
 
     /// Serialize a datetime into an integer number of microseconds since the epoch
     ///
@@ -375,11 +389,14 @@
     /// #[derive(Serialize)]
     /// struct S {
     ///     #[serde(serialize_with = "to_micro_ts")]
-    ///     time: NaiveDateTime
+    ///     time: NaiveDateTime,
     /// }
     ///
     /// let my_s = S {
-    ///     time: NaiveDate::from_ymd_opt(2018, 5, 17).unwrap().and_hms_micro_opt(02, 04, 59, 918355).unwrap(),
+    ///     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}"#);
@@ -389,7 +406,7 @@
     where
         S: ser::Serializer,
     {
-        serializer.serialize_i64(dt.timestamp_micros())
+        serializer.serialize_i64(dt.and_utc().timestamp_micros())
     }
 
     /// Deserialize a `NaiveDateTime` from a microseconds timestamp
@@ -399,20 +416,22 @@
     /// # Example:
     ///
     /// ```rust
-    /// # use chrono::NaiveDateTime;
+    /// # use chrono::{DateTime, NaiveDateTime};
     /// # use serde_derive::Deserialize;
     /// use chrono::naive::serde::ts_microseconds::deserialize as from_micro_ts;
     /// #[derive(Debug, PartialEq, Deserialize)]
     /// struct S {
     ///     #[serde(deserialize_with = "from_micro_ts")]
-    ///     time: NaiveDateTime
+    ///     time: NaiveDateTime,
     /// }
     ///
     /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918355 }"#)?;
-    /// assert_eq!(my_s, S { time: NaiveDateTime::from_timestamp_opt(1526522699, 918355000).unwrap() });
+    /// let expected = DateTime::from_timestamp(1526522699, 918355000).unwrap().naive_utc();
+    /// assert_eq!(my_s, S { time: expected });
     ///
     /// let my_s: S = serde_json::from_str(r#"{ "time": -1 }"#)?;
-    /// assert_eq!(my_s, S { time: NaiveDateTime::from_timestamp_opt(-1, 999_999_000).unwrap() });
+    /// let expected = DateTime::from_timestamp(-1, 999_999_000).unwrap().naive_utc();
+    /// assert_eq!(my_s, S { time: expected });
     /// # Ok::<(), serde_json::Error>(())
     /// ```
     pub fn deserialize<'de, D>(d: D) -> Result<NaiveDateTime, D::Error>
@@ -424,7 +443,7 @@
 
     pub(super) struct MicroSecondsTimestampVisitor;
 
-    impl<'de> de::Visitor<'de> for MicroSecondsTimestampVisitor {
+    impl de::Visitor<'_> for MicroSecondsTimestampVisitor {
         type Value = NaiveDateTime;
 
         fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
@@ -435,19 +454,21 @@
         where
             E: de::Error,
         {
-            NaiveDateTime::from_timestamp_micros(value)
-                .ok_or_else(|| E::custom(ne_timestamp(value)))
+            DateTime::from_timestamp_micros(value)
+                .map(|dt| dt.naive_utc())
+                .ok_or_else(|| invalid_ts(value))
         }
 
         fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
         where
             E: de::Error,
         {
-            NaiveDateTime::from_timestamp_opt(
+            DateTime::from_timestamp(
                 (value / 1_000_000) as i64,
                 ((value % 1_000_000) * 1_000) as u32,
             )
-            .ok_or_else(|| E::custom(ne_timestamp(value)))
+            .map(|dt| dt.naive_utc())
+            .ok_or_else(|| invalid_ts(value))
         }
     }
 }
@@ -465,13 +486,16 @@
 /// #[derive(Deserialize, Serialize)]
 /// struct S {
 ///     #[serde(with = "ts_microseconds_option")]
-///     time: Option<NaiveDateTime>
+///     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 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}"#);
@@ -499,11 +523,16 @@
     /// #[derive(Serialize)]
     /// struct S {
     ///     #[serde(serialize_with = "to_micro_tsopt")]
-    ///     time: Option<NaiveDateTime>
+    ///     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()),
+    ///     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}"#);
@@ -514,7 +543,7 @@
         S: ser::Serializer,
     {
         match *opt {
-            Some(ref dt) => serializer.serialize_some(&dt.timestamp_micros()),
+            Some(ref dt) => serializer.serialize_some(&dt.and_utc().timestamp_micros()),
             None => serializer.serialize_none(),
         }
     }
@@ -526,20 +555,22 @@
     /// # Example:
     ///
     /// ```rust
-    /// # use chrono::naive::NaiveDateTime;
+    /// # use chrono::{DateTime, NaiveDateTime};
     /// # use serde_derive::Deserialize;
     /// use chrono::naive::serde::ts_microseconds_option::deserialize as from_micro_tsopt;
     /// #[derive(Debug, PartialEq, Deserialize)]
     /// struct S {
     ///     #[serde(deserialize_with = "from_micro_tsopt")]
-    ///     time: Option<NaiveDateTime>
+    ///     time: Option<NaiveDateTime>,
     /// }
     ///
     /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918355 }"#)?;
-    /// assert_eq!(my_s, S { time: NaiveDateTime::from_timestamp_opt(1526522699, 918355000) });
+    /// let expected = DateTime::from_timestamp(1526522699, 918355000).unwrap().naive_utc();
+    /// assert_eq!(my_s, S { time: Some(expected) });
     ///
     /// let my_s: S = serde_json::from_str(r#"{ "time": -1 }"#)?;
-    /// assert_eq!(my_s, S { time: NaiveDateTime::from_timestamp_opt(-1, 999_999_000) });
+    /// let expected = DateTime::from_timestamp(-1, 999_999_000).unwrap().naive_utc();
+    /// assert_eq!(my_s, S { time: Some(expected) });
     /// # Ok::<(), serde_json::Error>(())
     /// ```
     pub fn deserialize<'de, D>(d: D) -> Result<Option<NaiveDateTime>, D::Error>
@@ -595,13 +626,12 @@
 /// #[derive(Deserialize, Serialize)]
 /// struct S {
 ///     #[serde(with = "ts_milliseconds")]
-///     time: NaiveDateTime
+///     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 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}"#);
@@ -613,8 +643,8 @@
     use core::fmt;
     use serde::{de, ser};
 
-    use super::ne_timestamp;
-    use crate::NaiveDateTime;
+    use crate::serde::invalid_ts;
+    use crate::{DateTime, NaiveDateTime};
 
     /// Serialize a datetime into an integer number of milliseconds since the epoch
     ///
@@ -629,11 +659,14 @@
     /// #[derive(Serialize)]
     /// struct S {
     ///     #[serde(serialize_with = "to_milli_ts")]
-    ///     time: NaiveDateTime
+    ///     time: NaiveDateTime,
     /// }
     ///
     /// let my_s = S {
-    ///     time: NaiveDate::from_ymd_opt(2018, 5, 17).unwrap().and_hms_milli_opt(02, 04, 59, 918).unwrap(),
+    ///     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}"#);
@@ -643,7 +676,7 @@
     where
         S: ser::Serializer,
     {
-        serializer.serialize_i64(dt.timestamp_millis())
+        serializer.serialize_i64(dt.and_utc().timestamp_millis())
     }
 
     /// Deserialize a `NaiveDateTime` from a milliseconds timestamp
@@ -653,20 +686,22 @@
     /// # Example:
     ///
     /// ```rust
-    /// # use chrono::NaiveDateTime;
+    /// # use chrono::{DateTime, NaiveDateTime};
     /// # use serde_derive::Deserialize;
     /// use chrono::naive::serde::ts_milliseconds::deserialize as from_milli_ts;
     /// #[derive(Debug, PartialEq, Deserialize)]
     /// struct S {
     ///     #[serde(deserialize_with = "from_milli_ts")]
-    ///     time: NaiveDateTime
+    ///     time: NaiveDateTime,
     /// }
     ///
     /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918 }"#)?;
-    /// assert_eq!(my_s, S { time: NaiveDateTime::from_timestamp_opt(1526522699, 918000000).unwrap() });
+    /// let expected = DateTime::from_timestamp(1526522699, 918000000).unwrap().naive_utc();
+    /// assert_eq!(my_s, S { time: expected });
     ///
     /// let my_s: S = serde_json::from_str(r#"{ "time": -1 }"#)?;
-    /// assert_eq!(my_s, S { time: NaiveDateTime::from_timestamp_opt(-1, 999_000_000).unwrap() });
+    /// let expected = DateTime::from_timestamp(-1, 999_000_000).unwrap().naive_utc();
+    /// assert_eq!(my_s, S { time: expected });
     /// # Ok::<(), serde_json::Error>(())
     /// ```
     pub fn deserialize<'de, D>(d: D) -> Result<NaiveDateTime, D::Error>
@@ -678,7 +713,7 @@
 
     pub(super) struct MilliSecondsTimestampVisitor;
 
-    impl<'de> de::Visitor<'de> for MilliSecondsTimestampVisitor {
+    impl de::Visitor<'_> for MilliSecondsTimestampVisitor {
         type Value = NaiveDateTime;
 
         fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
@@ -689,19 +724,18 @@
         where
             E: de::Error,
         {
-            NaiveDateTime::from_timestamp_millis(value)
-                .ok_or_else(|| E::custom(ne_timestamp(value)))
+            DateTime::from_timestamp_millis(value)
+                .map(|dt| dt.naive_utc())
+                .ok_or_else(|| invalid_ts(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)))
+            DateTime::from_timestamp((value / 1000) as i64, ((value % 1000) * 1_000_000) as u32)
+                .map(|dt| dt.naive_utc())
+                .ok_or_else(|| invalid_ts(value))
         }
     }
 }
@@ -719,13 +753,13 @@
 /// #[derive(Deserialize, Serialize)]
 /// struct S {
 ///     #[serde(with = "ts_milliseconds_option")]
-///     time: Option<NaiveDateTime>
+///     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 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}"#);
@@ -753,11 +787,16 @@
     /// #[derive(Serialize)]
     /// struct S {
     ///     #[serde(serialize_with = "to_milli_tsopt")]
-    ///     time: Option<NaiveDateTime>
+    ///     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()),
+    ///     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}"#);
@@ -768,7 +807,7 @@
         S: ser::Serializer,
     {
         match *opt {
-            Some(ref dt) => serializer.serialize_some(&dt.timestamp_millis()),
+            Some(ref dt) => serializer.serialize_some(&dt.and_utc().timestamp_millis()),
             None => serializer.serialize_none(),
         }
     }
@@ -780,20 +819,22 @@
     /// # Example:
     ///
     /// ```rust
-    /// # use chrono::naive::NaiveDateTime;
+    /// # use chrono::{DateTime, NaiveDateTime};
     /// # use serde_derive::Deserialize;
     /// use chrono::naive::serde::ts_milliseconds_option::deserialize as from_milli_tsopt;
     /// #[derive(Debug, PartialEq, Deserialize)]
     /// struct S {
     ///     #[serde(deserialize_with = "from_milli_tsopt")]
-    ///     time: Option<NaiveDateTime>
+    ///     time: Option<NaiveDateTime>,
     /// }
     ///
     /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918 }"#)?;
-    /// assert_eq!(my_s, S { time: NaiveDateTime::from_timestamp_opt(1526522699, 918000000) });
+    /// let expected = DateTime::from_timestamp(1526522699, 918000000).unwrap().naive_utc();
+    /// assert_eq!(my_s, S { time: Some(expected) });
     ///
     /// let my_s: S = serde_json::from_str(r#"{ "time": -1 }"#)?;
-    /// assert_eq!(my_s, S { time: NaiveDateTime::from_timestamp_opt(-1, 999_000_000) });
+    /// let expected = DateTime::from_timestamp(-1, 999_000_000).unwrap().naive_utc();
+    /// assert_eq!(my_s, S { time: Some(expected) });
     /// # Ok::<(), serde_json::Error>(())
     /// ```
     pub fn deserialize<'de, D>(d: D) -> Result<Option<NaiveDateTime>, D::Error>
@@ -849,13 +890,11 @@
 /// #[derive(Deserialize, Serialize)]
 /// struct S {
 ///     #[serde(with = "ts_seconds")]
-///     time: NaiveDateTime
+///     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 my_s = S { time: time.clone() };
 ///
 /// let as_string = serde_json::to_string(&my_s)?;
 /// assert_eq!(as_string, r#"{"time":1431684000}"#);
@@ -867,8 +906,8 @@
     use core::fmt;
     use serde::{de, ser};
 
-    use super::ne_timestamp;
-    use crate::NaiveDateTime;
+    use crate::serde::invalid_ts;
+    use crate::{DateTime, NaiveDateTime};
 
     /// Serialize a datetime into an integer number of seconds since the epoch
     ///
@@ -883,12 +922,11 @@
     /// #[derive(Serialize)]
     /// struct S {
     ///     #[serde(serialize_with = "to_ts")]
-    ///     time: NaiveDateTime
+    ///     time: NaiveDateTime,
     /// }
     ///
-    /// let my_s = S {
-    ///     time: NaiveDate::from_ymd_opt(2015, 5, 15).unwrap().and_hms_opt(10, 0, 0).unwrap(),
-    /// };
+    /// 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>(())
@@ -897,7 +935,7 @@
     where
         S: ser::Serializer,
     {
-        serializer.serialize_i64(dt.timestamp())
+        serializer.serialize_i64(dt.and_utc().timestamp())
     }
 
     /// Deserialize a `NaiveDateTime` from a seconds timestamp
@@ -907,17 +945,18 @@
     /// # Example:
     ///
     /// ```rust
-    /// # use chrono::NaiveDateTime;
+    /// # use chrono::{DateTime, NaiveDateTime};
     /// # use serde_derive::Deserialize;
     /// use chrono::naive::serde::ts_seconds::deserialize as from_ts;
     /// #[derive(Debug, PartialEq, Deserialize)]
     /// struct S {
     ///     #[serde(deserialize_with = "from_ts")]
-    ///     time: NaiveDateTime
+    ///     time: NaiveDateTime,
     /// }
     ///
     /// let my_s: S = serde_json::from_str(r#"{ "time": 1431684000 }"#)?;
-    /// assert_eq!(my_s, S { time: NaiveDateTime::from_timestamp_opt(1431684000, 0).unwrap() });
+    /// let expected = DateTime::from_timestamp(1431684000, 0).unwrap().naive_utc();
+    /// assert_eq!(my_s, S { time: expected });
     /// # Ok::<(), serde_json::Error>(())
     /// ```
     pub fn deserialize<'de, D>(d: D) -> Result<NaiveDateTime, D::Error>
@@ -929,7 +968,7 @@
 
     pub(super) struct SecondsTimestampVisitor;
 
-    impl<'de> de::Visitor<'de> for SecondsTimestampVisitor {
+    impl de::Visitor<'_> for SecondsTimestampVisitor {
         type Value = NaiveDateTime;
 
         fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
@@ -940,16 +979,22 @@
         where
             E: de::Error,
         {
-            NaiveDateTime::from_timestamp_opt(value, 0)
-                .ok_or_else(|| E::custom(ne_timestamp(value)))
+            DateTime::from_timestamp(value, 0)
+                .map(|dt| dt.naive_utc())
+                .ok_or_else(|| invalid_ts(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)))
+            if value > i64::MAX as u64 {
+                Err(invalid_ts(value))
+            } else {
+                DateTime::from_timestamp(value as i64, 0)
+                    .map(|dt| dt.naive_utc())
+                    .ok_or_else(|| invalid_ts(value))
+            }
         }
     }
 }
@@ -967,13 +1012,11 @@
 /// #[derive(Deserialize, Serialize)]
 /// struct S {
 ///     #[serde(with = "ts_seconds_option")]
-///     time: Option<NaiveDateTime>
+///     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 my_s = S { time: time.clone() };
 ///
 /// let as_string = serde_json::to_string(&my_s)?;
 /// assert_eq!(as_string, r#"{"time":1526522699}"#);
@@ -1001,12 +1044,11 @@
     /// #[derive(Serialize)]
     /// struct S {
     ///     #[serde(serialize_with = "to_tsopt")]
-    ///     time: Option<NaiveDateTime>
+    ///     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 expected = NaiveDate::from_ymd_opt(2018, 5, 17).unwrap().and_hms_opt(02, 04, 59).unwrap();
+    /// let my_s = S { time: Some(expected) };
     /// let as_string = serde_json::to_string(&my_s)?;
     /// assert_eq!(as_string, r#"{"time":1526522699}"#);
     /// # Ok::<(), serde_json::Error>(())
@@ -1016,7 +1058,7 @@
         S: ser::Serializer,
     {
         match *opt {
-            Some(ref dt) => serializer.serialize_some(&dt.timestamp()),
+            Some(ref dt) => serializer.serialize_some(&dt.and_utc().timestamp()),
             None => serializer.serialize_none(),
         }
     }
@@ -1028,17 +1070,18 @@
     /// # Example:
     ///
     /// ```rust
-    /// # use chrono::naive::NaiveDateTime;
+    /// # use chrono::{DateTime, NaiveDateTime};
     /// # use serde_derive::Deserialize;
     /// use chrono::naive::serde::ts_seconds_option::deserialize as from_tsopt;
     /// #[derive(Debug, PartialEq, Deserialize)]
     /// struct S {
     ///     #[serde(deserialize_with = "from_tsopt")]
-    ///     time: Option<NaiveDateTime>
+    ///     time: Option<NaiveDateTime>,
     /// }
     ///
     /// let my_s: S = serde_json::from_str(r#"{ "time": 1431684000 }"#)?;
-    /// assert_eq!(my_s, S { time: NaiveDateTime::from_timestamp_opt(1431684000, 0) });
+    /// let expected = DateTime::from_timestamp(1431684000, 0).unwrap().naive_utc();
+    /// assert_eq!(my_s, S { time: Some(expected) });
     /// # Ok::<(), serde_json::Error>(())
     /// ```
     pub fn deserialize<'de, D>(d: D) -> Result<Option<NaiveDateTime>, D::Error>
@@ -1083,57 +1126,8 @@
     }
 }
 
-// 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
-            ),
-        }
-    }
-}
-
 #[cfg(test)]
 mod tests {
-    use crate::naive::datetime::{test_decodable_json, test_encodable_json};
     use crate::serde::ts_nanoseconds_option;
     use crate::{DateTime, NaiveDate, NaiveDateTime, TimeZone, Utc};
 
@@ -1142,12 +1136,142 @@
 
     #[test]
     fn test_serde_serialize() {
-        test_encodable_json(serde_json::to_string);
+        assert_eq!(
+            serde_json::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!(
+            serde_json::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!(
+            serde_json::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!(
+            serde_json::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!(
+            serde_json::to_string(&NaiveDate::MIN.and_hms_opt(0, 0, 0).unwrap()).ok(),
+            Some(r#""-262143-01-01T00:00:00""#.into())
+        );
+        assert_eq!(
+            serde_json::to_string(
+                &NaiveDate::MAX.and_hms_nano_opt(23, 59, 59, 1_999_999_999).unwrap()
+            )
+            .ok(),
+            Some(r#""+262142-12-31T23:59:60.999999999""#.into())
+        );
     }
 
     #[test]
     fn test_serde_deserialize() {
-        test_decodable_json(|input| serde_json::from_str(input));
+        let from_str = serde_json::from_str::<NaiveDateTime>;
+
+        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#""-262143-01-01T00:00:00""#).ok(),
+            Some(NaiveDate::MIN.and_hms_opt(0, 0, 0).unwrap())
+        );
+        assert_eq!(
+            from_str(r#""+262142-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#""+262142-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());
     }
 
     // Bincode is relevant to test separately from JSON because
diff --git a/crates/chrono/src/naive/datetime/tests.rs b/crates/chrono/src/naive/datetime/tests.rs
index 4d36208..1612458 100644
--- a/crates/chrono/src/naive/datetime/tests.rs
+++ b/crates/chrono/src/naive/datetime/tests.rs
@@ -1,146 +1,5 @@
 use super::NaiveDateTime;
-use crate::{Datelike, FixedOffset, LocalResult, NaiveDate, TimeDelta, Utc};
-
-#[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());
-        #[cfg(feature = "alloc")]
-        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());
-        #[cfg(feature = "alloc")]
-        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_nanos() {
-    let valid_map = [
-        (1662921288000000000, "2022-09-11 18:34:48.000000000"),
-        (1662921288123456000, "2022-09-11 18:34:48.123456000"),
-        (1662921288123456789, "2022-09-11 18:34:48.123456789"),
-        (1662921287890000000, "2022-09-11 18:34:47.890000000"),
-        (-2208936075000000000, "1900-01-01 14:38:45.000000000"),
-        (-5337182663000000000, "1800-11-15 01:15:37.000000000"),
-        (0, "1970-01-01 00:00:00.000000000"),
-        (119731017000000000, "1973-10-17 18:36:57.000000000"),
-        (1234567890000000000, "2009-02-13 23:31:30.000000000"),
-        (2034061609000000000, "2034-06-16 09:06:49.000000000"),
-    ];
-
-    for (timestamp_nanos, _formatted) in valid_map.iter().copied() {
-        let naive_datetime = NaiveDateTime::from_timestamp_nanos(timestamp_nanos).unwrap();
-        assert_eq!(timestamp_nanos, naive_datetime.timestamp_nanos_opt().unwrap());
-        #[cfg(feature = "alloc")]
-        assert_eq!(naive_datetime.format("%F %T%.9f").to_string(), _formatted);
-    }
-
-    const A_BILLION: i64 = 1_000_000_000;
-    // Maximum datetime in nanoseconds
-    let maximum = "2262-04-11T23:47:16.854775804";
-    let parsed: NaiveDateTime = maximum.parse().unwrap();
-    let nanos = parsed.timestamp_nanos_opt().unwrap();
-    assert_eq!(
-        NaiveDateTime::from_timestamp_nanos(nanos).unwrap(),
-        NaiveDateTime::from_timestamp_opt(nanos / A_BILLION, (nanos % A_BILLION) as u32).unwrap()
-    );
-    // Minimum datetime in nanoseconds
-    let minimum = "1677-09-21T00:12:44.000000000";
-    let parsed: NaiveDateTime = minimum.parse().unwrap();
-    let nanos = parsed.timestamp_nanos_opt().unwrap();
-    assert_eq!(
-        NaiveDateTime::from_timestamp_nanos(nanos).unwrap(),
-        NaiveDateTime::from_timestamp_opt(nanos / A_BILLION, (nanos % A_BILLION) as u32).unwrap()
-    );
-
-    // Test that the result of `from_timestamp_nanos` 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_nanos(secs * 1_000_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);
-}
+use crate::{Datelike, FixedOffset, MappedLocalTime, NaiveDate, TimeDelta, Utc};
 
 #[test]
 fn test_datetime_add() {
@@ -156,13 +15,14 @@
         assert_eq!(lhs.checked_add_signed(rhs), sum);
         assert_eq!(lhs.checked_sub_signed(-rhs), sum);
     }
+    let seconds = |s| TimeDelta::try_seconds(s).unwrap();
 
-    check((2014, 5, 6, 7, 8, 9), TimeDelta::seconds(3600 + 60 + 1), Some((2014, 5, 6, 8, 9, 10)));
-    check((2014, 5, 6, 7, 8, 9), TimeDelta::seconds(-(3600 + 60 + 1)), Some((2014, 5, 6, 6, 7, 8)));
-    check((2014, 5, 6, 7, 8, 9), TimeDelta::seconds(86399), Some((2014, 5, 7, 7, 8, 8)));
-    check((2014, 5, 6, 7, 8, 9), TimeDelta::seconds(86_400 * 10), Some((2014, 5, 16, 7, 8, 9)));
-    check((2014, 5, 6, 7, 8, 9), TimeDelta::seconds(-86_400 * 10), Some((2014, 4, 26, 7, 8, 9)));
-    check((2014, 5, 6, 7, 8, 9), TimeDelta::seconds(86_400 * 10), Some((2014, 5, 16, 7, 8, 9)));
+    check((2014, 5, 6, 7, 8, 9), seconds(3600 + 60 + 1), Some((2014, 5, 6, 8, 9, 10)));
+    check((2014, 5, 6, 7, 8, 9), seconds(-(3600 + 60 + 1)), Some((2014, 5, 6, 6, 7, 8)));
+    check((2014, 5, 6, 7, 8, 9), seconds(86399), Some((2014, 5, 7, 7, 8, 8)));
+    check((2014, 5, 6, 7, 8, 9), seconds(86_400 * 10), Some((2014, 5, 16, 7, 8, 9)));
+    check((2014, 5, 6, 7, 8, 9), seconds(-86_400 * 10), Some((2014, 4, 26, 7, 8, 9)));
+    check((2014, 5, 6, 7, 8, 9), 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`.
@@ -172,17 +32,17 @@
     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 + TimeDelta::seconds(86399),
+        max_days_from_year_0 + seconds(86399),
         Some((NaiveDate::MAX.year(), 12, 31, 23, 59, 59)),
     );
-    check((0, 1, 1, 0, 0, 0), max_days_from_year_0 + TimeDelta::seconds(86_400), None);
-    check((0, 1, 1, 0, 0, 0), TimeDelta::max_value(), None);
+    check((0, 1, 1, 0, 0, 0), max_days_from_year_0 + seconds(86_400), None);
+    check((0, 1, 1, 0, 0, 0), TimeDelta::MAX, 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 - TimeDelta::seconds(1), None);
-    check((0, 1, 1, 0, 0, 0), TimeDelta::min_value(), None);
+    check((0, 1, 1, 0, 0, 0), min_days_from_year_0 - seconds(1), None);
+    check((0, 1, 1, 0, 0, 0), TimeDelta::MIN, None);
 }
 
 #[test]
@@ -193,19 +53,19 @@
     assert_eq!(since(ymdhms(2014, 5, 6, 7, 8, 9), ymdhms(2014, 5, 6, 7, 8, 9)), TimeDelta::zero());
     assert_eq!(
         since(ymdhms(2014, 5, 6, 7, 8, 10), ymdhms(2014, 5, 6, 7, 8, 9)),
-        TimeDelta::seconds(1)
+        TimeDelta::try_seconds(1).unwrap()
     );
     assert_eq!(
         since(ymdhms(2014, 5, 6, 7, 8, 9), ymdhms(2014, 5, 6, 7, 8, 10)),
-        TimeDelta::seconds(-1)
+        TimeDelta::try_seconds(-1).unwrap()
     );
     assert_eq!(
         since(ymdhms(2014, 5, 7, 7, 8, 9), ymdhms(2014, 5, 6, 7, 8, 10)),
-        TimeDelta::seconds(86399)
+        TimeDelta::try_seconds(86399).unwrap()
     );
     assert_eq!(
         since(ymdhms(2001, 9, 9, 1, 46, 39), ymdhms(1970, 1, 1, 0, 0, 0)),
-        TimeDelta::seconds(999_999_999)
+        TimeDelta::try_seconds(999_999_999).unwrap()
     );
 }
 
@@ -214,9 +74,9 @@
     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 += TimeDelta::minutes(10_000_000);
+    date += TimeDelta::try_minutes(10_000_000).unwrap();
     assert_eq!(date, ymdhms(2035, 10, 6, 20, 50, 10));
-    date += TimeDelta::days(10);
+    date += TimeDelta::try_days(10).unwrap();
     assert_eq!(date, ymdhms(2035, 10, 16, 20, 50, 10));
 }
 
@@ -225,9 +85,9 @@
     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 -= TimeDelta::minutes(10_000_000);
+    date -= TimeDelta::try_minutes(10_000_000).unwrap();
     assert_eq!(date, ymdhms(1997, 9, 26, 23, 30, 10));
-    date -= TimeDelta::days(10);
+    date -= TimeDelta::try_days(10).unwrap();
     assert_eq!(date, ymdhms(1997, 9, 16, 23, 30, 10));
 }
 
@@ -253,18 +113,6 @@
 }
 
 #[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 = [
@@ -424,41 +272,9 @@
 }
 
 #[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_opt().unwrap();
-    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_opt().unwrap();
-    assert_eq!(
-        parsed,
-        NaiveDateTime::from_timestamp_opt(nanos / A_BILLION, (nanos % A_BILLION) as u32).unwrap()
-    );
-
-    // Just beyond range
-    let maximum = "2262-04-11T23:47:16.854775804";
-    let parsed: NaiveDateTime = maximum.parse().unwrap();
-    let beyond_max = parsed + TimeDelta::milliseconds(300);
-    assert!(beyond_max.timestamp_nanos_opt().is_none());
-
-    // Far beyond range
-    let maximum = "2262-04-11T23:47:16.854775804";
-    let parsed: NaiveDateTime = maximum.parse().unwrap();
-    let beyond_max = parsed + TimeDelta::days(365);
-    assert!(beyond_max.timestamp_nanos_opt().is_none());
-}
-
-#[test]
 fn test_and_local_timezone() {
     let ndt = NaiveDate::from_ymd_opt(2022, 6, 15).unwrap().and_hms_opt(18, 59, 36).unwrap();
-    let dt_utc = ndt.and_local_timezone(Utc).unwrap();
+    let dt_utc = ndt.and_utc();
     assert_eq!(dt_utc.naive_local(), ndt);
     assert_eq!(dt_utc.timezone(), Utc);
 
@@ -569,13 +385,13 @@
         if offset_hour >= 0 {
             assert_eq!(local_max.unwrap().naive_local(), NaiveDateTime::MAX);
         } else {
-            assert_eq!(local_max, LocalResult::None);
+            assert_eq!(local_max, MappedLocalTime::None);
         }
         let local_min = NaiveDateTime::MIN.and_local_timezone(offset);
         if offset_hour <= 0 {
             assert_eq!(local_min.unwrap().naive_local(), NaiveDateTime::MIN);
         } else {
-            assert_eq!(local_min, LocalResult::None);
+            assert_eq!(local_min, MappedLocalTime::None);
         }
     }
 }
diff --git a/crates/chrono/src/naive/internals.rs b/crates/chrono/src/naive/internals.rs
index c6d7536..da591f8 100644
--- a/crates/chrono/src/naive/internals.rs
+++ b/crates/chrono/src/naive/internals.rs
@@ -1,62 +1,50 @@
-// This is a part of Chrono.
-// See README.md and LICENSE.txt for details.
-
-//! The internal implementation of the calendar and ordinal date.
-//!
-//! The current implementation is optimized for determining year, month, day and day of week.
-//! 4-bit `YearFlags` map to one of 14 possible classes of year in the Gregorian calendar,
-//! which are included in every packed `NaiveDate` instance.
-//! The conversion between the packed calendar date (`Mdf`) and the ordinal date (`Of`) is
-//! based on the moderately-sized lookup table (~1.5KB)
-//! and the packed representation is chosen for the efficient lookup.
-//! Every internal data structure does not validate its input,
-//! 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.
+//! Internal helper types for working with dates.
 
 #![cfg_attr(feature = "__internal_bench", allow(missing_docs))]
 
-use crate::Weekday;
 use core::fmt;
 
-/// The internal date representation: `year << 13 | Of`
-pub(super) type DateImpl = i32;
-
-/// MAX_YEAR is one year less than the type is capable of representing. Internally we may sometimes
-/// use the headroom, notably to handle cases where the offset of a `DateTime` constructed with
-/// `NaiveDate::MAX` pushes it beyond the valid, representable range.
-pub(super) const MAX_YEAR: DateImpl = (i32::MAX >> 13) - 1;
-
-/// MIN_YEAR is one year more than the type is capable of representing. Internally we may sometimes
-/// use the headroom, notably to handle cases where the offset of a `DateTime` constructed with
-/// `NaiveDate::MIN` pushes it beyond the valid, representable range.
-pub(super) const MIN_YEAR: DateImpl = (i32::MIN >> 13) + 1;
-
-/// The year flags (aka the dominical letter).
+/// Year flags (aka the dominical letter).
+///
+/// `YearFlags` are used as the last four bits of `NaiveDate`, `Mdf` and `IsoWeek`.
 ///
 /// There are 14 possible classes of year in the Gregorian calendar:
 /// common and leap years starting with Monday through Sunday.
-/// The `YearFlags` stores this information into 4 bits `abbb`,
-/// 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).
+///
+/// The `YearFlags` stores this information into 4 bits `LWWW`. `L` is the leap year flag, with `1`
+/// for the common year (this simplifies validating an ordinal in `NaiveDate`). `WWW` is a non-zero
+/// `Weekday` of the last day in the preceding year.
 #[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);
+// Weekday of the last day in the preceding year.
+// Allows for quick day of week calculation from the 1-based ordinal.
+const YEAR_STARTS_AFTER_MONDAY: u8 = 7; // non-zero to allow use with `NonZero*`.
+const YEAR_STARTS_AFTER_THUESDAY: u8 = 1;
+const YEAR_STARTS_AFTER_WEDNESDAY: u8 = 2;
+const YEAR_STARTS_AFTER_THURSDAY: u8 = 3;
+const YEAR_STARTS_AFTER_FRIDAY: u8 = 4;
+const YEAR_STARTS_AFTER_SATURDAY: u8 = 5;
+const YEAR_STARTS_AFTER_SUNDAY: u8 = 6;
+
+const COMMON_YEAR: u8 = 1 << 3;
+const LEAP_YEAR: u8 = 0 << 3;
+
+pub(super) const A: YearFlags = YearFlags(COMMON_YEAR | YEAR_STARTS_AFTER_SATURDAY);
+pub(super) const AG: YearFlags = YearFlags(LEAP_YEAR | YEAR_STARTS_AFTER_SATURDAY);
+pub(super) const B: YearFlags = YearFlags(COMMON_YEAR | YEAR_STARTS_AFTER_FRIDAY);
+pub(super) const BA: YearFlags = YearFlags(LEAP_YEAR | YEAR_STARTS_AFTER_FRIDAY);
+pub(super) const C: YearFlags = YearFlags(COMMON_YEAR | YEAR_STARTS_AFTER_THURSDAY);
+pub(super) const CB: YearFlags = YearFlags(LEAP_YEAR | YEAR_STARTS_AFTER_THURSDAY);
+pub(super) const D: YearFlags = YearFlags(COMMON_YEAR | YEAR_STARTS_AFTER_WEDNESDAY);
+pub(super) const DC: YearFlags = YearFlags(LEAP_YEAR | YEAR_STARTS_AFTER_WEDNESDAY);
+pub(super) const E: YearFlags = YearFlags(COMMON_YEAR | YEAR_STARTS_AFTER_THUESDAY);
+pub(super) const ED: YearFlags = YearFlags(LEAP_YEAR | YEAR_STARTS_AFTER_THUESDAY);
+pub(super) const F: YearFlags = YearFlags(COMMON_YEAR | YEAR_STARTS_AFTER_MONDAY);
+pub(super) const FE: YearFlags = YearFlags(LEAP_YEAR | YEAR_STARTS_AFTER_MONDAY);
+pub(super) const G: YearFlags = YearFlags(COMMON_YEAR | YEAR_STARTS_AFTER_SUNDAY);
+pub(super) const GF: YearFlags = YearFlags(LEAP_YEAR | YEAR_STARTS_AFTER_SUNDAY);
 
 const YEAR_TO_FLAGS: &[YearFlags; 400] = &[
     BA, G, F, E, DC, B, A, G, FE, D, C, B, AG, F, E, D, CB, A, G, F, ED, C, B, A, GF, E, D, C, BA,
@@ -77,45 +65,6 @@
     D, CB, A, G, F, ED, C, B, A, GF, E, D, C, // 400
 ];
 
-const YEAR_DELTAS: &[u8; 401] = &[
-    0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8,
-    8, 9, 9, 9, 9, 10, 10, 10, 10, 11, 11, 11, 11, 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14,
-    15, 15, 15, 15, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19, 20, 20, 20, 20,
-    21, 21, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23, 24, 24, 24, 24, 25, 25, 25, // 100
-    25, 25, 25, 25, 25, 26, 26, 26, 26, 27, 27, 27, 27, 28, 28, 28, 28, 29, 29, 29, 29, 30, 30, 30,
-    30, 31, 31, 31, 31, 32, 32, 32, 32, 33, 33, 33, 33, 34, 34, 34, 34, 35, 35, 35, 35, 36, 36, 36,
-    36, 37, 37, 37, 37, 38, 38, 38, 38, 39, 39, 39, 39, 40, 40, 40, 40, 41, 41, 41, 41, 42, 42, 42,
-    42, 43, 43, 43, 43, 44, 44, 44, 44, 45, 45, 45, 45, 46, 46, 46, 46, 47, 47, 47, 47, 48, 48, 48,
-    48, 49, 49, 49, // 200
-    49, 49, 49, 49, 49, 50, 50, 50, 50, 51, 51, 51, 51, 52, 52, 52, 52, 53, 53, 53, 53, 54, 54, 54,
-    54, 55, 55, 55, 55, 56, 56, 56, 56, 57, 57, 57, 57, 58, 58, 58, 58, 59, 59, 59, 59, 60, 60, 60,
-    60, 61, 61, 61, 61, 62, 62, 62, 62, 63, 63, 63, 63, 64, 64, 64, 64, 65, 65, 65, 65, 66, 66, 66,
-    66, 67, 67, 67, 67, 68, 68, 68, 68, 69, 69, 69, 69, 70, 70, 70, 70, 71, 71, 71, 71, 72, 72, 72,
-    72, 73, 73, 73, // 300
-    73, 73, 73, 73, 73, 74, 74, 74, 74, 75, 75, 75, 75, 76, 76, 76, 76, 77, 77, 77, 77, 78, 78, 78,
-    78, 79, 79, 79, 79, 80, 80, 80, 80, 81, 81, 81, 81, 82, 82, 82, 82, 83, 83, 83, 83, 84, 84, 84,
-    84, 85, 85, 85, 85, 86, 86, 86, 86, 87, 87, 87, 87, 88, 88, 88, 88, 89, 89, 89, 89, 90, 90, 90,
-    90, 91, 91, 91, 91, 92, 92, 92, 92, 93, 93, 93, 93, 94, 94, 94, 94, 95, 95, 95, 95, 96, 96, 96,
-    96, 97, 97, 97, 97, // 400+1
-];
-
-pub(super) const fn cycle_to_yo(cycle: u32) -> (u32, u32) {
-    let mut year_mod_400 = cycle / 365;
-    let mut ordinal0 = cycle % 365;
-    let delta = YEAR_DELTAS[year_mod_400 as usize] as u32;
-    if ordinal0 < delta {
-        year_mod_400 -= 1;
-        ordinal0 += 365 - YEAR_DELTAS[year_mod_400 as usize] as u32;
-    } else {
-        ordinal0 -= delta;
-    }
-    (year_mod_400, ordinal0 + 1)
-}
-
-pub(super) const fn yo_to_cycle(year_mod_400: u32, ordinal: u32) -> u32 {
-    year_mod_400 * 365 + YEAR_DELTAS[year_mod_400 as usize] as u32 + ordinal - 1
-}
-
 impl YearFlags {
     #[allow(unreachable_pub)] // public as an alias for benchmarks only
     #[doc(hidden)] // for benchmarks only
@@ -180,11 +129,13 @@
 }
 
 // OL: (ordinal << 1) | leap year flag
-pub(super) const MIN_OL: u32 = 1 << 1;
-pub(super) const MAX_OL: u32 = 366 << 1; // `(366 << 1) | 1` would be day 366 in a non-leap year
-pub(super) const MAX_MDL: u32 = (12 << 6) | (31 << 1) | 1;
+const MAX_OL: u32 = 366 << 1; // `(366 << 1) | 1` would be day 366 in a non-leap year
+const MAX_MDL: u32 = (12 << 6) | (31 << 1) | 1;
 
-const XX: i8 = -128;
+// The next table are adjustment values to convert a date encoded as month-day-leapyear to
+// ordinal-leapyear. OL = MDL - adjustment.
+// Dates that do not exist are encoded as `XX`.
+const XX: i8 = 0;
 const MDL_TO_OL: &[i8; MAX_MDL as usize + 1] = &[
     XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX,
     XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX,
@@ -269,178 +220,62 @@
     98, // 12
 ];
 
-/// Ordinal (day of year) and year flags: `(ordinal << 4) | flags`.
-///
-/// The whole bits except for the least 3 bits are referred as `Ol` (ordinal and leap flag),
-/// which is an index to the `OL_TO_MDL` lookup table.
-///
-/// The methods implemented on `Of` always return a valid value.
-#[derive(PartialEq, PartialOrd, Copy, Clone)]
-pub(super) struct Of(u32);
-
-impl Of {
-    #[inline]
-    pub(super) const fn new(ordinal: u32, YearFlags(flags): YearFlags) -> Option<Of> {
-        let of = Of((ordinal << 4) | flags as u32);
-        of.validate()
-    }
-
-    pub(super) const fn from_date_impl(date_impl: DateImpl) -> Of {
-        // We assume the value in the `DateImpl` is valid.
-        Of((date_impl & 0b1_1111_1111_1111) as u32)
-    }
-
-    #[inline]
-    pub(super) const fn from_mdf(Mdf(mdf): Mdf) -> Option<Of> {
-        let mdl = mdf >> 3;
-        if mdl > MAX_MDL {
-            // Panicking on out-of-bounds indexing would be reasonable, but just return `None`.
-            return None;
-        }
-        // Array is indexed from `[1..=MAX_MDL]`, with a `0` index having a meaningless value.
-        let v = MDL_TO_OL[mdl as usize];
-        let of = Of(mdf.wrapping_sub((v as i32 as u32 & 0x3ff) << 3));
-        of.validate()
-    }
-
-    #[inline]
-    pub(super) const fn inner(&self) -> u32 {
-        self.0
-    }
-
-    /// Returns `(ordinal << 1) | leap-year-flag`.
-    #[inline]
-    const fn ol(&self) -> u32 {
-        self.0 >> 3
-    }
-
-    #[inline]
-    const fn validate(self) -> Option<Of> {
-        let ol = self.ol();
-        match ol >= MIN_OL && ol <= MAX_OL {
-            true => Some(self),
-            false => None,
-        }
-    }
-
-    #[inline]
-    pub(super) const fn ordinal(&self) -> u32 {
-        self.0 >> 4
-    }
-
-    #[inline]
-    pub(super) const fn with_ordinal(&self, ordinal: u32) -> Option<Of> {
-        let of = Of((ordinal << 4) | (self.0 & 0b1111));
-        of.validate()
-    }
-
-    #[inline]
-    pub(super) const fn flags(&self) -> YearFlags {
-        YearFlags((self.0 & 0b1111) as u8)
-    }
-
-    #[inline]
-    pub(super) const fn weekday(&self) -> Weekday {
-        let Of(of) = *self;
-        weekday_from_u32_mod7((of >> 4) + (of & 0b111))
-    }
-
-    #[inline]
-    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_mod7(weekord))
-    }
-
-    #[cfg_attr(feature = "cargo-clippy", allow(clippy::wrong_self_convention))]
-    #[inline]
-    pub(super) const fn to_mdf(&self) -> Mdf {
-        Mdf::from_of(*self)
-    }
-
-    /// Returns an `Of` with the next day, or `None` if this is the last day of the year.
-    #[inline]
-    pub(super) const fn succ(&self) -> Option<Of> {
-        let of = Of(self.0 + (1 << 4));
-        of.validate()
-    }
-
-    /// Returns an `Of` with the previous day, or `None` if this is the first day of the year.
-    #[inline]
-    pub(super) const fn pred(&self) -> Option<Of> {
-        match self.ordinal() {
-            1 => None,
-            _ => Some(Of(self.0 - (1 << 4))),
-        }
-    }
-}
-
-impl fmt::Debug for Of {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        let Of(of) = *self;
-        write!(
-            f,
-            "Of(({} << 4) | {:#04o} /*{:?}*/)",
-            of >> 4,
-            of & 0b1111,
-            YearFlags((of & 0b1111) as u8)
-        )
-    }
-}
-
 /// Month, day of month and year flags: `(month << 9) | (day << 4) | flags`
+/// `M_MMMD_DDDD_LFFF`
 ///
-/// The whole bits except for the least 3 bits are referred as `Mdl`
-/// (month, day of month and leap flag),
-/// which is an index to the `MDL_TO_OL` lookup table.
+/// The whole bits except for the least 3 bits are referred as `Mdl` (month, day of month, and leap
+/// year flag), which is an index to the `MDL_TO_OL` lookup table.
 ///
-/// The methods implemented on `Mdf` do not always return a valid value.
-/// Dates that can't exist, like February 30, can still be represented.
-/// Use `Mdl::valid` to check whether the date is valid.
+/// The conversion between the packed calendar date (`Mdf`) and the ordinal date (`NaiveDate`) is
+/// based on the moderately-sized lookup table (~1.5KB) and the packed representation is chosen for
+/// efficient lookup.
+///
+/// The methods of `Mdf` validate their inputs as late as possible. Dates that can't exist, like
+/// February 30, can still be represented. This allows the validation to be combined with the final
+/// table lookup, which is good for performance.
 #[derive(PartialEq, PartialOrd, Copy, Clone)]
 pub(super) struct Mdf(u32);
 
 impl Mdf {
+    /// Makes a new `Mdf` value from month, day and `YearFlags`.
+    ///
+    /// This method doesn't fully validate the range of the `month` and `day` parameters, only as
+    /// much as what can't be deferred until later. The year `flags` are trusted to be correct.
+    ///
+    /// # Errors
+    ///
+    /// Returns `None` if `month > 12` or `day > 31`.
     #[inline]
     pub(super) const fn new(month: u32, day: u32, YearFlags(flags): YearFlags) -> Option<Mdf> {
-        match month >= 1 && month <= 12 && day >= 1 && day <= 31 {
+        match month <= 12 && day <= 31 {
             true => Some(Mdf((month << 9) | (day << 4) | flags as u32)),
             false => None,
         }
     }
 
+    /// Makes a new `Mdf` value from an `i32` with an ordinal and a leap year flag, and year
+    /// `flags`.
+    ///
+    /// The `ol` is trusted to be valid, and the `flags` are trusted to match it.
     #[inline]
-    pub(super) const fn from_of(Of(of): Of) -> Mdf {
-        let ol = of >> 3;
-        if ol <= MAX_OL {
-            // Array is indexed from `[1..=MAX_OL]`, with a `0` index having a meaningless value.
-            Mdf(of + ((OL_TO_MDL[ol as usize] as u32) << 3))
-        } else {
-            // Panicking here would be reasonable, but we are just going on with a safe value.
-            Mdf(0)
-        }
+    pub(super) const fn from_ol(ol: i32, YearFlags(flags): YearFlags) -> Mdf {
+        debug_assert!(ol > 1 && ol <= MAX_OL as i32);
+        // Array is indexed from `[2..=MAX_OL]`, with a `0` index having a meaningless value.
+        Mdf(((ol as u32 + OL_TO_MDL[ol as usize] as u32) << 3) | flags as u32)
     }
 
-    #[cfg(test)]
-    pub(super) const fn valid(&self) -> bool {
-        let Mdf(mdf) = *self;
-        let mdl = mdf >> 3;
-        if mdl <= MAX_MDL {
-            // Array is indexed from `[1..=MAX_MDL]`, with a `0` index having a meaningless value.
-            MDL_TO_OL[mdl as usize] >= 0
-        } else {
-            // Panicking here would be reasonable, but we are just going on with a safe value.
-            false
-        }
-    }
-
+    /// Returns the month of this `Mdf`.
     #[inline]
     pub(super) const fn month(&self) -> u32 {
         let Mdf(mdf) = *self;
         mdf >> 9
     }
 
+    /// Replaces the month of this `Mdf`, keeping the day and flags.
+    ///
+    /// # Errors
+    ///
+    /// Returns `None` if `month > 12`.
     #[inline]
     pub(super) const fn with_month(&self, month: u32) -> Option<Mdf> {
         if month > 12 {
@@ -451,12 +286,18 @@
         Some(Mdf((mdf & 0b1_1111_1111) | (month << 9)))
     }
 
+    /// Returns the day of this `Mdf`.
     #[inline]
     pub(super) const fn day(&self) -> u32 {
         let Mdf(mdf) = *self;
         (mdf >> 4) & 0b1_1111
     }
 
+    /// Replaces the day of this `Mdf`, keeping the month and flags.
+    ///
+    /// # Errors
+    ///
+    /// Returns `None` if `day > 31`.
     #[inline]
     pub(super) const fn with_day(&self, day: u32) -> Option<Mdf> {
         if day > 31 {
@@ -467,16 +308,59 @@
         Some(Mdf((mdf & !0b1_1111_0000) | (day << 4)))
     }
 
+    /// Replaces the flags of this `Mdf`, keeping the month and day.
     #[inline]
     pub(super) const fn with_flags(&self, YearFlags(flags): YearFlags) -> Mdf {
         let Mdf(mdf) = *self;
         Mdf((mdf & !0b1111) | flags as u32)
     }
 
-    #[cfg_attr(feature = "cargo-clippy", allow(clippy::wrong_self_convention))]
+    /// Returns the ordinal that corresponds to this `Mdf`.
+    ///
+    /// This does a table lookup to calculate the corresponding ordinal. It will return an error if
+    /// the `Mdl` turns out not to be a valid date.
+    ///
+    /// # Errors
+    ///
+    /// Returns `None` if `month == 0` or `day == 0`, or if a the given day does not exist in the
+    /// given month.
     #[inline]
-    pub(super) const fn to_of(&self) -> Option<Of> {
-        Of::from_mdf(*self)
+    pub(super) const fn ordinal(&self) -> Option<u32> {
+        let mdl = self.0 >> 3;
+        match MDL_TO_OL[mdl as usize] {
+            XX => None,
+            v => Some((mdl - v as u8 as u32) >> 1),
+        }
+    }
+
+    /// Returns the year flags of this `Mdf`.
+    #[inline]
+    pub(super) const fn year_flags(&self) -> YearFlags {
+        YearFlags((self.0 & 0b1111) as u8)
+    }
+
+    /// Returns the ordinal that corresponds to this `Mdf`, encoded as a value including year flags.
+    ///
+    /// This does a table lookup to calculate the corresponding ordinal. It will return an error if
+    /// the `Mdl` turns out not to be a valid date.
+    ///
+    /// # Errors
+    ///
+    /// Returns `None` if `month == 0` or `day == 0`, or if a the given day does not exist in the
+    /// given month.
+    #[inline]
+    pub(super) const fn ordinal_and_flags(&self) -> Option<i32> {
+        let mdl = self.0 >> 3;
+        match MDL_TO_OL[mdl as usize] {
+            XX => None,
+            v => Some(self.0 as i32 - ((v as i32) << 3)),
+        }
+    }
+
+    #[cfg(test)]
+    fn valid(&self) -> bool {
+        let mdl = self.0 >> 3;
+        MDL_TO_OL[mdl as usize] > 0
     }
 }
 
@@ -494,27 +378,10 @@
     }
 }
 
-/// Create a `Weekday` from an `u32`, with Monday = 0.
-/// Infallible, takes any `n` and applies `% 7`.
-#[inline]
-const fn weekday_from_u32_mod7(n: u32) -> Weekday {
-    match n % 7 {
-        0 => Weekday::Mon,
-        1 => Weekday::Tue,
-        2 => Weekday::Wed,
-        3 => Weekday::Thu,
-        4 => Weekday::Fri,
-        5 => Weekday::Sat,
-        _ => Weekday::Sun,
-    }
-}
-
 #[cfg(test)]
 mod tests {
-    use super::weekday_from_u32_mod7;
-    use super::{Mdf, Of};
+    use super::Mdf;
     use super::{YearFlags, A, AG, B, BA, C, CB, D, DC, E, ED, F, FE, G, GF};
-    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];
@@ -556,42 +423,6 @@
     }
 
     #[test]
-    fn test_of() {
-        fn check(expected: bool, flags: YearFlags, ordinal1: u32, ordinal2: u32) {
-            for ordinal in ordinal1..=ordinal2 {
-                let of = match Of::new(ordinal, flags) {
-                    Some(of) => of,
-                    None if !expected => continue,
-                    None => panic!("Of::new({}, {:?}) returned None", ordinal, flags),
-                };
-
-                assert!(
-                    of.validate().is_some() == expected,
-                    "ordinal {} = {:?} should be {} for dominical year {:?}",
-                    ordinal,
-                    of,
-                    if expected { "valid" } else { "invalid" },
-                    flags
-                );
-            }
-        }
-
-        for &flags in NONLEAP_FLAGS.iter() {
-            check(false, flags, 0, 0);
-            check(true, flags, 1, 365);
-            check(false, flags, 366, 1024);
-            check(false, flags, u32::MAX, u32::MAX);
-        }
-
-        for &flags in LEAP_FLAGS.iter() {
-            check(false, flags, 0, 0);
-            check(true, flags, 1, 366);
-            check(false, flags, 367, 1024);
-            check(false, flags, u32::MAX, u32::MAX);
-        }
-    }
-
-    #[test]
     fn test_mdf_valid() {
         fn check(expected: bool, flags: YearFlags, month1: u32, day1: u32, month2: u32, day2: u32) {
             for month in month1..=month2 {
@@ -683,69 +514,6 @@
     }
 
     #[test]
-    fn test_of_fields() {
-        for &flags in FLAGS.iter() {
-            for ordinal in 1u32..=366 {
-                if let Some(of) = Of::new(ordinal, flags) {
-                    assert_eq!(of.ordinal(), ordinal);
-                }
-            }
-        }
-    }
-
-    #[test]
-    fn test_of_with_fields() {
-        fn check(flags: YearFlags, ordinal: u32) {
-            let of = Of::new(ordinal, flags).unwrap();
-
-            for ordinal in 0u32..=1024 {
-                let of = of.with_ordinal(ordinal);
-                assert_eq!(of, Of::new(ordinal, flags));
-                if let Some(of) = of {
-                    assert_eq!(of.ordinal(), ordinal);
-                }
-            }
-        }
-
-        for &flags in NONLEAP_FLAGS.iter() {
-            check(flags, 1);
-            check(flags, 365);
-        }
-        for &flags in LEAP_FLAGS.iter() {
-            check(flags, 1);
-            check(flags, 366);
-        }
-    }
-
-    #[test]
-    fn test_of_weekday() {
-        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).unwrap().weekday();
-            for ordinal in 2u32..=flags.ndays() {
-                let of = Of::new(ordinal, flags).unwrap();
-                let expected = prev.succ();
-                assert_eq!(of.weekday(), expected);
-                prev = expected;
-            }
-        }
-    }
-
-    #[test]
     fn test_mdf_fields() {
         for &flags in FLAGS.iter() {
             for month in 1u32..=12 {
@@ -815,84 +583,9 @@
     }
 
     #[test]
-    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).unwrap().isoweekdate_raw();
-            assert_eq!(week, 1);
-        }
-    }
-
-    #[test]
-    fn test_of_to_mdf() {
-        for i in 0u32..=8192 {
-            if let Some(of) = Of(i).validate() {
-                assert!(of.to_mdf().valid());
-            }
-        }
-    }
-
-    #[test]
-    fn test_mdf_to_of() {
-        for i in 0u32..=8192 {
-            let mdf = Mdf(i);
-            assert_eq!(mdf.valid(), mdf.to_of().is_some());
-        }
-    }
-
-    #[test]
-    fn test_of_to_mdf_to_of() {
-        for i in 0u32..=8192 {
-            if let Some(of) = Of(i).validate() {
-                assert_eq!(of, of.to_mdf().to_of().unwrap());
-            }
-        }
-    }
-
-    #[test]
-    fn test_mdf_to_of_to_mdf() {
-        for i in 0u32..=8192 {
-            let mdf = Mdf(i);
-            if mdf.valid() {
-                assert_eq!(mdf, mdf.to_of().unwrap().to_mdf());
-            }
-        }
-    }
-
-    #[test]
-    fn test_invalid_returns_none() {
-        let regular_year = YearFlags::from_year(2023);
-        let leap_year = YearFlags::from_year(2024);
-        assert!(Of::new(0, regular_year).is_none());
-        assert!(Of::new(366, regular_year).is_none());
-        assert!(Of::new(366, leap_year).is_some());
-        assert!(Of::new(367, regular_year).is_none());
-
-        assert!(Mdf::new(0, 1, regular_year).is_none());
-        assert!(Mdf::new(13, 1, regular_year).is_none());
-        assert!(Mdf::new(1, 0, regular_year).is_none());
-        assert!(Mdf::new(1, 32, regular_year).is_none());
-        assert!(Mdf::new(2, 31, regular_year).is_some());
-
-        assert!(Of::from_mdf(Mdf::new(2, 30, regular_year).unwrap()).is_none());
-        assert!(Of::from_mdf(Mdf::new(2, 30, leap_year).unwrap()).is_none());
-        assert!(Of::from_mdf(Mdf::new(2, 29, regular_year).unwrap()).is_none());
-        assert!(Of::from_mdf(Mdf::new(2, 29, leap_year).unwrap()).is_some());
-        assert!(Of::from_mdf(Mdf::new(2, 28, regular_year).unwrap()).is_some());
-
-        assert!(Of::new(365, regular_year).unwrap().succ().is_none());
-        assert!(Of::new(365, leap_year).unwrap().succ().is_some());
-        assert!(Of::new(366, leap_year).unwrap().succ().is_none());
-
-        assert!(Of::new(1, regular_year).unwrap().pred().is_none());
-        assert!(Of::new(1, leap_year).unwrap().pred().is_none());
-    }
-
-    #[test]
-    fn test_weekday_from_u32_mod7() {
-        for i in 0..=1000 {
-            assert_eq!(weekday_from_u32_mod7(i), Weekday::try_from((i % 7) as u8).unwrap());
-        }
-        assert_eq!(weekday_from_u32_mod7(u32::MAX), Weekday::Thu);
+    fn test_mdf_new_range() {
+        let flags = YearFlags::from_year(2023);
+        assert!(Mdf::new(13, 1, flags).is_none());
+        assert!(Mdf::new(1, 32, flags).is_none());
     }
 }
diff --git a/crates/chrono/src/naive/isoweek.rs b/crates/chrono/src/naive/isoweek.rs
index 4b3d8d9..93d0dc4 100644
--- a/crates/chrono/src/naive/isoweek.rs
+++ b/crates/chrono/src/naive/isoweek.rs
@@ -5,7 +5,7 @@
 
 use core::fmt;
 
-use super::internals::{DateImpl, Of, YearFlags};
+use super::internals::YearFlags;
 
 #[cfg(any(feature = "rkyv", feature = "rkyv-16", feature = "rkyv-32", feature = "rkyv-64"))]
 use rkyv::{Archive, Deserialize, Serialize};
@@ -25,44 +25,44 @@
 )]
 #[cfg_attr(feature = "rkyv-validation", archive(check_bytes))]
 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,
+    // 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,
     // which year number might not match the calendar year number.
-    ywf: DateImpl, // (year << 10) | (week << 4) | flag
-}
-
-/// Returns the corresponding `IsoWeek` from the year and the `Of` internal value.
-//
-// internal use only. we don't expose the public constructor for `IsoWeek` for now,
-// 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(super) fn iso_week_from_yof(year: i32, of: Of) -> IsoWeek {
-    let (rawweek, _) = of.isoweekdate_raw();
-    let (year, week) = if rawweek < 1 {
-        // previous year
-        let prevlastweek = YearFlags::from_year(year - 1).nisoweeks();
-        (year - 1, prevlastweek)
-    } else {
-        let lastweek = of.flags().nisoweeks();
-        if rawweek > lastweek {
-            // next year
-            (year + 1, 1)
-        } else {
-            (year, rawweek)
-        }
-    };
-    let flags = YearFlags::from_year(year);
-    IsoWeek { ywf: (year << 10) | (week << 4) as DateImpl | DateImpl::from(flags.0) }
+    ywf: i32, // (year << 10) | (week << 4) | flag
 }
 
 impl IsoWeek {
+    /// Returns the corresponding `IsoWeek` from the year and the `Of` internal value.
+    //
+    // Internal use only. We don't expose the public constructor for `IsoWeek` for now
+    // 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(super) fn from_yof(year: i32, ordinal: u32, year_flags: YearFlags) -> Self {
+        let rawweek = (ordinal + year_flags.isoweek_delta()) / 7;
+        let (year, week) = if rawweek < 1 {
+            // previous year
+            let prevlastweek = YearFlags::from_year(year - 1).nisoweeks();
+            (year - 1, prevlastweek)
+        } else {
+            let lastweek = year_flags.nisoweeks();
+            if rawweek > lastweek {
+                // next year
+                (year + 1, 1)
+            } else {
+                (year, rawweek)
+            }
+        };
+        let flags = YearFlags::from_year(year);
+        IsoWeek { ywf: (year << 10) | (week << 4) as i32 | i32::from(flags.0) }
+    }
+
     /// Returns the year number for this ISO week.
     ///
     /// # Example
     ///
     /// ```
-    /// use chrono::{NaiveDate, Datelike, Weekday};
+    /// use chrono::{Datelike, NaiveDate, Weekday};
     ///
     /// let d = NaiveDate::from_isoywd_opt(2015, 1, Weekday::Mon).unwrap();
     /// assert_eq!(d.iso_week().year(), 2015);
@@ -89,7 +89,7 @@
     /// # Example
     ///
     /// ```
-    /// use chrono::{NaiveDate, Datelike, Weekday};
+    /// use chrono::{Datelike, NaiveDate, Weekday};
     ///
     /// let d = NaiveDate::from_isoywd_opt(2015, 15, Weekday::Mon).unwrap();
     /// assert_eq!(d.iso_week().week(), 15);
@@ -106,7 +106,7 @@
     /// # Example
     ///
     /// ```
-    /// use chrono::{NaiveDate, Datelike, Weekday};
+    /// use chrono::{Datelike, NaiveDate, Weekday};
     ///
     /// let d = NaiveDate::from_isoywd_opt(2015, 15, Weekday::Mon).unwrap();
     /// assert_eq!(d.iso_week().week0(), 14);
@@ -124,19 +124,28 @@
 /// # Example
 ///
 /// ```
-/// use chrono::{NaiveDate, Datelike};
+/// use chrono::{Datelike, NaiveDate};
 ///
-/// 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");
+/// 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_opt(    0,  1,  2).unwrap().iso_week()),  "-0001-W52");
-/// assert_eq!(format!("{:?}", NaiveDate::from_ymd_opt(10000, 12, 31).unwrap().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 {
@@ -155,7 +164,7 @@
 mod tests {
     #[cfg(feature = "rkyv-validation")]
     use super::IsoWeek;
-    use crate::naive::{internals, NaiveDate};
+    use crate::naive::date::{self, NaiveDate};
     use crate::Datelike;
 
     #[test]
@@ -163,13 +172,13 @@
         let minweek = NaiveDate::MIN.iso_week();
         let maxweek = NaiveDate::MAX.iso_week();
 
-        assert_eq!(minweek.year(), internals::MIN_YEAR);
+        assert_eq!(minweek.year(), date::MIN_YEAR);
         assert_eq!(minweek.week(), 1);
         assert_eq!(minweek.week0(), 0);
         #[cfg(feature = "alloc")]
         assert_eq!(format!("{:?}", minweek), NaiveDate::MIN.format("%G-W%V").to_string());
 
-        assert_eq!(maxweek.year(), internals::MAX_YEAR + 1);
+        assert_eq!(maxweek.year(), date::MAX_YEAR + 1);
         assert_eq!(maxweek.week(), 1);
         assert_eq!(maxweek.week0(), 0);
         #[cfg(feature = "alloc")]
diff --git a/crates/chrono/src/naive/mod.rs b/crates/chrono/src/naive/mod.rs
index c8c281b..83ab69c 100644
--- a/crates/chrono/src/naive/mod.rs
+++ b/crates/chrono/src/naive/mod.rs
@@ -4,18 +4,20 @@
 //! (e.g. [`TimeZone`](../offset/trait.TimeZone.html)),
 //! but can be also used for the simpler date and time handling.
 
+use core::ops::RangeInclusive;
+
+use crate::expect;
+use crate::Weekday;
+
 pub(crate) mod date;
 pub(crate) mod datetime;
 mod internals;
 pub(crate) mod isoweek;
 pub(crate) mod time;
 
-pub use self::date::{Days, NaiveDate, NaiveDateDaysIterator, NaiveDateWeeksIterator, NaiveWeek};
+pub use self::date::{NaiveDate, NaiveDateDaysIterator, NaiveDateWeeksIterator};
 #[allow(deprecated)]
 pub use self::date::{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;
@@ -25,15 +27,255 @@
 #[doc(hidden)]
 pub use self::internals::YearFlags as __BenchYearFlags;
 
-/// Serialization/Deserialization of naive types in alternate formats
+/// A week represented by a [`NaiveDate`] and a [`Weekday`] which is the first
+/// day of the week.
+#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
+pub struct NaiveWeek {
+    date: NaiveDate,
+    start: Weekday,
+}
+
+impl NaiveWeek {
+    /// Create a new `NaiveWeek`
+    pub(crate) const fn new(date: NaiveDate, start: Weekday) -> Self {
+        Self { date, start }
+    }
+
+    /// Returns a date representing the first day of the week.
+    ///
+    /// # Panics
+    ///
+    /// Panics if the first day of the week happens to fall just out of range of `NaiveDate`
+    /// (more than ca. 262,000 years away from common era).
+    ///
+    /// # 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]
+    #[must_use]
+    pub const fn first_day(&self) -> NaiveDate {
+        expect(self.checked_first_day(), "first weekday out of range for `NaiveDate`")
+    }
+
+    /// Returns a date representing the first day of the week or
+    /// `None` if the date is out of `NaiveDate`'s range
+    /// (more than ca. 262,000 years away from common era).
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use chrono::{NaiveDate, Weekday};
+    ///
+    /// let date = NaiveDate::MIN;
+    /// let week = date.week(Weekday::Mon);
+    /// if let Some(first_day) = week.checked_first_day() {
+    ///     assert!(first_day == date);
+    /// } else {
+    ///     // error handling code
+    ///     return;
+    /// };
+    /// ```
+    #[inline]
+    #[must_use]
+    pub const fn checked_first_day(&self) -> Option<NaiveDate> {
+        let start = self.start.num_days_from_monday() as i32;
+        let ref_day = self.date.weekday().num_days_from_monday() as i32;
+        // Calculate the number of days to subtract from `self.date`.
+        // Do not construct an intermediate date beyond `self.date`, because that may be out of
+        // range if `date` is close to `NaiveDate::MAX`.
+        let days = start - ref_day - if start > ref_day { 7 } else { 0 };
+        self.date.add_days(days)
+    }
+
+    /// Returns a date representing the last day of the week.
+    ///
+    /// # Panics
+    ///
+    /// Panics if the last day of the week happens to fall just out of range of `NaiveDate`
+    /// (more than ca. 262,000 years away from common era).
+    ///
+    /// # 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]
+    #[must_use]
+    pub const fn last_day(&self) -> NaiveDate {
+        expect(self.checked_last_day(), "last weekday out of range for `NaiveDate`")
+    }
+
+    /// Returns a date representing the last day of the week or
+    /// `None` if the date is out of `NaiveDate`'s range
+    /// (more than ca. 262,000 years away from common era).
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use chrono::{NaiveDate, Weekday};
+    ///
+    /// let date = NaiveDate::MAX;
+    /// let week = date.week(Weekday::Mon);
+    /// if let Some(last_day) = week.checked_last_day() {
+    ///     assert!(last_day == date);
+    /// } else {
+    ///     // error handling code
+    ///     return;
+    /// };
+    /// ```
+    #[inline]
+    #[must_use]
+    pub const fn checked_last_day(&self) -> Option<NaiveDate> {
+        let end = self.start.pred().num_days_from_monday() as i32;
+        let ref_day = self.date.weekday().num_days_from_monday() as i32;
+        // Calculate the number of days to add to `self.date`.
+        // Do not construct an intermediate date before `self.date` (like with `first_day()`),
+        // because that may be out of range if `date` is close to `NaiveDate::MIN`.
+        let days = end - ref_day + if end < ref_day { 7 } else { 0 };
+        self.date.add_days(days)
+    }
+
+    /// Returns a [`RangeInclusive<T>`] representing the whole week bounded by
+    /// [first_day](NaiveWeek::first_day) and [last_day](NaiveWeek::last_day) functions.
+    ///
+    /// # Panics
+    ///
+    /// Panics if the either the first or last day of the week happens to fall just out of range of
+    /// `NaiveDate` (more than ca. 262,000 years away from common era).
+    ///
+    /// # 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]
+    #[must_use]
+    pub const fn days(&self) -> RangeInclusive<NaiveDate> {
+        // `expect` doesn't work because `RangeInclusive` is not `Copy`
+        match self.checked_days() {
+            Some(val) => val,
+            None => panic!("{}", "first or last weekday is out of range for `NaiveDate`"),
+        }
+    }
+
+    /// Returns an [`Option<RangeInclusive<T>>`] representing the whole week bounded by
+    /// [checked_first_day](NaiveWeek::checked_first_day) and
+    /// [checked_last_day](NaiveWeek::checked_last_day) functions.
+    ///
+    /// Returns `None` if either of the boundaries are out of `NaiveDate`'s range
+    /// (more than ca. 262,000 years away from common era).
+    ///
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use chrono::{NaiveDate, Weekday};
+    ///
+    /// let date = NaiveDate::MAX;
+    /// let week = date.week(Weekday::Mon);
+    /// let _days = match week.checked_days() {
+    ///     Some(d) => d,
+    ///     None => {
+    ///         // error handling code
+    ///         return;
+    ///     }
+    /// };
+    /// ```
+    #[inline]
+    #[must_use]
+    pub const fn checked_days(&self) -> Option<RangeInclusive<NaiveDate>> {
+        match (self.checked_first_day(), self.checked_last_day()) {
+            (Some(first), Some(last)) => Some(first..=last),
+            (_, _) => None,
+        }
+    }
+}
+
+/// A duration in calendar days.
 ///
-/// 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.
+/// This is useful because when using `TimeDelta` it is possible that adding `TimeDelta::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
+/// `TimeDelta::days(n)` and `Days::new(n)` are equivalent.
+#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
+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)
+    }
+}
+
+/// Serialization/Deserialization of `NaiveDateTime` in alternate formats
 ///
-/// [1]: https://serde.rs/attributes.html#field-attributes
-/// [2]: https://tools.ietf.org/html/rfc3339
+/// The various modules in here are intended to be used with serde's [`with` annotation] to
+/// serialize as something other than the default ISO 8601 format.
+///
+/// [`with` annotation]: https://serde.rs/field-attrs.html#with
 #[cfg(feature = "serde")]
 pub mod serde {
     pub use super::datetime::serde::*;
 }
+
+#[cfg(test)]
+mod test {
+    use crate::{NaiveDate, Weekday};
+    #[test]
+    fn test_naiveweek() {
+        let date = NaiveDate::from_ymd_opt(2022, 5, 18).unwrap();
+        let asserts = [
+            (Weekday::Mon, "Mon 2022-05-16", "Sun 2022-05-22"),
+            (Weekday::Tue, "Tue 2022-05-17", "Mon 2022-05-23"),
+            (Weekday::Wed, "Wed 2022-05-18", "Tue 2022-05-24"),
+            (Weekday::Thu, "Thu 2022-05-12", "Wed 2022-05-18"),
+            (Weekday::Fri, "Fri 2022-05-13", "Thu 2022-05-19"),
+            (Weekday::Sat, "Sat 2022-05-14", "Fri 2022-05-20"),
+            (Weekday::Sun, "Sun 2022-05-15", "Sat 2022-05-21"),
+        ];
+        for (start, first_day, last_day) in asserts {
+            let week = date.week(start);
+            let days = week.days();
+            assert_eq!(Ok(week.first_day()), NaiveDate::parse_from_str(first_day, "%a %Y-%m-%d"));
+            assert_eq!(Ok(week.last_day()), NaiveDate::parse_from_str(last_day, "%a %Y-%m-%d"));
+            assert!(days.contains(&date));
+        }
+    }
+
+    #[test]
+    fn test_naiveweek_min_max() {
+        let date_max = NaiveDate::MAX;
+        assert!(date_max.week(Weekday::Mon).first_day() <= date_max);
+        let date_min = NaiveDate::MIN;
+        assert!(date_min.week(Weekday::Mon).last_day() >= date_min);
+    }
+
+    #[test]
+    fn test_naiveweek_checked_no_panic() {
+        let date_max = NaiveDate::MAX;
+        if let Some(last) = date_max.week(Weekday::Mon).checked_last_day() {
+            assert!(last == date_max);
+        }
+        let date_min = NaiveDate::MIN;
+        if let Some(first) = date_min.week(Weekday::Mon).checked_first_day() {
+            assert!(first == date_min);
+        }
+        let _ = date_min.week(Weekday::Mon).checked_days();
+        let _ = date_max.week(Weekday::Mon).checked_days();
+    }
+}
diff --git a/crates/chrono/src/naive/time/mod.rs b/crates/chrono/src/naive/time/mod.rs
index 0bdb765..f32d828 100644
--- a/crates/chrono/src/naive/time/mod.rs
+++ b/crates/chrono/src/naive/time/mod.rs
@@ -21,9 +21,6 @@
 use crate::{expect, try_opt};
 use crate::{FixedOffset, TimeDelta, Timelike};
 
-#[cfg(feature = "rustc-serialize")]
-mod rustc_serialize;
-
 #[cfg(feature = "serde")]
 mod serde;
 
@@ -76,13 +73,20 @@
 /// All methods accepting fractional seconds will accept such values.
 ///
 /// ```
-/// use chrono::{NaiveDate, NaiveTime, Utc};
+/// use chrono::{NaiveDate, NaiveTime};
 ///
 /// let t = NaiveTime::from_hms_milli_opt(8, 59, 59, 1_000).unwrap();
 ///
-/// let dt1 = NaiveDate::from_ymd_opt(2015, 7, 1).unwrap().and_hms_micro_opt(8, 59, 59, 1_000_000).unwrap();
+/// let dt1 = NaiveDate::from_ymd_opt(2015, 7, 1)
+///     .unwrap()
+///     .and_hms_micro_opt(8, 59, 59, 1_000_000)
+///     .unwrap();
 ///
-/// 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 dt2 = NaiveDate::from_ymd_opt(2015, 6, 30)
+///     .unwrap()
+///     .and_hms_nano_opt(23, 59, 59, 1_000_000_000)
+///     .unwrap()
+///     .and_utc();
 /// # let _ = (t, dt1, dt2);
 /// ```
 ///
@@ -164,9 +168,13 @@
 /// will be represented as the second part being 60, as required by ISO 8601.
 ///
 /// ```
-/// use chrono::{Utc, NaiveDate};
+/// use chrono::NaiveDate;
 ///
-/// let dt = NaiveDate::from_ymd_opt(2015, 6, 30).unwrap().and_hms_milli_opt(23, 59, 59, 1_000).unwrap().and_local_timezone(Utc).unwrap();
+/// let dt = NaiveDate::from_ymd_opt(2015, 6, 30)
+///     .unwrap()
+///     .and_hms_milli_opt(23, 59, 59, 1_000)
+///     .unwrap()
+///     .and_utc();
 /// assert_eq!(format!("{:?}", dt), "2015-06-30T23:59:60Z");
 /// ```
 ///
@@ -243,7 +251,7 @@
     #[inline]
     #[must_use]
     pub const fn from_hms(hour: u32, min: u32, sec: u32) -> NaiveTime {
-        expect!(NaiveTime::from_hms_opt(hour, min, sec), "invalid time")
+        expect(NaiveTime::from_hms_opt(hour, min, sec), "invalid time")
     }
 
     /// Makes a new `NaiveTime` from hour, minute and second.
@@ -286,7 +294,7 @@
     #[inline]
     #[must_use]
     pub const fn from_hms_milli(hour: u32, min: u32, sec: u32, milli: u32) -> NaiveTime {
-        expect!(NaiveTime::from_hms_milli_opt(hour, min, sec, milli), "invalid time")
+        expect(NaiveTime::from_hms_milli_opt(hour, min, sec, milli), "invalid time")
     }
 
     /// Makes a new `NaiveTime` from hour, minute, second and millisecond.
@@ -337,7 +345,7 @@
     #[inline]
     #[must_use]
     pub const fn from_hms_micro(hour: u32, min: u32, sec: u32, micro: u32) -> NaiveTime {
-        expect!(NaiveTime::from_hms_micro_opt(hour, min, sec, micro), "invalid time")
+        expect(NaiveTime::from_hms_micro_opt(hour, min, sec, micro), "invalid time")
     }
 
     /// Makes a new `NaiveTime` from hour, minute, second and microsecond.
@@ -388,7 +396,7 @@
     #[inline]
     #[must_use]
     pub const fn from_hms_nano(hour: u32, min: u32, sec: u32, nano: u32) -> NaiveTime {
-        expect!(NaiveTime::from_hms_nano_opt(hour, min, sec, nano), "invalid time")
+        expect(NaiveTime::from_hms_nano_opt(hour, min, sec, nano), "invalid time")
     }
 
     /// Makes a new `NaiveTime` from hour, minute, second and nanosecond.
@@ -440,7 +448,7 @@
     #[inline]
     #[must_use]
     pub const fn from_num_seconds_from_midnight(secs: u32, nano: u32) -> NaiveTime {
-        expect!(NaiveTime::from_num_seconds_from_midnight_opt(secs, nano), "invalid time")
+        expect(NaiveTime::from_num_seconds_from_midnight_opt(secs, nano), "invalid time")
     }
 
     /// Makes a new `NaiveTime` from the number of seconds since midnight and nanosecond.
@@ -485,10 +493,14 @@
     ///
     /// let parse_from_str = NaiveTime::parse_from_str;
     ///
-    /// assert_eq!(parse_from_str("23:56:04", "%H:%M:%S"),
-    ///            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_opt(13, 23, 45, 678_900).unwrap()));
+    /// assert_eq!(
+    ///     parse_from_str("23:56:04", "%H:%M:%S"),
+    ///     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_opt(13, 23, 45, 678_900).unwrap())
+    /// );
     /// ```
     ///
     /// Date and offset is ignored for the purpose of parsing.
@@ -496,8 +508,10 @@
     /// ```
     /// # 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_opt(12, 34, 56).unwrap()));
+    /// assert_eq!(
+    ///     parse_from_str("2014-5-17T12:34:56+09:30", "%Y-%m-%dT%H:%M:%S%z"),
+    ///     Ok(NaiveTime::from_hms_opt(12, 34, 56).unwrap())
+    /// );
     /// ```
     ///
     /// [Leap seconds](#leap-second-handling) are correctly handled by
@@ -507,8 +521,10 @@
     /// ```
     /// # 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_opt(8, 59, 59, 1_123).unwrap()));
+    /// assert_eq!(
+    ///     parse_from_str("08:59:60.123", "%H:%M:%S%.f"),
+    ///     Ok(NaiveTime::from_hms_milli_opt(8, 59, 59, 1_123).unwrap())
+    /// );
     /// ```
     ///
     /// Missing seconds are assumed to be zero,
@@ -517,8 +533,7 @@
     /// ```
     /// # use chrono::NaiveTime;
     /// # let parse_from_str = NaiveTime::parse_from_str;
-    /// assert_eq!(parse_from_str("7:15", "%H:%M"),
-    ///            Ok(NaiveTime::from_hms_opt(7, 15, 0).unwrap()));
+    /// assert_eq!(parse_from_str("7:15", "%H:%M"), 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());
@@ -552,8 +567,8 @@
     ///
     /// ```rust
     /// # use chrono::{NaiveTime};
-    /// let (time, remainder) = NaiveTime::parse_and_remainder(
-    ///     "3h4m33s trailing text", "%-Hh%-Mm%-Ss").unwrap();
+    /// let (time, remainder) =
+    ///     NaiveTime::parse_and_remainder("3h4m33s trailing text", "%-Hh%-Mm%-Ss").unwrap();
     /// assert_eq!(time, NaiveTime::from_hms_opt(3, 4, 33).unwrap());
     /// assert_eq!(remainder, " trailing text");
     /// ```
@@ -569,16 +584,22 @@
     /// # Example
     ///
     /// ```
-    /// use chrono::{TimeDelta, NaiveTime};
+    /// use chrono::{NaiveTime, TimeDelta};
     ///
-    /// let from_hms = |h, m, s| { NaiveTime::from_hms_opt(h, m, s).unwrap() };
+    /// let from_hms = |h, m, s| NaiveTime::from_hms_opt(h, m, s).unwrap();
     ///
-    /// assert_eq!(from_hms(3, 4, 5).overflowing_add_signed(TimeDelta::hours(11)),
-    ///            (from_hms(14, 4, 5), 0));
-    /// assert_eq!(from_hms(3, 4, 5).overflowing_add_signed(TimeDelta::hours(23)),
-    ///            (from_hms(2, 4, 5), 86_400));
-    /// assert_eq!(from_hms(3, 4, 5).overflowing_add_signed(TimeDelta::hours(-7)),
-    ///            (from_hms(20, 4, 5), -86_400));
+    /// assert_eq!(
+    ///     from_hms(3, 4, 5).overflowing_add_signed(TimeDelta::try_hours(11).unwrap()),
+    ///     (from_hms(14, 4, 5), 0)
+    /// );
+    /// assert_eq!(
+    ///     from_hms(3, 4, 5).overflowing_add_signed(TimeDelta::try_hours(23).unwrap()),
+    ///     (from_hms(2, 4, 5), 86_400)
+    /// );
+    /// assert_eq!(
+    ///     from_hms(3, 4, 5).overflowing_add_signed(TimeDelta::try_hours(-7).unwrap()),
+    ///     (from_hms(20, 4, 5), -86_400)
+    /// );
     /// ```
     #[must_use]
     pub const fn overflowing_add_signed(&self, rhs: TimeDelta) -> (NaiveTime, i64) {
@@ -625,16 +646,22 @@
     /// # Example
     ///
     /// ```
-    /// use chrono::{TimeDelta, NaiveTime};
+    /// use chrono::{NaiveTime, TimeDelta};
     ///
-    /// let from_hms = |h, m, s| { NaiveTime::from_hms_opt(h, m, s).unwrap() };
+    /// let from_hms = |h, m, s| NaiveTime::from_hms_opt(h, m, s).unwrap();
     ///
-    /// assert_eq!(from_hms(3, 4, 5).overflowing_sub_signed(TimeDelta::hours(2)),
-    ///            (from_hms(1, 4, 5), 0));
-    /// assert_eq!(from_hms(3, 4, 5).overflowing_sub_signed(TimeDelta::hours(17)),
-    ///            (from_hms(10, 4, 5), 86_400));
-    /// assert_eq!(from_hms(3, 4, 5).overflowing_sub_signed(TimeDelta::hours(-22)),
-    ///            (from_hms(1, 4, 5), -86_400));
+    /// assert_eq!(
+    ///     from_hms(3, 4, 5).overflowing_sub_signed(TimeDelta::try_hours(2).unwrap()),
+    ///     (from_hms(1, 4, 5), 0)
+    /// );
+    /// assert_eq!(
+    ///     from_hms(3, 4, 5).overflowing_sub_signed(TimeDelta::try_hours(17).unwrap()),
+    ///     (from_hms(10, 4, 5), 86_400)
+    /// );
+    /// assert_eq!(
+    ///     from_hms(3, 4, 5).overflowing_sub_signed(TimeDelta::try_hours(-22).unwrap()),
+    ///     (from_hms(1, 4, 5), -86_400)
+    /// );
     /// ```
     #[inline]
     #[must_use]
@@ -656,27 +683,40 @@
     /// # Example
     ///
     /// ```
-    /// use chrono::{TimeDelta, NaiveTime};
+    /// use chrono::{NaiveTime, TimeDelta};
     ///
-    /// let from_hmsm = |h, m, s, milli| { NaiveTime::from_hms_milli_opt(h, m, s, milli).unwrap() };
+    /// let from_hmsm = |h, m, s, milli| NaiveTime::from_hms_milli_opt(h, m, s, milli).unwrap();
     /// let since = NaiveTime::signed_duration_since;
     ///
-    /// assert_eq!(since(from_hmsm(3, 5, 7, 900), from_hmsm(3, 5, 7, 900)),
-    ///            TimeDelta::zero());
-    /// assert_eq!(since(from_hmsm(3, 5, 7, 900), from_hmsm(3, 5, 7, 875)),
-    ///            TimeDelta::milliseconds(25));
-    /// assert_eq!(since(from_hmsm(3, 5, 7, 900), from_hmsm(3, 5, 6, 925)),
-    ///            TimeDelta::milliseconds(975));
-    /// assert_eq!(since(from_hmsm(3, 5, 7, 900), from_hmsm(3, 5, 0, 900)),
-    ///            TimeDelta::seconds(7));
-    /// assert_eq!(since(from_hmsm(3, 5, 7, 900), from_hmsm(3, 0, 7, 900)),
-    ///            TimeDelta::seconds(5 * 60));
-    /// assert_eq!(since(from_hmsm(3, 5, 7, 900), from_hmsm(0, 5, 7, 900)),
-    ///            TimeDelta::seconds(3 * 3600));
-    /// assert_eq!(since(from_hmsm(3, 5, 7, 900), from_hmsm(4, 5, 7, 900)),
-    ///            TimeDelta::seconds(-3600));
-    /// assert_eq!(since(from_hmsm(3, 5, 7, 900), from_hmsm(2, 4, 6, 800)),
-    ///            TimeDelta::seconds(3600 + 60 + 1) + TimeDelta::milliseconds(100));
+    /// assert_eq!(since(from_hmsm(3, 5, 7, 900), from_hmsm(3, 5, 7, 900)), TimeDelta::zero());
+    /// assert_eq!(
+    ///     since(from_hmsm(3, 5, 7, 900), from_hmsm(3, 5, 7, 875)),
+    ///     TimeDelta::try_milliseconds(25).unwrap()
+    /// );
+    /// assert_eq!(
+    ///     since(from_hmsm(3, 5, 7, 900), from_hmsm(3, 5, 6, 925)),
+    ///     TimeDelta::try_milliseconds(975).unwrap()
+    /// );
+    /// assert_eq!(
+    ///     since(from_hmsm(3, 5, 7, 900), from_hmsm(3, 5, 0, 900)),
+    ///     TimeDelta::try_seconds(7).unwrap()
+    /// );
+    /// assert_eq!(
+    ///     since(from_hmsm(3, 5, 7, 900), from_hmsm(3, 0, 7, 900)),
+    ///     TimeDelta::try_seconds(5 * 60).unwrap()
+    /// );
+    /// assert_eq!(
+    ///     since(from_hmsm(3, 5, 7, 900), from_hmsm(0, 5, 7, 900)),
+    ///     TimeDelta::try_seconds(3 * 3600).unwrap()
+    /// );
+    /// assert_eq!(
+    ///     since(from_hmsm(3, 5, 7, 900), from_hmsm(4, 5, 7, 900)),
+    ///     TimeDelta::try_seconds(-3600).unwrap()
+    /// );
+    /// assert_eq!(
+    ///     since(from_hmsm(3, 5, 7, 900), from_hmsm(2, 4, 6, 800)),
+    ///     TimeDelta::try_seconds(3600 + 60 + 1).unwrap() + TimeDelta::try_milliseconds(100).unwrap()
+    /// );
     /// ```
     ///
     /// Leap seconds are handled, but the subtraction assumes that
@@ -687,15 +727,15 @@
     /// # let from_hmsm = |h, m, s, milli| { NaiveTime::from_hms_milli_opt(h, m, s, milli).unwrap() };
     /// # let since = NaiveTime::signed_duration_since;
     /// assert_eq!(since(from_hmsm(3, 0, 59, 1_000), from_hmsm(3, 0, 59, 0)),
-    ///            TimeDelta::seconds(1));
+    ///            TimeDelta::try_seconds(1).unwrap());
     /// assert_eq!(since(from_hmsm(3, 0, 59, 1_500), from_hmsm(3, 0, 59, 0)),
-    ///            TimeDelta::milliseconds(1500));
+    ///            TimeDelta::try_milliseconds(1500).unwrap());
     /// assert_eq!(since(from_hmsm(3, 0, 59, 1_000), from_hmsm(3, 0, 0, 0)),
-    ///            TimeDelta::seconds(60));
+    ///            TimeDelta::try_seconds(60).unwrap());
     /// assert_eq!(since(from_hmsm(3, 0, 0, 0), from_hmsm(2, 59, 59, 1_000)),
-    ///            TimeDelta::seconds(1));
+    ///            TimeDelta::try_seconds(1).unwrap());
     /// assert_eq!(since(from_hmsm(3, 0, 59, 1_000), from_hmsm(2, 59, 59, 1_000)),
-    ///            TimeDelta::seconds(61));
+    ///            TimeDelta::try_seconds(61).unwrap());
     /// ```
     #[must_use]
     pub const fn signed_duration_since(self, rhs: NaiveTime) -> TimeDelta {
@@ -722,7 +762,7 @@
         let secs_from_frac = frac.div_euclid(1_000_000_000);
         let frac = frac.rem_euclid(1_000_000_000) as u32;
 
-        expect!(TimeDelta::new(secs + secs_from_frac, frac), "must be in range")
+        expect(TimeDelta::new(secs + secs_from_frac, frac), "must be in range")
     }
 
     /// Adds given `FixedOffset` to the current time, and returns the number of days that should be
@@ -760,13 +800,13 @@
     /// # Example
     ///
     /// ```
-    /// use chrono::NaiveTime;
     /// use chrono::format::strftime::StrftimeItems;
+    /// use chrono::NaiveTime;
     ///
     /// let fmt = StrftimeItems::new("%H:%M:%S");
     /// 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");
+    /// assert_eq!(t.format("%H:%M:%S").to_string(), "23:56:04");
     /// ```
     ///
     /// The resulting `DelayedFormat` can be formatted directly via the `Display` trait.
@@ -905,12 +945,13 @@
     /// ([Why?](#leap-second-handling))
     /// Use the proper [formatting method](#method.format) to get a human-readable representation.
     ///
-    #[cfg_attr(not(feature = "std"), doc = "```ignore")]
-    #[cfg_attr(feature = "std", doc = "```")]
+    /// ```
+    /// # #[cfg(feature = "alloc")] {
     /// # use chrono::{NaiveTime, Timelike};
     /// 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 {
@@ -927,19 +968,23 @@
     /// use chrono::{NaiveTime, Timelike};
     ///
     /// 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);
+    /// 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.
     ///
-    #[cfg_attr(not(feature = "std"), doc = "```ignore")]
-    #[cfg_attr(feature = "std", doc = "```")]
+    /// ```
+    /// # #[cfg(feature = "alloc")] {
     /// # use chrono::{NaiveTime, Timelike};
     /// let leap = NaiveTime::from_hms_milli_opt(23, 59, 59, 1_000).unwrap();
     /// assert_eq!(leap.nanosecond(), 1_000_000_000);
     /// assert_eq!(leap.format("%H:%M:%S%.9f").to_string(), "23:59:60.000000000");
+    /// # }
     /// ```
     #[inline]
     fn nanosecond(&self) -> u32 {
@@ -982,7 +1027,10 @@
     /// use chrono::{NaiveTime, Timelike};
     ///
     /// 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(45),
+    ///     Some(NaiveTime::from_hms_nano_opt(23, 45, 4, 12_345_678).unwrap())
+    /// );
     /// assert_eq!(dt.with_minute(60), None);
     /// ```
     #[inline]
@@ -1009,7 +1057,10 @@
     /// use chrono::{NaiveTime, Timelike};
     ///
     /// 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(17),
+    ///     Some(NaiveTime::from_hms_nano_opt(23, 56, 17, 12_345_678).unwrap())
+    /// );
     /// assert_eq!(dt.with_second(60), None);
     /// ```
     #[inline]
@@ -1036,8 +1087,10 @@
     /// use chrono::{NaiveTime, Timelike};
     ///
     /// 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_opt(23, 56, 4, 333_333_333).unwrap()));
+    /// assert_eq!(
+    ///     dt.with_nanosecond(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);
     /// ```
     ///
@@ -1067,12 +1120,15 @@
     /// ```
     /// use chrono::{NaiveTime, Timelike};
     ///
-    /// assert_eq!(NaiveTime::from_hms_opt(1, 2, 3).unwrap().num_seconds_from_midnight(),
-    ///            3723);
-    /// 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_opt(23, 59, 59, 1_000).unwrap().num_seconds_from_midnight(),
-    ///            86399);
+    /// assert_eq!(NaiveTime::from_hms_opt(1, 2, 3).unwrap().num_seconds_from_midnight(), 3723);
+    /// 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_opt(23, 59, 59, 1_000).unwrap().num_seconds_from_midnight(),
+    ///     86399
+    /// );
     /// ```
     #[inline]
     fn num_seconds_from_midnight(&self) -> u32 {
@@ -1092,18 +1148,33 @@
 /// # Example
 ///
 /// ```
-/// use chrono::{TimeDelta, NaiveTime};
+/// use chrono::{NaiveTime, TimeDelta};
 ///
-/// let from_hmsm = |h, m, s, milli| { NaiveTime::from_hms_milli_opt(h, m, s, milli).unwrap() };
+/// let from_hmsm = |h, m, s, milli| NaiveTime::from_hms_milli_opt(h, m, s, milli).unwrap();
 ///
-/// assert_eq!(from_hmsm(3, 5, 7, 0) + TimeDelta::zero(),                  from_hmsm(3, 5, 7, 0));
-/// assert_eq!(from_hmsm(3, 5, 7, 0) + TimeDelta::seconds(1),              from_hmsm(3, 5, 8, 0));
-/// assert_eq!(from_hmsm(3, 5, 7, 0) + TimeDelta::seconds(-1),             from_hmsm(3, 5, 6, 0));
-/// assert_eq!(from_hmsm(3, 5, 7, 0) + TimeDelta::seconds(60 + 4),         from_hmsm(3, 6, 11, 0));
-/// assert_eq!(from_hmsm(3, 5, 7, 0) + TimeDelta::seconds(7*60*60 - 6*60), from_hmsm(9, 59, 7, 0));
-/// assert_eq!(from_hmsm(3, 5, 7, 0) + TimeDelta::milliseconds(80),        from_hmsm(3, 5, 7, 80));
-/// assert_eq!(from_hmsm(3, 5, 7, 950) + TimeDelta::milliseconds(280),     from_hmsm(3, 5, 8, 230));
-/// assert_eq!(from_hmsm(3, 5, 7, 950) + TimeDelta::milliseconds(-980),    from_hmsm(3, 5, 6, 970));
+/// assert_eq!(from_hmsm(3, 5, 7, 0) + TimeDelta::zero(), from_hmsm(3, 5, 7, 0));
+/// assert_eq!(from_hmsm(3, 5, 7, 0) + TimeDelta::try_seconds(1).unwrap(), from_hmsm(3, 5, 8, 0));
+/// assert_eq!(from_hmsm(3, 5, 7, 0) + TimeDelta::try_seconds(-1).unwrap(), from_hmsm(3, 5, 6, 0));
+/// assert_eq!(
+///     from_hmsm(3, 5, 7, 0) + TimeDelta::try_seconds(60 + 4).unwrap(),
+///     from_hmsm(3, 6, 11, 0)
+/// );
+/// assert_eq!(
+///     from_hmsm(3, 5, 7, 0) + TimeDelta::try_seconds(7 * 60 * 60 - 6 * 60).unwrap(),
+///     from_hmsm(9, 59, 7, 0)
+/// );
+/// assert_eq!(
+///     from_hmsm(3, 5, 7, 0) + TimeDelta::try_milliseconds(80).unwrap(),
+///     from_hmsm(3, 5, 7, 80)
+/// );
+/// assert_eq!(
+///     from_hmsm(3, 5, 7, 950) + TimeDelta::try_milliseconds(280).unwrap(),
+///     from_hmsm(3, 5, 8, 230)
+/// );
+/// assert_eq!(
+///     from_hmsm(3, 5, 7, 950) + TimeDelta::try_milliseconds(-980).unwrap(),
+///     from_hmsm(3, 5, 6, 970)
+/// );
 /// ```
 ///
 /// The addition wraps around.
@@ -1111,9 +1182,9 @@
 /// ```
 /// # use chrono::{TimeDelta, NaiveTime};
 /// # let from_hmsm = |h, m, s, milli| { NaiveTime::from_hms_milli_opt(h, m, s, milli).unwrap() };
-/// assert_eq!(from_hmsm(3, 5, 7, 0) + TimeDelta::seconds(22*60*60), from_hmsm(1, 5, 7, 0));
-/// assert_eq!(from_hmsm(3, 5, 7, 0) + TimeDelta::seconds(-8*60*60), from_hmsm(19, 5, 7, 0));
-/// assert_eq!(from_hmsm(3, 5, 7, 0) + TimeDelta::days(800),         from_hmsm(3, 5, 7, 0));
+/// assert_eq!(from_hmsm(3, 5, 7, 0) + TimeDelta::try_seconds(22*60*60).unwrap(), from_hmsm(1, 5, 7, 0));
+/// assert_eq!(from_hmsm(3, 5, 7, 0) + TimeDelta::try_seconds(-8*60*60).unwrap(), from_hmsm(19, 5, 7, 0));
+/// assert_eq!(from_hmsm(3, 5, 7, 0) + TimeDelta::try_days(800).unwrap(), from_hmsm(3, 5, 7, 0));
 /// ```
 ///
 /// Leap seconds are handled, but the addition assumes that it is the only leap second happened.
@@ -1122,13 +1193,13 @@
 /// # use chrono::{TimeDelta, NaiveTime};
 /// # let from_hmsm = |h, m, s, milli| { NaiveTime::from_hms_milli_opt(h, m, s, milli).unwrap() };
 /// let leap = from_hmsm(3, 5, 59, 1_300);
-/// assert_eq!(leap + TimeDelta::zero(),             from_hmsm(3, 5, 59, 1_300));
-/// assert_eq!(leap + TimeDelta::milliseconds(-500), from_hmsm(3, 5, 59, 800));
-/// assert_eq!(leap + TimeDelta::milliseconds(500),  from_hmsm(3, 5, 59, 1_800));
-/// assert_eq!(leap + TimeDelta::milliseconds(800),  from_hmsm(3, 6, 0, 100));
-/// assert_eq!(leap + TimeDelta::seconds(10),        from_hmsm(3, 6, 9, 300));
-/// assert_eq!(leap + TimeDelta::seconds(-10),       from_hmsm(3, 5, 50, 300));
-/// assert_eq!(leap + TimeDelta::days(1),            from_hmsm(3, 5, 59, 300));
+/// assert_eq!(leap + TimeDelta::zero(), from_hmsm(3, 5, 59, 1_300));
+/// assert_eq!(leap + TimeDelta::try_milliseconds(-500).unwrap(), from_hmsm(3, 5, 59, 800));
+/// assert_eq!(leap + TimeDelta::try_milliseconds(500).unwrap(), from_hmsm(3, 5, 59, 1_800));
+/// assert_eq!(leap + TimeDelta::try_milliseconds(800).unwrap(), from_hmsm(3, 6, 0, 100));
+/// assert_eq!(leap + TimeDelta::try_seconds(10).unwrap(), from_hmsm(3, 6, 9, 300));
+/// assert_eq!(leap + TimeDelta::try_seconds(-10).unwrap(), from_hmsm(3, 5, 50, 300));
+/// assert_eq!(leap + TimeDelta::try_days(1).unwrap(), from_hmsm(3, 5, 59, 300));
 /// ```
 ///
 /// [leap second handling]: crate::NaiveTime#leap-second-handling
@@ -1207,16 +1278,28 @@
 /// # Example
 ///
 /// ```
-/// use chrono::{TimeDelta, NaiveTime};
+/// use chrono::{NaiveTime, TimeDelta};
 ///
-/// let from_hmsm = |h, m, s, milli| { NaiveTime::from_hms_milli_opt(h, m, s, milli).unwrap() };
+/// let from_hmsm = |h, m, s, milli| NaiveTime::from_hms_milli_opt(h, m, s, milli).unwrap();
 ///
-/// assert_eq!(from_hmsm(3, 5, 7, 0) - TimeDelta::zero(),                  from_hmsm(3, 5, 7, 0));
-/// assert_eq!(from_hmsm(3, 5, 7, 0) - TimeDelta::seconds(1),              from_hmsm(3, 5, 6, 0));
-/// assert_eq!(from_hmsm(3, 5, 7, 0) - TimeDelta::seconds(60 + 5),         from_hmsm(3, 4, 2, 0));
-/// assert_eq!(from_hmsm(3, 5, 7, 0) - TimeDelta::seconds(2*60*60 + 6*60), from_hmsm(0, 59, 7, 0));
-/// assert_eq!(from_hmsm(3, 5, 7, 0) - TimeDelta::milliseconds(80),        from_hmsm(3, 5, 6, 920));
-/// assert_eq!(from_hmsm(3, 5, 7, 950) - TimeDelta::milliseconds(280),     from_hmsm(3, 5, 7, 670));
+/// assert_eq!(from_hmsm(3, 5, 7, 0) - TimeDelta::zero(), from_hmsm(3, 5, 7, 0));
+/// assert_eq!(from_hmsm(3, 5, 7, 0) - TimeDelta::try_seconds(1).unwrap(), from_hmsm(3, 5, 6, 0));
+/// assert_eq!(
+///     from_hmsm(3, 5, 7, 0) - TimeDelta::try_seconds(60 + 5).unwrap(),
+///     from_hmsm(3, 4, 2, 0)
+/// );
+/// assert_eq!(
+///     from_hmsm(3, 5, 7, 0) - TimeDelta::try_seconds(2 * 60 * 60 + 6 * 60).unwrap(),
+///     from_hmsm(0, 59, 7, 0)
+/// );
+/// assert_eq!(
+///     from_hmsm(3, 5, 7, 0) - TimeDelta::try_milliseconds(80).unwrap(),
+///     from_hmsm(3, 5, 6, 920)
+/// );
+/// assert_eq!(
+///     from_hmsm(3, 5, 7, 950) - TimeDelta::try_milliseconds(280).unwrap(),
+///     from_hmsm(3, 5, 7, 670)
+/// );
 /// ```
 ///
 /// The subtraction wraps around.
@@ -1224,8 +1307,8 @@
 /// ```
 /// # use chrono::{TimeDelta, NaiveTime};
 /// # let from_hmsm = |h, m, s, milli| { NaiveTime::from_hms_milli_opt(h, m, s, milli).unwrap() };
-/// assert_eq!(from_hmsm(3, 5, 7, 0) - TimeDelta::seconds(8*60*60), from_hmsm(19, 5, 7, 0));
-/// assert_eq!(from_hmsm(3, 5, 7, 0) - TimeDelta::days(800),        from_hmsm(3, 5, 7, 0));
+/// assert_eq!(from_hmsm(3, 5, 7, 0) - TimeDelta::try_seconds(8*60*60).unwrap(), from_hmsm(19, 5, 7, 0));
+/// assert_eq!(from_hmsm(3, 5, 7, 0) - TimeDelta::try_days(800).unwrap(), from_hmsm(3, 5, 7, 0));
 /// ```
 ///
 /// Leap seconds are handled, but the subtraction assumes that it is the only leap second happened.
@@ -1234,11 +1317,11 @@
 /// # use chrono::{TimeDelta, NaiveTime};
 /// # let from_hmsm = |h, m, s, milli| { NaiveTime::from_hms_milli_opt(h, m, s, milli).unwrap() };
 /// let leap = from_hmsm(3, 5, 59, 1_300);
-/// assert_eq!(leap - TimeDelta::zero(),            from_hmsm(3, 5, 59, 1_300));
-/// assert_eq!(leap - TimeDelta::milliseconds(200), from_hmsm(3, 5, 59, 1_100));
-/// assert_eq!(leap - TimeDelta::milliseconds(500), from_hmsm(3, 5, 59, 800));
-/// assert_eq!(leap - TimeDelta::seconds(60),       from_hmsm(3, 5, 0, 300));
-/// assert_eq!(leap - TimeDelta::days(1),           from_hmsm(3, 6, 0, 300));
+/// assert_eq!(leap - TimeDelta::zero(), from_hmsm(3, 5, 59, 1_300));
+/// assert_eq!(leap - TimeDelta::try_milliseconds(200).unwrap(), from_hmsm(3, 5, 59, 1_100));
+/// assert_eq!(leap - TimeDelta::try_milliseconds(500).unwrap(), from_hmsm(3, 5, 59, 800));
+/// assert_eq!(leap - TimeDelta::try_seconds(60).unwrap(), from_hmsm(3, 5, 0, 300));
+/// assert_eq!(leap - TimeDelta::try_days(1).unwrap(), from_hmsm(3, 6, 0, 300));
 /// ```
 ///
 /// [leap second handling]: crate::NaiveTime#leap-second-handling
@@ -1320,19 +1403,39 @@
 /// # Example
 ///
 /// ```
-/// use chrono::{TimeDelta, NaiveTime};
+/// use chrono::{NaiveTime, TimeDelta};
 ///
-/// let from_hmsm = |h, m, s, milli| { NaiveTime::from_hms_milli_opt(h, m, s, milli).unwrap() };
+/// let from_hmsm = |h, m, s, milli| NaiveTime::from_hms_milli_opt(h, m, s, milli).unwrap();
 ///
 /// assert_eq!(from_hmsm(3, 5, 7, 900) - from_hmsm(3, 5, 7, 900), TimeDelta::zero());
-/// assert_eq!(from_hmsm(3, 5, 7, 900) - from_hmsm(3, 5, 7, 875), TimeDelta::milliseconds(25));
-/// assert_eq!(from_hmsm(3, 5, 7, 900) - from_hmsm(3, 5, 6, 925), TimeDelta::milliseconds(975));
-/// assert_eq!(from_hmsm(3, 5, 7, 900) - from_hmsm(3, 5, 0, 900), TimeDelta::seconds(7));
-/// assert_eq!(from_hmsm(3, 5, 7, 900) - from_hmsm(3, 0, 7, 900), TimeDelta::seconds(5 * 60));
-/// assert_eq!(from_hmsm(3, 5, 7, 900) - from_hmsm(0, 5, 7, 900), TimeDelta::seconds(3 * 3600));
-/// assert_eq!(from_hmsm(3, 5, 7, 900) - from_hmsm(4, 5, 7, 900), TimeDelta::seconds(-3600));
-/// assert_eq!(from_hmsm(3, 5, 7, 900) - from_hmsm(2, 4, 6, 800),
-///            TimeDelta::seconds(3600 + 60 + 1) + TimeDelta::milliseconds(100));
+/// assert_eq!(
+///     from_hmsm(3, 5, 7, 900) - from_hmsm(3, 5, 7, 875),
+///     TimeDelta::try_milliseconds(25).unwrap()
+/// );
+/// assert_eq!(
+///     from_hmsm(3, 5, 7, 900) - from_hmsm(3, 5, 6, 925),
+///     TimeDelta::try_milliseconds(975).unwrap()
+/// );
+/// assert_eq!(
+///     from_hmsm(3, 5, 7, 900) - from_hmsm(3, 5, 0, 900),
+///     TimeDelta::try_seconds(7).unwrap()
+/// );
+/// assert_eq!(
+///     from_hmsm(3, 5, 7, 900) - from_hmsm(3, 0, 7, 900),
+///     TimeDelta::try_seconds(5 * 60).unwrap()
+/// );
+/// assert_eq!(
+///     from_hmsm(3, 5, 7, 900) - from_hmsm(0, 5, 7, 900),
+///     TimeDelta::try_seconds(3 * 3600).unwrap()
+/// );
+/// assert_eq!(
+///     from_hmsm(3, 5, 7, 900) - from_hmsm(4, 5, 7, 900),
+///     TimeDelta::try_seconds(-3600).unwrap()
+/// );
+/// assert_eq!(
+///     from_hmsm(3, 5, 7, 900) - from_hmsm(2, 4, 6, 800),
+///     TimeDelta::try_seconds(3600 + 60 + 1).unwrap() + TimeDelta::try_milliseconds(100).unwrap()
+/// );
 /// ```
 ///
 /// Leap seconds are handled, but the subtraction assumes that
@@ -1341,13 +1444,13 @@
 /// ```
 /// # use chrono::{TimeDelta, NaiveTime};
 /// # let from_hmsm = |h, m, s, milli| { NaiveTime::from_hms_milli_opt(h, m, s, milli).unwrap() };
-/// assert_eq!(from_hmsm(3, 0, 59, 1_000) - from_hmsm(3, 0, 59, 0), TimeDelta::seconds(1));
+/// assert_eq!(from_hmsm(3, 0, 59, 1_000) - from_hmsm(3, 0, 59, 0), TimeDelta::try_seconds(1).unwrap());
 /// assert_eq!(from_hmsm(3, 0, 59, 1_500) - from_hmsm(3, 0, 59, 0),
-///            TimeDelta::milliseconds(1500));
-/// assert_eq!(from_hmsm(3, 0, 59, 1_000) - from_hmsm(3, 0, 0, 0), TimeDelta::seconds(60));
-/// assert_eq!(from_hmsm(3, 0, 0, 0) - from_hmsm(2, 59, 59, 1_000), TimeDelta::seconds(1));
+///            TimeDelta::try_milliseconds(1500).unwrap());
+/// assert_eq!(from_hmsm(3, 0, 59, 1_000) - from_hmsm(3, 0, 0, 0), TimeDelta::try_seconds(60).unwrap());
+/// assert_eq!(from_hmsm(3, 0, 0, 0) - from_hmsm(2, 59, 59, 1_000), TimeDelta::try_seconds(1).unwrap());
 /// assert_eq!(from_hmsm(3, 0, 59, 1_000) - from_hmsm(2, 59, 59, 1_000),
-///            TimeDelta::seconds(61));
+///            TimeDelta::try_seconds(61).unwrap());
 /// ```
 impl Sub<NaiveTime> for NaiveTime {
     type Output = TimeDelta;
@@ -1374,17 +1477,29 @@
 /// ```
 /// use chrono::NaiveTime;
 ///
-/// 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");
+/// 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_opt(6, 59, 59, 1_500).unwrap()), "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 {
@@ -1430,17 +1545,29 @@
 /// ```
 /// use chrono::NaiveTime;
 ///
-/// 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");
+/// 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_opt(6, 59, 59, 1_500).unwrap()), "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 {
@@ -1514,99 +1641,3 @@
         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_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_opt(0, 0, 59, 1_000).unwrap()).ok(),
-        Some(r#""00:00:60""#.into())
-    );
-    assert_eq!(
-        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_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_opt(23, 59, 59, 1_999_999_999).unwrap()).ok(),
-        Some(r#""23: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<NaiveTime, E>,
-    E: ::std::fmt::Debug,
-{
-    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_opt(3, 5, 7, 98765432).unwrap())
-    );
-    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_opt(12, 34, 56, 789).unwrap())
-    );
-    assert_eq!(
-        from_str(r#""23:59:60.999999999""#).ok(),
-        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_opt(23, 59, 59, 1_999_999_999).unwrap())
-    );
-
-    // bad formats
-    assert!(from_str(r#""""#).is_err());
-    assert!(from_str(r#""000000""#).is_err());
-    assert!(from_str(r#""00:00:61""#).is_err());
-    assert!(from_str(r#""00:60:00""#).is_err());
-    assert!(from_str(r#""24:00:00""#).is_err());
-    assert!(from_str(r#""23:59:59,1""#).is_err());
-    assert!(from_str(r#""012:34:56""#).is_err());
-    assert!(from_str(r#""hh:mm:ss""#).is_err());
-    assert!(from_str(r#"0"#).is_err());
-    assert!(from_str(r#"86399"#).is_err());
-    assert!(from_str(r#"{}"#).is_err());
-    // pre-0.3.0 rustc-serialize format is now invalid
-    assert!(from_str(r#"{"secs":0,"frac":0}"#).is_err());
-    assert!(from_str(r#"null"#).is_err());
-}
diff --git a/crates/chrono/src/naive/time/rustc_serialize.rs b/crates/chrono/src/naive/time/rustc_serialize.rs
deleted file mode 100644
index 3c5c47a..0000000
--- a/crates/chrono/src/naive/time/rustc_serialize.rs
+++ /dev/null
@@ -1,30 +0,0 @@
-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)]
-mod tests {
-    use crate::naive::time::{test_decodable_json, test_encodable_json};
-    use rustc_serialize::json;
-
-    #[test]
-    fn test_encodable() {
-        test_encodable_json(json::encode);
-    }
-
-    #[test]
-    fn test_decodable() {
-        test_decodable_json(json::decode);
-    }
-}
diff --git a/crates/chrono/src/naive/time/serde.rs b/crates/chrono/src/naive/time/serde.rs
index 0992fb5..f9b1dde 100644
--- a/crates/chrono/src/naive/time/serde.rs
+++ b/crates/chrono/src/naive/time/serde.rs
@@ -16,7 +16,7 @@
 
 struct NaiveTimeVisitor;
 
-impl<'de> de::Visitor<'de> for NaiveTimeVisitor {
+impl de::Visitor<'_> for NaiveTimeVisitor {
     type Value = NaiveTime;
 
     fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
@@ -42,17 +42,91 @@
 
 #[cfg(test)]
 mod tests {
-    use crate::naive::time::{test_decodable_json, test_encodable_json};
     use crate::NaiveTime;
 
     #[test]
     fn test_serde_serialize() {
-        test_encodable_json(serde_json::to_string);
+        assert_eq!(
+            serde_json::to_string(&NaiveTime::from_hms_opt(0, 0, 0).unwrap()).ok(),
+            Some(r#""00:00:00""#.into())
+        );
+        assert_eq!(
+            serde_json::to_string(&NaiveTime::from_hms_milli_opt(0, 0, 0, 950).unwrap()).ok(),
+            Some(r#""00:00:00.950""#.into())
+        );
+        assert_eq!(
+            serde_json::to_string(&NaiveTime::from_hms_milli_opt(0, 0, 59, 1_000).unwrap()).ok(),
+            Some(r#""00:00:60""#.into())
+        );
+        assert_eq!(
+            serde_json::to_string(&NaiveTime::from_hms_opt(0, 1, 2).unwrap()).ok(),
+            Some(r#""00:01:02""#.into())
+        );
+        assert_eq!(
+            serde_json::to_string(&NaiveTime::from_hms_nano_opt(3, 5, 7, 98765432).unwrap()).ok(),
+            Some(r#""03:05:07.098765432""#.into())
+        );
+        assert_eq!(
+            serde_json::to_string(&NaiveTime::from_hms_opt(7, 8, 9).unwrap()).ok(),
+            Some(r#""07:08:09""#.into())
+        );
+        assert_eq!(
+            serde_json::to_string(&NaiveTime::from_hms_micro_opt(12, 34, 56, 789).unwrap()).ok(),
+            Some(r#""12:34:56.000789""#.into())
+        );
+        let leap = NaiveTime::from_hms_nano_opt(23, 59, 59, 1_999_999_999).unwrap();
+        assert_eq!(serde_json::to_string(&leap).ok(), Some(r#""23:59:60.999999999""#.into()));
     }
 
     #[test]
     fn test_serde_deserialize() {
-        test_decodable_json(|input| serde_json::from_str(input));
+        let from_str = serde_json::from_str::<NaiveTime>;
+
+        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_opt(3, 5, 7, 98765432).unwrap())
+        );
+        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_opt(12, 34, 56, 789).unwrap())
+        );
+        assert_eq!(
+            from_str(r#""23:59:60.999999999""#).ok(),
+            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_opt(23, 59, 59, 1_999_999_999).unwrap())
+        );
+
+        // bad formats
+        assert!(from_str(r#""""#).is_err());
+        assert!(from_str(r#""000000""#).is_err());
+        assert!(from_str(r#""00:00:61""#).is_err());
+        assert!(from_str(r#""00:60:00""#).is_err());
+        assert!(from_str(r#""24:00:00""#).is_err());
+        assert!(from_str(r#""23:59:59,1""#).is_err());
+        assert!(from_str(r#""012:34:56""#).is_err());
+        assert!(from_str(r#""hh:mm:ss""#).is_err());
+        assert!(from_str(r#"0"#).is_err());
+        assert!(from_str(r#"86399"#).is_err());
+        assert!(from_str(r#"{}"#).is_err());
     }
 
     #[test]
diff --git a/crates/chrono/src/naive/time/tests.rs b/crates/chrono/src/naive/time/tests.rs
index a991117..a8754ae 100644
--- a/crates/chrono/src/naive/time/tests.rs
+++ b/crates/chrono/src/naive/time/tests.rs
@@ -94,22 +94,26 @@
     let hmsm = |h, m, s, ms| NaiveTime::from_hms_milli_opt(h, m, s, ms).unwrap();
 
     check!(hmsm(3, 5, 59, 900), TimeDelta::zero(), hmsm(3, 5, 59, 900));
-    check!(hmsm(3, 5, 59, 900), TimeDelta::milliseconds(100), hmsm(3, 6, 0, 0));
-    check!(hmsm(3, 5, 59, 1_300), TimeDelta::milliseconds(-1800), hmsm(3, 5, 58, 500));
-    check!(hmsm(3, 5, 59, 1_300), TimeDelta::milliseconds(-800), hmsm(3, 5, 59, 500));
-    check!(hmsm(3, 5, 59, 1_300), TimeDelta::milliseconds(-100), hmsm(3, 5, 59, 1_200));
-    check!(hmsm(3, 5, 59, 1_300), TimeDelta::milliseconds(100), hmsm(3, 5, 59, 1_400));
-    check!(hmsm(3, 5, 59, 1_300), TimeDelta::milliseconds(800), hmsm(3, 6, 0, 100));
-    check!(hmsm(3, 5, 59, 1_300), TimeDelta::milliseconds(1800), hmsm(3, 6, 1, 100));
-    check!(hmsm(3, 5, 59, 900), TimeDelta::seconds(86399), hmsm(3, 5, 58, 900)); // overwrap
-    check!(hmsm(3, 5, 59, 900), TimeDelta::seconds(-86399), hmsm(3, 6, 0, 900));
-    check!(hmsm(3, 5, 59, 900), TimeDelta::days(12345), hmsm(3, 5, 59, 900));
-    check!(hmsm(3, 5, 59, 1_300), TimeDelta::days(1), hmsm(3, 5, 59, 300));
-    check!(hmsm(3, 5, 59, 1_300), TimeDelta::days(-1), hmsm(3, 6, 0, 300));
+    check!(hmsm(3, 5, 59, 900), TimeDelta::try_milliseconds(100).unwrap(), hmsm(3, 6, 0, 0));
+    check!(hmsm(3, 5, 59, 1_300), TimeDelta::try_milliseconds(-1800).unwrap(), hmsm(3, 5, 58, 500));
+    check!(hmsm(3, 5, 59, 1_300), TimeDelta::try_milliseconds(-800).unwrap(), hmsm(3, 5, 59, 500));
+    check!(
+        hmsm(3, 5, 59, 1_300),
+        TimeDelta::try_milliseconds(-100).unwrap(),
+        hmsm(3, 5, 59, 1_200)
+    );
+    check!(hmsm(3, 5, 59, 1_300), TimeDelta::try_milliseconds(100).unwrap(), hmsm(3, 5, 59, 1_400));
+    check!(hmsm(3, 5, 59, 1_300), TimeDelta::try_milliseconds(800).unwrap(), hmsm(3, 6, 0, 100));
+    check!(hmsm(3, 5, 59, 1_300), TimeDelta::try_milliseconds(1800).unwrap(), hmsm(3, 6, 1, 100));
+    check!(hmsm(3, 5, 59, 900), TimeDelta::try_seconds(86399).unwrap(), hmsm(3, 5, 58, 900)); // overwrap
+    check!(hmsm(3, 5, 59, 900), TimeDelta::try_seconds(-86399).unwrap(), hmsm(3, 6, 0, 900));
+    check!(hmsm(3, 5, 59, 900), TimeDelta::try_days(12345).unwrap(), hmsm(3, 5, 59, 900));
+    check!(hmsm(3, 5, 59, 1_300), TimeDelta::try_days(1).unwrap(), hmsm(3, 5, 59, 300));
+    check!(hmsm(3, 5, 59, 1_300), TimeDelta::try_days(-1).unwrap(), hmsm(3, 6, 0, 300));
 
     // regression tests for #37
-    check!(hmsm(0, 0, 0, 0), TimeDelta::milliseconds(-990), hmsm(23, 59, 59, 10));
-    check!(hmsm(0, 0, 0, 0), TimeDelta::milliseconds(-9990), hmsm(23, 59, 50, 10));
+    check!(hmsm(0, 0, 0, 0), TimeDelta::try_milliseconds(-990).unwrap(), hmsm(23, 59, 59, 10));
+    check!(hmsm(0, 0, 0, 0), TimeDelta::try_milliseconds(-9990).unwrap(), hmsm(23, 59, 50, 10));
 }
 
 #[test]
@@ -117,25 +121,25 @@
     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(TimeDelta::hours(11)),
+        hmsm(3, 4, 5, 678).overflowing_add_signed(TimeDelta::try_hours(11).unwrap()),
         (hmsm(14, 4, 5, 678), 0)
     );
     assert_eq!(
-        hmsm(3, 4, 5, 678).overflowing_add_signed(TimeDelta::hours(23)),
+        hmsm(3, 4, 5, 678).overflowing_add_signed(TimeDelta::try_hours(23).unwrap()),
         (hmsm(2, 4, 5, 678), 86_400)
     );
     assert_eq!(
-        hmsm(3, 4, 5, 678).overflowing_add_signed(TimeDelta::hours(-7)),
+        hmsm(3, 4, 5, 678).overflowing_add_signed(TimeDelta::try_hours(-7).unwrap()),
         (hmsm(20, 4, 5, 678), -86_400)
     );
 
     // overflowing_add_signed with leap seconds may be counter-intuitive
     assert_eq!(
-        hmsm(3, 4, 59, 1_678).overflowing_add_signed(TimeDelta::days(1)),
+        hmsm(3, 4, 59, 1_678).overflowing_add_signed(TimeDelta::try_days(1).unwrap()),
         (hmsm(3, 4, 59, 678), 86_400)
     );
     assert_eq!(
-        hmsm(3, 4, 59, 1_678).overflowing_add_signed(TimeDelta::days(-1)),
+        hmsm(3, 4, 59, 1_678).overflowing_add_signed(TimeDelta::try_days(-1).unwrap()),
         (hmsm(3, 5, 0, 678), -86_400)
     );
 }
@@ -144,9 +148,9 @@
 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 += TimeDelta::hours(10);
+    time += TimeDelta::try_hours(10).unwrap();
     assert_eq!(time, hms(22, 12, 12));
-    time += TimeDelta::hours(10);
+    time += TimeDelta::try_hours(10).unwrap();
     assert_eq!(time, hms(8, 12, 12));
 }
 
@@ -154,9 +158,9 @@
 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 -= TimeDelta::hours(10);
+    time -= TimeDelta::try_hours(10).unwrap();
     assert_eq!(time, hms(2, 12, 12));
-    time -= TimeDelta::hours(10);
+    time -= TimeDelta::try_hours(10).unwrap();
     assert_eq!(time, hms(16, 12, 12));
 }
 
@@ -173,24 +177,24 @@
     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), TimeDelta::zero());
-    check!(hmsm(3, 5, 7, 900), hmsm(3, 5, 7, 600), TimeDelta::milliseconds(300));
-    check!(hmsm(3, 5, 7, 200), hmsm(2, 4, 6, 200), TimeDelta::seconds(3600 + 60 + 1));
+    check!(hmsm(3, 5, 7, 900), hmsm(3, 5, 7, 600), TimeDelta::try_milliseconds(300).unwrap());
+    check!(hmsm(3, 5, 7, 200), hmsm(2, 4, 6, 200), TimeDelta::try_seconds(3600 + 60 + 1).unwrap());
     check!(
         hmsm(3, 5, 7, 200),
         hmsm(2, 4, 6, 300),
-        TimeDelta::seconds(3600 + 60) + TimeDelta::milliseconds(900)
+        TimeDelta::try_seconds(3600 + 60).unwrap() + TimeDelta::try_milliseconds(900).unwrap()
     );
 
     // 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, 6, 0, 200), hmsm(3, 5, 59, 1_800), TimeDelta::milliseconds(400));
-    //check!(hmsm(3, 5, 7, 1_200), hmsm(3, 5, 6, 1_800), TimeDelta::milliseconds(1400));
-    //check!(hmsm(3, 5, 7, 1_200), hmsm(3, 5, 6, 800), TimeDelta::milliseconds(1400));
+    check!(hmsm(3, 6, 0, 200), hmsm(3, 5, 59, 1_800), TimeDelta::try_milliseconds(400).unwrap());
+    //check!(hmsm(3, 5, 7, 1_200), hmsm(3, 5, 6, 1_800), TimeDelta::try_milliseconds(1400).unwrap());
+    //check!(hmsm(3, 5, 7, 1_200), hmsm(3, 5, 6, 800), TimeDelta::try_milliseconds(1400).unwrap());
 
     // 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) + TimeDelta::milliseconds(400), hmsm(3, 5, 7, 200));
-    //assert_eq!(hmsm(3, 5, 6, 1_800) + TimeDelta::milliseconds(400), hmsm(3, 5, 7, 200));
+    assert_eq!(hmsm(3, 5, 6, 800) + TimeDelta::try_milliseconds(400).unwrap(), hmsm(3, 5, 7, 200));
+    //assert_eq!(hmsm(3, 5, 6, 1_800) + TimeDelta::try_milliseconds(400).unwrap(), hmsm(3, 5, 7, 200));
 }
 
 #[test]
diff --git a/crates/chrono/src/offset/fixed.rs b/crates/chrono/src/offset/fixed.rs
index 8f37558..e7382be 100644
--- a/crates/chrono/src/offset/fixed.rs
+++ b/crates/chrono/src/offset/fixed.rs
@@ -9,7 +9,7 @@
 #[cfg(any(feature = "rkyv", feature = "rkyv-16", feature = "rkyv-32", feature = "rkyv-64"))]
 use rkyv::{Archive, Deserialize, Serialize};
 
-use super::{LocalResult, Offset, TimeZone};
+use super::{MappedLocalTime, Offset, TimeZone};
 use crate::format::{scan, ParseError, OUT_OF_RANGE};
 use crate::naive::{NaiveDate, NaiveDateTime};
 
@@ -49,15 +49,14 @@
     ///
     /// # Example
     ///
-    #[cfg_attr(not(feature = "std"), doc = "```ignore")]
-    #[cfg_attr(feature = "std", doc = "```")]
+    /// ```
+    /// # #[cfg(feature = "alloc")] {
     /// use chrono::{FixedOffset, TimeZone};
     /// let hour = 3600;
-    /// let datetime = FixedOffset::east_opt(5 * hour)
-    ///     .unwrap()
-    ///     .with_ymd_and_hms(2016, 11, 08, 0, 0, 0)
-    ///     .unwrap();
+    /// let datetime =
+    ///     FixedOffset::east_opt(5 * hour).unwrap().with_ymd_and_hms(2016, 11, 08, 0, 0, 0).unwrap();
     /// assert_eq!(&datetime.to_rfc3339(), "2016-11-08T00:00:00+05:00")
+    /// # }
     /// ```
     #[must_use]
     pub const fn east_opt(secs: i32) -> Option<FixedOffset> {
@@ -85,15 +84,14 @@
     ///
     /// # Example
     ///
-    #[cfg_attr(not(feature = "std"), doc = "```ignore")]
-    #[cfg_attr(feature = "std", doc = "```")]
+    /// ```
+    /// # #[cfg(feature = "alloc")] {
     /// use chrono::{FixedOffset, TimeZone};
     /// let hour = 3600;
-    /// let datetime = FixedOffset::west_opt(5 * hour)
-    ///     .unwrap()
-    ///     .with_ymd_and_hms(2016, 11, 08, 0, 0, 0)
-    ///     .unwrap();
+    /// let datetime =
+    ///     FixedOffset::west_opt(5 * hour).unwrap().with_ymd_and_hms(2016, 11, 08, 0, 0, 0).unwrap();
     /// assert_eq!(&datetime.to_rfc3339(), "2016-11-08T00:00:00-05:00")
+    /// # }
     /// ```
     #[must_use]
     pub const fn west_opt(secs: i32) -> Option<FixedOffset> {
@@ -133,11 +131,11 @@
         *offset
     }
 
-    fn offset_from_local_date(&self, _local: &NaiveDate) -> LocalResult<FixedOffset> {
-        LocalResult::Single(*self)
+    fn offset_from_local_date(&self, _local: &NaiveDate) -> MappedLocalTime<FixedOffset> {
+        MappedLocalTime::Single(*self)
     }
-    fn offset_from_local_datetime(&self, _local: &NaiveDateTime) -> LocalResult<FixedOffset> {
-        LocalResult::Single(*self)
+    fn offset_from_local_datetime(&self, _local: &NaiveDateTime) -> MappedLocalTime<FixedOffset> {
+        MappedLocalTime::Single(*self)
     }
 
     fn offset_from_utc_date(&self, _utc: &NaiveDate) -> FixedOffset {
diff --git a/crates/chrono/src/offset/local/mod.rs b/crates/chrono/src/offset/local/mod.rs
index 37e7889..611fe18 100644
--- a/crates/chrono/src/offset/local/mod.rs
+++ b/crates/chrono/src/offset/local/mod.rs
@@ -10,7 +10,7 @@
 use rkyv::{Archive, Deserialize, Serialize};
 
 use super::fixed::FixedOffset;
-use super::{LocalResult, TimeZone};
+use super::{MappedLocalTime, TimeZone};
 use crate::naive::{NaiveDate, NaiveDateTime, NaiveTime};
 #[allow(deprecated)]
 use crate::Date;
@@ -38,16 +38,18 @@
     ))
 ))]
 mod inner {
-    use crate::{FixedOffset, LocalResult, NaiveDateTime};
+    use crate::{FixedOffset, MappedLocalTime, NaiveDateTime};
 
-    pub(super) fn offset_from_utc_datetime(_utc_time: &NaiveDateTime) -> LocalResult<FixedOffset> {
-        LocalResult::Single(FixedOffset::east_opt(0).unwrap())
+    pub(super) fn offset_from_utc_datetime(
+        _utc_time: &NaiveDateTime,
+    ) -> MappedLocalTime<FixedOffset> {
+        MappedLocalTime::Single(FixedOffset::east_opt(0).unwrap())
     }
 
     pub(super) fn offset_from_local_datetime(
         _local_time: &NaiveDateTime,
-    ) -> LocalResult<FixedOffset> {
-        LocalResult::Single(FixedOffset::east_opt(0).unwrap())
+    ) -> MappedLocalTime<FixedOffset> {
+        MappedLocalTime::Single(FixedOffset::east_opt(0).unwrap())
     }
 }
 
@@ -57,14 +59,16 @@
     not(any(target_os = "emscripten", target_os = "wasi"))
 ))]
 mod inner {
-    use crate::{Datelike, FixedOffset, LocalResult, NaiveDateTime, Timelike};
+    use crate::{Datelike, FixedOffset, MappedLocalTime, NaiveDateTime, Timelike};
 
-    pub(super) fn offset_from_utc_datetime(utc: &NaiveDateTime) -> LocalResult<FixedOffset> {
+    pub(super) fn offset_from_utc_datetime(utc: &NaiveDateTime) -> MappedLocalTime<FixedOffset> {
         let offset = js_sys::Date::from(utc.and_utc()).get_timezone_offset();
-        LocalResult::Single(FixedOffset::west_opt((offset as i32) * 60).unwrap())
+        MappedLocalTime::Single(FixedOffset::west_opt((offset as i32) * 60).unwrap())
     }
 
-    pub(super) fn offset_from_local_datetime(local: &NaiveDateTime) -> LocalResult<FixedOffset> {
+    pub(super) fn offset_from_local_datetime(
+        local: &NaiveDateTime,
+    ) -> MappedLocalTime<FixedOffset> {
         let mut year = local.year();
         if year < 100 {
             // The API in `js_sys` does not let us create a `Date` with negative years.
@@ -84,7 +88,7 @@
         );
         let offset = js_date.get_timezone_offset();
         // We always get a result, even if this time does not exist or is ambiguous.
-        LocalResult::Single(FixedOffset::west_opt((offset as i32) * 60).unwrap())
+        MappedLocalTime::Single(FixedOffset::west_opt((offset as i32) * 60).unwrap())
     }
 }
 
@@ -100,7 +104,7 @@
 /// # Example
 ///
 /// ```
-/// use chrono::{Local, DateTime, TimeZone};
+/// use chrono::{DateTime, Local, TimeZone};
 ///
 /// let dt1: DateTime<Local> = Local::now();
 /// let dt2: DateTime<Local> = Local.timestamp_opt(0, 0).unwrap();
@@ -166,12 +170,12 @@
     }
 
     #[allow(deprecated)]
-    fn offset_from_local_date(&self, local: &NaiveDate) -> LocalResult<FixedOffset> {
+    fn offset_from_local_date(&self, local: &NaiveDate) -> MappedLocalTime<FixedOffset> {
         // Get the offset at local midnight.
         self.offset_from_local_datetime(&local.and_time(NaiveTime::MIN))
     }
 
-    fn offset_from_local_datetime(&self, local: &NaiveDateTime) -> LocalResult<FixedOffset> {
+    fn offset_from_local_datetime(&self, local: &NaiveDateTime) -> MappedLocalTime<FixedOffset> {
         inner::offset_from_local_datetime(local)
     }
 
@@ -229,7 +233,7 @@
 fn lookup_with_dst_transitions(
     transitions: &[Transition],
     dt: NaiveDateTime,
-) -> LocalResult<FixedOffset> {
+) -> MappedLocalTime<FixedOffset> {
     for t in transitions.iter() {
         // A transition can result in the wall clock time going forward (creating a gap) or going
         // backward (creating a fold). We are interested in the earliest and latest wall time of the
@@ -247,24 +251,24 @@
         let wall_latest = t.transition_utc.overflowing_add_offset(offset_max);
 
         if dt < wall_earliest {
-            return LocalResult::Single(t.offset_before);
+            return MappedLocalTime::Single(t.offset_before);
         } else if dt <= wall_latest {
             return match t.offset_after.local_minus_utc().cmp(&t.offset_before.local_minus_utc()) {
-                Ordering::Equal => LocalResult::Single(t.offset_before),
-                Ordering::Less => LocalResult::Ambiguous(t.offset_before, t.offset_after),
+                Ordering::Equal => MappedLocalTime::Single(t.offset_before),
+                Ordering::Less => MappedLocalTime::Ambiguous(t.offset_before, t.offset_after),
                 Ordering::Greater => {
                     if dt == wall_earliest {
-                        LocalResult::Single(t.offset_before)
+                        MappedLocalTime::Single(t.offset_before)
                     } else if dt == wall_latest {
-                        LocalResult::Single(t.offset_after)
+                        MappedLocalTime::Single(t.offset_after)
                     } else {
-                        LocalResult::None
+                        MappedLocalTime::None
                     }
                 }
             };
         }
     }
-    LocalResult::Single(transitions.last().unwrap().offset_after)
+    MappedLocalTime::Single(transitions.last().unwrap().offset_after)
 }
 
 #[cfg(test)]
@@ -273,9 +277,9 @@
     #[cfg(windows)]
     use crate::offset::local::{lookup_with_dst_transitions, Transition};
     use crate::offset::TimeZone;
-    use crate::{Datelike, TimeDelta, Utc};
+    use crate::{Datelike, Days, Utc};
     #[cfg(windows)]
-    use crate::{FixedOffset, LocalResult, NaiveDate, NaiveDateTime};
+    use crate::{FixedOffset, MappedLocalTime, NaiveDate, NaiveDateTime};
 
     #[test]
     fn verify_correct_offsets() {
@@ -292,7 +296,7 @@
 
     #[test]
     fn verify_correct_offsets_distant_past() {
-        let distant_past = Local::now() - TimeDelta::days(365 * 500);
+        let distant_past = Local::now() - Days::new(365 * 500);
         let from_local = Local.from_local_datetime(&distant_past.naive_local()).unwrap();
         let from_utc = Local.from_utc_datetime(&distant_past.naive_utc());
 
@@ -305,7 +309,7 @@
 
     #[test]
     fn verify_correct_offsets_distant_future() {
-        let distant_future = Local::now() + TimeDelta::days(365 * 35000);
+        let distant_future = Local::now() + Days::new(365 * 35000);
         let from_local = Local.from_local_datetime(&distant_future.naive_local()).unwrap();
         let from_utc = Local.from_utc_datetime(&distant_future.naive_utc());
 
@@ -368,7 +372,7 @@
             h: u32,
             n: u32,
             s: u32,
-            result: LocalResult<FixedOffset>,
+            result: MappedLocalTime<FixedOffset>,
         ) {
             let dt = NaiveDate::from_ymd_opt(y, m, d).unwrap().and_hms_opt(h, n, s).unwrap();
             assert_eq!(lookup_with_dst_transitions(transitions, dt), result);
@@ -382,17 +386,17 @@
             Transition::new(ymdhms(2023, 3, 26, 2, 0, 0), std, dst),
             Transition::new(ymdhms(2023, 10, 29, 3, 0, 0), dst, std),
         ];
-        compare_lookup(&transitions, 2023, 3, 26, 1, 0, 0, LocalResult::Single(std));
-        compare_lookup(&transitions, 2023, 3, 26, 2, 0, 0, LocalResult::Single(std));
-        compare_lookup(&transitions, 2023, 3, 26, 2, 30, 0, LocalResult::None);
-        compare_lookup(&transitions, 2023, 3, 26, 3, 0, 0, LocalResult::Single(dst));
-        compare_lookup(&transitions, 2023, 3, 26, 4, 0, 0, LocalResult::Single(dst));
+        compare_lookup(&transitions, 2023, 3, 26, 1, 0, 0, MappedLocalTime::Single(std));
+        compare_lookup(&transitions, 2023, 3, 26, 2, 0, 0, MappedLocalTime::Single(std));
+        compare_lookup(&transitions, 2023, 3, 26, 2, 30, 0, MappedLocalTime::None);
+        compare_lookup(&transitions, 2023, 3, 26, 3, 0, 0, MappedLocalTime::Single(dst));
+        compare_lookup(&transitions, 2023, 3, 26, 4, 0, 0, MappedLocalTime::Single(dst));
 
-        compare_lookup(&transitions, 2023, 10, 29, 1, 0, 0, LocalResult::Single(dst));
-        compare_lookup(&transitions, 2023, 10, 29, 2, 0, 0, LocalResult::Ambiguous(dst, std));
-        compare_lookup(&transitions, 2023, 10, 29, 2, 30, 0, LocalResult::Ambiguous(dst, std));
-        compare_lookup(&transitions, 2023, 10, 29, 3, 0, 0, LocalResult::Ambiguous(dst, std));
-        compare_lookup(&transitions, 2023, 10, 29, 4, 0, 0, LocalResult::Single(std));
+        compare_lookup(&transitions, 2023, 10, 29, 1, 0, 0, MappedLocalTime::Single(dst));
+        compare_lookup(&transitions, 2023, 10, 29, 2, 0, 0, MappedLocalTime::Ambiguous(dst, std));
+        compare_lookup(&transitions, 2023, 10, 29, 2, 30, 0, MappedLocalTime::Ambiguous(dst, std));
+        compare_lookup(&transitions, 2023, 10, 29, 3, 0, 0, MappedLocalTime::Ambiguous(dst, std));
+        compare_lookup(&transitions, 2023, 10, 29, 4, 0, 0, MappedLocalTime::Single(std));
 
         // std transition before dst transition
         // dst offset > std offset
@@ -402,17 +406,17 @@
             Transition::new(ymdhms(2023, 3, 24, 3, 0, 0), dst, std),
             Transition::new(ymdhms(2023, 10, 27, 2, 0, 0), std, dst),
         ];
-        compare_lookup(&transitions, 2023, 3, 24, 1, 0, 0, LocalResult::Single(dst));
-        compare_lookup(&transitions, 2023, 3, 24, 2, 0, 0, LocalResult::Ambiguous(dst, std));
-        compare_lookup(&transitions, 2023, 3, 24, 2, 30, 0, LocalResult::Ambiguous(dst, std));
-        compare_lookup(&transitions, 2023, 3, 24, 3, 0, 0, LocalResult::Ambiguous(dst, std));
-        compare_lookup(&transitions, 2023, 3, 24, 4, 0, 0, LocalResult::Single(std));
+        compare_lookup(&transitions, 2023, 3, 24, 1, 0, 0, MappedLocalTime::Single(dst));
+        compare_lookup(&transitions, 2023, 3, 24, 2, 0, 0, MappedLocalTime::Ambiguous(dst, std));
+        compare_lookup(&transitions, 2023, 3, 24, 2, 30, 0, MappedLocalTime::Ambiguous(dst, std));
+        compare_lookup(&transitions, 2023, 3, 24, 3, 0, 0, MappedLocalTime::Ambiguous(dst, std));
+        compare_lookup(&transitions, 2023, 3, 24, 4, 0, 0, MappedLocalTime::Single(std));
 
-        compare_lookup(&transitions, 2023, 10, 27, 1, 0, 0, LocalResult::Single(std));
-        compare_lookup(&transitions, 2023, 10, 27, 2, 0, 0, LocalResult::Single(std));
-        compare_lookup(&transitions, 2023, 10, 27, 2, 30, 0, LocalResult::None);
-        compare_lookup(&transitions, 2023, 10, 27, 3, 0, 0, LocalResult::Single(dst));
-        compare_lookup(&transitions, 2023, 10, 27, 4, 0, 0, LocalResult::Single(dst));
+        compare_lookup(&transitions, 2023, 10, 27, 1, 0, 0, MappedLocalTime::Single(std));
+        compare_lookup(&transitions, 2023, 10, 27, 2, 0, 0, MappedLocalTime::Single(std));
+        compare_lookup(&transitions, 2023, 10, 27, 2, 30, 0, MappedLocalTime::None);
+        compare_lookup(&transitions, 2023, 10, 27, 3, 0, 0, MappedLocalTime::Single(dst));
+        compare_lookup(&transitions, 2023, 10, 27, 4, 0, 0, MappedLocalTime::Single(dst));
 
         // dst transition before std transition
         // dst offset < std offset
@@ -422,17 +426,17 @@
             Transition::new(ymdhms(2023, 3, 26, 2, 30, 0), std, dst),
             Transition::new(ymdhms(2023, 10, 29, 2, 0, 0), dst, std),
         ];
-        compare_lookup(&transitions, 2023, 3, 26, 1, 0, 0, LocalResult::Single(std));
-        compare_lookup(&transitions, 2023, 3, 26, 2, 0, 0, LocalResult::Ambiguous(std, dst));
-        compare_lookup(&transitions, 2023, 3, 26, 2, 15, 0, LocalResult::Ambiguous(std, dst));
-        compare_lookup(&transitions, 2023, 3, 26, 2, 30, 0, LocalResult::Ambiguous(std, dst));
-        compare_lookup(&transitions, 2023, 3, 26, 3, 0, 0, LocalResult::Single(dst));
+        compare_lookup(&transitions, 2023, 3, 26, 1, 0, 0, MappedLocalTime::Single(std));
+        compare_lookup(&transitions, 2023, 3, 26, 2, 0, 0, MappedLocalTime::Ambiguous(std, dst));
+        compare_lookup(&transitions, 2023, 3, 26, 2, 15, 0, MappedLocalTime::Ambiguous(std, dst));
+        compare_lookup(&transitions, 2023, 3, 26, 2, 30, 0, MappedLocalTime::Ambiguous(std, dst));
+        compare_lookup(&transitions, 2023, 3, 26, 3, 0, 0, MappedLocalTime::Single(dst));
 
-        compare_lookup(&transitions, 2023, 10, 29, 1, 0, 0, LocalResult::Single(dst));
-        compare_lookup(&transitions, 2023, 10, 29, 2, 0, 0, LocalResult::Single(dst));
-        compare_lookup(&transitions, 2023, 10, 29, 2, 15, 0, LocalResult::None);
-        compare_lookup(&transitions, 2023, 10, 29, 2, 30, 0, LocalResult::Single(std));
-        compare_lookup(&transitions, 2023, 10, 29, 3, 0, 0, LocalResult::Single(std));
+        compare_lookup(&transitions, 2023, 10, 29, 1, 0, 0, MappedLocalTime::Single(dst));
+        compare_lookup(&transitions, 2023, 10, 29, 2, 0, 0, MappedLocalTime::Single(dst));
+        compare_lookup(&transitions, 2023, 10, 29, 2, 15, 0, MappedLocalTime::None);
+        compare_lookup(&transitions, 2023, 10, 29, 2, 30, 0, MappedLocalTime::Single(std));
+        compare_lookup(&transitions, 2023, 10, 29, 3, 0, 0, MappedLocalTime::Single(std));
 
         // std transition before dst transition
         // dst offset < std offset
@@ -442,17 +446,17 @@
             Transition::new(ymdhms(2023, 3, 24, 2, 0, 0), dst, std),
             Transition::new(ymdhms(2023, 10, 27, 2, 30, 0), std, dst),
         ];
-        compare_lookup(&transitions, 2023, 3, 24, 1, 0, 0, LocalResult::Single(dst));
-        compare_lookup(&transitions, 2023, 3, 24, 2, 0, 0, LocalResult::Single(dst));
-        compare_lookup(&transitions, 2023, 3, 24, 2, 15, 0, LocalResult::None);
-        compare_lookup(&transitions, 2023, 3, 24, 2, 30, 0, LocalResult::Single(std));
-        compare_lookup(&transitions, 2023, 3, 24, 3, 0, 0, LocalResult::Single(std));
+        compare_lookup(&transitions, 2023, 3, 24, 1, 0, 0, MappedLocalTime::Single(dst));
+        compare_lookup(&transitions, 2023, 3, 24, 2, 0, 0, MappedLocalTime::Single(dst));
+        compare_lookup(&transitions, 2023, 3, 24, 2, 15, 0, MappedLocalTime::None);
+        compare_lookup(&transitions, 2023, 3, 24, 2, 30, 0, MappedLocalTime::Single(std));
+        compare_lookup(&transitions, 2023, 3, 24, 3, 0, 0, MappedLocalTime::Single(std));
 
-        compare_lookup(&transitions, 2023, 10, 27, 1, 0, 0, LocalResult::Single(std));
-        compare_lookup(&transitions, 2023, 10, 27, 2, 0, 0, LocalResult::Ambiguous(std, dst));
-        compare_lookup(&transitions, 2023, 10, 27, 2, 15, 0, LocalResult::Ambiguous(std, dst));
-        compare_lookup(&transitions, 2023, 10, 27, 2, 30, 0, LocalResult::Ambiguous(std, dst));
-        compare_lookup(&transitions, 2023, 10, 27, 3, 0, 0, LocalResult::Single(dst));
+        compare_lookup(&transitions, 2023, 10, 27, 1, 0, 0, MappedLocalTime::Single(std));
+        compare_lookup(&transitions, 2023, 10, 27, 2, 0, 0, MappedLocalTime::Ambiguous(std, dst));
+        compare_lookup(&transitions, 2023, 10, 27, 2, 15, 0, MappedLocalTime::Ambiguous(std, dst));
+        compare_lookup(&transitions, 2023, 10, 27, 2, 30, 0, MappedLocalTime::Ambiguous(std, dst));
+        compare_lookup(&transitions, 2023, 10, 27, 3, 0, 0, MappedLocalTime::Single(dst));
 
         // offset stays the same
         let std = FixedOffset::east_opt(3 * 60 * 60).unwrap();
@@ -460,18 +464,18 @@
             Transition::new(ymdhms(2023, 3, 26, 2, 0, 0), std, std),
             Transition::new(ymdhms(2023, 10, 29, 3, 0, 0), std, std),
         ];
-        compare_lookup(&transitions, 2023, 3, 26, 2, 0, 0, LocalResult::Single(std));
-        compare_lookup(&transitions, 2023, 10, 29, 3, 0, 0, LocalResult::Single(std));
+        compare_lookup(&transitions, 2023, 3, 26, 2, 0, 0, MappedLocalTime::Single(std));
+        compare_lookup(&transitions, 2023, 10, 29, 3, 0, 0, MappedLocalTime::Single(std));
 
         // single transition
         let std = FixedOffset::east_opt(3 * 60 * 60).unwrap();
         let dst = FixedOffset::east_opt(4 * 60 * 60).unwrap();
         let transitions = [Transition::new(ymdhms(2023, 3, 26, 2, 0, 0), std, dst)];
-        compare_lookup(&transitions, 2023, 3, 26, 1, 0, 0, LocalResult::Single(std));
-        compare_lookup(&transitions, 2023, 3, 26, 2, 0, 0, LocalResult::Single(std));
-        compare_lookup(&transitions, 2023, 3, 26, 2, 30, 0, LocalResult::None);
-        compare_lookup(&transitions, 2023, 3, 26, 3, 0, 0, LocalResult::Single(dst));
-        compare_lookup(&transitions, 2023, 3, 26, 4, 0, 0, LocalResult::Single(dst));
+        compare_lookup(&transitions, 2023, 3, 26, 1, 0, 0, MappedLocalTime::Single(std));
+        compare_lookup(&transitions, 2023, 3, 26, 2, 0, 0, MappedLocalTime::Single(std));
+        compare_lookup(&transitions, 2023, 3, 26, 2, 30, 0, MappedLocalTime::None);
+        compare_lookup(&transitions, 2023, 3, 26, 3, 0, 0, MappedLocalTime::Single(dst));
+        compare_lookup(&transitions, 2023, 3, 26, 4, 0, 0, MappedLocalTime::Single(dst));
     }
 
     #[test]
@@ -486,17 +490,17 @@
         ];
         assert_eq!(
             lookup_with_dst_transitions(&transitions, NaiveDateTime::MAX.with_month(3).unwrap()),
-            LocalResult::Single(std)
+            MappedLocalTime::Single(std)
         );
         assert_eq!(
             lookup_with_dst_transitions(&transitions, NaiveDateTime::MAX.with_month(8).unwrap()),
-            LocalResult::Single(dst)
+            MappedLocalTime::Single(dst)
         );
         // Doesn't panic with `NaiveDateTime::MAX` as argument (which would be out of range when
         // converted to UTC).
         assert_eq!(
             lookup_with_dst_transitions(&transitions, NaiveDateTime::MAX),
-            LocalResult::Ambiguous(dst, std)
+            MappedLocalTime::Ambiguous(dst, std)
         );
 
         // Transition before UTC year end doesn't panic in year of `NaiveDate::MIN`
@@ -508,17 +512,17 @@
         ];
         assert_eq!(
             lookup_with_dst_transitions(&transitions, NaiveDateTime::MIN.with_month(3).unwrap()),
-            LocalResult::Single(dst)
+            MappedLocalTime::Single(dst)
         );
         assert_eq!(
             lookup_with_dst_transitions(&transitions, NaiveDateTime::MIN.with_month(8).unwrap()),
-            LocalResult::Single(std)
+            MappedLocalTime::Single(std)
         );
         // Doesn't panic with `NaiveDateTime::MIN` as argument (which would be out of range when
         // converted to UTC).
         assert_eq!(
             lookup_with_dst_transitions(&transitions, NaiveDateTime::MIN),
-            LocalResult::Ambiguous(std, dst)
+            MappedLocalTime::Ambiguous(std, dst)
         );
     }
 
diff --git a/crates/chrono/src/offset/local/tz_info/parser.rs b/crates/chrono/src/offset/local/tz_info/parser.rs
index 47cc037..509c4fe 100644
--- a/crates/chrono/src/offset/local/tz_info/parser.rs
+++ b/crates/chrono/src/offset/local/tz_info/parser.rs
@@ -247,6 +247,21 @@
         Ok(u32::from_be_bytes(buf))
     }
 
+    #[cfg(target_env = "ohos")]
+    pub(crate) fn seek_after(&mut self, offset: usize) -> Result<usize, io::Error> {
+        if offset < self.read_count {
+            return Err(io::Error::from(ErrorKind::UnexpectedEof));
+        }
+        match self.remaining.get((offset - self.read_count)..) {
+            Some(remaining) => {
+                self.remaining = remaining;
+                self.read_count = offset;
+                Ok(offset)
+            }
+            _ => Err(io::Error::from(ErrorKind::UnexpectedEof)),
+        }
+    }
+
     /// 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..)) {
diff --git a/crates/chrono/src/offset/local/tz_info/rule.rs b/crates/chrono/src/offset/local/tz_info/rule.rs
index 369e317..5e45682 100644
--- a/crates/chrono/src/offset/local/tz_info/rule.rs
+++ b/crates/chrono/src/offset/local/tz_info/rule.rs
@@ -20,7 +20,6 @@
     /// 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,
@@ -84,10 +83,10 @@
         &self,
         local_time: i64,
         year: i32,
-    ) -> Result<crate::LocalResult<LocalTimeType>, Error> {
+    ) -> Result<crate::MappedLocalTime<LocalTimeType>, Error> {
         match self {
             TransitionRule::Fixed(local_time_type) => {
-                Ok(crate::LocalResult::Single(*local_time_type))
+                Ok(crate::MappedLocalTime::Single(*local_time_type))
             }
             TransitionRule::Alternate(alternate_time) => {
                 alternate_time.find_local_time_type_from_local(local_time, year)
@@ -157,7 +156,7 @@
         };
 
         // Check if the current year is valid for the following computations
-        if !(i32::min_value() + 2 <= current_year && current_year <= i32::max_value() - 2) {
+        if !(i32::MIN + 2..=i32::MAX - 2).contains(&current_year) {
             return Err(Error::OutOfRange("out of range date time"));
         }
 
@@ -232,9 +231,9 @@
         &self,
         local_time: i64,
         current_year: i32,
-    ) -> Result<crate::LocalResult<LocalTimeType>, Error> {
+    ) -> Result<crate::MappedLocalTime<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) {
+        if !(i32::MIN + 2..=i32::MAX - 2).contains(&current_year) {
             return Err(Error::OutOfRange("out of range date time"));
         }
 
@@ -253,7 +252,7 @@
             - 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::Equal => Ok(crate::MappedLocalTime::Single(self.std)),
             Ordering::Less => {
                 if self.dst_start.transition_date(current_year).0
                     < self.dst_end.transition_date(current_year).0
@@ -261,41 +260,41 @@
                     // 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))
+                        Ok(crate::MappedLocalTime::Single(self.std))
                     } else if local_time > dst_start_transition_start
                         && local_time < dst_start_transition_end
                     {
-                        Ok(crate::LocalResult::None)
+                        Ok(crate::MappedLocalTime::None)
                     } else if local_time >= dst_start_transition_end
                         && local_time < dst_end_transition_end
                     {
-                        Ok(crate::LocalResult::Single(self.dst))
+                        Ok(crate::MappedLocalTime::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))
+                        Ok(crate::MappedLocalTime::Ambiguous(self.std, self.dst))
                     } else {
-                        Ok(crate::LocalResult::Single(self.std))
+                        Ok(crate::MappedLocalTime::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))
+                        Ok(crate::MappedLocalTime::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))
+                        Ok(crate::MappedLocalTime::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))
+                        Ok(crate::MappedLocalTime::Single(self.std))
                     } else if local_time >= dst_start_transition_start
                         && local_time < dst_start_transition_end
                     {
-                        Ok(crate::LocalResult::None)
+                        Ok(crate::MappedLocalTime::None)
                     } else {
-                        Ok(crate::LocalResult::Single(self.dst))
+                        Ok(crate::MappedLocalTime::Single(self.dst))
                     }
                 }
             }
@@ -306,41 +305,41 @@
                     // 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))
+                        Ok(crate::MappedLocalTime::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))
+                        Ok(crate::MappedLocalTime::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))
+                        Ok(crate::MappedLocalTime::Single(self.dst))
                     } else if local_time >= dst_end_transition_start
                         && local_time < dst_end_transition_end
                     {
-                        Ok(crate::LocalResult::None)
+                        Ok(crate::MappedLocalTime::None)
                     } else {
-                        Ok(crate::LocalResult::Single(self.std))
+                        Ok(crate::MappedLocalTime::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))
+                        Ok(crate::MappedLocalTime::Single(self.dst))
                     } else if local_time > dst_end_transition_start
                         && local_time < dst_end_transition_end
                     {
-                        Ok(crate::LocalResult::None)
+                        Ok(crate::MappedLocalTime::None)
                     } else if local_time >= dst_end_transition_end
                         && local_time < dst_start_transition_end
                     {
-                        Ok(crate::LocalResult::Single(self.std))
+                        Ok(crate::MappedLocalTime::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))
+                        Ok(crate::MappedLocalTime::Ambiguous(self.dst, self.std))
                     } else {
-                        Ok(crate::LocalResult::Single(self.dst))
+                        Ok(crate::MappedLocalTime::Single(self.dst))
                     }
                 }
             }
@@ -590,11 +589,11 @@
 
                 let week_day_of_first_month_day =
                     (4 + days_since_unix_epoch(year, month, 1)).rem_euclid(DAYS_PER_WEEK);
-                let first_week_day_occurence_in_month =
+                let first_week_day_occurrence_in_month =
                     1 + (week_day as i64 - week_day_of_first_month_day).rem_euclid(DAYS_PER_WEEK);
 
                 let mut month_day =
-                    first_week_day_occurence_in_month + (week as i64 - 1) * DAYS_PER_WEEK;
+                    first_week_day_occurrence_in_month + (week as i64 - 1) * DAYS_PER_WEEK;
                 if month_day > day_in_month {
                     month_day -= DAYS_PER_WEEK
                 }
@@ -688,7 +687,7 @@
         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 {
+        let year = match year >= i32::MIN as i64 && year <= i32::MAX as i64 {
             true => year as i32,
             false => return Err(Error::OutOfRange("i64 is out of range for i32")),
         };
diff --git a/crates/chrono/src/offset/local/tz_info/timezone.rs b/crates/chrono/src/offset/local/tz_info/timezone.rs
index 02b6f34..268739c 100644
--- a/crates/chrono/src/offset/local/tz_info/timezone.rs
+++ b/crates/chrono/src/offset/local/tz_info/timezone.rs
@@ -8,6 +8,9 @@
 use super::rule::{AlternateTime, TransitionRule};
 use super::{parser, Error, DAYS_PER_WEEK, SECONDS_PER_DAY};
 
+#[cfg(target_env = "ohos")]
+use crate::offset::local::tz_info::parser::Cursor;
+
 /// Time zone
 #[derive(Debug, Clone, Eq, PartialEq)]
 pub(crate) struct TimeZone {
@@ -25,7 +28,6 @@
     /// 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),
@@ -51,6 +53,12 @@
             }
         }
 
+        // ohos merge all file into tzdata since ver35
+        #[cfg(target_env = "ohos")]
+        {
+            return Self::from_tz_data(&find_ohos_tz_data(tz_string)?);
+        }
+
         let mut chars = tz_string.chars();
         if chars.next() == Some(':') {
             return Self::from_file(&mut find_tz_file(chars.as_str())?);
@@ -130,7 +138,7 @@
         &self,
         local_time: i64,
         year: i32,
-    ) -> Result<crate::LocalResult<LocalTimeType>, Error> {
+    ) -> Result<crate::MappedLocalTime<LocalTimeType>, Error> {
         self.as_ref().find_local_time_type_from_local(local_time, year)
     }
 
@@ -219,7 +227,7 @@
         &self,
         local_time: i64,
         year: i32,
-    ) -> Result<crate::LocalResult<LocalTimeType>, Error> {
+    ) -> Result<crate::MappedLocalTime<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) {
@@ -230,7 +238,7 @@
         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
+        // we must check _all_ of them, incase of any Overlapping (MappedLocalTime::Ambiguous) or Skipping (MappedLocalTime::None) transitions
         let offset_after_last = if !self.transitions.is_empty() {
             let mut prev = self.local_time_types[0];
 
@@ -244,29 +252,29 @@
 
                 match transition_start.cmp(&transition_end) {
                     Ordering::Greater => {
-                        // bakwards transition, eg from DST to regular
+                        // backwards 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));
+                            return Ok(crate::MappedLocalTime::Single(prev));
                         } else if local_leap_time >= transition_end
                             && local_leap_time <= transition_start
                         {
                             if prev.ut_offset < after_ltt.ut_offset {
-                                return Ok(crate::LocalResult::Ambiguous(prev, after_ltt));
+                                return Ok(crate::MappedLocalTime::Ambiguous(prev, after_ltt));
                             } else {
-                                return Ok(crate::LocalResult::Ambiguous(after_ltt, prev));
+                                return Ok(crate::MappedLocalTime::Ambiguous(after_ltt, prev));
                             }
                         }
                     }
                     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));
+                            return Ok(crate::MappedLocalTime::Single(prev));
                         } else if local_leap_time == transition_end {
                             if prev.ut_offset < after_ltt.ut_offset {
-                                return Ok(crate::LocalResult::Ambiguous(prev, after_ltt));
+                                return Ok(crate::MappedLocalTime::Ambiguous(prev, after_ltt));
                             } else {
-                                return Ok(crate::LocalResult::Ambiguous(after_ltt, prev));
+                                return Ok(crate::MappedLocalTime::Ambiguous(after_ltt, prev));
                             }
                         }
                     }
@@ -274,11 +282,11 @@
                         // 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));
+                            return Ok(crate::MappedLocalTime::Single(prev));
                         } else if local_leap_time < transition_end {
-                            return Ok(crate::LocalResult::None);
+                            return Ok(crate::MappedLocalTime::None);
                         } else if local_leap_time == transition_end {
-                            return Ok(crate::LocalResult::Single(after_ltt));
+                            return Ok(crate::MappedLocalTime::Single(after_ltt));
                         }
                     }
                 }
@@ -299,7 +307,7 @@
                 err => err,
             }
         } else {
-            Ok(crate::LocalResult::Single(offset_after_last))
+            Ok(crate::MappedLocalTime::Single(offset_after_last))
         }
     }
 
@@ -416,7 +424,7 @@
 
     /// 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() {
+        if unix_leap_time == i64::MIN {
             return Err(Error::OutOfRange("out of range operation"));
         }
 
@@ -573,7 +581,7 @@
 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() {
+        if ut_offset == i32::MIN {
             return Err(Error::LocalTimeType("invalid UTC offset"));
         }
 
@@ -587,7 +595,7 @@
 
     /// Construct a local time type with the specified UTC offset in seconds
     pub(super) const fn with_offset(ut_offset: i32) -> Result<Self, Error> {
-        if ut_offset == i32::min_value() {
+        if ut_offset == i32::MIN {
             return Err(Error::LocalTimeType("invalid UTC offset"));
         }
 
@@ -630,6 +638,58 @@
     }
 }
 
+#[cfg(target_env = "ohos")]
+fn from_tzdata_bytes(bytes: &mut Vec<u8>, tz_string: &str) -> Result<Vec<u8>, Error> {
+    const VERSION_SIZE: usize = 12;
+    const OFFSET_SIZE: usize = 4;
+    const INDEX_CHUNK_SIZE: usize = 48;
+    const ZONENAME_SIZE: usize = 40;
+
+    let mut cursor = Cursor::new(&bytes);
+    // version head
+    let _ = cursor.read_exact(VERSION_SIZE)?;
+    let index_offset_offset = cursor.read_be_u32()?;
+    let data_offset_offset = cursor.read_be_u32()?;
+    // final offset
+    let _ = cursor.read_be_u32()?;
+
+    cursor.seek_after(index_offset_offset as usize)?;
+    let mut idx = index_offset_offset;
+    while idx < data_offset_offset {
+        let index_buf = cursor.read_exact(ZONENAME_SIZE)?;
+        let offset = cursor.read_be_u32()?;
+        let length = cursor.read_be_u32()?;
+        let zone_name = str::from_utf8(index_buf)?.trim_end_matches('\0');
+        if zone_name != tz_string {
+            idx += INDEX_CHUNK_SIZE as u32;
+            continue;
+        }
+        cursor.seek_after((data_offset_offset + offset) as usize)?;
+        return match cursor.read_exact(length as usize) {
+            Ok(result) => Ok(result.to_vec()),
+            Err(_err) => Err(Error::InvalidTzFile("invalid ohos tzdata chunk")),
+        };
+    }
+
+    Err(Error::InvalidTzString("cannot find tz string within tzdata"))
+}
+
+#[cfg(target_env = "ohos")]
+fn from_tzdata_file(file: &mut File, tz_string: &str) -> Result<Vec<u8>, Error> {
+    let mut bytes = Vec::new();
+    file.read_to_end(&mut bytes)?;
+    from_tzdata_bytes(&mut bytes, tz_string)
+}
+
+#[cfg(target_env = "ohos")]
+fn find_ohos_tz_data(tz_string: &str) -> Result<Vec<u8>, Error> {
+    const TZDATA_PATH: &str = "/system/etc/zoneinfo/tzdata";
+    match File::open(TZDATA_PATH) {
+        Ok(mut file) => from_tzdata_file(&mut file, tz_string),
+        Err(err) => Err(err.into()),
+    }
+}
+
 // Possible system timezone directories
 #[cfg(unix)]
 const ZONE_INFO_DIRECTORIES: [&str; 4] =
@@ -819,7 +879,7 @@
         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![Transition::new(i32::MIN.into(), 0), Transition::new(0, 1)],
             vec![utc, cet],
             Vec::new(),
             Some(fixed_extra_rule),
@@ -927,7 +987,7 @@
     #[test]
     fn test_leap_seconds_overflow() -> Result<(), Error> {
         let time_zone_err = TimeZone::new(
-            vec![Transition::new(i64::min_value(), 0)],
+            vec![Transition::new(i64::MIN, 0)],
             vec![LocalTimeType::UTC],
             vec![LeapSecond::new(0, 1)],
             Some(TransitionRule::from(LocalTimeType::UTC)),
@@ -935,13 +995,13 @@
         assert!(time_zone_err.is_err());
 
         let time_zone = TimeZone::new(
-            vec![Transition::new(i64::max_value(), 0)],
+            vec![Transition::new(i64::MAX, 0)],
             vec![LocalTimeType::UTC],
             vec![LeapSecond::new(0, 1)],
             None,
         )?;
         assert!(matches!(
-            time_zone.find_local_time_type(i64::max_value()),
+            time_zone.find_local_time_type(i64::MAX),
             Err(Error::FindLocalTimeType(_))
         ));
 
diff --git a/crates/chrono/src/offset/local/unix.rs b/crates/chrono/src/offset/local/unix.rs
index ce96a6e..c1942eb 100644
--- a/crates/chrono/src/offset/local/unix.rs
+++ b/crates/chrono/src/offset/local/unix.rs
@@ -12,24 +12,24 @@
 
 use super::tz_info::TimeZone;
 use super::{FixedOffset, NaiveDateTime};
-use crate::{Datelike, LocalResult};
+use crate::{Datelike, MappedLocalTime};
 
-pub(super) fn offset_from_utc_datetime(utc: &NaiveDateTime) -> LocalResult<FixedOffset> {
+pub(super) fn offset_from_utc_datetime(utc: &NaiveDateTime) -> MappedLocalTime<FixedOffset> {
     offset(utc, false)
 }
 
-pub(super) fn offset_from_local_datetime(local: &NaiveDateTime) -> LocalResult<FixedOffset> {
+pub(super) fn offset_from_local_datetime(local: &NaiveDateTime) -> MappedLocalTime<FixedOffset> {
     offset(local, true)
 }
 
-fn offset(d: &NaiveDateTime, local: bool) -> LocalResult<FixedOffset> {
+fn offset(d: &NaiveDateTime, local: bool) -> MappedLocalTime<FixedOffset> {
     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.
+// be initialized in a static context.
 thread_local! {
     static TZ_INFO: RefCell<Option<Cache>> = Default::default();
 }
@@ -104,7 +104,7 @@
 }
 
 impl Cache {
-    fn offset(&mut self, d: NaiveDateTime, local: bool) -> LocalResult<FixedOffset> {
+    fn offset(&mut self, d: NaiveDateTime, local: bool) -> MappedLocalTime<FixedOffset> {
         let now = SystemTime::now();
 
         match now.duration_since(self.last_checked) {
@@ -151,21 +151,21 @@
         if !local {
             let offset = self
                 .zone
-                .find_local_time_type(d.timestamp())
+                .find_local_time_type(d.and_utc().timestamp())
                 .expect("unable to select local time type")
                 .offset();
 
             return match FixedOffset::east_opt(offset) {
-                Some(offset) => LocalResult::Single(offset),
-                None => LocalResult::None,
+                Some(offset) => MappedLocalTime::Single(offset),
+                None => MappedLocalTime::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 anyway.
+        // the entire time was skipped in which case we will return MappedLocalTime::None anyway.
         self.zone
-            .find_local_time_type_from_local(d.timestamp(), d.year())
+            .find_local_time_type_from_local(d.and_utc().timestamp(), d.year())
             .expect("unable to select local time type")
-            .map(|o| FixedOffset::east_opt(o.offset()).unwrap())
+            .and_then(|o| FixedOffset::east_opt(o.offset()))
     }
 }
diff --git a/crates/chrono/src/offset/local/win_bindings.rs b/crates/chrono/src/offset/local/win_bindings.rs
index 7574fb3..e78a955 100644
--- a/crates/chrono/src/offset/local/win_bindings.rs
+++ b/crates/chrono/src/offset/local/win_bindings.rs
@@ -1,13 +1,12 @@
-// Bindings generated by `windows-bindgen` 0.52.0
-
 #![allow(non_snake_case, non_upper_case_globals, non_camel_case_types, dead_code, clippy::all)]
-::windows_targets::link!("kernel32.dll" "system" fn GetTimeZoneInformationForYear(wyear : u16, pdtzi : *const DYNAMIC_TIME_ZONE_INFORMATION, ptzi : *mut TIME_ZONE_INFORMATION) -> BOOL);
-::windows_targets::link!("kernel32.dll" "system" fn SystemTimeToFileTime(lpsystemtime : *const SYSTEMTIME, lpfiletime : *mut FILETIME) -> BOOL);
-::windows_targets::link!("kernel32.dll" "system" fn SystemTimeToTzSpecificLocalTime(lptimezoneinformation : *const TIME_ZONE_INFORMATION, lpuniversaltime : *const SYSTEMTIME, lplocaltime : *mut SYSTEMTIME) -> BOOL);
-::windows_targets::link!("kernel32.dll" "system" fn TzSpecificLocalTimeToSystemTime(lptimezoneinformation : *const TIME_ZONE_INFORMATION, lplocaltime : *const SYSTEMTIME, lpuniversaltime : *mut SYSTEMTIME) -> BOOL);
+windows_targets::link!("kernel32.dll" "system" fn GetTimeZoneInformationForYear(wyear : u16, pdtzi : *const DYNAMIC_TIME_ZONE_INFORMATION, ptzi : *mut TIME_ZONE_INFORMATION) -> BOOL);
+windows_targets::link!("kernel32.dll" "system" fn SystemTimeToFileTime(lpsystemtime : *const SYSTEMTIME, lpfiletime : *mut FILETIME) -> BOOL);
+windows_targets::link!("kernel32.dll" "system" fn SystemTimeToTzSpecificLocalTime(lptimezoneinformation : *const TIME_ZONE_INFORMATION, lpuniversaltime : *const SYSTEMTIME, lplocaltime : *mut SYSTEMTIME) -> BOOL);
+windows_targets::link!("kernel32.dll" "system" fn TzSpecificLocalTimeToSystemTime(lptimezoneinformation : *const TIME_ZONE_INFORMATION, lplocaltime : *const SYSTEMTIME, lpuniversaltime : *mut SYSTEMTIME) -> BOOL);
 pub type BOOL = i32;
 pub type BOOLEAN = u8;
 #[repr(C)]
+#[derive(Clone, Copy)]
 pub struct DYNAMIC_TIME_ZONE_INFORMATION {
     pub Bias: i32,
     pub StandardName: [u16; 32],
@@ -19,24 +18,14 @@
     pub TimeZoneKeyName: [u16; 128],
     pub DynamicDaylightTimeDisabled: BOOLEAN,
 }
-impl ::core::marker::Copy for DYNAMIC_TIME_ZONE_INFORMATION {}
-impl ::core::clone::Clone for DYNAMIC_TIME_ZONE_INFORMATION {
-    fn clone(&self) -> Self {
-        *self
-    }
-}
 #[repr(C)]
+#[derive(Clone, Copy)]
 pub struct FILETIME {
     pub dwLowDateTime: u32,
     pub dwHighDateTime: u32,
 }
-impl ::core::marker::Copy for FILETIME {}
-impl ::core::clone::Clone for FILETIME {
-    fn clone(&self) -> Self {
-        *self
-    }
-}
 #[repr(C)]
+#[derive(Clone, Copy)]
 pub struct SYSTEMTIME {
     pub wYear: u16,
     pub wMonth: u16,
@@ -47,13 +36,8 @@
     pub wSecond: u16,
     pub wMilliseconds: u16,
 }
-impl ::core::marker::Copy for SYSTEMTIME {}
-impl ::core::clone::Clone for SYSTEMTIME {
-    fn clone(&self) -> Self {
-        *self
-    }
-}
 #[repr(C)]
+#[derive(Clone, Copy)]
 pub struct TIME_ZONE_INFORMATION {
     pub Bias: i32,
     pub StandardName: [u16; 32],
@@ -63,9 +47,3 @@
     pub DaylightDate: SYSTEMTIME,
     pub DaylightBias: i32,
 }
-impl ::core::marker::Copy for TIME_ZONE_INFORMATION {}
-impl ::core::clone::Clone for TIME_ZONE_INFORMATION {
-    fn clone(&self) -> Self {
-        *self
-    }
-}
diff --git a/crates/chrono/src/offset/local/win_bindings.txt b/crates/chrono/src/offset/local/win_bindings.txt
index 7fb3e2f..fc00509 100644
--- a/crates/chrono/src/offset/local/win_bindings.txt
+++ b/crates/chrono/src/offset/local/win_bindings.txt
@@ -1,5 +1,5 @@
 --out src/offset/local/win_bindings.rs
---config flatten sys
+--config flatten sys no-bindgen-comment
 --filter
     Windows.Win32.System.Time.GetTimeZoneInformationForYear
     Windows.Win32.System.Time.SystemTimeToFileTime
diff --git a/crates/chrono/src/offset/local/windows.rs b/crates/chrono/src/offset/local/windows.rs
index cee09ec..100b1f1 100644
--- a/crates/chrono/src/offset/local/windows.rs
+++ b/crates/chrono/src/offset/local/windows.rs
@@ -9,14 +9,13 @@
 // except according to those terms.
 
 use std::cmp::Ordering;
-use std::convert::TryFrom;
 use std::mem::MaybeUninit;
 use std::ptr;
 
 use super::win_bindings::{GetTimeZoneInformationForYear, SYSTEMTIME, TIME_ZONE_INFORMATION};
 
 use crate::offset::local::{lookup_with_dst_transitions, Transition};
-use crate::{Datelike, FixedOffset, LocalResult, NaiveDate, NaiveDateTime, NaiveTime, Weekday};
+use crate::{Datelike, FixedOffset, MappedLocalTime, NaiveDate, NaiveDateTime, NaiveTime, Weekday};
 
 // We don't use `SystemTimeToTzSpecificLocalTime` because it doesn't support the same range of dates
 // as Chrono. Also it really isn't that difficult to work out the correct offset from the provided
@@ -25,13 +24,13 @@
 // This method uses `overflowing_sub_offset` because it is no problem if the transition time in UTC
 // falls a couple of hours inside the buffer space around the `NaiveDateTime` range (although it is
 // very theoretical to have a transition at midnight around `NaiveDate::(MIN|MAX)`.
-pub(super) fn offset_from_utc_datetime(utc: &NaiveDateTime) -> LocalResult<FixedOffset> {
+pub(super) fn offset_from_utc_datetime(utc: &NaiveDateTime) -> MappedLocalTime<FixedOffset> {
     // Using a `TzInfo` based on the year of an UTC datetime is technically wrong, we should be
     // using the rules for the year of the corresponding local time. But this matches what
     // `SystemTimeToTzSpecificLocalTime` is documented to do.
     let tz_info = match TzInfo::for_year(utc.year()) {
         Some(tz_info) => tz_info,
-        None => return LocalResult::None,
+        None => return MappedLocalTime::None,
     };
     let offset = match (tz_info.std_transition, tz_info.dst_transition) {
         (Some(std_transition), Some(dst_transition)) => {
@@ -65,16 +64,16 @@
         }
         (None, None) => tz_info.std_offset,
     };
-    LocalResult::Single(offset)
+    MappedLocalTime::Single(offset)
 }
 
 // We don't use `TzSpecificLocalTimeToSystemTime` because it doesn't let us choose how to handle
 // ambiguous cases (during a DST transition). Instead we get the timezone information for the
 // current year and compute it ourselves, like we do on Unix.
-pub(super) fn offset_from_local_datetime(local: &NaiveDateTime) -> LocalResult<FixedOffset> {
+pub(super) fn offset_from_local_datetime(local: &NaiveDateTime) -> MappedLocalTime<FixedOffset> {
     let tz_info = match TzInfo::for_year(local.year()) {
         Some(tz_info) => tz_info,
-        None => return LocalResult::None,
+        None => return MappedLocalTime::None,
     };
     // Create a sorted slice of transitions and use `lookup_with_dst_transitions`.
     match (tz_info.std_transition, tz_info.dst_transition) {
@@ -88,7 +87,7 @@
                 Ordering::Greater => [dst_transition, std_transition],
                 Ordering::Equal => {
                     // This doesn't make sense. Let's just return the standard offset.
-                    return LocalResult::Single(tz_info.std_offset);
+                    return MappedLocalTime::Single(tz_info.std_offset);
                 }
             };
             lookup_with_dst_transitions(&transitions, *local)
@@ -103,7 +102,7 @@
                 [Transition::new(dst_transition, tz_info.std_offset, tz_info.dst_offset)];
             lookup_with_dst_transitions(&transitions, *local)
         }
-        (None, None) => return LocalResult::Single(tz_info.std_offset),
+        (None, None) => MappedLocalTime::Single(tz_info.std_offset),
     }
 }
 
@@ -141,42 +140,74 @@
             }
             tz_info.assume_init()
         };
+        let std_offset = (tz_info.Bias)
+            .checked_add(tz_info.StandardBias)
+            .and_then(|o| o.checked_mul(60))
+            .and_then(FixedOffset::west_opt)?;
+        let dst_offset = (tz_info.Bias)
+            .checked_add(tz_info.DaylightBias)
+            .and_then(|o| o.checked_mul(60))
+            .and_then(FixedOffset::west_opt)?;
         Some(TzInfo {
-            std_offset: FixedOffset::west_opt((tz_info.Bias + tz_info.StandardBias) * 60)?,
-            dst_offset: FixedOffset::west_opt((tz_info.Bias + tz_info.DaylightBias) * 60)?,
-            std_transition: system_time_from_naive_date_time(tz_info.StandardDate, year),
-            dst_transition: system_time_from_naive_date_time(tz_info.DaylightDate, year),
+            std_offset,
+            dst_offset,
+            std_transition: naive_date_time_from_system_time(tz_info.StandardDate, year).ok()?,
+            dst_transition: naive_date_time_from_system_time(tz_info.DaylightDate, year).ok()?,
         })
     }
 }
 
-fn system_time_from_naive_date_time(st: SYSTEMTIME, year: i32) -> Option<NaiveDateTime> {
+/// Resolve a `SYSTEMTIME` object to an `Option<NaiveDateTime>`.
+///
+/// A `SYSTEMTIME` within a `TIME_ZONE_INFORMATION` struct can be zero to indicate there is no
+/// transition.
+/// If it has year, month and day values it is a concrete date.
+/// If the year is missing the `SYSTEMTIME` is a rule, which this method resolves for the provided
+/// year. A rule has a month, weekday, and nth weekday of the month as components.
+///
+/// Returns `Err` if any of the values is invalid, which should never happen.
+fn naive_date_time_from_system_time(
+    st: SYSTEMTIME,
+    year: i32,
+) -> Result<Option<NaiveDateTime>, ()> {
     if st.wYear == 0 && st.wMonth == 0 {
-        return None; // No DST transitions for this year in this timezone.
+        return Ok(None);
     }
     let time = NaiveTime::from_hms_milli_opt(
         st.wHour as u32,
         st.wMinute as u32,
         st.wSecond as u32,
         st.wMilliseconds as u32,
-    )?;
-    // In Chrono's Weekday, Monday is 0 whereas in SYSTEMTIME Monday is 1 and Sunday is 0.
-    // Therefore we move back one day after converting the u16 value to a Weekday.
-    let day_of_week = Weekday::try_from(u8::try_from(st.wDayOfWeek).ok()?).ok()?.pred();
+    )
+    .ok_or(())?;
+
     if st.wYear != 0 {
-        return NaiveDate::from_ymd_opt(st.wYear as i32, st.wMonth as u32, st.wDay as u32)
-            .map(|d| d.and_time(time));
+        // We have a concrete date.
+        let date =
+            NaiveDate::from_ymd_opt(st.wYear as i32, st.wMonth as u32, st.wDay as u32).ok_or(())?;
+        return Ok(Some(date.and_time(time)));
     }
-    let date = if let Some(date) =
-        NaiveDate::from_weekday_of_month_opt(year, st.wMonth as u32, day_of_week, st.wDay as u8)
-    {
-        date
-    } else if st.wDay == 5 {
-        NaiveDate::from_weekday_of_month_opt(year, st.wMonth as u32, day_of_week, 4)?
-    } else {
-        return None;
+
+    // Resolve a rule with month, weekday, and nth weekday of the month to a date in the current
+    // year.
+    let weekday = match st.wDayOfWeek {
+        0 => Weekday::Sun,
+        1 => Weekday::Mon,
+        2 => Weekday::Tue,
+        3 => Weekday::Wed,
+        4 => Weekday::Thu,
+        5 => Weekday::Fri,
+        6 => Weekday::Sat,
+        _ => return Err(()),
     };
-    Some(date.and_time(time))
+    let nth_day = match st.wDay {
+        1..=5 => st.wDay as u8,
+        _ => return Err(()),
+    };
+    let date = NaiveDate::from_weekday_of_month_opt(year, st.wMonth as u32, weekday, nth_day)
+        .or_else(|| NaiveDate::from_weekday_of_month_opt(year, st.wMonth as u32, weekday, 4))
+        .ok_or(())?; // `st.wMonth` must be invalid
+    Ok(Some(date.and_time(time)))
 }
 
 #[cfg(test)]
@@ -184,7 +215,7 @@
     use crate::offset::local::win_bindings::{
         SystemTimeToFileTime, TzSpecificLocalTimeToSystemTime, FILETIME, SYSTEMTIME,
     };
-    use crate::{DateTime, Duration, FixedOffset, Local, NaiveDate, NaiveDateTime};
+    use crate::{DateTime, FixedOffset, Local, NaiveDate, NaiveDateTime, TimeDelta};
     use crate::{Datelike, TimeZone, Timelike};
     use std::mem::MaybeUninit;
     use std::ptr;
@@ -242,7 +273,7 @@
                 SystemTimeToFileTime(st, init.as_mut_ptr());
             }
             // SystemTimeToFileTime must have succeeded at this point, so we can assume the value is
-            // initalized.
+            // initialized.
             let filetime = unsafe { init.assume_init() };
             let bit_shift =
                 ((filetime.dwHighDateTime as u64) << 32) | (filetime.dwLowDateTime as u64);
@@ -256,7 +287,7 @@
             if let Some(our_result) = Local.from_local_datetime(&date).earliest() {
                 assert_eq!(from_local_time(&date), our_result);
             }
-            date += Duration::hours(1);
+            date += TimeDelta::try_hours(1).unwrap();
         }
     }
 }
diff --git a/crates/chrono/src/offset/mod.rs b/crates/chrono/src/offset/mod.rs
index 11928b4..346f809 100644
--- a/crates/chrono/src/offset/mod.rs
+++ b/crates/chrono/src/offset/mod.rs
@@ -37,72 +37,127 @@
 pub(crate) mod utc;
 pub use self::utc::Utc;
 
-/// The conversion result from the local time to the timezone-aware datetime types.
+/// The result of mapping a local time to a concrete instant in a given time zone.
+///
+/// The calculation to go from a local time (wall clock time) to an instant in UTC can end up in
+/// three cases:
+/// * A single, simple result.
+/// * An ambiguous result when the clock is turned backwards during a transition due to for example
+///   DST.
+/// * No result when the clock is turned forwards during a transition due to for example DST.
+///
+/// When the clock is turned backwards it creates a _fold_ in local time, during which the local
+/// time is _ambiguous_. When the clock is turned forwards it creates a _gap_ in local time, during
+/// which the local time is _missing_, or does not exist.
+///
+/// Chrono does not return a default choice or invalid data during time zone transitions, but has
+/// the `MappedLocalTime` type to help deal with the result correctly.
+///
+/// The type of `T` is usually a [`DateTime`] but may also be only an offset.
+pub type MappedLocalTime<T> = LocalResult<T>;
 #[derive(Clone, PartialEq, Debug, Copy, Eq, Hash)]
+
+/// Old name of [`MappedLocalTime`]. See that type for more documentation.
 pub enum LocalResult<T> {
-    /// Given local time representation is invalid.
-    /// This can occur when, for example, the positive timezone transition.
-    None,
-    /// Given local time representation has a single unique result.
+    /// The local time maps to a single unique result.
     Single(T),
-    /// Given local time representation has multiple results and thus ambiguous.
-    /// This can occur when, for example, the negative timezone transition.
-    Ambiguous(T /*min*/, T /*max*/),
+
+    /// The local time is _ambiguous_ because there is a _fold_ in the local time.
+    ///
+    /// This variant contains the two possible results, in the order `(earliest, latest)`.
+    Ambiguous(T, T),
+
+    /// The local time does not exist because there is a _gap_ in the local time.
+    ///
+    /// This variant may also be returned if there was an error while resolving the local time,
+    /// caused by for example missing time zone data files, an error in an OS API, or overflow.
+    None,
 }
 
-impl<T> LocalResult<T> {
-    /// Returns `Some` only when the conversion result is unique, or `None` otherwise.
+impl<T> MappedLocalTime<T> {
+    /// Returns `Some` if the time zone mapping has a single result.
+    ///
+    /// # Errors
+    ///
+    /// Returns `None` if local time falls in a _fold_ or _gap_ in the local time, or if there was
+    /// an error.
     #[must_use]
     pub fn single(self) -> Option<T> {
         match self {
-            LocalResult::Single(t) => Some(t),
+            MappedLocalTime::Single(t) => Some(t),
             _ => None,
         }
     }
 
-    /// Returns `Some` for the earliest possible conversion result, or `None` if none.
+    /// Returns the earliest possible result of the time zone mapping.
+    ///
+    /// # Errors
+    ///
+    /// Returns `None` if local time falls in a _gap_ in the local time, or if there was an error.
     #[must_use]
     pub fn earliest(self) -> Option<T> {
         match self {
-            LocalResult::Single(t) | LocalResult::Ambiguous(t, _) => Some(t),
+            MappedLocalTime::Single(t) | MappedLocalTime::Ambiguous(t, _) => Some(t),
             _ => None,
         }
     }
 
-    /// Returns `Some` for the latest possible conversion result, or `None` if none.
+    /// Returns the latest possible result of the time zone mapping.
+    ///
+    /// # Errors
+    ///
+    /// Returns `None` if local time falls in a _gap_ in the local time, or if there was an error.
     #[must_use]
     pub fn latest(self) -> Option<T> {
         match self {
-            LocalResult::Single(t) | LocalResult::Ambiguous(_, t) => Some(t),
+            MappedLocalTime::Single(t) | MappedLocalTime::Ambiguous(_, t) => Some(t),
             _ => None,
         }
     }
 
-    /// Maps a `LocalResult<T>` into `LocalResult<U>` with given function.
+    /// Maps a `MappedLocalTime<T>` into `MappedLocalTime<U>` with given function.
     #[must_use]
-    pub fn map<U, F: FnMut(T) -> U>(self, mut f: F) -> LocalResult<U> {
+    pub fn map<U, F: FnMut(T) -> U>(self, mut f: F) -> MappedLocalTime<U> {
         match self {
-            LocalResult::None => LocalResult::None,
-            LocalResult::Single(v) => LocalResult::Single(f(v)),
-            LocalResult::Ambiguous(min, max) => LocalResult::Ambiguous(f(min), f(max)),
+            MappedLocalTime::None => MappedLocalTime::None,
+            MappedLocalTime::Single(v) => MappedLocalTime::Single(f(v)),
+            MappedLocalTime::Ambiguous(min, max) => MappedLocalTime::Ambiguous(f(min), f(max)),
+        }
+    }
+
+    /// Maps a `MappedLocalTime<T>` into `MappedLocalTime<U>` with given function.
+    ///
+    /// Returns `MappedLocalTime::None` if the function returns `None`.
+    #[must_use]
+    pub(crate) fn and_then<U, F: FnMut(T) -> Option<U>>(self, mut f: F) -> MappedLocalTime<U> {
+        match self {
+            MappedLocalTime::None => MappedLocalTime::None,
+            MappedLocalTime::Single(v) => match f(v) {
+                Some(new) => MappedLocalTime::Single(new),
+                None => MappedLocalTime::None,
+            },
+            MappedLocalTime::Ambiguous(min, max) => match (f(min), f(max)) {
+                (Some(min), Some(max)) => MappedLocalTime::Ambiguous(min, max),
+                _ => MappedLocalTime::None,
+            },
         }
     }
 }
 
 #[allow(deprecated)]
-impl<Tz: TimeZone> LocalResult<Date<Tz>> {
+impl<Tz: TimeZone> MappedLocalTime<Date<Tz>> {
     /// Makes a new `DateTime` from the current date and given `NaiveTime`.
     /// The offset in the current date is preserved.
     ///
     /// Propagates any error. Ambiguous result would be discarded.
     #[inline]
     #[must_use]
-    pub fn and_time(self, time: NaiveTime) -> LocalResult<DateTime<Tz>> {
+    pub fn and_time(self, time: NaiveTime) -> MappedLocalTime<DateTime<Tz>> {
         match self {
-            LocalResult::Single(d) => {
-                d.and_time(time).map_or(LocalResult::None, LocalResult::Single)
+            MappedLocalTime::Single(d) => {
+                d.and_time(time).map_or(MappedLocalTime::None, MappedLocalTime::Single)
             }
-            _ => LocalResult::None,
+            _ => MappedLocalTime::None,
         }
     }
 
@@ -112,12 +167,12 @@
     /// Propagates any error. Ambiguous result would be discarded.
     #[inline]
     #[must_use]
-    pub fn and_hms_opt(self, hour: u32, min: u32, sec: u32) -> LocalResult<DateTime<Tz>> {
+    pub fn and_hms_opt(self, hour: u32, min: u32, sec: u32) -> MappedLocalTime<DateTime<Tz>> {
         match self {
-            LocalResult::Single(d) => {
-                d.and_hms_opt(hour, min, sec).map_or(LocalResult::None, LocalResult::Single)
+            MappedLocalTime::Single(d) => {
+                d.and_hms_opt(hour, min, sec).map_or(MappedLocalTime::None, MappedLocalTime::Single)
             }
-            _ => LocalResult::None,
+            _ => MappedLocalTime::None,
         }
     }
 
@@ -134,12 +189,12 @@
         min: u32,
         sec: u32,
         milli: u32,
-    ) -> LocalResult<DateTime<Tz>> {
+    ) -> MappedLocalTime<DateTime<Tz>> {
         match self {
-            LocalResult::Single(d) => d
+            MappedLocalTime::Single(d) => d
                 .and_hms_milli_opt(hour, min, sec, milli)
-                .map_or(LocalResult::None, LocalResult::Single),
-            _ => LocalResult::None,
+                .map_or(MappedLocalTime::None, MappedLocalTime::Single),
+            _ => MappedLocalTime::None,
         }
     }
 
@@ -156,12 +211,12 @@
         min: u32,
         sec: u32,
         micro: u32,
-    ) -> LocalResult<DateTime<Tz>> {
+    ) -> MappedLocalTime<DateTime<Tz>> {
         match self {
-            LocalResult::Single(d) => d
+            MappedLocalTime::Single(d) => d
                 .and_hms_micro_opt(hour, min, sec, micro)
-                .map_or(LocalResult::None, LocalResult::Single),
-            _ => LocalResult::None,
+                .map_or(MappedLocalTime::None, MappedLocalTime::Single),
+            _ => MappedLocalTime::None,
         }
     }
 
@@ -178,25 +233,34 @@
         min: u32,
         sec: u32,
         nano: u32,
-    ) -> LocalResult<DateTime<Tz>> {
+    ) -> MappedLocalTime<DateTime<Tz>> {
         match self {
-            LocalResult::Single(d) => d
+            MappedLocalTime::Single(d) => d
                 .and_hms_nano_opt(hour, min, sec, nano)
-                .map_or(LocalResult::None, LocalResult::Single),
-            _ => LocalResult::None,
+                .map_or(MappedLocalTime::None, MappedLocalTime::Single),
+            _ => MappedLocalTime::None,
         }
     }
 }
 
-impl<T: fmt::Debug> LocalResult<T> {
-    /// Returns the single unique conversion result, or panics accordingly.
+impl<T: fmt::Debug> MappedLocalTime<T> {
+    /// Returns a single unique conversion result or panics.
+    ///
+    /// `unwrap()` is best combined with time zone types where the mapping can never fail like
+    /// [`Utc`] and [`FixedOffset`]. Note that for [`FixedOffset`] there is a rare case where a
+    /// resulting [`DateTime`] can be out of range.
+    ///
+    /// # Panics
+    ///
+    /// Panics if the local time falls within a _fold_ or a _gap_ in the local time, and on any
+    /// error that may have been returned by the type implementing [`TimeZone`].
     #[must_use]
     #[track_caller]
     pub fn unwrap(self) -> T {
         match self {
-            LocalResult::None => panic!("No such local time"),
-            LocalResult::Single(t) => t,
-            LocalResult::Ambiguous(t1, t2) => {
+            MappedLocalTime::None => panic!("No such local time"),
+            MappedLocalTime::Single(t) => t,
+            MappedLocalTime::Ambiguous(t1, t2) => {
                 panic!("Ambiguous local time, ranging from {:?} to {:?}", t1, t2)
             }
         }
@@ -222,7 +286,7 @@
     ///
     /// This assumes the proleptic Gregorian calendar, with the year 0 being 1 BCE.
     ///
-    /// Returns `LocalResult::None` on invalid input data.
+    /// Returns `MappedLocalTime::None` on invalid input data.
     fn with_ymd_and_hms(
         &self,
         year: i32,
@@ -231,11 +295,11 @@
         hour: u32,
         min: u32,
         sec: u32,
-    ) -> LocalResult<DateTime<Self>> {
+    ) -> MappedLocalTime<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,
+            None => MappedLocalTime::None,
         }
     }
 
@@ -261,10 +325,10 @@
     /// Returns `None` on the out-of-range date, invalid month and/or day.
     #[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>> {
+    fn ymd_opt(&self, year: i32, month: u32, day: u32) -> MappedLocalTime<Date<Self>> {
         match NaiveDate::from_ymd_opt(year, month, day) {
             Some(d) => self.from_local_date(&d),
-            None => LocalResult::None,
+            None => MappedLocalTime::None,
         }
     }
 
@@ -296,10 +360,10 @@
         note = "use `from_local_datetime()` with a `NaiveDateTime` instead"
     )]
     #[allow(deprecated)]
-    fn yo_opt(&self, year: i32, ordinal: u32) -> LocalResult<Date<Self>> {
+    fn yo_opt(&self, year: i32, ordinal: u32) -> MappedLocalTime<Date<Self>> {
         match NaiveDate::from_yo_opt(year, ordinal) {
             Some(d) => self.from_local_date(&d),
-            None => LocalResult::None,
+            None => MappedLocalTime::None,
         }
     }
 
@@ -335,10 +399,10 @@
         note = "use `from_local_datetime()` with a `NaiveDateTime` instead"
     )]
     #[allow(deprecated)]
-    fn isoywd_opt(&self, year: i32, week: u32, weekday: Weekday) -> LocalResult<Date<Self>> {
+    fn isoywd_opt(&self, year: i32, week: u32, weekday: Weekday) -> MappedLocalTime<Date<Self>> {
         match NaiveDate::from_isoywd_opt(year, week, weekday) {
             Some(d) => self.from_local_date(&d),
-            None => LocalResult::None,
+            None => MappedLocalTime::None,
         }
     }
 
@@ -369,20 +433,20 @@
     ///
     /// # Errors
     ///
-    /// Returns `LocalResult::None` on out-of-range number of seconds and/or
-    /// invalid nanosecond, otherwise always returns `LocalResult::Single`.
+    /// Returns `MappedLocalTime::None` on out-of-range number of seconds and/or
+    /// invalid nanosecond, otherwise always returns `MappedLocalTime::Single`.
     ///
     /// # Example
     ///
     /// ```
-    /// use chrono::{Utc, TimeZone};
+    /// use chrono::{TimeZone, Utc};
     ///
     /// 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)),
-            None => LocalResult::None,
+    fn timestamp_opt(&self, secs: i64, nsecs: u32) -> MappedLocalTime<DateTime<Self>> {
+        match DateTime::from_timestamp(secs, nsecs) {
+            Some(dt) => MappedLocalTime::Single(self.from_utc_datetime(&dt.naive_utc())),
+            None => MappedLocalTime::None,
         }
     }
 
@@ -400,23 +464,23 @@
     /// since January 1, 1970 0:00:00 UTC (aka "UNIX timestamp").
     ///
     ///
-    /// Returns `LocalResult::None` on out-of-range number of milliseconds
+    /// Returns `MappedLocalTime::None` on out-of-range number of milliseconds
     /// and/or invalid nanosecond, otherwise always returns
-    /// `LocalResult::Single`.
+    /// `MappedLocalTime::Single`.
     ///
     /// # Example
     ///
     /// ```
-    /// use chrono::{Utc, TimeZone, LocalResult};
+    /// use chrono::{MappedLocalTime, TimeZone, Utc};
     /// match Utc.timestamp_millis_opt(1431648000) {
-    ///     LocalResult::Single(dt) => assert_eq!(dt.timestamp(), 1431648),
+    ///     MappedLocalTime::Single(dt) => assert_eq!(dt.timestamp(), 1431648),
     ///     _ => panic!("Incorrect timestamp_millis"),
     /// };
     /// ```
-    fn timestamp_millis_opt(&self, millis: i64) -> LocalResult<DateTime<Self>> {
-        match NaiveDateTime::from_timestamp_millis(millis) {
-            Some(dt) => LocalResult::Single(self.from_utc_datetime(&dt)),
-            None => LocalResult::None,
+    fn timestamp_millis_opt(&self, millis: i64) -> MappedLocalTime<DateTime<Self>> {
+        match DateTime::from_timestamp_millis(millis) {
+            Some(dt) => MappedLocalTime::Single(self.from_utc_datetime(&dt.naive_utc())),
+            None => MappedLocalTime::None,
         }
     }
 
@@ -428,17 +492,12 @@
     /// # Example
     ///
     /// ```
-    /// use chrono::{Utc, TimeZone};
+    /// use chrono::{TimeZone, Utc};
     ///
     /// 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 {
-            secs -= 1;
-            nanos += 1_000_000_000;
-        }
-        self.timestamp_opt(secs, nanos as u32).unwrap()
+        self.from_utc_datetime(&DateTime::from_timestamp_nanos(nanos).naive_utc())
     }
 
     /// Makes a new `DateTime` from the number of non-leap microseconds
@@ -447,14 +506,14 @@
     /// # Example
     ///
     /// ```
-    /// use chrono::{Utc, TimeZone};
+    /// use chrono::{TimeZone, Utc};
     ///
     /// assert_eq!(Utc.timestamp_micros(1431648000000).unwrap().timestamp(), 1431648);
     /// ```
-    fn timestamp_micros(&self, micros: i64) -> LocalResult<DateTime<Self>> {
-        match NaiveDateTime::from_timestamp_micros(micros) {
-            Some(dt) => LocalResult::Single(self.from_utc_datetime(&dt)),
-            None => LocalResult::None,
+    fn timestamp_micros(&self, micros: i64) -> MappedLocalTime<DateTime<Self>> {
+        match DateTime::from_timestamp_micros(micros) {
+            Some(dt) => MappedLocalTime::Single(self.from_utc_datetime(&dt.naive_utc())),
+            None => MappedLocalTime::None,
         }
     }
 
@@ -487,16 +546,16 @@
     fn from_offset(offset: &Self::Offset) -> Self;
 
     /// Creates the offset(s) for given local `NaiveDate` if possible.
-    fn offset_from_local_date(&self, local: &NaiveDate) -> LocalResult<Self::Offset>;
+    fn offset_from_local_date(&self, local: &NaiveDate) -> MappedLocalTime<Self::Offset>;
 
     /// Creates the offset(s) for given local `NaiveDateTime` if possible.
-    fn offset_from_local_datetime(&self, local: &NaiveDateTime) -> LocalResult<Self::Offset>;
+    fn offset_from_local_datetime(&self, local: &NaiveDateTime) -> MappedLocalTime<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>> {
+    fn from_local_date(&self, local: &NaiveDate) -> MappedLocalTime<Date<Self>> {
         self.offset_from_local_date(local).map(|offset| {
             // since FixedOffset is within +/- 1 day, the date is never affected
             Date::from_utc(*local, offset)
@@ -505,25 +564,12 @@
 
     /// 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>> {
-        // Return `LocalResult::None` when the offset pushes a value out of range, instead of
-        // panicking.
-        match self.offset_from_local_datetime(local) {
-            LocalResult::None => LocalResult::None,
-            LocalResult::Single(offset) => match local.checked_sub_offset(offset.fix()) {
-                Some(dt) => LocalResult::Single(DateTime::from_naive_utc_and_offset(dt, offset)),
-                None => LocalResult::None,
-            },
-            LocalResult::Ambiguous(o1, o2) => {
-                match (local.checked_sub_offset(o1.fix()), local.checked_sub_offset(o2.fix())) {
-                    (Some(d1), Some(d2)) => LocalResult::Ambiguous(
-                        DateTime::from_naive_utc_and_offset(d1, o1),
-                        DateTime::from_naive_utc_and_offset(d2, o2),
-                    ),
-                    _ => LocalResult::None,
-                }
-            }
-        }
+    fn from_local_datetime(&self, local: &NaiveDateTime) -> MappedLocalTime<DateTime<Self>> {
+        self.offset_from_local_datetime(local).and_then(|off| {
+            local
+                .checked_sub_offset(off.fix())
+                .map(|dt| DateTime::from_naive_utc_and_offset(dt, off))
+        })
     }
 
     /// Creates the offset for given UTC `NaiveDate`. This cannot fail.
@@ -568,13 +614,13 @@
             if offset_hour >= 0 {
                 assert_eq!(local_max.unwrap().naive_local(), NaiveDateTime::MAX);
             } else {
-                assert_eq!(local_max, LocalResult::None);
+                assert_eq!(local_max, MappedLocalTime::None);
             }
             let local_min = offset.from_local_datetime(&NaiveDateTime::MIN);
             if offset_hour <= 0 {
                 assert_eq!(local_min.unwrap().naive_local(), NaiveDateTime::MIN);
             } else {
-                assert_eq!(local_min, LocalResult::None);
+                assert_eq!(local_min, MappedLocalTime::None);
             }
         }
     }
@@ -604,7 +650,7 @@
             (-7003, "1969-12-31 23:59:52.997 UTC"),
         ] {
             match Utc.timestamp_millis_opt(*millis) {
-                LocalResult::Single(dt) => {
+                MappedLocalTime::Single(dt) => {
                     assert_eq!(dt.to_string(), *expected);
                 }
                 e => panic!("Got {:?} instead of an okay answer", e),
@@ -628,9 +674,9 @@
 
     #[test]
     fn test_nanos_never_panics() {
-        Utc.timestamp_nanos(i64::max_value());
+        Utc.timestamp_nanos(i64::MAX);
         Utc.timestamp_nanos(i64::default());
-        Utc.timestamp_nanos(i64::min_value());
+        Utc.timestamp_nanos(i64::MIN);
     }
 
     #[test]
diff --git a/crates/chrono/src/offset/utc.rs b/crates/chrono/src/offset/utc.rs
index 29b832a..5ae26ed 100644
--- a/crates/chrono/src/offset/utc.rs
+++ b/crates/chrono/src/offset/utc.rs
@@ -17,7 +17,7 @@
 #[cfg(any(feature = "rkyv", feature = "rkyv-16", feature = "rkyv-32", feature = "rkyv-64"))]
 use rkyv::{Archive, Deserialize, Serialize};
 
-use super::{FixedOffset, LocalResult, Offset, TimeZone};
+use super::{FixedOffset, MappedLocalTime, Offset, TimeZone};
 use crate::naive::{NaiveDate, NaiveDateTime};
 #[cfg(feature = "now")]
 #[allow(deprecated)]
@@ -33,9 +33,9 @@
 /// # Example
 ///
 /// ```
-/// use chrono::{TimeZone, NaiveDateTime, Utc};
+/// use chrono::{DateTime, TimeZone, Utc};
 ///
-/// let dt = Utc.from_utc_datetime(&NaiveDateTime::from_timestamp_opt(61, 0).unwrap());
+/// let dt = DateTime::from_timestamp(61, 0).unwrap();
 ///
 /// assert_eq!(Utc.timestamp_opt(61, 0).unwrap(), dt);
 /// assert_eq!(Utc.with_ymd_and_hms(1970, 1, 1, 0, 1, 1).unwrap(), dt);
@@ -95,9 +95,7 @@
     pub fn now() -> DateTime<Utc> {
         let now =
             SystemTime::now().duration_since(UNIX_EPOCH).expect("system time before Unix epoch");
-        let naive =
-            NaiveDateTime::from_timestamp_opt(now.as_secs() as i64, now.subsec_nanos()).unwrap();
-        Utc.from_utc_datetime(&naive)
+        DateTime::from_timestamp(now.as_secs() as i64, now.subsec_nanos()).unwrap()
     }
 
     /// Returns a `DateTime` which corresponds to the current date and time.
@@ -120,11 +118,11 @@
         Utc
     }
 
-    fn offset_from_local_date(&self, _local: &NaiveDate) -> LocalResult<Utc> {
-        LocalResult::Single(Utc)
+    fn offset_from_local_date(&self, _local: &NaiveDate) -> MappedLocalTime<Utc> {
+        MappedLocalTime::Single(Utc)
     }
-    fn offset_from_local_datetime(&self, _local: &NaiveDateTime) -> LocalResult<Utc> {
-        LocalResult::Single(Utc)
+    fn offset_from_local_datetime(&self, _local: &NaiveDateTime) -> MappedLocalTime<Utc> {
+        MappedLocalTime::Single(Utc)
     }
 
     fn offset_from_utc_date(&self, _utc: &NaiveDate) -> Utc {
diff --git a/crates/chrono/src/round.rs b/crates/chrono/src/round.rs
index 315d453..9b19a64 100644
--- a/crates/chrono/src/round.rs
+++ b/crates/chrono/src/round.rs
@@ -6,7 +6,6 @@
 use crate::{DateTime, NaiveDateTime, TimeDelta, TimeZone, Timelike};
 use core::cmp::Ordering;
 use core::fmt;
-use core::marker::Sized;
 use core::ops::{Add, Sub};
 
 /// Extension trait for subsecond rounding or truncation to a maximum number
@@ -22,8 +21,12 @@
     ///
     /// # Example
     /// ``` rust
-    /// # use chrono::{SubsecRound, Timelike, Utc, NaiveDate};
-    /// let dt = NaiveDate::from_ymd_opt(2018, 1, 11).unwrap().and_hms_milli_opt(12, 0, 0, 154).unwrap().and_local_timezone(Utc).unwrap();
+    /// # use chrono::{SubsecRound, Timelike, NaiveDate};
+    /// let dt = NaiveDate::from_ymd_opt(2018, 1, 11)
+    ///     .unwrap()
+    ///     .and_hms_milli_opt(12, 0, 0, 154)
+    ///     .unwrap()
+    ///     .and_utc();
     /// assert_eq!(dt.round_subsecs(2).nanosecond(), 150_000_000);
     /// assert_eq!(dt.round_subsecs(1).nanosecond(), 200_000_000);
     /// ```
@@ -34,8 +37,12 @@
     ///
     /// # Example
     /// ``` rust
-    /// # use chrono::{SubsecRound, Timelike, Utc, NaiveDate};
-    /// let dt = NaiveDate::from_ymd_opt(2018, 1, 11).unwrap().and_hms_milli_opt(12, 0, 0, 154).unwrap().and_local_timezone(Utc).unwrap();
+    /// # use chrono::{SubsecRound, Timelike, NaiveDate};
+    /// let dt = NaiveDate::from_ymd_opt(2018, 1, 11)
+    ///     .unwrap()
+    ///     .and_hms_milli_opt(12, 0, 0, 154)
+    ///     .unwrap()
+    ///     .and_utc();
     /// assert_eq!(dt.trunc_subsecs(2).nanosecond(), 150_000_000);
     /// assert_eq!(dt.trunc_subsecs(1).nanosecond(), 100_000_000);
     /// ```
@@ -95,7 +102,7 @@
 /// Both rounding and truncating are done via [`TimeDelta::num_nanoseconds`] and
 /// [`DateTime::timestamp_nanos_opt`]. This means that they will fail if either the
 /// `TimeDelta` or the `DateTime` are too big to represented as nanoseconds. They
-/// will also fail if the `TimeDelta` is bigger than the timestamp.
+/// will also fail if the `TimeDelta` is bigger than the timestamp, negative or zero.
 pub trait DurationRound: Sized {
     /// Error that can occur in rounding or truncating
     #[cfg(feature = "std")]
@@ -109,14 +116,18 @@
     ///
     /// # Example
     /// ``` rust
-    /// # use chrono::{DurationRound, TimeDelta, 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();
+    /// # use chrono::{DurationRound, TimeDelta, NaiveDate};
+    /// let dt = NaiveDate::from_ymd_opt(2018, 1, 11)
+    ///     .unwrap()
+    ///     .and_hms_milli_opt(12, 0, 0, 154)
+    ///     .unwrap()
+    ///     .and_utc();
     /// assert_eq!(
-    ///     dt.duration_round(TimeDelta::milliseconds(10)).unwrap().to_string(),
+    ///     dt.duration_round(TimeDelta::try_milliseconds(10).unwrap()).unwrap().to_string(),
     ///     "2018-01-11 12:00:00.150 UTC"
     /// );
     /// assert_eq!(
-    ///     dt.duration_round(TimeDelta::days(1)).unwrap().to_string(),
+    ///     dt.duration_round(TimeDelta::try_days(1).unwrap()).unwrap().to_string(),
     ///     "2018-01-12 00:00:00 UTC"
     /// );
     /// ```
@@ -126,14 +137,18 @@
     ///
     /// # Example
     /// ``` rust
-    /// # use chrono::{DurationRound, TimeDelta, 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();
+    /// # use chrono::{DurationRound, TimeDelta, NaiveDate};
+    /// let dt = NaiveDate::from_ymd_opt(2018, 1, 11)
+    ///     .unwrap()
+    ///     .and_hms_milli_opt(12, 0, 0, 154)
+    ///     .unwrap()
+    ///     .and_utc();
     /// assert_eq!(
-    ///     dt.duration_trunc(TimeDelta::milliseconds(10)).unwrap().to_string(),
+    ///     dt.duration_trunc(TimeDelta::try_milliseconds(10).unwrap()).unwrap().to_string(),
     ///     "2018-01-11 12:00:00.150 UTC"
     /// );
     /// assert_eq!(
-    ///     dt.duration_trunc(TimeDelta::days(1)).unwrap().to_string(),
+    ///     dt.duration_trunc(TimeDelta::try_days(1).unwrap()).unwrap().to_string(),
     ///     "2018-01-11 00:00:00 UTC"
     /// );
     /// ```
@@ -173,13 +188,11 @@
     T: Timelike + Add<TimeDelta, Output = T> + Sub<TimeDelta, Output = T>,
 {
     if let Some(span) = duration.num_nanoseconds() {
-        if span < 0 {
+        if span <= 0 {
             return Err(RoundingError::DurationExceedsLimit);
         }
-        let stamp = naive.timestamp_nanos_opt().ok_or(RoundingError::TimestampExceedsLimit)?;
-        if span == 0 {
-            return Ok(original);
-        }
+        let stamp =
+            naive.and_utc().timestamp_nanos_opt().ok_or(RoundingError::TimestampExceedsLimit)?;
         let delta_down = stamp % span;
         if delta_down == 0 {
             Ok(original)
@@ -209,10 +222,11 @@
     T: Timelike + Add<TimeDelta, Output = T> + Sub<TimeDelta, Output = T>,
 {
     if let Some(span) = duration.num_nanoseconds() {
-        if span < 0 {
+        if span <= 0 {
             return Err(RoundingError::DurationExceedsLimit);
         }
-        let stamp = naive.timestamp_nanos_opt().ok_or(RoundingError::TimestampExceedsLimit)?;
+        let stamp =
+            naive.and_utc().timestamp_nanos_opt().ok_or(RoundingError::TimestampExceedsLimit)?;
         let delta_down = stamp % span;
         match delta_down.cmp(&0) {
             Ordering::Equal => Ok(original),
@@ -237,11 +251,15 @@
     /// Error when `TimeDelta.num_nanoseconds` exceeds the limit.
     ///
     /// ``` rust
-    /// # use chrono::{DurationRound, TimeDelta, RoundingError, Utc, NaiveDate};
-    /// let dt = NaiveDate::from_ymd_opt(2260, 12, 31).unwrap().and_hms_nano_opt(23, 59, 59, 1_75_500_000).unwrap().and_local_timezone(Utc).unwrap();
+    /// # use chrono::{DurationRound, TimeDelta, RoundingError, NaiveDate};
+    /// let dt = NaiveDate::from_ymd_opt(2260, 12, 31)
+    ///     .unwrap()
+    ///     .and_hms_nano_opt(23, 59, 59, 1_75_500_000)
+    ///     .unwrap()
+    ///     .and_utc();
     ///
     /// assert_eq!(
-    ///     dt.duration_round(TimeDelta::days(300 * 365)),
+    ///     dt.duration_round(TimeDelta::try_days(300 * 365).unwrap()),
     ///     Err(RoundingError::DurationExceedsLimit)
     /// );
     /// ```
@@ -253,7 +271,10 @@
     /// # use chrono::{DurationRound, TimeDelta, RoundingError, TimeZone, Utc};
     /// let dt = Utc.with_ymd_and_hms(2300, 12, 12, 0, 0, 0).unwrap();
     ///
-    /// assert_eq!(dt.duration_round(TimeDelta::days(1)), Err(RoundingError::TimestampExceedsLimit),);
+    /// assert_eq!(
+    ///     dt.duration_round(TimeDelta::try_days(1).unwrap()),
+    ///     Err(RoundingError::TimestampExceedsLimit)
+    /// );
     /// ```
     TimestampExceedsLimit,
 }
@@ -287,7 +308,7 @@
     use super::{DurationRound, RoundingError, SubsecRound, TimeDelta};
     use crate::offset::{FixedOffset, TimeZone, Utc};
     use crate::Timelike;
-    use crate::{NaiveDate, NaiveDateTime};
+    use crate::{DateTime, NaiveDate};
 
     #[test]
     fn test_round_subsecs() {
@@ -429,12 +450,13 @@
             .unwrap();
 
         assert_eq!(
-            dt.duration_round(TimeDelta::zero()).unwrap().to_string(),
-            "2016-12-31 23:59:59.175500 UTC"
+            dt.duration_round(TimeDelta::new(-1, 0).unwrap()),
+            Err(RoundingError::DurationExceedsLimit)
         );
+        assert_eq!(dt.duration_round(TimeDelta::zero()), Err(RoundingError::DurationExceedsLimit));
 
         assert_eq!(
-            dt.duration_round(TimeDelta::milliseconds(10)).unwrap().to_string(),
+            dt.duration_round(TimeDelta::try_milliseconds(10).unwrap()).unwrap().to_string(),
             "2016-12-31 23:59:59.180 UTC"
         );
 
@@ -448,7 +470,7 @@
             )
             .unwrap();
         assert_eq!(
-            dt.duration_round(TimeDelta::minutes(5)).unwrap().to_string(),
+            dt.duration_round(TimeDelta::try_minutes(5).unwrap()).unwrap().to_string(),
             "2012-12-12 18:25:00 UTC"
         );
         // round down
@@ -461,24 +483,24 @@
             )
             .unwrap();
         assert_eq!(
-            dt.duration_round(TimeDelta::minutes(5)).unwrap().to_string(),
+            dt.duration_round(TimeDelta::try_minutes(5).unwrap()).unwrap().to_string(),
             "2012-12-12 18:20:00 UTC"
         );
 
         assert_eq!(
-            dt.duration_round(TimeDelta::minutes(10)).unwrap().to_string(),
+            dt.duration_round(TimeDelta::try_minutes(10).unwrap()).unwrap().to_string(),
             "2012-12-12 18:20:00 UTC"
         );
         assert_eq!(
-            dt.duration_round(TimeDelta::minutes(30)).unwrap().to_string(),
+            dt.duration_round(TimeDelta::try_minutes(30).unwrap()).unwrap().to_string(),
             "2012-12-12 18:30:00 UTC"
         );
         assert_eq!(
-            dt.duration_round(TimeDelta::hours(1)).unwrap().to_string(),
+            dt.duration_round(TimeDelta::try_hours(1).unwrap()).unwrap().to_string(),
             "2012-12-12 18:00:00 UTC"
         );
         assert_eq!(
-            dt.duration_round(TimeDelta::days(1)).unwrap().to_string(),
+            dt.duration_round(TimeDelta::try_days(1).unwrap()).unwrap().to_string(),
             "2012-12-13 00:00:00 UTC"
         );
 
@@ -486,11 +508,11 @@
         let dt =
             FixedOffset::east_opt(3600).unwrap().with_ymd_and_hms(2020, 10, 27, 15, 0, 0).unwrap();
         assert_eq!(
-            dt.duration_round(TimeDelta::days(1)).unwrap().to_string(),
+            dt.duration_round(TimeDelta::try_days(1).unwrap()).unwrap().to_string(),
             "2020-10-28 00:00:00 +01:00"
         );
         assert_eq!(
-            dt.duration_round(TimeDelta::weeks(1)).unwrap().to_string(),
+            dt.duration_round(TimeDelta::try_weeks(1).unwrap()).unwrap().to_string(),
             "2020-10-29 00:00:00 +01:00"
         );
 
@@ -498,11 +520,11 @@
         let dt =
             FixedOffset::west_opt(3600).unwrap().with_ymd_and_hms(2020, 10, 27, 15, 0, 0).unwrap();
         assert_eq!(
-            dt.duration_round(TimeDelta::days(1)).unwrap().to_string(),
+            dt.duration_round(TimeDelta::try_days(1).unwrap()).unwrap().to_string(),
             "2020-10-28 00:00:00 -01:00"
         );
         assert_eq!(
-            dt.duration_round(TimeDelta::weeks(1)).unwrap().to_string(),
+            dt.duration_round(TimeDelta::try_weeks(1).unwrap()).unwrap().to_string(),
             "2020-10-29 00:00:00 -01:00"
         );
     }
@@ -520,12 +542,13 @@
             .naive_utc();
 
         assert_eq!(
-            dt.duration_round(TimeDelta::zero()).unwrap().to_string(),
-            "2016-12-31 23:59:59.175500"
+            dt.duration_round(TimeDelta::new(-1, 0).unwrap()),
+            Err(RoundingError::DurationExceedsLimit)
         );
+        assert_eq!(dt.duration_round(TimeDelta::zero()), Err(RoundingError::DurationExceedsLimit));
 
         assert_eq!(
-            dt.duration_round(TimeDelta::milliseconds(10)).unwrap().to_string(),
+            dt.duration_round(TimeDelta::try_milliseconds(10).unwrap()).unwrap().to_string(),
             "2016-12-31 23:59:59.180"
         );
 
@@ -540,7 +563,7 @@
             .unwrap()
             .naive_utc();
         assert_eq!(
-            dt.duration_round(TimeDelta::minutes(5)).unwrap().to_string(),
+            dt.duration_round(TimeDelta::try_minutes(5).unwrap()).unwrap().to_string(),
             "2012-12-12 18:25:00"
         );
         // round down
@@ -554,24 +577,24 @@
             .unwrap()
             .naive_utc();
         assert_eq!(
-            dt.duration_round(TimeDelta::minutes(5)).unwrap().to_string(),
+            dt.duration_round(TimeDelta::try_minutes(5).unwrap()).unwrap().to_string(),
             "2012-12-12 18:20:00"
         );
 
         assert_eq!(
-            dt.duration_round(TimeDelta::minutes(10)).unwrap().to_string(),
+            dt.duration_round(TimeDelta::try_minutes(10).unwrap()).unwrap().to_string(),
             "2012-12-12 18:20:00"
         );
         assert_eq!(
-            dt.duration_round(TimeDelta::minutes(30)).unwrap().to_string(),
+            dt.duration_round(TimeDelta::try_minutes(30).unwrap()).unwrap().to_string(),
             "2012-12-12 18:30:00"
         );
         assert_eq!(
-            dt.duration_round(TimeDelta::hours(1)).unwrap().to_string(),
+            dt.duration_round(TimeDelta::try_hours(1).unwrap()).unwrap().to_string(),
             "2012-12-12 18:00:00"
         );
         assert_eq!(
-            dt.duration_round(TimeDelta::days(1)).unwrap().to_string(),
+            dt.duration_round(TimeDelta::try_days(1).unwrap()).unwrap().to_string(),
             "2012-12-13 00:00:00"
         );
     }
@@ -580,7 +603,7 @@
     fn test_duration_round_pre_epoch() {
         let dt = Utc.with_ymd_and_hms(1969, 12, 12, 12, 12, 12).unwrap();
         assert_eq!(
-            dt.duration_round(TimeDelta::minutes(10)).unwrap().to_string(),
+            dt.duration_round(TimeDelta::try_minutes(10).unwrap()).unwrap().to_string(),
             "1969-12-12 12:10:00 UTC"
         );
     }
@@ -597,7 +620,13 @@
             .unwrap();
 
         assert_eq!(
-            dt.duration_trunc(TimeDelta::milliseconds(10)).unwrap().to_string(),
+            dt.duration_trunc(TimeDelta::new(-1, 0).unwrap()),
+            Err(RoundingError::DurationExceedsLimit)
+        );
+        assert_eq!(dt.duration_trunc(TimeDelta::zero()), Err(RoundingError::DurationExceedsLimit));
+
+        assert_eq!(
+            dt.duration_trunc(TimeDelta::try_milliseconds(10).unwrap()).unwrap().to_string(),
             "2016-12-31 23:59:59.170 UTC"
         );
 
@@ -611,7 +640,7 @@
             )
             .unwrap();
         assert_eq!(
-            dt.duration_trunc(TimeDelta::minutes(5)).unwrap().to_string(),
+            dt.duration_trunc(TimeDelta::try_minutes(5).unwrap()).unwrap().to_string(),
             "2012-12-12 18:20:00 UTC"
         );
         // would round down
@@ -624,23 +653,23 @@
             )
             .unwrap();
         assert_eq!(
-            dt.duration_trunc(TimeDelta::minutes(5)).unwrap().to_string(),
+            dt.duration_trunc(TimeDelta::try_minutes(5).unwrap()).unwrap().to_string(),
             "2012-12-12 18:20:00 UTC"
         );
         assert_eq!(
-            dt.duration_trunc(TimeDelta::minutes(10)).unwrap().to_string(),
+            dt.duration_trunc(TimeDelta::try_minutes(10).unwrap()).unwrap().to_string(),
             "2012-12-12 18:20:00 UTC"
         );
         assert_eq!(
-            dt.duration_trunc(TimeDelta::minutes(30)).unwrap().to_string(),
+            dt.duration_trunc(TimeDelta::try_minutes(30).unwrap()).unwrap().to_string(),
             "2012-12-12 18:00:00 UTC"
         );
         assert_eq!(
-            dt.duration_trunc(TimeDelta::hours(1)).unwrap().to_string(),
+            dt.duration_trunc(TimeDelta::try_hours(1).unwrap()).unwrap().to_string(),
             "2012-12-12 18:00:00 UTC"
         );
         assert_eq!(
-            dt.duration_trunc(TimeDelta::days(1)).unwrap().to_string(),
+            dt.duration_trunc(TimeDelta::try_days(1).unwrap()).unwrap().to_string(),
             "2012-12-12 00:00:00 UTC"
         );
 
@@ -648,11 +677,11 @@
         let dt =
             FixedOffset::east_opt(3600).unwrap().with_ymd_and_hms(2020, 10, 27, 15, 0, 0).unwrap();
         assert_eq!(
-            dt.duration_trunc(TimeDelta::days(1)).unwrap().to_string(),
+            dt.duration_trunc(TimeDelta::try_days(1).unwrap()).unwrap().to_string(),
             "2020-10-27 00:00:00 +01:00"
         );
         assert_eq!(
-            dt.duration_trunc(TimeDelta::weeks(1)).unwrap().to_string(),
+            dt.duration_trunc(TimeDelta::try_weeks(1).unwrap()).unwrap().to_string(),
             "2020-10-22 00:00:00 +01:00"
         );
 
@@ -660,11 +689,11 @@
         let dt =
             FixedOffset::west_opt(3600).unwrap().with_ymd_and_hms(2020, 10, 27, 15, 0, 0).unwrap();
         assert_eq!(
-            dt.duration_trunc(TimeDelta::days(1)).unwrap().to_string(),
+            dt.duration_trunc(TimeDelta::try_days(1).unwrap()).unwrap().to_string(),
             "2020-10-27 00:00:00 -01:00"
         );
         assert_eq!(
-            dt.duration_trunc(TimeDelta::weeks(1)).unwrap().to_string(),
+            dt.duration_trunc(TimeDelta::try_weeks(1).unwrap()).unwrap().to_string(),
             "2020-10-22 00:00:00 -01:00"
         );
     }
@@ -682,7 +711,13 @@
             .naive_utc();
 
         assert_eq!(
-            dt.duration_trunc(TimeDelta::milliseconds(10)).unwrap().to_string(),
+            dt.duration_trunc(TimeDelta::new(-1, 0).unwrap()),
+            Err(RoundingError::DurationExceedsLimit)
+        );
+        assert_eq!(dt.duration_trunc(TimeDelta::zero()), Err(RoundingError::DurationExceedsLimit));
+
+        assert_eq!(
+            dt.duration_trunc(TimeDelta::try_milliseconds(10).unwrap()).unwrap().to_string(),
             "2016-12-31 23:59:59.170"
         );
 
@@ -697,7 +732,7 @@
             .unwrap()
             .naive_utc();
         assert_eq!(
-            dt.duration_trunc(TimeDelta::minutes(5)).unwrap().to_string(),
+            dt.duration_trunc(TimeDelta::try_minutes(5).unwrap()).unwrap().to_string(),
             "2012-12-12 18:20:00"
         );
         // would round down
@@ -711,23 +746,23 @@
             .unwrap()
             .naive_utc();
         assert_eq!(
-            dt.duration_trunc(TimeDelta::minutes(5)).unwrap().to_string(),
+            dt.duration_trunc(TimeDelta::try_minutes(5).unwrap()).unwrap().to_string(),
             "2012-12-12 18:20:00"
         );
         assert_eq!(
-            dt.duration_trunc(TimeDelta::minutes(10)).unwrap().to_string(),
+            dt.duration_trunc(TimeDelta::try_minutes(10).unwrap()).unwrap().to_string(),
             "2012-12-12 18:20:00"
         );
         assert_eq!(
-            dt.duration_trunc(TimeDelta::minutes(30)).unwrap().to_string(),
+            dt.duration_trunc(TimeDelta::try_minutes(30).unwrap()).unwrap().to_string(),
             "2012-12-12 18:00:00"
         );
         assert_eq!(
-            dt.duration_trunc(TimeDelta::hours(1)).unwrap().to_string(),
+            dt.duration_trunc(TimeDelta::try_hours(1).unwrap()).unwrap().to_string(),
             "2012-12-12 18:00:00"
         );
         assert_eq!(
-            dt.duration_trunc(TimeDelta::days(1)).unwrap().to_string(),
+            dt.duration_trunc(TimeDelta::try_days(1).unwrap()).unwrap().to_string(),
             "2012-12-12 00:00:00"
         );
     }
@@ -736,29 +771,29 @@
     fn test_duration_trunc_pre_epoch() {
         let dt = Utc.with_ymd_and_hms(1969, 12, 12, 12, 12, 12).unwrap();
         assert_eq!(
-            dt.duration_trunc(TimeDelta::minutes(10)).unwrap().to_string(),
+            dt.duration_trunc(TimeDelta::try_minutes(10).unwrap()).unwrap().to_string(),
             "1969-12-12 12:10:00 UTC"
         );
     }
 
     #[test]
     fn issue1010() {
-        let dt = NaiveDateTime::from_timestamp_opt(-4_227_854_320, 678_774_288).unwrap();
+        let dt = DateTime::from_timestamp(-4_227_854_320, 678_774_288).unwrap();
         let span = TimeDelta::microseconds(-7_019_067_213_869_040);
         assert_eq!(dt.duration_trunc(span), Err(RoundingError::DurationExceedsLimit));
 
-        let dt = NaiveDateTime::from_timestamp_opt(320_041_586, 920_103_021).unwrap();
+        let dt = DateTime::from_timestamp(320_041_586, 920_103_021).unwrap();
         let span = TimeDelta::nanoseconds(-8_923_838_508_697_114_584);
         assert_eq!(dt.duration_round(span), Err(RoundingError::DurationExceedsLimit));
 
-        let dt = NaiveDateTime::from_timestamp_opt(-2_621_440, 0).unwrap();
+        let dt = DateTime::from_timestamp(-2_621_440, 0).unwrap();
         let span = TimeDelta::nanoseconds(-9_223_372_036_854_771_421);
         assert_eq!(dt.duration_round(span), Err(RoundingError::DurationExceedsLimit));
     }
 
     #[test]
     fn test_duration_trunc_close_to_epoch() {
-        let span = TimeDelta::minutes(15);
+        let span = TimeDelta::try_minutes(15).unwrap();
 
         let dt = NaiveDate::from_ymd_opt(1970, 1, 1).unwrap().and_hms_opt(0, 0, 15).unwrap();
         assert_eq!(dt.duration_trunc(span).unwrap().to_string(), "1970-01-01 00:00:00");
@@ -769,7 +804,7 @@
 
     #[test]
     fn test_duration_round_close_to_epoch() {
-        let span = TimeDelta::minutes(15);
+        let span = TimeDelta::try_minutes(15).unwrap();
 
         let dt = NaiveDate::from_ymd_opt(1970, 1, 1).unwrap().and_hms_opt(0, 0, 15).unwrap();
         assert_eq!(dt.duration_round(span).unwrap().to_string(), "1970-01-01 00:00:00");
@@ -782,16 +817,22 @@
     fn test_duration_round_close_to_min_max() {
         let span = TimeDelta::nanoseconds(i64::MAX);
 
-        let dt = NaiveDateTime::from_timestamp_nanos(i64::MIN / 2 - 1).unwrap();
-        assert_eq!(dt.duration_round(span).unwrap().to_string(), "1677-09-21 00:12:43.145224193");
+        let dt = DateTime::from_timestamp_nanos(i64::MIN / 2 - 1);
+        assert_eq!(
+            dt.duration_round(span).unwrap().to_string(),
+            "1677-09-21 00:12:43.145224193 UTC"
+        );
 
-        let dt = NaiveDateTime::from_timestamp_nanos(i64::MIN / 2 + 1).unwrap();
-        assert_eq!(dt.duration_round(span).unwrap().to_string(), "1970-01-01 00:00:00");
+        let dt = DateTime::from_timestamp_nanos(i64::MIN / 2 + 1);
+        assert_eq!(dt.duration_round(span).unwrap().to_string(), "1970-01-01 00:00:00 UTC");
 
-        let dt = NaiveDateTime::from_timestamp_nanos(i64::MAX / 2 + 1).unwrap();
-        assert_eq!(dt.duration_round(span).unwrap().to_string(), "2262-04-11 23:47:16.854775807");
+        let dt = DateTime::from_timestamp_nanos(i64::MAX / 2 + 1);
+        assert_eq!(
+            dt.duration_round(span).unwrap().to_string(),
+            "2262-04-11 23:47:16.854775807 UTC"
+        );
 
-        let dt = NaiveDateTime::from_timestamp_nanos(i64::MAX / 2 - 1).unwrap();
-        assert_eq!(dt.duration_round(span).unwrap().to_string(), "1970-01-01 00:00:00");
+        let dt = DateTime::from_timestamp_nanos(i64::MAX / 2 - 1);
+        assert_eq!(dt.duration_round(span).unwrap().to_string(), "1970-01-01 00:00:00 UTC");
     }
 }
diff --git a/crates/chrono/src/time_delta.rs b/crates/chrono/src/time_delta.rs
index e5e22b6..3eb041a 100644
--- a/crates/chrono/src/time_delta.rs
+++ b/crates/chrono/src/time_delta.rs
@@ -10,9 +10,9 @@
 
 //! Temporal quantification
 
+use core::fmt;
 use core::ops::{Add, AddAssign, Div, Mul, Neg, Sub, SubAssign};
 use core::time::Duration;
-use core::{fmt, i64};
 #[cfg(feature = "std")]
 use std::error::Error;
 
@@ -103,12 +103,12 @@
     #[inline]
     #[must_use]
     pub const fn weeks(weeks: i64) -> TimeDelta {
-        expect!(TimeDelta::try_weeks(weeks), "TimeDelta::weeks out of bounds")
+        expect(TimeDelta::try_weeks(weeks), "TimeDelta::weeks out of bounds")
     }
 
     /// Makes a new `TimeDelta` with the given number of weeks.
     ///
-    /// Equivalent to `TimeDelta::seconds(weeks * 7 * 24 * 60 * 60)` with
+    /// Equivalent to `TimeDelta::try_seconds(weeks * 7 * 24 * 60 * 60)` with
     /// overflow checks.
     ///
     /// # Errors
@@ -130,12 +130,12 @@
     #[inline]
     #[must_use]
     pub const fn days(days: i64) -> TimeDelta {
-        expect!(TimeDelta::try_days(days), "TimeDelta::days out of bounds")
+        expect(TimeDelta::try_days(days), "TimeDelta::days out of bounds")
     }
 
     /// Makes a new `TimeDelta` with the given number of days.
     ///
-    /// Equivalent to `TimeDelta::seconds(days * 24 * 60 * 60)` with overflow
+    /// Equivalent to `TimeDelta::try_seconds(days * 24 * 60 * 60)` with overflow
     /// checks.
     ///
     /// # Errors
@@ -156,12 +156,12 @@
     #[inline]
     #[must_use]
     pub const fn hours(hours: i64) -> TimeDelta {
-        expect!(TimeDelta::try_hours(hours), "TimeDelta::hours out of bounds")
+        expect(TimeDelta::try_hours(hours), "TimeDelta::hours out of bounds")
     }
 
     /// Makes a new `TimeDelta` with the given number of hours.
     ///
-    /// Equivalent to `TimeDelta::seconds(hours * 60 * 60)` with overflow checks.
+    /// Equivalent to `TimeDelta::try_seconds(hours * 60 * 60)` with overflow checks.
     ///
     /// # Errors
     ///
@@ -181,12 +181,12 @@
     #[inline]
     #[must_use]
     pub const fn minutes(minutes: i64) -> TimeDelta {
-        expect!(TimeDelta::try_minutes(minutes), "TimeDelta::minutes out of bounds")
+        expect(TimeDelta::try_minutes(minutes), "TimeDelta::minutes out of bounds")
     }
 
     /// Makes a new `TimeDelta` with the given number of minutes.
     ///
-    /// Equivalent to `TimeDelta::seconds(minutes * 60)` with overflow checks.
+    /// Equivalent to `TimeDelta::try_seconds(minutes * 60)` with overflow checks.
     ///
     /// # Errors
     ///
@@ -205,7 +205,7 @@
     #[inline]
     #[must_use]
     pub const fn seconds(seconds: i64) -> TimeDelta {
-        expect!(TimeDelta::try_seconds(seconds), "TimeDelta::seconds out of bounds")
+        expect(TimeDelta::try_seconds(seconds), "TimeDelta::seconds out of bounds")
     }
 
     /// Makes a new `TimeDelta` with the given number of seconds.
@@ -228,7 +228,7 @@
     /// `i64::MAX` or less than `-i64::MAX`. Notably, this is not the same as `i64::MIN`.
     #[inline]
     pub const fn milliseconds(milliseconds: i64) -> TimeDelta {
-        expect!(TimeDelta::try_milliseconds(milliseconds), "TimeDelta::milliseconds out of bounds")
+        expect(TimeDelta::try_milliseconds(milliseconds), "TimeDelta::milliseconds out of bounds")
     }
 
     /// Makes a new `TimeDelta` with the given number of milliseconds.
@@ -281,6 +281,7 @@
     }
 
     /// Returns the total number of whole days in the `TimeDelta`.
+    #[inline]
     pub const fn num_days(&self) -> i64 {
         self.num_seconds() / SECS_PER_DAY
     }
@@ -372,6 +373,40 @@
         TimeDelta::new(secs, nanos as u32)
     }
 
+    /// Multiply a `TimeDelta` with a i32, returning `None` if overflow occurred.
+    #[must_use]
+    pub const fn checked_mul(&self, rhs: i32) -> Option<TimeDelta> {
+        // Multiply nanoseconds as i64, because it cannot overflow that way.
+        let total_nanos = self.nanos as i64 * rhs as i64;
+        let (extra_secs, nanos) = div_mod_floor_64(total_nanos, NANOS_PER_SEC as i64);
+        // Multiply seconds as i128 to prevent overflow
+        let secs: i128 = self.secs as i128 * rhs as i128 + extra_secs as i128;
+        if secs <= i64::MIN as i128 || secs >= i64::MAX as i128 {
+            return None;
+        };
+        Some(TimeDelta { secs: secs as i64, nanos: nanos as i32 })
+    }
+
+    /// Divide a `TimeDelta` with a i32, returning `None` if dividing by 0.
+    #[must_use]
+    pub const fn checked_div(&self, rhs: i32) -> Option<TimeDelta> {
+        if rhs == 0 {
+            return None;
+        }
+        let secs = self.secs / rhs as i64;
+        let carry = self.secs % rhs as i64;
+        let extra_nanos = carry * NANOS_PER_SEC as i64 / rhs as i64;
+        let nanos = self.nanos / rhs + extra_nanos as i32;
+
+        let (secs, nanos) = match nanos {
+            i32::MIN..=-1 => (secs - 1, nanos + NANOS_PER_SEC),
+            NANOS_PER_SEC..=i32::MAX => (secs + 1, nanos - NANOS_PER_SEC),
+            _ => (secs, nanos),
+        };
+
+        Some(TimeDelta { secs, nanos })
+    }
+
     /// Returns the `TimeDelta` as an absolute (non-negative) value.
     #[inline]
     pub const fn abs(&self) -> TimeDelta {
@@ -383,12 +418,14 @@
     }
 
     /// The minimum possible `TimeDelta`: `-i64::MAX` milliseconds.
+    #[deprecated(since = "0.4.39", note = "Use `TimeDelta::MIN` instead")]
     #[inline]
     pub const fn min_value() -> TimeDelta {
         MIN
     }
 
     /// The maximum possible `TimeDelta`: `i64::MAX` milliseconds.
+    #[deprecated(since = "0.4.39", note = "Use `TimeDelta::MAX` instead")]
     #[inline]
     pub const fn max_value() -> TimeDelta {
         MAX
@@ -440,6 +477,12 @@
         };
         TimeDelta { secs: -self.secs - secs_diff, nanos }
     }
+
+    /// The minimum possible `TimeDelta`: `-i64::MAX` milliseconds.
+    pub const MIN: Self = MIN;
+
+    /// The maximum possible `TimeDelta`: `i64::MAX` milliseconds.
+    pub const MAX: Self = MAX;
 }
 
 impl Neg for TimeDelta {
@@ -489,11 +532,7 @@
     type Output = TimeDelta;
 
     fn mul(self, rhs: i32) -> TimeDelta {
-        // Multiply nanoseconds as i64, because it cannot overflow that way.
-        let total_nanos = self.nanos as i64 * rhs as i64;
-        let (extra_secs, nanos) = div_mod_floor_64(total_nanos, NANOS_PER_SEC as i64);
-        let secs = self.secs * rhs as i64 + extra_secs;
-        TimeDelta { secs, nanos: nanos as i32 }
+        self.checked_mul(rhs).expect("`TimeDelta * i32` overflowed")
     }
 }
 
@@ -501,19 +540,7 @@
     type Output = TimeDelta;
 
     fn div(self, rhs: i32) -> TimeDelta {
-        let mut secs = self.secs / rhs as i64;
-        let carry = self.secs - secs * rhs as i64;
-        let extra_nanos = carry * NANOS_PER_SEC as i64 / rhs as i64;
-        let mut nanos = self.nanos / rhs + extra_nanos as i32;
-        if nanos >= NANOS_PER_SEC {
-            nanos -= NANOS_PER_SEC;
-            secs += 1;
-        }
-        if nanos < 0 {
-            nanos += NANOS_PER_SEC;
-            secs -= 1;
-        }
-        TimeDelta { secs, nanos }
+        self.checked_div(rhs).expect("`i32` is zero")
     }
 }
 
@@ -612,95 +639,137 @@
     }
 }
 
+#[cfg(feature = "serde")]
+mod serde {
+    use super::TimeDelta;
+    use serde::{de::Error, Deserialize, Deserializer, Serialize, Serializer};
+
+    impl Serialize for TimeDelta {
+        fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
+            <(i64, i32) as Serialize>::serialize(&(self.secs, self.nanos), serializer)
+        }
+    }
+
+    impl<'de> Deserialize<'de> for TimeDelta {
+        fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
+            let (secs, nanos) = <(i64, i32) as Deserialize>::deserialize(deserializer)?;
+            TimeDelta::new(secs, nanos as u32).ok_or(Error::custom("TimeDelta out of bounds"))
+        }
+    }
+
+    #[cfg(test)]
+    mod tests {
+        use super::{super::MAX, TimeDelta};
+
+        #[test]
+        fn test_serde() {
+            let duration = TimeDelta::new(123, 456).unwrap();
+            assert_eq!(
+                serde_json::from_value::<TimeDelta>(serde_json::to_value(duration).unwrap())
+                    .unwrap(),
+                duration
+            );
+        }
+
+        #[test]
+        #[should_panic(expected = "TimeDelta out of bounds")]
+        fn test_serde_oob_panic() {
+            let _ =
+                serde_json::from_value::<TimeDelta>(serde_json::json!([MAX.secs + 1, 0])).unwrap();
+        }
+    }
+}
+
 #[cfg(test)]
 mod tests {
     use super::OutOfRangeError;
     use super::{TimeDelta, MAX, MIN};
+    use crate::expect;
     use core::time::Duration;
 
     #[test]
     fn test_duration() {
-        assert!(TimeDelta::seconds(1) != TimeDelta::zero());
-        assert_eq!(TimeDelta::seconds(1) + TimeDelta::seconds(2), TimeDelta::seconds(3));
+        let days = |d| TimeDelta::try_days(d).unwrap();
+        let seconds = |s| TimeDelta::try_seconds(s).unwrap();
+
+        assert!(seconds(1) != TimeDelta::zero());
+        assert_eq!(seconds(1) + seconds(2), seconds(3));
+        assert_eq!(seconds(86_399) + seconds(4), days(1) + seconds(3));
+        assert_eq!(days(10) - seconds(1000), seconds(863_000));
+        assert_eq!(days(10) - seconds(1_000_000), seconds(-136_000));
         assert_eq!(
-            TimeDelta::seconds(86_399) + TimeDelta::seconds(4),
-            TimeDelta::days(1) + TimeDelta::seconds(3)
+            days(2) + seconds(86_399) + TimeDelta::nanoseconds(1_234_567_890),
+            days(3) + TimeDelta::nanoseconds(234_567_890)
         );
-        assert_eq!(TimeDelta::days(10) - TimeDelta::seconds(1000), TimeDelta::seconds(863_000));
-        assert_eq!(
-            TimeDelta::days(10) - TimeDelta::seconds(1_000_000),
-            TimeDelta::seconds(-136_000)
-        );
-        assert_eq!(
-            TimeDelta::days(2) + TimeDelta::seconds(86_399) + TimeDelta::nanoseconds(1_234_567_890),
-            TimeDelta::days(3) + TimeDelta::nanoseconds(234_567_890)
-        );
-        assert_eq!(-TimeDelta::days(3), TimeDelta::days(-3));
-        assert_eq!(
-            -(TimeDelta::days(3) + TimeDelta::seconds(70)),
-            TimeDelta::days(-4) + TimeDelta::seconds(86_400 - 70)
-        );
+        assert_eq!(-days(3), days(-3));
+        assert_eq!(-(days(3) + seconds(70)), days(-4) + seconds(86_400 - 70));
 
         let mut d = TimeDelta::default();
-        d += TimeDelta::minutes(1);
-        d -= TimeDelta::seconds(30);
-        assert_eq!(d, TimeDelta::seconds(30));
+        d += TimeDelta::try_minutes(1).unwrap();
+        d -= seconds(30);
+        assert_eq!(d, seconds(30));
     }
 
     #[test]
     fn test_duration_num_days() {
         assert_eq!(TimeDelta::zero().num_days(), 0);
-        assert_eq!(TimeDelta::days(1).num_days(), 1);
-        assert_eq!(TimeDelta::days(-1).num_days(), -1);
-        assert_eq!(TimeDelta::seconds(86_399).num_days(), 0);
-        assert_eq!(TimeDelta::seconds(86_401).num_days(), 1);
-        assert_eq!(TimeDelta::seconds(-86_399).num_days(), 0);
-        assert_eq!(TimeDelta::seconds(-86_401).num_days(), -1);
-        assert_eq!(TimeDelta::days(i32::MAX as i64).num_days(), i32::MAX as i64);
-        assert_eq!(TimeDelta::days(i32::MIN as i64).num_days(), i32::MIN as i64);
+        assert_eq!(TimeDelta::try_days(1).unwrap().num_days(), 1);
+        assert_eq!(TimeDelta::try_days(-1).unwrap().num_days(), -1);
+        assert_eq!(TimeDelta::try_seconds(86_399).unwrap().num_days(), 0);
+        assert_eq!(TimeDelta::try_seconds(86_401).unwrap().num_days(), 1);
+        assert_eq!(TimeDelta::try_seconds(-86_399).unwrap().num_days(), 0);
+        assert_eq!(TimeDelta::try_seconds(-86_401).unwrap().num_days(), -1);
+        assert_eq!(TimeDelta::try_days(i32::MAX as i64).unwrap().num_days(), i32::MAX as i64);
+        assert_eq!(TimeDelta::try_days(i32::MIN as i64).unwrap().num_days(), i32::MIN as i64);
     }
 
     #[test]
     fn test_duration_num_seconds() {
         assert_eq!(TimeDelta::zero().num_seconds(), 0);
-        assert_eq!(TimeDelta::seconds(1).num_seconds(), 1);
-        assert_eq!(TimeDelta::seconds(-1).num_seconds(), -1);
-        assert_eq!(TimeDelta::milliseconds(999).num_seconds(), 0);
-        assert_eq!(TimeDelta::milliseconds(1001).num_seconds(), 1);
-        assert_eq!(TimeDelta::milliseconds(-999).num_seconds(), 0);
-        assert_eq!(TimeDelta::milliseconds(-1001).num_seconds(), -1);
+        assert_eq!(TimeDelta::try_seconds(1).unwrap().num_seconds(), 1);
+        assert_eq!(TimeDelta::try_seconds(-1).unwrap().num_seconds(), -1);
+        assert_eq!(TimeDelta::try_milliseconds(999).unwrap().num_seconds(), 0);
+        assert_eq!(TimeDelta::try_milliseconds(1001).unwrap().num_seconds(), 1);
+        assert_eq!(TimeDelta::try_milliseconds(-999).unwrap().num_seconds(), 0);
+        assert_eq!(TimeDelta::try_milliseconds(-1001).unwrap().num_seconds(), -1);
     }
+
     #[test]
     fn test_duration_seconds_max_allowed() {
-        let duration = TimeDelta::seconds(i64::MAX / 1_000);
+        let duration = TimeDelta::try_seconds(i64::MAX / 1_000).unwrap();
         assert_eq!(duration.num_seconds(), i64::MAX / 1_000);
         assert_eq!(
             duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
             i64::MAX as i128 / 1_000 * 1_000_000_000
         );
     }
+
     #[test]
     fn test_duration_seconds_max_overflow() {
         assert!(TimeDelta::try_seconds(i64::MAX / 1_000 + 1).is_none());
     }
+
     #[test]
     #[should_panic(expected = "TimeDelta::seconds out of bounds")]
     fn test_duration_seconds_max_overflow_panic() {
         let _ = TimeDelta::seconds(i64::MAX / 1_000 + 1);
     }
+
     #[test]
     fn test_duration_seconds_min_allowed() {
-        let duration = TimeDelta::seconds(i64::MIN / 1_000); // Same as -i64::MAX / 1_000 due to rounding
+        let duration = TimeDelta::try_seconds(i64::MIN / 1_000).unwrap(); // Same as -i64::MAX / 1_000 due to rounding
         assert_eq!(duration.num_seconds(), i64::MIN / 1_000); // Same as -i64::MAX / 1_000 due to rounding
         assert_eq!(
             duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
             -i64::MAX as i128 / 1_000 * 1_000_000_000
         );
     }
+
     #[test]
     fn test_duration_seconds_min_underflow() {
         assert!(TimeDelta::try_seconds(-i64::MAX / 1_000 - 1).is_none());
     }
+
     #[test]
     #[should_panic(expected = "TimeDelta::seconds out of bounds")]
     fn test_duration_seconds_min_underflow_panic() {
@@ -710,52 +779,59 @@
     #[test]
     fn test_duration_num_milliseconds() {
         assert_eq!(TimeDelta::zero().num_milliseconds(), 0);
-        assert_eq!(TimeDelta::milliseconds(1).num_milliseconds(), 1);
-        assert_eq!(TimeDelta::milliseconds(-1).num_milliseconds(), -1);
+        assert_eq!(TimeDelta::try_milliseconds(1).unwrap().num_milliseconds(), 1);
+        assert_eq!(TimeDelta::try_milliseconds(-1).unwrap().num_milliseconds(), -1);
         assert_eq!(TimeDelta::microseconds(999).num_milliseconds(), 0);
         assert_eq!(TimeDelta::microseconds(1001).num_milliseconds(), 1);
         assert_eq!(TimeDelta::microseconds(-999).num_milliseconds(), 0);
         assert_eq!(TimeDelta::microseconds(-1001).num_milliseconds(), -1);
     }
+
     #[test]
     fn test_duration_milliseconds_max_allowed() {
         // The maximum number of milliseconds acceptable through the constructor is
         // equal to the number that can be stored in a TimeDelta.
-        let duration = TimeDelta::milliseconds(i64::MAX);
+        let duration = TimeDelta::try_milliseconds(i64::MAX).unwrap();
         assert_eq!(duration.num_milliseconds(), i64::MAX);
         assert_eq!(
             duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
             i64::MAX as i128 * 1_000_000
         );
     }
+
     #[test]
     fn test_duration_milliseconds_max_overflow() {
         // Here we ensure that trying to add one millisecond to the maximum storable
         // value will fail.
-        assert!(TimeDelta::milliseconds(i64::MAX)
-            .checked_add(&TimeDelta::milliseconds(1))
+        assert!(TimeDelta::try_milliseconds(i64::MAX)
+            .unwrap()
+            .checked_add(&TimeDelta::try_milliseconds(1).unwrap())
             .is_none());
     }
+
     #[test]
     fn test_duration_milliseconds_min_allowed() {
         // The minimum number of milliseconds acceptable through the constructor is
         // not equal to the number that can be stored in a TimeDelta - there is a
         // difference of one (i64::MIN vs -i64::MAX).
-        let duration = TimeDelta::milliseconds(-i64::MAX);
+        let duration = TimeDelta::try_milliseconds(-i64::MAX).unwrap();
         assert_eq!(duration.num_milliseconds(), -i64::MAX);
         assert_eq!(
             duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
             -i64::MAX as i128 * 1_000_000
         );
     }
+
     #[test]
     fn test_duration_milliseconds_min_underflow() {
         // Here we ensure that trying to subtract one millisecond from the minimum
         // storable value will fail.
-        assert!(TimeDelta::milliseconds(-i64::MAX)
-            .checked_sub(&TimeDelta::milliseconds(1))
+        assert!(TimeDelta::try_milliseconds(-i64::MAX)
+            .unwrap()
+            .checked_sub(&TimeDelta::try_milliseconds(1).unwrap())
             .is_none());
     }
+
     #[test]
     #[should_panic(expected = "TimeDelta::milliseconds out of bounds")]
     fn test_duration_milliseconds_min_underflow_panic() {
@@ -779,15 +855,21 @@
         // overflow checks
         const MICROS_PER_DAY: i64 = 86_400_000_000;
         assert_eq!(
-            TimeDelta::days(i64::MAX / MICROS_PER_DAY).num_microseconds(),
+            TimeDelta::try_days(i64::MAX / MICROS_PER_DAY).unwrap().num_microseconds(),
             Some(i64::MAX / MICROS_PER_DAY * MICROS_PER_DAY)
         );
         assert_eq!(
-            TimeDelta::days(-i64::MAX / MICROS_PER_DAY).num_microseconds(),
+            TimeDelta::try_days(-i64::MAX / MICROS_PER_DAY).unwrap().num_microseconds(),
             Some(-i64::MAX / MICROS_PER_DAY * MICROS_PER_DAY)
         );
-        assert_eq!(TimeDelta::days(i64::MAX / MICROS_PER_DAY + 1).num_microseconds(), None);
-        assert_eq!(TimeDelta::days(-i64::MAX / MICROS_PER_DAY - 1).num_microseconds(), None);
+        assert_eq!(
+            TimeDelta::try_days(i64::MAX / MICROS_PER_DAY + 1).unwrap().num_microseconds(),
+            None
+        );
+        assert_eq!(
+            TimeDelta::try_days(-i64::MAX / MICROS_PER_DAY - 1).unwrap().num_microseconds(),
+            None
+        );
     }
     #[test]
     fn test_duration_microseconds_max_allowed() {
@@ -804,7 +886,7 @@
         // microseconds by creating a TimeDelta with the maximum number of
         // milliseconds and then checking that the number of microseconds matches
         // the storage limit.
-        let duration = TimeDelta::milliseconds(i64::MAX);
+        let duration = TimeDelta::try_milliseconds(i64::MAX).unwrap();
         assert!(duration.num_microseconds().is_none());
         assert_eq!(
             duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
@@ -823,7 +905,8 @@
         );
         // Here we ensure that trying to add one microsecond to the maximum storable
         // value will fail.
-        assert!(TimeDelta::milliseconds(i64::MAX)
+        assert!(TimeDelta::try_milliseconds(i64::MAX)
+            .unwrap()
             .checked_add(&TimeDelta::microseconds(1))
             .is_none());
     }
@@ -842,7 +925,7 @@
         // microseconds by creating a TimeDelta with the minimum number of
         // milliseconds and then checking that the number of microseconds matches
         // the storage limit.
-        let duration = TimeDelta::milliseconds(-i64::MAX);
+        let duration = TimeDelta::try_milliseconds(-i64::MAX).unwrap();
         assert!(duration.num_microseconds().is_none());
         assert_eq!(
             duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
@@ -861,7 +944,8 @@
         );
         // Here we ensure that trying to subtract one microsecond from the minimum
         // storable value will fail.
-        assert!(TimeDelta::milliseconds(-i64::MAX)
+        assert!(TimeDelta::try_milliseconds(-i64::MAX)
+            .unwrap()
             .checked_sub(&TimeDelta::microseconds(1))
             .is_none());
     }
@@ -875,15 +959,21 @@
         // overflow checks
         const NANOS_PER_DAY: i64 = 86_400_000_000_000;
         assert_eq!(
-            TimeDelta::days(i64::MAX / NANOS_PER_DAY).num_nanoseconds(),
+            TimeDelta::try_days(i64::MAX / NANOS_PER_DAY).unwrap().num_nanoseconds(),
             Some(i64::MAX / NANOS_PER_DAY * NANOS_PER_DAY)
         );
         assert_eq!(
-            TimeDelta::days(-i64::MAX / NANOS_PER_DAY).num_nanoseconds(),
+            TimeDelta::try_days(-i64::MAX / NANOS_PER_DAY).unwrap().num_nanoseconds(),
             Some(-i64::MAX / NANOS_PER_DAY * NANOS_PER_DAY)
         );
-        assert_eq!(TimeDelta::days(i64::MAX / NANOS_PER_DAY + 1).num_nanoseconds(), None);
-        assert_eq!(TimeDelta::days(-i64::MAX / NANOS_PER_DAY - 1).num_nanoseconds(), None);
+        assert_eq!(
+            TimeDelta::try_days(i64::MAX / NANOS_PER_DAY + 1).unwrap().num_nanoseconds(),
+            None
+        );
+        assert_eq!(
+            TimeDelta::try_days(-i64::MAX / NANOS_PER_DAY - 1).unwrap().num_nanoseconds(),
+            None
+        );
     }
     #[test]
     fn test_duration_nanoseconds_max_allowed() {
@@ -899,13 +989,14 @@
         // Here we create a TimeDelta with the maximum possible number of nanoseconds
         // by creating a TimeDelta with the maximum number of milliseconds and then
         // checking that the number of nanoseconds matches the storage limit.
-        let duration = TimeDelta::milliseconds(i64::MAX);
+        let duration = TimeDelta::try_milliseconds(i64::MAX).unwrap();
         assert!(duration.num_nanoseconds().is_none());
         assert_eq!(
             duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
             i64::MAX as i128 * 1_000_000
         );
     }
+
     #[test]
     fn test_duration_nanoseconds_max_overflow() {
         // This test establishes that a TimeDelta can store more nanoseconds than are
@@ -918,10 +1009,12 @@
         );
         // Here we ensure that trying to add one nanosecond to the maximum storable
         // value will fail.
-        assert!(TimeDelta::milliseconds(i64::MAX)
+        assert!(TimeDelta::try_milliseconds(i64::MAX)
+            .unwrap()
             .checked_add(&TimeDelta::nanoseconds(1))
             .is_none());
     }
+
     #[test]
     fn test_duration_nanoseconds_min_allowed() {
         // The number of nanoseconds acceptable through the constructor is far fewer
@@ -936,13 +1029,14 @@
         // Here we create a TimeDelta with the minimum possible number of nanoseconds
         // by creating a TimeDelta with the minimum number of milliseconds and then
         // checking that the number of nanoseconds matches the storage limit.
-        let duration = TimeDelta::milliseconds(-i64::MAX);
+        let duration = TimeDelta::try_milliseconds(-i64::MAX).unwrap();
         assert!(duration.num_nanoseconds().is_none());
         assert_eq!(
             duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
             -i64::MAX as i128 * 1_000_000
         );
     }
+
     #[test]
     fn test_duration_nanoseconds_min_underflow() {
         // This test establishes that a TimeDelta can store more nanoseconds than are
@@ -955,7 +1049,8 @@
         );
         // Here we ensure that trying to subtract one nanosecond from the minimum
         // storable value will fail.
-        assert!(TimeDelta::milliseconds(-i64::MAX)
+        assert!(TimeDelta::try_milliseconds(-i64::MAX)
+            .unwrap()
             .checked_sub(&TimeDelta::nanoseconds(1))
             .is_none());
     }
@@ -966,18 +1061,19 @@
             MAX.secs as i128 * 1_000_000_000 + MAX.nanos as i128,
             i64::MAX as i128 * 1_000_000
         );
-        assert_eq!(MAX, TimeDelta::milliseconds(i64::MAX));
+        assert_eq!(MAX, TimeDelta::try_milliseconds(i64::MAX).unwrap());
         assert_eq!(MAX.num_milliseconds(), i64::MAX);
         assert_eq!(MAX.num_microseconds(), None);
         assert_eq!(MAX.num_nanoseconds(), None);
     }
+
     #[test]
     fn test_min() {
         assert_eq!(
             MIN.secs as i128 * 1_000_000_000 + MIN.nanos as i128,
             -i64::MAX as i128 * 1_000_000
         );
-        assert_eq!(MIN, TimeDelta::milliseconds(-i64::MAX));
+        assert_eq!(MIN, TimeDelta::try_milliseconds(-i64::MAX).unwrap());
         assert_eq!(MIN.num_milliseconds(), -i64::MAX);
         assert_eq!(MIN.num_microseconds(), None);
         assert_eq!(MIN.num_nanoseconds(), None);
@@ -985,67 +1081,70 @@
 
     #[test]
     fn test_duration_ord() {
-        assert!(TimeDelta::milliseconds(1) < TimeDelta::milliseconds(2));
-        assert!(TimeDelta::milliseconds(2) > TimeDelta::milliseconds(1));
-        assert!(TimeDelta::milliseconds(-1) > TimeDelta::milliseconds(-2));
-        assert!(TimeDelta::milliseconds(-2) < TimeDelta::milliseconds(-1));
-        assert!(TimeDelta::milliseconds(-1) < TimeDelta::milliseconds(1));
-        assert!(TimeDelta::milliseconds(1) > TimeDelta::milliseconds(-1));
-        assert!(TimeDelta::milliseconds(0) < TimeDelta::milliseconds(1));
-        assert!(TimeDelta::milliseconds(0) > TimeDelta::milliseconds(-1));
-        assert!(TimeDelta::milliseconds(1_001) < TimeDelta::milliseconds(1_002));
-        assert!(TimeDelta::milliseconds(-1_001) > TimeDelta::milliseconds(-1_002));
+        let milliseconds = |ms| TimeDelta::try_milliseconds(ms).unwrap();
+
+        assert!(milliseconds(1) < milliseconds(2));
+        assert!(milliseconds(2) > milliseconds(1));
+        assert!(milliseconds(-1) > milliseconds(-2));
+        assert!(milliseconds(-2) < milliseconds(-1));
+        assert!(milliseconds(-1) < milliseconds(1));
+        assert!(milliseconds(1) > milliseconds(-1));
+        assert!(milliseconds(0) < milliseconds(1));
+        assert!(milliseconds(0) > milliseconds(-1));
+        assert!(milliseconds(1_001) < milliseconds(1_002));
+        assert!(milliseconds(-1_001) > milliseconds(-1_002));
         assert!(TimeDelta::nanoseconds(1_234_567_890) < TimeDelta::nanoseconds(1_234_567_891));
         assert!(TimeDelta::nanoseconds(-1_234_567_890) > TimeDelta::nanoseconds(-1_234_567_891));
-        assert!(TimeDelta::milliseconds(i64::MAX) > TimeDelta::milliseconds(i64::MAX - 1));
-        assert!(TimeDelta::milliseconds(-i64::MAX) < TimeDelta::milliseconds(-i64::MAX + 1));
+        assert!(milliseconds(i64::MAX) > milliseconds(i64::MAX - 1));
+        assert!(milliseconds(-i64::MAX) < milliseconds(-i64::MAX + 1));
     }
 
     #[test]
     fn test_duration_checked_ops() {
-        assert_eq!(
-            TimeDelta::milliseconds(i64::MAX).checked_add(&TimeDelta::milliseconds(0)),
-            Some(TimeDelta::milliseconds(i64::MAX))
-        );
-        assert_eq!(
-            TimeDelta::milliseconds(i64::MAX - 1).checked_add(&TimeDelta::microseconds(999)),
-            Some(TimeDelta::milliseconds(i64::MAX - 2) + TimeDelta::microseconds(1999))
-        );
-        assert!(TimeDelta::milliseconds(i64::MAX)
-            .checked_add(&TimeDelta::microseconds(1000))
-            .is_none());
-        assert!(TimeDelta::milliseconds(i64::MAX)
-            .checked_add(&TimeDelta::nanoseconds(1))
-            .is_none());
+        let milliseconds = |ms| TimeDelta::try_milliseconds(ms).unwrap();
+        let seconds = |s| TimeDelta::try_seconds(s).unwrap();
 
         assert_eq!(
-            TimeDelta::milliseconds(-i64::MAX).checked_sub(&TimeDelta::milliseconds(0)),
-            Some(TimeDelta::milliseconds(-i64::MAX))
+            milliseconds(i64::MAX).checked_add(&milliseconds(0)),
+            Some(milliseconds(i64::MAX))
         );
         assert_eq!(
-            TimeDelta::milliseconds(-i64::MAX + 1).checked_sub(&TimeDelta::microseconds(999)),
-            Some(TimeDelta::milliseconds(-i64::MAX + 2) - TimeDelta::microseconds(1999))
+            milliseconds(i64::MAX - 1).checked_add(&TimeDelta::microseconds(999)),
+            Some(milliseconds(i64::MAX - 2) + TimeDelta::microseconds(1999))
         );
-        assert!(TimeDelta::milliseconds(-i64::MAX)
-            .checked_sub(&TimeDelta::milliseconds(1))
-            .is_none());
-        assert!(TimeDelta::milliseconds(-i64::MAX)
-            .checked_sub(&TimeDelta::nanoseconds(1))
-            .is_none());
+        assert!(milliseconds(i64::MAX).checked_add(&TimeDelta::microseconds(1000)).is_none());
+        assert!(milliseconds(i64::MAX).checked_add(&TimeDelta::nanoseconds(1)).is_none());
+
+        assert_eq!(
+            milliseconds(-i64::MAX).checked_sub(&milliseconds(0)),
+            Some(milliseconds(-i64::MAX))
+        );
+        assert_eq!(
+            milliseconds(-i64::MAX + 1).checked_sub(&TimeDelta::microseconds(999)),
+            Some(milliseconds(-i64::MAX + 2) - TimeDelta::microseconds(1999))
+        );
+        assert!(milliseconds(-i64::MAX).checked_sub(&milliseconds(1)).is_none());
+        assert!(milliseconds(-i64::MAX).checked_sub(&TimeDelta::nanoseconds(1)).is_none());
+
+        assert!(seconds(i64::MAX / 1000).checked_mul(2000).is_none());
+        assert!(seconds(i64::MIN / 1000).checked_mul(2000).is_none());
+        assert!(seconds(1).checked_div(0).is_none());
     }
 
     #[test]
     fn test_duration_abs() {
-        assert_eq!(TimeDelta::milliseconds(1300).abs(), TimeDelta::milliseconds(1300));
-        assert_eq!(TimeDelta::milliseconds(1000).abs(), TimeDelta::milliseconds(1000));
-        assert_eq!(TimeDelta::milliseconds(300).abs(), TimeDelta::milliseconds(300));
-        assert_eq!(TimeDelta::milliseconds(0).abs(), TimeDelta::milliseconds(0));
-        assert_eq!(TimeDelta::milliseconds(-300).abs(), TimeDelta::milliseconds(300));
-        assert_eq!(TimeDelta::milliseconds(-700).abs(), TimeDelta::milliseconds(700));
-        assert_eq!(TimeDelta::milliseconds(-1000).abs(), TimeDelta::milliseconds(1000));
-        assert_eq!(TimeDelta::milliseconds(-1300).abs(), TimeDelta::milliseconds(1300));
-        assert_eq!(TimeDelta::milliseconds(-1700).abs(), TimeDelta::milliseconds(1700));
-        assert_eq!(TimeDelta::milliseconds(-i64::MAX).abs(), TimeDelta::milliseconds(i64::MAX));
+        let milliseconds = |ms| TimeDelta::try_milliseconds(ms).unwrap();
+
+        assert_eq!(milliseconds(1300).abs(), milliseconds(1300));
+        assert_eq!(milliseconds(1000).abs(), milliseconds(1000));
+        assert_eq!(milliseconds(300).abs(), milliseconds(300));
+        assert_eq!(milliseconds(0).abs(), milliseconds(0));
+        assert_eq!(milliseconds(-300).abs(), milliseconds(300));
+        assert_eq!(milliseconds(-700).abs(), milliseconds(700));
+        assert_eq!(milliseconds(-1000).abs(), milliseconds(1000));
+        assert_eq!(milliseconds(-1300).abs(), milliseconds(1300));
+        assert_eq!(milliseconds(-1700).abs(), milliseconds(1700));
+        assert_eq!(milliseconds(-i64::MAX).abs(), milliseconds(i64::MAX));
     }
 
     #[test]
@@ -1055,19 +1154,30 @@
         assert_eq!(TimeDelta::zero() * i32::MIN, TimeDelta::zero());
         assert_eq!(TimeDelta::nanoseconds(1) * 0, TimeDelta::zero());
         assert_eq!(TimeDelta::nanoseconds(1) * 1, TimeDelta::nanoseconds(1));
-        assert_eq!(TimeDelta::nanoseconds(1) * 1_000_000_000, TimeDelta::seconds(1));
-        assert_eq!(TimeDelta::nanoseconds(1) * -1_000_000_000, -TimeDelta::seconds(1));
-        assert_eq!(-TimeDelta::nanoseconds(1) * 1_000_000_000, -TimeDelta::seconds(1));
+        assert_eq!(TimeDelta::nanoseconds(1) * 1_000_000_000, TimeDelta::try_seconds(1).unwrap());
+        assert_eq!(TimeDelta::nanoseconds(1) * -1_000_000_000, -TimeDelta::try_seconds(1).unwrap());
+        assert_eq!(-TimeDelta::nanoseconds(1) * 1_000_000_000, -TimeDelta::try_seconds(1).unwrap());
         assert_eq!(
             TimeDelta::nanoseconds(30) * 333_333_333,
-            TimeDelta::seconds(10) - TimeDelta::nanoseconds(10)
+            TimeDelta::try_seconds(10).unwrap() - TimeDelta::nanoseconds(10)
         );
         assert_eq!(
-            (TimeDelta::nanoseconds(1) + TimeDelta::seconds(1) + TimeDelta::days(1)) * 3,
-            TimeDelta::nanoseconds(3) + TimeDelta::seconds(3) + TimeDelta::days(3)
+            (TimeDelta::nanoseconds(1)
+                + TimeDelta::try_seconds(1).unwrap()
+                + TimeDelta::try_days(1).unwrap())
+                * 3,
+            TimeDelta::nanoseconds(3)
+                + TimeDelta::try_seconds(3).unwrap()
+                + TimeDelta::try_days(3).unwrap()
         );
-        assert_eq!(TimeDelta::milliseconds(1500) * -2, TimeDelta::seconds(-3));
-        assert_eq!(TimeDelta::milliseconds(-1500) * 2, TimeDelta::seconds(-3));
+        assert_eq!(
+            TimeDelta::try_milliseconds(1500).unwrap() * -2,
+            TimeDelta::try_seconds(-3).unwrap()
+        );
+        assert_eq!(
+            TimeDelta::try_milliseconds(-1500).unwrap() * 2,
+            TimeDelta::try_seconds(-3).unwrap()
+        );
     }
 
     #[test]
@@ -1078,85 +1188,110 @@
         assert_eq!(TimeDelta::nanoseconds(123_456_789) / -1, -TimeDelta::nanoseconds(123_456_789));
         assert_eq!(-TimeDelta::nanoseconds(123_456_789) / -1, TimeDelta::nanoseconds(123_456_789));
         assert_eq!(-TimeDelta::nanoseconds(123_456_789) / 1, -TimeDelta::nanoseconds(123_456_789));
-        assert_eq!(TimeDelta::seconds(1) / 3, TimeDelta::nanoseconds(333_333_333));
-        assert_eq!(TimeDelta::seconds(4) / 3, TimeDelta::nanoseconds(1_333_333_333));
-        assert_eq!(TimeDelta::seconds(-1) / 2, TimeDelta::milliseconds(-500));
-        assert_eq!(TimeDelta::seconds(1) / -2, TimeDelta::milliseconds(-500));
-        assert_eq!(TimeDelta::seconds(-1) / -2, TimeDelta::milliseconds(500));
-        assert_eq!(TimeDelta::seconds(-4) / 3, TimeDelta::nanoseconds(-1_333_333_333));
-        assert_eq!(TimeDelta::seconds(-4) / -3, TimeDelta::nanoseconds(1_333_333_333));
+        assert_eq!(TimeDelta::try_seconds(1).unwrap() / 3, TimeDelta::nanoseconds(333_333_333));
+        assert_eq!(TimeDelta::try_seconds(4).unwrap() / 3, TimeDelta::nanoseconds(1_333_333_333));
+        assert_eq!(
+            TimeDelta::try_seconds(-1).unwrap() / 2,
+            TimeDelta::try_milliseconds(-500).unwrap()
+        );
+        assert_eq!(
+            TimeDelta::try_seconds(1).unwrap() / -2,
+            TimeDelta::try_milliseconds(-500).unwrap()
+        );
+        assert_eq!(
+            TimeDelta::try_seconds(-1).unwrap() / -2,
+            TimeDelta::try_milliseconds(500).unwrap()
+        );
+        assert_eq!(TimeDelta::try_seconds(-4).unwrap() / 3, TimeDelta::nanoseconds(-1_333_333_333));
+        assert_eq!(TimeDelta::try_seconds(-4).unwrap() / -3, TimeDelta::nanoseconds(1_333_333_333));
     }
 
     #[test]
     fn test_duration_sum() {
-        let duration_list_1 = [TimeDelta::zero(), TimeDelta::seconds(1)];
+        let duration_list_1 = [TimeDelta::zero(), TimeDelta::try_seconds(1).unwrap()];
         let sum_1: TimeDelta = duration_list_1.iter().sum();
-        assert_eq!(sum_1, TimeDelta::seconds(1));
+        assert_eq!(sum_1, TimeDelta::try_seconds(1).unwrap());
 
         let duration_list_2 = [
             TimeDelta::zero(),
-            TimeDelta::seconds(1),
-            TimeDelta::seconds(6),
-            TimeDelta::seconds(10),
+            TimeDelta::try_seconds(1).unwrap(),
+            TimeDelta::try_seconds(6).unwrap(),
+            TimeDelta::try_seconds(10).unwrap(),
         ];
         let sum_2: TimeDelta = duration_list_2.iter().sum();
-        assert_eq!(sum_2, TimeDelta::seconds(17));
+        assert_eq!(sum_2, TimeDelta::try_seconds(17).unwrap());
 
         let duration_arr = [
             TimeDelta::zero(),
-            TimeDelta::seconds(1),
-            TimeDelta::seconds(6),
-            TimeDelta::seconds(10),
+            TimeDelta::try_seconds(1).unwrap(),
+            TimeDelta::try_seconds(6).unwrap(),
+            TimeDelta::try_seconds(10).unwrap(),
         ];
         let sum_3: TimeDelta = duration_arr.into_iter().sum();
-        assert_eq!(sum_3, TimeDelta::seconds(17));
+        assert_eq!(sum_3, TimeDelta::try_seconds(17).unwrap());
     }
 
     #[test]
     fn test_duration_fmt() {
         assert_eq!(TimeDelta::zero().to_string(), "P0D");
-        assert_eq!(TimeDelta::days(42).to_string(), "PT3628800S");
-        assert_eq!(TimeDelta::days(-42).to_string(), "-PT3628800S");
-        assert_eq!(TimeDelta::seconds(42).to_string(), "PT42S");
-        assert_eq!(TimeDelta::milliseconds(42).to_string(), "PT0.042S");
+        assert_eq!(TimeDelta::try_days(42).unwrap().to_string(), "PT3628800S");
+        assert_eq!(TimeDelta::try_days(-42).unwrap().to_string(), "-PT3628800S");
+        assert_eq!(TimeDelta::try_seconds(42).unwrap().to_string(), "PT42S");
+        assert_eq!(TimeDelta::try_milliseconds(42).unwrap().to_string(), "PT0.042S");
         assert_eq!(TimeDelta::microseconds(42).to_string(), "PT0.000042S");
         assert_eq!(TimeDelta::nanoseconds(42).to_string(), "PT0.000000042S");
         assert_eq!(
-            (TimeDelta::days(7) + TimeDelta::milliseconds(6543)).to_string(),
+            (TimeDelta::try_days(7).unwrap() + TimeDelta::try_milliseconds(6543).unwrap())
+                .to_string(),
             "PT604806.543S"
         );
-        assert_eq!(TimeDelta::seconds(-86_401).to_string(), "-PT86401S");
+        assert_eq!(TimeDelta::try_seconds(-86_401).unwrap().to_string(), "-PT86401S");
         assert_eq!(TimeDelta::nanoseconds(-1).to_string(), "-PT0.000000001S");
 
         // the format specifier should have no effect on `TimeDelta`
         assert_eq!(
-            format!("{:30}", TimeDelta::days(1) + TimeDelta::milliseconds(2345)),
+            format!(
+                "{:30}",
+                TimeDelta::try_days(1).unwrap() + TimeDelta::try_milliseconds(2345).unwrap()
+            ),
             "PT86402.345S"
         );
     }
 
     #[test]
     fn test_to_std() {
-        assert_eq!(TimeDelta::seconds(1).to_std(), Ok(Duration::new(1, 0)));
-        assert_eq!(TimeDelta::seconds(86_401).to_std(), Ok(Duration::new(86_401, 0)));
-        assert_eq!(TimeDelta::milliseconds(123).to_std(), Ok(Duration::new(0, 123_000_000)));
-        assert_eq!(TimeDelta::milliseconds(123_765).to_std(), Ok(Duration::new(123, 765_000_000)));
+        assert_eq!(TimeDelta::try_seconds(1).unwrap().to_std(), Ok(Duration::new(1, 0)));
+        assert_eq!(TimeDelta::try_seconds(86_401).unwrap().to_std(), Ok(Duration::new(86_401, 0)));
+        assert_eq!(
+            TimeDelta::try_milliseconds(123).unwrap().to_std(),
+            Ok(Duration::new(0, 123_000_000))
+        );
+        assert_eq!(
+            TimeDelta::try_milliseconds(123_765).unwrap().to_std(),
+            Ok(Duration::new(123, 765_000_000))
+        );
         assert_eq!(TimeDelta::nanoseconds(777).to_std(), Ok(Duration::new(0, 777)));
         assert_eq!(MAX.to_std(), Ok(Duration::new(9_223_372_036_854_775, 807_000_000)));
-        assert_eq!(TimeDelta::seconds(-1).to_std(), Err(OutOfRangeError(())));
-        assert_eq!(TimeDelta::milliseconds(-1).to_std(), Err(OutOfRangeError(())));
+        assert_eq!(TimeDelta::try_seconds(-1).unwrap().to_std(), Err(OutOfRangeError(())));
+        assert_eq!(TimeDelta::try_milliseconds(-1).unwrap().to_std(), Err(OutOfRangeError(())));
     }
 
     #[test]
     fn test_from_std() {
-        assert_eq!(Ok(TimeDelta::seconds(1)), TimeDelta::from_std(Duration::new(1, 0)));
-        assert_eq!(Ok(TimeDelta::seconds(86_401)), TimeDelta::from_std(Duration::new(86_401, 0)));
         assert_eq!(
-            Ok(TimeDelta::milliseconds(123)),
+            Ok(TimeDelta::try_seconds(1).unwrap()),
+            TimeDelta::from_std(Duration::new(1, 0))
+        );
+        assert_eq!(
+            Ok(TimeDelta::try_seconds(86_401).unwrap()),
+            TimeDelta::from_std(Duration::new(86_401, 0))
+        );
+        assert_eq!(
+            Ok(TimeDelta::try_milliseconds(123).unwrap()),
             TimeDelta::from_std(Duration::new(0, 123_000_000))
         );
         assert_eq!(
-            Ok(TimeDelta::milliseconds(123_765)),
+            Ok(TimeDelta::try_milliseconds(123_765).unwrap()),
             TimeDelta::from_std(Duration::new(123, 765_000_000))
         );
         assert_eq!(Ok(TimeDelta::nanoseconds(777)), TimeDelta::from_std(Duration::new(0, 777)));
@@ -1173,12 +1308,12 @@
 
     #[test]
     fn test_duration_const() {
-        const ONE_WEEK: TimeDelta = TimeDelta::weeks(1);
-        const ONE_DAY: TimeDelta = TimeDelta::days(1);
-        const ONE_HOUR: TimeDelta = TimeDelta::hours(1);
-        const ONE_MINUTE: TimeDelta = TimeDelta::minutes(1);
-        const ONE_SECOND: TimeDelta = TimeDelta::seconds(1);
-        const ONE_MILLI: TimeDelta = TimeDelta::milliseconds(1);
+        const ONE_WEEK: TimeDelta = expect(TimeDelta::try_weeks(1), "");
+        const ONE_DAY: TimeDelta = expect(TimeDelta::try_days(1), "");
+        const ONE_HOUR: TimeDelta = expect(TimeDelta::try_hours(1), "");
+        const ONE_MINUTE: TimeDelta = expect(TimeDelta::try_minutes(1), "");
+        const ONE_SECOND: TimeDelta = expect(TimeDelta::try_seconds(1), "");
+        const ONE_MILLI: TimeDelta = expect(TimeDelta::try_milliseconds(1), "");
         const ONE_MICRO: TimeDelta = TimeDelta::microseconds(1);
         const ONE_NANO: TimeDelta = TimeDelta::nanoseconds(1);
         let combo: TimeDelta = ONE_WEEK
@@ -1200,7 +1335,7 @@
         assert!(ONE_NANO != TimeDelta::zero());
         assert_eq!(
             combo,
-            TimeDelta::seconds(86400 * 7 + 86400 + 3600 + 60 + 1)
+            TimeDelta::try_seconds(86400 * 7 + 86400 + 3600 + 60 + 1).unwrap()
                 + TimeDelta::nanoseconds(1 + 1_000 + 1_000_000)
         );
     }
@@ -1208,7 +1343,7 @@
     #[test]
     #[cfg(feature = "rkyv-validation")]
     fn test_rkyv_validation() {
-        let duration = TimeDelta::seconds(1);
+        let duration = TimeDelta::try_seconds(1).unwrap();
         let bytes = rkyv::to_bytes::<_, 16>(&duration).unwrap();
         assert_eq!(rkyv::from_bytes::<TimeDelta>(&bytes).unwrap(), duration);
     }
diff --git a/crates/chrono/src/traits.rs b/crates/chrono/src/traits.rs
index 0018a7d..e582093 100644
--- a/crates/chrono/src/traits.rs
+++ b/crates/chrono/src/traits.rs
@@ -101,7 +101,7 @@
     /// # Examples
     ///
     /// ```
-    /// use chrono::{NaiveDate, Datelike};
+    /// use chrono::{Datelike, NaiveDate};
     ///
     /// assert_eq!(
     ///     NaiveDate::from_ymd_opt(2020, 5, 13).unwrap().with_year(2023).unwrap(),
@@ -134,7 +134,7 @@
     /// # Examples
     ///
     /// ```
-    /// use chrono::{NaiveDate, Datelike};
+    /// use chrono::{Datelike, NaiveDate};
     ///
     /// assert_eq!(
     ///     NaiveDate::from_ymd_opt(2023, 5, 12).unwrap().with_month(9).unwrap(),
@@ -146,7 +146,7 @@
     ///
     /// Don't combine multiple `Datelike::with_*` methods. The intermediate value may not exist.
     /// ```
-    /// use chrono::{NaiveDate, Datelike};
+    /// use chrono::{Datelike, NaiveDate};
     ///
     /// fn with_year_month(date: NaiveDate, year: i32, month: u32) -> Option<NaiveDate> {
     ///     date.with_year(year)?.with_month(month)
@@ -238,7 +238,7 @@
     /// # Examples
     ///
     /// ```
-    /// use chrono::{NaiveDate, Datelike};
+    /// use chrono::{Datelike, NaiveDate};
     ///
     /// 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);
@@ -330,7 +330,7 @@
 #[cfg(test)]
 mod tests {
     use super::Datelike;
-    use crate::{NaiveDate, TimeDelta};
+    use crate::{Days, NaiveDate};
 
     /// Tests `Datelike::num_days_from_ce` against an alternative implementation.
     ///
@@ -377,7 +377,7 @@
                 "on {:?}",
                 jan1_year
             );
-            let mid_year = jan1_year + TimeDelta::days(133);
+            let mid_year = jan1_year + Days::new(133);
             assert_eq!(
                 mid_year.num_days_from_ce(),
                 num_days_from_ce(&mid_year),
diff --git a/crates/chrono/src/weekday.rs b/crates/chrono/src/weekday.rs
index 618d535..92644e8 100644
--- a/crates/chrono/src/weekday.rs
+++ b/crates/chrono/src/weekday.rs
@@ -30,7 +30,6 @@
 /// assert_eq!(sunday.pred(), Weekday::Sat);
 /// ```
 #[derive(PartialEq, Eq, Copy, Clone, Debug, Hash)]
-#[cfg_attr(feature = "rustc-serialize", derive(RustcEncodable, RustcDecodable))]
 #[cfg_attr(
     any(feature = "rkyv", feature = "rkyv-16", feature = "rkyv-32", feature = "rkyv-64"),
     derive(Archive, Deserialize, Serialize),
@@ -102,7 +101,7 @@
     /// `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
+        self.days_since(Weekday::Mon) + 1
     }
 
     /// Returns a day-of-week number starting from Sunday = 1.
@@ -112,7 +111,7 @@
     /// `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
+        self.days_since(Weekday::Sun) + 1
     }
 
     /// Returns a day-of-week number starting from Monday = 0.
@@ -123,8 +122,8 @@
     ///
     /// # Example
     ///
-    #[cfg_attr(not(feature = "clock"), doc = "```ignore")]
-    #[cfg_attr(feature = "clock", doc = "```rust")]
+    /// ```
+    /// # #[cfg(feature = "clock")] {
     /// # use chrono::{Local, Datelike};
     /// // MTWRFSU is occasionally used as a single-letter abbreviation of the weekdays.
     /// // Use `num_days_from_monday` to index into the array.
@@ -132,10 +131,11 @@
     ///
     /// let today = Local::now().weekday();
     /// println!("{}", MTWRFSU[today.num_days_from_monday() as usize]);
+    /// # }
     /// ```
     #[inline]
     pub const fn num_days_from_monday(&self) -> u32 {
-        self.num_days_from(Weekday::Mon)
+        self.days_since(Weekday::Mon)
     }
 
     /// Returns a day-of-week number starting from Sunday = 0.
@@ -145,23 +145,33 @@
     /// `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)
+        self.days_since(Weekday::Sun)
     }
 
-    /// Returns a day-of-week number starting from the parameter `day` (D) = 0.
+    /// The number of days since the given day.
     ///
-    /// `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
+    /// # Examples
+    ///
+    /// ```
+    /// use chrono::Weekday::*;
+    /// assert_eq!(Mon.days_since(Mon), 0);
+    /// assert_eq!(Sun.days_since(Tue), 5);
+    /// assert_eq!(Wed.days_since(Sun), 3);
+    /// ```
+    pub const fn days_since(&self, other: Weekday) -> u32 {
+        let lhs = *self as u32;
+        let rhs = other as u32;
+        if lhs < rhs {
+            7 + lhs - rhs
+        } else {
+            lhs - rhs
+        }
     }
 }
 
 impl fmt::Display for Weekday {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        f.write_str(match *self {
+        f.pad(match *self {
             Weekday::Mon => "Mon",
             Weekday::Tue => "Tue",
             Weekday::Wed => "Wed",
@@ -266,7 +276,7 @@
 
     struct WeekdayVisitor;
 
-    impl<'de> de::Visitor<'de> for WeekdayVisitor {
+    impl de::Visitor<'_> for WeekdayVisitor {
         type Value = Weekday;
 
         fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
@@ -296,38 +306,42 @@
     use super::Weekday;
 
     #[test]
-    fn test_num_days_from() {
+    fn test_days_since() {
         for i in 0..7 {
             let base_day = Weekday::try_from(i).unwrap();
 
-            assert_eq!(base_day.num_days_from_monday(), base_day.num_days_from(Weekday::Mon));
-            assert_eq!(base_day.num_days_from_sunday(), base_day.num_days_from(Weekday::Sun));
+            assert_eq!(base_day.num_days_from_monday(), base_day.days_since(Weekday::Mon));
+            assert_eq!(base_day.num_days_from_sunday(), base_day.days_since(Weekday::Sun));
 
-            assert_eq!(base_day.num_days_from(base_day), 0);
+            assert_eq!(base_day.days_since(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.days_since(base_day.pred()), 1);
+            assert_eq!(base_day.days_since(base_day.pred().pred()), 2);
+            assert_eq!(base_day.days_since(base_day.pred().pred().pred()), 3);
+            assert_eq!(base_day.days_since(base_day.pred().pred().pred().pred()), 4);
+            assert_eq!(base_day.days_since(base_day.pred().pred().pred().pred().pred()), 5);
+            assert_eq!(base_day.days_since(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
-            );
+            assert_eq!(base_day.days_since(base_day.succ()), 6);
+            assert_eq!(base_day.days_since(base_day.succ().succ()), 5);
+            assert_eq!(base_day.days_since(base_day.succ().succ().succ()), 4);
+            assert_eq!(base_day.days_since(base_day.succ().succ().succ().succ()), 3);
+            assert_eq!(base_day.days_since(base_day.succ().succ().succ().succ().succ()), 2);
+            assert_eq!(base_day.days_since(base_day.succ().succ().succ().succ().succ().succ()), 1);
         }
     }
 
     #[test]
+    fn test_formatting_alignment() {
+        // No exhaustive testing here as we just delegate the
+        // implementation to Formatter::pad. Just some basic smoke
+        // testing to ensure that it's in fact being done.
+        assert_eq!(format!("{:x>7}", Weekday::Mon), "xxxxMon");
+        assert_eq!(format!("{:^7}", Weekday::Mon), "  Mon  ");
+        assert_eq!(format!("{:Z<7}", Weekday::Mon), "MonZZZZ");
+    }
+
+    #[test]
     #[cfg(feature = "serde")]
     fn test_serde_serialize() {
         use serde_json::to_string;
diff --git a/crates/chrono/taplo.toml b/crates/chrono/taplo.toml
deleted file mode 100644
index 5fe42eb..0000000
--- a/crates/chrono/taplo.toml
+++ /dev/null
@@ -1,4 +0,0 @@
-include = ["deny.toml", "**/Cargo.toml"]
-
-[formatting]
-inline_table_expand = false
diff --git a/crates/chrono/tests/dateutils.rs b/crates/chrono/tests/dateutils.rs
index cf3d908..a0a445a 100644
--- a/crates/chrono/tests/dateutils.rs
+++ b/crates/chrono/tests/dateutils.rs
@@ -1,8 +1,11 @@
 #![cfg(all(unix, feature = "clock", feature = "std"))]
 
-use chrono::{Datelike, Local, NaiveDate, NaiveDateTime, NaiveTime, TimeZone, Timelike};
 use std::{path, process, thread};
 
+#[cfg(target_os = "linux")]
+use chrono::Days;
+use chrono::{Datelike, Local, NaiveDate, NaiveDateTime, NaiveTime, TimeZone, Timelike};
+
 fn verify_against_date_command_local(path: &'static str, dt: NaiveDateTime) {
     let output = process::Command::new(path)
         .arg("-d")
@@ -28,19 +31,19 @@
     //     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
+    // This is used while a decision is made whether the `date` output needs to
+    // be exactly matched, or whether MappedLocalTime::Ambiguous 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!(
+        chrono::MappedLocalTime::Ambiguous(a, b) => assert!(
             format!("{}\n", a) == date_command_str || format!("{}\n", b) == date_command_str
         ),
-        chrono::LocalResult::Single(a) => {
+        chrono::MappedLocalTime::Single(a) => {
             assert_eq!(format!("{}\n", a), date_command_str);
         }
-        chrono::LocalResult::None => {
+        chrono::MappedLocalTime::None => {
             assert_eq!("", date_command_str);
         }
     }
@@ -94,7 +97,7 @@
             let end = NaiveDate::from_ymd_opt(*year + 1, 1, 1).unwrap().and_time(NaiveTime::MIN);
             while date <= end {
                 verify_against_date_command_local(DATE_PATH, date);
-                date += chrono::TimeDelta::hours(1);
+                date += chrono::TimeDelta::try_hours(1).unwrap();
             }
         }));
     }
@@ -141,8 +144,8 @@
     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);
+    let formatted_date = format!("{}\n", ldt.format(required_format));
+    assert_eq!(date_command_str, formatted_date);
 }
 
 #[test]
@@ -157,6 +160,6 @@
     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::TimeDelta::days(55);
+        date = date + Days::new(55);
     }
 }
diff --git a/crates/chrono/tests/wasm.rs b/crates/chrono/tests/wasm.rs
index 6937da9..ceb9b3d 100644
--- a/crates/chrono/tests/wasm.rs
+++ b/crates/chrono/tests/wasm.rs
@@ -25,7 +25,7 @@
     let actual = NaiveDateTime::parse_from_str(&now, "%s").unwrap().and_utc();
     let diff = utc - actual;
     assert!(
-        diff < chrono::TimeDelta::minutes(5),
+        diff < chrono::TimeDelta::try_minutes(5).unwrap(),
         "expected {} - {} == {} < 5m (env var: {})",
         utc,
         actual,
diff --git a/pseudo_crate/Cargo.lock b/pseudo_crate/Cargo.lock
index db8ce15..523b654 100644
--- a/pseudo_crate/Cargo.lock
+++ b/pseudo_crate/Cargo.lock
@@ -1097,9 +1097,9 @@
 
 [[package]]
 name = "chrono"
-version = "0.4.34"
+version = "0.4.39"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5bc015644b92d5890fab7489e49d21f879d5c990186827d42ec511919404f38b"
+checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825"
 dependencies = [
  "android-tzdata",
  "iana-time-zone",
diff --git a/pseudo_crate/Cargo.toml b/pseudo_crate/Cargo.toml
index 4782645..0a4cdc2 100644
--- a/pseudo_crate/Cargo.toml
+++ b/pseudo_crate/Cargo.toml
@@ -50,7 +50,7 @@
 cesu8 = "=1.1.0"
 cexpr = "=0.6.0"
 cfg-if = "=1.0.0"
-chrono = "=0.4.34"
+chrono = "=0.4.39"
 ciborium = "=0.2.2"
 ciborium-io = "=0.2.2"
 ciborium-ll = "=0.2.2"