后缀为"Z"时,本地时间未解析ASP.NET Core API ISO8601 [英] ASP.NET Core API ISO8601 not parsed in local time when suffix is 'Z'

查看:117
本文介绍了后缀为"Z"时,本地时间未解析ASP.NET Core API ISO8601的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

场景:我有一个采用POST请求的REST-API.作为正文数据,传递了ISO8601格式的日期时间.

Scenario: I have a REST-API that takes a POST-Request. As Body-Data there is passed a Datetime in ISO8601 Format.

{
    "validate": "2019-12-02T23:00:00Z",
    "configuration": {},
    "sortId": 1
}

在MVC中使用Modelbinding,可以自动解析Datetime.该变量应位于api服务器的本地时区.在这种情况下,欧洲/柏林.我希望时间是(参考示例)在2019-12-03:00:00:00.但这种情况并非如此.还需要一个小时.

With Modelbinding in MVC the Datetime gets parsed automaticly. The variable should be in the local timezone of the api-server. In this case Europe/Berlin. I would expect the time to be (refering to the example) to be on 2019-12-03:00:00:00. But this is not the case. It is still one hour off.

但是当我发布以下内容时:

But when i post the following:

{
    "validate": "2019-12-02T23:00:00+00:00",
    "configuration": {},
    "sortId": 1
}

解析到本地时区按预期方式工作.因为发布数据的客户端是用JS编写的,并且使用默认的Date.toISOString()函数,所以我总是在末尾得到一个"Z".根据ISO8601,这完全可以.

The parsing into the local timezone works as expected. Because the Client posting the data is written in JS and uses the default Date.toISOString() function, i always get a 'Z' in the ending. According to the ISO8601 this is totally fine.

推荐答案

Z 明确表示UTC. +00:00 不会.英国现在是 00:00 ,但夏天是 01:00 .1970年,全年使用夏季时间( 01:00 ).

Z explicitly means UTC. +00:00 doesn't. The UK is at 00:00 now, but 01:00 in the summer. In 1970, summer time (01:00) was used for the entire year.

这里涉及几个概念以及一些历史.首先, DateTime 没有偏移量或时区的概念.根据其

There are a couple of concepts involved here, and a bit of history. First of all, DateTime has no concept of offset or timezone. A DateTime can only be UTC, Local or Undefined, according to its Kind property.

使用 DateTime 意味着丢失偏移信息.结果值需要转换为 something .为此,使用机器的偏移量.也就是说, Web服务计算机的偏移量,而不是数据库服务器的偏移量.

Using DateTime means that the offset information is lost. The resulting value needs to be converted to something. To do that, the machine's offset is used. That is, the web service machine's offset, not the database server's.

然后,我们的容器或应用程序故障转移到具有默认UTC时区而不是我们配置的时区的计算机.在周末.

And then, our container or application fails over to a machine with a default UTC timezone instead of our configured timezone. Over the weekend.

值得阅读虚假的程序员相信时间,特别是 8.运行程序的计算机将始终处于格林尼治标准时间(GMT)时区.

一个更好的解决方案是使用 DateTimeOffset ,尽管即使那样也无法处理DST规则更改.

A better solution would be to use DateTimeOffset, although even that won't be able to handle DST rule changes.

一个更好的解决方案是使用IANA时区名称并传递 Europe/Berlin 而不是偏移量.不过,这并不常见.航空公司至少要发布飞行时间,包括偏移量和时区名称.

An even better solution would be to use IANA timezone names and pass Europe/Berlin instead of offsets. That's not common usage though. Airlines at least post flight times both with offsets and timezone names.

DateTime解析规则

DateTime 解析规则将转换后的 Z 或偏移量转换为 Local ,将任何其他内容转换为 Unspecified ,而无需转换.这听起来很奇怪,但是请考虑将 DateTime 构建为可在桌面应用程序上运行,而在桌面应用程序中, Local 时间才有意义.

DateTime parsing rules convert Z or offsets to Local with conversion and anything else to Unspecified without conversion. This sounds strange but consider that DateTime was built to work on desktop applications, where Local time makes sense.

此代码

var values=new[]{
"2019-12-02T23:00:00+00:00",
"2019-12-02T23:00:00Z",
"2019-12-02T23:00:00"
};
foreach(var value in values)
{
    var dt=DateTime.Parse(value);
    Console.WriteLine($"{dt:s}\t{dt.Kind}");
}

产生:

2019-12-03T01:00:00  Local
2019-12-03T01:00:00  Local
2019-12-02T23:00:00  Unspecified

这里丢失了 UTC 类型,作为航班预订系统的开发人员,我一点也不喜欢 .飞行时间是在机场的当地时间,而不是我的服务器.现在,我必须先将该值转换回UTC或类似的值,然后再将其保存到数据库中.我必须将其转换回原始的 airport 偏移量以打印机票并发送通知.

The UTC kind is lost here and, as a developer of flight reservation systems, I don't like that at all. Flight times are in the airport's local time, not my servers. Now I'll have to convert that value back to UTC or something, before saving it to a database. I have to convert it back to the original airport offset to print the tickets and send notifications.

如果出现任何错误,即使是由于航空公司的错误,我也必须赔偿.

And I'll have to reimburse you guys if there's any error, even if it's due to an airline's error.

JSON.NET(真正的API)解析规则

JSON.NET将具有 Z 的字符串解析为UTC,将具有Offsets的 Local 转换为UTC,而没有偏移为 Undefined 的字符串.对于可以接收来自任何地方的请求的API,UTC更为有用.默认情况下,大多数托管服务商和云服务也提供UTC计算机.

JSON.NET on the other hand, parses strings with Z to UTC, Offsets to Local with conversion and no offset to Undefined. For an API that receives requests from anywhere, UTC is far more useful. Most hosters and cloud services provide UTC machines by default too.

此代码:

class It
{
    public DateTime Dt{get;set;}
}


var values=new[]{
"{'dt':'2019-12-02T23:00:00+00:00'}",
"{'dt':'2019-12-02T23:00:00Z'}",
"{'dt':'2019-12-02T23:00:00'}"
};
foreach(var value in values)
{
    var dt=JsonConvert.DeserializeObject<It>(value).Dt;
    Console.WriteLine($"{dt:s}\t{dt.Kind}");
}

产生:

2019-12-03T01:00:00  Local
2019-12-02T23:00:00  Utc
2019-12-02T23:00:00  Unspecified

更好,但不喜欢.我仍然会丢失信息.

Better, but I don't like it. I still lose information.

带有DateTimeOffset的JSON

DateTimeOffset 包含偏移量,因此不会丢失任何信息.未指定的偏移量被视为 Local 时间.此代码段:

DateTimeOffset includes the offset so no information is lost. Unspecified offsets are treated as Local time. This snippet :

class It
{
    public DateTimeOffset Dt{get;set;}
}
void Main()
{
    var values=new[]{
    "{'dt':'2019-12-02T23:00:00+00:00'}",
    "{'dt':'2019-12-02T23:00:00Z'}",
    "{'dt':'2019-12-02T23:00:00'}"
    };
    foreach(var value in values)
    {
        var dt=JsonConvert.DeserializeObject<It>(value).Dt;
        Console.WriteLine($"{dt:o}");
    }
    
}

产生:

2019-12-02T23:00:00.0000000+00:00
2019-12-02T23:00:00.0000000+00:00
2019-12-02T23:00:00.0000000+02:00

为什么UTC到处都没有?

因为丢失了很多信息,这些信息很容易使该时间值不可用.有很多 个SO问题,发帖人试图比较UTC时间并由于DST效果甚至DST更改而获得了意想不到的结果.

Because that loses a lot of information that could easily make that time value unusable. There are a lot of SO questions where the poster tried to compare UTC time and got unexpected results because of DST effects or even DST changes.

几年前,埃及在几周内通知更改其DST规则.航空公司和在线代理商并不感到兴奋.

A few years back Egypt changed its DST rules with a couple of weeks notice. Airlines and online agents weren't thrilled.

此外,如果播放中的时区超过两个,该怎么办?国际航班很少在同一时区降落,因此无法存储UTC.航空公司不会在UTC上发布时间表,而是将其发布为当地时间,并以偏移量和IANA TZ名称作为附加信息.

Besides, what if there are more than two timezones in play? International flights rarely land in the same timezone, so storing UTC doesn't work. Airlines don't publish schedules in UTC, they publish them as local time, with offset and IANA TZ names as additional info.

值得阅读虚假的程序员相信时间,尤其是涉及UTC或UTC的部分格林尼治标准时间.

It's worth reading Falsehoods programmers believe about time, especially the parts that refer to UTC or GMT.

这篇关于后缀为"Z"时,本地时间未解析ASP.NET Core API ISO8601的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆