Como: Permitir que os usuários resolvam tempos ambíguos
Um tempo ambíguo é um tempo que mapeia para mais de um Tempo Universal Coordenado (UTC). Ocorre quando a hora do relógio é ajustada de volta no tempo, como durante a transição do horário de verão de um fuso horário de verão para seu horário padrão. Ao lidar com um tempo ambíguo, você pode seguir um destes procedimentos:
Se o tempo ambíguo for um item de dados inseridos pelo usuário, você pode deixar para o usuário resolver a ambiguidade.
Faça uma suposição sobre como o tempo é mapeado para UTC. Por exemplo, você pode supor que uma hora ambígua é sempre expressa na hora padrão do fuso horário.
Este tópico mostra como permitir que um usuário resolva um tempo ambíguo.
Para permitir que um usuário resolva um tempo ambíguo
Obtenha a data e a hora inseridas pelo usuário.
Chame o IsAmbiguousTime método para determinar se o tempo é ambíguo.
Se a hora for ambígua, chame o GetAmbiguousTimeOffsets método para recuperar uma matriz de TimeSpan objetos. Cada elemento na matriz contém um deslocamento UTC para o qual o tempo ambíguo pode ser mapeado.
Permita que o usuário selecione o deslocamento desejado.
Obtenha a data e hora UTC subtraindo o deslocamento selecionado pelo usuário da hora local.
Chame o
static
método (Shared
no Visual Basic .NET) SpecifyKind para definir a propriedade do valor de data e hora UTC Kind como DateTimeKind.Utc.
Exemplo
O exemplo a seguir solicita que o usuário insira uma data e hora e, se for ambíguo, permite que o usuário selecione a hora UTC para a qual a hora ambígua é mapeada.
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($"{ctr}.) {offsets[ctr].Hours} hours, {offsets[ctr].Minutes} 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($"{inputDate} local time corresponds to {utcDate} {utcDate.Kind.ToString()}.");
}
else
{
utcDate = inputDate.ToUniversalTime();
Console.WriteLine($"{inputDate} local time corresponds to {utcDate} {utcDate.Kind.ToString()}.");
}
}
private static DateTime GetUserDateTime()
{
// Flag to exit loop if date is valid.
bool exitFlag = false;
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;
}
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
O núcleo do código de exemplo usa uma matriz de TimeSpan objetos para indicar possíveis deslocamentos do tempo ambíguo do UTC. No entanto, é improvável que essas compensações sejam significativas para o usuário. Para esclarecer o significado das compensações, o código também observa se um deslocamento representa a hora padrão do fuso horário local ou seu horário de verão. O código determina qual hora é padrão e qual hora é luz do dia, comparando o deslocamento com o valor da BaseUtcOffset propriedade. Esta propriedade indica a diferença entre o UTC e a hora padrão do fuso horário.
Neste exemplo, todas as referências ao fuso horário local são feitas através da TimeZoneInfo.Local propriedade, o fuso horário local nunca é atribuído a uma variável de objeto. Essa é uma prática recomendada porque uma chamada para o método invalida todos os TimeZoneInfo.ClearCachedData objetos aos quais o fuso horário local está atribuído.