186 votes

Comment formater une date au format ISO 8601 avec un décalage de fuseau horaire en JavaScript ?

Objectif : Trouvez le local time y UTC time offset puis construire l'URL dans le format suivant.

Exemple d'URL : /Actions/Sleep?duration=2002-10-10T12:00:0005:00

Le format est basé sur le Recommandation du W3C . La documentation dit :

Par exemple, 2002-10-10T12:00:0005:00 (midi le 10 octobre 2002, heure d'été centrale et heure normale de l'Est aux États-Unis) est égal à 2002-10-10T17:00:00Z, soit cinq heures plus tard que 2002-10-10T12:00:00Z.

Donc, d'après ce que j'ai compris, je dois trouver mon heure locale en new Date() puis utiliser getTimezoneOffset() pour calculer la différence et l'attacher à la fin de la chaîne.

  1. Obtenez l'heure locale avec format

    var local = new Date().format("yyyy-MM-ddThh:mm:ss"); // 2013-07-02T09:00:00
  2. Obtenir l'heure UTC décalée d'une heure

    var offset = local.getTimezoneOffset() / 60; // 7
  3. Construct URL (à temps partiel uniquement)

    var duration = local + "-" + offset + ":00"; // 2013-07-02T09:00:00-7:00

La sortie ci-dessus signifie que mon heure locale est 2013/07/02 9h00 et que la différence avec l'UTC est de 7 heures (l'UTC est en avance de 7 heures sur l'heure locale).

Jusqu'à présent, cela semble fonctionner, mais que faire si getTimezoneOffset() renvoie une valeur négative comme -120 ?

Je me demande à quoi devrait ressembler le format dans un tel cas, car je n'arrive pas à le comprendre à partir de la documentation du W3C.

7voto

Nahuel Greco Points 137

Regarde ça :

function dateToLocalISO(date) {
    const off    = date.getTimezoneOffset()
    const absoff = Math.abs(off)
    return (new Date(date.getTime() - off*60*1000).toISOString().substr(0,23) +
            (off > 0 ? '-' : '+') + 
            Math.floor(absoff / 60).toFixed(0).padStart(2,'0') + ':' + 
            (absoff % 60).toString().padStart(2,'0'))
}

// Test it:
d = new Date()

dateToLocalISO(d)
// ==> '2019-06-21T16:07:22.181-03:00'

// Is similar to:

moment = require('moment')
moment(d).format('YYYY-MM-DDTHH:mm:ss.SSSZ') 
// ==> '2019-06-21T16:07:22.181-03:00'

5voto

Extragorey Points 616

Vous pouvez y parvenir grâce à quelques méthodes d'extension simples. La méthode d'extension Date suivante renvoie uniquement le composant de fuseau horaire au format ISO, puis vous pouvez en définir une autre pour la partie date/heure et les combiner pour obtenir une chaîne complète date-heure-décalage.

Date.prototype.getISOTimezoneOffset = function () {
    const offset = this.getTimezoneOffset();
    return (offset < 0 ? "+" : "-") + Math.floor(Math.abs(offset / 60)).leftPad(2) + ":" + (Math.abs(offset % 60)).leftPad(2);
}

Date.prototype.toISOLocaleString = function () {
    return this.getFullYear() + "-" + (this.getMonth() + 1).leftPad(2) + "-" +
        this.getDate().leftPad(2) + "T" + this.getHours().leftPad(2) + ":" +
        this.getMinutes().leftPad(2) + ":" + this.getSeconds().leftPad(2) + "." +
        this.getMilliseconds().leftPad(3);
}

Number.prototype.leftPad = function (size) {
    var s = String(this);
    while (s.length < (size || 2)) {
        s = "0" + s;
    }
    return s;
}

Exemple d'utilisation :

var date = new Date();
console.log(date.toISOLocaleString() + date.getISOTimezoneOffset());
// Prints "2020-08-05T16:15:46.525+10:00"

Je sais que nous sommes en 2020 et que la plupart des gens utilisent probablement Moment.js à l'heure actuelle, mais une solution simple de copier/coller est toujours pratique à avoir.

(La raison pour laquelle j'ai divisé les méthodes de date/heure et de décalage est que j'utilise une ancienne méthode de calcul de l'heure. Datejs qui fournit déjà un système flexible de toString avec des spécificateurs de format personnalisés, mais n'inclut pas le décalage du fuseau horaire. J'ai donc ajouté toISOLocaleString pour ceux qui n'ont pas cette bibliothèque).

4voto

Arnold Gandarillas Points 1780

Juste mes deux cents ici

J'étais confronté à ce problème avec les dates, alors voici ce que j'ai fait :

const moment = require('moment-timezone')

const date = moment.tz('America/Bogota').format()

Puis enregistrer la date dans la base de données pour pouvoir la comparer à partir d'une requête.


Pour installer moment-timezone

npm i moment-timezone

3voto

Captain Fantastic Points 170

Pas besoin de moment.js : Voici une réponse complète en aller-retour, d'un entrée type de "datetime-local" qui produit une chaîne ISOLocal en UTCsecondes à GMT et inversement :

<input type="datetime-local" value="2020-02-16T19:30">

isoLocal="2020-02-16T19:30"
utcSeconds=new Date(isoLocal).getTime()/1000

//here you have 1581899400 for utcSeconds

let isoLocal=new Date(utcSeconds*1000-new Date().getTimezoneOffset()*60000).toISOString().substring(0,16)
2020-02-16T19:30

2voto

OhadR Points 1180

Envisager d'utiliser un moment (comme Réponse de Matt ).

De la version 2.20.0 vous pouvez appeler .toISOString(true) pour empêcher la conversion UTC :

console.log(moment().toISOString(true));

// sample output:   2022-04-06T16:26:36.758+03:00

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X