mod calendar;
mod duration;
mod error;
mod instant;
mod now;
mod options;
mod plain_date;
mod plain_date_time;
mod plain_month_day;
mod plain_time;
mod plain_year_month;
mod zoneddatetime;
#[cfg(test)]
mod tests;
pub use self::{
duration::*, instant::*, now::*, plain_date::*, plain_date_time::*, plain_month_day::*,
plain_time::*, plain_year_month::*, zoneddatetime::*,
};
use crate::{
Context, JsNativeError, JsObject, JsResult, JsString, JsSymbol, JsValue,
builtins::{
BuiltInBuilder, BuiltInObject, IntrinsicObject,
temporal::calendar::get_temporal_calendar_slot_value_with_default,
},
context::intrinsics::Intrinsics,
js_string,
property::Attribute,
realm::Realm,
string::StaticJsStrings,
};
use temporal_rs::{
PlainDate as TemporalDate, ZonedDateTime as TemporalZonedDateTime,
partial::PartialZonedDateTime, primitive::FiniteF64,
};
use temporal_rs::{options::RelativeTo, partial::PartialDate};
pub(crate) enum DateTimeValues {
Year,
Month,
MonthCode,
Week,
Day,
Hour,
Minute,
Second,
Millisecond,
Microsecond,
Nanosecond,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub(crate) struct Temporal;
impl BuiltInObject for Temporal {
const NAME: JsString = StaticJsStrings::TEMPORAL;
}
impl IntrinsicObject for Temporal {
fn init(realm: &Realm) {
BuiltInBuilder::with_intrinsic::<Self>(realm)
.static_property(
JsSymbol::to_string_tag(),
Self::NAME,
Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
)
.static_property(
js_string!("Now"),
realm.intrinsics().objects().now(),
Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
)
.static_property(
js_string!("Duration"),
realm.intrinsics().constructors().duration().constructor(),
Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
)
.static_property(
js_string!("Instant"),
realm.intrinsics().constructors().instant().constructor(),
Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
)
.static_property(
js_string!("PlainDate"),
realm.intrinsics().constructors().plain_date().constructor(),
Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
)
.static_property(
js_string!("PlainDateTime"),
realm
.intrinsics()
.constructors()
.plain_date_time()
.constructor(),
Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
)
.static_property(
js_string!("PlainMonthDay"),
realm
.intrinsics()
.constructors()
.plain_month_day()
.constructor(),
Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
)
.static_property(
js_string!("PlainTime"),
realm.intrinsics().constructors().plain_time().constructor(),
Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
)
.static_property(
js_string!("PlainYearMonth"),
realm
.intrinsics()
.constructors()
.plain_year_month()
.constructor(),
Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
)
.static_property(
js_string!("ZonedDateTime"),
realm
.intrinsics()
.constructors()
.zoned_date_time()
.constructor(),
Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
)
.build();
}
fn get(intrinsics: &Intrinsics) -> JsObject {
intrinsics.objects().temporal()
}
}
pub(crate) fn get_relative_to_option(
options: &JsObject,
context: &mut Context,
) -> JsResult<Option<RelativeTo>> {
let value = options.get(js_string!("relativeTo"), context)?;
if value.is_undefined() {
return Ok(None);
}
if let Some(object) = value.as_object() {
if let Some(zdt) = object.downcast_ref::<ZonedDateTime>() {
return Ok(Some(RelativeTo::ZonedDateTime(zdt.inner.as_ref().clone())));
} else if let Some(date) = object.downcast_ref::<PlainDate>() {
return Ok(Some(RelativeTo::PlainDate(date.inner.clone())));
} else if let Some(dt) = object.downcast_ref::<PlainDateTime>() {
return Ok(Some(RelativeTo::PlainDate(dt.inner.clone().into())));
}
let calendar = get_temporal_calendar_slot_value_with_default(&object, context)?;
let (fields, timezone) = to_zoned_date_time_fields(
&object,
&calendar,
ZdtFieldsType::TimeZoneNotRequired,
context,
)?;
if timezone.is_none() {
return Ok(Some(RelativeTo::PlainDate(TemporalDate::from_partial(
PartialDate {
calendar_fields: fields.calendar_fields,
calendar,
},
None,
)?)));
}
let zdt = TemporalZonedDateTime::from_partial_with_provider(
PartialZonedDateTime {
fields,
timezone,
calendar,
},
None,
None,
None,
context.tz_provider(),
)?;
return Ok(Some(RelativeTo::ZonedDateTime(zdt)));
}
let Some(relative_to_str) = value.as_string() else {
return Err(JsNativeError::typ()
.with_message("relativeTo must be an object or string.")
.into());
};
Ok(Some(RelativeTo::try_from_str_with_provider(
&relative_to_str.to_std_string_escaped(),
context.tz_provider(),
)?))
}
pub(crate) fn is_partial_temporal_object(
value: &JsValue,
context: &mut Context,
) -> JsResult<Option<JsObject>> {
let Some(obj) = value.as_object() else {
return Ok(None);
};
if obj.is::<PlainDate>()
|| obj.is::<PlainDateTime>()
|| obj.is::<PlainMonthDay>()
|| obj.is::<PlainYearMonth>()
|| obj.is::<PlainTime>()
|| obj.is::<ZonedDateTime>()
{
return Ok(None);
}
let calendar_property = obj.get(js_string!("calendar"), context)?;
if !calendar_property.is_undefined() {
return Ok(None);
}
let time_zone_property = obj.get(js_string!("timeZone"), context)?;
if !time_zone_property.is_undefined() {
return Ok(None);
}
Ok(Some(obj))
}
impl JsValue {
pub(crate) fn to_finitef64(&self, context: &mut Context) -> JsResult<FiniteF64> {
let number = self.to_number(context)?;
let result = FiniteF64::try_from(number)?;
Ok(result)
}
}
fn extract_from_temporal_type<DF, DTF, YMF, MDF, ZDTF, Ret>(
object: &JsObject,
date_f: DF,
datetime_f: DTF,
year_month_f: YMF,
month_day_f: MDF,
zoned_datetime_f: ZDTF,
) -> JsResult<Option<Ret>>
where
DF: FnOnce(&PlainDate) -> JsResult<Option<Ret>>,
DTF: FnOnce(&PlainDateTime) -> JsResult<Option<Ret>>,
YMF: FnOnce(&PlainYearMonth) -> JsResult<Option<Ret>>,
MDF: FnOnce(&PlainMonthDay) -> JsResult<Option<Ret>>,
ZDTF: FnOnce(&ZonedDateTime) -> JsResult<Option<Ret>>,
{
if let Some(date) = object.downcast_ref::<PlainDate>() {
return date_f(&date);
} else if let Some(dt) = object.downcast_ref::<PlainDateTime>() {
return datetime_f(&dt);
} else if let Some(ym) = object.downcast_ref::<PlainYearMonth>() {
return year_month_f(&ym);
} else if let Some(md) = object.downcast_ref::<PlainMonthDay>() {
return month_day_f(&md);
} else if let Some(dt) = object.downcast_ref::<ZonedDateTime>() {
return zoned_datetime_f(&dt);
}
Ok(None)
}