use crate::{
evaluation::evaluator_value::EvaluatorValueRef, specs_response::spec_types::ConditionOperator,
unwrap_or_return, user::user_value::UserValueRef,
};
use chrono::Duration;
pub(crate) fn compare_time<'a>(
left: UserValueRef<'_>,
right: impl Into<EvaluatorValueRef<'a>>,
op: ConditionOperator,
) -> bool {
let right = right.into();
let raw_left_ts = unwrap_or_return!(left.timestamp_value().or(left.int_value()), false);
let left_ts = to_millis(raw_left_ts);
let right_ts = unwrap_or_return!(
right
.timestamp_value()
.or_else(|| right.float_value().map(|x| x as i64)),
false
);
match op {
ConditionOperator::Before => left_ts < right_ts,
ConditionOperator::After => left_ts > right_ts,
ConditionOperator::On => {
Duration::milliseconds(left_ts).num_days()
== Duration::milliseconds(right_ts).num_days()
}
_ => false,
}
}
fn to_millis(ts: i64) -> i64 {
let digits = ts.abs();
if digits < 10_000_000_000 {
ts.saturating_mul(1000)
} else {
ts
}
}
#[cfg(test)]
mod tests {
use crate::evaluation::comparisons::compare_time;
use crate::specs_response::spec_types::ConditionOperator;
use crate::user::user_value::UserValue;
use crate::{dyn_value, test_only_make_eval_value, DynamicValue};
use chrono::Utc;
fn create_str_value(s: &str) -> DynamicValue {
dyn_value!(s.to_string())
}
#[test]
fn test_compare_before() {
let now = Utc::now().timestamp_millis();
let left = DynamicValue::for_timestamp_evaluation(now);
let right = test_only_make_eval_value!(now + 1);
assert!(compare_time(
(&left).into(),
&right,
ConditionOperator::Before
));
}
#[test]
fn test_compare_after() {
let now = Utc::now().timestamp_millis();
let left = DynamicValue::for_timestamp_evaluation(now + 1);
let right = test_only_make_eval_value!(now);
assert!(compare_time(
(&left).into(),
&right,
ConditionOperator::After
));
}
#[test]
fn test_rfc3339_format() {
let test_eval_value = test_only_make_eval_value!("2023-01-02T00:00:00Z");
assert!(compare_time(
(&create_str_value("2023-01-01T00:00:00Z")).into(),
&test_eval_value,
ConditionOperator::Before
));
}
#[test]
fn test_custom_datetime_format() {
let test_eval_value = test_only_make_eval_value!("2023-01-02 00:00:00");
assert!(compare_time(
(&create_str_value("2023-01-01 00:00:00")).into(),
&test_eval_value,
ConditionOperator::Before
));
}
#[test]
fn test_date_only_format() {
let test_eval_value = test_only_make_eval_value!("2023-01-02");
assert!(compare_time(
(&create_str_value("2023-01-01")).into(),
&test_eval_value,
ConditionOperator::Before
));
}
#[test]
fn test_date_only_user_value_before_epoch_millis() {
let test_eval_value = test_only_make_eval_value!(1780286400000_i64); let left = UserValue::from_string("2026-05-30");
assert!(compare_time(
(&left).into(),
&test_eval_value,
ConditionOperator::Before
));
}
#[test]
fn test_iso_format_no_separator() {
let test_eval_value = test_only_make_eval_value!("2023-01-02 00:00:00Z");
assert!(compare_time(
(&create_str_value("2023-01-01 00:00:00Z")).into(),
&test_eval_value,
ConditionOperator::Before
));
}
#[test]
fn test_timestamp_string() {
let test_eval_value = test_only_make_eval_value!("1672617600000");
assert!(compare_time(
(&create_str_value("1672531200000")).into(), &test_eval_value, ConditionOperator::Before
));
}
#[test]
fn test_mixed_formats() {
let test_eval_value = test_only_make_eval_value!(1672617600000_i64);
assert!(compare_time(
(&create_str_value("2023-01-01T00:00:00Z")).into(),
&test_eval_value, ConditionOperator::Before
));
}
#[test]
fn test_invalid_input() {
let test_eval_value = test_only_make_eval_value!(1672617600000_i64);
assert!(!compare_time(
(&create_str_value("invalid-date")).into(),
&test_eval_value,
ConditionOperator::Before
));
}
}