#![allow(
clippy::unnecessary_wraps,
reason = "every getter has an overload's signature, which can fail"
)]
use super::Functions;
use super::overload::text;
use super::time::{self, DAY, NANOS};
use super::value::Value;
use icu::calendar::{Date, Iso};
struct Local {
date: Date<Iso>,
second: i64,
nanos: i128,
}
fn local(render: &dyn Functions, args: &[Value]) -> Result<Local, String> {
let nanos = match args.first() {
Some(Value::Timestamp(t)) => *t,
_ => 0,
};
let zone = (args.len() > 1).then(|| text(args, 1));
let seconds = i64::try_from(nanos.div_euclid(NANOS)).unwrap_or_default();
let local = seconds + i64::from(render.offset(zone, seconds)?);
Ok(Local {
date: time::date(local.div_euclid(DAY)),
second: local.rem_euclid(DAY),
nanos: nanos.rem_euclid(NANOS),
})
}
fn int(n: impl Into<i64>) -> Result<Value, String> {
Ok(Value::Int(n.into()))
}
pub(crate) fn full_year(render: &dyn Functions, args: &[Value]) -> Result<Value, String> {
int(local(render, args)?.date.year().extended_year())
}
pub(crate) fn month(render: &dyn Functions, args: &[Value]) -> Result<Value, String> {
int(local(render, args)?.date.month().ordinal - 1)
}
pub(crate) fn date(render: &dyn Functions, args: &[Value]) -> Result<Value, String> {
int(local(render, args)?.date.day_of_month().0)
}
pub(crate) fn day_of_month(render: &dyn Functions, args: &[Value]) -> Result<Value, String> {
int(local(render, args)?.date.day_of_month().0 - 1)
}
pub(crate) fn day_of_week(render: &dyn Functions, args: &[Value]) -> Result<Value, String> {
int(local(render, args)?.date.weekday() as u8 % 7)
}
pub(crate) fn day_of_year(render: &dyn Functions, args: &[Value]) -> Result<Value, String> {
int(local(render, args)?.date.day_of_year().0 - 1)
}
pub(crate) fn hours(render: &dyn Functions, args: &[Value]) -> Result<Value, String> {
int(local(render, args)?.second / 3600)
}
pub(crate) fn minutes(render: &dyn Functions, args: &[Value]) -> Result<Value, String> {
int(local(render, args)?.second / 60 % 60)
}
pub(crate) fn seconds(render: &dyn Functions, args: &[Value]) -> Result<Value, String> {
int(local(render, args)?.second % 60)
}
pub(crate) fn milliseconds(render: &dyn Functions, args: &[Value]) -> Result<Value, String> {
int(i64::try_from(local(render, args)?.nanos / 1_000_000).unwrap_or_default())
}
fn duration_in(args: &[Value], unit: i128) -> Result<Value, String> {
let nanos = match args.first() {
Some(Value::Duration(d)) => *d,
_ => 0,
};
int(i64::try_from(nanos / unit).unwrap_or_default())
}
pub(crate) fn duration_hours(_: &dyn Functions, args: &[Value]) -> Result<Value, String> {
duration_in(args, 3600 * NANOS)
}
pub(crate) fn duration_minutes(_: &dyn Functions, args: &[Value]) -> Result<Value, String> {
duration_in(args, 60 * NANOS)
}
pub(crate) fn duration_seconds(_: &dyn Functions, args: &[Value]) -> Result<Value, String> {
duration_in(args, NANOS)
}
pub(crate) fn duration_milliseconds(_: &dyn Functions, args: &[Value]) -> Result<Value, String> {
duration_in(args, NANOS / 1000)
}