Skip to content

Commit

Permalink
refactor: sort the date and time related funcs
Browse files Browse the repository at this point in the history
  • Loading branch information
chagelo committed Oct 2, 2024
1 parent 5d67b7b commit 4517302
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 105 deletions.
87 changes: 67 additions & 20 deletions src/query/expression/src/utils/date_helper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use std::sync::LazyLock;

use chrono::DateTime;
use chrono::Datelike;
use chrono::Days;
use chrono::Duration;
use chrono::LocalResult;
use chrono::NaiveDate;
Expand Down Expand Up @@ -273,7 +274,7 @@ pub const FACTOR_MINUTE: i64 = 60;
pub const FACTOR_SECOND: i64 = 1;
const LAST_DAY_LUT: [u8; 13] = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];

fn add_years_base(
fn eval_years_base(
year: i32,
month: u32,
day: u32,
Expand All @@ -288,7 +289,7 @@ fn add_years_base(
.ok_or_else(|| format!("Overflow on date YMD {}-{}-{}.", new_year, month, new_day))
}

fn add_months_base(
fn eval_months_base(
year: i32,
month: u32,
day: u32,
Expand Down Expand Up @@ -364,32 +365,32 @@ macro_rules! impl_interval_year_month {
};
}

impl_interval_year_month!(AddYearsImpl, add_years_base);
impl_interval_year_month!(AddMonthsImpl, add_months_base);
impl_interval_year_month!(EvalYearsImpl, eval_years_base);
impl_interval_year_month!(EvalMonthsImpl, eval_months_base);

impl AddYearsImpl {
impl EvalYearsImpl {
pub fn eval_date_diff(date_start: i32, date_end: i32, tz: TzLUT) -> i32 {
AddMonthsImpl::eval_date_diff(date_start, date_end, tz) / 12
EvalMonthsImpl::eval_date_diff(date_start, date_end, tz) / 12
}

pub fn eval_timestamp_diff(date_start: i64, date_end: i64, tz: TzLUT) -> i64 {
AddMonthsImpl::eval_timestamp_diff(date_start, date_end, tz) / 12
EvalMonthsImpl::eval_timestamp_diff(date_start, date_end, tz) / 12
}
}

pub struct AddQuartersImpl;
pub struct EvalQuartersImpl;

impl AddQuartersImpl {
impl EvalQuartersImpl {
pub fn eval_date_diff(date_start: i32, date_end: i32, tz: TzLUT) -> i32 {
AddMonthsImpl::eval_date_diff(date_start, date_end, tz) / 3
EvalMonthsImpl::eval_date_diff(date_start, date_end, tz) / 3
}

pub fn eval_timestamp_diff(date_start: i64, date_end: i64, tz: TzLUT) -> i64 {
AddMonthsImpl::eval_timestamp_diff(date_start, date_end, tz) / 3
EvalMonthsImpl::eval_timestamp_diff(date_start, date_end, tz) / 3
}
}

impl AddMonthsImpl {
impl EvalMonthsImpl {
pub fn eval_date_diff(date_start: i32, date_end: i32, tz: TzLUT) -> i32 {
let date_start = date_start.to_date(tz.tz);
let date_end = date_end.to_date(tz.tz);
Expand All @@ -415,27 +416,73 @@ impl AddMonthsImpl {
let (date_end_days, date_end_micros) =
(date_end / SECONDS_PER_DAY, date_end % SECONDS_PER_DAY);
let mut diff_months =
AddMonthsImpl::eval_date_diff(date_start_days as i32, date_end_days as i32, tz) as i64;
EvalMonthsImpl::eval_date_diff(date_start_days as i32, date_end_days as i32, tz) as i64;
diff_months -= (date_start_micros > date_end_micros) as i64;
diff_months
}

// current we don't consider tz here
pub fn months_between_ts(ts_a: i64, ts_b: i64) -> f64 {
EvalMonthsImpl::months_between(
(ts_a / 86_400_000_000) as i32,
(ts_b / 86_400_000_000) as i32,
)
}

pub fn months_between(date_a: i32, date_b: i32) -> f64 {
let date_a = Utc
.timestamp_opt((date_a as i64) * 86400, 0)
.unwrap()
.date_naive(); // Assuming date_a is in days
let date_b = Utc
.timestamp_opt((date_b as i64) * 86400, 0)
.unwrap()
.date_naive(); // Assuming date_b is in days

let year_diff = date_a.year() - date_b.year();
let month_diff = date_a.month() as i32 - date_b.month() as i32;

// Calculate total months difference
let total_months_diff = year_diff * 12 + month_diff;

// Determine if special case for fractional part applies
let is_same_day_of_month = date_a.day() == date_b.day();
let are_both_end_of_month = date_a
.checked_add_days(Days::new(1))
.map(|d| d.month() != date_a.month())
.unwrap_or(false)
&& date_b
.checked_add_days(Days::new(1))
.map(|d| d.month() != date_b.month())
.unwrap_or(false);

let day_fraction = if is_same_day_of_month || are_both_end_of_month {
0.0
} else {
let day_diff = date_a.day() as i32 - date_b.day() as i32;
day_diff as f64 / 31.0 // Using 31-day month for fractional part
};

// Total difference including fractional part
total_months_diff as f64 + day_fraction
}
}

pub struct AddWeeksImpl;
pub struct EvalWeeksImpl;

impl AddWeeksImpl {
impl EvalWeeksImpl {
pub fn eval_date_diff(date_start: i32, date_end: i32) -> i32 {
(date_end - date_start) / 7
}

pub fn eval_timestamp_diff(date_start: i64, date_end: i64) -> i64 {
AddDaysImpl::eval_timestamp_diff(date_start, date_end) / 7
EvalDaysImpl::eval_timestamp_diff(date_start, date_end) / 7
}
}

pub struct AddDaysImpl;
pub struct EvalDaysImpl;

impl AddDaysImpl {
impl EvalDaysImpl {
pub fn eval_date(date: i32, delta: impl AsPrimitive<i64>) -> std::result::Result<i32, String> {
check_date((date as i64).wrapping_add(delta.as_()))
}
Expand All @@ -456,9 +503,9 @@ impl AddDaysImpl {
}
}

pub struct AddTimesImpl;
pub struct EvalTimesImpl;

impl AddTimesImpl {
impl EvalTimesImpl {
pub fn eval_date(
date: i32,
delta: impl AsPrimitive<i64>,
Expand Down
Loading

0 comments on commit 4517302

Please sign in to comment.