It's very unclear what you're asking. If you want the UTC date with the hours always 0, then set the UTC hours to 0 and use toISOString, e.g.

var d = new Date();
d.setUTCHours(0,0,0,0);
console.log(d.toISOString());

Of course this is going to show the UTC date, which may be different to the date on the system that generated the Date.

Also,

new Date('2017-04-27').toISOString();

should return 2017-04-27T00:00:00Z (i.e. it should be parsed as UTC according to ECMA-262, which is contrary to ISO 8601 which would treat it as local), however that is not reliable in all implementations in use.

If you just want to get the current date in ISO 8601 format, you can do:

if (!Date.prototype.toISODate) {
  Date.prototype.toISODate = function() {
    return this.getFullYear() + '-' +
           ('0'+ (this.getMonth()+1)).slice(-2) + '-' +
           ('0'+ this.getDate()).slice(-2);
  }
}

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

However, since the built-in toISOString uses UTC this might be confusing. If the UTC date is required, then:

if (!Date.prototype.toUTCDate) {
  Date.prototype.toUTCDate = function() {
    return this.getUTCFullYear() + '-' +
           ('0'+ (this.getUTCMonth()+1)).slice(-2) + '-' +
           ('0'+ this.getUTCDate()).slice(-2);
  }
}

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

Answer from RobG on Stack Overflow
🌐
GitHub
gist.github.com › barbietunnie › 67d10b59f7716e3ff5892d70dd9a3cfa
Format JS Date in ISO-8601 without timezone issues · GitHub
The following function provides an easy way to format Javascript dates in ISO-8601 format without using date.toISOString(), which could lead to timezone issues as the date is first converted to UTC which could lead to discrepancies in the result in certain timezones.
🌐
GitHub
gist.github.com › tw-Frey › cefb813a4dbfb0b672449d19fdd95bf8
DateTime ISO 8601 without timezone component · GitHub
Section 4.2.2 of ISO 8601 gives examples with no TZ designator saying they are local times. 4.2.4 says UTC times use the 'Z' designator.
🌐
Bobby Hadz
bobbyhadz.com › blog › javascript-create-date-without-timezone
How to Create a Date without Timezone in JavaScript | bobbyhadz
To create a Date without the timezone, we called the toISOString() method on the Date object and removed the character Z from the ISO string. The Date object shows the exact same time as the one stored in the dateStr variable - 09:35:31.
🌐
MDN Web Docs
developer.mozilla.org › en-US › docs › Web › JavaScript › Reference › Global_Objects › Date › toISOString
Date.prototype.toISOString() - JavaScript | MDN
The toISOString() method of Date instances returns a string representing this date in the date time string format, a simplified format based on ISO 8601, which is always 24 or 27 characters long (YYYY-MM-DDTHH:mm:ss.sssZ or ±YYYYYY-MM-DDTHH:mm:ss.sssZ, respectively). The timezone is always ...
Top answer
1 of 16
336

Here's a simple helper function that will format JS dates for you.

function toIsoString(date) {
  var tzo = -date.getTimezoneOffset(),
      dif = tzo >= 0 ? '+' : '-',
      pad = function(num) {
          return (num < 10 ? '0' : '') + num;
      };

  return date.getFullYear() +
      '-' + pad(date.getMonth() + 1) +
      '-' + pad(date.getDate()) +
      'T' + pad(date.getHours()) +
      ':' + pad(date.getMinutes()) +
      ':' + pad(date.getSeconds()) +
      dif + pad(Math.floor(Math.abs(tzo) / 60)) +
      ':' + pad(Math.abs(tzo) % 60);
}

var dt = new Date();
console.log(toIsoString(dt));

2 of 16
86

getTimezoneOffset() returns the opposite sign of the format required by the spec that you referenced.

This format is also known as ISO8601, or more precisely as RFC3339.

In this format, UTC is represented with a Z while all other formats are represented by an offset from UTC. The meaning is the same as JavaScript's, but the order of subtraction is inverted, so the result carries the opposite sign.

Also, there is no method on the native Date object called format, so your function in #1 will fail unless you are using a library to achieve this. Refer to this documentation.

If you are seeking a library that can work with this format directly, I recommend trying moment.js. In fact, this is the default format, so you can simply do this:

var m = moment();    // get "now" as a moment
var s = m.format();  // the ISO format is the default so no parameters are needed

// sample output:   2013-07-01T17:55:13-07:00

This is a well-tested, cross-browser solution, and has many other useful features.

🌐
Wikipedia
en.wikipedia.org › wiki › ISO_8601
ISO 8601 - Wikipedia
1 week ago - ISO 8601 applies to these representations and formats: dates, in the Gregorian calendar (including the proleptic Gregorian calendar); times, based on the 24-hour timekeeping system, with optional UTC offset, time intervals, and combinations thereof. The standard does not assign specific meaning to any element of the dates/times represented: the meaning of any element depends on the context of its use.
Find elsewhere
🌐
GitHub
github.com › date-fns › date-fns › issues › 2151
formatISO doesn't use UTC (Z) timezone · Issue #2151 · date-fns/date-fns
January 12, 2021 - When making a sanity check of now.toISOString() === formatISO(now) (with const now = new Date()), it fails due to a timezone difference, as the formatISO doesn't match the browser's toISOString, which explicitly claims that The timezone is always ...
Author   scscgit
🌐
Reddit
reddit.com › r/rakulang › datetime no longer accepts iso8601 strings without the time part?
r/rakulang on Reddit: DateTime no longer accepts ISO8601 strings without the time part?
May 12, 2022 -

Considering that this works:

> DateTime.new: :2022year, :5month, :11day
2022-05-11T00:00:00Z

I find it odd that this doesn't:

> DateTime.new: '2022-05-11'
Invalid DateTime string '2022-05-11'; use an ISO 8601 timestamp (yyyy-mm-ddThh:mm:ssZ or yyyy-mm-ddThh:mm:ss+01:00) instead
  in block <unit> at <unknown file> line 1

Why is it willing to default the hour, minute, and second fields when I use the first form but not the second? And is this a recent change to Rakudo? I seem to recall this working before.

I'll probably just go open an issue against Rakudo, but I'm interested in other opinions about why it actually should work this way...

Top answer
1 of 3
6
For things like this the IRC logs are a goldmine. Here's a search for "datetime string" in #perl6 . From a quick glance at that Liz asked something similar and Larry seemed to conclude with: well, modules will happen, once we actually have a compiler that can derive slangs In the meantime, I note that these work: say '2022-05-09'.Date; # 2022-05-09 say '2022-05-09'.Date.DateTime; # 2022-05-09T00:00:00Z Perhaps this asymmetry between Date, which accepts a plain date, and DateTime, which does not, reflects some perceived wisdom that it's best to nudge folk to think about what they're doing. Then again, as you say, why does it work to use the constructor you showed without using the time fields? Also, if that's what the rationale was, one would think the error message would mention using Date...
2 of 3
4
I'm curious what you mean by "no longer". I think at least in 6.c it was this way, and I imagine it was the same back in earlier versions (I just don't have a way to test that). If I had to guess, though, the named argument method by its nature has to require arguments in any order and thus provides default values for all entities. In other words, there is an expectation of the weird stuff users may do, and a predictable way that it will handle it. OTOH, imagine I did this: Date.new: "8". What did I mean? Year 8? Month 8? Day 8? This is begging to be buggy in ways that Date.new: :8year is not. You might think this contrived, but I can easily see someone say Date.new: "04-08". Do we mean April of 8 AD? April of 2008? August of 4 AD/2004? Or August 4th or April 8th of some unspecified year? The ambiguity is bad, and thus if you try it, you'll get the following: Invalid Date string '04-08'; use yyyy-mm-dd instead A similar logic is applied to DateTime.new, even if perhaps it feels like things would be more obvious. u/raiph 's suggestion of "2022-05-11".Date.DateTime works, though, because you have a fully correct string into Date, and a predictable/logical coercion into DateTime (start of day).
Top answer
1 of 6
186

The option was introduced in the coreutils date (which is probably what you have) in 1999 (Apr. 8).

The documentation was removed in 2005 without much explanation in the commit.

In 2011, the help for --iso-8601 was reintroduced with the following explanation:

We deprecated and undocumented the --iso-8601 (-I) option mostly
because date could not parse that particular format.  Now that
it can, it's time to restore the documentation.
* src/date.c (usage): Document it.
* doc/coreutils.texi (Options for date): Reinstate documentation.
Reported by Hubert Depesz Lubaczewski in http://bugs.gnu.org/7444.

It looks like the help was taken out in version 5.90 and put back in, in version 8.15 (it is not in my 8.13) and the comment above suggests that it is now back to stay and not likely to be disappearing any time soon.

In version 8.31 (as provided by Solus July 2020) the man page has these two options:

   -I[FMT], --iso-8601[=FMT]
          output date/time in ISO 8601 format.  FMT='date' for date only (the default), 'hours', 'minutes', 'sec‐
          onds', or 'ns' for date and time to the indicated precision.  Example: 2006-08-14T02:34:56-06:00

   --rfc-3339=FMT
          output date/time in RFC 3339 format.  FMT='date', 'seconds', or 'ns' for date and time to the indicated
          precision.  Example: 2006-08-14 02:34:56-06:00
2 of 6
181

For a platform independent, (almost) fully compliant, ISO 8601 date, use this:

date +"%Y-%m-%dT%H:%M:%S%z"

This will result in a time such as: 2021-01-16T23:09:44-0500

This should work on macOS (BSD) and Linux.

Technically, for full ISO 8601 compliance, there should be a colon in the timezone offset:

date +"%Y-%m-%dT%H:%M:%S%:z"

The %:z format directive contains a colon between the hour and minute of the timezone offset. This will result in a fully compliant ISO 8601 time with a colon in the time offset, such as: 2021-01-16T23:09:44-05:00

But this doesn't work on macOS (as of this writing). That is, the date command on macOS (BSD) does not support the %:z directive. This should work on Linux (with GNU date).

Fully compliant and portable solution:

You can pass the date output through sed for a fully compliant ISO 8601 date. This should be portable on both macOS (BSD) and Linux:

date +"%Y-%m-%dT%H:%M:%S%z" | sed -E 's/([+-][0-9]{2})([0-9]{2})$/\1:\2/'

For UTC time (zero offset, historically known as "Zulu time") you can use:

date -u +"%Y-%m-%dT%H:%M:%SZ"

Note: The -u option sets the output to UTC time. The Z is not preceded by a % (or a colon) – so it is not a format directive; it is a literal 'Z' character. This is also fully compliant and works on macOS (BSD) and Linux.

This will result in a time such as: 2021-01-17T04:16:14Z

🌐
Webdevtutor
webdevtutor.net › blog › typescript-toisostring-without-timezone
Converting Date to ISO String in TypeScript without Time Zone
const date = new Date('2022-07-25T14:30:00'); const isoString = date.toISOString(); console.log(isoString); // Output: "2022-07-25T14:30:00.000Z"
Top answer
1 of 2
45

Update:

This is now covered by RFC 9557, which extends the original RFC 3339 by adding the time zone identifier in square brackets. For example:

2011-12-03T10:15:30+01:00[Europe/Paris]

Original Answer:

I understand these are not supported by ISO 8601, correct?

Correct. ISO-8601 does not concern itself with time zone identifiers. IANA/Olson TZ names are not a "standard". They are just the most reliable thing we have. (Some may consider them the de facto standard.)

What are platforms doing to support this?

Support what exactly? This part of your question is unclear. If you mean to support IANA time zones, well that's all over the place. Some platforms have them built-in, and some rely on libraries. If you mean to support a string representation of an ISO-8601 date-time-offset + time zone ID, some platforms have this and some do not. You'll have to be more specific if you want to know more.

I notice that the latest Java date/time library is using an extended ISO 8601 format for this, e.g. 2011-12-03T10:15:30+01:00[Europe/Paris]. (See DateTimeFormatter API.)

I think you are talking about DateTimeFormatter.ISO_ZONED_DATE_TIME. The docs say specifically:

The ISO-like date-time formatter...

...extends the ISO-8601 extended offset date-time format to add the time-zone. The section in square brackets is not part of the ISO-8601 standard.

So this is Java's specific format, not a standard.

Is there some converging convention (e.g. with other languages and platforms) for extending ISO 8601 to support time zone designation?

As far as I know, there is currently no standard that covers the combining of an ISO8601 timestamp and an IANA time zone identifier into a single format. One could represent it many different ways, including:

  • 2011-12-03T10:15:30+01:00[Europe/Paris] (this is the default in Java 8)
  • 2011-12-03T10:15:30+01:00(Europe/Paris)
  • 2011-12-03T10:15:30+01:00 Europe/Paris
  • 2011-12-03T10:15:30+01:00 - Europe/Paris
  • 2011-12-03T10:15:30+01:00/Europe/Paris
  • 2011-12-03T10:15:30+01:00|Europe/Paris
  • 2011-12-03T10:15:30 Europe/Paris (+01) (this is the default in Noda Time)

If what you're looking for is a way to include a ZonedDateTime or similar data in an API in a standardized manner, my personal recommendation would be to pass the time zone name in a separate field. That way, each portion of data is as good as it can be. For example in JSON:

{
  "timestamp": "2011-12-03T10:15:30+01:00",
  "timezone": "Europe/Paris"
}
2 of 2
26

The Answer by Matt Johnson is spot-on correct. I'll just add a few thoughts.

Time zone versus offset-from-UTC

An offset-from-UTC is merely a number of hours, minutes, and seconds ahead/behind UTC. Alone, this does make a date-time into a specific moment on the timeline. But it is not nearly as informative as including the official time zone name as well.

While there is no standard yet for including the time zone name, I do hope others follow the lead of the java.time classes in appending in square brackets the name of the time zone. This format seems sensible to me as it would be simple to truncate the square-bracket portion to be backward-compatible with non-savvy software.

For example:
2011-12-03T10:15:30+01:00[Europe/Paris]. If the data were only 2011-12-03T10:15:30+01:00, we would be able to identify the moment on the timeline, but would not be able to adjust other moments into the same frame of mind as we would not know what rules of adjustment to apply. Zones such as Europe/Zagreb, Africa/Brazzaville, Arctic/Longyearbyen, and Europe/Isle_of_Man all share the offset of +01:00, but they may well have other adjustments in force differing from those of Europe/Paris. So if you were to try to add three days to the value 2011-12-03T10:15:30+01:00, you really cannot faithfully compute the result because you do not know what adjustments may need to apply such as DST cutovers that may be occurring during those three days.

A time zone defines the set of rules for handling anomalies such as Daylight Saving Time (DST). Politicians around the world enjoy making adjustments to their time zones, or even re-defining them. So these rules change frequently. Think of a time zone as a collection of offsets over time, many periods of time in history wherein each period had a particular offset in use in that particular region.

You can think of a time zone as a collection of offset-from-UTC values. In America/Los_Angeles part of this year is 8 hours behind UTC, and part of the year will be 7 hours behind UTC. That makes 2 points of data collected as part of that time zone.

Another example, in previous years, Turkey spent part of each year 2 hours ahead of UTC and part of each year 3 hours ahead. In 2016, that changed to indefinitely staying 3 hours ahead. So, multiple points of data in the time zone Europe/Istanbul.

Just use UTC

Personally I do not see much value in even using values such as 2011-12-03T10:15:30+01:00. Without a time zone, you might just as well use UTC alone. In this case, 2011-12-03T09:15:30Z (9 AM instead of 10 AM).

Generally the best practice is to use UTC when storing and exchanging date-time values. Think of UTC as the One-True-Time, with zoned or offset values being mere variations.

🌐
UsefulAngle
usefulangle.com › post › 30 › javascript-get-date-time-with-offset-hours-minutes
How to get DateTime with Timezone Offset (8601 format) in Javascript
Javascript has a toISOString method that gives a datetime in ISO-8601 format. But it gives datetime strings only in UTC format, YYYY-MM-DDTHH:mm:ss.sssZ. It does not give a timezone offset in hours and minutes.
🌐
GitHub
gist.github.com › loilo › 736d5beaef4a96d652f585b1b678a12c
ISO 8601 date string – like Date.prototype.toISOString(), but with local timezone offset
ISO 8601 date string – like Date.prototype.toISOString(), but with local timezone offset - get-local-iso-string.js
🌐
xjavascript
xjavascript.com › blog › date-toisostring-but-local-time-instead-of-utc
How to Get Local Time ISO 8601 String in JavaScript (Instead of UTC with Date.toISOString()) — xjavascript.com
JavaScript’s Date object has no built-in method to directly return a local time ISO 8601 string. Let’s see why toISOString() isn’t sufficient: