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


Преобразование времени из одного часового пояса в другой

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

Обработка различий между часовыми поясами становится все более важной для всех приложений, которые работают с датами и временем. При работе приложения нельзя предполагать, что все значения времени могут быть выражены по местному времени, которое доступно из структуры DateTime. Например, веб-страница, которая отображает текущее время в восточной части США, будет содержать недостоверные сведения для пользователей в восточной Азии. В этом разделе объясняется, как преобразовать время из одного часового пояса в другой, а также как преобразовать значения DateTimeOffset с ограниченной поддержкой часовых поясов.

Преобразование во время в формате UTC

Время в формате UTC — это высокоточный, атомарный стандарт времени. Часовые пояса выражаются как положительные или отрицательные смещения относительно времени в формате UTC. Таким образом, время в формате UTC предоставляет тип времени свободного от часовых поясов или нейтрального времени часового пояса. Использование времени в формате UTC рекомендовано, когда важна совместимость даты и времени между компьютерами. (Дополнительные сведения и рекомендации по использованию даты и времени содержатся в разделе Рекомендации по использованию DateTime в платформе .NET Framework.) Преобразование отдельных часовых поясов во время в формате UTC упрощает сравнение времен.

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

Можно сериализовать структуру DateTimeOffset для однозначного представления одного момента времени. Поскольку объекты DateTimeOffset хранят значение даты и времени вместе с его смещением относительно времени в формате UTC, то они всегда представляют определенный момент времени по отношению ко времени UTC.

Самым простым способом преобразования времени в формате UTC является вызов static (Sharedв Visual Basic) метода TimeZoneInfo.ConvertTimeToUtc(DateTime). Точное преобразование, выполненное этим методом, зависит от значения свойства Kind параметра dateTime, как показано в следующей таблице.

Свойство DateTime.Kind

Преобразование

DateTimeKind.Local

Преобразовывает местное время во время в формате UTC.

DateTimeKind.Unspecified

Предполагает, что параметр dateTime является местным временем и преобразовывает местное время в UTC.

DateTimeKind.Utc

Возвращает неизмененный параметр dateTime.

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

Dim dateNow As Date = Date.Now      
Console.WriteLine("The date and time are {0} UTC.", _
                  TimeZoneInfo.ConvertTimeToUtc(dateNow))
DateTime dateNow = DateTime.Now;
Console.WriteLine("The date and time are {0} UTC.", 
                   TimeZoneInfo.ConvertTimeToUtc(dateNow));
Bb397769.alert_note(ru-ru,VS.90).gifПримечание.

Метод TimeZoneInfo.ConvertTimeToUtc(DateTime) не обязательно возвращает результаты, которые совпадают с результатами методов TimeZone.ToUniversalTime и DateTime.ToUniversalTime. Если местный часовой пояс на локальной системе содержит несколько правил коррекции, то метод TimeZoneInfo.ConvertTimeToUtc(DateTime) применяет соответствующее правило к конкретным дате и времени. Два других метода всегда применяют последнее правило коррекции.

Если значение даты и времени не представляет местное время или время в формате UTC, то метод ToUniversalTime скорее всего вернет ошибочный результат. Однако можно использовать метод TimeZoneInfo.ConvertTimeToUtc для преобразования даты и времени из заданного часового пояса. (Дополнительные сведения о получении объекта TimeZoneInfo, который представляет часовой пояс назначения, см. в разделе Поиск часового пояса, заданного в локальной системе.) В следующем коде используется метод TimeZoneInfo.ConvertTimeToUtc для преобразования восточного стандартного времени в UTC.

Dim easternTime As New Date(2007, 01, 02, 12, 16, 00)
Dim easternZoneId As String = "Eastern Standard Time"
Try
   Dim easternZone As TimeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById(easternZoneId)
   Console.WriteLine("The date and time are {0} UTC.", _ 
                     TimeZoneInfo.ConvertTimeToUtc(easternTime, easternZone))
Catch e As TimeZoneNotFoundException
   Console.WriteLine("Unable to find the {0} zone in the registry.", _
                     easternZoneId)
Catch e As InvalidTimeZoneException
   Console.WriteLine("Registry data on the {0} zone has been corrupted.", _ 
                     easternZoneId)
End Try                           
DateTime easternTime = new DateTime(2007, 01, 02, 12, 16, 00);
string easternZoneId = "Eastern Standard Time";
try
{
   TimeZoneInfo easternZone = TimeZoneInfo.FindSystemTimeZoneById(easternZoneId);
   Console.WriteLine("The date and time are {0} UTC.", 
                     TimeZoneInfo.ConvertTimeToUtc(easternTime, easternZone));
}
catch (TimeZoneNotFoundException)
{
   Console.WriteLine("Unable to find the {0} zone in the registry.", 
                     easternZoneId);
}                           
catch (InvalidTimeZoneException)
{
   Console.WriteLine("Registry data on the {0} zone has been corrupted.", 
                     easternZoneId);
}

Обратите внимание, что этот метод создает исключение ArgumentException, если свойство Kind объекта DateTime не совпадает с часовым поясом. Несоответствие возникает, если свойство Kind задано как DateTimeKind.Local, а объект TimeZoneInfo не представляет местный часовой пояс, или если свойство Kind задано как DateTimeKind.Utc, а объект TimeZoneInfo не равен DateTimeKind.Utc.

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

Dim localTime, otherTime, universalTime As DateTimeOffset

' Define local time in local time zone
localTime = New DateTimeOffset(#6/15/2007 12:00:00PM#)
Console.WriteLine("Local time: {0}", localTime)
Console.WriteLine()

' Convert local time to offset 0 and assign to otherTime
otherTime = localTime.ToOffset(TimeSpan.Zero)
Console.WriteLine("Other time: {0}", otherTime)
Console.WriteLine("{0} = {1}: {2}", _
                  localTime, otherTime, _
                  localTime.Equals(otherTime))
Console.WriteLine("{0} exactly equals {1}: {2}", _ 
                  localTime, otherTime, _
                  localTime.EqualsExact(otherTime))
Console.WriteLine()

' Convert other time to UTC
universalTime = localTime.ToUniversalTime() 
Console.WriteLine("Universal time: {0}", universalTime)
Console.WriteLine("{0} = {1}: {2}", _
                  otherTime, universalTime, _ 
                  universalTime.Equals(otherTime))
Console.WriteLine("{0} exactly equals {1}: {2}", _ 
                  otherTime, universalTime, _
                  universalTime.EqualsExact(otherTime))
Console.WriteLine()
' The example produces the following output to the console:
'    Local time: 6/15/2007 12:00:00 PM -07:00
'    
'    Other time: 6/15/2007 7:00:00 PM +00:00
'    6/15/2007 12:00:00 PM -07:00 = 6/15/2007 7:00:00 PM +00:00: True
'    6/15/2007 12:00:00 PM -07:00 exactly equals 6/15/2007 7:00:00 PM +00:00: False
'    
'    Universal time: 6/15/2007 7:00:00 PM +00:00
'    6/15/2007 7:00:00 PM +00:00 = 6/15/2007 7:00:00 PM +00:00: True
'    6/15/2007 7:00:00 PM +00:00 exactly equals 6/15/2007 7:00:00 PM +00:00: True   
DateTimeOffset localTime, otherTime, universalTime;

// Define local time in local time zone
localTime = new DateTimeOffset(new DateTime(2007, 6, 15, 12, 0, 0));
Console.WriteLine("Local time: {0}", localTime);
Console.WriteLine();

// Convert local time to offset 0 and assign to otherTime
otherTime = localTime.ToOffset(TimeSpan.Zero);
Console.WriteLine("Other time: {0}", otherTime);
Console.WriteLine("{0} = {1}: {2}", 
                  localTime, otherTime, 
                  localTime.Equals(otherTime));
Console.WriteLine("{0} exactly equals {1}: {2}", 
                  localTime, otherTime, 
                  localTime.EqualsExact(otherTime));
Console.WriteLine();

// Convert other time to UTC
universalTime = localTime.ToUniversalTime(); 
Console.WriteLine("Universal time: {0}", universalTime);
Console.WriteLine("{0} = {1}: {2}", 
                  otherTime, universalTime, 
                  universalTime.Equals(otherTime));
Console.WriteLine("{0} exactly equals {1}: {2}", 
                  otherTime, universalTime, 
                  universalTime.EqualsExact(otherTime));
Console.WriteLine();
// The example produces the following output to the console:
//    Local time: 6/15/2007 12:00:00 PM -07:00
//    
//    Other time: 6/15/2007 7:00:00 PM +00:00
//    6/15/2007 12:00:00 PM -07:00 = 6/15/2007 7:00:00 PM +00:00: True
//    6/15/2007 12:00:00 PM -07:00 exactly equals 6/15/2007 7:00:00 PM +00:00: False
//    
//    Universal time: 6/15/2007 7:00:00 PM +00:00
//    6/15/2007 7:00:00 PM +00:00 = 6/15/2007 7:00:00 PM +00:00: True
//    6/15/2007 7:00:00 PM +00:00 exactly equals 6/15/2007 7:00:00 PM +00:00: True   

Преобразование времени в формате UTC в заданный часовой пояс

Чтобы преобразовать время UTC в местное время, см. следующий далее раздел "Преобразование времени UTC в местное время". Чтобы преобразовать время в формате UTC во время в любом часовом поясе, вызовите метод ConvertTimeFromUtc. Этот метод принимает два параметра:

  • Время в формате UTC, которое требуется преобразовать. Оно должно быть значением DateTime, свойству Kind которого присвоено значение DateTimeKind.Utc или значение DateTimeKind.Unspecified.

  • Часовой пояс, в который требуется преобразовать время в формате UTC.

Следующий код преобразует время в формате UTC в центральное стандартное время.

Dim timeUtc As Date = Date.UtcNow
Try
   Dim cstZone As TimeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time")
   Dim cstTime As Date = TimeZoneInfo.ConvertTimeFromUtc(timeUtc, cstZone)
   Console.WriteLine("The date and time are {0} {1}.", _
                     cstTime, _
                     IIf(cstZone.IsDaylightSavingTime(cstTime), _
                         cstZone.DaylightName, cstZone.StandardName))
Catch e As TimeZoneNotFoundException
   Console.WriteLine("The registry does not define the Central Standard Time zone.")
Catch e As InvalidTimeZoneException
   Console.WriteLine("Registry data on the Central Standard Time zone has been corrupted.")
End Try
DateTime timeUtc = DateTime.UtcNow;
try
{
   TimeZoneInfo cstZone = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time");
   DateTime cstTime = TimeZoneInfo.ConvertTimeFromUtc(timeUtc, cstZone);
   Console.WriteLine("The date and time are {0} {1}.", 
                     cstTime, 
                     cstZone.IsDaylightSavingTime(cstTime) ?
                             cstZone.DaylightName : cstZone.StandardName);
}
catch (TimeZoneNotFoundException)
{
   Console.WriteLine("The registry does not define the Central Standard Time zone.");
}                           
catch (InvalidTimeZoneException)
{
   Console.WriteLine("Registry data on the Central STandard Time zone has been corrupted.");
}

Преобразование UTC в местное время

Чтобы преобразовать время в формате UTC в местное время, вызовите метод ToLocalTime объекта DateTime, время которого требуется преобразовать. Точное поведение метода зависит от значения свойства объекта Kind, как показано в следующей таблице.

Свойство DateTime.Kind

Преобразование

DateTimeKind.Local

Возвращает неизмененное значение DateTime.

DateTimeKind.Unspecified

Предполагает, что значение DateTime является временем в формате UTC и преобразует UTC в местное время.

DateTimeKind.Utc

Преобразует значение DateTime в местное время.

Примечание Метод TimeZone.ToLocalTime работает идентично методу DateTime.ToLocalTime. Он принимает один параметр, являющийся значением даты и времени, которое требуется преобразовать.

Можно также преобразовать время любого часового пояса в местное время с помощью static (Shared в Visual Basic) метода TimeZoneInfo.ConvertTime. Этот метод рассматривается в следующем разделе.

Преобразование между любыми двумя часовыми поясами

Можно преобразовать время между любыми двумя часовыми поясами с помощью любого из следующих двух static (Shared в Visual Basic) методов класса TimeZoneInfo:

  • ConvertTime

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

  • ConvertTimeBySystemTimeZoneId

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

Для обоих методов требуется, чтобы свойство Kind значения даты и времени, которое требуется преобразовать, соответствовало объекту TimeZoneInfo или идентификатору часового пояса, представляющего его часовой пояс. В противном случае возникает исключение ArgumentException. Например, если свойством Kind значения даты и времени является DateTimeKind.Local, то исключение возникнет в том случае, если объект TimeZoneInfo, который передан в качестве параметра метода, не равен TimeZoneInfo.Local. Также исключение возникнет в том случае, если идентификатор, переданный в качестве параметра метода, не равен TimeZoneInfo.Local.Id.

В следующем примере используется метод ConvertTime для преобразования из гавайского стандартного времени в местное время.

Dim hwTime As Date = #2/01/2007 8:00:00 AM#
Try
   Dim hwZone As TimeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Hawaiian Standard Time")
   Console.WriteLine("{0} {1} is {2} local time.", _
                     hwTime, _
                     IIf(hwZone.IsDaylightSavingTime(hwTime), hwZone.DaylightName, hwZone.StandardName), _
                     TimeZoneInfo.ConvertTime(hwTime, hwZone, TimeZoneInfo.Local))
Catch e As TimeZoneNotFoundException
   Console.WriteLine("The registry does not define the Hawaiian Standard Time zone.")
Catch e As InvalidTimeZoneException
   Console.WriteLine("Registry data on the Hawaiian Standard Time zone has been corrupted.")
End Try                     
DateTime hwTime = new DateTime(2007, 02, 01, 08, 00, 00);
try
{
   TimeZoneInfo hwZone = TimeZoneInfo.FindSystemTimeZoneById("Hawaiian Standard Time");
   Console.WriteLine("{0} {1} is {2} local time.", 
           hwTime, 
           hwZone.IsDaylightSavingTime(hwTime) ? hwZone.DaylightName : hwZone.StandardName, 
           TimeZoneInfo.ConvertTime(hwTime, hwZone, TimeZoneInfo.Local));
}
catch (TimeZoneNotFoundException)
{
   Console.WriteLine("The registry does not define the Hawaiian Standard Time zone.");
}                           
catch (InvalidTimeZoneException)
{
   Console.WriteLine("Registry data on the Hawaiian STandard Time zone has been corrupted.");
}

Преобразование значений DateTimeOffset

Значения даты и времени, представленные объектами DateTimeOffset, не соответствуют полностью часовым поясам, так как при создании этот объект не связан с часовым поясом. Однако, во многих случаях приложению достаточно преобразовать дату и время на основе двух различных значений смещения относительно времени в формате UTC, а не на основе времени конкретных часовых поясов. Чтобы выполнить это преобразование, можно вызвать метод ToOffset текущего экземпляра. Единственным параметром данного метода является смещение нового значения даты и времени, которое возвращает этот метод.

Например, если дата и время запроса пользователя к веб-странице известны и сериализованы в виде строки в формате мм/дд/гггг чч:мм:сс zzzz, то следующий метод ReturnTimeOnServer преобразует это значение даты и времени в значение даты и времени на веб-сервере.

Public Function ReturnTimeOnServer(clientString As String) As DateTimeOffset
   Dim format As String = "M/d/yyyy H:m:s zzz"
   Dim serverOffset As TimeSpan = TimeZoneInfo.Local.GetUtcOffset(DateTimeOffset.Now)

   Try      
      Dim clientTime As DateTimeOffset = DateTimeOffset.ParseExact(clientString, format, CultureInfo.InvariantCulture)
      Dim serverTime As DateTimeOffset = clientTime.ToOffset(serverOffset)
      Return serverTime
   Catch e As FormatException
      Return DateTimeOffset.MinValue
   End Try    
End Function
public DateTimeOffset ReturnTimeOnServer(string clientString)
{
   string format = @"M/d/yyyy H:m:s zzz";
   TimeSpan serverOffset = TimeZoneInfo.Local.GetUtcOffset(DateTimeOffset.Now);

   try
   {      
      DateTimeOffset clientTime = DateTimeOffset.ParseExact(clientString, format, CultureInfo.InvariantCulture);
      DateTimeOffset serverTime = clientTime.ToOffset(serverOffset);
      return serverTime;
   }
   catch (FormatException)
   {
      return DateTimeOffset.MinValue;
   }
}

Если методу передается строка "9/1/2007 5:32:07 -05:00", которая представляет дату и время в часовом поясе, который раньше времени в формате UTC на пять часов, то он возвращает "9/1/2007 3:32:07 -07:00" для сервера, который находится в тихоокеанском стандартном часовом поясе США.

Класс TimeZoneInfo также содержит перегрузку метода TimeZoneInfo.ConvertTime(DateTimeOffset, TimeZoneInfo), который выполняет преобразование часовых поясов со значениями DateTimeOffset. Параметрами данного метода являются значение DateTimeOffset и ссылка на часовой пояс, к которому требуется преобразовать время. Этот метод возвращает значение DateTimeOffset. Например, метод ReturnTimeOnServer в предыдущем примере может быть переписан для вызова метода ConvertTime(DateTimeOffset, TimeZoneInfo).

Public Function ReturnTimeOnServer(clientString As String) As DateTimeOffset
   Dim format As String = "M/d/yyyy H:m:s zzz"

   Try      
      Dim clientTime As DateTimeOffset = DateTimeOffset.ParseExact(clientString, format, CultureInfo.InvariantCulture)
      Dim serverTime As DateTimeOffset = TimeZoneInfo.ConvertTime(clientTime, TimeZoneInfo.Local)
      Return serverTime
   Catch e As FormatException
      Return DateTimeOffset.MinValue
   End Try    
End Function
public DateTimeOffset ReturnTimeOnServer(string clientString)
{
   string format = @"M/d/yyyy H:m:s zzz";

   try
   {      
      DateTimeOffset clientTime = DateTimeOffset.ParseExact(clientString, format, 
                                  CultureInfo.InvariantCulture);
      DateTimeOffset serverTime = TimeZoneInfo.ConvertTime(clientTime, 
                                  TimeZoneInfo.Local);
      return serverTime;
   }
   catch (FormatException)
   {
      return DateTimeOffset.MinValue;
   }
}

См. также

Основные понятия

Поиск часового пояса, заданного в локальной системе

Ссылки

TimeZoneInfo

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

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