简体   繁体   English

.NET Core 中的 TimeZoneInfo 托管在 unix (nginx)

[英]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.我收到错误, TimeZone在本地计算机上不可用。 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?当我在本地运行它时它有效,但我在 windows 上运行它。部署后它在 Nginx 中的 Unix 机器上运行。我可以看到FindSystemTimeZoneById在涉及 Unix 时在错误的文件夹中查找。有什么方法可以使这个工作?

.Net Core using system timezone. .Net Core 使用系统时区。 Unfortunately Windows and Linux have different timezone system.不幸的是,Windows 和 Linux 有不同的时区系统。 Now you have two ways:现在你有两种方法:

Working of off the previous answer , we can avoid the expensive try/catch by checking which OS we're running on:处理上一个答案,我们可以通过检查我们正在运行的操作系统来避免昂贵的try/catch

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))
{
  throw new NotImplementedException("I don't know how to do a lookup on a Mac.");
}

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您可以在此处查看 IANA 时区列表https://en.wikipedia.org/wiki/List_of_tz_database_time_zones

If you want to try a Windows time zone and then fallback on a IANA one if the Windows one doesn't exist:如果您想尝试使用 Windows 时区,然后在 Windows 时区不存在的情况下回退到 IANA 时区:

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

I was able to support this use-case in my development docker image by doing the following:通过执行以下操作,我能够在我的开发 docker 映像中支持此用例:

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.但在某些情况下它可能会有所帮助。

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.快速而肮脏的解决方案:在 Windows 上的虚拟应用程序中使用ToSerializedString序列化您的TimeZoneInfo ,保存输出,然后在您需要的地方使用FromSerializedString反序列化。

On Windows:在 Windows 上:

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

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;];];");

Starting with .NET 6 Preview 4, it is finally possible to work with time zones in a cross-platform manner.从 .NET 6 Preview 4 开始, 终于可以跨平台处理时区了。

The TimeZoneInfo.FindSystemTimeZoneById(string) method automatically accepts either Windows or IANA time zones on either platform and convert them if needed. TimeZoneInfo.FindSystemTimeZoneById(string)方法自动接受任一平台上的 Windows 或 IANA 时区,并在需要时进行转换。

// 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 will not have the necessary tzdata installed by default , so it must be installed in your Dockerfile for this to work correctly.请注意,如链接中所述,基于 .NET Core Alpine Linux 的 Docker 映像默认不会安装必要的tzdata ,因此必须将其安装在您的Dockerfile中才能正常工作。

I ended up writing a small helper function:最后写了个小帮手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;
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM