<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
  <title>Bloomberg JS Blog</title>
  <subtitle>The official Bloomberg JavaScript blog.</subtitle>
  <link href="https://bloomberg.github.io/js-blog/feed.xml" rel="self" />
  <link href="https://bloomberg.github.io/js-blog/" />
  <updated>2026-03-11T00:00:00Z</updated>
  <id>https://bloomberg.github.io/js-blog/</id>
  <author>
    <name>Bloomberg JavaScript Guild</name>
  </author>
  <entry>
    <title>Temporal: The 9-Year Journey to Fix Time in JavaScript</title>
    <link href="https://bloomberg.github.io/js-blog/post/temporal/" />
    <updated>2026-03-11T00:00:00Z</updated>
    <id>https://bloomberg.github.io/js-blog/post/temporal/</id>
    <content type="html">&lt;p&gt;Welcome to our blog! I&#39;m Jason Williams, a senior software engineer on Bloomberg&#39;s JavaScript Infrastructure and Terminal Experience team. Today the Bloomberg Terminal runs &lt;a href=&quot;https://bloomberg.github.io/js-blog/post/intro/&quot;&gt;a lot of JavaScript&lt;/a&gt;. Our team provides &lt;a href=&quot;https://www.youtube.com/watch?v=y1MCLZm8yAY&quot;&gt;a JavaScript environment&lt;/a&gt; to engineers across the company.&lt;/p&gt;
&lt;p&gt;Bloomberg may not be the first company you think of when discussing JavaScript. It certainly wasn&#39;t for me in 2018 before I worked here. Back then, I attended my first &lt;a href=&quot;https://tc39.es/&quot;&gt;TC39&lt;/a&gt; meeting in London, only to meet some Bloomberg engineers who were there discussing Realms, WebAssembly, Class Fields, and &lt;a href=&quot;https://github.com/tc39/agendas/blob/main/2018/03.md&quot;&gt;other topics&lt;/a&gt;. The company has now been involved with JavaScript standardization for numerous years, including partnering with Igalia. Some of the proposals we have assisted include &lt;a href=&quot;https://wingolog.org/archives/2015/06/18/arrow-functions-coming-to-chrome-45&quot;&gt;Arrow Functions&lt;/a&gt;, Async Await, BigInt, Class Fields, Promise.allSettled, Promise.withResolvers, WeakRefs, &lt;a href=&quot;https://bloomberg.github.io/js-blog/post/standardizing-source-maps/&quot;&gt;standardizing Source Maps&lt;/a&gt;, and more!&lt;/p&gt;
&lt;p&gt;The first proposal I worked on was &lt;a href=&quot;https://github.com/tc39/proposal-promise-allSettled&quot;&gt;Promise.allSettled&lt;/a&gt;, which was fulfilling. After that finished, I decided to help out on a proposal around dates and times, called Temporal.&lt;/p&gt;
&lt;h2 id=&quot;how-does-javascript-change&quot; tabindex=&quot;-1&quot;&gt;How Does JavaScript Change? &lt;a class=&quot;header-anchor&quot; href=&quot;https://bloomberg.github.io/js-blog/post/temporal/#how-does-javascript-change&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;JavaScript is unique in that it runs in all browsers. There is no single &amp;quot;owner,&amp;quot; so you can&#39;t just make a change in isolation and expect it to apply everywhere. You need buy-in from all parties. Evolution happens through &lt;a href=&quot;https://tc39.es/&quot;&gt;TC39&lt;/a&gt;, the Technical Committee responsible for ECMAScript.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://bloomberg.github.io/js-blog/images/temporal-image4.jpg&quot; alt=&quot;TC39 Plenary hosted at Bloomberg&#39;s NY office in 2018&quot;&gt;&lt;/p&gt;
&lt;p&gt;Proposals move through a series of &lt;a href=&quot;https://tc39.es/process-document/%20&quot;&gt;maturity stages&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Stage 0 - Idea&lt;/li&gt;
&lt;li&gt;Stage 1 - Problem space accepted&lt;/li&gt;
&lt;li&gt;Stage 2 - Draft design chosen, but work to continue&lt;/li&gt;
&lt;li&gt;Stage 2.7 - Proposal approved in principle; awaiting testing and feedback&lt;/li&gt;
&lt;li&gt;Stage 3 - Implementation and feedback&lt;/li&gt;
&lt;li&gt;Stage 4 - Standardized&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In 2018, when I first looked at Temporal, it was at Stage 1. The TC39 Committee was convinced the problem was real. It was a radical proposal to bring a whole new library for Dates and Times into JavaScript. It was:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A replacement for Date&lt;/li&gt;
&lt;li&gt;Providing different DateTime Types (instead of a single API)&lt;/li&gt;
&lt;li&gt;Immutable&lt;/li&gt;
&lt;li&gt;Adding first-class time zone and calendar support&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;But how did we get here? Why was Date such a pain point? For that, we need to take a step back.&lt;/p&gt;
&lt;h2 id=&quot;a-product-of-its-time&quot; tabindex=&quot;-1&quot;&gt;A Product of Its Time &lt;a class=&quot;header-anchor&quot; href=&quot;https://bloomberg.github.io/js-blog/post/temporal/#a-product-of-its-time&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In 1995, Brendan Eich was tasked with a 10-day sprint to create Mocha (which would later become JavaScript). Under intense time pressure, many design decisions were pragmatic. One of them was to port Java&#39;s Date implementation directly. As Brendan later explained:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;It was a straight port by Ken Smith (the only code in &amp;quot;Mocha&amp;quot; I didn&#39;t write) of Java&#39;s Date code from Java to C.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;At the time, this made sense. Java was ascendant and JavaScript was being framed as its lightweight companion. Internally, the philosophy was even referred to as &lt;strong&gt;MILLJ&lt;/strong&gt;: Make It Look Like Java.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://bloomberg.github.io/js-blog/images/temporal-image6.png&quot; alt=&quot;A Tweet by Brendan Eich that says: Ten-day-sprint Mocha, 25 years old today, finished in time to be demo&#39;ed via the mocha: console that looked close to this image, did not have Date (Ken Smith helped and we agreed per MILLJ to port java.util.Date, bugs and all), had strict ==, and of course had NaNs.&quot;&gt;&lt;/p&gt;
&lt;p&gt;Brendan &lt;a href=&quot;https://x.com/BrendanEich/status/1360745840269135873&quot;&gt;also noted&lt;/a&gt; that changing the API would have been politically difficult:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Changing it when everyone expected Java to be the &amp;quot;big brother&amp;quot; language would make confusion and bugs; Sun would have objected too.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In that moment, consistency with Java was more important than fundamentally rethinking the time model. It was a pragmatic trade-off. The Web was young, and most applications making use of JavaScript would be simple, at least, to begin with.&lt;/p&gt;
&lt;h2 id=&quot;the-web-grew-up-date-didnt&quot; tabindex=&quot;-1&quot;&gt;The Web Grew Up, Date Didn&#39;t &lt;a class=&quot;header-anchor&quot; href=&quot;https://bloomberg.github.io/js-blog/post/temporal/#the-web-grew-up-date-didnt&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;By the 2010s, JavaScript was powering banking systems, trading terminals, collaboration tools, and other complex systems running in every time zone on earth. Date was becoming more of a pain point for developers.&lt;/p&gt;
&lt;h3 id=&quot;mutability&quot; tabindex=&quot;-1&quot;&gt;Mutability &lt;a class=&quot;header-anchor&quot; href=&quot;https://bloomberg.github.io/js-blog/post/temporal/#mutability&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Developers would often write helper functions that accidently mutated the original Date object in place when they intended to return a new one:&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; date &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;2026-02-25T00:00:00Z&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;date&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toISOString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// &quot;2026-02-25T00:00:00.000Z&quot;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;addOneDay&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// oops! This is mutating the date&lt;/span&gt;
  d&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setDate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;d&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getDate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; d&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;addOneDay&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;date&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;date&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toISOString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// &quot;2026-02-26T00:00:00.000Z&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;inconsistent-month-arithmetic&quot; tabindex=&quot;-1&quot;&gt;Inconsistent Month Arithmetic &lt;a class=&quot;header-anchor&quot; href=&quot;https://bloomberg.github.io/js-blog/post/temporal/#inconsistent-month-arithmetic&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;pre class=&quot;language-javascript&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; billingDate &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Sat Jan 31 2026&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
billingDate&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setMonth&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;billingDate&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getMonth&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// Expected: Feb 28&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// Actual:   Mar 02&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Sometimes people want to get the last day of the month and fall into traps like this one, where they bump the month by one, but the days remain the same. Date does not constrain invalid calendar results back into a valid date. Instead, it silently rolls overflow into the next month.&lt;/p&gt;
&lt;h3 id=&quot;ambiguous-parsing&quot; tabindex=&quot;-1&quot;&gt;Ambiguous Parsing &lt;a class=&quot;header-anchor&quot; href=&quot;https://bloomberg.github.io/js-blog/post/temporal/#ambiguous-parsing&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;pre class=&quot;language-javascript&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;2026-06-25 15:15:00&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toISOString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// Potential Return Values:&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// - local TimeZone&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// - Invalid Date RangeError&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// - UTC&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this example, the string is similar, but not identical, to ISO 8601. Historically, browser behavior for &amp;quot;almost ISO&amp;quot; strings was &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1274354&quot;&gt;undefined by the specification&lt;/a&gt;. Some would treat it as local time, others as UTC, and one would throw entirely as invalid input.&lt;/p&gt;
&lt;p&gt;There&#39;s more, &lt;a href=&quot;https://jsdate.wtf/&quot;&gt;much more&lt;/a&gt;, but the point is that Date has been a pain point for JavaScript developers for the past three decades.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://bloomberg.github.io/js-blog/images/temporal-image3.png&quot; alt=&quot;State of JS survey results for &amp;quot;Language Pain Points&amp;quot; showing Dates as the #2 pain point at 10% (372 responses), behind only Lack of static typing at 28% (1,102 responses), and ahead of TypeScript support at 7% (276 responses).&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;the-library-era&quot; tabindex=&quot;-1&quot;&gt;The Library Era &lt;a class=&quot;header-anchor&quot; href=&quot;https://bloomberg.github.io/js-blog/post/temporal/#the-library-era&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The Web ecosystem had no choice but to patch Date&#39;s shortcomings with libraries. You can see the sheer rise of datetime libraries below. Today, they add up to more than 100 million downloads a week.&lt;/p&gt;
&lt;p&gt;Leading the charge was &lt;a href=&quot;https://momentjs.com/&quot;&gt;Moment.js&lt;/a&gt;, which boasts an expressive API, powerful parsing capabilities, and much-needed immutability. Created in 2011, it quickly became the de facto standard for handling date and time manipulations in JavaScript. So surely the problem is solved? Everyone should just grab a copy of this and call it a day.&lt;/p&gt;
&lt;p&gt;The widespread adoption of moment.js (plus other similar libraries) came with its own set of problems. Adding the library meant increasing bundle size, due to the fact that it needed to be shipped with its own set of locale information plus time zone data from the time zone database.&lt;/p&gt;
&lt;p&gt;Despite the use of minifiers, compilers, and static analysis tools, all of this extra data couldn&#39;t be tree-shaken away, because most developers don&#39;t know ahead of time which locales or time zones they&#39;ll need. In order to play it safe, the majority of users took all of the data wholesale and shipped it to their users.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://bloomberg.github.io/js-blog/images/temporal-image1.png&quot; alt=&quot;npm download trends for date-fns, luxon, and moment from 2015 to January 2026, all showing steep growth. As of Jan 11, 2026: date-fns leads at 39.6M weekly downloads, moment at 25.8M, and luxon at 18.9M, totaling over 84 million downloads per week.&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://bloomberg.github.io/js-blog/images/temporal-image5.png&quot; alt=&quot;Bundlephobia stats for moment@2.30.1 showing a publish size and install size of 4.15 MB, with a bar chart of install sizes across versions from 2.24.0 to 2.30.1 showing steady growth.&quot;&gt;&lt;/p&gt;
&lt;p&gt;Maggie Johnson-Pint, who had been a maintainer of Moment.js for quite a few years (alongside others), was no stranger to requests to deal with the package size.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;We were at the point with moment that it was more maintenance to keep up with modules, webpack, people wanting everything immutable because React, etc than any net new functionality&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;And people never stop talking about the size of course.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In 2017, Maggie decided it was time to standardise dates and times with a &amp;quot;Temporal Proposal&amp;quot; for the TC39 plenary that year. It was met with great enthusiasm, leading it to be advanced to Stage 1.&lt;/p&gt;
&lt;h2 id=&quot;the-champions-assemble&quot; tabindex=&quot;-1&quot;&gt;The Champions Assemble &lt;a class=&quot;header-anchor&quot; href=&quot;https://bloomberg.github.io/js-blog/post/temporal/#the-champions-assemble&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Stage 1&lt;/strong&gt; was a big milestone, but it was still far from the finish line. After the initial burst of energy, progress naturally slowed. Maggie and Matt Johnson-Pint were leading the effort alongside &lt;strong&gt;Brian Terlson&lt;/strong&gt;, while simultaneously balancing other responsibilities inside Microsoft. Temporal was still early enough that much of the immediate work was unglamorous: requirements gathering, clarifying semantics, and translating &amp;quot;the ecosystem&#39;s pain&amp;quot; into a design that could actually ship.&lt;/p&gt;
&lt;p&gt;At Bloomberg, that pain wasn&#39;t theoretical.&lt;/p&gt;
&lt;p&gt;We run JavaScript at scale across the Terminal, using underlying runtimes and engines such as &lt;strong&gt;Chromium, Node.js&lt;/strong&gt; and &lt;strong&gt;SpiderMonkey&lt;/strong&gt;. Our users, and the financial markets in which they invest, span every time zone on earth. We pass timestamps constantly: between services, into storage, into the UI, and across systems that all have to agree on what &amp;quot;now&amp;quot; means, even &lt;a href=&quot;https://lists.iana.org/hyperkitty/list/tz@iana.org/thread/XD4GXA47YMP37GQ6HRG7VVVAZDXGRH7S/#XD4GXA47YMP37GQ6HRG7VVVAZDXGRH7S&quot;&gt;when governments change DST rules with very little notice&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;On top of that, we had requirements that the built-in Date model simply wasn&#39;t designed for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A user-configured time zone&lt;/strong&gt; that is not the machine&#39;s time zone (and can change per request).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Correct historical time zone behavior&lt;/strong&gt; driven by IANA Time Zone Database (tzdata) updates.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Higher-precision timestamps&lt;/strong&gt; (nanoseconds, at a minimum), without duct-taping extra fields onto ad-hoc wrappers forever.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In parallel with Maggie bringing Temporal to TC39, Bloomberg engineer &lt;strong&gt;Andrew Paprocki&lt;/strong&gt; was talking with Igalia about making time zones configurable in V8. Specifically, they discussed introducing a supported indirection layer so an embedder could control the &amp;quot;perceived&amp;quot; time zone instead of relying on the OS default. In that conversation, &lt;strong&gt;Daniel Ehrenberg&lt;/strong&gt; (then working at Igalia) pointed Andrew at the early Temporal work because it looked strikingly similar to Bloomberg&#39;s existing value-semantic datetime types.&lt;/p&gt;
&lt;p&gt;That exchange became an early bridge between Bloomberg&#39;s production needs, Igalia&#39;s browser-and-standards expertise, and the emerging direction of Temporal. Over the years that followed, Bloomberg partnered with Igalia (including via sustained funding support) and contributed engineering time directly into moving Temporal forward, until it eventually became something the whole ecosystem could ship. Andrew was looking for some volunteers within Bloomberg who could help push Temporal forward and &lt;strong&gt;Philipp Dunkel&lt;/strong&gt; volunteered to be a spec champion. Alongside Andrew, he helped persuade Bloomberg to invest in making Temporal real, including a deeper partnership with Igalia. That support brought in &lt;strong&gt;Philip Chimento&lt;/strong&gt; and &lt;strong&gt;Ujjwal Sharma&lt;/strong&gt; as full time Temporal champions, adding the day-to-day focus the proposal needed to keep moving ahead.&lt;/p&gt;
&lt;p&gt;Richard Gibson (now an ECMAScript editor) volunteered as a Stage 3 reviewer in 2018, but over the years also cleaned up and directly contributed specification text for a smooth and comprehensible integration with the rest of the language.&lt;/p&gt;
&lt;p&gt;Shane Carr joined the Champions team, representing Google&#39;s Internationalization team. He provided the focus we needed on internationalization topics such as calendars, and also served as the glue between the standardization process and the voice of users who experienced pain points with tools related to JavaScript&#39;s internationalization API (Intl), such as formatting, time zones, and calendars.&lt;/p&gt;
&lt;p&gt;Finally, we had Justin Grant, who joined the Temporal champions in 2020 as a volunteer. After 10 years at three different startups that managed time-stamped data, he&#39;d seen engineering teams waste &lt;em&gt;thousands&lt;/em&gt; of hours fixing mistakes with dates, times, and time zones. Justin&#39;s experience grounded us in real-world use cases, helped us anticipate mistakes that developers would make, and ensured that Temporal shipped a &lt;code&gt;Temporal.ZonedDateTime&lt;/code&gt; API to help make DST bugs a thing of the past.&lt;/p&gt;
&lt;p&gt;Other honorable mentions not on this list include Daniel Ehrenberg, Adam Shaw, and Kevin Ness.&lt;/p&gt;
&lt;h3 id=&quot;the-current-and-past-champions-of-temporal&quot; tabindex=&quot;-1&quot;&gt;The Current &amp;amp; Past Champions of Temporal &lt;a class=&quot;header-anchor&quot; href=&quot;https://bloomberg.github.io/js-blog/post/temporal/#the-current-and-past-champions-of-temporal&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Maggie Johnson-Pint (Microsoft)&lt;/li&gt;
&lt;li&gt;Matt Johnson-Pint (Microsoft)&lt;/li&gt;
&lt;li&gt;Brian Terlson (Microsoft)&lt;/li&gt;
&lt;li&gt;Richard Gibson (Agoric)&lt;/li&gt;
&lt;li&gt;Philipp Dunkel (Bloomberg)&lt;/li&gt;
&lt;li&gt;Ujjwal Sharma (Igalia)&lt;/li&gt;
&lt;li&gt;Philip Chimento (Igalia)&lt;/li&gt;
&lt;li&gt;Jason Williams (Bloomberg)&lt;/li&gt;
&lt;li&gt;Shane Carr (Google)&lt;/li&gt;
&lt;li&gt;Justin Grant (Invited Expert)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;how-temporal-looks-today&quot; tabindex=&quot;-1&quot;&gt;How Temporal Looks Today &lt;a class=&quot;header-anchor&quot; href=&quot;https://bloomberg.github.io/js-blog/post/temporal/#how-temporal-looks-today&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Temporal is a top-level namespace object (similar to Math or Intl) that exists in the global scope. Underneath it are &amp;quot;types&amp;quot; that exist in the form of constructors. It&#39;s expected that developers will reach for the type they need when using the API, such as &lt;code&gt;Temporal.PlainDateTime&lt;/code&gt;, for example.&lt;/p&gt;
&lt;p&gt;Here are the types Temporal comes packed with:&lt;/p&gt;
&lt;h3 id=&quot;temporal-zoneddatetime&quot; tabindex=&quot;-1&quot;&gt;Temporal.ZonedDateTime &lt;a class=&quot;header-anchor&quot; href=&quot;https://bloomberg.github.io/js-blog/post/temporal/#temporal-zoneddatetime&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If you don&#39;t know which Temporal type you need, start with &lt;code&gt;Temporal.ZonedDateTime&lt;/code&gt;.
It is the closest conceptual replacement for &lt;code&gt;Date&lt;/code&gt;, but without the &amp;quot;footguns.&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Date represents:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;An exact moment in time (internally, milliseconds since epoch)&lt;/li&gt;
&lt;li&gt;Interpreted through the machine&#39;s current time zone&lt;/li&gt;
&lt;li&gt;With implicit, mutable behavior&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Temporal.ZonedDateTime represents:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;An exact moment in time&lt;/li&gt;
&lt;li&gt;With an explicit time zone&lt;/li&gt;
&lt;li&gt;With an explicit calendar&lt;/li&gt;
&lt;li&gt;And full daylight-saving correctness&lt;/li&gt;
&lt;li&gt;All as an immutable value&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you&#39;re currently writing:&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; now &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The Temporal equivalent is:&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; now &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Temporal&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Now&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;zonedDateTimeISO&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The above example uses the Now namespace, which gives you the type already set to your current local time and time zone.&lt;/p&gt;
&lt;p&gt;This type is optimized for DateTimes that may require some datetime arithmetic in which the daylight saving transition could potentially cause problems. &lt;code&gt;ZonedDateTime&lt;/code&gt; can take those transitions into account when doing any addition or subtraction of time (see example below).&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// London DST starts: 2026-03-29 01:00 -&gt; 02:00&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; zdt &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Temporal&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ZonedDateTime&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;2026-03-29T00:30:00+00:00[Europe/London]&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;zdt&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// → &quot;2026-03-29T00:30:00+00:00[Europe/London]&quot;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; plus1h &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; zdt&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;hours&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;plus1h&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// &quot;2026-03-29T02:30:00+01:00[Europe/London]&quot; (01:30 doesn&#39;t exist)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this example, we don&#39;t land at &lt;code&gt;01:30&lt;/code&gt; but &lt;code&gt;02:30&lt;/code&gt; instead, because &lt;code&gt;01:30&lt;/code&gt; doesn&#39;t exist at that specific point in time.&lt;/p&gt;
&lt;h3 id=&quot;temporal-instant&quot; tabindex=&quot;-1&quot;&gt;Temporal.Instant &lt;a class=&quot;header-anchor&quot; href=&quot;https://bloomberg.github.io/js-blog/post/temporal/#temporal-instant&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;Temporal.Instant&lt;/code&gt; is an exact moment in time, it has no time zone, no daylight saving, no calendar. It represents elapsed time since midnight on January 1, 1970 (the &lt;a href=&quot;https://en.wikipedia.org/wiki/Unix_time&quot;&gt;Unix epoch&lt;/a&gt;). Unlike &lt;code&gt;Date&lt;/code&gt;, which has a very similar data model, &lt;code&gt;Instant&lt;/code&gt; is measured in nanoseconds rather than milliseconds. This decision was taken by the champions because even though the browser has some coarsening for &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/DOMHighResTimeStamp#security_requirements&quot;&gt;security purposes&lt;/a&gt;, developers still need to deal with nanosecond-based timestamps that could have been generated from elsewhere.&lt;/p&gt;
&lt;p&gt;A typical example of &lt;code&gt;Temporal.Instant&lt;/code&gt; usage looks like this:&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// One exact moment in time&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; instant &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Temporal&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Instant&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;2026-02-25T15:15:00Z&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

instant&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// &quot;2026-02-25T15:15:00Z&quot;&lt;/span&gt;

instant&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toZonedDateTimeISO&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Europe/London&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// &quot;2026-02-25T15:15:00+00:00[Europe/London]&quot;&lt;/span&gt;

instant&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toZonedDateTimeISO&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;America/New_York&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// &quot;2026-02-25T10:15:00-05:00[America/New_York]&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;Instant&lt;/code&gt; can be created and then converted to different &amp;quot;zoned&amp;quot; DateTimes (more on that later). You would most likely store the &lt;code&gt;Instant&lt;/code&gt; (in your backing storage of choice) and then use the different TimeZone conversions to display the same time to users within their time zones.&lt;/p&gt;
&lt;h3 id=&quot;temporal-plaindate-plaintime-plaindatetime-plainyearmonth-plainmonthday&quot; tabindex=&quot;-1&quot;&gt;Temporal.[PlainDate, PlainTime, PlainDateTime, PlainYearMonth, PlainMonthDay] &lt;a class=&quot;header-anchor&quot; href=&quot;https://bloomberg.github.io/js-blog/post/temporal/#temporal-plaindate-plaintime-plaindatetime-plainyearmonth-plainmonthday&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;We also have a family of plain types. These are what we would call &amp;quot;wall time,&amp;quot; because if you imagine an analogue clock on the wall, it doesn&#39;t check for daylight saving or time zones. It&#39;s just a plain time (moving the clock forward by an hour would advance it an hour on the wall, even if you did this during a Daylight Saving transition).&lt;/p&gt;
&lt;p&gt;We have several types with progressively less information. This is useful, as you can choose the type you want to represent and don&#39;t need to worry about running calculations on any other un-needed data (such as calculating the time if you&#39;re only interested in displaying the date).&lt;/p&gt;
&lt;p&gt;These types are also useful if you only plan to display the value to the user and do not need to perform any date/time arithmetic, such as moving forwards or backwards by weeks (you will need a calendar) or hours (you could end up crossing a daylight saving boundary). The limitations of some of these types are also what make them so useful. It&#39;s hard for you to trip up and encounter unexpected bugs.&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; date &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Temporal&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;PlainDate&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;year&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2026&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;month&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;day&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;11&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// =&gt; 2026-03-11&lt;/span&gt;
date&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;year&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// =&gt; 2026&lt;/span&gt;
date&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;inLeapYear&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// =&gt; false&lt;/span&gt;
date&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// =&gt; &#39;2026-03-11&#39;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;calendars&quot; tabindex=&quot;-1&quot;&gt;Calendars &lt;a class=&quot;header-anchor&quot; href=&quot;https://bloomberg.github.io/js-blog/post/temporal/#calendars&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Temporal supports calendars. Browsers and runtimes ship with a set of &lt;a href=&quot;https://unicode-org.github.io/icu/userguide/datetime/calendar/#overview&quot;&gt;built-in calendars&lt;/a&gt;, which lets you represent, display, and do arithmetic in a user&#39;s preferred calendar system, not just format a Gregorian date differently.&lt;/p&gt;
&lt;p&gt;Because Temporal objects are calendar-aware, operations like &amp;quot;add one month&amp;quot; are performed &lt;strong&gt;in the rules of that calendar&lt;/strong&gt;, so you land on the expected result. In the example below, we add one Hebrew month to a Hebrew calendar date:&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; today &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Temporal&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;PlainDate&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;2026-03-11[u-ca=hebrew]&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
today&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toLocaleString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;en&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;calendar&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;hebrew&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// &#39;22 Adar 5786&#39;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; nextMonth &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; today&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;months&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
nextMonth&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toLocaleString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;en&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;calendar&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;hebrew&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// &#39;22 Nisan 5786&#39;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With legacy &lt;code&gt;Date&lt;/code&gt;, there&#39;s no way to express &amp;quot;&lt;em&gt;add one Hebrew month&lt;/em&gt;&amp;quot; as a first-class operation. You can &lt;em&gt;format&lt;/em&gt; using a different calendar, but any arithmetic you do is still Gregorian month arithmetic under the hood.&lt;/p&gt;
&lt;p&gt;If you tried to approximate this with &lt;code&gt;Date&lt;/code&gt;, it might look like:&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; legacyDate &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2026&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;11&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
legacyDate&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toLocaleDateString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;en&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;calendar&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;hebrew&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// &#39;22 Adar 5786&#39;&lt;/span&gt;
legacyDate&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setMonth&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;legacyDate&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getMonth&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
legacyDate&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toLocaleDateString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;en&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;calendar&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;hebrew&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// &#39;24 Nisan 5786&#39;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This adds one &lt;strong&gt;Gregorian&lt;/strong&gt; month (March → April). When you then &lt;em&gt;display&lt;/em&gt; the result in the Hebrew calendar, you land on a different day, &lt;strong&gt;24 Nisan&lt;/strong&gt; rather than &lt;strong&gt;22 Nisan&lt;/strong&gt;, because the calendars don&#39;t have the same month structure or month lengths.&lt;/p&gt;
&lt;h3 id=&quot;temporal-duration&quot; tabindex=&quot;-1&quot;&gt;Temporal.Duration &lt;a class=&quot;header-anchor&quot; href=&quot;https://bloomberg.github.io/js-blog/post/temporal/#temporal-duration&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Our final type is &lt;code&gt;Temporal.Duration&lt;/code&gt;. &lt;code&gt;Duration&lt;/code&gt; is straightforward and can be used with any of the other types when adding and subtracting. Another useful feature of &lt;code&gt;Duration&lt;/code&gt; is showing it in different units, like the example below:&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; duration &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Temporal&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Duration&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;hours&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;130&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;minutes&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

duration&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;total&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;unit&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;second&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// =&gt; 469200&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Most datetime libraries already have a duration type, so it made sense to include one. It also complements the other types by allowing the developer to compare Times or DateTimes and getting back a &lt;code&gt;Duration&lt;/code&gt; type.&lt;/p&gt;
&lt;h2 id=&quot;implementation&quot; tabindex=&quot;-1&quot;&gt;Implementation &lt;a class=&quot;header-anchor&quot; href=&quot;https://bloomberg.github.io/js-blog/post/temporal/#implementation&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Implementing Temporal was a challenge. It is a very large proposal that brings more changes to JavaScript than any other proposal in the programming language&#39;s history. Some specific challenges include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;This GIANT spec is bigger than all of ECMA-402 (The Internationalization spec); this made it hard (but not impossible) for a single person to implement&lt;/li&gt;
&lt;li&gt;The volatility of the spec created a moving target. There have been changes to the spec over the years, which meant implementations have struggled to keep up.&lt;/li&gt;
&lt;li&gt;Browsers demand that nearly all aspects are efficient and performant.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;Temporal is the biggest addition to ECMAScript since ES2015&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Whilst Firefox was able to implement Temporal as it was being specced - thanks to the great work of André Bargull (known online as Anba) - not all browsers or engines were able to work on Temporal during its earlier stages. This means that a lot of catch-up was needed by the later parts of Stage 3.&lt;/p&gt;
&lt;p&gt;Temporal, by the number of tests added to the official test suite for ECMAScript (Test262), is the biggest addition to the ECMAScript spec. Temporal today has ~4,500 tests, a high number compared to some of the other built-ins, including its predecessor, Date.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://bloomberg.github.io/js-blog/images/temporal-image2.png&quot; alt=&quot;Bar chart of Test262 ECMAScript test counts showing Temporal with 4,496 tests, far exceeding String (1,208), Date (594), Function (488), BigInt (75), and Boolean (51).&quot;&gt;&lt;/p&gt;
&lt;p&gt;In the June 2024 plenary, the Google Internationalization team and Boa decided to collaborate on the implementation of Temporal and to work on a Rust library that could serve both engines. The library is called &lt;a href=&quot;https://github.com/boa-dev/temporal&quot;&gt;&lt;code&gt;temporal_rs&lt;/code&gt;&lt;/a&gt;. Over the course of 2024 and 2025, it ramped up the implementation of Temporal thanks to the work of Kevin Ness, Manish Goregaokar, Jose Espina and students from the University of Bergen. Today &lt;code&gt;temporal_rs&lt;/code&gt; passes 100% of all tests and now serves other engines outside of V8 and Boa!&lt;/p&gt;
&lt;p&gt;&lt;code&gt;temporal_rs&lt;/code&gt; is pretty unconventional. It&#39;s rare, if not unprecedented, for multiple engines to collaborate on a shared library to implement a TC39 proposal. Not only did this work, but also it was a huge success. &lt;code&gt;temporal_rs&lt;/code&gt; meant that there was:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Reduced barrier to entry&lt;/strong&gt;: The students and other collaborators didn&#39;t need to understand the V8 or Boa codebase to contribute to the library.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Improved long-term maintenance:&lt;/strong&gt; &lt;code&gt;temporal_rs&lt;/code&gt; has a team of maintainers who will continue to work on the library even after Temporal has reached Stage 4. This provides developers with a stable location to raise issues, report bugs, or even contribute improvements themselves with engines as stakeholders.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Higher quality code to review:&lt;/strong&gt; Because &lt;code&gt;temporal_rs&lt;/code&gt; is scoped as a library, it means that reviewing it was easier because you didn&#39;t need the context of a whole engine. Also the library uses modern Rust features, such as the built-in linting (Clippy), formatting (Rustfmt), and CI tests against engines.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;shipped-and-standardized&quot; tabindex=&quot;-1&quot;&gt;Shipped &amp;amp; Standardized &lt;a class=&quot;header-anchor&quot; href=&quot;https://bloomberg.github.io/js-blog/post/temporal/#shipped-and-standardized&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;https://bloomberg.github.io/js-blog/images/temporal-image8.jpg&quot; alt=&quot;Philip Chimento on the microphone requesting consensus for Temporal Stage 4 at plenary&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://bloomberg.github.io/js-blog/images/temporal-image7.jpg&quot; alt=&quot;Temporal TC39 Champions at plenary, having achieved consensus! Left to right: Jason Williams, Justin Grant, Philip Chimento, Richard Gibson, Shane Carr, Adam Shaw&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://bloomberg.github.io/js-blog/images/temporal-cake.jpg&quot; alt=&quot;A chocolate cake celebrating Temporal reaching Stage 4, with the writing &amp;quot;Temporal is Stage 4&amp;quot; in white icing on the top&quot;&gt;&lt;/p&gt;
&lt;p&gt;Earlier today, Temporal reached Stage 4 in the TC39 staging process, which means it will be part of the next annual ECMAScript specification (ES2026). However, you don&#39;t need to wait until then - you can use it today!&lt;/p&gt;
&lt;p&gt;Temporal is already supported across:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Firefox v139 (since May 2025)&lt;/li&gt;
&lt;li&gt;Chrome v144 (since January 2026)&lt;/li&gt;
&lt;li&gt;Edge v144 (since January 2026)&lt;/li&gt;
&lt;li&gt;TypeScript 6.0 Beta (since February 2026)&lt;/li&gt;
&lt;li&gt;Safari (Partial Support in Technology Preview)&lt;/li&gt;
&lt;li&gt;Node.js v26 (TBC)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;whats-next&quot; tabindex=&quot;-1&quot;&gt;What&#39;s Next? &lt;a class=&quot;header-anchor&quot; href=&quot;https://bloomberg.github.io/js-blog/post/temporal/#whats-next&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There&#39;s still plenty of work to do for Temporal, such as figuring out &lt;a href=&quot;https://github.com/tc39/proposal-temporal/issues/3075&quot;&gt;how it integrates with the rest of the Web ecosystem&lt;/a&gt;. We&#39;ve had years of Web APIs working with or around the Date object, and those same APIs must be compatible with Temporal objects too. Here are some examples:&lt;/p&gt;
&lt;h3 id=&quot;integration-with-date-pickers&quot; tabindex=&quot;-1&quot;&gt;Integration With Date Pickers &lt;a class=&quot;header-anchor&quot; href=&quot;https://bloomberg.github.io/js-blog/post/temporal/#integration-with-date-pickers&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Developers will want to use Temporal with date pickers. Right now, that isn&#39;t possible (it may be possible to patch via a polyfill but there is nothing in the standard today). As we improve the ergonomics of using Temporal, we will need to add support in areas where Date is used today. One example is input types that are datetime related. See below:&lt;/p&gt;
&lt;pre class=&quot;language-html&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;input&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;date&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- element.valueAsPlainDate --&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;input&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;time&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- element.valueAsPlainTime --&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;input&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;week&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- element.valueAsPlainDate --&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;input&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;month&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- element.valueAsPlainYearMonth --&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;supplementing-domhighrestimestamp&quot; tabindex=&quot;-1&quot;&gt;Supplementing DOMHighResTimeStamp &lt;a class=&quot;header-anchor&quot; href=&quot;https://bloomberg.github.io/js-blog/post/temporal/#supplementing-domhighrestimestamp&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Due to Temporal Instants supporting time down to nanoseconds, they could be used anywhere a &lt;code&gt;DOMHighResTimeStamp&lt;/code&gt; is used. In the following example, we can use an Instant to set a cookie expiry, where normally we would have previously used a &lt;code&gt;DOMHighResTimeStamp&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;cookieStore&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;foo&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;bar&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;expires&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Temporal&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Now&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;instant&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;hours&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;24&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;epochMilliseconds&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And there&#39;s certainly more. What is certain is that the JavaScript community will continue working hard to bring Temporal not only to the Web platform, but also any other libraries that make use of Date today.&lt;/p&gt;
&lt;h2 id=&quot;a-better-time-for-javascript&quot; tabindex=&quot;-1&quot;&gt;A Better Time for JavaScript &lt;a class=&quot;header-anchor&quot; href=&quot;https://bloomberg.github.io/js-blog/post/temporal/#a-better-time-for-javascript&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Temporal is the result of nearly a decade of work across companies, engines, and individuals. It represents:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Years of consensus-building inside TC39 that was informed directly by the ecosystem&#39;s prior art&lt;/li&gt;
&lt;li&gt;Implementation work across multiple JavaScript engines&lt;/li&gt;
&lt;li&gt;Collaboration between Microsoft, Google, Mozilla, Bloomberg, Igalia, Boa, and many independent contributors&lt;/li&gt;
&lt;li&gt;And a rare example of shared infrastructure in the form of the &lt;code&gt;temporal_rs&lt;/code&gt; library&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We are proud to have funded and supported Igalia&#39;s work on Temporal for many years. That investment, combined with open collaboration, successfully helped move the proposal from idea to specification to shipping reality.&lt;/p&gt;
&lt;p&gt;The success of &lt;code&gt;temporal_rs&lt;/code&gt; demonstrates something important: new language features don&#39;t have to mean duplicated effort across engines. Shared, high-quality open source infrastructure can reduce costs, increase consistency, and accelerate innovation across the Web ecosystem.&lt;/p&gt;
&lt;p&gt;Temporal is not just a better API. It&#39;s proof that the JavaScript community can solve long-standing problems together.&lt;/p&gt;
&lt;p&gt;After nearly 30 years, JavaScript finally has a modern datetime API.&lt;/p&gt;
&lt;p&gt;And this time, we got it right.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Source Maps: Shipping Features Through Standards</title>
    <link href="https://bloomberg.github.io/js-blog/post/standardizing-source-maps/" />
    <updated>2026-03-10T00:00:00Z</updated>
    <id>https://bloomberg.github.io/js-blog/post/standardizing-source-maps/</id>
    <content type="html">&lt;p&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Glossary/Source_map&quot;&gt;Source maps&lt;/a&gt; are a vital part of modern web development. Today, we have an official standard, a large group of members, and many exciting features in development! But it wasn&#39;t always this way.&lt;/p&gt;
&lt;p&gt;It may surprise you to learn that, for years, there was no official standard describing the source map format. On one hand, it is incredible that for 10 years, bundlers, browsers, and devtools worked together with only a shared &lt;a href=&quot;https://docs.google.com/document/d/1g6tuP7unEkxUSZwLm4IcLoJn1eNDhEmZLAV2kphdvOY/edit&quot;&gt;Google Doc&lt;/a&gt; between them! On the other hand, it became impossible to add new features, deprecate old features, and build the necessary devtools to support dozens of deviations.&lt;/p&gt;
&lt;h2 id=&quot;why-do-we-need-source-maps&quot; tabindex=&quot;-1&quot;&gt;Why do we need Source Maps? &lt;a class=&quot;header-anchor&quot; href=&quot;https://bloomberg.github.io/js-blog/post/standardizing-source-maps/#why-do-we-need-source-maps&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Web development used to be simple! You’d write a bit of JavaScript, stick it in a &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tag, and send it to your users. This also made debugging very simple: the code that ran on the website was the exact code you authored.&lt;/p&gt;
&lt;p&gt;As web development became more complex, tools began to emerge to optimize large JavaScript applications. In 2009, Google released &lt;a href=&quot;https://googlecode.blogspot.com/2009/11/introducing-closure-tools.html&quot;&gt;Closure Tools&lt;/a&gt;, a suite of tools meant to address the growing complexity with applications like Google Maps, Google Docs, and Gmail.&lt;/p&gt;
&lt;p&gt;Closure Tools consisted of four discrete tools: an optimizing compiler, a template language, a JavaScript framework, and a developer tool. The compiler would eventually become Google’s &lt;a href=&quot;https://developers.google.com/closure/compiler&quot;&gt;Closure Compiler&lt;/a&gt; and the developer tool would heavily influence the future of &lt;a href=&quot;https://developer.chrome.com/docs/devtools&quot;&gt;Chrome DevTools&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The compiler and devtools have always gone hand-in-hand, and they form an important relationship that exists to this day. If developers are going to use a compiler to optimize, minify, and alter their source code, they will need devtools that will allow them to map the generated compiler output back to their source code! That is exactly the gap that source maps address.&lt;/p&gt;
&lt;h2 id=&quot;what-s-inside-a-source-map&quot; tabindex=&quot;-1&quot;&gt;What’s inside a source map? &lt;a class=&quot;header-anchor&quot; href=&quot;https://bloomberg.github.io/js-blog/post/standardizing-source-maps/#what-s-inside-a-source-map&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now that we know what purpose source maps serve, let’s dive into what information is inside a source map file.&lt;/p&gt;
&lt;p&gt;A source map is just a &lt;a href=&quot;https://ecma-international.org/publications-and-standards/standards/ecma-404/&quot;&gt;JSON file&lt;/a&gt;. Although some of the fields include encoded data, it should be mostly readable if you open a &lt;code&gt;.map&lt;/code&gt; file in your favorite IDE. As an example, in &lt;code&gt;out.js.map&lt;/code&gt;, you&#39;ll probably see something like this:&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;version&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Always the integer 3&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;file&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;out.js&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Optional: name of the generated file&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;sourceRoot&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Optional: prefix prepended to each entry in &quot;sources&quot;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;sources&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;foo.js&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;bar.js&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Required: list of original source URLs/paths (or null)&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;sourcesContent&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token null keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token null keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Optional: inlined source text, aligned with &quot;sources&quot;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;names&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;src&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;maps&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Optional: symbol names referenced by &quot;mappings&quot;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;mappings&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;A,AAAB;;ABCDE&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Required: encoded mapping data (base64-VLQ deltas)&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;ignoreList&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Optional: indexes into &quot;sources&quot; considered &quot;third-party&quot;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can interpret most of the file simply by reading it! It has the name of the generated JavaScript file, the one or more source files that went into it, what code was in each of those files, and a list of any files to mark as third-party or library code! The only part we can’t read plainly is the &lt;code&gt;mappings&lt;/code&gt; field.&lt;/p&gt;
&lt;h2 id=&quot;how-mappings-work&quot; tabindex=&quot;-1&quot;&gt;How mappings work &lt;a class=&quot;header-anchor&quot; href=&quot;https://bloomberg.github.io/js-blog/post/standardizing-source-maps/#how-mappings-work&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Let’s think about mappings for a minute. What information would we need to accurately trace the location where a developer might set a breakpoint in a generated file like &lt;code&gt;bundle.js&lt;/code&gt; all the way back to the exact file and position it came from in a source file like &lt;code&gt;App.ts&lt;/code&gt;?&lt;/p&gt;
&lt;h3 id=&quot;what-information-do-we-need-in-mappings&quot; tabindex=&quot;-1&quot;&gt;What information do we need in mappings? &lt;a class=&quot;header-anchor&quot; href=&quot;https://bloomberg.github.io/js-blog/post/standardizing-source-maps/#what-information-do-we-need-in-mappings&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;All we really need is:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;For the generated file
&lt;ul&gt;
&lt;li&gt;Filename&lt;/li&gt;
&lt;li&gt;Line&lt;/li&gt;
&lt;li&gt;Column&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;For the source file
&lt;ul&gt;
&lt;li&gt;Filename&lt;/li&gt;
&lt;li&gt;Line&lt;/li&gt;
&lt;li&gt;Column&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Conceptually, we could imagine representing these with arrays of numbers, assuming we also had an array of file names. We could design something like:&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;sources&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;foo.js&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// One original source file&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;mappings&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// &quot;sources&quot; index 0, line 1, column 2&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But now we need a way to map a position in the generated code to one of these &lt;code&gt;mappings&lt;/code&gt;. So maybe we add a new field that contains mappings for each line in the generated file, pointing to an entry in our &lt;code&gt;mappings&lt;/code&gt; array! Something like:&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;sources&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;foo.js&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// One original source file&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;mappings&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// &quot;sources&quot; index 0, line 1, column 2&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;lineMaps&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// The first 5 columns all map to the first entry in the `mappings` array and the rest map to the second entry&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You could reduce the source map size by omitting duplicates in the &lt;code&gt;lineMaps&lt;/code&gt; array. So, the same information could be represented like:&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;sources&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;foo.js&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// One original source file&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;mappings&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// &quot;sources&quot; index 0, line 1, column 2&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;lineMaps&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// The first 5 columns all map to the first entry in the `mappings` array and the rest map to the second entry&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This would work nicely! The only real problem is, &lt;code&gt;lineMaps&lt;/code&gt; is going to be enormous for large files. Even using &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Indexed_collections#sparse_arrays&quot;&gt;sparse arrays&lt;/a&gt;, you will have an array entry per character! Even a modest web app, when minified, will contain between 200,000 and 2,000,000 characters.&lt;/p&gt;
&lt;p&gt;This per-character mapping model was actually used in early source map revisions (1 and 2), before being replaced in Revision 3.&lt;/p&gt;
&lt;h2 id=&quot;revision-3-the-modern-source-map&quot; tabindex=&quot;-1&quot;&gt;Revision 3: The modern source map &lt;a class=&quot;header-anchor&quot; href=&quot;https://bloomberg.github.io/js-blog/post/standardizing-source-maps/#revision-3-the-modern-source-map&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Reducing the size of source maps became a top priority as JavaScript bundles grew into hundreds of thousands, and eventually millions, of characters.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/tc39/ecma426/blob/main/source-map-rev3.md&quot;&gt;Revision 3&lt;/a&gt; (written in 2011, still the format we use today) made four key architectural changes to dramatically shrink map size:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Moved from per-character mapping IDs to segment-based source location entries
&lt;ol&gt;
&lt;li&gt;Instead of mapping each character in a generated file, it only keeps track of where the mapping changes.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mappings&lt;/code&gt; is now a string, containing segments encoded using &lt;a href=&quot;https://en.wikipedia.org/wiki/Variable-length_quantity&quot;&gt;Base64 VLQ&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Removed the &lt;code&gt;lineMaps&lt;/code&gt; array
&lt;ol&gt;
&lt;li&gt;Instead of two arrays that reference each other, we now have one &lt;code&gt;mappings&lt;/code&gt; string, which encodes, for each segment, the:
&lt;ol&gt;
&lt;li&gt;Generated column&lt;/li&gt;
&lt;li&gt;Source index&lt;/li&gt;
&lt;li&gt;Original line&lt;/li&gt;
&lt;li&gt;Original column&lt;/li&gt;
&lt;li&gt;Optional name index&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Note: Generated lines are separated by &lt;code&gt;;&lt;/code&gt; in the mappings string.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Switched from absolute to relative encoding
&lt;ol&gt;
&lt;li&gt;Instead of storing &lt;code&gt;generatedColumn: 120&lt;/code&gt;, we now store &lt;code&gt;generatedColumn: +3&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;With Revision 3, the source map above can be represented like:&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;version&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;file&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;bundle.js&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;sources&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;foo.js&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;names&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;mappings&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;AAAE,KAAI&quot;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;These changes mean source maps are much smaller (thanks to VLQ) and much easier to encode and decode.&lt;/p&gt;
&lt;h2 id=&quot;a-decade-without-a-standard&quot; tabindex=&quot;-1&quot;&gt;A decade without a standard &lt;a class=&quot;header-anchor&quot; href=&quot;https://bloomberg.github.io/js-blog/post/standardizing-source-maps/#a-decade-without-a-standard&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Revision 3 landed in 2011 and it worked well! It worked so well that the entire web ecosystem decided to stop touching it for years. New bundlers spun up, emitting Revision 3 source maps, while browsers continued to build devtools that would consume Revision 3 source maps.&lt;/p&gt;
&lt;p&gt;Things were going great in the sense that breakpoints always landed in &amp;quot;roughly&amp;quot; the right spot. But the state it was in made it impossible to add new features, deprecate old behaviors, or correct ambiguity.&lt;/p&gt;
&lt;h3 id=&quot;adding-a-new-feature-without-a-standard&quot; tabindex=&quot;-1&quot;&gt;Adding a new feature without a standard &lt;a class=&quot;header-anchor&quot; href=&quot;https://bloomberg.github.io/js-blog/post/standardizing-source-maps/#adding-a-new-feature-without-a-standard&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Despite the complications, one new feature did manage to make its way through the ambiguity and into bundlers and devtools alike!&lt;/p&gt;
&lt;p&gt;As JavaScript frameworks began to grow in popularity, a common problem that faced developers was the need to step through callstacks consisting of dozens of framework files and only a few files they authored. In 2014, Google’s Chrome DevTools allowed developers to create &lt;a href=&quot;https://developer.chrome.com/docs/devtools/settings/ignore-list&quot;&gt;ignore lists&lt;/a&gt;, specifying files or patterns they wished to exclude from stack traces and step-through debugging.&lt;/p&gt;
&lt;p&gt;This was great, but it would be far better if bundlers could let devtools know which files to ignore without forcing the developer to manually go through and list files. To solve this problem, in 2022, Google began looking for an &lt;code&gt;x_google_ignoreList&lt;/code&gt; array inside source maps. If found, they would automatically add any files in the array to their DevTools &lt;code&gt;ignoreList&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This feature was so popular that Firefox began to support &lt;code&gt;x_google_ignoreList&lt;/code&gt; in &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1824705&amp;amp;_gl=1*snzg04*_ga*MjgzNTQyNjU4LjE3NzIxMTYwOTE.*_ga_X4N05QV93S*czE3NzIxMTYwOTEkbzEkZzAkdDE3NzIxMTYwOTEkajYwJGwwJGgw&quot;&gt;2023&lt;/a&gt;! This is an amazing success story about open source tooling, web frameworks, and browsers collaborating without a formal group or standard. However, it also made it abundantly clear that we needed an easier way to communicate.&lt;/p&gt;
&lt;p&gt;While adding the ignoreList was successful, most large companies wanted a way to decode function names in stack traces, and this became incredibly difficult to coordinate without a standard.&lt;/p&gt;
&lt;p&gt;Imagine the following code:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// sample.js&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;penne&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;spaghetti&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;penne&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;orzo&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;spaghetti&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;orzo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you don’t transpile, optimize, or bundle your code, you will get perfectly readable stack traces! But if you do, you will likely end up reading through callstacks with single letter function names that are impossible to trace back to your source code.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// **original** output                           // **compiled** output&lt;/span&gt;
Error                                            Error
    at &lt;span class=&quot;token function&quot;&gt;penne&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;sample&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;js&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;33&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;                        at &lt;span class=&quot;token function&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;out&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;js&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;82&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    at &lt;span class=&quot;token function&quot;&gt;spaghetti&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;sample&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;js&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;25&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;         vs         at &lt;span class=&quot;token function&quot;&gt;o&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;out&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;js&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;97&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    at &lt;span class=&quot;token function&quot;&gt;orzo&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;sample&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;js&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;25&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;                         at &lt;span class=&quot;token function&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;out&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;js&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;107&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;https://bloomberg.github.io/js-blog/images/image1.png&quot; alt=&quot;pasta-sourcemaps logo&quot;&gt;&lt;/p&gt;
&lt;p&gt;To solve this problem, Bloomberg created &lt;a href=&quot;https://github.com/bloomberg/pasta-sourcemaps&quot;&gt;pasta-sourcemaps&lt;/a&gt;. Pasta takes advantage of the same &lt;code&gt;x_&lt;/code&gt; prefix by adding a &lt;code&gt;x_com_bloomberg_sourcesFunctionMappings&lt;/code&gt; to our source maps. We can then parse this list back out in our devtools and apply the original function names back to the stack traces.&lt;/p&gt;
&lt;p&gt;Though this feature was wanted by all browsers and most devtools, it was too large and too complex to simply ship. Although Chrome did ship support for pasta-sourcemaps behind a flag, it became abundantly clear we needed an official group to discuss this feature’s intricacies.&lt;/p&gt;
&lt;h2 id=&quot;tg4&quot; tabindex=&quot;-1&quot;&gt;TG4 &lt;a class=&quot;header-anchor&quot; href=&quot;https://bloomberg.github.io/js-blog/post/standardizing-source-maps/#tg4&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In 2023, Bloomberg set out to begin the process of standardizing source maps. We began, as many inspirational tech stories do, meeting in a humble Google office in Munich. We gathered a group of engineers from Bloomberg, Google, Mozilla, Vercel, Igalia, and JetBrains and began organizing years worth of questions and confusions around source maps from the ecosystem-at-large.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://bloomberg.github.io/js-blog/images/image2.jpg&quot; alt=&quot;TG4 members from Vercel, Mozilla, Google and Igalia sit together working through source maps issues&quot;&gt;&lt;/p&gt;
&lt;p&gt;With our new group of constituents involved in browsers, devtools, compilers, and open source, we shopped around for a &amp;quot;venue&amp;quot; for the source map standard and landed on &lt;a href=&quot;https://ecma-international.org/&quot;&gt;Ecma International&lt;/a&gt;, the same industry association that &lt;a href=&quot;https://tc39.es/&quot;&gt;TC39&lt;/a&gt; uses.&lt;/p&gt;
&lt;p&gt;In October of 2023, we became an official &lt;a href=&quot;https://ecma-international.org/task-groups/tc39-tg4/&quot;&gt;Task Group&lt;/a&gt; underneath the TC39 umbrella.&lt;/p&gt;
&lt;p&gt;Our Task Group (TC39-TG4) spent 2024 working through an enormous backlog of issues filed against source maps. Topics discussed included improving correctness, formalizing unofficial features, writing specification text, creating tools to validate and test source maps, and new features we would add after we became an official standard.&lt;/p&gt;
&lt;p&gt;At the end of 2024, we were officially standardized as &lt;a href=&quot;https://tc39.es/ecma426/&quot;&gt;ECMA-426&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://bloomberg.github.io/js-blog/images/image3.jpg&quot; alt=&quot;Members of TG4 have dinner together to celebrate the standard&#39;s completion&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;future-work&quot; tabindex=&quot;-1&quot;&gt;Future Work &lt;a class=&quot;header-anchor&quot; href=&quot;https://bloomberg.github.io/js-blog/post/standardizing-source-maps/#future-work&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In 2025, we began to dream big with ideas for new features. We came up with &lt;a href=&quot;https://github.com/tc39/ecma426/tree/main/proposals&quot;&gt;five ideas&lt;/a&gt; and began work to implement two of them: &lt;a href=&quot;https://github.com/tc39/ecma426/blob/main/proposals/scopes.md&quot;&gt;Scopes&lt;/a&gt; and &lt;a href=&quot;https://github.com/tc39/ecma426/blob/main/proposals/range-mappings.md&quot;&gt;Range Mappings&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;scopes&quot; tabindex=&quot;-1&quot;&gt;Scopes &lt;a class=&quot;header-anchor&quot; href=&quot;https://bloomberg.github.io/js-blog/post/standardizing-source-maps/#scopes&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The Scopes proposal builds off Bloomberg’s pasta-sourcemaps, but generalizes the idea far beyond function names. The goal is to let source maps reflect the realities of modern JavaScript compilation by embedding scope and binding information directly into the map (instead of forcing devtools to re-parse your sources and &amp;quot;guess&amp;quot;).&lt;/p&gt;
&lt;p&gt;That gives bundlers and devtools a common language to communicate things like:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Functions that were inlined by the compiler&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;So a debugger can reconstruct missing stack frames, and &amp;quot;Step Over / Step Out&amp;quot; behaves like the original code even when the runtime no longer has a real function boundary.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Variables that were renamed, folded, or erased&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;Including cases like minification renaming, constant folding, or compilation patterns where a &amp;quot;real&amp;quot; authored binding doesn&#39;t exist as a variable in generated JavaScript at all.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The scopes that were removed or introduced by transforms&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;So devtools can hide compiler-internal frames/scopes, and revive original ones, without each tool inventing its own heuristics.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;How to &lt;em&gt;compute&lt;/em&gt; a binding&#39;s value in generated code&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;The proposal can encode expressions a debugger can evaluate in the generated scope to present the &amp;quot;original&amp;quot; binding value back to the user.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;range-mappings&quot; tabindex=&quot;-1&quot;&gt;Range Mappings &lt;a class=&quot;header-anchor&quot; href=&quot;https://bloomberg.github.io/js-blog/post/standardizing-source-maps/#range-mappings&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Range Mappings is a much smaller (but extremely practical) idea: sometimes we want a mapping to apply to an entire range of text, not just a single point.&lt;/p&gt;
&lt;p&gt;Today, mappings are essentially &amp;quot;pins&amp;quot; in the generated file. If a tool asks &amp;quot;what is column 137 mapped to?&amp;quot; and there isn’t an exact pin at 137, consumers usually fall back to the closest previous mapping on that line. That loss of precision becomes especially painful when you try to compose source maps (TypeScript to JS, then JS to minified JS), because you can only reliably compose mappings that exist in both maps at exactly the right places.&lt;/p&gt;
&lt;p&gt;Range mappings address this by letting a generator mark specific mappings as &amp;quot;range mappings,&amp;quot; meaning:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Assume every character after this mapping (up to the next mapping) is mapped by applying the same offset into the original source.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;In other words, you get the precision of &amp;quot;map every character,&amp;quot; without actually emitting a mapping per character. This is particularly powerful for transforms like &amp;quot;strip types,&amp;quot; in which huge stretches of runtime code are identical.&lt;/p&gt;
&lt;p&gt;To avoid breaking the &lt;code&gt;mappings&lt;/code&gt; field, the proposal adds a new field, &lt;code&gt;rangeMappings&lt;/code&gt;, that encodes (per generated line) which mapping segments should be treated as range mappings.&lt;/p&gt;
&lt;h4 id=&quot;range-mappings-example&quot; tabindex=&quot;-1&quot;&gt;Range Mappings Example &lt;a class=&quot;header-anchor&quot; href=&quot;https://bloomberg.github.io/js-blog/post/standardizing-source-maps/#range-mappings-example&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Imagine you have a JavaScript file with a comment at the top that you plan to strip out.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// header comment we will strip&lt;/span&gt;
console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;hi&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After you compile it, you get this result:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;hi&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Without Range Mappings, the source map for the following operation would look like:&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;version&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;file&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;out.js&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;sources&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;input.js&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;sourcesContent&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;// header comment we will stripnconsole.log(&#39;hi&#39;);n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;names&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;mappings&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;AACA&quot;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This works well, except we will lose all column precision. The source map says &amp;quot;I know things on line 1 used to be on line 2,&amp;quot; but that’s all.&lt;/p&gt;
&lt;p&gt;With Range Mappings, we can specifically say that line 1 used to be on line 2 &lt;strong&gt;and&lt;/strong&gt; it is a range mapping, so preserve the column information!&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;version&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;file&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;out.js&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;sources&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;input.js&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;sourcesContent&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;// header comment we will stripnconsole.log(&#39;hi&#39;);n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;names&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;mappings&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;AACA&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;rangeMappings&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;B&quot;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This approach allows browsers to provide greatly improved experiences with their console and step-through debugging, with no added cost to the user.&lt;/p&gt;
&lt;h2 id=&quot;wrapping-up&quot; tabindex=&quot;-1&quot;&gt;Wrapping up &lt;a class=&quot;header-anchor&quot; href=&quot;https://bloomberg.github.io/js-blog/post/standardizing-source-maps/#wrapping-up&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For years, source maps have &amp;quot;just worked&amp;quot; based on a shared understanding across browsers and tools. ECMA-426 gives us a real specification and a place to evolve.&lt;/p&gt;
&lt;p&gt;This process has been an incredible ride, and I think it really highlights the best parts of open source. So many people with knowledge to share have put in hard work to benefit the entire JavaScript ecosystem.&lt;/p&gt;
&lt;p&gt;If you’re a bundler author, a devtools engineer, or you maintain anything that produces or consumes source maps (error monitoring, replay debuggers, etc), TG4 is exactly where we want your input. The proposal work is happening &lt;a href=&quot;https://github.com/tc39/ecma426&quot;&gt;in the open&lt;/a&gt; and we would love to hear from you!&lt;/p&gt;
&lt;p&gt;If you are a consumer of source maps, stay tuned! Scopes and Range Mappings will be coming to browser devtools near you soon!&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Intro</title>
    <link href="https://bloomberg.github.io/js-blog/post/intro/" />
    <updated>2026-03-09T00:00:00Z</updated>
    <id>https://bloomberg.github.io/js-blog/post/intro/</id>
    <content type="html">&lt;p&gt;Hello, world 👋&lt;/p&gt;
&lt;p&gt;This is a new blog written by engineers, for engineers. On it, we will be publishing technical content from Bloomberg folk who work on our thriving JavaScript environment. This also includes web/web-adjacent technologies, and it very much includes TypeScript. After all, TypeScript is JavaScript plus types.&lt;/p&gt;
&lt;p&gt;Why now? A better question is perhaps: why not sooner? For more than 20 years, JavaScript has powered the Bloomberg Terminal, which is used by more than 350,000 financial professionals around the world. During this time, thousands of Bloomberg engineers have shipped more than 10,000 apps, accumulating more than 100 million lines of server-side and client-side JavaScript code. We have a strong interest in maintaining open web technology (as well as the adjacent runtimes and tooling) as a robust, long-lived technology basis for our business. Correspondingly, for over a decade, we&#39;ve participated seriously in the broader web community through technical contributions to its foundations, financial support, and deep engagement in standards groups like TC39.&lt;/p&gt;
&lt;p&gt;Much of this participation has long been visible through a variety of sources (but only if you know where to look). It includes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Our firm’s public &lt;a href=&quot;https://github.com/bloomberg&quot;&gt;GitHub&lt;/a&gt; repo and open source projects we’ve published for the JS community (like &lt;a href=&quot;https://bloomberg.github.io/stricli/&quot;&gt;Stricli&lt;/a&gt; and &lt;a href=&quot;https://bloomberg.github.io/ts-blank-space/&quot;&gt;ts-blank-space&lt;/a&gt;);&lt;/li&gt;
&lt;li&gt;Proposals for new JavaScript features (like &lt;a href=&quot;https://github.com/tc39/proposal-change-array-by-copy&quot;&gt;&lt;code&gt;Array.prototype.toSorted&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;https://github.com/tc39/proposal-promise-with-resolvers&quot;&gt;&lt;code&gt;Promise.withResolvers&lt;/code&gt;&lt;/a&gt;);&lt;/li&gt;
&lt;li&gt;Various &lt;a href=&quot;http://typescript.com&quot;&gt;TypeScript&lt;/a&gt; language features seen in TypeScript &lt;a href=&quot;https://devblogs.microsoft.com/typescript/announcing-typescript-3-8/&quot;&gt;3.8&lt;/a&gt;, &lt;a href=&quot;https://devblogs.microsoft.com/typescript/announcing-typescript-4-3/#ecmascript-#private-class-elements&quot;&gt;4.3&lt;/a&gt;, and &lt;a href=&quot;https://devblogs.microsoft.com/typescript/announcing-typescript-5-5/#isolated-declarations&quot;&gt;5.5&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;Contributions to &lt;a href=&quot;https://ecma-international.org/news/ecma-tc39-ecmascript-initiates-a-new-task-group-to-standardize-source-maps/&quot;&gt;JavaScript tooling&lt;/a&gt; (including &lt;a href=&quot;https://github.com/bloomberg/pasta-sourcemaps&quot;&gt;&lt;code&gt;pasta-sourcemaps&lt;/code&gt;&lt;/a&gt;) and &lt;a href=&quot;https://nearform.com/insights/bloomberg-invests-in-node-js-shouldnt-you&quot;&gt;Node.js&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;New web performance metrics (like &lt;a href=&quot;https://github.com/bloomberg/container-timing&quot;&gt;Container Timing&lt;/a&gt;);&lt;/li&gt;
&lt;li&gt;Conference talks (such as at &lt;a href=&quot;https://www.youtube.com/watch?v=ODgs0eWAIKc&quot;&gt;JSConf&lt;/a&gt; and &lt;a href=&quot;https://www.youtube.com/watch?v=y1MCLZm8yAY&quot;&gt;Perf.now&lt;/a&gt;) and &lt;a href=&quot;https://bsky.app/profile/robpalmer.bsky.social/post/3m5v4lywtrs27&quot;&gt;social media&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;Hosting &lt;a href=&quot;https://www.youtube.com/playlist?list=PLnZuxOufsXntTFmTgNKoS4zMWG-MltoYS&quot;&gt;meetups&lt;/a&gt;, &lt;a href=&quot;https://nodejs.org/en/blog/events/collab-summit-2024-london&quot;&gt;collaboration summits&lt;/a&gt;, &lt;a href=&quot;https://bsky.app/profile/robpalmer.bsky.social/post/3m5uhs5og3k27&quot;&gt;standardization meetings&lt;/a&gt;; and&lt;/li&gt;
&lt;li&gt;Occasional &lt;a href=&quot;https://www.bloomberg.com/company/stories/10-insights-adopting-typescript-at-scale/&quot;&gt;long-form guest blog posts&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A lot of this has been done in collaboration with partners such as Igalia, as well as institutions such as Ecma International, OpenJS, Unicode, and the W3C.&lt;/p&gt;
&lt;p&gt;But we&#39;ve never had a central place to bring it together to share what we&#39;ve done or what we&#39;re up to next. This new blog will hopefully solve that problem!&lt;/p&gt;
&lt;p&gt;Stay tuned for some exciting posts in the next few days! 😉&lt;/p&gt;
</content>
  </entry>
</feed>