web-dev-qa-db-ja.com

DST(夏時間)が有効かどうか、およびそれがオフセットであるかどうかを確認する方法は?

これは、これが必要なJSコードの一部です:

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

前の日付時刻を取得したいのですが、DSTが使用中の場合、日付は1時間ずれています。 DSTが使用中かどうかを確認する方法がわかりません。

夏時間の開始と終了をいつ知ることができますか?

135
Jo Smo

このコードは、getTimezoneOffsetが標準時間と夏時間(DST)の間にgreater値を返すという事実を使用しています。したがって、標準時間中に予想される出力を決定し、指定された日付の出力が同じ(標準)か少ない(DST)かを比較します。

getTimezoneOffsetは、UTCのゾーンwestの分positive分数を返すことに注意してください。通常はnegative時間(UTCの「背後」にあるため)と記述されます。たとえば、ロサンゼルスはTC-8h Standard、TC-7h DSTです。 getTimezoneOffsetは、480ではなく、12月(冬、標準時)に-480(正の480分)を返します。これは、東半球のnegative数を返します(冬のシドニーの-600は、これが「先」であっても(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!");
}
276
Sheldon Griffin

2つの日付を作成します。1つは6月、もう1つは1月です。 getTimezoneOffset()値を比較します。

  • 1月のオフセット> 6月のオフセットの場合、クライアントは北半球にあります
  • 1月のオフセット<6月のオフセットの場合、クライアントは南半球にあります
  • 差がない場合、クライアントのタイムゾーンはDSTを監視しません

次に、現在の日付のgetTimezoneOffset()を確認します。

  • 北半球の6月に等しい場合、現在のタイムゾーンはDST(+1時間)です
  • 南半球の1月に等しい場合、現在のタイムゾーンはDST(+1時間)
19
Jon Nylander

今日も同じ問題に直面しましたが、夏時間の開始と終了が米国とは異なる時間に(少なくとも私の理解では)異なるため、わずかに異なるルートを使用しました。

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

次に、現在のタイムゾーンオフセットとDSTおよびnonDSTを比較して、どれが一致するかを確認します。

12
Aaron Cole

Sheldon Griffinが提供するソリューションに関するMatt Johansonのコメントに基づいて、次のコードを作成しました。

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

これは、すべてのコメントと以前に提案された回答、具体的にはそれを考慮に入れて、すべての世界のベストを取得しようとします。

1)同じ年に複数の日付をテストするときに結果を再計算する必要がないように、1年ごとのstdTimezoneOffsetの結果をキャッシュします。

2)DST(存在する場合)が必ずしも7月にあるとは想定しておらず、ある時点およびある場所で任意の月になっても機能します。ただし、実際には7月(または数か月近く)が実際にDSTである場合、パフォーマンスの点でより高速に動作します。

3)さらに悪い場合は、各月の最初のgetTimezoneOffsetを比較します。 [そして、それをテストされた年に一度]。

それでも、DST期間がある場合は1か月よりも長いという前提があります。

誰かがその仮定を削除したい場合、彼はループをアーロン・コールが提供する溶質のようなものに変えることができます-しかし、私はまだ半年先にジャンプして、2つの異なるオフセットが見つかったらループから抜け出します]

9
epeleg

この回答は受け入れられた回答と非常に似ていますが、Dateプロトタイプをオーバーライドせず、2つではなく1つの関数呼び出しのみを使用して夏時間が有効かどうかを確認します。


アイデアは、7か月間続くDSTを遵守している国はないということです[1]、DSTを観測する地域では、1月のUTC時間からのオフセットは7月のオフセットとは異なります。

夏時間は時計を移動しますforwards、JavaScriptは常にgreater値を返します標準時間中。したがって、1月と7月の間の最小オフセットを取得すると、DST中にタイムゾーンオフセットが取得されます。

次に、日付のタイムゾーンがその最小値に等しいかどうかを確認します。そうである場合、DSTにいます。そうでない場合はそうではありません。

次の関数はこのアルゴリズムを使用します。日付オブジェクトdを受け取り、その日付で夏時間が有効な場合はtrueを返し、そうでない場合はfalseを返します。

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

moment.js ライブラリは、その時間オブジェクトに .isDst() メソッドを提供します。

moment#isDSTは、現在の時刻が夏時間かどうかを確認します。

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

ブラウザのJavaScriptのgetTimezoneOffset()メソッドは、00:00タイムゾーンからのオフセット分数を返します。たとえば、夏時間(DST)のAmerica/New_Yorkタイムゾーンは数値300を返します。300分はゼロから5時間の差です。 300分を60分で割ると5時間になります。すべてのタイムゾーンは、ゼロタイムゾーン+00:00/Etc/GMT /グリニッジ標準時間と比較されます。

MDN Webドキュメント

次に知っておく必要があるのは、オフセットが実際のタイムゾーンの反対の符号を持つことです。

タイムゾーンに関する情報は、Internet Assigned Numbers Authority(iana)によって管理されています

ianaタイムゾーン

タイムゾーンの適切にフォーマットされたテーブルは、joda.orgによって提供されます

joda-time Time Zones

+00:00またはEtc/GMTはグリニッジ標準時

すべてのタイムゾーンは+00:00/"Etc/GMT" /グリニッジ標準時からオフセットされています

夏時間は常に、夏の「通常の」時間よりも早い時間です。秋のシーズンに時計を戻します。 (何をすべきかを思い出すための「フォールバック」スローガン)

したがって、夏時間(冬)のアメリカ/ニューヨーク時間は、通常の時間の1時間前です。したがって、たとえば、通常は午後5時でした。夏のニューヨーク市の午後、現在は午後4時です。夏時間のアメリカ/ニューヨーク時間。 「America/New_York」時間という名前は、「ロングフォーマット」タイムゾーン名です。米国の東海岸では通常、タイムゾーンを東部標準時(EST)と呼びます

今日のタイムゾーンオフセットを他の日付のタイムゾーンオフセットと比較する場合は、タイムゾーンオフセットの数学記号(+/- "正/負")がタイムゾーンの反対であることを知る必要があります。

Joda.orgのタイムゾーンテーブルを見て、 "America/New_York"のタイムゾーンを見つけます。標準オフセットの前にマイナス記号が付いています。

地球はその軸上で反時計回りに回転します。グリニッジの日の出を見る人は、ニューヨーク市の誰かが日の出を見る5時間前に日の出を見る。そして、米国東海岸の誰かが日の出を見ると、米国西海岸の誰かが日の出を見ることになります。

このすべてを知る必要があるのには理由があります。そのため、1年のさまざまな時期にすべてのタイムゾーンをテストする必要なく、一部のJavaScriptコードがDSTステータスを正しく取得しているかどうかを論理的に判断できます。

ニューヨークの11月で、時計が1時間遅れていると想像してください。ニューヨーク市の夏では、オフセットは240分または4時間です。

これをテストするには、7月の日付を作成してからオフセットを取得します。

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

console.log('july_Timezone_OffSet: ' + july_Timezone_OffSet)

ブラウザの開発者ツールコンソールログには何が印刷されますか?

答えは:240

そのため、1月に日付を作成し、冬季のタイムゾーンオフセットに対してブラウザが何を返すかを確認できます。

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)

答えは:300

明らかに、300は240よりも大きいです。これはどういう意味ですか?冬のオフセットが夏のオフセットより大きいことをテストするコードを作成する必要がありますか?または、夏のオフセットは冬のオフセットよりも少ないですか?夏時間帯と冬時間帯のオフセットに差がある場合は、この時間帯にDSTが使用されていると想定できます。しかし、todayがブラウザーのタイムゾーンにDSTを使用しているかどうかはわかりません。そのため、今日のタイムゾーンオフセットを取得する必要があります。

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

console.log('todaysTimeZone : ' + todaysTimeZone)

答えは:? -時期によって異なります

今日のタイムゾーンオフセットとサマータイムゾーンオフセットが同じ場合、およびサマータイムゾーンオフセットとウィンタータイムゾーンオフセットは異なるため、論理的な推論により、今日はそうではないDSTで。

夏時間帯と冬時間帯のオフセットの比較を省略し(この時間帯にDSTが使用されているかどうかを確認するため)、今日の時間帯のオフセットと夏時間のTZオフセットを比較して、常に正しい答えを得ることができますか?

today's TZ Offset !== Summer TZ Offset

さて、今日は冬ですか、夏ですか?それを知っていれば、次のロジックを適用できます。

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

しかし、問題は、今日の日付が冬なのか夏なのかわからないということです。すべてのタイムゾーンには、DSTの開始時と終了時に関する独自のルールを設定できます。世界のすべてのタイムゾーンについて、すべてのタイムゾーンのルールを追跡する必要があります。したがって、より良い、より簡単な方法があれば、それをより良く、より簡単な方法で行うこともできます。

残っているのは、このタイムゾーンでDSTが使用されているかどうかを確認し、今日のタイムゾーンオフセットとサマータイムゾーンオフセットを比較する必要があるということです。それは常にあなたに信頼できる答えを与えるでしょう。

最終的なロジックは次のとおりです。

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

ブラウザのタイムゾーンが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
}
2
Alan Wells

Moment.js ライブラリをここで説明するいくつかの概念(1月から6月と比較して)を使用すると非常にうまく機能することがわかりました。

この単純な関数は、ユーザーがいるタイムゾーンが夏時間を遵守しているかどうかを返します。

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

これが機能することを確認する簡単な方法(Windows)は、タイムゾーンを非DSTゾーンに変更することです。たとえば、Arizonaはfalseを返しますが、ESTまたはPSTはtrueを返します。

enter image description here

1
Nico Westerdale

あなたは近いが少し離れている。あなた自身の時計の結果であるため、あなた自身の時間を計算する必要はありません。現在地で夏時間を使用しているかどうかを検出できますが、オフセットによって生成された遠隔地では使用できません。

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

DSTにいる場合、これはまだ間違っており、1時間もずれています。現在DST内にいるかどうかにかかわらず、リモートタイムアカウントが必要であり、それに応じて調整します。これを計算してから時計を変更してください-2015年2月1日と言って、DSTの外にいるかのように時計を1時間戻す次に、まだ2時間遅れているはずの場所のオフセットを計算します。 2時間前に1時間表示されます。それでも時間を考慮して調整する必要があります。私はニューヨークとデンバーでそれをやったが、デンバーではいつも間違った時間(前の時間)に行く。

1
Larry Enzer
  1. xを、夏時間を考慮せずに、対象の年までの予想ミリ秒数とします。
  2. yを、対象の日付の年の初めから Epoch からのミリ秒数とします。
  3. zを、対象の完全な日時の Epoch からのミリ秒数とする
  4. txyの両方をzから減算したものをz - y - xとします。これにより、DSTによるオフセットが生成されます。
  5. tがゼロの場合、DSTは有効ではありません。 tがゼロでない場合、DSTは有効です。
(function(){"use strict";
function isDaylightSavingsInEffect(dateInput) {
    return dstOffsetAtDate(dateInput) !== 0;
}
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");
})();

上記のコードスニペットは、多くの理由でここに投稿された他のすべての回答よりも優れていると思います。

  • Antarctica/Casey であっても、この答えはすべてのタイムゾーンで機能します。
  • 夏時間は非常に変更される可能性があります。 20年後、国によっては通常の2ではなく3つのDST期間がある場合があります。このコードは、DSTが有効であるかどうかだけでなく、DSTオフセットをミリ秒単位で返すことでそのケースを処理します。
  • 1年の月のサイズとうるう年の働き方は、私たちの時間を太陽に合わせて調整するのに最適です。なんてこった、完璧に機能するので、私たちがやることはただ あちこちで数秒調整するだけ だけです。うるう年の現在のシステムは 1582年2月24日 以来有効であり、近い将来に有効になる可能性があります。
  • このコードは、DSTを使用しないタイムゾーンで機能します。
  • このコードは、DSTが実装される前の歴史的な時代(1900年代など)に機能します。
  • このコードは最大限に整数最適化されており、タイトなループで呼び出されても問題はありません。上記のコードスニペットを実行した後、出力の一番下までスクロールして、パフォーマンスベンチマークを確認します。私のコンピューターは、Chromeで最大97ミリ秒で16384日付を処理できます。
0
Jack Giffin

最近、UTCとDSTを使用して日付文字列を作成する必要がありましたが、シェルドンの答えに基づいて、これをまとめました。

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