Skip to main content

Temporal_rs is here! The datetime library powering Temporal in Boa, Kiesel, and V8

· 15 min read

clock banner

After 2 years of development, we're pleased to announce the 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, which we first announced in our Temporal blog post, if you're interested in learning more about small implementation details.

Currently, temporal_rs v0.1 is being used by Boa, Kiesel, V8, and Yavashark for their Temporal implementations (more on that later) and is estimated to land unflagged in Chromium v144.

Why v0.1? Why not v1.0?

Right now the Temporal proposal is at Stage 3 (4 being the final stage) in the standards process. Although unlikely, we want to remain on a minor version to catch any changes which come in (mostly bug fixes) before the proposal reaches stage 4 and thus complete. We expect that to happen in Q1 2026.

Fear not! temporal_rs passes over 4000 specification tests, is stable and ready to use.

To celebrate the release of temporal_rs, we'll cover a short background of the Temporal implementation in Boa and why temporal_rs was split into its own crate, we'll go over the library's general design, and then we'll walk through a couple brief examples of using temporal_rs before finally talking about the FFI and engine adoption.

Some background and history

"Temporal is the single biggest addition to ECMAScript since ES6"

Jason Williams, TC39 Delegate

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 an absolutely massive PR, #3277.

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 takeaways from this PR:

  • Temporal is a massive specification update, it's the single biggest addition to ECMAScript since ES6.
  • There is a lot of room to potentially optimize Temporal if we do not deal with JsValue directly.

After a couple weeks, the question came up amongst maintainers of not just Boa, but also other engines: "could we separate the datetime logic and implementation off into a completely separate library?" Sure.

The first commit of then boa_temporal occurred in PR #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 its own repository later 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:

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 calendars and time zones were removed from the specification in the first half of 2024, so temporal_rs was able to remove that support, which greatly benefited the entire API. For instance, here's the same code in the 0.1 version of temporal_rs:

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.
  • Duration moved from using f64 internally to FiniteF64, and then to non-floating-point integers.
  • We moved from a large TemporalFields type to "Partial" objects, which better represent JavaScript property bags.
  • A good portion of missing method implementations were added as well.
  • Internal utility methods were moved to the Neri-Schneider algorithms.

In general, the implementation was moving along at a pretty decent pace, and would continue to do so well into roughly April of 2025 (mostly helped along by a group of students from the University of Bergen who began helping with the implementation in January 2025), but there were two final hurdles: 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 bit of time, and ZonedDateTime was developed alongside the time zone data.

This work began in November 2024, by stubbing out the general support of time zone data sourcing and ZonedDateTime. Then, after almost 10 months of general work, the last major updates to time zone data sourcing were merged at the beginning of September in PR #537 and #538. As a result, we were finally able to stabilize temporal_rs's API for a 0.1 release.

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's what makes it interesting!

Temporal API overview

The Temporal API focuses on a group of 8 date and time types, each of which corresponds to a different aspect of date and time with varying support for calendars and time zones, which are, unsurprisingly, represented in temporal_rs by the Calendar and TimeZone types.

Temporal typeCategoryCalendar supportTime zone support
PlainDateCalendar dateyesno
PlainTimeWall-clock timenono
PlainDateTimeCalendar date and wall-clock timeyesno
ZonedDateTimeCalendar date and exact timeyesyes
InstantExact timenono
DurationTime spannono
PlainYearMonthCalendar dateyesno
PlainMonthDayCalendar dateyesno

There is also 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.

For a full view of the API, we recommend checking our documentation.

temporal_rs design overview

temporal_rs in general implements large portions of the specification directly in the codebase. However, it does still have some dependencies, which can be broken down into 4 main groups.

  1. Time zone data, for sourcing time zone data
  2. Calendrical calculations, for handling non-ISO calendar calculations
  3. RFC9557 parsing, for parsing of RFC9557's internet extended date/time format (IXDTF)
  4. Utilities

Temporal dependency graph

Notably, the dependencies that are highlighted in purple come from ICU4X. ICU4X is a phenomenal Rust project that takes a new approach to Unicode's ICU in order to make a new, more modular version of ICU.

While ICU4X provides the majority of the internationalization (i18n), Unicode, and formatting focused functionality, temporal_rs builds on top of ICU4X to provide an ECMAScript compliant date/time API for both native Rust and ECMAScript implementers.

Time zone data

While we plan to go into time zones in a completely separate post, one of temporal_rs's primary design decisions was to offer a way to customize the source of time zone data, while also having an optional default source for convenience. The time zone data sourcing functionality is provided by timezone_provider, a sister crate of temporal_rs that provides a project agnostic crate alongside default trait implementations for sourcing time zone data.

We currently expose three types of provider implementations:

  • 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.

We hope to have a zero copy compiled timezone provider available in the near future.

Using temporal_rs

Let's dive into using temporal_rs from Rust.

Setup

First, add temporal_rs as a dependency to your project using cargo:

cargo add temporal_rs

Or include the below in your project's Cargo.toml.

temporal_rs = "0.1.0"

By default, temporal_rs will use a compiled time zone data provider that compiles the time zone data into the binary. If you prefer to use the file system time zone database or a zoneinfo64 resource bundle, you can disable the compiled time zone data by setting default-features = false; you can import your preferred provider from the timezone_provider crate, then provide it to any API that requires a time zone provider.

For instance, to use the FsTzdbProvider, your Cargo.toml would look like the following.

timezone_provider = { version = "0.0.17", features = ["tzif"] }
temporal_rs = { version = "0.1.0", default-features = false, features = ["sys"]}

The sys feature for temporal_rs enables the default implementation for Now, and the tzif feature for timezone_provider enables the FsTzdbProvider.

Please note: timezone_provider is still considered unstable for the near future.

Some examples

The below examples will be using temporal_rs with the default features.

Retrieve today's date

use temporal_rs::Temporal;

// We can easily retrieve today's date using `Temporal::now()`
let today = Temporal::now().plain_date_iso(None).unwrap()

Date operations available

Temporal provides a nice API for working with date and date/time via PlainDate and PlainDateTime.

use std::convert::TryFrom;
use temporal_rs::{Calendar, Temporal, options::DifferenceSettings, partial::PartialDuration};

// We can get today's date
let today = Temporal::now().plain_date_iso(None).unwrap();

// We can also add a Duration.
let partial = PartialDuration::empty().with_days(1);
let tomorrow = today.add(&partial.try_into().unwrap(), None).unwrap();

// We can get the difference between 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
println!("{tomorrow_japanese}"); // 2025-09-24[u-ca=japanese]

Working with dates and time zones

You can also easily work with dates and time zones with the ZonedDateTime type.

use temporal_rs::options::{DifferenceSettings, Disambiguation, OffsetDisambiguation, Unit};
use temporal_rs::{Calendar, Temporal, TimeZone, ZonedDateTime};

// We can 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();

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

// And we can easily get the difference between two `ZonedDateTime`s
let mut options = DifferenceSettings::default();
options.largest_unit = Some(Unit::Year);
let diff = today.since(&zdt, options).unwrap();
println!("{diff}"); // P6M23D

// We can change the calendar for the `ZonedDateTime`
let today_coptic = today.with_calendar(Calendar::COPTIC);
println!("{today_coptic}"); // 2025-09-24T10:36:56.914365368-05:00[America/Chicago][u-ca=coptic]

// We can also easily convert it into just the date.
let today_plain_date_coptic = today_coptic.to_plain_date();
println!("{today_coptic}"); // 2025-09-24[u-ca=coptic]

While we can extend these examples further, a more fun exercise for the reader would be to take a look at the Temporal cookbook, as it displays the utility of the Temporal API using JavaScript and all of these examples are now usable from Rust as well.

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 FFI crate temporal_capi, which provides C and C++ bindings to temporal_rs.

The bindings are autogenerated via Diplomat, which is a project for generating FFI definitions for Rust libraries. In general, it's a really cool project and we would definitely recommend checking it out if you're looking to generate FFI bindings for other languages for your Rust library.

"Diplomat made the FFI code extremely easy: I basically wrote the entire temporal_capi FFI layer over the course of a couple PRs, each of which probably took me ~15 minutes each of relatively mindless "tab through docs, add API" work. Diplomat is really good at this type of thing."

Manishearth Rust Reddit Q&A:

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

First, this approach 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, since any future updates can be done primarily in one place and then released downstream. temporal_rs plus the engine specific integration code, while not a small amount of code, is a relatively trivial amount of work in comparison to a from scratch implementation.

Third, with adoption from multiple engines, temporal_rs benefits via external test coverage beyond the native Rust unit tests. For instance, looking at the engines that offer conformance numbers (Boa, Kiesel, and V8), each implementation is currently north of 95% conformance with V8 reaching the highest at around 99% conformance. There is still a small disparity in conformance, but this can be explained by the absence of some related features, i.e. Boa still hasn't completed its Intl.DateTimeFormat implementation yet, so it fails all ECMA402 toLocaleString tests. Nonetheless, we can still 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 reference case for setting up a Rust library over FFI, being used in both a C++ and Zig codebase.

Conclusion

The 0.1 release of temporal_rs is out. We expect 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. Although, we will make changes and semantic versioning bumps based on feedback or the Temporal specification.

Our current plan is to have any remaining issues addressed and the API fully stable, in preparation for the "stabilization" of Temporal and its subsequent introduction to the ECMAScript specification. Once Temporal is "stabilized", we will move forward with a 1.0 release.

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, but seeing the wide adoption we've been getting from other engines, we can say that this project has been a great success! And with any luck, we hope this library will find its place in the Rust ecosystem as well.

Special thanks

We'd like to thank all the contributors to temporal_rs for helping it get to v0.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 related.

Discussion

How can you support Boa?

Boa is an independent JavaScript engine implementing the ECMAScript specification, and we rely on the support of the community to keep it going. If you want to support us, you can do so by donating to our open collective. Proceeeds here go towards this very website, the domain name, and remunerating members of the team who have worked on the features released.

If financial contribution is not your strength, you can contribute by asking to be assigned to one of our open issues, and asking for mentoring if you don't know your way around the engine. Our contribution guide should help you here. If you are more used to working with JavaScript or frontend web development, we also welcome help to improve our web presence, either in our website, or in our testing representation page or benchmarks page. You can also contribute to our Criterion benchmark comparison GitHub action.

We are also looking to improve the documentation of the engine, both for developers of the engine itself and for users of the engine. Feel free to contact us in Matrix.

Implementing Temporal, the new date/time API for JavaScript (and Rust!)

· 13 min read

Developing a JavaScript engine in Rust can seem like pretty daunting task to some. In order to demystify working on a feature and to go over what we've been working on implementing in Boa recently, we thought we'd write a post about implementing a JavaScript feature in Rust.

More specifically, this will be the first in a series of posts primarily about implementing the new date/time built-in: Temporal. We'll be going over general lessons and interesting design choices we've stumbled upon, as well as the crates supporting that implementation.

Why should you care? Well, we are not only implementing Temporal for JavaScript, but for Rust as well ... more on that in a bit.

First, an aside!

What even is Temporal?

Temporal is a modern API for handling date/time in a calendar and time zone aware manner that includes nine objects with over 200+ methods.

How ECMAScript Engines Optimize Your Variables

· 14 min read

In this post, we will dive into how ECMAScript engines store variables, go over storage optimizations, and learn about scope analysis. If you are an ECMAScript developer, you will get some practical tips to improve the performance of your code. If you write your own ECMAScript engine or any interpreter/compiler, you might get some implementation ideas.

Boa release v0.20

· 10 min read

Summary

Boa v0.20 is now available! After 5 months of development we are very happy to present you the latest release of the Boa JavaScript engine. Boa makes it easy to embed a JS engine in your projects, and you can even use it from WebAssembly. See the about page for more info.

In this release, our conformance has grown from 87.3% to 89.92% in the official ECMAScript Test Suite (Test262). This small jump is expected as we're shifting most of our focus to performance as the majority of the engine is now conformant. We will continue to implement more of the specification as we go along but we expect these changes to be much smaller than we've been used to.

You can check the full list of changes here, and the full information on conformance here.

Boa release v0.19

· 11 min read

Summary

Boa v0.19 is now available! After 4 months of development we are very happy to present you the latest release of the Boa JavaScript engine. Boa makes it easy to embed a JS engine in your projects, and you can even use it from WebAssembly. See the about page for more info.

In this release, our conformance has grown from 85.03% to 87.3% in the official ECMAScript Test Suite (Test262). Interestingly, this was partly because around 2000 tests were removed from test262 as part of the removal of custom calendars and timezones. Overall, Boa's conformance in real terms has improved by ~6%.

You can check the full list of changes here, and the full information on conformance here.

Boa release v0.18

· 21 min read

Summary

Boa v0.18 is now available! After 7 months of development we are very happy to present you the latest release of the Boa JavaScript engine. Boa makes it easy to embed a JS engine in your projects, and you can even use it from WebAssembly. See the about page for more info.

In this release, our conformance has grown from 79.36% to 85.03% in the official ECMAScript Test Suite (Test262). This means we now pass 3,550 more tests than in the previous version. Moreover, our amount of ignored tests decreased from 9,496 to 1,391 thanks to all the new builtins we have implemented for this release.

You can check the full list of changes here, and the full information on conformance here.

You probably noticed that something seems different... This release marks a major update to the design of our website, and the introduction of our new logo! We'd like to thank @ZackMitkin for being the one that started the work on this nifty redesign, and @kelbazz for designing the logo. We're planning to add some additional pages to learn more about the APIs that Boa exposes. Additionally, expect some more blog posts from us in the future! We would like to write about how to use certain APIs, design challenges that we encountered while developing the engine, and internal implementation details. Subscribe to our RSS feed if you're interested in staying up to date!

This big release was partly possible thanks to those who have supported us. Thanks to funds we've received we have been able to renew our domain name, remunerate members of the team who have worked on the features released, and discuss the possibility of using dedicated servers for benchmarking. If you wish to sponsor Boa, you can do so by donating to our open collective. You can also check easy or good first issues if you want to contribute some code instead.

Boa release v0.17

· 13 min read

Summary

Boa v0.17 is now available! This is one of the biggest Boa releases since the project started, and after around 7 months of development, we are very happy to present you the latest release of the Boa JavaScript engine. Boa makes it easy to embed a JS engine in your projects, and you can even use it from WebAssembly. See the about page for more info.

In this release, our conformance has grown from 74.53% to 78.74% in the official ECMAScript Test Suite (Test262). While this might look as a small increase, we now pass 6,079 more tests than in the previous version. In any case, the big changes in this release are not related to conformance, but to huge internal enhancements and new APIs that you will be able to use.

You can check the full list of changes here, and the full information on conformance here.

Moreover, this big release was partly possible thanks to a grant by Lit Protocol. Thanks to this grant, we were able to remunerate 2 team members for their 20h/week work each during three and a half months. If you wish to sponsor Boa, you can do so by donating to our open collective. You can also check easy or good first issues.

Furthermore, we now have a new domain for Boa, boajs.dev.

Adding a JavaScript interpreter to your Rust project

· 14 min read

Introduction

When we develop tools for our users, we sometimes want to give them some form of control over how they work. This is common in games, where we can add scripting for our users to be able to create extensions, or even for business tools, where we allow our customer to change or extend the behaviour of our platform. For those cases, using Rust, a compiled, type safe language can be a challenge, since once a program has been compiled, it's tricky to change or extend it at runtime. Furthermore, many of our users will prefer to use a more common scripting language, such as JavaScript.

This is where Boa enters the scene. Boa is a Javascript engine fully written in Rust. Currently, it can be used in places where you need most of the JavaScript language to work, even though, we would advise to wait to get all our known blocker bugs solved before using this for critical workloads. You can check how conformant we are with the official ECMAScript specification here.

And, before going further, we would like to mention that you can contribute to Boa by solving one of the issues where we need special help, and we now also accept financial contributions in our OpenCollective page.

Note: You can see more examples of integrating Boa in our repository.

Boa release v0.16

· 5 min read

Summary

Boa v0.16 is now available! After around 3 months of development, we are very happy to present you the newest release of the Boa JavaScript engine. Boa makes it easy to embed a JS engine in your projects, and you can even use it from WebAssembly. See the about page for more info.

Boa currently supports part of the JavaScript language. In this release, our conformance has grown from 62.29% to 74.53% in the official ECMAScript Test Suite (Test262). The engine now passes 68,612 tests, coming from 56,372 in Boa 0.15 (21.7% increase), and we have closed 9 issues and merged 59 pull requests. You can check the full list of changes here, and the full information on conformance here.

Boa release v0.15

· 6 min read

Summary

Boa v0.15 is now available! After around 3 months of development, we are very happy to present you the newest release of the Boa JavaScript engine. Boa makes it easy to embed a JS engine in your projects, and you can even use it from WebAssembly. See the about page for more info.

Boa currently supports part of the JavaScript language. In this release, our conformance has grown from 49.74% to 62.29% in the official ECMAScript Test Suite (Test262). The engine now passes 56,372 tests, coming from 43,986 in Boa 0.14 (28.1% increase), and we have closed 18 issues and merged 58 pull requests. You can check the full list of changes here, and the full information on conformance here.

Boa release v0.14

· 7 min read

Summary

Boa v0.14 is here! After almost 6 months of development, we are very happy to present you the newest release of the Boa JavaScript engine. Boa makes it easy to embed a JS engine in your projects, and you can even use it from webassembly. See the about page for more info. Together with this release, we present you: A new way to contribute to Boa, a virtual machine, usable examples and much more.

Boa currently supports part of the JavaScript language. In this release, our conformance has grown from 41.01% to 49.74% in the official ECMAScript Test Suite (Test262). The engine now passes 43,986 tests, coming from 33,192 in Boa 0.13 (32.5% increase), and we have closed 40 issues and merged 137 pull requests. You can check the full list of changes here, and the full information on conformance here.

Boa release v0.13

· 5 min read

Boa v0.13 is here! Boa is a JavaScript engine written in the Rust programming language. It makes it easy to embed a JS engine in your projects, and you can even use it from webassembly. See the about page for more info.

We currently support part of the language. In this release, our conformance has grown to 41.97% of the official ECMAScript Test Suite (Test262). We have closed 40 issues and merged 105 pull requests. You can check the full list of changes here.

This release brings some new features, such as support for calling Rust closures from JavaScript to improve better interopability between JS and Rust.

Boa release v0.12

· 3 min read

Boa v0.12 is here! Boa is a JavaScript parser, compiler and executor written in the Rust programming language. It makes it easy to embed a JS engine in your projects, and you can even use it from webassembly. See the About page for more info.

We currently support part of the language. In this release, our conformance has grown to 33.97% of the official ECMAScript Test Suite (Test262). In this release, we have closed 19 issues and merged 69 pull requests. You can check the full list of changes here.

Let's dive into the most relevant changes of this release.

Boa release v0.11

· 6 min read

Boa has reached a new release. v0.11, our biggest one yet!

Since v0.10 we've closed 77 issues and merged 129 pull requests. The engine has been faster and more compliant to the spec. Below are some of the highlights but please see the changelog for more information.

What is Boa? See the About page for more info.

Boa release v0.10

· 4 min read

Boa is an experimental Javascript lexer, parser and compiler written in Rust. It has support for some of the language, can be embedded in Rust projects fairly easily and also used from the command line. Boa also exists to serve as a Rust implementation of the EcmaScript specification, there will be areas where we can utilise Rust and its fantastic ecosystem to make a fast, concurrent and safe engine.

We have a long way to go, however v0.10 has been the biggest release to date, with 138 issues closed!

We have some highlights, but if you prefer to read the full changelog, you can do that here

Boa v0.9: measureme & optimisations

· 6 min read

Hello World!

Boa is an experimental Javascript lexer, parser and compiler written in Rust. It has support for some of the language, can be embedded in Rust projects fairly easily and also used from the command line.
Boa also exists to serve as a Rust implementation of the EcmaScript specification, there will be areas where we can utilise Rust and its fantastic ecosystem to make a fast, concurrent and safe engine.

Today we're pleased to announce our latest release, version 0.9.
v0.9 is by far the biggest release we've had since Boa began. You can find the full changes from the changelog. The milestone behind this version was further optimisation and an increase in new features. We can show you how we can identify areas that can be optimised.