2

我正在尝试使用 .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”

当前时区测试 (.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

当前时区测试 (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+01:00) 显示时,为什么这显示好像我在英国冬季时间 (UTC+00:00)?

如果我更改我的时区设置,我会得到本地/通用时间的预期结果,但如果它们设置为我当前的时间/区域,这似乎会给出不一致的结果。

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

4

2 回答 2

2

英国在夏季(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 年夏天,英国(以及所有 EEC)观察到夏令时(夏令时)。

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

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

于 2013-08-27T11:35:34.640 回答
0

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

这是我的单元测试和结果:

        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() 有点多余,您很可能会得到意想不到的结果。

于 2015-07-20T00:21:00.327 回答