JavaScript Temporal is coming(developer.mozilla.org) |
JavaScript Temporal is coming(developer.mozilla.org) |
There's no geographic adjustment but at least there is some choice for users about which Islamic calendar variation should be used. For example, "islamic-rgsa" in JS is the Hijri calendar, Saudi Arabia sighting.
Temporal has built-in support for non-Gregorian calendars, including parsing, arithmetic, etc. so you can do things like this:
Temporal.PlainDate.from("2025-01-30").withCalendar('islamic-rgsa').month // => 8
Temporal.PlainDate.from("2025-01-30[u-ca=islamic-rgsa]').month // => 8
function chineseNewYears() { const dt = Temporal.Now.plainDateISO().withCalendar('chinese'); const current = Temporal.PlainDate.from({year: dt.year, month: 1, day: 1, calendar: 'chinese'}) const next = current.add({years: 1}) return { current, next } } `The next Chinese New Year is ${chineseNewYears().next.withCalendar('gregory').toLocaleString('en-UK')}` // => 'The next Chinese New Year is 17/02/2026'
More info about how calendars are used in Temporal is here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
> 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.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
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.)
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.
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.
With that out of the way, very excited for Temporal and am very thankful to the people doing this hard work!
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.
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.
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
I can't get it working with Firefox developer edition or firefox nightly on Fedora Linux. What am I missing here? Can someone please guide me?
Just annoyed to use it I have to update all my unit test mocks for Date hahaha...
Being able to replace all the various date and time libraries with something browser-native is a massive win for bundle sizes, as even the most lightweight ones are going to start creeping up there once you're dealing with localisation on top of it.
I'm still guessing I misunderstood something fundamental about date-fns, but for now I'm advocating for Luxon.
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)
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.
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.
It is not a "watch out it may have some quirks on FF and break in Safari" early
It's "Polyfill everywhere" early
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).
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).
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.
A couple of weeks after that, on the night of the time change, I went to a party and afterwards a friend of mine and I went back to my house and started jamming and messing around with synthesizers and so on. As it neared 2:00 am, he told me he'd best be heading home, because it was getting rather late. I told him not to worry and that we were about to travel back in time...which we did. Then we spent another hour hanging out until it was almost 2:00 am again and he left.
I don't ever recall actually witnessing this happening before, in the past, I've always awakened in the morning to find I needed to change the clock on the stove. I really recommend staying up for the time change, because this is a pretty magical time of year. If you don't like the hour you experienced between 1:00 am and 2:00 am, you have just one opportunity per year where guess what — you get a do-over! Or if you really loved it, guess what - you can relive it!
I ended up fixing it by hand changing the time, releasing a version every 6 months for years, otherwise we would get mails about it from the few users using it.
I think I could automate this or otherwise solve the issue, but it always felt nice to move the clocks of a few hundred people.
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.
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.
Joda time has inspired spinoffs on lots of platforms. Including js-joda for the javascript ecosystem. I'm not sure how much the new Temporal approach is based on that but it wouldn't surprise me that that was one of the starting points for the new standard.
Could you elaborate on that? What is the issue?
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!
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.
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.
The way this kotlin library works is that it implements a modern API that uses the underlying platform rather than re-implementing a bunch of things. This is mostly not a bad decision but it does have its limitations. One of the limitations is that not all platforms exposes a sane way to e.g. resolve timezones by their name and localize times while taking into account e.g. day light saving. Fixing that basically requires dealing with the time zone database and not all platforms expose that.
I ran into this recently. I managed to work around it as this is something you can dig out of existing browser APIs but it was annoying having to deal with that. Unfortunately there are probably a few more obstacles on other Kotlin platforms.
If only humans could read int64 epoch values
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!
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.
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.
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...
I partially implemented it in the icu4x library.
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).
https://github.com/tc39/proposal-intl-duration-format/issues...
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?
Evaluating .Now multiple times in a loop will yield different values, which is unexpected.
C# did the same and it shouldn't have been:
https://ericlippert.com/2014/05/19/when-should-i-write-a-pro...
Temporal.Instant.from('2020-01-01') != Temporal.Instant.from('2020-01-01')
This isnt inherently bad, but it effectively removes the ability to use these objects as Map keys or collecting them in a Set. I know why that decision was made, I'm just sad that this wont be possible. Maybe there will be some version that relies on records and tuples, if these ever make it. 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' ]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)
Talk about slow turning ships!
> 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?
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!
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.
Using other libraries for something as fundamental as this always seemed odd.
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.
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.
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.
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 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 no "it's coming" really. With build processes and polyfills there's no reason to to use it already.
Or maybe I'm just fortunate to work in sectors where no one ever really cares about bundle size.
I don't think it's safe to say, more direct comparison of JS's Temporal would be java.time[1], which was introduced in Java 1.8 in 2014.
[1]: https://docs.oracle.com/javase/8/docs/api/java/time/package-...
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?
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!
> 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]
https://tc39.es/proposal-temporal/docs/
Not the most intuitive name though.
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
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.
[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.]
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.
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.
Working with assembly is comparatively expert work that few professionals are good at. JavaScript can be written by kids.
…Huh? Are you referring to transpilation?
And the browser probably already has some way to access that database anyway.
> 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.)
That sounds like it would be used as yet another data point with which to fingerprint and locate people ._.
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.
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...
For example, store dates in UTC 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.
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).
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.
I personally prefer local times when reading logs, but I'll absolutely take UTC over a wrong local time.
For the Set case you could use a Map{v.epochMilliseconds:v} and preserve the Instant.
Not great, but I think we all blame JS for this rather than Temporal. This could be made to work by the runtime but then polyfills would fail.
I had to resort to numbers (Unix time) to not have to add memoization everywhere. Seems like this will continue with Temporal. Or React-Compiler will solve this.
> 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.
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.
Time has the opposite problem. I expect it to be a class, not a namespace. Time.Time creates more confusion, not less.
Temporal is not "odd", it's just a bit less common in english that many people are used to
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 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.
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:)
Boy, it's a different company doing this now, but this is definitely still something that is happening, especially in mobile.
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.
I remember when google introduced gmail in 2004. Suddenly google had done full single-page application in javascript, proving that not only was it possible, but that the resulting user-experience was awesome.
At the time, there were no javascript frameworks. Jquery (if you can even call it a framework) wasn't created until 2006. I don't think there were even helper libraries.
I mostly remember javascript from dynamicdrive.com, where you would go to find quick snippets of "Dynamic HTML" to copy/paste into your html. Sometimes there were useful things like roll-over menus, but I remember many of them being silly toys, like sparkles that would follow your mouse around the screen, or snow which would slowly cover the page.
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
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.
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.
There has been so many better and lightweight alternatives for years that if you haven't already refactored it away, you just don't care about your users or the bundle size. (And I have personally done that exercise a handful of times myself, I know it can be painful, but it's just one relatively small PR!)
What's wrong with continuing to use moment.js in an application where it works well?
I'd also argue that presenting dates in ~0KB of javascript is better and less error-prone than several KB of javascript - it also allows users to see dates in non-Gregorian calendars when they prefer.
In reality, it probably means adding yet another polyfill to the list.
Tangentially... Why did you quote the entire parent post? Quoting a small subset of a large post to respond is one thing, but copying the entire post into a reply adds unnecessary repetition and visual noise to the thread for no benefit. (Is it just me or is this becoming more common?)
Immutability is double edged. If I'm doing a bunch of math on a date, I don't want to be creating a dozen copies either.
SQL query builders also have this problem.
So you're effectively deciding for instance to send your user newsletter at varying hours, sometimes at 1h00, sometimes at 3h00. Or accept that every scheduled event needs to be appropriately timezoned and adjusted as needed if DST change. Or to have your logs timestamp be non obvious when comparing events separated by months, or have to convert all your business timestamps to a different timezone.
Those are all sensitive decisions, and we usually accept the trade-off, but it needs to be an explicit tradeoff.
"America/Michigan/Detroit"
We built that already. We call it time zones.
this one looks much better indeed
JS doesn't really have breaking changes. Until they do, MomentJS will always work.
> It standardizes it across platforms and implementations
Does it? I mean it prints the date and is a standard library, but I don't think it standardizes anything. Web doesn't really benefit from everyone using the same date library. It's all strings once it's sent over the wire.
>> d = Temporal.Duration.from({milliseconds: 60000})
>> d.seconds
0
>> d.milliseconds
60000
>> d = d.round({largestUnit: 'second'})
>> d.seconds
60
>> d.milliseconds
0React is a fundamentally flawed framework because of the lack of this feature. It inverts the responsibility of any non-primitive prop by putting the burden on the parent element instead of the child to decide when to rerender things. So elements are no longer self-contained if they receive any non-primitive values (besides react elements).
The React compiler auto-memoization that facebook is pushing also addresses this issue through build-time magic. I not fond of this approach.
Could you clarify which part you’re referring to? I’m disappointed at them feeling trepidation after BigInt, but the thread I linked (and some other discussions I’ve seen) make me understand why they’d choose to focus effort elsewhere.
It would be a monumental change and it’s not entirely clear how much of the community outside the React and similar ecosystems would adopt it. It might have significant performance issues for the desired use cases and choices about value semantics would affect usability.
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.
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.
Oh boy do I have news for you... https://tc39.es/proposal-pattern-matching/
:P
You could see all the new features, you could use them, you could design your site around them. But so many people refused to upgrade, so as a web developer you were forced to do stupid things to make IE6 work.
And it's not like IE7 was that much better. You needed to put effort into making that work too. At least Chrome and Firefox would usually both do the same thing.
The end of the dark ages was when IE9 was released in 2011 which massively improved the browser.
Think about sites like blogs. The user only needs to know on what date a blogpost is published. Likewise for newspapers: we have hundreds of years of paper newspapers where people know on what date an article is published but not at what time. Think about banks. My bank tells me the date of a transaction, not its time. Likewise for brokerages.
01/31/2025 11:35:11 AM.,ESTTime 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
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.)
https://en.wikipedia.org/wiki/Time_in_the_Republic_of_Irelan...
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.
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...
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.
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.
How so? UTC is a constant point in time. The difficulty lies in representing the value correctly, but the point in time is unchanged.
Unlike what sibling comment mentioned, if an appointment is scheduled at 1739287704987, the value will be the same regardless of where and when it's accessed from.
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.
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.
Can't guarantee no issues, but my gut feel is you'll have a much better experience with 20 -> 24 for example.
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.
[0] https://learn.microsoft.com/en-us/dotnet/csharp/language-ref...
[1] https://timdeschryver.dev/blog/pattern-matching-examples-in-...
We would all benefit if JS was more like C# in my opinion.
console.log(x = "hello");For dates in the past it isn't much of a problem. `America/[city in chile]` in the past (created before the change, refering to times before the change) still has a specific point-in-time meaning even when things change.
The problem is dates records created in the past but referring to times in the future. Which could now be ambiguous or wrong... and this is the first time I'm thinking about it, I'm not sure how easy it is to detect, I guess it should be detectable which dates may be ambiguous/wrong if you know the date of their creation (before the change was known), but it would take caring to write guards about it and having access to databases with sufficient info.
Right - date-times in the past are always easy (at least until you have to take relativity into account). An event happened at some instant in the universe and you just need an agreed upon representation of that instant. UTC works fine for this - record the UTC-based instant at which the event happened and you can always translate it into any other representation without losing information. Recording it in your local timezone is fine too, as long as you also record the UTC offset or timezone along with the instant.
> I guess it should be detectable which dates may be ambiguous/wrong if you know the date of their creation (before the change was known)
Yeah - in theory, when a timezone is added, you could probably link it to timezones that users of the new timezone might have previously used. And then any future times that were saved using that timezone, you ask someone if they are still correct or if the timezone needs to be adjusted to the new one
For example, if a new timezone was added for southeast Colorado, you might ask someone about all times scheduled in both the Denver & Phoenix timezones, because you don't know which one people might have picked.
It gets complicated though because you need to keep track of which entries have been double checked and which ones haven't, and you need to keep track of the version of tzdb that you reconciled against, because there could be another change in the future.
e.g.
const a = { b: 1 }
console.log(a.b = 2); // logs 2 let x;
console.log(x = 'hello');
My point is that the `x = 'hello'` part is an assignment, and an expression, and has the exact same semantics regardless of whether you use that expression as a statement. So, assignments would seem to be expressions.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.
And again, it's a weird inversion in the role of a machine. Machines should make life easier for us, not the opposite.
What about, say, Amsterdam and Stockholm?
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)
But I guess ruby is unusual there! Or I'm wrong.
But good to know most have it as opt-in, anyway!
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.)
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.
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.
Finally, a "use type" with guaranteed type boundaries could offer loads of runtime optimizations and speedups that TS cannot offer (and has no intention of offering).
Objects aren't actually "untyped". Every object has a hidden class with a definite type or "shape" (a shape basically means the same keys with the same value types in the same order). The inline cache (IC) stores which shapes have been used (and how often they've been used) for a specific function. The shape is checked every time the function is run with a series of assertions.
If your function only ever sees one shape, it is monomorphic and will get a lot of great optimizations not only on itself, but maybe on it's parent function as monomorphic functions can be inlined (one of the most important optimizations) with some asserts to make sure things went as expected.
If a function is called with 2-4 types in the IC, it is polymorphic in v8 which slows down the IC lookup and disables some optimizations. More than 4 types is called Megamorphic in v8 and is the slowest possible option.
Here's a whirlwind overview of how this works https://www.youtube.com/watch?v=xckH5s3UuX4
Types offer a streamlined version of all this.
Untyped -> typed simply does what already happens, but the assertions throw if they fail.
Types have other advantages within a function. There's a tradeoff in optimization where you don't want to optimize too early because you might have gotten it wrong and wasted a bunch of time and energy. Types make guarantees that your optimizations are correct which means you can optimize more earlier and there may even be optimizations that would simply be impossible otherwise.
A strong type system would disallow some of the stupidly-dynamic JS stuff which prevents optimization. This is an indirect massive benefit of a good type system (one that TS misses out on as it makes it easy to make types for very slow code patterns).
Typed -> typed is another important consideration. Instead of waiting hundreds of runs for your simple `.map(x => x.foo)` to inline, strong type guarantees mean you can inline it from the very beginning and all those useless assertion conditional branch instructions simply aren't needed. Polymorphism slows down current operations as it waits to dispatch, but because the types show what polymorphism exists and exactly which variant each call site uses, you can always match the exact call site to the correct monomorphic variant which also speeds things up.
Typed -> untyped is super-easy. The compiler knows the shape of the typed objects. It could probably add a greater weight to typed IC entries executing so they produce optimized versions sooner because the types add stronger consistency guarantees.
(FWIW, I'm the author of a datetime library in Rust called Jiff.)
Wednesday January 2st 1908 00:00 clocks were turned forward 28 minutes to 00:28. So an entire 28 minutes of time never eexisted in Iceland even thought today they are on UTC year round and one might think they are the best and easiest country to handle timezone wise.
The 28 minutes jump is likely Iceland coming into alignment with GMT, for much the same reasons as Ireland did; to improve trade and commerce in a world now using telegraphs, telephones and trains. We're ok becoming disconnected from mean solar time in order to connect more with each other.
Samoa skipped a day in 2011, jumping from UTC−11:00 to UTC+13:00, so that it could align with Australia and New Zealand, its biggest trading partners -- so Australia's Friday is also Samoa's Friday.
We'll always have discontinuities in civil timekeeping, as it's there to serve the whims of humans, not the other way around.
Those two facts aren’t connected. At the time that those 28 minutes were skipped, Iceland was using the equivalent of UTC-01:00.
on this particular instant, in Iceland, 28 minutes were skipped because Iceland changed from the offset of Reykjavik’s mean solar time, rounded to the nearest minute (UTC–1:28) to the offset of Reykjavik’s mean solar time, rounded to the nearest hour (UTC–1).
So only from that moment on, Iceland was using UTC–1.
>> 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.most often it is "most often" that causes bugs in software. And when related to date/time it often are severe bugs. ;-)
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.
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".
Some timezone identifiers have changed, e.g. Asia/Calcutta to Asia/Kolkata in 2008 and Europe/Kiev to Europe/Kyiv in 2022. But the TZ DB maintainers are rather reluctant to make such changes, and require “long-time widespread use of the new city name” in English before deciding so.
The naming conventions for timezone identifiers are written out at https://ftp.iana.org/tz/tzdb-2022b/theory.html#naming
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
Thanks! I was the co-champion of that proposal. Parts of it were merged into Temporal last year, and other parts are already part of the JS Internationalization (ECMA-402) specification here: https://tc39.es/ecma402/#sec-use-of-iana-time-zone-database
See https://github.com/eggert/tz/blob/main/backward for all the deprecated zones.
[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...
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.
> 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.
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:00It's always seemed reasonable to me. Sure, "TIMESTAMP WITH UTC OFFSET" would be even clearer -- but, as has been pointed out already, there are 2 valid ways you might want to handle time addition/subtraction, and only one of those ways enables addition to be done without pure speculation on what decisions will be made by political entities in the future, and PostgreSQL does it that way.
Sol3/CA/Toronto
I'd also like all 50 state capitols (and possibly also their largest city) to exist as E.G.
Sol3/US/WA-Olympia and Sol3/US/WA-Seattle (respectively to the above; I don't know Canadian provinces that well)
Sol3 is a prefix for the 3rd planet (starting ordinal 1, but anything in the orbit of Sol can be Sol0) in our solar system. It's also nicely short so easy to type out in command lines.
Every state _should_ have it's own TZ file, even if it's just an alias. That's a good forward compatible way of allowing the same config to work if future legislative efforts produce or remove timezones. It would also allow E.G. Arizona's non DST timezone to remain correctly configured in some future where the US finally ends the nightmare of DST forever.
Country largely just makes sense to disambiguate cases like the two different cities a few hundred km apart both named Vancouver.
Use case: Configure device for customer in another state, OK like the mailing address state 2 letter code is XX what city? Oh there's a choice of two. The one I've heard of is probably the biggest city. Either way, it comes out OK.
What if you don't know what state something is in? Sol3/US/*City should shell expand on command lines.
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.
And it's not even a timestamp with a UTC offset! It's just a Unix timestamp.
If you think the current naming is "reasonable," then we are likely living in two different planes of existence. And no amount of back-and-forth over the Internet is going to help. This is a level of dissonance that requires an in-person discussion in the pub to resolve.
(there's also https://github.com/mweber26/timestampandtz which is delightfully simple, 33 commits, last one 7 years ago)