use crate::{
Dt, MAX_YEAR, MIN_YEAR, Mode, NS_PER_DAY, PLAUSIBLE_YYYYMM_YEAR_RANGE, parse_jd, parse_mjd,
parse_yyddd, parse_yymmdd, parse_yyyyjjj, parse_yyyymm,
};
#[inline]
pub(crate) fn parse_i32_year(input: &str) -> Option<Dt> {
let year: i32 = input.parse().ok()?;
if !(MIN_YEAR..=MAX_YEAR).contains(&year) {
return None;
}
Some(Dt::from_ymd(year as i64, 1, 1))
}
#[inline]
pub(crate) fn parse_two_digit_year(input: &str) -> Option<Dt> {
let y: i32 = input.parse().ok()?;
let year = if y <= 68 { 2000 + y } else { 1900 + y };
if !(MIN_YEAR..=MAX_YEAR).contains(&year) {
return None;
}
Some(Dt::from_ymd(year as i64, 1, 1))
}
#[inline]
pub(crate) fn frac_to_nanos(frac_part: &str) -> Option<i128> {
if frac_part.is_empty() {
return Some(0);
}
let digits = frac_part.len().min(9);
let frac_int: i128 = frac_part[..digits].parse().ok()?;
let scale = 10i128.pow(digits as u32);
let mut result = (frac_int * NS_PER_DAY) / scale;
let rem = (frac_int * NS_PER_DAY) % scale;
if rem * 2 >= scale {
result += 1;
}
Some(result)
}
pub(crate) fn try_pure_numeric(
input: &str,
total_digits: u8,
integer_digits: u8,
is_decimal: bool,
mode: Mode,
) -> Option<Dt> {
if (1..=4).contains(&total_digits) {
return match mode {
Mode::Scientific => parse_i32_year(input),
_ => {
match total_digits {
2 => parse_two_digit_year(input),
4 => parse_i32_year(input),
_ => None, }
}
};
}
if total_digits == 5 || (is_decimal && integer_digits == 5) {
return match mode {
Mode::Legacy => parse_yyddd(input),
Mode::Scientific => parse_mjd(input).or_else(|| parse_yyddd(input)),
Mode::Auto => {
if is_decimal {
parse_mjd(input).or_else(|| parse_yyddd(input))
} else {
parse_yyddd(input).or_else(|| parse_mjd(input))
}
}
_ => None,
};
}
if total_digits == 6 {
return match mode {
Mode::Legacy => parse_yymmdd(input).or_else(|| parse_yyyymm(input)),
Mode::Scientific => parse_yyyymm(input).or_else(|| parse_yymmdd(input)),
Mode::Auto => {
let year_start = if input.starts_with('-') { 1 } else { 0 };
let year: i32 = input[year_start..year_start + 4].parse().unwrap_or(0);
if PLAUSIBLE_YYYYMM_YEAR_RANGE.contains(&year) {
parse_yyyymm(input).or_else(|| parse_yymmdd(input))
} else {
parse_yymmdd(input).or_else(|| parse_yyyymm(input))
}
}
_ => None,
};
}
if integer_digits == 7 {
return match mode {
Mode::Legacy => parse_yyyyjjj(input),
Mode::Scientific => parse_jd(input, !is_decimal).or_else(|| parse_yyyyjjj(input)),
Mode::Auto => {
if is_decimal {
parse_jd(input, false)
} else {
parse_yyyyjjj(input).or_else(|| parse_jd(input, true))
}
}
_ => None,
};
}
None
}