5

多くのWebサイト(通常はフォーラム)では、ユーザーが次を選択してTimeZone設定を指定できることを確認しました。

  • TimeZone
  • DSTを使用するかどうか

私の知る限り、変換を行うとき、.NETは常にDSTを考慮に入れるため、問題は次のとおりです。

「DSTを使用しない」部分をC#で実装するにはどうすればよいですか?

このポイントの下で、私はこれまでに何とかしたことを提示しますが、それはハッキーな感じがして、よりクリーンでより良いアプローチがあるかどうか疑問に思いました。

まず、DSTが自動的に適用されることを確認するために、次のテストを作成しました。

[Test]
public void DateTimeConversion_ToLocalTime_HandlesDSTByDefault()
{
    var utcDateInDstInterval = new DateTime(2012, 07, 15, 0, 0, 0, DateTimeKind.Utc);
    var utcDateOutisdeDstInterval = new DateTime(2012, 02, 15, 0, 0, 0, DateTimeKind.Utc);

    var roTimezone = TimeZoneInfo.FindSystemTimeZoneById("GTB Standard Time");

    Assert.AreEqual(3, TimeZoneInfo.ConvertTimeFromUtc(utcDateInDstInterval, roTimezone).Hour);
    Assert.AreEqual(2, TimeZoneInfo.ConvertTimeFromUtc(utcDateOutisdeDstInterval, roTimezone).Hour);
}

このテストは合格し、次のことを示しています。

  • DSTが適用されない場合(たとえば冬季)、ルーマニアの時刻はUTC+2時間です。
  • DSTが適用される場合(たとえば夏時間)、ルーマニアの時刻はUTC+3時間です。
  • 日時変換を行う場合、DSTは自動的に考慮されます

TimeZoneInfo.GetAdjustmentRules()次に、オブジェクトの配列を返すメソッドに気づき、AdjustmentRuleこれらのルールの効果を元に戻すと、DSTの影響を受けない値を取得できることがわかりました。

DateTimeそのため、オブジェクトがDSTの影響を受ける場合に、これを行う次のメソッドを作成しました。

private DateTime RemoveDSTFromDateTime(DateTime dateTime, TimeZoneInfo timeZoneInfo)
{
    if (!dateTime.IsDaylightSavingTime())
        return dateTime;

    var result = dateTime;

    foreach (var adjustmentRule in timeZoneInfo.GetAdjustmentRules())
        result = result.Subtract(adjustmentRule.DaylightDelta);

    return result;
}

元のDST/DSTなしのシナリオに戻りますが、今回は結果がDSTの影響を受けないようにします。

[Test]
public void DateTimeConversion_ToLocalTime_WithoutDST()
{
    var utcDateInDstInterval = new DateTime(2012, 07, 15, 0, 0, 0, DateTimeKind.Utc);
    var utcDateOutisdeDstInterval = new DateTime(2012, 02, 15, 0, 0, 0, DateTimeKind.Utc);

    var roTimezone = TimeZoneInfo.FindSystemTimeZoneById("GTB Standard Time");

    var convertedDateWithDst = TimeZoneInfo.ConvertTimeFromUtc(utcDateInDstInterval, roTimezone);
    var convertedDateWithoutDst = TimeZoneInfo.ConvertTimeFromUtc(utcDateOutisdeDstInterval, roTimezone);

    Assert.AreEqual(2, RemoveDSTFromDateTime(convertedDateWithDst, roTimezone).Hour);
    Assert.AreEqual(2, RemoveDSTFromDateTime(convertedDateWithoutDst, roTimezone).Hour);
}

このテストも合格し、DSTの影響がキャンセルされたことを示しています(時期に関係なく、常にUTC + 2hを取得します)。

これを書き留めていると、うまくいくように見える別のアイデアが浮かびました。メソッドを使用する代わりに、UTC日付にTimeZoneInfo.Convert...()追加するだけです。roTimezone.BaseUtcOffset

誰かがこれを行う正しい方法を示すことができますか?

4

3 に答える 3

4

質問を解析すると、2つの解決策が提案されているようです。

  1. DST調整を決定し、変換後の出力から削除します。

  2. UTCDateTimeを取得して追加すると、BaseUtcOffset常に標準時間を処理できます。

あなたの質問はDSTを実装しない方法だったので、オプション#2で自分で答えたと思います。

そうは言っても、あなたの最初の仮定には欠陥があります。多くのサイトがタイムゾーンとDSTを要求する理由は、通常、タイムゾーンの実装が最初からDSTをサポートしていないためです。彼らがしているのは、ベースオフセットを選択して、1年の設定された時間に1時間を追加するかどうかを決定することです。彼らはそれを「タイムゾーン」と呼ぶかもしれませんが、.NetのTimeZoneInfoクラスやNodaTimeのようなライブラリほど堅牢ではありません。

byなどの「タイムゾーン」を本当に選択している場合TimeZoneInfo.GetSystemTimeZones()(プロパティを保存してIdプロパティを表示する必要がありDisplayNameます)、DSTを使用するかどうかをユーザーに絶対に尋ねないでください。ユーザーがDSTが使用されていない場所(アリゾナなど)に住んでいる場合は、そのための選択肢がすでにあります。ユーザーは通常、必要な効果を得るために適切な選択を選択することにかなり優れています。特に、奇妙なDSTルール(インディアナなど)のある地域に住んでいる場合はなおさらです。

のようなIANA/Olsonスタイルのタイムゾーンを使用している場合、それらがNoda Time"America/New York"によって提供されているか、他の実装によって提供されているかにかかわらず、同じ考え方が当てはまります。ユーザーではなく、DSTの決定をライブラリに委託する必要があります。

これをライブラリに委託するための非常に有効な議論の1つは、これらのDSTルールは変更される可能性があり、その存続期間の多くの時点で変更されているということです過去の情報を扱うあらゆる種類のアプリケーションやサイトを作成している場合、今日有効なものは過去に起こったことに対する正しい調整ではないことに気付くかもしれません。また、オーストラリアのように、特定のエリアが1時間ではなく30分オフセットされているタイムゾーンの世界には、多くの奇妙な点があります。本当にこれを自分で管理したいですか?おそらくそうではありません。:)

于 2012-09-11T18:59:16.907 に答える
3

私が持っている1つの提案は、カスタムを作成し、それを使用してオブジェクトTimeZoneInfoを生成することですDateTime

myTimeZoneInfo = TimeZoneInfo.CreateCustomTimeZone(
                 TimeZoneInfo.Local.Id,
                 TimeZoneInfo.Local.BaseUtcOffset,
                 TimeZoneInfo.Local.DisplayName,
                 TimeZoneInfo.Local.StandardName, "", null, true);

重要なパラメータは、です。trueこれはdisableDaylightSavingsTimeです。

使用法:

DateTime noDaylightSavings = TimeZoneInfo.ConvertTimeFromUtc(reading, myTimeZoneInfo);

また

DateTime noDaylightSavings = TimeZoneInfo.ConvertTimeToUtc(reading, myTimeZoneInfo);
于 2014-04-03T15:56:38.993 に答える
2

最近、アリゾナの現在時刻をリモートで計算するときにDSTを削除するためにこれを行いました。私の場合、データベースに郵便番号別のDST(y / n)フラグがありました。DST調整を削除するために上記のコード(サンプル#2)を使用している場合は、一部の調整が存在するが期限切れになっているため、適用する調整の時間枠を限定することをお勧めします(そして、変更が来ています)。これが私のために働いたものの例です:

private DateTime RemoveDSTFromDateTime(DateTime dateTime, TimeZoneInfo timeZoneInfo)
{
    #region detail...
    //removes daylight savings time adjustment as defined in current year
    int _currYear = DateTime.Now.Year;

    if (!dateTime.IsDaylightSavingTime())
        return dateTime;

    var result = dateTime;

    foreach (var adjustmentRule in timeZoneInfo.GetAdjustmentRules())
    {
        if (adjustmentRule.DateStart.Year <= _currYear && adjustmentRule.DateEnd.Year >= _currYear)
        {
            result = result.Subtract(adjustmentRule.DaylightDelta);
        }
    }

    return result; 
    #endregion
}
于 2013-04-30T19:38:11.207 に答える