.NET - System.TimeSpan (日期间隔)

创建时间:
2014-06-14 18:38
最近更新:
2018-06-15 15:24

Resource - MSDN

  1. TimeSpan 结构 - 表示一个时间间隔。TimeSpan 对象表示时间间隔或持续时间,按正负天数、小时数、分钟数、秒数以及秒的小数部分进行度量。用于度量持续时间的最大时间单位是天。更大的时间单位 (如月和年) 的天数不同,因此为保持一致性,时间间隔以天为单位来度量。TimeSpan 对象的值是等于所表示时间间隔的刻度数。一个刻度等于 100 纳秒,TimeSpan 对象的值的范围在 System.TimeSpan.MinValue 和 System.TimeSpan.MaxValue 之间。
  2. TimeSpan.MaxValue 字段 - 表示最大的 TimeSpan 值。此字段为只读。此字段的值等效于 System.Int64.MaxValue 刻度数。此值的字符串表示形式为 +10675199.02:48:05.4775807。
  3. TimeSpan.MinValue 字段 - 表示最小的 TimeSpan 值。此字段为只读。此字段的值等效于 System.Int64.MinValue 刻度数。此值的字符串表示形式为 -10675199.02:48:05.4775808。

源码分析

  • System.TimeSpan 结构的核心只有一个,即: internal long _ticks;
  • 通过 public long Ticks { get { return this._ticks; } } 对外公开该核心。
  • 所有构造函数最终都是给 _ticks 赋值。例如 public TimeSpan(long ticks) { this._ticks = ticks; }
  • 获取 毫秒部分 的值: public int Milliseconds { get { return (int) (this._ticks / 10000L % 1000L); } },Days、Hours、Minutes、Seconds 等其他部分类似。
  • _ticks 换算成 毫秒 public double TotalMilliseconds { get { return num = (double) this._ticks * 0.0001; } },所有 Total* 属性类似。

Source Code of System.TimeSpan from JetBrains dotPeek 1.0 at 2018-06-15

Complete Copy:

// Type: System.TimeSpan
// Assembly: mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
// Assembly location: C:\Windows\Microsoft.NET\Framework\v4.0.30319\mscorlib.dll

using System.Globalization;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Security;

namespace System
{
  [ComVisible(true)]
  [__DynamicallyInvokable]
  [Serializable]
  public struct TimeSpan : IComparable, IComparable<TimeSpan>, IEquatable<TimeSpan>, IFormattable
  {
    [__DynamicallyInvokable]
    public static readonly TimeSpan Zero = new TimeSpan(0L);
    [__DynamicallyInvokable]
    public static readonly TimeSpan MaxValue = new TimeSpan(long.MaxValue);
    [__DynamicallyInvokable]
    public static readonly TimeSpan MinValue = new TimeSpan(long.MinValue);
    [__DynamicallyInvokable]
    public const long TicksPerMillisecond = 10000L;
    private const double MillisecondsPerTick = 0.0001;
    [__DynamicallyInvokable]
    public const long TicksPerSecond = 10000000L;
    private const double SecondsPerTick = 1E-07;
    [__DynamicallyInvokable]
    public const long TicksPerMinute = 600000000L;
    private const double MinutesPerTick = 1.66666666666667E-09;
    [__DynamicallyInvokable]
    public const long TicksPerHour = 36000000000L;
    private const double HoursPerTick = 2.77777777777778E-11;
    [__DynamicallyInvokable]
    public const long TicksPerDay = 864000000000L;
    private const double DaysPerTick = 1.15740740740741E-12;
    private const int MillisPerSecond = 1000;
    private const int MillisPerMinute = 60000;
    private const int MillisPerHour = 3600000;
    private const int MillisPerDay = 86400000;
    internal const long MaxSeconds = 922337203685L;
    internal const long MinSeconds = -922337203685L;
    internal const long MaxMilliSeconds = 922337203685477L;
    internal const long MinMilliSeconds = -922337203685477L;
    internal const long TicksPerTenthSecond = 1000000L;
    internal long _ticks;
    private static volatile bool _legacyConfigChecked;
    private static volatile bool _legacyMode;

    [__DynamicallyInvokable]
    public long Ticks
    {
      [__DynamicallyInvokable] get
      {
        return this._ticks;
      }
    }

    [__DynamicallyInvokable]
    public int Days
    {
      [__DynamicallyInvokable] get
      {
        return (int) (this._ticks / 864000000000L);
      }
    }

    [__DynamicallyInvokable]
    public int Hours
    {
      [__DynamicallyInvokable] get
      {
        return (int) (this._ticks / 36000000000L % 24L);
      }
    }

    [__DynamicallyInvokable]
    public int Milliseconds
    {
      [__DynamicallyInvokable] get
      {
        return (int) (this._ticks / 10000L % 1000L);
      }
    }

    [__DynamicallyInvokable]
    public int Minutes
    {
      [__DynamicallyInvokable] get
      {
        return (int) (this._ticks / 600000000L % 60L);
      }
    }

    [__DynamicallyInvokable]
    public int Seconds
    {
      [__DynamicallyInvokable] get
      {
        return (int) (this._ticks / 10000000L % 60L);
      }
    }

    [__DynamicallyInvokable]
    public double TotalDays
    {
      [__DynamicallyInvokable] get
      {
        return (double) this._ticks * (0.0 / 1.0);
      }
    }

    [__DynamicallyInvokable]
    public double TotalHours
    {
      [__DynamicallyInvokable] get
      {
        return (double) this._ticks * (0.0 / 1.0);
      }
    }

    [__DynamicallyInvokable]
    public double TotalMilliseconds
    {
      [__DynamicallyInvokable] get
      {
        double num = (double) this._ticks * 0.0001;
        if (num > 922337203685477.0)
          return 922337203685477.0;
        if (num < -922337203685477.0)
          return -922337203685477.0;
        else
          return num;
      }
    }

    [__DynamicallyInvokable]
    public double TotalMinutes
    {
      [__DynamicallyInvokable] get
      {
        return (double) this._ticks * 1.66666666666667E-09;
      }
    }

    [__DynamicallyInvokable]
    public double TotalSeconds
    {
      [__DynamicallyInvokable] get
      {
        return (double) this._ticks * 1E-07;
      }
    }

    private static bool LegacyMode
    {
      get
      {
        if (!TimeSpan._legacyConfigChecked)
        {
          TimeSpan._legacyMode = TimeSpan.GetLegacyFormatMode();
          TimeSpan._legacyConfigChecked = true;
        }
        return TimeSpan._legacyMode;
      }
    }

    static TimeSpan()
    {
    }

    [__DynamicallyInvokable]
    public TimeSpan(long ticks)
    {
      this._ticks = ticks;
    }

    [__DynamicallyInvokable]
    public TimeSpan(int hours, int minutes, int seconds)
    {
      this._ticks = TimeSpan.TimeToTicks(hours, minutes, seconds);
    }

    [__DynamicallyInvokable]
    public TimeSpan(int days, int hours, int minutes, int seconds)
    {
      this = new TimeSpan(days, hours, minutes, seconds, 0);
    }

    [__DynamicallyInvokable]
    public TimeSpan(int days, int hours, int minutes, int seconds, int milliseconds)
    {
      long num = ((long) days * 3600L * 24L + (long) hours * 3600L + (long) minutes * 60L + (long) seconds) * 1000L + (long) milliseconds;
      if (num > 922337203685477L || num < -922337203685477L)
        throw new ArgumentOutOfRangeException((string) null, Environment.GetResourceString("Overflow_TimeSpanTooLong"));
      this._ticks = num * 10000L;
    }

    [__DynamicallyInvokable]
    public static TimeSpan operator -(TimeSpan t)
    {
      if (t._ticks == TimeSpan.MinValue._ticks)
        throw new OverflowException(Environment.GetResourceString("Overflow_NegateTwosCompNum"));
      else
        return new TimeSpan(-t._ticks);
    }

    [__DynamicallyInvokable]
    public static TimeSpan operator -(TimeSpan t1, TimeSpan t2)
    {
      return t1.Subtract(t2);
    }

    [__DynamicallyInvokable]
    public static TimeSpan operator +(TimeSpan t)
    {
      return t;
    }

    [__DynamicallyInvokable]
    public static TimeSpan operator +(TimeSpan t1, TimeSpan t2)
    {
      return t1.Add(t2);
    }

    [__DynamicallyInvokable]
    public static bool operator ==(TimeSpan t1, TimeSpan t2)
    {
      return t1._ticks == t2._ticks;
    }

    [__DynamicallyInvokable]
    public static bool operator !=(TimeSpan t1, TimeSpan t2)
    {
      return t1._ticks != t2._ticks;
    }

    [__DynamicallyInvokable]
    public static bool operator <(TimeSpan t1, TimeSpan t2)
    {
      return t1._ticks < t2._ticks;
    }

    [__DynamicallyInvokable]
    public static bool operator <=(TimeSpan t1, TimeSpan t2)
    {
      return t1._ticks <= t2._ticks;
    }

    [__DynamicallyInvokable]
    public static bool operator >(TimeSpan t1, TimeSpan t2)
    {
      return t1._ticks > t2._ticks;
    }

    [__DynamicallyInvokable]
    public static bool operator >=(TimeSpan t1, TimeSpan t2)
    {
      return t1._ticks >= t2._ticks;
    }

    [__DynamicallyInvokable]
    public TimeSpan Add(TimeSpan ts)
    {
      long ticks = this._ticks + ts._ticks;
      if (this._ticks >> 63 == ts._ticks >> 63 && this._ticks >> 63 != ticks >> 63)
        throw new OverflowException(Environment.GetResourceString("Overflow_TimeSpanTooLong"));
      else
        return new TimeSpan(ticks);
    }

    [__DynamicallyInvokable]
    public static int Compare(TimeSpan t1, TimeSpan t2)
    {
      if (t1._ticks > t2._ticks)
        return 1;
      return t1._ticks < t2._ticks ? -1 : 0;
    }

    public int CompareTo(object value)
    {
      if (value == null)
        return 1;
      if (!(value is TimeSpan))
        throw new ArgumentException(Environment.GetResourceString("Arg_MustBeTimeSpan"));
      long num = ((TimeSpan) value)._ticks;
      if (this._ticks > num)
        return 1;
      return this._ticks < num ? -1 : 0;
    }

    [__DynamicallyInvokable]
    public int CompareTo(TimeSpan value)
    {
      long num = value._ticks;
      if (this._ticks > num)
        return 1;
      return this._ticks < num ? -1 : 0;
    }

    [__DynamicallyInvokable]
    public static TimeSpan FromDays(double value)
    {
      return TimeSpan.Interval(value, 86400000);
    }

    [__DynamicallyInvokable]
    public TimeSpan Duration()
    {
      if (this.Ticks == TimeSpan.MinValue.Ticks)
        throw new OverflowException(Environment.GetResourceString("Overflow_Duration"));
      else
        return new TimeSpan(this._ticks >= 0L ? this._ticks : -this._ticks);
    }

    [__DynamicallyInvokable]
    public override bool Equals(object value)
    {
      if (value is TimeSpan)
        return this._ticks == ((TimeSpan) value)._ticks;
      else
        return false;
    }

    [__DynamicallyInvokable]
    public bool Equals(TimeSpan obj)
    {
      return this._ticks == obj._ticks;
    }

    [__DynamicallyInvokable]
    public static bool Equals(TimeSpan t1, TimeSpan t2)
    {
      return t1._ticks == t2._ticks;
    }

    [__DynamicallyInvokable]
    public override int GetHashCode()
    {
      return (int) this._ticks ^ (int) (this._ticks >> 32);
    }

    [__DynamicallyInvokable]
    public static TimeSpan FromHours(double value)
    {
      return TimeSpan.Interval(value, 3600000);
    }

    private static TimeSpan Interval(double value, int scale)
    {
      if (double.IsNaN(value))
        throw new ArgumentException(Environment.GetResourceString("Arg_CannotBeNaN"));
      double num = value * (double) scale + (value >= 0.0 ? 0.5 : -0.5);
      if (num > 922337203685477.0 || num < -922337203685477.0)
        throw new OverflowException(Environment.GetResourceString("Overflow_TimeSpanTooLong"));
      else
        return new TimeSpan((long) num * 10000L);
    }

    [__DynamicallyInvokable]
    public static TimeSpan FromMilliseconds(double value)
    {
      return TimeSpan.Interval(value, 1);
    }

    [__DynamicallyInvokable]
    public static TimeSpan FromMinutes(double value)
    {
      return TimeSpan.Interval(value, 60000);
    }

    [__DynamicallyInvokable]
    public TimeSpan Negate()
    {
      if (this.Ticks == TimeSpan.MinValue.Ticks)
        throw new OverflowException(Environment.GetResourceString("Overflow_NegateTwosCompNum"));
      else
        return new TimeSpan(-this._ticks);
    }

    [__DynamicallyInvokable]
    public static TimeSpan FromSeconds(double value)
    {
      return TimeSpan.Interval(value, 1000);
    }

    [__DynamicallyInvokable]
    public TimeSpan Subtract(TimeSpan ts)
    {
      long ticks = this._ticks - ts._ticks;
      if (this._ticks >> 63 != ts._ticks >> 63 && this._ticks >> 63 != ticks >> 63)
        throw new OverflowException(Environment.GetResourceString("Overflow_TimeSpanTooLong"));
      else
        return new TimeSpan(ticks);
    }

    [__DynamicallyInvokable]
    public static TimeSpan FromTicks(long value)
    {
      return new TimeSpan(value);
    }

    internal static long TimeToTicks(int hour, int minute, int second)
    {
      long num = (long) hour * 3600L + (long) minute * 60L + (long) second;
      if (num > 922337203685L || num < -922337203685L)
        throw new ArgumentOutOfRangeException((string) null, Environment.GetResourceString("Overflow_TimeSpanTooLong"));
      else
        return num * 10000000L;
    }

    [__DynamicallyInvokable]
    public static TimeSpan Parse(string s)
    {
      return TimeSpanParse.Parse(s, (IFormatProvider) null);
    }

    [__DynamicallyInvokable]
    public static TimeSpan Parse(string input, IFormatProvider formatProvider)
    {
      return TimeSpanParse.Parse(input, formatProvider);
    }

    [__DynamicallyInvokable]
    public static TimeSpan ParseExact(string input, string format, IFormatProvider formatProvider)
    {
      return TimeSpanParse.ParseExact(input, format, formatProvider, TimeSpanStyles.None);
    }

    [__DynamicallyInvokable]
    public static TimeSpan ParseExact(string input, string[] formats, IFormatProvider formatProvider)
    {
      return TimeSpanParse.ParseExactMultiple(input, formats, formatProvider, TimeSpanStyles.None);
    }

    [__DynamicallyInvokable]
    public static TimeSpan ParseExact(string input, string format, IFormatProvider formatProvider, TimeSpanStyles styles)
    {
      TimeSpanParse.ValidateStyles(styles, "styles");
      return TimeSpanParse.ParseExact(input, format, formatProvider, styles);
    }

    [__DynamicallyInvokable]
    public static TimeSpan ParseExact(string input, string[] formats, IFormatProvider formatProvider, TimeSpanStyles styles)
    {
      TimeSpanParse.ValidateStyles(styles, "styles");
      return TimeSpanParse.ParseExactMultiple(input, formats, formatProvider, styles);
    }

    [__DynamicallyInvokable]
    public static bool TryParse(string s, out TimeSpan result)
    {
      return TimeSpanParse.TryParse(s, (IFormatProvider) null, out result);
    }

    [__DynamicallyInvokable]
    public static bool TryParse(string input, IFormatProvider formatProvider, out TimeSpan result)
    {
      return TimeSpanParse.TryParse(input, formatProvider, out result);
    }

    [__DynamicallyInvokable]
    public static bool TryParseExact(string input, string format, IFormatProvider formatProvider, out TimeSpan result)
    {
      return TimeSpanParse.TryParseExact(input, format, formatProvider, TimeSpanStyles.None, out result);
    }

    [__DynamicallyInvokable]
    public static bool TryParseExact(string input, string[] formats, IFormatProvider formatProvider, out TimeSpan result)
    {
      return TimeSpanParse.TryParseExactMultiple(input, formats, formatProvider, TimeSpanStyles.None, out result);
    }

    [__DynamicallyInvokable]
    public static bool TryParseExact(string input, string format, IFormatProvider formatProvider, TimeSpanStyles styles, out TimeSpan result)
    {
      TimeSpanParse.ValidateStyles(styles, "styles");
      return TimeSpanParse.TryParseExact(input, format, formatProvider, styles, out result);
    }

    [__DynamicallyInvokable]
    public static bool TryParseExact(string input, string[] formats, IFormatProvider formatProvider, TimeSpanStyles styles, out TimeSpan result)
    {
      TimeSpanParse.ValidateStyles(styles, "styles");
      return TimeSpanParse.TryParseExactMultiple(input, formats, formatProvider, styles, out result);
    }

    [__DynamicallyInvokable]
    public override string ToString()
    {
      return TimeSpanFormat.Format(this, (string) null, (IFormatProvider) null);
    }

    [__DynamicallyInvokable]
    public string ToString(string format)
    {
      return TimeSpanFormat.Format(this, format, (IFormatProvider) null);
    }

    [__DynamicallyInvokable]
    public string ToString(string format, IFormatProvider formatProvider)
    {
      if (TimeSpan.LegacyMode)
        return TimeSpanFormat.Format(this, (string) null, (IFormatProvider) null);
      else
        return TimeSpanFormat.Format(this, format, formatProvider);
    }

    [SecurityCritical]
    [MethodImpl(MethodImplOptions.InternalCall)]
    private static bool LegacyFormatMode();

    [SecuritySafeCritical]
    private static bool GetLegacyFormatMode()
    {
      if (TimeSpan.LegacyFormatMode())
        return true;
      else
        return CompatibilitySwitches.IsNetFx40TimeSpanLegacyFormatMode;
    }
  }
}