My DateTime format changes when binding

2.3k views Asked by At

I'm based in the UK, and my computer always shows a UK date format (dd/mm/yyyy).

My WPF project is, for some reason converting my DateTime format to US type. This occurs on my work machine and home machine.

I've been able to replicate the issue very simply

<Window x:Class="TimeIssues.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525">
<Grid>
    <TextBlock Text="{Binding MyTime}"></TextBlock> <!-- the value is 1/28/2014 10:15:37 (note it is M/dd/yyyy....)
</Grid>
</Window>

And in the code behind, simply

public partial class MainWindow : Window
{
    public MainWindow()
    {
        SetMyTime("28/01/2014 10:15:37"); //note, this is dd/MM/yyyy .... format
        this.DataContext = this;
        InitializeComponent();
    }

    private void SetMyTime(string dateTime)
    {
        DateTime dt;
        DateTime.TryParseExact(dateTime, "dd/MM/yyyy HH:mm:ss", CultureInfo.InvariantCulture, DateTimeStyles.None, out dt);
        MyTime = dt; // the value is expected, showing 28/01/2014 10:15:37
    }

    public DateTime MyTime { get; set; }
}

Just to confirm that this isn't an IT issue (or so I think), my PC is set for UK (and the Location is also set to UK as is the Current language for non-unicode programs)

enter image description here

I have read WPF format DateTime in TextBlock? but this won't help (I don't think) as that question is about setting the format when the format is known.

If I update my MyTime from DateTime to a string, then the result is expected (UK format)! The issue is WPF changes the format when the type is DateTime which is not desired!

My issue is 2 fold -

  1. I won't know the format the user needs (my software is distributed world wide).
  2. WPF appears to change the format incorrectly any way!

How do I tell WPF to use the user's locale settings? Is there any way to read the OS settings (as per the screen shot above)?

2

There are 2 answers

11
Rohit Vats On BEST ANSWER

CultureInfo is picked from Thread's current culture which in your case will be set to en-US. You need to set it to en-GB like this:

Thread.CurrentThread.CurrentCulture = CultureInfo.GetCultureInfo("en-GB");

But when you set this you will see, XAML doesn't pick this. For XAML to pick it you have to override FrameworkElement.LanguageProperty metadata.

Override OnStartup() method in your App.xaml.cs and place this code there and you are good to go:

protected override void OnStartup(StartupEventArgs e)
{
   base.OnStartup(e);

   Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("en-GB");
   Thread.CurrentThread.CurrentCulture = CultureInfo.GetCultureInfo("en-GB");

   FrameworkElement.LanguageProperty.OverrideMetadata(
                typeof(FrameworkElement),
                new FrameworkPropertyMetadata(
           XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.IetfLanguageTag)));
}

UPDATE

Is there any way to read the OS settings (as per the screen shot above)?

In case you want to pick CultureInfo based on the format selected for system, you can do that as well by getting LCID for OS. This is how you do it:

[DllImport("kernel32.dll")]
private static extern int GetUserDefaultLCID();

protected override void OnStartup(StartupEventArgs e)
{
   base.OnStartup(e);

   int machineLCID = GetUserDefaultLCID();
   CultureInfo machineCultureInfo = CultureInfo.GetCultureInfo(machineLCID);
   Thread.CurrentThread.CurrentUICulture = machineCultureInfo;
   Thread.CurrentThread.CurrentCulture = machineCultureInfo;

   FrameworkElement.LanguageProperty.OverrideMetadata(
                typeof(FrameworkElement),
                new FrameworkPropertyMetadata(
           XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.IetfLanguageTag)));
}
2
Newyork167 On

Try something like <TextBlock Text="{Binding MyTime, ConverterCulture='en-GB'} </TextBlock>.

If that fails try <TextBlock Text="{Binding MyTime, ConverterCulture='en-GB', StringFormat={}{0:dd/MM/yyyy} </TextBlock>

One thing you might try is instead of returning a DateTime object, try making your class get/set a formatted string based on the current CultureInfo of the system running the program. This would bind the string the way you want it instead of the default DateTime binding of en-US.