Wie gebe ich eine nach ISO 8601 formatierte Zeichenfolge in JavaScript aus?

247

Ich habe ein DateObjekt. Wie rendere ich den titleTeil des folgenden Snippets?

<abbr title="2010-04-02T14:12:07">A couple days ago</abbr>

Ich habe den Teil "Relative Zeit in Worten" aus einer anderen Bibliothek.

Ich habe folgendes versucht:

function isoDate(msSinceEpoch) {

   var d = new Date(msSinceEpoch);
   return d.getUTCFullYear() + '-' + (d.getUTCMonth() + 1) + '-' + d.getUTCDate() + 'T' +
          d.getUTCHours() + ':' + d.getUTCMinutes() + ':' + d.getUTCSeconds();

}

Aber das gibt mir:

"2010-4-2T3:19"
James A. Rosen
quelle

Antworten:

453

Es gibt bereits eine Funktion namens toISOString():

var date = new Date();
date.toISOString(); //"2011-12-19T15:28:46.493Z"

Wenn Sie sich in einem Browser befinden , der dies nicht unterstützt, sind Sie hier genau richtig:

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';
    };

  }() );
}
Anatoly Mironov
quelle
1
.toISOString () gibt definitiv das Datum in UTC zurück?
Jon Wells
new Date("xx").toISOString()produziert NaN-NaN-NaNTNaN:NaN:NaN.NZdie native Implementierung wirft RangeException.
Joseph Lennox
Wenn Sie ein Datumsobjekt an einen Seifendienst übergeben möchten, ist dies der richtige Weg! :) Vielen Dank.
thinklinux
1
In der vom OP bereitgestellten Stichprobe gibt es keine Millisekunden oder Zeitzonen.
Dan Dascalescu
Alle diese Funktionsaufrufe wie "getUTCFullYear" schlagen fehl, weil sie dem IE-Dokumentmodus 5 nicht bekannt sind.
Elaskanator
63

Siehe das letzte Beispiel auf Seite 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
Dev-Null-Bewohner
quelle
1
Die vom OP ( <abbr title="2010-04-02T14:12:07">) bereitgestellte Stichprobe hat keine Zeitzone. Vielleicht wollten sie die Ortszeit, was für eine UI-Zeitzeichenfolge sinnvoll wäre?
Dan Dascalescu
60

Nahezu jede ISO-Methode im Web löscht die Zeitzoneninformationen, indem vor der Ausgabe der Zeichenfolge eine Konvertierung in die "U" -Ulu-Zeit (UTC) angewendet wird. Die native .toISOString () des Browsers löscht auch Zeitzoneninformationen.

Dadurch werden wertvolle Informationen verworfen, da der Server oder Empfänger jederzeit ein vollständiges ISO-Datum in die Zulu-Zeit oder die erforderliche Zeitzone konvertieren kann, während die Zeitzoneninformationen des Absenders abgerufen werden.

Die beste Lösung, auf die ich gestoßen bin, besteht darin, die Javascript-Bibliothek von Moment.js zu verwenden und den folgenden Code zu verwenden:

Um die aktuelle ISO-Zeit mit Zeitzoneninformationen und Millisekunden abzurufen

now = moment().format("YYYY-MM-DDTHH:mm:ss.SSSZZ")
// "2013-03-08T20:11:11.234+0100"

now = moment().utc().format("YYYY-MM-DDTHH:mm:ss.SSSZZ")
// "2013-03-08T19:11:11.234+0000"

now = moment().utc().format("YYYY-MM-DDTHH:mm:ss") + "Z"
// "2013-03-08T19:11:11Z" <- better use the native .toISOString() 

Abrufen der ISO-Zeit eines nativen JavaScript-Datumsobjekts mit Zeitzoneninformationen, jedoch ohne Millisekunden

var current_time = Date.now();
moment(current_time).format("YYYY-MM-DDTHH:mm:ssZZ")

Dies kann mit Date.js kombiniert werden, um Funktionen wie Date.today () zu erhalten, deren Ergebnis dann an moment übergeben werden kann.

Eine so formatierte Datumszeichenfolge ist JSON-Compilant und eignet sich gut zum Speichern in einer Datenbank. Python und C # scheinen es zu mögen.

Daniel F.
quelle
21
Mach dir keine Sorgen mit Datteln. Verwenden Sie einfach moment.js und retten Sie Ihre Haare.
Valamas
1
Auf Python und DBs stellte sich heraus, dass es ein Schmerz war. DBs verwenden UTC (kein Problem, da Sie problemlos auf UTC-Serverseite konvertieren können). Wenn Sie also die Offset-Informationen beibehalten möchten, benötigen Sie ein anderes Feld. Und Python bevorzugt die Verwendung von Nanosekunden anstelle der Millisekunden von Javascript, die normalerweise ausreichen und gegenüber einfachen Sekunden vorzuziehen sind. In Python analysiert nur dateutil.parser.parse es korrekt, und um Millisekunden-ISO-Werte zu schreiben, ist ein "_when = when.strftime" (% Y-% m-% dT% H:% M:% S.% f% z erforderlich "); return _when [: - 8] + _when [-5:]", um die Nanos in Millis umzuwandeln. das ist nicht nett.
Daniel F
3
Sie können das Format einfach so weglassen : moment(new Date()).format(). "Ab Version 1.5.0 wird beim Aufrufen des Moment # -Formats ohne Format standardmäßig ... das ISO8601-Format verwendet. YYYY-MM-DDTHH:mm:ssZ" Doc: Scrollen
Sie
1
Guter Punkt @ user193130, aber Sie müssen wirklich vorsichtig sein, da sich die Ausgabe von der nativen Methode unterscheidet. moment().format() "2015-03-04T17:16:05+03:00" (new Date()).toISOString() "2015-03-04T14:16:24.555Z"
Olga
1
Vielleicht wählerisch, aber diese Beispiele geben den aktuellen Offset von UTC zurück, nicht die Zeitzone. Eine Zeitzone ist eine geografische Region, die üblicherweise als "Amerika / Toronto" ausgedrückt wird. Viele Zeitzonen ändern ihren UTC-Versatz zweimal im Jahr und die Zeitzone kann nicht (immer) aus dem aktuellen UTC-Versatz bestimmt werden ... daher werden bei dieser Antwort auch die Zeitzoneninformationen gelöscht :-)
Martin Fido
27

Die gestellte Frage war das ISO-Format mit reduzierter Genauigkeit. Voila:

 new Date().toISOString().slice(0, 19) + 'Z'
 // '2014-10-23T13:18:06Z'

Angenommen, das nachfolgende Z wird gewünscht, andernfalls einfach weglassen.

arcseldon
quelle
14

Kürzeste, aber von Internet Explorer 8 und früheren Versionen nicht unterstützte:

new Date().toJSON()
younes0
quelle
12

Wenn Sie IE7 nicht unterstützen müssen, ist das Folgende ein großartiger, prägnanter Hack:

JSON.parse(JSON.stringify(new Date()))
Russell Davis
quelle
Für IE7 ist diese Entscheidung auch geeignet, wenn json3-library ( bestiejs.github.io/json3 ) enthalten war. Danke :)
Vladimir
Scheitert auch in IE8. ("'JSON' ist undefiniert")
Cees Timmerman
1
Roundtrips durch JSON sind hässlich, insbesondere wenn Ihr erklärtes Ziel Prägnanz ist. Verwenden Sie toJSONstattdessen die Datumsmethode. JSON.stringifybenutzt es sowieso unter der Decke.
Mark Amery
@CeesTimmerman IE8 unterstützt das JSONObjekt, jedoch nicht in einigen Kompatibilitätsmodi. Siehe stackoverflow.com/questions/4715373/…
Mark Amery
3
Inwiefern ist das besser als .toISOString()?
Martin
7

Normalerweise möchte ich kein UTC-Datum anzeigen, da Kunden die Konvertierung nicht gerne in ihrem Kopf durchführen. Um ein lokales ISO-Datum anzuzeigen , verwende ich die Funktion:

function toLocalIsoString(date, includeSeconds) {
    function pad(n) { return n < 10 ? '0' + n : n }
    var localIsoString = date.getFullYear() + '-'
        + pad(date.getMonth() + 1) + '-'
        + pad(date.getDate()) + 'T'
        + pad(date.getHours()) + ':'
        + pad(date.getMinutes()) + ':'
        + pad(date.getSeconds());
    if(date.getTimezoneOffset() == 0) localIsoString += 'Z';
    return localIsoString;
};

Bei der obigen Funktion werden Informationen zum Zeitzonenversatz weggelassen (außer wenn die Ortszeit zufällig UTC ist). Daher verwende ich die folgende Funktion, um den lokalen Versatz an einem einzelnen Ort anzuzeigen. Sie können die Ausgabe auch an die Ergebnisse der obigen Funktion anhängen, wenn Sie den Versatz jedes Mal anzeigen möchten:

function getOffsetFromUTC() {
    var offset = new Date().getTimezoneOffset();
    return ((offset < 0 ? '+' : '-')
        + pad(Math.abs(offset / 60), 2)
        + ':'
        + pad(Math.abs(offset % 60), 2))
};

toLocalIsoStringverwendet pad. Bei Bedarf funktioniert es wie fast jede Pad-Funktion, aber der Vollständigkeit halber verwende ich Folgendes:

// Pad a number to length using padChar
function pad(number, length, padChar) {
    if (typeof length === 'undefined') length = 2;
    if (typeof padChar === 'undefined') padChar = '0';
    var str = "" + number;
    while (str.length < length) {
        str = padChar + str;
    }
    return str;
}
Charles Burns
quelle
3

Nach dem 'T' fehlt ein '+'.

isoDate: function(msSinceEpoch) {
  var d = new Date(msSinceEpoch);
  return d.getUTCFullYear() + '-' + (d.getUTCMonth() + 1) + '-' + d.getUTCDate() + 'T'
         + d.getUTCHours() + ':' + d.getUTCMinutes() + ':' + d.getUTCSeconds();
}

Sollte es tun.

Für die führenden Nullen können Sie dies von hier aus verwenden :

function PadDigits(n, totalDigits) 
{ 
    n = n.toString(); 
    var pd = ''; 
    if (totalDigits > n.length) 
    { 
        for (i=0; i < (totalDigits-n.length); i++) 
        { 
            pd += '0'; 
        } 
    } 
    return pd + n.toString(); 
} 

Verwenden Sie es so:

PadDigits(d.getUTCHours(),2)
kaiz.net
quelle
Großer Fang! Die fehlenden "0" werden jedoch nicht angesprochen.
James A. Rosen
1
Schreiben Sie eine Funktion zum Konvertieren einer Ganzzahl in eine 2-stellige Zeichenfolge (stellen Sie eine '0' voran, wenn das Argument kleiner als 10 ist) und rufen Sie sie für jeden Teil des Datums / der Uhrzeit auf.
dan04
3
function timeStr(d) { 
  return ''+
    d.getFullYear()+
    ('0'+(d.getMonth()+1)).slice(-2)+
    ('0'+d.getDate()).slice(-2)+
    ('0'+d.getHours()).slice(-2)+
    ('0'+d.getMinutes()).slice(-2)+
    ('0'+d.getSeconds()).slice(-2);
}
Sean
quelle
1
Im IE5-Modus musste ich diesen Weg gehen, da alle anderen Antworten hier Funktionen verwendeten, die es nicht gibt.
Elaskanator
3

Das Problem mit toISOString ist, dass datetime nur als "Z" angegeben wird.

ISO-8601 definiert auch Datum und Uhrzeit mit Zeitzonenunterschied in Stunden und Minuten in Form von 2016-07-16T19: 20: 30 + 5: 30 (wenn die Zeitzone vor UTC liegt) und 2016-07-16T19: 20: 30-01 : 00 (wenn die Zeitzone hinter UTC liegt).

Ich denke nicht, dass es eine gute Idee ist, ein anderes Plugin, moment.js, für eine so kleine Aufgabe zu verwenden, besonders wenn Sie es mit ein paar Codezeilen bekommen können.



    var timezone_offset_min = new Date().getTimezoneOffset(),
        offset_hrs = parseInt(Math.abs(timezone_offset_min/60)),
        offset_min = Math.abs(timezone_offset_min%60),
        timezone_standard;

    if(offset_hrs < 10)
        offset_hrs = '0' + offset_hrs;

    if(offset_min > 10)
        offset_min = '0' + offset_min;

    // getTimezoneOffset returns an offset which is positive if the local timezone is behind UTC and vice-versa.
    // So add an opposite sign to the offset
    // If offset is 0, it means timezone is UTC
    if(timezone_offset_min < 0)
        timezone_standard = '+' + offset_hrs + ':' + offset_min;
    else if(timezone_offset_min > 0)
        timezone_standard = '-' + offset_hrs + ':' + offset_min;
    else if(timezone_offset_min == 0)
        timezone_standard = 'Z';

    // Timezone difference in hours and minutes
    // String such as +5:30 or -6:00 or Z
    console.log(timezone_standard); 

Sobald Sie den Zeitzonenversatz in Stunden und Minuten festgelegt haben, können Sie ihn an eine Datums- / Uhrzeitzeichenfolge anhängen.

Ich habe einen Blog-Beitrag darüber geschrieben: http://usefulangle.com/post/30/javascript-get-date-time-with-offset-hours-minutes

Nützlicher Winkel
quelle
2

Ich konnte mit sehr wenig Code unter die Ausgabe kommen.

var ps = new Date('2010-04-02T14:12:07')  ;
ps = ps.toDateString() + " " + ps.getHours() + ":"+ ps.getMinutes() + " hrs";

Ausgabe:

Fri Apr 02 2010 19:42 hrs
Srikanth Srikanth
quelle
0
function getdatetime() {
    d = new Date();
    return (1e3-~d.getUTCMonth()*10+d.toUTCString()+1e3+d/1)
        .replace(/1(..)..*?(\d+)\D+(\d+).(\S+).*(...)/,'$3-$1-$2T$4.$5Z')
        .replace(/-(\d)T/,'-0$1T');
}

Ich habe die Grundlagen zu Stack Overflow irgendwo gefunden (ich glaube, es war Teil eines anderen Stack Exchange-Code-Golfspiels) und es verbessert, damit es auch in Internet Explorer 10 oder früher funktioniert. Es ist hässlich, aber es erledigt den Job.

Jonas Byström
quelle
0

Um Seans großartige und prägnante Antwort mit etwas Zucker und moderner Syntax zu erweitern:

// date.js

const getMonthName = (num) => {
  const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Oct', 'Nov', 'Dec'];
  return months[num];
};

const formatDate = (d) => {
  const date = new Date(d);
  const year = date.getFullYear();
  const month = getMonthName(date.getMonth());
  const day = ('0' + date.getDate()).slice(-2);
  const hour = ('0' + date.getHours()).slice(-2);
  const minutes = ('0' + date.getMinutes()).slice(-2);

  return `${year} ${month} ${day}, ${hour}:${minutes}`;
};

module.exports = formatDate;

Dann zB.

import formatDate = require('./date');

const myDate = "2018-07-24T13:44:46.493Z"; // Actual value from wherever, eg. MongoDB date
console.log(formatDate(myDate)); // 2018 Jul 24, 13:44
Juha Untinen
quelle