web-dev-qa-db-fra.com

Comment vérifier si l'heure d'été est en vigueur et s'il s'agit de quel décalage?

Ceci est un peu de mon code JS pour lequel cela est nécessaire:

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 et la date dans il y a, mais si le DST est utilisé, les dates sont décalées d'une heure. Je ne sais pas comment vérifier si le DST est utilisé ou non.

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

139
Jo Smo

Ce code utilise le fait que getTimezoneOffset renvoie une valeur supérieure entre l'heure avancée et l'heure avancée (DST). Ainsi, il détermine la sortie attendue pendant l’heure standard et compare si la sortie de la date donnée est identique (Standard) ou inférieure (DST).

Notez que getTimezoneOffset renvoie des nombres de minutes positifs pour les zones ouest de UTC, qui sont généralement exprimés sous la forme négative heures (car ils sont "derrière" UTC). Par exemple, Los Angeles est TC – 8h Standard, TC-7h DST. getTimezoneOffset renvoie 480 (positif de 480 minutes) en décembre (hiver, heure normale), plutôt que -480. Il renvoie des nombres négatifs pour l'hémisphère oriental (tel que -600 pour Sydney en hiver, bien que ce soit "en avance" (TC + 10h).

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.isDstObserved = function () {
    return this.getTimezoneOffset() < this.stdTimezoneOffset();
}

var today = new Date();
if (today.isDstObserved()) { 
    alert ("Daylight saving time!");
}
284
Sheldon Griffin

Créez deux dates: une en juin et une en janvier. Comparez leurs valeurs getTimezoneOffset ().

  • si décalage de janvier> décalage de juin, le client se trouve dans l'hémisphère nord
  • si décalage de janvier <décalage de juin, le client se trouve dans l'hémisphère sud
  • si aucune différence, le fuseau horaire du client n'observe pas l'heure d'été

Maintenant, vérifiez getTimezoneOffset () de la date actuelle.

  • si égal à juin, hémisphère nord, le fuseau horaire actuel est DST (+1 heure)
  • si égal à janvier, hémisphère sud, le fuseau horaire actuel est DST (+1 heure)
19
Jon Nylander

J’étais confronté au même problème aujourd’hui, mais comme notre heure d’heure commence et s’arrête à des heures différentes de celle des États-Unis (du moins de ma compréhension), j’ai emprunté un itinéraire légèrement différent.

var arr = [];
for (var i = 0; i < 365; i++) {
 var d = new Date();
 d.setDate(i);
 newoffset = d.getTimezoneOffset();
 arr.Push(newoffset);
}
DST = Math.min.apply(null, arr);
nonDST = Math.max.apply(null, arr);

Ensuite, il vous suffit de comparer le décalage de fuseau horaire actuel avec DST et nonDST pour déterminer celui qui correspond.

12
Aaron Cole

Cette réponse est assez similaire à la réponse acceptée, mais ne remplace pas le prototype Date et n'utilise qu'un seul appel de fonction pour vérifier si l'heure d'été est effective plutôt que deux.


L'idée est la suivante: aucun pays n'observant l'heure d'été de 7 mois[1], dans une zone qui observe DST, le décalage par rapport à l’heure UTC de janvier sera différent de celui de juillet.

Alors que l'heure d'été fait avancer les horloges , JavaScript renvoie toujours une valeur supérieure pendant l'heure normale. Par conséquent, obtenir le décalage minimum entre janvier et juillet générera le décalage du fuseau horaire pendant l'heure d'été.

Nous vérifions ensuite si le fuseau horaire des dates est égal à cette valeur minimale. Si c'est le cas, nous sommes en heure d'été; sinon nous ne le sommes pas.

La fonction suivante utilise cet algorithme. Il faut un objet de date, d, et renvoie true si l'heure d'été est en vigueur pour cette date et false s'il ne l'est pas:

function isDST(d) {
    let jan = new Date(d.getFullYear(), 0, 1).getTimezoneOffset();
    let jul = new Date(d.getFullYear(), 6, 1).getTimezoneOffset();
    return Math.max(jan, jul) != d.getTimezoneOffset(); 
}
10
Toastrackenigma

Sur la base du commentaire de Matt Johanson sur la solution fournie par Sheldon Griffin, j'ai créé le code suivant:

    Date.prototype.stdTimezoneOffset = function() {
        var fy=this.getFullYear();
        if (!Date.prototype.stdTimezoneOffset.cache.hasOwnProperty(fy)) {

            var maxOffset = new Date(fy, 0, 1).getTimezoneOffset();
            var monthsTestOrder=[6,7,5,8,4,9,3,10,2,11,1];

            for(var mi=0;mi<12;mi++) {
                var offset=new Date(fy, monthsTestOrder[mi], 1).getTimezoneOffset();
                if (offset!=maxOffset) { 
                    maxOffset=Math.max(maxOffset,offset);
                    break;
                }
            }
            Date.prototype.stdTimezoneOffset.cache[fy]=maxOffset;
        }
        return Date.prototype.stdTimezoneOffset.cache[fy];
    };

    Date.prototype.stdTimezoneOffset.cache={};

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

Il essaie d’obtenir le meilleur de tous les mondes en tenant compte de tous les commentaires et réponses précédemment suggérés, et plus précisément de ce qui suit:

1) Met en cache le résultat annuel stdTimezoneOffset afin que vous n'ayez pas besoin de le recalculer lorsque vous testez plusieurs dates au cours d'une même année.

2) Cela ne suppose pas que l'heure d'été (si elle existe) est nécessairement en juillet et fonctionnera même si elle le sera à un moment ou à un autre. Toutefois, en ce qui concerne les performances, cela fonctionnera plus rapidement si effectivement juillet (ou presque par mois) est effectivement l'heure d'été.

3) Dans le pire des cas, il comparera le getTimezoneOffset du premier de chaque mois. [et faites cela une fois par année testée].

L’hypothèse qui en découle encore est que, s’il existe une période d’heure d’été, elle est supérieure à un mois.

Si quelqu'un veut supprimer cette hypothèse, il peut changer de boucle en quelque chose de plus semblable à la solution fournie par Aaron Cole - mais je voudrais tout de même sauter un an et demi et m'échapper de la boucle lorsque deux décalages différents sont trouvés]

9
epeleg

La bibliothèque moment.js fournit une méthode .isDst() sur ses objets temporels.

moment # isDST vérifie si le moment actuel est en heure d'été.

moment([2011, 2, 12]).isDST(); // false, March 12 2011 is not DST
moment([2011, 2, 14]).isDST(); // true, March 14 2011 is DST
4
Daniel F

La méthode getTimezoneOffset() en JavaScript, dans un navigateur, renvoie le nombre de minutes décalées par rapport au fuseau horaire 00:00. Par exemple, le fuseau horaire America/New_York dans l'heure avancée (DST) renvoie le nombre 300. 300 minutes correspond à une différence de 5 heures par rapport à zéro. 300 minutes divisées par 60 minutes est 5 heures. Chaque fuseau horaire est comparé au fuseau horaire zéro, +00: 00/Etc/GMT/heure de Greenwich.

MDN Web Docs

La prochaine chose que vous devez savoir, est que le décalage a le signe opposé du fuseau horaire actuel.

Les informations sur les fuseaux horaires sont gérées par l’Autorité des numéros attribués sur Internet (iana).

fuseaux horaires iana

Un tableau bien formaté des fuseaux horaires est fourni par joda.org

fuseaux horaires joda-time

+00: 00 ou Etc/GMT est l'heure de Greenwich

Tous les fuseaux horaires sont décalés de +00: 00/"Etc/GMT"/heure de Greenwich

L'heure d'été est toujours antérieure à l'heure "normale" de l'été. Vous réglez vos horloges à l'automne. (Slogan "Fall Back" pour se rappeler quoi faire)

Ainsi, l'heure Amérique/New_York en heure avancée (hiver) est une heure avant l'heure normale. Ainsi, par exemple, ce qui était normalement 17 heures dans l'après-midi à New York en été, il est maintenant 16 heures. Heure Amérique/New_York en heure avancée. Le nom "America/New_York" time est un nom de fuseau horaire "Long Format". La côte est des États-Unis appelle généralement leur fuseau horaire Eastern Standard Time (EST)

Si vous souhaitez comparer le décalage de fuseau horaire actuel au décalage de fuseau horaire d'une autre date, vous devez savoir que le signe mathématique (+/- "Positif/Négatif") du décalage de fuseau horaire est l'inverse du fuseau horaire.

Consultez le tableau des fuseaux horaires sur joda.org et recherchez le fuseau horaire de "America/New_York". Le signe négatif apparaît devant le décalage standard.

La terre tourne dans le sens contraire des aiguilles d'une montre sur son axe. Une personne regarde le lever du soleil à Greenwich et voit le lever du soleil 5 heures avant que quelqu'un de New York ne voie le lever du soleil. Et quelqu'un sur la côte ouest des États-Unis verra le lever du soleil après que quelqu'un de la côte est des États-Unis verra le lever du soleil.

Il y a une raison pour laquelle vous devez savoir tout cela. Ainsi, vous serez en mesure de déterminer logiquement si un code JavaScript obtient l'état DST correctement ou non, sans avoir à tester chaque fuseau horaire à différents moments de l'année.

Imaginez que nous sommes en novembre à New York et que les horloges ont été retardées d’une heure. En été, à New York, le décalage est de 240 minutes ou 4 heures.

Vous pouvez tester cela en créant une date du mois de juillet, puis en obtenant le décalage.

var July_Date = new Date(2017, 6, 1);
var july_Timezone_OffSet = July_Date.getTimezoneOffset();

console.log('july_Timezone_OffSet: ' + july_Timezone_OffSet)

Qu'est-ce qui sera imprimé dans le journal de la console des outils de développement du navigateur?

La réponse est: 240

Vous pouvez donc créer une date en janvier et voir ce que votre navigateur renvoie pour un décalage de fuseau horaire pour la saison hivernale.

var Jan_Date = new Date(2017, 0, 1);//Month is zero indexed - Jan is zero
var jan_Timezone_OffSet = Jan_Date.getTimezoneOffset();

console.log('jan_Timezone_OffSet: ' + jan_Timezone_OffSet)

La réponse est: 300

Évidemment, 300 est plus grand que 240. Alors, qu'est-ce que cela signifie? Devez-vous écrire du code qui teste pour le décalage d'hiver étant plus grand que le décalage d'été? Ou l'été moins compensé que l'hiver? S'il existe une différence entre les décalages de fuseaux horaires d'été et d'hiver, vous pouvez alors supposer que l'heure d'été est utilisée pour ce fuseau horaire. Mais cela ne vous dit pas si aujourd'hui utilise DST pour le fuseau horaire des navigateurs. Donc, vous devrez obtenir le décalage de fuseau horaire pour aujourd'hui.

var today = new Date();
var todaysTimeZone = today.getTimezoneOffset();

console.log('todaysTimeZone : ' + todaysTimeZone)

La réponse est:? - dépend de la période de l'année

Si le décalage de fuseau horaire actuel et le décalage de fuseau horaire sont les mêmes, ET, les décalages de fuseaux horaires d'été et d'hiver sont différents, alors, par déduction logique, aujourd'hui ne doit pas être en heure d'été.

Pouvez-vous omettre de comparer les décalages de fuseaux horaires d'été et d'hiver (pour savoir si l'heure d'été est utilisé pour ce fuseau horaire) et comparer simplement le décalage de fuseau horaire actuel au décalage TZ d'été et obtenir toujours la bonne réponse?

today's TZ Offset !== Summer TZ Offset

Eh bien, est-ce aujourd'hui en hiver ou en été? Si vous le saviez, vous pouvez appliquer la logique suivante:

if ( it_is_winter && ( todays_TZ_Offset !== summer_TZ_Offset) {
  var are_We_In_DST = true;
}

Mais le problème est que vous ne savez pas si la date du jour est en hiver ou en été. Chaque fuseau horaire peut avoir ses propres règles pour le début et la fin de l'heure d'été. Vous devez suivre les règles de chaque fuseau horaire pour chaque fuseau horaire du monde. Donc, s’il existe un moyen meilleur et plus simple, vous pourriez aussi bien le faire mieux.

Ce qui nous reste, c'est que vous devez savoir si ce fuseau horaire utilise l'heure d'été, puis comparez le décalage de fuseau horaire actuel avec le décalage de fuseau horaire d'été. Cela vous donnera toujours une réponse fiable.

La logique finale est:

if ( DST_Is_Used_In_This_Time_Zone && ( todays_TZ_Offset !== summer_TZ_Offset) {
  var are_We_In_DST = true;
}

Fonction pour déterminer si le fuseau horaire dans le navigateur utilise DST:

function is_DST_Used_In_This_TimeZone() {
  var Jan_Date, jan_Timezone_OffSet, July_Date, july_Timezone_OffSet 
      offsetsNotEqual, thisYear, today;

  today = new Date();//Create a date object that is now
  thisYear = today.getFullYear();//Get the year as a number

  Jan_Date = new Date(thisYear, 0, 1);//Month is zero indexed - Jan is zero
  jan_Timezone_OffSet = Jan_Date.getTimezoneOffset();

  console.log('jan_Timezone_OffSet: ' + jan_Timezone_OffSet)

  July_Date = new Date(thisYear, 6, 1);
  july_Timezone_OffSet = July_Date.getTimezoneOffset();

  console.log('july_Timezone_OffSet: ' + july_Timezone_OffSet)

  offsetsNotEqual = july_Timezone_OffSet !== jan_Timezone_OffSet;//True if not equal

  console.log('offsetsNotEqual: ' + offsetsNotEqual);

  return offsetsNotEqual;//If the offsets are not equal for summer and
       //winter then the only possible reason is that DST is used for
       //this time zone
}
3
Alan Wells

J'ai constaté que l'utilisation de la bibliothèque Moment.js avec certains des concepts décrits ici (comparaison de janvier à juin) fonctionne très bien.

Cette fonction simple renverra si le fuseau horaire dans lequel l'utilisateur se trouve respecte l'heure d'été:

function HasDST() {
    return moment([2017, 1, 1]).isDST() != moment([2017, 6, 1]).isDST();
}

Un moyen simple de vérifier que cela fonctionne (sous Windows) consiste à modifier votre fuseau horaire en une zone non DST, par exemple Arizona renverra false, alors que EST ou PST renverra true.

enter image description here

1
Nico Westerdale

Vous êtes proche mais un peu en retrait. Vous n'avez jamais besoin de calculer votre propre temps car c'est le résultat de votre propre horloge. Il peut détecter si vous utilisez l'heure d'été dans votre région, mais pas dans une région éloignée générée par le décalage:

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

Ce sera toujours faux et dans une heure s'ils sont en heure d'été. Vous avez besoin d’un compte de temps distant s’ils se trouvent ou non dans leur heure d’heure et qu’ils s’ajuste en conséquence. essayez de calculer cela et changez votre horloge en - disons le 01/02/2015 et réinitialisez l'horloge d'une heure comme si elle était en dehors de l'heure d'été. Ensuite, calculez un décalage pour une place qui devrait rester 2 heures en retard. Il montrera une heure d'avance sur la fenêtre de deux heures. Vous auriez encore besoin de tenir compte de l'heure et de l'ajuster. Je l'ai fait pour New York et Denver et je me trompe toujours (heure d'avance) à Denver.

1
Larry Enzer

Solution d'avenir qui fonctionne dans tous les fuseaux horaires

  1. Soit x le nombre de millisecondes attendu dans l'année d'intérêt sans tenir compte de l'heure d'été.
  2. Soit y le nombre de millisecondes écoulées depuis le Epoch depuis le début de l'année de la date d'intérêt.
  3. Soit z le nombre de millisecondes écoulées depuis le Epoch de la date et de l’heure d’intérêt
  4. Soit t la soustraction de x et y de z: z - y - x. Cela donne le décalage dû à DST.
  5. Si t vaut zéro, alors l'heure d'été n'est pas effective. Si t n'est pas zéro, alors l'heure d'été est effective.
(function(){"use strict";
function dstOffsetAtDate(dateInput) {
    var fullYear = dateInput.getFullYear()|0;
        // "Leap Years are any year that can be exactly divided by 4 (2012, 2016, etc)
        //   except if it can be exactly divided by 100, then it isn't (2100,2200,etc)
        //        except if it can be exactly divided by 400, then it is (2000, 2400)"
        // (https://www.mathsisfun.com/leap-years.html).
    var isLeapYear = ((fullYear & 3) | (fullYear/100 & 3)) === 0 ? 1 : 0;
        // (fullYear & 3) = (fullYear % 4), but faster
    //Alternative:var isLeapYear=(new Date(currentYear,1,29,12)).getDate()===29?1:0
    var fullMonth = dateInput.getMonth()|0;
    return (
        // 1. We know what the time since the Epoch really is
        (+dateInput) // same as the dateInput.getTime() method
        // 2. We know what the time since the Epoch at the start of the year is
        - (+new Date(fullYear, 0, 0)) // day defaults to 1 if not explicitly zeroed
        // 3. Now, subtract what we would expect the time to be if daylight savings
        //      did not exist. This yields the time-offset due to daylight savings.
        - ((
            ((
                // Calculate the day of the year in the Gregorian calendar
                // The code below works based upon the facts of signed right shifts
                //    • (x) >> n: shifts n and fills in the n highest bits with 0s 
                //    • (-x) >> n: shifts n and fills in the n highest bits with 1s
                // (This assumes that x is a positive integer)
                (31 & ((-fullMonth) >> 4)) + // January // (-11)>>4 = -1
                ((28 + isLeapYear) & ((1-fullMonth) >> 4)) + // February
                (31 & ((2-fullMonth) >> 4)) + // March
                (30 & ((3-fullMonth) >> 4)) + // April
                (31 & ((4-fullMonth) >> 4)) + // May
                (30 & ((5-fullMonth) >> 4)) + // June
                (31 & ((6-fullMonth) >> 4)) + // July
                (31 & ((7-fullMonth) >> 4)) + // August
                (30 & ((8-fullMonth) >> 4)) + // September
                (31 & ((9-fullMonth) >> 4)) + // October
                (30 & ((10-fullMonth) >> 4)) + // November
                // There are no months past December: the year rolls into the next.
                // Thus, fullMonth is 0-based, so it will never be 12 in Javascript
                
                (dateInput.getDate()|0) // get day of the month
                                
            )&0xffff) * 24 * 60 // 24 hours in a day, 60 minutes in an hour
            + (dateInput.getHours()&0xff) * 60 // 60 minutes in an hour
            + (dateInput.getMinutes()&0xff)
        )|0) * 60 * 1000 // 60 seconds in a minute * 1000 milliseconds in a second
        - (dateInput.getSeconds()&0xff) * 1000 // 1000 milliseconds in a second
        - dateInput.getMilliseconds()
    );
}

// Demonstration:
var date = new Date(2100, 0, 1)
for (var i=0; i<12; i=i+1|0, date.setMonth(date.getMonth()+1|0))
    console.log(date.getMonth()+":\t"+dstOffsetAtDate(date)/60/60/1000+"h\t"+date);
date = new Date(1900, 0, 1);
for (var i=0; i<12; i=i+1|0, date.setMonth(date.getMonth()+1|0))
    console.log(date.getMonth()+":\t"+dstOffsetAtDate(date)/60/60/1000+"h\t"+date);

// Performance Benchmark:
console.time("Speed of processing 16384 dates");
for (var i=0,month=date.getMonth()|0; i<16384; i=i+1|0)
    date.setMonth(month=month+1+(dstOffsetAtDate(date)|0)|0);
console.timeEnd("Speed of processing 16384 dates");
})();

Je crois que l'extrait de code ci-dessus est supérieur à toutes les autres réponses publiées ici pour de nombreuses raisons.

  • Cette réponse fonctionne dans tous les fuseaux horaires, même Antarctique/Casey .
  • L'heure d'été est très susceptible de changer. Il se peut que dans 20 ans, un pays puisse avoir 3 périodes DST au lieu de la période normale 2. Ce code traite ce cas en renvoyant le décalage DST en millisecondes, pas seulement si DST est activé ou non.
  • La taille des mois de l'année et la façon dont les années bissextiles fonctionnent parfaitement nous permettent de garder notre temps sur la bonne voie avec le Soleil. Heck, cela fonctionne si parfaitement que tout ce que nous faisons est juste ajuster quelques secondes ici et là . Notre système actuel d’années bissextiles est en vigueur depuis le 24 février 1582 et le restera probablement dans un avenir prévisible.
  • Ce code fonctionne dans les fuseaux horaires qui n'utilisent pas l'heure d'été.
  • Ce code fonctionne à une époque historique antérieure à la mise en œuvre de DST (comme les années 1900).
  • Ce code est optimisé au maximum en termes d’entier et ne devrait vous poser aucun problème s’il est appelé dans une boucle serrée. Après avoir exécuté l'extrait de code ci-dessus, faites défiler l'écran vers le bas pour afficher le point de repère des performances. Mon ordinateur peut traiter 16384 dates en ~ 97ms sur Chrome.

Toutefois, si vous ne vous préparez pas pour plus de 2 périodes d'heure d'été, vous pouvez utiliser le code ci-dessous pour déterminer si l'heure d'été est effective en tant que booléen.

function isDaylightSavingsInEffect(dateInput) {
    // To satisfy the original question
    return dstOffsetAtDate(dateInput) !== 0;
}
1
Jack Giffin

J'ai récemment eu besoin de créer une chaîne de date avec UTC et DST, et d'après la réponse de Sheldon, j'ai rassemblé 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>
0
akinuri