共用方式為


HOW TO:對 Web 使用者顯示當地語系化的日期和時間資訊

更新:2007 年 11 月

由於網頁可在任何地方顯示,因此與使用者互動時,剖析和格式化日期與時間值的作業不應倚賴預設格式 (大部分情況下為 Web 伺服器上本機文化特性的格式)。處理使用者輸入之日期和時間字串的 Web Form 應改用使用者偏好的文化特性剖析字串。同樣地,對使用者顯示的日期和時間資料應使用符合使用者文化特性的格式。本主題將說明如何執行這項作業。

剖析使用者輸入的日期和時間字串

  1. 判斷 HttpRequest.UserLanguages 屬性傳回的字串陣列是否已填入。如果尚未填入,則繼續進行步驟 6。

  2. 如果 UserLanguages 屬性所傳回的字串陣列已填入,就會擷取它的第一個項目。第一個項目指出使用者的預設或慣用的語言和區域。

  3. 呼叫 CultureInfo.CultureInfo(String, Boolean) 建構函式以具現化 CultureInfo 物件,此物件代表使用者慣用的文化特性。

  4. 呼叫 DateTimeDateTimeOffset 型別的 TryParse 或 Parse 方法嘗試轉換。使用 TryParse 或 Parse 方法的多載與 provider 參數,並將下列任一項傳遞給該多載:

  5. 如果轉換失敗,則針對 UserLanguages 屬性傳回的字串陣列中其餘每一個項目重複步驟 2 到 4。

  6. 如果轉換還是失敗,或者,如果 UserLanguages 屬性所傳回的字串陣列為空白,請使用由 CultureInfo.InvariantCulture 屬性所傳回的 Invariant 文化特性 (不因文化特定而異) 來剖析字串。

剖析使用者要求的本地日期和時間

  1. 在 Web Form 中加入 HiddenField 控制項。

  2. 建立 JavaScript 函式,該函式會將目前的日期和時間以及本機時區與 Coordinated Universal Time (UTC) 之間的位移寫入 Value 屬性,藉此處理 Submit 按鈕的 onClick 事件。使用分隔符號 (例如分號) 分隔字串的兩個元件。

  3. 將指令碼的文字傳遞至 ClientScriptManager.RegisterClientScriptBlock(Type, String, String, Boolean) 方法,藉此使用 Web Form 的 PreRender 事件將函式插入 HTML 輸出資料流中。

  4. 藉由提供 JavaScript 函式的名稱給 Submit 按鈕的 OnClientClick 屬性,連接事件處理常式與 Submit 按鈕的 onClick 事件。

  5. 為 Submit 按鈕的 Click 事件建立處理常式。

  6. 判斷 HttpRequest.UserLanguages 屬性傳回的字串陣列是否已填入事件處理常式中。如果尚未填入,則繼續進行步驟 14。

  7. 如果 UserLanguages 屬性所傳回的字串陣列已填入,就會擷取它的第一個項目。第一個項目指出使用者的預設或慣用的語言和區域。

  8. 呼叫 CultureInfo.CultureInfo(String, Boolean) 建構函式以具現化 CultureInfo 物件,此物件代表使用者慣用的文化特性。

  9. 將指派給 Value 屬性的字串傳遞至 Split 方法,藉此將使用者本地日期和時間的字串表示,以及使用者本機時區位移的字串表示儲存到不同的陣列項目中。

  10. 呼叫 DateTime.ParseDateTime.TryParse(String, IFormatProvider, DateTimeStyles, DateTime%) 方法,將使用者要求的日期和時間轉換成 DateTime 值。使用方法多載與 provider 參數,並將下列任一項傳遞給該多載:

  11. 如果步驟 10 中的剖析作業失敗,請移至步驟 13。否則請呼叫 UInt32.Parse(String) 方法,將使用者時區位移的字串表示轉換成整數。

  12. 具現化 DateTimeOffset,它會藉由呼叫 DateTimeOffset.DateTimeOffset(DateTime, TimeSpan) 建構函式的方式呈現使用者的本機時間。

  13. 如果步驟 10 中的轉換失敗,則針對 UserLanguages 屬性傳回的字串陣列中其餘每一個項目重複步驟 7 到 12。

  14. 如果轉換還是失敗,或者,如果 UserLanguages 屬性所傳回的字串陣列為空白,請使用由 CultureInfo.InvariantCulture 屬性所傳回的 Invariant 文化特性 (不因文化特定而異) 來剖析字串。然後重複步驟 7 到 12。

執行結果為 DateTimeOffset 物件,表示網頁使用者的本地時間。然後您可以呼叫 ToUniversalTime 方法以判斷對等的 UTC。您也可以呼叫 TimeZoneInfo.ConvertTime(DateTimeOffset, TimeZoneInfo) 方法並且傳遞 TimeZoneInfo.Local 的值做為轉換時間的目標時區,藉此判斷 Web 伺服器上的對等日期和時間。

範例

以下範例同時包含 HTML 原始檔和 ASP.NET Web Form 的程式碼,會要求使用者輸入日期和時間值。用戶端指令碼也會將使用者要求的本地日期和時間資訊,以及使用者時區與 UTC 之間的位移寫入隱藏欄位中。伺服器會接著剖析這項資訊,並傳回顯示使用者輸入的網頁。此外還會利用使用者的本地時間、伺服器上的時間及 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 >

    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" >
    <title>Parsing a Date and Time Value</title>
</head>
<body>
    <form id="DateForm" >
    <div>
    <center>
       <asp:Label ID="Label1"  Text="Enter a Date and Time:" Width="248px"></asp:Label>
       <asp:TextBox ID="DateString"  Width="176px"></asp:TextBox><br />
    </center>       
    <br />
    <center>
    <asp:Button ID="OKButton"  Text="Button"  
            OnClientClick="AddDateInformation()" onclick="OKButton_Click" />
    <asp:HiddenField ID="DateInfo"  Value=""   />
    </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 >

    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" >
    <title>Parsing a Date and Time Value</title>
</head>
<body>
    <form id="DateForm" >
    <div>
    <center>
       <asp:Label ID="Label1"  Text="Enter a Date and Time:" Width="248px"></asp:Label>
       <asp:TextBox ID="DateString"  Width="176px"></asp:TextBox><br />
    </center>       
    <br />
    <center>
    <asp:Button ID="OKButton"  Text="Button"  
            OnClientClick="AddDateInformation()" onclick="OKButton_Click" />
    <asp:HiddenField ID="DateInfo"  Value=""   />
    </center>
    <br />
    </div>
    </form>
</body>
</html>

用戶端指令碼會呼叫 JavaScript toLocaleString 方法。如此會產生一個字串,該字串符合使用者地區設定的格式設定慣例,這可增加在伺服器上剖析該字串的成功率。

HttpRequest.UserLanguages 屬性會從 HTTP 要求所包含 Accept-Language 標頭中的文化特性名稱填入。不過,並非所有瀏覽器的要求都包含 Accept-Language 標頭,而且使用者可以完全隱藏標頭。因此,剖析使用者輸入時務必有後援文化特性。通常後援文化特性是 CultureInfo.InvariantCulture 傳回的不因國別而異的文化特性。使用者也可以將文字方塊中輸入的文化特性名稱提供給 Internet Explorer,如此就會有文化特性名稱無效的可能。因此具現化 CultureInfo 物件時,務必使用例外處理。

從 Internet Explorer 提交的 HTTP 要求擷取時,HttpRequest.UserLanguages 陣列會依使用者偏好設定填入。陣列中的第一個項目包含使用者主要文化特性/區域的名稱。如果陣列包含任何額外的項目,Internet Explorer 會為這些項目指派任意限定規範,並且使用分號與文化特性名稱分隔。例如,fr-FR 文化特性的項目可能採用這個格式 fr-FR;q=0.7。

範例會呼叫 CultureInfo 建構函式,且其 useUserOverride 參數會設為 false,以建立新的 CultureInfo 物件。如此可確定,如果文化特性名稱是伺服器上預設的文化特性名稱,則類別建構函式建立的 CultureInfo 物件會包含文化特性的預設設定,並且不會反映使用伺服器的 [地區及語言選項] 應用程式覆寫的任何設定。伺服器上任何覆寫設定的值都不會出現在使用者的系統上,或是反映在使用者輸入中。

由於這個範例會剖析兩個日期和時間的字串表示 (一個由使用者輸入,另一個儲存到隱藏欄位),因此會預先定義可能需要的 CultureInfo 物件。它會建立 CultureInfo 物件陣列,該陣列會比 HttpRequest.UserLanguages 屬性傳回的項目數大。然後具現化每個語言/區域字串的 CultureInfo 物件,同時還會具現化代表 CultureInfo.InvariantCultureCultureInfo 物件。

您的程式碼可以呼叫 ParseTryParse 方法,將使用者的日期和時間字串表示轉換成 DateTime 值。您可能需要針對單一剖析作業重複呼叫剖析方法。因此 TryParse 方法可能較佳,因為它會在剖析作業失敗時傳回 false。相反地,對於 Web 應用程式而言,處理 Parse 方法可能擲回的重複例外狀況可能是相當昂貴的方法。

編譯程式碼

若要編譯程式碼,請建立沒有程式碼後置 (Code-behind) 的 ASP.NET 網頁。然後將範例複製到網頁中,取代所有現有的程式碼。ASP.NET 網頁應包含下列控制項:

  • Label 控制項,程式碼中並未參考這個控制項。將 Text 屬性設為 [輸入數字:]。

  • 名為 DateString 的 TextBox 控制項。

  • 名為 OKButton 的 Button 控制項。將 Text 屬性設為 [確定]。

  • 名為 DateInfo 的 HiddenField 控制項。

安全性

為避免使用者將指令碼插入 HTML 資料流中,絕不可將使用者輸入直接回應 (Echo) 至伺服器回應中,而是使用 HttpServerUtility.HtmlEncode 方法將使用者輸入編碼。

請參閱

概念

格式設定 HOW TO 主題

日期和時間格式字串

剖析日期和時間字串