Como: Exibir informações de tempo e de data localizado a usuários da Web

Devido a uma página da Web poder ser exibido em qualquer lugar no mundo, operações que analisam e formatam valores de data e hora não devem confiar em um formato padrão (que geralmente é o formato da cultura local do servidor Web) durante a interação com o usuário. Em vez disso, os formulários da Web que lidam com sequências de caracteres de data e hora inseridas pelo usuário devem analisar as sequências usando a cultura preferencial do usuário. Da mesma forma, dados de data e hora devem ser exibidos para o usuário em um formato que está de acordo com a cultura do usuário. Este tópico mostra como fazer isso.

Para analisar sequências de caracteres de Data e hora inseridas pelo usuário

  1. Determine se a matriz de sequências de caracteres retornada pela propriedade HttpRequest.UserLanguages está preenchida. Se não estiver, vá para a etapa 6.

  2. Se a matriz de sequências de caracteres retornada pela propriedade UserLanguages estiver preenchida, recupere o primeiro elemento. O primeiro elemento indica a região ou idioma preferencial ou padrão do usuário.

  3. Instanciar um CultureInfo o objeto que representa o usuário preferencial cultura chamando o CultureInfo.CultureInfo(String, Boolean) construtor.

  4. Chame o método TryParse ou o método Parse dos tipos DateTime ou DateTimeOffset para tentar a conversão. Use uma sobrecarga do método TryParse ou Parse com um parâmetro provider, e passe a ele um dos seguintes:

  5. Se a conversão falhar, repita as etapas de 2 a 4 para cada elemento restante na matriz de sequências de caracteres retornada pela propriedade UserLanguages.

  6. Se a conversão ainda falhar ou se o matriz de sequências de caracteres retornada pela propriedade UserLanguages estiver vazia, analise a sequência de caracteres usando a cultura invariável, que é retornada pela propriedade CultureInfo.InvariantCulture.

Para analisar a data e hora locais do pedido do usuário

  1. Adicione um controle HiddenField ao formulário.

  2. Crie uma função de JavaScript que manipula o evento onClick de um botão Submit escrevendo a data e hora atuais e o deslocamento da zona de tempo local do Tempo Universal Coordenado (UTC) para a propriedade Value. Use um delimitador (como um ponto-e-vírgula) para separar os dois componentes de sequência de caracteres.

  3. Use o evento PreRender do formulário da Web para inserir a função no fluxo de saída do HTML, passando o texto do script para o método ClientScriptManager.RegisterClientScriptBlock(Type, String, String, Boolean).

  4. Conecte o manipulador de eventos ao evento onClick do botão Submit fornecendo o nome da função JavaScript ao atributo OnClientClick do botão Submit.

  5. Crie um manipulador para o evento Click do botão Submit.

  6. No manipulador de eventos, determine se a matriz de sequências de caracteres retornada pela propriedade HttpRequest.UserLanguages é preenchida. Se não estiver, vá para a etapa 14.

  7. Se a matriz de sequências de caracteres retornada pela propriedade UserLanguages estiver preenchida, recupere o primeiro elemento. O primeiro elemento indica a região ou idioma preferencial ou padrão do usuário.

  8. Instanciar um CultureInfo o objeto que representa o usuário preferencial cultura chamando o CultureInfo.CultureInfo(String, Boolean) construtor.

  9. Passe a sequência de caracteres atribuída à propriedade Value para o método Split para armazenar a representação de sequência de caracteres da data e hora locais do deslocamento da zona de tempo local do usuário em elementos separados na matriz.

  10. Chame tanto o método DateTime.Parse ou o método DateTime.TryParse(String, IFormatProvider, DateTimeStyles, DateTime) para converter uma data e hora do pedido do usuário em um valor DateTime. Use uma sobrecarga do método com um parâmetro provider, e passe a ele um dos seguintes:

  11. Se a operação de análise na etapa 10 falhar, vá para a etapa 13. Caso contrário, chamar o UInt32.Parse(String) método para converter a representação de seqüência de caracteres de compensação de fuso horário do usuário para um inteiro.

  12. Crie uma instância DateTimeOffset representando a hora local do usuário chamando o construtor DateTimeOffset.DateTimeOffset(DateTime, TimeSpan).

  13. Se a conversão na etapa 10 falhar, repita as etapas de 7 a 12 para cada elemento restante na matriz de sequências de caracteres retornada pela propriedade UserLanguages.

  14. Se a conversão ainda falhar ou se o matriz de sequências de caracteres retornada pela propriedade UserLanguages estiver vazia, analise a sequência de caracteres usando a cultura invariável, que é retornada pela propriedade CultureInfo.InvariantCulture. Em seguida, repita as etapas 7 a 12.

O resultado é um objeto DateTimeOffset que representa a hora local do usuário da sua página da Web. Em seguida, você pode determinar o UTC equivalente chamando o método ToUniversalTime. Você também pode determinar a data e hora equivalentes no seu servidor Web, chamando o método TimeZoneInfo.ConvertTime(DateTimeOffset, TimeZoneInfo) e passando um valor de TimeZoneInfo.Local como a zona de tempo em que a hora será convertida.

Exemplo

O exemplo a seguir contém tanto a fonte do HTML quanto o código para um formulário da Web ASP.NET que pede ao usuário para inserir um valor de data e hora. Um script lateral do cliente também grava informações de data e hora locais do pedido do usuário e do deslocamento da zona de tempo do usuário do UTC num campo oculto. Essa informação é, em seguida, analisada pelo servidor, que retorna uma página da Web que exibe a entrada do usuário. Ele também exibe a data e hora da solicitação do usuário usando a hora local do usuário, a hora no servidor e o UTC.


<%@ Page Language="VB" %>
<%@ Import  Namespace="System.Globalization" %> 
<%@ Assembly Name="System.Core" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">

    Protected Sub OKButton_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles OKButton.Click
        Dim locale As String = ""
        Dim styles As DateTimeStyles = DateTimeStyles.AllowInnerWhite Or DateTimeStyles.AllowLeadingWhite Or _
                                       DateTimeStyles.AllowTrailingWhite
        Dim inputDate, localDate As Date
        Dim localDateOffset As DateTimeOffset
        Dim integerOffset As Integer
        Dim result As Boolean

        ' Exit if input is absent.
        If String.IsNullOrEmpty(Me.DateString.Text) Then Exit Sub

        ' Hide form elements.
        Me.DateForm.Visible = False

        ' Create array of CultureInfo objects
        Dim cultures(Request.UserLanguages.Length) As CultureInfo
        For ctr As Integer = Request.UserLanguages.GetLowerBound(0) To Request.UserLanguages.GetUpperBound(0)
            locale = Request.UserLanguages(ctr)
            If Not String.IsNullOrEmpty(locale) Then
                ' Remove quality specifier, if present.
                If locale.Contains(";") Then _
                   locale = Left(locale, InStr(locale, ";") - 1)
                Try
                   cultures(ctr) = New CultureInfo(Request.UserLanguages(ctr), False)
                Catch
                End Try
            Else
                cultures(ctr) = CultureInfo.CurrentCulture
            End If
        Next
        cultures(Request.UserLanguages.Length) = CultureInfo.InvariantCulture
        ' Parse input using each culture.
        For Each culture As CultureInfo In cultures
            result = Date.TryParse(Me.DateString.Text, culture.DateTimeFormat, styles, inputDate)
            If result Then Exit For
        Next
        ' Display result to user.
        If result Then
            Response.Write("<P />")
            Response.Write("The date you input was " + Server.HtmlEncode(CStr(Me.DateString.Text)) + "<BR />")
        Else
            ' Unhide form.
            Me.DateForm.Visible = True
            Response.Write("<P />")
            Response.Write("Unable to recognize " + Server.HtmlEncode(Me.DateString.Text) + ".<BR />")
        End If

        ' Get date and time information from hidden field.
        Dim dates() As String = Request.Form.Item("DateInfo").Split(";")

        ' Parse local date using each culture.
        For Each culture As CultureInfo In cultures
            result = Date.TryParse(dates(0), culture.DateTimeFormat, styles, localDate)
            If result Then Exit For
        Next
        ' Parse offset 
        result = Integer.TryParse(dates(1), integerOffset)
        ' Instantiate DateTimeOffset object representing user's local time
        If result Then
            Try
                localDateOffset = New DateTimeOffset(localDate, New TimeSpan(0, -integerOffset, 0))
            Catch ex As Exception
                result = False
            End Try
        End If
        ' Display result to user.
        If result Then
            Response.Write("<P />")
            Response.Write("Your local date and time is " + localDateOffset.ToString() + ".<BR />")
            Response.Write("The date and time on the server is " & _
                           TimeZoneInfo.ConvertTime(localDateOffset, _
                                                    TimeZoneInfo.Local).ToString() & ".<BR />")
            Response.Write("Coordinated Universal Time is " + localDateOffset.ToUniversalTime.ToString() + ".<BR />")
        Else
            Response.Write("<P />")
            Response.Write("Unable to recognize " + Server.HtmlEncode(dates(0)) & ".<BR />")
        End If
    End Sub

    Protected Sub Page_PreRender(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.PreRender
        Dim script As String = "function AddDateInformation() { " & vbCrLf & _
                  "var today = new Date();" & vbCrLf & _
                  "document.DateForm.DateInfo.value = today.toLocaleString() + " & Chr(34) & Chr(59) & Chr(34) & " + today.getTimezoneOffset();" & vbCrLf & _
                  " }"
        ' Register client script
        Dim scriptMgr As ClientScriptManager = Page.ClientScript
        scriptMgr.RegisterClientScriptBlock(Me.GetType(), "SubmitOnClick", script, True)
    End Sub
</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
    <title>Parsing a Date and Time Value</title>
</head>
<body>
    <form id="DateForm" runat="server">
    <div>
    <center>
       <asp:Label ID="Label1" runat="server" Text="Enter a Date and Time:" Width="248px"></asp:Label>
       <asp:TextBox ID="DateString" runat="server" Width="176px"></asp:TextBox><br />
    </center>       
    <br />
    <center>
    <asp:Button ID="OKButton" runat="server" Text="Button"  
            OnClientClick="AddDateInformation()" onclick="OKButton_Click" />
    <asp:HiddenField ID="DateInfo"  Value=""  runat="server" />
    </center>
    <br />
    </div>
    </form>
</body>
</html>

<%@ Page Language="C#" %>
<%@ Import Namespace="System.Globalization" %>
<%@ Assembly Name="System.Core" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">

    protected void OKButton_Click(object sender, EventArgs e)
    {
        string locale = "";
        DateTimeStyles styles = DateTimeStyles.AllowInnerWhite | DateTimeStyles.AllowLeadingWhite |
                                       DateTimeStyles.AllowTrailingWhite;
        DateTime inputDate;
        DateTime localDate = DateTime.Now;
        DateTimeOffset localDateOffset = DateTimeOffset.Now;
        int integerOffset;
        bool result = false;

        // Exit if input is absent.
        if (string.IsNullOrEmpty(this.DateString.Text)) return;

        // Hide form elements.
        this.DateForm.Visible = false;

        // Create array of CultureInfo objects
        CultureInfo[] cultures = new CultureInfo[Request.UserLanguages.Length + 1];
        for (int ctr = Request.UserLanguages.GetLowerBound(0); ctr <= Request.UserLanguages.GetUpperBound(0);
             ctr++)
        {
            locale = Request.UserLanguages[ctr];
            if (! string.IsNullOrEmpty(locale))
            {

                // Remove quality specifier, if present.
                if (locale.Contains(";"))
                   locale = locale.Substring(locale.IndexOf(';') -1);
                try
                {
                    cultures[ctr] = new CultureInfo(Request.UserLanguages[ctr], false);
                }
                catch (Exception) { }
            }
            else
            {
                cultures[ctr] = CultureInfo.CurrentCulture;
            }
        }
        cultures[Request.UserLanguages.Length] = CultureInfo.InvariantCulture;
        // Parse input using each culture.
        foreach (CultureInfo culture in cultures)
        {
            result = DateTime.TryParse(this.DateString.Text, culture.DateTimeFormat, styles, out inputDate);
            if (result) break;
        }
        // Display result to user.
        if (result)
        {
            Response.Write("<P />");
            Response.Write("The date you input was " + Server.HtmlEncode(this.DateString.Text) + "<BR />");
        }
        else
        {
            // Unhide form.
            this.DateForm.Visible = true;
            Response.Write("<P />");
            Response.Write("Unable to recognize " + Server.HtmlEncode(this.DateString.Text) + ".<BR />");
        }

        // Get date and time information from hidden field.
        string[] dates= Request.Form["DateInfo"].Split(';');

        // Parse local date using each culture.
        foreach (CultureInfo culture in cultures)
        {
            result = DateTime.TryParse(dates[0], culture.DateTimeFormat, styles, out localDate);
            if (result) break;
        }
        // Parse offset 
        result = int.TryParse(dates[1], out integerOffset);
        // Instantiate DateTimeOffset object representing user's local time
        if (result) 
        {
            try
            {
                localDateOffset = new DateTimeOffset(localDate, new TimeSpan(0, -integerOffset, 0));
            }
            catch (Exception)
            {
                result = false;
            }
        }
        // Display result to user.
        if (result)
        {
            Response.Write("<P />");
            Response.Write("Your local date and time is " + localDateOffset.ToString() + ".<BR />");
            Response.Write("The date and time on the server is " + 
                           TimeZoneInfo.ConvertTime(localDateOffset, 
                                                    TimeZoneInfo.Local).ToString() + ".<BR />");
            Response.Write("Coordinated Universal Time is " + localDateOffset.ToUniversalTime().ToString() + ".<BR />");
        }
        else
        {
            Response.Write("<P />");
            Response.Write("Unable to recognize " + Server.HtmlEncode(dates[0]) + ".<BR />");
        }
    }

    protected void Page_PreRender(object sender, System.EventArgs e)
    {
        string script = "function AddDateInformation() { \n" +
                  "var today = new Date();\n" +
                  "document.DateForm.DateInfo.value = today.toLocaleString() + \";\" + today.getTimezoneOffset();\n" +
                  " }";
        // Register client script
        ClientScriptManager scriptMgr = Page.ClientScript;
        scriptMgr.RegisterClientScriptBlock(this.GetType(), "SubmitOnClick", script, true);
    }

</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
    <title>Parsing a Date and Time Value</title>
</head>
<body>
    <form id="DateForm" runat="server">
    <div>
    <center>
       <asp:Label ID="Label1" runat="server" Text="Enter a Date and Time:" Width="248px"></asp:Label>
       <asp:TextBox ID="DateString" runat="server" Width="176px"></asp:TextBox><br />
    </center>       
    <br />
    <center>
    <asp:Button ID="OKButton" runat="server" Text="Button"  
            OnClientClick="AddDateInformation()" onclick="OKButton_Click" />
    <asp:HiddenField ID="DateInfo"  Value=""  runat="server" />
    </center>
    <br />
    </div>
    </form>
</body>
</html>

O script lateral do cliente chama o método toLocaleString do JavaScript. Isso produz uma sequência de caracteres que segue as convenções de formatação da localidade do usuário, que é mais provável a ser analisado com sucesso no servidor.

A propriedade HttpRequest.UserLanguages é preenchida com os nomes de cultura que estão contidos em cabeçalhos Accept-Language incluídos em uma solicitação HTTP. No entanto, nem todos os navegadores incluem cabeçalhos Accept-Language em suas solicitações, e os usuários também podem suprimir os cabeçalhos totalmente. Isso torna importante ter uma cultura de fallback ao analisar entradas do usuário. Normalmente, a cultura de fallback é a cultura invariável retornada por CultureInfo.InvariantCulture. Os usuários também podem fornecer ao Internet Explorer nomes de cultura que eles inserem em um caixa de texto, o que cria a possibilidade dos nomes cultura não serem válidos. Isso torna importante usar tratamento de exceções ao instanciar um objeto CultureInfo.

Quando recuperada de um solicitação HTTP enviada pelo Internet Explorer, a matriz HttpRequest.UserLanguages é preenchida por ordem de preferência do usuário. O primeiro elemento na matriz contém o nome da cultura/região primária do usuário. Se a matriz contém quaisquer itens adicionais, o Internet Explorer arbitrariamente atribui a eles um especificador de qualidade, que é delimitado do nome da cultura por um ponto-e-vírgula. Por exemplo, uma entrada para a cultura fr-FR pode tomar a forma fr-FR;q=0.7.

As chamadas de exemplo do CultureInfo construtor com sua useUserOverride parâmetro definido como false para criar um novo CultureInfo objeto. Isso garante que, se o nome de cultura é o nome da cultura padrão no servidor, o novo CultureInfo contém as configurações padrão de uma cultura de objeto criado pelo construtor da classe e não reflete qualquer configuração substituída usando o servidor regionais e idioma aplicativo. Os valores de qualquer configuração substituída no servidor provavelmente existe no sistema do usuário ou ser refletido na entrada do usuário.

Como este exemplo analisa duas representações de sequência de caracteres de uma data e hora (uma entrada pelo usuário, a outra armazenada para o campo oculto), ele define os possíveis objetos CultureInfo que podem ser necessários com antecedência. Ele cria uma matriz de objetos CultureInfo que é maior do que o número de elementos retornados pela propriedade HttpRequest.UserLanguages. Ele instancia um objeto CultureInfo para cada sequência de caracteres de linguagem/região, e também instancia um objeto CultureInfo que representa CultureInfo.InvariantCulture.

Seu código pode chamar tanto o método Parse quanto o método TryParse para converter uma representação de sequência de caracteres de data e hora em um valor DateTime. Chamadas repetidas para um método de análise podem ser necessárias para uma única operação de análise. Como resultado, o método TryParse é melhor, porque ele retorna false se uma operação de análise falhar. Por outro lado, manipular as exceções repetidas que podem ser lançadas pelo método Parse pode ser uma proposta muito cara em um aplicativo da Web.

Compilando o código

Para compilar o código, crie um ASP.NET página da Web sem um código-behind. Copie o exemplo para a página da Web para que ele substitua todo o código existente. O ASP.NET página da Web deve conter os seguintes controles:

  • Um controle Label, não mencionado no código. Defina sua propriedade Text como "Digite um número:".

  • Um controle TextBox chamado DateString.

  • Um controle Button chamado OKButton. Defina sua propriedade Text como "OK".

  • Um controle HiddenField chamado DateInfo.

Segurança

Para evitar que um usuário insira script no fluxo HTML, a entrada do usuário nunca deve ser ecoada diretamente de volta na resposta do servidor. Em vez disso, ela deve ser codificada usando o método HttpServerUtility.HtmlEncode.

Consulte também

Conceitos

Executar operações de formatação

Sequências de caracteres de formato padrão de data e hora

Sequências de Caracteres de Formato Personalizado de Data e Hora

Análisando Sequências de Caracteres de Data e Horário