70

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?

noshitsherlock
  • 1,103
  • 2
  • 11
  • 28
  • I think this question sounds like it should be over in the UNIX area of StackExchange as it sounds like you need to install/configure the time zone database on your Unix machine appropriately. – Martin Costello Jan 10 '17 at 10:41
  • But it seems like the error is FindSystemTimeZoneById is looking in the wrong folder when it comes to unix, the timezones are installed but ofc not located in the same directory as on a windows machine. – noshitsherlock Jan 10 '17 at 11:17
  • 2
    .NET Core on Unix looks in `/usr/share/zoneinfo/` for the time zone files. If you want it to look in a different directory you can set the `TZDIR` environment variable to the directory that contains your tzfiles. See the [Unix implementation](https://github.com/dotnet/coreclr/blob/master/src/mscorlib/src/System/TimeZoneInfo.Unix.cs) for more information. On Windows, the timezone information is read from the registry, and not from files on disk. – Eric Erhardt Jan 10 '17 at 18:19
  • Extra keywords for search engines: System.TimeZoneNotFoundException: The time zone ID '...' was not found on the local computer. System.IO.FileNotFoundException: Could not find file '/usr/share/zoneinfo/...' – Endy Tjahjono Mar 02 '20 at 01:16

8 Answers8

47

.Net Core using system timezone. Unfortunately Windows and Linux have different timezone system. Now you have two ways:

Michael Freidgeim
  • 26,542
  • 16
  • 152
  • 170
J. Doe
  • 2,651
  • 1
  • 13
  • 31
  • 7
    This is a current limitation of .NET Core on Unix. See [the GitHub issue here](https://github.com/dotnet/corefx/issues/2538). You need to pass in a different time zone ID on Windows than on Unix. The issue is marked as "Up for grabs". Submissions welcome ;). – Eric Erhardt Jan 10 '17 at 18:12
46

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");
}
Uli
  • 1,565
  • 14
  • 24
  • 2
    Hi, where can I find a side to side comparison of Windows and Linux timezoneIDs? It's so hard to find. All I want was to find the linux equivalent of 'Mountain Standard Time' – JkAlombro Jul 10 '20 at 11:37
  • 4
    if its OSX the timezone called `Place of Birth of Our Dear Prophet and Visionary +08:30` – Boppity Bop Jan 21 '21 at 17:40
  • 1
    OSX is the same as Linux. If you just need to develop on OSX you can `cp /usr/share/zoneinfo/America/New_York /usr/share/zoneinfo/Eastern\ Standard\ Time` – JuJoDi Feb 12 '22 at 21:13
  • This solution should have if/else or even a switch. Once OSPlatform has matched, the others should not be tested. – Andrew Dec 12 '22 at 15:40
25

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

Alvaro Bardaji
  • 385
  • 2
  • 5
21

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.

Tobias J
  • 19,813
  • 8
  • 81
  • 66
17

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");
sam
  • 542
  • 5
  • 11
  • slightly OCD.. but you should just use firstordefault instead of any like this: `TimeZoneInfo.GetSystemTimeZones().FirstOrDefault(x => x.Id == "Eastern Standard Time") ?? TimeZoneInfo.FindSystemTimeZoneById("America/New_York");` or even just `TimeZoneInfo.GetSystemTimeZones().FirstOrDefault(x => x.Id is "Eastern Standard Time" or "America/New_York");` (assuming you're not on .net 6 which handles it automatically) – user15716642 Mar 05 '23 at 22:20
13

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.

EverPresent
  • 1,903
  • 17
  • 21
5

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;];];");
EsbenB
  • 3,356
  • 25
  • 44
fidke
  • 151
  • 3
  • 2
0

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;
    }
EsbenB
  • 3,356
  • 25
  • 44