Jak sprawdzić, czy obowiązuje DST (czas letni), a jeśli tak, to przesunięcie?

154

To jest fragment mojego kodu JS, do którego jest to potrzebne:

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);

Chcę uzyskać datę i godzinę „temu”, ale jeśli czas letni jest używany, daty są przesunięte o 1 godzinę. Nie wiem, jak sprawdzić, czy czas letni obowiązuje, czy nie.

Skąd mogę wiedzieć, kiedy zaczyna się i kończy czas letni?

Jo Smo
źródło

Odpowiedzi:

313

Ten kod wykorzystuje fakt, że getTimezoneOffsetzwraca większą wartość w czasie standardowym w porównaniu z czasem letnim (DST). W ten sposób określa oczekiwaną produkcję w czasie standardowym i porównuje, czy wynik w danym dniu jest taki sam (standardowy), czy mniejszy (czas letni).

Zwróć uwagę, że getTimezoneOffsetzwraca dodatnią liczbę minut dla stref na zachód od UTC, które są zwykle podawane jako godziny ujemne (ponieważ znajdują się „za” UTC). Na przykład Los Angeles to standard UTC – 8h , UTC – 7h DST. getTimezoneOffsetzwraca 480(dodatnie 480 minut) w grudniu (zima, czas standardowy), a nie -480. Zwraca liczby ujemne dla półkuli wschodniej (np. -600Dla Sydney zimą, mimo że jest „naprzód” ( 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
źródło
28
Mogę sprawdzić, czy to działa na arenie międzynarodowej. Obecnie nie ma stref czasowych, które używają jakiejkolwiek formy czasu letniego, w których zarówno 1 stycznia, jak i 1 lipca znajdują się w okresie czasu letniego lub oba poza nim. Ponadto we wszystkich strefach czasowych w TZDB ( z jednym trywialnym wyjątkiem ) większe z dwóch przesunięć to przesunięcie czasu letniego. Ponieważ JavaScript getTimezoneOffsetzwraca wartość odwrotną, Math.maxto rzeczywiście zwraca standardowe przesunięcie. Kod jest poprawny.
Matt Johnson-Pint
7
Jednakże, jeśli strefa czasowa nie zmienia jego definicję tak, że zarówno 01 stycznia i 01 lipca są albo zarówno w DST lub obie nie w czas letni (DST i nadal obowiązuje), to kod nie będzie działać w tej strefie.
Matt Johnson-Pint
9
To nie działa na ogół, np. Są kraje, w których nie przestrzegano czasu letniego w niektórych latach, a także niektóre kraje przywracają czas letni podczas ramadanu. Poza tym definicja ECMAScript dla Date jest zepsuta, a także obsługa zmiennej środowiskowej TZ jest zepsuta w niektórych implementacjach. Wszystko to razem sprawia, że ​​ta metoda jest zawodna. Lepiej jest używać biblioteki, która nie używa daty, np. Timezonecomplete
rogierschouten
5
Ten kod nie działa w krajach, które nie przestrzegają czasu letniego, jak na przykład RPA lub Islandia; co oznacza, że ​​jeśli użyjesz go do porównania z innymi strefami czasowymi w tych krajach, nie pokaże tam poprawnych czasów. Zaproponuj używanie czasu UTC przez cały czas i ręcznie sprawdź, czy teraz czas mieści się w określonym zakresie czasu letniego. Wtedy wystarczy zmienić normalny przesunięcie czasu UTC o +1, aby uzyskać czas letni.
Kebman
1
Jak to może być poprawne? Na przykład Niemcy wprowadziły czas letni 30.10.2016, a USA tydzień później 06.11.2016. Złe informacje, takie jak ta, powodują takie rzeczy: macworld.co.uk/news/apple/ ...
Daniel F
22

Utwórz dwie daty: jedną w czerwcu, drugą w styczniu. Porównaj ich wartości getTimezoneOffset ().

  • jeśli offset styczniowy> offset czerwcowy, klient znajduje się na półkuli północnej
  • jeśli offset styczeń <offset czerwiec, klient znajduje się na półkuli południowej
  • jeśli nie ma różnicy, strefa czasowa klienta nie przestrzega czasu letniego

Teraz sprawdź getTimezoneOffset () aktualnej daty.

  • jeśli odpowiada czerwcu, półkuli północnej, to aktualna strefa czasowa to DST (+1 godzina)
  • jeśli jest równy styczniu, półkula południowa, to aktualna strefa czasowa to DST (+1 godzina)
Jon Nylander
źródło
Dlaczego potrzebujesz półkul? czy nie wystarczy powiedzieć, że jeśli getTimezoneOffset () dla bieżącej daty jest równe mniejszej z dwóch getTimezoneOffset (), to jego czas letni? [a przesunięcie jest różnicą między tymi dwoma?]
epeleg
Nie potrzebujesz półkul, co wyraźnie pokazuje zaakceptowana odpowiedź :)
Jon Nylander
To nie zadziała. Najlepszą rzeczą do zrobienia jest upewnienie się, że używasz czasu UTC i ręczne ustawienie przesunięcia dla regionu, dla którego chcesz to zrobić. Następnie ręcznie znajdź początek i koniec czasu letniego dla tego samego regionu (jeśli istnieje). Następnie chcesz sprawdzić, czy czas dla tego regionu mieści się w zakresie czasu letniego, czy nie, a następnie zaktualizować przesunięcie odpowiednio o +1. Umożliwia to porównanie krajów, w których obowiązuje czas letni, i tych, które tego nie robią.
Kebman
Pytanie brzmi, jak określić, czy czas letni obowiązuje w danym momencie w strefie czasowej komputera klienckiego Kebman, a nie jak wyświetlić daty, klienci internetowi już to robią.
Jon Nylander
Powinieneś sprawdzić między styczniem a lipcem (lub lutym a sierpniem, marcem i wrześniem itd.), Ponieważ są one oddalone od siebie o 6 miesięcy.
kpull1
17

Ta odpowiedź jest dość podobna do zaakceptowanej odpowiedzi, ale nie zastępuje Dateprototypu i używa tylko jednego wywołania funkcji do sprawdzenia, czy obowiązuje czas letni, a nie dwa.


Chodzi o to, że ponieważ żaden kraj nie obserwuje czasu letniego, który trwa 7 miesięcy [1] , na obszarze, na którym obserwuje się czas letni, przesunięcie względem czasu UTC w styczniu będzie inne niż w lipcu.

Podczas gdy czas letni przesuwa zegary do przodu , JavaScript zawsze zwraca większą wartość w czasie standardowym. Dlatego uzyskanie minimalnego przesunięcia między styczniem a lipcem spowoduje przesunięcie strefy czasowej podczas czasu letniego.

Następnie sprawdzamy, czy strefa czasowa dat jest równa tej minimalnej wartości. Jeśli tak, to mamy czas letni; w przeciwnym razie nie jesteśmy.

Poniższa funkcja używa tego algorytmu. Pobiera obiekt daty di zwraca, truejeśli dla tej daty obowiązuje czas letni, a falsejeśli nie:

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
źródło
1
To działa, ale jeśli w bieżącej strefie czasowej nie ma czasu letniego, wtedy również wyniknie prawda, co nie jest poprawne. Jeśli przełączysz się na Math.max(...) != d.get...(), zwróci wartość true, jeśli czas letni jest przestrzegany w danej strefie czasowej ORAZ data jest obecnie w czasie letnim. Jeśli czas letni nie jest przestrzegany lub data odpowiada przesunięciu standardowemu, zwróci wartość fałsz.
GreySage
12

Miałem dzisiaj ten sam problem, ale ponieważ czas letni zaczyna się i kończy w innym czasie niż w USA (przynajmniej w moim rozumieniu), wybrałem nieco inną trasę.

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);

Następnie wystarczy porównać bieżące przesunięcie strefy czasowej z czasem letnim i innym niż letni, aby zobaczyć, która z nich pasuje.

Aaron Cole
źródło
W ten sposób też to robimy. Oznacza to, że należy obliczyć pory roku, w których czas letni zmienia się w docelowej strefie czasowej, i obliczyć przesunięcia dla bieżącego dnia i ostatniej daty zmiany. Będą się różnić o godzinę lub będą równe (zakładając, że dana strefa czasowa to przesunięcie godzinowe).
Heather
Nie ma potrzeby tworzenia 365 wartości, podejście do wyszukiwania binarnego, które zatrzymuje się, gdy tylko zostanie określona zmiana przesunięcia, powinno być znacznie bardziej wydajne, nawet jeśli nie obserwuje się czasu letniego. Wszystkie te podejścia zakładają, że w miejscach każdego roku obowiązuje czas letni, co niekoniecznie jest prawdą. Miejsca od czasu do czasu przyjmują i rezygnują z czasu letniego (chociaż ECMAScript zakłada, że ​​aktualne zasady, niezależnie od ich obszaru, są zawsze stosowane).
RobG,
2
Rob - jak możesz to zrobić za pomocą wyszukiwania binarnego, jeśli nie wiesz, gdzie szukać (tj. Czy miejsce, którego szukasz, znajduje się powyżej lub poniżej punktu testowego?)
epeleg
9

Na podstawie komentarza Matta Johansona dotyczącego rozwiązania dostarczonego przez Sheldona Griffina stworzyłem następujący kod:

    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(); 
    };

Stara się uzyskać to, co najlepsze ze wszystkich światów, biorąc pod uwagę wszystkie komentarze i wcześniej sugerowane odpowiedzi, a konkretnie to:

1) Buforuje wynik na rok stdTimezoneOffset, aby nie trzeba było go ponownie obliczać podczas testowania wielu dat w tym samym roku.

2) Nie zakłada, że ​​czas letni (jeśli w ogóle istnieje) przypada koniecznie w lipcu i będzie działał, nawet jeśli w którymś momencie i miejscu będzie w dowolnym miesiącu. Jednak pod względem wydajności będzie działać szybciej, jeśli rzeczywiście lipiec (lub kilka miesięcy) to czas letni.

3) W gorszym przypadku porównuje getTimezoneOffset z pierwszego dnia każdego miesiąca. [i zrób to raz na testowany rok].

Zakłada się, że nadal trwa, jeśli okres czasu letniego jest dłuższy niż jeden miesiąc.

Jeśli ktoś chce usunąć to założenie, może zmienić pętlę w coś bardziej podobnego do tego, co jest w rozwiązaniu dostarczonym przez Aarona Cole'a - ale i tak przeskoczyłbym pół roku do przodu i wyrwałbym się z pętli, gdy zostaną znalezione dwa różne przesunięcia]

epeleg
źródło
4

Moment.js biblioteka dostarcza .isDst()metody na jego obiektów czasowych.

moment # isDST sprawdza, czy aktualny moment jest w czasie letnim.

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.
źródło
Próbowałem var moment = require ('moment'); this.logger.info (moment ([2011, 2, 12]). isDST ()); this.logger.info (moment ([2011, 2, 14]). isDST ()); oba są fałszywe
Logan_B
Daty zmiany czasu letniego są różne w różnych krajach , nawet między stanami w tym samym kraju (tj. Stanie Arizona). W USA było to 2011-03-13, podczas gdy w Niemczech było to 2011-03-31. Tak więc wynik będzie się różnić w zależności od strefy czasowej moment.js jest skonfigurowany do pracy.
Daniel F
1
Różni się nawet w zależności od stanu Arizona timeanddate.com/time/us/arizona-no-dst.html
Daniel F
3

getTimezoneOffset()Metoda w JavaScript w przeglądarce, zwraca liczbę minut offsetowych ze strefy 00:00 czasu. Na przykład strefa czasowa America / New_York w czasie letnim (DST) zwraca liczbę 300. 300 minut to 5 godzin różnicy od zera. 300 minut podzielone przez 60 minut to 5 godzin. Każda strefa czasowa jest porównywana z zerową strefą czasową, +00: 00 / Etc / GMT / Greenwich.

MDN Web Docs

Następną rzeczą, którą musisz wiedzieć, jest to, że przesunięcie ma znak przeciwny do rzeczywistej strefy czasowej.

Informacje o strefach czasowych są utrzymywane przez Internet Assigned Numbers Authority (IANA)

Iana strefy czasowe

Ładnie sformatowaną tabelę stref czasowych dostarcza joda.org

Strefy czasowe czasu joda

+00: 00 lub Etc / GMT to czas Greenwich

Wszystkie strefy czasowe są przesunięte od +00: 00 / „Etc / GMT” / czasu Greenwich

Czas letni jest zawsze wcześniejszy niż „zwykły” czas letni. Zegary przestawiacie na jesień. (Slogan „Fall Back”, aby pamiętać, co robić)

Tak więc czas America / New_York w czasie letnim (zima) jest jedną godzinę przed regularnym czasem. Na przykład to, co zwykle latem było o 17:00 w Nowym Jorku, to teraz godzina 16:00 czasu Ameryki / Nowego Jorku w czasie letnim. Czas „America / New_York” to nazwa strefy czasowej „Long Format”. Wschodnie wybrzeże Stanów Zjednoczonych zazwyczaj nazywa swoją strefę czasową Wschodnim Czasem Standardowym (EST)

Jeśli chcesz porównać dzisiejsze przesunięcie strefy czasowej z przesunięciem strefy czasowej innej daty, musisz wiedzieć, że znak matematyczny (+/- „dodatnia / ujemna”) przesunięcia strefy czasowej jest przeciwieństwem strefy czasowej.

Spójrz na tabelę stref czasowych na joda.org i znajdź strefę czasową dla „America / New_York”. Przed standardowym przesunięciem będzie oznaczony minus.

Ziemia obraca się przeciwnie do ruchu wskazówek zegara wokół swojej osi. Osoba oglądająca wschód słońca w Greenwich widzi wschód słońca na 5 godzin przed tym, jak ktoś w Nowym Jorku zobaczy wschód słońca. A ktoś na zachodnim wybrzeżu USA zobaczy wschód słońca po tym, jak ktoś na wschodnim wybrzeżu Stanów Zjednoczonych zobaczy wschód słońca.

Jest powód, dla którego musisz to wszystko wiedzieć. Dzięki temu będziesz w stanie logicznie określić, czy jakiś kod JavaScript otrzymuje poprawny stan czasu letniego, czy nie, bez konieczności testowania każdej strefy czasowej o różnych porach roku.

Wyobraź sobie, że w Nowym Jorku jest listopad, a zegary cofnięto o godzinę. Latem w Nowym Jorku przesunięcie to 240 minut lub 4 godziny.

Możesz to sprawdzić, tworząc datę przypadającą na lipiec, a następnie uzyskując przesunięcie.

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

console.log('july_Timezone_OffSet: ' + july_Timezone_OffSet)

Co zostanie wydrukowane w dzienniku konsoli narzędzi programistycznych przeglądarki?

Odpowiedź brzmi: 240

Więc teraz możesz utworzyć datę w styczniu i zobaczyć, co zwraca Twoja przeglądarka dla przesunięcia strefy czasowej na sezon zimowy.

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)

Odpowiedź brzmi: 300

Oczywiście 300 to więcej niż 240. Więc co to oznacza? Czy powinieneś napisać kod sprawdzający, czy przesunięcie zimowe jest większe niż przesunięcie letnie? A może lato mniej niż zimowe? Jeśli istnieje różnica między przesunięciem letniej i zimowej strefy czasowej, można założyć, że w tej strefie czasowej używany jest czas letni. Ale to nie mówi ci, czy dzisiaj używa się czasu letniego dla strefy czasowej przeglądarek. Musisz więc pobrać dzisiejsze przesunięcie strefy czasowej.

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

console.log('todaysTimeZone : ' + todaysTimeZone)

Odpowiedź to: ? - Zależy od pory roku

Jeśli przesunięcie dzisiejszej strefy czasowej i przesunięcie strefy czasowej letniej jest takie samo, ORAZ przesunięcie strefy czasowej letniej i zimowej jest różne, to zgodnie z logiczną dedukcją dzisiejszy dzień NIE może być czasem letnim.

Czy możesz pominąć porównanie przesunięć strefy czasowej letniej i zimowej (aby wiedzieć, czy czas letni jest używany w tej strefie czasowej) i po prostu porównać przesunięcie dzisiejszej strefy czasowej z przesunięciem letniego czasu TZ i zawsze uzyskać poprawną odpowiedź?

today's TZ Offset !== Summer TZ Offset

Cóż, dziś zimą czy latem? Gdybyś to wiedział, mógłbyś zastosować następującą logikę:

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

Problem w tym, że nie wiadomo, czy dzisiejsza data jest zimą czy latem. Każda strefa czasowa może mieć własne zasady dotyczące rozpoczęcia i zakończenia czasu letniego. Musisz śledzić zasady każdej strefy czasowej dla każdej strefy czasowej na świecie. Tak więc, jeśli istnieje lepszy i łatwiejszy sposób, równie dobrze możesz to zrobić w lepszy i łatwiejszy sposób.

Pozostaje nam tylko to, że musisz wiedzieć, czy ta strefa czasowa używa czasu letniego, a następnie porównać dzisiejsze przesunięcie strefy czasowej z przesunięciem strefy czasowej letniej. To zawsze da ci wiarygodną odpowiedź.

Ostateczna logika to:

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

Funkcja określająca, czy strefa czasowa w przeglądarce używa czasu letniego:

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
źródło
Według dateandtime.com czas letni rozpoczął się 10 marca 2019 roku, a zatem przypada latem, a nie zimą, a przesunięcie czasu letniego w Nowym Jorku wynosi -4, a nie -5.
jk7
Jeśli w odpowiedzi trzeba wprowadzić poprawki lub poprawki, wprowadź zmiany, a zostaną one sprawdzone.
Alan Wells
2

Użyj Moment.js ( https://momentjs.com/ )

moment().isDST(); poda, jeśli obserwuje się oszczędność światła dziennego.

Posiada również funkcję pomocniczą do obliczania czasu względnego. Nie musisz wykonywać ręcznych obliczeń npmoment("20200105", "YYYYMMDD").fromNow();

Santhosh S.
źródło
1

Jesteś blisko, ale trochę daleko. Nigdy nie musisz obliczać własnego czasu, ponieważ jest on wynikiem twojego własnego zegara. Może wykryć, czy korzystasz z czasu letniego w Twojej lokalizacji, ale nie w odległej lokalizacji wynikającej z przesunięcia:

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

To nadal będzie błędne i wyłączone o godzinę, jeśli są w czasie letnim. Potrzebujesz konta czasu zdalnego, jeśli obecnie znajdują się w swoim czasie letnim lub nie, i odpowiednio dostosuj. spróbuj to obliczyć i zmień zegar na - powiedzmy 01.02.2015 i cofnij zegar o godzinę, jakby był poza czasem letnim. Następnie oblicz przesunięcie dla miejsca, które powinno być jeszcze 2 godziny za. Pokaże się godzinę przed dwugodzinnym oknem. Nadal musiałbyś liczyć się z godziną i dostosować. Zrobiłem to dla NY i Denver i zawsze idę niepoprawnie (godzinę do przodu) w Denver.

Larry Enzer
źródło
1

Zauważyłem, że korzystanie z biblioteki Moment.js z niektórymi opisanymi tu koncepcjami (porównanie stycznia do czerwca) działa bardzo dobrze.

Ta prosta funkcja zwraca, czy strefa czasowa, w której znajduje się użytkownik, przestrzega czasu letniego:

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

Prostym sposobem sprawdzenia, czy to działa (w systemie Windows), jest zmiana strefy czasowej na strefę inną niż DST, na przykład Arizona zwróci wartość false, a EST lub PST zwróci true.

wprowadź opis obrazu tutaj

Nico Westerdale
źródło
1

Przyszłościowe rozwiązanie, które działa we wszystkich strefach czasowych

  1. Niech xbędzie spodziewaną liczbą milisekund do roku będącego przedmiotem zainteresowania bez uwzględnienia czasu letniego.
  2. Pozwolić ybyć liczba milisekund od epoki od początku roku do dnia zainteresowania.
  3. Niech zbędzie liczbą milisekund, które upłynęły od epoki pełnej interesującej daty i godziny
  4. Niech tbędzie odejmowanie zarówno xi yze z: z - y - x. Daje to przesunięcie wynikające z czasu letniego.
  5. Jeśli twynosi zero, czas letni nie obowiązuje. Jeśli tnie jest zerem, obowiązuje czas letni.

(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");
})();

Uważam, że powyższy fragment kodu jest lepszy od wszystkich innych odpowiedzi zamieszczonych tutaj z wielu powodów.

  • Ta odpowiedź działa we wszystkich strefach czasowych, nawet na Antarktydzie / Casey .
  • Czas letni może ulec zmianie. Może się zdarzyć, że za 20 lat w jakimś kraju będą obowiązywały 3 okresy czasu letniego zamiast normalnych 2. Ten kod obsługuje ten przypadek, zwracając przesunięcie czasu letniego w milisekundach, a nie tylko o tym, czy czas letni obowiązuje, czy nie.
  • Rozmiar miesięcy w roku i sposób, w jaki działają lata przestępne, doskonale wpisują się w utrzymywanie naszego czasu zgodnie ze słońcem. Do licha, działa tak doskonale, że wszystko, co robimy, to tylko kilka sekund tu i tam . Nasz obecny system lat przestępnych obowiązuje od 24 lutego 1582 roku i prawdopodobnie będzie obowiązywał w dającej się przewidzieć przyszłości.
  • Ten kod działa w strefach czasowych, które nie używają czasu letniego.
  • Ten kod działa w czasach historycznych przed wprowadzeniem czasu letniego (np. Na początku XX wieku).
  • Ten kod jest maksymalnie zoptymalizowany pod kątem liczby całkowitej i nie powinien stwarzać problemu, jeśli zostanie wywołany w ciasnej pętli. Po uruchomieniu powyższego fragmentu kodu przewiń w dół do końca wyniku, aby zobaczyć test porównawczy wydajności. Mój komputer jest w stanie przetworzyć 16384 dat w ~ 97 ms w przeglądarce Chrome.

Jeśli jednak nie przygotowujesz się na więcej niż 2 okresy czasu letniego, poniższy kod może posłużyć do określenia, czy czas letni obowiązuje jako wartość logiczna.

function isDaylightSavingsInEffect(dateInput) {
    // To satisfy the original question
    return dstOffsetAtDate(dateInput) !== 0;
}
Jack Giffin
źródło
0

Niedawno musiałem utworzyć ciąg daty z UTC i DST i na podstawie odpowiedzi Sheldona złożyłem to razem:

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
źródło
0

Czy jest problem z używaniem Date.toString().indexOf('Daylight Time') > -1

"" + new Date()

Sobota 01 stycznia 100050 00:00:00 GMT-0500 (Wschodni czas standardowy )

"" + new Date(...)

Niedz. 01 maja 100033 00:00:00 GMT-0400 (wschodni czas letni )

Wydaje się, że jest to zgodne ze wszystkimi przeglądarkami.

YC
źródło
Tak, to nie działa na całym świecie. Latem w Europie dostajesz"Thu Jul 02 2020 14:07:01 GMT+0200 (Central European Summer Time)"
Tadej Krevh
0

Styl ES6

Math.min(...[0, 6].map(v => new Date(95, v, 1).getTimezoneOffset() * -1));
nkitku
źródło