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

  • 相关阅读:
    Atitit  atiMail atiDns新特性 v2  q39
    Atitit  atiMail atiDns新特性 v2  q39
    Atitit.aticmd v4  新特性q39 添加定时器释放功能
    Atitit.aticmd v4  新特性q39 添加定时器释放功能
    Atitit. Atiposter 发帖机 新特性 poster new feature   v7 q39
    Atitit. Atiposter 发帖机 新特性 poster new feature   v7 q39
    Atitit.编程语言and 自然语言的比较and 编程语言未来的发展
    Atitit.编程语言and 自然语言的比较and 编程语言未来的发展
    atitit.解决struts2 SpringObjectFactory.getClassInstance NullPointerException  v2 q31
    知也atitit.解决struts2 SpringObjectFactory.getClassInstance NullPointerException  v2 q31无涯 - I
  • 原文地址:https://www.cnblogs.com/aoximin/p/15730952.html
Copyright © 2011-2022 走看看