.net 在Linux上运行时,C#TimeZoneInfo.FindSystemTimeZoneById返回不正确的调整规则

nr9pn0ug  于 2022-11-19  发布在  .NET
关注(0)|答案(2)|浏览(184)

在Windows上运行以下代码时,如果Windows时区有效,它将返回正确的TimeZoneInfo,其中包含1个AdjustmentRule:

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

但是,当在Linux容器中运行时,在将时区名称转换为正确的等效IANA名称后,返回的TimeZoneInfo具有154个重叠的AdjustmentRules:

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

var timeZone = TimeZoneInfo.FindSystemTimeZoneById(ianaTimezone);

这会导致在以后尝试使用TimeZoneInfo执行任何操作时出现System.InvalidTimeZoneException: The elements of the AdjustmentRule array must be in chronological order and must not overlap.
我不知道如何解决这个问题,因为我找不到任何类似的解决方案时,环顾四周。
任何帮助都将不胜感激!

q8l4jmvw

q8l4jmvw1#

升级到.NET 6并没有解决这个问题。最后,我只是发送时区名称并生成一个新的TimeZoneInfo,而不是在发送之前序列化TimeZoneInfo,并在收到消息后反序列化。
不是一个理想的解决方案,但为我的情况工作!

brvekthn

brvekthn2#

仅供参考,. NET不直接处理时区。.NET运行时只是从主机操作系统请求时区信息,这就是此错误的来源。
时区逻辑实际上是操作系统的一部分,因此TimeZoneInfo .NET组件只是查询操作系统上可用的时区。如果操作系统找不到您要的时区,TimeZoneInfo类将抛出InvalidTimeZoneException,如上面所述。
当涉及到Linux,特别是Linux Docker容器时,标准的TimeZones有点用词不当。Linux风格之间在可用的TimeZones方面经常存在很大的差异。
如果你在Linux容器上运行,大多数较小的容器发行版不包含任何超出标准“Etc/UTC”的时区信息。因此,当有人调用以获取给定Id(上面的字符串)的TimeZoneInfo时,由于操作系统没有这个时区的概念,它会告诉TimeZoneInfo如此,从而导致异常。
不过,你并没有倒霉。
您可以在您的发行版上安装tzdata包。tzdata是一组标准的时区,它应该涵盖大多数时区Map场景。
下面是一个使用apt-get安装tzdata的示例
apt-get install -y --no-install-recommends tzdata
不可能确切知道是否会找到时区ID(您在“中欧标准时间”上方发布的字符串),所以我已经养成了一个习惯,在搜索时区时添加一些保护逻辑,这样如果没有找到时区,我就不会在我的应用中得到堆栈跟踪,而是最终得到一个默认时区。

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;

相关问题