方法 : ユーザーがあいまいな時刻を解決できるようにする
更新 : 2007 年 11 月
あいまいな時刻とは、複数の世界協定時刻 (UTC: Coordinated Universal Time) に対応する時刻です。このようなことは、あるタイム ゾーンで夏時間から標準時間に移行する際など、クロック時刻を元に戻すときに発生します。あいまいな時刻は、次のいずれかの方法で対処できます。
あいまいな時刻がユーザーによって入力されたデータの項目である場合は、あいまいさの解決をユーザーに任せることができます。
UTC に対する時刻の対応方法を想定します。たとえば、あいまいな時刻は常にタイム ゾーンの標準時刻を表す、などと想定できます。
このトピックでは、あいまいな時刻をユーザーに解決させる方法について説明します。
あいまいな時刻をユーザーに解決させるには
ユーザーが入力した日付と時刻を取得します。
IsAmbiguousTime メソッドを呼び出して、時刻があいまいかどうかを判定します。
時刻があいまいな場合は、GetAmbiguousTimeOffsets メソッドを呼び出して、TimeSpan オブジェクトの配列を取得します。配列の各要素には、あいまいな時刻に対応する可能性のある UTC オフセットが格納されています。
適切なオフセットを選択するようにユーザーに促します。
ユーザーが選択したオフセットを現地時刻から減算して、UTC の日付と時刻を取得します。
static (Visual Basic .NET では Shared) SpecifyKind メソッドを呼び出して、UTC の日時の値の Kind プロパティに DateTimeKind.Utc を設定します。
使用例
次の例では、日付と時刻の入力をユーザーに要求し、入力された値があいまいな場合は、あいまいな時刻に対応する UTC 時刻をユーザーが選択できるようにします。
Private Sub GetUserDateInput()
' Get date and time from user
Dim inputDate As Date = GetUserDateTime()
Dim utcDate As Date
' Exit if date has no significant value
If inputDate = Date.MinValue Then Exit Sub
If TimeZoneInfo.Local.IsAmbiguousTime(inputDate) Then
Console.WriteLine("The date you've entered is ambiguous.")
Console.WriteLine("Please select the correct offset from Universal Coordinated Time:")
Dim offsets() As TimeSpan = TimeZoneInfo.Local.GetAmbiguousTimeOffsets(inputDate)
For ctr As Integer = 0 to offsets.Length - 1
Dim zoneDescription As String
If offsets(ctr).Equals(TimeZoneInfo.Local.BaseUtcOffset) Then
zoneDescription = TimeZoneInfo.Local.StandardName
Else
zoneDescription = TimeZoneInfo.Local.DaylightName
End If
Console.WriteLine("{0}.) {1} hours, {2} minutes ({3})", _
ctr, offsets(ctr).Hours, offsets(ctr).Minutes, zoneDescription)
Next
Console.Write("> ")
Dim selection As Integer = CInt(Console.ReadLine())
' Convert local time to UTC, and set Kind property to DateTimeKind.Utc
utcDate = Date.SpecifyKind(inputDate - offsets(selection), DateTimeKind.Utc)
Console.WriteLine("{0} local time corresponds to {1} {2}.", inputDate, utcDate, utcDate.Kind.ToString())
Else
utcDate = inputDate.ToUniversalTime()
Console.WriteLine("{0} local time corresponds to {1} {2}.", inputDate, utcDate, utcDate.Kind.ToString())
End If
End Sub
Private Function GetUserDateTime() As Date
Dim exitFlag As Boolean = False ' flag to exit loop if date is valid
Dim dateString As String
Dim inputDate As Date = Date.MinValue
Console.Write("Enter a local date and time: ")
Do While Not exitFlag
dateString = Console.ReadLine()
If dateString.ToUpper = "E" Then exitFlag = True
If Date.TryParse(dateString, inputDate) Then
exitFlag = true
Else
Console.Write("Enter a valid date and time, or enter 'e' to exit: ")
End If
Loop
Return inputDate
End Function
private void GetUserDateInput()
{
// Get date and time from user
DateTime inputDate = GetUserDateTime();
DateTime utcDate;
// Exit if date has no significant value
if (inputDate == DateTime.MinValue) return;
if (TimeZoneInfo.Local.IsAmbiguousTime(inputDate))
{
Console.WriteLine("The date you've entered is ambiguous.");
Console.WriteLine("Please select the correct offset from Universal Coordinated Time:");
TimeSpan[] offsets = TimeZoneInfo.Local.GetAmbiguousTimeOffsets(inputDate);
for (int ctr = 0; ctr < offsets.Length; ctr++)
{
Console.WriteLine("{0}.) {1} hours, {2} minutes", ctr, offsets[ctr].Hours, offsets[ctr].Minutes);
}
Console.Write("> ");
int selection = Convert.ToInt32(Console.ReadLine());
// Convert local time to UTC, and set Kind property to DateTimeKind.Utc
utcDate = DateTime.SpecifyKind(inputDate - offsets[selection], DateTimeKind.Utc);
Console.WriteLine("{0} local time corresponds to {1} {2}.", inputDate, utcDate, utcDate.Kind.ToString());
}
else
{
utcDate = inputDate.ToUniversalTime();
Console.WriteLine("{0} local time corresponds to {1} {2}.", inputDate, utcDate, utcDate.Kind.ToString());
}
}
private DateTime GetUserDateTime()
{
bool exitFlag = false; // flag to exit loop if date is valid
string dateString;
DateTime inputDate = DateTime.MinValue;
Console.Write("Enter a local date and time: ");
while (! exitFlag)
{
dateString = Console.ReadLine();
if (dateString.ToUpper() == "E")
exitFlag = true;
if (DateTime.TryParse(dateString, out inputDate))
exitFlag = true;
else
Console.Write("Enter a valid date and time, or enter 'e' to exit: ");
}
return inputDate;
}
この例の中核となるコードでは、TimeSpan オブジェクトの配列を使用して、UTC からのあいまいな時刻のオフセットとして可能性のある値を示しています。しかし、これらのオフセットはユーザーにとっては意味がないものと考えられます。オフセットの意味を明確にするため、コードでは、オフセットがローカル タイム ゾーンの標準時刻を表すのか、または夏時間を表すのかも示します。時刻が標準時刻なのか夏時間なのかを判定するには、オフセットを BaseUtcOffset プロパティの値と比較します。このプロパティは、UTC とタイム ゾーンの標準時刻の間の差を示します。
この例では、ローカル タイム ゾーンに対するすべての参照は、TimeZoneInfo.Local プロパティを通して行います。ローカル タイム ゾーンをオブジェクト変数に割り当てることはしません。TimeZoneInfo.ClearCachedData メソッドを呼び出すと、ローカル タイム ゾーンが割り当てられているオブジェクトは無効になるので、これが推奨される方法です。
コードのコンパイル方法
この例で必要な要素は次のとおりです。
System.Core.dll への参照をプロジェクトに追加する。
System 名前空間を using ステートメントでインポートする (C# のコードで必要)。