添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

通常,使用 DateTime DateTimeOffset 值执行日期和时间运算时,结果不会反映任何时区调整规则。 即使日期和时间值的时区明确可辨时(例如,将 Kind 属性设置为 Local 时)也是如此。 本主题介绍如何对特定时区内的日期和时间值执行算术运算。 算术运算的结果将反映时区调整规则。

将调整规则应用到日期和时间运算

  • 采取措施将日期和时间值与其所属时区紧密耦合。 例如声明同时包含日期和时间值及其时区的结构。 下方示例使用此方法链接 DateTime 值与其时区。

    // Define a structure for DateTime values for internal use only
    internal struct TimeWithTimeZone
       TimeZoneInfo TimeZone;
       DateTime Time;
    
    ' Define a structure for DateTime values for internal use only
    Friend Structure TimeWithTimeZone
        Dim TimeZone As TimeZoneInfo
        Dim Time As Date
    End Structure
    
  • 调用 ConvertTimeToUtc 方法或 ConvertTime 方法,将时间转换为协调世界时 (UTC)。

  • 对 UTC 时间执行算术运算。

  • 调用 TimeZoneInfo.ConvertTime(DateTime, TimeZoneInfo) 方法,将时间从 UTC 转换到与原始时间相关联的时区。

    下方示例向中部标准时间 2008 年 3 月 9 日凌晨 1:30 增加了 2 小时 30 分钟。 30 分钟后(即 2008 年 3 月 9 日凌晨 2:00)会发生到夏时令的时区转换。 由于该示例遵从了上一部分中列出的四个步骤,因此它将最终时间正确地报告为 2008 年 3 月 9 日凌晨 5:00。

    using System;
    public struct TimeZoneTime
       public TimeZoneInfo TimeZone;
       public DateTime Time;
       public TimeZoneTime(TimeZoneInfo tz, DateTime time)
          if (tz == null)
             throw new ArgumentNullException("The time zone cannot be a null reference.");
          this.TimeZone = tz;
          this.Time = time;
       public TimeZoneTime AddTime(TimeSpan interval)
          // Convert time to UTC
          DateTime utcTime = TimeZoneInfo.ConvertTimeToUtc(this.Time, this.TimeZone);
          // Add time interval to time
          utcTime = utcTime.Add(interval);
          // Convert time back to time in time zone
          return new TimeZoneTime(this.TimeZone, TimeZoneInfo.ConvertTime(utcTime,
                                  TimeZoneInfo.Utc, this.TimeZone));
    public class TimeArithmetic
       public const string tzName = "Central Standard Time";
       public static void Main()
             TimeZoneTime cstTime1, cstTime2;
             TimeZoneInfo cst = TimeZoneInfo.FindSystemTimeZoneById(tzName);
             DateTime time1 = new DateTime(2008, 3, 9, 1, 30, 0);
             TimeSpan twoAndAHalfHours = new TimeSpan(2, 30, 0);
             cstTime1 = new TimeZoneTime(cst, time1);
             cstTime2 = cstTime1.AddTime(twoAndAHalfHours);
             Console.WriteLine("{0} + {1} hours = {2}", cstTime1.Time,
                                                        twoAndAHalfHours.ToString(),
                                                        cstTime2.Time);
          catch
             Console.WriteLine("Unable to find {0}.", tzName);
    
    Public Structure TimeZoneTime
        Public TimeZone As TimeZoneInfo
        Public Time As Date
        Public Sub New(tz As TimeZoneInfo, time As Date)
            If tz Is Nothing Then _
               Throw New ArgumentNullException("The time zone cannot be a null reference.")
            Me.TimeZone = tz
            Me.Time = time
        End Sub
        Public Function AddTime(interval As TimeSpan) As TimeZoneTime
            ' Convert time to UTC
            Dim utcTime As DateTime = TimeZoneInfo.ConvertTimeToUtc(Me.Time, _
                                                                    Me.TimeZone)
            ' Add time interval to time
            utcTime = utcTime.Add(interval)
            ' Convert time back to time in time zone
            Return New TimeZoneTime(Me.TimeZone, TimeZoneInfo.ConvertTime(utcTime, _
                                    TimeZoneInfo.Utc, Me.TimeZone))
        End Function
    End Structure
    Module TimeArithmetic
        Public Const tzName As String = "Central Standard Time"
        Public Sub Main()
                Dim cstTime1, cstTime2 As TimeZoneTime
                Dim cst As TimeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById(tzName)
                Dim time1 As Date = #03/09/2008 1:30AM#
                Dim twoAndAHalfHours As New TimeSpan(2, 30, 0)
                cstTime1 = New TimeZoneTime(cst, time1)
                cstTime2 = cstTime1.AddTime(twoAndAHalfHours)
                Console.WriteLine("{0} + {1} hours = {2}", cstTime1.Time, _
                                                           twoAndAHalfHours.ToString(), _
                                                           cstTime2.Time)
            Catch
                Console.WriteLine("Unable to find {0}.", tzName)
            End Try
        End Sub
    End Module
    

    DateTimeDateTimeOffset 值都将与其所属的任何时区解除关联。 只有能够立即识别任意日期和时间所属的时区,才能在执行日期和时间运算时自动应用时区调整规则。 这意味着,日期和时间及其关联时区必须紧密耦合。 可通过方法进行此操作,其中包括:

  • 假设应用程序中使用的所有时间均属于某个特定时区。 尽管在某些情况下适用,但此方法的灵活性和可移植性有限。

  • 在类型字段中包括日期和时间及其关联时区,定义将二者紧密耦合的类型。 代码示例中使用了此方法,定义了将日期和时间以及时区存储在两个成员字段中的结构。

    该示例演示如何对 DateTime 值执行算术运算,以便将时区调整规则应用于结果。 但是,可以轻松地使用 DateTimeOffset 值。 下面的示例演示如何调整原始示例中的代码,以使用 DateTimeOffset 值(而不是 DateTime 值)。

    using System;
    public struct TimeZoneTime
       public TimeZoneInfo TimeZone;
       public DateTimeOffset Time;
       public TimeZoneTime(TimeZoneInfo tz, DateTimeOffset time)
          if (tz == null)
             throw new ArgumentNullException("The time zone cannot be a null reference.");
          this.TimeZone = tz;
          this.Time = time;
       public TimeZoneTime AddTime(TimeSpan interval)
          // Convert time to UTC
          DateTimeOffset utcTime = TimeZoneInfo.ConvertTime(this.Time, TimeZoneInfo.Utc);
          // Add time interval to time
          utcTime = utcTime.Add(interval);
          // Convert time back to time in time zone
          return new TimeZoneTime(this.TimeZone, TimeZoneInfo.ConvertTime(utcTime, this.TimeZone));
    public class TimeArithmetic
       public const string tzName = "Central Standard Time";
       public static void Main()
             TimeZoneTime cstTime1, cstTime2;
             TimeZoneInfo cst = TimeZoneInfo.FindSystemTimeZoneById(tzName);
             DateTime time1 = new DateTime(2008, 3, 9, 1, 30, 0);
             TimeSpan twoAndAHalfHours = new TimeSpan(2, 30, 0);
             cstTime1 = new TimeZoneTime(cst,
                            new DateTimeOffset(time1, cst.GetUtcOffset(time1)));
             cstTime2 = cstTime1.AddTime(twoAndAHalfHours);
             Console.WriteLine("{0} + {1} hours = {2}", cstTime1.Time,
                                                        twoAndAHalfHours.ToString(),
                                                        cstTime2.Time);
          catch
             Console.WriteLine("Unable to find {0}.", tzName);
    
    Public Structure TimeZoneTime
        Public TimeZone As TimeZoneInfo
        Public Time As DateTimeOffset
        Public Sub New(tz As TimeZoneInfo, time As DateTimeOffset)
            If tz Is Nothing Then _
               Throw New ArgumentNullException("The time zone cannot be a null reference.")
            Me.TimeZone = tz
            Me.Time = time
        End Sub
        Public Function AddTime(interval As TimeSpan) As TimeZoneTime
            ' Convert time to UTC
            Dim utcTime As DateTimeOffset = TimeZoneInfo.ConvertTime(Me.Time, TimeZoneInfo.Utc)
            ' Add time interval to time
            utcTime = utcTime.Add(interval)
            ' Convert time back to time in time zone
            Return New TimeZoneTime(Me.TimeZone, TimeZoneInfo.ConvertTime(utcTime, Me.TimeZone))
        End Function
    End Structure
    Module TimeArithmetic
        Public Const tzName As String = "Central Standard Time"
        Public Sub Main()
                Dim cstTime1, cstTime2 As TimeZoneTime
                Dim cst As TimeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById(tzName)
                Dim time1 As Date = #03/09/2008 1:30AM#
                Dim twoAndAHalfHours As New TimeSpan(2, 30, 0)
                cstTime1 = New TimeZoneTime(cst, _
                               New DateTimeOffset(time1, cst.GetUtcOffset(time1)))
                cstTime2 = cstTime1.AddTime(twoAndAHalfHours)
                Console.WriteLine("{0} + {1} hours = {2}", cstTime1.Time, _
                                                           twoAndAHalfHours.ToString(), _
                                                           cstTime2.Time)
            Catch
                Console.WriteLine("Unable to find {0}.", tzName)
            End Try
        End Sub
    End Module
    

    请注意,如果未先将 DateTimeOffset 值转换为 UTC 就进行相加,那么结果将反映正确的时间点,但其时差无法反映指定时区在当时的时差。

    此示例需要:

  • 使用 using 语句导入的 System 命名空间(在 C# 代码中是必需的)。
  • 日期、时间和时区
  • 使用日期和时间执行算术运算
  • 即将推出:在整个 2024 年,我们将逐步取消以“GitHub 问题”作为内容的反馈机制,并将其替换为新的反馈系统。 有关详细信息,请参阅:https://aka.ms/ContentUserFeedback

    提交和查看相关反馈

  •