【问题标题】:Check a date (datetime) if it is Daylight Saving Time with unknown region - c#检查日期(日期时间)是否是具有未知区域的夏令时 - c#
【发布时间】:2022-01-20 06:40:03
【问题描述】:

根据我从其他问题中了解到的情况,我使用下面的代码检查日期是否为夏令时并根据需要进行更改。我不知道应用程序将使用哪个区域,因此我使用的是 Utc。但是它没有按预期工作。

DateTime dateValWithOffset = dateVal;
TimeZoneInfo timeZoneInfo = TimeZoneInfo.Utc;

if(timeZoneInfo.IsDaylightSavingTime(dateValWithOffset))
{
 dateValWithOffset = dateValWithOffset.AddMinutes(60);
}

示例:对于 示例日期 (06-JUL-21 06.16.34.547000000 AM),上述代码应将 dateValWithOffset 显示为 07/06/2021 02:16:34.547 AM > 但它返回 07/06/2021 01:16:34.547 AM 。如果有人可以指出我哪里出错了。

【问题讨论】:

  • UTC 是通用的,所以没有夏令时。
  • 如果您不知道时区/地区,则无法应用夏令时规则。因为每个时区都有不同的规则。
  • 偏移量不会告诉你时区。为此,您需要时区信息。大多数情况下,保存为 UTC 并仅转换为 UI 上的本地(浏览器)时间就足够了。
  • 时间和日历比时间和偏移量要复杂得多。在 .NET 中,您可以使用 NodaTime 表示瞬间并使用 IANA 时区数据库处理时区
  • 使用 DateTimeOffset 足以将值显示为本地时间,无需在任何时区进行调整,但不足以告诉您 DST 是否适用。如果原始时区的 DST 规则发生变化(发生的频率比人们想象的要频繁得多),则必须调整 DateTimeOffset 值。当然,UTC 值也是如此。俄罗斯在过去 10 年中两次更改了夏令时规则。埃及突然改变了 DST 规则,只通知了几周

标签: c# datetime timezone dst


【解决方案1】:

呵呵,我喜欢微软的做法,时间,然后尝试修复它以及您可以用非常有趣的方式来做看似明智的事情:) 有趣的可爱错误领域。

更新:首先要解决这个问题:IMO 出错的地方是您的日期格式不包含有关 UTC 零偏移量的时间信息,也不包含记录的偏移量信息

所以让我从最常见的错误开始,作为一个术语问题,.net(或者)UTC 是一个时刻的概念并不完全正确。它不是,实际上它是 ISO 8601 定义的一个符号,它可以而且应该以序列化形式传播并包含最大合规性的偏移量。 https://en.wikipedia.org/wiki/ISO_8601#Coordinated_Universal_Time_(UTC)

如果您关心,请通读https://docs.microsoft.com/en-us/dotnet/standard/base-types/how-to-round-trip-date-and-time-values,如果您添加额外信息,请考虑它是否真的不是最实际的时间协调。

如果您想在雾蒙蒙的街道上散步,请尽情享受,您可以复制粘贴此单元测试并在监控本地人和调试输出窗口的同时逐步执行。

[TestMethod]
public void DateJugglingTest()
{
    var now = DateTime.Now; // local time, though on a server in the cloud, practially useless
    Debug.WriteLine(now.ToString("O"));            
    Debug.WriteLine(now.Kind.ToString());

    var utcZulu = DateTime.SpecifyKind(now, DateTimeKind.Utc); //now is not utc (zero) but intending it so will change the kind
    Debug.WriteLine(utcZulu.ToString("O"));
    Debug.WriteLine(utcZulu.Kind.ToString());
    Debug.WriteLine(utcZulu.ToLocalTime().ToString("O")); //local time at point of execution, notice we're an hour in the future, very common mistake

    var dateTimeOffset = new DateTimeOffset(now);//much more relevant datetime type in C# in a global village time period
    Debug.WriteLine(dateTimeOffset.DateTime.ToString("O"));
    Debug.WriteLine(dateTimeOffset.UtcDateTime.ToString("O"));

    dateTimeOffset = new DateTimeOffset(now, new TimeSpan(1,0,0));
    Debug.WriteLine(dateTimeOffset.DateTime.ToString("O"));
    Debug.WriteLine(dateTimeOffset.UtcDateTime.ToString("O"));
    Debug.WriteLine(dateTimeOffset.ToString("O"));

    var tzi = TimeZoneInfo.FindSystemTimeZoneById("Romance Standard Time");
    Debug.WriteLine(tzi.GetUtcOffset(utcZulu)); //another common pitfall because method is oblivious to datatime.kind
    Debug.WriteLine(tzi.GetUtcOffset(now));

    string utcFORMATstring = "2021-12-17T11:36:20.1234567+01:00"; //This is Universally Coordinated Time format a.k.a. UTC actually
    dateTimeOffset = DateTimeOffset.Parse(utcFORMATstring);
    Debug.WriteLine(tzi.GetUtcOffset(dateTimeOffset.DateTime));  //but this method still doesn't do right
    Debug.WriteLine(tzi.GetUtcOffset(dateTimeOffset.UtcDateTime)); //no matter which you choose

    Debug.WriteLine(dateTimeOffset.DateTime.ToUniversalTime().ToString("O")); //this one gets the right result
    Debug.WriteLine(dateTimeOffset.UtcDateTime.ToUniversalTime().ToString("O"));
    

    utcFORMATstring = "2021-12-17T11:36:20.1234567+00:00"; //equivalent to ...567Z
    dateTimeOffset = DateTimeOffset.Parse(utcFORMATstring);
    Debug.WriteLine(tzi.IsDaylightSavingTime(dateTimeOffset.DateTime)); //interesting feature to see if a given moment will be daylight saving in the actual timezone

    //Example
    var whenItWasAtZeroOffsetZuluTimeBecauseStoredAsRegularDateSomewhere = DateTime.SpecifyKind(DateTime.UtcNow, DateTimeKind.Utc);
    var whenItWasSerializedAsIs = whenItWasAtZeroOffsetZuluTimeBecauseStoredAsRegularDateSomewhere.ToString("O");
    Debug.WriteLine(whenItWasSerializedAsIs);

    var whenItWasToTheSystem = whenItWasAtZeroOffsetZuluTimeBecauseStoredAsRegularDateSomewhere; //for the sake of imagined backward compatibility somewhere
    DateTime whenToDisplay;
    //If having to be manual because that is all you have            
    whenToDisplay = DateTime.SpecifyKind(whenItWasToTheSystem.Add(tzi.GetUtcOffset(whenItWasToTheSystem)), DateTimeKind.Local);
    Debug.WriteLine(whenToDisplay.ToString("O")); //And this is just because somebody at Microsoft hate the world :)) notice date is completely correctly configured but is way off

    //The way your api's should really send dates around, as strings carrying the offset
    dateTimeOffset = new DateTimeOffset(whenToDisplay, tzi.GetUtcOffset(whenItWasToTheSystem));
    var correctAtAnywhereInCloudTopology = dateTimeOffset.ToString("O"); //This is totally UTC as defined in ISO 8601
    Debug.WriteLine(correctAtAnywhereInCloudTopology);
    Assert.IsTrue(true);
}

更新:我添加了定义的链接,所以就像有人立即指出的那样,它与通用时间协调中某个时刻的数据格式无关。 但是,如果完全诚实,英国格林威治经度的给定时间没有偏移“UTC”本身并不能协调任何东西,这是我们的意图,就像我们必须从名称中推测的那样。 所以例如我们在都柏林有一个云集群,例如为爱沙尼亚的客户提供服务。您需要一种格式的日期,该格式包含参考点的时间和数据的偏移量,以便在 IMO 前端有意义并可用,除非不断地相互转换是浪费资源。

【讨论】:

  • 在有趣的错误列表中添加 UTC 与符号有关的概念。您发布的字符串格式化代码与问题无关。它仅显示了格式化 .NET 的内置日期类型的不同方式。甚至没有接近实际处理时区而不是偏移量。
  • 这不是“微软搞砸了”,因为 Java 最初的情况更糟。这就是为什么创建像 JodaTime 和用于 .NET 的 NodaTime 这样的库的原因。以及为什么 IANA 时区数据库已成为时区名称和 DST 规则的事实标准。
  • 确实,UTC 是一个与 ISO-8601 完全不同的概念。没有“UTC 格式”之类的东西。虽然在序列化形式中包含 UTC 偏移量很有用,但它仍然不会告诉您字符串。
  • 好吧,伙计们,我有意见。 IMO 例如,由正在使用的 TimeZoneInfo 元素表示的偏移量是为了与 DateTimeOffset 互换以及在运行时实际表示它的一种方式。此外,世界协调时间的目的是能够协调时间,这样做你不需要在“我有它”的地方有时间,你需要时区的偏移来旅行和。并举例说明如何使用 TimeZoneInfo.FindSystemTimeZoneById 获取时区,然后将其用于某事,完全设置 Shalini 的原因
  • @PanagiotisKanavos 而根据en.wikipedia.org/wiki/ISO_8601#Coordinated_Universal_Time_(UTC),您和 Jon Skeet 在技术上是正确的 - 请记住我们正在对系统进行的操作,与在某处的某人进行交互,因此“Z”之上的错误" 包括偏移量在内的时刻是数据实际包含协调信息的时间,我发现它也与指向 DateTimeOffset 类相关,因为它可以访问两者
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-05-08
  • 1970-01-01
  • 1970-01-01
  • 2020-08-14
  • 2018-01-12
  • 2012-04-07
相关资源
最近更新 更多