Search code examples
c#datetimelocalizationblazorblazor-webassembly

In Blazor WebAssembly in a component, how can I make DateTime.ToString use the date format of the current culture, assuming the culture is correct?


I have temporarily set my browser language and locale to English - United Kingdom even though I am in the United States. I have removed "en-US" and now have "en-GB" as my only language preference.

In my Blazor WebAssembly site, on a component, I have a property that returns a string: myDate.ToString("d") + System.Globalization.CultureInfo.CurrentCulture.DisplayName; that renders on my page as 6/27/2020en (GB), where myDate is a DateTime set to June 27, 2020 at 00:00:00.000. My Blazor site has app.UseRequestLocalization(...) middleware set up.

Isn't is supposed to show the date in UK format, namely 27/06/2020? I can only guess that ShortDatePattern isn't getting properly set from CultureInfo.CurrentCulture. What could it be?

UPDATE: All WebAssembly component outputs show me that DateTimeFormatInfo.CurrentInfo.ShortDatePattern == "M/d/yyyy" even though CultureInfo.CurrentCulture.Name == "en-GB". Why might that be? What sets ShortDatePattern from the culture and can I "re-initialize" it?

An explicit call to myDate.ToString("d", System.Globalization.CultureInfo.GetCultureInfo("en-GB")); still strangely outputs the M/d/yyyy format (U.S. format). Why might that be?

UPDATE 2: I created a minimal example: File-New Project, Blazor Web Assembly, .NET 5 ASP.NET Core hosted. I replaced App.Razor with the following:

<div> current culture @(System.Globalization.CultureInfo.CurrentCulture.Name) </div>
<div> current date format @(System.Globalization.CultureInfo.CurrentCulture.DateTimeFormat.ShortDatePattern) </div>
<div> today @DateTime.Now.ToString("d") </div>

That results in (unexpectedly):

enter image description here

Firefox browser settings (Edge and Chrome are similar and show the same issue):

enter image description here

That results in sending Accept-Language: en-GB,en-US;q=0.7,en;q=0.3--which seems to be the correct way to "prefer en-GB" and results in CultureInfo.CurrentCulture having the correct value.

I've tried it with Microsoft.AspNetCore.Components.WebAssembly.* nuget packages version 5.0.9, 5.0.11 - both show the same incorrect result.

UPDATE 3: The same minimal project in 6.0.0-rc.1 works and gives the right date format! Is this really a Blazor 5 bug that they never fixed?


Solution

  • For .NET 6+, this seems to be fixed.

    For .NET 5, I could not find the root cause, so I needed to code this workaround, which needs to be called explicitly when needed. Obviously this is undesirable if we can find a better solution to allow the use of DateTime.ToString as intended.

    /// <summary>
    /// Returns a short date-only string from a date/time value, based on the user's current culture.
    /// </summary>
    public static string ToLocalShortDate(this DateTime value)
    {
        // this is needed because I can't get localization to work -- see https://stackoverflow.com/q/69542125/7453
        //   (if we can fix, better to use DateTime.ToString("d"))
    
        string format;
        // countries taken from https://en.wikipedia.org/wiki/Date_format_by_country
        if (CurrentCulture.Name.EndsWithAny("US", "CA", "ZA", "KE", "GH", "en"))
            format = "MM/dd/yyyy";
        else if (CurrentCulture.Name.EndsWithAny("CN", "JP", "KR", "KP", "TW", "HU", "MN", "LT", "BT"))
            format = "yyyy-MM-dd";
        else format = "dd/MM/yyyy";
    
        return value.ToString(format);
    }
            
    /// <summary>
    /// Returns true if and only if a string ends with any of some strings.
    /// The value will not match a null reference.
    /// </summary>
    public static bool EndsWithAny(this string value, params string[] allowedValues) =>
        allowedValues != null && value != null && allowedValues.Any(s => CurrentCulture.Name.EndsWith(s));