Skip to content

Commit b7db68a

Browse files
committed
First pass at a release post
1 parent 7752d46 commit b7db68a

File tree

1 file changed

+258
-0
lines changed

1 file changed

+258
-0
lines changed

blog/temporal-release.md

Lines changed: 258 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,258 @@
1+
# Temporal_rs release v0.1
2+
3+
After almost 2+ years of development, we're pleased to announce the 0.1 release
4+
of `temporal_rs`. A calendar and time zone aware Rust date/time library based on
5+
ECMAScript's Temporal API.
6+
7+
`temporal_rs` is a highly conformant implementation of the Temporal API in Rust that can be
8+
used in native Rust code or embedded into ECMAScript engines / interpreters to support their
9+
implementations.
10+
11+
Currently, `temporal_rs` is being used by Boa, Kiesel, V8, and Yavashark for their Temporal
12+
implementations (but more on that later).
13+
14+
### TODO: tentative post summary
15+
16+
To celebrate the 0.1 release of `temporal_rs`, we'll cover a short background of the Temporal
17+
implementation in Boa and why `temporal_rs` was split into it's own crate, then we'll walk
18+
through a couple brief examples of using `temporal_rs`, and finally we'll talk about the
19+
FFI and engine adoption.
20+
21+
## Some background and history
22+
23+
In this section, we'll reflect on the overall implementation, some general difficulties
24+
we had along with lessons learned.
25+
26+
The temporal implementation in Boa began over two years ago and culminated in a
27+
absolutely massive PR, [#3277](https://github.com/boa-dev/boa/pull/3277) (ASIDE from
28+
nekevss: mea culpa).
29+
30+
The PR itself stubbed out a lot of the methods, implemented some Duration and Instant
31+
functionality, and started the support for custom calendars. There were, however, 2
32+
major take aways from this PR: first, Temporal is a massive specification update; and
33+
second, there is a lot of room to potentially optimize Temporal if we did not deal with
34+
`JsValue` directly.
35+
36+
After a couple weeks, the question came up amongst the maintainers: could we separate
37+
the Boa's implementation off into a completely separate library? Sure, why not.
38+
39+
The first commit of then `boa_temporal` occurred in PR [#3461](https://github.com/boa-dev/boa/pull/3461),
40+
which moved the majority of the existing functionality into a separate crate with the
41+
primary concern at the time of being able to support custom calendars, which was then
42+
ported into it's [own repository later](https://github.com/boa-dev/temporal/pull/1) a
43+
couple months later.
44+
45+
These early versions of `temporal_rs` were vastly different than the 0.1 release version,
46+
and it can be easily seen with a short glance through the first PR. `temporal_rs` needed
47+
to support custom calendars and time zones. In order to do this, each calendar was generic
48+
on a `CalendarProtocol` trait.
49+
50+
So to create a new date in the early versions of `temporal_rs`, you would have something
51+
like the following code:
52+
53+
```rust
54+
use temporal_rs::{Date, Calendar, options::ArithmeticOverflow};
55+
let date = Date::new_with_overflow(
56+
2025,
57+
9,
58+
21,
59+
Calendar::<()>::from_str("iso8601").unwrap(),
60+
ArithmeticOverflow::Reject
61+
).unwrap();
62+
```
63+
64+
Luckily, custom calendar and time zone were removed from the specification. In the first
65+
half of 2024, so `temporal_rs` was able to remove that support, which greatly benefitted
66+
the entire API. For instance, here's the same code in the 0.1 version of `temporal_rs`:
67+
68+
```rust
69+
use temporal_rs::PlainDate;
70+
let date = PlainDate::try_new_iso(2025, 9, 21).unwrap();
71+
```
72+
73+
That was 2024 though, we're in September of 2025, so what's happened since the crate
74+
was initially split off from Boa over a year and a half ago. Well, plenty! In early 2024
75+
the internal algorithm for `Duration` was overhauled in the specification, so `temporal_rs`
76+
had a complete rewrite of `Duration`.
77+
78+
The general implementation was moving along as well, but there was one final hurdle: time
79+
zone data and `ZonedDateTime`. Time zones and time zone data are a topic for a completely
80+
different blog post in the future. But suffice to say, it took a little time, and the
81+
`ZonedDateTime` implementation developed alongside the development of time zone data.
82+
83+
That's it for our brief background on `temporal_rs`.
84+
85+
Date and time is hard, and there is a lot that goes into it, especially when it comes to
86+
calendars and time zones. But that also doesn't mean its not interesting.
87+
88+
## Using `temporal_rs`
89+
90+
Let's dive into using `temporal_rs` from Rust.
91+
92+
### Setup
93+
94+
First, add `temporal_rs` as a dependency.
95+
96+
```bash
97+
cargo add temporal_rs
98+
```
99+
100+
By default, `temporal_rs` will use a compiled time zone data provider that compiles the
101+
time zone data into the binary. There are a few options that can be used for time zone
102+
providers:
103+
104+
- CompiledTzdbProvider (current default), a provider that parses time zone data at
105+
runtime using data compiled into the binary.
106+
- FsTzdbProvider, a provider that parses time zone data at runtime using the file system time zone
107+
database (if it exists for that OS).
108+
- ZoneInfo64TzdbProvider, a provider using ICU's zoneinfo64 resource bundle.
109+
110+
Currently, we do not have a way to select certain provider's via feature flag, but a provider
111+
can be selected by setting `no-default-features` and importing the provider from
112+
`timezone_provider` for the API's that require time zone data.
113+
114+
### The Temporal API
115+
116+
The Temporal API revolves around a group of 8 date and time types, each of which corresponds
117+
to a different aspect of date and time with varying support for `Calendar`s and `TimeZone`s.
118+
119+
| Temporal type | Category | Calendar support | Time zone support |
120+
|----------------|--------------------------------------|--------------------|--------------------|
121+
| PlainDate | Calendar date | yes | no |
122+
| PlainTime | Wall-clock time | no | no |
123+
| PlainDateTime | Calendar date and wall-clock time | yes | no |
124+
| ZonedDateTime | Calendar date and exact time | yes | yes |
125+
| Instant | Exact time | no | no |
126+
| Duration | None | no | no |
127+
| PlainYearMonth | Calendar date | yes | no |
128+
| PlainMonthDay | Calendar date | yes | no |
129+
130+
There is also the `Now`, which provides access to the current host system time. This can then
131+
be used to map the current `Instant` to any of the above Temporal types.
132+
133+
The types in the same categories will share similar APIs that are related to that category. For instance,
134+
all types that support a calendar date will have a `with_calendar` method as well as calendar date
135+
accessors. The exception being PlainYearMonth and PlainMonthDay which are missing their day and
136+
year, respectively ... for all intents and purposes.
137+
138+
### Some examples
139+
140+
You retrieve the current date using the `Temporal` type.
141+
142+
```rust
143+
use temporal_rs::Temporal;
144+
let today = Temporal::now().to_plain_date_iso(None).unwrap()
145+
146+
```
147+
148+
With the current date, we can now do a variety of operations the date.
149+
150+
```rust
151+
use temporal_rs::{Temporal, Calendar, partial::PartialDuration, options::DifferenceSettings};
152+
let today = Temporal::now().to_plain_date_iso(None).unwrap();
153+
154+
// We can add a Duration.
155+
let partial = PartialDuration::empty().with_days(1);
156+
let tomorrow = today.add(Duration::from_partial_duration(partial).unwrap()).unwrap();
157+
158+
// We can get the difference two dates
159+
let diff = today.since(&tomorrow, DifferenceSettings::default()).unwrap();
160+
161+
// We can change the calendar
162+
let tomorrow_japanese = tomorrow.with_calendar(Calendar::JAPANESE);
163+
164+
// We can retrieve the calendar's RFC9557 string
165+
let tomorrow_string = tomorrow_japanese.to_string();
166+
```
167+
168+
We can also easily deal with a `ZonedDateTime` as well.
169+
170+
```rust
171+
use temporal_rs::{ZonedDateTime, TimeZone, Temporal};
172+
use temporal_rs::options::{Disambiguation, OffsetDisambiguation, DifferenceSettings};
173+
174+
// Parse a ZonedDateTime from utf8 bytes.
175+
let zdt = ZonedDateTime::from_utf8(
176+
b"2025-03-01T11:16:10Z[America/Chicago][u-ca=iso8601]",
177+
Disambiguation::Compatible,
178+
OffsetDisambiguation::Reject,
179+
).unwrap();
180+
181+
// Change the time zone.
182+
let zurich_zone = TimeZone::try_from_str("Europe/Zurich").unwrap();
183+
let zdt_zurich = zdt.with_timezone(zurich_zone).unwrap();
184+
185+
// Or get the current ZonedDateTime
186+
let today = Temporal::now().zoned_date_time_iso(None).unwrap();
187+
188+
// Difference the two `ZonedDateTime`s
189+
let diff = today.since(&zdt, DifferenceSettings::default()).unwrap();
190+
191+
// Change the calendar
192+
let today_coptic = today.with_calendar(Calendar::COPTIC);
193+
```
194+
195+
While we can extend these examples further, a more fun exercise for the reader would be taking
196+
a look at the [Temporal cookbook](https://tc39.es/proposal-temporal/docs/cookbook.html)
197+
as it displays the utility of the Temporal API using JavaScript.
198+
199+
## FFI and engine adoption
200+
201+
As previously stated, `temporal_rs` is used in Boa, Kiesel, and V8. There's just one thing,
202+
the latter of the two are ECMAScript implementations written in Zig and C++, respectively,
203+
not Rust. This was made possible through `temporal_rs`'s sister crate `temporal_capi`,
204+
a FFI library that provides C and C++ bindings to `temporal_rs`.
205+
206+
The bindings are autogenerated via [Diplomat](https://github.com/rust-diplomat/diplomat), which
207+
is a project for generating FFI definitions for Rust libraries. In general, it's a really cool
208+
project and would definitely recommend checking it out if you're looking to generate FFI
209+
bindings for other languages for your Rust library.
210+
211+
There is some added benefits to offering C and C++ bindings beyond the classic: oh, let's
212+
(re)write it in Rust.
213+
214+
First, this allows other languages and engines to benefit from Rust's type system and memory
215+
safety guarantees without having to rewrite everything in Rust. It's a more modular and
216+
incremental approach that provides some level of flexibility.
217+
218+
Secondly, with how large the API is, `temporal_rs` streamlines the ability to adopt the
219+
Temporal API for any current and future implementations, alongside any future update
220+
that needs to be made can be done primarily in one place and then released downstream. While
221+
it's easy to say: "just use our library" to promote adoption. Seriously, just use the
222+
library. The Temporal API is massive from an implementation perspective and the glue
223+
code plus `temporal_rs` is relatively trivial in comparison to a fresh implementation.
224+
225+
Third, with adoption from multiple engines, `temporal_rs` benefits via further test coverage
226+
beyond the native unit tests. For instance, of the engines that offer conformance numbers
227+
(Boa, Kiesel, and V8), all of them are currently north of 95% conformance with V8 reaching
228+
the highest at around 99% conformance. The conformance difference between the engines being
229+
due to the current implementation state of other features, i.e. Boa still hasn't completed
230+
its `Intl.DateTimeFormat` implementation yet so it fails all ECMA402 `toLocaleString` tests.
231+
As a result though, we can be fairly confident in the general correctness of `temporal_rs`,
232+
and any potential bugs will ideally be found and addressed fairly quickly.
233+
234+
In general, `temporal_rs` is a pretty good test case with reference code for setting up
235+
a Rust library over FFI with usage in a C++ and Zig codebase, so that's really cool.
236+
237+
## Conclusion
238+
239+
The 0.1 release of `temporal_rs` is out. We expected the general API to remain fairly stable
240+
moving forward, with any non-patch bumps being for added features. Feel free to try it
241+
out, and provide feedback / file any issues you come across.
242+
243+
`temporal_rs` started as an interesting experiment in creating an engine agnostic library
244+
of the Temporal API that could also be usable as a date/time library in native Rust code.
245+
We've seen pretty successful results from other engines adopting the library for use. And
246+
with any luck, it will also be useful for the Rust ecosystem as a whole.
247+
248+
## Special thanks
249+
250+
We'd like to thank all the contributors to `temporal_rs` for helping it get to 0.1.
251+
252+
Thanks to the University of Bergen students who helped drive some of the major conformance
253+
push earlier this year.
254+
255+
Also, a huge thanks to all the Temporal champions for all their work on the specification
256+
as well as the ICU4X project for their incredible ongoing work on calendars and all things
257+
i18n datetime related.
258+

0 commit comments

Comments
 (0)