zoukankan      html  css  js  c++  java
  • 重学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 概念和比较到此结束,那么遇到具体问题也可以根据其特征来分析了,该系列持续更新。

  • 相关阅读:
    android开发过程遇到的一些错误
    TCP/IP协议详解笔记——ARP协议和RARP协议
    TCP/IP协议详解笔记——IP协议
    C# Exchange发送邮件
    Echarts柱状图堆叠显示总数
    Git解决fatal: unable to connect to github.com问题
    IIS 413错误 解决方案
    C#启动外部Exe控制台程序并输入命令
    再看JavaScript
    Web Api(5)
  • 原文地址:https://www.cnblogs.com/aoximin/p/15730952.html
Copyright © 2011-2022 走看看