微信号:iDotNet

介绍:专注分享 .NET 相关技术文章、教程和工具.有时也会涉及到IT职场相关的一些东西,或者来点幽默趣文.

.NET日期时间你需要了解的必要信息

2019-06-07 11:45 DotNet

(给DotNet加星标,提升.Net技能


转自:Julian_酱
cnblogs.com/JulianHuang/p/10967289.html

DateTime数据类型是一个复杂的问题,复杂到足以让你在编写【将日期从Web服务器返回到浏览器】简单代码时感到困惑。


ASP.NET MVC 5和 Web API 2/ASP.NETCore 以不同方式序列化日期,这可能会给在一个Web应用程序中同时使用这两个序列化的开发人员带来更多混淆。


本文会尽量覆盖 ASP.NET / ASP.NETCore 中与 Date/Time有关的歧义、参数绑定、序列化相关的知识点和坑位。 


Date/Time值歧义和应对策略


使用Datetime最大的问题在于歧义,整个地球分为24个时区,每个时区都有自己的本地时间


例如一个DateTime值指示了本地时间,这个值在同时区的其他系统依然标示了同一时间点; 但是在其他时区以外,这个DateTime值就会有各自的解释。


电邮中若有

Sun , 04, June 2019 9:45:29 +0800

说明信件发送第时间是2019年6月04日,星期日,上午9点45分29秒,该地区领先UTC8小时 (+800,就是东八区时间)。


对于发这封邮件的时间,北京本地时9点45,伦敦是凌晨1点45 ......


正因为这个现状,在Internet以及无线电通信时,时间的统一很重要。


业界提出了不同的格式来明确地表示单一时间点, Web开发行业提出了不同的解决方案以明确定义时间值。


UTC时间


在国际无线电通信中,为避免各自为战而普遍使用一个标准时间,称为协调世界时(UTC)


UTC是0时区的时间值,与格林威治标准时间(GMT)一样,都与英国伦敦的当地时间相同


UTC能准确代表单一时间点,UTC 时间对于住在加利福尼亚和中国的人来说都是一样的。


如果把以上北京时间2019/06/04 09:45:29转化为UTC时间,可以使用以下公式: UTC + 时区差 = 当地时间。


因为北京时间是东8区,所以这个点UTC时间是 2019/06/04 02:45:29(也可认为该值是伦敦时间)


开发者可以考虑的解决方案 是: 使用UTC时间存储date/time、服务端维护、计算也使用UT时间、将UTC时间发送到浏览器,浏览器javascript在Web页上转化为当地时间。


ISO 8601


Web上有许多时间显示格式,但最著名并大规模采用的是ISO-8601 标准。https://www.cl.cam.ac.uk/~mgk25/iso-time.html


当没有更多信息的时候,只包含Date/Time 的写法被假定为当地时间,要指示该时间是UTC时间,可在Datetime值后面加上字母 z,


在Datetime值后面增加 +hh:mm、 +hhmm, -hh 可指示该时间值相对于UTC时间的偏移


// Date: 2016-10-12 10:18:42 UTC time
ISO 8601: 2016-10-11T10:18:42z== 2016-10-11T10:18:42+0000

// Date: 2016-10-12 10:18:42 Pacific time, 表示该时间值相对于UTC时间值提前6小时
ISO 8601: 2016-10-11T10:18:42-06:00


.NET 中关于Date/Time的实现


.Net 4.0+ 提供的各种结构已经全方位支持 date, timezone, timezone之间的转化,足以解决开发者遇到的Date/Time相关的问题。


DateTime


DateTime 定义了一个特殊的date/time, 内置的Kind属性提供了受限的时区信息:


① DateTimeKind.UTC 指定了UTC的DateTime,明确定义了单一时间点


② DateTimeKind.Local 指示了本地时间,这个值在具有相同时区的其他系统依然能够定义一个时间点,但是在其他时区以外,这个DateTime值会有不同解释。


③ DateTimeKind.Unspecified 更没有兼容性,仅表示时间值


我们关注 DateTime.ToUniversalTime() 方法的表现,当DateTime被设定为Unspecified时候, ToUniversalTime会首先假定该值是 Local


// 以下代码的执行环境是北京时间
var dt1 = new DateTime(2019, 6, 4, 9, 45, 29, DateTimeKind.Local);
var dt1_temp = dt1.ToUniversalTime();

var dt2 = new DateTime(2019, 6, 4, 9, 45, 29, DateTimeKind.Utc);
var dt2_temp = dt2.ToUniversalTime();

var dt3 = new DateTime(2019, 6, 4, 9, 45, 29, DateTimeKind.Unspecified);
var dt3_temp = dt3.ToUniversalTime();

Console.WriteLine(dt1_temp.ToString());
Console.WriteLine(dt2_temp.ToString());
Console.WriteLine(dt3_temp.ToString());// Unspecified DateTime在被应用ToUniversalTime 方法时会被假定是Local

output:
2019/6/4 1:45:29
2019/6/4 9:45:29
2019/6/4 1:45:29

 when to use datetime?


  • 你只处理当地时间,你没有跨越时区的计算


  • 你只处理 UTC时间


  • 处理抽象日期/时间(使用 Unspecified):例如跨国公司的跨时区门店都在早上9点开业


DateTimeOffset


表示时间点,通常表示为一天中相对于UTC时间的日期/时间,该结构体自然带有相对于UTC时间的偏移信息


when to use DateTimeOffset?


  • 代码需要应对不同时区的时间值


  • 时区之间相互转化


  • 需要进行跨时区的计算


https://docs.microsoft.com/en-us/dotnet/standard/datetime/converting-between-datetime-and-offset

 

Date/Time 序列化


Web API2 和ASP.NET Core内置的JSON序列化器是Newtonsoft.Json,JSON.NET将日期时间序列化为ISO-8601格式:



ASP.NET MVC 5内置的JSON Serializer 还是System.Web.Script.Serialization.JavaScriptSerializer, 该序列化器将date序列化为时间戳:“\/Date(ticks)\/”, ticks 表示从1970-1-1 00:00:00 UTC(Unix Epoch)经历的毫秒数,这样的格式在客户端需要使用JavaScript做一些本地转化, 转化后的值无法体现时区。 


public ActionResult Contact()
{
var data = new Test
{
Name = "hj",
Time = DateTime.Now
};
return Json(data,JsonRequestBehavior.AllowGet);
}
output:
{
"Name": "hj",
"Time": "/Date(1559634654877)/"
}


JavaScriptSerializer还有更多缺点,现在社区鼓励使用Json.Net 序列化器。

 

Date/Time字符串转换


在开发中,常涉及Date/Time 参数绑定和字符串转换, 当中也有一些坑位需要规避。


一个时间日期字符串, 若没有相对于UTC的偏移信息,转换后的DateTime对象的DateTimKind是Unspecified;


若指定了offset,转换后的DateTime对象的DateTimeKind是Local, 并且时间值被调整到机器的当地时间。


最近我们生产环境WebSite再迁移到k8s集群 (UTC时间)之后,就遇到这样的问题:


订单转储的预期是:北京时间2019-05-11--->2019-05-12


实际情况是在网站端转换为Unspecified, 而进一步ToUniversalTime()过滤的时候,该时间段又被假定是机器的当地时间, 也就是说查询时间段变成了: 伦敦时间2019-05-11--->2019-05-12


这样自然与预期不符。


解决思路: 添加偏移信息,告知明确的时间段: 2019-05-11 00:00:00+08:00 ----> 2019-05-12 00:00:00+08:00


https://docs.microsoft.com/en-us/dotnet/standard/base-types/parsing-datetime

 

开发者每天都在使用的Date/Time有很多学问, 涉及Culture、Calendar、夏令时, 这里只是浅谈最常用的知识点和坑位。


推荐阅读

(点击标题可跳转阅读)

.NET Core 3 中的性能提升

构建可读性更高的ASP.NET Core 路由

C#中Queue与RabbitMQ的消息队列应用


看完本文有收获?请转发分享给更多人

关注「DotNet」加星标,提升.Net技能 

好文章,我在看❤️

 
DotNet 更多文章 Vue+axios+WebAPI+NPOI导出Excel文件 C#中Queue与RabbitMQ的消息队列应用(附源码) .NET Core 3 中的性能提升 构建可读性更高的ASP.NET Core 路由 ASP.NET Core 使用IHttpClientFactory发出HTTP请求
猜您喜欢 教你用几行代码撩一个绚丽的ArtLine 成为顶尖高手!高效程序员的7个共同特征 漫画:什么是布隆算法? 【新手】计算器(二) 数据绑定之谜