web-dev-qa-db-ja.com

DateTimeをUTCに変換する際に問題がある

データベースにすべての日付をUTC形式で保存しています。ユーザーにタイムゾーンを尋ね、タイムゾーンに加えて、UTCを把握するためのサーバー時間を使用します。

それができたら、新しく変換されたUTC日付を使用して、データベース内の範囲を検索する必要があります。

しかし、私は常にこの例外を取得します。

System.ArgumentException was unhandled by user code  
Message="The conversion could not be completed because the   
supplied DateTime did not have the Kind property set correctly.  
For example, when the Kind property is DateTimeKind.Local,   
the source time zone must be TimeZoneInfo.Local.  
Parameter name: sourceTimeZone"

なぜこれを取得しているのかわかりません。

私は2つの方法を試しました

 TimeZoneInfo zone = TimeZoneInfo.FindSystemTimeZoneById(id);
 // I also tried DateTime.UtcNow
 DateTime now = DateTime.SpecifyKind(DateTime.Now, DateTimeKind.Local); 
 var utc = TimeZoneInfo.ConvertTimeToUtc(now , zone );

失敗したので疲れました

 DateTime now = DateTime.SpecifyKind(DateTime.Now, DateTimeKind.Local); 
 var utc = TimeZoneInfo.ConvertTimeBySystemTimeZoneId(now, 
                                           ZoneId, TimeZoneInfo.Utc.Id);

これも同じエラーで両方に失敗しました。私は何を間違えていますか?

これは編集できますか?

 DateTime localServerTime = DateTime.SpecifyKind(DateTime.Now, DateTimeKind.Local);
 TimeZoneInfo info = TimeZoneInfo.FindSystemTimeZoneById(id);

 var usersTime = TimeZoneInfo.ConvertTime(localServerTime, info);

 var utc = TimeZoneInfo.ConvertTimeToUtc(usersTime, userInfo);

編集2 @ジョンスキート

ええ、私はこのすべてをする必要さえないかもしれないと考えていました。時間の問題が今私を混乱させているので、その理由は投稿が本来あるべきほど明確でないかもしれないからです。 DateTime.Nowが何を取得しているのかわかりません(タイムゾーンを別のタイムゾーンに変更しようとしましたが、現地時間を取得し続けました)。

これは私が自分のものにしたかったものです。ユーザーがサイトにアクセスするとアラートが追加され、utcとして保存されます(DateTime.Nowになる前に、だれかがすべてのUTCを保存することを提案しました)。

そのため、ユーザーが私のサイトにアクセスする前に、ホスティングサーバーがどこにあるかによって、翌日になる可能性があります。したがって、アラートが8月30日(その時間)に表示されると言われたが、サーバーの時差があれば8月29日にアラートが表示され、アラートが表示されます。

だから私はそれと戦いたかった。だから今、私は彼らの現地時間を保存してからこのオフセットのものを使うべきかどうかわかりませんか?または、UTC時間を保存するだけです。ユーザーがローカル時間で考えている可能性が高いため、UTC時間を保存するだけではまだ間違っている可能性があり、UTCが実際にどのように機能するかはわかりません。

編集3

 var info = TimeZoneInfo.FindSystemTimeZoneById(id)

 DateTimeOffset usersTime = TimeZoneInfo.ConvertTime(DataBaseUTCDate,
                                             TimeZoneInfo.Utc, info);
55
chobo2

DateTime構造体は、2つのタイムゾーンのみをサポートします。

  • マシンが実行されているlocalタイムゾーン。
  • およびUTC。

DateTimeOffset 構造を見てください。

var info = TimeZoneInfo.FindSystemTimeZoneById("Tokyo Standard Time");

DateTimeOffset localServerTime = DateTimeOffset.Now;

DateTimeOffset usersTime = TimeZoneInfo.ConvertTime(localServerTime, info);

DateTimeOffset utc = localServerTime.ToUniversalTime();

Console.WriteLine("Local Time:  {0}", localServerTime);
Console.WriteLine("User's Time: {0}", usersTime);
Console.WriteLine("UTC:         {0}", utc);

出力:

Local Time:  30.08.2009 20:48:17 +02:00
User's Time: 31.08.2009 03:48:17 +09:00
UTC:         30.08.2009 18:48:17 +00:00
38
dtb

次のように、KindUnspecifiedに設定する必要があります。

DateTime now = DateTime.SpecifyKind(DateTime.Now, DateTimeKind.Unspecified);
var utc = TimeZoneInfo.ConvertTimeToUtc(now , zone);

DateTimeKind.Localはローカルタイムゾーンを意味し、他のタイムゾーンは意味しません。そのため、エラーが発生していました。

94
SLaks

Dtbにあるように、特定のタイムゾーンで日付/時刻を保存する場合は、DateTimeOffsetを使用する必要があります。

ただし、投稿から本当に必要なことはまったく明確ではありません。あなたはDateTime.Nowを使用した例を与えるだけで、あなたは推測サーバー時間を使用していると言います。実際に何時に欲しいですか? UTCの現在時刻だけが必要な場合は、DateTime.UtcNowまたはDateTimeOffset.UtcNowを使用します。現在のUTC時間を知るためにタイムゾーンを知る必要はありません。まさにそれが普遍的だからです。

他の方法でユーザーから日付/時刻を取得している場合は、より多くの情報を提供してください-そのようにして、私たちはあなたがする必要があることを解決することができます。それ以外の場合は、単に推測しています。

7
Jon Skeet

他の人の答えは非常に複雑に思えます。特定の要件があり、これは私のためにうまくいきました:

void Main()
{
    var startDate = DateTime.Today;
    var StartDateUtc = TimeZoneInfo.ConvertTimeBySystemTimeZoneId(DateTime.SpecifyKind(startDate.Date, DateTimeKind.Unspecified), "Eastern Standard Time", "UTC");
    startDate.Dump();
    StartDateUtc.Dump();
}

どの出力が(linqpadから)私が期待したもの:

12/20/2013 12:00:00 AM

12/20/2013 5:00:00 AM

不特定の種類のヒントのスラックに小道具。それが欠けていたものです。しかし、2種類の日付(ローカルとUTC)しか存在しないという話はすべて、私にとって問題を混乱させました。

参考までに、これを実行したマシンは中央タイムゾーンにあり、DSTは有効ではありませんでした。

7
JohnOpincar

[〜#〜] utc [〜#〜] は、標準タイムゾーンとして全員が同意したタイムゾーンです。具体的には、イギリスのロンドンを含むタイムゾーンです。 [〜#〜] edit [〜#〜]:正確に同じタイムゾーンではないことに注意してください。たとえば、UTCにはDSTがありません。 (ありがとう、ジョン・スキート)

UTCの唯一の特別な点は、他のタイムゾーン(_DateTime.UtcNow_、_DateTime.ToUniversalTime_、および他のメンバー)よりも.Netで使用する方がはるかに簡単なことです。

したがって、他の人が述べたように、データベース内のすべての日付をUTCで保存し、表示する前にTimeZoneInfo.ConvertTime(time, usersTimeZone)を記述することにより、ユーザーのローカル時間に変換するのが最善です。


もっと面倒になりたい場合は、 geolocate ユーザーのIPアドレスを使用して、タイムゾーンを自動的に推測できます。

2
SLaks