Comment sortir une chaîne au format ISO 8601 en JavaScript?

247

J'ai un Dateobjet. Comment rendre la titlepartie de l'extrait de code suivant?

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

J'ai la partie "temps relatif en mots" d'une autre bibliothèque.

J'ai essayé ce qui suit:

function isoDate(msSinceEpoch) {

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

}

Mais cela me donne:

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

Réponses:

453

Il existe déjà une fonction appelée toISOString():

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

Si, d'une manière ou d'une autre, vous utilisez un navigateur qui ne le prend pas en charge, je vous ai couvert:

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
la source
1
.toISOString () renvoie définitivement la date en UTC?
Jon Wells
new Date("xx").toISOString()produit NaN-NaN-NaNTNaN:NaN:NaN.NZL'implémentation native lève RangeException.
Joseph Lennox
Si vous voulez passer un objet date à un service soap ... c'est comme ça! :) Merci.
thinklinux
1
Dans l'échantillon fourni par l'OP, il n'y a ni millisecondes ni fuseau horaire.
Dan Dascalescu
Tous ces appels de fonction comme "getUTCFullYear" échouent car ils ne sont pas connus du document IE mode 5.
Elaskanator
63

Voir le dernier exemple à la 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
dev-null-dweller
la source
1
L'échantillon fourni par l'OP ( <abbr title="2010-04-02T14:12:07">) n'a pas de fuseau horaire. Peut-être qu'ils voulaient l'heure locale, ce qui aurait du sens pour une chaîne horaire d'interface utilisateur?
Dan Dascalescu
60

Presque toutes les méthodes to-ISO sur le Web suppriment les informations de fuseau horaire en appliquant une conversion en temps ulu "Z" (UTC) avant de sortir la chaîne. Le navigateur natif .toISOString () supprime également les informations de fuseau horaire.

Cela supprime des informations précieuses, car le serveur ou le destinataire peut toujours convertir une date ISO complète en heure zoulou ou selon le fuseau horaire requis, tout en obtenant les informations de fuseau horaire de l'expéditeur.

La meilleure solution que j'ai rencontrée consiste à utiliser la bibliothèque javascript Moment.js et à utiliser le code suivant:

Pour obtenir l'heure ISO actuelle avec des informations de fuseau horaire et des millisecondes

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

Pour obtenir l'heure ISO d'un objet Date JavaScript natif avec des informations de fuseau horaire mais sans millisecondes

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

Ceci peut être combiné avec Date.js pour obtenir des fonctions comme Date.today () dont le résultat peut ensuite être passé à moment.

Une chaîne de date formatée comme celle-ci est compilante JSON et se prête bien à être stockée dans une base de données. Python et C # semblent l'aimer.

Daniel F
la source
21
ne pas bourrer de dates avec les gens. Utilisez simplement moment.js et enregistrez vos cheveux.
Valamas
1
en fait, sur python et db, cela s'est avéré être une douleur. db utilise UTC (pas de problème, car vous pouvez facilement le convertir en serveur UTC), donc si vous souhaitez conserver les informations de décalage, vous avez besoin d'un autre champ. Et Python préfère l'utilisation des nanosecondes au lieu des millisecondes de javascript, qui sont généralement suffisantes et préférables en quelques secondes. Sur python, seul dateutil.parser.parse l' analyse correctement, et pour écrire celui de l'ISO en millisecondes, il faut un "_when = when.strftime ("% Y-% m-% dT% H:% M:% S.% f% z "); renvoie _when [: - 8] + _when [-5:]" pour convertir les nanos en millis. c'est pas gentil.
Daniel F
3
Vous pouvez réellement omettre simplement le format comme ceci: moment(new Date()).format(). "A partir de la version 1.5.0, l'appel du format moment # sans format sera par défaut ... le format ISO8601 YYYY-MM-DDTHH:mm:ssZ". Doc: faites défiler vers le haut à partir de momentjs.com/docs/#/displaying/fromnow
user193130
1
Bon point @ user193130 mais vous devez vraiment faire attention car la sortie diffère de la méthode native. moment().format() "2015-03-04T17:16:05+03:00" (new Date()).toISOString() "2015-03-04T14:16:24.555Z"
Olga
1
Peut-être difficile, mais ces exemples renvoient le décalage actuel par rapport à UTC, pas le fuseau horaire. Un fuseau horaire est une région géographique communément exprimée par exemple "Amérique / Toronto". De nombreux fuseaux horaires changent leur décalage UTC deux fois par an et le fuseau horaire ne peut pas (toujours) être déterminé à partir du décalage UTC actuel ... ainsi cette réponse supprime également les informations de fuseau horaire :-)
Martin Fido
27

La question posée était le format ISO avec une précision réduite. Voila:

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

En supposant que le Z de fin est voulu, sinon omettez simplement.

arcseldon
la source
14

Plus court, mais non pris en charge par Internet Explorer 8 et versions antérieures:

new Date().toJSON()
younes0
la source
12

Si vous n'avez pas besoin de prendre en charge IE7, voici un excellent hack concis:

JSON.parse(JSON.stringify(new Date()))
Russell Davis
la source
pour IE7, cette décision est également valable si json3-library était incluse ( bestiejs.github.io/json3 ). Merci :)
Vladimir
Échoue également dans IE8. ("'JSON' n'est pas défini")
Cees Timmerman
1
Les allers-retours via JSON sont laids, surtout si votre objectif déclaré est la concision; utilisez toJSONplutôt la méthode de la date . JSON.stringifyl'utilise de toute façon sous les couvertures.
Mark Amery
@CeesTimmerman IE8 prend en charge l' JSONobjet, mais pas dans certains modes de compatibilité. Voir stackoverflow.com/questions/4715373/…
Mark Amery
3
En quoi est-ce mieux que ça .toISOString()?
Martin
7

Je ne veux généralement pas afficher de date UTC car les clients n'aiment pas faire la conversion dans leur tête. Pour afficher une date ISO locale , j'utilise la fonction:

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 fonction ci-dessus omet les informations de décalage de fuseau horaire (sauf si l'heure locale se trouve être UTC), j'utilise donc la fonction ci-dessous pour afficher le décalage local dans un seul emplacement. Vous pouvez également ajouter sa sortie aux résultats de la fonction ci-dessus si vous souhaitez afficher le décalage à chaque fois:

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

toLocalIsoStringutilise pad. Si nécessaire, cela fonctionne comme presque n'importe quelle fonction de pad, mais pour être complet, voici ce que j'utilise:

// 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
la source
3

Il manque un «+» après le «T»

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

devrait le faire.

Pour les zéros principaux, vous pouvez utiliser ceci à partir d' ici :

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

L'utiliser comme ceci:

PadDigits(d.getUTCHours(),2)
kaiz.net
la source
Superbe capture! Cependant, il ne corrige pas les "0" manquants.
James A. Rosen
1
Écrivez une fonction pour convertir un entier en une chaîne de 2 caractères (en ajoutant un «0» si l'argument est inférieur à 10) et appelez-le pour chaque partie de la date / heure.
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
la source
1
En mode IE5, j'ai dû suivre cette voie car toutes les autres réponses ici utilisaient des fonctions qui n'existent pas.
Elaskanator
3

Le problème avec toISOString est qu'il ne donne la date / heure qu'en "Z".

ISO-8601 définit également l'heure et la différence de fuseau horaire en heures et minutes, sous les formes comme 2016-07-16T19: 20: 30 + 5: 30 (lorsque le fuseau horaire est en avance UTC) et 2016-07-16T19: 20: 30-01 : 00 (lorsque le fuseau horaire est derrière UTC).

Je ne pense pas que ce soit une bonne idée d'utiliser un autre plugin, moment.js pour une si petite tâche, surtout quand vous pouvez l'obtenir avec quelques lignes de code.



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

Une fois que vous avez décalé le fuseau horaire en heures et minutes, vous pouvez l'ajouter à une chaîne datetime.

J'ai écrit un article de blog à ce sujet: http://usefulangle.com/post/30/javascript-get-date-time-with-offset-hours-minutes

Angle utile
la source
2

J'ai pu obtenir une sortie en dessous avec très moins de code.

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

Production:

Fri Apr 02 2010 19:42 hrs
Srikanth Srikanth
la source
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');
}

J'ai trouvé les bases de Stack Overflow quelque part (je pense que cela faisait partie d'un autre code de Stack Exchange au golf), et je l'ai amélioré pour qu'il fonctionne sur Internet Explorer 10 ou une version antérieure également. C'est moche, mais ça fait le boulot.

Jonas Byström
la source
0

Pour étendre la grande réponse concise de Sean avec du sucre et une syntaxe moderne:

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

Ensuite, par exemple.

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
la source