5

私のソフトウェアは、現地時間を使用して日付/時刻を表示し、UTC でサーバーに送信します。サーバー側では、この日付/時刻に月、年、週、日などを追加したいと考えています。ただし、問題は、このようなメソッドを UTC 日付/時刻で使用してから現地時間に変換した場合、このメソッドを現地時間で直接使用した場合と同じ結果になるでしょうか?

これは C# での例です。

// #1
var utc = DateTime.Now.ToUtcTime();
utc = utc.AddWeeks(2); // or AddDays, AddYears, AddMonths...
var localtime = utc.ToLocalTime();

// #2
var localtime = DateTime.Now;
localtime = localtime.AddWeeks(2); // or AddDays, AddYears, AddMonths...

#1 と #2 の結果は常に同じでしょうか? または、タイムゾーンが結果に影響を与える可能性がありますか?

4

2 に答える 2

10

答えはあなたを驚かせるかもしれませんが、それはNOです。タイムゾーンが結果に影響しない限り、日、週、月、または年を追加することはできません。

その理由は、すべての現地日が 24 時間制であるとは限らないためです。タイムゾーン、そのゾーンの規則、および DST が問題の期間に移行しているかどうかによって、一部の「日」は 23、23.5、24、24.5、または 25 時間になる場合があります。(正確に言いたい場合は、代わりに「標準日」という用語を使用して、正確に 24 時間を意味することを示してください。)

例として、最初に、太平洋時間や東部時間など、DST のために変更される米国のタイム ゾーンの 1 つにコンピューターを設定します。次に、これらの例を実行します。

これは、2013年の「春先」への移行をカバーしています。

DateTime local1 = new DateTime(2013, 3, 10, 0, 0, 0, DateTimeKind.Local);
DateTime local2 = local1.AddDays(1);

DateTime utc1 = local1.ToUniversalTime();
DateTime utc2 = utc1.AddDays(1);
DateTime local3 = utc2.ToLocalTime();

Debug.WriteLine(local2); //  3/11/2013 12:00:00 AM
Debug.WriteLine(local3); //  3/11/2013 1:00:00 AM

そして、これは2013年の「フォールバック」移行をカバーしています:

DateTime local1 = new DateTime(2013, 11, 3, 0, 0, 0, DateTimeKind.Local);
DateTime local2 = local1.AddDays(1);

DateTime utc1 = local1.ToUniversalTime();
DateTime utc2 = utc1.AddDays(1);
DateTime local3 = utc2.ToLocalTime();

Debug.WriteLine(local2); //  11/4/2013 12:00:00 AM
Debug.WriteLine(local3); //  11/3/2013 11:00:00 PM

両方の例でわかるように、結果はどちらか一方に 1 時間ずれていました。

その他のポイント:

  • 方法はありませんAddWeeks。7 を掛けて、代わりに日数を追加します。
  • 方法はありませんToUtcTime。を探していたと思いますToUniversalTime
  • 電話しないでくださいDateTime.Now.ToUniversalTime()。内部.NowではUTC時間を取得し、とにかく現地時間に変換する必要があるため、これは冗長です。代わりに、を使用してDateTime.UtcNowください。
  • このコードがサーバー上で実行されている場合は、種類のあるものを呼び出し.Nowたり.ToLocalTime、操作したりしないでください。そうする場合、ユーザーではなくサーバーのタイムゾーンを導入しています。ユーザーが同じタイム ゾーンにいない場合、またはアプリケーションを別の場所に展開した場合、問題が発生します。DateTimeLocal
  • この種の問題を回避したい場合は、NodaTimeを調べてください。API は、一般的な間違いを防ぐことができます。

代わりに、次のことを行う必要があります。

// on the client
DateTime local = new DateTime(2013, 3, 10, 0, 0, 0, DateTimeKind.Local);
DateTime utc = local.ToUniversalTime();
string zoneId = TimeZoneInfo.Local.Id;

// send both utc time and zone to the server
// ...

// on the server
TimeZoneInfo tzi = TimeZoneInfo.FindSystemTimeZoneById(zoneId);
DateTime theirTime = TimeZoneInfo.ConvertTimeFromUtc(utc, tzi);
DateTime newDate = theirTime.AddDays(1);
Debug.WriteLine(newDate); //   3/11/2013 12:00:00 AM

参考までに、代わりに Noda Time を使用した場合は次のようになります。

// on the client
LocalDateTime local = new LocalDateTime(2013, 3, 10, 0, 0, 0);
DateTimeZone zone = DateTimeZoneProviders.Tzdb.GetSystemDefault();
ZonedDateTime zdt = local.InZoneStrictly(zone);

// send zdt to server
// ...

// on the server
LocalDateTime newDate = zdt.LocalDateTime.PlusDays(1);
Debug.WriteLine(newDate); // 3/11/2013 12:00:00 AM
于 2013-08-04T15:56:10.770 に答える