249 votes

Format date in a specific timezone

Je utilise Moment.js pour analyser et formater des dates dans mon application web. Dans le cadre d'un objet JSON, mon serveur backend envoie des dates en tant que nombre de millisecondes depuis l'époque UTC (décalage Unix).

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

// la réponse varie en fonction de votre fuseau horaire
const m1 = moment('3/11/2012 13:00').utc().format("MM/DD HH:mm")

// problème résolu, toujours "03/11 17:00"
const m2 = moment('3/11/2012 13:00 -0400').utc().format("MM/DD HH:mm")

console.log({ m1, m2 })

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

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

2 votes

Moment ne prend pas encore en charge cela, mais ils y travaillent. github.com/timrwood/moment/pull/671

6 votes

Ce devrait simplement fonctionner. Si vous transmettez à moment une chaîne temporelle qui inclut le décalage souhaité, alors il devrait conserver ce décalage et afficher l'heure locale telle quelle, plutôt que de s'ajuster automatiquement à l'heure locale du navigateur. Si je voulais qu'il s'ajuste à l'heure locale du navigateur, alors 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 le convertit-il à son propre décalage du navigateur. Conception terrible.

0 votes

@Les décalages de Triynko sont soumis à l'heure d'été, donc cela ne fonctionne pas toujours comme prévu.

336voto

user113215 Points 4402

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 véritable décalage par rapport à l'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 qu'avant :

// toujours "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 .zone() en tant que setter a été obsolète dans Moment.js 2.9.0. Il acceptait une chaîne contenant un identifiant de fuseau horaire (par exemple, "-0400" or "-04:00" pour -4 heures) ou un nombre représentant les minutes derrière l'UTC (par exemple, 240 pour New York pendant l'heure d'été).

// toujours "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 .tz() à la place :

// détermine le décalage correct pour America/Phoenix au moment donné
// toujours "2013-05-22 16:55"
moment(1369266934311).tz('America/Phoenix').format('YYYY-MM-DD HH:mm')

0 votes

J'avais des problèmes avec ça via une erreur "TypeError: Object 240 has no method 'format'". J'ai réalisé que la méthode zone est disponible uniquement en tant que "setter" à partir de la version 2.1.0 de Moment.js (et j'avais une version plus ancienne). Merci!

0 votes

Vous pouvez également passer un fuseau horaire "America/Phoenix" également.

0 votes

Est-ce que Moment a une façon d'utiliser le fuseau horaire du navigateur de l'utilisateur?

103voto

Nicola Pedretti Points 1657

Quelques réponses mentionnent déjà que moment-timezone est la meilleure option avec un 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 en paramètre:

Le premier code prend la date et suppose que le fuseau horaire est celui passé en paramètre. Le second prend la date, suppose le fuseau horaire du navigateur et change ensuite l'heure et le fuseau horaire en fonction du fuseau horaire passé en paramètre.

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 de -5 par rapport à l'UTC. Donc dans le premier cas, cela ne change pas et il définit la date et l'heure avec le fuseau horaire UTC.

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

REMARQUE: Le paramètre de format est vraiment important. S'il est omis, moment pourrait 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 en paramètre:

Dans ce cas, les deux se comportent de manière équivalente


Même si maintenant je comprends pourquoi cela fonctionne de cette manière, je trouve que c'était une fonctionnalité assez déroutante et que cela valait la peine d'être expliqué.

4 votes

Moment(...).tz n'est pas une fonction

8 votes

Avez-vous bien installé moment-timezone?

1 votes

Est-il possible d'obtenir le moment analysé et converti sans le formater? Par exemple, si je veux le formater différemment sans le réanalyser à chaque fois.

73voto

Philip Nuzhnyy Points 855

Utiliser moment-timezone

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

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

moment.tz.add('Europe/Berlin|CET CEST CEMT|-10 -20 -30')

0 votes

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 en tant qu'UTC dans MySQL, mais à afficher dans une zone spécifique en fonction de la configuration de l'utilisateur et non du fuseau horaire du client.

24voto

Manto Points 973

.zone() a été obsolète, et vous devriez utiliser utcOffset à la place:

// pour un fuseau horaire qui est de +7 heures UTC
moment(1369266934311).utcOffset(420).format('YYYY-MM-DD HH:mm')

12voto

Facu Farias Points 44

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, j'ai défini le fuseau horaire et ça fonctionne à merveille :

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

Merci beaucoup !

20 votes

Vous ne devriez pas utiliser le constructeur new Date(). Moment fournit tout ce dont vous auriez besoin pour analyser les dates. Consultez la documentation sur le Parsing.

0 votes

Oui, mais si je ne le fais pas, je reçois un avertissement de Moment, indiquant que c'est obsolète ou quelque chose comme ça

7 votes

Le avertissement signifie que Moment effectue un retour interne à exactement ce que vous faites (utilisant new Date() interne), mais cela est incohérent entre les navigateurs. Au lieu de cela, vous devriez fournir le format attendu en tant que deuxième argument. Exemple : moment("25-12-1995", "DD-MM-YYYY").

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