diff --git a/Cargo.lock b/Cargo.lock index 9e689e3..b12d243 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -71,6 +71,67 @@ version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + +[[package]] +name = "futures-macro" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "futures-task" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" + +[[package]] +name = "futures-timer" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" + +[[package]] +name = "futures-util" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +dependencies = [ + "futures-core", + "futures-macro", + "futures-task", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "glob" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" + +[[package]] +name = "hashbrown" +version = "0.15.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" + [[package]] name = "iana-time-zone" version = "0.1.63" @@ -95,6 +156,16 @@ dependencies = [ "cc", ] +[[package]] +name = "indexmap" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" +dependencies = [ + "equivalent", + "hashbrown", +] + [[package]] name = "js-sys" version = "0.3.77" @@ -145,9 +216,31 @@ dependencies = [ "chrono", "num-traits", "regex", + "rstest", "winnow", ] +[[package]] +name = "pin-project-lite" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "proc-macro-crate" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edce586971a4dfaa28950c6f18ed55e0406c1ab88bbce2c6f6293a7aaba73d35" +dependencies = [ + "toml_edit", +] + [[package]] name = "proc-macro2" version = "1.0.95" @@ -195,18 +288,75 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +[[package]] +name = "relative-path" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba39f3699c378cd8970968dcbff9c43159ea4cfbd88d43c00b22f2ef10a435d2" + +[[package]] +name = "rstest" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fc39292f8613e913f7df8fa892b8944ceb47c247b78e1b1ae2f09e019be789d" +dependencies = [ + "futures-timer", + "futures-util", + "rstest_macros", + "rustc_version", +] + +[[package]] +name = "rstest_macros" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f168d99749d307be9de54d23fd226628d99768225ef08f6ffb52e0182a27746" +dependencies = [ + "cfg-if", + "glob", + "proc-macro-crate", + "proc-macro2", + "quote", + "regex", + "relative-path", + "rustc_version", + "syn", + "unicode-ident", +] + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + [[package]] name = "rustversion" version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" +[[package]] +name = "semver" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" + [[package]] name = "shlex" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +[[package]] +name = "slab" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04dc19736151f35336d325007ac991178d504a119863a2fcb3758cdb5e52c50d" + [[package]] name = "syn" version = "2.0.101" @@ -218,6 +368,23 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "toml_datetime" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" + +[[package]] +name = "toml_edit" +version = "0.22.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow", +] + [[package]] name = "unicode-ident" version = "1.0.18" diff --git a/Cargo.toml b/Cargo.toml index 2f0013f..55df981 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,3 +13,6 @@ regex = "1.10.4" chrono = { version="0.4.38", default-features=false, features=["std", "alloc", "clock"] } winnow = "0.7.10" num-traits = "0.2.19" + +[dev-dependencies] +rstest = "0.25" diff --git a/tests/common/mod.rs b/tests/common/mod.rs new file mode 100644 index 0000000..6956e99 --- /dev/null +++ b/tests/common/mod.rs @@ -0,0 +1,24 @@ +use chrono::{DateTime, FixedOffset}; +use parse_datetime::{parse_datetime, parse_datetime_at_date}; + +pub fn check_absolute(input: &str, expected: &str) { + let parsed = match parse_datetime(input) { + Ok(v) => v, + Err(e) => panic!("Failed to parse date from value '{input}': {e}"), + }; + + assert_eq!( + &parsed.to_rfc3339().replace("T", " "), + expected, + "Input value: {input}" + ); +} + +pub fn check_relative(now: DateTime, input: &str, expected: &str) { + let parsed = match parse_datetime_at_date(now.into(), input) { + Ok(v) => v, + Err(e) => panic!("Failed to parse date from value '{input}': {e}"), + }; + let expected_parsed = DateTime::parse_from_rfc3339(expected).unwrap(); + assert_eq!(parsed, expected_parsed, "Input value: {input}"); +} diff --git a/tests/date.rs b/tests/date.rs new file mode 100644 index 0000000..ba8ef53 --- /dev/null +++ b/tests/date.rs @@ -0,0 +1,92 @@ +use rstest::rstest; + +mod common; +use common::check_absolute; + +// The expected values are produced by GNU date version 8.32 +// export LC_TIME=en_US.UTF-8 +// export TZ=UTC +// date --rfc-3339=seconds --date="2022-11-14" +// +// Documentation for the date format can be found at: +// https://www.gnu.org/software/coreutils/manual/html_node/Calendar-date-items.html + +#[rstest] +#[case::iso8601("2022-11-14", "2022-11-14 00:00:00+00:00")] +#[case::short_year_22("22-11-14", "2022-11-14 00:00:00+00:00")] +#[case::short_year_68("68-11-14", "2068-11-14 00:00:00+00:00")] +#[case::short_year_00("00-11-14", "2000-11-14 00:00:00+00:00")] +#[case::short_year_69("69-11-14", "1969-11-14 00:00:00+00:00")] +#[case::short_year_99("99-11-14", "1999-11-14 00:00:00+00:00")] +#[case::us_style("11/14/2022", "2022-11-14 00:00:00+00:00")] +#[case::us_style_short_year("11/14/22", "2022-11-14 00:00:00+00:00")] +#[case::year_zero("0000-01-01", "0000-01-01 00:00:00+00:00")] +#[case::year_001("001-11-14", "0001-11-14 00:00:00+00:00")] +#[case::year_100("100-11-14", "0100-11-14 00:00:00+00:00")] +#[case::year_999("999-11-14", "0999-11-14 00:00:00+00:00")] +#[case::year_9999("9999-11-14", "9999-11-14 00:00:00+00:00")] +/** TODO: https://github.com/uutils/parse_datetime/issues/160 +#[case::year_10000("10000-12-31", "10000-12-31 00:00:00+00:00")] +#[case::year_100000("100000-12-31", "100000-12-31 00:00:00+00:00")] +#[case::year_1000000("1000000-12-31", "1000000-12-31 00:00:00+00:00")] +#[case::year_10000000("10000000-12-31", "10000000-12-31 00:00:00+00:00")] +#[case::max_date("2147485547-12-31", "2147485547-12-31 00:00:00+00:00")] +**/ +#[case::long_month_in_the_middle("14 November 2022", "2022-11-14 00:00:00+00:00")] +#[case::long_month_in_the_middle_lowercase("14 november 2022", "2022-11-14 00:00:00+00:00")] +#[case::long_month_in_the_middle_uppercase("14 NOVEMBER 2022", "2022-11-14 00:00:00+00:00")] +#[case::short_month_in_the_middle("14 nov 2022", "2022-11-14 00:00:00+00:00")] +#[case::short_month_in_the_uppercase("14 NOV 2022", "2022-11-14 00:00:00+00:00")] +#[case::long_month_in_the_middle_hyphened("14-november-2022", "2022-11-14 00:00:00+00:00")] +#[case::long_month_in_the_middle_nospace("14november2022", "2022-11-14 00:00:00+00:00")] +#[case::short_month_in_the_middle_hyphened("14-nov-2022", "2022-11-14 00:00:00+00:00")] +#[case::short_month_in_the_middle_nospace("14nov2022", "2022-11-14 00:00:00+00:00")] +#[case::long_month_at_start("November 14 2022", "2022-11-14 00:00:00+00:00")] +#[case::long_month_at_start_with_comma("November 14, 2022", "2022-11-14 00:00:00+00:00")] +#[case::short_month_at_start("nov 14 2022", "2022-11-14 00:00:00+00:00")] +#[case::long_month_in_the_middle_jan("14 January 2022", "2022-01-14 00:00:00+00:00")] +#[case::long_month_in_the_middle_feb("14 February 2022", "2022-02-14 00:00:00+00:00")] +#[case::long_month_in_the_middle_mar("14 March 2022", "2022-03-14 00:00:00+00:00")] +#[case::long_month_in_the_middle_apr("14 April 2022", "2022-04-14 00:00:00+00:00")] +#[case::long_month_in_the_middle_may("14 May 2022", "2022-05-14 00:00:00+00:00")] +#[case::long_month_in_the_middle_jun("14 June 2022", "2022-06-14 00:00:00+00:00")] +#[case::long_month_in_the_middle_jul("14 July 2022", "2022-07-14 00:00:00+00:00")] +#[case::long_month_in_the_middle_aug("14 August 2022", "2022-08-14 00:00:00+00:00")] +#[case::long_month_in_the_middle_sep("14 September 2022", "2022-09-14 00:00:00+00:00")] +#[case::long_month_in_the_middle_oct("14 October 2022", "2022-10-14 00:00:00+00:00")] +#[case::long_month_in_the_middle_dec("14 December 2022", "2022-12-14 00:00:00+00:00")] +#[case::short_month_in_the_middle_jan("14 jan 2022", "2022-01-14 00:00:00+00:00")] +#[case::short_month_in_the_middle_feb("14 feb 2022", "2022-02-14 00:00:00+00:00")] +#[case::short_month_in_the_middle_mar("14 mar 2022", "2022-03-14 00:00:00+00:00")] +#[case::short_month_in_the_middle_apr("14 apr 2022", "2022-04-14 00:00:00+00:00")] +#[case::short_month_in_the_middle_may("14 may 2022", "2022-05-14 00:00:00+00:00")] +#[case::short_month_in_the_middle_jun("14 jun 2022", "2022-06-14 00:00:00+00:00")] +#[case::short_month_in_the_middle_jul("14 jul 2022", "2022-07-14 00:00:00+00:00")] +#[case::short_month_in_the_middle_aug("14 aug 2022", "2022-08-14 00:00:00+00:00")] +#[case::short_month_in_the_middle_sep("14 sep 2022", "2022-09-14 00:00:00+00:00")] +#[case::short_month_in_the_middle_sept("14 sept 2022", "2022-09-14 00:00:00+00:00")] +#[case::short_month_in_the_middle_oct("14 oct 2022", "2022-10-14 00:00:00+00:00")] +#[case::short_month_in_the_middle_dec("14 dec 2022", "2022-12-14 00:00:00+00:00")] +fn test_absolute_date_numeric(#[case] input: &str, #[case] expected: &str) { + check_absolute(input, expected); +} + +#[rstest] +#[case::us_style("11/14", 2022, "2022-11-14 00:00:00+00:00")] +#[case::aphabetical_full_month_in_front("november 14", 2022, "2022-11-14 00:00:00+00:00")] +#[case::aphabetical_full_month_at_back("14 november", 2022, "2022-11-14 00:00:00+00:00")] +#[case::aphabetical_short_month_in_front("nov 14", 2022, "2022-11-14 00:00:00+00:00")] +#[case::aphabetical_short_month_at_back("14 nov", 2022, "2022-11-14 00:00:00+00:00")] +#[case::aphabetical_full_month_in_front("november 14", 2022, "2022-11-14 00:00:00+00:00")] +#[case::aphabetical_full_month_at_back("14 november", 2022, "2022-11-14 00:00:00+00:00")] +#[case::aphabetical_short_month_in_front("nov 14", 2022, "2022-11-14 00:00:00+00:00")] +#[case::aphabetical_short_month_at_back("14 nov", 2022, "2022-11-14 00:00:00+00:00")] +#[case::aphabetical_long_month_at_back_hyphen("14-november", 2022, "2022-11-14 00:00:00+00:00")] +#[case::aphabetical_short_month_at_back_hyphen("14-nov", 2022, "2022-11-14 00:00:00+00:00")] +fn test_date_ommititing_year(#[case] input: &str, #[case] year: u32, #[case] expected: &str) { + use chrono::DateTime; + use common::check_relative; + + let now = DateTime::parse_from_rfc3339(&format!("{year}-06-01T00:00:00+00:00")).unwrap(); + check_relative(now, input, expected); +} diff --git a/tests/simple.rs b/tests/simple.rs deleted file mode 100644 index 8b13789..0000000 --- a/tests/simple.rs +++ /dev/null @@ -1 +0,0 @@ -