Cross Platform DateTime in .NET Core

If you are deploying to multiple platforms or even just developing on Windows and then deploying to linux, dealing with time zones might trip you up.

The problem arises when you try to localize UTC time to some specific time zone. When I run this code:

var windowsTimeZoneId = "Central Europe Standard Time";
var zone = TimeZoneInfo.FindSystemTimeZoneById(windowsTimeZoneId);
var dt = TimeZoneInfo.ConvertTime(DateTimeOffset.UtcNow, zone);
Console.WriteLine(dt);

on my Windows machine everything works as expected, but the same code being run on linux blows up with

System.TimeZoneNotFoundException: Couldn't read time zone file ...

What’s going on here?

The time zone data are sourced from the underlying operating system and, unfortunately, Windows and linux use different sources for that data. I haven’t found the exact source for Windows, for linux it’s IANA Time Zone Database.

You can find more details about this issue in discussions on github in corefx repo, for example here and there.

To make it work you need some kind of mapping table. There is a project specifically for this TimeZoneConverter. You can find more details on its github page, but the gist looks like this:

// Windows ID
var tz1 = TZConvert.GetTimeZoneInfo("Eastern Standard Time");

// IANA
var tz2 = TZConvert.GetTimeZoneInfo("America/New_York");

// -> both work anywhere

If you are more serious about date and time, I would recommend you to check out Noda Time project, led by Jon Skeet. With Noda Time, the code might look like this:

var zone1 = DateTimeZoneProviders.Tzdb["Europe/Budapest"];
var zone2 = TzdbDateTimeZoneSource.Default.WindowsMapping
  .PrimaryMapping["Central Europe Standard Time"];

BEWARE!

Time zone data changes quite frequently, they change, come and go; so you need to keep it updated, no matter what library you choose.

Comments

comments powered by Disqus