Wil*_*lie 1 timezone-offset asp.net-web-api asp.net-core asp.net-core-2.2
场景:我有一个接受 POST 请求的 REST-API。作为正文数据,传递了 ISO8601 格式的日期时间。
{
"validate": "2019-12-02T23:00:00Z",
"configuration": {},
"sortId": 1
}
Run Code Online (Sandbox Code Playgroud)
通过 MVC 中的模型绑定,可以自动解析日期时间。该变量应位于 api 服务器的本地时区。在本例中为欧洲/柏林。我预计时间(参考示例)为 2019-12-03:00:00:00。但这种情况并非如此。现在还有一小时休息时间。
但是当我发布以下内容时:
{
"validate": "2019-12-02T23:00:00+00:00",
"configuration": {},
"sortId": 1
}
Run Code Online (Sandbox Code Playgroud)
解析为本地时区按预期进行。因为发布数据的客户端是用 JS 编写的,并使用默认的 Date.toISOString() 函数,所以我总是在结尾处得到一个“Z”。根据 ISO8601,这是完全没问题的。
Z明确表示 UTC。+00:00没有。英国现在是00:00夏天01:00。1970 年,01:00全年使用夏令时 ( )。
这里涉及到几个概念和一些历史。首先,DateTime没有偏移量或时区的概念。根据其Kind属性,ADateTime只能是UTC、Local或。Undefined
使用DateTime意味着偏移信息丢失。结果值需要转换为某种东西。为此,需要使用机器的偏移量。也就是说,Web 服务计算机的偏移量,而不是数据库服务器的偏移量。
然后,我们的容器或应用程序故障转移到具有默认 UTC 时区而不是我们配置的时区的计算机。整个周末。
程序员对时间的看法值得一读,尤其是8. The machine that a program runs on will always be in the GMT time zone.
更好的解决方案是使用DateTimeOffset,尽管即使这样也无法处理 DST 规则更改。
更好的解决方案是使用 IANA 时区名称并传递Europe/Berlin而不是偏移量。但这不是常见用法。航空公司至少会发布带有偏移量和时区名称的航班时间。
日期时间解析规则
DateTime解析规则将转换Z或偏移量转换为Local带转换,将其他任何内容转换为Unspecified不转换。这听起来很奇怪,但考虑到它DateTime是为在桌面应用程序上工作而构建的,在桌面应用程序上Local时间是有意义的。
这段代码
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}");
}
Run Code Online (Sandbox Code Playgroud)
生产:
2019-12-03T01:00:00 Local
2019-12-03T01:00:00 Local
2019-12-02T23:00:00 Unspecified
Run Code Online (Sandbox Code Playgroud)
这种UTC情况在这里消失了,作为航班预订系统的开发人员,我根本不喜欢这种情况。航班时间是机场当地时间,而不是我的服务器时间。现在,我必须先将该值转换回 UTC 或其他格式,然后再将其保存到数据库中。我必须将其转换回原始机场偏移量才能打印机票并发送通知。
如果出现任何错误,即使是由于航空公司的错误,我也必须赔偿你们。
JSON.NET(真正的API)解析规则
另一方面,JSON.NET 使用ZUTC 解析字符串,Local使用转换解析偏移量,不使用偏移量解析Undefined。对于从任何地方接收请求的 API,UTC 更有用。大多数托管服务商和云服务也默认提供 UTC 机器。
这段代码:
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}");
}
Run Code Online (Sandbox Code Playgroud)
生产:
2019-12-03T01:00:00 Local
2019-12-02T23:00:00 Utc
2019-12-02T23:00:00 Unspecified
Run Code Online (Sandbox Code Playgroud)
更好,但我不喜欢它。我仍然丢失信息。
带有 DateTimeOffset 的 JSON
DateTimeOffset包括偏移量,因此不会丢失任何信息。未指定的偏移量被视为Local时间。这个片段:
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}");
}
}
Run Code Online (Sandbox Code Playgroud)
生产:
2019-12-02T23:00:00.0000000+00:00
2019-12-02T23:00:00.0000000+00:00
2019-12-02T23:00:00.0000000+02:00
Run Code Online (Sandbox Code Playgroud)
为什么不是到处都是 UTC?
因为这会丢失大量信息,很容易使该时间值无法使用。有很多SO问题,发帖者试图比较 UTC 时间,但由于 DST 影响甚至 DST 变化而得到了意想不到的结果。
几年前,埃及在提前几周通知后更改了夏令时规则。航空公司和在线代理商并不高兴。
此外,如果游戏中存在两个以上时区怎么办?国际航班很少降落在同一时区,因此存储 UTC 不起作用。航空公司不会以 UTC 发布时刻表,而是以当地时间发布时刻表,并以偏移量和 IANA TZ 名称作为附加信息。
值得一读的是程序员对时间的看法,尤其是涉及 UTC 或 GMT 的部分。
| 归档时间: |
|
| 查看次数: |
10007 次 |
| 最近记录: |