12004:十亿秒后的时刻
题目
按照无时区公历规则,计算给定时刻十亿秒后的日期与时间。
解析
十亿秒可以先拆成整天和日内余数:
text
1000000000 = 11574 × 86400 + 64001
先把 6400 秒加入日内时刻,并把可能产生的一天进位并入待增加天数;再按照每月实际天数推进日期。这样不依赖 time_t 的表示,也不会引入本地时区和夏令时规则。
输出对象只在全部计算成功后更新。若日期非法,或跨年时会超过 int64_t 的表示范围,直接返回失败。
解析
c
#include <stdbool.h>
#include <stdint.h>
typedef struct {
int64_t year;
unsigned month;
unsigned day;
unsigned hour;
unsigned minute;
unsigned second;
} CivilTime;
static bool is_leap_year(int64_t year) {
return year % 4 == 0 &&
(year % 100 != 0 || year % 400 == 0);
}
static unsigned days_in_month(
int64_t year,
unsigned month
) {
static const unsigned days[] = {
31, 28, 31, 30, 31, 30,
31, 31, 30, 31, 30, 31
};
if (month == 2 && is_leap_year(year)) {
return 29;
}
return days[month - 1];
}
static bool civil_time_valid(CivilTime value) {
if (value.year < 1 ||
value.month < 1 ||
value.month > 12 ||
value.hour > 23 ||
value.minute > 59 ||
value.second > 59) {
return false;
}
return value.day >= 1 &&
value.day <= days_in_month(
value.year,
value.month
);
}
bool add_gigasecond(CivilTime start, CivilTime *out) {
if (out == NULL || !civil_time_valid(start)) {
return false;
}
const uint32_t seconds_per_day = UINT32_C(86400);
const uint32_t whole_days = UINT32_C(11574);
const uint32_t remaining_seconds = UINT32_C(6400);
CivilTime result = start;
uint32_t seconds_of_day =
(uint32_t)result.hour * UINT32_C(3600) +
(uint32_t)result.minute * UINT32_C(60) +
result.second +
remaining_seconds;
uint32_t days_to_add =
whole_days + seconds_of_day / seconds_per_day;
seconds_of_day %= seconds_per_day;
result.hour = (unsigned)(seconds_of_day / UINT32_C(3600));
seconds_of_day %= UINT32_C(3600);
result.minute = (unsigned)(seconds_of_day / UINT32_C(60));
result.second = (unsigned)(seconds_of_day % UINT32_C(60));
while (days_to_add > 0) {
unsigned month_days = days_in_month(
result.year,
result.month
);
unsigned remaining = month_days - result.day;
if (days_to_add <= remaining) {
result.day += (unsigned)days_to_add;
days_to_add = 0;
continue;
}
days_to_add -= remaining + 1;
result.day = 1;
if (result.month < 12) {
++result.month;
} else {
if (result.year == INT64_MAX) {
return false;
}
result.month = 1;
++result.year;
}
}
*out = result;
return true;
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
来源与改编
题型改编自 Exercism C Track 的 Gigasecond,采用 MIT 许可;本题改为无时区公历接口,并补充日期校验与年份溢出语义。