使用DateTime结构解析ISO8601日期/时间

我试图用.NET的DateTime结构解析ISO8601格式的日期/时间字符串。

为了让我完全解决问题,我将使用.NET和JavaScript执行测试。 我目前在英国(英国夏令时,UTC + 01:00)。

我对ISO8601的理解是:

  • 当字符串后缀为“Z”时,时间以UTC表示。
  • 当字符串后缀为“+/- hh:mm”时,时间以本地时间表示,其中“+/- hh:mm”表示与UTC的偏移量。

请考虑以下ISO8601日期/时间格式字符串:

"1987-01-05T08:45:30.500+0100" 

鉴于我的观点,该字符串表示当地时间为“08:45:30”,UTC时间为“07:45:30”

当前TimeZone测试(.NET)

 DateTime now = DateTime.Now; Console.WriteLine(now.ToLocalTime()); // 27/08/2013 12:02:43 Console.WriteLine(now.ToUniversalTime()); // 27/08/2013 11:02:43 

当前TimeZone测试(JavaScript)

 var now = new Date(Date.now()); now.toString(); // Tue Aug 27 2013 12:03:46 GMT+0100 (GMT Daylight Time) now.toUTCString(); // Tue, 27 Aug 2013 11:03:46 GMT 

除了两个例子之间的微小(分钟/秒)差异之外,它们正在回归我对英国夏令时(UTC + 01:00)的期望。 分钟/秒差异是因为我无法同时运行.NET测试和JavaScript测试。

所以现在让我们使用我的ISO8601日期/时间格式化字符串:

解析ISO8601格式字符串(.NET)

 DateTime dt = DateTime.Parse("1987-01-05T08:45:30.500+0100"); Console.WriteLine(dt.ToLocalTime()); // 05/01/1987 07:45:30 Console.WriteLine(dt.ToUniversalTime()); // 05/01/1987 07:45:30 

解析ISO8601格式字符串(JavaScript)

 var dt = new Date("1987-01-05T08:45:30.500+0100"); dt.toString(); // Mon Jan 05 1987 07:45:30 GMT+0000 (GMT Standard Time) dt.toUTCString(); //Mon, 05 Jan 1987 07:45:30 GMT 

这似乎与显示日期/时间“ 现在 ”的示例一致。 为什么这个显示好像我在英国冬令时(UTC + 00:00),当“现在”的例子显示在英国夏令时(UTC + 01:00)?

如果我更改了我的时区设置,我会获得本地/世界时的预期结果,但如果将它们设置为我当前的时间/区域,则这似乎会产生不一致的结果。

编辑:简而言之,当我尝试解析字符串时,就好像.NET和JavaScript都忽略了夏令时/英国夏令时(UTC + 01:00)。 结果对冬天来说是正确的,并且当我实际改变我的时间/区域时也是正确的……但是现在这在我在英国测试的“ 任何 ”机器上是不正确的。

英国在夏天使用夏令时 (将时钟提前一小时)(8月27日,示例中的“现在”),但不是在冬季(1月5日,从解析“ 1987-01-05 T08:45”) :30.500 + 0100″ )。

实际上,在冬天,英国使用UTC。 你的机器好像有英国的TimeZoneInfo 。 您可以使用TimeZoneInfo.Local.DisplayName (自.NET 3.5)或TimeZone.CurrentTimeZone.StandardName (旧)进行检查。

您可以使用dt.IsDaylightSavingTime()进行检查。

加成:

我的答案只是关于.NET(但也许同样适用于JavaScript?)。 您提供的示例完全按预期工作。 1987年1月的日期和时间将转换为您所在的当地区域,据说是英国区域,1987年1月,英国自冬季以来一直处于+0000。 你给的时间字符串标有+0100(好像是来自德国或英国以东一小时的其他国家),这在解析字符串时得到了承认。 1987年夏天的日期将正确地转换为不同,因为在1987年夏天,英国(以及所有欧洲经济共同体)观察到夏季时间(夏令时)。

总结:在解释时间时考虑偏移指示符或区域说明符+0100 。 这将在您的计算机上转换为英国时间。 如果要转换为UTC而不是转换为计算机的本地时间,请使用带有DateTimeStyles枚举的重载并包含标志DateTimeStyles.AdjustToUniversal

如果需要更好地表示时间绝对区域的值,请考虑使用结构DateTimeOffset而不是DateTime 。 您还可以考虑NODA时间而不是.NET类型。

ToLocalTime和ToUniversalTime确实考虑了夏令时并做了很好的工作。 至少在.Net中,Javascript Date对象有缺陷,我建议使用moment.js和moment-timezone.js进行js中的转换。

这是我的unit testing和结果:

  var now = DateTime.Now; Console.WriteLine(now.ToLocalTime()); Console.WriteLine(now.ToUniversalTime()); //Test 1 TimeZone UTC+1 London, etc.. //current day 20th July = BST /* 07/20/2015 01:06:43 07/20/2015 00:06:43*/ //set day to 20th Januray UK winter time /* 01/20/2015 01:07:55 01/20/2015 01:07:55*/ 

为了让你在.Net中获得上述结果,你需要a)将时区设置为UTC + 2 b)在ToLocalTime()中遇到故障,此后修复,MSDN在转换日期时提到XP上的缺陷。

最后DateTime.Now返回本地时间,因此使用DateTime.Now.ToLocalTime()有点多余,你可能会得到意想不到的结果。