欲しいのは 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の投稿にもチラとみえておる通り「閏秒」は加味しておらぬのでよ。注意、になるのか、これ?)