在各时区之间转换时间Converting times between time zones

对任何使用日期和时间的应用程序而言,处理各时区之间的差异变得愈发重要。It is becoming increasingly important for any application that works with dates and times to handle differences between time zones. 应用程序无法再假定所有时间都可以用本地时间表示,这是 DateTime 结构中可用的时间。An application can no longer assume that all times can be expressed in the local time, which is the time available from the DateTime structure. 例如,显示美国东部当前时间的网页对东亚客户而言缺乏可信度。For example, a Web page that displays the current time in the eastern part of the United States will lack credibility to a customer in eastern Asia. 本主题介绍如何将时间从一个时区转换到另一个时区,以及如何转换 DateTimeOffset 的时区感知功能。This topic explains how to convert times from one time zone to another, as well as how to convert DateTimeOffset values that have limited time zone awareness.

转换为协调世界时Converting to Coordinated Universal Time

协调世界时 (UTC) 是一项高精度的原子时标准。Coordinated Universal Time (UTC) is a high-precision, atomic time standard. 世界的时区表示为相对于 UTC 的正/负偏移量。The world’s time zones are expressed as positive or negative offsets from UTC. 因此,UTC 提供一种无时区或中间时区的时间。Thus, UTC provides a kind of time-zone free or time-zone neutral time. 如果日期和时间在计算机之间的可移植性非常重要,则建议使用 UTC 时间。The use of UTC time is recommended when a date and time's portability across computers is important. (有关使用日期和时间的详细信息和其他最佳做法,请参阅在.NET Framework 中使用 DateTime 的编码最佳做法。)将各个时区转换为 UTC 可简化时间比较。(For details and other best practices using dates and times, see Coding best practices using DateTime in the .NET Framework.) Converting individual time zones to UTC makes time comparisons easy.

备注

您还可以序列化 DateTimeOffset 结构以明确表示单个时间点。You can also serialize a DateTimeOffset structure to unambiguously represent a single point in time. 由于 DateTimeOffset 对象存储日期和时间值以及其相对于 UTC 的偏移量,因此,它们始终表示与 UTC 的关系中的特定时间点。Because DateTimeOffset objects store a date and time value along with its offset from UTC, they always represent a particular point in time in relationship to UTC.

若要将时间转换为 UTC,最简单的方法是调用 static (Visual Basic) TimeZoneInfo.ConvertTimeToUtc(DateTime) 方法的SharedThe easiest way to convert a time to UTC is to call the static (Shared in Visual Basic) TimeZoneInfo.ConvertTimeToUtc(DateTime) method. 方法所执行的确切转换取决于 dateTime 参数的 Kind 属性的值,如下表所示。The exact conversion performed by the method depends on the value of the dateTime parameter's Kind property, as the following table shows.

DateTime.Kind 转换Conversion
DateTimeKind.Local 将本地时间转换为 UTC。Converts local time to UTC.
DateTimeKind.Unspecified 假定 dateTime 参数为本地时间并将本地时间转换为 UTC。Assumes the dateTime parameter is local time and converts local time to UTC.
DateTimeKind.Utc 返回未更改的 dateTime 参数。Returns the dateTime parameter unchanged.

以下代码可将当前本地时间转换为 UTC,并将结果显示在控制台上。The following code converts the current local time to UTC and displays the result to the console.

DateTime dateNow = DateTime.Now;
Console.WriteLine("The date and time are {0} UTC.", 
                   TimeZoneInfo.ConvertTimeToUtc(dateNow));
Dim dateNow As Date = Date.Now      
Console.WriteLine("The date and time are {0} UTC.", _
                  TimeZoneInfo.ConvertTimeToUtc(dateNow))

如果日期和时间值不表示本地时间或 UTC,则 ToUniversalTime 方法可能会返回错误的结果。If the date and time value does not represent either the local time or UTC, the ToUniversalTime method will likely return an erroneous result. 但是,可以使用 TimeZoneInfo.ConvertTimeToUtc 方法转换指定时区的日期和时间。However, you can use the TimeZoneInfo.ConvertTimeToUtc method to convert the date and time from a specified time zone. (有关检索表示目标时区的 TimeZoneInfo 对象的详细信息,请参阅查找本地系统上定义的时区。)下面的代码使用 TimeZoneInfo.ConvertTimeToUtc 方法将东部标准时间转换为 UTC。(For details on retrieving a TimeZoneInfo object that represents the destination time zone, see Finding the time zones defined on a local system.) The following code uses the TimeZoneInfo.ConvertTimeToUtc method to convert Eastern Standard Time to UTC.

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);
}
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 对象的 Kind 属性与时区不匹配,此方法将引发 ArgumentExceptionNote that this method throws an ArgumentException if the DateTime object's Kind property and the time zone are mismatched. 如果 DateTimeKind.Local Kind 属性,但 TimeZoneInfo 对象不表示本地时区,或者 Kind 属性 DateTimeKind.UtcTimeZoneInfo 对象不等于 TimeZoneInfo.Utc,则会发生不匹配。A mismatch occurs if the Kind property is DateTimeKind.Local but the TimeZoneInfo object does not represent the local time zone, or if the Kind property is DateTimeKind.Utc but the TimeZoneInfo object does not equal TimeZoneInfo.Utc.

所有这些方法都采用 DateTime 值作为参数,并返回一个 DateTime 值。All of these methods take DateTime values as parameters and return a DateTime value. 对于 DateTimeOffset 值,DateTimeOffset 结构具有 ToUniversalTime 实例方法,该方法可将当前实例的日期和时间转换为 UTC。For DateTimeOffset values, the DateTimeOffset structure has a ToUniversalTime instance method that converts the date and time of the current instance to UTC. 下面的示例调用 ToUniversalTime 方法,将本地时间和几个其他时间转换为协调世界时(UTC)。The following example calls the ToUniversalTime method to convert a local time and several other times to Coordinated Universal Time (UTC).

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

将 UTC 转换为指定的时区Converting UTC to a designated time zone

若要将 UTC 转换为本地时间,请参阅后面的 "将 UTC 转换为本地时间" 一节。To convert UTC to local time, see the "Converting UTC to Local Time" section that follows. 若要将 UTC 转换为任何指定时区中的时间,请调用 ConvertTimeFromUtc 方法。To convert UTC to the time in any time zone that you designate, call the ConvertTimeFromUtc method. 该方法采用两个参数:The method takes two parameters:

  • 要转换的 UTC。The UTC to convert. 这必须是 Kind 属性设置为 UnspecifiedUtcDateTime 值。This must be a DateTime value whose Kind property is set to Unspecified or Utc.

  • UTC 要转换的目标时区。The time zone to convert the UTC to.

以下代码可将 UTC 转换为中部标准时间。The following code converts UTC to Central Standard Time.

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.");
}
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

将 UTC 转换为本地时间Converting UTC to local time

若要将 UTC 转换为本地时间,请调用要转换其时间的 DateTime 对象的 ToLocalTime 方法。To convert UTC to local time, call the ToLocalTime method of the DateTime object whose time you want to convert. 该方法的具体行为取决于对象的 Kind 属性的值,如下表所示。The exact behavior of the method depends on the value of the object’s Kind property, as the following table shows.

DateTime.Kind 转换Conversion
DateTimeKind.Local 返回未更改的 DateTime 值。Returns the DateTime value unchanged.
DateTimeKind.Unspecified 假定 DateTime 值为 UTC 并将 UTC 转换为本地时间。Assumes that the DateTime value is UTC and converts the UTC to local time.
DateTimeKind.Utc DateTime 值转换为本地时间。Converts the DateTime value to local time.

备注

TimeZone.ToLocalTime 方法的行为与 DateTime.ToLocalTime 方法相同。The TimeZone.ToLocalTime method behaves identically to the DateTime.ToLocalTime method. 它采用单个参数,即要转换的日期和时间值。It takes a single parameter, which is the date and time value to convert.

你还可以使用 static (Visual Basic 中SharedTimeZoneInfo.ConvertTime 方法,将任意指定时区中的时间转换为本地时间。You can also convert the time in any designated time zone to local time by using the static (Shared in Visual Basic) TimeZoneInfo.ConvertTime method. 下一节将讨论此方法。This technique is discussed in the next section.

在任意两个时区之间转换Converting between any two time zones

您可以使用 TimeZoneInfo 类的以下两个 static``Shared (Visual Basic)方法之一在任意两个时区之间进行转换:You can convert between any two time zones by using either of the following two static (Shared in Visual Basic) methods of the TimeZoneInfo class:

  • ConvertTime

    此方法的参数是要转换的日期和时间值、表示日期和时间值的时区的 TimeZoneInfo 对象以及表示将日期和时间值转换为的时区的 TimeZoneInfo 对象。This method's parameters are the date and time value to convert, a TimeZoneInfo object that represents the time zone of the date and time value, and a TimeZoneInfo object that represents the time zone to convert the date and time value to.

  • ConvertTimeBySystemTimeZoneId

    此方法的参数是要转换的日期和时间值、日期和时间值的时区的标识符,以及要将日期和时间值转换为的时区的标识符。This method's parameters are the date and time value to convert, the identifier of the date and time value's time zone, and the identifier of the time zone to convert the date and time value to.

这两种方法都要求要转换的日期和时间值的 Kind 属性以及表示其时区的 TimeZoneInfo 对象或时区标识符彼此对应。Both methods require that the Kind property of the date and time value to convert and the TimeZoneInfo object or time zone identifier that represents its time zone correspond to one another. 否则会引发 ArgumentExceptionOtherwise, an ArgumentException is thrown. 例如,如果日期和时间值的 Kind 属性是 DateTimeKind.Local,则如果作为参数传递给该方法的 TimeZoneInfo 对象不等于 TimeZoneInfo.Local,则会引发异常。For example, if the Kind property of the date and time value is DateTimeKind.Local, an exception is thrown if the TimeZoneInfo object passed as a parameter to the method is not equal to TimeZoneInfo.Local. 如果作为参数传递给该方法的标识符不等于 TimeZoneInfo.Local.Id,也会引发异常。An exception is also thrown if the identifier passed as a parameter to the method is not equal to TimeZoneInfo.Local.Id.

下面的示例使用 ConvertTime 方法将夏威夷标准时间转换为本地时间。The following example uses the ConvertTime method to convert from Hawaiian Standard Time to local time.

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.");
}
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                     

转换 DateTimeOffset 值Converting DateTimeOffset values

DateTimeOffset 对象所表示的日期和时间值不能完全识别时区,因为在实例化对象时,该对象与其时区无关。Date and time values represented by DateTimeOffset objects are not fully time-zone aware because the object is disassociated from its time zone at the time it is instantiated. 但是,大多数情况下,应用程序仅需根据两种相对于 UTC 的偏移量,而不是特定时区的时间来转换日期和时间。However, in many cases an application simply needs to convert a date and time based on two different offsets from UTC rather than on the time in particular time zones. 若要执行此转换,可以调用当前实例的 ToOffset 方法。To perform this conversion, you can call the current instance's ToOffset method. 该方法的单个参数是此方法要返回的新日期和时间值的偏移量。The method's single parameter is the offset of the new date and time value that the method is to return.

例如,如果用户所请求网页的日期和时间已知,并且已被序列化为 MM/dd/yyyy hh:mm:ss zzzz 格式的字符串,以下 ReturnTimeOnServer 方法会将此日期和时间值转换为 Web 服务器上的日期和时间。For example, if the date and time of a user request for a Web page is known and is serialized as a string in the format MM/dd/yyyy hh:mm:ss zzzz, the following ReturnTimeOnServer method converts this date and time value to the date and time on the Web server.

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

如果向该方法传递字符串“9/1/2007 5:32:07 -05:00”(表示比 UTC 早五个小时的时区中的日期和时间),则对于处在美国太平洋标准时区中的服务器,它将返回 9/1/2007 3:32:07 AM -07:00。If the method is passed the string "9/1/2007 5:32:07 -05:00", which represents the date and time in a time zone five hours earlier than UTC, it returns 9/1/2007 3:32:07 AM -07:00 for a server located in the U.S. Pacific Standard Time zone.

TimeZoneInfo 类还包括 TimeZoneInfo.ConvertTime(DateTimeOffset, TimeZoneInfo) 方法的重载,该重载使用 ToOffset(TimeSpan) 值执行时区转换。The TimeZoneInfo class also includes an overload of the TimeZoneInfo.ConvertTime(DateTimeOffset, TimeZoneInfo) method that performs time zone conversions with ToOffset(TimeSpan) values. 方法的参数是 DateTimeOffset 值和对时间要转换到的时区的引用。The method's parameters are a DateTimeOffset value and a reference to the time zone to which the time is to be converted. 方法调用返回 DateTimeOffset 值。The method call returns a DateTimeOffset value. 例如,可以按如下所示重写上一示例中的 ReturnTimeOnServer 方法,以调用 ConvertTime(DateTimeOffset, TimeZoneInfo) 方法。For example, the ReturnTimeOnServer method in the previous example could be rewritten as follows to call the ConvertTime(DateTimeOffset, TimeZoneInfo) method.

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

请参阅See also