Преобразование времени из одного часового пояса в другой
Обновлен: Ноябрь 2007
Обработка различий между часовыми поясами становится все более важной для всех приложений, которые работают с датами и временем. При работе приложения нельзя предполагать, что все значения времени могут быть выражены по местному времени, которое доступно из структуры DateTime. Например, веб-страница, которая отображает текущее время в восточной части США, будет содержать недостоверные сведения для пользователей в восточной Азии. В этом разделе объясняется, как преобразовать время из одного часового пояса в другой, а также как преобразовать значения DateTimeOffset с ограниченной поддержкой часовых поясов.
Преобразование во время в формате UTC
Время в формате UTC — это высокоточный, атомарный стандарт времени. Часовые пояса выражаются как положительные или отрицательные смещения относительно времени в формате UTC. Таким образом, время в формате UTC предоставляет тип времени свободного от часовых поясов или нейтрального времени часового пояса. Использование времени в формате UTC рекомендовано, когда важна совместимость даты и времени между компьютерами. (Дополнительные сведения и рекомендации по использованию даты и времени содержатся в разделе Рекомендации по использованию DateTime в платформе .NET Framework.) Преобразование отдельных часовых поясов во время в формате UTC упрощает сравнение времен.
![]() |
---|
Можно сериализовать структуру DateTimeOffset для однозначного представления одного момента времени. Поскольку объекты DateTimeOffset хранят значение даты и времени вместе с его смещением относительно времени в формате UTC, то они всегда представляют определенный момент времени по отношению ко времени UTC. |
Самым простым способом преобразования времени в формате UTC является вызов static (Sharedв Visual Basic) метода TimeZoneInfo.ConvertTimeToUtc(DateTime). Точное преобразование, выполненное этим методом, зависит от значения свойства Kind параметра dateTime, как показано в следующей таблице.
Свойство DateTime.Kind |
Преобразование |
---|---|
Преобразовывает местное время во время в формате UTC. |
|
Предполагает, что параметр dateTime является местным временем и преобразовывает местное время в 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));
![]() |
---|
Метод 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:
-
Параметрами этого метода являются значение даты и времени, которое требуется преобразовать, объект TimeZoneInfo, представляющий часовой пояс значения даты и времени, и объект TimeZoneInfo, представляющий часовой пояс, к которому требуется преобразовать значение даты и времени.
-
Параметрами этого метода являются значение даты и времени, которое требуется преобразовать, идентификатор часового пояса для значения даты и времени и идентификатор часового пояса, к которому требуется преобразовать значение даты и времени.
Для обоих методов требуется, чтобы свойство 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;
}
}
См. также
Основные понятия
Поиск часового пояса, заданного в локальной системе