14

日付/時刻をUTCとしてデータベースに保存し、特定のタイムゾーンに基づいてアプリケーション内で現地時間に計算します。たとえば、次の日付/時刻があるとします。

01/04/2010 00:00

DST(夏時間)を遵守している英国などの国で、この特定の時間に夏時間になっているとしましょう。この日付をUTCに変換してデータベースに保存すると、実際には次のように保存されます。

31/03/2010 23:00

日付はDSTの場合は-1時間調整されます。これは、送信時にDSTを監視している場合に正常に機能します。しかし、時計を戻すとどうなりますか?その日付をデータベースから取得して現地時間に変換すると、その特定の日時は31/03/2010 23:00実際にはとして処理されたときと見なされ01/04/2010 00:00ます。

私が間違っている場合は訂正してください。ただし、UTCとして時刻を保存する場合、これはちょっとした欠陥ではありませんか?

タイムゾーン変換の例

基本的に私が行っているのは、ユーザーが範囲レポートを実行できるようにするために、情報がシステムに送信される日時を保存することです。日付/時刻の保存方法は次のとおりです。

public DateTime LocalDateTime(string timeZoneId)
{
    var tzi = TimeZoneInfo.FindSystemTimeZoneById(timeZoneId);
    return TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow, tzi).ToUniversalTime().ToLocalTime(); 
}

UTCとして保存:

var localDateTime = LocalDateTime("AUS Eastern Standard Time");
WriteToDB(localDateTime.ToUniversalTime());
4

6 に答える 6

38

DSTの変更の日付は、現在それらを監視しているかどうかに基づいて調整するのではなく、説明している瞬間にDSTが監視されているかどうかに基づいて調整します。したがって、1月の場合、調整は適用されません。

ただし、問題があります。一部の現地時間はあいまいです。たとえば、英国の2010年10月31日の午前1時30分は、時計が午前2時から午前1時まで戻るため、UTC01:30またはUTC02:30のいずれかを表すことができます。UTCで表される任意の瞬間から、その瞬間に表示される現地時間まで取得できますが、操作を元に戻すことはできません。

同様に、現地時間が発生しない可能性が非常に高くなります。たとえば、2010年3月28日の午前1時30分は、英国では発生しませんでした。午前1時に時計が午前2時にジャンプしたためです。

その長所と短所は、ある瞬間を表現しようとしている場合、UTCを使用して明確な表現を取得できることです。特定のタイムゾーンで時間を表現しようとしている場合は、タイムゾーン自体(ヨーロッパ/ロンドンなど)と、その特定の時間にオフセットされたインスタントまたはローカルの日時のUTC表現が必要になります。 (DST遷移を明確にするため)。もう1つの方法は、UTCとそれからのオフセットのみを保存することです。これにより、その瞬間の現地時間を知ることができますが、タイムゾーンが実際にはわからないため、1分後の現地時間が予測できないことを意味します。(これはDateTimeOffset基本的に保存するものです。)

これを野田タイムでかなり扱いやすくしたいと思っていますが、それでも可能性として知っておく必要があります。

編集:

表示したコードが正しくありません。これが理由です。見やすくするためにコードの構造を変更しましたが、同じ呼び出しを実行していることがわかります。

var tzi = TimeZoneInfo.FindSystemTimeZoneById("AUS Eastern Standard Time");
var aussieTime = TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow, tzi);
var serverLocalTime = aussieTime.ToLocalTime(); 
var utcTime = serverLocalTime.ToUniversalTime();

それでは、今考えてみましょう。これは、私の現地時間では13:38(UTC + 1、ロンドン)、12:38 UTC、22:39はシドニーです。

あなたのコードは以下を与えるでしょう:

aussieTime = 22:39 (correct)
serverLocalTime = 23:39 (*not* correct)
utcTime = 22:39 (*not* correct)

結果を呼び出すべきではありません-UTCで呼び出されていると想定します(実際にある種のを取得している場合を除きますが、この場合はそうではありません)。ToLocalTimeTimeZoneInfo.ConvertTimeFromUtcDateTimeDateTimeKind.Local

したがって、この場合22:39を正確に保存している場合、UTCでの現在の時刻を正確に保存しているわけではありません。

于 2010-04-05T19:12:43.537 に答える
2

日付と時刻をUTCとして保存しようとしているのは良いことです。実際の日時と現地時間はその仮名であるため、UTCを考えるのが一般的に最も簡単です。また、タイムスパンを取得するために日付/時刻の値を計算する必要がある場合、UTCは絶対に重要です。私は通常、日付をUTCとして内部的に操作し、ユーザーに値を表示するときにのみ現地時間に変換します(必要な場合)。

発生しているバグは、ローカルタイムゾーンを日付/時刻の値に誤って割り当てていることです。英国の1月に、現地時間を夏のタイムゾーンにあると解釈するのは正しくありません。時間値が表す時間と場所で有効だったタイムゾーンを使用する必要があります。

表示のために時間を戻すことは、システムの要件に完全に依存します。時刻は、ユーザーの現地時間またはデータのソース時刻として表示できます。ただし、いずれの場合も、夏時間の調整は、ターゲットのタイムゾーンと時間に適切に適用する必要があります。

于 2010-04-05T19:40:38.987 に答える
1

UTCに変換するときに使用される特定のオフセットも保存することで、これを回避できます。あなたの例では、日付を次のように保存します

31/12/2009 23:00 +0100

これをユーザーに表示するときは、同じオフセットを使用して変換するか、選択に応じて現在のローカルオフセットを使用できます。

このアプローチにも独自の問題があります。時間は厄介なものです。

于 2010-04-05T19:15:16.817 に答える
1

TimeZoneInfo.ConvertTimeFromUtc()メソッドは、問題を解決します。

using System;

class Program {
  static void Main(string[] args) {
    DateTime dt1 = new DateTime(2009, 12, 31, 23, 0, 0, DateTimeKind.Utc);
    TimeZoneInfo tz = TimeZoneInfo.FindSystemTimeZoneById("GMT Standard Time");
    Console.WriteLine(TimeZoneInfo.ConvertTimeFromUtc(dt1, tz));
    DateTime dt2 = new DateTime(2010, 4, 1, 23, 0, 0, DateTimeKind.Utc);
    Console.WriteLine(TimeZoneInfo.ConvertTimeFromUtc(dt2, tz));
    Console.ReadLine();
  }
}

出力:

12/31/2009 11:00:00 PM 
4/2/2010 12:00:00 AM

.NET 3.5以降が必要であり、過去の夏時間の変更を保持するオペレーティングシステム(Vista、Win7、またはWin2008)で実行する必要があります。

于 2010-04-05T20:45:09.240 に答える
0

私が間違っている場合は訂正してください。ただし、UTCとして時刻を保存する場合、これはちょっとした欠陥ではありませんか?

はい、そうです。また、調整の日数は23時間または25時間になるため、前日のイディオムは現地時間であると同時に、24時間は1年に2日間違っています。

修正は、1つの標準を選択し、それに固執することです。日付をUTCとして保存し、ローカルとして表示するのはかなり標準的です。ローカル(+-何か)=新しい時間の計算を行うショートカットを使用しないでください。問題ありません。

于 2010-04-05T19:13:18.187 に答える
0

これは大きな欠陥ですが、UTCで時刻を保存することの欠陥ではありません(これが唯一の合理的なことであるためです。現地時間を保存することは常に災害です)。これは欠陥であり、夏時間の概念です。本当の問題は、タイムゾーン情報が変わることです。DSTルールは動的で歴史的です。2010年に米国で開始されたDSTは、2000年に開始されたときと同じではありません。最近まで、Windowsにはこの履歴データすら含まれていなかったため、正しく実行することは本質的に不可能でした。あなたはそれを正しくするためにtzデータベースを使わなければなりませんでした。今、私はそれをグーグルで検索しましたが、.NET 3.5とVista(Windows 2008も想定しています)がある程度改善され、System.TimeZoneInfoが実際に履歴データを処理しているようです。これを見てください

しかし、基本的にDSTは実行する必要があります。

于 2010-04-05T19:38:46.083 に答える