【问题标题】:Format Local DateTime with appropriate Local DST-aware Timezone (eg. PST or PDT) depending on time of year根据一年中的时间,使用适当的本地 DST 感知时区(例如 PST 或 PDT)格式化本地 DateTime
【发布时间】:2019-07-03 18:50:30
【问题描述】:

在为 PST 配置的计算机上给定一个 Local DateTime 值(当 DST 开始时,它将在 3 月 10 日隐式更改为 PDT),如何获取包含适当 时区的字符串 - 例如。 PST/PDT,不偏移! - 在输出中?

DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss ???")

预期的输出字符串,例如:

"2019-02-09 13:04:22 PST"  // right after lunch today
"2019-04-09 13:04:22 PDT"  // right after lunch in two months

MSDN DateTime Custom Format Strings 页面显示了将“PST”显式硬编码到输出中的示例,这将在半年和/或本地 TZ 更改时出错。计算机和人会移动,因此硬编码 TZ 值是“不合适的”。

最好这可以通过只是一个格式字符串来完成,允许在渲染/到字符串阶段之前提供 DateTime 值 - 尽管似乎没有“ZZZ”格式。我已经指定了“本地”日期时间类型,希望能减少一些额外的怪癖..

【问题讨论】:

  • 你试过TimeZoneInfo吗?从那里你可以创建一个扩展方法,你可以在任何 DateTime 属性上使用它。 docs.microsoft.com/en-us/dotnet/api/…
  • @bene_rawr 我主要处理一些旧的、讨厌的 ASP <%= Eval("Property", "FormatString") %> 代码,我希望,也许是徒劳的,我错过了一些字符串格式的魔法:}
  • 所有FormatStrings 都列在您刚刚发布的链接中。所以没有什么比这更神奇的了。
  • 是什么让您认为世界上每个时区和每种语言都存在时区缩写?甚至,那么是什么让您认为时区缩写足以识别时区?提示 - 这两个问题都是无定形的。考虑“CST”或“IST”——每个人在世界上都有三到四个他们可能属于的地方。还有很多很多其他的案例......
  • 考虑使用 DateTimeOffset 并简单地显示偏移量而不是一些非标准时区缩写

标签: c# .net datetime localization timezone


【解决方案1】:

TimeZoneInfo 应该可以在这里提供帮助:https://docs.microsoft.com/en-us/dotnet/api/system.timezoneinfo.standardname?view=netframework-4.7.2

看起来TimeZoneInfo 给出了全名(“太平洋标准时间”/“太平洋夏令时间”)而不是缩写(“PST”/“PDT”)。这是一个问题,您仍然需要找到短名称的来源。这里有一些关于如何做到这一点的想法:Timezone Abbreviations

using System;
using Xunit;

namespace Q54610867
{
    public class TimeZoneTests
    {
        // I'm on Mac/Unix. If you're on Windows, change the ID to "Pacific Standard Time"
        // See: https://github.com/dotnet/corefx/issues/2538
        readonly TimeZoneInfo pacificStandardTime = TimeZoneInfo.FindSystemTimeZoneById("America/Los_Angeles");

        [Fact]
        public void Today()
        {
            var today = new DateTime(2019, 2, 9, 13, 4, 22, DateTimeKind.Local);

            Assert.Equal("2019-02-09 13:04:22 Pacific Standard Time", ToStringWithTz(today, pacificStandardTime));
        }

        [Fact]
        public void future()
        {
            var future = new DateTime(2019, 4, 9, 13, 4, 22, DateTimeKind.Local);

            Assert.Equal("2019-04-09 13:04:22 Pacific Daylight Time", ToStringWithTz(future, pacificStandardTime));
        }

        static string ToStringWithTz(DateTime dateTime, TimeZoneInfo tz)
            => $"{dateTime.ToString("yyyy-MM-dd HH:mm:ss")} {(tz.IsDaylightSavingTime(dateTime) ? tz.DaylightName : tz.StandardName)}";
    }
}

【讨论】:

  • 对于“特定(过去或未来)日期的本地时间”,合适的 TZ 似乎需要一些胶水,这并不总是当前时间 D:
  • 我使用您原始帖子中的示例日期添加了一个工作示例。根据我的理解,它可以满足您的所有要求(除了使用长名称而不是缩写)。你能举一个具体的例子说明缺少什么吗?
  • CLDR 在世界各地实际使用的时区的本地化名称方面做得更好,所以我在我的 TimeZoneNames 库中使用了 CLDR 数据,如 Soner 的回答所示。不过,缩写仍然是 sh*t - 并没有太多工作要做。
  • 哦,你说你在 Mac / Unix 上。你现在真的得到“太平洋标准时间”和“太平洋夏令时间”了吗?如果是这样,那么他们现在必须在那里使用 CLDR 数据。否则它只会显示来自 TZDB 的“PST”和“PDT”缩写(但在世界其他地方会惨遭失败)。
  • 我发布的代码运行,并且断言在我的开发环境(OSX 上的 .NET Core)中传递。 TimeZoneInfo.FindSystemTimeZoneById("America/Los_Angeles").DaylightName 返回Pacific Standard Time
【解决方案2】:

由于DateTime 实例保留时区信息,因此无法使用自定义日期和时间格式字符串来做到这一点。 "zzz" specifier 代表 UTC Offset 值,DateTime.Kind"K" specifier 也不反映时区缩写。两者都对你的情况没用。

但是,有一个名为 TimeZoneNames 的 nuget 包,它是由时区极客 Matt Johnson 编写的,您可以获得时区名称的缩写(同时支持 IANA 和 Windows 时区标识符)

var tz = TZNames.GetAbbreviationsForTimeZone("Pacific Standard Time", "en-US");
Console.WriteLine(tz.Standard); // PST
Console.WriteLine(tz.Daylight); // PDT

如果你想以编程方式获取你的windows时区标识符,你可以使用TimeZoneInfo.Local.Id property,如果你想获取当前的语言代码,你可以顺便使用CultureInfo.CurrentCulture.Name property

var tz = TZNames.GetAbbreviationsForTimeZone(TimeZoneInfo.Local.Id, CultureInfo.CurrentCulture.Name);

但在此之前,您应该检查您的本地时间是否为夏令时,以选择附加格式化字符串的缩写。

DateTime now = DateTime.Now;
bool isDaylight = TimeZoneInfo.Local.IsDaylightSavingTime(now);

如果isDaylighttrue,则应使用TimeZoneValues.Daylight属性的结果,否则应使用第一个代码部分的TimeZoneValues.Standard属性。

最后,您需要在DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss) 字符串的末尾附加这些缩写之一。

关于包装页面上 Matt 的重要说明;

时区缩写有时不一致,但 必须为每个时区正确本地化。在大多数情况下, 您应该只对最终用户显示输出使用缩写。不要 解析输入时尝试使用缩写。

来自Matt's comment的第二条重要提示;

是什么让您认为时区缩写实际上存在于 世界上的每个时区和每种语言?甚至,那是什么让 您认为时区缩写足以识别时间 区?提示 - 这两个问题都是无定形的。考虑“CST”或“IST” - 每个人在世界上都有三四个他们可能属于的地方。 还有很多很多其他的情况......

【讨论】:

  • 即使我很后悔将缩写词放入我的 TimeZoneNames 库中。像“东部标准时间”这样的全名——当然,我可以依靠 CLDR。但是,在任何地方都没有一致且被广泛接受的时区缩写的重要来源。 TZDB 和 CLDR 在这方面都是失败的。有人将不得不花费比我更多的时间将它们整理成各种可接受的缩写“集合”,并弄清楚它们在什么标准下是可以接受的。恕我直言 - 如果您可以完全避免使用时区缩写,您应该这样做。
  • @MattJohnson 我感受到你的痛苦,我的朋友。即使有人(我希望我有)在这个主题上花费大量时间,因为来源不可靠 - 可能永远不会 - ,这个过程将是痛苦的。正如您mentioned 一样,它们也不是独一无二的。即使您将“CST”显示为输出,阅读它的人也会感到困惑。
猜你喜欢
  • 2015-09-08
  • 2015-05-16
  • 2014-04-13
  • 1970-01-01
  • 1970-01-01
  • 2017-03-10
  • 2021-09-25
  • 1970-01-01
  • 2016-05-22
相关资源
最近更新 更多