Windows 10 breaks .NET date parsing in certain locales

If you’re running an app in Windows 10 or Windows Server 2016 under .NET 4.0 or newer, you will see date parsing errors under seven locales. This blog post will explain the issue, the fix (it’s coming!) and the workarounds.

First off, I would like to thank the .NET Framework team at Microsoft for fixing this speedily. Jay Schmelzer and his people also helped by giving me all the details and proofreading this blog post. That said, my recommendations and any possible mistakes are still my own, not theirs. :-)

Edit 2015-10-09: This has been fixed now. The updates are as follows:

  • KB3093266 – Windows 10
  • KB3088956 – Windows Server 2012 R2 and Windows 8.1
  • KB3088955 – Windows Server 2012 and Windows 8
  • KB3088957 – Windows 7 SP1, Windows Server 2008 SP2, Windows Server 2008 R2 SP1, and Windows Vista SP2

The issue

Windows 10 changes the date and time formatting settings for some cultures. Of particular concern are seven cultures for three different regions:

  • Finnish
  • Norwegian Bokmål (“Norway” and “Svalbard and Jan Mayen” variants)
  • Serbian (variants “Cyrillic, Kosovo”, “Latin, Montenegro”, “Latin, Serbia” and “Latin, Kosovo”).

For these seven cultures, Windows 10 changes the date and time separators to be the same. For example, in Finnish, the standard date format used to be 26.8.2015 21:08, while it is now 26.8.2015 21.08 – note the subtle change in the time separator.

Note that any change in separators can cause your code to break – for example, if you have written a parser that imports time-of-day values by relying on certain culture settings, you may find that your parsing logic no longer works. But the fact that the time separator changed to be the same as the date separator creates an issue far more insidious and severe.

In all currently released versions of .NET, the DateTime.Parse method has a shortcoming: It always fails to parse a date or a date+time combination in a culture where the date/time separators are the same character. This bug, together with Windows 10’s culture changes, breaks the previously hard rule of DateTime.Parse always being able to parse the culture’s default DateTime representation. Now, DateTime.Parse(DateTime.Now.ToString()) no longer works under the described conditions. Neither does DateTime.Parse(DateTime.Now.ToShortDateString()), which is somewhat counterintuitive since the changed time separator isn’t even involved, but true nonetheless – the parser thinks it’s parsing a time instead of a date.

If you own the callsite to DateTime.Parse, you can use ParseExact (see an example below in the workarounds section) and avoid the issue. In fact, using ParseExact is a best practice anyway, if you know the format you’re parsing from. But the real is problem is that almost all of .NET Framework relies on the assumption that default datetime representations survive format/parse roundtrips – and thus, many parts of .NET don’t use ParseExact.

The most problematic failures will occur in databinding and modelbinding code. You will find that WPF, WinForms and Modern (UWP) Apps will fail when binding dates to controls. ASP.NET MVC will fail on modelbinding from form input. It will simply be impossible to enter a valid date. Depending on your scenario, your application may throw FormatExceptions, your DateTime fields will always show errors and refuse to accept input, or your modelbound ASP.NET input will be empty.

Yes, that’s serious. That’s why we have this on Connect (for .NET Framework) and GitHub (for CoreCLR).

The fix (and what about previous .NET or Windows versions?)

Microsoft has fixed this issue in a forthcoming update to .NET 4.6. This patch is planned to ship in Windows 10’s September update. DateTime.Parse will be improved to deal with a scenario where the two separators are the same. The separators won’t change back, and the new separators may still break your code in other scenarios – but that’s not a Windows or .NET Framework bug.

How about previous versions of Windows? Since it was Windows 10 that introduced the new separators, you won’t hit this on older versions of Windows. Technically you could – if your system was running a custom locale with date/time separators set to the same character, but in practice custom locales are rare, and such custom locales probably nonexistent. At the moment, there are no plans to patch this separately for older Windows versions.

How about previous versions of .NET Framework? First off, you will not see this if you’re running an app on a version older than .NET 4.0. That is because .NET 4.0 is the first version of the Framework to use the OS culture data – versions before that carried their own regional settings, and they don’t contain cultures where date and time separator is the same character.

The workarounds

If you can wait until the update comes out, you don’t need to read the rest of this blog post. If you can’t, I’ll give you some ideas on what to do.

As I already stated, if you have an explicit DateTime.Parse call, replace it with ParseExact. That is fairly straightforward to do if you can special case the mentioned 7 cultures. For example, for a Finnish date-only field, you can do DateTime.Parse(stringToParse, "d.M.yyyy", CultureInfo.GetCultureInfo("fi-FI")).

For all the other scenarios, you need to apply the previous code fix… The trick is knowing where to do it.

  • For Windows Forms data binding, you need to set the Binding.Parse event to a logic that special cases the said cultures. For a big app, the problem is getting that set up for all the relevant bindings in your application. You might want to explore reflection or similar strategies for doing programmatic injection of custom parsers for all DateTime fields. If you already have custom parsers in place, good luck marrying these two together.
  • For WPF data binding, you might want to embed this into an IValueConverter (see tutorial). Again, finding all the necessary injection spots may be a headache.
  • For ASP.NET MVC, you need to write a custom ModelBinder. The nice thing here is that you are able to apply this binding easily to all DateTime/Nullable<DateTime> objects by just adding your binder to the ModelBinders collection in your application startup. However, it is important to remember that the default behavior for ASP.NET MVC is to use InvariantCulture for parsing HTTP GET request parameters but to use the CurrentCulture for HTTP POST parameters (more here).
  • If you are at the deployment end of the stick (i.e. trying to get those .NET apps to run on computers you administer), you can turn the custom locale approach to your benefit and create a locale that has separate date & time separators. You need to use Locale Builder for that – and yes, it works on Windows 10 even though the blog post only talks about 8.1. Of course, this doesn’t help you as a developer if you cannot enforce the custom locale on your customers.

If you come across other scenarios or have solutions to share, add a comment. Please let me know if you have other feedback / questions / clarifications as well. Thanks!

August 27, 2015 · Jouni Heikniemi · 22 Comments
Tags: ,  · Posted in: .NET

22 Responses

  1. Paul - August 27, 2015

    Thanks Jouni!

    I have noticed that ADO.NET suffers from a similar problem.
    Can you confirm it is the same issue?

    The example below works for en-GB but not fi-FI.
    Note: I would never write code like this!

    test("en-GB");
    test("fi-FI");

    private void test(string culture)
    {
    Thread.CurrentThread.CurrentCulture = CultureInfo.GetCultureInfo(culture);

    DataTable dataTable = new DataTable();
    dataTable.Columns.Add("BirthDay", typeof(DateTime));
    DataRow dataRow = dataTable.NewRow();
    dataRow["BirthDay"] = DateTime.Now.Date;
    dataTable.Rows.Add(dataRow);

    string date1 = string.Format("'{0:yyyy-MM-dd}'", DateTime.Now.Date); // OK for FI or EN
    string date2 = string.Format("'{0:d}'", DateTime.Now.Date); // EN: "'27/08/2015'" FI: "'27.8.2015'"

    var rows1 = dataTable.Select("Birthday=" + date1);
    var rows2 = dataTable.Select("Birthday=" + date2); // Fails for FI
    }

    p.s. I was the creator of the thread on Reddit.

  2. Perttu - August 28, 2015

    Excellent post. I'm glad I noticed this post before stumbling on the bug :)

  3. Jouni Heikniemi - August 31, 2015

    Paul, sorry for the delay in answering this – and thanks for kicking off the Reddit thread.

    Yes, that's the same bug as far as I can tell. https://msdn.microsoft.com/en-us/library/system.data.datacolumn.expression(v=vs.110).aspx (which is the referenced document for the filter expressions as well) doesn't really document the available syntax, and http://www.csharp-examples.net/dataview-rowfilter/ seems empirical rather than authoritative… but thinking all that through, your post looks exactly like this bug.

  4. Paul - September 1, 2015

    Thanks Jouni.

    The annoying thing is that I have been running the Windows 10 beta for months but never spotted this. I use en-GB here but I have lots of customers in Norway.

  5. Tarek - September 2, 2015

    just in case it may help, if anyone wanted to go with the custom locale workaround, the blog http://blogs.msdn.com/b/shawnste/archive/2015/08/27/locale-builder-and-finnish-or-other-locales.aspx can help

  6. Jouni Heikniemi - September 3, 2015

    Paul, I hear you. Don't be too annoyed by yourself – it's not a native locale to you, like it is for us. We spotted the time separator change almost instantly in W10 Previews as it broke some of our parsers (boo us!), but even we didn't realize the issues with having the same d/t separator until much later (about at the same time you started off your Reddit thread). Which is, of course, a mitigating aspect: databinding DateTimes isn't that common afterall.

    I think this does explain a few mysterious errors I saw during the Win10 preview though… Such as PrimoPDF throwing up random parse error dialogs :-)

  7. Tatu - December 10, 2015

    While doing a part-time return to C# development I encountered this issue. I checked if my Windows 10 installation has a KB3093266 update. Nope. It's now 10th December, and I have installed all the available updates. I tried to install manually a 64bit-version of the update, but it was whining about incorrect Windows version (whatever that means..).

  8. DateTime.Parse(string) kullanmayı bırakamaz mıyız? | Soner Gönül - December 28, 2015

    […] geçti. Date and time notation in Italy sayfasına göre de doğru olan : gibi görünüyor. Benzer durumlar Windows 10'a ilk geçiş sürecinde de yaşandı. Reddit'te benzer bir thread dahi mevcut. Ek olarak Culture data shouldn’t be considered […]

  9. Olli Janatuinen - January 20, 2016

    Are you reported this issue to Microsoft that they must fix these time separators to Windows 10? Microsoft cannot just decide what time separator is used here.

    I just tested to install latest hotfixes and it is still wrong. I'm going to open ticket for them.

  10. Jouni Heikniemi - January 21, 2016

    Olli, it's not as black and white as that. The Finnish official stand on time separators is that dot should be used. See e.g. http://www.kielikello.fi/index.php?mid=2&pid=11&aid=1709 or SFS 4175. Microsoft is doing kinda the right thing even though I do agree it's not that simple in real life.

    If you can still repro the date parsing issue (i.e. [DateTime]::Parse fails on a string with same date/time separator), send me email at jouni@heikniemi.net and let's look into that.

    Tatu: It may be that the KB is no longer necessary once you're post version 1511; that ISO may contain the fixes and the separate KBs no longer show up.

  11. Veksi - February 22, 2016

    It looks like there is a bug also in DayOfWeek formatting. For instance:
    var culture = new CultureInfo("fi-FI");
    var nextMonday = DateTime.Now.AddDays(7 – (int)DayOfWeek.Monday);
    var str = nextMonday.ToString("dddd", culture);

    Prints "maanantaina", whereas I believe it should be "maanantai". It can be seen also in "Time & Language" settings and also makes
    var culture = new CultureInfo("fi-FI");
    var dayName = culture.DateTimeFormat.GetDayName(DayOfWeek.Monday);
    work wrong. I wonder if there's a bug filed already for this?

  12. Jouni Heikniemi - February 28, 2016

    Veksi, that's an interesting point – I don't think I have ever considered that a bug. Did the behavior change at some time in the past?

  13. Vijay - April 11, 2016

    I can still reproduce it.Is this fixed for Silverlight applications as well?

  14. online car insurance - June 5, 2016

    If the car value publications will be charged against whichpackages. Pennsylvania auto insurance company generally does not build equity, but neither is inexpensive. You'll NEVER be invested in our financial budget. The cost of insurance companies try to save whereverhave car insurance quote is fast, easy, and safe. Insurance, whether it is just details-and everyone knows will raise his score by paying the least of which is affordable just confusedyour dealerships, consider your credit score in your household. Your credit is only $250, your monthly car insurance rates. This is why there is not against the theft of your carwill increase significantly. When you pay for that perfect car insurance companies in America involve a deductible that is risky and provide the vehicle and the insurance company is and thehave the required auto insurance. However, you will never know what to do, but also vehicle impoundment and even be granted a 60 day period. If you are done with orderjust cluttering up the tank when you were still making a claim, but you can and does not need that you can about the type of car, previous coverage is "totaled,"car insurance. However, some of the car. At that point, the costs involved in an accident. This can be a huge difference in quotes as they are financially solvent to thean online form if you don't take the burden of time that you mark off an hour with you and your total now costing you more to protect your car ato protect you from 7,400.

  15. Joose - June 10, 2016

    This is not fixed for Silverlight. I guess it's because Microsoft has stopped development on Silverlight.

  16. Jouni Heikniemi - June 22, 2016

    The fix for Silverlight should be out now. Haven't tested myself though.

  17. Kari Viljaranta - July 1, 2016

    Wikipedia has a good point on the subject. Even though period is the standard time separator, and is used in written language, printed timetables and such, finns have always used : in computing, and a sudden switch will keep errors popping up unexpectedly for a long time yet. I got a sudden arithmetic overflow from sql just yesterday, caused by CONVERT (DATETIME,'2016-06-30 14.21.21',20). Without access to sourcecode, only fix was to succumb to olden ways and set Windows 10 to use 14:21:21

  18. luat bravolaw - August 19, 2016

    This blog was… how do I say it? Relevant!! Finally I've found something
    which helped me. Thanks a lot!

  19. Daniel Latikaynen - November 3, 2016

    Date formatting works for our Finnish customers, but was suddenly changed in our (newer) development environment. Could not believe this to be true and thought something must be broken with my Windows, until I found this post. Thanks for the effort you put into this, it really helped.

  20. paket wisata bromo midnight tour - November 30, 2016

    Wow, ini pos adalah baik , saya adik adalah menganalisis jenis ini hal, Oleh karena itu saya
    akan menginformasikan nya.

  21. flings near me - June 11, 2017

    I loved as much as you'll receive carried out right here.
    The sketch is tasteful, your authored material stylish.
    nonetheless, you command get bought an impatience over that you wish be delivering the following.
    unwell unquestionably come further formerly again since exactly the same nearly very often inside case you shield this increase.

  22. adultfrienedfinder com login - June 15, 2017

    I was excited to find this site. I want to to thank you for your time for this
    particularly fantastic read!! I definitely enjoyed every part of it and i also
    have you saved to fav to check out new stuff in your website.

Leave a Reply