DateTime.ToLocalTime() behavior change with .NET 4.5 on Server 2008R2? - c#

We are seeing bizarre behavior with .NET 4.5 and System.DateTime. The behavior of ToLocalTime() when applied to DateTime objects with Kind=Utc seems different on Server 2008R2 machines with .NET 4.5 compared with .NET 4.0. Even more bizarre, the problem does not manifest on developer PCs with .NET 4.5 installed.
Does anyone have an explanation for this behavior? I can't turn up any bug reports on Microsoft sites. We can use a more complicated approach to convert times that works, but it's hard to ensure no one ever uses .ToLocalTime() in the future.
Developer PC - Windows 7, VS2012, .NET 4.5 installed during VS2012 install:
unixEpoch 621355968000000000 Utc
asLocal1 635121441023588986 Local
asLocal2 635121441023588986 Unspecified
Production Server 1 - Server 2008R2, .NET 4.0
unixEpoch 621355968000000000 Utc
asLocal1 635121441023588986 Local
asLocal2 635121441023588986 Unspecified
Production Server 2 - Server 2008R2, .NET 4.5 installed as standalone package
unixEpoch 621355968000000000 Utc
asLocal1 ***635121405023588986*** Local
asLocal2 635121441023588986 Unspecified
Other than having .NET 4.5 installed, production servers 1 and 2 are identical. The problem manifests when run in several different local timezones around the globe.
Sample code that demonstrates the problem:
using System;
using NUnit.Framework;
namespace DateTimeToLocal
{
[TestFixture]
public class DateTimeFixture
{
private const long unixTimeInNanos = 1376561702358898611;
[Test]
public void Demonstrate()
{
DateTime unixEpoch = new DateTime(1970, 01, 01, 0, 0, 0, DateTimeKind.Utc);
DateTime utc = unixEpoch.AddTicks(unixTimeInNanos / 100);
// Method 1 - doesn't work on 2008R2 with .NET 4.5
DateTime asLocal1 = utc.ToLocalTime();
// Method 2 - works across all .NET 4.0 and .NET 4.5
TimeZoneInfo localTz = TimeZoneInfo.FindSystemTimeZoneById(TimeZoneInfo.Local.StandardName);
DateTime asLocal2 = TimeZoneInfo.ConvertTimeFromUtc(utc, localTz);
Console.WriteLine("unixEpoch {0} {1}", unixEpoch.Ticks,unixEpoch.Kind);
Console.WriteLine("asLocal1 {0} {1}", asLocal1.Ticks, asLocal1.Kind);
Console.WriteLine("asLocal2 {0} {1}", asLocal2.Ticks, asLocal2.Kind);
Assert.AreEqual(asLocal1, asLocal2);
}
public static void Main(string[] args)
{
var t = new DateTimeFixture();
t.Demonstrate();
}
}
}

This problem goes away when the following hotfix is applied to the server running 2008R2: http://support.microsoft.com/kb/2863058/en-us
It appears that under the hood, DateTime.ToLocalTime() uses a lookup technique that fails unless the timezone database update contained in that hotfix has been applied.
This was extremely hard to track down, and I've not seen ANY other web forum mentioning the link between that database update and something as fundamental as utc.ToLocalTime() failing for dates in August 2013, no where near a recent boundary that changed due to legislation, etc. in the Eastern U.S. Still wondering how exactly this is not being seen more places?

Related

Date deserialization difference between kestrel on windows and kestrel on macOs/linux

I have tried searching informations on net.core documentation (issue etc) without results.
The code is simpler:
[HttpGet()]
[Route("dob")]
public string dobTest()
{
var content = #"""1942-01-01T22:00:00.000Z""";
var settings = new JsonSerializerSettings()
{
//DateFormatHandling = DateFormatHandling.IsoDateFormat,
//DateParseHandling = DateParseHandling.DateTimeOffset,
DateTimeZoneHandling = DateTimeZoneHandling.Local,
//DateTimeZoneHandling = DateTimeZoneHandling.RoundtripKind
};
var dob = JsonConvert.DeserializeObject<DateTime>(content, settings);
return $"dob: {dob.ToString("yyyy-MM-dd HH:mm:ss.fff")} - {dob.Kind}";
}
if I run this code on Mac or Linux the result is:
dob: 1942-01-02 00:00:00.000 - Local
if I run this code on windows the result is:
dob: 1942-01-01 23:00:00.000 - Local
My MacOs timezone is set on Rome(UTC +01:00)
Windows timezone is set on Rome(UTC +01:00)
the version of Newtonsoft.Json is 12.0.3
The version of net framework is net core 3.1
Linux and OSX both use the IANA time zone database for its primary source of time zone information, which has correct historical data for time zones in 1942 in Rome, under the identifier Europe/Rome. You can see that UTC+2 is the correct offset for the date given here as well.
Windows, on the other hand, does not have that history for this time zone. The equivalent Windows identifier is W. Europe Standard Time, which has an English display name of (UTC+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna. You can see the data Windows has in the registry under the following key:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones\W. Europe Standard Time
If you examine this key using RegEdit, you'll notice that unlike several other time zones, there is no Dynamic DST subkey for this zone. That means Windows is not aware of any historical differences in DST rules, and thus treats every year the under the same set of rules.
Windows does have historical data for some zones, but in general Microsoft only guarantees historical accuracy since 2010 per its DST/TZ support policy.
Thus, if you have the need in your application for historical time zone accuracy, then you should use IANA time zones only. In .NET, you can do this by using TZDB provider in the Noda Time library.

DateTime.Parse not working on Windows Server 2012

I have an old and heavy windows application where DateTime.TryParse(string value, out result) is used extensively.
The below code runs smoothly on Windows 7 and Windows 10.
// Below is done when the application starts
System.Threading.Thread.CurrentThread.CurrentCulture = new CultureInfo("en-AU");
var success = DateTime.TryParse("20 02", out result);
// Above is just an example of one of the ways we have been using it. Here success is true and results are -> 20/02/2020 12:00:00 AM
But above statement returns false when executed on Windows Server 2012 R2 Standard.
Appears like Win Server 2012 has broken the
DateTime.TryParse. Interestingly if I use .netFramework 3.5 then it works in all OS. But we are on framework v4.6.2 (VS-2019).
Is this a bug in Microsoft OS or .netFramework 4.6? Is there any existing workaround for this without making any changes in code, maybe a .net framework patch, etc. Honestly, it will be difficult for me to make any changes in code related to this as its usage is more than 1.5k in the application.
Thanks in advance !!!
Maybe not the answer, but can you try this on your Windows Server 2012 R2.
foreach (var ci in CultureInfo.GetCultures(System.Globalization.CultureTypes.AllCultures).OrderBy(ci => ci.Name))
{
Console.WriteLine("{0} ({1})", ci.Name, ci.EnglishName);
}
are you culture part of that list?
Read this: https://learn.microsoft.com/en-gb/openspecs/windows_protocols/ms-lcid/a9eac961-e77d-41a6-90a5-ce1a8b0cdb9c
Or do this: https://learn.microsoft.com/en-us/archive/blogs/shawnste/locale-builder-v2-0-for-windows-8-1server-2012-r2-released

How to update the Windows Language Code Identifier in Windows Server?

I recently started having a problem with CultureInfo in my web application.
The code in question:
public static CultureInfo ConvertToCultureInfo(this string input)
{
try
{
return new CultureInfo(input);
}
catch (Exception)
{
return new CultureInfo("en-US");
}
}
When a user whose locale is 'en-AT' is accessing my website the request for this cultureinfo works on my local but is failing on my Windows Server 2012 box (and falling back to en-US, which is incorrect).
We tracked it down to an issue with the MS-LCID version 10.1 but this is allegedly only available for Windows Server 2016.
However, this occurs to me as kind of silly - why can't we just download a package that updates the existing LCID to support the newer locales? It's still the same list of dateformats and Windows Server 2012 is still supported. I can't find any resources on updating this and was hoping someone here knew a bit about this and could point me in the right direction.
Right now my best lead is to additionally test for custom CultureInfos and supply my own formats, but this seems like overkill when there exists the LCID, it's just somewhat out of date.

different Computer, different CultureInfo - Problems with datetime format "latvian"

it is a web page (Asp.Net MVC), multi-language including english, latvian, lithuvian, russian, polonia.
For selecting a date we choose the jQuery-Ui-datepicker including extra localization files for each language. (Date is given as string: "DateTime".ToString("d", new CultureInfo("lv")) )
All runs fine with all languages at my development computer (Win10, DotNet 4.5, Visual Studio 2012).
Running the web application at the server (Windows Server 2012 R2) other languages without problems. But the latvian language leads to problems.
I added trace code around the CultureInfo for Latvian 'lv'.
There is an difference between the CultureInfo.DateTimeFormat.ShortDatePattern between development notebook and web Server.
CultureInfo.DateTimeFormat.ShortDatePattern
- my computer: 'dd.MM.yyyy'
- web server : 'dd.MM.yyyy.'
the fastest solution would be: trim final point at datetime format.
(the javascript seems to work without the 'final point')
Is it a Framework Bug ?
which system needs a fix ? the server or my computer (inclusing javascript datepicker localization source)
How to solve it in a nice way (so it doesnt seems hacky)
thanks,
Mathias

DateTime.Parse throws an exception with Optimse Code compiler option

In my project I have the line
DateTime alarmDateTime = DateTime.Parse(AlarmTimeStamp.Text);
AlarmTimeStamp.Text is for example "04/09/2015 10:23" (The computer's Region setting is English UK)
This throws a FormatException, but only when the Optimise Code compiler setting is on, i.e. a Release build. If I turn this off, it works as expected.
I'm not sure where to begin with debugging this since the debugger doesn't work correctly with optimised code.
If it's relevant, this is from a ASP.Net Web Forms application, .Net 3.5 hosted in Windows Server 2008 R2, IIS 7.5.
Edit:
I have done some testing and found that this only occurs on one of my servers. I have 2 servers configured, a development and test. This issue only occurring on my development server. There is no difference between them though. They are both built from the same image.
change your code like this..
string timeString = AlarmTimeStamp.Text;
IFormatProvider culture = new CultureInfo("en-GB", true);
DateTime alarmDateTime = DateTime.ParseExact(timeString, "dd/MM/yyyy HH:mm", culture);

Categories

Resources