1. 程式人生 > >計算兩個日期相差天數的最簡潔的代碼

計算兩個日期相差天數的最簡潔的代碼

string 不同 都是 card tps 飛機 ret con 使用數組

國際慣例,轉載註明出處。大飛機: https://user.qzone.qq.com/16491848/blog/1551429397?source=namecardword

 1 static void Main(string[] args)
 2 {
 3     Console.WriteLine(CountDays(2019, 3, 3) - CountDays(1949, 10, 1));
 4     Console.ReadKey();
 5 }
 6 
 7 static int CountDays(int y, int m, int d)
 8 {
 9     if
(m < 3) 10 { 11 y--; 12 m += 12; 13 } 14 return 365 * y + (y >> 2) - y / 100 + y / 400 + (153 * m - 457) / 5 + d - 306; 15 }
該算法先根據年月日求出該日期距離 0001年1月1日 的總天數,然後兩個天數直接相減,即可求出日期差。

而求總天數的代碼就是這個算法的核心,只有兩行。我現在詳細說說這個算法的原理:

計算日期差的算法,無論什麽算法(除了故意浪費時間的算法),時間復雜度都是 O(1),這個沒什麽好說的。關鍵在於優化計算步驟。

日期差計算有兩個難點:
1. 怎樣解決閏年的 2 月天數問題
2. 怎樣解決不同月份的天數不同問題(常規算法是使用數組記錄每個月的天數)

為了解決這兩個問題,該算法先把 1 月和 2 月當成上一年的 13 月和 14 月。然後,我們看一下每個月的天數:
月份:03-04-05-06-07;08-09-10-11-12;13-14
天數:31-30-31-30-31;31-30-31-30-31;31-30(28)
為了凸顯規律,我將 5 個月分成了一組。

可以看到,將 1、2 月挪動後,月份與天數的規律就出來了:

5 個月一組,1-0-1-0-1,重復(先減去 30,好看清楚)。

在這個規律的基礎上,為了後續計算的方便,先求出 m 月之前有多少天(以 3 月為第一個月),得到這樣的序列(先減去 30,好看清楚):

0-1-1-2-2,3-4-4-5-5,6-7
比如說第 6 個數字 3,對應的是 8 月,表示 8 月之前一共有 3 + 30 * 5 = 153 天。(30 * 5,表示加上 3~7 月每月 30 天)

於是,找到這樣的表達式(註意:C 語言整數相除的結果直接取整,並不做四舍五入):
(m * 3 - 7) / 5
可以得出前面提到的:
0-1-1-2-2,3-4-4-5-5,6-7
這樣的規律序列。

再把每月 30 天加進去,得出表達式:
(153 * m - 457) / 5
該表達式求出 m 月之前一共有多少天。

例:
m = 3 時,3 月是第一個月,所以表達式值為 0;
m = 4 時,表達式值為 31,就是 3 月的總天數;
m = 7 時,表達式值為 3 ~ 6 月的總天數。
因為把閏月挪到了最後一個月,所以 m = 14 時(就是表示 2 月),計算結果只是 3 ~ 13 月的總天數,並不會受閏月影響。

以上,就是算法最難理解的一部分。

其他代碼都簡單了,
+ (y >> 2) - y / 100 + y / 400
是直接加上期間有多少閏年。y>>2 是 y / 4 等效的位移運算寫法(效率更高)。

就是這麽簡單~

上面是轉載內容。這裏面有個難點,就是(m * 3 - 7) / 5這個公式是怎麽來的。

技術分享圖片

技術分享圖片

其實,只要意識到,每個區間的第一個數是等差數列,是可以直接快速算出這個特定公式的

技術分享圖片

計算兩個日期相差天數的最簡潔的代碼