web-dev-qa-db-ja.com

日付をUTCに正しく変換してから変換する方法は?

私はDateTimeをUTCに変換するのに苦労しています。概念とすべて、私が正しく理解していないものです。

「7/10/2013」のように日付と時刻の文字列を取得すると、次のようになります。

  Convert.ToDateTime("7/10/2013").ToUniversalTime();

これにより、データベースに "7/10/2013 4:00:00 AM"として記録されます。サーバーは米国東海岸(-5)にあります。もちろん、2013年7月の間、DSTはまだ観測されているため、その間のオフセットは-4であり、追加の4時間4:00:00 AM "はUTCとして記録されます。

私がこの投稿を書いているとき、それは2014年2月であり、DSTは有効ではないので、現在のオフセットは-5です。私のアプリケーションでは、それがアプリケーションで選択したオフセットです。

"7/1/2013 4:00:00 AM"に-5オフセットを適用すると、日付は "7/9になります。 =/2013 11:00:00 PM "。

どちらが間違っていて、1日ずれています。

質問#1

次に、UTC時間を適切に戻すにはどうすればよいですか?つまり、ユーザーが2014年2月に現在アプリケーションをロードしているとき(現在、タイムゾーンオフセット-5を使用)、2013年7月10日4:00:00 AMは2013年7月9日ではなく2013年7月10日のままである必要があります。

.ToUniversalTime()はサーバーのDSTを考慮に入れるので、何が私を混乱させるのですか?サーバーが置かれている場所の影響を受けないハードセットの「ユニバーサル時間」はありますか????

質問#2

西海岸と東海岸の両方にサーバーがあり、データベースに書き込んでいるとどうなりますか?記録されているUTC時刻が東海岸または西海岸に基づいているかどうか、アプリケーションはどのように知ることができますか?

基本的に、「7/10/2013 4:00:00 AM」は東海岸で作成されたUTC時間である(つまり、米国東海岸では7/10/2013 00:00:00 AMを示します)。西海岸のサーバーではありませんか(米国西海岸の場合、2013年7月9日20:00:00であることを示しています)。

それが愚かに聞こえる場合は申し訳ありません。どんなアドバイスでも大歓迎です。

==========最終編集、現在のソリューション===============

MiMoの答えは理にかなっています。私は2つのことに戸惑っていました。

  1. データベースに格納されているUTC時間はサーバーにとって何を意味しますか?
  2. サーバーの時間とアプリケーションのユーザーとの関係は何ですか?

私のアプリケーションは異なるタイムゾーンのユーザーが使用でき、一部のユーザーはサーバーと同じタイムゾーンにいますが、そうでないユーザーもいます。一部の旅行など、サーバーと同じタイムゾーンに属していても、常に異なるタイムゾーンに到達する可能性があります。私のアプリケーションでは、ユーザーがどのタイムゾーンを使用しているかを選択でき、適切に時間を反映しています。

もともとは、データベースからUTC時間を取得し、そこからユーザーのタイムゾーンオフセットを差し引くだけです。ミモが示唆したように、それは間違っています。その理由は上の私の投稿で見ることができます。

私の元の解決策は、サーバーのタイムゾーンオフセットを今すぐ取得し、それを使用してUTCから加算/減算することでしたが、それも誤りです。 2013年7月10日と同様に、当時のサーバーのオフセットは-4でした。現在、2014年2月のサーバーのタイムゾーンオフセットは-5です。その解決策はもちろん.ToLocalTime()を使用することです

TimeZone.ToLocalTime()の使用方法に関するMimoの提案をさらに詳しく説明する前に、一時的に問題を修正するために行った作業を次に示します。

  1. データベースからUTC日付を取得し、サーバーが表示する.ToLocalTimeに変換します。したがって、サーバーでは、7/10/2013 4:00:00 AMは7/10/2013 12:00:00 AMになります。

  2. サーバーのタイムゾーンオフセットを取得します。米国東海岸にあるため、現在は-5と表示されています。

  3. ユーザーのタイムゾーンオフセットを取得します。西海岸の場合、ユーザーは現在-8を選択します。東海岸の場合、ユーザーは現在-5を選択します。

  4. ユーザーのタイムゾーンとサーバーのタイムゾーンの差を取得します。西海岸は-3です。東海岸は0です。

  5. 7/10/2013 12:00:00 AMから差を差し引くと、西海岸の期限は2013年7月9日21:00:00 PMになり、東海岸の期限は2013年7月10日12:00:00 AMになります。

すべて正解です。

みんなありがとう。 TimeZone.ToLocalTime()を調べて、ステップ2〜5を減らすことができるかどうかを確認します。

12
Liming

ToLocalTime()を使用して現地時間に戻します。日付/時刻が7月であるため、DSTの場合、5時間ではなく4時間シフトすることがわかります。

クライアント(例:Webブラウザー)がサーバーに接続している場合、最終的に日付/時刻はサーバーではなくクライアントのローカル時刻に変換されます。これを行うには、 TimeZone.ToLocalTime() を使用するのが最善の方法です。クライアントがいるタイムゾーンをサービス対象に送信し、常にそのタイムゾーンに直接変換します。

時間を加算/減算しないでください-常にタイムゾーンを通過し、TimeZoone.ToLocalTime()を使用してください。 DSTが関係している場合、時間の追加/減算は機能しません。

ブラウザ内から現在の(ローカル)タイムゾーンを取得することはできないことに注意してください。クライアントがブラウザの場合、ある種の構成からタイムゾーンを取得するか、ユーザーに入力してもらう必要があります。

また、さまざまなタイムゾーンの処理を開始すると、日付だけではなくなります。常に完全な日付と時刻を処理する必要があります。時間の部分を削除または失うと、すべての変換が機能しなくなります。

質問2に関して:UTC時刻は特定のタイムゾーンに基づくのではなく、普遍的なものであるため、UTCに変換すると、サーバーのタイムゾーンについてこれ以上心配する必要はありません。

5
MiMo

データベースに現地時間をUTCとして保存する場合は、まず現地時間を世界時に変換する必要があります。

 DateTime dbDateTime = localDateTime.ToUniversalTime();
 ... store dbDateTime in the database ...

データベースから読み取ると、KindプロパティはUnspecifiedに設定されます。 Kindプロパティを明示的にUTCに設定する必要があります。

dbDateTime = ... get from database, e.g. (DateTime) reader["SomeDateTimeColumn"]
dbDateTime = DateTime.SpecifyKind(dbDateTime, DateTimeKind.Utc);

その後、それを現地時間に変換したい場合は、以下を使用できます。

DateTime localDateTime = dbDateTime.ToLocalTime();
11
Joe

同じ問題があり、次の拡張メソッドを作成しました。

    public const string UTC = "UTC";

   public static DateTime Convert(this DateTime date, string fromZone, string toZone)
    {
        TimeZoneInfo to = TimeZoneInfo.FindSystemTimeZoneById(toZone);
        TimeZoneInfo from = TimeZoneInfo.FindSystemTimeZoneById(fromZone);
        return new DateTime(TimeZoneInfo.ConvertTime(date, from, to).Ticks, DateTimeKind.Unspecified); 
    }

    public static bool IsDayLightSaving(this DateTime date, string zone)
    {
        TimeZoneInfo to = TimeZoneInfo.FindSystemTimeZoneById(zone);
        return to.IsDaylightSavingTime(date);
    }

    public static DateTime ConvertToUTC(this DateTime date, string fromZone)
    {
        return date.Convert(fromZone, DateTime_Extension.UTC);
    }

    public static DateTime ConvertToLocal(this DateTime date, string toZone)
    {
        return date.Convert(DateTime_Extension.UTC, toZone);
    }

私が見つけた問題は、実際に現在のユーザーのタイムゾーンを見つけることです。これはヘッダーで渡されないため(JavaScript経由で取得できます)、ユーザーに登録時にタイムゾーンを選択するように依頼することにしました

お役に立てれば

2
KevDevMan

多分それは早朝でもう1杯のコーヒーが必要ですが、(少なくとも表示のために)TimeZoneInfo.ConvertTimeFromUtcを使用してユーザーの希望のTZを指定するだけの解決策ではありませんか?または、ConvertTimeFromUtcが、目的のTZへの変換が実行されている日付/時刻を考慮しない点ですか?より深く考える:たとえそうであっても、サーバーがDSTに移行したがユーザーの希望するTZがまだ移行していないEdgeのケースを考慮に入れているかどうか誰かが知っていますか?

1
JimMSDN

want日付を現地時間で保存しますか?日付の部分のみを気にする場合は、データベースに保存する前に、解析した時間をUtcにforceする必要があります。

DateTime utcDate = DateTime.SpecifyKind(Convert.ToDateTime("7/10/2013"),DateTimeKind.Utc);

そうすれば、データベースに保存されるときにUTCでalreadyとなり、時間コンポーネントは含まれません。

1
D Stanley