mktimeのGMT(UTC)版はなぜないのか

欲しいのは mkgmtime。が、標準に、ない。検索したらこんなんあった:





やだろ、これ。「閏年か毎年分調べる」んでなく、「閏年の数を数える」んでねーの? と、気持ち悪くてしょうがなくなり、

1 count leap years between dates

ってな検索を。

\(
\displaystyle \lfloor{\frac{y}{4}\rfloor} \;-\; \lfloor{\frac{y}{100}\rfloor} \;+\; \lfloor{\frac{y}{400}\rfloor}
\)


だな。そりゃそーだなこれ。で、基本、UNIX time_t のために、「1970年1月1日から去年までの閏年の数」と今年が閏年かどうか、だけわかれば、mkgmtime に近いものが書けるな。

 1 #include <numeric>
 2 #define CNT_LEAP(y) ((int)((y) / 4) - (int)((y) / 100) + (int)((y) / 400))
 3 time_t mkgmtime(
 4     short year, short mon, short day,
 5     short hour=0, short min=0, short sec=0)
 6 {
 7     static const int dom[] = {
 8         31, 28, 31, 30, 31, 30,
 9         31, 31, 30, 31, 30, 31,
10     };
11     int days = 365 * (year - 1970) + CNT_LEAP(year - 1) - CNT_LEAP(1970 - 1);
12     days += std::accumulate(&dom[0], &dom[mon - 1], 0);
13     days += day - 1;
14     if (mon > 2 && ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0)) {
15         ++days;
16     }
17     return days * 86400 + hour * 3600 + min * 60 + sec;
18 }

それはそうと、どうも遥か遠い記憶があるなぁと思ったらこれ、「datediff」な、本質は。epoch に無知でいられない点だけがスペシャルなだけで。


一応確認のために、mktime との差が正確に9時間になるかどうか:

 1 // ...
 2 
 3 #include <ctime>
 4 time_t from_mktime(
 5     short year, short mon, short day, short hour=0, short min=0, short sec=0)
 6 {
 7     std::tm smt = {0};
 8     smt.tm_year = year - 1900;
 9     smt.tm_mon = mon - 1;
10     smt.tm_mday = day;
11     smt.tm_hour = hour;
12     smt.tm_min = min;
13     smt.tm_sec = sec;
14     return std::mktime(&smt) + 9*3600;
15 }
16 
17 #include <iostream>
18 int main(void)
19 {
20     for (int y = 1970; y <= 2020; ++y) {
21         for (int m = 1; m <= 1; ++m) {
22             int d = 2;
23             std::cout
24                 << y << "." << m << "." << d
25                 << " "
26                 << mkgmtime(y, m, d) - from_mktime(y, m, d) << std::endl;
27             d = 28;
28             std::cout
29                 << y << "." << m << "." << d
30                 << " "
31                 << mkgmtime(y, m, d) - from_mktime(y, m, d) << std::endl;
32         }
33     }
34 }

よさげ。(注意:stackoverflowの投稿にもチラとみえておる通り「閏秒」は加味しておらぬのでよ。注意、になるのか、これ?)