Gewusst wie: Anzeigen lokalisierter Datums- und Uhrzeitangaben für Webbenutzer

Eine Webseite kann an beliebigen Standorten weltweit angezeigt werden kann. Bei der Interaktion mit dem Benutzer sollten daher Vorgänge, mit denen Datums- und Uhrzeitwerte analysiert und formatiert werden, nicht auf einem Standardformat (meist dem Format der lokalen Kultur des Webservers) beruhen. Web Forms, die vom Benutzer eingegebene Datums- und Uhrzeitzeichenfolgen verarbeiten, sollten die Zeichenfolgen stattdessen unter Verwendung der bevorzugten Kultur des Benutzers analysieren. Und auch Datums- und Uhrzeitdaten sollten dem Benutzer in einem Format angezeigt werden, das dessen Kultur entspricht. In diesem Artikel wird die Vorgehensweise veranschaulicht.

So analysieren Sie vom Benutzer eingegebene Datums- und Uhrzeitzeichenfolgen

  1. Stellen Sie fest, ob das von der HttpRequest.UserLanguages-Eigenschaft zurückgegebene Zeichenfolgenarray Daten enthält. Falls nicht, fahren Sie mit Schritt 6 fort.

  2. Wenn das von der UserLanguages-Eigenschaft zurückgegebene Zeichenfolgenarray Daten enthält, rufen Sie dessen erstes Element ab. Das erste Element gibt die standardmäßige bzw. bevorzugte Sprache und Region des Benutzers an.

  3. Instanziieren Sie ein CultureInfo-Objekt, das die bevorzugte Kultur des Benutzers darstellt, indem Sie den CultureInfo.CultureInfo(String, Boolean)-Konstruktor aufrufen.

  4. Rufen Sie entweder die TryParse-Methode oder die Parse-Methode des DateTime-Typs oder des DateTimeOffset-Typs auf, um zu versuchen, eine Konvertierung auszuführen. Verwenden Sie eine Überladung der TryParse-Methode oder der Parse-Methode mit einem provider-Parameter, und übergeben Sie eines der folgenden Objekte:

  5. Wenn die Konvertierung fehlschlägt, wiederholen Sie die Schritte 2 bis 4 für jedes verbleibende Element in dem durch die UserLanguages-Eigenschaft zurückgegebenen Zeichenfolgenarray.

  6. Wenn die Konvertierung weiterhin fehlschlägt oder das von der UserLanguages-Eigenschaft zurückgegebene Zeichenfolgenarray leer ist, analysieren Sie die Zeichenfolge unter Verwendung der invarianten Kultur, die von der CultureInfo.InvariantCulture-Eigenschaft zurückgegeben wird.

So analysieren Sie das lokale Datum und die Ortszeit der Benutzeranforderung

  1. Fügen Sie einem Web Form ein HiddenField-Steuerelement hinzu.

  2. Erstellen Sie eine JavaScript-Funktion, die das onClick-Ereignis einer Submit-Schaltfläche behandelt, indem das aktuelle Datum und die aktuelle Zeit sowie der Offset der lokalen Zeitzone von der koordinierten Weltzeit (Coordinated Universal Time, UTC) in die Value-Eigenschaft geschrieben wird. Verwenden Sie ein Trennzeichen (z. B. ein Semikolon), um die beiden Komponenten der Zeichenfolge zu trennen.

  3. Verwenden Sie das PreRender-Ereignis des Web Forms, um die Funktion in den HTML-Ausgabestream einzufügen, indem Sie den Text des Skripts an die ClientScriptManager.RegisterClientScriptBlock(Type, String, String, Boolean)-Methode übergeben.

  4. Verbinden Sie den Ereignishandler mit dem onClick-Ereignis der Submit-Schaltfläche, indem Sie den Namen der JavaScript-Funktion für das OnClientClick-Attribut der Submit-Schaltfläche bereitstellen.

  5. Erstellen Sie einen Handler für das Click-Ereignis der Submit-Schaltfläche.

  6. Bestimmen Sie im Ereignishandler, ob das von der HttpRequest.UserLanguages-Eigenschaft zurückgegebene Zeichenfolgenarray Daten enthält. Falls nicht, fahren Sie mit Schritt 14 fort.

  7. Wenn das von der UserLanguages-Eigenschaft zurückgegebene Zeichenfolgenarray Daten enthält, rufen Sie dessen erstes Element ab. Das erste Element gibt die standardmäßige bzw. bevorzugte Sprache und Region des Benutzers an.

  8. Instanziieren Sie ein CultureInfo-Objekt, das die bevorzugte Kultur des Benutzers darstellt, indem Sie den CultureInfo.CultureInfo(String, Boolean)-Konstruktor aufrufen.

  9. Übergeben Sie die der Value-Eigenschaft zugewiesene Zeichenfolge an die Split-Methode, um die Zeichenfolgendarstellung des lokalen Datums und der Ortszeit des Benutzers und die Zeichenfolgendarstellung des Offsets der lokalen Zeitzone des Benutzers in getrennten Arrayelementen zu speichern.

  10. Rufen Sie entweder die DateTime.Parse-Methode oder die DateTime.TryParse(String, IFormatProvider, DateTimeStyles, DateTime%)-Methode auf, um das Datum und die Uhrzeit der Benutzeranforderung in einen DateTime-Wert zu konvertieren. Verwenden Sie eine Überladung der Methode mit einem provider-Parameter, und übergeben Sie eines der folgenden Objekte:

  11. Wenn die Analyseoperation in Schritt 10 fehlschlägt, fahren Sie mit Schritt 13 fort. Andernfalls rufen Sie die UInt32.Parse(String)-Methode auf, um die Zeichenfolgendarstellung des Zeitzonenoffsets des Benutzers in eine ganze Zahl zu konvertieren.

  12. Instanziieren Sie einen DateTimeOffset, der die Ortszeit des Benutzers darstellt, indem Sie den DateTimeOffset.DateTimeOffset(DateTime, TimeSpan)-Konstruktor aufrufen.

  13. Wenn die Konvertierung in Schritt 10 fehlschlägt, wiederholen Sie die Schritte 7 bis 12 für jedes verbleibende Element in dem durch die UserLanguages-Eigenschaft zurückgegebenen Zeichenfolgenarray.

  14. Wenn die Konvertierung weiterhin fehlschlägt oder das von der UserLanguages-Eigenschaft zurückgegebene Zeichenfolgenarray leer ist, analysieren Sie die Zeichenfolge unter Verwendung der invarianten Kultur, die von der CultureInfo.InvariantCulture-Eigenschaft zurückgegeben wird. Wiederholen Sie dann die Schritte 7 bis 12.

Das Ergebnis ist ein DateTimeOffset-Objekt, das die Ortszeit des Benutzers Ihrer Webseite darstellt. Sie können dann die entsprechende UTC bestimmen, indem Sie die ToUniversalTime-Methode aufrufen. Sie können auch das entsprechende Datum und die entsprechende Uhrzeit auf Ihrem Webserver feststellen, indem Sie die TimeZoneInfo.ConvertTime(DateTimeOffset, TimeZoneInfo)-Methode aufrufen und einen Wert von TimeZoneInfo.Local als Zeitzone übergeben, in die die Uhrzeit konvertiert werden soll.

Beispiel

Das folgende Beispiel enthält sowohl den HTML-Quellcode als auch den Code für ein ASP.NET-Web Form, in dem der Benutzer aufgefordert wird, einen Datums- und Uhrzeitwert einzugeben. Außerdem schreibt ein clientseitiges Skript Informationen zum lokalen Datum und der Ortszeit der Benutzeranforderung sowie zum Offset der Zeitzone des Benutzers von der UTC in ein ausgeblendetes Feld. Anschließend werden die Informationen vom Server analysiert, der eine Webseite zurückgibt, in der die Benutzereingabe angezeigt wird. Darüber hinaus werden Datum und Uhrzeit der Benutzeranforderung unter Verwendung der Ortszeit des Benutzers, die Uhrzeit auf dem Server sowie die UTC angezeigt.


<%@ 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>

Das clientseitige Skript ruft die JavaScript-Methode toLocaleString auf. Auf diese Weise wird eine Zeichenfolge generiert, die den Formatierungskonventionen des Benutzergebietsschemas entspricht und dadurch wahrscheinlich erfolgreicher auf dem Server analysiert werden kann.

Die HttpRequest.UserLanguages-Eigenschaft wird unter Verwendung der Kulturnamen aufgefüllt, die in Accept-Language-Headern innerhalb einer HTTP-Anforderung enthalten sind. Allerdings schließen nicht alle Browser Accept-Language-Header in ihre Anforderungen ein, und die Header können vom Benutzer auch vollständig unterdrückt werden. Daher ist es wichtig, bei der Analyse der Benutzereingabe über eine Fallbackkultur zu verfügen. Die Fallbackkultur ist in der Regel die von der CultureInfo.InvariantCulture-Eigenschaft zurückgegebene invariante Kultur. Benutzer können auch Kulturnamen für Internet Explorer bereitstellen, die sie in ein Textfeld eingeben. Dabei ist es möglich, dass die Kulturnamen nicht gültig sind. Aus diesem Grund sollte beim Instanziieren eines CultureInfo-Objekts unbedingt eine Ausnahmebehandlung verwendet werden.

Wenn das HttpRequest.UserLanguages-Array durch eine von Internet Explorer gesendeten HTTP-Anforderung abgerufen wird, wird es in der Reihenfolge der Benutzereinstellungen aufgefüllt. Das erste Element im Array enthält den Namen der primären Kultur/Region des Benutzers. Wenn das Array zusätzliche Elemente enthält, weist Ihnen Internet Explorer beliebig einen Qualitätsbezeichner zu, der durch ein Semikolon vom Kulturnamen getrennt ist. Beispielsweise könnte ein Eintrag für die Kultur fr-FR wie folgt aussehen: fr-FR;q=0.7.

Im Beispiel wird der CultureInfo-Konstruktor, dessen useUserOverride-Parameter auf false festgelegt ist, aufgerufen, um ein neues CultureInfo-Objekt zu erstellen. So wird sichergestellt, dass, wenn der Kulturname dem standardmäßigen Kulturnamen auf dem Server entspricht, das neue, vom Klassenkonstruktor erstellte CultureInfo-Objekt die Standardkultureinstellungen beinhaltet und keine Einstellungen widerspiegelt, die durch die Anwendung Regions- und Sprachoptionen des Servers überschrieben wurden. Es ist unwahrscheinlich, dass die Werte von auf dem Server überschriebenen Einstellungen auf dem Benutzersystem vorhanden sind oder in der Benutzereingabe wiedergegeben werden.

Da in diesem Beispiel zwei Zeichenfolgendarstellungen eines Datums und einer Uhrzeit (einerseits vom Benutzer eingegeben und andererseits im ausgeblendeten Feld gespeichert) analysiert werden, werden die möglicherweise erforderlichen CultureInfo-Objekte im Voraus definiert. Es wird ein Array von CultureInfo-Objekten erstellt, das um ein Element größer als die Anzahl der von der HttpRequest.UserLanguages-Eigenschaft zurückgegebenen Elemente ist. Anschließend wird ein CultureInfo-Objekt für jede Sprach-/Regionszeichenfolge und darüber hinaus ein CultureInfo-Objekt instanziiert, das CultureInfo.InvariantCulture darstellt.

Der Code kann entweder die Parse-Methode oder die TryParse-Methode zur Konvertierung der benutzerspezifischen Zeichenfolgendarstellung eines Datums und einer Uhrzeit in einen DateTime-Wert aufrufen. Für einen einzelnen Analysevorgang muss eine Parse-Methode möglicherweise wiederholt aufgerufen werden. Folglich ist die TryParse-Methode besser geeignet, da sie false zurückgibt, falls ein Analysevorgang fehlschlägt. Die Behandlung der wiederholten Ausnahmen, die von der Parse-Methode ausgelöst werden , kann sich in einer Webanwendung hingegen als kostenintensives Unterfangen herausstellen.

Kompilieren des Codes

Um den Code zu kompilieren, erstellen Sie eine ASP.NET-Webseite ohne Code-Behind. Anschließend kopieren Sie das Beispiel in die Webseite, um den gesamten vorhandenen Code zu ersetzen. Die ASP.NET-Webseite sollte die folgenden Steuerelemente enthalten:

  • Ein Label-Steuerelement, auf das im Code nicht verwiesen wird. Legen Sie die zugehörige Text-Eigenschaft auf "Enter a Number:" fest.

  • Ein TextBox-Steuerelement mit dem Namen DateString.

  • Ein Button-Steuerelement mit dem Namen OKButton. Legen Sie die entsprechende Text-Eigenschaft auf "OK" fest.

  • Ein HiddenField-Steuerelement mit dem Namen DateInfo.

Sicherheit

Um zu verhindern, dass ein Benutzer Skriptcode in den HTML-Stream einfügt, sollte die Benutzereingabe in der Serverantwort nie direkt wiedergegeben werden. Stattdessen sollte sie mithilfe der HttpServerUtility.HtmlEncode-Methode codiert werden.

Siehe auch

Konzepte

Durchführen von Formatierungsvorgängen

Datums- und Uhrzeitstandardformatzeichenfolgen

Benutzerdefinierte und DateTime-Formatzeichenfolgen

Verarbeiten von Zeichenfolgen für Datum und Uhrzeit