Come posso generare una stringa formattata ISO 8601 in JavaScript?


247

Ho un Dateoggetto Come si esegue il rendering della titleparte del seguente frammento?

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

Ho la parte "tempo relativo in parole" di un'altra libreria.

Ho provato quanto segue:

function isoDate(msSinceEpoch) {

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

}

Ma questo mi dà:

"2010-4-2T3:19"

Risposte:


453

Esiste già una funzione chiamata toISOString():

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

Se, in qualche modo, sei su un browser che non lo supporta, ti ho coperto:

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

  }() );
}

1
.toISOString () restituisce definitivamente la data in UTC?
Jon Wells,

new Date("xx").toISOString()produce NaN-NaN-NaNTNaN:NaN:NaN.NZL'implementazione nativa genera RangeException.
Joseph Lennox,

Se vuoi passare un oggetto data a un servizio di sapone ... questo è il modo! :) Grazie.
thinklinux,

1
Nel campione fornito dall'OP, non ci sono millisecondi o fuso orario.
Dan Dascalescu,

Tutte quelle chiamate di funzione come "getUTCFullYear" non riescono perché non sono note alla modalità documento IE 5.
Elaskanator

63

Vedi l'ultimo esempio alla pagina 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

1
L'esempio fornito dall'OP ( <abbr title="2010-04-02T14:12:07">) non ha fuso orario. Forse volevano l'ora locale, che avrebbe senso per una stringa di tempo dell'interfaccia utente?
Dan Dascalescu,

60

Quasi tutti i metodi ISO sul Web rilasciano le informazioni sul fuso orario applicando un ulu time (UTC) convertito in "Z" prima di emettere la stringa. .ToISOString () nativo del browser elimina anche le informazioni sul fuso orario.

Ciò elimina informazioni preziose, in quanto il server o il destinatario, può sempre convertire una data ISO completa nell'ora Zulu o in qualsiasi fuso orario richiesto, pur ottenendo le informazioni sul fuso orario del mittente.

La migliore soluzione che ho incontrato è utilizzare la libreria javascript Moment.js e utilizzare il seguente codice:

Per ottenere l'ora ISO corrente con informazioni sul fuso orario e millisecondi

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() 

Per ottenere l'ora ISO di un oggetto Date JavaScript nativo con informazioni sul fuso orario ma senza millisecondi

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

Questo può essere combinato con Date.js per ottenere funzioni come Date.today () il cui risultato può quindi essere passato al momento.

Una stringa di data formattata in questo modo è compilatore JSON e si presta bene per essere archiviata in un database. Python e C # sembrano apprezzarlo.


21
non andare in giro con le persone date. Usa moment.js e risparmia i capelli.
Valamas,

1
in realtà, su Python e DB si è rivelato essere un dolore. db usa UTC (nessun problema, dato che puoi facilmente convertirlo in lato server UTC), quindi se vuoi conservare le informazioni di offset hai bisogno di un altro campo. E Python preferisce l'uso dei nanosecondi invece dei millisecondi di javascript, che di solito sono sufficienti e preferibili in pochi secondi. Su Python, solo dateutil.parser.parse lo analizza correttamente e per scrivere ISO di millisecondi è necessario un "_when = when.strftime ("% Y-% m-% dT% H:% M:% S.% f% z "); restituisce _when [: - 8] + _when [-5:]" per convertire i nanos in millis. non è carino.
Daniel F,

3
Si può effettivamente basta omettere il formato in questo modo: moment(new Date()).format(). "A partire dalla versione 1.5.0, il formato del momento # senza un formato verrà impostato automaticamente su ... il formato ISO8601 YYYY-MM-DDTHH:mm:ssZ". Doc: Scorri verso l'alto da momentjs.com/docs/#/displaying/fromnow
user193130

1
Buon punto @ user193130 ma devi davvero stare attento perché l'output differisce dal metodo nativo. moment().format() "2015-03-04T17:16:05+03:00" (new Date()).toISOString() "2015-03-04T14:16:24.555Z"
Olga

1
Forse essere pignoli ma questi esempi restituiscono l'offset corrente da UTC, non il fuso orario. Un fuso orario è una regione geografica comunemente espressa come ad esempio "America / Toronto". Molti fusi orari cambiano il loro offset UTC due volte all'anno e il fuso orario non può (sempre) essere determinato dall'attuale offset UTC ... quindi questa risposta fa cadere anche le informazioni sul fuso orario :-)
Martin Fido

27

La domanda posta era il formato ISO con precisione ridotta. Ecco:

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

Supponendo che la Z finale sia voluta, altrimenti ometti.


14

Più breve, ma non supportato da Internet Explorer 8 e precedenti:

new Date().toJSON()

12

Se non hai bisogno di supportare IE7, il seguente è un ottimo trucco conciso:

JSON.parse(JSON.stringify(new Date()))

per IE7 questa decisione è adatta anche se è stata inclusa la libreria json3 ( bestiejs.github.io/json3 ). Grazie :)
vladimir

Fallisce anche in IE8. ("'JSON' non è definito")
Cees Timmerman,

1
Andare in giro per JSON è brutto, specialmente se il tuo obiettivo dichiarato è la concisione; utilizzare toJSONinvece il metodo della data . JSON.stringifylo sta usando comunque sotto le coperte.
Mark Amery,

@CeesTimmerman IE8 supporta l' JSONoggetto, sebbene non in alcune modalità di compatibilità. Vedi stackoverflow.com/questions/4715373/…
Mark Amery

3
In che modo è meglio di .toISOString()?
Martin

7

In genere non voglio visualizzare una data UTC poiché ai clienti non piace fare la conversione nella loro testa. Per visualizzare una data ISO locale , utilizzo la funzione:

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

La funzione sopra omette le informazioni sull'offset del fuso orario (tranne se l'ora locale è UTC), quindi uso la funzione seguente per mostrare l'offset locale in una singola posizione. Puoi anche aggiungere il suo output ai risultati della funzione sopra se vuoi mostrare l'offset in ogni volta:

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

toLocalIsoStringusi pad. Se necessario, funziona come quasi tutte le funzioni dei pad, ma per completezza questo è quello che uso:

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

3

Manca un '+' dopo la 'T'

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

dovrebbe farlo.

Per gli zeri iniziali puoi usare questo da qui :

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(); 
} 

Usandolo in questo modo:

PadDigits(d.getUTCHours(),2)

Ottima cattura! Tuttavia, non risolve gli "0" mancanti.
James A. Rosen,

1
Scrivi una funzione per convertire un numero intero in una stringa di 2 caratteri (antepone uno '0' se l'argomento è inferiore a 10) e chiamalo per ogni parte della data / ora.
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);
}

1
Nella modalità IE5 ho dovuto seguire questa strada poiché tutte le altre risposte qui utilizzavano funzioni che non esistono.
Elaskanator

3

Il problema con toISOString è che fornisce datetime solo come "Z".

ISO-8601 definisce anche il datetime con la differenza di fuso orario in ore e minuti, nelle forme come 2016-07-16T19: 20: 30 + 5: 30 (quando il fuso orario è avanti UTC) e 2016-07-16T19: 20: 30-01 : 00 (quando il fuso orario è dietro UTC).

Non penso sia una buona idea usare un altro plugin, moment.js per un compito così piccolo, specialmente quando puoi ottenerlo con poche righe di codice.



    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); 

Una volta ottenuto l'offset del fuso orario in ore e minuti, è possibile aggiungere a una stringa datetime.

Ho scritto un post sul blog: http://usefulangle.com/post/30/javascript-get-date-time-with-offset-hours-minutes



2

Sono stato in grado di ottenere un output inferiore con molto meno codice.

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

Produzione:

Fri Apr 02 2010 19:42 hrs

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

Ho trovato le basi su Stack Overflow da qualche parte (credo che facesse parte di alcuni altri giochi di golf con Stack Exchange) e l'ho migliorato in modo che funzioni anche su Internet Explorer 10 o versioni precedenti. È brutto, ma fa il lavoro.


0

Per estendere la risposta grande e concisa di Sean con un po 'di zucchero e sintassi moderna:

// 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;

Quindi ad es.

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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.