1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
//! Boa's implementation of `Temporal.Now` ECMAScript global namespace object.
use crate::{
Context, JsArgs, JsObject, JsResult, JsString, JsSymbol, JsValue,
builtins::{BuiltInBuilder, BuiltInObject, IntrinsicObject},
context::intrinsics::Intrinsics,
js_string,
property::Attribute,
realm::Realm,
string::StaticJsStrings,
};
use temporal_rs::{
TemporalError, TemporalResult, TimeZone,
host::{HostClock, HostHooks, HostTimeZone},
now::Now as InnerNow,
provider::TimeZoneProvider,
unix_time::EpochNanoseconds,
};
use super::{
create_temporal_date, create_temporal_datetime, create_temporal_instant, create_temporal_time,
create_temporal_zoneddatetime, to_temporal_timezone_identifier,
};
/// The `Temporal.Now` global namespace object
///
/// More information:
///
/// - [ECMAScript Temporal proposal][spec]
/// - [MDN reference][mdn]
///
/// [spec]: https://tc39.es/proposal-temporal/#sec-temporal-now-object
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Now
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Now;
impl IntrinsicObject for Now {
/// Initializes the `Temporal.Now` object.
fn init(realm: &Realm) {
// is an ordinary object.
// has a [[Prototype]] internal slot whose value is %Object.prototype%.
// is not a function object.
// does not have a [[Construct]] internal method; it cannot be used as a constructor with the new operator.
// does not have a [[Call]] internal method; it cannot be invoked as a function.
BuiltInBuilder::with_intrinsic::<Self>(realm)
.static_property(
JsSymbol::to_string_tag(),
StaticJsStrings::NOW_TAG,
Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
)
.static_method(Self::time_zone_id, js_string!("timeZoneId"), 0)
.static_method(Self::instant, js_string!("instant"), 0)
.static_method(Self::plain_date_time_iso, js_string!("plainDateTimeISO"), 0)
.static_method(Self::zoned_date_time_iso, js_string!("zonedDateTimeISO"), 0)
.static_method(Self::plain_date_iso, js_string!("plainDateISO"), 0)
.static_method(Self::plain_time_iso, js_string!("plainTimeISO"), 0)
.build();
}
fn get(intrinsics: &Intrinsics) -> JsObject {
intrinsics.objects().now()
}
}
impl BuiltInObject for Now {
const NAME: JsString = StaticJsStrings::NOW_NAME;
}
impl Now {
/// 2.2.1 `Temporal.Now.timeZoneId ( )`
///
/// Returns the currently active system time zone identifier.
///
/// More information:
/// - [ECMAScript specification][spec]
/// - [MDN reference][mdn]
///
/// [spec]: https://tc39.es/proposal-temporal/#sec-temporal.now.timezone
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Now/timeZoneId
fn time_zone_id(_: &JsValue, _: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
// TODO: this should be optimized once system time zone is in context
// 1. Return ! SystemTimeZone().
let context: &Context = context;
let time_zone = context.get_system_time_zone(context.tz_provider())?;
Ok(JsString::from(time_zone.identifier_with_provider(context.tz_provider())?).into())
}
/// 2.2.2 `Temporal.Now.instant()`
///
/// Returns the current time as an `Temporal.Instant`.
///
/// More information:
/// - [ECMAscript specification][spec]
/// - [MDN reference][mdn]
///
/// [spec]: https://tc39.es/proposal-temporal/#sec-temporal.now.instant
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Now/instant
fn instant(_: &JsValue, _: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
let now: InnerNow<&Context> = InnerNow::new(context);
let instant = now.instant()?;
create_temporal_instant(instant, None, context)
}
/// 2.2.3 `Temporal.Now.plainDateTimeISO ( [ temporalTimeZoneLike ] )`
///
/// Returns the current date and time as a `Temporal.PlainDateTime` with an ISO8601 calendar.
///
/// Takes an optional time zone, which defaults to the sytem time zone if undefined.
///
/// More information:
/// - [ECMAscript specification][spec]
/// - [MDN reference][mdn]
///
/// [spec]: https://tc39.es/proposal-temporal/#sec-temporal.now.plaindatetimeiso
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Now/plainDateTimeISO
fn plain_date_time_iso(
_: &JsValue,
args: &[JsValue],
context: &mut Context,
) -> JsResult<JsValue> {
let time_zone = args
.get_or_undefined(0)
.map(|v| to_temporal_timezone_identifier(v, context))
.transpose()?;
let now: InnerNow<&Context> = InnerNow::new(context);
let datetime = now.plain_date_time_iso_with_provider(time_zone, context.tz_provider())?;
create_temporal_datetime(datetime, None, context).map(Into::into)
}
/// 2.2.4 `Temporal.Now.zonedDateTimeISO ( [ temporalTimeZoneLike ] )`
///
/// Returns the current date and time as a `Temporal.ZonedDateTime` with an ISO8601 calendar.
///
/// Takes an optional time zone, which defaults to the sytem time zone if undefined.
///
/// More information:
/// - [ECMAscript specification][spec]
/// - [MDN reference][mdn]
///
/// [spec]: https://tc39.es/proposal-temporal/#sec-temporal.now.zoneddatetimeiso
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Now/zonedDateTimeISO
fn zoned_date_time_iso(
_: &JsValue,
args: &[JsValue],
context: &mut Context,
) -> JsResult<JsValue> {
let time_zone = args
.get_or_undefined(0)
.map(|v| to_temporal_timezone_identifier(v, context))
.transpose()?;
let now: InnerNow<&Context> = InnerNow::new(context);
let zdt = now.zoned_date_time_iso_with_provider(time_zone, context.tz_provider())?;
create_temporal_zoneddatetime(zdt, None, context).map(Into::into)
}
/// 2.2.5 `Temporal.Now.plainDateISO ( [ temporalTimeZoneLike ] )`
///
/// Returns the current date as a `Temporal.PlainDate` with an ISO8601 calendar.
///
/// Takes an optional time zone, which defaults to the sytem time zone if undefined.
///
/// More information:
/// - [ECMAscript specification][spec]
/// - [MDN reference][mdn]
///
/// [spec]: https://tc39.es/proposal-temporal/#sec-temporal.now.plaindateiso
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Now/plainDateISO
fn plain_date_iso(_: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
let time_zone = args
.get_or_undefined(0)
.map(|v| to_temporal_timezone_identifier(v, context))
.transpose()?;
let now: InnerNow<&Context> = InnerNow::new(context);
let pd = now.plain_date_iso_with_provider(time_zone, context.tz_provider())?;
create_temporal_date(pd, None, context).map(Into::into)
}
/// 2.2.6 `Temporal.Now.plainTimeISO ( [ temporalTimeZoneLike ] )`
///
/// Returns the current time as a `Temporal.PlainTime` with an ISO8601 calendar.
///
/// Takes an optional time zone, which defaults to the sytem time zone if undefined.
///
/// More information:
/// - [ECMAscript specification][spec]
/// - [MDN reference][mdn]
///
/// [spec]: https://tc39.es/proposal-temporal/#sec-temporal.now.plaintimeiso
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Now/plainTimeISO
fn plain_time_iso(_: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
let time_zone = args
.get_or_undefined(0)
.map(|v| to_temporal_timezone_identifier(v, context))
.transpose()?;
let now: InnerNow<&Context> = InnerNow::new(context);
let pt = now.plain_time_with_provider(time_zone, context.tz_provider())?;
create_temporal_time(pt, None, context).map(Into::into)
}
}
impl HostHooks for &Context {}
impl HostClock for &Context {
fn get_host_epoch_nanoseconds(&self) -> TemporalResult<EpochNanoseconds> {
Ok(EpochNanoseconds::from(
self.clock().now().nanos_since_epoch() as i128,
))
}
}
impl HostTimeZone for &Context {
fn get_host_time_zone(&self, provider: &impl TimeZoneProvider) -> TemporalResult<TimeZone> {
iana_time_zone::get_timezone()
.map_err(|_| TemporalError::range().with_message("Unable to fetch system time zone"))
.and_then(|id| TimeZone::try_from_str_with_provider(&id, provider))
}
}