221 votes

Comment vérifier si l'heure d'été est en vigueur et, le cas échéant, le décalage ?

Voici un bout de mon code JS pour lequel j'ai besoin de ce système :

var secDiff = Math.abs(Math.round((utc_date-this.premiere_date)/1000));
this.years = this.calculateUnit(secDiff,(86400*365));
this.days = this.calculateUnit(secDiff-(this.years*(86400*365)),86400);
this.hours = this.calculateUnit((secDiff-(this.years*(86400*365))-(this.days*86400)),3600);
this.minutes = this.calculateUnit((secDiff-(this.years*(86400*365))-(this.days*86400)-(this.hours*3600)),60);
this.seconds = this.calculateUnit((secDiff-(this.years*(86400*365))-(this.days*86400)-(this.hours*3600)-(this.minutes*60)),1);

Je veux obtenir la date en "ago", mais si l'heure d'été est utilisée, les dates sont décalées d'une heure. Je ne sais pas comment vérifier si l'heure d'été est en vigueur ou non.

Comment puis-je savoir quand l'heure d'été commence et se termine ?

2voto

OXiGEN Points 985

Mise à jour : Après avoir essayé d'utiliser ces fonctions dans un datetime j'ai remarqué que le passage de mars à avril faisait basculer le fuseau horaire comme prévu, puisque ma zone bascule dans l'heure d'été en mars. De manière inattendue, le passage au fuseau horaire suivant a eu lieu au lieu de basculer entre l'heure normale et l'heure d'été dans le même fuseau horaire.

Il s'avère que c'est parce que mes fonctions originales créaient toujours new Date() pour le moment présent ou pour un moment fixe arbitraire dans le passé. En comparant cela aux heures relatives de mars et d'avril, il aurait logiquement détecté le basculement de l'heure d'été comme un changement de fuseau horaire.

La solution était de passer les temps relatifs dans les fonctions d'utilité, ainsi toutes mes comparaisons étaient pour le temps relatif au lieu de maintenant ou le temps fixe arbitraire. J'ai perdu un peu de la compacité, mais maintenant la logique fonctionne comme il faut.

Mises à jour du flux de travail :

  • t La valeur par défaut du paramètre new Date()
    • Pour le temps fixe, passer dans un Date
    • Pour l'heure actuelle, passez dans null ou rien
  • std() mis à jour pour utiliser t.setMonth(v); pour changer le mois pour les heures fixes
    • .getTimezoneOffset() ne peut pas être enchaîné à .setMonth() Nous devons donc passer de la notation à une ligne à l'utilisation de fermetures ( {} ), les terminaisons ( ; ), et return
  • console.log() L'exemple passe en boucle chaque mois ( 0 a 11 )

    • L'objet à date fixe doit être cloné en utilisant le même horodatage ( let ts = +t; )
    • El + avant le Date le transforme en un number avec l'horodatage Unix
    • Date() accepte également les timestamps Unix pour créer des temps fixes
    • Si nous ne le clonons pas, chaque appel passera autour de la même Date avec les mois fixés à 6 ce qui va à l'encontre du but recherché
    • Ok, nous ne clonons pas vraiment, nous créons simplement un nouvel objet en utilisant les mêmes paramètres ; même différence ;)

    let ns = { std: (t = new Date()) => Math.max(...[0, 6].map(v => { t.setMonth(v); return t.getTimezoneOffset(); })), is_dst: (t = new Date()) => t.getTimezoneOffset() < ns.std(t), utc: (t, std = 0) => { t = t || new Date(); let z = std ? ns.std(t) : t.getTimezoneOffset(), zm = z % 60; return 'UTC' + (z > 0 ? '-' : '+') + (z / 60) + (zm ? ':' + zm : ''); } };

    //current time only console.log(ns.std(), ns.is_dst(), ns.utc(), ns.utc(null, 1));

    //iterate each month let t = new Date(2021,0,1); for (let i = 0; i < 12; i++) { t.setMonth(i); let ts = +t; console.log(t.toDateString().split(" ")[1], ns.std(new Date(ts)), ns.is_dst(new Date(ts)), ns.utc(new Date(ts)), ns.utc(new Date(ts), 1)); }


Développer la solution compacte et cryptique de @nkitku pour la transformer en un ensemble de fonctions réutilisables.

Flux de travail :

  • Toutes les fonctions ont une portée dans un espace de nom. ns afin qu'elles n'entrent pas en conflit avec d'autres fonctions du code qui peuvent avoir le même nom.
    • L'espacement des noms permet également une notation compacte des fonctions ; std: ()=>Math.max(), est équivalent à function std(){ return Math.max(); }
  • std() renvoie le décalage du fuseau horaire en heure normale
  • [0, 6] met en place une comparaison d'un mois sans DST et d'un mois avec DST
    • 0 pour le mois de janvier, puisque Date.setMonth() est indexé à zéro
    • 6 pour le mois de juillet
    • Apparemment, l'heure normale n'est pas en janvier pour tout le monde, donc nous devons vérifier à la fois en janvier et en juillet.
  • ...[] convertit le Array de mois à un Set afin que nous puissions appliquer la map() fonction
    • Les tableaux bruts ne peuvent pas fonctionner map()
    • map() exécute un ensemble de variables sur la même fonction et renvoie un tableau de résultats
  • Créer un nouveau Date objet avec année, mois, jour
    • L'année ( 95 dans l'exemple) est arbitraire puisque l'année n'est pas importante pour ce calcul.
    • Le mois se branche sur nos valeurs [0, 6] en tant que variable v
    • Le jour ( 1 dans l'exemple) est également arbitraire
    • Logiquement, nous aurions pu créer un new Date() alors .setMonth(v) mais l'utilisation des nombres arbitraires est plus compacte et plus rapide.
  • Maintenant que nous avons les dates, getTimezoneOffset() retourne les décalages pour chaque mois et les pousse dans le tableau de résultats
  • Math.max() trouve la plus grande valeur parmi les résultats, qui sera le décalage de l'heure standard.
  • is_dst() vérifie si c'est actuellement l'heure d'été.
    • new Date().getTimezoneOffset() obtient le décalage actuel, avec ou sans DST
    • ns.std() obtient le décalage en heure normale
    • Si le décalage actuel est inférieur, il s'agit d'un DST.
  • utc() renvoie une chaîne de caractères en notation UTC
    • El std le paramètre est désactivé par défaut
    • z = std ? ns.std() : new Date().getTimezoneOffset() règle l'heure sur DST ou standard en fonction du drapeau
    • zm = z % 60 captures minutes car certaines zones utilisent 30 minutes par exemple
    • (z > 0 ? '-' : '+') attribue le signe correct selon la notation UTC ; les valeurs de décalage positives sont indiquées comme des décalages négatifs dans la notation.
    • (z / 60) saisit les heures dans un format à un chiffre selon la notation, donc pas besoin de .toString().padStart(2,'0 )` pour le format à deux chiffres
    • (zm ? ':' + zm : '') Ajoute les minutes si elles existent pour le fuseau horaire.

Cette version étant destinée à être compacte, vous pourriez gagner encore plus de place en supprimant les espaces blancs superflus. Mais c'est là le travail d'un mineur.

std:()=>Math.max(...[0,6].map(v=>new Date(95,v,1).getTimezoneOffset())),

const ns = {
  std: () => Math.max(...[0, 6].map(v => new Date(95, v, 1).getTimezoneOffset())),
  is_dst: () => new Date().getTimezoneOffset() < ns.std(),
  utc: (std = 0) => {
    let z = std ? ns.std() : new Date().getTimezoneOffset(),
      zm = z % 60;
    return 'UTC' + (z > 0 ? '-' : '+') + (z / 60) + (zm ? ':' + zm : '');
  }
};

console.log(ns.std(), ns.is_dst(), ns.utc(), ns.utc(1));

2voto

Vicky Points 124

Avec https://date-fns.org/v2.22.1/docs/Time-Zones peut être résolu avec une seule ligne

new Date().getUTCHours() + getTimezoneOffset('Europe/Amsterdam') / 1000 / 60 / 60 ;

1 votes

Qu'est-ce que tu veux dire ?

1voto

Larry Enzer Points 11

Tu es proche mais un peu à l'écart. Vous n'avez jamais besoin de calculer votre propre temps car il résulte de votre propre horloge. Il peut détecter si vous utilisez l'heure d'été dans votre région mais pas pour une région éloignée produite par le décalage :

newDateWithOffset = new Date(utc + (3600000*(offset)));

Ce sera toujours faux et décalé d'une heure s'ils sont en DST. Essayez de calculer ceci et changez votre horloge à - disons 2/1/2015 et remettez l'horloge à zéro d'une heure comme si elle était en dehors de l'heure d'été. Ensuite, calculez un décalage pour un lieu qui devrait toujours avoir 2 heures de retard. Le résultat sera une heure d'avance sur la fenêtre de deux heures. Vous devrez toujours tenir compte de l'heure et l'ajuster. Je l'ai fait pour New York et Denver et je me trompe toujours (heure d'avance) à Denver.

0voto

akinuri Points 1019

J'ai récemment eu besoin de créer une chaîne de date avec UTC et DST, et sur la base de la réponse de Sheldon, j'ai mis au point ceci :

Date.prototype.getTimezone = function(showDST) {
    var jan = new Date(this.getFullYear(), 0, 1);
    var jul = new Date(this.getFullYear(), 6, 1);

    var utcOffset = new Date().getTimezoneOffset() / 60 * -1;
    var dstOffset = (jan.getTimezoneOffset() - jul.getTimezoneOffset()) / 60;

    var utc = "UTC" + utcOffset.getSign() + (utcOffset * 100).preFixed(1000);
    var dst = "DST" + dstOffset.getSign() + (dstOffset * 100).preFixed(1000);

    if (showDST) {
        return utc + " (" + dst + ")";
    }

    return utc;
}
Number.prototype.preFixed = function (preCeiling) {
    var num = parseInt(this, 10);
    if (preCeiling && num < preCeiling) {
        num = Math.abs(num);
        var numLength        = num.toString().length;
        var preCeilingLength = preCeiling.toString().length;
        var preOffset        = preCeilingLength - numLength;
        for (var i = 0; i < preOffset; i++) {
            num = "0" + num;
        }
    }
    return num;
}
Number.prototype.getSign = function () {
    var num  = parseInt(this, 10);
    var sign = "+";
    if (num < 0) {
        sign = "-";
    }
    return sign;
}

document.body.innerHTML += new Date().getTimezone() + "<br>";
document.body.innerHTML += new Date().getTimezone(true);

<p>Output for Turkey (UTC+0200) and currently in DST: &nbsp; UTC+0300 (DST+0100)</p>
<hr>

0voto

Y C Points 51

Y a-t-il un problème à utiliser le Date.toString().indexOf('Daylight Time') > -1

"" + new Date()

Sat Jan 01 100050 00:00:00 GMT-0500 (Eastern Standard Temps)

"" + new Date(...)

Sun May 01 100033 00:00:00 GMT-0400 (Eastern Lumière du jour Temps)

Cela semble compatible avec tous les navigateurs.

5 votes

Oui, ça ne marche pas partout dans le monde. En été, en Europe, on a "Thu Jul 02 2020 14:07:01 GMT+0200 (Central European Summer Time)"

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