From 04e7e42608be0d49233b45047debb3989968aa83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rn=20Horstmann?= Date: Fri, 3 Nov 2023 16:23:53 +0100 Subject: [PATCH] The date_add_month kernels should keep the time portion unchanged --- CHANGELOG.md | 4 ++++ Cargo.lock | 2 +- Cargo.toml | 2 +- src/kernels.rs | 57 ++++++++++++++++++++++++++++++-------------------- 4 files changed, 40 insertions(+), 25 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 127436e..096c4d4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## [0.3.1](https://github.com/jhorstmann/packedtime-rs/tree/0.3.1) (2023-11-03) + + - The `date_add_month` kernels should leave the time part unchanged + ## [0.3.0](https://github.com/jhorstmann/packedtime-rs/tree/0.3.0) (2023-11-01) - Support calculating the difference between dates in units of years or months diff --git a/Cargo.lock b/Cargo.lock index a4f791c..e8bf6dc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -358,7 +358,7 @@ checksum = "a170cebd8021a008ea92e4db85a72f80b35df514ec664b296fdcbb654eac0b2c" [[package]] name = "packedtime-rs" -version = "0.3.0" +version = "0.3.1" dependencies = [ "chrono", "chronoutil", diff --git a/Cargo.toml b/Cargo.toml index 284f232..e6d32b5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ name = "packedtime-rs" description = "Utilities for efficiently storing, parsing, formatting and truncating timestamps" authors = ["Jörn Horstmann "] -version = "0.3.0" +version = "0.3.1" edition = "2021" repository = "https://github.com/jhorstmann/packedtime-rs" diff --git a/src/kernels.rs b/src/kernels.rs index b87d81d..f3c6a45 100644 --- a/src/kernels.rs +++ b/src/kernels.rs @@ -77,46 +77,57 @@ pub fn date_trunc_quarter_timestamp_millis_float(ts: f64) -> f64 { } #[inline] -pub fn date_add_month_timestamp_millis(ts: i64, months: i32) -> i64 { +pub fn date_part_year_timestamp_millis(ts: i64) -> i32 { let epoch_days = EpochDays::from_timestamp_millis(ts); - let new_epoch_days = epoch_days.add_months(months); - new_epoch_days.to_timestamp_millis() + epoch_days.extract_year() } #[inline] -pub fn date_add_month_timestamp_millis_float(ts: f64, months: i32) -> f64 { - let epoch_days = EpochDays::from_timestamp_millis_float(ts); - let new_epoch_days = epoch_days.add_months(months); - new_epoch_days.to_timestamp_millis_float() +pub fn date_part_month_timestamp_millis(ts: i64) -> i32 { + let epoch_days = EpochDays::from_timestamp_millis(ts); + epoch_days.extract_month() } #[inline] -pub fn date_part_year_timestamp_millis(ts: i64) -> i32 { - let epoch_days = EpochDays::from_timestamp_millis(ts); - epoch_days.extract_year() +fn timestamp_to_epoch_days_and_remainder(ts: i64) -> (EpochDays, i64) { + let (days, millis) = (ts.div_euclid(MILLIS_PER_DAY), ts.rem_euclid(MILLIS_PER_DAY)); + (EpochDays::new(days as i32), millis) } #[inline] -pub fn date_part_month_timestamp_millis(ts: i64) -> i32 { - let epoch_days = EpochDays::from_timestamp_millis(ts); - epoch_days.extract_month() +fn timestamp_to_epoch_days_and_remainder_float(ts: f64) -> (EpochDays, f64) { + let days = (ts * (1.0 / MILLIS_PER_DAY as f64)).floor(); + let millis = ts - days * (MILLIS_PER_DAY as f64); + (EpochDays::new(unsafe { days.to_int_unchecked() }), millis) +} + +#[inline] +pub fn date_add_month_timestamp_millis(ts: i64, months: i32) -> i64 { + let (epoch_days, millis) = timestamp_to_epoch_days_and_remainder(ts); + let new_epoch_days = epoch_days.add_months(months); + new_epoch_days.to_timestamp_millis() + millis +} + +#[inline] +pub fn date_add_month_timestamp_millis_float(ts: f64, months: i32) -> f64 { + let (epoch_days, millis) = timestamp_to_epoch_days_and_remainder_float(ts); + let new_epoch_days = epoch_days.add_months(months); + new_epoch_days.to_timestamp_millis_float() + millis } #[inline] fn timestamp_to_year_month_millis_of_month(ts: i64) -> (i32, i32, i64) { - let (days, millis) = (ts.div_euclid(MILLIS_PER_DAY), ts.rem_euclid(MILLIS_PER_DAY)); - let (year, month, d0) = EpochDays::new(days as i32).to_ymd(); - let millis_of_month = (d0 as i64)*MILLIS_PER_DAY + millis; + let (ed, millis) = timestamp_to_epoch_days_and_remainder(ts); + let (year, month, day) = ed.to_ymd(); + let millis_of_month = (day as i64)*MILLIS_PER_DAY + millis; (year, month, millis_of_month) } #[inline] fn timestamp_to_year_month_millis_of_month_float(ts: f64) -> (i32, i32, f64) { - let days = (ts * (1.0 / MILLIS_PER_DAY as f64)).floor(); - let epoch_days = EpochDays::new(unsafe { days.to_int_unchecked() }); - let millis = ts - days * (MILLIS_PER_DAY as f64); - let (year, month, d0) = epoch_days.to_ymd(); - let millis_of_month = (d0 as f64)*(MILLIS_PER_DAY as f64) + millis; + let (ed, millis) = timestamp_to_epoch_days_and_remainder_float(ts); + let (year, month, day) = ed.to_ymd(); + let millis_of_month = (day as f64)*(MILLIS_PER_DAY as f64) + millis; (year, month, millis_of_month) } @@ -265,11 +276,11 @@ mod tests { fn test_date_add_months_timestamp_millis() { assert_eq!( date_add_month_timestamp_millis(1661102969_000, 1), - 1663718400_000 + 1663781369000 ); assert_eq!( date_add_month_timestamp_millis(1661102969_000, 12), - 1692576000_000 + 1692638969000 ); }