Comment vérifier si DST (heure d'été) est en vigueur, et si oui, le décalage?

154

C'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 le datetime dans «il y a», mais si l'heure d'été est en cours d'utilisation, 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?

Jo Smo
la source

Réponses:

313

Ce code utilise le fait qui getTimezoneOffsetrenvoie une valeur plus élevée pendant l'heure d'hiver par rapport à l'heure d'été (DST). Ainsi, il détermine la sortie attendue pendant l'heure standard, et il compare si la sortie de la date donnée est la même (Standard) ou moins (DST).

Notez que getTimezoneOffsetrenvoie des nombres positifs de minutes pour les zones à l' ouest de UTC, qui sont généralement exprimées en heures négatives (puisqu'elles sont "en retard" sur UTC). Par exemple, Los Angeles est UTC – 8h Standard, UTC-7h DST. getTimezoneOffsetrenvoie 480(positif 480 minutes) en décembre (hiver, heure normale), plutôt que -480. Il renvoie des nombres négatifs pour l'hémisphère oriental (comme -600pour Sydney en hiver, bien que ce soit "en avant" ( UTC + 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!");
}
Sheldon Griffin
la source
28
Je peux vérifier que cela fonctionne à l'international. Il n'existe actuellement aucun fuseau horaire qui utilise une forme d'heure d'été où le 1er janvier et le 1er juillet sont tous les deux à la fois ou en dehors de la période d'heure d'été. En outre, dans tous les fuseaux horaires de la TZDB ( à une exception triviale ), le plus grand des deux décalages est le décalage DST. Puisque JavaScript getTimezoneOffsetrenvoie la valeur inverse, alors Math.maxrenvoie effectivement le décalage standard . Le code est correct.
Matt Johnson-Pint
7
Toutefois, si un fuseau horaire modifie jamais sa définition de telle sorte que le 1er janvier et le 1er juillet soient tous les deux à l'heure d'été, ou les deux non à l'heure d'été (et l'heure d'été s'applique toujours), ce code ne fonctionnera pas dans cette zone.
Matt Johnson-Pint
9
Cela ne fonctionne pas en général, par exemple il y a des pays qui n'ont pas observé l'heure d'été certaines années et aussi certains pays rétablissent l'heure d'été pendant le ramadan. À côté de cela, la définition ECMAScript pour Date est interrompue et la gestion de la variable d'environnement TZ est également interrompue dans certaines implémentations. Tout cela combiné rend cette méthode peu fiable. Vous feriez mieux d'utiliser une bibliothèque qui n'utilise pas Date, par exemple timezonecomplete
rogierschouten
5
Ce code ne fonctionne pas dans les pays qui n'observent pas l'heure d'été, comme par exemple l'Afrique du Sud ou l'Islande; ce qui signifie que si vous l'utilisez pour comparer avec d'autres fuseaux horaires dans ces pays, il n'affichera pas les heures correctes là-bas. Suggérez d'utiliser l'UTC jusqu'au bout et vérifiez manuellement si l'heure actuelle se situe dans une certaine plage d'heure d'été. Ensuite, il suffit de changer le décalage de l'heure normale UTC de +1 pour obtenir l'heure d'été.
Kebman
1
Comment cela peut-il être correct? L'Allemagne, par exemple, est entrée à l'heure d'été le 30/10/2016 tandis que les États-Unis sont entrés une semaine plus tard le 06/11/2016. De mauvaises informations comme celle-ci sont à l'origine de ce genre de choses: macworld.co.uk/news/apple
Daniel F
22

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

  • si décalage janvier> décalage juin, le client est 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é

Vérifiez maintenant 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)
Jon Nylander
la source
Pourquoi avez-vous besoin des hémisphères? ne serait-il pas suffisant de dire que si getTimezoneOffset () pour la date actuelle est égal au plus petit des deux getTimezoneOffset (), alors son heure d'été? [et le décalage est la différence entre les deux?]
epeleg
Vous n'avez pas besoin des hémisphères comme le démontre clairement la réponse acceptée :)
Jon Nylander
Cela ne fonctionnera pas. La meilleure chose à faire est de vous assurer d'utiliser les heures UTC et de définir manuellement le décalage pour la région pour laquelle vous le souhaitez. Recherchez ensuite manuellement le début et la fin de l'heure d'été pour la même région (le cas échéant). Ensuite, vous souhaitez vérifier si l'heure de cette région est dans la plage DST ou non, puis mettre à jour le décalage en conséquence avec +1. Cela permet de comparer les pays qui respectent l'heure d'été et ceux qui ne le font pas.
Kebman
La question est de savoir comment déterminer si l'heure d'été est en vigueur pour le moment dans le fuseau horaire de la machine cliente Kebman, et non comment afficher les dates, les clients Web gèrent déjà cela pour vous.
Jon Nylander
Vous devez vérifier entre janvier et juillet (ou février et août, mars et septembre, etc.) car ils sont espacés de 6 mois.
kpull1
17

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


L'idée est que, comme aucun pays n'observe l'heure d'été qui dure 7 mois [1] , dans une zone qui observe l'heure d'été, le décalage par rapport à l'heure UTC en janvier sera différent de celui de juillet.

Alors que l' heure d'été déplace horloges avant , JavaScript renvoie toujours une plus grande valeur au cours de l' heure normale. Par conséquent, obtenir le décalage minimum entre janvier et juillet obtiendra 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, alors nous sommes en DST; sinon nous ne le sommes pas.

La fonction suivante utilise cet algorithme. Il prend un objet date d, et renvoie truesi l'heure d'été est en vigueur pour cette date, et falsesi ce n'est pas le cas:

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(); 
}
Toastrackenigma
la source
1
Cela fonctionne, mais s'il n'y a pas d'heure d'été dans la zone horaire actuelle, le résultat sera également vrai, ce qui n'est pas correct. Si vous le basculez sur Math.max(...) != d.get...(), il retournera vrai si l'heure d'été est observée dans le fuseau horaire donné ET que la date est actuellement à l'heure d'été. Si l'heure d'été n'est pas observée ou si la date correspond au décalage standard, elle renvoie false.
GreySage
12

J'ai été confronté au même problème aujourd'hui, mais comme notre heure d'été commence et s'arrête à des heures différentes des États-Unis (du moins d'après ce que je comprends), 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, vous comparez simplement le décalage du fuseau horaire actuel avec DST et nonDST pour voir lequel correspond.

Aaron Cole
la source
C'est ainsi que nous procédons également. Autrement dit, déterminez les heures de l'année pendant lesquelles l'heure d'été change dans votre fuseau horaire cible et calculez les décalages pour le jour en cours et la date de modification la plus récente. Ils différeront d'une heure ou seront égaux (en supposant que le fuseau horaire en question est un décalage horaire).
Heather
Il n'est pas nécessaire de créer 365 valeurs, une approche de recherche binaire qui s'arrête dès qu'un changement de décalage est déterminé devrait être beaucoup plus efficace, même lorsque l'heure d'été n'est pas observée. Toutes ces approches supposent que les lieux observent l'heure d'été chaque année, ce qui n'est pas nécessairement vrai. Les lieux adoptent et abandonnent l'heure d'été de temps en temps (bien qu'ECMAScript assume les règles actuelles, quelle que soit leur zone, appliquées toujours).
RobG
2
Rob - comment pouvez-vous faire cela via une recherche binaire si vous ne savez pas où chercher (c'est-à-dire que l'endroit que vous recherchez est au-dessus ou en dessous de votre point de test?)
epeleg
9

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 suggérées précédemment et plus précisément:

1) Met en cache le résultat pour une année stdTimezoneOffset afin que vous n'ayez pas besoin de le recalculer lors du test de plusieurs dates dans la même année.

2) Il ne suppose pas que l'heure d'été (si elle existe) est nécessairement en juillet, et qu'elle fonctionnera même si elle le sera à un moment et à un autre à n'importe quel mois. Cependant, en termes de performances, cela fonctionnera plus rapidement si en effet juillet (ou près de quelques mois) sont effectivement DST.

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 qu'il fait toujours est que la période s'il y a DST est plus longue qu'un seul mois.

Si quelqu'un veut supprimer cette hypothèse, il peut changer la boucle en quelque chose qui ressemble plus à la solution fournie par Aaron Cole - mais je sauterais encore six mois à l'avance et sortirais de la boucle lorsque deux décalages différents seraient trouvés]

epeleg
la source
4

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

moment # isDST vérifie si le moment actuel est à l'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
Daniel F
la source
J'ai essayé var moment = require ('moment'); this.logger.info (moment ([2011, 2, 12]). isDST ()); this.logger.info (moment ([2011, 2, 14]). isDST ()); les deux sont faux
Logan_B
Les dates de changement d'heure d'été varient selon les pays , même entre les États du même pays (c'est-à-dire l'État de l'Arizona). Aux USA c'était le 2011-03-13, alors qu'en Allemagne c'était le 2011-03-31. Ainsi, le résultat sera différent selon le fuseau horaire moment.js est configuré pour fonctionner.
Daniel F
1
Cela varie même au sein de l'état de l'Arizona timeanddate.com/time/us/arizona-no-dst.html
Daniel F
3

La getTimezoneOffset()méthode en JavaScript, dans un navigateur, renvoie le nombre de minutes de décalage par rapport au fuseau horaire 00:00. Par exemple, le fuseau horaire Amérique / New_York dans Daylight Savings (DST) renvoie le nombre 300. 300 minutes correspondent à 5 heures de différence par rapport à zéro. 300 minutes divisées par 60 minutes font 5 heures. Chaque fuseau horaire est comparé au fuseau horaire zéro, +00: 00 / Etc / GMT / heure de Greenwich.

Documents Web MDN

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

Les informations sur les fuseaux horaires sont conservées par Internet Assigned Numbers Authority (iana)

fuseaux horaires iana

Un tableau des fuseaux horaires bien formaté 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 souvenir de ce qu'il faut faire)

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

Si vous souhaitez comparer le décalage de fuseau horaire d'aujourd'hui 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'opposé du fuseau horaire.

Regardez le tableau des fuseaux horaires sur joda.org et trouvez le fuseau horaire pour "America / New_York". Il aura un signe négatif devant le décalage standard.

La terre tourne dans le sens antihoraire sur son axe. Une personne regarde le lever du soleil à Greenwich voit le lever du soleil 5 heures avant que quelqu'un à 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 sur la côte est des États-Unis voit 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 le statut 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 reculé 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 qui est en 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 désormais créer une date en janvier et voir ce que votre navigateur renvoie pour un décalage de fuseau horaire pour la saison d'hiver.

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

De toute évidence, 300 est plus grand que 240. Alors, qu'est-ce que cela signifie? Devriez-vous écrire du code qui teste que le décalage d'hiver est plus grand que le décalage d'été? Ou le décalage d'été moins que le décalage d'hiver? S'il existe une différence entre les décalages de fuseau horaire d'été et d'hiver, vous pouvez supposer que l'heure d'été est utilisée pour ce fuseau horaire. Mais cela ne vous dit pas si aujourd'hui utilise l'heure d'été pour le fuseau horaire du navigateur. Vous devrez donc obtenir le décalage du 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 du fuseau horaire du jour et le décalage du fuseau horaire d'été sont identiques, ET que les décalages de fuseau horaire 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 fuseau horaire d'été et d'hiver, (Pour savoir si l'heure d'été est utilisée pour ce fuseau horaire) et simplement comparer le décalage de fuseau horaire d'aujourd'hui au décalage TZ d'été, et toujours obtenir 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 d'aujourd'hui est en hiver ou en été. Chaque fuseau horaire peut avoir ses propres règles pour le démarrage et l'arrêt de l'heure d'été. Vous auriez besoin de garder une trace des règles de chaque fuseau horaire pour chaque fuseau horaire dans le monde. Donc, s'il existe un moyen meilleur et plus simple, vous pouvez aussi bien le faire de la manière la plus simple et la meilleure.

Ce qu'il nous reste, c'est que vous devez savoir si ce fuseau horaire utilise l'heure d'été, puis comparer le décalage du fuseau horaire d'aujourd'hui avec le décalage du 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 permettant de déterminer si le fuseau horaire dans le navigateur utilise l'heure d'été:

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
}
Alan Wells
la source
1
Selon dateandtime.com, l' heure d'été a commencé le 10 mars 2019 et se situe donc en été, pas en hiver, et le décalage d'heure d'été de New York est de -4 et non de -5.
jk7
Si une amélioration ou un correctif doit être apporté à la réponse, veuillez effectuer une modification et elle sera examinée.
Alan Wells
2

Utilisez Moment.js ( https://momentjs.com/ )

moment().isDST(); vous donnera si des économies de lumière du jour sont observées.

En outre, il a une fonction d'aide pour calculer le temps relatif pour vous. Vous n'avez pas besoin de faire des calculs manuels, par exemplemoment("20200105", "YYYYMMDD").fromNow();

Santhosh S
la source
1

Vous êtes proche mais un peu décalé. Vous n'avez jamais besoin de calculer votre propre temps car il est le résultat de votre propre horloge. Il peut détecter si vous utilisez l'heure d'été dans votre emplacement, mais pas pour un emplacement distant produit par le décalage:

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

Ce sera toujours faux et hors d'une heure s'ils sont en DST. Vous avez besoin d'un compte de temps distant s'ils sont actuellement dans leur heure d'été ou non et ajustez en conséquence. essayez de calculer cela et changez votre horloge en - disons 2/1/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 un lieu qui devrait encore avoir 2 heures de retard. Il affichera une heure avant la fenêtre de deux heures. Vous devrez toujours tenir compte de l'heure et vous ajuster. Je l'ai fait pour New York et Denver et toujours aller la mauvaise (heure d'avance) à Denver.

Larry Enzer
la source
1

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

Cette fonction simple retournera si le fuseau horaire dans lequel se trouve l'utilisateur 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) est de changer votre fuseau horaire en une zone non DST, par exemple l'Arizona retournera false, alors que EST ou PST retournera true.

entrez la description de l'image ici

Nico Westerdale
la source
1

Solution évolutive qui fonctionne dans tous les fuseaux horaires

  1. Soit xle nombre attendu de millisecondes dans l'année d'intérêt sans tenir compte de l'heure d'été.
  2. Soit yle nombre de millisecondes depuis l' époque depuis le début de l'année de la date d'intérêt.
  3. Soit zle nombre de millisecondes depuis l' époque de la date et de l'heure complètes
  4. Laissez - têtre la soustraction des deux xet yde z: z - y - x. Cela donne le décalage dû à l'heure d'été.
  5. Si test égal à zéro, alors DST n'est pas en vigueur. Si tn'est pas nul, alors DST est en vigueur.

(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 pense 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 en Antarctique / Casey .
  • L'heure d'été est très sujette à changement. Il se peut que dans 20 ans, certains pays aient 3 périodes DST au lieu de la normale 2. Ce code gère ce cas en renvoyant le décalage DST en millisecondes, pas seulement si l'heure d'été est en vigueur ou non.
  • La taille des mois de l'année et la façon dont fonctionnent les années bissextiles s'intègrent parfaitement pour garder notre temps sur la bonne voie avec le soleil. Heck, cela fonctionne si parfaitement que tout ce que nous faisons est juste d' ajuster quelques secondes ici et là . Notre système actuel des 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 dans les temps historiques avant l'implémentation de l'heure d'été (comme les années 1900).
  • Ce code est optimisé au maximum pour les entiers 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 vers le bas de la sortie pour voir l'indice de performance. Mon ordinateur est capable de traiter 16384 dates en ~ 97 ms sur Chrome.

Cependant, si vous ne vous préparez pas pour plus de 2 périodes DST, le code ci-dessous peut être utilisé pour déterminer si DST est en vigueur en tant que booléen.

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

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 ceci ensemble:

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>

akinuri
la source
0

Y a-t-il un problème lors de l'utilisation du Date.toString().indexOf('Daylight Time') > -1

"" + new Date()

Sam 01 janvier 100050 00:00:00 GMT-0500 (heure normale de l' Est )

"" + new Date(...)

Dim 01 mai 100033 00:00:00 GMT-0400 ( heure avancée de l' Est )

Cela semble compatible avec tous les navigateurs.

YC
la source
Oui, cela ne fonctionne pas partout dans le monde. En été en Europe, vous obtenez"Thu Jul 02 2020 14:07:01 GMT+0200 (Central European Summer Time)"
Tadej Krevh le
0

Style ES6

Math.min(...[0, 6].map(v => new Date(95, v, 1).getTimezoneOffset() * -1));
nkitku
la source