Skip to content
Merged
Changes from 1 commit
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
b7db68a
First pass at a release post
nekevss Sep 21, 2025
4b3aa94
Some general updates to history and the design section
nekevss Sep 22, 2025
f1ff7fd
Test and update the examples
nekevss Sep 22, 2025
407bdb8
A few more changes based on feedback
nekevss Sep 22, 2025
39ad73f
Update blog/temporal-release/index.md
nekevss Sep 23, 2025
bb39730
Update blog/temporal-release/index.md
nekevss Sep 23, 2025
c2a2642
Update blog/temporal-release/index.md
nekevss Sep 23, 2025
0df2d73
Update blog/temporal-release/index.md
nekevss Sep 23, 2025
6e52045
Update blog/temporal-release/index.md
nekevss Sep 23, 2025
c6d19b3
Update blog/temporal-release/index.md
nekevss Sep 23, 2025
2714a84
Update blog/temporal-release/index.md
nekevss Sep 23, 2025
2b9fcd0
Update blog/temporal-release/index.md
nekevss Sep 23, 2025
6728cab
Update blog/temporal-release/index.md
nekevss Sep 23, 2025
a0708b0
Update blog/temporal-release/index.md
nekevss Sep 23, 2025
103f65e
Update blog/temporal-release/index.md
nekevss Sep 23, 2025
5f687ed
Update blog/temporal-release/index.md
nekevss Sep 23, 2025
6be2ded
Update blog/temporal-release/index.md
nekevss Sep 23, 2025
807ac64
Update blog/temporal-release/index.md
nekevss Sep 23, 2025
e4116cb
Update blog/temporal-release/index.md
nekevss Sep 23, 2025
63b36ae
Update blog/temporal-release/index.md
nekevss Sep 23, 2025
d72acbf
Update blog/temporal-release/index.md
nekevss Sep 23, 2025
9b2f76b
Update blog/temporal-release/index.md
nekevss Sep 23, 2025
4c3ec30
Update blog/temporal-release/index.md
nekevss Sep 23, 2025
dfd6351
Update blog/temporal-release/index.md
nekevss Sep 23, 2025
cd29081
Update blog/temporal-release/index.md
nekevss Sep 23, 2025
cc068a2
Update blog/temporal-release/index.md
nekevss Sep 23, 2025
0b56ed8
Update blog/temporal-release/index.md
nekevss Sep 23, 2025
6d6c2be
Update blog/temporal-release/index.md
nekevss Sep 23, 2025
ce2f674
Update blog/temporal-release/index.md
nekevss Sep 23, 2025
5f61010
Update blog/temporal-release/index.md
nekevss Sep 23, 2025
91b1f5a
Update blog/temporal-release/index.md
nekevss Sep 23, 2025
bf68b50
Update blog/temporal-release/index.md
nekevss Sep 23, 2025
b996a63
Update blog/temporal-release/index.md
nekevss Sep 23, 2025
d6db7c9
Update blog/temporal-release/index.md
nekevss Sep 23, 2025
8997b46
Update blog/temporal-release/index.md
nekevss Sep 23, 2025
567e3e4
Small consistency updates + publish date
nekevss Sep 23, 2025
6c5daea
small change to wording
nekevss Sep 23, 2025
2e5d631
Update blog/2025-09-23-temporal-release/index.md
nekevss Sep 23, 2025
e489191
Add clock image at top
nekevss Sep 23, 2025
be5b408
Update title and description
nekevss Sep 23, 2025
217d2d1
Update the date sensitive values for a 9-24 release
nekevss Sep 23, 2025
01f4a50
shorten title and add link to temporal project in the first instance …
jasonwilliams Sep 23, 2025
5d3cd82
Update blog/2025-09-24-temporal-release/index.md
nekevss Sep 24, 2025
7162e9d
Update blog/2025-09-24-temporal-release/index.md
nekevss Sep 24, 2025
178118c
Update blog/2025-09-24-temporal-release/index.md
nekevss Sep 24, 2025
08c3adf
Update blog/2025-09-24-temporal-release/index.md
nekevss Sep 24, 2025
915b5fd
Update blog/2025-09-24-temporal-release/index.md
nekevss Sep 24, 2025
5a1c174
Small adjustment to zero copy
nekevss Sep 24, 2025
6fa9f07
Update index.md
jasonwilliams Sep 24, 2025
9d6e17a
Update index.md
jasonwilliams Sep 24, 2025
b58db37
Update index.md
jasonwilliams Sep 24, 2025
1742a3f
Update index.md
jasonwilliams Sep 24, 2025
8049024
Update index.md
jasonwilliams Sep 24, 2025
3314af8
Update index.md
jasonwilliams Sep 24, 2025
b439c19
Update index.md
jasonwilliams Sep 24, 2025
1706ff3
Update index.md
jasonwilliams Sep 24, 2025
006f7ba
Update index.md
jasonwilliams Sep 24, 2025
3ba5e87
Update index.md
jasonwilliams Sep 24, 2025
ccf5b44
Update index.md
jasonwilliams Sep 24, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
258 changes: 258 additions & 0 deletions blog/temporal-release.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,258 @@
# Temporal_rs release v0.1

After almost 2+ years of development, we're pleased to announce the 0.1 release
of `temporal_rs`. A calendar and time zone aware Rust date/time library based on
ECMAScript's Temporal API.

`temporal_rs` is a highly conformant implementation of the Temporal API in Rust that can be
used in native Rust code or embedded into ECMAScript engines / interpreters to support their
implementations.

Currently, `temporal_rs` is being used by Boa, Kiesel, V8, and Yavashark for their Temporal
implementations (but more on that later).

### TODO: tentative post summary

To celebrate the 0.1 release of `temporal_rs`, we'll cover a short background of the Temporal
implementation in Boa and why `temporal_rs` was split into it's own crate, then we'll walk
through a couple brief examples of using `temporal_rs`, and finally we'll talk about the
FFI and engine adoption.

## Some background and history

In this section, we'll reflect on the overall implementation, some general difficulties
we had along with lessons learned.

The temporal implementation in Boa began over two years ago and culminated in a
absolutely massive PR, [#3277](https://github.com/boa-dev/boa/pull/3277) (ASIDE from
nekevss: mea culpa).

The PR itself stubbed out a lot of the methods, implemented some Duration and Instant
functionality, and started the support for custom calendars. There were, however, 2
major take aways from this PR: first, Temporal is a massive specification update; and
second, there is a lot of room to potentially optimize Temporal if we did not deal with
`JsValue` directly.

After a couple weeks, the question came up amongst the maintainers: could we separate
the Boa's implementation off into a completely separate library? Sure, why not.

The first commit of then `boa_temporal` occurred in PR [#3461](https://github.com/boa-dev/boa/pull/3461),
which moved the majority of the existing functionality into a separate crate with the
primary concern at the time of being able to support custom calendars, which was then
ported into it's [own repository later](https://github.com/boa-dev/temporal/pull/1) a
couple months later.

These early versions of `temporal_rs` were vastly different than the 0.1 release version,
and it can be easily seen with a short glance through the first PR. `temporal_rs` needed
to support custom calendars and time zones. In order to do this, each calendar was generic
on a `CalendarProtocol` trait.

So to create a new date in the early versions of `temporal_rs`, you would have something
like the following code:

```rust
use temporal_rs::{Date, Calendar, options::ArithmeticOverflow};
let date = Date::new_with_overflow(
2025,
9,
21,
Calendar::<()>::from_str("iso8601").unwrap(),
ArithmeticOverflow::Reject
).unwrap();
```

Luckily, custom calendar and time zone were removed from the specification. In the first
half of 2024, so `temporal_rs` was able to remove that support, which greatly benefitted
the entire API. For instance, here's the same code in the 0.1 version of `temporal_rs`:

```rust
use temporal_rs::PlainDate;
let date = PlainDate::try_new_iso(2025, 9, 21).unwrap();
```

That was 2024 though, we're in September of 2025, so what's happened since the crate
was initially split off from Boa over a year and a half ago. Well, plenty! In early 2024
the internal algorithm for `Duration` was overhauled in the specification, so `temporal_rs`
had a complete rewrite of `Duration`.

The general implementation was moving along as well, but there was one final hurdle: time
zone data and `ZonedDateTime`. Time zones and time zone data are a topic for a completely
different blog post in the future. But suffice to say, it took a little time, and the
`ZonedDateTime` implementation developed alongside the development of time zone data.

That's it for our brief background on `temporal_rs`.

Date and time is hard, and there is a lot that goes into it, especially when it comes to
calendars and time zones. But that also doesn't mean its not interesting.

## Using `temporal_rs`

Let's dive into using `temporal_rs` from Rust.

### Setup

First, add `temporal_rs` as a dependency.

```bash
cargo add temporal_rs
```

By default, `temporal_rs` will use a compiled time zone data provider that compiles the
time zone data into the binary. There are a few options that can be used for time zone
providers:

- CompiledTzdbProvider (current default), a provider that parses time zone data at
runtime using data compiled into the binary.
- FsTzdbProvider, a provider that parses time zone data at runtime using the file system time zone
database (if it exists for that OS).
- ZoneInfo64TzdbProvider, a provider using ICU's zoneinfo64 resource bundle.

Currently, we do not have a way to select certain provider's via feature flag, but a provider
can be selected by setting `no-default-features` and importing the provider from
`timezone_provider` for the API's that require time zone data.

### The Temporal API

The Temporal API revolves around a group of 8 date and time types, each of which corresponds
to a different aspect of date and time with varying support for `Calendar`s and `TimeZone`s.

| Temporal type | Category | Calendar support | Time zone support |
|----------------|--------------------------------------|--------------------|--------------------|
| PlainDate | Calendar date | yes | no |
| PlainTime | Wall-clock time | no | no |
| PlainDateTime | Calendar date and wall-clock time | yes | no |
| ZonedDateTime | Calendar date and exact time | yes | yes |
| Instant | Exact time | no | no |
| Duration | None | no | no |
| PlainYearMonth | Calendar date | yes | no |
| PlainMonthDay | Calendar date | yes | no |

There is also the `Now`, which provides access to the current host system time. This can then
be used to map the current `Instant` to any of the above Temporal types.

The types in the same categories will share similar APIs that are related to that category. For instance,
all types that support a calendar date will have a `with_calendar` method as well as calendar date
accessors. The exception being PlainYearMonth and PlainMonthDay which are missing their day and
year, respectively ... for all intents and purposes.

### Some examples

You retrieve the current date using the `Temporal` type.

```rust
use temporal_rs::Temporal;
let today = Temporal::now().to_plain_date_iso(None).unwrap()

```

With the current date, we can now do a variety of operations the date.

```rust
use temporal_rs::{Temporal, Calendar, partial::PartialDuration, options::DifferenceSettings};
let today = Temporal::now().to_plain_date_iso(None).unwrap();

// We can add a Duration.
let partial = PartialDuration::empty().with_days(1);
let tomorrow = today.add(Duration::from_partial_duration(partial).unwrap()).unwrap();

// We can get the difference two dates
let diff = today.since(&tomorrow, DifferenceSettings::default()).unwrap();

// We can change the calendar
let tomorrow_japanese = tomorrow.with_calendar(Calendar::JAPANESE);

// We can retrieve the calendar's RFC9557 string
let tomorrow_string = tomorrow_japanese.to_string();
```

We can also easily deal with a `ZonedDateTime` as well.

```rust
use temporal_rs::{ZonedDateTime, TimeZone, Temporal};
use temporal_rs::options::{Disambiguation, OffsetDisambiguation, DifferenceSettings};

// Parse a ZonedDateTime from utf8 bytes.
let zdt = ZonedDateTime::from_utf8(
b"2025-03-01T11:16:10Z[America/Chicago][u-ca=iso8601]",
Disambiguation::Compatible,
OffsetDisambiguation::Reject,
).unwrap();

// Change the time zone.
let zurich_zone = TimeZone::try_from_str("Europe/Zurich").unwrap();
let zdt_zurich = zdt.with_timezone(zurich_zone).unwrap();

// Or get the current ZonedDateTime
let today = Temporal::now().zoned_date_time_iso(None).unwrap();

// Difference the two `ZonedDateTime`s
let diff = today.since(&zdt, DifferenceSettings::default()).unwrap();

// Change the calendar
let today_coptic = today.with_calendar(Calendar::COPTIC);
```

While we can extend these examples further, a more fun exercise for the reader would be taking
a look at the [Temporal cookbook](https://tc39.es/proposal-temporal/docs/cookbook.html)
as it displays the utility of the Temporal API using JavaScript.

## FFI and engine adoption

As previously stated, `temporal_rs` is used in Boa, Kiesel, and V8. There's just one thing,
the latter of the two are ECMAScript implementations written in Zig and C++, respectively,
not Rust. This was made possible through `temporal_rs`'s sister crate `temporal_capi`,
a FFI library that provides C and C++ bindings to `temporal_rs`.

The bindings are autogenerated via [Diplomat](https://github.com/rust-diplomat/diplomat), which
is a project for generating FFI definitions for Rust libraries. In general, it's a really cool
project and would definitely recommend checking it out if you're looking to generate FFI
bindings for other languages for your Rust library.

There is some added benefits to offering C and C++ bindings beyond the classic: oh, let's
(re)write it in Rust.

First, this allows other languages and engines to benefit from Rust's type system and memory
safety guarantees without having to rewrite everything in Rust. It's a more modular and
incremental approach that provides some level of flexibility.

Secondly, with how large the API is, `temporal_rs` streamlines the ability to adopt the
Temporal API for any current and future implementations, alongside any future update
that needs to be made can be done primarily in one place and then released downstream. While
it's easy to say: "just use our library" to promote adoption. Seriously, just use the
library. The Temporal API is massive from an implementation perspective and the glue
code plus `temporal_rs` is relatively trivial in comparison to a fresh implementation.

Third, with adoption from multiple engines, `temporal_rs` benefits via further test coverage
beyond the native unit tests. For instance, of the engines that offer conformance numbers
(Boa, Kiesel, and V8), all of them are currently north of 95% conformance with V8 reaching
the highest at around 99% conformance. The conformance difference between the engines being
due to the current implementation state of other features, i.e. Boa still hasn't completed
its `Intl.DateTimeFormat` implementation yet so it fails all ECMA402 `toLocaleString` tests.
As a result though, we can be fairly confident in the general correctness of `temporal_rs`,
and any potential bugs will ideally be found and addressed fairly quickly.

In general, `temporal_rs` is a pretty good test case with reference code for setting up
a Rust library over FFI with usage in a C++ and Zig codebase, so that's really cool.

## Conclusion

The 0.1 release of `temporal_rs` is out. We expected the general API to remain fairly stable
moving forward, with any non-patch bumps being for added features. Feel free to try it
out, and provide feedback / file any issues you come across.

`temporal_rs` started as an interesting experiment in creating an engine agnostic library
of the Temporal API that could also be usable as a date/time library in native Rust code.
We've seen pretty successful results from other engines adopting the library for use. And
with any luck, it will also be useful for the Rust ecosystem as a whole.

## Special thanks

We'd like to thank all the contributors to `temporal_rs` for helping it get to 0.1.

Thanks to the University of Bergen students who helped drive some of the major conformance
push earlier this year.

Also, a huge thanks to all the Temporal champions for all their work on the specification
as well as the ICU4X project for their incredible ongoing work on calendars and all things
i18n datetime related.