UTC形式のDateTimeを表す文字列を解析したい。
私の文字列表現には、文字列がUTC時間を表すことを示すZulu時間仕様が含まれています。
var myDate = DateTime.Parse("2012-09-30T23:00:00.0000000Z");
上記から、myDate.KindはDateTimeKind.Utcであると予想されますが、DatetimeKind.Localです。
私は何を間違っていますか、UTC時間を表す文字列を解析する方法は?
どうもありがとう!
Noda Time プロジェクトを個人的に使用します。 (確かに私は著者として偏見がありますが、それはよりきれいになります...)しかし、あなたがそれをすることができないなら...
DateTime.ParseExact
を使用して、期待する正確な形式を指定し、解析コードにDateTimeStyles.AssumeUniversal
およびDateTimeStyles.AdjustToUniversal
を含めます。
using System;
using System.Globalization;
class Test
{
static void Main()
{
var date = DateTime.ParseExact("2012-09-30T23:00:00.0000000Z",
"yyyy-MM-dd'T'HH:mm:ss.fffffff'Z'",
CultureInfo.InvariantCulture,
DateTimeStyles.AssumeUniversal |
DateTimeStyles.AdjustToUniversal);
Console.WriteLine(date);
Console.WriteLine(date.Kind);
}
}
(AdjustToUniversal
を使用せずにデフォルトでローカルに調整する理由はまったくありませんが、気にしないでください...)
編集:ちょうどmattytommoの提案に対する私の反対を拡大するために、私はそれが情報を失うことを証明することを目指しました。私はこれまで失敗しました-しかし、非常に独特な方法で。これをご覧ください-2012年10月28日午前2時(UTC午前1時)に時計が戻るヨーロッパ/ロンドンタイムゾーンで実行されています。
DateTime local1 = DateTime.Parse("2012-10-28T00:30:00.0000000Z");
DateTime local2 = DateTime.Parse("2012-10-28T01:30:00.0000000Z");
Console.WriteLine(local1 == local2); // True
DateTime utc1 = TimeZoneInfo.ConvertTimeToUtc(local1);
DateTime utc2 = TimeZoneInfo.ConvertTimeToUtc(local2);
Console.WriteLine(utc1 == utc2); // False. Hmm.
「DSTの有無」フラグが保存されているように見えますどこかですが、どこで解決できるかがわからないでしょう。 TimeZoneInfo.ConvertTimeToUtc
stateのドキュメント
dateTimeがあいまいな時間に対応する場合、このメソッドはソースタイムゾーンの標準時間であると想定します。
それはappearではありませんlocal2
...
編集:さて、それはさらに奇妙になります-それはあなたが使用しているフレームワークのバージョンに依存します。このプログラムを検討してください。
using System;
using System.Globalization;
class Test
{
static void Main()
{
DateTime local1 = DateTime.Parse("2012-10-28T00:30:00.0000000Z");
DateTime local2 = DateTime.Parse("2012-10-28T01:30:00.0000000Z");
DateTime utc1 = TimeZoneInfo.ConvertTimeToUtc(local1);
DateTime utc2 = TimeZoneInfo.ConvertTimeToUtc(local2);
Console.WriteLine(utc1);
Console.WriteLine(utc2);
DateTime utc3 = local1.ToUniversalTime();
DateTime utc4 = local2.ToUniversalTime();
Console.WriteLine(utc3);
Console.WriteLine(utc4);
}
}
したがって、これは2つのdifferent UTC値を取り、DateTime.Parse
で解析してから、2つの異なる方法でUTCに変換します。
.NET 3.5での結果:
28/10/2012 01:30:00 // Look - we've lost information
28/10/2012 01:30:00
28/10/2012 00:30:00 // But ToUniversalTime() seems okay...
28/10/2012 01:30:00
.NET 4.5ベータでの結果:
28/10/2012 00:30:00 // It's okay!
28/10/2012 01:30:00
28/10/2012 00:30:00
28/10/2012 01:30:00
いつものように、ジョンの答えは非常に包括的なものです。とはいえ、DateTimeStyles.RoundtripKind
についてはまだ誰も言及していません。 DateTimeを文字列に変換し、同じDateTimeに戻す場合(DateTime.Kind
設定の保持を含む)、DateTimeStyles.RoundtripKind
フラグを使用します。
ジョンが言ったように、正しいことは、DateTimeオブジェクトを文字列に変換するときに「O」フォーマッタを使用することです。これにより、精度とタイムゾーンの両方の情報が保持されます。繰り返しになりますが、Jonが言ったように、逆変換するときはDateTime.ParseExact
を使用します。ただし、DateTimeStyles.RoundtripKindを使用すると、常に何を入れたのかがわかります。
var now = DateTime.UtcNow;
var strNow = now.ToString("O");
var newNow = DateTime.ParseExact(strNow, "O", CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind);
上記のコードでは、newNow
はUTCであるという事実を含め、now
とまったく同じ時間です。 DateTime.Now
の代わりにDateTime.UtcNow
を除いて同じコードを実行すると、now
の正確なコピーがnewNow
として返されますが、今回は現地時間です。
私の目的では、これは正しいことでした。なぜなら、渡されて変換されたものはすべて、まったく同じものに変換されるようにしたかったからです。
次を使用してTimeZoneInfo
クラスを使用します。
var myDate = TimeZoneInfo.ConvertTimeToUtc(DateTime.Parse("2012-09-30T23:00:00.0000000Z"));
以前に同様の問題に遭遇し、数時間後に(そして髪を引っ張って)後で DateTime.SpecifyKind を使用してしまいました:
DateTime.SpecifyKind(inputDate, DateTimeKind.Utc);
上記のコメントでも誰かがこれを避けていると思います。
パーサーメソッドには次の形式を使用できます。yyyy-MM-ddTHH:mm:ss.ffffffK
これにより、最後にタイムゾーン情報が適切に処理されます( 。NET 2.0以降 )。
RE: ISO 8601