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

Приложения .NET могут использовать сведения о дате и времени несколькими способами..NET applications can use date and time information in several ways. Ниже приведены наиболее распространенные способы использования сведений о дате и времени.The more common uses of date and time information include:

  • для представления только даты; сведения о времени не имеют значения;To reflect a date only, so that time information is not important.

  • для представления только времени; сведения о дате не имеют значения;To reflect a time only, so that date information is not important.

  • для представления абстрактных даты и времени, не привязанных к определенному времени и месту (например, большинство магазинов международных сетей открываются по рабочим дням в 9:00);To reflect an abstract date and time that is not tied to a specific time and place (for example, most stores in an international chain open on weekdays at 9:00 A.M.).

  • Для получения сведений о дате и времени из источников, находящихся за пределами .NET, обычно данные о дате и времени хранятся в простом типе данных.To retrieve date and time information from sources outside of .NET, typically where date and time information is stored in a simple data type.

  • для однозначной идентификации конкретного момента времени:To uniquely and unambiguously identify a single point in time. Некоторым приложениям требуется, чтобы дата и время были однозначными только в основной системе.Some applications require that a date and time be unambiguous only on the host system. Для других приложений требуется однозначная десериализация в разных системах (т. е. Дата, сериализованная на одной системе, может быть понятна и использована в другой системе в любой точке мира).Other apps require that it be unambiguous across systems (that is, a date serialized on one system can be meaningfully deserialized and used on another system anywhere in the world).

  • для сохранения нескольких связанных значений времени (например, местного времени запрашивающей системы и серверного времени получения веб-запроса);To preserve multiple related times (such as the requestor's local time and the server's time of receipt for a Web request).

  • для выполнения арифметических операций с датой и временем, возможно, с результатом, однозначно определяющим момент времени.To perform date and time arithmetic, possibly with a result that uniquely and unambiguously identifies a single point in time.

.NET включает DateTime типы, DateTimeOffset , TimeSpan и TimeZoneInfo , все из которых можно использовать для создания приложений, работающих с датами и временем..NET includes the DateTime, DateTimeOffset, TimeSpan, and TimeZoneInfo types, all of which can be used to build applications that work with dates and times.

Примечание

Этот раздел не обсуждает, TimeZone так как его функциональность почти полностью включена в TimeZoneInfo класс.This topic doesn't discuss TimeZone because its functionality is almost entirely incorporated in the TimeZoneInfo class. Везде, где это возможно, используйте TimeZoneInfo класс вместо TimeZone класса.Whenever possible, use the TimeZoneInfo class instead of the TimeZone class.

Структура DateTimeOffsetThe DateTimeOffset structure

Структура DateTimeOffset представляет значение даты и времени, а также смещение, которое указывает, насколько это значение отличается от времени в формате UTC.The DateTimeOffset structure represents a date and time value, together with an offset that indicates how much that value differs from UTC. Таким образом, значение всегда однозначно идентифицирует единственный момент времени.Thus, the value always unambiguously identifies a single point in time.

Тип DateTimeOffset включает все функциональные возможности типа DateTime , а также сведения о часовом поясе.The DateTimeOffset type includes all of the functionality of the DateTime type along with time zone awareness. Это делает его пригодным для приложений, которые:This makes it suitable for applications that:

  • однозначно идентифицируют единственный момент времени;Uniquely and unambiguously identify a single point in time. тип DateTimeOffset можно использовать для однозначного определения текущего момента времени, для ведения журнала времени транзакций, ведения журнала времени событий системы или приложений, а также для записи времени создания и изменения файлов;The DateTimeOffset type can be used to unambiguously define the meaning of "now", to log transaction times, to log the times of system or application events, and to record file creation and modification times.

  • выполняют общие арифметические операции с датами и временем;Perform general date and time arithmetic.

  • сохраняют несколько связанных значений времени, если они хранятся как два отдельных значения или два члена структуры.Preserve multiple related times, as long as those times are stored as two separate values or as two members of a structure.

Примечание

Эти варианты использования значений DateTimeOffset более распространены, чем варианты использования значений DateTime .These uses for DateTimeOffset values are much more common than those for DateTime values. В результате рекомендуется использовать DateTimeOffset тип даты и времени по умолчанию для разработки приложений.As a result, consider DateTimeOffset as the default date and time type for application development.

DateTimeOffsetЗначение не привязано к определенному часовому поясу, но может исходить из различных часовых поясов.A DateTimeOffset value isn't tied to a particular time zone, but can originate from a variety of time zones. В следующем примере перечисляются часовые пояса, к которым DateTimeOffset могут принадлежать несколько значений (включая местное Тихоокеанское время).The following example lists the time zones to which a number of DateTimeOffset values (including a local Pacific Standard Time) can belong.

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
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

Выходные данные показывают, что все значения даты и времени в этом примере могут принадлежать по крайней мере трем разным часовым поясам.The output shows that each date and time value in this example can belong to at least three different time zones. DateTimeOffsetЗначение 6/10/2007 показывает, что если значение даты и времени представляет летнее время, его смещение от времени в формате UTC не обязательно соответствует базовому смещению UTC исходного часового пояса или смещению от времени UTC, обнаруженному в его отображаемом имени.The DateTimeOffset value of 6/10/2007 shows that if a date and time value represents a daylight saving time, its offset from UTC doesn't even necessarily correspond to the originating time zone's base UTC offset or to the offset from UTC found in its display name. Поскольку одно DateTimeOffset значение не тесно связано со своим часовым поясом, оно не может отражать переход часового пояса на летнее время и обратно.Because a single DateTimeOffset value isn't tightly coupled with its time zone, it can't reflect a time zone's transition to and from daylight saving time. Это может быть проблематичным при использовании арифметических операций с датами и временем для работы со DateTimeOffset значениями.This can be problematic when date and time arithmetic is used to manipulate a DateTimeOffset value. Сведения о том, как выполнять арифметические операции с датами и временем, которые принимают учетные данные правил коррекции часового пояса, см. в разделе Выполнение арифметических операций с датами и временем.For a discussion of how to perform date and time arithmetic in a way that takes account of a time zone's adjustment rules, see Performing arithmetic operations with dates and times.

Структура DateTimeThe DateTime structure

Значение DateTime определяет конкретную дату и время.A DateTime value defines a particular date and time. Он включает Kind свойство, которое предоставляет ограниченные сведения о часовом поясе, к которому относится эта дата и время.It includes a Kind property that provides limited information about the time zone to which that date and time belongs. Значение DateTimeKind , возвращаемое свойством Kind , указывает, представляет ли значение DateTime местное время (DateTimeKind.Local), время в формате UTC (DateTimeKind.Utc) или неопределенное время (DateTimeKind.Unspecified).The DateTimeKind value returned by the Kind property indicates whether the DateTime value represents the local time (DateTimeKind.Local), Coordinated Universal Time (UTC) (DateTimeKind.Utc), or an unspecified time (DateTimeKind.Unspecified).

DateTimeСтруктура подходит для приложений с одной или несколькими из следующих характеристик.The DateTime structure is suitable for applications with one or more of the following characteristics:

  • работают только с датами;Work with dates only.

  • работают только со временем;Work with times only.

  • работают с абстрактными датами и временем;Work with abstract dates and times.

  • работают с датами и временем, для которых отсутствуют сведения о часовом поясе;Work with dates and times for which time zone information is missing.

  • работают только с датами и временем в формате UTC;Work with UTC dates and times only.

  • Получение сведений о дате и времени из источников за пределами .NET, таких как базы данных SQL.Retrieve date and time information from sources outside of .NET, such as SQL databases. (как правило, информация о дате и времени хранится в этих источниках в простом формате, который совместим со структурой DateTime );Typically, these sources store date and time information in a simple format that is compatible with the DateTime structure.

  • выполняют арифметические операции с датой и временем, но учитывают только общие результаты.Perform date and time arithmetic, but are concerned with general results. Например, в операции сложения, которая добавляет шесть месяцев к определенным дате и времени, часто не важно, корректируется ли результат с учетом перехода на летнее время.For example, in an addition operation that adds six months to a particular date and time, it is often not important whether the result is adjusted for daylight saving time.

Кроме случая, когда определенное значение DateTime представляет время в формате UTC, значение даты и времени часто является неоднозначным или ограниченным в плане возможности переноса.Unless a particular DateTime value represents UTC, that date and time value is often ambiguous or limited in its portability. Например, если значение DateTime представляет местное время, оно является переносимым внутри местного часового пояса (то есть если значение десериализуется в другой системе в том же часовом поясе, оно по-прежнему однозначно определяет конкретный момент времени).For example, if a DateTime value represents the local time, it is portable within that local time zone (that is, if the value is deserialized on another system in the same time zone, that value still unambiguously identifies a single point in time). За пределами местного часового пояса значение DateTime может иметь несколько интерпретаций.Outside the local time zone, that DateTime value can have multiple interpretations. Если свойство Kind имеет значение DateTimeKind.Unspecified, значение даты и времени становится еще менее переносимым: в этом случае оно неоднозначно даже в том же часовом поясе и, возможно, даже на том же компьютере, на котором оно было впервые сериализовано.If the value's Kind property is DateTimeKind.Unspecified, it is even less portable: it is now ambiguous within the same time zone and possibly even on the same system on which it was first serialized. Значение DateTime однозначно идентифицирует момент времени независимо от времени системы или часового пояса, в котором оно используется, только если это значение представляет время в формате UTC.Only if a DateTime value represents UTC does that value unambiguously identify a single point in time regardless of the system or time zone in which the value is used.

Важно!

При сохранении или совместном использовании данных DateTime следует использовать формат UTC, а для свойства DateTime значения Kind должно быть задано значение DateTimeKind.Utc.When saving or sharing DateTime data, UTC should be used and the DateTime value's Kind property should be set to DateTimeKind.Utc.

Структура TimeSpanThe TimeSpan structure

Структура TimeSpan представляет интервал времени.The TimeSpan structure represents a time interval. Ее обычно используют двумя способами:Its two typical uses are:

  • для отражения интервала времени между двумя значениями даты и времениReflecting the time interval between two date and time values. (например, при вычитании одного значения DateTime из другого возвращается значение TimeSpan );For example, subtracting one DateTime value from another returns a TimeSpan value.

  • для измерения прошедшего времени.Measuring elapsed time. Например, Stopwatch.Elapsed свойство возвращает TimeSpan значение, отражающее интервал времени, прошедший с момента вызова одного из Stopwatch методов, которые начинают измерять прошедшее время.For example, the Stopwatch.Elapsed property returns a TimeSpan value that reflects the time interval that has elapsed since the call to one of the Stopwatch methods that begins to measure elapsed time.

TimeSpanЗначение может также использоваться в качестве замены DateTime значения, когда это значение отражает время без ссылки на конкретный день.A TimeSpan value can also be used as a replacement for a DateTime value when that value reflects a time without reference to a particular day. Это использование аналогично DateTime.TimeOfDay DateTimeOffset.TimeOfDay свойствам и, возвращающим TimeSpan значение, которое представляет время без ссылки на дату.This usage is similar to the DateTime.TimeOfDay and DateTimeOffset.TimeOfDay properties, which return a TimeSpan value that represents the time without reference to a date. Например, структуру TimeSpan можно использовать для представления ежедневного времени открытия или закрытия магазина или времени, в которое происходит любое регулярное событие.For example, the TimeSpan structure can be used to reflect a store's daily opening or closing time, or it can be used to represent the time at which any regular event occurs.

В примере ниже определяется структура StoreInfo , которая включает объекты TimeSpan , представляющие время закрытия и открытия магазина, а также объект TimeZoneInfo , представляющий часовой пояс магазина.The following example defines a StoreInfo structure that includes TimeSpan objects for store opening and closing times, as well as a TimeZoneInfo object that represents the store's time zone. Структура также включает два метода, IsOpenNow и IsOpenAt, указывающие, открыт ли магазин в то время, которое указал пользователь, предположительно находящийся в местном часовом поясе.The structure also includes two methods, IsOpenNow and IsOpenAt, that indicates whether the store is open at a time specified by the user, who is assumed to be in the local time zone.

using System;

public struct StoreInfo
{
   public String store;
   public TimeZoneInfo tz;
   public TimeSpan open;
   public TimeSpan close;

   public bool IsOpenNow()
   {
      return IsOpenAt(DateTime.Now.TimeOfDay);
   }

   public bool IsOpenAt(TimeSpan time)
   {
      TimeZoneInfo local = TimeZoneInfo.Local;
      TimeSpan offset = TimeZoneInfo.Local.BaseUtcOffset;

      // Is the store in the same time zone?
      if (tz.Equals(local)) {
         return time >= open & time <= close;
      }
      else {
         TimeSpan delta = TimeSpan.Zero;
         TimeSpan storeDelta = TimeSpan.Zero;

         // Is it daylight saving time in either time zone?
         if (local.IsDaylightSavingTime(DateTime.Now.Date + time))
            delta = local.GetAdjustmentRules()[local.GetAdjustmentRules().Length - 1].DaylightDelta;

         if (tz.IsDaylightSavingTime(TimeZoneInfo.ConvertTime(DateTime.Now.Date + time, local, tz)))
            storeDelta = tz.GetAdjustmentRules()[tz.GetAdjustmentRules().Length - 1].DaylightDelta;

         TimeSpan comparisonTime = time + (offset - tz.BaseUtcOffset).Negate() + (delta - storeDelta).Negate();
         return comparisonTime >= open & comparisonTime <= close;
      }
   }
}
Public Structure StoreInfo
    Dim store As String
    Dim tz As TimeZoneInfo
    Dim open As TimeSpan
    Dim close As TimeSpan

    Public Function IsOpenNow() As Boolean
        Return IsOpenAt(Date.Now.TimeOfDay)
    End Function

    Public Function IsOpenAt(time As TimeSpan) As Boolean
        Dim local As TimeZoneInfo = TimeZoneInfo.Local
        Dim offset As TimeSpan = TimeZoneInfo.Local.BaseUtcOffset

        ' Is the store in the same time zone?
        If tz.Equals(local) Then
            Return time >= open AndAlso time <= close
        Else
            Dim delta As TimeSpan = TimeSpan.Zero
            Dim storeDelta As TimeSpan = TimeSpan.Zero

            ' Is it daylight saving time in either time zone?
            If local.IsDaylightSavingTime(Date.Now.Date + time) Then
                delta = local.GetAdjustmentRules(local.GetAdjustmentRules().Length - 1).DaylightDelta
            End If
            If tz.IsDaylightSavingTime(TimeZoneInfo.ConvertTime(Date.Now.Date + time, local, tz))
                storeDelta = tz.GetAdjustmentRules(tz.GetAdjustmentRules().Length - 1).DaylightDelta
            End If
            Dim comparisonTime As TimeSpan = time + (offset - tz.BaseUtcOffset).Negate() + (delta - storeDelta).Negate
            Return (comparisonTime >= open AndAlso comparisonTime <= close)
        End If
    End Function
End Structure

Затем клиентский код может использовать структуру StoreInfo , как показано ниже.The StoreInfo structure can then be used by client code like the following.

public class Example
{
   public static void Main()
   {
      // Instantiate a StoreInfo object.
      var store103 = new StoreInfo();
      store103.store = "Store #103";
      store103.tz = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
      // Store opens at 8:00.
      store103.open = new TimeSpan(8, 0, 0);
      // Store closes at 9:30.
      store103.close = new TimeSpan(21, 30, 0);

      Console.WriteLine("Store is open now at {0}: {1}",
                        DateTime.Now.TimeOfDay, store103.IsOpenNow());
      TimeSpan[] times = { new TimeSpan(8, 0, 0), new TimeSpan(21, 0, 0),
                           new TimeSpan(4, 59, 0), new TimeSpan(18, 31, 0) };
      foreach (var time in times)
         Console.WriteLine("Store is open at {0}: {1}",
                           time, store103.IsOpenAt(time));
   }
}
// The example displays the following output:
//       Store is open now at 15:29:01.6129911: True
//       Store is open at 08:00:00: True
//       Store is open at 21:00:00: False
//       Store is open at 04:59:00: False
//       Store is open at 18:31:00: False
Module Example
    Public Sub Main()
        ' Instantiate a StoreInfo object.
        Dim store103 As New StoreInfo()
        store103.store = "Store #103"
        store103.tz = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time")
        ' Store opens at 8:00.
        store103.open = new TimeSpan(8, 0, 0)
        ' Store closes at 9:30.
        store103.close = new TimeSpan(21, 30, 0)

        Console.WriteLine("Store is open now at {0}: {1}",
                          Date.Now.TimeOfDay, store103.IsOpenNow())
        Dim times() As TimeSpan = {New TimeSpan(8, 0, 0),
                                    New TimeSpan(21, 0, 0),
                                    New TimeSpan(4, 59, 0),
                                    New TimeSpan(18, 31, 0)}
        For Each time In times
            Console.WriteLine("Store is open at {0}: {1}",
                              time, store103.IsOpenAt(time))
        Next
    End Sub
End Module
' The example displays the following output:
'       Store is open now at 15:29:01.6129911: True
'       Store is open at 08:00:00: True
'       Store is open at 21:00:00: False
'       Store is open at 04:59:00: False
'       Store is open at 18:31:00: False

Класс TimeZoneInfoThe TimeZoneInfo class

Класс TimeZoneInfo class represents any of the Earth's time zones, and enables the conversion of any date and time in one time zone to its equivalent in another time zone.The TimeZoneInfo class represents any of the Earth's time zones, and enables the conversion of any date and time in one time zone to its equivalent in another time zone. Класс TimeZoneInfo позволяет работать со значениями даты и времени, обеспечивая однозначную идентификацию единственного момента времени с помощью любого значения даты и времени.The TimeZoneInfo class makes it possible to work with dates and times so that any date and time value unambiguously identifies a single point in time. Класс TimeZoneInfo также является расширяемым.The TimeZoneInfo class is also extensible. Хотя он зависит от сведений о часовом поясе, предоставленных для систем Windows и определенных в реестре, он поддерживает создание настраиваемых часовых поясов.Although it depends on time zone information provided for Windows systems and defined in the registry, it supports the creation of custom time zones. Кроме того, он поддерживает сериализацию и десериализацию сведений о часовом поясе.It also supports the serialization and deserialization of time zone information.

В некоторых случаях использование всех преимуществ класса TimeZoneInfo может потребовать дальнейших усилий по разработке.In some cases, taking full advantage of the TimeZoneInfo class may require further development work. Если значения даты и времени не тесно связаны с часовыми поясами, к которым они относятся, требуется дополнительная работа.If date and time values are not tightly coupled with the time zones to which they belong, further work is required. Если приложение не предоставляет какой-либо механизм для связывания даты и времени со связанным часовым поясом, то определенное значение даты и времени можно легко привязать к его часовому поясу.Unless your application provides some mechanism for linking a date and time with its associated time zone, it's easy for a particular date and time value to become disassociated from its time zone. Одним из способов связывания этой информации является определение класса или структуры, содержащих значение даты и времени и связанный с ним часовой пояс.One method of linking this information is to define a class or structure that contains both the date and time value and its associated time zone object.

Чтобы воспользоваться преимуществами поддержки часовых поясов в .NET, необходимо знание часового пояса, к которому принадлежит значение даты и времени при создании экземпляра объекта даты и времени.To take advantage of time zone support in .NET, you must know the time zone to which a date and time value belongs when that date and time object is instantiated. Часовой пояс часто неизвестен, особенно в веб-или сетевых приложениях.The time zone is often not known, particularly in web or network apps.

См. также статьюSee also