簡體   English   中英

從通用或本地DateTime添加/減去的最佳實踐

[英]Best practice for adding/subtracting from universal or local DateTime

我正在嘗試在DateTime周圍添加一個包裝器以包含時區信息。 這是我到目前為止所擁有的:

public struct DateTimeWithZone {
    private readonly DateTime _utcDateTime;
    private readonly TimeZoneInfo _timeZone;

    public DateTimeWithZone(DateTime dateTime, TimeZoneInfo timeZone) {
        _utcDateTime = TimeZoneInfo.ConvertTimeToUtc(DateTime.SpecifyKind(dateTime, DateTimeKind.Unspecified), timeZone);
        _timeZone = timeZone;
    }

    public DateTime UniversalTime { get { return _utcDateTime; } }

    public TimeZoneInfo TimeZone { get { return _timeZone; } }

    public DateTime LocalTime { get { return TimeZoneInfo.ConvertTimeFromUtc(_utcDateTime, _timeZone); } }

    public DateTimeWithZone AddDays(int numDays) {
        return new DateTimeWithZone(TimeZoneInfo.ConvertTimeFromUtc(UniversalTime.AddDays(numDays), _timeZone), _timeZone);
    }

    public DateTimeWithZone AddDaysToLocal(int numDays) {
        return new DateTimeWithZone(LocalTime.AddDays(numDays), _timeZone);
    }
}

這是根據先前問題中提供的@Jon Skeet的答案改編的。

由於夏令時問題,我正在努力增加/減少時間。 根據以下內容,最佳做法是添加/減去通用時間:

https://msdn.microsoft.com/en-us/library/ms973825.aspx#datetime_topic3b

我遇到的問題是,如果我說:

var timeZone = TimeZoneInfo.FindSystemTimeZoneById("Romance Standard Time");            
var date = new DateTimeWithZone(new DateTime(2003, 10, 26, 00, 00, 00), timeZone);
date.AddDays(1).LocalTime.ToString();

這將返回26/10/2003 23:00:00。 正如你所看到的那樣,當地時間已經減少了一個小時(由於夏令時結束),所以如果我要顯示它,它會說它與它剛剛添加一天的那天相同。 但是,如果我要說:

date.AddDaysToLocal(1).LocalTime.ToString();

我會回來27/10/2003 00:00:00並保留時間。 這看起來對我來說是正確的,但它違背了加入世界時的最佳做法。

如果有人能幫助澄清正確的方法,我會很感激。 請注意,我已經看過Noda Time,它目前需要做太多工作才能轉換成它,我也想更好地理解這個問題。

兩種方式都是正確的(或不正確的)取決於您需要做什么。

我喜歡將這些視為不同類型的計算:

  1. 按時間順序計算。

  2. 日歷計算。

按時間順序計算涉及以物理時間為常規單位的時間算術。 例如,添加秒,納秒,小時或天。

日歷計算涉及人類發現方便的單位時間算術,但並不總是具有相同的物理時間長度。 例如,添加數月或數年(每個都有不同的天數)。

當您想要添加一個不一定具有固定秒數的粗單位時,日歷計算很方便,但您仍希望在日期中保留更精細的字段單位,例如天,小時,分鍾和秒。

在您的本地時間計算中,您添加一天,並假設日歷計算是您的意圖,您保留當地時間,盡管在本地日歷中1天並非總是24小時。 請注意,本地時間的算術可能會導致本地時間與UTC有兩次映射,甚至是映射到UTC的映射。 因此,您的代碼應該構建為使您知道這種情況永遠不會發生,或者能夠檢測到它何時發生並以適合您的應用程序的任何方式做出反應(例如消除模糊映射的歧義)。

在您的UTC時間計算(按時間順序計算)中,您總是添加86400秒,然后本地日歷可能會做出反應,但這可能是由於UTC偏移更改(夏令時相關或其他)。 UTC偏移量變化可能大到24小時,因此添加按時間順序排列的日期可能甚至不會使當月日歷日突然加1。 按時間順序計算的結果總是具有唯一的UTC < - >局部映射(假設輸入具有唯一的映射)。

兩種計算都很有用。 兩者都是常見的。 知道您需要哪些,並知道如何使用API​​來計算您需要的任何內容。

只是為了補充霍華德的好答案,要明白你所指的“最佳實踐”是關於經過一段時間的增量。 實際上,如果你想增加24小時,你會在UTC中這樣做,你會發現你最終會在23:00結束,因為當天還有一個小時。

我通常會考慮添加一天作為日歷計算(使用霍華德的術語),因此無論當天有多少小時都沒關系 - 你在當地時間增加一天。

然后你必須驗證結果是那天的有效時間,因為很可能在前向轉換的“間隙”中找到了無效值。 你必須決定如何調整。 同樣,當您轉換為UTC時,您應該測試不明確的時間並相應地進行調整。

要知道,不這樣做你自己的任何調整,你依靠的默認行為TimeZoneInfo方法,在不明確的時間(盡管通常期望的行為是調整 ),它向后調整,並ConvertTimeFromUtc將拋出無效時間內的例外情況。

這就是為什么Noda Time中的ZonedDateTime具有“解析器”的概念,以允許您更具體地控制此行為。 您的代碼缺少任何類似的概念。

我還要補充說,雖然你說你已經看過Noda Time而且轉換成它的工作太多了 - 我鼓勵你再看一遍。 人們不一定需要改進他們的整個應用程序來使用它。 你可以,但你也可以在需要的地方介紹它。 例如,您可能希望在此DateTimeWithZone類中內部使用它,以強制您沿着正確的路徑前進。

還有一件事 - 當你在輸入中使用SpecifyKind時,你基本上就是要忽略輸入類型。 由於您正在設計用於重用的通用代碼,因此您可能會發現錯誤的可能性。 例如,我可能會傳入DateTime.UtcNow ,您將假設它是基於時區的時間。 Noda Time通過使用單獨的類型而不是“kind”來避免這個問題。 如果您要繼續使用DateTime ,那么您應該評估應用適當操作的類型。 只是忽略它肯定會讓你陷入困境。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM