moment.js - UTC donne une date erronée

94

Pourquoi moment.js UTC affiche-t-il toujours la mauvaise date? Par exemple à partir de la console développeur de Chrome:

moment(('07-18-2013')).utc().format("YYYY-MM-DD").toString()
// or
moment.utc(new Date('07-18-2013')).format("YYYY-MM-DD").toString()

Les deux renverront "2013-07-17" pourquoi revient-il 17ème au lieu de 18ème , qui a été transmis.

Mais si j'utilise momentjs sans utc:

moment(new Date('07-18-2013')).format("YYYY-MM-DD").toString()

Je reçois "2013-07-18", ce que j'attends aussi en utilisant moment.js UTC.

Cela signifie-t-il que nous ne pouvons pas obtenir la date correcte lorsque vous utilisez moment.js UTC?

brg
la source
4
Je ne pense pas que vous ayez besoin toString()après format()(il renvoie déjà une chaîne).
alex

Réponses:

159

Par défaut, MomentJS analyse en heure locale. Si seule une chaîne de date (sans heure) est fournie, l'heure par défaut est minuit.

Dans votre code, vous créez une date locale, puis la convertissez en fuseau horaire UTC (en fait, cela fait basculer l'instance du moment en mode UTC ), donc lorsqu'elle est formatée, elle est décalée (en fonction de votre heure locale) vers l'avant ou en arrière.

Si le fuseau horaire local est UTC + N (N étant un nombre positif) et que vous analysez une chaîne de date uniquement, vous obtiendrez la date précédente.

Voici quelques exemples pour l'illustrer (mon décalage horaire local est UTC + 3 pendant l'heure d'été):

>>> moment('07-18-2013', 'MM-DD-YYYY').utc().format("YYYY-MM-DD HH:mm")
"2013-07-17 21:00"
>>> moment('07-18-2013 12:00', 'MM-DD-YYYY HH:mm').utc().format("YYYY-MM-DD HH:mm")
"2013-07-18 09:00"
>>> Date()
"Thu Jul 25 2013 14:28:45 GMT+0300 (Jerusalem Daylight Time)"

Si vous voulez que la chaîne date-heure soit interprétée comme UTC, vous devez être explicite à ce sujet:

>>> moment(new Date('07-18-2013 UTC')).utc().format("YYYY-MM-DD HH:mm")
"2013-07-18 00:00"

ou, comme Matt Johnson le mentionne dans sa réponse, vous pouvez ( et devriez probablement ) l'analyser comme une date UTC en premier lieu en utilisant moment.utc()et inclure la chaîne de format comme deuxième argument pour éviter toute ambiguïté.

>>> moment.utc('07-18-2013', 'MM-DD-YYYY').format("YYYY-MM-DD HH:mm")
"2013-07-18 00:00"

Pour faire l'inverse et convertir une date UTC en date locale, vous pouvez utiliser la local()méthode, comme suit:

>>> moment.utc('07-18-2013', 'MM-DD-YYYY').local().format("YYYY-MM-DD HH:mm")
"2013-07-18 03:00"
MasterAM
la source
Merci beaucoup. Donc, fondamentalement, je devrais toujours passer dans le temps lorsque vous utilisez UTC ou passer en UTC comme dans votre deuxième approche.
brg
Soit cela, soit respectez le fuseau horaire local. Si vous envoyez des heures depuis le serveur, vous pouvez les exprimer sous forme d'horodatage Unix (X) ou sous forme de chaînes à un fuseau horaire spécifique. Pourquoi utiliser UTC au lieu du fuseau horaire local de l'utilisateur, de toute façon (sauf dans le but d'envoyer des données normalisées au serveur)?
MasterAM
1
Sachez que new Date('07-18-2013 UTC')cela ne fonctionnera pas dans IE8, si vous vous en souciez.
Dzmitry Lazerka
2
J'ai du mal avec ça depuis si longtemps. Ils devraient vraiment bien expliquer cela sur leur site, car je suppose que c'est le cas d'utilisation le plus courant de moment.js. Merci beaucoup! Tu as vraiment sauvé ma peau!
WebWanderer
ce code fonctionne pour moi: [code] moment (strDate, 'DD / MM / YYYY h: mm A'). utc (strDate) .format ("YYYY-MM-DD HH: mm") [/ code]
Omar Isaid
36

Les deux Dateet momentanalyseront la chaîne d'entrée dans le fuseau horaire local du navigateur par défaut. Cependant Dateest parfois incompatible à cet égard. Si la chaîne YYYY-MM-DDutilise spécifiquement des traits d'union , ou si c'est le cas YYYY-MM-DD HH:mm:ss, elle l'interprétera comme l'heure locale . Contrairement à Date, momentsera toujours cohérent sur la façon dont il analyse.

La bonne façon d'analyser un moment d'entrée comme UTC dans le format que vous avez fourni serait comme ceci:

moment.utc('07-18-2013', 'MM-DD-YYYY')

Reportez-vous à cette documentation .

Si vous souhaitez ensuite le formater différemment pour la sortie, procédez comme suit:

moment.utc('07-18-2013', 'MM-DD-YYYY').format('YYYY-MM-DD')

Vous n'avez pas besoin d'appeler toStringexplicitement.

Notez qu'il est très important de fournir le format d'entrée. Sans cela, une date telle 01-04-2013que celle du 4 janvier ou du 1er avril pourrait être traitée, en fonction des paramètres de culture du navigateur.

Matt Johnson-Pint
la source
Juste pour apprendre, dans la console: moment.utc ('2013-07-18 0:00 +0100', 'YYYY-MM-DD HH: mm') me donne "2013-07-18 0:00 +0100 " Mais ce qui s'affiche sur jsfiddle lorsqu'il est exécuté est différent c'est-à-dire: Thu 25 Jul 2013 01:00:00 GMT + 0100 Notez le 01:00:00 . Merci.
brg
La sortie d'un raw momentsur la console n'est pas très utile. Vous regardez probablement l'une de ses propriétés internes. Vous devez le formater avant de vérifier les résultats. Par exemple moment.utc().format()ou moment().format().
Matt Johnson-Pint
La date et le moment analyseront la chaîne d'entrée dans le fuseau horaire local du navigateur par défaut. Je suis actuellement sur EDT. new Date('2010-12-12')me donne Date {Sat Dec 11 2010 19:00:00 GMT-0500 (Eastern Daylight Time)}en FF 38.0.5. Juste pour contextualiser ce que «dans l'heure locale» signifie exactement - dans ce cas, cela semble signifier, « Datesupposera qu'une chaîne d'heure sans zone est en UTC et analysera l'heure locale». d.getUTCDate()= 12and d.getDate()=11
ruffin
1
Oui, il y a quelques exceptions. ES5 (la plupart des navigateurs actuels) interprétera les dates avec des traits d'union comme UTC, mais à peu près tout le reste est interprété comme l'heure locale. ES6 modifie ce comportement pour interpréter la même chaîne que l'heure locale. J'ai mis à jour la réponse.
Matt Johnson-Pint
Ha, oui, je viens de rencontrer cela à MDN en disant exactement cela ( '2012-12-12'est UTC b / c c'est au format ISO, mais 'December 12, 2012'et même '2012/12/12'sont analysés avec un fuseau horaire local dans ES5), mais vous m'avez battu. Tellement génial que ES6 les rend tous locaux [dit-il sarcastiquement]. Les dates sont une douleur, (c) Advent of Dates
ruffin