skip to Main Content

When running the below code on Windows with a valid Windows timezone it returns the correct TimeZoneInfo with 1 AdjustmentRule:

var timeZone = TimeZoneInfo.FindSystemTimeZoneById("Central Europe Standard Time");

However, when running inside a Linux container, after converting the timezone name to the correct IANA equivalent, the TimeZoneInfo returned has 154 AdjustmentRules that overlap:

var ianaTimezone = TZConvert.WindowsToIana("Central Europe Standard Time"); // returns 'Europe/Budapest'

var timeZone = TimeZoneInfo.FindSystemTimeZoneById(ianaTimezone);

This causes System.InvalidTimeZoneException: The elements of the AdjustmentRule array must be in chronological order and must not overlap. when trying to do anything with the TimeZoneInfo afterwards.

I’m lost as to how to resolve this, as I can’t find anything similar when looking around for solutions.

Any help would be very much appreciated!

2

Answers


  1. Chosen as BEST ANSWER

    Upgrading to .NET 6 didn't fix the issue. In the end, I just resorted to sending the timezone name and generating a new TimeZoneInfo, rather than serialising the TimeZoneInfo before sending it, and deserialising after the message has been received.

    Not an ideal solution but worked for my case!


  2. Just FYI, Timezones are not directly handled by .NET. The .NET runtime simply requests TimeZone information from the host operating system and that’s where this error comes from.

    Timezone logic is actually part of the OS, so the TimeZoneInfo .NET component simply queries the available timezones on your OS. If the OS can’t find the Timezone you’re after, the TimeZoneInfo class will throw up the InvalidTimeZoneException as you outlined above.

    When it comes to Linux, particularly Linux Docker containers, standard Timezones are a bit of a misnomer. There are often large discrepancies between Linux flavours as to which TimeZones are available.

    If you’re running on a Linux container, most smaller container distros do not contain any Timezone information beyond the stock standard "Etc/UTC". So when someone calls to get TimeZoneInfo for a given Id (the string from above), since the OS has no notion of this Timezone, it tells TimeZoneInfo so and thus your exception.

    However, you’re not out of luck.

    You can install the tzdata package on your distro. tzdata is a standard set of Timezones which should cover most Timezone mapping scenarios.
    Here’s an example install of tzdata using apt-get

    apt-get install -y --no-install-recommends tzdata

    It’s impossible to know for sure if a timezone ID (the string you posted above "Central Europe Standard Time") will be found, so I’ve made it a habit to add some protective logic around searching for Timezones so in case the Timezone isn’t found, I don’t get a stack trace in my app but instead end up with a default Timezone. Better than nothing.

    var timeZoneId = "Central Standard Time";
    var finalTimeZone = TimeZoneInfo.Utc;
    if (string.IsNullOrEmpty(timeZoneId))
        return finalTimeZone;
    
    try
    {
        finalTimeZone = TimeZoneInfo.FindSystemTimeZoneById(timeZoneId);
    }
    catch(InvalidTimeZoneException)
    {
        _logger.Warn("Timezone ID of '{timeZoneId}' not found");
        finalTimeZone = TimeZoneInfo.Utc;
    }
    
    return finalTimeZone;
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search