reifydb_function/datetime/
age.rs1use reifydb_core::value::column::data::ColumnData;
5use reifydb_type::value::{container::temporal::TemporalContainer, date::Date, duration::Duration, r#type::Type};
6
7use crate::{ScalarFunction, ScalarFunctionContext, error::ScalarFunctionError, propagate_options};
8
9pub struct DateTimeAge;
10
11impl DateTimeAge {
12 pub fn new() -> Self {
13 Self
14 }
15}
16
17impl ScalarFunction for DateTimeAge {
18 fn scalar(&self, ctx: ScalarFunctionContext) -> crate::error::ScalarFunctionResult<ColumnData> {
19 if let Some(result) = propagate_options(self, &ctx) {
20 return result;
21 }
22 let columns = ctx.columns;
23 let row_count = ctx.row_count;
24
25 if columns.len() != 2 {
26 return Err(ScalarFunctionError::ArityMismatch {
27 function: ctx.fragment.clone(),
28 expected: 2,
29 actual: columns.len(),
30 });
31 }
32
33 let col1 = columns.get(0).unwrap();
34 let col2 = columns.get(1).unwrap();
35
36 match (col1.data(), col2.data()) {
37 (ColumnData::DateTime(container1), ColumnData::DateTime(container2)) => {
38 let mut container = TemporalContainer::with_capacity(row_count);
39
40 for i in 0..row_count {
41 match (container1.get(i), container2.get(i)) {
42 (Some(dt1), Some(dt2)) => {
43 let nanos1 = dt1.time().to_nanos_since_midnight() as i64;
45 let nanos2 = dt2.time().to_nanos_since_midnight() as i64;
46 let mut nanos_diff = nanos1 - nanos2;
47 let mut days_borrow: i32 = 0;
48
49 if nanos_diff < 0 {
50 days_borrow = 1;
51 nanos_diff += 86_400_000_000_000;
52 }
53
54 let date1 = dt1.date();
56 let date2 = dt2.date();
57
58 let y1 = date1.year();
59 let m1 = date1.month() as i32;
60 let day1 = date1.day() as i32;
61
62 let y2 = date2.year();
63 let m2 = date2.month() as i32;
64 let day2 = date2.day() as i32;
65
66 let mut years = y1 - y2;
67 let mut months = m1 - m2;
68 let mut days = day1 - day2 - days_borrow;
69
70 if days < 0 {
71 months -= 1;
72 let borrow_month = if m1 - 1 < 1 {
73 12
74 } else {
75 m1 - 1
76 };
77 let borrow_year = if m1 - 1 < 1 {
78 y1 - 1
79 } else {
80 y1
81 };
82 days += Date::days_in_month(
83 borrow_year,
84 borrow_month as u32,
85 ) as i32;
86 }
87
88 if months < 0 {
89 years -= 1;
90 months += 12;
91 }
92
93 let total_months = years * 12 + months;
94 container.push(Duration::new(total_months, days, nanos_diff));
95 }
96 _ => container.push_default(),
97 }
98 }
99
100 Ok(ColumnData::Duration(container))
101 }
102 (ColumnData::DateTime(_), other) => Err(ScalarFunctionError::InvalidArgumentType {
103 function: ctx.fragment.clone(),
104 argument_index: 1,
105 expected: vec![Type::DateTime],
106 actual: other.get_type(),
107 }),
108 (other, _) => Err(ScalarFunctionError::InvalidArgumentType {
109 function: ctx.fragment.clone(),
110 argument_index: 0,
111 expected: vec![Type::DateTime],
112 actual: other.get_type(),
113 }),
114 }
115 }
116
117 fn return_type(&self, _input_types: &[Type]) -> Type {
118 Type::Duration
119 }
120}