Temporal is great. I've been using it for a while in production using a polyfill [1], and it solves all issues I've encountered with the old Date() API (which is a lot).
It clearly takes inspiration from other high-quality time libraries such as chrono in Rust and Joda Time in Java and combines them into a nice API that's pretty comfortable to use.
Yes, it is a bit more complex to handle since it separates time into naive time, instant and zoned time. But by experience, developers only confront complexity when they are forced to, and time _is_ complex.
If you want to do the operation "add one day to this timestamp", you _must_ decide whether that timestamp is local to a specific timezone and which one. Otherwise you'll get a bug twice per year due to DST, or when the user switches time zones, or when you deploy on a server with a different timezone.
It even solves the serialization issue of the difference between a "fixed-offset" timestamp (e.g. 2025-01-01T00:00+02:00) and one in a specific timezone (e.g. Europe/Paris).
> It clearly takes inspiration from other high-quality time libraries such as chrono in Rust
You might be interested in Jiff (a crate for Rust), which is inspired by Temporal. And here is a comparison I did with other datetime crates (including `chrono`): https://docs.rs/jiff/latest/jiff/_documentation/comparison/i...
I actually don't think Temporal takes a ton of inspiration from the `chrono` crate personally. I think it's definitely more from Joda (as you mentioned) or `java.time` these days, and some of the other Javascript datetime libraries that have cropped up over the years (thinking about date-fns and Moment.js).
> Otherwise you'll get a bug twice per year due to DST
Those of us of a certain age learned long ago never to schedule cron (etc.) jobs in a production environment between 01:00 and 03:00 local time.
That won't save you everywhere, Greenland falls back at midnight (12 AM Sunday to 11 PM Saturday) in order to synchronize their DST change with Europe
> chrono in Rust and Joda Time in Java
Those are from different time epochs, by the time Rust 1.0 was released, Java already had this approach implemented in standard library via java.time and didn't need any 3rd party libraries for this.
> It even solves the serialization issue of the difference between a "fixed-offset" timestamp (e.g. 2025-01-01T00:00+02:00) and one in a specific timezone (e.g. Europe/Paris).
Could you elaborate on that? What is the issue?
+02:00 is not political. It's an offset from UTC and will be the same offset in the past and future.
Europe/Paris is political. It defines that offsets change at certain times of the year, but that could change tomorrow, or the political boundary that the timezone applies to could split such that the person or entity needing a time in their "local" timezone finds another one needs to be picked (see various US states/counties applying/disapplying daylight savings).
It's impossible to be 100% confident what the offset from UTC will be at any time in the future. You also need to be a historian to correctly apply it to times in the past - take https://en.wikipedia.org/wiki/Time_in_the_Republic_of_Irelan... as an example!
That but also and for me more importantly it does not tell you how to add time - If you add one month of hours to a date in October, it depends on the timezone whether you will end up one hour of local time earlier or not (due to DST), because then +02:00 might be +01:00
While this is true, most often if you want to do "now plus a month" you'll mean "at the same time on the local clock", and disregarding timezone changes, while most often if you want to do "now plus four hours" you'd actually mean four real hours, and you want to calculate in the DST changes to make sure you have four actual hours in your duration
That's how Temporal works:
>> zdt = Temporal.ZonedDateTime.from("2024-03-09T17:00-05[US/Eastern]")
>> zdt.add("P1d").toString()
"2024-03-10T17:00:00-04:00[US/Eastern]"
>> zdt.add("PT24h").toString()
"2024-03-10T18:00:00-04:00[US/Eastern]"
If you don't have the time zone and instead just an offset, then Temporal can't do this: >> zdt = Temporal.ZonedDateTime.from("2024-03-09T17:00-05[-05]")
>> zdt.add("P1d").toString()
"2024-03-10T17:00:00-05:00[-05:00]"
>> zdt.add("PT24h").toString()
"2024-03-10T17:00:00-05:00[-05:00]"
Adding 1 day still works the same with respect to civil time but the offset is wrong since it doesn't account for the DST change. And adding 24 hours leads to a different result as well. This is one of the reasons why RFC 9557 is so important for serializing zoned datetimes when you want your arithmetic to be DST safe. Previously, to get this right, you had to include a time zone out of band somehow along with your RFC 3339 timestamp.https://datatracker.ietf.org/doc/rfc9557/ for folks' reference about the new [] suffix syntax.
It's a really well thought out RFC: the offset, the civil time zone name, and a flag for whether that civil time zone is critical information can all be stored, and an inconsistency marked critical MUST be acted upon by the application explicitly, either by rejecting or requesting user interaction.
This may seem redundant, but it's really important to answer "what happens if I have a future timestamp stored, and the USA suddenly rejects daylight savings time. Do I honor the absolute point in time, or do I honor the notion of 5pm?"
Unfortunately, there's going to be a lot of chaos if this happens. Systems like Postgres only store the absolute point in time, normalized to UTC, despite what the name "timestamp with time zone" might imply; an application team or DBA making a decision about this might need to look at other domain-specific metadata e.g. the physical location of the associated asset to determine whether to add or remove an hour. I shudder to think about what this might imply for e.g. HIPAA protected medical systems; the impact of the ensuing bugs might be measured in lives.
Yeah the PostgreSQL situation is just utterly appalling. The fact that there is a type called "timestamp with time zone," that specifically calls out the fact that it has a time zone, but actually doesn't have a time zone is absolutely crazytown.
> This may seem redundant, but it's really important to answer "what happens if I have a future timestamp stored, and the USA suddenly rejects daylight savings time. Do I honor the absolute point in time, or do I honor the notion of 5pm?"
Yeah! It's great that Temporal rejects by default, but does let you override that and choose whether to respect the instant or respect to the civil time. And it lets you do that with a high level configuration knob. You don't have to code up the logic yourself.
I agree, but I believe Postgres is just following the SQL standard here?
What's even crazier is that writing plain TIMESTAMP gets you TIMESTAMP WITHOUT TIME ZONE, as is also mandated by the standard (the Postgres docs call this one out specifically). And that behaviour can be summarized as: not only don't store the timezone, but also ignore the timezone you get given.
For example, I'm on GMT/UTC right now, and I see this:
select '2025-01-30T12:00:00-0800'::timestamp with time zone; -- 2025-01-30 20:00:00+00
select '2025-01-30T12:00:00-0800'::timestamp; -- 2025-01-30 12:00:00
There are many valid and justifiable reasons to do crazy things. But it's still crazy. :-)
I don't think that completely absolves PostgreSQL though. It seems like they could add things to improve the situation and de-emphasize the use of TIMESTAMP and TIMESTAMP WITH TIME ZONE. But I am not a database or PostgreSQL expert, and there are assuredly trade-offs with doing this.
But yes, absolutely, the fact that TIMESTAMP is not just a timestamp without a time zone, but is actually a civil time is also equal parts crazytown. Like, a timestamp is 100% an instant in time. It is physical time. A number of seconds since an epoch. But PostreSQL (or the SQL standard) interprets it as a civil time? It's ludicrous and has assuredly confused countless humans. Especially those among us who don't know enough to question that PostgreSQL (or the SQL standard) might have gotten it wrong in the first place.
I wonder what happens when a timezone ceases to exist, e.g. what if Paris is renamed to New New York after the British take revenge and take over France.
Your example of “New X” is spot on, because there was a timezone with that name, “US/Pacific-New”, which was different than “US/Pacific”. Bit of history: it was added to some timezone libraries because there was a bill in congress to add it, but it never passed. I had to fix a bug because users were getting set with that timezone and then other systems/libraries were barfing on it…
https://www.icann.org/en/blogs/details/how-time-zones-are-co...
Hopefully the British would be kind enough to email the TZ DB group at the IANA (tz@iana.org) a couple years in advance of the legislation to change the name so that the group can get started on collecting the DST rules for Europe/NewNewYork. Some people and devices will probably stick to Europe/Paris out of habit and/or resistance to the change, so the TZ DB would probably be unlikely to remove it, but they may point references from it to Europe/NewNewYork as the new "canonical" name. Plenty of the DB entries are just pointers to other entries already today, for one instance it was decided that America/City and Europe/City maybe is too conflicted a namespace and we see increasingly more "the canonical name is America/State/City" or "the canonical name is Europe/Country/City".
As a Canadian, I would love for my timezone to be Americas/Toronto or Americas/Canada/Toronto rather than America/Toronto, but that's pretty far down my register of first world problems.
A timezone changing or being eliminated doesn’t erase the history of that timezone. So you can still use the last definition of such a timezone if the date is still in the future, or use the appropriate definition of the timezone at the time of a date marked in the past.
> you can still use the last definition of such a timezone if the date is still in the future
but that'll possibly give you an incorrect time!
If you want to store "8am in Paris on the 2026-01-01", then you store "2026-01-01T08:00:00 Europe/Paris". Great, if Paris decides to change their offset rules, that's fine.
Currently, that would be `2026-01-01T08:00:00+01:00` but if Paris decide to ditch DST, it could become `2026-01-01T08:00:00+00:00`. All good, you stored a timezone rather than an offset, so you're decoupled from the timezone->offset changes.
But if tomorrow `Europe/Paris` cease to exist, and is replaced with Europe/NewNewYork? The last definition of Europe/Paris would make this date `2026-01-01T08:00:00+01:00`, but if Europe/NewNewYork ditched DST then it wouldn't be 8am for the people living there, it'd be 7am.
You're decoupled from the timezone->offset changes, but not from location->timezone changes.
Here are a couple starting points
https://medium.com/servicios-a0/on-solving-the-tzdb-changes-...
https://github.com/tc39/proposal-canonical-tz - appropriately to these comments, a proposal to handle tzdb changes, built on top of JS Temporal, includes some great examples of all the ways this can happen
Then Europe/Paris will become an alias for Europe/NewNewYork
What if England and Germany fight for France, half the country being occupied by Germany using `Europe/Francefurt` and the other half by England using `Europe/NewNewYork`? Then you can't know for sure how to interpret a "Europe/Paris" date without knowing the exact geographical location
If I understand [1] correctly, two new zones (or one new one and the old one) would be created in that case. E.g. if Strasbourg would be occupied by Germany in 2027, a new Europe/Strasbourg could be created which has the same rules as Europe/Paris until 2026, and the rules of Europe/Berlin as of 2027.
[1] https://en.wikipedia.org/wiki/Tz_database
--
By the way, I looked up the time zone in Crimea.
> On 29 March 2014, after annexation by Russia, Crimea switched from Eastern European Time (UTC+02:00) to Moscow Time (UTC+04:00 then, subsequently changed to UTC+03:00). [2]
Crimea has its own zone in the IANA database, Europe/Simferopol, which was updated in 2014 (and already existed before, as it already used Moscow time from 1994 to 1997). [3]
[2] https://en.wikipedia.org/wiki/Time_in_Ukraine
[3] https://lists.iana.org/hyperkitty/list/tz@iana.org/thread/DS... https://github.com/eggert/tz/commit/bb203f1bb0b6cd4bb2b08f25... https://github.com/eggert/tz/blob/bb203f1bb0b6cd4bb2b08f2560...
The issue is that if you have a timestamp (e.g., `2025-06-20T17:00:00+02:00`) and a time zone (e.g., `Europe/Paris`) and you go to serialize it, are you explicitly including the time zone in that serialization? And when you deserialize it, are you checking that the offset is still valid for that time zone at that time?
Temporal fixes this by using RFC 9557[1], which includes the time zone in the serialized representation. RFC 9557 is a superset of RFC 3339. So where as previously you might just emit `2025-06-20T17:00:00+02:00`, using RFC 9557, you would emit `2025-06-20T17:00:00+02:00[Europe/Paris]`. For example, using Temporal:
>> instant = Temporal.Instant.from('2025-06-20T17:00:00+02')
>> zdt = instant.toZonedDateTimeISO("Europe/Paris")
>> zdt.toJSON()
"2025-06-20T17:00:00+02:00[Europe/Paris]"
And when you go to deserialize an RFC 9557 timestamp, Temporal will do some validation to help ensure it's still correct. For example, you might serialize a RFC 9557 timestamp that is in the future, but at some later point, that region might abolish DST. At which point, your RFC 9557 timestamp might or might not resolve to the intended time. If it was in DST, Temporal will reject it at parsing time.You can read more about this at https://tc39.es/proposal-temporal/docs/zoneddatetime.html and search for "conflict". There's an example about Brazil abolishing DST in 2019 that should lay it out for you.
Separately from even this, there are other concerns. If you forget to include the time zone in your serialization and then just deserialize it as a simple timestamp, then it makes it very easy for arithmetic on that value to be wrong because it won't be DST safe (unless you're careful to reconstitute its time zone somehow). With Temporal and RFC 9557, all of that is handled for you automatically.
I get that it’s more correct, but it assumes that Europe/Paris is a constant representation of how to apply the timezone-specific stuff but that’s incorrect. For example, ‘2025-06-20T17:00:00+02[Europe/Dublin]’ is a very different time if it’s created today vs if it were created in 1760 [1]. That’s a very extreme example, but timezone rules change and dates created from before the change was announced would be interpreted differently from ones created after they were announced. It’s interesting to me the standard doesn’t embed the creation time of the timestamp in UTC as well.
https://en.wikipedia.org/wiki/Time_in_the_Republic_of_Irelan...
It does not assume that -- implementing libraries need to -- and do, in practice right now -- implement the rules for jurisdictions change the rules for offsets.
That's part of why they are tied to a certain city -- time zone rules are unlikely to bisect a city, although if they did I guess they'd have to deprecate it as a timezone name and use something else! Not sure if this has ever happened.
All of this is kept track of in the IANA Time Zone database, and labels like `Europe/Paris` are from keys into that database, not arbitrary. https://www.iana.org/time-zones
Sometimes when jurisdictions do weird stuff like changing their rules for (say) when Daylight Savings starts with no notice (effective tomorrow!), the libraries can take a bit of time to catch up and be correct again (and have the new version be distributed to all users).
But keeping track of (say) that America/New York on March 25 2024 is UTC-4 but March 2025 1990 is UTC-5 hours (they changed when Daylight Savings started in between those years) is absolutely something current (eg OS) time libraries do.
As well as keeping track of the gregorian correction in (depending on country) October 1582 (skipping over 10 days in the calendar!), when calculating historical intervals. They really do this, already!
That's why you say "Europe/Paris" or "America/New York" instead of "UTC-5", to let the library figure out the rules for offsets at that location on the time specified.
I assume Temporal will do the same. JS environments are usually running on OS's that will already provide this service, the browser or other execution environment won't have to implement it from scratch. Although I think moment.js did it from scratch, and distributes a timezone database with moment.js packages.
> As well as keeping track of the gregorian correction in (depending on country) October 1582 (skipping over 10 days in the calendar!), when calculating historical intervals. They really do this, already!
Which libraries do this? Libraries usually implement proleptic calendars, including Temporal[1], which specifically do not account for shifts like this. And indeed, the Temporal docs even call out this specific example.
(I agree with the rest of your comment!)
[1]: https://tc39.es/proposal-temporal/docs/calendars.html#handli...
Ah, I guess not as many as I thought!
Ruby DateTime does it, I hadn't realized it was unusual, if it is!
Here it is particularly called out in documentation with example taking account that April 23rd 1616 in England was not the same day as April 23rd 1616 in Italy, and DateTime knows that! https://ruby-doc.org/stdlib-2.6.1/libdoc/date/rdoc/DateTime....
(That class however is using weird "Date::ENGLAND" constants for locale instead of ISO timezone locales, which is a legacy mistake!)
(I work in archiving cultural history, so probably deal with pre-19th century dates a lot more than the average coder)
update: I was curious what would happen if I gave DateTime a non-existent date...
DateTime.iso8601('1752-09-05', Date::ENGLAND) => invalid date (Date::Error)
it knows! (England skipped some days in September 1752 as part of Gregorian adjustment)
Ah yeah, those look like opt-in calendars to me I think. Definitely other datetime libraries do that. They just also require opt-in AFAIK.
> That's part of why they are tied to a certain city -- time zone rules are unlikely to bisect a city, although if they did I guess they'd have to deprecate it as a timezone name and use something else! Not sure if this has ever happened.
It's actually easier to create this problem than by bisecting a city, and the easier way is even more complex than bisecting a city.
You obviously can't put every hamlet, town and village into tzdb, for a lot of reasons. So, if you're trying to represent a time in a place that isn't in tzdb, you have to pick the nearest location that is in tzdb. And it's quite possible that between when you enter your time and when that time comes to pass, the location you were specifying for changes it's rules in a way that's different from the original place you chose.
If you bisect a city, you could create two new names, so that if you encountered the old name you'd know that something needed to be reconciled. But if you chose the nearest place and then your rules changed, you'd have no way to know automatically that it needed to be revisited.
For example, parts of Chile decided not to do DST any more. To support this, a new timezone, America/Punta_Arenas, was added to tzdb. Before this, if you were in Punta Arenas, you would just put all your times as America/Santiago. And now you have no way of knowing if those times are really supposed to be Santiago or if they were Punta Arenas and Santiago was just the best you could do at the time.
Location-based tz's are the best we can do right now but even still they have intractable problems when things change.
Right, I mean that if in 2030 for some odd reason half of Punta Arenas does DST and half does not, then 'America/Punta_Arenas' would not work as a timezone designator anymore! Obviously unlikely, I probably should not have mentioned it.
Can you provide a concrete example? Ideally using Temporal to show where it's going wrong. Like, if you created `2025-06-20T17:00:00+02[Europe/Dublin]` (the instant) in 1760, then its civil representation would be different, to account for the rules in place at the time. And then if you went to deserialize it today, Temporal would reject it. You'd get an error, because the rules in place when the string was serialized don't match the rules in place today for that instant.
To be clear, I might be misunderstanding what you're saying. So that's why I'm asking for a concrete example. That will cut through everything. And if you didn't, I would strongly suggest you take a look at https://tc39.es/proposal-temporal/docs/zoneddatetime.html and search for "conflict". I think that will help explain things.
> I get that it’s more correct
We can chase perfection, but perfection isn't the goal. All models are wrong, but some are useful. In other words, the question isn't whether Temporal's model of interaction with time is wrong (it is!), it's how wrong it is and what its impact is that matters.
I must be misunderstanding what you’re saying. How does Temporal know to reject something serialized from before a rule was changed when the creation time of the serialized representation isn’t encoded? You’re saying in 1760 [Europe/Dublin] would be a different string vs today? A more concrete example is normal time-zone rule changes - `2025-06-20T17:00:00+02[Europe/Dublin]` would represent different instants if Dubling passed a new DST rule adjusting the clock back by 15 minutes at 2025-06-20T16:50:00+02[Europe/Dublin] - then the meaning of the instant is different because now there’s 2 different `2025-06-20T17:00:00+02[Europe/Dublin]` and which one you get will depend on when you deserialize.
Can you check out the Brazil example in the docs I linked? That really should clear everything up. It explains how a datetime in the future gets serialized, but after a DST change, that serialized datetime becomes invalid.
The way this works is by looking at offsets. Think of a time zone as a function mapping between civil time and physical time. Or, another way to think about it is a mapping from a civil time to an offset (which may not exist for gaps or may not be unique for folds) and a mapping from physical time to an offset (of which there is a bijection). With RFC 9557, you encode both the offset and the time zone into the serialized representation. Consider a case when you encode an offset corresponding to DST, and then DST is abolished. Your tzdb is updated. Then you go to deserialize this datetime. Its offset no longer matches the rules. This can be detected and Temporal reports an error. This is all explained in the docs.
Note that DST is only an example here, because it's a common manifestation of how this error arises. But it can happen with any change in offset.
So if you're in 1760 and you write down a datetime in the future using the rules of that time (of which, I'm not even sure that's a sensible question to ask), then you'd have a particular offset encoded in that future datetime. Now fast forward to the future and the rules have changed and are no longer consistent with the offset encoded in the datetime. Thus, you get an error.
Here's another take on the idea that I wrote for Jiff: https://docs.rs/jiff/latest/jiff/tz/enum.OffsetConflict.html
Think of it like this. In an RFC 9557 timestamp, you have an offset and you have a time zone. Those two pieces of information may be inconsistent with one another. For example, `2025-01-30T17:00+10[US/Eastern]`. When that happens, you can report an error. That's pretty much it.
> then the meaning of the instant is different because now there’s 2 different `2025-06-20T17:00:00+02[Europe/Dublin]` and which one you get will depend on when you deserialize.
If the region adjusted their close back by 15 minutes, then the offset would change. As for `2025-06-20T17:00:00+02[Europe/Dublin]`, it can only feasibly have two different interpretations: you can either interpret it as the instant `2025-06-20T17:00:00+02`, or you can interpret it as the civil time `2025-06-20T17:00:00` in the time zone `Europe/Dublin`, ignoring the offset. Or you can reject it. Temporal supports all of these modes, and it will by default reject such strings when the offset and time zone are inconsistent.
(There's a fourth mode, "prefer offset," that I won't get into here... It's not usually used for deserialization/parsing.)
So in my use cases, there's three types of dates that matter:
1. Past dates. These can be stored UTC, and just rendered in the appropriate timezone as a matter of formatting.
2. Future non-human dates: e.g. the next execution time of a job that runs every hour. These can just be UTC
3. Future human dates: I care about the human selected timezone so that events happen on the wall clock time the user expects. The UTC time and UTC offset are meaningless.
So in cases 1 and 2, having a non-UTC date is not required, while for case 3, the only thing that UTC offset is doing is adding information that could be inconsistent or confusing.
e.g. If the concert is on at 2026-01-31T18:00:00[Europe/Dublin] , that's all that matters, whether that ends up being 2026-01-31T18:00:00+00:00 or 2026-01-31T18:00:00+01:00 is unimportant for whether the building is going to be open at the time. So the system failing to give customers on the day of the concert a countdown because `2026-01-31T18:00:00+00:00[Europe/Dublin]` has become inconsistent because e.g. the EU actually did go ahead and abolish DST is suboptimal.
For that specific use case, sure! But Temporal isn't for Macha's 3 use cases. Not all future datetimes are only concerned with civil time. Some are concerned with the precise instant in time. So how do you choose which one? There is no one universal right answer, so IMO, the right default is to reject.
But if you know your use cases and know you always want to adhere to civil time even if it means a change in the precise instant, then Temporal supports that too:
>> zdt = Temporal.ZonedDateTime.from("2025-06-20T17:00+08[US/Eastern]")
Uncaught RangeError: Offset +08:00 is invalid for 2025-06-20T17:00:00 in US/Eastern
InterpretISODateTimeOffset ecmascript.mjs:1467
ToTemporalZonedDateTime ecmascript.mjs:1531
from zoneddatetime.mjs:478
<anonymous> debugger eval code:1
>> zdt = Temporal.ZonedDateTime.from("2025-06-20T17:00+08[US/Eastern]", {offset: 'ignore'})
>> zdt.toString()
"2025-06-20T17:00:00-04:00[US/Eastern]"
> So in cases 1 and 2, having a non-UTC date is not requiredIf the only operation you need is formatting, then I agree, you can apply the time zone to the instant right before it's displayed. But there are many other operations (such as arithmetic or computing durations between datetimes) you might want to do that do required a time zone. You might still be able to get away with only storing a UTC date, but it really depends on what you're doing.
Places like Europe/Paris or America/Los Angeles can participate in daylight savings, and if they do, they may have different schedules, and those schedules may change at different points in history due to the passing of laws. Europe and the us already have a different schedule for daylight savings, and the whole west coast is trying to opt into permanent daylight savings for the last several years. But that would require an act of congress.
Programmatically it mostly means you have to ship metadata about how the offsets change over time, which needs to be updated periodically. Browsers already ship that metadata, so it is really nice to finally have a way to access it from JavaScript without shipping the extra few tens of kilobytes.
Europe/Paris might change between now and the referenced time.
In other words, 2025-01-01T00:00+02:00 was NOT Europe/Paris (as it was CET at that time, GMT+1), 2024-08-01T00:00+02:00 could have been Europe/Paris (CEST, GMT+2), 2030-08-01T00:00+02:00 may be Europe/Paris (CEST, GMT+2), or perhaps not (CET, GMT+1). Or it may be a completely different TZ that incidentally shares the same offset at that time.
One represents a time in a specific place, and one represents merely a shift from UTC. A specific time zone can have different offsets depending on the time of year, for example with Daylight Savings Time.
It's so much nicer than what we're used to working with!
I built a set of low-level calendar components for building date/range pickers [0]. In anticipation of Temporal landing in browsers I decided to forgo Date (at least on the surface, I hid it away) and polyfilled the slither of Temporal I needed. When it lands I can just delete a bunch of code. The components come in at less than 10kb already, so I am looking forward to making them even slimmer!
This is true, but there's one fly in the ointment I noticed: a lot of people _hate_ using time zones that refer to a real life location.
They ain't gonna bother finding out whether "Europe/Paris" is like a wide slice of France or just specifically Paris, they don't want to tell you they live in Paris and will get annoyed.
When using things to like, schedule online community events or whatever, this has been a pain. People _want_ to use fixed offset, they are fine with things like "CET/CEST", and _hate_ things like "Europe/yourexactcoordinates."
And before you run into here, _I_ know time zones well enough to be chill - most of them (all?) are actually really large areas. But there's plenty of people who are both privacy-minded and not really interested in researching the differences between a "time" and a "time zone" or whatever because they aren't terminal dorks.
I’m also using it in production and it’s so much better than any of the existing alternatives
> time _is_ complex
If only humans could read int64 epoch values
And lived on a flat planet.
That’s not a valid argument. There is no reason why people in Japan couldn’t start their workday at 03:00, or people in France at 22:00
And while people in London might start work at 21:00, folks in Oxford might start at 20:55 and folks in Norwich might start at 21:02.
Time zones aren't just so everyone on the planet can start work at 09:00 local time. They're also for snapping everyone in a region to a shared time, even if it's a little off from their solar time.
Check out the history of railway time for the birth of time zones: https://en.wikipedia.org/wiki/Railway_time
Because it makes the lives of every single person harder to make lazy programmers jobs easier. That's the only reason to do that.
Travelling would be so much more annoying if we did it that way. Imagine constantly having to double check what the local time is for getting out of bed.
I think that’s fine if you always stay in one place. The adjustment for jet-lagged visitors may be more disruptive though.
How would that be useful for humans? Machines should make life easier for humans, not vice versa. For humans, I don't see any benefit to having to use a universal timezone. Being able to talk about time in a relative manner without converting timezones is very useful. I don't want to check timezones whenever someone tells me that they had to stay up until midnight, or wake up at 4am lol.
You've just introduced timezones
It always cracks me up when people think they are proposing a simpler system by ignoring complexity. Is akin to people saying, "why don't we just change the start/end time of schools/businesses instead of changing the clock back?" As if getting companies to agree to when to make a change, and updating all of their documents/signage/etc. would somehow be easier than allowing them to continue to say "open at 8."
For this one, It really amuses me on how they think they would accomplish keeping someone's phone to alarm at the equivalent of 7am when they fly across a nation.
Granted, I still hold the silly view that we should probably change daylight savings time to be a 10 minute change of the clock every month. Up for six months, down for 6 months. Would effectively be trying to tie it to actual solar time, which is what we seem to care about. And would be trivial with modern devices. (Though, no, I don't hold that this will happen.)
My bank opens at 9am. My pharmacy opens at 8am. The corner cafe opens at 7:30 but is completely closed on Wednesdays. This "complexity," if you want to call it that, requires very little cognitive load, and certainly doesn't require any standardized features to be added to every operating system and programming language standard library.
The complexity I was referencing was having all businesses change by exactly the same amount on a given day. Which happens relatively flawlessly twice a year in much of the world. Just having them be different times for different companies is a completely separate thing.
Yes, but that's still all the same ballpark. It's useful to know that 9am is in the morning for almost everyone. Yes, there are exceptions but they are still just that - exceptions. I'm not sure how useful it would be to add even more chaos.
And again, it's a weird inversion in the role of a machine. Machines should make life easier for us, not the opposite.
Well i mean, why stop there. We could alter the time of every clock every day by milliseconds or seconds, to keep perfect track of the solar timing. Better yet we could just trash the clock all together and decide to care about the things that got done rather than the exact time spent on it. This is probably not sarcasm
If we could easily change the duration of a second, I'd see little argument for why we wouldn't do that. Some of these solutions are easier than others.
Amusingly, these difficulties aren't static, either. Easy to argue that before rail and modern time pieces, what you are talking about is exactly what happened when people were using solar clocks.
Your idea is a lot better than my plan. When I am king of the world, no business or transactions will be allowed to occur on Feb 29th. Instead, every 4th year there would be a nothing day, where nothing happens. So no systems would ever have to deal with leap days or 366 day years.
if only it was as simply a reading int64 epoch values :')
Just add "What Three Words" for time.
"Eastern Daylight Time"
"America/Michigan/Detroit"
We built that already. We call it time zones.
Same! We've also been using the polyfill in production for a ~year or so.
We recently configured the node-pg driver to leave the postgres DATE / TIMESTAMP / TIMESTAMPTZ dates as "just strings" (instead of its default parsing to JS dates), and then we go straight from strings -> temporals at our ORM layer, without the jank/hop of it first being a JS Date.
...shoot, we need to get the Temporal out-of-the-box support updated in our Joist (https://github.com/joist-orm/joist-orm/) docs. :-/
But it's been great, having `DATE` in the db => `PlainDate` in the TS backend => `Date` in GraphQL API => `PlainDate` again in the TS/React FE. Very clean.
why does the polyfill have dependencies? And it's 200KB alone compared to 60KB of moment.
Did you bother to look at it?
It has a single dependency, and that single dependency has no dependencies of its own.
So what is that dependency?
"temporal-spec"
And it looks like it comes from the same github repo. It basically looks like they broke out the API definitions so that they could be depended on by other potential implementations. This isn't atypical.
Oh sorry I was looking at https://www.npmjs.com/package/@js-temporal/polyfill
this one looks much better indeed
If payload size is the top concern you shouldn't be using Moment either though. Luxon and DayJS are both considerably smaller (their uncompressed size is about what Moment's compressed size is) and the date-fns library is much, much smaller and also tree-shakeable. Moment also performs at or near the bottom of all available options if speed is a concern. Other than reflexive popularity or the cost already being paid there's not really a good reason to use it anymore.
Exactly. I should've written even compared to moment
See also Swift’s built-in Date/DateComponents/Calendar types.
Man, that took some time to find in the docs:
Temporal.ZonedDateTime.prototype.withTimeZone() [0], which allows to convert from one timezone to another
const meetingTime = Temporal.ZonedDateTime.from(
"2021-08-01T12:00[America/New_York]",
);
const meetingTimeInParis = meetingTime.withTimeZone("Europe/Paris");
console.log(meetingTimeInParis.toString()); // 2021-08-01T18:00:00+02:00[Europe/Paris]
To me, timezone translations as well as durations are such an essential thing which libraries must handle, and it's nice to see that Temporal handles both. But it looks like Temporal.Duration doesn't offer a custom `format` function, for example `duration.format('H\hmm\m')` or something like that to format a duration into 1h03m.[0] https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
The DurationFormatter proposal allows you control over which units you want formatted and at what brevity: eg. 1 yr, 3 hours, and 3m. See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
I partially implemented it in the icu4x library.
Agreed this sounds like they are looking for Intl.DurationFormatter.
Temporal.Duration.prototype.toLocaleString will end up using Intl.DurationFormatter though, so that will ultimately be what he wants (probably going to depend on that ICU4X implementation being complete though).
Anyone knows how the data about each timezone stays updated within Temporal? Does the TC39 update the data somewhere, then each browser copies that data internally and releases a new version of the browser? If a user visits my website and this user has not updated their browser with the new data, will they see incorrect hours?
For example Mexico removed DST in 2022 [1]. When using third party libraries like pytz or moment-timezone, you just update the library on your side with the updated data for Mexico. Or bump the language if it's handled in the standard library. What about Temporal and my visitors' browser?
Reading the proposal page “ Time Zones and Resolving Ambiguity”[1], it only mentions that it uses the IANA time zone database[2] not when it updates it. However I imagine the users computer has access to this database as well and probably handles it being updated. I’m not sure about this. It’s also entirely possible for the browser to download this database and maintain it too, separately from updates. I’m sure it depends on the implementation.
Since it's built into the browser it's probably updated when the browser is updated. Browser vendors did a lot of work to update quickly, browsers are probably the most up-to-date software on your average person's computer.
Please don't forget about us node users (and deno and bun I guess, too).
If you're running years old js runtimes in a bigcorp that doesn't feel like updating for the next decade, I'll pray for you. (Because there's nothing else to do.)
Smolcorp here, we just went from 12-20 across several large projects, it was gnarly. And now, 20 is already set to sunset soon. at some point it just feels like you should give up trying, but I'm hoping 20 to >20 isn't as bad as 12 -> 20
I work with both node and Python. The difference in upgrade experiences is measured in several orders of magnitude. My most recent few projects jumped Python versions because features I wanted were introduced. I cannot remember a time I had to rewrite application code because of an upgraded Python version (well I do, it was the Python 2 to 3 migration a very long time ago).
In the meantime new node versions constantly break backwards compatibility. Upgrading packages is a mess. Runtime environments are not properly isolated, third party packages sometimes explicitly do not work with specific versions of node, etc. For a community so focused on creating tooling, it has the worst tools of any ecosystem I have seen. I would rather work with C than with node.
Really, can you give a more specific example? I have never had a node upgrade break my code, and would be fairly surprised if I were to run into that situation! I also don't quite understand your other points - runtime environments are isolated, that's the point of the node_modules folder, and it's one of the things that Node/NPM does particularly well at. Were you installing your packages globally?
You must be lucky. Anything the relies on their floating ABI breaks on every update (C dependencies are very common for certain tasks)
Oh man 12 -> 20 must have hurt. In my experience, Node really stepped up their game in most any regard after the iojs split, and these days I've had almost zero problems jumping from one major LTS release to the next.
Can't guarantee no issues, but my gut feel is you'll have a much better experience with 20 -> 24 for example.
I know it doesn't always work out, but it definitely helps to keep current, rather than performing a massive update every X years. Most of the time the changes are minimal, but they add up over several major revisions.
Of course, every now and then something like eslint will completely break every project in existence by changing the configuration format, then you have to wait for all of the plugins to be updated (if ever), then hope all your linting rules are still valid... yeah I'm still bitter about that one.
Picking Javascript as the foundation of your project and being dismayed at how much work it takes to keep up is a restatement of the definition of insanity.
deno added this about a year ago https://docs.deno.com/api/web/~/Temporal https://deno.com/blog/v1.40#temporal-api
It's going to depend on the implementation and the system. The implementation will probably end up needing to define a time zone provider, which will ultimately be provided by host/system hooks provided to Temporal from the engine implementation.
On Unix systems (including Linux distros, macOS and Android), there is a system copy of the IANA Time Zone Database. I actually don't know if browsers use that or if they ship their own copy. But Temporal definitely uses the IANA tzdb.
> If a user visits my website and this user has not updated their browser with the new data, will they see incorrect hours?
Yeah I think this is generally correct. But I don't think that's a departure from current norms? I think this is also just true in general. If the user doesn't update to their system to account for new time zone transition rules then that's just kinda how the cookie crumbles.
The alternative is that every application ships their own tzdb. And to be clear, some do that and sometimes it is warranted. But in general this would be wasteful and likely lead overall to inconsistency between applications and likely a slower cadence of updates. (Because now every application has to be updated and shipped out again.)
Windows has its own complex in different ways system-wide Time Zone Database, but these days also has a full IANA Time Zone Database compatibility layer.
There are quite a few things marinating in the TC39 pot right now. This is one that I wish would ship sooner, rather than later. I do recognize that it takes dev effort (on the part of v8, JSC, and SpiderMonkey engineers) to get the major browsers to support any of these new features. So I truly appreciate all that folks are doing to move the ball forward. The impatient person in me is cheering, "now get Records and Tuples going too! You can skip that silly Pipe-syntax war if you want!"
Records and tuples are unlikely to ever ship, or at least are extremely unlikely to ship with the semantics around equality people want. My understanding is that browser vendors already have pretty strong opposition to introducing new primitives at this point. Reading this thread[1] will give some explanation as to the hiccups with how equality would behave. It sucks, because while I wouldn't have expected BigInt to have gotten much adoption in the first place, I constantly run into cases where I'd want collections with structural equality.
Additionally, my understanding is that the opposition to adding new primitives also affects pattern matching, though I'm not sure why. I'm much less up to date on that proposal.
[1] https://github.com/tc39/proposal-record-tuple/issues/387
The one I want is pattern matching (https://tc39.es/proposal-pattern-matching/), which is still at stage 1 so many years away, sadly.
Pattern matching (and expression based assignment, of which idk if there’s a proposal for or not) are two things that would really drive a ton of value.
It's going to end up looking a lot like C# [0][1]; these two/three (JS/TS, C#) languages have been converging for a while now. Now just waiting for C# to get official first party discriminated unions!
[0] https://learn.microsoft.com/en-us/dotnet/csharp/language-ref...
[1] https://timdeschryver.dev/blog/pattern-matching-examples-in-...
Assignment is already an expression, no?
console.log(x = "hello");
I also REALLY want records and tuples.
It's great that Temporal is coming, and I'm sure there are bunch of other nice things coming up too, but unfortunately I don't share your optimism with the specific proposals that you mention (even though those would be very nice).
Pipelines, pattern matching and records+tuples have all been in the works for 4+ years, and are all still in stages 1-2. I don't think any of them has seen any significant progress in the past year, except maybe pattern matching. According to an issue in the records and tuples repo, there's been pushback on the value semantics of it (i.e. whether === can be made to work). Dropping value semantics would significantly reduce the whole proposal's usefulness.
I think all of them are at least a year or two away from reaching stage 3, if they ever do. But hey at least we now have array grouping functions.
Even when it does ship it'll probably be another year before enough browsers have updated to safely use it in production. So you'll need a polyfill. Which you can start using today anyways!
It's not just the major browser makers. I was working on a JavaScript inference engine around when ES6 started to roll out, I had decent ES5 support but when all the syntatic updates came I had to give up. They basically killed the JavaScript ecosystem with all the updates. We only have complile to JS languages now. Those that still writes in vanilla JS are like those who still build apps in assembly langauge.
> We only have complile to JS languages now. Those that still writes in vanilla JS are like those who still build apps in assembly langauge.
I strongly disagree, it's never been easier and more pleasant to write modern JS without transpilers. I've only rarely had to reach for a framework or transpiler in the last few years.
Come now, this is silly. There are plenty of us that are explicitly avoiding build phases because, for us, what needs to be built adds very little benefit.
Working with assembly is comparatively expert work that few professionals are good at. JavaScript can be written by kids.
> Those that still writes in vanilla JS are like those who still build apps in assembly langauge.
…Huh? Are you referring to transpilation?
Records.. Wasn't Dictionary an ECMA5 proposal or was that just a novel touch in AS3?
[edit: For those who don't know, Dictionary was a type in AS3 that let you use any object reference or string or number as a unique key, with any type of value attached. Garbage collection worked around this so it wasn't a weak reference as long as the dictionary object itself was alive. Think of a Javascript Set except with strongly typed keys of any kind you specified. Errors thrown at compile time. God..I miss that language.]
We’ve had Map with those semantics since 2014, came out in Chrome a few months before Set.
Record/Tuple objects are immutable primitives with structural equality, not object reference equality. So little relation to AS3 Dictionary/ES6 Map, besides being possible keys for Map/Set.
> Record/Tuple objects are immutable primitives with structural equality
TIL and also god that would be amazing, almost to the point of making JS/TS actually nice if done right (what’s next, pattern matching?). The number one footgun in JS imo is the combination of mutability and reference copying. Immutable or at least easy-to-copy plain old data is fantastic when it is well supported in the language.
> what’s next, pattern matching?
Oh boy do I have news for you... https://tc39.es/proposal-pattern-matching/
:P
I had the impression the implementation happens first, then the ratification later when things worked out well.
Providing comparison functions that work with existing APIs is solid design, should be required reading for any new types added really. Kudos to the designers!
const durations = [
Temporal.Duration.from({ hours: 1 }),
Temporal.Duration.from({ hours: 2 }),
Temporal.Duration.from({ hours: 1, minutes: 30 }),
Temporal.Duration.from({ hours: 1, minutes: 45 }),
];
durations.sort(Temporal.Duration.compare);
console.log(durations.map((d) => d.toString()));
// [ 'PT1H', 'PT1H30M', 'PT1H45M', 'PT2H' ]
They should add an event to detect when someone changes timezones. That could be another entry in the "falsehoods that programmers believe about time": programmers believe that your timezone is fixed during usage. But in reality there are millions of people moving between timezones every day.
Where would you expect this event to be used? I don't think most web applications somewhat dependent on time should directly have to listen and respond to these events for the amount of people affected by it just doesn't justify the extra effort, I would assume. Libraries could benefit, of course.
First JavaScript is unfortunately not just for web apps. It’s also for desktop apps.
Say my normal work day is from 8-5 and I work in the Eastern time zone. I set my Slack DND to outside those hours.
I hop on a plane and go somewhere on the west coast. The perfect case, Slack would notify me of the change and let me decide whether I wanted to adjust the DND to local time or keep it.
There are two possible scenarios for me. I could have flown to Seattle for a business meeting and I want to change my DND to local time to be in sync with the rest of the team onsite.
The other scenario is that I’m flying to Los Angeles to hang out. But I’m working during the day and I still need to work east code time.
> First JavaScript is unfortunately not just for web apps. It’s also for desktop apps.
A bit of a tangent but I’d say server is bigger than desktop. Like it or not JS (or TS) is the only cross platform development language that’s feasible today if you want to use a single language stack. As much as I despise the JS ecosystem practices and haphazard tooling there is no point trying to put the genie back in the bottle.
JS could be an amazing language to work with if they'd just spec out a "use type" subset that uses an actually-sound Hindley-Milner type system on typed parts (verify types at the untyped fringes and throw if they don't match) while disallowing all the bad parts like type coercion or any of the many other footguns in the language.
TypeScript??
Would hope your server time zone changes quite rarely and only when you know about it, though.
To my understanding, it shouldn't require that much effort since browsers should already be keeping track of timezone changes, see Chromium's time_zone_monitor [0]. Browsers could emit a "timezonechange" event on the window.
A quick search of gecko-dev shows entries for both WM_TIMECHANGE and NSSystemTimeZoneDidChangeNotification, although they haven't separated it into its own service. I imagine they also track timezone changes for other platforms.
[0] https://source.chromium.org/chromium/chromium/src/+/main:ser...
> They should add an event to detect when someone changes timezones.
That sounds like it would be used as yet another data point with which to fingerprint and locate people ._.
I don't believe adding this event would represent a new data point for fingerprinting because it's already possible to detect timezone changes by polling `Intl.DateTimeFormat().resolvedOptions().timeZone` and `new Date().getTimezoneOffset()`.
The client's timezone should only matter to the client. There's no condition where their clock matters except to translate a timestamp into their local time (for their convenience). Who cares if they change time zones?
So that you can update the UI to show the new time zone? Or change the time format to indicate that it’s no longer in the same time zone as the user is in? That’s just off the top of my head, I’m sure there’s more.
I agree that it would be a nice feature, but I'd really have to be scraping the bottom of the feature barrel before I got to this. Unless my product heavily featured scheduling, or was a clock.
Sending emails at specific user times, billing (be careful with this one!), scheduling events in the future, reporting it to other users (Microsoft Teams' "it's 20:39 in this user's Timezone").
Since this requires state to track should be up to the developer to define how they want to track and respond to changes in timezone? I'm not sure I would want Temporal to have an opinion on how to handle that?
I would expect a timezonechange event to get emitted on the window and that the developer would be responsible for handling it accordingly. This wouldn't require any changes to Temporal.
Right, like the browser/app environment would be responsible for it, and then devs can hook into that if they want to handle it or not?
Suggestion, design your app to not be time zone dependant if at all possible.
For example, store dates in UTC and render instantaneously in current time zone.
That only works for past events, not future ones. Converting to UTC is lossy so rendering timestamps correctly in the future becomes problematic with DST/TZ rule changes.
Really depends on what you want to do. If it's something like "set the date at which new system behavior x becomes effective", UTC is perfectly fine; for scheduling a meeting, not so much.
For timestamps, which are considered fixed points in time, yeah. Dates and times are different. If you block off 12-1pm for lunch in your calendar every day, the actual timestamp of that event might change if you fly elsewhere and set it to use the local timezone automatically. Same with holidays and birthdays.
> and render instantaneously in current time zone
And for that you need to have a timezone-change event, if you don't want to poll the current system timezone.
If you are on a plane or ISS you could even be timezoneless.
Iss uses Coordinated Universal Time which is just GMT.
Wouldn't you be in the time zone you are traveling over, the same as with other modes of transportation?
You might but that isn't useful. Basically a web app will show you a time affected by your tailwind and weird geopolitics. (The weird politics are not so bad if you stay in the same time zone just changes 2 times a year)
I.i.r.c. ISS uses UTC
UTC for the win
How would the runtime know that though? If you're in a plane with no internet, or if you're privacy conscious and you have location services turned off, there's no way for the JS engine to know you're in a different timezone.
I mean your argument has some merit but I'd argue that "you get the new timezone if you create a new date after your system updates its local timezone" is good enough.
Furthermore, most applications will just use UTC; local timezone is more used to adjust the displayed time, and even then it's opt in (e.g. someone reading a log will want server time or UTC, someone using a calendar will want to see their local time OR the time at the location of an event, etc).
The operating system is responsible for tracking timezone changes. If you turn off automatic timezone switching or you're in an airplane without internet then the timezone change just won't be detected, which is perfectly fine. That isn't an argument against supporting a timezonechange event.
Every major operating system has had a way to keep track of timezone changes going back over 25 years. This was during the era where most people were on desktops, but now most people are on mobile devices so it's more relevant than ever. Chromium already has a time_zone_monitor service in place, which I linked in a different reply.
Currently, if you want to detect that the timezone has changed you have to poll `Intl.DateTimeFormat().resolvedOptions().timeZone` and `new Date().getTimezoneOffset()`. An event would just let you get notified without requiring polling.
Updating the displayed time on the client is precisely one of the reasons that this feature can be desirable.
> someone reading a log will want server time or UTC
I personally prefer local times when reading logs, but I'll absolutely take UTC over a wrong local time.
I've used Temporal a bit with a polyfill. It's a huge improvement.
There's no "it's coming" really. With build processes and polyfills there's no reason to to use it already.
Related. Others?
JavaScript Temporal Is Coming - https://news.ycombinator.com/item?id=42809834 - Jan 2025 (18 comments)
Mozilla: Temporal (Limited Availability) - https://news.ycombinator.com/item?id=42776548 - Jan 2025 (1 comment)
Is It Time for the JavaScript Temporal API? - https://news.ycombinator.com/item?id=29712118 - Dec 2021 (100 comments)
Temporal: Getting started with JavaScript's new date time API - https://news.ycombinator.com/item?id=27661667 - June 2021 (194 comments)
JavaScript Temporal - https://news.ycombinator.com/item?id=27395236 - June 2021 (1 comment)
JavaScript Proposal Temporal for Dates is now stage 3 - https://news.ycombinator.com/item?id=26432346 - March 2021 (1 comment)
2024: Nested CSS 2025: Temporal
Once we can style <option>'s HTML/CSS/ECMA will be complete. Thank you for everyone's hard work. Let's focus on interop and PWA apis!
Carbon is a similar class in the PHP world that's inherited from DateTime. This gives a good description of how working with mutable timestamps can cause problems, because methods like $newInstance = $instance->addDay() modify the original instance and return it, rather than returning a copy that's a day later:
https://carbon.nesbot.com/docs/
So it's best to mostly use CarbonImmutable so that a new instance is always returned, which works better for higher-order programming style that's closer to pure functional programming. I do wish that Carbon was immutable by default, with CarbonMutable as a fallback when necessary, but it's too late for them to change it now.
I could see a project using use..as statements and/or aliases in config/app.php (edit: in Laravel) to import CarbonImmutable and Carbon as aliases like CRBN and CRBNMUT respectively, so that code works as intended without monkey patching or otherwise swapping the classnames and losing code portability.
> I could see a project using use..as statements and/or aliases in config/app.php (edit: in Laravel) to import CarbonImmutable and Carbon as aliases
This wouldn't work the way you're hoping for. use statements are file-scoped; a use statement in config/app.php would only affect that configuration file, not the entire application.
Oh I was thinking of adding the custom CRBN or Carb or whatever as class aliases to the original CarbonImmutable class in config/app.php. I actually haven't used aliases yet though, so I'm going by the assumption that they "just work".
I've had problems in other projects too where I wanted to disallow use of classes like Carbon after declaring a child class that overrides certain behaviors, so that the code is more future-proof for newly onboarded developers who don't know the pitfalls yet. In C/C++ I would just do:
#define Carbon "Please don't use Carbon, use CRBN or CRBNMUT instead."
So attempts to use Carbon would show up as compiler errors. But there are no #defines in PHP, so I haven't figured out a way to do that yet :-/ Maybe I could declare Carbon as a constant somewhere or something. But I don't think there's a way to undefine constants for times when the original word is needed, like with #undef.I get that the naming Temporal is used for avoiding conflicts with typical time objects like Moment, Datetime, etc. But isn't it a terrible name? At first glance I thought it was some kind of garbage collection control
There are only 2 hard problems in software engineering: naming things, cache invalidation, and off by one errors.
temporal
> 1. of or relating to time as opposed to eternity
> 2. of or relating to grammatical tense or a distinction of time
> 3. of or relating to time as distinguished from space
https://www.merriam-webster.com/dictionary/temporal
Sounds like a good name to me.
I thought it was Temporal the workflow engine in the browser
There's even the concept of "Temporal Dead Zone" in Javascript already which describes the period of time where variables aren't accessible.
I also think it's a terrible name. I'd even take DateV2 over this. I get they need backwards compatibility but Temporal sounds terrible. DateTime isn't by standard part of JS so why not use that? Until then const DateTime = Temporal
I agree, the naming is unfortunate. DateTime would have been way better.
We're definitely bike-shedding a decision that has already been made, but I agree that it's a horrible name.
First, "Temporal" is an adjective, not a noun. It might be related to time, but it doesn't make intuitive sense.
But more importantly, choosing an odd name because it has a lower probability of conflicting with old code will just make the language increasingly obscure over time.
When they added Promise and Generator, there were plenty of libraries that used those object names. It didn't matter, because unlike reserved keywords, you can override built-in Objects.
In my opinion the standards committee needs to have backbone and do the right thing for the long-term health of the language and use "Time".
But again, I'm sure this argument has come and gone and the decision has been made and agreed upon by all the browser makers and JS engine implementations.
I thought it was about the distributed async task framework!
I like it. got a Star Trek vibe.
While I love that javascript has been taking features from popular libraries (read: jquery) and integrating them into vanilla, I do despair a little that every time it does so with a much more verbose and annoying invocation.
It sounds kinda cool and sci-fi-ey, but yeah I have a feeling I'm gonna struggle remembering the name of this new API lol
Curious to see how Temporal works with JS on the client side!
It’s an awesome tool for durable execution, I’ve been using it in my OSS projects, and it has been instrumental in building a leading Reverse ETL platform powered by Temporal.
this is about a new datetime library in ecma standard, not the orchestration service temporal.io
From TFA:
> When JavaScript was created in 1995, the Date object was copied from Java's early, flawed java.util.Date implementation. Java replaced this implementation in 1997, but JavaScript is stuck with the same API for almost 30 years, despite known problems.
I'm not a JavaScript or web developer, and I was surprised by the above. Can anyone comment on why the language was stuck with an inadequate api for so long? What are the forces at work here?
Well browser standards were pretty much gimped by microsoft during the IE5/IE6 era, so from 1998 until around 2010 there was no progress on standards and Microsoft was actively trying to prevent web applications from becoming a thing in order to not damage Windows market share.
From 2010 until about 2020 I would say the standard committee took hold and they have been quite busy with other things. Since JS is a language defined by committee it can take quite some time for people to agree on APIs which is a subjective topic. The last thing the standards body want is to introduce an API and then deprecate it in favor of another API slightly later.
> during the IE5/IE6 era
During that era was a peak of browser innovation. IE5 and IE6 contributed a lot of things to web standards. They contributed a bunch of things that web standards eventually rejected too, but that was the risk of innovation at the time.
It was the period between IE6's last feature update and IE7's first release where Microsoft declared the browser wars "finished" and disbanded the IE team entirely that was the Darkest Age. So about 2001-2006 were the darkest few years.
It certainly had repercussions until around 2010, but the worst "sabotages" were done and gone by then. "Legacy" problems.
Microsoft was MASSIVELY trying to make web applications a thing. They introduced HTML Applications[1] in 1999 (e.g. Electron). In 2001, they added the JavaScript features that let us have Gmail and Google Maps (XMLHttpRequest). They let you rebuild your Windows desktop or any folder as a HTML in Windows 2000/ME. They created a ton of APIs from web components[2] to CSS effects[3] in 1998.
However, when Netscape died, Microsoft did a 180 and went from the leader in promoting the web to the absolute worst obstruction. It seemed like they completely de-funded their IE development team.
[1] https://en.wikipedia.org/wiki/HTML_Application
[2] https://en.wikipedia.org/wiki/HTML_Components
[3] https://learn.microsoft.com/en-us/previous-versions/ms530752... (previously was just filter:)
> Microsoft was actively trying to prevent web applications from becoming a thing in order to not damage Windows market share.
Boy, it's a different company doing this now, but this is definitely still something that is happening, especially in mobile.
Not to the same level as back then, the closest thing would be Apple refusing to implement good PWA integration and Web Push Notifications (forcing people to use Apple Push Notifications which only works in Safari). PWAs are still (mostly) supported in Safari, they just don't integrate at the OS level in iOS.
Apple is still actively developing Safari and JSC and implementing standards, Microsoft basically COMPLETELY FROZE browser improvements for 10+ years. Worse even, they pushed proprietary Microsoft-only solutions to try to lock-in people.
Is Java not designed by committee?
Javascript, for the longest time, was a _slow_ moving target - web browsers themselves had cross browser issues where API X might work on browser A but not on browser B.
There were so many bigger issues like that I think that made this not a high priority in the grand scheme of things.
I think a good example of this is jQuery - while jQuery is a good tool, a huge part of its usage was the quirks between browsers. Selectors and the class of problems jQuery solved had more immediate impact to web applications, so fixing and taking from it became a more immediate concern.
JS API -> moment/date-fn/luxon -> Temporal has the same kind of trajectory. Not that those libraries will now be immediately 'bad' mind you - just that the base API is more sane.
> Java replaced this implementation in 1997
If that date's correct, they replaced it with another flawed implementation. The 'good' one came much later: https://jcp.org/en/jsr/detail?id=310
> What are the forces at work here?
I feel like I'm always simultaneously engaged in about 5 HN threads at a time, advocating for some combination of immutability, type-safety, and/or no-nulls. It's basically all I do.
By and large, people simply aren't into it. "Because the world is shared and mutable" is a pretty common rebuttal:
4 hours ago: https://news.ycombinator.com/item?id=42876487
2 days ago: https://news.ycombinator.com/item?id=42850569
1997 would be JDK 1.1, which introduced the java.util.Calendar/GregorianCalendar classes. The Calendar API was an improvement in some use cases over Date, but it's biggest flaw was mutability. The current API is based on JodaTime and is very similar to Temporal.
I've been a JavaScript developer since the nineties and I too have been puzzled about this very thing. Everyone has known Date has been broken for a very long time and a plethora of pollyfills and datetime libraries have sprung up to band-aid the situation but nothing ever got close to being resolved as major ECMAscript versions were released over the years. I guess if it takes 270 pages for MDN to explain it, it's a rocket science problem that's well over my head.
First rule of being a platform: Do Not Break Existing Code.
Well, Java did not break existing code, they added the new code alongside the old one. Just like JavaScript seems to be doing years later.
That's fair, but they didn't need to - just make a new Date library and deprecate the old one.
Going back even further in time, Java.util.Date was was heavily inspired by a C library.
That’s the origin of getMonth() in Java (and therefore in JS) returning a value from 0-11 and not 1-12 as many coders initially expect.
What was the origin for this peculiarity in C? That I don’t know, but I’m curious to find out if anyone knows.
C uses zero-based array indexing. A C array variable is a pointer to its first element, and an element index is just an offset from that. Element 0 is at start + 0, element 1 is at start + (1 * element size) etc.
Which why the fields of the 'tm' structure [1] (used to represent dates and times) are zero based§. Makes it easy to index into eg an array of day names using tm_wday. I guess at one time Java.util.Date was a leaky abstraction layer on-top of such an api.
§ Except for the tm_mday element, which curiously is 1-based. I've always assumed that this is because it is unlikely to be used as an array index. A long time ago I'm ashamed to admit that I used tm_mday == 0 as a quick check for an invalid tm value.
Just spitballing, but in C it was always the convention to use zero-based indexing. Probably because you were often adding these indexes to pointers (literal memory addresses) to index into an array, so you needed a zero to index into the first slot of the array.
I think they thought they could get away with a hotfix like Intl.DateTimeFormat()
At first glance, this seems to be in the JodaTime/NodaTime/Js-Joda tradition of representing different "granularities" of date and time information with distinct types, e.g. with and without timezone information. I'm not sure if there's a formal relationship, since this seems to use different names.
I personally like that approach, but I'm not sure how much sense that makes without static typing. (Maybe TypeScript is established enough that JavaScript APIs are now designed with TypeScript in mind?)
From experience with js-joda, there's a definitely learning curve compared to moment's "one size fits all" type for all things date related. But I found that a lot of stupid mistakes of the kind "a person's age is wrong for an hour after midnight during daylight savings time" are prevented by default.
There’s a learning curve for developers who thought time is easy. The ones with battle scars will feel right at home.
This is the most extraordinary thing that I have personally seen in my career as a software developer, and I have worked in many different fields and different languages and on different platforms, but this is by a very wide margin the most exciting.
I detect the slightest bit of sarcasm but then again it’s hard to read tone in random internet comments.
Why is it extraordinary? moment.js has been excellent for me, same for PHP's builtin DateTimeImmutable. What does this do that makes it extraordinary?
It standardizes it across platforms and implementations; I mean you mention Moment.js, but it's been superseded by Luxon and DayJS ages ago; Moment is very large in terms of file size and doesn't support tree shaking, it creates mutable objects, same as Date, etc etc etc.
But there's the problem. Use momentjs today and you're behind the times, but use the new standard library date functions and you're pretty much guaranteed that code that works today will still work in 20 years.
One reason Temporal is a huge deal is because it differentiates between Date, Time, and DateTime. All of the libraries building on top of jsDate couldn't really do this effectively. I've been using Temporal in production now for about 2 years with a polyfill and while this distinction can be annoying at first, the ability to be so much more specific is very helpful.
It is great news. I was not aware this was in the works.
Using other libraries for something as fundamental as this always seemed odd.
Does this mean we can finally stop downloading and running a third of a MB of js on every website? moment.js, luxon, date-fns, are all obsolete? https://bundlephobia.com/package/moment@2.30.1
The implications of Temporal are absolutely huge. This is a game-changer and I can't wait to see how everyone benefits, developers and users alike.
how are they huge?
As mentioned a couple posts up, it would certainly help finally stop a lot of web applications (generally accidentally) bundling a bonus copy of the entire IANA TZ DB via Moment.js including it all by default "just in case". Cutting a lot of poor tree shaking out of the web by truly and finally "killing" Moment.js will be huge in download sizes if nothing else.
I would start by arguing that not every website needs to deal with dates and times on the client side. And furthermore, if a website only needs to deal with dates but not times (surprisingly common) it can be done in a few KB of JavaScript—the Gregorian calendar is easy compared to the mess of ever-changing time zones and leap seconds.
I used this (via polyfill) for my Typescript implementation of the calendar of the church, and it was fabulous. Using the old Javascript dates I felt like I was always tripping over something... this was actually nicer than Python's (already quite good) datetime support.
in python, 'pendulum' is the datetime swiss army knife. If you havent been using it, you should check it out
I'd suggest `whenever`, which has taken inspiration from Temporal: https://github.com/ariebovenberg/whenever
For Pendulum, I'd suggest folks take a gander at its issue list to see if the bugs reported are 1) real and 2) something you can live with.
Well, when GitHub is back up anyway. Lol.
thanks to you both, I'll check whenever and Pendulum out! :)
Thanks for the headsup
Wow, this is great! We were using the proposal library at my job when I first joined, but switched to moment since Temporal seemed frozen. For what it's worth, moment is excellent too, but having good datetime support in the standard library is going to be fantastic.
FYI, the Moment.js docs recommend not using Moment.js[0]
> We now generally consider Moment to be a legacy project in maintenance mode. It is not dead, but it is indeed done.
The author spells out a few pitfalls of Moment's design and why they're not addressing these as well as alternatives (Luxon, Day.js, date-fns, js-Joda)I've switched to Day.js instead[1]
Oh thanks for the rec! I was aware that Moment was marking itself as legacy, but Day.js looks like a bonus here. Hopefully we can begin making the Temporal transition over the next few years though.
Long-needed, though I think it'll take the ecosystem quite a while to catch up and standardize around it
For one: a couple years ago my company migrated from moment to dayjs, which was a huge improvement and carried most of the benefits of Temporal. So even if it were available tomorrow, migration wouldn't be a super high priority for us
Still a great thing!
My work does a lot of stuff with time and scheduling, and let me tell you having timezone-unaware date/time objects distinct from specific points in time will be so damn useful. The old Date class made it really easy to accidentally screw that up. Third party libraries help, but something as important and fundamental as time really should have a good built-in implementation.
I look forward to the day it's widely available.
But red across the board at https://caniuse.com/temporal looks like it's still far away, and a 20Kb polyfill seems heavy compared to the 2Kb size of Day.js
https://test262.fyi/# will give you a bit better update on the progress on implementation in the various engines / interpreters :)
Oh wow, I was complaining about working with dates in JavaScript around 2010 or so. It only took 15 years to sort this out.
Dates/Times/Calendars, and all the politics therein, is perhaps the second most complex thing computers are asked to do. The first being human languages (UNICODE, LTR Vs. RTL, CTL, Encoding, Sorting/Collation, Normalization, etc).
Everyone agrees that Date in Javascript wasn't very good, but getting agreement over how to solve thousands of legitimately hard problems takes time. My viewpoint is that it is IMPRESSIVE it ONLY took them 15-years to get this far, and I congratulate everyone and all the hard work it took.
Point taken, I realize it's complicated stuff. My gripe with it was more that other exotic features were being implemented while this was being neglected.
Well assuming this actually sorts it out, which remains to be seen.
The name collision with Temporal, the popular durable execution service, is unfortunate.
Thought this was about https://temporal.io/ ...
Great video covering the API: https://youtu.be/oOK3UzLJ_Cs?si=1MJYtFBmcyJs4tLj
With any new DateTime object in any language I usually look at its persistent fields to judge what the memory and access characteristics are.
In case of Temporal it looks like that Chrome goes the JavaScript Date way as it only holds the timestamp:
extern class JSTemporalInstant extends JSObject { nanoseconds: BigInt; }
And then calendrical fields are computed on the fly. Is this correct?
The ECMAScript official docs.
https://tc39.es/proposal-temporal/docs/
Not the most intuitive name though.
I have one question: why ˋTemporal`? That looks weird to me. Why now `Time`?
Right, a different name would avoid confusion with temporal.io.
Is not `Time` a far more overloaded term than `Temporal`?
This is great. You need to write so much code to do conversion between arbitrary timezones reliably now. And even if you don't mind including yet another (large) dependency instead, even those almost all have problems around DST boundaries/ambiguous dates as you simply don't have access to the timezone rules in the browser right now.
It’s been 84 years… Jokes aside, congrats to the team! This is huge news for JS.
If the time zone handling can be added like Golang time package, that would make it very convenient.
that'll work as soon as everyone in the world agrees to download the latest version of their favorite web browser each time Western Sahara is reclassified
We are anyways discussing the future :)
Deep cut.
Also when the King of Morocco makes another snap decision about Ramadan timezones.
How likely are we to get temporal literals? And in JSON?
Why aren’t time zones enums and instead still text strings?
It’s almost a shame, considering all the effort that went into Moment and Luxon, which will largely be superseded. Luxon especially is a joy to work with.
Another way of viewing this would be that these and other implementations have paved the way for standardization, which would possibly never have happened without them.
I spent a day fighting with date-fns trying to get some date calculations working and was to the point I was questioning if my entire approach was flawed because there was no reason I should be spending that much time figuring our some simple date calculations. Eventually I decided to try swapping to Luxon. 30 minutes later and it was all working.
I'm still guessing I misunderstood something fundamental about date-fns, but for now I'm advocating for Luxon.
For the longest time date-fns approach to timezones was "Do you really need timezones? Aren't UTC offsets enough?" which was pretty fatal for a date time library, no matter how simple and light it makes your bundle.
It looks like they did finally launch TZ support in September last year, and I haven't investigated it (and probably never will, given Temporal is coming a Temporal polyfill seems a better option)
Salute to the folks who built momentjs... we used their stuff in prod and it worked like a charm
I’ve used date libraries from several languages and they’re all pretty awkward, but Ruby seems to have a very elegant solution thanks to the fact that primitives are also objects, so for example you can write things like 1.minute.ago or 1.day.from.now, which really helps in quick code comprehension.
That would actually be ActiveSupport, which does many things and the pain of its absence is quickly felt in any non-Rails codebase :)
Yea, I forgot to mention that this was in a Rails context. In any case this is only possible because of Ruby’s primitives-as-objects design.
Relevant XKCD : https://xkcd.com/2867/
Relevant Tom Scott video: https://www.youtube.com/watch?v=-5wpm-gesOY
Well I failed one interview because to calculate number of days in between I suggested substracting Unix timestamps and dividing the difference by 86400.
Is there a problem with that or were the interviewers just being stubborn?
I understand the interviewer wanted to approach the problem as non decimal number of months in a year and variable number of days in a month. One day as the most granular entity. I didn't even wanted to argue over leap years and why the year 1900 wasn't one. It was consecutive meeting in a row and I was too tired for his shit.
Handling dates is an archetypal engineering and logic puzzle to evaluate programmers.
Coming but only available in one browser or run time, and then with a feature flag.
That's generally how that works for new things like this. It is rare for a new thing like this to be adapted by everyone at the exact same time.
Certainly within the context of browsers. There is a reason why websites like https://caniuse.com exist in the first place. If you pay attention you will also see that for APIs on MDN it will also have a browser compatibility list.
Mentioned elsewhere in this thread, but https://test262.fyi/# is great for keeping up to date with the current engine / interpreter support :)
Yes I am just saying how early this is.
It is not a "watch out it may have some quirks on FF and break in Safari" early
It's "Polyfill everywhere" early
Time and timezones are a big and complicated thing, I'm not surprised / appreciate they're taking their time with it. A library is temporary (ha) and is often superseded (e.g. momentjs -> luxon -> dayjs), but standard libraries are in it for the long time (Date has been around for 30 years and will be around for another 30 alongside Temporal).
There's a polyfill in the meantime.
Umm..I am not sure how the Islamic/Hijri calendar gonna work. Tomorrow is the first Shabaan in Pakistan but it is still 30th Rajab in Saudia. How will JS figure this difference out?
I might be mistaken but I think Hatchet.dev is a good Typescript alternative to Temporal
Not the temporal you are thinking of. its Date replacement in JS.
I was really confused for a minute, I thought this was referring to the Uber spinoff durable execution framework https://temporal.io/
Awesome. Can’t wait
Can someone who's been following this explain why they're designing a new API instead of merging one of the successful open source APIs into the standard?
There are plenty of very popular libraries that are low quality and/or have some major issues, popularity of a package is not necessarily indicative of a perfect design. When you put something into your language standard to be supported for the next 30 years you want to make sure it’s as correct for as many people as possible. “Oh this seems to work fine let’s merge it” is not a high enough bar.
It’s inspired by JodaTime which got “merged” into Java, so you could say they are actually just merging an open source project, it’s just not one of the common JS ones.
Are those open source APIs standardized though? JS and browser standards are a different beast altogether than e.g. date library documentation. They need to write and specify exact behaviour, so that multiple implementations can be written by all relevant parties.
Indeed. For anyone interested in Temporal specifically, they can see the proposal here: https://tc39.es/proposal-temporal/
Here's an example of the specification for computing the duration between two dates: https://tc39.es/proposal-temporal/#sec-temporal-calendardate...
(I picked one of the "simpler" ones. Have fun.)
Temporal API is far more consequential than what was attempted before. Their proposal for serializing timezones is about to become the de facto standard extension to ISO 8601 (date/time).
Will this finally have a proper datetime formatter, too?
Great Mozilla!
Finally!
Holy fuck. This has some seriously fucked up syntax, function names and the like. Ugliest shit I've ever seen.
This is the first javascript change in a decade that actually seems like an improvement for web pages (and not just web applications). Nice.
they should ship the entire javascript straight to trash already.
> working with dates and times in JavaScript will be hugely simplified
> To help you get up to speed, there are over 270 pages of Temporal docs on MDN
Not that I'm complaining about extensive documentation, but seeing these two lines juxtaposed doesn't inspire much confidence.
Blog author here, I have to admit I enjoyed your comment. This is because it's mostly reference documentation, so each method of each class has it's own page, for example:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
There is only so much you can do to simplify such a complex domain as time.
But there is a lot you can do to make your description reflect that reality
MDN docs tend to be very thorough and well-written. It looks like most of these pages are for various utility functions, each of which has its own page.
Dealing with dates and times and cache invalidation have been two of the hardest problems I've dealt with and the one uses the other.
270 pages of documentation -- wonderful! /s
I was very confused why Mozilla was shilling for temporal.io
The vast majority of websites should be calculating dates in a server and merely presenting them to clients.
I have wondered why there isn’t a span style element which takes a UTC timestamp and presents it to the user in their preferred time zone. I even wonder if it could be done in private way so that JS cannot even access the value (made more difficult by layout and size).
Similarly a form element for date times could simply return the UTC from the local choice.
I am just wondering out loud and not an expert.
Just want to chime in as someone who from time-to-time (heh) has to deal with datetime-related things and say, I hope for nuclear annihilation upon all clocks and other miscellaneous time-telling instruments, and most of all to whomever it is the world over that decides that, no, we're special and don't need to follow any kind of logic for our timezones (looking at you, China but also basically everyone else in the world).
With that out of the way, very excited for Temporal and am very thankful to the people doing this hard work!
Future generations will no doubt remember this announcement as a revolutionary leap into a brighter future. But I'm sure I'll still be using Moment.js ten years from now the way I'm still using JQuery 3.x now.
Javascript is all we have for front end web apps now, impoverished as it is as a language. But excuse me if I don't get excited every time a proposal is rolled out to bring it close to the 21st century.
And that's fair, thanks to the compatibility guarantees, those libraries will continue to work long in the future. However, they're suboptimal; MomentJS is a relatively large and difficult to compress / tree-shake library, for example. Have you considered switching to Luxon? It should be a relatively small transition.