From 78fc0650d341a198e4958071fd9f80472a764c4e Mon Sep 17 00:00:00 2001 From: olliemath Date: Fri, 29 Sep 2023 11:53:26 +0100 Subject: [PATCH] Revert "Merge pull request #7 from olliemath/0-3-release-branch" This reverts commit 6f7d9a2f1b8afef6fb009720dacc921bfe412329, reversing changes made to c58bdd8c19325928e148dbffd313a47a2593527f. --- .github/workflows/ci.yml | 8 +- .github/workflows/publish.yml | 26 --- Cargo.toml | 2 +- LICENSE | 2 +- README.md | 16 +- benches/delta.rs | 4 +- src/delta.rs | 322 +++++++++------------------------- src/lib.rs | 26 +-- src/relative_duration.rs | 52 ++++-- src/rule.rs | 77 +++++--- 10 files changed, 203 insertions(+), 332 deletions(-) delete mode 100644 .github/workflows/publish.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4f4d704..9df78d0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,7 +16,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout sources - uses: actions/checkout@v3 + uses: actions/checkout@v2 - name: Install stable toolchain uses: actions-rs/toolchain@v1 @@ -35,7 +35,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout sources - uses: actions/checkout@v3 + uses: actions/checkout@v2 - name: Install stable toolchain uses: actions-rs/toolchain@v1 @@ -54,7 +54,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout sources - uses: actions/checkout@v3 + uses: actions/checkout@v2 - name: Install stable toolchain uses: actions-rs/toolchain@v1 @@ -74,4 +74,4 @@ jobs: uses: actions-rs/cargo@v1 with: command: clippy - args: -- -D warnings + args: -- -D warnings -A deprecated diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml deleted file mode 100644 index 10cac86..0000000 --- a/.github/workflows/publish.yml +++ /dev/null @@ -1,26 +0,0 @@ -name: crates_io_publish - -on: - release: - types: [published] - -jobs: - build: - name: Crates IO Upload - runs-on: ubuntu-latest - - steps: - - name: Checkout sources - uses: actions/checkout@v3 - - - name: Install stable toolchain - uses: actions-rs/toolchain@v1 - with: - toolchain: stable - - - name: Run cargo publish - env: - CARGO_REGISTRY_TOKEN : ${{ secrets.CRATES_IO_TOKEN }} - uses: actions-rs/cargo@v1 - with: - command: publish diff --git a/Cargo.toml b/Cargo.toml index e2469b7..220e8b7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT" name = "chronoutil" readme = "README.md" repository = "https://github.com/olliemath/chronoutil" -version = "0.3.0" +version = "0.2.5" [dependencies] "chrono" = { version = "^0.4.24", default-features = false } diff --git a/LICENSE b/LICENSE index 12d7056..14843ab 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2020-2023 Oliver Margetts +Copyright (c) 2020-2022 Oliver Margetts Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 6123d83..07ded9c 100644 --- a/README.md +++ b/README.md @@ -27,14 +27,14 @@ Put this in your `Cargo.toml`: ```toml [dependencies] -chronoutil = "0.3" +chronoutil = "0.2.5" ``` ## Overview ### RelativeDuration -ChronoUtils uses a [**`RelativeDuration`**](https://docs.rs/chronoutil/0.3.0/chronoutil/relative_duration/struct.RelativeDuration.html) type to represent the magnitude of a time span +ChronoUtils uses a [**`RelativeDuration`**](https://docs.rs/chronoutil/0.2.5/chronoutil/relative_duration/struct.RelativeDuration.html) type to represent the magnitude of a time span which may not be absolute (i.e. which is not simply a fixed number of nanoseconds). A relative duration is made up of a number of months together with an absolute [`Duration`]() component. @@ -61,7 +61,7 @@ assert_eq!(start + delta, NaiveDate::from_ymd(2020, 3, 1)); ### DateRule ChronoUtil provides a -[**`DateRule`**](https://docs.rs/chronoutil/0.3.0/chronoutil/rule/struct.DateRule.html) +[**`DateRule`**](https://docs.rs/chronoutil/0.2.5/chronoutil/rule/struct.DateRule.html) iterator to reliably generate a collection of dates at regular intervals. For example, the following will yield one `NaiveDate` on the last day of each month in 2025: @@ -76,11 +76,11 @@ let rule = DateRule::monthly(start).with_count(12); ChronoUtil also exposes useful shift functions which are used internally, namely: -- [**`shift_months`**](https://docs.rs/chronoutil/0.3.0/chronoutil/delta/fn.shift_months.html) to shift a datelike value by a given number of months -- [**`shift_years`**](https://docs.rs/chronoutil/0.3.0/chronoutil/delta/fn.shift_years.html) to shift a datelike value by a given number of years -- [**`with_year`**](https://docs.rs/chronoutil/0.3.0/chronoutil/delta/fn.shift_months.html) to shift a datelike value to a given day -- [**`with_month`**](https://docs.rs/chronoutil/0.3.0/chronoutil/delta/fn.with_month.html) to shift a datelike value to a given month -- [**`with_year`**](https://docs.rs/chronoutil/0.3.0/chronoutil/delta/fn.with_year.html) to shift a datelike value to a given year +- [**`shift_months`**](https://docs.rs/chronoutil/0.2.5/chronoutil/delta/fn.shift_months.html) to shift a datelike value by a given number of months +- [**`shift_years`**](https://docs.rs/chronoutil/0.2.5/chronoutil/delta/fn.shift_years.html) to shift a datelike value by a given number of years +- [**`with_year`**](https://docs.rs/chronoutil/0.2.5/chronoutil/delta/fn.shift_months.html) to shift a datelike value to a given day +- [**`with_month`**](https://docs.rs/chronoutil/0.2.5/chronoutil/delta/fn.with_month.html) to shift a datelike value to a given month +- [**`with_year`**](https://docs.rs/chronoutil/0.2.5/chronoutil/delta/fn.with_year.html) to shift a datelike value to a given year ## Design decisions and gotchas diff --git a/benches/delta.rs b/benches/delta.rs index fc68701..5f9e073 100644 --- a/benches/delta.rs +++ b/benches/delta.rs @@ -5,7 +5,7 @@ use chronoutil::delta::{is_leap_year, shift_months}; fn shift_months_benchmark(c: &mut Criterion) { let shifts = black_box(-18..19); - let base = NaiveDate::from_ymd_opt(2020, 12, 31).unwrap(); + let base = NaiveDate::from_ymd(2020, 12, 31); c.bench_function("shift_months", |b| { b.iter::, _>(|| shifts.clone().map(|s| shift_months(base, s)).collect()) @@ -29,7 +29,7 @@ fn shift_months_many_benchmark(c: &mut Criterion) { for m in 1..13 { for d in 1..31 { if in_month(y, m, d) { - bases.push(NaiveDate::from_ymd_opt(y, m, d).unwrap()); + bases.push(NaiveDate::from_ymd(y, m, d)); } } } diff --git a/src/delta.rs b/src/delta.rs index 1c779b6..cd52edb 100644 --- a/src/delta.rs +++ b/src/delta.rs @@ -79,8 +79,8 @@ pub fn shift_years_opt(date: D, years: i32) -> Option { /// ```rust /// # use chrono::NaiveDate; /// # use chronoutil::with_day; -/// let start = NaiveDate::from_ymd_opt(2020, 2, 1).unwrap(); -/// assert_eq!(with_day(start, 31), Some(NaiveDate::from_ymd_opt(2020, 2, 29).unwrap())); +/// let start = NaiveDate::from_ymd(2020, 2, 1); +/// assert_eq!(with_day(start, 31), Some(NaiveDate::from_ymd(2020, 2, 29))); /// assert_eq!(with_day(start, 42), None); /// ``` pub fn with_day(date: D, day: u32) -> Option { @@ -98,8 +98,8 @@ pub fn with_day(date: D, day: u32) -> Option { /// ```rust /// # use chrono::NaiveDate; /// # use chronoutil::with_month; -/// let start = NaiveDate::from_ymd_opt(2020, 1, 31).unwrap(); -/// assert_eq!(with_month(start, 2), Some(NaiveDate::from_ymd_opt(2020, 2, 29).unwrap())); +/// let start = NaiveDate::from_ymd(2020, 1, 31); +/// assert_eq!(with_month(start, 2), Some(NaiveDate::from_ymd(2020, 2, 29))); /// assert_eq!(with_month(start, 13), None); /// ``` pub fn with_month(date: D, month: u32) -> Option { @@ -132,8 +132,8 @@ pub fn with_month_opt(date: D, month: u32) -> Option { /// ```rust /// # use chrono::NaiveDate; /// # use chronoutil::with_year; -/// let start = NaiveDate::from_ymd_opt(2020, 2, 29).unwrap(); -/// assert_eq!(with_year(start, 2021), NaiveDate::from_ymd_opt(2021, 2, 28).unwrap()); +/// let start = NaiveDate::from_ymd(2020, 2, 29); +/// assert_eq!(with_year(start, 2021), NaiveDate::from_ymd(2021, 2, 28)); /// ``` pub fn with_year(date: D, year: i32) -> D { with_year_opt(date, year).unwrap() @@ -175,186 +175,75 @@ mod tests { #[test] fn test_shift_months() { - let base = NaiveDate::from_ymd_opt(2020, 1, 31).unwrap(); - - assert_eq!( - shift_months(base, 0), - NaiveDate::from_ymd_opt(2020, 1, 31).unwrap() - ); - assert_eq!( - shift_months(base, 1), - NaiveDate::from_ymd_opt(2020, 2, 29).unwrap() - ); - assert_eq!( - shift_months(base, 2), - NaiveDate::from_ymd_opt(2020, 3, 31).unwrap() - ); - assert_eq!( - shift_months(base, 3), - NaiveDate::from_ymd_opt(2020, 4, 30).unwrap() - ); - assert_eq!( - shift_months(base, 4), - NaiveDate::from_ymd_opt(2020, 5, 31).unwrap() - ); - assert_eq!( - shift_months(base, 5), - NaiveDate::from_ymd_opt(2020, 6, 30).unwrap() - ); - assert_eq!( - shift_months(base, 6), - NaiveDate::from_ymd_opt(2020, 7, 31).unwrap() - ); - assert_eq!( - shift_months(base, 7), - NaiveDate::from_ymd_opt(2020, 8, 31).unwrap() - ); - assert_eq!( - shift_months(base, 8), - NaiveDate::from_ymd_opt(2020, 9, 30).unwrap() - ); - assert_eq!( - shift_months(base, 9), - NaiveDate::from_ymd_opt(2020, 10, 31).unwrap() - ); - assert_eq!( - shift_months(base, 10), - NaiveDate::from_ymd_opt(2020, 11, 30).unwrap() - ); - assert_eq!( - shift_months(base, 11), - NaiveDate::from_ymd_opt(2020, 12, 31).unwrap() - ); - assert_eq!( - shift_months(base, 12), - NaiveDate::from_ymd_opt(2021, 1, 31).unwrap() - ); - assert_eq!( - shift_months(base, 13), - NaiveDate::from_ymd_opt(2021, 2, 28).unwrap() - ); - - assert_eq!( - shift_months(base, -1), - NaiveDate::from_ymd_opt(2019, 12, 31).unwrap() - ); - assert_eq!( - shift_months(base, -2), - NaiveDate::from_ymd_opt(2019, 11, 30).unwrap() - ); - assert_eq!( - shift_months(base, -3), - NaiveDate::from_ymd_opt(2019, 10, 31).unwrap() - ); - assert_eq!( - shift_months(base, -4), - NaiveDate::from_ymd_opt(2019, 9, 30).unwrap() - ); - assert_eq!( - shift_months(base, -5), - NaiveDate::from_ymd_opt(2019, 8, 31).unwrap() - ); - assert_eq!( - shift_months(base, -6), - NaiveDate::from_ymd_opt(2019, 7, 31).unwrap() - ); - assert_eq!( - shift_months(base, -7), - NaiveDate::from_ymd_opt(2019, 6, 30).unwrap() - ); - assert_eq!( - shift_months(base, -8), - NaiveDate::from_ymd_opt(2019, 5, 31).unwrap() - ); - assert_eq!( - shift_months(base, -9), - NaiveDate::from_ymd_opt(2019, 4, 30).unwrap() - ); - assert_eq!( - shift_months(base, -10), - NaiveDate::from_ymd_opt(2019, 3, 31).unwrap() - ); - assert_eq!( - shift_months(base, -11), - NaiveDate::from_ymd_opt(2019, 2, 28).unwrap() - ); - assert_eq!( - shift_months(base, -12), - NaiveDate::from_ymd_opt(2019, 1, 31).unwrap() - ); - assert_eq!( - shift_months(base, -13), - NaiveDate::from_ymd_opt(2018, 12, 31).unwrap() - ); - - assert_eq!( - shift_months(base, 1265), - NaiveDate::from_ymd_opt(2125, 6, 30).unwrap() - ); + let base = NaiveDate::from_ymd(2020, 1, 31); + + assert_eq!(shift_months(base, 0), NaiveDate::from_ymd(2020, 1, 31)); + assert_eq!(shift_months(base, 1), NaiveDate::from_ymd(2020, 2, 29)); + assert_eq!(shift_months(base, 2), NaiveDate::from_ymd(2020, 3, 31)); + assert_eq!(shift_months(base, 3), NaiveDate::from_ymd(2020, 4, 30)); + assert_eq!(shift_months(base, 4), NaiveDate::from_ymd(2020, 5, 31)); + assert_eq!(shift_months(base, 5), NaiveDate::from_ymd(2020, 6, 30)); + assert_eq!(shift_months(base, 6), NaiveDate::from_ymd(2020, 7, 31)); + assert_eq!(shift_months(base, 7), NaiveDate::from_ymd(2020, 8, 31)); + assert_eq!(shift_months(base, 8), NaiveDate::from_ymd(2020, 9, 30)); + assert_eq!(shift_months(base, 9), NaiveDate::from_ymd(2020, 10, 31)); + assert_eq!(shift_months(base, 10), NaiveDate::from_ymd(2020, 11, 30)); + assert_eq!(shift_months(base, 11), NaiveDate::from_ymd(2020, 12, 31)); + assert_eq!(shift_months(base, 12), NaiveDate::from_ymd(2021, 1, 31)); + assert_eq!(shift_months(base, 13), NaiveDate::from_ymd(2021, 2, 28)); + + assert_eq!(shift_months(base, -1), NaiveDate::from_ymd(2019, 12, 31)); + assert_eq!(shift_months(base, -2), NaiveDate::from_ymd(2019, 11, 30)); + assert_eq!(shift_months(base, -3), NaiveDate::from_ymd(2019, 10, 31)); + assert_eq!(shift_months(base, -4), NaiveDate::from_ymd(2019, 9, 30)); + assert_eq!(shift_months(base, -5), NaiveDate::from_ymd(2019, 8, 31)); + assert_eq!(shift_months(base, -6), NaiveDate::from_ymd(2019, 7, 31)); + assert_eq!(shift_months(base, -7), NaiveDate::from_ymd(2019, 6, 30)); + assert_eq!(shift_months(base, -8), NaiveDate::from_ymd(2019, 5, 31)); + assert_eq!(shift_months(base, -9), NaiveDate::from_ymd(2019, 4, 30)); + assert_eq!(shift_months(base, -10), NaiveDate::from_ymd(2019, 3, 31)); + assert_eq!(shift_months(base, -11), NaiveDate::from_ymd(2019, 2, 28)); + assert_eq!(shift_months(base, -12), NaiveDate::from_ymd(2019, 1, 31)); + assert_eq!(shift_months(base, -13), NaiveDate::from_ymd(2018, 12, 31)); + + assert_eq!(shift_months(base, 1265), NaiveDate::from_ymd(2125, 6, 30)); } #[test] fn test_shift_months_with_overflow() { - let base = NaiveDate::from_ymd_opt(2020, 12, 31).unwrap(); + let base = NaiveDate::from_ymd(2020, 12, 31); assert_eq!(shift_months(base, 0), base); - assert_eq!( - shift_months(base, 1), - NaiveDate::from_ymd_opt(2021, 1, 31).unwrap() - ); - assert_eq!( - shift_months(base, 2), - NaiveDate::from_ymd_opt(2021, 2, 28).unwrap() - ); - assert_eq!( - shift_months(base, 12), - NaiveDate::from_ymd_opt(2021, 12, 31).unwrap() - ); - assert_eq!( - shift_months(base, 18), - NaiveDate::from_ymd_opt(2022, 6, 30).unwrap() - ); - - assert_eq!( - shift_months(base, -1), - NaiveDate::from_ymd_opt(2020, 11, 30).unwrap() - ); - assert_eq!( - shift_months(base, -2), - NaiveDate::from_ymd_opt(2020, 10, 31).unwrap() - ); - assert_eq!( - shift_months(base, -10), - NaiveDate::from_ymd_opt(2020, 2, 29).unwrap() - ); - assert_eq!( - shift_months(base, -12), - NaiveDate::from_ymd_opt(2019, 12, 31).unwrap() - ); - assert_eq!( - shift_months(base, -18), - NaiveDate::from_ymd_opt(2019, 6, 30).unwrap() - ); + assert_eq!(shift_months(base, 1), NaiveDate::from_ymd(2021, 1, 31)); + assert_eq!(shift_months(base, 2), NaiveDate::from_ymd(2021, 2, 28)); + assert_eq!(shift_months(base, 12), NaiveDate::from_ymd(2021, 12, 31)); + assert_eq!(shift_months(base, 18), NaiveDate::from_ymd(2022, 6, 30)); + + assert_eq!(shift_months(base, -1), NaiveDate::from_ymd(2020, 11, 30)); + assert_eq!(shift_months(base, -2), NaiveDate::from_ymd(2020, 10, 31)); + assert_eq!(shift_months(base, -10), NaiveDate::from_ymd(2020, 2, 29)); + assert_eq!(shift_months(base, -12), NaiveDate::from_ymd(2019, 12, 31)); + assert_eq!(shift_months(base, -18), NaiveDate::from_ymd(2019, 6, 30)); } #[test] fn test_shift_months_datetime() { - let date = NaiveDate::from_ymd_opt(2020, 1, 31).unwrap(); - let o_clock = NaiveTime::from_hms_opt(1, 2, 3).unwrap(); + let date = NaiveDate::from_ymd(2020, 1, 31); + let o_clock = NaiveTime::from_hms(1, 2, 3); let base = NaiveDateTime::new(date, o_clock); assert_eq!( shift_months(base, 0).date(), - NaiveDate::from_ymd_opt(2020, 1, 31).unwrap() + NaiveDate::from_ymd(2020, 1, 31) ); assert_eq!( shift_months(base, 1).date(), - NaiveDate::from_ymd_opt(2020, 2, 29).unwrap() + NaiveDate::from_ymd(2020, 2, 29) ); assert_eq!( shift_months(base, 2).date(), - NaiveDate::from_ymd_opt(2020, 3, 31).unwrap() + NaiveDate::from_ymd(2020, 3, 31) ); assert_eq!(shift_months(base, 0).time(), o_clock); assert_eq!(shift_months(base, 1).time(), o_clock); @@ -444,103 +333,79 @@ mod tests { #[test] fn test_shift_years() { - let base = NaiveDate::from_ymd_opt(2020, 2, 29).unwrap(); - - assert_eq!( - shift_years(base, 0), - NaiveDate::from_ymd_opt(2020, 2, 29).unwrap() - ); - assert_eq!( - shift_years(base, 1), - NaiveDate::from_ymd_opt(2021, 2, 28).unwrap() - ); - assert_eq!( - shift_years(base, 4), - NaiveDate::from_ymd_opt(2024, 2, 29).unwrap() - ); - assert_eq!( - shift_years(base, 80), - NaiveDate::from_ymd_opt(2100, 2, 28).unwrap() - ); - assert_eq!( - shift_years(base, -1), - NaiveDate::from_ymd_opt(2019, 2, 28).unwrap() - ); - assert_eq!( - shift_years(base, -4), - NaiveDate::from_ymd_opt(2016, 2, 29).unwrap() - ); - assert_eq!( - shift_years(base, -20), - NaiveDate::from_ymd_opt(2000, 2, 29).unwrap() - ); - assert_eq!( - shift_years(base, -120), - NaiveDate::from_ymd_opt(1900, 2, 28).unwrap() - ); + let base = NaiveDate::from_ymd(2020, 2, 29); + + assert_eq!(shift_years(base, 0), NaiveDate::from_ymd(2020, 2, 29)); + assert_eq!(shift_years(base, 1), NaiveDate::from_ymd(2021, 2, 28)); + assert_eq!(shift_years(base, 4), NaiveDate::from_ymd(2024, 2, 29)); + assert_eq!(shift_years(base, 80), NaiveDate::from_ymd(2100, 2, 28)); + assert_eq!(shift_years(base, -1), NaiveDate::from_ymd(2019, 2, 28)); + assert_eq!(shift_years(base, -4), NaiveDate::from_ymd(2016, 2, 29)); + assert_eq!(shift_years(base, -20), NaiveDate::from_ymd(2000, 2, 29)); + assert_eq!(shift_years(base, -120), NaiveDate::from_ymd(1900, 2, 28)); } #[test] fn test_with_month() { - let base = NaiveDate::from_ymd_opt(2020, 1, 31).unwrap(); + let base = NaiveDate::from_ymd(2020, 1, 31); assert_eq!(with_month(base, 0), None); assert_eq!(with_month(base, 1), Some(base)); assert_eq!( with_month(base, 2).unwrap(), - NaiveDate::from_ymd_opt(2020, 2, 29).unwrap() + NaiveDate::from_ymd(2020, 2, 29) ); assert_eq!( with_month(base, 3).unwrap(), - NaiveDate::from_ymd_opt(2020, 3, 31).unwrap() + NaiveDate::from_ymd(2020, 3, 31) ); assert_eq!( with_month(base, 4).unwrap(), - NaiveDate::from_ymd_opt(2020, 4, 30).unwrap() + NaiveDate::from_ymd(2020, 4, 30) ); assert_eq!( with_month(base, 5).unwrap(), - NaiveDate::from_ymd_opt(2020, 5, 31).unwrap() + NaiveDate::from_ymd(2020, 5, 31) ); assert_eq!( with_month(base, 6).unwrap(), - NaiveDate::from_ymd_opt(2020, 6, 30).unwrap() + NaiveDate::from_ymd(2020, 6, 30) ); assert_eq!( with_month(base, 7).unwrap(), - NaiveDate::from_ymd_opt(2020, 7, 31).unwrap() + NaiveDate::from_ymd(2020, 7, 31) ); assert_eq!( with_month(base, 8).unwrap(), - NaiveDate::from_ymd_opt(2020, 8, 31).unwrap() + NaiveDate::from_ymd(2020, 8, 31) ); assert_eq!( with_month(base, 9).unwrap(), - NaiveDate::from_ymd_opt(2020, 9, 30).unwrap() + NaiveDate::from_ymd(2020, 9, 30) ); assert_eq!( with_month(base, 10).unwrap(), - NaiveDate::from_ymd_opt(2020, 10, 31).unwrap() + NaiveDate::from_ymd(2020, 10, 31) ); assert_eq!( with_month(base, 11).unwrap(), - NaiveDate::from_ymd_opt(2020, 11, 30).unwrap() + NaiveDate::from_ymd(2020, 11, 30) ); assert_eq!( with_month(base, 12).unwrap(), - NaiveDate::from_ymd_opt(2020, 12, 31).unwrap() + NaiveDate::from_ymd(2020, 12, 31) ); assert_eq!(with_month(base, 13), None); assert_eq!( - with_month(NaiveDate::from_ymd_opt(2021, 1, 31).unwrap(), 2), - Some(NaiveDate::from_ymd_opt(2021, 2, 28).unwrap()) + with_month(NaiveDate::from_ymd(2021, 1, 31), 2), + Some(NaiveDate::from_ymd(2021, 2, 28)) ); // Backwards shifts work too assert_eq!( - with_month(NaiveDate::from_ymd_opt(2021, 2, 15).unwrap(), 1), - Some(NaiveDate::from_ymd_opt(2021, 1, 15).unwrap()) + with_month(NaiveDate::from_ymd(2021, 2, 15), 1), + Some(NaiveDate::from_ymd(2021, 1, 15)) ); } @@ -578,27 +443,12 @@ mod tests { #[test] fn test_with_year() { - let base = NaiveDate::from_ymd_opt(2020, 2, 29).unwrap(); + let base = NaiveDate::from_ymd(2020, 2, 29); - assert_eq!( - with_year(base, 2024), - NaiveDate::from_ymd_opt(2024, 2, 29).unwrap() - ); - assert_eq!( - with_year(base, 2021), - NaiveDate::from_ymd_opt(2021, 2, 28).unwrap() - ); - assert_eq!( - with_year(base, 2020), - NaiveDate::from_ymd_opt(2020, 2, 29).unwrap() - ); - assert_eq!( - with_year(base, 2019), - NaiveDate::from_ymd_opt(2019, 2, 28).unwrap() - ); - assert_eq!( - with_year(base, 2016), - NaiveDate::from_ymd_opt(2016, 2, 29).unwrap() - ); + assert_eq!(with_year(base, 2024), NaiveDate::from_ymd(2024, 2, 29)); + assert_eq!(with_year(base, 2021), NaiveDate::from_ymd(2021, 2, 28)); + assert_eq!(with_year(base, 2020), NaiveDate::from_ymd(2020, 2, 29)); + assert_eq!(with_year(base, 2019), NaiveDate::from_ymd(2019, 2, 28)); + assert_eq!(with_year(base, 2016), NaiveDate::from_ymd(2016, 2, 29)); } } diff --git a/src/lib.rs b/src/lib.rs index 1bd9456..065bcf7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -23,8 +23,8 @@ //! let one_day = RelativeDuration::days(1); //! let one_month = RelativeDuration::months(1); //! let delta = one_month + one_day; -//! let start = NaiveDate::from_ymd_opt(2020, 1, 1).unwrap(); -//! assert_eq!(start + delta, NaiveDate::from_ymd_opt(2020, 2, 2).unwrap()); +//! let start = NaiveDate::from_ymd(2020, 1, 1); +//! assert_eq!(start + delta, NaiveDate::from_ymd(2020, 2, 2)); //! ``` //! //! The behaviour of `RelativeDuration` is consistent and well-defined in edge-cases @@ -36,8 +36,8 @@ //! let one_day = RelativeDuration::days(1); //! let one_month = RelativeDuration::months(1); //! let delta = one_month + one_day; -//! let start = NaiveDate::from_ymd_opt(2020, 1, 30).unwrap(); -//! assert_eq!(start + delta, NaiveDate::from_ymd_opt(2020, 3, 1).unwrap()); +//! let start = NaiveDate::from_ymd(2020, 1, 30); +//! assert_eq!(start + delta, NaiveDate::from_ymd(2020, 3, 1)); //! ``` //! //! ### DateRule @@ -51,7 +51,7 @@ //! ```rust //! # use chrono::NaiveDate; //! # use chronoutil::DateRule; -//! let start = NaiveDate::from_ymd_opt(2025, 1, 31).unwrap(); +//! let start = NaiveDate::from_ymd(2025, 1, 31); //! let rule = DateRule::monthly(start).with_count(12); //! // 2025-1-31, 2025-2-28, 2025-3-31, 2025-4-30, ... //! ``` @@ -101,13 +101,13 @@ //! # use chrono::NaiveDate; //! # use chronoutil::RelativeDuration; //! -//! let d1 = (NaiveDate::from_ymd_opt(2020, 1, 31).unwrap() + RelativeDuration::months(1)) +//! let d1 = (NaiveDate::from_ymd(2020, 1, 31) + RelativeDuration::months(1)) //! + RelativeDuration::months(1); -//! let d2 = NaiveDate::from_ymd_opt(2020, 1, 31).unwrap() +//! let d2 = NaiveDate::from_ymd(2020, 1, 31) //! + (RelativeDuration::months(1) + RelativeDuration::months(1)); //! -//! assert_eq!(d1, NaiveDate::from_ymd_opt(2020, 3, 29).unwrap()); -//! assert_eq!(d2, NaiveDate::from_ymd_opt(2020, 3, 31).unwrap()); +//! assert_eq!(d1, NaiveDate::from_ymd(2020, 3, 29)); +//! assert_eq!(d2, NaiveDate::from_ymd(2020, 3, 31)); //! ``` //! //! If you want a series of shifted dates, we advise using the `DateRule`, which takes @@ -115,12 +115,12 @@ //! ```rust //! # use chrono::NaiveDate; //! # use chronoutil::{RelativeDuration, DateRule}; -//! let start = NaiveDate::from_ymd_opt(2020, 1, 31).unwrap(); +//! let start = NaiveDate::from_ymd(2020, 1, 31); //! let delta = RelativeDuration::months(1); //! let mut rule = DateRule::new(start, delta); -//! assert_eq!(rule.next().unwrap(), NaiveDate::from_ymd_opt(2020, 1, 31).unwrap()); -//! assert_eq!(rule.next().unwrap(), NaiveDate::from_ymd_opt(2020, 2, 29).unwrap()); -//! assert_eq!(rule.next().unwrap(), NaiveDate::from_ymd_opt(2020, 3, 31).unwrap()); +//! assert_eq!(rule.next().unwrap(), NaiveDate::from_ymd(2020, 1, 31)); +//! assert_eq!(rule.next().unwrap(), NaiveDate::from_ymd(2020, 2, 29)); +//! assert_eq!(rule.next().unwrap(), NaiveDate::from_ymd(2020, 3, 31)); //! ``` extern crate chrono; diff --git a/src/relative_duration.rs b/src/relative_duration.rs index a6ed9be..4c19f09 100644 --- a/src/relative_duration.rs +++ b/src/relative_duration.rs @@ -2,7 +2,7 @@ use core::ops::{Add, Div, Mul, Neg, Sub}; use std::time::Duration as StdDuration; -use chrono::{DateTime, Duration, NaiveDate, NaiveDateTime, TimeZone}; +use chrono::{Date, DateTime, Duration, NaiveDate, NaiveDateTime, TimeZone}; use super::delta::shift_months; @@ -275,6 +275,18 @@ impl Add for NaiveDateTime { } } +impl Add for Date +where + Tz: TimeZone, +{ + type Output = Date; + + #[inline] + fn add(self, rhs: RelativeDuration) -> Date { + shift_months(self, rhs.months) + rhs.duration + } +} + impl Add for DateTime where Tz: TimeZone, @@ -305,6 +317,18 @@ impl Sub for NaiveDateTime { } } +impl Sub for Date +where + Tz: TimeZone, +{ + type Output = Date; + + #[inline] + fn sub(self, rhs: RelativeDuration) -> Date { + self + (-rhs) + } +} + impl Sub for DateTime where Tz: TimeZone, @@ -378,63 +402,57 @@ mod tests { #[test] fn test_date_arithmetic() { - let base = NaiveDate::from_ymd_opt(2020, 2, 29).unwrap(); + let base = NaiveDate::from_ymd(2020, 2, 29); assert_eq!( base + RelativeDuration { months: 24, duration: Duration::zero() }, - NaiveDate::from_ymd_opt(2022, 2, 28).unwrap() + NaiveDate::from_ymd(2022, 2, 28) ); assert_eq!( base + RelativeDuration { months: 48, duration: Duration::zero() }, - NaiveDate::from_ymd_opt(2024, 2, 29).unwrap() + NaiveDate::from_ymd(2024, 2, 29) ); - let not_leap = NaiveDate::from_ymd_opt(2020, 2, 28).unwrap(); + let not_leap = NaiveDate::from_ymd(2020, 2, 28); let tricky_delta = RelativeDuration { months: 24, duration: Duration::days(1), }; - assert_eq!( - base + tricky_delta, - NaiveDate::from_ymd_opt(2022, 3, 1).unwrap() - ); + assert_eq!(base + tricky_delta, NaiveDate::from_ymd(2022, 3, 1)); assert_eq!(base + tricky_delta, not_leap + tricky_delta); } #[test] fn test_date_negative_arithmetic() { - let base = NaiveDate::from_ymd_opt(2020, 2, 29).unwrap(); + let base = NaiveDate::from_ymd(2020, 2, 29); assert_eq!( base - RelativeDuration { months: 24, duration: Duration::zero() }, - NaiveDate::from_ymd_opt(2018, 2, 28).unwrap() + NaiveDate::from_ymd(2018, 2, 28) ); assert_eq!( base - RelativeDuration { months: 48, duration: Duration::zero() }, - NaiveDate::from_ymd_opt(2016, 2, 29).unwrap() + NaiveDate::from_ymd(2016, 2, 29) ); - let not_leap = NaiveDate::from_ymd_opt(2020, 2, 28).unwrap(); + let not_leap = NaiveDate::from_ymd(2020, 2, 28); let tricky_delta = RelativeDuration { months: 24, duration: Duration::days(-1), }; - assert_eq!( - base - tricky_delta, - NaiveDate::from_ymd_opt(2018, 3, 1).unwrap() - ); + assert_eq!(base - tricky_delta, NaiveDate::from_ymd(2018, 3, 1)); assert_eq!(base - tricky_delta, not_leap - tricky_delta); } diff --git a/src/rule.rs b/src/rule.rs index c17757b..f01e36b 100644 --- a/src/rule.rs +++ b/src/rule.rs @@ -3,7 +3,7 @@ use std::iter::Iterator; use super::delta::with_day; use super::relative_duration::RelativeDuration; -use chrono::{DateTime, Datelike, NaiveDate, NaiveDateTime, TimeZone}; +use chrono::{Date, DateTime, Datelike, NaiveDate, NaiveDateTime, TimeZone}; /// DateRule is an iterator for yielding evenly spaced dates /// according to a given RelativeDuration. It avoids some @@ -118,13 +118,13 @@ where /// ```rust /// # use chrono::NaiveDate; /// # use chronoutil::DateRule; - /// let start = NaiveDate::from_ymd_opt(2020, 2, 29).unwrap(); + /// let start = NaiveDate::from_ymd(2020, 2, 29); /// let mut rule = DateRule::monthly(start).with_rolling_day(31).unwrap(); /// - /// assert_eq!(rule.next().unwrap(), NaiveDate::from_ymd_opt(2020, 2, 29).unwrap()); - /// assert_eq!(rule.next().unwrap(), NaiveDate::from_ymd_opt(2020, 3, 31).unwrap()); - /// assert_eq!(rule.next().unwrap(), NaiveDate::from_ymd_opt(2020, 4, 30).unwrap()); - /// assert_eq!(rule.next().unwrap(), NaiveDate::from_ymd_opt(2020, 5, 31).unwrap()); + /// assert_eq!(rule.next().unwrap(), NaiveDate::from_ymd(2020, 2, 29)); + /// assert_eq!(rule.next().unwrap(), NaiveDate::from_ymd(2020, 3, 31)); + /// assert_eq!(rule.next().unwrap(), NaiveDate::from_ymd(2020, 4, 30)); + /// assert_eq!(rule.next().unwrap(), NaiveDate::from_ymd(2020, 5, 31)); /// // etc. /// ``` /// @@ -202,6 +202,35 @@ impl Iterator for DateRule { } } +impl Iterator for DateRule> +where + Tz: TimeZone, +{ + type Item = Date; + + fn next(&mut self) -> Option { + if self.count.is_some() && self._current_count >= self.count.unwrap() { + return None; + } + + let mut current_date = self.start.clone() + self.freq * self._current_count as i32; + if let Some(rolling_day) = self.rolling_day { + current_date = with_day(current_date, rolling_day).unwrap(); + } + + if let Some(end) = &self.end { + if (*end >= self.start && current_date >= *end) + || (*end < self.start && current_date <= *end) + { + return None; + } + } + + self._current_count += 1; + Some(current_date) + } +} + impl Iterator for DateRule> where Tz: TimeZone, @@ -239,7 +268,7 @@ mod tests { #[test] fn test_rrule_with_date() { - let start = NaiveDate::from_ymd_opt(2020, 1, 1).unwrap(); + let start = NaiveDate::from_ymd(2020, 1, 1); // Seconds, hours, minutes etc for (i, date) in DateRule::secondly(start) @@ -299,7 +328,7 @@ mod tests { "DateRule should finish before the count is up" ); - let finish = NaiveDate::from_ymd_opt(2020, 1, 29).unwrap(); + let finish = NaiveDate::from_ymd(2020, 1, 29); let weeks: Vec = DateRule::weekly(start).with_end(finish).collect(); assert_eq!(weeks[0], start, "DateRule should start at the initial day"); assert_eq!( @@ -314,7 +343,7 @@ mod tests { ); // Months, years - let interesting = NaiveDate::from_ymd_opt(2020, 1, 30).unwrap(); // The day will change each month + let interesting = NaiveDate::from_ymd(2020, 1, 30); // The day will change each month let months: Vec = DateRule::monthly(interesting).with_count(5).collect(); assert_eq!( @@ -323,12 +352,12 @@ mod tests { ); assert_eq!( months[1], - NaiveDate::from_ymd_opt(2020, 2, 29).unwrap(), + NaiveDate::from_ymd(2020, 2, 29), "DateRule should handle Feb" ); assert_eq!( months[2], - NaiveDate::from_ymd_opt(2020, 3, 30).unwrap(), + NaiveDate::from_ymd(2020, 3, 30), "DateRule should not loose days" ); assert_eq!( @@ -344,7 +373,7 @@ mod tests { ); assert_eq!( years[1], - NaiveDate::from_ymd_opt(2021, 1, 30).unwrap(), + NaiveDate::from_ymd(2021, 1, 30), "DateRule should increment in years" ); assert_eq!( @@ -357,8 +386,8 @@ mod tests { #[test] fn test_rrule_with_datetime() { // Seconds - let o_clock = NaiveTime::from_hms_opt(1, 2, 3).unwrap(); - let day = NaiveDate::from_ymd_opt(2020, 1, 1).unwrap(); + let o_clock = NaiveTime::from_hms(1, 2, 3); + let day = NaiveDate::from_ymd(2020, 1, 1); let start = NaiveDateTime::new(day, o_clock); let seconds_passed = 60 * 60 + 2 * 60 + 3; @@ -396,7 +425,7 @@ mod tests { } // Months - let interesting = NaiveDate::from_ymd_opt(2020, 1, 30).unwrap(); // The day will change each month + let interesting = NaiveDate::from_ymd(2020, 1, 30); // The day will change each month let istart = NaiveDateTime::new(interesting, o_clock); let months: Vec = DateRule::monthly(istart).with_count(5).collect(); @@ -406,13 +435,13 @@ mod tests { ); assert_eq!( months[1].date(), - NaiveDate::from_ymd_opt(2020, 2, 29).unwrap(), + NaiveDate::from_ymd(2020, 2, 29), "DateRule should handle Feb" ); assert_eq!(months[1].time(), o_clock, "Time should remain the same"); assert_eq!( months[2].date(), - NaiveDate::from_ymd_opt(2020, 3, 30).unwrap(), + NaiveDate::from_ymd(2020, 3, 30), "DateRule should not loose days" ); assert_eq!(months[2].time(), o_clock, "Time should remain the same"); @@ -420,7 +449,7 @@ mod tests { #[test] fn test_rrule_edge_cases() { - let start = NaiveDate::from_ymd_opt(2020, 1, 1).unwrap(); + let start = NaiveDate::from_ymd(2020, 1, 1); // Zero count let mut dates: Vec = DateRule::daily(start).with_count(0).collect(); @@ -439,15 +468,15 @@ mod tests { #[test] fn test_backwards_rrule() { - let start = NaiveDate::from_ymd_opt(2020, 3, 31).unwrap(); - let end = NaiveDate::from_ymd_opt(2019, 12, 31).unwrap(); + let start = NaiveDate::from_ymd(2020, 3, 31); + let end = NaiveDate::from_ymd(2019, 12, 31); let freq = RelativeDuration::months(-1); let dates1: Vec = DateRule::new(start, freq).with_count(3).collect(); assert_eq!(dates1.len(), 3); - assert_eq!(dates1[0], NaiveDate::from_ymd_opt(2020, 3, 31).unwrap()); - assert_eq!(dates1[1], NaiveDate::from_ymd_opt(2020, 2, 29).unwrap()); - assert_eq!(dates1[2], NaiveDate::from_ymd_opt(2020, 1, 31).unwrap()); + assert_eq!(dates1[0], NaiveDate::from_ymd(2020, 3, 31)); + assert_eq!(dates1[1], NaiveDate::from_ymd(2020, 2, 29)); + assert_eq!(dates1[2], NaiveDate::from_ymd(2020, 1, 31)); let dates2: Vec = DateRule::new(start, freq).with_end(end).collect(); @@ -461,7 +490,7 @@ mod tests { fn test_long_running_rules() { // Sanity tests for long-running shifts with various start months for month in &[1, 3, 5, 7, 8, 10, 12] { - let start = NaiveDate::from_ymd_opt(2020, *month as u32, 31).unwrap(); + let start = NaiveDate::from_ymd(2020, *month as u32, 31); let mut rule = DateRule::monthly(start); for _ in 0..120 {