llkv_executor/utils/
date.rs

1use llkv_result::{Error, Result as LlkvResult};
2use time::{Date, Month};
3
4/// Parse a string literal formatted as `YYYY-MM-DD` into the Arrow `Date32` day count.
5pub fn parse_date32_literal(text: &str) -> LlkvResult<i32> {
6    let mut parts = text.split('-');
7    let year_str = parts
8        .next()
9        .ok_or_else(|| Error::InvalidArgumentError(format!("invalid DATE literal '{text}'")))?;
10    let month_str = parts
11        .next()
12        .ok_or_else(|| Error::InvalidArgumentError(format!("invalid DATE literal '{text}'")))?;
13    let day_str = parts
14        .next()
15        .ok_or_else(|| Error::InvalidArgumentError(format!("invalid DATE literal '{text}'")))?;
16    if parts.next().is_some() {
17        return Err(Error::InvalidArgumentError(format!(
18            "invalid DATE literal '{text}'"
19        )));
20    }
21
22    let year = year_str.parse::<i32>().map_err(|_| {
23        Error::InvalidArgumentError(format!("invalid year in DATE literal '{text}'"))
24    })?;
25    let month_num = month_str.parse::<u8>().map_err(|_| {
26        Error::InvalidArgumentError(format!("invalid month in DATE literal '{text}'"))
27    })?;
28    let day = day_str.parse::<u8>().map_err(|_| {
29        Error::InvalidArgumentError(format!("invalid day in DATE literal '{text}'"))
30    })?;
31
32    let month = Month::try_from(month_num).map_err(|_| {
33        Error::InvalidArgumentError(format!("invalid month in DATE literal '{text}'"))
34    })?;
35
36    let date = Date::from_calendar_date(year, month, day).map_err(|err| {
37        Error::InvalidArgumentError(format!("invalid DATE literal '{text}': {err}"))
38    })?;
39    let days = date.to_julian_day() - epoch_julian_day();
40    Ok(days)
41}
42
43pub fn epoch_julian_day() -> i32 {
44    Date::from_calendar_date(1970, Month::January, 1)
45        .expect("1970-01-01 is a valid date")
46        .to_julian_day()
47}