正在使用DateTime结构分析ISO8601日期/时间
本文关键字:ISO8601 日期 时间 结构 DateTime | 更新日期: 2023-09-27 18:29:03
我正在尝试用.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
这似乎与显示日期/时间"now"的示例不一致。当"现在"示例显示在英国夏令时(UTC+01:00)时,为什么显示为我在英国冬季时间(UTC+00:00)?
如果我更改时区设置,我会得到本地/环球时间的预期结果,但如果将其设置为我的当前时区,则会产生不一致的结果。
编辑:简而言之,当我试图解析字符串时,就好像.NET和JavaScript都忽略了夏令时/英国夏令时(UTC+01:00)。这个结果在冬天是正确的,当我身体上改变时间/区域时也是正确的。。。但就目前情况来看,这在我在英国测试过的"任何"机器上都是不正确的。
英国在夏季(8月27日,示例中的"现在")使用夏季时间(将时钟提前一小时),但在冬季(1月5日,根据您对"1987-01-05T08: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中进行转换。
这是我的单元测试和结果:
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()有点多余,很可能会得到意外的结果。