你需要了解的有关.NET日期时间的必要信息
引言
DateTime是一个时常让人复杂困惑的数据类型,开发人员编写【将日期从Web服务器返回到浏览器】类似代码有时结果与预期不符。
ASP.NET MVC 5和 Web API 2/ASP.NETCore 以不同方式序列化日期,这可能会给在一个Web应用程序中同时使用这两个序列化的开发人员带来更多混淆。
本文会尽量覆盖 ASP.NET / ASP.NETCore 中与 Date/Time有关的歧义、参数绑定、序列化相关的知识点和坑位。
知识点
DateTime
DateTime最大问题在于有歧义:地球上各时区形成了一个万花筒,某一时刻在各个时区的本地定义值是不同的;同理给出某时间值,万花筒上的各个时区使用这个值标识了 不同的时刻。
正因为这个现状,在Internet以及无线电通信时,需要定义统一的时间标准。
UTC时间标准
协调世界时(Coordinated Universal Time,缩写为UTC)是全世界定义时钟和时间的主要时间标准。 以原子时秒长为基础在时刻上尽量接近世界时的一种计量系统,
格林威治GMT时间 是19 世纪中叶英帝国基准时间,他以格林威治天文台的0度经线,将世界分为24个时区。 为了方便在不需要精确到秒的情况下,通常将GMT和UTC视为等同。
UTC能精确代表单一时间点,UTC时刻对于住在加利福尼亚和中国的人来说都是一样的。世界上所有时区的本地时间 都以相对于UTC正负偏移表示(以英国格林威治时区为0时区)
如果把以上北京时间2019/06/04 09:45:29转化为UTC时间,可以使用以下公式: UTC + 时区差 = 当地时间。
电邮中若有
Sun,04,June 2019 9:45:29 +0800
说明信件发送第时间是2019年6月04日,星期日,上午9点45分29秒,该地区领先UTC8小时 (+800,就是东八区时间)。
发这封邮件的时间,北京时间是9点45,伦敦时间凌晨1点45 ......
中国大陆采用ISO 8601-1988的《数据元和交换格式信息交换日期和时间表示法》(GB/T 7408-1994)称之为国际协调时间,代替原来的GB/T 7408-1994;中国台湾采用CNS 7648的《资料元及交换格式–资讯交换–日期及时间的表示法》,称之为世界统一时间。
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 : --11T10::42z == 2016-10-11T10:18:42+00:00 // Date: 2016-10-12 10:18:42 Pacific time 对应的UTC时间是 2016-10-11T16:18:42
ISO : --11T10::-:00 # 本地时间上午10点左右, 英国伦敦时间下午4点左右: 该本地时间相对伦敦时间提前 6小时。
也是就说我们现在常见的时间格式 2026-10-11T10:18:42+08: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(, , , , , , DateTimeKind.Local);
var dt1_temp = dt1.ToUniversalTime(); var dt2 = new DateTime(, , , , , , DateTimeKind.Utc);
var dt2_temp = dt2.ToUniversalTime(); var dt3 = new DateTime(, , , , , , DateTimeKind.Unspecified);
var dt3_temp = dt3.ToUniversalTime();
var dt4 = new DateTime(, 6, 4, 9, 45, 29); // Unspecified DateTime
var dt4_temp = dt4.ToUniversalTime();
Console.WriteLine(dt1_temp.ToString());
Console.WriteLine(dt2_temp.ToString());
Console.WriteLine(dt3_temp.ToString()); // Unspecified DateTime在被应用ToUniversalTime 方法时会被假定是Local
Console.WriteLine(dt4_temp.ToString());
output:
2019/6/4 1:45:29
2019/6/4 9:45:29
2019/6/4 1:45:29
2019/6/4 1:45:29
when to use datetime?
你只处理当地时间,你没有跨越时区的计算
你只处理 UTC时间
处理抽象日期/时间(使用 Unspecified):例如跨国公司的跨时区门店都在早上9点开业
DateTimeOffset
表示时间点,通常表示为一天中相对于UTC时间的日期/时间,该结构体自然带有相对于UTC时间的偏移信息
when to use DateTimeOffset?
代码需要应对不同时区的时间值
时区之间相互转化
需要进行跨时区的计算
Date/Time序列化
Web API2 和ASP.NET Core内置的JSON序列化器是Newtonsoft.Json,JSON.NET将日期时间序列化为ISO-8601格式:
|
Date value
|
serialized value
|
|
DateTime.Now (Pacific time)
|
2016-10-11T19:25:34.8346658-07:00
|
|
DateTime.UtcNow
|
2016-10-12T01:25:34.8346658Z
|
|
new DateTime(2016, 6, 6, 4, 5,5 )
|
2016-06-06T04:05:05
|
|
new DateTimeOffset(new DateTime(2016, 6, 6, 4, 5,5 ), new TimeSpan(-2, 0,0))
|
2016-06-06T04:05:05-02:00
|
这样的格式在客户端需要使用JavaScript做一些本地转化, 转化后的值无法体现时区。
public ActionResult Contact()
{
var data = new Test
{
Name = "hj",
Time = DateTime.Now
};
return Json(data,JsonRequestBehavior.AllowGet);
} output:
{
JavaScriptSerializer还有更多缺点,现在社区鼓励使用Json.Net 序列化器。
Date/Time字符串转换
在开发中,常涉及Date/Time 参数绑定和字符串转换, 当中也有一些坑位需要规避。
一个时间日期字符串, 若没有相对于UTC的偏移信息,转换后的DateTime对象的DateTimeKind是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
开发者每天都在使用的Date/Time有很多学问, 涉及Culture、Calendar、夏令时, 这里只是浅谈最常用的知识点和坑位。
码甲拙见,如有问题请下方留言大胆斧正;码字+Visio制图,均为原创,看官请不吝好评+关注, ~。。~
本文欢迎转载,请转载页面明显位置注明原作者及原文链接。
你需要了解的有关.NET日期时间的必要信息的更多相关文章
- EasyUI datagrid 日期时间格式化
EasyUI datagrid中显示日期时间时,会显示为以下不太直观的数值: 添加以下JavaScript脚本,然后在field中添加 formatter: DateTimeFormatter 即可. ...
- POCO库——Foundation组件之日期时间DateTime
日期时间DateTime:内部提供多个设计计时器.日期.时区.时间戳等: Clock.h :Clock时钟计时类,_clock:Int64类型时钟值,CLOCKVAL_MIN.CLOCKVAL_MAX ...
- db2 日期时间格式
db2日期和时间常用汇总 1.db2可以通过SYSIBM.SYSDUMMY1.SYSIBM.DUAL获取寄存器中的值,也可以通过VALUES关键字获取寄存器中的值. SELECT 'HELLO DB2 ...
- Angularjs在控制器(controller.js)的js代码中使用过滤器($filter)格式化日期/时间实例
Angularjs内置的过滤器(filter)为我们的数据信息格式化提供了比较强大的功能,比如:格式化时间,日期.格式化数字精度.语言本地化.格式化货币等等.但这些过滤器一般都是在VIEW中使用的,比 ...
- MySQL学习笔记八:日期/时间的处理
MySQL日期时间的处理,在其官网文档上都有详细的阐述,想了解更多的同学可自行查阅. 1.查询当前日期时间:函数有now(),localtime(),current_timestamp(),sysda ...
- Java日期时间操作的一些方法
1. 获得Calendar实例: Calendar c = Calendar.getInstance(); 2. 定义日期/时间的格式: SimpleDateFormat sdf =new Simpl ...
- mysql与oracle的日期/时间函数小结
前言 本文的日期/时间全部格式化为”2016-01-01 01:01:01“形式: MONITOR_TIME为数据库表字段: 字符串与日期/时间相互转换函数 Oracle 日期/时间转字符串函数:to ...
- js 日期时间排序 数组
不多说直接show代码 var timeArr=[ {'id':'A01','date':'2016-04-20 23:22:11'}, {'id':'A02','date':'2016-04-21 ...
- sql server日期时间转字符串
一.sql server日期时间函数Sql Server中的日期与时间函数 1. 当前系统日期.时间 select getdate() 2. dateadd 在向指定日期加上一段时间的基 ...
随机推荐
- HTML 学习笔记 JQuery(盒子操作)
这边博客详细的讲述一下JQuery中关于盒子模型的一些方法 offset([coordinates])方法 获取匹配元素在当前适口的相对偏移 返回的对象包含两个模型属性:top和left 以像素计.此 ...
- (图解)Description Resource Path Location Type Java compiler level does not match the version of
Description Resource Path Location Type Java compiler level does not match the version of project 编译 ...
- ABAP 数值转换大写
转自:http://www.dasunny.com/wordpress/sapnotes/2015113091.htmlSAP标准的数值转换函数 SPELL_AMOUNT, 仅对整数部分进行了处理,小 ...
- 关于SAP S4 HANA 的13个问题
SAP S/4HANA的路线图是怎样的?价格是多少?下一步还将添加哪些新模块?莫不闻专业SAP问答平台结合SAP HANA及SAP HANA应用商务套件开发全球负责人Uwe Grigoleit帮大家整 ...
- Node.js学习笔记(1):Node.js快速开始
Node.js学习笔记(1):Node.js快速开始 Node.js的安装 下载 官方网址:https://nodejs.org/en/ 说明: 在Windows上安装时务必选择全部组件,包括勾选Ad ...
- swift中反向循环
First of all, protocol extensions change how reverse is used: for i in (1...5).reverse() { print(i) ...
- P4474 王者之剑
P4474 王者之剑 题目大意 n*m的带权网格,任意选择起点开始时刻为0秒.以下操作,每秒按顺序执行 在第i秒开始的时候,在方格(x,y)上,获得(x,y)的值 在偶数秒,周围四格的值清零 每秒可选 ...
- iOS SDK:iOS调试技巧
感谢原创 在程序中,无论是你想弄清楚为什么数组中有3个对象而不是5个,或者为什么一个新的玩家开始之后,游戏在倒退——调试在这些处理过程中是比较重要的一部分.通过本文的学习,我们将知道在程序中,可以使用 ...
- 【博弈论】hihocoder
#1163 : 博弈游戏·Nim游戏 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 今天我们要认识一对新朋友,Alice与Bob. Alice与Bob总是在进行各种各样 ...
- 51nod 1040
题目 题解:我们要求的是这个式子: $ \sum\limits_{i = 1}^n {\gcd (n,i)} $ (下面式子中的d都是n的因子) 变形下 $ \sum\limits_{d = 1} ...