日付と時刻を使用してタイム ゾーン間の違いを処理するアプリケーションにとって、ますます重要になっています。 アプリケーションでは、すべての時刻をローカル時刻 ( DateTime 構造体から使用できる時刻) で表すことができると想定できなくなりました。 たとえば、米国東部の現在時刻を表示する Web ページでは、東アジアの顧客に対する信頼性が失われます。 この記事では、あるタイム ゾーンから別のタイム ゾーンに時刻を変換し、タイム ゾーン認識が制限されている DateTimeOffset 値を変換する方法について説明します。
協定世界時への変換
協定世界時 (UTC) は、高精度のアトミック時間標準です。 世界のタイム ゾーンは、UTC からの正または負のオフセットとして表されます。 したがって、UTC では、タイム ゾーンフリータイムまたはタイム ゾーンニュートラルタイムが提供されます。 コンピューター間での日付と時刻の移植性が重要な場合は、UTC を使用することをお勧めします。 日付と時刻を使用した詳細およびその他のベスト プラクティスについては、 .NET Framework での DateTime を使用したコーディングのベスト プラクティスに関するページを参照してください。 個々のタイム ゾーンを UTC に変換すると、時刻の比較が簡単になります。
注
DateTimeOffset構造体をシリアル化して、1 つの時点を明確に表すこともできます。 DateTimeOffsetオブジェクトは、UTC からのオフセットと共に日付と時刻の値を格納するため、常に UTC に関連する特定の時点を表します。
時刻を UTC に変換する最も簡単な方法は、 static
(Visual Basic のShared
) TimeZoneInfo.ConvertTimeToUtc(DateTime) メソッドを呼び出す方法です。 メソッドによって実行される正確な変換は、次の表に示すように、 dateTime
パラメーターの Kind プロパティの値によって異なります。
DateTime.Kind |
変換 |
---|---|
DateTimeKind.Local |
現地時刻を UTC に変換します。 |
DateTimeKind.Unspecified |
dateTime パラメーターが現地時刻であり、現地時刻を UTC に変換することを前提としています。 |
DateTimeKind.Utc |
dateTime パラメーターを変更せずに返します。 |
次のコードは、現在の現地時刻を UTC に変換し、結果をコンソールに表示します。
DateTime dateNow = DateTime.Now;
Console.WriteLine($"The date and time are {TimeZoneInfo.ConvertTimeToUtc(dateNow)} UTC.");
Dim dateNow As Date = Date.Now
Console.WriteLine("The date and time are {0} UTC.", _
TimeZoneInfo.ConvertTimeToUtc(dateNow))
日付と時刻の値が現地時刻または UTC を表していない場合、 ToUniversalTime メソッドは誤った結果を返す可能性があります。 ただし、 TimeZoneInfo.ConvertTimeToUtc メソッドを使用して、指定したタイム ゾーンから日付と時刻を変換できます。 宛先タイム ゾーンを表す TimeZoneInfo オブジェクトの取得の詳細については、「 ローカル システムで定義されているタイム ゾーンの検索」を参照してください。 次のコードでは、 TimeZoneInfo.ConvertTimeToUtc メソッドを使用して東部標準時を 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 {TimeZoneInfo.ConvertTimeToUtc(easternTime, easternZone)} UTC.");
}
catch (TimeZoneNotFoundException)
{
Console.WriteLine($"Unable to find the {easternZoneId} zone in the registry.");
}
catch (InvalidTimeZoneException)
{
Console.WriteLine($"Registry data on the {easternZoneId} zone has been corrupted.");
}
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
TimeZoneInfo.ConvertTimeToUtc メソッドは、DateTime オブジェクトの Kind プロパティとタイム ゾーンが一致しない場合にArgumentExceptionをスローします。 Kind プロパティがDateTimeKind.Localされていても、TimeZoneInfo オブジェクトがローカル タイム ゾーンを表していない場合、または Kind プロパティがDateTimeKind.Utcされているが、TimeZoneInfo オブジェクトがTimeZoneInfo.Utc等しくない場合、不一致が発生します。
これらのメソッドはすべて、パラメーターとして DateTime 値を受け取り、 DateTime 値を返します。 DateTimeOffset値の場合、DateTimeOffset構造体には、現在のインスタンスの日時を UTC に変換するToUniversalTime インスタンス メソッドがあります。 次の例では、 ToUniversalTime メソッドを呼び出して、現地時刻とその他の複数回を 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: {localTime}");
Console.WriteLine();
// Convert local time to offset 0 and assign to otherTime
otherTime = localTime.ToOffset(TimeSpan.Zero);
Console.WriteLine($"Other time: {otherTime}");
Console.WriteLine($"{localTime} = {otherTime}: {localTime.Equals(otherTime)}");
Console.WriteLine($"{localTime} exactly equals {otherTime}: {localTime.EqualsExact(otherTime)}");
Console.WriteLine();
// Convert other time to UTC
universalTime = localTime.ToUniversalTime();
Console.WriteLine($"Universal time: {universalTime}");
Console.WriteLine($"{otherTime} = {universalTime}: {universalTime.Equals(otherTime)}");
Console.WriteLine($"{otherTime} exactly equals {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 を指定されたタイム ゾーンに変換する
UTC を現地時刻に変換するには、次の「 UTC から現地時刻への変換 」セクションを参照してください。 指定したタイム ゾーンの時刻に UTC を変換するには、 ConvertTimeFromUtc メソッドを呼び出します。 このメソッドは、次の 2 つのパラメーターを受け取ります。
次のコードは、UTC を標準時に変換します。
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 から現地時刻への変換
UTC を現地時刻に変換するには、時刻を変換するDateTime オブジェクトのToLocalTime メソッドを呼び出します。 次の表に示すように、メソッドの正確な動作は、オブジェクトの Kind プロパティの値によって異なります。
DateTime.Kind |
変換 |
---|---|
DateTimeKind.Local |
変更せずに DateTime 値を返します。 |
DateTimeKind.Unspecified |
DateTime値が UTC であり、UTC を現地時刻に変換することを前提としています。 |
DateTimeKind.Utc |
DateTime値を現地時刻に変換します。 |
注
TimeZone.ToLocalTime メソッドは、DateTime.ToLocalTime
メソッドと同じように動作します。 変換する 1 つのパラメーター (日付と時刻の値) を受け取ります。
static
(Visual Basic のShared
) TimeZoneInfo.ConvertTimeメソッドを使用して、指定したタイム ゾーンの時刻を現地時刻に変換することもできます。 この手法については、次のセクションで説明します。
任意の 2 つのタイム ゾーン間の変換
TimeZoneInfo クラスの次の 2 つのstatic
(Visual Basic のShared
) のいずれかを使用して、任意の 2 つのタイム ゾーン間で変換できます。
-
このメソッドのパラメーターは、変換する日付と時刻の値、日付と時刻の値のタイム ゾーンを表す
TimeZoneInfo
オブジェクト、および日付と時刻の値を変換するタイム ゾーンを表すTimeZoneInfo
オブジェクトです。 -
このメソッドのパラメーターは、変換する日付と時刻の値、日付と時刻の値のタイム ゾーンの識別子、および日付と時刻の値を変換するタイム ゾーンの識別子です。
どちらの方法でも、変換する日付と時刻の値の Kind プロパティと、そのタイム ゾーンを表す TimeZoneInfo オブジェクトまたはタイム ゾーン識別子が相互に対応している必要があります。 それ以外の場合は、ArgumentException が投げられます。 たとえば、日付と時刻の値の Kind
プロパティが DateTimeKind.Local
されている場合、メソッドにパラメーターとして渡された TimeZoneInfo
オブジェクトが TimeZoneInfo.Local
と等しくない場合、例外がスローされます。 メソッドにパラメーターとして渡される識別子が TimeZoneInfo.Local.Id
と等しくない場合も例外がスローされます。
次の例では、 ConvertTime メソッドを使用してハワイ標準時から現地時刻に変換します。
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 値の変換
DateTimeOffsetオブジェクトによって表される日付と時刻の値は、オブジェクトがインスタンス化された時点でタイム ゾーンとの関連付けが解除されるため、タイム ゾーンに完全には対応していません。 ただし、多くの場合、アプリケーションでは、特定のタイム ゾーンの時刻ではなく、UTC からの 2 つの異なるオフセットに基づいて日付と時刻を変換する必要があります。 この変換を実行するには、現在のインスタンスの ToOffset メソッドを呼び出します。 メソッドの単一パラメーターは、メソッドが返す新しい日付と時刻の値のオフセットです。
たとえば、Web ページに対するユーザー要求の日付と時刻が既知で、MM/dd/yyyy hh:mm:ss zzzz 形式の文字列としてシリアル化されている場合、次の ReturnTimeOnServer
メソッドは、この日付と時刻の値を Web サーバー上の日付と時刻に変換します。
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 より 5 時間前のタイム ゾーンの日付と時刻を表し、米国太平洋標準時ゾーンにあるサーバーの "9/1/2007 3:32:07 AM -07:00" を返します。
TimeZoneInfo クラスには、ToOffset(TimeSpan)値を使用してタイム ゾーン変換を実行するTimeZoneInfo.ConvertTime(DateTimeOffset, TimeZoneInfo) メソッドのオーバーロードも含まれています。 メソッドのパラメーターは、 DateTimeOffset 値と、時刻の変換先となるタイム ゾーンへの参照です。 メソッド呼び出しは、 DateTimeOffset 値を返します。 たとえば、前の例の ReturnTimeOnServer
メソッドを次のように書き換えて、 ConvertTime(DateTimeOffset, TimeZoneInfo) メソッドを呼び出します。
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
こちらもご覧ください
.NET