2

@Jon Skeetが私にたくさんの助けをくれた私の最後の質問に続いて(ありがとう!)

UTCとして保存されている日付/時刻を、ローカルの日付/時刻に変換して戻すときに、どうすれば安全に作業できるのか疑問に思っています。

ジョンが私の最後の質問で示したように、使用は瞬間DateTimeOffsetを表し、現地時間が1分後に何を言うかを予測する方法はありません。これらの日時に基づいて計算できる必要があります。

では、データベースから日付を取得し、それらをローカルの日付/時刻に変換して、正確になるように特定の計算を行う場合、どうすれば保証できますか?

シナリオ

私のアプリケーションは、電子メールで送信された情報を記録します。メールを受信した日時が送信時刻として記録されます。メールは交換から引き出されます。

私が知る必要があるのは:

1)これらの電子メールがさまざまな国から送信されている場合Recieved、電子メールの日付/時刻をUTC形式に変換して保存するだけですか?例えばEmail.Received.ToUniversalTime()

4

2 に答える 2

6

いいえ、それを想定することはできません。UTC時間は完全に線形であり、安全に計算を行うことができます。現地時間に変換すると、完全に線形ではなくなります。

夏時間の変更が発生すると、現地時間に重複またはギャップが生じます。夏時間の変更にまたがる計算を行う場合、結果は1時間ずれます(それが時間の変更量である場合、これが最も一般的です)。

DateTime / DateTimeOffset値を現地時間に変換する前に計算を行うと、結果は常に正しいものになります。ただし、値をローカルのDateTime値に変換すると、値があいまいになる可能性があることに注意してください。夏時間の変更時に値がオーバーラップ内にある場合、その日の正確な時刻が1回目か2回目かを判断することはできません。

于 2010-04-15T17:36:17.667 に答える
2

日付/時刻を正しく処理する最も安全な方法は、すべてをUTCとして保存し、現地時間で表示することです。Guffaが示唆しているように、すべての日付/時刻の計算はUTCで行う必要があります。UTCで保存し、表示しながらその場で現地時間に変換します。

タイムゾーンに日付/時刻を認識させる方法

Microsoftには、DateTime変数とTimeZoneInfo変数を構造体にカプセル化する方法に関する記事があります

これは、現地時間を簡単に取得できるように1つのプロパティが追加されたMicrosoftのサンプル構造です。これを完全に使用するには、さらに作業が必要ですが、良いスタートです。

public struct TimeZoneTime
{
   public TimeZoneInfo TimeZone;
   public DateTimeOffset Time;

   public TimeZoneTime(DateTimeOffset time)
   {
      this.TimeZone = TimeZone.Local;
      this.Time = time;   
   }

   public TimeZoneTime(TimeZoneInfo tz, DateTimeOffset time)
   {
      if (tz == null) 
         throw new ArgumentNullException("The time zone cannot be a null reference.");

      this.TimeZone = tz;
      this.Time = time;   
   }

   public TimeZoneTime AddTime(TimeSpan interval)
   {
      // Convert time to UTC
      DateTimeOffset utcTime = TimeZoneInfo.ConvertTime(this.Time, TimeZoneInfo.Utc);      
      // Add time interval to time
      utcTime = utcTime.Add(interval);
      // Convert time back to time in time zone
      return new TimeZoneTime(this.TimeZone, TimeZoneInfo.ConvertTime(utcTime, this.TimeZone));
   }

    public DateTime LocalDate 
    {
        get { return Time.ToOffset(TimeZone); }
    }
}

あなたのシナリオ

  1. はい、メールオブジェクトのReceivedTimeまたはSentOnのいずれかを使用し、保存と計算のためにUTCに変換します。これは、上記のサンプルよりもはるかに複雑ではありません。

    Message msg = new Message();
    DateTime received = msg.ReceivedTime.ToUniversalTime();
    received.AddDays(7);
    Console.WriteLine(received.ToLocalTime());
    
于 2010-04-15T17:55:16.637 に答える