0

ローカルカレンダーの日時を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時間かかります。夏時間の調整は、どこでも数日程度になることはないと確信しています。)
4

1 に答える 1

0

少なくとも現在のUSA規則では、上記の必須/優先動作と一致する実装が利用可能になりました。全体として、このメカニズムはそれほど非効率的ではありません。最悪の場合(スキップされた分)、それはO(lg n)です。ここで、nは夏と冬の間の変化の分数(私が住んでいる60)であり、他のすべての場合、それはO(1)です。

  • 入力は「顔」(DSTを知らないカレンダーの日付と時刻)です。
  • 出力はDate、入力面に基づいて設定されたローカル面を持つです。
    • 入力面が正確に1つのローカル日付を表す場合、出力は面の統計がコンストラクターDateに渡された場合と同じになります。Date
    • 入力面がゼロのローカル日付を表す場合(DSTが前方にスキップするため)、出力Dateはスキップ後の最初の1分を反映します。
    • 入力面が2つのローカル日付を表す場合(DSTが繰り返されるため)、出力Dateは2つのうち早い方を反映します。

実装に関する注意:

  • この.getTimezoneOffset()方法は、2つの日付が不連続性の反対側にあるかどうかを判断するために使用されます。
  • 面が近くにある可能性のある不連続性の前のオフセットは、Dateその面の24ローカル時間前のオフセットを取得することによって検出されます。
  • 顔は、ローカルで解釈されるコンストラクターにDateその統計を渡すことによってに変換されます。Date
  • 変換されたローカル面がDate入力面と同じでない場合、この面は現地時間で直接表現できません。スキップされました。
    • 変換されDateたものは無効として扱われます。
    • 不連続性に続くタイムゾーンオフセットはDate、入力面から24時間後のローカル面のオフセットを取得することによって決定されます。
    • 不連続性の前後のオフセットの違いが見つかります。入力面のの時間から後の時間(定義上、両方ともローカル日付として表現可能である必要があります)まで、不連続後の最初の1分を見つけるために二分探索が使用されます。このDate分を表すのが出力です。
  • 変換されたローカル面がDate入力面と同じである場合、
    • 変換されDateたものに不連続性前のオフセットがある場合、それは正しいです。
    • これには、DST変更の近くにない顔が含まれます。不連続性がない場合、その日のすべての時間は同じオフセットを共有します。
    • 顔が2倍になったとしても、早い解釈が正しい解釈です。(これが発生する可能性があるかどうかは、実装に依存する可能性があります。)
    • Date不連続後に変換が発生した場合、
    • 少なくともオフセット差だけ不連続よりも遅い時間であれば正しいです。
    • それが不連続からその後の1つのオフセット差までの時間の範囲内にある場合、それは2倍の時間の後の解釈にあります。オフセットの差を差し引くことで正しい日付が見つかり、以前の解釈が得られます。
    • オフセットの差が1つ早いaのオフセットが早い場合、 ADateはこの範囲内にあると判断されます。Date変換されDateたオフセットは遅いため、不連続性はそれよりも最近発生したと判断されます。
于 2013-01-09T20:47:00.663 に答える