Browse Source

New date methods and update builtin (#3614)

pull/3620/head
Kevin 10 months ago committed by GitHub
parent
commit
806c3c9167
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 2
      core/engine/src/builtins/temporal/now.rs
  2. 237
      core/engine/src/builtins/temporal/plain_date/mod.rs
  3. 189
      core/temporal/src/components/date.rs
  4. 2
      core/temporal/src/components/duration/date.rs
  5. 4
      core/temporal/src/iso.rs
  6. 2
      core/temporal/src/utils.rs

2
core/engine/src/builtins/temporal/now.rs

@ -67,7 +67,7 @@ impl Now {
#[allow(clippy::unnecessary_wraps)]
fn time_zone_id(_: &JsValue, _args: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
// 1. Return ! SystemTimeZone().
Ok(system_time_zone(context).expect("retrieving the system timezone must not fail"))
system_time_zone(context)
}
/// `Temporal.Now.instant()`

237
core/engine/src/builtins/temporal/plain_date/mod.rs

@ -1,6 +1,8 @@
//! Boa's implementation of the ECMAScript `Temporal.PlainDate` builtin object.
#![allow(dead_code, unused_variables)]
// TODO (nekevss): DOCS DOCS AND MORE DOCS
use crate::{
builtins::{
options::{get_option, get_options_object},
@ -21,7 +23,7 @@ use boa_temporal::{
options::ArithmeticOverflow,
};
use super::{calendar, JsCustomCalendar, PlainDateTime, ZonedDateTime};
use super::{calendar, create_temporal_calendar, JsCustomCalendar, PlainDateTime, ZonedDateTime};
/// The `Temporal.PlainDate` object.
#[derive(Debug, Clone, Trace, Finalize, JsData)]
@ -229,90 +231,183 @@ impl BuiltInConstructor for PlainDate {
}
}
// -- `PlainDate` getter methods --
// ==== `PlainDate` getter methods ====
impl PlainDate {
fn get_calendar_id(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
Err(JsNativeError::error()
.with_message("calendars not yet implemented.")
.into())
}
/// 3.3.3 get `Temporal.PlainDate.prototype.calendarId`
fn get_calendar_id(this: &JsValue, _: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
let date = this
.as_object()
.and_then(JsObject::downcast_ref::<Self>)
.ok_or_else(|| {
JsNativeError::typ().with_message("the this object must be an instant object.")
})?;
fn get_year(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
Err(JsNativeError::error()
.with_message("not yet implemented.")
.into())
Ok(JsString::from(date.inner.calendar().identifier(context)?).into())
}
fn get_month(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
Err(JsNativeError::error()
.with_message("not yet implemented.")
.into())
/// 3.3.4 get `Temporal.PlainDate.prototype.year`
fn get_year(this: &JsValue, _: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
let date = this
.as_object()
.and_then(JsObject::downcast_ref::<Self>)
.ok_or_else(|| {
JsNativeError::typ().with_message("the this object must be an instant object.")
})?;
Ok(date.inner.contextual_year(context)?.into())
}
fn get_month_code(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
Err(JsNativeError::error()
.with_message("not yet implemented.")
.into())
/// 3.3.5 get `Temporal.PlainDate.prototype.month`
fn get_month(this: &JsValue, _: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
let date = this
.as_object()
.and_then(JsObject::downcast_ref::<Self>)
.ok_or_else(|| {
JsNativeError::typ().with_message("the this object must be an instant object.")
})?;
Ok(date.inner.contextual_month(context)?.into())
}
/// 3.3.6 get Temporal.PlainDate.prototype.monthCode
fn get_month_code(this: &JsValue, _: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
let date = this
.as_object()
.and_then(JsObject::downcast_ref::<Self>)
.ok_or_else(|| {
JsNativeError::typ().with_message("the this object must be an instant object.")
})?;
Ok(JsString::from(date.inner.contextual_month_code(context)?.as_str()).into())
}
/// 3.3.7 get `Temporal.PlainDate.prototype.day`
fn get_day(this: &JsValue, _: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
let date = this
.as_object()
.and_then(JsObject::downcast_ref::<Self>)
.ok_or_else(|| {
JsNativeError::typ().with_message("the this object must be an instant object.")
})?;
Ok(date.inner.contextual_day(context)?.into())
}
/// 3.3.8 get `Temporal.PlainDate.prototype.dayOfWeek`
fn get_day_of_week(this: &JsValue, _: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
let date = this
.as_object()
.and_then(JsObject::downcast_ref::<Self>)
.ok_or_else(|| {
JsNativeError::typ().with_message("the this object must be an instant object.")
})?;
Ok(date.inner.contextual_day_of_week(context)?.into())
}
/// 3.3.9 get `Temporal.PlainDate.prototype.dayOfYear`
fn get_day_of_year(this: &JsValue, _: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
let date = this
.as_object()
.and_then(JsObject::downcast_ref::<Self>)
.ok_or_else(|| {
JsNativeError::typ().with_message("the this object must be an instant object.")
})?;
Ok(date.inner.contextual_day_of_year(context)?.into())
}
/// 3.3.10 get `Temporal.PlainDate.prototype.weekOfYear`
fn get_week_of_year(this: &JsValue, _: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
let date = this
.as_object()
.and_then(JsObject::downcast_ref::<Self>)
.ok_or_else(|| {
JsNativeError::typ().with_message("the this object must be an instant object.")
})?;
Ok(date.inner.contextual_week_of_year(context)?.into())
}
/// 3.3.11 get `Temporal.PlainDate.prototype.yearOfWeek`
fn get_year_of_week(this: &JsValue, _: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
let date = this
.as_object()
.and_then(JsObject::downcast_ref::<Self>)
.ok_or_else(|| {
JsNativeError::typ().with_message("the this object must be an instant object.")
})?;
Ok(date.inner.contextual_year_of_week(context)?.into())
}
fn get_day(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
Err(JsNativeError::error()
.with_message("not yet implemented.")
.into())
}
/// 3.3.12 get `Temporal.PlainDate.prototype.daysInWeek`
fn get_days_in_week(this: &JsValue, _: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
let date = this
.as_object()
.and_then(JsObject::downcast_ref::<Self>)
.ok_or_else(|| {
JsNativeError::typ().with_message("the this object must be an instant object.")
})?;
fn get_day_of_week(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
Err(JsNativeError::error()
.with_message("not yet implemented.")
.into())
Ok(date.inner.contextual_days_in_week(context)?.into())
}
fn get_day_of_year(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
Err(JsNativeError::error()
.with_message("not yet implemented.")
.into())
}
/// 3.3.13 get `Temporal.PlainDate.prototype.daysInMonth`
fn get_days_in_month(
this: &JsValue,
_: &[JsValue],
context: &mut Context,
) -> JsResult<JsValue> {
let date = this
.as_object()
.and_then(JsObject::downcast_ref::<Self>)
.ok_or_else(|| {
JsNativeError::typ().with_message("the this object must be an instant object.")
})?;
fn get_week_of_year(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
Err(JsNativeError::error()
.with_message("not yet implemented.")
.into())
Ok(date.inner.contextual_days_in_month(context)?.into())
}
fn get_year_of_week(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
Err(JsNativeError::error()
.with_message("not yet implemented.")
.into())
}
/// 3.3.14 get `Temporal.PlainDate.prototype.daysInYear`
fn get_days_in_year(this: &JsValue, _: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
let date = this
.as_object()
.and_then(JsObject::downcast_ref::<Self>)
.ok_or_else(|| {
JsNativeError::typ().with_message("the this object must be an instant object.")
})?;
fn get_days_in_week(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
Err(JsNativeError::error()
.with_message("not yet implemented.")
.into())
Ok(date.inner.contextual_days_in_year(context)?.into())
}
fn get_days_in_month(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
Err(JsNativeError::error()
.with_message("not yet implemented.")
.into())
}
/// 3.3.15 get `Temporal.PlainDate.prototype.monthsInYear`
fn get_months_in_year(
this: &JsValue,
_: &[JsValue],
context: &mut Context,
) -> JsResult<JsValue> {
let date = this
.as_object()
.and_then(JsObject::downcast_ref::<Self>)
.ok_or_else(|| {
JsNativeError::typ().with_message("the this object must be an instant object.")
})?;
fn get_days_in_year(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
Err(JsNativeError::error()
.with_message("not yet implemented.")
.into())
Ok(date.inner.contextual_months_in_year(context)?.into())
}
fn get_months_in_year(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
Err(JsNativeError::error()
.with_message("not yet implemented.")
.into())
}
/// 3.3.16 get `Temporal.PlainDate.prototype.inLeapYear`
fn get_in_leap_year(this: &JsValue, _: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
let date = this
.as_object()
.and_then(JsObject::downcast_ref::<Self>)
.ok_or_else(|| {
JsNativeError::typ().with_message("the this object must be an instant object.")
})?;
fn get_in_leap_year(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
Err(JsNativeError::error()
.with_message("not yet implemented.")
.into())
Ok(date.inner.contextual_in_leap_year(context)?.into())
}
}
@ -337,10 +432,16 @@ impl PlainDate {
.into())
}
fn get_calendar(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
Err(JsNativeError::error()
.with_message("not yet implemented.")
.into())
/// 3.3.20 `Temporal.PlainDate.prototype.getCalendar ( )`
fn get_calendar(this: &JsValue, _: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
let date = this
.as_object()
.and_then(JsObject::downcast_ref::<Self>)
.ok_or_else(|| {
JsNativeError::typ().with_message("the this object must be an instant object.")
})?;
create_temporal_calendar(date.inner.calendar().clone(), None, context)
}
fn add(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {

189
core/temporal/src/components/date.rs

@ -1,5 +1,7 @@
//! This module implements `Date` and any directly related algorithms.
use tinystr::TinyAsciiStr;
use crate::{
components::{
calendar::{CalendarProtocol, CalendarSlot},
@ -72,29 +74,29 @@ impl<C: CalendarProtocol> Date<C> {
#[inline]
#[must_use]
/// Returns this `Date`'s year value.
pub const fn year(&self) -> i32 {
/// Returns this `Date`'s ISO year value.
pub const fn iso_year(&self) -> i32 {
self.iso.year()
}
#[inline]
#[must_use]
/// Returns this `Date`'s month value.
pub const fn month(&self) -> u8 {
/// Returns this `Date`'s ISO month value.
pub const fn iso_month(&self) -> u8 {
self.iso.month()
}
#[inline]
#[must_use]
/// Returns this `Date`'s day value.
pub const fn day(&self) -> u8 {
/// Returns this `Date`'s ISO day value.
pub const fn iso_day(&self) -> u8 {
self.iso.day()
}
#[inline]
#[must_use]
/// Returns the `Date`'s inner `IsoDate` record.
pub const fn iso_date(&self) -> IsoDate {
pub const fn iso(&self) -> IsoDate {
self.iso
}
@ -123,6 +125,179 @@ impl<C: CalendarProtocol> Date<C> {
}
}
// ==== Calendar-derived Public API ====
impl<C: CalendarProtocol> Date<C> {
/// Returns the calendar year value with provided context.
pub fn contextual_year(&self, context: &mut dyn Any) -> TemporalResult<i32> {
self.calendar.year(
&super::calendar::CalendarDateLike::Date(self.clone()),
context,
)
}
/// Returns the calendar year value.
pub fn year(&self) -> TemporalResult<i32> {
self.contextual_year(&mut ())
}
/// Returns the calendar month value with provided context.
pub fn contextual_month(&self, context: &mut dyn Any) -> TemporalResult<u8> {
self.calendar.month(
&super::calendar::CalendarDateLike::Date(self.clone()),
context,
)
}
/// Returns the calendar month value.
pub fn month(&self) -> TemporalResult<u8> {
self.contextual_month(&mut ())
}
/// Returns the calendar month code value with provided context.
pub fn contextual_month_code(&self, context: &mut dyn Any) -> TemporalResult<TinyAsciiStr<4>> {
self.calendar.month_code(
&super::calendar::CalendarDateLike::Date(self.clone()),
context,
)
}
/// Returns the calendar month code value.
pub fn month_code(&self) -> TemporalResult<TinyAsciiStr<4>> {
self.contextual_month_code(&mut ())
}
/// Returns the calendar day value with provided context.
pub fn contextual_day(&self, context: &mut dyn Any) -> TemporalResult<u8> {
self.calendar.day(
&super::calendar::CalendarDateLike::Date(self.clone()),
context,
)
}
/// Returns the calendar day value.
pub fn day(&self) -> TemporalResult<u8> {
self.contextual_day(&mut ())
}
/// Returns the calendar day of week value with provided context.
pub fn contextual_day_of_week(&self, context: &mut dyn Any) -> TemporalResult<u16> {
self.calendar.day_of_week(
&super::calendar::CalendarDateLike::Date(self.clone()),
context,
)
}
/// Returns the calendar day of week value.
pub fn day_of_week(&self) -> TemporalResult<u16> {
self.contextual_day_of_week(&mut ())
}
/// Returns the calendar day of year value with provided context.
pub fn contextual_day_of_year(&self, context: &mut dyn Any) -> TemporalResult<u16> {
self.calendar.day_of_week(
&super::calendar::CalendarDateLike::Date(self.clone()),
context,
)
}
/// Returns the calendar day of year value.
pub fn day_of_year(&self) -> TemporalResult<u16> {
self.contextual_day_of_week(&mut ())
}
/// Returns the calendar week of year value with provided context.
pub fn contextual_week_of_year(&self, context: &mut dyn Any) -> TemporalResult<u16> {
self.calendar.week_of_year(
&super::calendar::CalendarDateLike::Date(self.clone()),
context,
)
}
/// Returns the calendar week of year value.
pub fn week_of_year(&self) -> TemporalResult<u16> {
self.contextual_week_of_year(&mut ())
}
/// Returns the calendar year of week value with provided context.
pub fn contextual_year_of_week(&self, context: &mut dyn Any) -> TemporalResult<i32> {
self.calendar.year_of_week(
&super::calendar::CalendarDateLike::Date(self.clone()),
context,
)
}
/// Returns the calendar year of week value.
pub fn year_of_week(&self) -> TemporalResult<i32> {
self.contextual_year_of_week(&mut ())
}
/// Returns the calendar days in week value with provided context.
pub fn contextual_days_in_week(&self, context: &mut dyn Any) -> TemporalResult<u16> {
self.calendar.days_in_week(
&super::calendar::CalendarDateLike::Date(self.clone()),
context,
)
}
/// Returns the calendar days in week value.
pub fn days_in_week(&self) -> TemporalResult<u16> {
self.contextual_days_in_week(&mut ())
}
/// Returns the calendar days in month value with provided context.
pub fn contextual_days_in_month(&self, context: &mut dyn Any) -> TemporalResult<u16> {
self.calendar.days_in_month(
&super::calendar::CalendarDateLike::Date(self.clone()),
context,
)
}
/// Returns the calendar days in month value.
pub fn days_in_month(&self) -> TemporalResult<u16> {
self.contextual_days_in_month(&mut ())
}
/// Returns the calendar days in year value with provided context.
pub fn contextual_days_in_year(&self, context: &mut dyn Any) -> TemporalResult<u16> {
self.calendar.days_in_year(
&super::calendar::CalendarDateLike::Date(self.clone()),
context,
)
}
/// Returns the calendar days in year value.
pub fn days_in_year(&self) -> TemporalResult<u16> {
self.contextual_days_in_year(&mut ())
}
/// Returns the calendar months in year value with provided context.
pub fn contextual_months_in_year(&self, context: &mut dyn Any) -> TemporalResult<u16> {
self.calendar.months_in_year(
&super::calendar::CalendarDateLike::Date(self.clone()),
context,
)
}
/// Returns the calendar months in year value.
pub fn months_in_year(&self) -> TemporalResult<u16> {
self.contextual_months_in_year(&mut ())
}
/// Returns whether the date is in a leap year for the given calendar with provided context.
pub fn contextual_in_leap_year(&self, context: &mut dyn Any) -> TemporalResult<bool> {
self.calendar.in_leap_year(
&super::calendar::CalendarDateLike::Date(self.clone()),
context,
)
}
/// Returns returns whether the date in a leap year for the given calendar.
pub fn in_leap_year(&self) -> TemporalResult<bool> {
self.contextual_in_leap_year(&mut ())
}
}
impl<C: CalendarProtocol> IsoDateSlots for Date<C> {
/// Returns the structs `IsoDate`
fn iso_date(&self) -> IsoDate {

2
core/temporal/src/components/duration/date.rs

@ -212,7 +212,7 @@ impl DateDuration {
fractional_days += f64::from(months_weeks_in_days);
// k. Let isoResult be ! AddISODate(plainRelativeTo.[[ISOYear]]. plainRelativeTo.[[ISOMonth]], plainRelativeTo.[[ISODay]], 0, 0, 0, truncate(fractionalDays), "constrain").
let iso_result = plain_relative_to.iso_date().add_iso_date(
let iso_result = plain_relative_to.iso().add_iso_date(
&DateDuration::new_unchecked(0.0, 0.0, 0.0, fractional_days.trunc()),
ArithmeticOverflow::Constrain,
)?;

4
core/temporal/src/iso.rs

@ -171,11 +171,11 @@ impl IsoDate {
) -> TemporalResult<Self> {
match overflow {
ArithmeticOverflow::Constrain => {
let m = month.clamp(1, 12);
let month = month.clamp(1, 12);
let days_in_month = utils::iso_days_in_month(year, month);
let d = day.clamp(1, days_in_month);
// NOTE: Values are clamped in a u8 range.
Ok(Self::new_unchecked(year, m as u8, d as u8))
Ok(Self::new_unchecked(year, month as u8, d as u8))
}
ArithmeticOverflow::Reject => {
if !is_valid_date(year, month, day) {

2
core/temporal/src/utils.rs

@ -305,7 +305,7 @@ pub(crate) fn iso_days_in_month(year: i32, month: i32) -> i32 {
1 | 3 | 5 | 7 | 8 | 10 | 12 => 31,
4 | 6 | 9 | 11 => 30,
2 => 28 + mathematical_in_leap_year(epoch_time_for_year(year)),
_ => unreachable!("an invalid month value is an implementation error."),
_ => unreachable!("ISODaysInMonth panicking is an implementation error."),
}
}

Loading…
Cancel
Save