Skip to main content

How to Display Localized Date and Time Information to Web Users in ASP.NET.

---
title: How to Display Localized Date and Time Information to Web Users in ASP.NET
subtitle: Display Localized Date and Time Information to Web Users
author: Microsoft
date: March 30, 2017
source: https://docs.microsoft.com/en-us/dotnet/standard/base-types/how-to-display-localized-date-and-time-information-to-web-users
notoc: true
---

Because a Web page can be displayed anywhere in the world, operations that parse
and format date and time values should not rely on a default format (which most
often is the format of the Web server's local culture) when interacting with the
user. Instead, Web forms that handle date and time strings input by the user
should parse the strings using the user's preferred culture. Similarly, date and
time data should be displayed to the user in a format that conforms to the
user's culture. This topic shows how to do this.

## Example

The following example contains both the HTML source and the code for an ASP.NET
Web form that asks the user to input a date and time value. A client-side script
also writes information on the local date and time of the user's request and the
offset of the user's time zone from UTC to a hidden field. This information is
then parsed by the server, which returns a Web page that displays the user's
input. It also displays the date and time of the user's request using the user's
local time, the time on the server, and UTC.

```cs
<%@ 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:"></asp:Label>
               <asp:TextBox ID="DateString" runat="server"></asp:TextBox><br />
            </center>
        <center>
            <asp:Button ID="OKButton" runat="server" Text="Button" OnClientClick="AddDateInformation()" onclick="OKButton_Click" />
            <asp:HiddenField ID="DateInfo" Value="" runat="server" />
        </center>
        </div>
    </form>
</body>
</html>
```

The client-side script calls the JavaScript `toLocaleString` method. This
produces a string that follows the formatting conventions of the user's locale,
which is more likely to be successfully parsed on the server.

The `System.Web.HttpRequest.UserLanguages` property is populated from the
culture names that are contained in `Accept-Language` headers included in an
HTTP request. However, not all browsers include `Accept-Language` headers in
their requests, and users can also suppress the headers completely. This makes
it important to have a fallback culture when parsing user input. Typically the
fallback culture is the invariant culture returned by
`System.Globalization.CultureInfo.InvariantCulture`. Users can also provide
Internet Explorer with culture names that they input in a text box, which
creates the possibility that the culture names may not be valid. This makes it
important to use exception handling when instantiating a
`System.Globalization.CultureInfo` object.

When retrieved from an HTTP request submitted by Internet Explorer, the
`System.Web.HttpRequest.UserLanguages` array is populated in order of user
preference. The first element in the array contains the name of the user's
primary culture/region. If the array contains any additional items, Internet
Explorer arbitrarily assigns them a quality specifier, which is delimited from
the culture name by a semicolon. For example, an entry for the fr-FR culture
might take the form `fr-FR;q=0.7`.

The example calls the `System.Globalization.CultureInfo` constructor with its
`useUserOverride` parameter set to `false` to create a new
`System.Globalization.CultureInfo` object. This ensures that, if the culture
name is the default culture name on the server, the new
`System.Globalization.CultureInfo` object created by the class constructor
contains a culture's default settings and does not reflect any settings
overridden by using the server's **Regional and Language Options** application.
The values from any overridden settings on the server are unlikely to exist on
the user's system or to be reflected in the user's input.

Because this example parses two string representations of a date and time (one
input by the user, the other stored to the hidden field), it defines the
possible `System.Globalization.CultureInfo` objects that may be required in
advance. It creates an array of `System.Globalization.CultureInfo` objects that
is one greater than the number of elements returned by the
`System.Web.HttpRequest.UserLanguages` property. It then instantiates a
`System.Globalization.CultureInfo` object for each language/region string, and
also instantiates a `System.Globalization.CultureInfo` object that represents
`System.Globalization.CultureInfo.InvariantCulture`.

Your code can call either the `System.DateTime.Parse` or the
`System.DateTime.TryParse` method to convert the user's string representation of
a date and time to a `System.DateTime` value. Repeated calls to a parse method
may be required for a single parsing operation. As a result, the
`System.DateTime.TryParse` method is better because it returns `false` if a
parse operation fails. In contrast, handling the repeated exceptions that may be
thrown by the `System.DateTime.Parse` method can be a very expensive proposition
in a Web application.

## .NET Framework Security

To prevent a user from injecting script into the HTML stream, user input should
never be directly echoed back in the server response. Instead, it should be
encoded by using the `System.Web.HttpServerUtility.HtmlEncode` method.

## See also

- [Performing Formatting Operations](https://docs.microsoft.com/en-us/dotnet/standard/base-types/performing-formatting-operations)
- [Standard Date and Time Format Strings](https://docs.microsoft.com/en-us/dotnet/standard/base-types/standard-date-and-time-format-strings)
- [Custom Date and Time Format Strings](https://docs.microsoft.com/en-us/dotnet/standard/base-types/custom-date-and-time-format-strings)
- [Parsing Date and Time Strings](https://docs.microsoft.com/en-us/dotnet/standard/base-types/parsing-datetime)