Mettre en forme la date dans un fuseau horaire spécifique

177

J'utilise Moment.js pour analyser et mettre en forme les dates dans mon application Web. Dans le cadre d'un objet JSON, mon serveur backend envoie des dates en nombre de millisecondes à partir de l'époque UTC (décalage Unix).

L'analyse des dates dans un fuseau horaire spécifique est facile - il suffit d'ajouter l'identificateur de fuseau horaire RFC 822 à la fin de la chaîne avant l'analyse:

// response varies according to your timezone
const m1 = moment('3/11/2012 13:00').utc().format("MM/DD HH:mm")

// problem solved, always "03/11 17:00"
const m2 = moment('3/11/2012 13:00 -0400').utc().format("MM/DD HH:mm")

console.log({ m1, m2 })
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>

Mais comment formater une date dans un fuseau horaire spécifique ?

Je veux des résultats cohérents quelle que soit l'heure actuelle du navigateur, mais je ne veux pas afficher les dates en UTC.

menthe tranquille
la source
2
Moment ne le prend pas encore en charge, mais ils y travaillent. github.com/timrwood/moment/pull/671
Ben
5
Cela devrait juste fonctionner. Si vous passez moment une chaîne de temps qui inclut le décalage souhaité, alors il doit conserver ce décalage et afficher l'heure locale comme donnée, plutôt que de s'ajuster automatiquement à l'heure locale du navigateur. Si je voulais qu'il s'adapte à l'heure locale du navigateur, je lui donnerais une heure UTC au lieu de lui donner explicitement un décalage à utiliser. Je veux dire ... je lui donne un décalage explicite, pourquoi est-il essentiellement en train de le manger et de faire sa propre conversion vers le décalage du navigateur. Conception terrible.
Triynko du
Les compensations @Triynko sont soumises à l'heure d'été, donc cela ne fonctionne pas toujours comme prévu.
pinkpanther
1
Quelque chose en rapport avec cela, je veux imprimer l'heure dans un format spécifique, par exemple le 15 mars 2018, mais je ne trouve pas la chaîne de format pour le faire. Le générique DD MMM, YYYYne fonctionne pas, quand je l'utilise comme moment.tz("2018-02-15T14:20:00.000+0530", "Asia/Bangkok").format("DD MMM, YYYY"). Quelqu'un peut-il me diriger dans la documentation où je peux trouver toutes les clés pour le formatage du temps lors de l'utilisation de cette api.
pRmdk
@PramodKumar Qu'est-ce qui ne va pas? Cela donne "15 Feb, 2018". Vouliez-vous utiliser la chaîne de format DD MMMM, YYYYpour obtenir "15 February, 2018"?
quietmint

Réponses:

248

Comme indiqué dans la réponse de Manto , .utcOffset()est la méthode préférée à partir de Moment 2.9.0. Cette fonction utilise le décalage réel par rapport à UTC, et non le décalage inverse (par exemple -240 pour New York pendant l'heure d'été). Les chaînes de décalage comme "+0400" fonctionnent de la même manière que précédemment:

// always "2013-05-23 00:55"
moment(1369266934311).utcOffset(60).format('YYYY-MM-DD HH:mm')
moment(1369266934311).utcOffset('+0100').format('YYYY-MM-DD HH:mm')

L'ancien en .zone()tant que setter était obsolète dans Moment.js 2.9.0. Il acceptait une chaîne contenant un identifiant de fuseau horaire (par exemple, "-0400" ou "-04: 00" pendant -4 heures) ou un nombre représentant des minutes de retard sur UTC (par exemple, 240 pour New York pendant l'heure d'été).

// always "2013-05-23 00:55"
moment(1369266934311).zone(-60).format('YYYY-MM-DD HH:mm')
moment(1369266934311).zone('+0100').format('YYYY-MM-DD HH:mm')

Pour travailler avec des fuseaux horaires nommés au lieu de décalages numériques, incluez Moment Timezone et utilisez à la .tz()place:

// determines the correct offset for America/Phoenix at the given moment
// always "2013-05-22 16:55"
moment(1369266934311).tz('America/Phoenix').format('YYYY-MM-DD HH:mm')
menthe tranquille
la source
J'avais des problèmes avec cela via une erreur "TypeError: Object 240 has no method 'format'" erreur. J'ai réalisé que la zone n'est disponible qu'en tant que setter sur la version 2.1.0 et plus de Moment.js (et j'étais sur une version plus ancienne). Merci!
Melinda Weathers
5
@ebi Il utilise déjà le fuseau horaire du navigateur par défaut. Pour accéder au décalage du fuseau horaire du navigateur, utilisez .zone()comme un getter, qui renvoie les minutes de UTC (par exemple, renvoie 300 pour New York pendant l'heure standard).
quietmint
1
@EricCope Non, pas tout à fait. Vous pouvez cependant utiliser .tz("America/Phoenix")si vous incluez momentjs.com/timezone . J'ai mis à jour la réponse avec un exemple.
quietmint
1
Notez que l'utilisation du décalage ne fonctionnera pas comme prévu si le fuseau horaire a des décalages différents en raison de l'heure d'été.
pinkpanther
1
.UtcOffset () gérera-t-il automatiquement l'heure d'été? comme quand je règle UTC +1 CET en hiver, est-ce que je parie UTC +2 CEST pendant l'heure d'été? Parce que cela le rend utilisable ou non!
haemse
61

Utiliser le fuseau horaire du moment

moment(date).tz('Europe/Berlin').format(format)

Avant de pouvoir accéder à un fuseau horaire particulier, vous devrez le charger comme tel (ou en utilisant des méthodes alternatives décrites ici )

moment.tz.add('Europe/Berlin|CET CEST CEMT|-10 -20 -30')
Philip Nuzhnyy
la source
Je ne pense pas que le moment tz était disponible lorsque la question a été posée, mais je pense que c'est peut-être la voie à suivre. Je travaille actuellement sur un problème similaire avec tous les horodatages stockés au format UTC dans MySQL, mais à afficher dans une zone spécifique dépendant de la configuration de l'utilisateur et non du fuseau horaire du client.
nickdnk
47

Quelques réponses mentionnent déjà que le fuseau horaire du moment est la voie à suivre avec le fuseau horaire nommé. Je veux juste clarifier quelque chose à propos de cette bibliothèque qui était assez déroutant pour moi. Il y a une différence entre ces deux déclarations:

moment.tz(date, format, timezone)

moment(date, format).tz(timezone)

En supposant qu'un fuseau horaire n'est pas spécifié dans la date passée:

Le premier code prend la date et suppose que le fuseau horaire est celui qui est passé. Le second prendra la date, prendra le fuseau horaire du navigateur, puis changera l'heure et le fuseau horaire en fonction du fuseau horaire transmis.

Exemple:

moment.tz('2018-07-17 19:00:00', 'YYYY-MM-DD HH:mm:ss', 'UTC').format() // "2018-07-17T19:00:00Z"

moment('2018-07-17 19:00:00', 'YYYY-MM-DD HH:mm:ss').tz('UTC').format() // "2018-07-18T00:00:00Z"

Mon fuseau horaire est +5 depuis utc. Donc, dans le premier cas, cela ne change pas et il définit la date et l'heure pour avoir le fuseau horaire utc.

Dans le second cas, il suppose que la date passée est en -5, puis le transforme en UTC, et c'est pourquoi il crache la date "2018-07-18T00: 00: 00Z"

REMARQUE: le paramètre de format est vraiment important. En cas d'omission, le moment peut revenir à la classe Date, ce qui peut entraîner des comportements imprévisibles


En supposant que le fuseau horaire est spécifié dans la date passée:

Dans ce cas, ils se comportent tous les deux de la même manière


Même si maintenant je comprends pourquoi cela fonctionne de cette façon, je pensais que c'était une fonctionnalité assez déroutante et méritait d'être expliquée.

Nicola Pedretti
la source
1
moment (...). tz n'est pas une fonction
K - La toxicité du SO augmente.
5
Avez-vous installé moment-fuseau horaire?
Nicola Pedretti
existe-t-il un moyen de récupérer le moment analysé et converti sans formatage? Par exemple, si je veux formater de différentes manières sans tout recommencer.
jEremyB
Merci d'avoir clarifié ceci - j'ai eu des problèmes lors de la définition d'un fuseau horaire différent de celui du navigateur de l'utilisateur, et c'était exactement le problème.
Robin Schaaf le
20

.zone () est obsolète et vous devriez utiliser utcOffset à la place:

// for a timezone that is +7 UTC hours
moment(1369266934311).utcOffset(420).format('YYYY-MM-DD HH:mm')
Manto
la source
8

J'avais le même problème avec Moment.js. J'ai installé moment-timezone, mais le problème n'a pas été résolu. Ensuite, j'ai fait exactement ce qui est exposé ici, définir le fuseau horaire et cela fonctionne comme un charme:

moment(new Date({your_date})).zone("+08:00")

Merci beaucoup!

facundofarias
la source
16
Vous ne devriez pas utiliser le new Date()constructeur. Moment fournit tout ce dont vous avez besoin pour analyser les dates. Voir Analyse des documents.
quietmint le
Oui, mais si je ne le fais pas, je reçois un avertissement de Moment, indiquant qu'il est obsolète de quelque chose comme ça
facundofarias
7
L'avertissement signifie que Moment revient en interne exactement à ce que vous faites (en utilisant en new Date()interne), mais cela n'est pas cohérent entre les navigateurs . Au lieu de cela, vous devez utiliser fournir le format attendu comme deuxième argument. Exemple: moment("12-25-1995", "MM-DD-YYYY").
quietmint
4

Je viens de comprendre cela, et comme j'ai eu le même problème, je posterais simplement les résultats que j'avais obtenus

lors de l'analyse, vous pouvez mettre à jour l'offset (c'est-à-dire que j'analyse une donnée (1.1.2014) et je veux seulement la date, 1er janvier 2014. Sur GMT + 1, j'obtiendrais 31.12.2013.

moment(moment.utc('1.1.2014').format());

Eh bien, cela m'a été utile pour prendre en charge tous les fuseaux horaires

B

Bard Rotzer
la source
-7

Vous pouvez essayer ceci,

Ici, vous pouvez obtenir la date en fonction du fuseau horaire du client (navigateur).

moment(new Date().getTime()).zone(new Date().toString().match(/([-\+][0-9]+)\s/)[1]).format('YYYY-MM-DD HH:mm:ss')

Le regex vous donne essentiellement la valeur de décalage.

À votre santé!!

K.Karthik
la source
Habituellement, le moment vous donne tout ce dont vous avez besoin. Vous n'avez jamais besoin de faire correspondre quoi que ce soit de personnalisé.
Mahesh Samudra