Chrome将没有Z的ISO时间解释为UTC; C#问题

tig*_*tig 10 javascript asp.net datetime utc

在Chrome,FF和IE上运行这个jsfiddle:http://jsfiddle.net/E9gq9/7/,你会得到:

铬:

Chrome http://images.devs-on.net/Image/vBTz86J0f4o8zlL3-Region.png

火狐:

Firefox http://images.devs-on.net/Image/aNPxNPUpltyjVpSX-Region.png

IE:

IE http://images.devs-on.net/Image/WXLM5Ev1Viq4ecFq-Region.png

苹果浏览器:

Safari http://images.devs-on.net/Image/AEcyUouX04k2yIPo-Region.png

ISO 8601似乎没有说明如何解释没有尾随Z的字符串.

我们的服务器(ASP.NET MVC4)将UTC时间从数据库中拉出来,DateTime并简单地将它们填入JSON中.正如您所看到的,我们在浏览器上得到了不一致的结果.

我们应该在服务器端向他们添加Z吗?

T.J*_*der 11

我们应该在服务器端向他们添加Z吗?

TL; DR是的,你可能应该这样做.

多年来,在没有时区的情况下正确处理日期和日期/时间已经多变 - 在规范和JavaScript引擎遵守规范方面.

当这个答案最初写于2013年时,ES5规范(第一个具有JavaScript的定义日期/时间格式)很明确:没有时区= UTC:

缺席时区偏移的值是"Z".

这与ES5日期/时间格式所依据的ISO-8601不一致,其中缺少时区指示符意味着"当地时间".有些实现从未实现过ES5的含义,而是坚持使用ISO-8601.

ES2015(又名"ES6")中,它被更改为与ISO-8601相匹配:

如果不存在时区偏移,则将日期时间解释为本地时间.

但是,这会导致现有代码出现不兼容问题,特别是对于仅限日期的表单2018-07-01,因此在ES2016中它又被更改了:

如果不存在时区偏移,则仅日期表单将被解释为UTC时间,而日期时间表单将被解释为本地时间.

因此new Date("2018-07-01")被解析为UTC,但new Date("2018-07-01T00")被解析为本地时间.

自ES2017和即将推出的ES2018以来,它一直保持一致; 这是当前标准草案的链接,该标准也包含上述文本.

您可以在此处测试当前的浏览器:

function test(val, expect) {
  var result = +val === +expect ? "Good" : "ERROR";
  console.log(val.toISOString(), expect.toISOString(), result);
}
test(new Date("2018-07-01"), new Date(Date.UTC(2018, 6, 1)));
test(new Date("2018-07-01T00:00:00"), new Date(2018, 6, 1));
Run Code Online (Sandbox Code Playgroud)

截至2018年4月的状况:

  • IE11做对了(有趣的是)
  • Firefox做对了
  • Chrome 65(桌面版,Android版)做对了
  • Chrome 64(iOS v11.3)错误地显示日期/时间表(解析为UTC)
  • v11.3中的iOS Safari获取错误的日期/时间表(解析为UTC)

奇怪的是,我在v6问题列表中找不到问题,这个问题已在v6.4(Chrome 64中的v8)和v6.5(Chrome 65中的v8)之间修复; 我只能找到这个仍然开放的问题,但似乎已经修复了.

  • 哇.这肯定是ECMAScript规范所说的 - 但它非常破碎,IMO - 并直接针对ISO-8601,其中声明:"如果根据4.2.2.2到4.2.2.4使用本地时间,则区域指示符为空." 叹.请注意,鉴于它将被及时解析,我认为整个API都被打破了.双重叹息. (5认同)

tig*_*tig 6

在一天结束时,如果我的服务器总是以所有浏览器正确处理的格式发送客户端DateTime对象,则可以修复我在此应用程序中遇到的问题.

这意味着最后必须有'Z'.原来ASP.NET MVC4 Json序列化程序基于Json.NET,但默认情况下没有打开Utc.默认值DateTimeZoneHandling似乎是,RoundtripKind并且这不会输出带有Z的值,即使DateTime.Kind == Utc这很烦人.

所以修复似乎是,设置Json.NET处理时区的方式DateTimeZoneHandling.Utc:

var json = GlobalConfiguration.Configuration.Formatters.JsonFormatter;
// Force Utc formatting ('Z' at end). 
json.SerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.Utc;
Run Code Online (Sandbox Code Playgroud)

现在,从我的服务器到浏览器的所有内容都被格式化为ISO-8601,最后带有'Z'.我测试过的所有浏览器都做对了.