Поделиться через


Выбор между типами DateTime, DateTimeOffset и TimeZoneInfo

Обновлен: Ноябрь 2007

Приложения платформы .NET Framework, использующие сведения о дате и времени, являются очень разнообразными и могут использовать эти сведения несколькими способами. Стандартные способы использование сведений о дате и времени включают одно или несколько из следующего:

  • Отображение только даты, сведения о времени не имеют значения.

  • Отображение только времени, сведения о дате не имеют значения.

  • Отображение абстрактной даты и времени, не привязанных к определенному времени и месту (например, большинство магазинов международных сетей открываются по рабочим дням в 9:00 часов утра).

  • Извлечение сведений о дате и времени из источников вне платформы .NET Framework, в которых сведения о дате и времени обычно хранятся в простом типе данных.

  • Для однозначной идентификации конкретного момента времени. Некоторым приложениям требуется, чтобы дата и время были однозначными только в локальной системе; другим требуется, чтобы оно было однозначным в разных системах (т.е. сериализованная дата на одном компьютере может быть десериализована и использована на другом компьютере в любой точке мира).

  • Сохранение нескольких связанных времен (таких как локальное время того, кто делает запрос, и серверное время получения веб-запроса).

  • Выполнение арифметических действий с датой и временем, возможно, с результатом, который однозначно определяет момент времени.

Платформа .NET Framework включает в себя типы DateTime, DateTimeOffset и TimeZoneInfo, каждый из которых может использоваться для построения приложений, работающих с датой и временем.

Bb384267.alert_note(ru-ru,VS.90).gifПримечание.

В этом разделе не рассматривается четвертый тип — TimeZone, поскольку его возможности практически полностью включены в класс TimeZoneInfo. Везде, где это возможно, разработчикам следует использовать класс TimeZoneInfo вместо класса TimeZone.

Структура DateTime

Значение DateTime определяет конкретные дату и время. Начиная с версии 2.0, платформа .NET Framework включает в себя свойство Kind, которое предоставляет ограниченные сведения о часовом поясе, которому принадлежат дата и время. Значение DateTimeKind, возвращенное свойством Kind указывает, представляет ли значение DateTime локальное время (DateTimeKind.Local), время в формате UTC (DateTimeKind.Utc) или неопределенное время (DateTimeKind.Unspecified).

Структура DateTime подходит для приложений, которые:

  • Работают только с датами.

  • Работают только со временем.

  • Работают с абстрактными датами и временем.

  • Получают сведения о дате и времени из источников вне платформы .NET Framework, таких как базы данных SQL. Как правило, эти источники хранят сведения о дате и времени в простом формате, который совместим со структурой DateTime.

  • Выполняют арифметические действия с датами и временем, но связаны с основными результатами. Например, в операции сложения, которая добавляет шесть месяцев к конкретной дате и времени, часто не важно, учитывается ли в результате переход на летнее время.

Кроме случая, когда определенное значение DateTime представляет время в формате UTC, значение даты и времени часто является неоднозначным или ограниченным при переносе. Например, если значение DateTime представляет локальное время, то оно является переносимым внутри этого часового пояса (то есть, если значение десериализуется в другой системе с тем же часовым поясом, то это значение по-прежнему однозначно определяет единственный момент времени). Но вне в местного часового пояса, значение DateTime может иметь несколько интерпретаций. Если свойство значения Kind равно DateTimeKind.Unspecified, то оно является еще менее переносимым: оно неоднозначно даже в том же часовом поясе и, возможно, даже на том же компьютере, на котором оно было изначально сериализовано. Только если значение DateTime представляет время в формате UTC, можно гарантировать, что значение однозначно идентифицирует единственный момент времени независимо от времени системы или часового пояса, в котором используется значение.

Bb384267.alert_caution(ru-ru,VS.90).gifВажное примечание.

При сохранении или совместном использования данных DateTime должно использоваться время в формате UTC и значение DateTime свойства Kind должно быть иметь значение DateTimeKindUTC().

Структура DateTimeOffset

Структура DateTimeOffset представляет значение даты и времени вместе со значением, указывающим, на сколько это время отличается от времени в формате UTC. Таким образом, значение всегда однозначно определяет единственный момент времени.

Несмотря на то, что тип DateTimeOffset включает большинство функций типа DateTime, он не предназначен для замены типа DateTime при разработке приложений. Однако он подходит для приложений, выполняющих следующее:

  • Однозначно идентифицирующих конкретный момент времени. Тип DateTimeOffset можно использовать для однозначного определения значения "сейчас", для ведения журнала времени транзакций, ведения журнала времени событий системы или приложений и для записи времени создания и изменения файлов.

  • Выполняющих общие арифметические действия с датами и временем.

  • Сохраняющих несколько связанных времен, пока эти времена хранятся как два разделенных значения или в виде двух элементов структуры.

Bb384267.alert_note(ru-ru,VS.90).gifПримечание.

Такое использование значений DateTimeOffset более распространено, чем значений DateTime. В результате тип DateTimeOffset должен рассматриваться как тип даты и времени по умолчанию для разработки приложений.

Значение DateTimeOffset не связано с конкретным часовым поясом, но оно может быть создано из любого часового пояса. Чтобы это наглядно показать это, в следующем примере приведен список часовых поясов, которым могут принадлежать значения DateTimeOffset (включая локальное местное Тихоокеанское время).

Imports System.Collections.ObjectModel

Module TimeOffsets
   Public Sub Main()
      Dim thisTime As DateTimeOffset 

      thisTime = New DateTimeOffset(#06/10/2007#, New TimeSpan(-7, 0, 0))
      ShowPossibleTimeZones(thisTime) 

      thisTime = New DateTimeOffset(#03/10/2007#, New TimeSpan(-6, 0, 0))  
      ShowPossibleTimeZones(thisTime)

      thisTime = New DateTimeOffset(#03/10/2007#, New TimeSpan(+1, 0, 0))
      ShowPossibleTimeZones(thisTime)
   End Sub

   Private Sub ShowPossibleTimeZones(offsetTime As DateTimeOffset)
      Dim offset As TimeSpan = offsetTime.Offset
      Dim timeZones As ReadOnlyCollection(Of TimeZoneInfo)

      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
      For Each timeZone As TimeZoneInfo In timeZones
         ' Compare offset with offset for that date in that time zone
         If timeZone.GetUtcOffset(offsetTime.DateTime).Equals(offset) Then
            Console.WriteLine("   {0}", timeZone.DisplayName)
         End If   
      Next
      Console.WriteLine()
   End Sub
End Module
' 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
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

Выходные данные показывают, что каждое значение даты и времени в этом примере может принадлежать по меньшей мере трем разным часовым поясам. Значение DateTimeOffset даты 10.06.2007 показывает, что если значение даты и времени представляет летнее время, его смещение от времени в формате UTC необязательно соответствуют базовым смещениям от UTC исходных часовых поясов или смещению от UTC, находящемуся в отображаемом имени. Это означает, что так как одно значение DateTimeOffset не является тесно связанным с его часовым поясом, то оно не отражает переход часового пояса на или с летнего времени. Это может быть особенно проблематичным, когда для управления значением DateTimeOffset используются арифметические действия с датами и временем. (выполнения арифметических операций с датами и временем с учетом правил коррекции часовых поясов см. в разделе Выполнение арифметических операций с датами и временем).

Класс TimeZoneInfo

Класс TimeZoneInfo представляет все часовые пояса Земли и обеспечивает преобразование любой даты и времени одного часового пояса в его эквивалент в другом часовом поясе. Класс TimeZoneInfo предоставляет возможность работы с датами и временем таким образом, чтобы любые значения даты и времени однозначно идентифицировали единственный момент времени. Также класс TimeZoneInfo является расширяемым. Несмотря на то, что он зависит от сведений о часовом поясе, предоставляемых для систем Windows и определенных в реестре, он поддерживает создание настраиваемых часовых поясов. Он также поддерживает сериализацию и десериализацию сведений часового пояса.

В некоторых случаях для использования всех преимуществ класса TimeZoneInfo от разработчика могут потребоваться дополнительные усилия. Во-первых, значения даты и времени не являются тесно связанными с часовыми поясами, к которым они принадлежат. В результате, если приложение не предоставляет некоторый механизм для связывания даты и времени с соответствующими часовыми поясами, то конкретное значение даты и времени легко становится несоответствующим своему часовому поясу. (одним из способов связывания этих сведений является определение класса или структуры, которая содержит как значение даты и времени, так и соответствующий ему объект часового пояса). Во-вторых, Windows XP и более ранние версии Windows не поддерживают в полной мере данные исторических часовых поясов, а Windows Vista имеет только ограниченную поддержку. Приложениям, предназначенным для обработки исторических дат и времени, необходимо более широко использовать настраиваемые часовые пояса.

Использование всех преимуществ поддержки часовых поясов в платформе .NET Framework возможно, только если при создании объекта даты и времени известен часовой пояс, которому принадлежит значение даты и времени. Это зачастую сложно, особенно для сетевых или веб-приложений.

См. также

Другие ресурсы

Время и часовые пояса