ローカルカレンダーの日時をUnixエポック以降のUTCミリ秒(またはDate
同じものを表すオブジェクト)に変換するJavaScriptアルゴリズムを探しています。いくつかの相対的なカレンダーの日付に対してこれを行うための典型的で、しばしば役立つ方法YYYY-MM-DD hh:mm:ss.zzz
は次のとおりです。
# Close, but not quite monotonic
(new Date(YYYY, MM-1, DD, hh, mm, ss, zzz)).getTime()
JavaScriptの実装にはDSTを処理する方法があり(夏時間、夏時間、必要に応じて独自のロケールに相当)、残念ながら、手元のアプリケーションでは機能せず、代わりに単調な現地時間を必要とします(ただし、必要に応じて歪む可能性があります)。
変換は、2つの相対的なカレンダー日付(つまり、タイムゾーンを無視する、DSTを無視する)AおよびBに対して、関数Cである変換が次のようになるという意味で単調でなければなりません。
If A is strictly earlier than B then C(A) ≤ C(B)
If A is simultaneous to B then C(A) = C(B)
If A is strictly later than B then C(A) ≥ C(B)
(これは、時間取得関数への連続した呼び出しが厳密に減少しないという意味で単調性を指していません。このアプリケーションには現在の時間の概念がなく、そのようなものは必要ありません。)
私は自分自身の実装に取り組み始めましたが、それは複雑になる恐れがあり、おそらく他の誰かがより良いアイデアを持っていると思います。
質問は次のとおりです。
- これはすでに実装されていますか?
- そうでない場合、これを実装するためのより適切な方法は、以下に概説するものよりもありますか?
- 不連続性検出ヒューリスティックは、世界中のすべての既知のDSTで機能しますか?
JavaScriptDate
の動作
以下は、2012年の米国におけるDSTのコーナーケースを表しています。値はFirefoxの実験結果です。ここで、関数Cが、指定さDate
れたローカルの日付と時刻を使用してオブジェクトを作成し、getTime()
メソッドを使用してUTCミリ秒を取得した結果を表すとします。
- スキップ時間:DSTの開始日である2012-03-11では、現地時間で02:00から始まる時間がスキップされます。01:59の次の分は03:00です。Firefoxでは、入力時間が遅いと、解決される時間が早くなる可能性があります。例:01:45 <02:15、ただしC(01:45)> C(02:15)であるため、スケールは単調ではありません。
- 2倍の時間:DSTの終了日である2012-11-04に、01:00から始まる時間が現地時間で2回発生します。01:59夏時間の次の分は01:00標準時、次に01:59の次の分です。標準時は02:00標準時です。Firefoxでは、C(01:30)は、後の繰り返しである標準時01:30に対応します。
- 解決動作が後で優先されることが保証されている限り、これは単調性を壊しません。(私はこの保証の文書を持っていませんが、おそらくECMA-262のいくつかの言語に基づいています。)
必須/推奨される動作
ここで、関数Cが目的の動作を伴う変換を表すとします。
- スキップされた時間:スキップされた分の日付は、スキップされていない最初の分に解決される必要があります。たとえば、DSTの開始日に、02:15、02:30、および02:45は、スキップされていない次の分である03:00に解決されます。つまり、C(02:15)= C(02:30)= C(02:45)= C(03:00)です。
- スキップされていない時間は変換されないままになります:01:45 <02:15 <02:45 <03:15をC(01:45)<C(02:15)= C(02:45)<C(03:15)と比較します。
- 2倍の時間:複数回発生する1分間の日付は、最初の発生のみに解決する必要があります。たとえば、DSTの終了日の01:30は、標準時間ではなく01:30の夏時間に解決されます。これは、2つのうち早い方であるためです。
- 以前と同じですが、以前の時間が保証されている点が異なります。
これらのルールは、Vixiecronのルールに大まかに基づいています。ただし、このアプリケーションは現在の時刻の概念を処理しないため、時刻の変化を監視するために必要な状態がありません。時間をスキップまたは2倍にするかどうか、またいつ行うかを決定する他の方法が必要になります。
ちなみに、追加の要件として、実装は米国のロケールで実行されていると想定してはなりません。国際的に機能する必要があり、可能な限り、設定より規約を使用します。
実装の考え
日付が不連続に該当するかどうかを検出するために役立つと私が考えた1つのことは、ローカル日付のスパンの幅を日付から±1暦日テストすることです。2つの日付のUTC時間の差が48時間未満またはそれより大きい場合は、それぞれ、一部の時間がスキップまたは2倍になったことを意味します。
hh:mm:ss.zzz
スキップされた場合、UTCに変換して戻った後、読み取りが異なる場合は、指定された時間自体がスキップされるかどうかをさらに判断できます。その場合、時間は不連続後の最初の1分に解決されます。- 2倍にすると、後の繰り返しですべての時間の範囲を決定する可能性があります。与えられた時間が後の繰り返しの範囲内にある場合、それは前の時間に戻されます。それ以外の場合は、そのままにしておきます。
これらは両方とも、不連続性の正確な位置を必要とする可能性があります。これは、たとえば、±1の日付で囲まれたバイナリ検索で実行できます。
このヒューリスティックは、複数の理由で失敗する可能性があります。私はそれらがありそうもないという印象を持っていますが、夏の時間のルールは奇妙で、世界中で一貫性がありません。
- 同じ3暦日以内に、いずれかの方向に複数の不連続性が発生する可能性がある場合。(米国では、1年に2か月の間隔があります。たとえば、4時間よりも長い量を調整する場所はないと思います。)
- 不連続性が補完的である場合、そもそも不連続性が検出されない可能性があります。
- いずれにせよ、単純な検索では、範囲内に不連続性が1つしかないことを前提としています。
- 単一の不連続性が(ほぼ)3暦日の期間を占める可能性がある場合。(米国では、各不連続性が1時間かかります。夏時間の調整は、どこでも数日程度になることはないと確信しています。)