@@ -104,18 +104,18 @@ ago? Well, plenty!
104
104
- Internal utility methods were moved to the Neri-Schneider algorithms.
105
105
106
106
In general, the implementation was moving along at a pretty decent pace,
107
- and would continue to do so well into roughly April of 2025 (mostly helped
108
- along by a group of students from the University of Bergen who began
109
- helping with the implementation in January 2025), but there were two
110
- final hurdles: time zone data and ` ZonedDateTime ` .
107
+ and would continue to do so well into roughly April of 2025 (mostly
108
+ helped along by a group of students from the University of Bergen who
109
+ began helping with the implementation in January 2025), but there were
110
+ two final hurdles: time zone data and ` ZonedDateTime ` .
111
111
112
112
Time zones and time zone data are a topic for a completely different
113
- blog post in the future. But suffice to say, it took a little bit of time, and
114
- ` ZonedDateTime ` was developed alongside the time zone data.
113
+ blog post in the future. But suffice to say, it took a little bit of
114
+ time, and ` ZonedDateTime ` was developed alongside the time zone data.
115
115
116
- This work began in November 2024, by stubbing out the general support of time zone data
117
- sourcing and ` ZonedDateTime ` . Then, after almost 10 months of general work, the
118
- last major updates to time zone data
116
+ This work began in November 2024, by stubbing out the general support of
117
+ time zone data sourcing and ` ZonedDateTime ` . Then, after almost 10
118
+ months of general work, the last major updates to time zone data
119
119
sourcing were merged at the beginning of September in PR
120
120
[ #537 ] ( https://github.com/boa-dev/temporal/pull/537 ) and
121
121
[ #538 ] ( https://github.com/boa-dev/temporal/pull/538 ) . As a result, we
@@ -124,7 +124,8 @@ were finally able to stabilize `temporal_rs`'s API for a 0.1 release.
124
124
That's it for our brief background on ` temporal_rs ` .
125
125
126
126
Date and time is hard, and there is a lot that goes into it, especially
127
- when it comes to calendars and time zones. But that's what makes it interesting!
127
+ when it comes to calendars and time zones. But that's what makes it
128
+ interesting!
128
129
129
130
## Temporal API overview
130
131
@@ -140,13 +141,13 @@ represented in `temporal_rs` by the `Calendar` and `TimeZone` types.
140
141
| PlainDateTime | Calendar date and wall-clock time | yes | no |
141
142
| ZonedDateTime | Calendar date and exact time | yes | yes |
142
143
| Instant | Exact time | no | no |
143
- | Duration | None | no | no |
144
+ | Duration | Time span | no | no |
144
145
| PlainYearMonth | Calendar date | yes | no |
145
146
| PlainMonthDay | Calendar date | yes | no |
146
147
147
- There is also ` Now ` , which provides access to the current host
148
- system time. This can then be used to map the current ` Instant ` to any
149
- of the above Temporal types.
148
+ There is also ` Now ` , which provides access to the current host system
149
+ time. This can then be used to map the current ` Instant ` to any of the
150
+ above Temporal types.
150
151
151
152
The types in the same categories will share similar APIs that are
152
153
related to that category. For instance, all types that support a
@@ -185,11 +186,11 @@ native Rust and ECMAScript implementers.
185
186
186
187
While we plan to go into time zones in a completely separate post, one
187
188
of ` temporal_rs ` 's primary design decisions was to offer a way to
188
- customize the source of time zone data, while also having an optional default
189
- source for convenience. The time zone
190
- data sourcing functionality is provided by ` timezone_provider ` , a sister
191
- crate of ` temporal_rs ` that provides a project agnostic crate alongside
192
- default trait implementations for sourcing time zone data.
189
+ customize the source of time zone data, while also having an optional
190
+ default source for convenience. The time zone data sourcing
191
+ functionality is provided by ` timezone_provider ` , a sister crate of
192
+ ` temporal_rs ` that provides a project agnostic crate alongside default
193
+ trait implementations for sourcing time zone data.
193
194
194
195
We currently expose three types of provider implementations:
195
196
@@ -222,11 +223,12 @@ temporal_rs = "0.1.0"
222
223
```
223
224
224
225
By default, ` temporal_rs ` will use a compiled time zone data provider
225
- that compiles the time zone data into the binary. If you prefer to
226
- use the file system time zone database or a zoneinfo64 resource bundle,
227
- you can disable the compiled time zone data by setting ` default-features = false ` ;
228
- you can import your preferred provider from the ` timezone_provider ` crate,
229
- then provide it to any API that requires a time zone provider.
226
+ that compiles the time zone data into the binary. If you prefer to use
227
+ the file system time zone database or a zoneinfo64 resource bundle, you
228
+ can disable the compiled time zone data by setting
229
+ ` default-features = false ` ; you can import your preferred provider from
230
+ the ` timezone_provider ` crate, then provide it to any API that requires
231
+ a time zone provider.
230
232
231
233
For instance, to use the ` FsTzdbProvider ` , your ` Cargo.toml ` would look
232
234
like the following.
@@ -236,8 +238,9 @@ timezone_provider = { version = "0.0.17", features = ["tzif"] }
236
238
temporal_rs = { version = " 0.1.0" , default-features = false , features = [" sys" ]}
237
239
```
238
240
239
- The ` sys ` feature for ` temporal_rs ` enables the default implementation for ` Now ` ,
240
- and the ` tzif ` feature for ` timezone_provider ` enables the ` FsTzdbProvider ` .
241
+ The ` sys ` feature for ` temporal_rs ` enables the default implementation
242
+ for ` Now ` , and the ` tzif ` feature for ` timezone_provider ` enables the
243
+ ` FsTzdbProvider ` .
241
244
242
245
Please note: ` timezone_provider ` is still considered unstable for the
243
246
near future.
@@ -252,7 +255,7 @@ features.
252
255
``` rust
253
256
use temporal_rs :: Temporal ;
254
257
255
- // Get today's date
258
+ // We can easily retrieve today's date using `Temporal::now()`
256
259
let today = Temporal :: now (). plain_date_iso (None ). unwrap ()
257
260
```
258
261
@@ -265,10 +268,10 @@ Temporal provides a nice API for working with date and date/time via
265
268
use std :: convert :: TryFrom ;
266
269
use temporal_rs :: {Calendar , Temporal , options :: DifferenceSettings , partial :: PartialDuration };
267
270
268
- // Get today's date
271
+ // We can get today's date
269
272
let today = Temporal :: now (). plain_date_iso (None ). unwrap ();
270
273
271
- // We can add a Duration.
274
+ // We can also add a Duration.
272
275
let partial = PartialDuration :: empty (). with_days (1 );
273
276
let tomorrow = today . add (& partial . try_into (). unwrap (), None ). unwrap ();
274
277
@@ -281,7 +284,7 @@ let diff = today
281
284
let tomorrow_japanese = tomorrow . with_calendar (Calendar :: JAPANESE );
282
285
283
286
// We can retrieve the calendar's RFC9557 string
284
- println! (" {tomorrow_japanese}" );
287
+ println! (" {tomorrow_japanese}" ); // 2025-09-23[u-ca=japanese]
285
288
```
286
289
287
290
#### Working with dates and time zones
@@ -293,35 +296,35 @@ You can also easily work with dates and time zones with the
293
296
use temporal_rs :: options :: {DifferenceSettings , Disambiguation , OffsetDisambiguation , Unit };
294
297
use temporal_rs :: {Calendar , Temporal , TimeZone , ZonedDateTime };
295
298
296
- // Parse a ZonedDateTime from utf8 bytes.
299
+ // We can parse a ZonedDateTime from utf8 bytes.
297
300
let zdt = ZonedDateTime :: from_utf8 (
298
301
b " 2025-03-01T11:16:10Z[America/Chicago][u-ca=iso8601]" ,
299
302
Disambiguation :: Compatible ,
300
303
OffsetDisambiguation :: Reject ,
301
304
)
302
305
. unwrap ();
303
306
304
- // Change the time zone.
305
- let zurich_zone = TimeZone :: try_from_str (" Europe/Zurich" ). unwrap ();
306
- let _zdt_zurich = zdt . with_timezone (zurich_zone ). unwrap ();
307
-
308
- // Or get the current ZonedDateTime
307
+ // We can get the current ZonedDateTime
309
308
let today = Temporal :: now (). zoned_date_time_iso (None ). unwrap ();
310
309
311
- // Difference the two `ZonedDateTime`s
310
+ // And we can easily get the difference the two `ZonedDateTime`s
312
311
let mut options = DifferenceSettings :: default ();
313
312
options . largest_unit = Some (Unit :: Year );
314
313
let diff = today . since (& zdt , options ). unwrap ();
315
- println! (" {diff}" );
314
+ println! (" {diff}" ); // P6M22D
316
315
317
- // Change the calendar
316
+ // We can change the calendar for the `ZonedDateTime`
318
317
let today_coptic = today . with_calendar (Calendar :: COPTIC );
319
- println! (" {today_coptic}" );
318
+ println! (" {today_coptic}" ); // 2025-09-23T12:36:56.914365368-05:00[America/Chicago][u-ca=coptic]
319
+
320
+ // We can also easily convert it into just the date.
321
+ let today_plain_date_coptic = today_coptic . to_plain_date ();
322
+ println! (" {today_coptic}" ); // 2025-09-23[u-ca=coptic]
320
323
```
321
324
322
325
While we can extend these examples further, a more fun exercise for the
323
- reader would be to take a look at the [ Temporal cookbook] [ cookbook ] , as it
324
- displays the utility of the Temporal API using JavaScript and all of
326
+ reader would be to take a look at the [ Temporal cookbook] [ cookbook ] , as
327
+ it displays the utility of the Temporal API using JavaScript and all of
325
328
these examples are now usable from Rust as well.
326
329
327
330
## FFI and engine adoption
@@ -348,26 +351,26 @@ that provides some level of flexibility.
348
351
349
352
Secondly, with how large the API is, ` temporal_rs ` streamlines the
350
353
ability to adopt the Temporal API for any current and future
351
- implementations, since any future updates can
352
- be done primarily in one place and then released downstream. While it's
353
- easy to say: "just use our library" to promote adoption. Seriously, just
354
- use the library. The Temporal API is massive from an implementation
355
- perspective and the glue code plus ` temporal_rs ` is relatively trivial
356
- in comparison to a fresh, from scratch implementation.
354
+ implementations, since any future updates can be done primarily in one
355
+ place and then released downstream. ` temporal_rs ` plus the engine
356
+ specific integration code, while not a small amount of code, is a
357
+ relatively trivial amount of work in comparison to a from scratch
358
+ implementation.
357
359
358
360
Third, with adoption from multiple engines, ` temporal_rs ` benefits via
359
361
external test coverage beyond the native Rust unit tests. For instance,
360
- of the engines that offer conformance numbers (Boa, Kiesel, and V8), all
361
- of them are currently north of 95% conformance with V8 reaching the
362
- highest at around 99% conformance. There is still a small disparity in
363
- conformance, but this can be explained by the absence of some related features, i.e. Boa still hasn't completed its ` Intl.DateTimeFormat `
364
- implementation yet so it fails all ECMA402 ` toLocaleString ` tests.
365
- Nonetheless, we can still be fairly confident in the general correctness of
366
- ` temporal_rs ` , and any potential bugs will ideally be found and
367
- addressed fairly quickly.
368
-
369
- In general, ` temporal_rs ` is a pretty good reference case for setting up a
370
- Rust library over FFI, being used in both a C++ and Zig codebase.
362
+ looking at the engines that offer conformance numbers (Boa, Kiesel, and
363
+ V8), every Temporal implementation is currently north of 95% conformance
364
+ with V8 reaching the highest at around 99% conformance. There is still a
365
+ small disparity in conformance, but this can be explained by the absence
366
+ of some related features, i.e. Boa still hasn't completed its
367
+ ` Intl.DateTimeFormat ` implementation yet so it fails all ECMA402
368
+ ` toLocaleString ` tests. Nonetheless, we can still be fairly confident in
369
+ the general correctness of ` temporal_rs ` , and any potential bugs will
370
+ ideally be found and addressed fairly quickly.
371
+
372
+ In general, ` temporal_rs ` is a pretty good reference case for setting up
373
+ a Rust library over FFI, being used in both a C++ and Zig codebase.
371
374
372
375
## Conclusion
373
376
@@ -379,14 +382,15 @@ versioning bumps based on feedback or the Temporal specification.
379
382
380
383
Our current plan is to have any remaining issues addressed and the API
381
384
fully stable, in preparation for the "stabilization" of Temporal and its
382
- subsequent introduction to the ECMAScript specification.
383
- Once Temporal is "stabilized", we will move forward with a 1.0 release.
385
+ subsequent introduction to the ECMAScript specification. Once Temporal
386
+ is "stabilized", we will move forward with a 1.0 release.
384
387
385
388
` temporal_rs ` started as an interesting experiment in creating an engine
386
389
agnostic library of the Temporal API that could also be usable as a
387
- date/time library in native Rust code, but seeing the wide adoption we've
388
- been getting from other engines, we can say that this project has been a great success! And with any
389
- luck, we hope this library will find its place in the Rust ecosystem as well.
390
+ date/time library in native Rust code, but seeing the wide adoption
391
+ we've been getting from other engines, we can say that this project has
392
+ been a great success! And with any luck, we hope this library will find
393
+ its place in the Rust ecosystem as well.
390
394
391
395
## Special thanks
392
396
0 commit comments