use std::any::Any;
use chrono::{DateTime, FixedOffset, NaiveDate, NaiveDateTime, NaiveTime, Timelike, Utc};
use chrono_tz::Tz;
use crate::expression::TemplateObject;
use crate::util::Utf16String;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum TemporalKind {
Instant,
LocalDate,
LocalDateTime,
LocalTime,
OffsetDateTime,
OffsetTime,
Year,
YearMonth,
ZonedDateTime,
}
#[derive(Clone, Debug)]
pub enum TemporalValue {
Instant(DateTime<Utc>),
LocalDate(NaiveDate),
LocalDateTime(NaiveDateTime),
LocalTime(NaiveTime),
OffsetDateTime(DateTime<FixedOffset>),
OffsetTime(NaiveTime, FixedOffset),
Year(i32),
YearMonth(i32, u32),
ZonedDateTime(DateTime<Tz>),
}
impl TemporalValue {
#[must_use]
pub const fn kind(&self) -> TemporalKind {
match self {
Self::Instant(_) => TemporalKind::Instant,
Self::LocalDate(_) => TemporalKind::LocalDate,
Self::LocalDateTime(_) => TemporalKind::LocalDateTime,
Self::LocalTime(_) => TemporalKind::LocalTime,
Self::OffsetDateTime(_) => TemporalKind::OffsetDateTime,
Self::OffsetTime(_, _) => TemporalKind::OffsetTime,
Self::Year(_) => TemporalKind::Year,
Self::YearMonth(_, _) => TemporalKind::YearMonth,
Self::ZonedDateTime(_) => TemporalKind::ZonedDateTime,
}
}
#[must_use]
pub fn to_javascript_iso_string(&self) -> Utf16String {
Utf16String::from_rust_str(&match self {
Self::LocalDateTime(value) => value.format("%Y-%m-%dT%H:%M:%S%.f").to_string(),
_ => self.to_utf16_string().to_string_lossy(),
})
}
}
impl TemplateObject for TemporalValue {
fn class_name(&self) -> &str {
match self {
Self::Instant(_) => "java.time.Instant",
Self::LocalDate(_) => "java.time.LocalDate",
Self::LocalDateTime(_) => "java.time.LocalDateTime",
Self::LocalTime(_) => "java.time.LocalTime",
Self::OffsetDateTime(_) => "java.time.OffsetDateTime",
Self::OffsetTime(_, _) => "java.time.OffsetTime",
Self::Year(_) => "java.time.Year",
Self::YearMonth(_, _) => "java.time.YearMonth",
Self::ZonedDateTime(_) => "java.time.ZonedDateTime",
}
}
fn to_utf16_string(&self) -> Utf16String {
Utf16String::from_rust_str(&match self {
Self::Instant(value) => value.to_rfc3339_opts(chrono::SecondsFormat::AutoSi, true),
Self::LocalDate(value) => value.format("%Y-%m-%d").to_string(),
Self::LocalDateTime(value) if value.second() == 0 && value.nanosecond() == 0 => {
value.format("%Y-%m-%dT%H:%M").to_string()
}
Self::LocalDateTime(value) => value.format("%Y-%m-%dT%H:%M:%S%.f").to_string(),
Self::LocalTime(value) => value.format("%H:%M:%S%.f").to_string(),
Self::OffsetDateTime(value) => {
value.to_rfc3339_opts(chrono::SecondsFormat::AutoSi, false)
}
Self::OffsetTime(value, offset) => {
format!("{}{}", value.format("%H:%M:%S%.f"), offset)
}
Self::Year(value) => value.to_string(),
Self::YearMonth(year, month) => format!("{year:04}-{month:02}"),
Self::ZonedDateTime(value) => {
format!(
"{}[{}]",
value.to_rfc3339_opts(chrono::SecondsFormat::AutoSi, false),
value.timezone()
)
}
})
}
fn as_any(&self) -> &dyn Any {
self
}
}