web-dev-qa-db-fra.com

Comment initialiser une date JavaScript à un fuseau horaire particulier

J'ai l'heure de la date dans un fuseau horaire particulier sous forme de chaîne et je souhaite convertir cela en heure locale. Mais, je ne sais pas comment définir le fuseau horaire dans l'objet Date.

Par exemple, j'ai Feb 28 2013 7:00 PM ET, alors je peux 

var mydate = new Date();
mydate.setFullYear(2013);
mydate.setMonth(02);
mydate.setDate(28);
mydate.setHours(7);
mydate.setMinutes(00);  

Autant que je sache, je peux définir l'heure UTC ou l'heure locale. Mais comment régler l'heure dans un autre fuseau horaire? 

J'ai essayé d'utiliser l'addition/la soustraction du décalage de l'heure UTC mais je ne sais pas comment contrer l'heure d'été. Je ne sais pas si je me dirige dans la bonne direction. 

Comment puis-je convertir en javascript l'heure d'un fuseau horaire différent en heure locale?

113
pavanred

Contexte

L'objet Date de JavaScript suit le temps en UTC en interne, mais accepte généralement les entrées et les sorties à l'heure locale de l'ordinateur sur lequel il est exécuté. Il ne dispose pas d'installations pour travailler avec l'heure dans d'autres fuseaux horaires. Il peut analyser et afficher les dates au format UTC ou Local, mais il ne peut pas fonctionner directement avec d'autres fuseaux horaires.

Pour être tout à fait précis, la représentation interne d'un objet Date est un nombre unique représentant le nombre de millisecondes écoulées depuis 1970-01-01 00:00:00 UTC, sans tenir compte des secondes intercalaires. Il n'y a pas de fuseau horaire ni de format de chaîne stockés dans l'objet Date lui-même. Lorsque différentes fonctions de l'objet Date sont utilisées, le fuseau horaire local de l'ordinateur est appliqué à la représentation interne. Si la fonction génère une chaîne, les informations sur les paramètres régionaux de l'ordinateur peuvent être prises en compte pour déterminer comment produire cette chaîne. Les détails varient selon les fonctions et certains sont spécifiques à la mise en œuvre.

Bibliothèques

Heureusement, certaines bibliothèques peuvent être utilisées pour travailler avec des fuseaux horaires. Bien qu'ils ne puissent toujours pas modifier le comportement de l'objet Date, ils implémentent généralement la base de données de fuseaux horaires Olson/IANA standard et fournissent des fonctions permettant de l'utiliser en JavaScript. Certains ont des frais généraux si vous utilisez un navigateur Web, car la base de données peut devenir un peu volumineuse si vous voulez tout. Heureusement, nombre de ces bibliothèques vous permettent de choisir de manière sélective les zones que vous souhaitez prendre en charge, ce qui rend la taille des données beaucoup plus agréable. De plus, certains utilisent des fonctionnalités modernes pour obtenir des données de fuseau horaire à partir de l'API Intl au lieu de les envoyer eux-mêmes.

À ma connaissance, il existe plusieurs bibliothèques pour cela:

Luxon est probablement le pari le plus sûr pour toutes les utilisations modernes et son poids le plus léger, car il utilise l'API Intl pour ses données de fuseau horaire.

Moment-timezone est une extension de moment.js et apporte ses propres données de fuseau horaire.

js-joda est une implémentation JavaScript de l'API Joda-Time (à partir de Java) et comprend la prise en charge du fuseau horaire via un module séparé.

date-fns-tz est une extension de date-fns 2.x. date-fns-timezone est une extension de date-fns 1.x.

BigEasy/TimeZone semble également être sur la bonne voie.

WallTime-js a atteint la fin de sa vie , et les propriétaires migrent vers l'instant-timezone.

TimeZoneJS a été le plus long, mais est connu pour avoir des bogues de longue date, en particulier près des transitions de l'heure d'été. Espérons que ces problèmes seront corrigés à un moment donné dans l’avenir.

tz.js existe également depuis un certain temps, mais n'est pas très bien documenté, à mon humble avis.

Vous devriez évaluer ces bibliothèques pour voir laquelle répondra à vos besoins. Si vous n'êtes pas sûr, allez avec moment/moment-fuseau horaire.

Prise en charge native dans les navigateurs modernes

Si vous pouvez limiter votre utilisation aux navigateurs Web modernes, vous pouvez désormais effectuer les opérations suivantes sans bibliothèques spéciales:

new Date().toLocaleString("en-US", {timeZone: "America/New_York"})

Ce n'est pas une solution complète, mais cela fonctionne pour de nombreux scénarios qui nécessitent uniquement une conversion de sortie (de l'heure UTC ou locale à un fuseau horaire spécifique, mais pas dans l'autre sens). Cela fait partie de l’API d’internationalisation ECMAScript (ECMA-402). Voir cet article pour plus de détails. Ce tableau de compatibilité suit les versions prises en charge. Il s'agit de l'API Intl mentionnée ci-dessus que certaines bibliothèques utilisent en interne maintenant.

Propositions futures

La proposition temporelle TC39 vise à fournir un nouvel ensemble d'objets standard permettant de travailler avec des dates et des heures dans le langage JavaScript lui-même. Cela inclura la prise en charge d'un objet sensible au fuseau horaire.

196
Matt Johnson

Vous pouvez spécifier un décalage de fuseau horaire sur new Date(), par exemple:

new Date('Feb 28 2013 19:00:00 EST')

ou

new Date('Feb 28 2013 19:00:00 GMT-0500')

Puisque Date stocke l'heure UTC (c'est-à-dire que getTime est retourné en UTC), javascript convertira l'heure en UTC. Lorsque vous appelez des éléments tels que toString, javascript convertira l'heure UTC en fuseau horaire local du navigateur et renverra la chaîne en fuseau horaire local, c'est-à-dire Si utilise UTC+8:

> new Date('Feb 28 2013 19:00:00 GMT-0500').toString()
< "Fri Mar 01 2013 08:00:00 GMT+0800 (CST)"

Aussi, vous pouvez utiliser la méthode normale getHours/Minute/Second:

> new Date('Feb 28 2013 19:00:00 GMT-0500').getHours()
< 8

(Ce 8 signifie que l'heure est convertie en mon heure locale - UTC+8, le nombre d'heures est 8.)

13
maowtm

J'ai rencontré un problème similaire avec les tests unitaires (plus précisément en plaisanterie lorsque les tests unitaires sont exécutés localement pour créer les instantanés puis que le serveur de CI s'exécute (potentiellement) dans un fuseau horaire différent, ce qui entraîne l'échec de la comparaison d'instantané). Je me suis moqué de notre Date et de certaines des méthodes de support comme ceci: 

describe('...', () => {
  let originalDate;

  beforeEach(() => {
    originalDate = Date;
    Date = jest.fn(
      (d) => {
        let newD;
        if (d) {
          newD = (new originalDate(d));
        } else {
          newD = (new originalDate('2017-05-29T10:00:00z'));
        }
        newD.toLocaleString = () => {
          return (new originalDate(newD.valueOf())).toLocaleString("en-US", {timeZone: "America/New_York"});
        };
        newD.toLocaleDateString = () => {
          return (new originalDate(newD.valueOf())).toLocaleDateString("en-US", {timeZone: "America/New_York"});
        };
        newD.toLocaleTimeString = () => {
          return (new originalDate(newD.valueOf())).toLocaleTimeString("en-US", {timeZone: "America/New_York"});
        };
        return newD;
      }
    );
    Date.now = () => { return (Date()); };
  });

  afterEach(() => {
    Date = originalDate;
  });

});
2
JRulle

je sais que c'est 3 ans trop tard, mais peut-être que ça peut aider quelqu'un d'autre, parce que je n'ai rien trouvé de tel, sauf pour la bibliothèque moment-timezone, qui n'est pas exactement la même chose que ce qu'il demande ici.

ive fait quelque chose de similaire pour le fuseau horaire allemand, C’est un peu complexe en raison de l’heure avancée et des années bissextiles pour lesquelles vous disposez de 366 jours.

il faudra peut-être un peu de travail avec la fonction "isDaylightSavingTimeInGermany" pendant que différents fuseaux horaires changent à différentes heures de l'heure d'été.

quoi qu'il en soit, consultez cette page: https://github.com/zerkotin/german-timezone-converter/wiki

les méthodes principales sont: convertLocalDateToGermanTimezone convertGermanDateToLocalTimezone

je me suis efforcé de la documenter, pour que cela ne soit pas si déroutant.

2
zerkotin

En me basant sur les réponses ci-dessus, j’utilise cette doublure native pour convertir la longue chaîne de fuseau horaire en chaîne de trois lettres:

var longTz = 'America/Los_Angeles';
var shortTz = new Date().
    toLocaleString("en", {timeZoneName: "short", timeZone: longTz}).
    split(' ').
    pop();

Cela donnera PDT ou PST en fonction de la date fournie. Dans mon cas d'utilisation particulier, le développement sur Salesforce (Aura/Lightning), nous pouvons obtenir le fuseau horaire de l'utilisateur dans le format long à partir du backend.

1
Shane

Essayez d’utiliser ctoc à partir de npm . https://www.npmjs.com/package/ctoc_timezone

Il a une fonctionnalité simple pour changer les fuseaux horaires (la plupart des fuseaux horaires autour de 400) et tous les formats personnalisés que vous voulez qu'il affiche.

1
Sandeep Chowdary

J'ai trouvé le moyen le plus compatible de le faire, sans me soucier d'une bibliothèque tierce, en utilisant getTimezoneOffset pour calculer l'horodatage approprié ou en mettant à jour l'heure, puis en utilisant les méthodes normales pour obtenir la date et l'heure nécessaires.

var mydate = new Date();
mydate.setFullYear(2013);
mydate.setMonth(02);
mydate.setDate(28);
mydate.setHours(7);
mydate.setMinutes(00);

// ET timezone offset in hours.
var timezone = -5;
// Timezone offset in minutes + the desired offset in minutes, converted to ms.
// This offset should be the same for ALL date calculations, so you should only need to calculate it once.
var offset = (mydate.getTimezoneOffset() + (timezone * 60)) * 60 * 1000;

// Use the timestamp and offset as necessary to calculate min/sec etc, i.e. for countdowns.
var timestamp = mydate.getTime() + timezone_offset,
    seconds = Math.floor(timestamp / 1000) % 60,
    minutes = Math.floor(timestamp / 1000 / 60) % 60,
    hours   = Math.floor(timestamp / 1000 / 60 / 60);

// Or update the timestamp to reflect the timezone offset.
mydate.setTime(mydate.getTime() + timezone_offset);
// Then Output dates and times using the normal methods.
var date = mydate.getDate(),
    hour = mydate.getHours();

MODIFIER

J'utilisais auparavant des méthodes UTC lors de l'exécution des transformations de date, ce qui était incorrect. En ajoutant le décalage à l'heure, l'utilisation des fonctions locales get renverra les résultats souhaités.

0
Shaun Cockerill

Essayez: date-from-timezone , il résout la date attendue à l’aide du Intl.DateTimeFormat disponible nativement.

J'utilise cette méthode dans l'un de mes projets depuis quelques années déjà, mais c'est maintenant que j'ai décidé de la publier en tant que petit projet OS :)

0
Mariusz Nowak