Bagaimana cara memeriksa apakah DST (Daylight Saving Time) sedang berlaku, dan jika demikian, offset?

154

Ini adalah sedikit kode JS saya yang diperlukan:

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

Saya ingin mendapatkan datetime di "lalu", tetapi jika DST sedang digunakan maka tanggal dimatikan oleh 1 jam. Saya tidak tahu bagaimana memeriksa apakah DST berlaku atau tidak.

Bagaimana saya bisa tahu kapan penghematan siang hari dimulai dan berakhir?

Jo Smo
sumber

Jawaban:

313

Kode ini menggunakan fakta yang getTimezoneOffsetmengembalikan nilai lebih besar selama Waktu Standar versus Waktu Siang Hari (DST). Dengan demikian ia menentukan output yang diharapkan selama Waktu Standar, dan membandingkan apakah output dari tanggal yang diberikan sama (Standar) atau kurang (DST).

Perhatikan bahwa getTimezoneOffsetmengembalikan jumlah menit positif untuk zona di barat UTC, yang biasanya dinyatakan sebagai jam negatif (karena mereka "di belakang" UTC). Sebagai contoh, Los Angeles adalah UTC – 8h Standard, UTC-7h DST. getTimezoneOffsetmengembalikan 480(positif 480 menit) pada bulan Desember (musim dingin, Waktu Standar), daripada -480. Ini mengembalikan angka negatif untuk Belahan Timur (seperti -600untuk Sydney di musim dingin, meskipun ini "di depan" ( UTC + 10j ).

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
sumber
28
Saya dapat memverifikasi bahwa ini berfungsi secara internasional. Saat ini tidak ada zona waktu yang menggunakan segala bentuk DST di mana 1 Jan dan 1 Juli keduanya berada di dalam atau keduanya di luar periode DST. Juga, di semua zona waktu di TZDB ( dengan satu pengecualian sepele ) yang lebih besar dari dua offset adalah offset DST. Karena JavaScript getTimezoneOffsetmengembalikan nilai terbalik, maka Math.maxmemang mengembalikan offset standar . Kode itu benar.
Matt Johnson-Pint
7
Namun, jika ada zona waktu yang mengubah definisinya sedemikian rupa sehingga tanggal 1 Januari dan 1 Juli keduanya dalam DST, atau keduanya tidak dalam DST (dan DST masih berlaku), maka kode ini tidak akan berfungsi di zona itu.
Matt Johnson-Pint
9
Ini tidak berfungsi secara umum, misalnya ada negara yang belum pernah mengamati DST pada tahun-tahun tertentu dan juga beberapa negara mengembalikan DST selama bulan ramadhan. Selain itu, definisi ECMAScript untuk Date rusak dan juga penanganan variabel lingkungan TZ rusak dalam beberapa implementasi. Semua ini dikombinasikan membuat metode ini tidak dapat diandalkan. Anda lebih baik menggunakan perpustakaan yang tidak menggunakan Tanggal mis.
Waktuzonecomplete
5
Kode ini tidak berfungsi di negara-negara yang tidak mematuhi DST, seperti misalnya Afrika Selatan atau Islandia; artinya jika Anda menggunakannya untuk membandingkan dengan zona waktu lainnya di negara-negara tersebut, itu tidak akan menunjukkan waktu yang tepat di sana. Sarankan menggunakan UTC sepenuhnya, dan periksa secara manual apakah waktu sekarang berada dalam kisaran DST tertentu. Maka itu hanya masalah mengubah waktu normal UTC diimbangi dengan +1 untuk mendapatkan DST.
Kebman
1
Bagaimana ini bisa benar? Jerman misalnya memasuki DST pada 2016-10-30 sementara Amerika Serikat masuk satu minggu kemudian pada 2016-11-06. Informasi buruk seperti ini adalah apa yang menyebabkan hal-hal seperti ini terjadi: macworld.co.uk/news/apple/…
Daniel F
22

Buat dua tanggal: satu di bulan Juni, satu di bulan Januari. Bandingkan nilai getTimezoneOffset () mereka.

  • jika offset Januari> offset Juni, klien ada di belahan bumi utara
  • jika offset Januari <offset Juni, klien berada di belahan bumi selatan
  • jika tidak ada perbedaan, zona waktu klien tidak mematuhi DST

Sekarang periksa getTimezoneOffset () dari tanggal saat ini.

  • jika sama dengan Juni, belahan bumi utara, maka zona waktu saat ini adalah DST (+1 jam)
  • jika sama dengan Januari, belahan bumi selatan, maka zona waktu saat ini adalah DST (+1 jam)
Jon Nylander
sumber
Mengapa Anda membutuhkan hemisfer? apakah itu tidak cukup untuk mengatakan bahwa jika getTimezoneOffset () untuk tanggal saat ini sama dengan yang lebih kecil dari dua getTimezoneOffset () maka DST? [dan offset adalah perbedaan antara keduanya?]
epeleg
Anda tidak memerlukan belahan otak seperti yang ditunjukkan dengan jelas oleh jawaban yang diterima :)
Jon Nylander
Ini tidak akan berhasil. Hal terbaik untuk dilakukan adalah memastikan Anda menggunakan waktu UTC dan secara manual mengatur offset untuk wilayah yang Anda inginkan. Kemudian secara manual temukan mulai dan selesai untuk DST untuk wilayah yang sama (jika ada). Kemudian Anda ingin memeriksa apakah waktu untuk wilayah itu di dalam rentang DST atau tidak, dan kemudian memperbarui offset sesuai dengan +1. Hal ini memungkinkan untuk membandingkan negara yang mengamati DST dan negara yang tidak.
Kebman
Pertanyaannya adalah bagaimana menentukan apakah DST berlaku saat ini di zona waktu mesin klien Kebman, bukan bagaimana menampilkan tanggal, klien web sudah menangani itu untuk Anda.
Jon Nylander
Anda harus memeriksa antara Januari dan Juli (atau Februari dan Agustus, Maret dan September, dll.) Karena keduanya terpisah 6 bulan.
kpull1
17

Jawaban ini sangat mirip dengan jawaban yang diterima, tetapi tidak mengesampingkan Dateprototipe, dan hanya menggunakan satu pemanggilan fungsi untuk memeriksa apakah Daylight Savings Time berlaku, bukan dua.


Idenya adalah bahwa, karena tidak ada negara yang mengamati DST yang berlangsung selama 7 bulan [1] , di daerah yang mengamati DST, offset dari waktu UTC pada bulan Januari akan berbeda dengan yang di bulan Juli.

Saat Daylight Savings Time memindahkan jam ke depan , JavaScript selalu mengembalikan nilai lebih besar selama Waktu Standar. Karenanya, mendapatkan offset minimum antara Januari dan Juli akan mendapatkan zona waktu offset selama DST.

Kami kemudian memeriksa apakah zona waktu tanggal sama dengan nilai minimum itu. Jika ya, maka kita berada di DST; kalau tidak, kita tidak.

Fungsi berikut menggunakan algoritma ini. Dibutuhkan objek tanggal d,, dan kembali truejika waktu musim panas berlaku untuk tanggal tersebut, dan falsejika tidak:

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
sumber
1
Ini berfungsi, tetapi jika tidak ada DST di TimeZone saat ini maka itu juga akan menghasilkan true, yang tidak benar. Jika Anda beralih ke Math.max(...) != d.get...(), itu akan mengembalikan true jika DST diamati dalam zona waktu yang diberikan DAN tanggal saat ini di DST. Jika DST tidak diamati atau tanggal cocok dengan standar offset, itu akan kembali salah.
GreySage
12

Saya dihadapkan dengan masalah yang sama hari ini, tetapi karena daylight saving kami mulai dan berhenti pada waktu yang berbeda dari Amerika Serikat (setidaknya dari pemahaman saya), saya menggunakan rute yang sedikit berbeda ..

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

Maka Anda cukup membandingkan offset zona waktu saat ini dengan DST dan nonDST untuk melihat mana yang cocok.

Aaron Cole
sumber
Ini adalah bagaimana kami melakukannya juga. Yaitu, cari tahu waktu dalam setahun perubahan DST di zona waktu target Anda, dan menghitung offset untuk hari ini dan tanggal perubahan terbaru. Mereka akan berbeda satu jam atau sama (dengan asumsi zona waktu yang dimaksud adalah offset satu jam).
Heather
Tidak perlu untuk membuat nilai-nilai 365, pendekatan pencarian biner yang berhenti segera setelah perubahan dalam offset ditentukan harus jauh lebih efisien, bahkan ketika penghematan siang hari tidak diamati. Semua pendekatan ini mengasumsikan bahwa tempat-tempat mengamati penghematan siang hari setiap tahun, yang belum tentu benar. Tempat mengadopsi dan mengabaikan penghematan siang hari dari waktu ke waktu (meskipun ECMAScript mengasumsikan aturan saat ini, apa pun bidangnya, diterapkan selalu).
RobG
2
Rob - bagaimana Anda bisa melakukan ini melalui pencarian biner jika Anda tidak tahu di mana harus mencari (yaitu tempat yang Anda cari berada di atas atau di bawah titik uji r Anda?)
epeleg
9

Berdasarkan komentar Matt Johanson tentang solusi yang diberikan oleh Sheldon Griffin, saya membuat kode berikut:

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

Itu mencoba untuk mendapatkan yang terbaik dari semua dunia dengan mempertimbangkan semua komentar dan jawaban yang disarankan sebelumnya dan secara khusus:

1) Tembolok hasil untuk stdTimezoneOffset per tahun sehingga Anda tidak perlu menghitung ulang saat menguji beberapa tanggal pada tahun yang sama.

2) Ini tidak berasumsi bahwa DST (jika ada sama sekali) harus pada bulan Juli, dan akan bekerja bahkan jika itu akan pada suatu titik dan suatu tempat akan ada bulan. Namun Performa akan bekerja lebih cepat jika memang Juli (atau dekat bulan) memang DST.

3) Kasus yang lebih buruk itu akan membandingkan getTimezoneOffset dari yang pertama setiap bulan. [dan lakukan itu Sekali per tahun yang diuji].

Asumsi itu masih membuat adalah bahwa jika ada periode DST lebih besar dari satu bulan.

Jika seseorang ingin menghapus asumsi itu, ia dapat mengubah lingkaran menjadi sesuatu yang lebih seperti apa yang ada di solutin yang disediakan oleh Aaron Cole - tapi saya masih akan melompat setengah tahun ke depan dan keluar dari lingkaran ketika dua offset berbeda ditemukan]

epeleg
sumber
4

The moment.js perpustakaan menyediakan .isDst()metode pada objek waktunya.

moment # isDST memeriksa apakah momen saat ini dalam waktu musim panas.

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
sumber
Saya mencoba var moment = require ('moment'); this.logger.info (moment ([2011, 2, 12]). isDST ()); this.logger.info (moment ([2011, 2, 14]). isDST ()); keduanya palsu
Logan_B
Tanggal perubahan DST bervariasi di antara negara , bahkan di antara negara bagian di negara yang sama (yaitu negara bagian Arizona). Di AS pada 2011-03-13, sedangkan di Jerman pada 2011-03-31. Jadi hasilnya akan berbeda tergantung pada zona waktu saat mana. Js dikonfigurasikan untuk bekerja.
Daniel F
1
Bahkan bervariasi di dalam negara bagian Arizona timeanddate.com/time/us/arizona-no-dst.html
Daniel F
3

The getTimezoneOffset()metode dalam JavaScript, dalam browser, mengembalikan jumlah menit offset dari zona 00:00 waktu. Misalnya, zona waktu America / New_York di Daylight Savings (DST) mengembalikan angka 300. 300 menit adalah perbedaan 5 jam dari nol. 300 menit dibagi 60 menit adalah 5 jam. Setiap zona waktu dibandingkan dengan zona waktu nol, +00: 00 / Dll / GMT / Waktu Greenwich.

Dokumen Web MDN

Hal berikutnya yang harus Anda ketahui, adalah offset memiliki tanda kebalikan dari zona waktu aktual.

Informasi tentang zona waktu dikelola oleh Otoritas Angka yang Ditugaskan Internet (iana)

zona waktu iana

Tabel Zona Waktu yang diformat dengan baik disediakan oleh joda.org

Zona Waktu joda-waktu

+00: 00 atau Dll / GMT adalah waktu Greenwich

Semua zona waktu diimbangi dari +00: 00 / "Dll ​​/ GMT" / Waktu Greenwich

Waktu Musim Panas selalu lebih awal dari waktu "reguler" di musim panas. Anda mengatur jam Anda kembali di musim gugur. (Slogan "Fall Back" untuk mengingat apa yang harus dilakukan)

Jadi, waktu Amerika / New_York di Daylight Savings (musim dingin) adalah satu jam sebelum waktu reguler. Jadi, misalnya, apa yang biasanya jam 5 sore di kota New York di musim panas, sekarang jam 4 sore Amerika / waktu New York di Daylight Savings. Nama waktu "Amerika / New_York" adalah nama zona waktu "Format Panjang". Pantai timur AS biasanya menyebut zona waktu mereka Eastern Standard Time (EST)

Jika Anda ingin membandingkan offset zona waktu hari ini dengan offset zona waktu pada beberapa tanggal lain, Anda perlu tahu bahwa tanda matematika (+/- "Positif / Negatif") dari zona waktu offset adalah kebalikan dari zona waktu.

Lihatlah tabel zona waktu di joda.org dan temukan zona waktu untuk "Amerika / New_York" Ini akan memiliki tanda negatif di depan Offset Standar.

Bumi berputar berlawanan arah jarum jam pada porosnya. Seseorang yang menyaksikan matahari terbit di Greenwich melihat matahari terbit 5 jam sebelum seseorang di Kota New York melihat matahari terbit. Dan seseorang di Pantai Barat AS akan melihat matahari terbit setelah seseorang di Pantai Timur AS melihat matahari terbit.

Ada alasan mengapa Anda perlu mengetahui semua ini. Sehingga Anda dapat menentukan secara logis apakah beberapa kode JavaScript mendapatkan status DST dengan benar atau tidak, tanpa perlu menguji setiap zona waktu pada waktu yang berbeda dalam setahun.

Bayangkan bulan November di New York City, dan jam telah diatur mundur satu jam. Di musim panas di New York City, offset adalah 240 menit atau 4 jam.

Anda dapat menguji ini dengan membuat tanggal pada bulan Juli dan kemudian mendapatkan offsetnya.

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

console.log('july_Timezone_OffSet: ' + july_Timezone_OffSet)

Apa yang akan dicetak ke log konsol alat pengembang browser?

Jawabannya adalah: 240

Jadi, sekarang Anda dapat membuat tanggal di Januari dan melihat apa yang dikembalikan browser Anda untuk offset zona waktu untuk musim dingin.

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)

Jawabannya adalah: 300

Jelas 300 lebih besar dari 240. Jadi, apa artinya ini? Haruskah Anda menulis kode yang menguji offset musim dingin lebih besar daripada offset musim panas? Atau offset musim panas kurang dari offset musim dingin? Jika ada perbedaan antara offset zona waktu musim panas dan musim dingin, maka Anda dapat mengasumsikan bahwa DST digunakan untuk zona waktu ini. Tetapi itu tidak memberi tahu Anda jika hari ini menggunakan DST untuk zona waktu browser. Jadi, Anda harus mendapatkan offset zona waktu untuk hari ini.

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

console.log('todaysTimeZone : ' + todaysTimeZone)

Jawabannya adalah:? - Tergantung pada waktu tahun

Jika offset zona waktu hari ini dan offset zona waktu musim panas adalah sama, DAN offset zona waktu musim panas dan musim dingin berbeda, maka dengan deduksi logis, hari ini TIDAK boleh dalam DST.

Dapatkah Anda menghilangkan membandingkan offset zona waktu musim panas dan musim dingin, (Untuk mengetahui apakah DST digunakan untuk zona waktu ini) dan hanya membandingkan offset zona waktu hari ini dengan offset TZ musim panas, dan selalu mendapatkan jawaban yang benar?

today's TZ Offset !== Summer TZ Offset

Nah, apakah hari ini di musim dingin atau musim panas? Jika Anda tahu itu maka Anda bisa menerapkan logika berikut:

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

Tetapi masalahnya adalah, Anda tidak tahu apakah kencan hari ini di musim dingin atau musim panas. Setiap zona waktu dapat memiliki aturannya sendiri untuk kapan DST dimulai dan berhenti. Anda harus melacak aturan setiap zona waktu untuk setiap zona waktu di dunia. Jadi, jika ada cara yang lebih baik dan lebih mudah maka Anda mungkin melakukannya dengan cara yang lebih baik dan lebih mudah.

Yang tersisa, adalah Anda perlu tahu apakah zona waktu ini menggunakan DST, dan kemudian membandingkan zona waktu hari ini dengan zona waktu musim panas. Itu akan selalu memberi Anda jawaban yang dapat diandalkan.

Logika terakhir adalah:

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

Berfungsi untuk menentukan apakah zona waktu di browser menggunakan 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
}
Alan Wells
sumber
1
Menurut dateandtime.com, DST dimulai 10 Maret di 2019, dan karenanya di musim panas, bukan musim dingin, dan offset DST New York adalah -4, bukan -5.
jk7
Jika perbaikan atau perbaikan perlu dilakukan untuk jawabannya, silakan edit, dan itu akan ditinjau.
Alan Wells
2

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

moment().isDST(); akan memberi Anda jika penghematan cahaya Hari diamati.

Juga memiliki fungsi pembantu untuk menghitung waktu relatif untuk Anda. Anda tidak perlu melakukan perhitungan manual misalnyamoment("20200105", "YYYYMMDD").fromNow();

Santhosh S
sumber
1

Anda sudah dekat tetapi sedikit off. Anda tidak perlu menghitung waktu Anda sendiri karena ini adalah hasil dari jam Anda sendiri. Itu dapat mendeteksi jika Anda menggunakan waktu musim panas di lokasi Anda tetapi tidak untuk lokasi jarak jauh yang diproduksi oleh offset:

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

Ini akan tetap salah dan mati satu jam jika mereka berada di DST. Anda memerlukan akun waktu jauh jika mereka berada di dalam DST mereka atau tidak dan menyesuaikannya. coba hitung ini dan ubah jam Anda ke - misalkan 2/1/2015 dan reset jam satu jam seolah-olah di luar DST. Kemudian hitung untuk offset untuk tempat yang masih tertinggal 2 jam. Ini akan menunjukkan satu jam di depan jendela dua jam. Anda masih perlu menghitung jam dan menyesuaikannya. Saya melakukannya untuk NY dan Denver dan selalu salah (jam depan) di Denver.

Larry Enzer
sumber
1

Saya telah menemukan bahwa menggunakan perpustakaan Moment.js dengan beberapa konsep yang dijelaskan di sini (membandingkan Jan hingga Juni) bekerja sangat baik.

Fungsi sederhana ini akan mengembalikan apakah zona waktu yang digunakan pengguna dalam mengamati Daylight Saving Time:

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

Cara sederhana untuk memeriksa apakah ini berfungsi (pada Windows) adalah mengubah zona waktu Anda menjadi zona non DST, misalnya Arizona akan mengembalikan false, sedangkan EST atau PST akan mengembalikan true.

masukkan deskripsi gambar di sini

Nico Westerdale
sumber
1

Solusi Masa Depan-Bukti Yang Bekerja Di Semua Zona Waktu

  1. Membiarkan xmenjadi jumlah yang diharapkan dari milidetik ke tahun bunga tanpa memperhitungkan penghematan siang hari.
  2. Membiarkan ymenjadi jumlah milidetik sejak Zaman sejak awal tahun tanggal bunga.
  3. Membiarkan zmenjadi jumlah milidetik sejak Zaman penuh tanggal dan waktu menarik
  4. Biarkan tmenjadi pengurangan dari kedua xdan ydari z: z - y - x. Ini menghasilkan offset karena DST.
  5. Jika tnol, maka DST tidak berlaku. Jika ttidak nol, maka DST berlaku.

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

Saya percaya bahwa cuplikan kode di atas lebih unggul daripada semua jawaban lain yang diposting di sini karena berbagai alasan.

  • Jawaban ini berfungsi di semua zona waktu, bahkan Antartika / Casey .
  • Tabungan siang hari bisa sangat berubah. Mungkin 20 tahun dari sekarang, beberapa negara mungkin memiliki 3 periode DST daripada normal 2. Kode ini menangani kasus itu dengan mengembalikan offset DST dalam milidetik, bukan hanya apakah DST berlaku atau tidak.
  • Ukuran bulan dalam setahun dan cara Leap Years bekerja sangat cocok untuk menjaga waktu kita tetap di jalur matahari. Heck, itu bekerja sangat sempurna sehingga semua yang pernah kita lakukan hanya menyesuaikan beberapa detik di sana-sini . Sistem tahun kabisat kami saat ini telah berlaku sejak 24 Februari 1582 , dan kemungkinan akan tetap berlaku di masa mendatang.
  • Kode ini berfungsi di zona waktu yang tidak menggunakan DST.
  • Kode ini berfungsi di masa bersejarah sebelum ketika DST diimplementasikan (seperti tahun 1900-an).
  • Kode ini dioptimalkan integer maksimal dan seharusnya tidak memberi Anda masalah jika dipanggil dalam loop ketat. Setelah menjalankan cuplikan kode di atas, gulir ke bawah ke bagian bawah output untuk melihat tolok ukur kinerja. Komputer saya dapat memproses 16384 tanggal dalam ~ 97ms pada Chrome.

Namun, jika Anda tidak mempersiapkan lebih dari 2 periode DST, maka kode di bawah ini dapat digunakan untuk menentukan apakah DST berlaku sebagai boolean.

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

Saya baru-baru ini perlu membuat string tanggal dengan UTC dan DST, dan berdasarkan jawaban Sheldon saya menyatukan ini:

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
sumber
0

Apakah ada masalah menggunakan Date.toString().indexOf('Daylight Time') > -1

"" + new Date()

Sabtu 01 Jan 100050 00:00:00 GMT-0500 ( Waktu Standar Timur )

"" + new Date(...)

Minggu 01 Mei 100033 00:00:00 GMT-0400 ( Waktu Siang Timur )

Tampaknya ini kompatibel dengan semua browser.

YC
sumber
Ya, itu tidak berfungsi di seluruh dunia. Di musim panas di Eropa, Anda dapatkan"Thu Jul 02 2020 14:07:01 GMT+0200 (Central European Summer Time)"
Tadej Krevh
0

Gaya ES6

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