Analyser la date sans javascript de fuseau horaire

147

Je souhaite analyser la date sans fuseau horaire en JavaScript. J'ai essayé:

new Date(Date.parse("2005-07-08T00:00:00+0000"));

Renvoie le vendredi 8 juillet 2005 02:00:00 GMT + 0200 (heure avancée d'Europe centrale)

new Date(Date.parse("2005-07-08 00:00:00 GMT+0000"));

Renvoie le même résultat

new Date(Date.parse("2005-07-08 00:00:00 GMT-0000"));

Renvoie le même résultat

Je veux analyser le temps:

  1. Sans fuseau horaire.

  2. Sans appeler le constructeur Date.UTC ou new Date (année, mois, jour).

  3. Juste une simple chaîne de passage dans le constructeur de date (sans approches de prototype).

  4. Je dois faire l' Dateobjet d'un produit , non String.

Athlan
la source
3
Vous pouvez simplement omettre le Date.parsebtw et passer directement la chaîne au Dateconstructeur.
Bergi
1
Je ne sais pas pourquoi vous en avez besoin, mais je suis presque sûr que Date a toujours le fuseau horaire local de l'utilisateur. Si vous voulez que votre JavaScript fonctionne avec d'autres fuseaux horaires que vous devrez utiliser un objet wrapper pour Date, cela fonctionnera peut-être pour vous: github.com/mde/timezone-js
HMR
1
Malheureusement, j'ai dû copier l' Dateobjet pour obtenir l'objet correct pour comparer les dates dans MongoDB:new Date(dateStart.getFullYear(), dateStart.getMonth(), dateStart.getDate())
Athlan
Si vous souhaitez analyser une date sans heure, vous devez spécifier le fuseau horaire que vous souhaitez utiliser, car «2005-07-08» signifie différentes choses dans différents fuseaux horaires. À partir de mai 2020, la documentation MDN déconseille toute fonctionnalité d'analyse de date intégrée en raison des différences d'implémentation. Cependant, l'utilisation de Date.parse ("2005-07-08") retournera probablement une heure de 00:00 UTC. date-fns parse d'autre part, retournera 00:00 heure locale lors de l'analyse de la même chaîne de date
Andy

Réponses:

106

La date est correctement analysée, c'est juste toString qui la convertit dans votre fuseau horaire local:

let s = "2005-07-08T11:22:33+0000";
let d = new Date(Date.parse(s));

// this logs for me 
// "Fri Jul 08 2005 13:22:33 GMT+0200 (Central European Summer Time)" 
// and something else for you

console.log(d.toString()) 

// this logs
// Fri, 08 Jul 2005 11:22:33 GMT
// for everyone

console.log(d.toUTCString())

Les objets Javascript Date sont des horodatages - ils contiennent simplement un certain nombre de millisecondes depuis l'époque. Il n'y a pas d'informations de fuseau horaire dans un objet Date. Quelle date calendaire (jour, minutes, secondes) cet horodatage représente est une question d'interprétation (une des to...Stringméthodes).

L'exemple ci-dessus montre que la date est correctement analysée - c'est-à-dire qu'elle contient en fait une quantité de millisecondes correspondant à "2005-07-08T11: 22: 33" en GMT.

Georg
la source
4
Malheureusement, je dois produire un objet Date, pas une chaîne.
Athlan
@Athlan: ajout de quelques explications.
georg
1
J'avais vérifié. J'ai passé la date analysée en requête MongoDB new Date(Date.parse("2005-07-08T11:22:33+0000"))et date copiée par le constructeur: new Date(dateStart.getFullYear(), dateStart.getMonth(), dateStart.getDate()). Les deux solutions, des résultats différents, deuxième correct! Votre réponse était utile, juste mentionnée dans hunlock.com/blogs/Javascript_Dates-The_Complete_Reference . Up.
Athlan
A parfaitement fonctionné pour moi - .toUTCString () était le ticket qui m'a donné l'heure correcte de retour de la chaîne d'origine. ie nouvelle Date ("2016-08-22T19: 45: 00.0000000"). toUTCString ()
Michael Giovanni Pumo
38
La racine de tout mal dans les dates et l'heure JavaScript est contenue dans votre première phrase ... C'est juste toString qui le CONVERTI dans votre fuseau horaire local ... Où est la responsabilité unique dans ce domaine? La méthode toString doit simplement stringifier le résultat et ne pas le convertir. Si je veux que la date soit convertie, je devrais avoir d'autres méthodes pour le faire.
ancre
109

J'ai le même problème. J'obtiens une date sous forme de chaîne, par exemple: '2016-08-25T00: 00: 00', mais j'ai besoin d'un objet Date avec l'heure correcte. Pour convertir String en objet, j'utilise getTimezoneOffset:

var date = new Date('2016-08-25T00:00:00')
var userTimezoneOffset = date.getTimezoneOffset() * 60000;
new Date(date.getTime() - userTimezoneOffset);

getTimezoneOffset()renverra une valeur négative ou positive de l'éther. Cela doit être soustrait pour fonctionner dans tous les endroits du monde.

wawka
la source
6
J'ai le même problème et j'ai trouvé cela utile. Cependant, j'ai trouvé que cela ne gère pas les décalages de fuseau horaire en raison de l'heure d'été. Exemple: je suis en mode PST donc mon décalage actuel (en mars) par rapport à GMT est -8: 00, mais en mai, il serait -7: 00. Ma solution était de calculervar userTimezoneOffset = date.getTimezoneOffset()*60000;
mmh02
3
À moins que je ne sois complètement idiot, cela revient en fait au mauvais moment. getTimezoneOffset()renvoie le nombre de minutes dans la direction opposée à laquelle vous pensez - mon fuseau horaire est UTC-4 pour le moment mais getTimezoneOffset()renvoie un 240 positif. Par conséquent, il userTimezoneOffsetdoit être soustrait date.getTime()et non ajouté.
vaindil
1
Je suis d'accord avec @vaindil que vous devriez soustraire. La solution de wakwa ne fonctionne que lorsque vous êtes du bon côté de Greenwich. Wakwas devrait le corriger.
Janne Harju
1
Ah! a parlé trop tôt. Cela ne fonctionne pas pour la plupart des fuseaux horaires. Je peux confirmer qu'il renvoie une date erronée lors de la compensation des heures AEST et CEST avec l'heure GMT.
saran3h
1
@vaindil maintenant le résultat est le même que new Date('2016-08-25T00:00:00Z')je pense que le but était de manipuler new Date('2016-08-25T00:00:00Z')pour que l'heure locale soit affichée avec l'heure 0:00 mais ce code a manquéZ
barbsan
14

J'ai rencontré le même problème, puis je me suis souvenu de quelque chose de bizarre à propos d'un projet hérité sur lequel je travaillais et de la façon dont ils ont géré ce problème. Je ne l'ai pas compris à l'époque et je m'en fichais vraiment jusqu'à ce que je rencontre moi-même le problème

var date = '2014-01-02T00:00:00.000Z'
date = date.substring(0,10).split('-')
date = date[1] + '-' + date[2] + '-' + date[0]

new Date(date) #Thu Jan 02 2014 00:00:00 GMT-0600

Pour une raison quelconque, le fait de passer la date en tant que «01 -02-2014» définit le fuseau horaire sur zéro et ignore le fuseau horaire de l'utilisateur. Cela peut être un hasard dans la classe Date, mais il existait il y a quelque temps et existe aujourd'hui. Et cela semble fonctionner entre les navigateurs. Essayez-le par vous-même.

Ce code est implémenté dans un projet global où les fuseaux horaires importent beaucoup mais la personne qui regarde la date ne se soucie pas du moment exact où elle a été introduite.

Iwnnay
la source
Je pense que c'est intentionnel parce que le "Z" désigne UTC que JS convertit ensuite, mais sans fuseau horaire, il ne peut pas le convertir, donc il suppose essentiellement le fuseau horaire de l'utilisateur. J'adorerais avoir une confirmation ou une meilleure explication.
dlsso
7
Le comportement bancal est dû aux tirets. Chrome, Firefox et IE11 interprètent tous 2014/5/31et 2014/05/31comme Sam 31 mai 2014 00:00:00 GMT-0600 (heure avancée de la montagne) `(MDT étant mon fuseau horaire actuel). Avec des tirets ... tous les navigateurs interprètent 2014-05-31comme ven 30 mai 2014 18:00:00 GMT-0600 (Mountain Daylight Time). Curieusement, avec 2014-5-31, Chrome revient samedi, Firefox revient vendredi et IE11 dit que la date n'est pas valide. On dirait qu'un date.replace('-','/')pourrait faire l'affaire.
atheaos
6

L' Dateobjet lui-même contiendra de toute façon le fuseau horaire, et le résultat renvoyé est l'effet de sa conversion en chaîne par défaut. C'est-à-dire que vous ne pouvez pas créer un objet de date sans fuseau horaire. Mais ce que vous pouvez faire est d'imiter le comportement de l' Dateobjet en créant le vôtre. Il est cependant préférable de le remettre à des bibliothèques comme moment.js .

Michik
la source
2
Malheureusement, je dois produire un objet Date, pas une chaîne.
Athlan
3

solution simple

const handler1 = {
  construct(target, args) {
    let newDate = new target(...args);
    var tzDifference = newDate.getTimezoneOffset();
    return new target(newDate.getTime() + tzDifference * 60 * 1000);
  }
};

Date = new Proxy(Date, handler1);
Alexey
la source
3

La date en javascript est simplement simple à l'intérieur. les données date-heure sont donc stockées à l'époque unix UTC (millisecondes ou ms).

Si vous voulez avoir une heure "fixe" qui ne change pas quel que soit le fuseau horaire dans lequel vous vous trouvez sur terre, vous pouvez ajuster l'heure en UTC pour qu'elle corresponde à votre fuseau horaire local actuel et l'enregistrer. Et lorsque vous le récupérez, quel que soit votre fuseau horaire local dans lequel vous vous trouvez, il affichera l'heure UTC ajustée en fonction de celui qui l'a sauvegardée et ajoutera le décalage du fuseau horaire local pour obtenir l'heure "fixe".

Pour enregistrer la date (en ms)

toUTC(datetime) {
  const myDate = (typeof datetime === 'number')
    ? new Date(datetime)
    : datetime;

  if (!myDate || (typeof myDate.getTime !== 'function')) {
    return 0;
  }

  const getUTC = myDate.getTime();
  const offset = myDate.getTimezoneOffset() * 60000; // It's in minutes so convert to ms
  return getUTC - offset; // UTC - OFFSET
}

Pour récupérer / afficher la date (en ms)

fromUTC(datetime) {
  const myDate = (typeof datetime === 'number')
    ? new Date(datetime)
    : datetime;

  if (!myDate || (typeof myDate.getTime !== 'function')) {
    return 0;
  }

  const getUTC = myDate.getTime();
  const offset = myDate.getTimezoneOffset() * 60000; // It's in minutes so convert to ms
  return getUTC + offset; // UTC + OFFSET
}

Ensuite vous pouvez:

const saveTime = new Date(toUTC(Date.parse("2005-07-08T00:00:00+0000")));
// SEND TO DB....

// FROM DB...
const showTime = new Date(fromUTC(saveTime));
DRBendanillo
la source
2

Vous pouvez utiliser ce code

var stringDate = "2005-07-08T00:00:00+0000";
var dTimezone = new Date();
var offset = dTimezone.getTimezoneOffset() / 60;
var date = new Date(Date.parse(stringDate));
date.setHours(date.getHours() + offset);
deype0
la source
1
Je ne pense pas que cela tienne compte de l'heure d'été
Daniel Thompson
2

Puisqu'il s'agit vraiment d'un problème de formatage lors de l'affichage de la date (par exemple, les affichages en heure locale), j'aime utiliser le nouvel objet (ish) Intl.DateTimeFormat pour effectuer le formatage car il est plus explicite et fournit plus d'options de sortie:

const dateOptions = { timeZone: 'UTC', month: 'long', day: 'numeric', year: 'numeric' };

const dateFormatter = new Intl.DateTimeFormat('en-US', dateOptions);
const dateAsFormattedString = dateFormatter.format(new Date('2019-06-01T00:00:00.000+00:00'));

console.log(dateAsFormattedString) // "June 1, 2019"

Comme indiqué, en définissant la zone horaire sur «UTC», il n'effectuera pas de conversions locales. En prime, il vous permet également de créer des sorties plus soignées. Vous pouvez en savoir plus sur l' objet Intl.DateTimeFormat de Mozilla - Intl.DateTimeFormat .

Éditer:

La même fonctionnalité peut être obtenue sans créer un nouvel Intl.DateTimeFormatobjet. Passez simplement les options de paramètres régionaux et de date directement dans la toLocaleDateString()fonction.

const dateOptions = { timeZone: 'UTC', month: 'long', day: 'numeric', year: 'numeric' };
const myDate = new Date('2019-06-01T00:00:00.000+00:00');
today.toLocaleDateString('en-US', dateOptions); // "June 1, 2019"
John Galt
la source
1

Juste une note générique. un moyen de le garder flexible.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date

Nous pouvons utiliser getMinutes (), mais il ne renvoie qu'un seul nombre pendant les 9 premières minutes.

let epoch = new Date() // Or any unix timestamp

let za = new Date(epoch),
    zaR = za.getUTCFullYear(),
    zaMth = za.getUTCMonth(),
    zaDs = za.getUTCDate(),
    zaTm = za.toTimeString().substr(0,5);

console.log(zaR +"-" + zaMth + "-" + zaDs, zaTm)

Date.prototype.getDate()
    Returns the day of the month (1-31) for the specified date according to local time.
Date.prototype.getDay()
    Returns the day of the week (0-6) for the specified date according to local time.
Date.prototype.getFullYear()
    Returns the year (4 digits for 4-digit years) of the specified date according to local time.
Date.prototype.getHours()
    Returns the hour (0-23) in the specified date according to local time.
Date.prototype.getMilliseconds()
    Returns the milliseconds (0-999) in the specified date according to local time.
Date.prototype.getMinutes()
    Returns the minutes (0-59) in the specified date according to local time.
Date.prototype.getMonth()
    Returns the month (0-11) in the specified date according to local time.
Date.prototype.getSeconds()
    Returns the seconds (0-59) in the specified date according to local time.
Date.prototype.getTime()
    Returns the numeric value of the specified date as the number of milliseconds since January 1, 1970, 00:00:00 UTC (negative for prior times).
Date.prototype.getTimezoneOffset()
    Returns the time-zone offset in minutes for the current locale.
Date.prototype.getUTCDate()
    Returns the day (date) of the month (1-31) in the specified date according to universal time.
Date.prototype.getUTCDay()
    Returns the day of the week (0-6) in the specified date according to universal time.
Date.prototype.getUTCFullYear()
    Returns the year (4 digits for 4-digit years) in the specified date according to universal time.
Date.prototype.getUTCHours()
    Returns the hours (0-23) in the specified date according to universal time.
Date.prototype.getUTCMilliseconds()
    Returns the milliseconds (0-999) in the specified date according to universal time.
Date.prototype.getUTCMinutes()
    Returns the minutes (0-59) in the specified date according to universal time.
Date.prototype.getUTCMonth()
    Returns the month (0-11) in the specified date according to universal time.
Date.prototype.getUTCSeconds()
    Returns the seconds (0-59) in the specified date according to universal time.
Date.prototype.getYear()
    Returns the year (usually 2-3 digits) in the specified date according to local time. Use getFullYear() instead. 
NVRM
la source
-1

(new Date().toString()).replace(/ \w+-\d+ \(.*\)$/,"")

Cela aura la sortie: Tue Jul 10 2018 19:07:11

(new Date("2005-07-08T11:22:33+0000").toString()).replace(/ \w+-\d+ \(.*\)$/,"")

Cela aura la sortie: Fri Jul 08 2005 04:22:33

Remarque: l'heure renvoyée dépendra de votre fuseau horaire local

xxnations
la source
-1

C'est la solution que j'ai trouvée pour ce problème qui fonctionne pour moi.


bibliothèque utilisée: momentjs avec la classe Date javascript.

Étape 1. Convertissez la date de chaîne en objet moment (PS: moment conserve la date et l'heure d'origine tant que la toDate()méthode n'est pas appelée):

const dateMoment = moment("2005-07-08T11:22:33+0000");

Étape 2. Extrait hourset minutesvaleurs de l'objet Moment créé précédemment:

  const hours = dateMoment.hours();
  const mins = dateMoment.minutes();

Étape 3. Convertissez le moment en date (PS: cela changera la date d'origine en fonction du fuseau horaire de votre navigateur / machine, mais ne vous inquiétez pas et lisez l'étape 4.):

  const dateObj = dateMoment.toDate();

Étape 4. Réglez manuellement les heures et les minutes extraites à l'étape 2.

  dateObj.setHours(hours);
  dateObj.setMinutes(mins);

Étape 5. dateObj va maintenant afficher la date d'origine sans aucune différence de fuseau horaire. Même les changements d'heure d'été n'auront aucun effet sur l'objet de date car nous définissons manuellement les heures et les minutes d'origine.

J'espère que cela t'aides.

saran3h
la source
-7

Il existe des problèmes inhérents à l'analyse des dates qui ne sont malheureusement pas bien résolus par défaut.

-Les dates lisibles par l'homme ont un fuseau horaire implicite
-Il existe de nombreux formats de date largement utilisés sur le Web qui sont ambigus

Pour résoudre ces problèmes facilement et proprement, il faudrait une fonction comme celle-ci:

>parse(whateverDateTimeString,expectedDatePattern,timezone)
"unix time in milliseconds"

J'ai cherché ceci, mais je n'ai rien trouvé de tel!

J'ai donc créé: https://github.com/zsoltszabo/timestamp-grabber

Prendre plaisir!

user2667976
la source