2013-08-26 73 views
3

我想用.NET的DateTime结构解析一个ISO8601格式的日期/时间字符串。用DateTime解析ISO8601日期/时间struct

为了让我充分认识到这个问题,我将使用.NET和JavaScript进行测试。我目前在英国(英国夏令时,即UTC + 01:00)。

我ISO8601的理解是:

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

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

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

鉴于以上我的观点,这个字符串表示的“8时45分三十〇秒”本地时间和UTC时间“7点45分三十秒”

当前时区测试(.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)一样。结果对冬天来说是正确的,当我改变我的时间/地区时也是正确的。但现在这是不正确的“任何”我在英国测试过的机器。

+0

我认为'+ 0100'被忽略,它可能取决于本地计算机上的'区域设置'。我测试了代码,它显示了我07:45:30'与'02:45:30'不像你的测试。 –

+0

这就是你得到的生活/编码在UTC时区...解析*总是*返回本地时间,但在你的情况下UTC到本地是没有操作。 –

+0

实际上你的代码应该是'Local:05/01/1987 07:45:30'和'UTC:05/01/1987 08:45:30','+ 0100'只是表示时间是UTC,因此所有当地时间都将是UTC时间1。 –

回答

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年夏天,英国(以及所有的欧洲经济共同体)都观测到了夏令时(夏令时)。

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

如果你想更好地代表了时间绝对区的值,可以考虑使用,而不是DateTime的结构DateTimeOffset。你也可以考虑NODA时间而不是.NET类型。

+0

这是正确的。我终于搞清楚了,我试图做的一点是,.NET和JavaScript似乎都不能保留偏移量。因此,您总是会收到UTC时间。我想这是因为如果偏移量被保留下来,这将与用户机器不一致。即如果偏移量是+0100而用户时区是+800,则偏移量(本地/时间)在用户机器上将不一致......如果这有意义的话? – series0ne

+0

@ series0ne我认为你错了。请尝试将字符串“”1987-01-05T08:45:30.500 + 0100“'更改为'“1987-07-05T08:45:30.500 + 0100”(夏天)。 ***编辑:***另外,为了避免混淆,请尝试使用远离英国的区域的字符串,比如'+ 1100'或其他。该区域被考虑。 –

+0

我编辑了整个问题,你会介意再看一下吗?谢谢。 – series0ne

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上述结果你就需要一)设定时区为UTC + 2 B)碰上ToLocalTime()中的毛刺已经修复,MSDN在转换日期时提到了XP上的缺陷。

终于DateTime.Now返回当地时间,所以使用DateTime.Now.ToLocalTime()有点多余,你可能会得到意想不到的结果。