DateTime与DateTimeOffset

2018/05/09 320

DateTime

DateTime值定义特定日期和时间。它包括Kind属性,可提供有关时区的信息的日期和时间所属有限。

DateTimeKind返回值Kind属性指示是否DateTime值表示

  1. 本地时间DateTimeKind.Local
  2. 世界时UTC(DateTimeKind.Utc)
  3. 未指定DateTimeKind.Unspecified

DateTime结构适用于以下场景

  1. 仅使用日期
  2. 仅使用时间
  3. 使用抽象的日期和时间
  4. 不需要时区信息的日期和时间
  5. 只使用UTC日期和时间
  6. 从外部.Net中,如SQL Server中检索日期和时间信息。通常,这些源按DateTime结构兼容的简单格式存储日期和时间信息
  7. 执行日期和时间算法,但不关注常规结果。 例如,在向特定日期和时间添加六个月的加法运算中,是否将结果调整为夏令时通常并不重要。

除非特定的 DateTime 值表示 UTC,否则日期和时间值通常不明确的或其可移植性受限。 例如,如果 DateTime 值表示本地时间,则在该本地时区内可移植(即,如果在其他系统的相同时区上反序列化此值,它仍然明确标识单个时间点)。 在本地时区之外, DateTime 值可以具有多个解释。 如果值的 Kind 属性是 DateTimeKind.Unspecified,则它的可移植性更低:此时它在相同时区内(可能甚至在首次序列化的同一系统上)是不明确的。 仅当 DateTime 值表示 UTC 时,无论使用此值的系统和时区如何,它都会明确标识单个时间点。

在保存或共享 DateTime 数据时,应使用 UTC 并将 DateTime 值的 Kind 属性设置为 DateTimeKind.Utc。

DateTimeOffset

DateTimeOffset 结构表示日期和时间值,以及指示此值与 UTC 的差异程度的偏移量。 因此,此值始终明确地标识单个时间点。

DateTimeOffset 类型包括 DateTime 类型的所有功能以及时区感知功能。 这使其适用于应用程序执行以下操作:

  1. 唯一、明确地标识单个时间点。 DateTimeOffset 类型可用于明确定义“现在”的含义、记录事务时间、记录系统或应用程序事件时间以及记录创建和修改时间。
  2. 执行常规日期和时间算法。
  3. 保留多个相关时间,只要这些时间存储为两个单独的值或结构中的两个成员。

DateTimeOffset 值的使用频率比 DateTime 值的更高。 因此,在应用程序开发中应考虑使用 DateTimeOffset 作为默认日期和时间类型。

代码示例

DateTimeOffset 值不限于特定时区,而可以来自各个时区。 为了说明这一点,以下示例列出了 DateTimeOffset 值(包括本地太平洋标准时间)可属于的时区。

using System;
using System.Collections.ObjectModel;

public class TimeOffsets
{
   public static void Main()
   {
      DateTime thisDate = new DateTime(2007, 3, 10, 0, 0, 0);
      DateTime dstDate = new DateTime(2007, 6, 10, 0, 0, 0);
      DateTimeOffset thisTime;
      
      thisTime = new DateTimeOffset(dstDate, new TimeSpan(-7, 0, 0));
      ShowPossibleTimeZones(thisTime);

      thisTime = new DateTimeOffset(thisDate, new TimeSpan(-6, 0, 0));  
      ShowPossibleTimeZones(thisTime);

      thisTime = new DateTimeOffset(thisDate, new TimeSpan(+1, 0, 0));
      ShowPossibleTimeZones(thisTime);
   }

   private static void ShowPossibleTimeZones(DateTimeOffset offsetTime)
   {
      TimeSpan offset = offsetTime.Offset;
      ReadOnlyCollection<TimeZoneInfo> timeZones;
            
      Console.WriteLine("{0} could belong to the following time zones:", 
                        offsetTime.ToString());
      // Get all time zones defined on local system
      timeZones = TimeZoneInfo.GetSystemTimeZones();     
      // Iterate time zones 
      foreach (TimeZoneInfo timeZone in timeZones)
      {
         // Compare offset with offset for that date in that time zone
         if (timeZone.GetUtcOffset(offsetTime.DateTime).Equals(offset))
            Console.WriteLine("   {0}", timeZone.DisplayName);
      }
      Console.WriteLine();
   } 
}
// This example displays the following output to the console:
//       6/10/2007 12:00:00 AM -07:00 could belong to the following time zones:
//          (GMT-07:00) Arizona
//          (GMT-08:00) Pacific Time (US & Canada)
//          (GMT-08:00) Tijuana, Baja California
//       
//       3/10/2007 12:00:00 AM -06:00 could belong to the following time zones:
//          (GMT-06:00) Central America
//          (GMT-06:00) Central Time (US & Canada)
//          (GMT-06:00) Guadalajara, Mexico City, Monterrey - New
//          (GMT-06:00) Guadalajara, Mexico City, Monterrey - Old
//          (GMT-06:00) Saskatchewan
//       
//       3/10/2007 12:00:00 AM +01:00 could belong to the following time zones:
//          (GMT+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna
//          (GMT+01:00) Belgrade, Bratislava, Budapest, Ljubljana, Prague
//          (GMT+01:00) Brussels, Copenhagen, Madrid, Paris
//          (GMT+01:00) Sarajevo, Skopje, Warsaw, Zagreb
//          (GMT+01:00) West Central Africa

输出显示,此示例中的每个日期和时间值至少可以属于三个不同时区。 2007 年 6 月 10 日的 DateTimeOffset 值显示,如果日期和时间值表示夏令时,则其相对于 UTC 的偏移量甚至不一定对应于原始时区的基本 UTC 偏移量或其显示名称中找到的相对于 UTC 的偏移量。 这意味着,因为单个 DateTimeOffset 值与其时区并非紧密耦合的,因此它无法反映到/从夏令时的时区转换。 这在使用日期和时间运算操纵 DateTimeOffset 值时特别容易出现问题。 (有关如何以考虑时区调整规则的方式执行日期和时间运算的讨论,请参阅 Performing arithmetic operations with dates and times。)

来自官方文档

评论