Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
Dates and Times in JavaScript – A New API for Dates from TC39 (igalia.com)
268 points by 98codes on July 9, 2020 | hide | past | favorite | 154 comments


I'd like to see the JavaScript people, the Java people, the PHP people, the Perl people, the Python people, the C people, the C++ people, and the people for every other significant language that supports functions (either directly or as methods on objects) to get together and once and for all agree on how the heck we are supposed to deal with times and dates.

Then all of them should implement that in their standard library, so that going forward we've got one sane conceptual time handling system everywhere.

I tire of dealing with the quirks of everyone having their own approach.


Basically we need Unicode But For Time.

These are similar problems: getting a computer-amenable model of something that's fundamentally a human phenomenon, and carries multiple centuries and multiple continents of accumulated context, ambiguity, and edge-cases. This is an extremely difficult class of problems, but in the case of text & characters, we managed to finally get a pretty well-functioning and broadly-supported solution after a few decades of gratuitously-incompatible half-solutions. There's hope.


We have “Unitime”, in a sense, because we have RFC3339 and ISO-8601. What we don’t have are good date time handling in standard libraries.

In spite of Unicode we also have a bunch of programs and libraries that mangle text.


I love ISO-8601, but some of their design choices areTaTbitTstrange.


For a serialisation format, I like the Ts, because it sometimes makes munging data with cut and awk and so on slightly easier. I'd agree it's not a great display format, but then I don't think it's supposed to be.


Right, and it's distinctive, which sneaks type information past all the gremlins in your pipeline determined to strip away any and every bit of context they find in your data. On the whole I think it's probably for the best, but it is ugly.


It's pretty horrible. Apart from being hard to read (why pick an uppercase later that looks similar to numerals?), it only works for full dates or times or datetimes. You can't have literals for just years, or just hours, or just a a particular month. Even 10:20 is ambigious -- is that twenty past 10 (am), or 10 minutes 20 seconds past the hour, or a duration (iso also covers durations, but they are weird and clunky)?

Compare 2020-7-29T19:45 to Chinese style:

2020年7月29日19時45分

Easier to read and you can pick any subset of components unambiguously.


ISO-8601 allows replacing the T with a space, which transforms it from a strange format to a great one.

The T-form is still useful for filenames and the like


ISO-8601 does not allow replacing the T with a space. You are thinking of RFC 3339 “Date and Time on the Internet: Timestamps”, a profile of ISO-8601 that does allow replacing the T with a space.

From https://tools.ietf.org/html/rfc3339#page-8:

> NOTE: ISO 8601 defines date and time separated by "T". Applications using this syntax may choose, for the sake of readability, to specify a full-date and full-time separated by (say) a space character.

See https://en.wikipedia.org/wiki/ISO_8601#Combined_date_and_tim... for more references.


Almost everything should be capable of parsing and outputting ISO 8601 dates [1] today. About the biggest recommendation that still seems to lacking in documentation is that you should probably consider offsets (Z or -0500 etc) required rather than "optional", and that you have to remember that offsets are not timezones (and that generally you should store offsets as presented rather than convert between offsets; makes it easier to adjust offsets based on timezones).

[1] https://en.wikipedia.org/wiki/ISO_8601


> consider offsets (Z or -0500 etc) required rather than "optional"

ISO8601 without an offset is semantically different to one with an offset, it represents a time in local timezone (context-dependent). It isn't an "optional" offset in the sense that you can just omit it, it is a fundamentally different data type.

Without this distinction, there is no way to specify a local time in ISO8601, which would be highly inconvenient for certain applications. For example, how do you represent an event that occurs at 9am every day regardless of location? After all, dates and times are used for more than just storing absolute timestamps.

You are absolutely correct that offsets are also not timezones, which makes the ability to specify local "floating" times even more important (i.e. you can't just denormalize the above concept into a list of timestamps with offsets for each timezone you care about, as the offsets will change over time [edit: and tz->offset conversion is lossy and not reversible]).


personally I think the mistake is trying to fit both purposes into a single format or type. as you state, it's a fundamentally different data type. representing a fixed moment in time is hard. representing a "floating" time of day is hard. trying to do both with the same type is pretty insane, but unfortunately common.


It wouldn't really be much different if we had ISO8601.1 and ISO8601.2, would it? The standard can define two different types, and it makes it clear what it means to have a time without an offset specifier. It also defines formats for durations, intervals, and repeating intervals.

Is the distinction in representation too subtle?

We accept this subtlety elsewhere; we are used to 0 and "0" being different things, and expect them to behave differently under operators. Few would find the following surprising:

    0 + 0 == 0
    "0" + "0" == "00"
Then why would we expect these to behave the same?

   20200710T010000Z + `3 hours`
   20200710T010000 + `3 hours`
The first is a fixed timestamp in UTC, the result of the second depends on timezone.


Good point, which is why ISO 8601 does have a very different duration format (though the options for it such as calendar weeks make it a lot more obvious why it isn't just HH:MM:SS).

Maybe there should be a "float" offset marker. Another thing I was reminded of is that +0000 offset should be Z (UTC), but it is often application dependent if -0000 offset is also Z as some applications use -0000 for "user local time, regardless of user". Which is related to "floating", but yet another semantic difference.


I haven't run into that use of -0000, that's insane.

I suspect a side-effect of libraries lacking support for the full range of ISO8601 (for example, refusing to parse a value without an offset, forcing people to use such hacks). Wouldn't surprise me; iOS doesn't even have a consistent way to parse ISO8601 values with and without milliseconds.

[edit:

Apparently this is a RFC3339 thing, did not know that: https://tools.ietf.org/html/rfc3339#section-4.3

Negative zero offset is invalid in ISO8601, but valid and carries the meaning you describe in RFC3339. I misread what that meaning actually is from your comment - it is different to a "floating" or unqualified local time, it always represents a UTC time but with an unknown local time offset. ]


From what I can tell, there's no library to parse the full range of ISO 8601 in Python. The standard string that people claim is "just ISO 8601" ("YYYY-MM-DDTHH:mm:ss.sssZ") is not full ISO 8601 compliance.

ECMAScript specifies "simplified extended ISO 8601", which is just that string above.


Reminds me of some of my difficulty convincing old C# developers to break years of DateTime habits and move on to DateTimeOffset. One round trips ISO 8601 directly and the other uses "magic" (DateTimeKind) that is sometimes (likely) wrong.

That also reminds me that .NET documentation likes to pedantically remind me that what I think of as ISO 8601 is probably more specifically IETF RFC 3339, which defines a formal BNF grammar as ISO didn't think to do that in the 80s. (Yay, standards.)


Python adds a nice twist on making time parsing confusing. It has two strptime implementations. There is time.strptime and datetime.strptime. The former has much more limited timezone handling than the later.

It took me quite a while staring at Stack Overflow answers and my code, wondering why the SO answers supposedly worked and my code did not, before I realized I had time.strptime and they were using datetime.strptime.


isodatetime for ISO 8601:2004, and eventually[1] 8601-1:2019.

python-dateutil for incomplete but stdlibbish ISO 8601:2004.

python-edtf for ISO 8601-2:2019.

However, the ISO 8601-2:2019 spec is something of a clusterfuck born out of EDTF.

Most public discourse about it can be found in various confused crossover threads from people who need open-ended dates for their projects.[2-9]

Here's a haskell implementation of ISO 8601-1:2019 and ISO 8601-2:2019, for reference.[10]

[1]: https://github.com/metomi/isodatetime/issues/138

[2]: https://www.loc.gov/standards/datetime/

[3]: https://www.loc.gov/standards/datetime/background.html

[4]: https://www.loc.gov/standards/datetime/implementations.html

[5]: https://github.com/plk/biblatex/issues/656

[6]: https://github.com/ixc/python-edtf/issues/24

[7]: https://github.com/saw-leipzig/csv2cmi/issues/18

[8]: https://github.com/schemaorg/schemaorg/issues/242

[9]: https://github.com/JohnLukeBentley/open-datetime-standard-bo...

[10]: https://github.com/druimalban/iso8601-timestamp


They should kill datetime.fromisoformat() with fire.


Not every point in time refers to a timezone. If I write that 1 january 1970 was an eventful date, I can't/dont want to add a timezone to it. Then you may want to store/format times without dates, etc...


One would think, but it's inconsistent unfortunately. Most platforms have input and output of ISO 8601 but they are less interoperable than you would expect. PHP's claimed ISO 8601 parsing is completely inadequate; it consists of a single format string. Postgres's ISO 8601 output is, by their own admission, broken: https://www.postgresql.org/docs/12/datatype-datetime.html#DA...


> Almost everything should be capable of parsing and outputting ISO 8601 dates [1] today.

Why is it so hard to configure a Linux system (its locale settings) to get RFC 3339 formatted dates everywhere? Sure, I can `ls -l --time-style=full-iso`, `git log --date=iso`, `date --iso-8601=s`, `date --rfc-3339=s` and change the configuration of every single application by hand. Am I missing something?

Often, people recommend the hackish `LC_TIME=en_DK.UTF-8`. This however, doesn't work for Java applications and caused various other issues.


I don't think it's actually that important that every language deals with them the exact same way. I interpret that to mean they all translate the APIs as literally as possible between them, using the same method names, same types of arguments, etc. Different languages all have their own quirks and patterns and it's also useful that the library be idiomatic within the language.

Most of the problems I have seen in dealing with time, across various languages, arise from allowing types to be way too ambiguous. A lot of code uses interchangeably things like "UTC -0700" and "America/Los_Angeles" which are actually very different (one incorporates daylight savings and one doesn't). The important fix is that languages start using reasonable abstractions and are stricter about requiring explicit conversions between types rather than trying to implicitly guess an interpretation.

The first library I've seen get this right was Joda in Java, and it later got included into the standard library for Java. It's been copied other languages, and I've used it on the frontend a bit as JSJoda, but the literal translation makes it a bit awkward in JS and I found it was hard to get other JS developers to prefer it over the more popular moment or date-fns. Temporal looks great, it actually seems to borrow heavily from Joda but doesn't literally copy all of the names or methods so hopefully it will be the best of both worlds.


It's not just that. Timezones are the real bugger. Microsoft has their own list of names separate from the standard IANA timezones, for example. If it weren't for timezones, IMO dates are pretty damn trivial. It's just a matter of storing and transferring them properly (in UTC, always!)


Timestamps are damn trivial. When people use dates, that's all they want 90% of the time. The remaining 10% is where all the hard problems are.

For example, lets say I have a store that opens from 8:00-17:00 every day, and it's currently 22:00. How long is it till it opens next?


Three days and an hour more than you think, because it's the weekend, and an extra day because the public holiday for tomorrow may or not be a working day. Oh and there was a timezone change.


And it's December 31st.. Still shocked by how many times I see a year rollover go bad.


Even before the rollover it get's bad. I had a CI failure on 31 December 2018 for code which worked fine on 31 December 2017, because it was the first time for that code to have Dec 31 in week 1 of the next year.

And last year someone else's code failed on 30 December 2019, so I had a pretty good idea where to look.

Still need to fix a bug in code written only yesteryear because the 1st of July wasn't on a Monday this year, but I decided to snooze that test failure ... it'll work fine again in 9 years.


There was a leap second too, you forgot that one!


...oh, and I hope you know whether your customer is Israeli or Palestinian!

https://www.972mag.com/the-worlds-only-ethnic-time-zone/


People joke, but I worked on a calendar application (well, it was a time series graph) where a leap second caused a rendering bug.


There was this bug in Java related to a leap second that broke all Java servers in the world one summer..


No, they are not trivial at all as I explained in my previous comment. For more sauce: https://codeblog.jonskeet.uk/2019/03/27/storing-utc-is-not-a...

About your question it’s impossible to answer without further context. There may be DST tonight, or a leap second, or the enforcement of some strange treaty that will change the time zone..


This is a case for events! The store opens when the owner unlocks the door..... but since you are in that nebulous time when it is "closed" the next "open" may never happen.. so maybe what really needs to happen is a giant disclaimer around times for things...

like in your search results for let's say some M-F 8-5 business... it would say "Hours: 8:00-17:00, Closed right now, in 72% of the cases, the next opening time is tomorrow morning at 8"


As a shortcut for coming up with the corner cases yourselves, this document has a good list of them: https://moment.github.io/luxon/docs/manual/math.html


I recently did this for a task scheduler. The logic lives in SQL. That was a "fun" query to write... You might think it's the wrong tool for the job, but it was a lot faster than reading every possible row and checking it in the application itself.


You forgot there will be a leap second and switch to summer time.


There is a case to not store a time in UTC: you schedule a meeting in the future and the local authorities change when they start DST in that location. Now your user gets the alert an hour too early or late for their meeting. The scenario is more fleshed out in the link below but I don't want to just copy and paste the article into the comment.

http://www.creativedeletion.com/2015/03/19/persisting_future...


No they are absolutely not. Ask Jon Skeet for example:

https://codeblog.jonskeet.uk/2010/12/01/the-joys-of-date-tim...

https://codeblog.jonskeet.uk/2019/03/27/storing-utc-is-not-a...

Or look at the usual falsehood list:

https://gist.github.com/timvisee/fcda9bbdff88d45cc9061606b4b...

Some interesting ones:

A week (or a month) always begins and ends in the same year.

Months have either 28, 29, 30, or 31 days.

There is a leap year every year divisible by 4.

The day before Saturday is always Friday.


> in UTC, always!

… which the proposal doesn't use. (It uses POSIX.)


I can't speak for every language you listed, but C# has great and clear datetime builtin.

Probably the only thing perhaps not the most standard are the names they use for actual time zones? So perhaps that could be improved.

But seriously I don't know how the fuck javascript people can work with dates. It's ATROCIOUS. I think my favorite one is 0 indexes on months? like if you do date(2020,07,09).. is that July 9th 2020? nope, fucking June! Not June 8th.. but June 9th.

I don't know what monster did that but there should be a special place in coding hell for him/her!


I believe that the logic behind 0 based months in many languages that use them, although I don’t know if this is true for JavaScript, is that month numbers are often used as an index into a table of month names so numbering months from 0 is convenient.


Well sure, I get the reason behind.. but the reality is it's just a horrible convention, especially when you pass multiple inputs (year, month, day, hour, minute, second) and "month" is based on 0 index but the rest are not.


> I can't speak for every language you listed, but C# has great and clear datetime builtin.

If you think built-in .NET DateTime is any good, give NodaTime a try. Standard DateTime is barely usable, compared to it.

For JavaScript, there is excellent js-joda library (same design as NodaTime and Joda-Time), but it's 43 kB minified and compressed, which is... not terrible but also not great, really depends on your use case if it's worth it.


>For JavaScript, there is excellent js-joda library

Well that was kind of my point- needing an external library to manage datetime is ludicrous. That's why I'm talking about what C# has builtin. No matter what new project you start, whoevers code you are working in- you can just use builtin.

>give NodaTime a try. Standard DateTime is barely usable, compared to it.

Went to the website to see some example code.. looks basically the same? Anyway thanks for the heads up but I work with datetime stuff constantly and I am not missing anything. It's easy to create datetimes, convert between time zones, add timespans etc.


> Went to the website to see some example code.. looks basically the same?

The main difference is that there are separate types for the following concepts:

1) A point in time in global timeline

2) A specific date and time in specific time zone

3) Specific date and time but without any information about time zone (and two more related types that contain only date information or only time information).

There are a few more types, but these illustrate the main difference from .NET DateTime. In case you missed it, the basic concepts are explained here: https://nodatime.org/3.0.x/userguide/concepts (which I should have linked to in the first place).

This blog post by Jon Skeet explains the troubles with DateTime: https://blog.nodatime.org/2011/08/what-wrong-with-datetime-a... (he's also one of the authors of NodaTime).


Regarding JavaScript, either you avoid manipulating dates and just pass them to the server in ISO format, or you use a library like Moment.js.

The native API's are a disaster and using them is just asking for trouble!


How does that work? Do you really mean it's August 9?


I have worked on a DoD program that dealt with time precision. It is not a trivial task let me assure you.


Your proposal might seem crazy, but we've actually been able to do this before. While learning WebXR not long ago and looking for examples, I discovered it was based on OpenXR (1) and literally every big tech company has APIs that were similar - I ended up reading docs and sample code from Android, C#, and even Apple to get a better idea of how things were wired together. It was a very pleasant surprise!!

1) https://en.m.wikipedia.org/wiki/OpenXR


So much this. Not to mention that even within the same language, the implementation can differ (e.g. Firefox vs Chrome).

I recently had to parse a bunch of dates in python, writing them to postgres, and then handle the same dates in javascript. And boy was it a PITA. The worst problem was the handling of "BC" dates. I had to hack my way around the boundary between python and sql. Javascript is no better, it simply doesn't compute BC dates without heavy hackery.


I agree in principle, but achieving that kind of harmony between languages is analogous to the world‘s governments agreeing to “save succeeding generations from the scourge of war”. That sounds like an exaggeration, but even if language maintainers are all enlightened enough to compromise, the communities are not necessarily going to comply. The minute a language changes how it deals with dates and times, it’s more than likely someone will, very loudly, announce their intent to fork it in order to preserve the old way of doing things.


Tom Scott has a great video about time and timezones on Computerphile: https://youtu.be/-5wpm-gesOY


Maybe I’m stating the obvious here, but there is actually a standard: ISO 8601. Vendors however don’t seem to follow this, either consistently or at all. As for a standard library, Javascript doesn’t have one - everything is built into the core language. Also, fundamental differences between language syntaxes could have a huge impact on usage and implementation. So even if every existing and future language on the planet followed ISO 8601, there would always be that language barrier.


ISO8601 is a representation standard, not a standard for abstract concepts.

https://news.ycombinator.com/item?id=23783603 called for Unicode but for Time, which I think is perfect. In that framing, ISO8601 is UTF-8, but it is Unicode that is needed for everyone to agree on what is "code point" and what is a "character" (equivalently, what is a "calendar date", what is an "absolute timestamp", etc).


I don't expect that the usage and implementation would be the same in all languages. Just that they would at a high level have the same representations and provide the same operations.

For example, if the standard was that a datetime would be represented as separate year, month, day, hour, minute, second, time zone some languages might implement that as a struct with names fields for each of those 7 elements.

Some languages might implement it as an object with properties for each of those elements.

Some might implement it as an array with one entry for each of those elements.

If the standard called for a function add_seconds that adds a given number of seconds to a datetime, modifying that datetime in place, languages that use a datetime struct might provide a standalone function that takes a pointer to a datetime struct and the number of seconds to add.

Languages that represent datetime as an object might have add_seconds as a member function.

So if I'm a Perl programmer and know how this standard works in Perl that would not necessarily mean it is obvious to me how it works in Python or C. But it would mean I could think about time the same way in all of them. I could expect to have corresponding data structures in all of them, with the same core set of operations available in all of them.

Names might be slightly different (e.g., what the standard calls add_seconds might become addSeconds in a language that by convention uses camel case for member function names), but the point is what these functions and data structures actually do would be standardized so once I know how to do all my date and time stuff following this standard it is easy to map that to the language specific implementations in JavaScript, Java, PHP, C, and the rest.


There is no approach that works for all use-cases when you are dealing with time (there are only various trade-offs).

There is the tz database that is correct for many use cases. It should be available in all languages that you listed https://en.wikipedia.org/wiki/Tz_database


The C++ model is very nice to work with. C++20 will be even better as Howard Hinnant's Date library has been incorporated.


They are yet to agree how to deal with strings, how do you expect them to agree with time and dates?


I'm not sure strings are easier. When to use mutable vs. immutable strings has a significant performance impact, how do you manage memory for them (including when do you copy strings vs work with a slice) are all questions where there's at least 3-4 distinct designs that you might want (a C like language, a C++-like language, a Rust-like language, and a GC'd language).

In contrast, for dates and times, everyone really could have used the same design. Maybe you'd need a slightly different design for dynamic languages, but I'm not even sure about that.


Technically, Javascript is a standard. By Ecma International: https://www.ecma-international.org


Yeah I don't care what the solution is.... if everyone just does it, that would be great.

Then I'll care / complain about the solution ;)


Temporal does in fact conform to standards like ISO 8601 for serialization/parsing etc.


Random question, but how does time work if your box is on, say, Mars?


There’s a history of using local Martian solar time in the past, driven by the need to operate in the Martian daytime for rover safety. They even made special watches that ran “slow” compared to earth times so that they kept correct Martian solar time for some of the missions.

However for “absolute” chronological records you would be looking at using Barycentric Coordinate Time, which is what we get when we do a bunch of corrections to subtract the effects of the sun and earth’s (and the other planets) mass and motion, leaving us with a virtual “clock” that is suitably common for anything in the solar system.

To quote one definition of Barycentric Coordinate Time - ”It is equivalent to the proper time experienced by a clock at rest in a coordinate frame co-moving with the barycentre of the Solar System: that is, a clock that performs exactly the same movements as the Solar system but is outside the system’s gravity well.

The ELI5 I normally use is roughly: It’s what we get if we take the Solar System in its normal orbit around the Milky Way, with some fancy magic we subtract away all the stuff, sun, planets, moons and all the asteroids and comets we can count, and then with a little more fancy magic, we put a super accurate clock that doesn’t weigh anything at all back at the center of where all the solar system stuff used to be.”


Two fun asides:

1) Latitude on another planet is straightforward: take the rotational equator, divide into 90 degrees north and south, done. But what about Longitude? Here on Earth, the prime meridian is Greenwich, because reasons. On Mars, it's indexed to a certain crater. But on the gas giants? Yeah, we still don't have a good plan about that.

2) Paul Krugman's thesis (yes, that Paul Krugman) is on relativistic economies. As in, my planet is in a deep gravity well, your's isn't. My clocks pas a lot slower. Now, how do I calculate interest? What about letters of credit for ships traveling between places to ship goods? His conclusion: let's hope there isn't money by then, because interest can't work between relativistic time frames.


#2 is fascinating! I'll have to look for the thesis to read.


In reality: Even if in a few hundred years we have the capability to travel at FTL to other solar systems, we will still be using GMT as "ship's time".


Community driven libraries APIs are a mess, look at React Native or Js in general. I'd rather a (group of) specialist to develop the API.


Sorry for not being clearer. By "JavaScript people", "Java People", etc., I didn't mean the communities. I meant the people who make the standards for those languages.



This basically exists, and it's called ISO 8601. But the scope of ISO 8601 isn't programming languages and APIs, but data models and their representations. A subset of ISO 8601 forms the basis of RFC 3339. Official copies of ISO 8601 are available for a fee from ISO. For the purposes of this discussion thread, consult this file hosted by the US Library of Congress for reference [1].

ISO 8601 defines a number of terms of art to represent a thorough mental model of the problem space, and then goes on to define string representations on how to express them. But it's paywalled, so people reach for RFC 3339 and the Wikipedia article instead. These focus on representations, and the definition of the concepts isn't captured clearly, so sometimes they're rediscovered independently. Other times, they're not.

Serious attempts to figure this out usually coalesce to something that looks and behaves like Java 8 time. Java 8 time may be verbose, but its concepts are clearly mapped out, and the API bears some marks of a misuse-resistant design. Compared to that, there's efforts like the standard libs for Python, Ruby, Go, or most third-party libs for JS, Rust, that don't bring clarity to the table, and don't present any solution for dealing with calendrical or clock-face objects, and do little to discourage misuse of their point-in-time objects in abstract contexts.

This proposal falls much, much closer to the Java 8 way than to the "everything is an instant, go make your own classes" way.

One shortcoming of ISO 8601 is that it has no provisions for abstract timezones. Instead, people go outside of the standard to represent ISO datetimes alongside IANA timezones.

But the most glaring problem with ISO 8601 is that it doesn't define partials where a more-significant term is unknown or missing: there's no valid, unambiguous way to refer to the 15th day of March, while leaving the year deliberately unspecified. This means that anniversary dates (e.g birthdays, holidays) aren't possible to represent in the abstract.

Likewise, there's no valid, unambiguous way to refer to the 29th second of the fourth minute of every hour. This is much less important than the birthday shortcoming.

The Library of Congress has a standard which extends ISO 8601 with a number of useful constructs for their purposes [2], like uncertainty qualifiers, but even that standard has no mechanism to represent a month+day partial in the abstract.

[1] https://www.loc.gov/standards/datetime/iso-tc154-wg5_n0038_i... [2] https://www.loc.gov/standards/datetime/


> to refer to the 15th day of March, while leaving the year deliberately unspecified

Quoting from https://en.wikipedia.org/wiki/ISO_8601#Calendar_dates

> The 2000 [of ISO 8601] version allowed writing "--04-05" to mean "April 5" but the 2004 version does not allow omitting the year when a month is present.


I think this is a great proposal and a huge step in the right direction for JS. I am curious though, is there a reason not to just essentially duplicate the Joda[0]/Java[1]/ThreeTen[2] API? As far as I understand, they are generally considered a gold standard as far as datetime APIs.

Is it too Java-y that it wouldn't make sense to port to JS? Are there copyright implications?

The JS Temporal proposal _does_ as far as I can tell, share many of the underlying fundamental concepts, which is great, but then confusingly has some types, such as `LocalDateTime`, which mean the exact opposite of what they do in the well-known Java API [3].

There is still discussion going on about these details, but from my perspective it seems like the best thing would be to just copy the Java naming conventions exactly.

[0]: https://www.joda.org/joda-time/

[1]: https://docs.oracle.com/javase/8/docs/api/java/time/package-...

[2]: https://www.threeten.org/

[3]: https://github.com/tc39/proposal-temporal/issues/707


This. They already copied the crappy date API from Java. Why not copy the good one too?


I don't usually laugh at HN comments, but this is pretty good. And it's true. Joda-Time and its near relatives are just genuinely good. So much effort has gone into addressing so many edge and corner cases that it seems like a shame to not just tuck all that work under one's arm and steal it.


I assume it doesn't help that Oracle is arguing in court that APIs should be copyrightable.


There is already a JS port of Joda[1] which works well and, crucially, uses all the same names and concepts. Could we just replace the Temporal proposal with this and save a lot of work and confusion?

[1] https://js-joda.github.io/js-joda/



+1 to going off of Joda API. This is a very well-thought out datetime API with a fluent interface for building date/time objects in an immutable way. Just doing this would be a huge step improvement for JS.


I find that the Java 8 java.time API [1] easier to understand than Joda Time [2] when working with timezones. In particular, the OffsetDateTime and ZonedDateTime classes in java.time seem well-designed and easy to use. The equivalents in Joda Time are harder for me.

[1] https://docs.oracle.com/javase/8/docs/api/java/time/package-...

[2] https://www.joda.org/joda-time/apidocs/index.html


Agreed. Joda had the right abstractions (instants, durations, etc) but the class hierarchy for them was unnecessarily complex. A lot of this complexity comes from opting for the abstractions to be either mutable or immutable.

For example, `ReadableInstant` [1] in Joda implements 3 interfaces and has 7 subclasses. And really, what is the difference between `AbstractDateTime` and `BaseDateTime`? Whereas `Instant` from java.time [2] is an immutable value type and I haven't found it lacking in any respect.

On the whole java.time has struck me as extremely well designed (after coming from Python and previous date and time libraries in Java) and I think it would behoove other languages to liberally copy its design.

[1] https://www.joda.org/joda-time/apidocs/org/joda/time/Readabl...

[2] https://docs.oracle.com/javase/8/docs/api/java/time/Instant....


Considering that JodaTime was more or less the reference for java.time, I would be very disappointed if java.time was worse and didn't get rid of JodaTime's design flaws.


> Considering that JodaTime was more or less the reference for java.time

It would probably be more correct to say that java.time is Joda version 2. Colebourne, the original author of Joda, was also one of the leads on JSR-310, and very much intended that 310 learn from the mistakes on Joda.


> I am curious though, is there a reason not to just essentially duplicate the Joda[0]/Java[1]/ThreeTen[2] API?

They're definitely an influence, just not the only one.

> LocalDateTime

That's a strawman proposal that's essentially user feedback and not a part of the API. Not yet atleast.


> The JS Temporal proposal _does_ as far as I can tell, share many of the underlying fundamental concepts, which is great, but then confusingly has some types, such as `LocalDateTime`

I can't find a mention of LocalDateTime in the Temporal docs, did you mean something else?


It's a current WIP idea for the spec: https://github.com/tc39/proposal-temporal/pull/700

Figuring out a name is still part of the ongoing discussion, so this specific case of `LocalDateTime` isn't a huge deal, and I might have misrepresented things slightly in my original comment, sorry! But I do think the overall point still stands - that it might be best to just use the same names and terminology as Java does.



Joda Time, like Python's datetime and a lot of other date/time libraries, has a date/time class that includes a timezone. Temporal keeps that separate. I think it's a different enough design that Joda Time's popularity isn't enough of a justification for adopting its API.


It has a date/time class that doesn't include a timezone too...


So glad to read that the core objects are immutable. This is probably my biggest gripe of other date/time manipulation libraries, eg moment.js.


https://date-fns.org/ is the most popular alternative to moment-js, has an intuitive functional API and treats dates as immutable. I migrate every project I touch over to it since it has so many fewer footguns.


I wanted to use date-fns on the current project. But, the gotcha is due to its lack of timezone support many of its functions are inherently broken (e.g. startOfWeek). So, if you need rich calculations with timezone support watch out!


+1 for date-fns. It's not uncommon to look at a downloads in a JavaScript bundle to find out Moment — and its timezone and localization files — are a huge percentage of a download for a single `moment.format()` call.


Huh - thanks for the link. The Moment folks also have Luxon, which I've been using, but there's quite a lot more momentum behind date-fns.


Or give day.js a try. It is basically moment.js without its problems, and pretty popular too. I tried date-fns but found it cumbersome to use... Ymmv.


A comment on the side,

>JavaScript Date is broken in ways that cannot be fixed without breaking the web.

I really dislike the arrogant tone that many "new" people employ when talking about some "old" thing they are trying to "improve". (Quotes are there to indicate sarcasm).

Date is not 'broken', it may just not do whatever the author wishes it did; it is not 'broken' in the sense of failing to perform its intended function adequately.

I hope people could change their ways and be a bit more decent in general.

Aside from that, I welcome the new API as I think it would be an improvement over what we have now.


Date is "broken" in that it aged pretty poorly, has a very non-ideal API surface and exposes developers to a number of footguns, that could, ideally, be avoided.

The fact that a vanishingly small percentage of JavaScript developers use Date for non-trivial applications is a great indicator of these failures.


I think https://maggiepint.com/2017/04/09/fixing-javascript-date-get... and https://maggiepint.com/2017/04/11/fixing-javascript-date-web... are better links for the motivations of what parts of Date can't be fixed without needing a new API.



Very excited about the timezone improvements here! Their cookbook has great examples https://tc39.es/proposal-temporal/docs/cookbook.html#preserv...


Great proposal, but Temporal is a poor name. Why not, in the age of the import keyword, finally just have a standard library, and import Date from std like a proper programming language?


There is a proposal for that[1] which introduces a `js:` pseudo-protocol for importing a build in module (or a standard library):

    import Temporal from "js:temporal";
1: https://github.com/tc39/proposal-built-in-modules


I agree Temporal is an odd name for the object representing an Instant. But it shouldn't be Date either. A Date does not have a time associated with it.

Java really did a good job here: Instant, LocalDate, LocalDateTime, ZonedDateTime. (If they hadn't already had java.util.Date, they probably could've replaced LocalDate/LocalDateTime with Date/DateTime, but that ship sailed).


Temporal is just the namespace. It has classes called DateTime, Date, Time, TimeZone, Duration etc.


I agree, I think there should have been some drop-in replacement which would allow old scripts to continue working but also let new work make use of these improvements with `Date`. I feel that this duality will persist for a long time, and it can lead to answers, documentation and codebases becoming a confusing mess. It's hard to predict exactly what this mess will look like, only... er... Time will tell.


TL;DR:

Actual spec: https://tc39.es/proposal-temporal/

Less formal docs: https://tc39.es/proposal-temporal/docs/

Examples: https://tc39.es/proposal-temporal/docs/cookbook.html

You can try Temporal in the JS console on a doc page.


And people used to complain about Java development being slow and behind other languages...

Regarding JavaScript temporals - better late than never I guess.


It's been WIP for a few years now! It's easily one of the largest changes to the stdlib of JavaScript recently, and things like these take forever to standardize.


This is one of those glaring problems that somehow was passed over the last 10 times people got together to decide to improve JS. Remarkable that it has taken so long.


It's been WIP for years now. Just takes a lot of time to standardize something like this, you know...


It's probably due to Javascript having such a giant ecosystem. I feel that moment and date-fns dull the pain so much that most people just don't care. Otherwise, this would have been solved faster.


Date is actually pretty good.

* If you're reading UTC dates from the backend and displaying them in local time, new Date(year + 1900, month, day, hour, minute, second) works great.

* It's also easy to calculate repeating intervals in local time by using that constructor with getYear(), getMonth(), etc.

* Send it back to the server with .toISOString(). Add a .replace('Z', '') on that so .NET binds a DateTime with the right Kind.


So can I round trip it to JSON yet, no, bummer...


JSON has a deliberately limited vocabulary, and is never going to be extended. Objects, arrays, strings, numbers, booleans and null, that’s all you’re ever going to get.


Does this mean I can get rid of moment.js now?


I've switched most of my work that used to use moment over to Luxon[0] now. It's still written by the same authors, but fixes a lot of the drawbacks[1].

[0]: https://moment.github.io/luxon/index.html [1]: https://moment.github.io/luxon/docs/manual/moment.html


Luxon is great.

Also, if you find you only really need one or maybe two date time utilities, date-fns [1] is an alternative that that takes an even more modular approach for tinier imports.

[1] https://date-fns.org/


I'm using React Widgets[0] and I prefer moment over Globalize (been through so much pain with this). Maybe it's time to either write a localizer for Luxor or find a new date time picker

[0]: https://jquense.github.io/react-widgets/localization/


Depending on your specific needs [0], a lot of date localization can be done (painfully, but possibly) directly with Browser Intl [1] calls instead of a library.

[0] Current user's current locale is easy. If for some reason you need to show some other locale than what the browser is using you'll likely still need Moment or Globalize.

[1] https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...


I've been using date-fns on the backend. It's great; so long as you don't have to deal with timezones, because the functions only accept and return Date objects, which don't support internal timezone. The other day I needed to get the hour of day based on a user's timezone, though. And had to resort to moment-timezone because NO i dont want to have to handle the math on my own.


Check out https://www.npmjs.com/package/date-fns-tz. The API is much less intuitive than the `date-fns` one because javascript Date objects don't store their timezone, but I've used it in a real project and it's workable once you grok the mental model.


Personally, I prefer Luxon's timezone handling. I get the appeal of not providing custom classes, but _actually changing the underlying timestamp_ to adjust for timezone has always caused nothing but trouble for me. It becomes an all-or-nothing system (you must use `date-fns-tz` to manipulate the dates) with nothing to actually enforce that.


moment.js is so annoying because if I don't do momentObject.clone() everywhere I end up having many unwanted side-effects.


I have been lucky, then.

I pulled in moment about 5 years ago into our group’s stack, but we mostly use it for parsing and formatting date (only) strings for date arithmetic. The government vital records forms we are working with seldom deal with time of day, and when they do, it’s an optional string down to minutes resolution only.

I guess all the converting to and from strings coincidentally protected me from mutability. Good to know.


I've been burned by this so many times! Code that uses moment is written, tested, and then never touched to make sure you stay sane


The Temporal API is immutable, so you won't have to deal with it anymore.


You can already use https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe... for quite a few of moment’s use cases.


Not yet, but fingers crossed, it would reach Stage 3 in a few months.


Asking for uni-time ignores physics. It just doesn't exist. It can already be measured clocks separated by a meter in altitude run differently. We might have something that works for daily human stuff, but if you leave the planet or ask for Pico seconds, no standard can help...


Anyone doing specialized calculations with time at that level of precision is going to be using specialized code and not any built-in time handling code.


That just proves my point, uni-time is a dead end.


Reminds me of the incredible Time on Unix[1] article.

1. https://venam.nixers.net/blog/unix/2020/05/02/time-on-unix.h...


It would be great to hear feedback from everyone on the Temporal survey: https://forms.gle/iL9iZg7Y9LvH41Nv8


So long as months are indexed by 1 I'm all for it.


They are!


I'm excited to see this land in Node.js! Currently there are only hacky solutions for calculating nanosecond-accuracy wall clock time.


I think it's quite nice! It tries to be as unopinionated as possible, and does a good job at it.


Why not using a namespace like stdlib/datetime instead of this weird named Temporal thing?


because Temporal is not currently used anywhere (as far as we noticed) and it won't break anything while still being descriptive.


You will still need libraries to do nicely formatted time strings like "next week" or "3 hours ago"


Look at `Intl.RelativeTimeFormat`[1] and `Intl.DateTimeFormat`[2].

Regrettably Safari is—yet again—lacking with support, but in the meantime there is a polyfill.

1. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...

2. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...


I find RelativeTimeFormat to be not as useful as it seems—it’s surprisingly limited in scope and utility. You still have to calculate the magnitude and unit of the distance (“3 hours ago” → (3, 'hour') rather than saying “here’s a Date object that happens to be about three hours in the future, you tell me what unit to show”), and it only supports one unit at a time (“1 day ago” or “27 hours ago”, not anything like “1 day, 3 hours ago”), and it can’t produce anything like “next Tuesday” or “this Friday”.

Twice I’ve started with it, twice I’ve tossed it out because in the end it didn’t help my code at all. (Both times I only cared about English, so its replacement which did a better job of formatting values for my situation took pretty much no extra code—for exact equivalence, formatter.format(-n, 'day') for known positive n becomes a simple ternary, `n == 1 ? '1 day ago' : '${n} days ago'` (or if the formatter has the {numeric: 'auto'} option, change '1 day ago' to 'yesterday'); but even with full localisation, I’d still be unlikely to use RelativeTimeFormat.)


I guess Temporal will help you there[1]:

    const now = Temporal.now.absolute();
    const then = Temporal.Absolute.from(
      '1989-11-09T22:45:00+0100[Europe/Berlin]',
    );

    const sinceThen = now.difference(then);
    sinceThen.toLocaleString('en');
1: https://tc39.es/proposal-temporal/docs/duration.html#toLocal...


> You will still need libraries to do nicely formatted time strings like "next week" or "3 hours ago"

If you want those formatted values to be consistent with the rest of your app, you will need this anyway.

You app does support localisation right?

Also: there’s no guarantee a browser would have the same localisation as your app (for instance German-language browser, English website).

You really have to do this 100% yourself in your app if you want the result to look right.


Apps are seldomly translated into my native language, but I do have my browser configured to use my native language, so I often see date values in a different language from the rest of the app, and it doesn’t bother me at all. In fact I hardly notice it.


You would do new Intl.DateTimeFormat(siteLocale) and not new Intl.DateTimeFormat(browserLocale) to get consistent formatting.


Will it allow for using TAI?


Not the core API, but a simple custom timezone can be used to implement TAI. I worked on a POC for it, but you can totally test this with the polyfill right now.

https://github.com/ryzokuken/temporal-tai


Kind of, but not really? The proposal's Absolute represents time in the POSIX timescale, so it is inherently incapable of representing all of TAI, the same as it is inherently incapable of representing UTC.

I attempted to test your library's behavior in this regard, but I do not think you are correctly implementing the proposal's TimeZone. TimeZone.getDateTimeFor() is supposed to take an Absolute and return, in your case, the time that absolute represents in TAI (that time, in the TimeZone). But this:

  var one_before = new Temporal.Absolute(915148799n * 1000000000n);
  console.log(one_before.toString());
  console.log((new Temporal.TimeZone('UTC')).getDateTimeFor(one_before).toString());
  console.log((new TAI()).getDateTimeFor(one_before).toString());
emits,

  1998-12-31T23:59:59Z
  1998-12-31T23:59:59
  1970-01-01T00:15:15.148768
That last timestamp being the output supposedly in TAI; but that POSIX timestamp, 915148799 represents 1999-01-01T00:00:30 in TAI. That is, the second line, 1998-12-31T23:59:59 in UTC == 1999-01-01T00:00:30 TAI.

The other direction (getPossibleAbsolutes) is similarly effected.


Just gimme epoch time and we're good.


Temporal.now.absolute().getEpochNanoseconds()


In Planck time.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: