mirror of https://github.com/boa-dev/boa.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1381 lines
51 KiB
1381 lines
51 KiB
#[cfg(test)] |
|
mod tests; |
|
|
|
use crate::{ |
|
builtins::BuiltIn, |
|
gc::{empty_trace, Finalize, Trace}, |
|
object::{ConstructorBuilder, ObjectData, PROTOTYPE}, |
|
property::Attribute, |
|
value::{PreferredType, Value}, |
|
BoaProfiler, Context, Result, |
|
}; |
|
use chrono::{prelude::*, Duration, LocalResult}; |
|
use std::fmt::Display; |
|
|
|
const NANOS_IN_MS: f64 = 1_000_000f64; |
|
|
|
#[inline] |
|
fn is_zero_or_normal_opt(value: Option<f64>) -> bool { |
|
value |
|
.map(|value| value == 0f64 || value.is_normal()) |
|
.unwrap_or(true) |
|
} |
|
|
|
macro_rules! check_normal_opt { |
|
($($v:expr),+) => { |
|
$(is_zero_or_normal_opt($v.into()) &&)+ true |
|
}; |
|
} |
|
|
|
#[inline] |
|
fn ignore_ambiguity<T>(result: LocalResult<T>) -> Option<T> { |
|
match result { |
|
LocalResult::Ambiguous(v, _) => Some(v), |
|
LocalResult::Single(v) => Some(v), |
|
LocalResult::None => None, |
|
} |
|
} |
|
|
|
macro_rules! getter_method { |
|
($name:ident) => {{ |
|
fn get_value(this: &Value, _: &[Value], context: &mut Context) -> Result<Value> { |
|
Ok(Value::from(this_time_value(this, context)?.$name())) |
|
} |
|
get_value |
|
}}; |
|
(Self::$name:ident) => {{ |
|
fn get_value(_: &Value, _: &[Value], _: &mut Context) -> Result<Value> { |
|
Ok(Value::from(Date::$name())) |
|
} |
|
get_value |
|
}}; |
|
} |
|
|
|
macro_rules! setter_method { |
|
($name:ident($($e:expr),* $(,)?)) => {{ |
|
fn set_value(this: &Value, args: &[Value], context: &mut Context) -> Result<Value> { |
|
let mut result = this_time_value(this, context)?; |
|
result.$name( |
|
$( |
|
args |
|
.get($e) |
|
.and_then(|value| { |
|
value.to_numeric_number(context).map_or_else( |
|
|_| None, |
|
|value| { |
|
if value == 0f64 || value.is_normal() { |
|
Some(value) |
|
} else { |
|
None |
|
} |
|
}, |
|
) |
|
}) |
|
),* |
|
); |
|
|
|
this.set_data(ObjectData::Date(result)); |
|
Ok(Value::from(result.get_time())) |
|
} |
|
set_value |
|
}}; |
|
} |
|
|
|
#[derive(Debug, Finalize, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] |
|
pub struct Date(Option<NaiveDateTime>); |
|
|
|
impl Display for Date { |
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
|
match self.to_local() { |
|
Some(v) => write!(f, "{}", v.format("%a %b %d %Y %H:%M:%S GMT%:z")), |
|
_ => write!(f, "Invalid Date"), |
|
} |
|
} |
|
} |
|
|
|
unsafe impl Trace for Date { |
|
// Date is a stack value, it doesn't require tracing. |
|
// only safe if `chrono` never implements `Trace` for `NaiveDateTime` |
|
empty_trace!(); |
|
} |
|
|
|
impl Default for Date { |
|
fn default() -> Self { |
|
Self(Some(Utc::now().naive_utc())) |
|
} |
|
} |
|
|
|
impl BuiltIn for Date { |
|
const NAME: &'static str = "Date"; |
|
|
|
fn attribute() -> Attribute { |
|
Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE |
|
} |
|
|
|
fn init(context: &mut Context) -> (&'static str, Value, Attribute) { |
|
let _timer = BoaProfiler::global().start_event(Self::NAME, "init"); |
|
|
|
let date_object = ConstructorBuilder::new(context, Self::constructor) |
|
.name(Self::NAME) |
|
.length(Self::LENGTH) |
|
.method(getter_method!(get_date), "getDate", 0) |
|
.method(getter_method!(get_day), "getDay", 0) |
|
.method(getter_method!(get_full_year), "getFullYear", 0) |
|
.method(getter_method!(get_hours), "getHours", 0) |
|
.method(getter_method!(get_milliseconds), "getMilliseconds", 0) |
|
.method(getter_method!(get_minutes), "getMinutes", 0) |
|
.method(getter_method!(get_month), "getMonth", 0) |
|
.method(getter_method!(get_seconds), "getSeconds", 0) |
|
.method(getter_method!(get_time), "getTime", 0) |
|
.method(getter_method!(get_year), "getYear", 0) |
|
.method( |
|
getter_method!(Self::get_timezone_offset), |
|
"getTimezoneOffset", |
|
0, |
|
) |
|
.method(getter_method!(get_utc_date), "getUTCDate", 0) |
|
.method(getter_method!(get_utc_day), "getUTCDay", 0) |
|
.method(getter_method!(get_utc_full_year), "getUTCFullYear", 0) |
|
.method(getter_method!(get_utc_hours), "getUTCHours", 0) |
|
.method( |
|
getter_method!(get_utc_milliseconds), |
|
"getUTCMilliseconds", |
|
0, |
|
) |
|
.method(getter_method!(get_utc_minutes), "getUTCMinutes", 0) |
|
.method(getter_method!(get_utc_month), "getUTCMonth", 0) |
|
.method(getter_method!(get_utc_seconds), "getUTCSeconds", 0) |
|
.method(setter_method!(set_date(0)), "setDate", 1) |
|
.method(setter_method!(set_full_year(0, 1, 2)), "setFullYear", 1) |
|
.method(setter_method!(set_hours(0, 1, 2, 3)), "setHours", 1) |
|
.method(setter_method!(set_milliseconds(0)), "setMilliseconds", 1) |
|
.method(setter_method!(set_minutes(0, 1, 2)), "setMinutes", 1) |
|
.method(setter_method!(set_month(0, 1)), "setMonth", 1) |
|
.method(setter_method!(set_seconds(0, 1)), "setSeconds", 1) |
|
.method(setter_method!(set_year(0, 1, 2)), "setYear", 1) |
|
.method(setter_method!(set_time(0)), "setTime", 1) |
|
.method(setter_method!(set_utc_date(0)), "setUTCDate", 1) |
|
.method( |
|
setter_method!(set_utc_full_year(0, 1, 2)), |
|
"setUTCFullYear", |
|
1, |
|
) |
|
.method(setter_method!(set_utc_hours(0, 1, 2, 3)), "setUTCHours", 1) |
|
.method( |
|
setter_method!(set_utc_milliseconds(0)), |
|
"setUTCMilliseconds", |
|
1, |
|
) |
|
.method(setter_method!(set_utc_minutes(0, 1, 2)), "setUTCMinutes", 1) |
|
.method(setter_method!(set_utc_month(0, 1)), "setUTCMonth", 1) |
|
.method(setter_method!(set_utc_seconds(0, 1)), "setUTCSeconds", 1) |
|
.method(getter_method!(to_date_string), "toDateString", 0) |
|
.method(getter_method!(to_gmt_string), "toGMTString", 0) |
|
.method(getter_method!(to_iso_string), "toISOString", 0) |
|
.method(getter_method!(to_json), "toJSON", 0) |
|
// Locale strings |
|
.method(getter_method!(to_string), "toString", 0) |
|
.method(getter_method!(to_time_string), "toTimeString", 0) |
|
.method(getter_method!(to_utc_string), "toUTCString", 0) |
|
.method(getter_method!(value_of), "valueOf", 0) |
|
.static_method(Self::now, "now", 0) |
|
.static_method(Self::parse, "parse", 1) |
|
.static_method(Self::utc, "UTC", 7) |
|
.build(); |
|
|
|
(Self::NAME, date_object.into(), Self::attribute()) |
|
} |
|
} |
|
|
|
impl Date { |
|
/// The amount of arguments this function object takes. |
|
pub(crate) const LENGTH: usize = 7; |
|
|
|
/// Converts the `Date` to a local `DateTime`. |
|
/// |
|
/// If the `Date` is invalid (i.e. NAN), this function will return `None`. |
|
pub fn to_local(&self) -> Option<DateTime<Local>> { |
|
self.0 |
|
.map(|utc| Local::now().timezone().from_utc_datetime(&utc)) |
|
} |
|
|
|
/// Converts the `Date` to a UTC `DateTime`. |
|
/// |
|
/// If the `Date` is invalid (i.e. NAN), this function will return `None`. |
|
pub fn to_utc(&self) -> Option<DateTime<Utc>> { |
|
self.0 |
|
.map(|utc| Utc::now().timezone().from_utc_datetime(&utc)) |
|
} |
|
|
|
/// Optionally sets the individual components of the `Date`. |
|
/// |
|
/// Each component does not have to be within the range of valid values. For example, if `month` is too large |
|
/// then `year` will be incremented by the required amount. |
|
#[allow(clippy::too_many_arguments)] |
|
pub fn set_components( |
|
&mut self, |
|
utc: bool, |
|
year: Option<f64>, |
|
month: Option<f64>, |
|
day: Option<f64>, |
|
hour: Option<f64>, |
|
minute: Option<f64>, |
|
second: Option<f64>, |
|
millisecond: Option<f64>, |
|
) { |
|
#[inline] |
|
fn num_days_in(year: i32, month: u32) -> i32 { |
|
let month = month + 1; // zero-based for calculations |
|
NaiveDate::from_ymd( |
|
match month { |
|
12 => year + 1, |
|
_ => year, |
|
}, |
|
match month { |
|
12 => 1, |
|
_ => month + 1, |
|
}, |
|
1, |
|
) |
|
.signed_duration_since(NaiveDate::from_ymd(year, month, 1)) |
|
.num_days() as i32 |
|
} |
|
|
|
#[inline] |
|
fn fix_month(year: &mut i32, month: &mut i32) { |
|
*year += *month / 12; |
|
*month = if *month < 0 { |
|
*year -= 1; |
|
11 + (*month + 1) % 12 |
|
} else { |
|
*month % 12 |
|
} |
|
} |
|
|
|
#[inline] |
|
fn fix_day(year: &mut i32, month: &mut i32, day: &mut i32) { |
|
fix_month(year, month); |
|
loop { |
|
if *day < 0 { |
|
*month -= 1; |
|
fix_month(year, month); |
|
*day += num_days_in(*year, *month as u32); |
|
} else { |
|
let num_days = num_days_in(*year, *month as u32); |
|
if *day >= num_days { |
|
*day -= num_days_in(*year, *month as u32); |
|
*month += 1; |
|
fix_month(year, month); |
|
} else { |
|
break; |
|
} |
|
} |
|
} |
|
} |
|
|
|
// If any of the args are infinity or NaN, return an invalid date. |
|
if !check_normal_opt!(year, month, day, hour, minute, second, millisecond) { |
|
self.0 = None; |
|
return; |
|
} |
|
|
|
let naive = if utc { |
|
self.to_utc().map(|dt| dt.naive_utc()) |
|
} else { |
|
self.to_local().map(|dt| dt.naive_local()) |
|
}; |
|
|
|
self.0 = naive.and_then(|naive| { |
|
let mut year = year.unwrap_or_else(|| naive.year() as f64) as i32; |
|
let mut month = month.unwrap_or_else(|| naive.month0() as f64) as i32; |
|
let mut day = day.unwrap_or_else(|| naive.day() as f64) as i32 - 1; |
|
let hour = hour.unwrap_or_else(|| naive.hour() as f64) as i64; |
|
let minute = minute.unwrap_or_else(|| naive.minute() as f64) as i64; |
|
let second = second.unwrap_or_else(|| naive.second() as f64) as i64; |
|
let millisecond = |
|
millisecond.unwrap_or_else(|| naive.nanosecond() as f64 / NANOS_IN_MS) as i64; |
|
|
|
fix_day(&mut year, &mut month, &mut day); |
|
|
|
let duration = Duration::hours(hour) |
|
+ Duration::minutes(minute) |
|
+ Duration::seconds(second) |
|
+ Duration::milliseconds(millisecond); |
|
NaiveDate::from_ymd_opt(year, month as u32 + 1, day as u32 + 1) |
|
.and_then(|dt| dt.and_hms(0, 0, 0).checked_add_signed(duration)) |
|
.and_then(|dt| { |
|
if utc { |
|
Some(Utc.from_utc_datetime(&dt).naive_utc()) |
|
} else { |
|
ignore_ambiguity(Local.from_local_datetime(&dt)).map(|dt| dt.naive_utc()) |
|
} |
|
}) |
|
}); |
|
} |
|
|
|
/// `Date()` |
|
/// |
|
/// Creates a JavaScript `Date` instance that represents a single moment in time in a platform-independent format. |
|
/// |
|
/// More information: |
|
/// - [ECMAScript reference][spec] |
|
/// - [MDN documentation][mdn] |
|
/// |
|
/// [spec]: https://tc39.es/ecma262/#sec-date-constructor |
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/Date |
|
pub(crate) fn constructor( |
|
new_target: &Value, |
|
args: &[Value], |
|
context: &mut Context, |
|
) -> Result<Value> { |
|
if new_target.is_undefined() { |
|
Self::make_date_string() |
|
} else { |
|
let prototype = new_target |
|
.as_object() |
|
.and_then(|obj| { |
|
obj.get(&PROTOTYPE.into(), obj.clone().into(), context) |
|
.map(|o| o.as_object()) |
|
.transpose() |
|
}) |
|
.transpose()? |
|
.unwrap_or_else(|| context.standard_objects().object_object().prototype()); |
|
let mut obj = context.construct_object(); |
|
obj.set_prototype_instance(prototype.into()); |
|
let this = obj.into(); |
|
if args.is_empty() { |
|
Self::make_date_now(&this) |
|
} else if args.len() == 1 { |
|
Self::make_date_single(&this, args, context) |
|
} else { |
|
Self::make_date_multiple(&this, args, context) |
|
} |
|
} |
|
} |
|
|
|
/// `Date()` |
|
/// |
|
/// The `Date()` function is used to create a string that represent the current date and time. |
|
/// |
|
/// More information: |
|
/// - [ECMAScript reference][spec] |
|
/// - [MDN documentation][mdn] |
|
/// |
|
/// [spec]: https://tc39.es/ecma262/#sec-date-constructor |
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/Date |
|
pub(crate) fn make_date_string() -> Result<Value> { |
|
Ok(Value::from(Local::now().to_rfc3339())) |
|
} |
|
|
|
/// `Date()` |
|
/// |
|
/// The newly-created `Date` object represents the current date and time as of the time of instantiation. |
|
/// |
|
/// More information: |
|
/// - [ECMAScript reference][spec] |
|
/// - [MDN documentation][mdn] |
|
/// |
|
/// [spec]: https://tc39.es/ecma262/#sec-date-constructor |
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/Date |
|
pub(crate) fn make_date_now(this: &Value) -> Result<Value> { |
|
let date = Date::default(); |
|
this.set_data(ObjectData::Date(date)); |
|
Ok(this.clone()) |
|
} |
|
|
|
/// `Date(value)` |
|
/// |
|
/// The newly-created `Date` object represents the value provided to the constructor. |
|
/// |
|
/// More information: |
|
/// - [ECMAScript reference][spec] |
|
/// - [MDN documentation][mdn] |
|
/// |
|
/// [spec]: https://tc39.es/ecma262/#sec-date-constructor |
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/Date |
|
pub(crate) fn make_date_single( |
|
this: &Value, |
|
args: &[Value], |
|
context: &mut Context, |
|
) -> Result<Value> { |
|
let value = &args[0]; |
|
let tv = match this_time_value(value, context) { |
|
Ok(dt) => dt.0, |
|
_ => match value.to_primitive(context, PreferredType::Default)? { |
|
Value::String(ref str) => match chrono::DateTime::parse_from_rfc3339(&str) { |
|
Ok(dt) => Some(dt.naive_utc()), |
|
_ => None, |
|
}, |
|
tv => { |
|
let tv = tv.to_number(context)?; |
|
let secs = (tv / 1_000f64) as i64; |
|
let nsecs = ((tv % 1_000f64) * 1_000_000f64) as u32; |
|
NaiveDateTime::from_timestamp_opt(secs, nsecs) |
|
} |
|
}, |
|
}; |
|
|
|
let date = Date(tv); |
|
this.set_data(ObjectData::Date(date)); |
|
Ok(this.clone()) |
|
} |
|
|
|
/// `Date(year, month [ , date [ , hours [ , minutes [ , seconds [ , ms ] ] ] ] ])` |
|
/// |
|
/// The newly-created `Date` object represents the date components provided to the constructor. |
|
/// |
|
/// More information: |
|
/// - [ECMAScript reference][spec] |
|
/// - [MDN documentation][mdn] |
|
/// |
|
/// [spec]: https://tc39.es/ecma262/#sec-date-constructor |
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/Date |
|
pub(crate) fn make_date_multiple( |
|
this: &Value, |
|
args: &[Value], |
|
context: &mut Context, |
|
) -> Result<Value> { |
|
let year = args[0].to_number(context)?; |
|
let month = args[1].to_number(context)?; |
|
let day = args |
|
.get(2) |
|
.map_or(Ok(1f64), |value| value.to_number(context))?; |
|
let hour = args |
|
.get(3) |
|
.map_or(Ok(0f64), |value| value.to_number(context))?; |
|
let min = args |
|
.get(4) |
|
.map_or(Ok(0f64), |value| value.to_number(context))?; |
|
let sec = args |
|
.get(5) |
|
.map_or(Ok(0f64), |value| value.to_number(context))?; |
|
let milli = args |
|
.get(6) |
|
.map_or(Ok(0f64), |value| value.to_number(context))?; |
|
|
|
// If any of the args are infinity or NaN, return an invalid date. |
|
if !check_normal_opt!(year, month, day, hour, min, sec, milli) { |
|
let date = Date(None); |
|
this.set_data(ObjectData::Date(date)); |
|
return Ok(this.clone()); |
|
} |
|
|
|
let year = year as i32; |
|
let month = month as u32; |
|
let day = day as u32; |
|
let hour = hour as u32; |
|
let min = min as u32; |
|
let sec = sec as u32; |
|
let milli = milli as u32; |
|
|
|
let year = if (0..=99).contains(&year) { |
|
1900 + year |
|
} else { |
|
year |
|
}; |
|
|
|
let final_date = NaiveDate::from_ymd_opt(year, month + 1, day) |
|
.and_then(|naive_date| naive_date.and_hms_milli_opt(hour, min, sec, milli)) |
|
.and_then(|local| ignore_ambiguity(Local.from_local_datetime(&local))) |
|
.map(|local| local.naive_utc()); |
|
|
|
let date = Date(final_date); |
|
this.set_data(ObjectData::Date(date)); |
|
Ok(this.clone()) |
|
} |
|
|
|
/// `Date.prototype.getDate()` |
|
/// |
|
/// The `getDate()` method returns the day of the month for the specified date according to local time. |
|
/// |
|
/// More information: |
|
/// - [ECMAScript reference][spec] |
|
/// - [MDN documentation][mdn] |
|
/// |
|
/// [spec]: https://tc39.es/ecma262/#sec-date.prototype.getdate |
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getDate |
|
pub fn get_date(&self) -> f64 { |
|
self.to_local().map_or(f64::NAN, |dt| dt.day() as f64) |
|
} |
|
|
|
/// `Date.prototype.getDay()` |
|
/// |
|
/// The `getDay()` method returns the day of the week for the specified date according to local time, where 0 |
|
/// represents Sunday. |
|
/// |
|
/// More information: |
|
/// - [ECMAScript reference][spec] |
|
/// - [MDN documentation][mdn] |
|
/// |
|
/// [spec]: https://tc39.es/ecma262/#sec-date.prototype.getday |
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getDay |
|
pub fn get_day(&self) -> f64 { |
|
self.to_local().map_or(f64::NAN, |dt| { |
|
let weekday = dt.weekday() as u32; |
|
let weekday = (weekday + 1) % 7; // 0 represents Monday in Chrono |
|
weekday as f64 |
|
}) |
|
} |
|
|
|
/// `Date.prototype.getFullYear()` |
|
/// |
|
/// The `getFullYear()` method returns the year of the specified date according to local time. |
|
/// |
|
/// More information: |
|
/// - [ECMAScript reference][spec] |
|
/// - [MDN documentation][mdn] |
|
/// |
|
/// [spec]: https://tc39.es/ecma262/#sec-date.prototype.getfullyear |
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getFullYear |
|
pub fn get_full_year(&self) -> f64 { |
|
self.to_local().map_or(f64::NAN, |dt| dt.year() as f64) |
|
} |
|
|
|
/// `Date.prototype.getHours()` |
|
/// |
|
/// The `getHours()` method returns the hour for the specified date, according to local time. |
|
/// |
|
/// More information: |
|
/// - [ECMAScript reference][spec] |
|
/// - [MDN documentation][mdn] |
|
/// |
|
/// [spec]: https://tc39.es/ecma262/#sec-date.prototype.gethours |
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getHours |
|
pub fn get_hours(&self) -> f64 { |
|
self.to_local().map_or(f64::NAN, |dt| dt.hour() as f64) |
|
} |
|
|
|
/// `Date.prototype.getMilliseconds()` |
|
/// |
|
/// The `getMilliseconds()` method returns the milliseconds in the specified date according to local time. |
|
/// |
|
/// More information: |
|
/// - [ECMAScript reference][spec] |
|
/// - [MDN documentation][mdn] |
|
/// |
|
/// [spec]: https://tc39.es/ecma262/#sec-date.prototype.getmilliseconds |
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getMilliseconds |
|
pub fn get_milliseconds(&self) -> f64 { |
|
self.to_local() |
|
.map_or(f64::NAN, |dt| dt.nanosecond() as f64 / NANOS_IN_MS) |
|
} |
|
|
|
/// `Date.prototype.getMinutes()` |
|
/// |
|
/// The `getMinutes()` method returns the minutes in the specified date according to local time. |
|
/// |
|
/// More information: |
|
/// - [ECMAScript reference][spec] |
|
/// - [MDN documentation][mdn] |
|
/// |
|
/// [spec]: https://tc39.es/ecma262/#sec-date.prototype.getminutes |
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getMinutes |
|
pub fn get_minutes(&self) -> f64 { |
|
self.to_local().map_or(f64::NAN, |dt| dt.minute() as f64) |
|
} |
|
|
|
/// `Date.prototype.getMonth()` |
|
/// |
|
/// The `getMonth()` method returns the month in the specified date according to local time, as a zero-based value |
|
/// (where zero indicates the first month of the year). |
|
/// |
|
/// More information: |
|
/// - [ECMAScript reference][spec] |
|
/// - [MDN documentation][mdn] |
|
/// |
|
/// [spec]: https://tc39.es/ecma262/#sec-date.prototype.getmonth |
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getMonth |
|
pub fn get_month(&self) -> f64 { |
|
self.to_local().map_or(f64::NAN, |dt| dt.month0() as f64) |
|
} |
|
|
|
/// `Date.prototype.getSeconds()` |
|
/// |
|
/// The `getSeconds()` method returns the seconds in the specified date according to local time. |
|
/// |
|
/// More information: |
|
/// - [ECMAScript reference][spec] |
|
/// - [MDN documentation][mdn] |
|
/// |
|
/// [spec]: https://tc39.es/ecma262/#sec-date.prototype.getseconds |
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getSeconds |
|
pub fn get_seconds(&self) -> f64 { |
|
self.to_local().map_or(f64::NAN, |dt| dt.second() as f64) |
|
} |
|
|
|
/// `Date.prototype.getYear()` |
|
/// |
|
/// The getYear() method returns the year in the specified date according to local time. Because getYear() does not |
|
/// return full years ("year 2000 problem"), it is no longer used and has been replaced by the getFullYear() method. |
|
/// |
|
/// More information: |
|
/// - [ECMAScript reference][spec] |
|
/// - [MDN documentation][mdn] |
|
/// |
|
/// [spec]: https://tc39.es/ecma262/#sec-date.prototype.getyear |
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getYear |
|
pub fn get_year(&self) -> f64 { |
|
self.to_local() |
|
.map_or(f64::NAN, |dt| dt.year() as f64 - 1900f64) |
|
} |
|
|
|
/// `Date.prototype.getTime()` |
|
/// |
|
/// The `getTime()` method returns the number of milliseconds since the Unix Epoch. |
|
/// |
|
/// More information: |
|
/// - [ECMAScript reference][spec] |
|
/// - [MDN documentation][mdn] |
|
/// |
|
/// [spec]: https://tc39.es/ecma262/#sec-date.prototype.gettime |
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getTime |
|
pub fn get_time(&self) -> f64 { |
|
self.to_utc() |
|
.map_or(f64::NAN, |dt| dt.timestamp_millis() as f64) |
|
} |
|
|
|
/// `Date.prototype.getTimeZoneOffset()` |
|
/// |
|
/// The getTimezoneOffset() method returns the time zone difference, in minutes, from current locale (host system |
|
/// settings) to UTC. |
|
/// |
|
/// More information: |
|
/// - [ECMAScript reference][spec] |
|
/// - [MDN documentation][mdn] |
|
/// |
|
/// [spec]: https://tc39.es/ecma262/#sec-date.prototype.gettimezoneoffset |
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getTimezoneOffset |
|
#[inline] |
|
pub fn get_timezone_offset() -> f64 { |
|
let offset_seconds = chrono::Local::now().offset().local_minus_utc() as f64; |
|
offset_seconds / 60f64 |
|
} |
|
|
|
/// `Date.prototype.getUTCDate()` |
|
/// |
|
/// The `getUTCDate()` method returns the day (date) of the month in the specified date according to universal time. |
|
/// |
|
/// More information: |
|
/// - [ECMAScript reference][spec] |
|
/// - [MDN documentation][mdn] |
|
/// |
|
/// [spec]: https://tc39.es/ecma262/#sec-date.prototype.getutcdate |
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getUTCDate |
|
pub fn get_utc_date(&self) -> f64 { |
|
self.to_utc().map_or(f64::NAN, |dt| dt.day() as f64) |
|
} |
|
|
|
/// `Date.prototype.getUTCDay()` |
|
/// |
|
/// The `getUTCDay()` method returns the day of the week in the specified date according to universal time, where 0 |
|
/// represents Sunday. |
|
/// |
|
/// More information: |
|
/// - [ECMAScript reference][spec] |
|
/// - [MDN documentation][mdn] |
|
/// |
|
/// [spec]: https://tc39.es/ecma262/#sec-date.prototype.getutcday |
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getUTCDay |
|
pub fn get_utc_day(&self) -> f64 { |
|
self.to_utc().map_or(f64::NAN, |dt| { |
|
let weekday = dt.weekday() as u32; |
|
let weekday = (weekday + 1) % 7; // 0 represents Monday in Chrono |
|
weekday as f64 |
|
}) |
|
} |
|
|
|
/// `Date.prototype.getUTCFullYear()` |
|
/// |
|
/// The `getUTCFullYear()` method returns the year in the specified date according to universal time. |
|
/// |
|
/// More information: |
|
/// - [ECMAScript reference][spec] |
|
/// - [MDN documentation][mdn] |
|
/// |
|
/// [spec]: https://tc39.es/ecma262/#sec-date.prototype.getutcfullyear |
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getUTCFullYear |
|
pub fn get_utc_full_year(&self) -> f64 { |
|
self.to_utc().map_or(f64::NAN, |dt| dt.year() as f64) |
|
} |
|
|
|
/// `Date.prototype.getUTCHours()` |
|
/// |
|
/// The `getUTCHours()` method returns the hours in the specified date according to universal time. |
|
/// |
|
/// More information: |
|
/// - [ECMAScript reference][spec] |
|
/// - [MDN documentation][mdn] |
|
/// |
|
/// [spec]: https://tc39.es/ecma262/#sec-date.prototype.getutchours |
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getUTCHours |
|
pub fn get_utc_hours(&self) -> f64 { |
|
self.to_utc().map_or(f64::NAN, |dt| dt.hour() as f64) |
|
} |
|
|
|
/// `Date.prototype.getUTCMilliseconds()` |
|
/// |
|
/// The `getUTCMilliseconds()` method returns the milliseconds portion of the time object's value. |
|
/// |
|
/// More information: |
|
/// - [ECMAScript reference][spec] |
|
/// - [MDN documentation][mdn] |
|
/// |
|
/// [spec]: https://tc39.es/ecma262/#sec-date.prototype.getutcmilliseconds |
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getUTCMilliseconds |
|
pub fn get_utc_milliseconds(&self) -> f64 { |
|
self.to_utc() |
|
.map_or(f64::NAN, |dt| dt.nanosecond() as f64 / NANOS_IN_MS) |
|
} |
|
|
|
/// `Date.prototype.getUTCMinutes()` |
|
/// |
|
/// The `getUTCMinutes()` method returns the minutes in the specified date according to universal time. |
|
/// |
|
/// More information: |
|
/// - [ECMAScript reference][spec] |
|
/// - [MDN documentation][mdn] |
|
/// |
|
/// [spec]: https://tc39.es/ecma262/#sec-date.prototype.getutcminutes |
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getUTCMinutes |
|
pub fn get_utc_minutes(&self) -> f64 { |
|
self.to_utc().map_or(f64::NAN, |dt| dt.minute() as f64) |
|
} |
|
|
|
/// `Date.prototype.getUTCMonth()` |
|
/// |
|
/// The `getUTCMonth()` returns the month of the specified date according to universal time, as a zero-based value |
|
/// (where zero indicates the first month of the year). |
|
/// |
|
/// More information: |
|
/// - [ECMAScript reference][spec] |
|
/// - [MDN documentation][mdn] |
|
/// |
|
/// [spec]: https://tc39.es/ecma262/#sec-date.prototype.getutcmonth |
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getUTCMonth |
|
pub fn get_utc_month(&self) -> f64 { |
|
self.to_utc().map_or(f64::NAN, |dt| dt.month0() as f64) |
|
} |
|
|
|
/// `Date.prototype.getUTCSeconds()` |
|
/// |
|
/// The `getUTCSeconds()` method returns the seconds in the specified date according to universal time. |
|
/// |
|
/// More information: |
|
/// - [ECMAScript reference][spec] |
|
/// - [MDN documentation][mdn] |
|
/// |
|
/// [spec]: https://tc39.es/ecma262/#sec-date.prototype.getutcseconds |
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getUTCSeconds |
|
pub fn get_utc_seconds(&self) -> f64 { |
|
self.to_utc().map_or(f64::NAN, |dt| dt.second() as f64) |
|
} |
|
|
|
/// `Date.prototype.setDate()` |
|
/// |
|
/// The `setDate()` method sets the day of the `Date` object relative to the beginning of the currently set |
|
/// month. |
|
/// |
|
/// More information: |
|
/// - [ECMAScript reference][spec] |
|
/// - [MDN documentation][mdn] |
|
/// |
|
/// [spec]: https://tc39.es/ecma262/#sec-date.prototype.setdate |
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/setDate |
|
pub fn set_date(&mut self, day: Option<f64>) { |
|
if let Some(day) = day { |
|
self.set_components(false, None, None, Some(day), None, None, None, None) |
|
} else { |
|
self.0 = None |
|
} |
|
} |
|
|
|
/// `Date.prototype.setFullYear()` |
|
/// |
|
/// The `setFullYear()` method sets the full year for a specified date according to local time. Returns new |
|
/// timestamp. |
|
/// |
|
/// More information: |
|
/// - [ECMAScript reference][spec] |
|
/// - [MDN documentation][mdn] |
|
/// |
|
/// [spec]: https://tc39.es/ecma262/#sec-date.prototype.setfullyear |
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/setFullYear |
|
pub fn set_full_year(&mut self, year: Option<f64>, month: Option<f64>, day: Option<f64>) { |
|
if let Some(year) = year { |
|
self.set_components(false, Some(year), month, day, None, None, None, None) |
|
} else { |
|
self.0 = None |
|
} |
|
} |
|
|
|
/// `Date.prototype.setHours()` |
|
/// |
|
/// The `setHours()` method sets the hours for a specified date according to local time, and returns the number |
|
/// of milliseconds since January 1, 1970 00:00:00 UTC until the time represented by the updated `Date` |
|
/// instance. |
|
/// |
|
/// More information: |
|
/// - [ECMAScript reference][spec] |
|
/// - [MDN documentation][mdn] |
|
/// |
|
/// [spec]: https://tc39.es/ecma262/#sec-date.prototype.sethours |
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/setHours |
|
pub fn set_hours( |
|
&mut self, |
|
hour: Option<f64>, |
|
minute: Option<f64>, |
|
second: Option<f64>, |
|
millisecond: Option<f64>, |
|
) { |
|
if let Some(hour) = hour { |
|
self.set_components( |
|
false, |
|
None, |
|
None, |
|
None, |
|
Some(hour), |
|
minute, |
|
second, |
|
millisecond, |
|
) |
|
} else { |
|
self.0 = None |
|
} |
|
} |
|
|
|
/// `Date.prototype.setMilliseconds()` |
|
/// |
|
/// The `setMilliseconds()` method sets the milliseconds for a specified date according to local time. |
|
/// |
|
/// More information: |
|
/// - [ECMAScript reference][spec] |
|
/// - [MDN documentation][mdn] |
|
/// |
|
/// [spec]: https://tc39.es/ecma262/#sec-date.prototype.setmilliseconds |
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/setMilliseconds |
|
pub fn set_milliseconds(&mut self, millisecond: Option<f64>) { |
|
if let Some(millisecond) = millisecond { |
|
self.set_components(false, None, None, None, None, None, None, Some(millisecond)) |
|
} else { |
|
self.0 = None |
|
} |
|
} |
|
|
|
/// `Date.prototype.setMinutes()` |
|
/// |
|
/// The `setMinutes()` method sets the minutes for a specified date according to local time. |
|
/// |
|
/// More information: |
|
/// - [ECMAScript reference][spec] |
|
/// - [MDN documentation][mdn] |
|
/// |
|
/// [spec]: https://tc39.es/ecma262/#sec-date.prototype.setminutes |
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/setMinutes |
|
pub fn set_minutes( |
|
&mut self, |
|
minute: Option<f64>, |
|
second: Option<f64>, |
|
millisecond: Option<f64>, |
|
) { |
|
if let Some(minute) = minute { |
|
self.set_components( |
|
false, |
|
None, |
|
None, |
|
None, |
|
None, |
|
Some(minute), |
|
second, |
|
millisecond, |
|
) |
|
} else { |
|
self.0 = None |
|
} |
|
} |
|
|
|
/// `Date.prototype.setMonth()` |
|
/// |
|
/// The `setMonth()` method sets the month for a specified date according to the currently set year. |
|
/// |
|
/// More information: |
|
/// - [ECMAScript reference][spec] |
|
/// - [MDN documentation][mdn] |
|
/// |
|
/// [spec]: https://tc39.es/ecma262/#sec-date.prototype.setmonth |
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/setMonth |
|
pub fn set_month(&mut self, month: Option<f64>, day: Option<f64>) { |
|
if let Some(month) = month { |
|
self.set_components(false, None, Some(month), day, None, None, None, None) |
|
} else { |
|
self.0 = None |
|
} |
|
} |
|
|
|
/// `Date.prototype.setSeconds()` |
|
/// |
|
/// The `setSeconds()` method sets the seconds for a specified date according to local time. |
|
/// |
|
/// More information: |
|
/// - [ECMAScript reference][spec] |
|
/// - [MDN documentation][mdn] |
|
/// |
|
/// [spec]: https://tc39.es/ecma262/#sec-date.prototype.setseconds |
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/setSeconds |
|
pub fn set_seconds(&mut self, second: Option<f64>, millisecond: Option<f64>) { |
|
if let Some(second) = second { |
|
self.set_components( |
|
false, |
|
None, |
|
None, |
|
None, |
|
None, |
|
None, |
|
Some(second), |
|
millisecond, |
|
) |
|
} else { |
|
self.0 = None |
|
} |
|
} |
|
|
|
/// `Date.prototype.setYear()` |
|
/// |
|
/// The `setYear()` method sets the year for a specified date according to local time. |
|
/// |
|
/// More information: |
|
/// - [ECMAScript reference][spec] |
|
/// - [MDN documentation][mdn] |
|
/// |
|
/// [spec]: https://tc39.es/ecma262/#sec-date.prototype.setyear |
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/setYear |
|
pub fn set_year(&mut self, year: Option<f64>, month: Option<f64>, day: Option<f64>) { |
|
if let Some(mut year) = year { |
|
year += if (0f64..100f64).contains(&year) { |
|
1900f64 |
|
} else { |
|
0f64 |
|
}; |
|
self.set_components(false, Some(year), month, day, None, None, None, None) |
|
} else { |
|
self.0 = None |
|
} |
|
} |
|
|
|
/// `Date.prototype.setTime()` |
|
/// |
|
/// The `setTime()` method sets the Date object to the time represented by a number of milliseconds since |
|
/// January 1, 1970, 00:00:00 UTC. |
|
/// |
|
/// More information: |
|
/// - [ECMAScript reference][spec] |
|
/// - [MDN documentation][mdn] |
|
/// |
|
/// [spec]: https://tc39.es/ecma262/#sec-date.prototype.settime |
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/setTime |
|
pub fn set_time(&mut self, time: Option<f64>) { |
|
if let Some(time) = time { |
|
let secs = (time / 1_000f64) as i64; |
|
let nsecs = ((time % 1_000f64) * 1_000_000f64) as u32; |
|
self.0 = ignore_ambiguity(Local.timestamp_opt(secs, nsecs)).map(|dt| dt.naive_utc()); |
|
} else { |
|
self.0 = None |
|
} |
|
} |
|
|
|
/// `Date.prototype.setUTCDate()` |
|
/// |
|
/// The `setUTCDate()` method sets the day of the month for a specified date according to universal time. |
|
/// |
|
/// More information: |
|
/// - [ECMAScript reference][spec] |
|
/// - [MDN documentation][mdn] |
|
/// |
|
/// [spec]: https://tc39.es/ecma262/#sec-date.prototype.setutcdate |
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/setUTCDate |
|
pub fn set_utc_date(&mut self, day: Option<f64>) { |
|
if let Some(day) = day { |
|
self.set_components(true, None, None, Some(day), None, None, None, None) |
|
} else { |
|
self.0 = None |
|
} |
|
} |
|
|
|
/// `Date.prototype.setFullYear()` |
|
/// |
|
/// The `setFullYear()` method sets the full year for a specified date according to local time. Returns new |
|
/// timestamp. |
|
/// |
|
/// More information: |
|
/// - [ECMAScript reference][spec] |
|
/// - [MDN documentation][mdn] |
|
/// |
|
/// [spec]: https://tc39.es/ecma262/#sec-date.prototype.setutcfullyear |
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/setUTCFullYear |
|
pub fn set_utc_full_year(&mut self, year: Option<f64>, month: Option<f64>, day: Option<f64>) { |
|
if let Some(year) = year { |
|
self.set_components(true, Some(year), month, day, None, None, None, None) |
|
} else { |
|
self.0 = None |
|
} |
|
} |
|
|
|
/// `Date.prototype.setUTCHours()` |
|
/// |
|
/// The `setUTCHours()` method sets the hour for a specified date according to universal time, and returns the |
|
/// number of milliseconds since January 1, 1970 00:00:00 UTC until the time represented by the updated `Date` |
|
/// instance. |
|
/// |
|
/// More information: |
|
/// - [ECMAScript reference][spec] |
|
/// - [MDN documentation][mdn] |
|
/// |
|
/// [spec]: https://tc39.es/ecma262/#sec-date.prototype.setutchours |
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/setUTCHours |
|
pub fn set_utc_hours( |
|
&mut self, |
|
hour: Option<f64>, |
|
minute: Option<f64>, |
|
second: Option<f64>, |
|
millisecond: Option<f64>, |
|
) { |
|
if let Some(hour) = hour { |
|
self.set_components( |
|
true, |
|
None, |
|
None, |
|
None, |
|
Some(hour), |
|
minute, |
|
second, |
|
millisecond, |
|
) |
|
} else { |
|
self.0 = None |
|
} |
|
} |
|
|
|
/// `Date.prototype.setUTCMilliseconds()` |
|
/// |
|
/// The `setUTCMilliseconds()` method sets the milliseconds for a specified date according to universal time. |
|
/// |
|
/// More information: |
|
/// - [ECMAScript reference][spec] |
|
/// - [MDN documentation][mdn] |
|
/// |
|
/// [spec]: https://tc39.es/ecma262/#sec-date.prototype.setutcmilliseconds |
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/setUTCMilliseconds |
|
pub fn set_utc_milliseconds(&mut self, millisecond: Option<f64>) { |
|
if let Some(millisecond) = millisecond { |
|
self.set_components(true, None, None, None, None, None, None, Some(millisecond)) |
|
} else { |
|
self.0 = None |
|
} |
|
} |
|
|
|
/// `Date.prototype.setUTCMinutes()` |
|
/// |
|
/// The `setUTCMinutes()` method sets the minutes for a specified date according to universal time. |
|
/// |
|
/// More information: |
|
/// - [ECMAScript reference][spec] |
|
/// - [MDN documentation][mdn] |
|
/// |
|
/// [spec]: https://tc39.es/ecma262/#sec-date.prototype.setutcminutes |
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/setUTCMinutes |
|
pub fn set_utc_minutes( |
|
&mut self, |
|
minute: Option<f64>, |
|
second: Option<f64>, |
|
millisecond: Option<f64>, |
|
) { |
|
if let Some(minute) = minute { |
|
self.set_components( |
|
true, |
|
None, |
|
None, |
|
None, |
|
None, |
|
Some(minute), |
|
second, |
|
millisecond, |
|
) |
|
} else { |
|
self.0 = None |
|
} |
|
} |
|
|
|
/// `Date.prototype.setUTCMonth()` |
|
/// |
|
/// The `setUTCMonth()` method sets the month for a specified date according to universal time. |
|
/// |
|
/// More information: |
|
/// - [ECMAScript reference][spec] |
|
/// - [MDN documentation][mdn] |
|
/// |
|
/// [spec]: https://tc39.es/ecma262/#sec-date.prototype.setutcmonth |
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/setUTCMonth |
|
pub fn set_utc_month(&mut self, month: Option<f64>, day: Option<f64>) { |
|
if let Some(month) = month { |
|
self.set_components(true, None, Some(month), day, None, None, None, None) |
|
} else { |
|
self.0 = None |
|
} |
|
} |
|
|
|
/// `Date.prototype.setUTCSeconds()` |
|
/// |
|
/// The `setUTCSeconds()` method sets the seconds for a specified date according to universal time. |
|
/// |
|
/// More information: |
|
/// - [ECMAScript reference][spec] |
|
/// - [MDN documentation][mdn] |
|
/// |
|
/// [spec]: https://tc39.es/ecma262/#sec-date.prototype.setutcseconds |
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/setUTCSeconds |
|
pub fn set_utc_seconds(&mut self, second: Option<f64>, millisecond: Option<f64>) { |
|
if let Some(second) = second { |
|
self.set_components( |
|
true, |
|
None, |
|
None, |
|
None, |
|
None, |
|
None, |
|
Some(second), |
|
millisecond, |
|
) |
|
} else { |
|
self.0 = None |
|
} |
|
} |
|
|
|
/// `Date.prototype.toDateString()` |
|
/// |
|
/// The `toDateString()` method returns the date portion of a Date object in English. |
|
/// |
|
/// More information: |
|
/// - [ECMAScript reference][spec] |
|
/// - [MDN documentation][mdn] |
|
/// |
|
/// [spec]: https://tc39.es/ecma262/#sec-date.prototype.todatestring |
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toDateString |
|
pub fn to_date_string(&self) -> String { |
|
self.to_local() |
|
.map(|date_time| date_time.format("%a %b %d %Y").to_string()) |
|
.unwrap_or_else(|| "Invalid Date".to_string()) |
|
} |
|
|
|
/// `Date.prototype.toGMTString()` |
|
/// |
|
/// The `toGMTString()` method converts a date to a string, using Internet Greenwich Mean Time (GMT) conventions. |
|
/// |
|
/// More information: |
|
/// - [ECMAScript reference][spec] |
|
/// - [MDN documentation][mdn] |
|
/// |
|
/// [spec]: https://tc39.es/ecma262/#sec-date.prototype.togmtstring |
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toGMTString |
|
pub fn to_gmt_string(&self) -> String { |
|
self.to_utc_string() |
|
} |
|
|
|
/// `Date.prototype.toISOString()` |
|
/// |
|
/// The `toISOString()` method returns a string in simplified extended ISO format (ISO 8601). |
|
/// |
|
/// More information: |
|
/// - [ISO 8601][iso8601] |
|
/// - [ECMAScript reference][spec] |
|
/// - [MDN documentation][mdn] |
|
/// |
|
/// [iso8601]: http://en.wikipedia.org/wiki/ISO_8601 |
|
/// [spec]: https://tc39.es/ecma262/#sec-date.prototype.toisostring |
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString |
|
pub fn to_iso_string(&self) -> String { |
|
self.to_utc() |
|
// RFC 3389 uses +0.00 for UTC, where JS expects Z, so we can't use the built-in chrono function. |
|
.map(|f| f.format("%Y-%m-%dT%H:%M:%S.%3fZ").to_string()) |
|
.unwrap_or_else(|| "Invalid Date".to_string()) |
|
} |
|
|
|
/// `Date.prototype.toJSON()` |
|
/// |
|
/// The `toJSON()` method returns a string representation of the `Date` object. |
|
/// |
|
/// More information: |
|
/// - [ECMAScript reference][spec] |
|
/// - [MDN documentation][mdn] |
|
/// |
|
/// [spec]: https://tc39.es/ecma262/#sec-date.prototype.tojson |
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toJSON |
|
pub fn to_json(&self) -> String { |
|
self.to_iso_string() |
|
} |
|
|
|
/// `Date.prototype.toTimeString()` |
|
/// |
|
/// The `toTimeString()` method returns the time portion of a Date object in human readable form in American |
|
/// English. |
|
/// |
|
/// More information: |
|
/// - [ECMAScript reference][spec] |
|
/// - [MDN documentation][mdn] |
|
/// |
|
/// [spec]: https://tc39.es/ecma262/#sec-date.prototype.totimestring |
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toTimeString |
|
pub fn to_time_string(&self) -> String { |
|
self.to_local() |
|
.map(|date_time| date_time.format("%H:%M:%S GMT%:z").to_string()) |
|
.unwrap_or_else(|| "Invalid Date".to_string()) |
|
} |
|
|
|
/// `Date.prototype.toUTCString()` |
|
/// |
|
/// The `toUTCString()` method returns a string representing the specified Date object. |
|
/// |
|
/// More information: |
|
/// - [ECMAScript reference][spec] |
|
/// - [MDN documentation][mdn] |
|
/// |
|
/// [spec]: https://tc39.es/ecma262/#sec-date.prototype.toutcstring |
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toUTCString |
|
pub fn to_utc_string(&self) -> String { |
|
self.to_utc() |
|
.map(|date_time| date_time.format("%a, %d %b %Y %H:%M:%S GMT").to_string()) |
|
.unwrap_or_else(|| "Invalid Date".to_string()) |
|
} |
|
|
|
/// `Date.prototype.valueOf()` |
|
/// |
|
/// The `valueOf()` method returns the primitive value of a `Date` object. |
|
/// |
|
/// More information: |
|
/// - [ECMAScript reference][spec] |
|
/// - [MDN documentation][mdn] |
|
/// |
|
/// [spec]: https://tc39.es/ecma262/#sec-date.prototype.valueof |
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/valueOf |
|
pub fn value_of(&self) -> f64 { |
|
self.get_time() |
|
} |
|
|
|
/// `Date.now()` |
|
/// |
|
/// The static `Date.now()` method returns the number of milliseconds elapsed since January 1, 1970 00:00:00 UTC. |
|
/// |
|
/// More information: |
|
/// - [ECMAScript reference][spec] |
|
/// - [MDN documentation][mdn] |
|
/// |
|
/// [spec]: https://tc39.es/ecma262/#sec-date.now |
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/now |
|
pub(crate) fn now(_: &Value, _: &[Value], _: &mut Context) -> Result<Value> { |
|
Ok(Value::from(Utc::now().timestamp_millis() as f64)) |
|
} |
|
|
|
/// `Date.parse()` |
|
/// |
|
/// The `Date.parse()` method parses a string representation of a date, and returns the number of milliseconds since |
|
/// January 1, 1970, 00:00:00 UTC or NaN if the string is unrecognized or, in some cases, contains illegal date |
|
/// values. |
|
/// |
|
/// More information: |
|
/// - [ECMAScript reference][spec] |
|
/// - [MDN documentation][mdn] |
|
/// |
|
/// [spec]: https://tc39.es/ecma262/#sec-date.parse |
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/parse |
|
pub(crate) fn parse(_: &Value, args: &[Value], context: &mut Context) -> Result<Value> { |
|
// This method is implementation-defined and discouraged, so we just require the same format as the string |
|
// constructor. |
|
|
|
if args.is_empty() { |
|
return Ok(Value::number(f64::NAN)); |
|
} |
|
|
|
match DateTime::parse_from_rfc3339(&args[0].to_string(context)?) { |
|
Ok(v) => Ok(Value::number(v.naive_utc().timestamp_millis() as f64)), |
|
_ => Ok(Value::number(f64::NAN)), |
|
} |
|
} |
|
|
|
/// `Date.UTC()` |
|
/// |
|
/// The `Date.UTC()` method accepts parameters similar to the `Date` constructor, but treats them as UTC. |
|
/// |
|
/// More information: |
|
/// - [ECMAScript reference][spec] |
|
/// - [MDN documentation][mdn] |
|
/// |
|
/// [spec]: https://tc39.es/ecma262/#sec-date.utc |
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/UTC |
|
pub(crate) fn utc(_: &Value, args: &[Value], context: &mut Context) -> Result<Value> { |
|
let year = args |
|
.get(0) |
|
.map_or(Ok(f64::NAN), |value| value.to_number(context))?; |
|
let month = args |
|
.get(1) |
|
.map_or(Ok(1f64), |value| value.to_number(context))?; |
|
let day = args |
|
.get(2) |
|
.map_or(Ok(1f64), |value| value.to_number(context))?; |
|
let hour = args |
|
.get(3) |
|
.map_or(Ok(0f64), |value| value.to_number(context))?; |
|
let min = args |
|
.get(4) |
|
.map_or(Ok(0f64), |value| value.to_number(context))?; |
|
let sec = args |
|
.get(5) |
|
.map_or(Ok(0f64), |value| value.to_number(context))?; |
|
let milli = args |
|
.get(6) |
|
.map_or(Ok(0f64), |value| value.to_number(context))?; |
|
|
|
if !check_normal_opt!(year, month, day, hour, min, sec, milli) { |
|
return Ok(Value::number(f64::NAN)); |
|
} |
|
|
|
let year = year as i32; |
|
let month = month as u32; |
|
let day = day as u32; |
|
let hour = hour as u32; |
|
let min = min as u32; |
|
let sec = sec as u32; |
|
let milli = milli as u32; |
|
|
|
let year = if (0..=99).contains(&year) { |
|
1900 + year |
|
} else { |
|
year |
|
}; |
|
|
|
NaiveDate::from_ymd_opt(year, month + 1, day) |
|
.and_then(|f| f.and_hms_milli_opt(hour, min, sec, milli)) |
|
.map_or(Ok(Value::number(f64::NAN)), |f| { |
|
Ok(Value::number(f.timestamp_millis() as f64)) |
|
}) |
|
} |
|
} |
|
|
|
/// The abstract operation `thisTimeValue` takes argument value. |
|
/// |
|
/// In following descriptions of functions that are properties of the Date prototype object, the phrase “this |
|
/// Date object” refers to the object that is the this value for the invocation of the function. If the `Type` of |
|
/// the this value is not `Object`, a `TypeError` exception is thrown. The phrase “this time value” within the |
|
/// specification of a method refers to the result returned by calling the abstract operation `thisTimeValue` with |
|
/// the this value of the method invocation passed as the argument. |
|
/// |
|
/// More information: |
|
/// - [ECMAScript reference][spec] |
|
/// |
|
/// [spec]: https://tc39.es/ecma262/#sec-thistimevalue |
|
#[inline] |
|
pub fn this_time_value(value: &Value, context: &mut Context) -> Result<Date> { |
|
if let Value::Object(ref object) = value { |
|
if let ObjectData::Date(ref date) = object.borrow().data { |
|
return Ok(*date); |
|
} |
|
} |
|
Err(context.construct_type_error("'this' is not a Date")) |
|
}
|
|
|