繁体   English   中英

检查日期(日期时间)是否为未知区域的夏令时 - c#

[英]Check a date (datetime) if it is Daylight Saving Time with unknown region - c#

根据我从其他问题中了解到的情况,我使用下面的代码来检查日期是否是夏令时并根据需要进行更改。 我不知道应用程序将使用哪个区域,因此我使用的是 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 如果有人能指出我哪里错了,请。

正如jason.kaisersmith在评论中所说,“UTC 是通用的,所以没有夏令时。”

详细地说,UTC 没有任何夏令时。 相反,世界各地的每个时区都以不同的方式观察夏令时。 有些时区根本不使用它。 某些时区在与其他时区不同的日期或时间开始和停止 DST。 甚至有一个时区将 DST 转换 30 分钟,而不是通常的 1 小时。 如果没有时区参考,DST 的概念就毫无意义。

为清楚起见和参考,这里是按国家/地区划分的 2022 年预计 DST 日期的概述,以及 2022 年上半年下半年的日期和时间的详细列表。

Datetime值应始终采用 UTC。 要在机器或用户的本地时区中格式化日期时间,您应该转换为DateTimeOffset 知道当地时间和知道那个时间是否在夏令时是两件不同的事情。

// machine local
var timeZoneInfo = TimeZoneInfo.Local;
// or by name
var timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById(name);
var localTime = new DateTimeOffset(dateVal, timeZoneInfo.GetUtcOffset(dateVal));
var isDst = timeZoneInfo.IsDaylightSavingTime(localTime)

恕我直言DateTime是一种可怕的类型,设计于云计算时代之前。 Utc之外的所有DateTimeKind值都鼓励程序员继续错误地处理日期,应弃用。

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

更新:首先解决这个问题: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如果您添加额外的信息,最实际的时间协调。

如果您想走在雾蒙蒙的街道上,请放纵我,您可以复制粘贴此单元测试并在监视本地人和调试 output windows 的同时逐步完成。

[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 前端有意义并可以使用,除非不断地相互转换是浪费资源。

暂无
暂无

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

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