DateTime和DateTimeOffset是同胞兄弟吗?
小编在日常开发中,用得最多的时间类型就是DateTime,直到一次偶然的邂逅,让小编遇见了DateTimeOffset。当时小编也是一脸迷茫,因为在小编的C#编程字典里就没出现过DateTimeOffset的字样,实属惭愧。于是心中立马产生疑惑:DateTimeOffset是用来干嘛的?它和DateTime之间又是什么关系?带着种种疑问和不解,小编今天就带你一起一窥究竟!
开场前,先了解下GMT、UTC、TimeZone这三个时间概念
GMT:Greenwich Mean Time,格林威治平时(也称格林威治时间)。它规定太阳每天经过位于英国伦敦郊区的皇家格林威治天文台的时间为中午12点。1972年之前,格林威治时间(GMT)一直是世界时间的标准。1972年之后,GMT 不再是一个时间标准了,取而代之的是UTC。
UTC:Coodinated Universal Time,协调世界时,又称世界统一时间、世界标准时间、国际协调时间。UTC 是现在全球通用的时间标准,全球各地都同意将各自的时间进行同步协调。
TimeZone: 时间区域,简称时区。按照规定从格林威治本初子午线起,经度每向东或者向西间隔15°,就划分一个时区,在这个区域内,大家使用同样的标准时间。全球共分为24个标准时区,相邻时区的时间相差一个小时。
举个例子:北京位于东八区,和伦敦时间(UTC时间)相差+8个小时。当小编每天早上8点出门上班的时候 ,大洋彼岸的英国人民正处于睡梦中,因为那儿正值午夜零点,这就是我们常说的时差。顺带提一句,虽然我国地域辽阔横跨5个时区,但统一采用北京时间作为标准时间,目的就是为了方便时间管理。
首先登场的是:DateTime
DateTime表示的是一个日期和时间值。这里我们先思考一个问题:假设有个陌生人电话告诉你现在时间是某月某日某时某分,但你又不知道对方在哪里,那么这个时间对你来说是不清晰的,它可能是当地时间(东京时间、悉尼时间...),也有可能是UTC时间。因此DateTime有个只读属性Kind,它是一个DateTimeKind枚举,用来表示时间类型。定义如下:
1 public enum DateTimeKind
2 {
3 // 未指明是UTC时间,还是当地时间
4 Unspecified = 0,
5 // 表示UTC时间
6 Utc = 1,
7 // 表示本地时间
8 Local = 2
9 }
通过DateTime构造函数,可以看出Kind属性值是由构造函数传入的。下面来看DateTime的几种常见用法:
1 DateTime dt1 = new DateTime(2023, 7, 27, 8, 40, 25);
2 Console.WriteLine($"DateTime:{dt1}, 时间类型:{dt1.Kind}, 转本地时间:{dt1.ToLocalTime()},转UTC时间:{dt1.ToUniversalTime()}");
3
4 DateTime dt2 = DateTime.Now;
5 Console.WriteLine($"DateTime:{dt2}, 时间类型:{dt2.Kind}, 转本地时间:{dt2.ToLocalTime()},转UTC时间:{dt2.ToUniversalTime()}");
6
7 DateTime dt3 = DateTime.UtcNow;
8 Console.WriteLine($"DateTime:{dt3}, 时间类型:{dt3.Kind}, 转本地时间:{dt3.ToLocalTime()},转UTC时间:{dt3.ToUniversalTime()}");
9
10 DateTime dt4 = new DateTime(2023, 7, 27, 8, 40, 25, DateTimeKind.Local);
11 Console.WriteLine($"DateTime:{dt4}, 时间类型:{dt4.Kind}, 转本地时间:{dt4.ToLocalTime()},转UTC时间:{dt4.ToUniversalTime()}");
12
13 DateTime dt5 = new DateTime(2023, 7, 27, 8, 40, 25, DateTimeKind.Utc);
14 Console.WriteLine($"DateTime:{dt5}, 时间类型:{dt5.Kind}, 转本地时间:{dt5.ToLocalTime()},转UTC时间:{dt5.ToUniversalTime()}");
输出结果:
DateTime: 2023 / 7 / 27 8:40:25, 时间类型: Unspecified, 转本地时间: 2023 / 7 / 27 16:40:25,转UTC时间: 2023 / 7 / 27 0:40:25
DateTime: 2023 / 7 / 27 14:04:00, 时间类型: Local, 转本地时间: 2023 / 7 / 27 14:04:00,转UTC时间: 2023 / 7 / 27 6:04:00
DateTime: 2023 / 7 / 27 6:04:00, 时间类型: Utc, 转本地时间: 2023 / 7 / 27 14:04:00,转UTC时间: 2023 / 7 / 27 6:04:00
DateTime: 2023 / 7 / 27 8:40:25, 时间类型: Local, 转本地时间: 2023 / 7 / 27 8:40:25,转UTC时间: 2023 / 7 / 27 0:40:25
DateTime: 2023 / 7 / 27 8:40:25, 时间类型: Utc, 转本地时间: 2023 / 7 / 27 16:40:25,转UTC时间: 2023 / 7 / 27 8:40:25
由此可见,DateTime是通过Kind属性来区分是本地时间还是UTC时间,同时本地时间和UTC时间之间可以相互转换,转换条件就是根据你电脑当前所设置的时区。不足之处就是DateTime提供了非常有限的时区信息,如果不看Kind属性,你无法判断它是来自本地时间还是UTC时间,因此在跨时区系统间的数据移植性较差(除非是指定是UTC时间)。
接着出场的就是:DateTimeOffset
DateTimeOffset表示一个时间点,通常以相对于协调世界时 (UTC) 的日期和时间来表示。它既包含了DateTime属性,又包含了一个TimeSpan类型的Offset属性(表示相对于UTC时间的偏移量).
通过DateTimeOffset构造函数,可以看出Offset属性值是由构造函数传入的。下面来看DateTimeOffset的几种常见用法:
1 DateTimeOffset dto1 = new DateTimeOffset(2023, 7, 27, 8, 40, 25, TimeSpan.Zero);
2 Console.WriteLine($"DateTimeOffset:{dto1}, 时间偏移:{dto1.Offset}, 转本地时间:{dto1.ToLocalTime()},转UTC时间:{dto1.ToUniversalTime()}");
3
4 DateTimeOffset dto2 = DateTimeOffset.Now;
5 Console.WriteLine($"DateTimeOffset:{dto2}, 时间偏移:{dto2.Offset}, 转本地时间:{dto2.ToLocalTime()},转UTC时间:{dto2.ToUniversalTime()}");
6
7 DateTimeOffset dto3 = DateTimeOffset.UtcNow;
8 Console.WriteLine($"DateTimeOffset:{dto3}, 时间偏移:{dto3.Offset}, 转本地时间:{dto3.ToLocalTime()},转UTC时间:{dto3.ToUniversalTime()}");
9
10 DateTimeOffset dto4 = new DateTimeOffset(2023, 7, 27, 8, 40, 25, new TimeSpan(8, 0, 0));
11 Console.WriteLine($"DateTimeOffset:{dto4}, 时间偏移:{dto4.Offset}, 转本地时间:{dto4.ToLocalTime()},转UTC时间:{dto4.ToUniversalTime()}");
12
13 DateTimeOffset dto5 = new DateTimeOffset(new DateTime(2023, 7, 27, 8, 40, 25), new TimeSpan(-8, 0, 0));
14 Console.WriteLine($"DateTimeOffset:{dto5}, 时间偏移:{dto5.Offset}, 转本地时间:{dto5.ToLocalTime()},转UTC时间:{dto5.ToUniversalTime()}");
输出结果:
DateTimeOffset:2023/7/27 8:40:25 +00:00, 偏移量:00:00:00, 转本地时间:2023/7/27 16:40:25 +08:00,转UTC时间:2023/7/27 8:40:25 +00:00
DateTimeOffset:2023/7/27 15:46:14 +08:00, 偏移量:08:00:00, 转本地时间:2023/7/27 15:46:14 +08:00,转UTC时间:2023/7/27 7:46:14 +00:00
DateTimeOffset:2023/7/27 7:46:14 +00:00, 偏移量:00:00:00, 转本地时间:2023/7/27 15:46:14 +08:00,转UTC时间:2023/7/27 7:46:14 +00:00
DateTimeOffset:2023/7/27 8:40:25 +08:00, 偏移量:08:00:00, 转本地时间:2023/7/27 8:40:25 +08:00,转UTC时间:2023/7/27 0:40:25 +00:00
DateTimeOffset:2023/7/27 8:40:25 -08:00, 偏移量:-08:00:00, 转本地时间:2023/7/28 0:40:25 +08:00,转UTC时间:2023/7/27 16:40:25 +00:00
可以看出,DateTimeOffset除了包含日期和时间之外,还包含相对于UTC时间的偏移量,因此不再需要Kind属性,就能区分出是UTC时间(如:dto1和dto3)还是本地时间(如:dto2、dto4和dto5),同时还能反馈时间所在的时区(如:dto2和dto4是东八区,dto5是西八区)。
最后得出结论:
DateTimeOffset和DateTime之间的确存在血缘关系,DateTimeOffset相当于是DateTime的一个包装,它除了具有DateTime的所有功能之外,还包含时区信息。如果你的系统不需要考虑时区问题或者只用UTC时间,那么DateTime就够用了。如果你的系统是全球化的,客户来自不同时区的不同国家,那么服务端就需要用DateTimeOffset来保存时间,这样客户端很容易将带有时区的时间字符串(如:"2023/7/27 8:40:25 +08:00")转成本地时间来显示。总而言之,小编认为DateTimeOffset功能比DateTime更强大、也更加灵活。微软官方建议用DateTimeOffset作为应用开发的默认时间类型。
参考资料:
彻底弄懂GMT、UTC、时区和夏令时 - 知乎 (zhihu.com)
c#:细说时区、DateTime和DateTimeOffset在国际化中的应用 - 知乎 (zhihu.com)
谈谈你最熟悉的System.DateTime[上篇] - Artech - 博客园 (cnblogs.com)
Compare types related to date and time | Microsoft Learn
DateTime和DateTimeOffset是同胞兄弟吗?的更多相关文章
- DateTime , DateTime2 ,DateTimeOffset 之间的小区别
闲来无事列了个表比对一下这3兄弟之间还是有一点差距的╮(╯_╰)╭ DateTime DateTime2 DateTimeOffset 日期范围 1753-01-01到 9999-12-31 00 ...
- C#中 DateTime , DateTime2 ,DateTimeOffset 之间的小区别 (转载)
闲来无事列了个表比对一下这3兄弟之间还是有一点差距的╮(╯_╰)╭ DateTime DateTime2 DateTimeOffset 日期范围 1753-01-01到 9999-12-31 00 ...
- DateTime还是DateTimeOffset?Now还是UtcNow?
(此文章同时发表在本人微信公众号"dotNET每日精华文章",欢迎右边二维码来关注.) 题记:新年第一篇文章,就来谈谈关于时间的简单技术问题:该用DateTime还是DateTim ...
- 第二节:比较DateTime和DateTimeOffset两种时间类型并介绍Quartz.Net中用到的几类时间形式(定点、四舍五入、倍数、递增)
一. 时间的类型 1. 背景 这里为什么要介绍时间类型呢,明明是定时调度篇,原因是在定时任务中,任务什么时间开始执行,什么时间结束执行,要用到各种各样的时间模式,虽然这不能算是一个复杂的问题,但在正式 ...
- 重学c#系列——datetime 和 datetimeoffset[二十一]
前言 简单介绍一下datetime和 datetimeoffset. 正文 了解一个国家的文化,就要了解一个国家的历史. 要了解datetimeoffset,那么很有必要了解一下datetime. 表 ...
- DateTime和DateTimeOffset的区别
1,DateTime 表示时间上的一刻,通常以日期和当天时间来表示. 2, DateTimeOffset 表示一个时间点,通常以相对于协调世界时(UTC)的日期和时间来表示. 3,下面是微软官方给出的 ...
- .NETFramework:DateTimeOffset
ylbtech-.NETFramework:DateTimeOffset 表示一个时间点,通常相对于协调世界时(UTC)的日期和时间来表示. 1.程序集 mscorlib, Version=4.0.0 ...
- 如何使用 System.Text.Json 序列化 DateTimeOffset 为 Unix 时间戳
在 .NET 中,日期和时间通常使用 DateTime 或 DateTimeOffset 来表示.这两种数据类型都可以表示日期和时间,但它们之间有一些明显的区别.DateTime 是不带时区信息的,而 ...
- 初试ASP.NET Web API/MVC API(附Demo)
写在前面 HTTP RESTful 创建Web API 调用Web API 运行截图及Demo下载 ASP.NET Web API是一个框架,可以很容易构建达成了广泛的HTTP服务客户端,包括浏览 ...
- ASP.NET Web API(MVC API)
ASP.NET Web API是一个框架,可以很容易构建达成了广泛的HTTP服务客户端,包括浏览器和移动设备.是构建RESTful应用程序的理想平台的.NET框架. 上面是微软对Web API给出 ...
随机推荐
- Vue+echarts实现中国地图射线效果
效果图如上 前提是安装Echarts并引入 并且配置中国地图json文件这些都在同账号另一篇博客上有说明,查看请自行移步 下展示代码 <template> <div class=&q ...
- Rust中的函数指针
什么是函数指针 通过函数指针允许我们使用函数作为另一个函数的参数.函数的类型是 fn (使用小写的 "f" )以免与 Fn 闭包 trait 相混淆.fn 被称为 函数指针(fun ...
- ai问答:使用vite如何配置多入口页面
Vite 是一个 web 开发构建工具,它可以用于开发单页应用和多页应用.要在 Vite 中配置多入口,可以: 在 vite.config.js 中定义多个 entry 入口: export defa ...
- 2022-02-11:单词缩写。 给定一个由n个不重复非空字符串组成的数组,你需要按照以下规则为每个单词生成最小的缩写。 初始缩写由起始字母+省略字母的数量+结尾字母组成。 若存在冲突,亦即多于一个单
2022-02-11:单词缩写. 给定一个由n个不重复非空字符串组成的数组,你需要按照以下规则为每个单词生成最小的缩写. 初始缩写由起始字母+省略字母的数量+结尾字母组成. 若存在冲突,亦即多于一个单 ...
- SpringBoot源码学习4——SpringBoot内嵌Tomcat启动流程源码分析
系列文章目录和关于我 零丶引入 我在初学spring的时候,很懵逼,因为整个项目中不存在main方法,让我有点摸不着头脑.那时候我知道有个东西叫tomcat是它监听了端口,解析了协议调到了我的serv ...
- Django4全栈进阶之路21 项目实战(三种方式开发部门管理):方式二:CBV+Django内置类(ListView, CreateView, UpdateView, DeleteView, DetailView)
在 Django 中,视图(View)是处理请求并返回响应的主要机制.Django 中有许多视图类可用于处理常见的 CRUD(Create.Read.Update.Delete)操作以及其他类型的请求 ...
- requests标头在json序列化时报错TypeError: Object of type CaseInsensitiveDict is not JSON serializable
requests的作者似乎为了解决header里大小写兼容的问题,而创建了大小写不敏感的数据结构CaseInsensitiveDict,requests返回的响应标头即是一个CaseInsensiti ...
- AcWing 3729. 改变数组元素
给定一个空数组 V 和一个整数数组 a1,a2,-,an. 现在要对数组 V进行 n次操作. 第 i次操作的具体流程如下: 从数组 V尾部插入整数 0. 2.将位于数组 V末尾的 ai 个元素都 ...
- 在C++中,传值还是传引用?
情况一:需要修改原对象 需要修改原对象的情况,必须要传引用.这种情况没什么要说的. 情况二:不需要修改原对象 对于内置类型(整数.浮点数.字符类型等),传值效率更高.主要有三点原因: 内存开销更小.由 ...
- Python 中常见的 TypeError 是什么?
翻译:BioIT 爱好者原文:TypeError: A Bytes-Like object Is Required, not 'str' | Finxter 简介 目标:在本教程中,我们的目标是修复以 ...