Sdílet prostřednictvím


Postupy: Zobrazit lokalizované informace data a času uživatelům webu

Protože lze webovou stránku zobrazit kdekoli na světě, operace pro analýzu a formátování data a času by při interakci s uživatelem neměli spoléhat na výchozí formát (což je nejčastěji formát jazykové verze místního webového serveru). Místo toho by webové formuláře, které zpracovávají řetězce data a času zadávané uživatelem, měly analyzovat řetězce pomocí upřednostňované jazykové verze daného uživatele. Podobně by měly být datum a čas zobrazeny uživateli ve formátu, který odpovídá jazykové verzi daného uživatele. Toto téma ukazuje, jak toto provést.

Chcete-li analyzovat řetězce data a času zadané uživatelem

  1. Určete, zda je naplněno pole řetězců vrácené vlastností HttpRequest.UserLanguages. Pokud tomu tak není, pokračujte krokem 6.

  2. Pokud je naplněno pole řetězců vrácené vlastností UserLanguages, načtěte jeho první prvek. První prvek označuje výchozí nastavení uživatele nebo preferovaný jazyk a oblast.

  3. Vytvořte instanci objektu CultureInfo, který představuje preferovanou jazykovou verzi uživatele, voláním konstruktoru CultureInfo.CultureInfo(String, Boolean).

  4. Zavolejte metodu TryParse nebo Parse typu DateTime nebo DateTimeOffset pro pokus o převod. Použijte přetížení metody TryParse nebo Parse s parametrem provider a předejte jí kterýkoli ze dvou následujících objektů:

  5. Pokud převod selže, opakujte kroky 2 až 4 pro každý zbývající element v poli řetězců vráceného vlastností UserLanguages.

  6. Pokud se převod stále nedaří nebo pokud je pole řetězců vrácené vlastností UserLanguages prázdné, analyzujte řetězec pomocí neutrální jazykové verze, která je vrácena vlastností CultureInfo.InvariantCulture.

Chcete-li analyzovat místní datum a čas požadavku uživatele

  1. Přidejte ovládací prvek HiddenField do webového formuláře.

  2. Vytvořte funkci jazyka JavaScript, která zpracovává událost onClick tlačítka Submit pomocí zápisu aktuálního data a času a posunu místního časového pásma od času UTC do vlastnosti Value. Použijte oddělovač (jako je středník) k oddělení těchto dvou součástí řetězce.

  3. Použijte událost PreRender webového formuláře, která vloží funkci do výstupního datového proudu HTML předáním textu skriptu metodě ClientScriptManager.RegisterClientScriptBlock(Type, String, String, Boolean).

  4. Připojte obslužnou rutinu události k tlačítku Submit a jeho události onClick poskytnutím názvu funkce jazyka JavaScript atributu OnClientClick tlačítka Submit.

  5. Vytvořte obslužnou rutiny pro tlačítko Submit a jeho událost Click.

  6. V obslužné rutině události zjistěte, zda je pole řetězců vrácené vlastností HttpRequest.UserLanguages naplněné. Pokud tomu tak není, pokračujte krokem 14.

  7. Pokud je pole řetězců vrácené vlastností UserLanguages naplněno, získejte jeho první prvek. První prvek označuje výchozí nastavení uživatele nebo preferovaný jazyk a oblast.

  8. Vytvořte instanci objektu CultureInfo, který představuje preferovanou jazykovou verzi uživatele, voláním konstruktoru CultureInfo.CultureInfo(String, Boolean).

  9. Předejte řetězec přiřazený vlastnosti Value metodě Split pro uložení řetězcového vyjádření místního data a času uživatele a posunu místního časového pásma uživatele do samostatných prvků pole.

  10. Zavolejte metodu DateTime.Parse nebo metodu DateTime.TryParse(String, IFormatProvider, DateTimeStyles, DateTime%) pro převedení data a času požadavku uživatele na hodnotu DateTime. Použijte přetížení metody s parametrem provider a předejte jí kterýkoli ze dvou následujících objektů:

  11. V případě selhání operace analýzy v kroku 10, přejděte ke kroku 13. V opačném případě volejte metodu UInt32.Parse(String) pro převedení řetězcového vyjádření posunu časového pásma uživatele na celé číslo.

  12. Vytvořte instanci DateTimeOffset, která představuje místní čas uživatele, voláním konstruktoru DateTimeOffset.DateTimeOffset(DateTime, TimeSpan).

  13. Pokud převod v kroku 10 selže, opakujte kroky 7 až 12 pro každý zbývající prvek v poli řetězců vráceném vlastností UserLanguages.

  14. Pokud se převod stále nedaří nebo pokud je pole řetězců vrácené vlastností UserLanguages prázdné, analyzujte řetězec pomocí neutrální jazykové verze, která je vrácena vlastností CultureInfo.InvariantCulture. Poté opakujte kroky 7 až 12.

Výsledkem je objekt DateTimeOffset, který představuje místní čas uživatele vaší webové stránky. Poté můžete určit odpovídající čas standardu UTC voláním metody ToUniversalTime. Můžete také určit odpovídající datum a čas na vašem webovém serveru voláním metody TimeZoneInfo.ConvertTime(DateTimeOffset, TimeZoneInfo) a předáním hodnoty TimeZoneInfo.Local jakožto časového pásma, do kterého má být čas převeden.

Příklad

Následující příklad obsahuje zdrojový kód jazyk HTML i kód pro formulář technologie ASP.NET, který žádá uživatele o zadání hodnoty data a času. Skript na straně klienta také zapíše informace o místním datu a času žádosti uživatele a posunu časového pásma uživatele od času UTC do skrytého pole. Tyto informace jsou poté analyzovány serverem, který vrací webovou stránku zobrazující uživatelský vstup. Také zobrazuje datum a čas požadavku uživatele pomocí místního času uživatele, čas serveru a čas 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>

Skript na straně klienta volá metodu toLocaleString jazyka JavaScript. Ta vytváří řetězec řídící se úmluvami formátování národního prostředí uživatele, jehož analýza bude zcela určitě úspěšnější na serveru.

Vlastnost HttpRequest.UserLanguages je naplněna názvy jazykových verzí obsažených v záhlaví Accept-Language, které jsou součástí požadavku HTTP. Ne všechny prohlížeče však ve svých požadavcích zahrnují záhlaví Accept-Language a uživatelé mohou také potlačit záhlaví úplně. Proto je důležité mít záložní jazykovou verzi při analýze vstupu uživatele. Obvykle je záložní jazyková verze neutrální jazyková verze vrácená CultureInfo.InvariantCulture. Uživatelé mohou také poskytovat Internet Explorer s názvy jazykových verzí, které vložili do textového pole, které vytvoří tu možnost, že názvy jazykových verzí mohou být neplatné. Proto je důležité použít zpracování výjimek při vytvoření instance objektu CultureInfo.

Při načítání z odeslaných HTTP požadavků Internet Explorerem je pole HttpRequest.UserLanguages naplněno v pořadí podle předvolby uživatele. První prvek pole obsahuje název primární jazykové verze/oblasti uživatele. Pokud pole obsahuje jakékoli další položky, Internet Explorer jim libovolně přiřadí specifikátor kvality, který je oddělen středníkem od názvu jazykové verze. Například položka pro jazykovou verzi fr-FR může mít formu fr-FR;q=0.7.

Příklad volá konstruktor CultureInfo s jeho parametrem useUserOverride nastaveným false pro vytvoření nového objektu CultureInfo. To zajišťuje, že pokud je název jazykové verze výchozím názvem jazykové verze na serveru, pak nový objekt CultureInfo vytvořený pomocí konstruktoru třídy obsahuje výchozí nastavení jazykové verze a neprojeví se žádné nastavení přepsané použitím aplikace serveru Místní a jazykové nastavení. Je nepravděpodobné, že v uživatelském systému existují hodnoty z jakéhokoli přepsaného nastavení na serveru, nebo že se projeví v uživatelském vstupu.

Protože jsou v tomto příkladu analyzovány dvě řetězcové vyjádření data a času (jeden uživatelský vstup, druhý uložený do skrytého pole), jsou možné objekty CultureInfo, které mohou být požadovány, definovány předem. Vytvoří se pole objektů CultureInfo, které je o jedničku větší než počet prvků vrácených vlastností HttpRequest.UserLanguages. Poté se vytvoří instance objektu CultureInfo pro každý řetězec jazyka nebo oblasti a také se vytvoří instance objektu CultureInfo, který představuje CultureInfo.InvariantCulture.

Váš kód může volat metodu Parse nebo metodu TryParse pro převedení řetězcového vyjádření data a času uživatele na hodnotu DateTime. Pro jedinou operaci analýzy může být vyžadováno opakované volání metody analýzy. V důsledku toho je metoda TryParse lepší, protože vrátí false v případě selhání operace analýzy. Naopak ošetřování opakovaných výjimek, které mohou být vyvolány metodou Parse může být ve webové aplikaci velmi nákladnou záležitostí.

Probíhá kompilace kódu

Chcete-li kód zkompilovat, vytvořte webovou stránku ASP.NET bez kódu na pozadí. Zkopírujte poté příklad do webové stránka tak, aby nahradil veškerý existující kód. Webová stránka ASP.NET by měla obsahovat následující ovládací prvky:

  • Ovládací prvek Label, na který není odkaz v kódu. Nastavte jeho vlastnost Text na "Zadejte číslo:".

  • Ovládací prvek TextBox s názvem DateString.

  • Ovládací prvek Button s názvem OKButton. Nastavte jeho vlastnost Text na "OK".

  • Ovládací prvek HiddenField s názvem DateInfo.

Zabezpečení

Pro zabránění vložení skriptu do proudu HTML uživatelem, by uživatelský vstup neměl být nikdy přímo vepisován zpět do odpovědi serveru. Místo toho by měl být kódován pomocí metody HttpServerUtility.HtmlEncode.

Viz také

Koncepty

Provádění operací formátování

Standardní formátovací řetězce data a času

Vlastní formátovací řetězce data a času

Analýza řetězců data a času