iOS NSDate計算之夏令時

夏時令(Daylight Saving Time:DST),又稱“日光節(jié)約時制”和“夏令時間”,是一種為節(jié)約能源而人為規(guī)定地方時間的制度,在這一制度實行期間所采用的統(tǒng)一時間稱為“夏令時間”。一般在天亮早的夏季人為將時間調(diào)快一小時,可以使人早起早睡,減少照明量,以充分利用光照資源,從而節(jié)約照明用電。各個采納夏時制的國家具體規(guī)定不同。目前全世界有近110個國家每年要實行夏令時。

公司有個郵件項目,其中Exchange日歷需要大量的日期時間的計算。前兩天客戶反饋一個問題:循環(huán)日歷修改單日后,生成的exception日期未生效,也就是說修改后的會議時間沒有改動。正常來說這是個主流程功能,不太可能出現(xiàn)這樣的問題,我們本地各種日志分析和造日歷會議想要復(fù)現(xiàn)這個問題,徒勞無功。后來在查另一個完全不相干的問題時,查到了用戶時區(qū)被改動導(dǎo)致日期錯誤問題,靈感乍現(xiàn),連忙去試試之前用戶反饋的日歷周期在不同時區(qū)上的日歷表現(xiàn)。果然,這次看到了不同。

先看我在控制臺輸出的兩個日期:

//美國時區(qū)
(lldb) po excStartTime
2022-02-18 07:15:00 +0000

(lldb) po self.startTime
2021-10-29 06:15:00 +0000

(lldb) po [excStartTime beginningOfDay]
2022-02-18 05:00:00 +0000

(lldb) po [self.startTime beginningOfDay]
2021-10-29 04:00:00 +0000

//中國時區(qū)
(lldb) po excStartTime
2022-02-18 07:15:00 +0000

(lldb) po self.startTime
2021-10-29 06:15:00 +0000

(lldb) po [excStartTime beginningOfDay]
2022-02-17 16:00:00 +0000

(lldb) po [self.startTime beginningOfDay]
2021-10-28 16:00:00 +0000

//獲取一天的開始時間
- (NSDate *)beginningOfDay {
    NSCalendar *calendar = [NSCalendar currentCalendar];
    // Get the weekday component of the current date
    NSDateComponents *components = [calendar components:(NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay)
                                               fromDate:self];
    return [calendar dateFromComponents:components];
}
看到這個數(shù)據(jù)2022-02-18 05:00:00 +0000 2021-10-29 04:00:00 +0000我們實在無法理解,同時區(qū)條件下,兩個日期的一天開始時間竟然不同?而且中國可以,美國不行?這不可能吧!時區(qū)固定了,開始時間還能變?我一度以為計算錯了,換了各種方法和時區(qū),結(jié)果都是一樣的!內(nèi)心無比狂躁啊,只能搜索,為什么兩個日期計算出來會相差一個小時。驀然的,一個夏令時調(diào)整時間相差1小時的新聞出現(xiàn)在我的眼前,然后看剛才的日期2021-10-29,這正好是在夏令時期間,而我的時區(qū)是在美國,是一個實行夏令時的國家。一切得到了解釋,日歷計算日開始時間自動給我算上了夏令時,而我拿一個2021-10-29有夏令時的日開始時間,去參與計算一個2022-02-18無夏令時日期,自然不可能算對。

代碼驗證下

NSTimeInterval daylightSavingInterval = [[NSTimeZone systemTimeZone] daylightSavingTimeOffsetForDate:[calendar dateFromComponents:components]];

(lldb) po daylightSavingInterval
3600

果然是1小時。

知道了原因就好辦了。既然一天的時間開始變早了一小時,想要消除這個誤差,那么在夏令時期間補上即可,再拿補上1小時后的時間去參與后續(xù)計算即可??梢杂?code>daylightSavingTimeOffsetForDate方法獲取到夏令時差,這個方法會根據(jù)該時區(qū)國家是否有夏令時而變動,0或者3600,因此可以直接兼容無夏令時的情況。其他方法可參考NSTimeZone類的方法。
//獲取一天的開始時間,同時消除夏令時時差
- (NSDate *)benginningOfDayWithDayLinght {
    NSCalendar *calendar = [NSCalendar currentCalendar];
    // Get the weekday component of the current date
    NSDateComponents *components = [calendar components:(NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay)
                                               fromDate:self];
    //計算一天開始時間要補上美國等夏令時間差1小時 (美國夏令時結(jié)束日是2021-11-07)去掉時差在計算,否則每天的開始時間不一致會導(dǎo)致exception計算錯誤。
    //如果需要支持夏令時,通過isDaylightSavingTimeForDate或者daylightSavingTimeOffsetForDate判斷
    NSTimeInterval daylightSavingInterval = [[NSTimeZone systemTimeZone] daylightSavingTimeOffsetForDate:[calendar dateFromComponents:components]];
    NSTimeInterval sinceTime = [calendar dateFromComponents:components].timeIntervalSince1970;
    NSDate *resultDate = [NSDate dateWithTimeIntervalSince1970:sinceTime+daylightSavingInterval];
    return resultDate;
}
后言:夏令時,雖然達到了節(jié)約能源的目的,但隨著都市化夜生活的增多,作用越來越小了。而且還增加了人心理和生理負擔(dān)以及各種場合系統(tǒng)的計算負擔(dān)。功與過,實難論斷。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容