The idea for Temporal came from a conversation about how poor the Date implementation of JavaScript is. Some history of that is in this blogpost, where Brendan Eich reveals he pretty much copied  Java date handling given his short timescale to get JavaScript implemented.

At the time of writing, Temporal is still Stage 3 proposal  for addition to the ECMAScript language, but that’s pretty far along so we can expect it to see it implemented as a JavaScript API in the not too distant future. There is a working polyfill available for Node here, but I’ve created a library from a rollup of it and its dependencies  so we can start to use it from Apps Script right now.

Since it’s only a proposal, the details may change, but I’ll try to keep it up to date as we go along. It’s a pretty sizeable polyfill, and I didn’t minify it on purpose for now, in case you want to have a look into the details of how it works. I’ll probably do that in a later update.

Apps Script usage

Include bmTemporal in your project

"userSymbol": "bmTemporal",
"libraryId": "1o_qJw1fdgF4NgRnHrsB_Jsbu3gYe1fQnPze33V9jHLqBCXHmzZaBgmGH"
Pull out the Temporal API, and you’re good to go.
const {Temporal} = bmTemporal

Fundamentals

The major problems that Temporal is designed to solve (Moment.js already helps solve many of these – but Temporal will be built into JavaScript in due course)

  • date mutability
  • date artithmetic and comparision
  • parser unreliability
  • timezone spaghetti
  • alternative calendars
  • millisecond accuracy

Another issue that people get worried about is if there’s a ‘Y2k’ problem for JavaScript date. Well there might be, but not until

Sat Sep 13 275760

So I don’t imagine JavaScript will be around then (even though VBA might be!)

Examples

I won’t go into too much examples in this article, as I plan to implement all the Date/Time worksheet functions to be callable from Apps Script, and will use Temporal to enable that – which should cover most of its capabilities – I’ll be posting that shortly, but rather I’ll go into how Temporal is organized to solve the problems with the Date() object.

Concepts

Temporal thinks of time in two buckets

Exact time

This is UTC (Co-ordinated Universal time) and is the baseline time.
temporal timezones utc
This is stored as the number of milliseconds since 1st Jan 1970 (the epoch) in the JavaScript date object, unadjusted for local time. If you’re wondering by UTC and not CUT, it’s to avoid favoring any particular language where the words might be similar but the order different).
It happens to be equivalent to GMT, but treated separately because GMT refers to an actual timezone, whereas a UTC is a baseline time from which times in TimeZones are calculated.
Like GMT, UTC has no concept of DST (daylight saving time)
Temporal has 2 types to deal with this ‘exact time’

 

Temporal.Instant

Rather like the Date object, this stores the elapsed time since the epoch, except it’s the number of nanoseconds, rather than milliseconds which solves the problem of the potential lack of specificty with milliseconds. However, since nanoseconds would overflow the accuracy possible for the Integer part of JavaScript numbers – see Number.MAX_SAFE_INTEGER Temporal uses  BigInt , which is supported in Apps Script V8, (although the Apps Script IDE doesn’t actually support BigInt shortcut syntax such as 200n)

 

UTC now

const timeStamp = Temporal.now.instant()

equivalent to

new Date()

Get milliseconds

const ms = Temporal.now.instant().epochMilliseconds

equivalent to

new Date().getTime()

 

Temporal.ZonedDateTime

This stores the UTC, but also information about a Timezone which can be used to translate it into wall-clock time, as well as a calendar system to which it should be applied. The default calendar is defined by ISO8601 as the Gregorian Calendar.

 

Wall-clock time

The time according to the timezone you are referencing. Essentially it’s  UTC adjusted by the timezone offset for the region you are in.
temporal wall-clock-time

 

Plain dates

These are namespaces for Dates without TimeZones and can be used where only local times are relevant.

 

Temporal.PlainDate

There are also variants for

Temporal.PlainTime

and

Temporal.PlainDateTime

Note that when you pass a date string for parsing that actually contains a TimeZone it will be used to calculate the PlainDate, otherwise the local timezone will be used.

The local date/time now
const local = Temporal.plainDateTimeISO()

 

TimeZones

The IANA or tz database is a list of known timezones names.

An entry contains things like the DST rules, the timezone offset from UTC and various other rules an info. Temporal uses either the name of the offset to reference a timezone. A datestring containing a timezone name looks like this

2019-09-03T17:34:05+09:00[Asia/Tokyo]

and one containing an offset looks like this

2020-09-06T10:35:24.485-07:00

 

Temporal.TimeZone

A TimeZone can be created futlike this

const tz = Temporal.TimeZone.from(‘Europe/London’);

When dealing with Spreadsheets, you may want to get the timezone of the sheet

const tz = Temporal.TimeZone.from(SpreadsheetApp.getActiveSpreadsheet().getSpreadsheetTimeZone())

and convert the current time to that timezone

console.log(Temporal.now.instant().toString({timeZone:tz}))

 

Temporal Arithmetic

Temporal features a number of date comparison and arithmetical methods such as .add, .dif etc. but I’ll be covering them in more detail in a later article.

 

Links

bmTemporal:  IDE

libraryId: 1o_qJw1fdgF4NgRnHrsB_Jsbu3gYe1fQnPze33V9jHLqBCXHmzZaBgmGH