L'objet de date Javascript est-il toujours un jour de congé?

238

Dans mon application Java Script, la date est stockée dans un format comme celui-ci:

2011-09-24

Maintenant, lorsque j'essaie d'utiliser la valeur ci-dessus pour créer un nouvel objet Date (afin de pouvoir récupérer la date dans un format différent), la date revient toujours un jour de congé. Voir ci-dessous:

var doo = new Date("2011-09-24");
console.log(doo);

journaux:

Fri Sep 23 2011 20:00:00 GMT-0400 (Eastern Daylight Time)
levi
la source
11
La classe Date de Javascript ne représente pas une date, elle représente un horodatage (identique en Java). Pour en faire une date, il utilise un fuseau horaire et c'est la cause de votre problème. Il l'analyse avec le fuseau horaire GMT / UTC (24 septembre 2011, 00 : 00 UTC), puis le sort avec un fuseau horaire différent de 4 heures (23 septembre 2011, 20 h 00 GMT-0400).
Codo
2
J'obtiens une "date invalide". Remplacez les caractères «-» par des caractères «/» et réessayez. Ou divisez la date en ses bits et définissez les composants individuellement (si vous le faites, soustrayez 1 du numéro du mois).
RobG
@Codo - oui, bonne réponse. ECMA-262 15.9.1.15 s'applique. Le PO doit utiliser "2011-09-24T20: 00: 00-04: 00" ou similaire.
RobG
1
J'ai trouvé que le format "24 septembre 2011" retournera la date appropriée. Voir ici pour une explication: stackoverflow.com/questions/2587345/javascript-date-parse
christurnerio

Réponses:

98

Notez que l'heure d'été est -4 hourset que les heures à la date de votre retour sont 20.

20h + 4h = 24h

qui est minuit du 2011-09-24. La date a été analysée en UTC (GMT) car vous avez fourni une chaîne de date uniquement sans indicateur de fuseau horaire. Si vous aviez donné une chaîne date / heure sans indicateur à la place (new Date("2011-09-24T00:00:00") ), elle aurait été analysée dans votre fuseau horaire local. (Historiquement, il y a eu des incohérences, notamment parce que la spécification a changé plusieurs fois, mais les navigateurs modernes devraient être corrects; ou vous pouvez toujours inclure un indicateur de fuseau horaire.)

Vous obtenez la bonne date, vous n'avez simplement jamais spécifié le bon fuseau horaire.

Si vous devez accéder aux valeurs de date, vous pouvez utiliser getUTCDate()ou l' une des autres getUTC*()fonctions :

var d,
    days;
d = new Date('2011-09-24');
days = ['Sun', 'Mon', 'Tues', 'Wed', 'Thurs', 'Fri', 'Sat'];
console.log(days[d.getUTCDay()]);
zzzzBov
la source
24
Comment "spécifiez-vous le fuseau horaire correct"? Le constructeur de date interprète toujours la chaîne de date comme UTC, mais ajuste ensuite pour le fuseau horaire. Je peux même faire une nouvelle date ('2012-01-02 EDT') et je la ramène toujours à la veille en raison de l'application du décalage pour l'heure d'été, ce qui n'a aucun sens car si je vous disais que c'est la date selon le fuseau horaire local actuel d'EDT, puis ne lui appliquez pas de décalage supplémentaire. Je lui ai dit que le fuseau horaire était EDT mais qu'il applique toujours un décalage supplémentaire en le reculant un jour.
AaronLS
1
@AaronLS, EDTest l' heure avancée (aussi connu comme l' heure d'été) , ESTest le fuseau horaire applicable en Janvier.
zzzzBov
1
Le créer comme simplement UTC à partir d'une chaîne serait ce que j'aimerais faire, c'est pourquoi j'ai demandé "Comment spécifiez-vous" le fuseau horaire correct "?" concernant l'endroit où vous avez déclaré "vous n'avez jamais spécifié le fuseau horaire correct". Si je le fais, new Date('2012-01-01 GMT')il applique toujours un décalage car il le convertit en heure locale de l'utilisateur.
AaronLS
7
@AaronLS, si vous êtes obligé d'utiliser les get*méthodes et en avez besoin pour retourner la date / heure correcte, y compris le décalage de fuseau horaire inconnu, ajoutez simplement le décalage de fuseau horaire inconnu: d = new Date('2013-01-08 GMT'); d.setMinutes(d.getMinutes() + d.getTimezoneOffset());cela normalisera la date aux paramètres régionaux de l'utilisateur afin que les .get*méthodes reviennent la valeur attendue. Les .getUTC*méthodes seront alors incorrectes, alors soyez prudent.
zzzzBov
1
Il existe une différence entre la définition d'un comportement pour fournir une référence et son utilisation en tant qu'échappement lorsque les implémenteurs n'ont pas réussi à implémenter quelque chose correctement. Et ce n'est pas la même représentation si les données ne correspondent pas aux attentes.
Dissident Rage
252

Il y a plusieurs choses folles qui se produisent avec un objet JS DATE qui convertit des chaînes, par exemple, considérez la date suivante que vous avez fournie

Remarque: Les exemples suivants peuvent être ou non un jour de congé selon VOTRE fuseau horaire et l'heure actuelle.

new Date("2011-09-24"); // Year-Month-Day
// => Fri Sep 23 2011 17:00:00 GMT-0700 (MST) - ONE DAY OFF.

Cependant, si nous réorganisons le format de chaîne en Mois-Jour-Année ...

new Date("09-24-2011");
=> // Sat Sep 24 2011 00:00:00 GMT-0700 (MST) - CORRECT DATE.

Un autre étrange

new Date("2011-09-24");
// => Fri Sep 23 2011 17:00:00 GMT-0700 (MST) - ONE DAY OFF AS BEFORE.

new Date("2011/09/24"); // change from "-" to "/".
=> // Sat Sep 24 2011 00:00:00 GMT-0700 (MST) - CORRECT DATE.

Nous pourrions facilement changer les tirets dans votre date "2011-09-24" lors de la création d'une nouvelle date

new Date("2011-09-24".replace(/-/g, '\/')); // => "2011/09/24".
=> // Sat Sep 24 2011 00:00:00 GMT-0700 (MST) - CORRECT DATE.

Et si nous avions une chaîne de date comme "2011-09-24T00: 00: 00"

new Date("2011-09-24T00:00:00");
// => Fri Sep 23 2011 17:00:00 GMT-0700 (MST) - ONE DAY OFF.

Maintenant, changez le trait d' union pour faire une barre oblique comme avant; ce qui se produit?

new Date("2011/09/24T00:00:00");
// => Invalid Date

Je dois généralement gérer le format de date 2011-09-24T00: 00: 00 alors c'est ce que je fais.

new Date("2011-09-24T00:00:00".replace(/-/g, '\/').replace(/T.+/, ''));
// => Sat Sep 24 2011 00:00:00 GMT-0700 (MST) - CORRECT DATE.

METTRE À JOUR

Si vous fournissez des arguments distincts au constructeur Date, vous pouvez obtenir d'autres sorties utiles comme décrit ci-dessous

Remarque: les arguments peuvent être de type Number ou String. Je vais montrer des exemples avec des valeurs mixtes.

Obtenez le premier mois et le premier jour d'une année donnée

new Date(2011, 0); // Normal behavior as months in this case are zero based.
=> // Sat Jan 01 2011 00:00:00 GMT-0700 (MST)

Obtenez le dernier mois et le dernier jour d'une année

new Date((2011 + 1), 0, 0); // The second zero roles back one day into the previous month's last day.
=> // Sat Dec 31 2011 00:00:00 GMT-0700 (MST)

Exemple d'arguments Number, String. Notez que le mois est mars, car le mois est à nouveau basé sur zéro.

new Date(2011, "02"); 
=> // Tue Mar 01 2011 00:00:00 GMT-0700 (MST)

Si nous faisons la même chose mais avec un jour de zéro, nous obtenons quelque chose de différent.

new Date(2011, "02", 0); // again the zero roles back from March to the last day of February.
=> // Mon Feb 28 2011 00:00:00 GMT-0700 (MST)

L'ajout d'un jour de zéro à n'importe quel argument année et mois obtiendra le dernier jour du mois précédent. Si vous continuez avec des nombres négatifs, vous pouvez continuer à reculer un autre jour

new Date(2011, "02", -1);
=> // Sun Feb 27 2011 00:00:00 GMT-0700 (MST)
SoEzPz
la source
12
Cela m'a vraiment aidé le mieux. Je viens d'ajouter le .replace (/ - / g, '\ /'). Replace (/ T. + /, '') À la fin de mes données lorsque j'ai fait une nouvelle date. Super facile!
Devin Prejean
64
Wow - javascript est terriblement incohérent.
psparrow
2
Les appels .replace () ont vraiment aidé ce soir.
abandonner
2
oui j'ai testé tout cela, et c'est vraiment étrange.
chintan adatiya
27
Tout cela est dû au comportement du Date.parse () sous-jacent essayant de suivre ISO 8601. Lorsque la chaîne de date suit le format aaaa-mm-jj, il est supposé être ISO 8601 avec UTC 00:00 implicite. Lorsque la chaîne s'écarte du format (par exemple mm-jj-aaaa ou barre oblique au lieu d'un trait d'union), elle revient à l'analyseur plus lâche selon RFC 2822 qui utilise l'heure locale lorsque le fuseau horaire est absent. Certes, tout cela sera assez mystérieux pour une personne moyenne.
Mizstik
71

Pour normaliser la date et éliminer le décalage indésirable (testé ici: https://jsfiddle.net/7xp1xL5m/ ):

var doo = new Date("2011-09-24");
console.log(  new Date( doo.getTime() + Math.abs(doo.getTimezoneOffset()*60000) )  );
// Output: Sat Sep 24 2011 00:00:00 GMT-0400 (Eastern Daylight Time)

Cela accomplit également la même chose et mérite @tpartee (testé ici: https://jsfiddle.net/7xp1xL5m/1/ ):

var doo = new Date("2011-09-24");
console.log( new Date( doo.getTime() - doo.getTimezoneOffset() * -60000 )  );
AaronLS
la source
Cela l'a fait pour moi - j'ai dû travailler avec des dates à partir d'une API puis les trier / comparer, donc simplement ajouter le décalage de fuseau horaire fonctionne mieux.
chakeda
Cela a fonctionné pour moi, sauf que je devais soustraire le timeZoneOffset, pas l'ajouter
ErikAGriffin
@ErikAGriffin Êtes-vous dans un fuseau horaire positif, IE GMT + 0X00 au lieu de GMT-0X00?
AaronLS
J'ai fait quelque chose de similaire:doo.setMinutes(doo.getMinutes() + doo.getTimezoneOffset())
Dissident Rage
2
@AaronLS Vous étiez sur la bonne voie mais une logique légèrement fausse. Pour compenser le décalage TZ, la logique correcte est la suivante: console.log (new Date (doo.getTime () - doo.getTimezoneOffset () * -60000)); - Le signe du décalage est important et ne peut pas être absolu, mais vous avez également besoin du signe inverse pour la correction, nous multiplions donc le décalage par -60000 pour que le signe inverse s'applique.
tpartee
28

Si vous souhaitez obtenir l'heure 0 d'une date dans le fuseau horaire local, transmettez les parties de date individuelles au Dateconstructeur.

new Date(2011,08,24); // month value is 0 based, others are 1 based.
lincolnk
la source
26

Je veux juste ajouter que, apparemment, l'ajout d'un espace à la fin de la chaîne utilisera UTC pour la création.

new Date("2016-07-06")
> Tue Jul 05 2016 17:00:00 GMT-0700 (Pacific Daylight Time)

new Date("2016-07-06 ")
> Wed Jul 06 2016 00:00:00 GMT-0700 (Pacific Daylight Time)

Edit: Ce n'est pas une solution recommandée, juste une réponse alternative. Veuillez ne pas utiliser cette approche car il est très difficile de savoir ce qui se passe. Il existe un certain nombre de façons dont quelqu'un pourrait refactoriser ce problème, provoquant accidentellement un bogue.

Kyle Shrader
la source
Pour l'exemple avec l'espace à la fin, la console renvoie "Invalid Date = $ 2"
Brian Risk
1
fonctionne très bien! nouvelle date (data.Date + "") .toLocaleDateString ("en-US")
Nakres
Pour être juste, ce n'était qu'une réponse alternative et ce n'est pas une solution recommandée.
Kyle Shrader
25

Je pense que cela a à voir avec l'ajustement du fuseau horaire. La date que vous avez créée est en GMT et l'heure par défaut est minuit, mais votre fuseau horaire est EDT, il soustrait donc 4 heures. Essayez ceci pour vérifier:

var doo = new Date("2011-09-25 EDT");
FishBasketGordo
la source
3
C'est la meilleure réponse ici. + 1 million pour l'utilisation des chaînes de localisation de fuseau horaire intégrées au lieu de la conversion par programme.
blearn
2
Celui-ci aide. Cela fonctionne comme ceci: $ scope.dat = new Date (datestring + 'EDT'). Notez la différence entre EDT et EST cependant: lien
Weihui Guo
Je ne sais pas ce qui se passe dans les coulisses, mais cela fonctionne parfaitement.
the_haystacker
Je dirais que c'est la réponse la plus simpliste et moins de reformatage de code.
Michael
Merci, je considère la meilleure façon pour moi.
Janderson Constantino
11

Votre problème concerne spécifiquement le fuseau horaire. Notez une partie GMT-0400- c'est que vous avez 4 heures de retard sur GMT. Si vous ajoutez 4 heures à la date / heure affichée, vous obtiendrez exactement minuit 2011/09/24. Utilisez toUTCString()plutôt la méthode pour obtenir la chaîne GMT:

var doo = new Date("2011-09-24");
console.log(doo.toUTCString());
Aleks G
la source
7

Ce n'est probablement pas une bonne réponse, mais je veux juste partager mon expérience avec ce problème.

Mon application utilise globalement la date utc au format 'AAAA-MM-JJ', tandis que le plugin datepicker que j'utilise n'accepte que la date js, il m'est difficile de considérer à la fois utc et js. Donc, quand je veux passer une date au format 'AAAA-MM-JJ' à mon sélecteur de date, je la convertis d'abord au format 'MM / JJ / AAAA' en utilisant moment.js ou tout ce que vous voulez, et la date affichée sur le sélecteur de date est maintenant correct. Pour votre exemple

var d = new Date('2011-09-24'); // d will be 'Fri Sep 23 2011 20:00:00 GMT-0400 (EDT)' for my lacale
var d1 = new Date('09/24/2011'); // d1 will be 'Sat Sep 24 2011 00:00:00 GMT-0400 (EDT)' for my lacale

Apparemment, d1 est ce que je veux. J'espère que cela serait utile pour certaines personnes.

Jie Zhang
la source
1
Le simple fait de changer les formats comme vous l'avez fait a fonctionné de la même manière pour moi. Si étrange.
jAC
5

Ceci à travers moi pour une boucle, +1 sur la réponse de zzzBov. Voici une conversion complète d'une date qui a fonctionné pour moi en utilisant les méthodes UTC:

//myMeeting.MeetingDate = '2015-01-30T00:00:00'

var myDate = new Date(myMeeting.MeetingDate);
//convert to JavaScript date format
//returns date of 'Thu Jan 29 2015 19:00:00 GMT-0500 (Eastern Standard Time)' <-- One Day Off!

myDate = new Date(myDate.getUTCFullYear(), myDate.getUTCMonth(), myDate.getUTCDate());
//returns date of 'Fri Jan 30 2015 00:00:00 GMT-0500 (Eastern Standard Time)' <-- Correct Date!
cmartin
la source
4

Cela signifie 2011-09-24 00:00:00 GMT, et puisque vous y êtes GMT -4, ce sera20:00 la veille.

Personnellement, je comprends 2011-09-24 02:00:00, parce que je vis GMT +2.

pimvdb
la source
3

Bien que dans le cas de l'OP, le fuseau horaire est EDT, rien ne garantit que l'utilisateur exécutant votre script sera dans le fuseau horaire EDT, donc le codage en dur du décalage ne fonctionnera pas nécessairement. La solution que j'ai trouvée fractionne la chaîne de date et utilise les valeurs distinctes dans le constructeur Date.

var dateString = "2011-09-24";
var dateParts = dateString.split("-");
var date = new Date(dateParts[0], dateParts[1] - 1, dateParts[2]);

Notez que vous devez prendre en compte un autre élément de bizarrerie JS: le mois est basé sur zéro.

Brian Risk
la source
2

J'ai rencontré ce problème exact lorsque mon client était à l'heure normale de l'Atlantique. La valeur de date que le client a récupérée était "2018-11-23" et lorsque le code l'a transmise à new Date("2018-11-23")la sortie pour le client, c'était la veille. J'ai créé une fonction utilitaire comme indiqué dans l'extrait de code qui a normalisé la date, donnant au client la date attendue.

date.setMinutes(date.getMinutes() + date.getTimezoneOffset());

var normalizeDate = function(date) {
  date.setMinutes(date.getMinutes() + date.getTimezoneOffset());
  return date;
};

var date = new Date("2018-11-23");

document.getElementById("default").textContent = date;
document.getElementById("normalized").textContent = normalizeDate(date);
<h2>Calling new Date("2018-11-23")</h2>
<div>
  <label><b>Default</b> : </label>
  <span id="default"></span>
</div>
<hr>
<div>
  <label><b>Normalized</b> : </label>
  <span id="normalized"></span>
</div>

Gabriel Gates
la source
2

si vous cherchez simplement à vous assurer que les différentes parties de la date restent les mêmes à des fins d'affichage, * cela semble fonctionner, même lorsque je change de fuseau horaire:

var doo = new Date("2011-09-24 00:00:00")

il suffit d'ajouter les zéros là-dedans.

Dans mon code, je fais ceci:

let dateForDisplayToUser = 
  new Date( `${YYYYMMDDdateStringSeparatedByHyphensFromAPI} 00:00:00` )
  .toLocaleDateString( 
    'en-GB', 
    { day: 'numeric', month: 'short', year: 'numeric' }
  )

Et je change de fuseau horaire sur mon ordinateur et la date reste la même que la chaîne de date aaaa-mm-jj que j'obtiens de l'API.

Mais est-ce que je manque quelque chose / est-ce une mauvaise idée?

* au moins en chrome. Cela ne fonctionne pas dans Safari! au moment de la rédaction de cet article

Timothy Mitchell
la source
Lorsque vous le faites .toISOString(), cela remonte à 1 jour.
vivek_23
new Date('2019/11/18 05:30:00').toISOString();a travaillé pour moi
vivek_23
1

La meilleure façon de gérer cela sans utiliser plus de méthodes de conversion,

 var mydate='2016,3,3';
 var utcDate = Date.parse(mydate);
 console.log(" You're getting back are 20.  20h + 4h = 24h :: "+utcDate);

Maintenant, ajoutez simplement GMT dans votre date ou vous pouvez l'ajouter.

 var  mydateNew='2016,3,3'+ 'GMT';
 var utcDateNew = Date.parse(mydateNew);
 console.log("the right time that you want:"+utcDateNew)

En direct: https://jsfiddle.net/gajender/2kop9vrk/1/

Gajender Singh
la source
1

J'ai rencontré un problème comme celui-ci. Mais mon problème était le décalage lors de l'obtention de la date de la base de données.

ceci est tracé dans la base de données et il est au format UTC.

2019-03-29 19: 00: 00.0000000 +00: 00

Donc, quand je reçois de la base de données et vérifie la date, il ajoute un décalage avec elle et renvoie à javascript.

entrez la description de l'image ici

Il ajoute +05: 00 car il s'agit du fuseau horaire de mon serveur. Mon client est sur un fuseau horaire différent +07: 00.

2019-03-28T19: 00: 00 + 05: 00 // c'est ce que j'obtiens en javascript.

Voici donc ma solution ce que je fais avec ce problème.

var dates = price.deliveryDate.split(/-|T|:/);
var expDate = new Date(dates[0], dates[1] - 1, dates[2], dates[3], dates[4]);
var expirationDate = new Date(expDate);

Ainsi, lorsque la date provient du serveur et que le serveur est décalé, je divise la date et supprime le décalage du serveur, puis convertis en date. Cela résout mon problème.

Uxmaan Ali
la source
1

si vous avez besoin d'une solution simple pour cela, voir:

new Date('1993-01-20'.split('-')); 

entrez la description de l'image ici

Sebastiao Marcos
la source
0

Vous utilisez le format de chaîne de date ISO qui, selon cette page , entraîne la construction de la date à l'aide du fuseau horaire UTC:

Remarque: l'analyse des chaînes de date avec le constructeur Date (et Date.parse, ils sont équivalents) est fortement déconseillée en raison des différences et des incohérences du navigateur. La prise en charge des chaînes au format RFC 2822 est par convention uniquement. La prise en charge des formats ISO 8601 diffère en ce que les chaînes de date uniquement (par exemple, "1970-01-01") sont traitées comme UTC et non comme locales.

Si vous formatez le texte différemment, par exemple "Jan 01 1970", (au moins sur ma machine), il utilise votre fuseau horaire local.

Paul Wintz
la source
0

Essayer d'ajouter mes 2 cents à ce fil (en développant la réponse @ paul-wintz).

Il me semble que lorsque le constructeur Date reçoit une chaîne qui correspond à la première partie du format ISO 8601 (partie date), il effectue une conversion de date précise dans le fuseau horaire UTC avec 0 heure. Lorsque cette date est convertie en heure locale, un décalage de date peut se produire si minuit UTC est une date antérieure dans le fuseau horaire local.

new Date('2020-05-07')
Wed May 06 2020 20:00:00 GMT-0400 (Eastern Daylight Time)

Si la chaîne de date est dans un autre format "plus lâche" (utilise "/" ou la date / mois n'est pas complétée par zéro), elle crée la date dans le fuseau horaire local, donc pas de problème de décalage de date.

new Date('2020/05/07')
Thu May 07 2020 00:00:00 GMT-0400 (Eastern Daylight Time)
new Date('2020-5-07')
Thu May 07 2020 00:00:00 GMT-0400 (Eastern Daylight Time)
new Date('2020-5-7')
Thu May 07 2020 00:00:00 GMT-0400 (Eastern Daylight Time)
new Date('2020-05-7')
Thu May 07 2020 00:00:00 GMT-0400 (Eastern Daylight Time)

Ainsi, une solution rapide, comme mentionné ci-dessus, consiste à remplacer "-" par "/" dans votre chaîne au format ISO uniquement.

new Date('2020-05-07'.replace('-','/'))
Thu May 07 2020 00:00:00 GMT-0400 (Eastern Daylight Time)
Florin D
la source
0

Pour stocker yyyy-mm-ddau format MySql Date, vous devez procéder comme suit:

const newDate = new Date( yourDate.getTime() + Math.abs(yourDate.getTimezoneOffset()*60000) );
console.log(newDate.toJSON().slice(0, 10)); // yyyy-mm-dd
Paulo Guimarães
la source
-1

Votre journal génère GMT afin que vous souhaitiez spécifier votre fuseau horaire:

var doo = new Date("2011-09-24 EST");
bmacx7
la source
3
Cette question a déjà beaucoup de réponses. Si vous voulez quand même répondre à la question, vous devez mentionner quelque chose de nouveau que les autres réponses ne font pas. La première réponse explique déjà plus en détail le problème du fuseau horaire.
Calvin Godfrey
Cette réponse est presque exactement la même que stackoverflow.com/a/7556642/8828658
un arachnide de pierre
Peu importe si son explication est plus approfondie ... son code est toujours différent du mien. Le mien est beaucoup plus simple. Et ouais arachnide de pierre tu as raison. Ma faute.
bmacx7
-3

peu importe, n'a pas remarqué le GMT -0400, ce qui fait que la date est hier

Vous pouvez essayer de définir une «heure» par défaut à 12:00:00

ChrisH
la source
Ouais, j'ai été un peu rapide avec ma réponse, désolé. Révisé ma réponse.
ChrisH
-3

Ce qui suit a fonctionné pour moi -

    var doo = new Date("2011-09-24").format("m/d/yyyy");
Venu
la source
Cela ne fonctionnera toujours pas tant que vous ne jouerez pas avec le fuseau horaire.
Gar