使用日期和时间执行算术运算Performing arithmetic operations with dates and times

尽管同时DateTimeDateTimeOffset结构都可提供对它们的值执行算术运算的成员、 算术运算的结果有很大差异。Although both the DateTime and the DateTimeOffset structures provide members that perform arithmetic operations on their values, the results of arithmetic operations are very different. 本主题介绍这些差异、 联系起来的日期和时间数据中的时区感知度和讨论如何执行完全时区感知运算使用日期和时间数据。This topic examines those differences, relates them to degrees of time zone awareness in date and time data, and discusses how to perform fully time zone aware operations using date and time data.

比较和算术运算的日期时间值Comparisons and arithmetic operations with DateTime values

DateTime.Kind属性允许DateTimeKind要分配给以指示它是否表示本地时间、 协调世界时 (UTC) 还是未指定时区的时间的日期和时间值。The DateTime.Kind property allows a DateTimeKind value to be assigned to the date and time to indicate whether it represents local time, Coordinated Universal Time (UTC), or the time in an unspecified time zone. 此有限的时区信息时进行比较或执行日期和时间算术运算,但是,将忽略DateTimeKind值。However, this limited time zone information is ignored when comparing or performing date and time arithmetic on DateTimeKind values. 以下示例通过比较当前本地时间与当前 UTC 时间,对此进行了阐释。The following example, which compares the current local time with the current UTC time, illustrates this.

using System;

public enum TimeComparison
{
   EarlierThan = -1,
   TheSameAs = 0,
   LaterThan = 1
}

public class DateManipulation
{
   public static void Main()
   {
      DateTime localTime = DateTime.Now;
      DateTime utcTime = DateTime.UtcNow;
      
      Console.WriteLine("Difference between {0} and {1} time: {2}:{3} hours", 
                        localTime.Kind.ToString(), 
                        utcTime.Kind.ToString(), 
                        (localTime - utcTime).Hours, 
                        (localTime - utcTime).Minutes);
      Console.WriteLine("The {0} time is {1} the {2} time.", 
                        localTime.Kind.ToString(), 
                        Enum.GetName(typeof(TimeComparison), localTime.CompareTo(utcTime)), 
                        utcTime.Kind.ToString());  
   }
}
// If run in the U.S. Pacific Standard Time zone, the example displays 
// the following output to the console:
//    Difference between Local and Utc time: -7:0 hours
//    The Local time is EarlierThan the Utc time.                                                    
Public Enum TimeComparison As Integer
   EarlierThan = -1
   TheSameAs = 0
   LaterThan = 1
End Enum

Module DateManipulation
   Public Sub Main()
      Dim localTime As Date = Date.Now
      Dim utcTime As Date = Date.UtcNow
      
      Console.WriteLine("Difference between {0} and {1} time: {2}:{3} hours", _
                        localTime.Kind.ToString(), _
                        utcTime.Kind.ToString(), _
                        (localTime - utcTime).Hours, _
                        (localTime - utcTime).Minutes)
      Console.WriteLine("The {0} time is {1} the {2} time.", _
                        localTime.Kind.ToString(), _ 
                        [Enum].GetName(GetType(TimeComparison), localTime.CompareTo(utcTime)), _
                        utcTime.Kind.ToString())  
      ' If run in the U.S. Pacific Standard Time zone, the example displays 
      ' the following output to the console:
      '    Difference between Local and Utc time: -7:0 hours
      '    The Local time is EarlierThan the Utc time.                                                    
   End Sub
End Module

CompareTo(DateTime)方法报告本地时间早于 (或小于) UTC 时间,并且减法运算指示,美国的 UTC 和本地系统之间的差异其 UTC 时间与本地时间之间的时差是 7 小时。The CompareTo(DateTime) method reports that the local time is earlier than (or less than) the UTC time, and the subtraction operation indicates that the difference between UTC and the local time for a system in the U.S. Pacific Standard Time zone is seven hours. 但由于这两个值提供的单个时间点的表现形式有所不同,因此从本例中可清楚得知,此时间间隔完全是由本地时区与 UTC 之间的时差所致。But because these two values provide different representations of a single point in time, it is clear in this case that this time interval is completely attributable to the local time zone's offset from UTC.

一般来说,DateTime.Kind属性不会影响返回的结果Kind比较和算术方法 (如指示比较两个相同时间点),尽管它可能会影响这些结果的解释。More generally, the DateTime.Kind property does not affect the results returned by Kind comparison and arithmetic methods (as the comparison of two identical points in time indicates), although it can affect the interpretation of those results. 例如:For example:

  • 对两个日期和时间值的任何算术运算的结果执行其DateTime.Kind属性均等于DateTimeKind反映了两个值之间的实际时间间隔。The result of any arithmetic operation performed on two date and time values whose DateTime.Kind properties both equal DateTimeKind reflects the actual time interval between the two values. 同样,对两个日期和时间值进行比较可精确反映出时间之间的关系。Similarly, the comparison of two such date and time values accurately reflects the relationship between times.

  • 对两个日期和时间值的任何算术或比较运算的结果执行其DateTime.Kind属性均等于DateTimeKind或使用不同的两个日期和时间值DateTime.Kind属性值反映的时钟时间差异之间的两个值。The result of any arithmetic or comparison operation performed on two date and time values whose DateTime.Kind properties both equal DateTimeKind or on two date and time values with different DateTime.Kind property values reflects the difference in clock time between the two values.

  • 对本地日期和时间值执行的算术或比较运算不考虑某个特定值是否不明确或无效,也不考虑任何调整规则(因本地时区与夏令时的来回转换)的影响。Arithmetic or comparison operations on local date and time values do not consider whether a particular value is ambiguous or invalid, nor do they take account of the effect of any adjustment rules that result from the local time zone's transition to or from daylight saving time.

  • 任何比较或计算 UTC 与本地时间之差的运算所得出的结果中都包含一个时间间隔,它等于本地时区与 UTC 之间的时差。Any operation that compares or calculates the difference between UTC and a local time includes a time interval equal to the local time zone's offset from UTC in the result.

  • 任何比较或计算未指定时间与 UTC 或本地时间的运算都反映简单的时钟时间。Any operation that compares or calculates the difference between an unspecified time and either UTC or the local time reflects simple clock time. 时区差异未纳入考虑范围,且结果不会反映是否应用了时区调整规则。Time zone differences are not considered, and the result does not reflect the application of time zone adjustment rules.

  • 任何比较或计算两个未指定时间之差的运算都可能包含一个未知间隔,它反映两个不同时区内的时间之差。Any operation that compares or calculates the difference between two unspecified times may include an unknown interval that reflects the difference between the time in two different time zones.

许多情况下,时区差异不会影响日期和时间计算 (的其中一些讨论,请参阅DateTime、 DateTimeOffset、 TimeSpan 和 TimeZoneInfo 之间进行选择) 或在其中上下文日期和时间数据定义比较或算术运算的含义。There are many scenarios in which time zone differences do not affect date and time calculations (for a discussion of some of these, see Choosing between DateTime, DateTimeOffset, TimeSpan, and TimeZoneInfo) or in which the context of the date and time data defines the meaning of comparison or arithmetic operations.

比较和 DateTimeOffset 值的算术运算Comparisons and arithmetic operations with DateTimeOffset values

一个DateTimeOffset值不仅包含日期和时间,而且还明确定义的日期和时间相对于 UTC 的偏移量。A DateTimeOffset value includes not only a date and time, but also an offset that unambiguously defines that date and time relative to UTC. 这样可以定义的方式稍有不同的相等性DateTimeOffset值。This makes it possible to define equality somewhat differently than for DateTimeOffset values. DateTime值是否相等,如果它们具有相同的日期和时间值DateTimeOffset值是否相等,如果它们都表示相同的点的时间。Whereas DateTime values are equal if they have the same date and time value, DateTimeOffset values are equal if they both refer to the same point in time. 这使得DateTimeOffset更准确、 更不需要解释时用于比较和大多数算术运算,确定两个日期和时间之间的间隔中的值。This makes a DateTimeOffset value more accurate and less in need of interpretation when used in comparisons and in most arithmetic operations that determine the interval between two dates and times. 以下示例中,即DateTimeOffset等效于上一示例中比较本地和 UTCDateTimeOffset值,说明了这种行为的差异。The following example, which is the DateTimeOffset equivalent to the previous example that compared local and UTC DateTimeOffset values, illustrates this difference in behavior.

using System;

public enum TimeComparison
{
   EarlierThan = -1,
   TheSameAs = 0,
   LaterThan = 1
}

public class DateTimeOffsetManipulation
{
   public static void Main()
   {
      DateTimeOffset localTime = DateTimeOffset.Now;
      DateTimeOffset utcTime = DateTimeOffset.UtcNow;
      
      Console.WriteLine("Difference between local time and UTC: {0}:{1:D2} hours", 
                        (localTime - utcTime).Hours, 
                        (localTime - utcTime).Minutes);
      Console.WriteLine("The local time is {0} UTC.", 
                        Enum.GetName(typeof(TimeComparison), localTime.CompareTo(utcTime)));  
   }
}
// Regardless of the local time zone, the example displays 
// the following output to the console:
//    Difference between local time and UTC: 0:00 hours.
//    The local time is TheSameAs UTC.
Public Enum TimeComparison As Integer
   EarlierThan = -1
   TheSameAs = 0
   LaterThan = 1
End Enum

Module DateTimeOffsetManipulation
   Public Sub Main()
      Dim localTime As DateTimeOffset = DateTimeOffset.Now
      Dim utcTime As DateTimeOffset = DateTimeOffset.UtcNow
      
      Console.WriteLine("Difference between local time and UTC: {0}:{1:D2} hours.", _
                        (localTime - utcTime).Hours, _
                        (localTime - utcTime).Minutes)
      Console.WriteLine("The local time is {0} UTC.", _
                        [Enum].GetName(GetType(TimeComparison), localTime.CompareTo(utcTime)))  
   End Sub
End Module
' Regardless of the local time zone, the example displays 
' the following output to the console:
'    Difference between local time and UTC: 0:00 hours.
'    The local time is TheSameAs UTC.
'          Console.WriteLine(e.GetType().Name)

在此示例中,CompareTo方法,指示当前的本地时间到当前的 UTC 时间相等和相减CompareTo(DateTimeOffset)值,该值指示两个时间之间的区别是TimeSpan.ZeroIn this example, the CompareTo method indicates that the current local time and the current UTC time are equal, and subtraction of CompareTo(DateTimeOffset) values indicates that the difference between the two times is TimeSpan.Zero.

使用的主要限制DateTimeOffset日期和时间算术中的值在于,虽然DateTimeOffset值有一些时区感知功能,它们并不能完全感知时区。The chief limitation of using DateTimeOffset values in date and time arithmetic is that although DateTimeOffset values have some time zone awareness, they are not fully time zone aware. 尽管DateTimeOffset值的偏移量能反映时区与 UTC 的偏移量时DateTimeOffset变量首先分配一个值,它将成为此后与其时区。Although the DateTimeOffset value's offset reflects a time zone's offset from UTC when a DateTimeOffset variable is first assigned a value, it becomes disassociated from the time zone thereafter. 由于不再直接与可识别时间关联,日期和时间间隔的相加和相减将不会考虑时区调整规则。Because it is no longer directly associated with an identifiable time, the addition and subtraction of date and time intervals does not consider a time zone's adjustment rules.

举例说明,美国中部标准时区的夏令时转换发生于 To illustrate, the transition to daylight saving time in the U.S. Central Standard Time zone occurs at 2:00 A.M. 2008 年 3 月 9 日凌晨 2:00。on March 9, 2008. 这意味着,向中部标准时间 2008 年 3 月 9 日凌晨 1:30 增加两个半小时的间隔,This means that adding a two and a half hour interval to a Central Standard time of 1:30 A.M. 得出的日期和时间应为 on March 9, 2008, should produce a date and time of 5:00 A.M. 2008 年 3 月 9 日凌晨 5:00。on March 9, 2008. 但是,如下面的示例所示,加法运算得出的结果却是 However, as the following example shows, the result of the addition is 4:00 A.M. 2008 年 3 月 9 日凌晨 4:00。on March 9, 2008. 请注意,此运算结果并不表示正确的时间点,它也不是我们所关注的时区的时间(也就是说,运算未得出预期的时区时差)。Note that this result of this operation does represent the correct point in time, although it is not the time in the time zone in which we are interested (that is, it does not have the expected time zone offset).

using System;

public class IntervalArithmetic
{
   public static void Main()
   {
      DateTime generalTime = new DateTime(2008, 3, 9, 1, 30, 0);
      const string tzName = "Central Standard Time";
      TimeSpan twoAndAHalfHours = new TimeSpan(2, 30, 0);

      // Instantiate DateTimeOffset value to have correct CST offset
      try
      {
         DateTimeOffset centralTime1 = new DateTimeOffset(generalTime, 
                    TimeZoneInfo.FindSystemTimeZoneById(tzName).GetUtcOffset(generalTime));
      
         // Add two and a half hours      
         DateTimeOffset centralTime2 = centralTime1.Add(twoAndAHalfHours);
         // Display result
         Console.WriteLine("{0} + {1} hours = {2}", centralTime1, 
                                                    twoAndAHalfHours.ToString(), 
                                                    centralTime2);  
      }
      catch (TimeZoneNotFoundException)
      {
         Console.WriteLine("Unable to retrieve Central Standard Time zone information.");
      }
   }
}
// The example displays the following output to the console:
//    3/9/2008 1:30:00 AM -06:00 + 02:30:00 hours = 3/9/2008 4:00:00 AM -06:00
Module IntervalArithmetic
   Public Sub Main()
      Dim generalTime As Date = #03/09/2008 1:30AM#
      Const tzName As String = "Central Standard Time"
      Dim twoAndAHalfHours As New TimeSpan(2, 30, 0)

      ' Instantiate DateTimeOffset value to have correct CST offset
      Try
         Dim centralTime1 As New DateTimeOffset(generalTime, _
                    TimeZoneInfo.FindSystemTimeZoneById(tzName).GetUtcOffset(generalTime))
      
         ' Add two and a half hours      
         Dim centralTime2 As DateTimeOffset = centralTime1.Add(twoAndAHalfHours)
         ' Display result
         Console.WriteLine("{0} + {1} hours = {2}", centralTime1, _
                                                    twoAndAHalfHours.ToString(), _
                                                    centralTime2)   
      Catch e As TimeZoneNotFoundException
         Console.WriteLine("Unable to retrieve Central Standard Time zone information.")
      End Try
   End Sub
End Module
' The example displays the following output to the console:
'    3/9/2008 1:30:00 AM -06:00 + 02:30:00 hours = 3/9/2008 4:00:00 AM -06:00

与时区内时间的算术运算Arithmetic operations with times in time zones

TimeZoneInfo类包括许多时它们将时间从一个时区转换到另一个自动应用调整的转换方法。The TimeZoneInfo class includes a number of conversion methods that automatically apply adjustments when they convert times from one time zone to another. 其中包括:These include the following:

有关详细信息,请参阅各时区之间转换时间For details, see Converting times between time zones.

ConvertTimeToUtc(DateTime)类不提供任何执行日期和时间运算时自动应用调整规则的方法。The ConvertTimeToUtc(DateTime) class does not provide any methods that automatically apply adjustment rules when you perform date and time arithmetic. 但是可以通过将某一时区内的时间转换为 UTC,执行算术运算,然后再将 UTC 转换回该时区内的时间,来实现此目的。However, you can do this by converting the time in a time zone to UTC, performing the arithmetic operation, and then converting from UTC back to the time in the time zone. 有关详细信息,请参阅如何:在日期和时间算术中使用时区For details, see How to: Use time zones in date and time arithmetic.

例如,以下代码类似于之前向 2008 年 3 月 9 日凌晨 2:00 增加For example, the following code is similar to the previous code that added two-and-a-half hours to 2:00 A.M. 两个半小时的代码。on March 9, 2008. 但是,由于其在执行日期和时间算术前将中部标准时间转换为 UTC,然后将 UTC 结果转换回中部标准时间,所以得出的时间反映的是中部标准时区转换为夏令时。However, because it converts a Central Standard time to UTC before it performs date and time arithmetic, and then converts the result from UTC back to Central Standard time, the resulting time reflects the Central Standard Time Zone's transition to daylight saving time.

using System;

public class TimeZoneAwareArithmetic
{
   public static void Main()
   {
      const string tzName = "Central Standard Time";
      
      DateTime generalTime = new DateTime(2008, 3, 9, 1, 30, 0);
      TimeZoneInfo cst = TimeZoneInfo.FindSystemTimeZoneById(tzName);
      TimeSpan twoAndAHalfHours = new TimeSpan(2, 30, 0);

      // Instantiate DateTimeOffset value to have correct CST offset
      try
      {
         DateTimeOffset centralTime1 = new DateTimeOffset(generalTime, 
                                       cst.GetUtcOffset(generalTime));
      
         // Add two and a half hours
         DateTimeOffset utcTime = centralTime1.ToUniversalTime();
         utcTime += twoAndAHalfHours;
               
         DateTimeOffset centralTime2 = TimeZoneInfo.ConvertTime(utcTime, cst);
         // Display result
         Console.WriteLine("{0} + {1} hours = {2}", centralTime1, 
                                                    twoAndAHalfHours.ToString(), 
                                                    centralTime2);  
      }
      catch (TimeZoneNotFoundException)
      {
         Console.WriteLine("Unable to retrieve Central Standard Time zone information.");
      }
   }
}
// The example displays the following output to the console:
//    3/9/2008 1:30:00 AM -06:00 + 02:30:00 hours = 3/9/2008 5:00:00 AM -05:00
Module TimeZoneAwareArithmetic
   Public Sub Main()
      Const tzName As String = "Central Standard Time"
      
      Dim generalTime As Date = #03/09/2008 1:30AM#
      Dim cst As TimeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById(tzName) 
      Dim twoAndAHalfHours As New TimeSpan(2, 30, 0)

      ' Instantiate DateTimeOffset value to have correct CST offset
      Try
         Dim centralTime1 As New DateTimeOffset(generalTime, _
                    cst.GetUtcOffset(generalTime))
      
         ' Add two and a half hours 
         Dim utcTime As DateTimeOffset = centralTime1.ToUniversalTime()
         utcTime += twoAndAHalfHours
         
         Dim centralTime2 As DateTimeOffset = TimeZoneInfo.ConvertTime(utcTime, cst)
         ' Display result
         Console.WriteLine("{0} + {1} hours = {2}", centralTime1, _
                                                    twoAndAHalfHours.ToString(), _
                                                    centralTime2)   
      Catch e As TimeZoneNotFoundException
         Console.WriteLine("Unable to retrieve Central Standard Time zone information.")
      End Try
   End Sub
End Module
' The example displays the following output to the console:
'    3/9/2008 1:30:00 AM -06:00 + 02:30:00 hours = 3/9/2008 5:00:00 AM -05:00

请参阅See also