453 votes

Créer une date avec un fuseau horaire défini sans utiliser une représentation sous forme de chaîne de caractères

J'ai une page Web avec trois listes déroulantes pour le jour, le mois et l'année. Si j'utilise le JavaScript Date qui prend des nombres, alors j'obtiens un Date pour mon fuseau horaire actuel :

new Date(xiYear, xiMonth, xiDate)

Donner la date correcte, mais il pense que cette date est GMT+01:00 en raison de l'heure d'été.

Le problème ici est que je passe ensuite cette Date à une méthode Ajax et lorsque la date est désérialisée sur le serveur, elle a été convertie en GMT et a donc perdu une heure, ce qui fait reculer le jour d'une unité. Maintenant, je pourrais simplement passer le jour, le mois et l'année individuellement dans la méthode Ajax, mais il semble qu'il devrait y avoir un meilleur moyen.

La réponse acceptée m'a orienté dans la bonne direction, mais en utilisant simplement la fonction setUTCHours() par lui-même changé :

Apr 5th 00:00 GMT+01:00 

a

Apr 4th 23:00 GMT+01:00

J'ai également dû définir la date, le mois et l'année UTC pour obtenir le résultat suivant

Apr 5th 01:00 GMT+01:00

ce qui est ce que je voulais.

12 votes

Si la réponse acceptée vous a indiqué la bonne direction mais n'a pas répondu à votre question, je dirais qu'elle ne devrait pas être la réponse acceptée. La réponse doit répondre à la question posée.

511voto

jishi Points 10442

En utilisant .setUTCHours() il serait possible de définir les dates en temps UTC, ce qui permettrait d'utiliser les heures UTC dans tout le système.

Vous ne pouvez pas le définir en utilisant UTC dans le constructeur, à moins que vous ne spécifiez une chaîne de date.

Utilisation de new Date(Date.UTC(year, month, day, hour, minute, second)) vous pouvez créer un objet Date à partir d'une heure UTC spécifique.

107 votes

La syntaxe "new Date(Date.UTC(...))" vous permet de créer une date qui est équivalent à une date UTC en termes de point dans le temps qu'elle représente, mais elle n'est pas la même - elle a un fuseau horaire différent (non UTC).

56 votes

N'oubliez pas que lorsque vous utilisez "Date", la valeur "mois" est comprise entre 0 et 11 (et non entre 1 et 12). Je continuais à obtenir un décalage horaire de 2h (alors qu'il aurait dû être de 1h) et il m'a fallu des heures pour découvrir que la raison était un mauvais mois.

4 votes

Cette réponse est géniale. Mais j'utilise une bibliothèque [datepicker ui] qui utilise new Date à plusieurs endroits. Tout ce que je veux, c'est définir le fuseau horaire UTC et chaque date sera conforme au nouveau fuseau horaire. Je suis surpris que Javascript n'ait rien pour cela.

210voto

T.W.R.Cole Points 726
var d = new Date(xiYear, xiMonth, xiDate);
d.setTime( d.getTime() + d.getTimezoneOffset()*60*1000 );

Cette réponse est adaptée spécifiquement à la question initiale, et ne donnera pas la réponse que vous attendez nécessairement. En particulier, certaines personnes voudront soustraire le décalage du fuseau horaire au lieu de l'ajouter. Rappelez-vous cependant que le but de cette solution est de modifier l'objet date de javascript pour une désérialisation particulière, et non d'être correct dans tous les cas.

1 votes

Vous pourriez juste faire *60000 au lieu de *60*1000 :)

62 votes

@gthmb bien sûr, mais j'ai l'impression que *60*1000 est plus clair dans ce cas ; en d'autres termes, la raison de sa présence est assez évidente.

22 votes

Cela fonctionne presque pour moi, sauf que je dois utiliser - (moins) au lieu de + (plus) pour obtenir l'heure correcte pour mon fuseau horaire.

183voto

monsterclub Points 141

Je crois que vous avez besoin de la createDateAsUTC (veuillez comparer avec la fonction convertDateToUTC )

function createDateAsUTC(date) {
    return new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate(), date.getHours(), date.getMinutes(), date.getSeconds()));
}

function convertDateToUTC(date) { 
    return new Date(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), date.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds()); 
}

39 votes

Je suis étonné de la clarté et de l'utilité de ses réponses. Je ne savais pas que travailler avec des dates en Javascript était un tel cauchemar jusqu'à aujourd'hui :S

0 votes

Pouvez-vous expliquer la différence entre les deux ? Le premier se convertit date dans le fuseau horaire UTC, mais la seconde semble ne rien faire d'utile ? (renvoie la même date que date )

4 votes

Je comprends maintenant : La première renvoie la date dans le fuseau horaire UTC, avec les valeurs littérales de date de l'heure locale. La seconde renvoie la date dans le fuseau horaire local, mais avec les valeurs littérales de la date UTC.

28voto

Andrzej Doyle Points 52541

Je ne pense pas que cela soit possible - il n'est pas possible de définir le fuseau horaire d'un objet Date après sa création.

Et d'une certaine manière, cela a du sens - conceptuellement (si ce n'est peut-être pas dans la mise en œuvre) ; par http://en.wikipedia.org/wiki/Unix_timestamp (c'est moi qui souligne) :

Le temps Unix, ou temps POSIX, est un système permettant de décrire des instants dans le temps, définis comme le nombre de secondes écoulées depuis minuit. Temps universel coordonné (UTC) du jeudi 1er janvier 1970.

Une fois que vous en avez construit un, il représentera un certain point en temps "réel". Le fuseau horaire n'est pertinent que lorsque vous souhaitez convertir ce point de temps abstrait en une chaîne de caractères lisible par l'homme.

Il est donc logique que vous ne puissiez modifier l'heure réelle que la date représente que dans le constructeur. Malheureusement, il semble qu'il n'y ait aucun moyen de passer un fuseau horaire explicite - et le constructeur que vous appelez (sans doute correctement) traduit vos variables d'heure "locales" en GMT lorsqu'il les stocke de manière canonique - il n'y a donc aucun moyen d'utiliser la fonction int, int, int Constructeur pour les heures GMT.

D'un point de vue positif, il est trivial d'utiliser le constructeur qui prend un String à la place. Il n'est même pas nécessaire de convertir le mois numérique en chaîne de caractères (du moins sur Firefox), donc j'espérais qu'une implémentation naïve fonctionnerait. Cependant, après l'avoir essayé, il fonctionne avec succès dans Firefox, Chrome et Opera mais échoue dans Konqueror ("Invalid Date"), Safari ("Invalid Date") et IE ("NaN"). Je suppose qu'il suffirait de disposer d'un tableau de consultation pour convertir le mois en une chaîne de caractères, comme suit :

var months = [ '', 'January', 'February', ..., 'December'];

function createGMTDate(xiYear, xiMonth, xiDate) {
   return new Date(months[xiMonth] + ' ' + xiDate + ', ' + xiYear + ' 00:00:00 GMT');
}

6 votes

S'il n'y a aucun moyen de "définir le fuseau horaire d'un objet Date après sa création", voulez-vous dire qu'il existe un moyen de définir le fuseau horaire d'un objet Date ? comme il est créé ? Il ne semble pas qu'une date js soit "une enveloppe fine autour d'un nombre de secondes depuis l'époque" - il semble qu'il s'agisse de ce nombre de secondes, plus un fuseau horaire.

1 votes

@Anthony, Il ne peut utiliser que le fuseau horaire du client. Javascript peut faire un aller-retour entre local et utc, mais il n'a pas accès à une base de données de fuseaux horaires. Il ne peut pas, par exemple, vous indiquer l'heure de Mexico lorsque vous vous trouvez à San Diego.

18voto

Norman Gray Points 4337

Si vous souhaitez traiter le problème légèrement différent, mais connexe, de la création d'un objet Date en Javascript à partir de l'année, du mois, du jour, ..., y compris le fuseau horaire - c'est-à-dire que si vous voulez analyser une chaîne de caractères pour en faire une date, vous devez apparemment effectuer un exercice compliqué et exaspérant :

// parseISO8601String : string -> Date
// Parse an ISO-8601 date, including possible timezone,
// into a Javascript Date object.
//
// Test strings: parseISO8601String(x).toISOString()
// "2013-01-31T12:34"              -> "2013-01-31T12:34:00.000Z"
// "2013-01-31T12:34:56"           -> "2013-01-31T12:34:56.000Z"
// "2013-01-31T12:34:56.78"        -> "2013-01-31T12:34:56.780Z"
// "2013-01-31T12:34:56.78+0100"   -> "2013-01-31T11:34:56.780Z"
// "2013-01-31T12:34:56.78+0530"   -> "2013-01-31T07:04:56.780Z"
// "2013-01-31T12:34:56.78-0330"   -> "2013-01-31T16:04:56.780Z"
// "2013-01-31T12:34:56-0330"      -> "2013-01-31T16:04:56.000Z"
// "2013-01-31T12:34:56Z"          -> "2013-01-31T12:34:56.000Z"
function parseISO8601String(dateString) {
    var timebits = /^([0-9]{4})-([0-9]{2})-([0-9]{2})T([0-9]{2}):([0-9]{2})(?::([0-9]*)(\.[0-9]*)?)?(?:([+-])([0-9]{2})([0-9]{2}))?/;
    var m = timebits.exec(dateString);
    var resultDate;
    if (m) {
        var utcdate = Date.UTC(parseInt(m[1]),
                               parseInt(m[2])-1, // months are zero-offset (!)
                               parseInt(m[3]),
                               parseInt(m[4]), parseInt(m[5]), // hh:mm
                               (m[6] && parseInt(m[6]) || 0),  // optional seconds
                               (m[7] && parseFloat(m[7])*1000) || 0); // optional fraction
        // utcdate is milliseconds since the epoch
        if (m[9] && m[10]) {
            var offsetMinutes = parseInt(m[9]) * 60 + parseInt(m[10]);
            utcdate += (m[8] === '+' ? -1 : +1) * offsetMinutes * 60000;
        }
        resultDate = new Date(utcdate);
    } else {
        resultDate = null;
    }
    return resultDate;
}

En d'autres termes, vous créez une "heure UTC" en utilisant la date sans le fuseau horaire (afin de savoir dans quelle région elle se trouve, à savoir la "région" UTC, et elle n'est pas proposée par défaut dans la région locale), puis vous appliquez manuellement le décalage horaire indiqué.

Ça n'aurait pas été bien si quelqu'un avait effectivement pensée sur l'objet date Javascript depuis plus de, oooh, cinq minutes....

1 votes

Merci pour cette excellente fonction ! la seule chose que je changerais serait d'ajouter le support des deux points dans le décalage du fuseau horaire. var timebits = /^([0-9]{4})-([0-9]{2})-([0-9]{2})T([0-9]{2}) :([0-9]{2})(? :([0-9]*)( \. [0-9]*)?)‌​?(?:([+-])([0-9]{2}[‌​:]?)([0-9]{2}))?/;

2 votes

Ils y ont pensé ; malheureusement, le "ils" était les concepteurs du langage Java, car JS a simplement copié la classe Date de Java pour son implémentation initiale.

0 votes

@Xanthir Oooh, vous avez raison, et j'avais oublié à quel point l'objet Date original de Java était horrible ; mais au moins Java l'a déprécié et est passé à autre chose, ce que Javascript semble incapable de faire (c'est un langage bizarre, Javascript : plutôt mignon, et pas aussi horrible qu'il n'y paraît).

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