From 74d7614eff66f6028489572e1609f3587797b7b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rn=20Horstmann?= Date: Tue, 31 Oct 2023 09:24:53 +0100 Subject: [PATCH] Implement diff_years kernels --- benches/bench_date_add.rs | 45 +++++++++++++++++++++++++++++++++++---- src/epoch_days.rs | 45 +++++++++++++++++++++++++++++++++++++++ src/kernels.rs | 35 +++++++++++++++++++++++++----- 3 files changed, 116 insertions(+), 9 deletions(-) diff --git a/benches/bench_date_add.rs b/benches/bench_date_add.rs index 4167e04..5923878 100644 --- a/benches/bench_date_add.rs +++ b/benches/bench_date_add.rs @@ -2,7 +2,11 @@ use chrono::NaiveDateTime; use chronoutil::shift_months; use criterion::{criterion_group, criterion_main, Criterion, Throughput}; -use packedtime_rs::{date_add_month_timestamp_millis, date_add_month_timestamp_millis_float, date_diff_month_timestamp_millis, date_diff_month_timestamp_millis_float}; +use packedtime_rs::{ + date_add_month_timestamp_millis, date_add_month_timestamp_millis_float, + date_diff_month_timestamp_millis, date_diff_month_timestamp_millis_float, + date_diff_year_timestamp_millis, date_diff_year_timestamp_millis_float, +}; use rand::rngs::StdRng; use rand::{Rng, SeedableRng}; @@ -52,7 +56,29 @@ fn bench_date_diff_month_float(start: &[f64], end: &[f64], output: &mut [i32]) { }); } +#[inline(never)] +fn bench_date_diff_year(start: &[i64], end: &[i64], output: &mut [i32]) { + assert_eq!(start.len(), end.len()); + assert_eq!(start.len(), output.len()); + output + .iter_mut() + .zip(start.iter().copied().zip(end.iter().copied())) + .for_each(|(output, (start, end))| { + *output = date_diff_year_timestamp_millis(start, end); + }); +} +#[inline(never)] +fn bench_date_diff_year_float(start: &[f64], end: &[f64], output: &mut [i32]) { + assert_eq!(start.len(), end.len()); + assert_eq!(start.len(), output.len()); + output + .iter_mut() + .zip(start.iter().copied().zip(end.iter().copied())) + .for_each(|(output, (start, end))| { + *output = date_diff_year_timestamp_millis_float(start, end); + }); +} #[inline(never)] fn bench_date_add_month_chronoutil(input: &[i64], output: &mut [i64], months: i32) { @@ -109,16 +135,27 @@ pub fn bench_date_add(c: &mut Criterion) { c.benchmark_group("date_diff_month") .throughput(Throughput::Bytes( - (BATCH_SIZE * 2 * std::mem::size_of::() + BATCH_SIZE*std::mem::size_of::()) as u64, + (BATCH_SIZE * 2 * std::mem::size_of::() + BATCH_SIZE * std::mem::size_of::()) + as u64, )) .bench_function("date_diff_month", |b| { b.iter(|| bench_date_diff_month(&input, &input2, &mut output_diff)) }) .bench_function("date_diff_month_float", |b| { b.iter(|| bench_date_diff_month_float(&input_float, &input_float2, &mut output_diff)) - }) - ; + }); + c.benchmark_group("date_diff_year") + .throughput(Throughput::Bytes( + (BATCH_SIZE * 2 * std::mem::size_of::() + BATCH_SIZE * std::mem::size_of::()) + as u64, + )) + .bench_function("date_diff_year", |b| { + b.iter(|| bench_date_diff_year(&input, &input2, &mut output_diff)) + }) + .bench_function("date_diff_year_float", |b| { + b.iter(|| bench_date_diff_year_float(&input_float, &input_float2, &mut output_diff)) + }); } criterion_group!(benches, bench_date_add); diff --git a/src/epoch_days.rs b/src/epoch_days.rs index d29384a..88b285f 100644 --- a/src/epoch_days.rs +++ b/src/epoch_days.rs @@ -205,6 +205,15 @@ impl EpochDays { (y1 * 12 + m1) - (y0 * 12 + m0) - (d1 < d0) as i32 } + #[inline] + pub fn diff_years(&self, other: EpochDays) -> i32 { + let (y0, m0, d0) = self.to_ymd(); + let (y1, m1, d1) = other.to_ymd(); + + // y1 - y0 - ((m1 < m0) | ((m1 == m0) & (d1 < d0))) as i32 + y1 - y0 - ((m1, d1) < (m0, d0)) as i32 + } + #[inline] pub fn date_trunc_month(&self) -> Self { let (y, m, d) = self.to_ymd(); @@ -332,6 +341,42 @@ mod tests { ); } + #[test] + fn test_date_diff_year_epoch_days() { + assert_eq!( + EpochDays::from_ymd(2023, 10, 1).diff_years(EpochDays::from_ymd(2023, 10, 1)), + 0 + ); + assert_eq!( + EpochDays::from_ymd(2023, 10, 1).diff_years(EpochDays::from_ymd(2023, 11, 1)), + 0 + ); + assert_eq!( + EpochDays::from_ymd(2023, 1, 1).diff_years(EpochDays::from_ymd(2024, 1, 1)), + 1 + ); + assert_eq!( + EpochDays::from_ymd(2023, 2, 28).diff_years(EpochDays::from_ymd(2024, 2, 28)), + 1 + ); + assert_eq!( + EpochDays::from_ymd(2023, 2, 28).diff_years(EpochDays::from_ymd(2024, 2, 29)), + 1 + ); + assert_eq!( + EpochDays::from_ymd(2023, 6, 15).diff_years(EpochDays::from_ymd(2024, 6, 14)), + 0 + ); + assert_eq!( + EpochDays::from_ymd(2023, 6, 15).diff_years(EpochDays::from_ymd(2025, 6, 14)), + 1 + ); + assert_eq!( + EpochDays::from_ymd(2023, 6, 15).diff_years(EpochDays::from_ymd(2025, 6, 16)), + 2 + ); + } + #[test] fn test_extract_year() { assert_eq!(2022, EpochDays::from_ymd(2022, 1, 1).extract_year()); diff --git a/src/kernels.rs b/src/kernels.rs index 162a9ea..b87d81d 100644 --- a/src/kernels.rs +++ b/src/kernels.rs @@ -134,13 +134,24 @@ pub fn date_diff_month_timestamp_millis_float(t0: f64, t1: f64) -> i32 { (y1*12 + m1) - (y0*12 + m0) - ((ms1 < ms0) as i32) } +#[inline] +pub fn date_diff_year_timestamp_millis(t0: i64, t1: i64) -> i32 { + let (y0, m0, ms0) = timestamp_to_year_month_millis_of_month(t0); + let (y1, m1, ms1) = timestamp_to_year_month_millis_of_month(t1); + y1 - y0 - (((m1, ms1) < (m0, ms0)) as i32) +} + +#[inline] +pub fn date_diff_year_timestamp_millis_float(t0: f64, t1: f64) -> i32 { + let (y0, m0, ms0) = timestamp_to_year_month_millis_of_month_float(t0); + let (y1, m1, ms1) = timestamp_to_year_month_millis_of_month_float(t1); + y1 - y0 - (((m1, ms1) < (m0, ms0)) as i32) +} + #[cfg(test)] mod tests { use crate::epoch_days::EpochDays; - use crate::{ - date_add_month_timestamp_millis, date_trunc_month_timestamp_millis, - date_trunc_quarter_timestamp_millis, date_trunc_year_timestamp_millis, - }; + use crate::{date_add_month_timestamp_millis, date_diff_month_timestamp_millis, date_diff_year_timestamp_millis, date_trunc_month_timestamp_millis, date_trunc_quarter_timestamp_millis, date_trunc_year_timestamp_millis}; use chrono::{Datelike, NaiveDate, NaiveDateTime, NaiveTime}; use std::ops::Add; @@ -264,8 +275,22 @@ mod tests { #[test] fn test_date_diff_months() { - // assert_eq!(epoch_day.add_months(-1), EpochDays::from_ymd(2022, 6, 30)); + assert_eq!(date_diff_month_timestamp_millis(EpochDays::from_ymd(2023, 10, 1).to_timestamp_millis(), EpochDays::from_ymd(2023, 10, 1).to_timestamp_millis()), 0); + assert_eq!(date_diff_month_timestamp_millis(EpochDays::from_ymd(2023, 10, 1).to_timestamp_millis(), EpochDays::from_ymd(2023, 11, 1).to_timestamp_millis()), 1); + assert_eq!(date_diff_month_timestamp_millis(EpochDays::from_ymd(2023, 10, 15).to_timestamp_millis(), EpochDays::from_ymd(2023, 11, 14).to_timestamp_millis()), 0); + assert_eq!(date_diff_month_timestamp_millis(EpochDays::from_ymd(2023, 10, 15).to_timestamp_millis(), EpochDays::from_ymd(2023, 11, 15).to_timestamp_millis()), 1); + assert_eq!(date_diff_month_timestamp_millis(EpochDays::from_ymd(2023, 10, 15).to_timestamp_millis(), EpochDays::from_ymd(2023, 11, 16).to_timestamp_millis()), 1); + } + #[test] + fn test_date_diff_years() { + assert_eq!(date_diff_year_timestamp_millis(EpochDays::from_ymd(2023, 10, 1).to_timestamp_millis(), EpochDays::from_ymd(2023, 10, 1).to_timestamp_millis()), 0); + assert_eq!(date_diff_year_timestamp_millis(EpochDays::from_ymd(2023, 10, 1).to_timestamp_millis(), EpochDays::from_ymd(2023, 11, 1).to_timestamp_millis()), 0); + assert_eq!(date_diff_year_timestamp_millis(EpochDays::from_ymd(2023, 10, 15).to_timestamp_millis(), EpochDays::from_ymd(2024, 10, 14).to_timestamp_millis()), 0); + assert_eq!(date_diff_year_timestamp_millis(EpochDays::from_ymd(2023, 10, 15).to_timestamp_millis(), EpochDays::from_ymd(2024, 10, 15).to_timestamp_millis()), 1); + assert_eq!(date_diff_year_timestamp_millis(EpochDays::from_ymd(2023, 10, 15).to_timestamp_millis(), EpochDays::from_ymd(2024, 10, 16).to_timestamp_millis()), 1); + assert_eq!(date_diff_year_timestamp_millis(EpochDays::from_ymd(2024, 2, 29).to_timestamp_millis(), EpochDays::from_ymd(2025, 2, 28).to_timestamp_millis()), 0); + assert_eq!(date_diff_year_timestamp_millis(EpochDays::from_ymd(2024, 2, 29).to_timestamp_millis(), EpochDays::from_ymd(2025, 3, 1).to_timestamp_millis()), 1); } #[test]