What is the new Javascript Temporal object?

Asked

Viewed 455 times

13

I recently discovered that you have a proposal on stage 3 a new object to work with dates. This is called Temporal.

I analyzed an example code in a post from Linkedin that uses this new API:

console.log(
  "Initialization",
  Temporal.now.instant()
);

// Initialization 2021-01-13T20:57:01.500944804Z

It works similar to the object Math, and in the example above it returns "almost" the same thing as new Date().toISOString() (but appearances deceive...):

console.log(new Date().toISOString());

In the post, it was said that this would be a solution for Javascript developers who need to work and manipulate dates. At the time I aroused interest and would like to know more about this new implementation.

  1. This is a new implementation that came to replace the object Date? I know that the Date is not going anywhere, but the Temporal API is here to solve some problems?

    1. If yes, which?
  2. I know it’s stage 3, but it’s possible to use it on Node.js in some version through a flag?

  3. Some version of Typescript supports, even if experimentally, this new API?

  4. The headaches I get when working with dates will finally be resolved with a "saviour object"? (I know there’s no silver bullet)

  • 1

    (Off-topic) Just for the record, "silver bullet" refers to a solution or technology capable of substantially increasing the productivity of projects, it has not been found at a more "macro" level (such as the change of the programming paradigm) but significant gains at a more "micro" level there are, for example, adopting the right technology for the problem in question (as opposed to adopting a less suitable one) or using a productivity-enhancing library to solve a certain problem. There would also enter a more modern API to deal with dates (I don’t know if a class can only manage to improve).

2 answers

12

The Temporal API is, at the time of writing this response, a proposed addition to Ecmascript that is at stage 3 of the process of incorporation into the specification (the infamous TC39 process). Repository for the proposal.

Through standardization, the Temporal API will consist of a global object Temporal (similar to the existing Math, Date, JSON etc.) which will clump together classes, functions and utilities for handling dates and times in Javascript. Although the API of this proposal should not be amended, the implementers of this proposal SHOULD NOT send implementations Temporal not marked until the IETF Program the time zone sequence serialization formats / calendar.

On the API we can quote:

  • Remarkable constructors of the object Temporal:
    • Temporal.Instant
    • Temporal.PlainDateTime
    • Temporal.PlainDate
    • Temporal.PlainTime
    • Temporal.PlainYearMonth
    • Temporal.PlainMonthDay
    • Temporal.TimeZone
    • Temporal.Duration
  • Other properties of the object Temporal:
    • Temporal.now

I already want to leave a will: each of the builders above has a specific functionality and its own methods. : -) For individual details, see specification and documentation of the proposal.

Until then, the only "native Javascript" way to handle dates and times in Javascript is to use the object Date and its respective functions and methods. However, this API is extremely old and has several problems of design.

As is common knowledge, Javascript was implemented in a very short time by Brendan Eich, who based the operation of Date in the API (now mostly depreciated) java.Util.Date. Although with future updates, Java has gained new ways of dealing with dates and times, Javascript has remained with the infamous API Date. The Temporal API is the "evolution" of time and date management in Javascript, without the problems of the old API.

The new Temporal API aims at solving these problems, since:

  • Provides simple and easy-to-use Apis for running date and time-related computations.
  • First class support for all time Zones, which includes summer time support (calculations STD-safe)
  • Handles only immutable objects (unlike most Apis Date, that are mutable).
  • Analyzes only strictly specified string formats.
  • Supports other calendars besides Gregorian.

Thus, as we have seen above, the new object Temporal will provide a wide variety of constructors and objects for:

  • Represent actual date and time information.
  • Enable appropriate computations based on each type.

I don’t think it’s worth stretching any further than that, since the proposal documentation is quite complete and expressive, and, as we have seen, may be subject to change. When the API is stabilized, I commit to updating this response with more detailed information.


FAQ of the question

Is this a new implementation that came to replace the Date object? I know Date’s not going anywhere, but Temporal’s here to solve some problems?

No. The Date doesn’t really go anywhere, because it would break the web, which would go against one of the main principles of the TC39 process, which is not to break old Javascript Apis.

The Temporal API has come to make work with dates and times easier. It’s very likely to make the API Date less common in new projects and applications, but Date will never cease to exist in Javascript.

I know it is in stage 2, but it is possible to use it on Node.js in some version through a flag?

Edited on March 11, 2021: Just passed to stage 3, which means that the engine may start initial implementations - still no stability guaranteed.

Node.js (based on V8 engine) yet does not have native Temporal API support, but does exist polyfill that can be used.

However, I do not think it wise to make use of this API at this time for "real" projects, since it is not yet fully stabilized.

Some version of Typescript supports, even if experimentally, this new API?

No. Typescript does not yet provide "native" type settings for the Temporal API.

Will the headaches I have when working with dates finally be resolved with a "saving object"? (I know that silver bullet does not exist)

All probably not. : -) But as we saw above, the Temporal API will solve several historical API problems Date, which will certainly make it easier to work with dates and times.

However, it is a complicated field and full of edge-cases. While it’s easy, the Temporal API doesn’t make them go away.

  • "First class support for all Zones team ..." This made me open a smile, because as far as I know, nodejs does not implement timezones correctly and to deal with this I have to write a lot of code or download libraries.... If implemented in fact, the timezones will be a headache less :D.

  • I made sure that the Date no JS was inherited from Java and then Java let go, but JS continued with Date, guess why.... backcompatibility :|

  • 1

    Yeah, the Date will always exist because of backward compatibility, which is one of the "pillars" of the modern web. But don’t worry! So that Temporal is standardised (and the support is disseminated), Date will rarely be used in new projects - at least I hope. P

  • "The API is still subject to change" I think according to the link I added to the question, the API doesn’t seem to change. See what was written in the proposal: "NOTE: Although the API of this proposal should not be amended, the implementers of this proposal SHOULD NOT send implementations Temporal not flagged until the IETF allows the time zone serialization formats / calendar." I think it’s worth mentioning in the response this update.

  • @Cmtecardeal, you can edit, if you like, I’m kind of running out of time to go over this in detail right now. I still plan to rewrite this response from scratch when I advance to stage 4. The worst thing is to find the time... : D

6


To another answer has already given an overview, I would just like to complement a few points.

Obs: as the API is still subject to change, I haven’t gone into the examples much. I’ve only put a few that use the current version of polyfill (which may or may not have changed when you are reading this reply), to give a sense of what the API is capable of.


We can start with the main motivation of this proposal, according to their own creators:

Date has been a long-Standing Pain point in Ecmascript. This proposes Temporal ... that brings a Modern date/time API to the Ecmascript language.

In free translation, it would be: "Date has long been a problem point in Ecmascript. We propose Temporal... that brings a modern date API to the language".

The idea of proposal, therefore, is to create a new date API, to correct some points that they consider problematic in Date.

One curiosity is that some of those responsible for the proposal are the creators of the Moment js..


One of the problems is the fact that Date, despite the name, not being exactly a date (in order to represent a single value of day, month, year, hour, minute and second). As already explained here and here, the Date actually represents a timestamp: the quantity of milliseconds since the Unix Epoch (which in turn amounts to 1970-01-01T00:00Z - January 1, 1970 at midnight, at UTC).

That is, the Date represents a unique moment, a point in the timeline. Think of "now": at this very moment, what day is today and what time is it? In every part of the world, the answer will be different (in some parts of the world, it is February 14, in others it can be February 13 or 15, and the time will also be different). Although the date and time are different, the instant (the value of the timestamp) is the same for everyone. And the Date, according to the language specification, only saves timestamp information.

When you print the date (via alert or console.log) or when it obtains information from it (via getters or toString()), this timestamp is converted to the time zone that is configured in the environment where the code is running (browser, Node, etc). That is, the Date uses the time zone setting to convert the timestamp to the correct date and time values (or converts to UTC when you use methods such as toISOString() or the "getters UTC", as getUTCHours, getUTCMonth, etc.).

That approach one-size-Fits-all (a guy to to all govern all situations) can even "simplify" things (so we have a single type of general purpose), but also ends up generating various situations - in my opinion - drawbacks.

For example, if you just want a birthday date (only day, month and year), no matter what time it is or Timezone, just do something like new Date(ano, mes, dia). However, actually internally the time will be set to midnight in the time zone of the environment in which the code runs (be the browser, or the Node, etc.). This is because only the day, month and year is not enough to get the timestamp (for example, a date like the 14/02/2021 does not represent a single instant, you need to know what time and in which time zone it refers, to have a timestamp value). So with Date you are always dealing with timestamps and time zones, even when you do not want or need.

An example (running on Node - remembering that set the process.env.TZ does not work on Windows, and set it in the middle of the script works only from Node 13):

let d = new Date(2021, 1, 14); // em Date, fevereiro é mês 1 :-(
let t = Temporal.PlainDate.from({ year: 2021, month: 2, day: 14 }); // fevereiro é mês 2 \o/
console.log(d.toString(), t);

// mudar para o timezone da Califórnia
process.env.TZ = 'America/Los_Angeles';
console.log(d.toString(), t);

I create a Date and a Temporal.PlainDate which corresponds to February 14, 2021 - incidentally, another incredible bonus of this API: the months nay are indexed at zero - January is 1 and not zero!

Timezone configured in my environment is America/Sao_Paulo (alias "Brasília Time"). So the Date will have the set time for midnight in Brasilia Time, and this is the Timezone used to print the date.

But when I change the Timezone of the environment, it affects the output of toString() (the timestamp of Date is still the same, but this will be converted to the new Timezone when printed). Now PlainDate is not affected by this setting as it only stores the day, month and year, no matter what time or Timezone. The output is:

Sun Feb 14 2021 00:00:00 GMT-0300 (Brasilia Standard Time) Temporal.PlainDate <2021-02-14>
Sat Feb 13 2021 19:00:00 GMT-0800 (Pacific Standard Time) Temporal.PlainDate <2021-02-14>

Remembering that the result may vary according to the Timezone that is configured in your environment.

Notice that Date.toString() shows a different value according to the Timezone that is configured (by the way, the same occurs with the getters: d.getDate() return 14 or 13, depending on the configured Timezone). Now PlainDate, by having no information about schedules or timezones, is not affected by any configuration and keeps its value constant.

I believe this will avoid many mistakes that usually occur until today ("I created a Date but it shows the wrong day/time").

In addition, the new API defines several different types, one for each situation (going in the opposite direction from the one-size-Fits-all): has one type for date (only day, month and year), another for time (only hour, minute, second), another for date and time, but without time zone, another for date/time and time zone, another for timestamp, etc.

This image (taken from documentation) gives us a good summary of the types available:

Temporal types


Conversion between timezones

One thing Javascript doesn’t have is conversion between different timezones.

The closest we have is something like d.toLocaleString('pt-BR', { timeZone: 'Europe/Berlin' }), which actually returns the converted date and time values to the given Timezone. But the problem is that the format depends on the locale, and we have no control over it. And if we want the date/time in a specific Timezone, but in another format? I would have to go changing the locale until I find one, but what if none has the specific format I want? Or if I just don’t want a format, but an object containing the date and time values converted to another Timezone?

With Date, not enough. Already the Temporal provides for various ways to convert:

  • keeping local time: I have an object representing 02/14/2021 at 10am in Brasilia Time, I want to change only Timezone (ie convert to 02/14/2021 at 10am in Japan zone, for example)
  • keeping the moment: when is 14/02/2021 at 10am in Brasilia Time, what day and time is it in Japan? (A: 22h of the same day)

The API still handles more complex cases that only timezones bring to you, such as daylight savings: it allows you to handle the various corner cases which occur (when an hour is skipped, or when it occurs 2 times - in cases where the clock is set back by one hour when daylight saving time ends, for example), and allow you to view each Timezone’s change history.


Arithmetic of dates

Javascript does not currently have good support for date arithmetic. In practice, the best we can do to calculate the difference between two dates is to subtract the values from the timestamps and then do the calculations in hand.

But this is not always enough. Just to stay in a case, the difference in months is not something as trivial as it seems: for example, between 01/01/2019 and 01/02/2019 there are 31 days. Dividing by 30 and rounding, gives 1 month.

But between 01/02/2019 and 01/03/2019 there are 28 days. Dividing by 30, gives 0,93: if round down, gives zero months. But between February 1 and March 1 the difference is not one month? Then we should round up in this case?

But if it was between 01/01/2019 and 29/01/2019, the difference is also 28 days. Only between January 1st and January 29th it hasn’t been 1 month, so I can’t round up in this case. "Ah, so I just jump up if I’m not in the same month".

Then you see that between 01/01/2019 and 27/02/2019 the difference is 57 days, divided by 30 is 1,9. If you round it up, it’s 2, but between January 1st and February 27th it hasn’t been two months. And now?

With Temporal, just do something like:

const today = Temporal.PlainDate.from('2019-01-01');
const futureDate = Temporal.PlainDate.from('2019-02-27');
const until = today.until(futureDate, { largestUnit: 'months' });
console.log(until); // 1 mês e 26 dias

// ou, se quiser apenas a quantidade de meses, use until.months

In fact, a specific type is foreseen for durations: Temporal.Duration. This will make it easier to perform operations such as "adding days/months/years/any-other-amount-of-time to a date".

Of course, this could change the behavior of some corner cases. For example, if you add 1 month to 31 January:

let d = new Date(2021, 0, 31); // 31 de janeiro de 2021
// somar 1 mês
d.setMonth(d.getMonth() + 1);
console.log(d.toString()); // 3 de março!

In fact the "sum" is made by setting the value of the month and keeping the other fields. In the above case, we change the month to February, and the day stays at 31, but as February does not have 31 days, an adjustment is made to March 3 (the "surplus" days end up "giving overflow" and "invading" the following month).

But here comes a semantic question: if I have a date in January and we are 1 month, why is the result a date in March? Shouldn’t it be in February? This is arguable, since there is no "official" rule for date arithmetic (as it exists in mathematics) and each API implements it in a way. But the Temporal (using the current implementation of polyfill) adjusts the date to the last day of February if the value of the day exceeds the number of days of the month:

let d = Temporal.PlainDate.from('2021-01-31'); // 31 de janeiro de 2021
d = d.add(Temporal.Duration.from({ months: 1 }));
console.log(d); // Temporal.PlainDate <2021-02-28> (28 de fevereiro de 2021)

Finally, a good summary of the possibilities is in itself documentation.


In short, the problems of working with dates will continue to exist (how to treat correctly, convert between timezones, make calculations, etc). What can be easier - I hope - is to solve these problems :-)

And remembering that Date will not go away, including the new API provides the conversion of Date for Temporal.Instant.

  • 1

    +1000 A real lesson, as always :). Your explanation made me understand a bug I have on my server. I was saving the UTC timestamp, so what I did was a hand operation to adjust the time zone, and when the mobile app received the date fields (which were in UTC), the mobile time zone was automatically adjusting to the device’s time zone (in the case of America/Saopaulo). I’m excited to be able to use this new API soon :). -1 headache....

  • 1

    @Cmtecardeal I added a few more things to the answer. But I think I won’t add much more because the API is still subject to change (including, I got to test a few weeks ago and actually the current version has changed a lot, even the names of some classes and methods included)then I guess I’ll wait until it’s officially launched so I can update the answer with more examples...

  • 1

    We had this update on Github’s proposal: ""NOTE: Although the API of this proposal should not be amended, the implementers of this proposal SHOULD NOT send unmarked Temporal implementations until the IETF has set the time zone serialization formats / calendar."" I think the API itself won’t change anymore. What’s missing now is just implementation issues. I didn’t get to check completely, but it may be that the API follows this pattern now, so changes in stage 3 are already hard enough to happen.

  • 1

    @Cmtecardeal Good, even so, I think I’ll wait a little longer to update the answer. I haven’t finished reading all the documentation...

Browser other questions tagged

You are not signed in. Login or sign up in order to post.