web-dev-qa-db-fra.com

Comment convertir l'heure correctement à travers les fuseaux horaires?

Supposons qu'un utilisateur de CA, US récupère une date, une heure et un fuseau horaire:

Le marathon mondial de la bière débute le 15/8/2013 à 10h00, heure de Paris UTC-08: 00

Un autre utilisateur, en Europe centrale, ouvre la page où cette date et cette heure sont affichées. Il ne veut pas faire de calculs de temps (avait déjà peu de bières). Il veut juste voir cette date et cette heure:

8/15/2013 19:00

Étant donné le navigateur reçoit les informations de date et heure, telles que saisies par l'utilisateur en Californie:

Existe-t-il un moyen, en javascript, sans services Web externes, d'effectuer une conversion correcte? Autrement dit, pour détecter que 10h00 UTC-08: 00 devrait en fait être 10h00 UTC-07: 00, car l'heure d'été est en vigueur.

J'ai peut-être mal compris cela depuis le début, mais je ne veux pas laisser l'utilisateur qui entre choisir s'il doit choisir UTC-08: 00 (PST) ou UTC-07: 00 (PDT). Je suppose que puisque le fuseau horaire standard dans CA est PST, les gens ne pensent pas à PDT en été. Ou le font-ils?

En Europe centrale, la date standard est UTC + 01: 00, la date d'été est UTC + 02: 00. Par conséquent, la différence entre CA et Europe devrait être de 9 heures, à l’exception de deux périodes de l’année, lorsque l’une ou l’autre zone bascule entre les modes Standard et Heure avancée.

Mettre à jour:

Après un peu plus de réflexion et de lecture des commentaires, voici ce dont j'avais idéalement besoin:

var utcOffset = f('2013-08-15T10:00', 'America/Los_Angeles');
// utcOffset == "-07:00"
var utcOffset = f('2013-11-15T10:00', 'America/Los_Angeles');
// utcOffset == "-08:00"

Jusqu'à présent, il semble que le plugin moment.js/timezone , suggéré par Guido Preite en soit capable (plus ou moins).

Tout autre moyen, en utilisant des API de navigateur?

14
rdamborsky

Existe-t-il un moyen, en javascript, sans services Web externes, d'effectuer une conversion correcte? Autrement dit, pour détecter que 10h00 UTC-08: 00 devrait en fait être 10h00 UTC-07: 00, car l'heure d'été est en vigueur.

10: 00-8 et 10: 00-7 sont deux moments différents dans le temps. Ils sont égaux à 18:00 et 17:00 respectivement (Z = UTC). Lorsque vous mesurez un décalage, l’heure avancée n’entre pas dans l’image. Déjà.

Je suppose que puisque le fuseau horaire standard dans CA est PST, les gens ne pensent pas à PDT en été. Ou le font-ils?

En général, les gens ne pensent qu’à «l’heure du Pacifique», ce qui signifie à la fois PST en hiver et PDT en été. Mais les ordinateurs sont plus précis. Lorsque vous voyez PST, cela signifie UTC-8. Lorsque vous voyez PDT, cela signifie UTC-7. Il serait invalide d'étiqueter en utilisant un formulaire tout en se référant simultanément au décalage de l'autre.

Les abréviations de fuseau horaire peuvent être ambiguës . Idéalement, lorsque vous référencez la zone par programme, vous devez utiliser le nom de la zone IANA, tel que America/Los_Angeles. Cependant, ceci n'est actuellement pas possible dans toutes les exécutions JavaScript sans bibliothèque. ( Ils y travaillent bien .)

En Europe centrale, la date standard est UTC + 01: 00, la date d'été est UTC + 02: 00. Par conséquent, la différence entre CA et Europe devrait être de 9 heures, à l’exception de deux périodes de l’année, lorsque l’une ou l’autre zone bascule entre les modes Standard et Heure avancée.

Correct. Ils pourraient être espacés de 8, 9 ou 10 heures. Ils changent à des moments complètement différents, alors n'essayez pas de gérer cela vous-même.

Jusqu'ici, il semble que le plugin moment.js/timezone, suggéré par Guido Preite, soit capable de le faire (plus ou moins).

Moment-timezone est une excellente bibliothèque. Cependant, d'après le scénario que vous avez décrit, je ne pense pas que vous ayez à vous soucier de la conversion de fuseau horaire autant que vous le pensiez. Voyez si vous pouvez suivre cette logique:

  1. En Californie, l'utilisateur entre une date et une heure dans une zone de texte.
  2. Vous lisez cette valeur dans une chaîne, puis vous la analysez dans une date:

    var dt = new Date("8/15/2013 10:00");
    

    ou en utilisant moment.js:

    var m = moment("8/15/2013 10:00", "M/D/YYYY HH:mm");
    
  3. Étant donné que cette opération est effectuée sur l'ordinateur de l'utilisateur, JavaScript suppose automatiquement qu'il s'agit d'une date et d'une heure local. Vous n'avez pas besoin de fournir d'informations de décalage ou de fuseau horaire.

  4. Cela signifie qu’en raison des transitions DST, le temps entré peut être invalide ou ambigu. JavaScript ne fait pas un si bon travail à gérer cela, en fait - vous obtiendrez des résultats différents sur différents navigateurs. Si vous voulez être sans ambiguïté, vous devez fournir un décalage.

    // PST
    var dt = new Date("3/11/2013 1:00 UTC-08:00");
    
    // PDT
    var dt = new Date("3/11/2013 1:00 UTC-07:00");
    
  5. Une fois que vous avez une Date (ou une moment), vous pouvez évaluer son équivalent UTC:

    var s = dt.toISOString();  //  2013-08-15T17:00:00Z
    

    c'est la même chose avec moment.js, mais vous aurez un meilleur support du navigateur:

    var s = m.toISOString();  //  2013-08-15T17:00:00Z
    
  6. Vous stockez cette valeur UTC dans votre base de données.

  7. L'autre utilisateur d'Europe centrale arrive et charge les données.

  8. Vous le transmettez à une Date ou moment en JavaScript:

    var dt = new Date("2013-08-15T17:00:00Z");
    

    ou avec moment.js (encore une fois, meilleur support du navigateur)

    var m = moment("2013-08-15T17:00:00Z")
    
  9. Comme JavaScript connaît les règles de fuseau horaire de l'ordinateur local, vous pouvez maintenant afficher cette date et le fuseau horaire correspondant à celui de l'Europe centrale s'affichera:

    var s = dt.ToString();  //  browser specific output
    // ex: "Thu Aug 15 2013 19:00:00 GMT+0200 (Central Europe Daylight Time)"
    

    ou avec moment.js, vous pouvez mieux contrôler le format de sortie

    var s = m.format("DD/MM/YYYY HH:mm"); // "15/08/2013 19:00"
    

    vous pouvez également laisser moment.js décider du format de sortie à afficher:

    var s = m.format("llll"); // "Thu, 15 Aug 2013 19:00"
    

Pour résumer, si vous souhaitez uniquement effectuer la conversion vers et à partir du fuseau horaire local (quelle que soit la zone), vous pouvez tout faire avec juste Date. Moment.js facilitera l'analyse et le formatage, mais ce n'est pas absolument nécessaire.

Il n'y a que quelques scénarios qui nécessitent une bibliothèque de fuseaux horaires (tels que moment-fuseau horaire ou autres).

  • Vous voulez convertir vers ou depuis une zone qui est pas le fuseau horaire local ou UTC.

  • Vous travaillez avec des dates antérieures, et les règles de fuseau horaire ou d'heure d'été ont été modifiées depuis, et vous avez des dates qui seraient interprétées différemment dans le nouveau règles que avec les anciens. C'est un peu technique, mais ça arrive. Lire plus ici et ici .

22
Matt Johnson

J'ai développé cette solution à partir d'autres exemples ... espérons que cela fonctionne pour vous! Disponible sur jsfiddle .

/* 
* Author: Mohammad M. AlBanna
* Website: MBanna.me
* Description: Get the current time in different time zone 
*/

//Check daylight saving time prototype
Date.prototype.stdTimezoneOffset = function() {
    var jan = new Date(this.getFullYear(), 0, 1);
    var jul = new Date(this.getFullYear(), 6, 1);
    return Math.max(jan.getTimezoneOffset(), jul.getTimezoneOffset());
}

Date.prototype.dst = function() {
    return this.getTimezoneOffset() < this.stdTimezoneOffset();
}

var today = new Date();
var isDST = today.dst() ? true : false;
var pstOffset = isDST ? 7 : 8;
var cstOffset = isDST ? 5 : 6;
var estOffset = isDST ? 4 : 5;
var gmtOffset = 1;

pstOffset = pstOffset * 60 * 60 * 1000;
cstOffset = cstOffset * 60 * 60 * 1000;
estOffset = estOffset * 60 * 60 * 1000;
gmtOffset = gmtOffset * 60 * 60 * 1000;

var todayMillis = today.getTime();
var timeZoneOffset = (today.getTimezoneOffset() * 60 * 1000);

var curretPST = todayMillis - pstOffset; 
var curretCST = todayMillis - cstOffset; 
var curretEST = todayMillis - estOffset;
var curretGMT = todayMillis - gmtOffset;

addP("PST Time : " + new Date(curretPST).toUTCString());
addP("CST Time : " + new Date(curretCST).toUTCString());
addP("EST Time : " + new Date(curretEST).toUTCString());
addP("GMT Time : " + new Date(curretGMT).toUTCString());
addP("Local Time : " + new Date(today.getTime() - timeZoneOffset ).toUTCString());

function addP(value){
    var p = document.createElement("p");
    p.innerHTML = value;
    document.body.appendChild(p);
}
1
Mohammad AlBanna

Le constructeur par défaut crée une instance de l'heure locale

var localDate = new Date(); 

Je ne peux pas le tester pour le moment, mais vous devriez pouvoir fournir votre date/heure (en tant que paramètre au constructeur).

var eventDate = [SOMEDATE];
var localDate = new Date(eventDate);

..et vous devriez pouvoir appeler des fonctions d'objet Date comme getMonth, qui renvoie les données dans le fuseau horaire local. Comme indiqué à: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date

Note1: Sans serveur = il n'y a pas de serveur | db? Si tel est le cas, la date doit être enregistrée au format UTC dans la base de données et chargée en tant qu’heure locale pour chaque utilisateur. Ainsi, vous n’aurez pas à vous inquiéter des conversions.

Note2: Cette question contient du code montrant comment obtenir la différence de fuseau horaire: Comment obtenir l'heure locale exacte du client?

1
Damb