簡體   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