noshitsherlock
noshitsherlock

Reputation: 1153

TimeZoneInfo in .NET Core when hosting on unix (nginx)

For example, when I try to do the following.

TimeZoneInfo.FindSystemTimeZoneById("Central European Standard Time")

I get the error, that the TimeZone is not available on the local computer. When I run this locally it works, but there I run it on windows. When deployed it runs on a Unix machine in Nginx. I can see that FindSystemTimeZoneById is looking in the wrong folder when it comes to Unix. Is there any way to make this work?

Upvotes: 75

Views: 56664

Answers (8)

J. Doe
J. Doe

Reputation: 2747

.NET Core uses system timezone. Unfortunately Windows and Linux have a different timezone system. Now you have two ways:

Upvotes: 47

EsbenB
EsbenB

Reputation: 3406

I ended up writing a small helper function:

    public static TimeZoneInfo GetTimeZone(string unixId, string windowsId)
    {
        foreach (TimeZoneInfo timezone in TimeZoneInfo.GetSystemTimeZones())
        {
            if (timezone.Id == windowsId|| timezone.Id == unixId)
            {
                return timezone;
            }
        }
        return null;
    }

Upvotes: 0

fidke
fidke

Reputation: 181

Quick and dirty solution: serialize your TimeZoneInfo with ToSerializedString in a dummy app on Windows, save the output, then deserialize with FromSerializedString where you need it.

On Windows:

Console.WriteLine(TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time").ToSerializedString());

Output:

Eastern Standard Time;-300;(UTC-05:00) Eastern Time (US & Canada);Eastern Standard Time;Eastern Daylight Time;[01:01:0001;12:31:2006;60;[0;02:00:00;4;1;0;];[0;02:00:00;10;5;0;];][01:01:2007;12:31:9999;60;[0;02:00:00;3;2;0;];[0;02:00:00;11;1;0;];];

Then:

// TimeZoneInfo is immutable
public static readonly TimeZoneInfo EST = TimeZoneInfo.FromSerializedString(
            "Eastern Standard Time;-300;(UTC-05:00) Eastern Time (US & Canada);Eastern Standard Time;Eastern Daylight Time;[01:01:0001;12:31:2006;60;[0;02:00:00;4;1;0;];[0;02:00:00;10;5;0;];][01:01:2007;12:31:9999;60;[0;02:00:00;3;2;0;];[0;02:00:00;11;1;0;];];");

Upvotes: 5

Tobias J
Tobias J

Reputation: 22893

Starting with .NET 6, it is finally possible to work with time zones in a cross-platform manner.

The TimeZoneInfo.FindSystemTimeZoneById(string) method automatically accepts either Windows or IANA time zones on either platform and convert them if needed.

// Both of these will now work on any supported OS where ICU and time zone data are available.
TimeZoneInfo tzi1 = TimeZoneInfo.FindSystemTimeZoneById("AUS Eastern Standard Time");
TimeZoneInfo tzi2 = TimeZoneInfo.FindSystemTimeZoneById("Australia/Sydney");

Note that, as specified on the link, the .NET Core Alpine Linux-based Docker images do not have the necessary tzdata installed by default, so it must be installed in your Dockerfile for this to work correctly.

Upvotes: 31

Uli
Uli

Reputation: 1675

Working of off the previous answer, we can avoid the expensive try/catch by checking which OS we're running on:

using System;
using System.Runtime.InteropServices;

TimeZoneInfo easternStandardTime;
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
  easternStandardTime = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
}
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
  easternStandardTime = TimeZoneInfo.FindSystemTimeZoneById("America/New_York");
}
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
{
  easternStandardTime = TimeZoneInfo.FindSystemTimeZoneById("America/New_York");
}

Upvotes: 48

EverPresent
EverPresent

Reputation: 1970

I was able to support this use-case in my development docker image by doing the following:

cp /usr/share/zoneinfo/America/Los_Angeles "/usr/share/zoneinfo/Pacific Standard Time"

Obviously, I don't think that would be a good idea for production deployments. But it might help in some scenarios.

Upvotes: 13

sam
sam

Reputation: 542

If you want to try a Windows time zone and then fallback on a IANA one if the Windows one doesn't exist:

var tzi  = TimeZoneInfo.GetSystemTimeZones().Any(x => x.Id == "Eastern Standard Time") ? 
    TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time") : 
    TimeZoneInfo.FindSystemTimeZoneById("America/New_York");

Upvotes: 17

Alvaro Bardaji
Alvaro Bardaji

Reputation: 385

Can you please try this?

   TimeZoneInfo easternZone;
        try
        {
            easternZone = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
        }
        catch (TimeZoneNotFoundException)
        {
            easternZone = TimeZoneInfo.FindSystemTimeZoneById("America/New_York");
        }

You can review the list of IANA time zones here https://en.wikipedia.org/wiki/List_of_tz_database_time_zones

Upvotes: 25

Related Questions