linux 内核中 mktime函数

本文深入解析了Linux内核中mktime()函数的原理,详细阐述了计算当前时间距离1970-01-01的秒数的数学表达式,包括对月份天数的计算方法,以及不同月份情况下天数的特殊调整。通过公式推导,清晰展示了函数内部逻辑与计算过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Linux内核中的mktime()函数.     

计算当前时间(>=1970-01-01 00:00:00) 距离1970-01-01 00:00:00的秒数

具体定义如下:

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 */  
}  

函数实现的表达式看出,实现mktime 最关键的是找出计算每月天数的方法。

当前时间距离0001-01-01 的天数:  

1. 当前时间的月份mon>2,     D(mon > 2)  = year/4-year/100+year/400 + (year-1) *365 + month_to_days(mon) + day-1                     

2. 当前时间的月份mon <=2,  D(mon <= 2)  = (year-1)/4- (year-1)/100+ (year-1)/400 + (year-1)*365+ month_to_days(mon) + day-1

现在问题在于如何求出month_to_days(mon)表达式. 

假定2月份是30天,  mon 与  month_to_days(mon) 关系如下:

mon      days       month_to_days(mon)          数列标记{Dm}

1           31           0                                        D1  =  0

2           30          31                                        D2  =  31

3           31          61                                        D3  =  61

4           30          92                                        D4  =  92

5           31          122                                      D5  = 122

6           30          153                                      D6  = 153

7           31          183                                      D7  = 183

8           31          214                                      D8  = 214

9           30          245                                      D9  = 245

10         31           275                                     D10 = 275

11         30          306                                      D11 = 306

12         31          336                                      D12  = 336

讨论: m <= 7 情况

D2 - D1 = 31  

D3 - D2 = 30  

D4 - D3 = 31  

D5 - D4 = 30

D6 - D5 = 31

D7 - D6 = 30

D8 - D7 = 31

上式相加,  可以得出:  D2m+1 - D1 = 31*m+30*m = 61*m;   D2m - D1 = 31*m+30*(m-1)  = 61*m-30

由于D1 = 0.    D2m+1 = 61*m   ==> Dm =  61*(m-1)/2= (61*m-1)/2 - 30,      m为<=7的奇数

                       D2m  = 61*m-30  ==> Dm = 61*m/2  -  30                          ,     m为<=7的偶数

讨论: m >7 情况

D9  -  D8  = 31

D10 - D9  = 30

D11 - D10 = 31

D12 - D11 = 30

上式相加,  可以得出:  D2m+1 - D8 = 31*(m-3)+30*(m-4) = 61*m-213;   D2m - D8 = 31*(m-4)+30*(m-4)  = 61*m-244

由于D8 = 214, D2m+1 = 61*m + 1 ==>Dm = 61*(m-1)/2 + 1  = (61*m+1)/2 - 30,  m为>7奇数

                          D2m = 61*m - 30     ==> Dm = 61*m/2 - 30                                    , m 为>7偶数

综上所述:    Dm = 61*m/2 - 30,          m为偶数

                   Dm =  (61*m-1)/2 - 30,   m为<=7 奇数

                   Dm =   (61*m+1)/2 - 30,  m为>7 奇数

上述是在假定2月份为30天得出的结论, 如果考虑m>2月份的情况, 此时月份与天的数关系为:

                         Dm = 61*m/2 - 30 - 61 + 31 + 28  = 61*(m-2)/2 + 29,            m为3 <= m <= 12的偶数   (1)

                         Dm =  (61*m-1)/2 - 30 - 61 +31 + 28 = (61*(m-2)-1)/2 + 29,   m为3 <= m <= 7 奇数       (2)

                         Dm = (61*m+1)/2 - 30 - 61 + 31 + 28 = (61*(m-2)+1)/2 + 29,  m为8 <= m <= 12 奇数     (3)

(3)式:8 <= m <= 12     ==>    6 <= m-2 <= 10     

                                       ==>    1 <= (m-2)/6 <= 10/6  

                                       ==>     61*(m-2)+1 <= 61*(m-2)+ (m-2)/6 <= 61*(m-2) + 10/6

                                       ==>    (61*(m-2)+1)/2 <= (61*(m-2)+ (m-2)/6)/2 <= (61*(m-2) + 10/6)/2 =  (61*(m-2) + 1)/2 + 1/3

                                        由于 m为奇数,   所以 (61*(m-2) + 1)/2 为整数,  按计算机取整  (61*(m-2) + 1)/2 =  (61*(m-2) + 1)/2 + 1/3

                                        即       (61*(m-2)+1)/2 = (61*(m-2)+ (m-2)/6)/2  = 367*(m-2)/12

                                        Dm = 367*(m-2)/12 + 29

(2)式:  3<= m <= 7         ==>                 1 <= m-2 <= 5

                                        ==>   -1 <   1/6  <=  (m-2)/6 <= 5/6  < 1

                                        ==>  61*(m-2)-1  <  61*(m-2) + (m-2)/6  <  61*(m-2) +1

                                        ==>  (61*(m-2)-1)/2  <  (61*(m-2) + (m-2)/6)/2  <  (61*(m-2) +1)/2

                                        由于 m为奇数, 所以 (61*(m-2)-1)/2  和  (61*(m-2) +1)/2 都为整数

                                        而 (61*(m-2) +1)/2  -(61*(m-2)-1)/2 = 1

                                        所以按计算机取整  (61*(m-2)-1)/2 = (61*(m-2) + (m-2)/6)/2 = 367*(m-2)/12

                                       Dm = 367*(m-2)/12 + 29

(1)式:  3 <= m <= 12    ==>  1 <= m-2 <= 10

                                      ==>  0 < 1/12 <= (m-2)/12 <= 10/12  < 1

                                      ==>    61*(m-2)/2 < 61*(m-2)/2 + (m-2)/12 < 61*(m-2)/2 + 1

                                      由m 为偶数, 所以 61*(m-2)/2 和 61*(m-2)/2 + 1 都为整数

                                      而 61*(m-2)/2+1  -  61*(m-2)/2 = 1

                                      所以按计算机取整 61*(m-2)/2 = 61*(m-2)/2 + (m-2)/12 = 367*(m-2)/12

                                     Dm = 367*(m-2)/12 + 29

综上可以得出结论: m > 2 时,  Dm = 367*(m-2)/12 + 29,  即 month_to_days(m) = 367*(m-2)/12 + 29

                              m = 1 时,  Dm = 0, 即  month_to_days(1) = 0       =   367*(13-2)/12 + 29 - 365 = month_to_days(13) -365

                              m = 2时, Dm = 31, 即  month_to_days(2) = 31   =  367*(14-2)/12 + 29 - 365 =  month_to_days(14) -365

                              即 m <= 2 时  month_to_days(m) = month_to_days(m+12) - 365

回到主问题: 

当前时间距离0001-01-01 的天数:  

1. 当前时间的月份mon>2,     D(mon > 2)  = year/4-year/100+year/400 + (year-1) *365 + month_to_days(mon) + day-1                     

2. 当前时间的月份mon <=2,  D(mon <= 2)  = (year-1)/4- (year-1)/100+ (year-1)/400 + (year-1)*365+ month_to_days(mon) + day-1

D(mon > 2)  = year/4-year/100+year/400 + (year-1) *365 + month_to_days(mon) + day-1

                     = year/4-year/100+year/400 + (year-1) *365 + 367*(mon-2)/12 + 29+ day-1

                     = year/4-year/100+year/400 + year*365 + 367*(mon-2)/12 + day - 337

D(mon <= 2)  = (year-1)/4- (year-1)/100+ (year-1)/400 + (year-1)*365+ month_to_days(mon) + day-1

                       = (year-1)/4- (year-1)/100+ (year-1)/400 + (year-1)*365 + month_to_days(mon+12) - 365 + day-1

                       = (year-1)/4- (year-1)/100+ (year-1)/400 + (year-1)*365 + 367*(mon+12-2)/12 + 29 - 365 + day-1

                       =  (year-1)/4- (year-1)/100+ (year-1)/400 + (year-1)*365 + 367*(mon-2+12)/12 + day-337

D(1970-01-01 00:00:00) =  1969/4 - 1969/100 + 1969/400 + 1969*365 + 367*11/12 + 1 - 337 =  719162


D(mon > 2) - D(1970-01-01 00:00:00)  = (year/4-year/100+year/400 + 367*(mon-2)/12 + day) + year*365- 719499

D(mon <= 2) D(1970-01-01 00:00:00)  = ((year-1)/4- (year-1)/100+ (year-1)/400 + 367*(mon-2+12)/12 + day) + (year-1)*365 -719499

即为linux mktime 函数实现计算距离1970-01-01 00:00:00 天数的表达式



                     
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值