Skip to main content Go to the homepage
State of the Browser

Temporal:
It's about time!

After more than seven years of specification work, Temporal is finally here! In this talk, we’ll explore the history, the challenges, and the new API that’s set to replace JavaScript’s long-maligned Date object. You’ll learn how Temporal simplifies working with dates, times, time zones, and why it’s truly about time we had it.

Transcript

Yeah, so hi everybody, I'm Jason Williams, Senior Software Engineer at Bloomberg in the Application Frameworks team. So we provide tooling and infrastructure to the rest of the corporation. I was also, before that, I was at the BBC for six years as well. Yeah. (audience laughs) I was a tech lead of the BBC Sounds team and some of the projects there. Actually, I think there was like a one, it was weird, like a one week overlap between me arriving and Jake leaving, so I don't know what happened in that week. But basically, yeah, I'm gonna tell you a little bit about Temple. I'm gonna tell you more about the story, really, of how the sort of process works rather than how to use it. I think there's a lot of smart people here, so I'm sure you will, some of you probably already been using it already. But I guess I, to give you some context, we'll probably start with TC39. So can I have a hands up who knows of TC39? Okay, so, okay, I'd say most of you. Like my friend asked me, it's not like WD40, it's not the 39th, (audience laughs) it's not the 39th attempt at a technical committee. It's technical committee 39, the JavaScript committee, I guess, these days, within ECMA. Interestingly, it used to be the programming languages committee. Back in the day, you had all languages in there. So you had Fortran, COBOL, a few others, Eiffel, and then over time, they got quite big, and they all moved into their own committee, and then TC39 remained as the JavaScript committee, or as people still refer to it, as ECMA script committee today. I think actually when it started, probably mid to late '90s, it was, I think the first meeting was like four people, and I think it was only about 15 minutes long. It's like, hey, should we have this? Yeah, sure, let's go for it. No other browsers or anything like that to worry about at the time. Yeah, so my employer, Bloomberg, had been an ECMA member for a while, been an active participant for numerous years, and in case you're wondering what it looks like, some people do ask me what happens. This is like a picture of a typical meeting. You can see the back of Keith Kirkle's head. Here he is. And yeah, essentially the idea is that people will come, they will bring their ideas that may be representing their company or organization or open source organizations, representing users on the web, so representing yourselves as well, bringing ideas or pain points, and yeah, this is another picture. This is Bloomberg and my company hosting. I think this is Tokyo. But it's the same, yeah, same concept wherever it is. Essentially what happens in those meetings is things will get reviewed or people will bring ideas, and most of the time, it's proposals being talked about. So any of you who've done anything with W3C, it's pretty much the same sort of concept as that. And the way that we do that is we have a stages process in TC39. So we have a stage from stage zero, which is essentially an idea, all the way to stage four, which is pretty much, it is now in the spec. I'm not gonna go too much into detail on this, but I'll give you a little bit of a whirlwind tour. So yeah, like I said, stage zero, anybody can make a stage zero proposal. We call this the straw man proposal. You don't need to be a member or a delegate or anything like that. It's pretty much as easy as opening up a repo and just laying out the problems that you have with JavaScript or the ecosystem and some ideas. We call this the problem space. I really like that definition because at stage zero, you don't need to have the solution at that point. It's more about getting people to sort of have a conversation and engage with some of the pain points that we have with the language. Then assuming the committee are happy with that, and you could maybe have someone to champion it from within the committee, so usually like a member or a delegate, that will then go to stage one. Stage one is usually where, again, keeping things pretty high level. We don't need to worry too much about the overall final solution, but that's when things start to get hashed out. Are there some ideas that we haven't thought about? Maybe we don't even need this proposal at all. Maybe we can just fix something else that will then fix this. Or maybe there's some more testing we need to do with the wider community to see if this is an avenue that's worth going down. Usually if that's okay and people are still thinking it's going in a good direction with stage two, that's when we need to start really thinking about the solution that we want to move forward with. This is usually when the community get involved as well. At this stage, there's probably polyfills. There used to even be implementations at this stage. Not so much anymore, mainly because stage two can get quite busy now and something being stage two doesn't guarantee it's gonna be complete. So at this stage, you probably more have implementations in JavaScript and polyfills. But that's still good. The community can still get involved and give feedback. I'm gonna skip 2.7 'cause it's mainly just about test. But essentially, at stage three, you've got two implementations in two of the top browsers. You've probably got a good set of tests at this point as well. It's ready to be implemented properly by everyone else. And at this point, this is the longest stage, really. And the reason why stage three is the longest stage for most proposals is because by the time you're at stage three, it's probably on nightly, it's probably a flag. People are trying it out and that's when you start getting feedback. You can write a spec from stage two, but really, until you're stage three and people are actually using the thing, that's when you really get some good feedback come through. It could be about ergonomics, it could be about performance, and that's when you get that cycle. So they come back to you, you make some changes, that goes back out on a nightly, people try it again, and so on, so you sort of have that feedback loop. And then stage four is pretty much, it's complete, it's in the spec and everyone's happy. We can all sail off to the sunset, whatever. So, Temporal, what is it? I would be surprised if no one knows what it is at this point, but who knows? It is a new date time library in JavaScript. It's been a long time coming. It is a replacement for date, so you should not need the date object once you have this. Obviously, for legacy and compatibility, I can imagine it will still be around for a while in a lot of projects. It's strongly typed, so I guess what I mean by that is we really think about types in mind, and you'll see a bit more of that later on. And it's immutable, a lot of people wanted this, I think we wanted this. It's got good support for internationalization as well. And it's stage three, which is why I was making all those excuses earlier about stage three being the longest stage. It's been stage three for about four years. Yeah, we're getting there, we're getting there. Yeah, I mean, it's been the most longed for feature that I think jobs developers have wanted for a long time. I think it's been top. So this screenshot is state of JS survey, this is 2025. This actually only came out last week. It's been top for a few years now. This has actually started to come down, it was higher. I think it's because there are polyfills that people are using. I've been talking to people about temporal for too long, and there's many polyfills, it's in browsers as nightly, so I think what's happening is many people filling this out are probably already using it now. But still, you can see that it's not even close. It's way ahead, it's top. Yeah, so why so long? When Dave asked me to come here today and talk about temporal war, I was like, wow, yeah, that's an amazing opportunity, I'd love to. Yeah, I can't wait, I'd love to come here and talk to you all about temporal war. And then I also realized that, yeah, people have been waiting so long for this, I feel like I've been summoned to explain myself. It wasn't, you should come and talk about temporal war. Why has it taken so long? You need to tell us what has been going on. Well, I guess to really think about it, we need to go back, way back. We need to go back to 1995. You know, Oasis and Blur were battling it out at the top of the charts. Who remembers that? Windows 95, finally a start button in the bottom left corner. Toy Story came out, I mean, that was the first full length CGI movie. That was a pretty big thing at the time. And yes, JavaScript was announced in typical '90s fashion. Mailing lists, typical Times New Roman background, loads of text, don't expect you to be reading that, but essentially, yeah, Netscape announced JavaScript to the world. And as many of you know the story, Brendan Eich was tasked with his 10 day sprint to make the JavaScript programming language. The time he was told by Netscape, "Make it look like Java," that's what the MLLJ is. "Make it look like Java." And you've probably heard a story about JavaScript being created in 10 days, I think some people have heard about that. You know, one of the reasons why it was quick to do, I guess, was many of the APIs were copied from Java, so dates was one of them. It was a complete port of the Java util date. And Brendan and Ken, they did actually talk probably shortly about bringing a new date library to JavaScript at the time. But, you know, expediency, let's just get this out, this was a prototype, date is fine in Java, it's not. So they just did a port, and it was a one for one port, so even the bugs, as Brendan mentions, were ported across as well, and there were many of them. I think at the time, to give people here context, no one knew how big the web was going to be, and I've spoken to Brendan about this in the past, and I think back then, it was like, well, we can ship something, and we can improve it, it's not that big of a deal. Yeah, I think we know that that's not been the case. As I said, yeah, bugs were fixed, but there are some things in date, as you all know, that we just cannot change. For one, it is mutable. If, and I see this a lot all the time, if you make any helper methods, people end up tripping over themselves, so in this example here, people have a helper method to add one day to a date, and then return the new date, but they often end up mutating the date object that's been passed in, and because they're changeable, this happens all the time, you can even scan GitHub and various repositories where you can see that date objects are meant to be returned, and they're also changing it as well, and leading to much undefined behavior. But even if you are meaning to mutate date, it also doesn't really go the way that you intend. This is an example, people want billing dates last day of the month, that sort of thing, and here we've got Saturday, January 31st, we wanna set it to the end of the month, hoping to get, well, today, February 28th, and instead we've got March 2nd. This happens a lot as well, there's many examples of this, and yeah, the reason why date, of course, does this is 'cause it's when you add, when you set a month and you add it, it zeroes the days back to zero, bumps the month by one, and then it adds the days back in, so it's gone to February with zero days, and puts the 31 days back in, bumping it over onto March 2nd, many, many examples of this. Time zone support, of course, some people obviously need to use that. With date, you just have your local time zone and UTC, there's not really much more you can do, of course, there's some hacks out there to get around it, but essentially, you can't really go back and forth between time zones. And then there's unpredictable parsing behavior. It's pretty good with ISO strings, but pretty much anything outside of that was never really spec'd, and sometimes you get things like this that kind of look a bit like an ISO string, but you've got the gap in the middle where maybe you would have the colon, and this has improved, to be fair, between browsers, but even something like this was a nightmare. There was a point where all three browsers, so Safari, Chrome, and Firefox did something different when you'd pass this in. One treated it like a local time zone, so they just assumed, okay, this is local to you, I'm gonna treat it like that. Another browser treated it as UTC, and another browser would throw an error, a range error, an invalid date, so you had completely, once you went off the beaten track, it was completely, you were on your own. There's more, I mean, you all know there's more than that. I'm just really scratching the surface. jsdate.wtf is a great quiz. Some of you may have already been on there. There's so many crazy things. Highly recommend going there. Not now, of course, I'm doing the talk, but definitely bookmark it. It's a great site. In my opinion, and again, this is the same survey as before, it's the biggest, I think, yeah, data's the biggest pain point in JavaScript. I know it's second here, but TypeScript has fixed the top one, lack of static typing, I think it's a fixed problem, it's solved. Data's just been top of the pain point for many years. As I said earlier, if the web had maybe stayed small, and it was only sort of maybe used by a few applications, maybe it would have been okay. Maybe we could have patched it, fixed it, and replaced it earlier. But websites got bigger, and the web blew up. I mean, this is 2000 to 2007, 12K average response size for a website, 2007 we were already at 60K. It just got bigger and bigger. And I think many of you know now, sometimes we're not even talking about websites anymore, we're talking about web applications. Over here we're seeing 32K back in 2011, 256K here, I think it was around 2019. So yeah, this was not something that we could just swap out and replace. People were wanting more from the JavaScript standard library, so to speak. So okay, we've got a big ecosystem now. Maybe we could just use libraries to fix it. I mean, yeah, we have NPM, we have scripts, and various places that you can pull things from. Why not just use libraries? And that's essentially what we did in a big way. I mean, the sheer size of downloads for date time libraries, you can see that Moment really led the pack for almost two decades. We got date-fns that only really took over last year as the most downloaded date time library. But between these three, you're looking at, it's around 100 million downloads a week, per week. I actually think date time libraries contribute to some of the biggest bandwidth of downloads on NPM. So that's what we did. As a web ecosystem, we can't really change date, as Brendan made some patches, but we have to sort of work around it in libraries. And maybe that's okay, maybe for things that we can't have in the ecosystem of JavaScript, maybe libraries are the second best place to do that. The only problem, though, is size. Some of you may have used Moment in the past, or have noticed that the size of the library could be a problem. Moment was huge. I mean, this is the latest version showing 4.15. This is, to be fair, this is not gzipped. But this was something that people ran into all the time. And it wasn't just Moment, to be fair. It was a lot of other date time libraries. So many websites were just, their bundle size was just increasing and increasing with complexity. And some of that increasing was date time libraries. Why? Well, this is me breaking Moment apart. And actually, Moment.js itself, as in the runtime and everything that's, all the inner workings of Moment is actually just this bit on the left. That's the core library of Moment.js. Essentially, I guess the bloat, so to speak, is the, first you have the locales. So it comes with date time formatting for different locales across the world. Yeah, I guess you kind of need that. And also time zones. Yeah. That's pretty big. You're basically downloading the time zone database in JS form on your website. And people think, well, that's bad. And I was saying to someone the other day, well, yeah, that is bad, but it's even worse now because your downloads are sharded per origin. So if you're getting Moment from a CDN, you're getting this about 20 times in your browser. So yeah, it's pretty big. I guess you can't even tree shake some of this out because you don't really know ahead of time which locales you're gonna be dealing with, which time zones you might be dealing with. If you've got users from all over the world, you can't then just say, well, maybe we just get rid of the Brazil bit. I'm not gonna have anyone from there. You don't know. So sometimes you need the whole thing. To be fair, some people have gone around it by removing some locales they don't use, but as a whole, the majority were using Moment Wholesale. And for those of you who are eagle-eyed, you can't really see it too well, but gzipped, this is about 270K. So okay, that's a lot better than the 4.15MB. But 270K, if we go back to the previous image, that's bigger than the average entire response of a website up until 2017. So just that one date/time library is bigger than the average size of an entire website or web application. So it's a big deal. And people did bring it up over and over again. I was chatting to Maggie Johnson-Pint, who was a maintainer of Moment.js. I'd say the straw that broke the camel's back for her was when she mentioned that this got brought up in JSConf EU. Great conference, by the way. And I remember, I think that this was the point when even for Maggie, who worked on Moment and had been maintaining it, she felt, well, okay, something needs to be done now. I can only do so much for a library. She said to me, it's very clear that the only sustainable path is in the standard, basically. We need to build this into the browser. The browser has this information anyway. The browsers have locales. The browser has time zones and ICU data and the time zone database. We just need to expose that. We need to stop shipping this as a JavaScript library. And that was when Maggie Johnson decided to come to TC39 and really start talking about this is a problem. Sorry. So I mentioned stage zero earlier, the problem space. That's essentially where this led to. Maggie very quickly knocked together a deck called the Tempore Proposal. And that was actually the first instance of where the word Tempore was used for this. She basically came to the committee in 2017 and she showed a few things. She showed timeline math, calendar math, how that all sort of works, how they're currently doing it in user space with these JavaScript libraries. She showed some Moment JS syntax and how Moment deals with things at the moment. And, you know, however, daytime libraries are doing things as well and how Java deals with it in their library, so we've got NodaTime and JodaTime at the end. 'Cause Java had moved on at this point. Java had version two, version three, so they were like, yeah, this daytime library is rubbish. Let's get rid of that. We couldn't do that on the web. We have a mantra in standards. Many of you know it, don't break the web. So we were pretty much stuck with date whilst other languages were able to move on. But essentially, yeah, she brought these ideas to the committee, says we really need to move forward and have some of these in the browser. There were questions, of course. You know, is the API too big? Should we be yet again basing our API on Java? That's probably not a good idea. And can we have months that start from one? But the point is, it went through, people were happy, we had stage one in 2017. Whilst all this was going on, yeah, so my employer, we are the Bloomberg terminal. Some of you may have seen, probably seen in movies or TV shows. It's also used a hell of a lot whenever they need some backdrop of a million things happening on a machine in some financial setting. But essentially, we were using JavaScript as well. I mean, we were using Spider Monkey on the server side, which was unheard of then. I think it's still unheard of now. I think we're probably the only people doing that. We were doing that back in early 2000s, 2002, not long after Spider Monkey and Firefox was all opened up and open sourced. But also, on the front end as well, we have these weird and wonderful functions that do all sorts of things. Let's allow some of our users to watch videos, trade with each other, talk to each other, send emails, all the things that you would typically do in a browser. And for us, around 2012, 2013, we switched to using a browser for our rendering. So we actually used Chromium embedded to do a lot of our rendering for our users as well. And we also start using the JavaScript's ecosystem a lot more, especially date, which was important for us, of course. As you can imagine, there's stock exchanges all over the world, some of them time trades to do nanosecond precision. We have to pass all of these date times around. And so improving this was beneficial to us. While this was happening, and we wanted to see this happen, things were a bit slow on Tempore, so it did get to stage one, great, awesome. But I think the committee realized it took a bite of something more than it could chew. It was a very large undertaking. It had three spec champions at this point. Maggie and Matt, who both were the maintainers of Moment.js, moved into Microsoft, and Brian also started to take a bit of a step back, who works on TC39 as well. My colleague, Philip Dunkel, made a decision, which I think was probably the most important decision of Tempore's history, which was we need to seriously get behind this proposal and invest in it, because even though we were able to tinkle around the edges and move it a little bit forward, we really need people to work on Tempore and drive it full-time. So my colleague, Philip Dunkel, some of you have met. In 2018, he not only added himself as a spec champion, he convinced Bloomberg that we need to partner up with Igalia, and we actually had Philip Chimento and Ujjwal work on Temporal full-time from that point. I then joined about a year later in 2019, and then we basically upped meetings from ad hoc every now and then, once or so a month, to biweekly, then to weekly, and pretty much all through the pandemic. I remember just chatting about dates and times and random time offsets in Brazil, and the Cook Islands, have their DSTs on the quarter hour. Yeah, it was great fun. Shane joined from Google's Intl team, and Justin Grant was an invited expert who'd had previous experience in iCal. So we had a good team. We really had a solid team put together, and we started to basically put the structure together of what Tempore is gonna be. So what is it? It's a top-level object in the global scope. Some of you may have seen that if you've experimented with it already. It's what we call a namespace object, so a bit like Intl or Math, if you've used those, and then we essentially have the classes that you would need just underneath that in the form of constructor functions. So the first one is Instant. It's an exact moment in time, so you can think of it like an epoch. There's no time zone, there's no daylight savings, no calendar or anything like that. It's just, I guess, an increasing number on the absolute timeline. An example of an Instant is something like this. You can create the date, and then you can show that in different time zones. So an example here. The mental model of this is you would probably store an Instant as UTC, and then show users in their own time zone, but the actual storage would be not tied to any time zone at all. We then have a family of plane types, and they represent wall clock time, so the time that you would actually see, and again, there's no daylight savings or anything like that. This is just pure wall clock time, and we give you, hopefully, the types that you need. Yeah, you've got plane month day, plane year month, plane date, plane time, plane date time, and so on. The idea of breaking this up is to try and avoid bugs, first of all, but also to give you the types that you need. You might not need everything. You might not need the times, you might not need the dates. It's just to give you the types that you need for whatever you're putting together. And the reason why we focus on that is because people have been using date a lot to just represent the date, and they null the time by zeroing the hours, minutes, and seconds, which I guess is all you can do, or vice versa, and that's led to bugs. In fact, one of the bugs we saw when my colleague, Philip Trimento from Igalia, was booking a flight to, (laughs) he was, sorry, he was booking a hotel to a TC39 meeting when the hotel he was using, they had a bug with their date, which I found quite poetic, that. (audience laughs) A TC39 delegate trying to fix date hits a date bug on the way to a meeting to fix date. He's based in Vancouver, and this was in Bergen. I think you can see that he basically tried to book July 10th to 14th. He clicked, confirmed, and he got back July 9th, 13th. He quickly panicked and rang up the hotel, and said, "No, that's not what I wanted." On their end, they actually got it correct, so they said to him, "What do you want about it? "It is 10th to 14th. "What you booked was correct." The bug was on the front end, so when he booked it on the back end, it was all perfectly fine. They then sent the date back to the front end by just converting it to an epoch, so it could be serialized, sent it to the back end, and what they did, essentially, is they called this to local date string. They wanted to show it in his local format, and well, I guess it does that, but it also converts the date back to his time. I'm seeing a few nodding heads. We've all been there, right? Basically, yeah, so he's Vancouver, so the time, they nulled out the time because they only cared about the date. They only cared about the July 10th, so the hours, minutes, and seconds, which was zero, zero, zero, which meant that when they called to local date string, it went back by nine hours, so instead of midnight July 10th, it was now three o'clock in the afternoon on July 9th, and yeah, that's why he was getting this. This happens a lot. Another example that we see. If he was using temporal, the type best for this would be plainDates. Again, we don't care about the time, so we don't need to worry about that, and this is essentially something you would do. You have the ISO string that you could send from the back end, create your object with that, and then you could, to local string that. You don't have to have it this explicit. This was just so I could reproduce what he would see. So yeah, plain types are quite good. You have, yeah, they're there for you to think about what you want to represent, so the talk time, when the session started. The year month is also quite useful, and then play month day, so my birthday is November 6th. You don't need to know the year. Don't worry about it, but the type is there. zonedDateTime is really cool. It's basically, again, it's an exact moment in time, but you can also display a war clock time as well. It is a date time that is zoned to a particular time zone, and again, yeah, you have an example at the bottom. So yeah, here's an example. So in this example here, we're coming up to the DST, so yeah, 29th of March, half 12. We've got a forward moving DST. I want to add an hour, and we still managed to land on a correct time. So if you was using something else like a plainDateTime, you'd land on maybe 1.30, which would be incorrect, but that's okay. That's a war clock time, so it doesn't matter. With zonedDateTime, it will make sure you're still in the correct place. This is what we refer to as real time versus war clock time. zonedDateTime will also validate as well, so if you give it an invalid time. So for example, did you know midnight in Brazil on the 4th of November 2018 didn't exist? They set their DST to start at midnight for that one year. I think they only did it for that one year. So everything between midnight and I guess midnight 59, 12.59 a.m. did not exist. So if you try to set a time on that, to be fair, date will adjust for you, but now it's changed the time underneath you, and you didn't know that. With temporal, you can choose to have that reject, and we've had a lot of people who say, well, I do want to know when someone's given me a time that is invalid, and then with temporal, it can tell you. You can also have it be more relaxed and adjust for you as well. So when we design this API, we try to make it so it has a sane default, which we call compatible to sort of match what date does, but also give users an option to opt out and have it be a bit more strict. Finally, we have for zonedDateTime and some plain types, calendars. So you can take a date, and you can convert it to a different calendar. It will still be on the same timeline in an absolute sense, but you can show it and display it for that calendar too. So going back to the, so yeah, this is an example. We have the Hebrew calendar, Buddhist calendar, Japanese, Chinese calendars, and you can use withCalendar() to do that. So yeah, back to the March example. We can take the same March, end of March 29th. We can do with calendar, Japanese, and we can show the era is the Reiwa era, and the era year is the eighth year in the Reiwa era. And yeah, we have people already using this as well for date pickers and calendar pickers and things like that to show in cultural calendars. Finally is duration. I think duration is pretty self-explanatory. On all the types I've explained so far, you can do since, until, add, subtract, and the duration type pretty much works with all of them. It's pretty much the same as any duration you've used in a date library like looks on or moment. So there's not too much to go into on there, but essentially, yeah, there will be a duration type that comes with this as well. I just wanted to show this. People say, why plane? That's weird. We wanted to make sure that people choose the types that they need, so there are prefixes. We've got the zone, we've got the plane. We didn't want to just have date time. In fact, when we started this way back when, I think the type was just called date time, we felt that people would just go straight to that and start using it without understanding whether it's zoned to something or whether it's just a plane war clock. So the prefixes are very intentional. It's to force people to really sit down and think about, well, okay, what am I doing and what type do I need? Am I gonna do any date time arithmetic? Or am I just literally taking a date and displaying it on a web page? I'm not doing anything fancy, so we tried to come up with some prefixes to make people think. And I'm just showing you this to show that it was democratic. Don't blame me. (laughs) People seem to like the plane for the war clock and people seem to like the zoned for the zonedDateTime. So yeah, blame Twitter if you don't like the plane, if you don't like the prefixes. And they're very interoperable as well. So you can take a plane year and a plane month, sorry, a plane year month and a plane month day. If you put those together, you get a plane date. You can take a plane date. If you add a time to that plane date, there's methods for doing that. It will give you back a plane date time object. And if you attach a time zone to a plane date time object, you will get a zonedDateTime. And then from a zonedDateTime, you can also get an instance, you can get an epoch in milliseconds or seconds or even nanoseconds if you want. And duration works with all of them. So yeah, it's on the bottom, but it works with all of those types. So I guess that's what I mean when I say strongly typed. It's not really strongly typed in the sense that your IDE's gonna fail or anything, but we really tried to think of it in that sort of sense. So this is what we put together. Took a few years. I think by this point, we've got to about maybe 2019, 2020. We wanted to make sure that people could serialize these. People could save these types maybe to a database. And then reuse them a state later on. That was really important. So how did we do that? Well, we didn't want to make the mistake that date made. We didn't want to try and parse every possible type of time you could put in. So we just stuck with ISO 8601. This was a very quick and easy decision. I think everyone in the room was just like, "Yeah, ISO 8601 or nothing." So basically, yeah, it makes it a lot simpler for developers. It makes it a lot simpler for engines. And we don't have the same issues with date where browsers may do one thing and another browser may do something else. This is what an ISO 8601 string looks like on the top left. You've made use in it before. We've got the offset on the right. And all of our types map onto that. So you've got the plain month day, the plain year month, 202602, the plainDate, you have plainTime, you have the plainDateTime, and you even have an instant which works because you've got the offset. Sorry. So anything you call, sorry, sorry, I should say, any of these types where you call to string or to JSON, you get the ISO equivalent of that and then you can store that. We did hit a problem though. zonedDateTime doesn't work. ISO never really supported us being able to add a time zone to these types. So we actually hit a roadblock, and this is actually one of the reasons why Temporal sort of took a bit more time. zonedDateTime has a time zone. There's no way on there to put that, and also calendar, which I showed you, there's no way on there to put that as well. So we, yeah, we were like, well, what do we do with this? One of our delegates said to us, well, you know what, like, parsers and people just tag on the end time zones anyway. I mean, it's not really standard, but people just do it, it kind of works. I guess many parsers that know that there's gonna be a tagged time zone on the end inside of the square brackets will use it if it's there, and parsers that just follow the standard to a strict letter will ignore it. So in a way, it was a hack that was backwards compatible. It kind of just worked across the board. So we took a bit of a long shot and went to IETF. Ujwah Sharma from Igalia, he sat down with IETF and says, look, we need to fix this, and maybe we could just have this be a standard. It's already a de facto standard. Maybe we could just standardize it, and that's when he, after about a year and a half was worth of work, we managed to have an RFC on IETF. So it was, boom, approved. We now made it standard, and this is great, actually, because this doesn't just benefit Temporal. It doesn't just benefit JavaScript. Any language that's used in ISO now gets this. Completely standardized, it's not a hack anymore. This is done. So this was a really good side quest, very valuable. Yeah. Okay, so going back to our ISO string, we now have a timezone on the end, and again, this is now standard. It's no longer a hack. This is part of RFC 3339, but not only that, when we spent time standardizing it, we didn't want to just standardize it for timezones and then have to come back a year later and say, "Oh, can we have this?" We wanted to make it so that you could add custom data as well. So calendars, this is a valid ISO string. We've got the Asia, Tokyo timezone on the end, and also the calendar of your choice, so you can serialize that and store that. And I think you can also, I don't show it here, but there's essentially a prefix where you can also add custom metadata as well. So if anything else, frameworks want to add, they can add it, and it will be fine. It will be completely, parsers should be completely fine. And it's backwards compatible, so any parser that's not on the latest, this will still work. This should be still valid. So this was great. We could now do zonedDateTime. We could serialize them down to a string, and just something like this was about a year and a half to two years worth of work. We were able to do stuff in the meantime while we waited, but we had to take one step. I mean, going to TC39 is low enough anyway, I think for most people, but then going even lower down into IETF and dealing with this, it was a bit of a journey. But yeah, so we now had support for every single type. So we've got Temporal, we've got the type sorted. You can serialize them down to strings. Implementing it, implementing Temporal was a challenge. It's a huge challenge. It's a massive spec. Jake mentioned it earlier. It's the biggest addition. It is actually the biggest addition to JavaScript since ES6. And ES6 was a lot of stuff. This is just one API, and it's the biggest addition to JavaScript we've had. There was spec volatility doing this. We actually had more features than what I showed you. We've actually removed features because the API suface area was huge. Many edge cases, and we had to make sure we'd integrated, of course, with the information that browsers throw into the engines and all of that worked as well. Yeah, there's so many. I want to give a shout out to Firefox. Firefox did really well on this. Anba (André Bargull), who worked with us on this, he was contributing to Firefox as he was going along, and he was joining all the spec meetings. And yeah, Mozilla did a fantastic job, and they were able to get a finished implementation of what was May last year. So yeah, big shout out to Anba. Yeah. I just want to give you a bit of an idea of how big this is. So we judge things by test size. So basically how many tests it took to implement something. We have a framework called Test 262 in ECMAScript. Every single engine that implements JavaScript runs that framework. Any of you, if any of you are from W3C, I guess it's a bit like Web Platform Test. It's the JavaScript equivalent of that. And for some of the built-ins, these are the number of tests. So for our good friend dates, that I think many of you have been using for many, many years, we have around 594 tests. BigInt, which was added two years ago, 75, Boolean, 51. String has 1,208. Function is 488. (audience laughing) Temporal is 4,496. (audience laughing and applauding) 4,500 tests. I want you to keep that in mind. I want you to keep that number in mind. 2017 I created a JavaScript engine in Rust called Boa. I went to, at the time, the biggest JavaScript conference and showed people some Rust code. I don't recommend doing that. (audience laughing) It's not good for your mental health to be doing that. At the time, Boa, it was very new. It was experimental. It was just to see what happens if we work together, creating a JavaScript engine in Rust. Can we get the community together to work on that? It ended up doing pretty well, actually. It had some good maintainers. We managed to build up a team. We managed to build a community around it. Today, there's a lot of things, a lot of projects that make use of it. I had a maintainer come up to me in 2020, 2021, and say, "I want to implement temporal." I said, "Okay, you know that's a big undertaking. That's not BigInt. That's a big thing." Really want to do it. Myself, that maintainer who's called Kevin Ness and another maintainer called Jose Espina, we got together and we just thought, "Okay, let's have a crack at it and start putting some things together." It went pretty well. We didn't finish at the time, but I think we got about 30% of the spec done. I don't remember how many tests that was, but we got a majority of it done. We managed to get some of the date types and things working. Now, at the same time, I was still going to spec meetings, so I was talking to other engines as well, not just us. Of course, V8. Many of you know V8 powers Chromium. It powers Node.js and Dino and various other projects. They also need Temporal, right? You need to have it in Chrome. V8 were also working on this, but again, as I said, it's a big undertaking. They were a little bit behind us at the time, but as I said, the spec was fluctuating, so they, of course, just like many engines did, have a hard time keeping up. We just weren't as good as Anba in Firefox. Firefox was just amazing ahead of the game. I chatted with the Intl team and the V8 team, and we, at the time, they were very interested in Rust as well. Chromium were interested in Rust, for type safety, for ease of development, and yeah, improving security. We tried to, between us, do something that was pretty unconventional at the time. I don't think it's ever been done to implement the spec proposal. We partnered up, and we decided that because Temporal is so big, and it's such a huge spec to implement, that we should try and join up forces, actually, and try to put it as a library. So a couple of years ago, at TC39, I sat down with Shane Carr, Google Intl team, and someone else from the V8, and we said, yeah, let's do it. Let's work together on this, and Boa and V8 started working on a new library in Rust called TemporalRS. We put that together. I very quickly made sure that we had a team. I'm a big fan of, I guess what I call, open source sustainability. So basically, what that means for me is it's not like a one-man band, putting something together. There's loads of hype. Everyone goes, "Wait, this is great!" Downloads it, and then a year later, things start slowing down because that person has gone off and needs to do something else. It was really important that this wasn't just gonna be me or some people in Boa doing stuff. It was what we had input from Google as well. So I basically headed up the project, and I think people liked that because it meant that I wasn't writing any code. They kept me away from that. Kevin Ness, who I mentioned earlier, he really was one of the main contributors to this. But what was great was we had Manish from the Google Intl team who really contributed and helped as well. So it really was a joint effort. And we also had some students involved from Bergen University who jumped in, and they were able to start contributing as well. They had never contributed to an engine before, so this was the first time for them. Shane actually had to give them a crash course on Rust and how to contribute to large projects, so it really was the first time for them. Very quickly, we started on 37%. So like I said, we already had some code for Temporal, so we didn't start from zero. We moved that code into a library, so that's why we're not starting from zero. We have 37%. We had some of the base classes sorted out. So this is Q4, 2024. We had what was called the Bergen project, so the students from university jumped in and they were able to help out and start contributing loads of stuff. They took us all the way to 92%. And that was with help from Shane, Karr, Kevin, and myself, just mentoring and helping them contribute code. And then at this point, V8 integrated Temporal.0. This was a big moment for me. V8 has never had Rust code integrated in it before. In fact, in order to get this to work in V8, they had to change the entire build system to build Rust and cargo and everything else. So this was a big moment. I'm proud to say that, yeah, TemporalRS is the first ever Rust library to be integrated directly into V8. Kevin and Manish really took it to 100%. And actually, it only reached 100% this year, so second week of January. And yeah, all those tests that I mentioned before, the 4,500 temporal RS passes all of those tests. So it was a success. It worked. Pretty unconventional, not something we've really done before and not something I don't think V8 have ever done before. But I think it worked well. It reduced barrier to entry. The people who were contributing to the students didn't have to worry about contributing to V8. They didn't have to worry about how BOA works. They just were able to focus on the library. So it was well scoped. It was well contained. There was long-term maintenance. So Manish from Google, he was willing to stay on the project and help us with that. We had someone from BOA, two people from BOA who was willing to stay on the project. And so we had good maintenance. We actually had input from other engines as well. So in the end, it wasn't just two, V8 and BOA. We actually have about five engines now using this. And yeah, I think because it was easier to review, we had higher quality code because it was well scoped and we were able to use the modern Rust tooling. And so because of all of that, we were able to finally ship Temporal. So we got it in Chromium 144 and that's on-flagged. So that came out Jan 6th. And then Edge was about 10 days later. But again, it's the same V8 engine, so there's power in both. As I mentioned, Firefox has been amazing. So we had that in Firefox on-flagged from last year in May. Amber did a really great job there. Node, of course, use V8. So they'll be getting it soon. They've had to make some changes to the build system. But we should be seeing it in version 26. Safari is actually being implemented. I was gonna, I don't need to say, contact your local browser vendor. It is being implemented. So if you use Safari technology preview, it is actually in there. They're about 70% done. You can actually run it in Safari with the flag. And you're able to experiment and use it. It's not finished, but we should see it finish this year. Igalia are working on that. And we have all the types of temporal now as well. It's in 6.0 beta, which came out, I think. I think it's already out, but 6.0 proper is gonna come out soon. And I also wanna give a quick shout out to Eric Meyer of CSS fame, who handled most of the documentation on MDN as well. So, yeah, yeah. He's been helping us with this. So what's next? Integration in this role. We obviously want it to work across the web. Date pickers. So right now you can do element value as date. You should be able to do value as, and then plainDate, plainDateTime, and so on. Anywhere that you pass a timestamp, you should be able to pass a temporal instance. So in this example, you've got "add 24 hours", and you can pass that as milliseconds. So this should work anywhere where a high res timestamp can be passed. Structured clone, that can handle most types. It can't handle temporal right now, but we're planning to add that support as well. And date conversion, going back and forth between date and plain and instance, that is already supported. So that's pretty much how you would do it. We do still support date. And yeah, finally, we hope to go to stage four in just over a week. So 10th of March. That will be hopefully the final meeting of temporal. And we hope to basically go to that meeting and announce that the work is finished. There's still a few loose ends, but not much. And hopefully we can all sit back and rejoice after about 10 years worth of work. Say it's done. Thank you.

About Jason Williams

Jason Williams

Jason Williams is a senior software engineer on Bloomberg’s performance team and the creator of the Boa JavaScript engine, an experimental Rust-based engine for the web. With two decades of experience spanning web performance, open source, and standards, Jason has represented Bloomberg in both TC39 and the W3C, and previously led engineering projects as a principal software engineer at the BBC.