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 OverflowIt'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());
old_date = Fri Jan 08 2021 16:01:30 GMT+0900
const new_date = old_date.toISOString().substring(0, 10);
new_date = "2021-01-08"
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. Of course it always raises the question "local time where?"...
The zone designator is empty if use is made of local time in accordance with 4.2.2.2 through 4.2.2.4, it is the UTC designator [Z] if use is made of UTC of day in accordance with 4.2.4 and it is the difference-component if use is made of local time and the difference from UTC in accordance with 4.2.5.2.
Without the timezone designator, the datetime string will be interpreted as local time -- but as local time to the SERVER.
If your users are in different timezones, the dates they submit without TZ information will be interpreted incorrectly with your local TZ offset.
moment.js is great but sometimes you don't want to pull a large number of dependencies for simple things.
The following works as well:
var tzoffset = (new Date()).getTimezoneOffset() * 60000; //offset in milliseconds
var localISOTime = (new Date(Date.now() - tzoffset)).toISOString().slice(0, -1);
console.log(localISOTime) // => '2015-01-26T06:40:36.181'
The slice(0, -1) gets rid of the trailing Z which represents Zulu timezone and can be replaced by your own.
My solution without using moment is to convert it to a timestamp, add the timezone offset, then convert back to a date object, and then run the toISOString()
var date = new Date(); // Or the date you'd like converted.
var isoDateTime = new Date(date.getTime() - (date.getTimezoneOffset() * 60000)).toISOString();
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));
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.
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...
Hey. I was reading about the ISO 8601 and loved it, but the local time confuse me hahaha.
How I write down the local hour? I learned that if I used 'Z' on the final of the date It means UTC.
Here where I live is -3GMT, how can I transform today (2022-03-31T09:45:30) into ISO8601 showing my local hour?
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
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
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/Paris2011-12-03T10:15:30+01:00 - Europe/Paris2011-12-03T10:15:30+01:00/Europe/Paris2011-12-03T10:15:30+01:00|Europe/Paris2011-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"
}
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.
There is already a function called toISOString():
var date = new Date();
date.toISOString(); //"2011-12-19T15:28:46.493Z"
If, somehow, you're on a browser that doesn't support it, I've got you covered:
if (!Date.prototype.toISOString) {
(function() {
function pad(number) {
var r = String(number);
if (r.length === 1) {
r = '0' + r;
}
return r;
}
Date.prototype.toISOString = function() {
return this.getUTCFullYear() +
'-' + pad(this.getUTCMonth() + 1) +
'-' + pad(this.getUTCDate()) +
'T' + pad(this.getUTCHours()) +
':' + pad(this.getUTCMinutes()) +
':' + pad(this.getUTCSeconds()) +
'.' + String((this.getUTCMilliseconds() / 1000).toFixed(3)).slice(2, 5) +
'Z';
};
}());
}
console.log(new Date().toISOString())
See the last example on page https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference:Global_Objects:Date:
/* Use a function for the exact format desired... */
function ISODateString(d) {
function pad(n) {return n<10 ? '0'+n : n}
return d.getUTCFullYear()+'-'
+ pad(d.getUTCMonth()+1)+'-'
+ pad(d.getUTCDate())+'T'
+ pad(d.getUTCHours())+':'
+ pad(d.getUTCMinutes())+':'
+ pad(d.getUTCSeconds())+'Z'
}
var d = new Date();
console.log(ISODateString(d)); // Prints something like 2009-09-28T19:03:12Z