mktime算法

/* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
 * Assumes input in normal date format, i.e. 1980-12-31 23:59:59
 * => year=1980, mon=12, day=31, hour=23, min=59, sec=59.
 *
 * [For the Julian calendar (which was used in Russia before 1917,
 * Britain & colonies before 1752, anywhere else before 1582,
 * and is still in use by some communities) leave out the
 * -year/100+year/400 terms, and add 10.]
 *
 * This algorithm was first published by Gauss (I think).
 *
 * WARNING: this function will overflow on 2106-02-07 06:28:16 on
 * machines where long is 32-bit! (However, as time_t is signed, we
 * will already get problems at other places on 2038-01-19 03:14:08)
 */
unsigned long
mktime(const unsigned int year0, const unsigned int mon0,
        const unsigned int day, const unsigned int hour,
        const unsigned int min, const unsigned int sec)
 {
         unsigned int mon = mon0, year = year0;
         /* 1..12 -> 11,12,1..10 */
         if (0 >= (int) (mon -= 2)) {
                 mon += 12;      /* Puts Feb last since it has leap day */
                 year -= 1;
         }
 
         return ((((unsigned long)
                   (year/4 - year/100 + year/400 + 367*mon/12 + day) +
                   year*365 - 719499
             )*24 + hour /* now have hours */
           )*60 + min /* now have minutes */
         )*60 + sec; /* finally seconds */
}

咱們能夠看出核心算式this

   Timestamp = (((Days * 24) + hour) * 60) + min) * 60 + secspa

   LeapDays = year/4 - year/100 + year/400 code

  Days = year * 365 +  367* mon/12 + day - 719499 + LeapDaysorm


其中LeapDays是用來計算到當前年份一共有多少個閏年,閏年規則是能被4整除,不能被100整除,世紀年能被400整除。get

爲了方便計算,咱們將年份調整爲從3月開始2月結束,這樣作,咱們能夠將2月這個特殊月份,放到每一年的最後一個月中。咱們按照大小月規則,忽略2月份的特殊性,一年有367天。在給定的月和日下面,咱們能夠獲得367 * mon / 12 ,就是指定的月在咱們設定的規則下當年通過了多少天。input

咱們經過下面的代碼來證實這個結論it

#include<stdio.h>
#include<stdlib.h>
int main(){
	 int i;
	 unsigned long j = 0;
	 unsigned long n = 0;
	 unsigned long m = 0;
	 for(i = 1;i<=12;i++){
		  j = (unsigned long)( 367 * i / 12);
		  m = j - n;
		  n = j;
		  printf("月份:%d,從上月到達本月初經歷了:%lu天\r\n",i+2,m);
	 }
	 return 0;
}

能夠得出下面的結果:io

月份:3,從上月到達本月初經歷了:30天
月份:4,從上月到達本月初經歷了:31天
月份:5,從上月到達本月初經歷了:30天
月份:6,從上月到達本月初經歷了:31天
月份:7,從上月到達本月初經歷了:30天
月份:8,從上月到達本月初經歷了:31天
月份:9,從上月到達本月初經歷了:31天
月份:10,從上月到達本月初經歷了:30天
月份:11,從上月到達本月初經歷了:31天
月份:12,從上月到達本月初經歷了:30天
月份:13,從上月到達本月初經歷了:31天 //次年1月
月份:14,從上月到達本月初經歷了:31天 //次年2月

當咱們指定月份的時候,咱們須要考慮的特殊月份只有3月份,因此咱們獲得了367*mon/12 - 30。同時當天也沒有過完,就須要367*mon/12 + day -30 -1。ast

咱們按照全部年份都是正常年份來算的話,每一年有365天,那麼當前年份沒有過完,咱們就能夠知道到當前年份有 (year - 1) * 365。那麼咱們能夠獲得這麼一個公式 (year -1) * 365 + 367 * mon/12 - 31 + day。function

也就是至關於,咱們忽略閏年影響,咱們應當獲得的天數總數爲

(year -1 ) * 365 + 367 * mon/12 - 31 + 59  + day = year * 365 + 367 * mon/12  + day - 337

其中的59是由如下規則得出的,公元1年1月1日,到公元1年3月1日,一共有31 + 28 = 59天的差距。

從公元1年1月1日到1970年1月1日,一共通過了719162,因此咱們能夠獲得 year * 365 + 367 * mon/12 + day -337 - 719162 = year * 365 + 367 * mon/12 + day- 719499。


這裏面將3月份做爲當年第一個月將2月份做爲當年最後一個月,這個方式很是巧妙,簡化了對特殊月份的處理。

相關文章
相關標籤/搜索