Partilhar via


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

  1. Obtenha a data e a hora inseridas pelo usuário.

  2. Chame o IsAmbiguousTime método para determinar se o tempo é ambíguo.

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

  4. Permita que o usuário selecione o deslocamento desejado.

  5. Obtenha a data e hora UTC subtraindo o deslocamento selecionado pelo usuário da hora local.

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

Consulte também