重学c#系列——datetime 和 datetimeoffset[二十一]
前言
简单介绍一下datetime和 datetimeoffset.
正文
了解一个国家的文化,就要了解一个国家的历史。
要了解datetimeoffset,那么很有必要了解一下datetime。
表示时间上的一刻,通常以日期和当天的时间表示。
继承
Object-> ValueType-> DateTime
那么可以看到DateTime 是值类型了。
实际上了解Datetime 有两个重要的参数,一个是:ticks 另一个是:kind。
ticks
Int64
一个日期和时间,以公历 0001 年 1 月 1 日 00:00:00.000 以来所经历的以 100 纳秒为间隔的间隔数来表示。
kind
DateTimeKind
枚举值之一,该值指示 ticks 是指定了本地时间、协调世界时 (UTC),还是两者皆未指定。
这里有一个值得注意的是这个ticks 是以公历 0001 年 1 月 1 日 00:00:00.000 开始计算的,且单位是100纳秒。
比如说,我这个ticks 是200,那么就是20000纳秒了。
和秒的计算公式为:1 纳秒=0.000000001 秒。
DateTimeKind 指定是本地,还是utc,或者不指定。
初始化如下:
public DateTime(long ticks, DateTimeKind kind)
{
if (ticks < 0L || ticks > 3155378975999999999L)
throw new ArgumentOutOfRangeException(nameof (ticks), SR.ArgumentOutOfRange_DateTimeBadTicks);
if (kind < DateTimeKind.Unspecified || kind > DateTimeKind.Local)
throw new ArgumentException(SR.Argument_InvalidDateTimeKind, nameof (kind));
this._dateData = (ulong) (ticks | (long) kind << 62);
}
而其他年月日其实也就是转换为tickes。
public DateTime(int year, int month, int day)
{
this._dateData = (ulong) DateTime.DateToTicks(year, month, day);
}
然后DateToTicks:
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static long DateToTicks(int year, int month, int day)
{
if (year < 1 || year > 9999 || (month < 1 || month > 12) || day < 1)
ThrowHelper.ThrowArgumentOutOfRange_BadYearMonthDay();
int[] numArray = DateTime.IsLeapYear(year) ? DateTime.s_daysToMonth366 : DateTime.s_daysToMonth365;
if (day > numArray[month] - numArray[month - 1])
ThrowHelper.ThrowArgumentOutOfRange_BadYearMonthDay();
int num = year - 1;
return (long) (num * 365 + num / 4 - num / 100 + num / 400 + numArray[month - 1] + day - 1) * 864000000000L;
}
由上面可值,其他的转换都是通过_dateData 来转换。
那么datetime 有什么问题呢? 其实可以想象一个问题,就是这个设计的时候呢。
有一个local 还有 一个 UTC,那么可能local就是UTC呢?完全可能,从这里开始概念就开始出现偏差了。
public static DateTime Now
{
get
{
DateTime utc = UtcNow;
long offset = TimeZoneInfo.GetDateTimeNowUtcOffsetFromUtc(utc, out bool isAmbiguousLocalDst).Ticks;
long tick = utc.Ticks + offset;
if (tick > DateTime.MaxTicks)
{
return new DateTime(DateTime.MaxTicks, DateTimeKind.Local);
}
if (tick < DateTime.MinTicks)
{
return new DateTime(DateTime.MinTicks, DateTimeKind.Local);
}
return new DateTime(tick, DateTimeKind.Local, isAmbiguousLocalDst);
}
}
DateTime.Now,那么就是本地时间了,然后看下面这个东西。
static void Main(string[] args)
{
DateTime d = DateTime.Now;
DateTime d2 = d.ToUniversalTime();
Console.WriteLine(d.Equals(d2));
Console.Read();
}
返回为false,理论上他们应该是同一个时间。
那么这个equal 是干什么呢?
public bool Equals(DateTime value)
{
return InternalTicks == value.InternalTicks;
}
查看一下:
internal long InternalTicks => (long)(_dateData & TicksMask);
这个时候只要_dateData 不相等,那么就不相等, 是的因为时区不同,这个自然不同。
// Returns the tick count for this DateTime. The returned value is
// the number of 100-nanosecond intervals that have elapsed since 1/1/0001
// 12:00am.
//
public long Ticks => InternalTicks;
static void Main(string[] args)
{
DateTime d = DateTime.Now;
DateTime d2 = d.ToUniversalTime();
Console.WriteLine(d2.Ticks);
Console.WriteLine(d.Ticks);
Console.WriteLine(d.Equals(d2));
Console.Read();
}
计算一下相差时间:
static void Main(string[] args)
{
DateTime d = DateTime.Now;
DateTime d2 = d.ToUniversalTime();
Console.WriteLine((d.Ticks - d2.Ticks)/60/60/10000000);
Console.WriteLine(d.Equals(d2));
Console.Read();
}
那么把本地时间调成协调世界时会发生什么呢?
这时候就是true了,所以一套代码在不同时区的机器上有不同的效果了。
当然,对于datetime 我们就需要做兼容了,就是要判断其时区做处理,这里就不演示了,
DateTimeOffset是什么呢? 和datetime 有什么关系呢。
首先来看时间相等情况:
static void Main(string[] args)
{
DateTimeOffset d = DateTimeOffset.Now;
DateTimeOffset d2 = d.ToUniversalTime();
Console.WriteLine(d.Equals(d2));
Console.Read();
}
它似乎解决了我们前面的问题,那么其实怎么做的呢?
DateTimeOffset 有两个重要的参数:
ticks
Int64
一个日期和时间,以 0001 年 1 月 1 日午夜 12:00:00 以来所经历的以 100 纳秒为间隔的间隔数来表示。
offset
TimeSpan
与协调世界时 (UTC) 之间的时间偏移量。
实例化:
// Constructs a DateTimeOffset from a tick count and offset
public DateTimeOffset(long ticks, TimeSpan offset)
{
_offsetMinutes = ValidateOffset(offset);
// Let the DateTime constructor do the range checks
DateTime dateTime = new DateTime(ticks);
_dateTime = ValidateDate(dateTime, offset);
}
这里可以看到DateTimeOffset 就没有了kind 这个概念年了,而是直接指名了这个offset概念,就是和utc到底相差多少时差。
而其相等,那么也是用UTc来计算的。
public bool Equals(DateTimeOffset other) =>
UtcDateTime.Equals(other.UtcDateTime);
这样,其实就解决了这个时区概念了。
结
至此datetime 和 datetimeoffset 概念和比较到此结束,那么遇到具体问题也可以根据其特征来分析了,该系列持续更新。
重学c#系列——datetime 和 datetimeoffset[二十一]的更多相关文章
- 重学c#系列——c#运行原理(二)
前言 c# 是怎么运行的呢?是否和java一样运行在像jvm的虚拟机上呢?其实差不多,但是更广泛. c# 运行环境不仅c#可以运行,符合.net framework 开发规范的都可以运行. c# 程序 ...
- 重学c#系列——字典(十一)
前言 重学c#系列继续更新,简单看一下字典的源码. 看源码主要是解释一下江湖中的两个传言: 字典foreach 顺序是字典添加的顺序 字典删除元素后,字典顺序将会改变 正文 那么就从实例化开始看起,这 ...
- 重学c#系列——string.empty 和 "" 还有null[二十]
前言 简单整理一下string.empty 和 "" 还有 null的区别. 正文 首先null 和 string.empty 还有 "" 是不一样的. nul ...
- 重学c#系列——对c#粗浅的认识(一)
前言 什么是c#呢? 首先你是如何读c#的呢?c sharp?或者c 井? 官方读法是:see sharp. 有没有发现开发多年,然后感觉名字不对. tip:为个人重新整理,如学习还是看官网,c# 文 ...
- 重学c#系列——list(十二)
前言 简单介绍一下list. 正文 这里以list为介绍. private static readonly T[] s_emptyArray = new T[0]; public List() { t ...
- 重学c#系列——盛派自定义异常源码分析(八)
前言 接着异常七后,因为以前看过盛派这块代码,正好重新整理一下. 正文 BaseException 首先看下BaseException 类: 继承:public class BaseException ...
- 重学Golang系列(一): 深入理解 interface和reflect
前言 interface(即接口),是Go语言中一个重要的概念和知识点,而功能强大的reflect正是基于interface.本文即是对Go语言中的interface和reflect基础概念和用法的一 ...
- 重学c#系列——c# 托管和非托管资源(三)
前言 c# 托管和非托管比较重要,因为这涉及到资源的释放. 现在只要在计算机上运行的,无论玩出什么花来,整个什么概念,逃不过输入数据修改数据输出数据(计算机本质),这里面有个数据的输入,那么我们的内存 ...
- 重学c#系列——异常续[异常注意事项](七)
前言 对上节异常的补充,也可以说是异常使用的注意事项. 正文 减少try catch的使用 前面提及到,如果一个方法没有实现该方法的效果,那么就应该抛出异常. 如果有约定那么可以按照约定,如果约定有歧 ...
随机推荐
- RSA,DSA,ECDSA,EdDSA和Ed25519的区别
RSA,DSA,ECDSA,EdDSA和Ed25519的区别 用过ssh的朋友都知道,ssh key的类型有很多种,比如dsa.rsa. ecdsa.ed25519等,那这么多种类型,我们要如何选择呢 ...
- 13.Merge k Sorted Lists
思路:利用map<int,vector<ListNode*> > 做值和指针的映射,最后将指针按值依次链接起来, 时间复杂度O(N),空间O(N) Merge k sorted ...
- 单元测试在Unity中的应用
项目描述:简单演示单元测试在Unity中的应用 项目地址:UnityTestRunner_Tutorial - SouthBegonia 项目版本:2020.3.20f1 项目用法:打开就用,代码都放 ...
- Shell 输出第五行的内容
目录 Shell 输出第五行的内容 题目 题解-awk 题解-sed Shell 输出第五行的内容 题目 写一个 bash脚本以输出一个文本文件 nowcoder.txt 中第5行的内容. 示例: 假 ...
- STM32 部分重映射和完全重映射(查看数据手册)
数据手册如何查找对应的映射: 打开官网直接搜索STM32F可以看到数据手册,里面有关于重映射的表格,输入第6页的页码,点击9.3中的9.3x可打开对应的链接. 举例说明: STM32中拥有重映射功能 ...
- c学习 - 第八章:函数
8.7 数组作函数的参数 1.数组元素作函数的参数--值传递,单向传递 2.数组名做函数的参数--地址传送 (1)实参:数组名做实参,传递的是数组首元素的地址 (2)形参:使用同类型的数组名或指针变量 ...
- redis入门到精通系列(三):key的通用操作和redis内部db的通用操作
五种数据类型都用到了key,key本身是一种字符串,通过key可以获取redis中保存的对象.这一篇博客就将介绍key的通用操作. (一)key基本操作 删除key del key key是否存在 e ...
- MySQL(5):安装MySQL
下载地址 下载地址:https://dev.mysql.com/get/Downloads/MySQL-5.7/mysql-5.7.19-winx64.zip 安装步骤 第一步:下载得到压缩包,并解压 ...
- springboot整合jetty
1.jetty介绍 通常我们进行Java Web项目开发,必须要选择一种服务器来部署并运行Java应用程序,Tomcat和Jetty作为目前全球范围内最著名的两款开源servlet容器,该怎么选呢. ...
- 部署应用程序到Tomcat的webapps目录
一.方法如下 1.通过MyEclipse上方工具栏Manage Deployments,依次选择项目和服务器: 2.通过右击项目Export,生成war包到webapps中: 3.复制项目WebRoo ...