/src/open62541/deps/libc_time.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Originally released by the musl project (http://www.musl-libc.org/) under the |
2 | | * MIT license. Taken from the file /src/time/__secs_to_tm.c */ |
3 | | |
4 | | #include <limits.h> |
5 | | #include "libc_time.h" |
6 | | |
7 | | /* 2000-03-01 (mod 400 year, immediately after feb29 */ |
8 | 0 | #define LEAPOCH (946684800LL + 86400*(31+29)) |
9 | | |
10 | 0 | #define DAYS_PER_400Y (365*400 + 97) |
11 | 0 | #define DAYS_PER_100Y (365*100 + 24) |
12 | 0 | #define DAYS_PER_4Y (365*4 + 1) |
13 | | |
14 | | int |
15 | 0 | musl_secs_to_tm(long long t, struct musl_tm *tm) { |
16 | 0 | long long days, secs, years; |
17 | 0 | int remdays, remsecs, remyears; |
18 | 0 | int qc_cycles, c_cycles, q_cycles; |
19 | 0 | int months; |
20 | 0 | int wday, yday, leap; |
21 | 0 | static const char days_in_month[] = {31,30,31,30,31,31,30,31,30,31,31,29}; |
22 | | |
23 | | /* Reject time_t values whose year would overflow int */ |
24 | 0 | if (t < INT_MIN * 31622400LL || t > INT_MAX * 31622400LL) |
25 | 0 | return -1; |
26 | | |
27 | 0 | secs = t - LEAPOCH; |
28 | 0 | days = secs / 86400LL; |
29 | 0 | remsecs = (int)(secs % 86400); |
30 | 0 | if (remsecs < 0) { |
31 | 0 | remsecs += 86400; |
32 | 0 | --days; |
33 | 0 | } |
34 | |
|
35 | 0 | wday = (3+days)%7; |
36 | 0 | if (wday < 0) wday += 7; |
37 | |
|
38 | 0 | qc_cycles = (int)(days / DAYS_PER_400Y); |
39 | 0 | remdays = (int)(days % DAYS_PER_400Y); |
40 | 0 | if (remdays < 0) { |
41 | 0 | remdays += DAYS_PER_400Y; |
42 | 0 | --qc_cycles; |
43 | 0 | } |
44 | |
|
45 | 0 | c_cycles = remdays / DAYS_PER_100Y; |
46 | 0 | if (c_cycles == 4) --c_cycles; |
47 | 0 | remdays -= c_cycles * DAYS_PER_100Y; |
48 | |
|
49 | 0 | q_cycles = remdays / DAYS_PER_4Y; |
50 | 0 | if (q_cycles == 25) --q_cycles; |
51 | 0 | remdays -= q_cycles * DAYS_PER_4Y; |
52 | |
|
53 | 0 | remyears = remdays / 365; |
54 | 0 | if (remyears == 4) --remyears; |
55 | 0 | remdays -= remyears * 365; |
56 | |
|
57 | 0 | leap = !remyears && (q_cycles || !c_cycles); |
58 | 0 | yday = remdays + 31 + 28 + leap; |
59 | 0 | if (yday >= 365+leap) yday -= 365+leap; |
60 | |
|
61 | 0 | years = remyears + 4*q_cycles + 100*c_cycles + 400LL*qc_cycles; |
62 | |
|
63 | 0 | for (months=0; days_in_month[months] <= remdays; months++) |
64 | 0 | remdays -= days_in_month[months]; |
65 | |
|
66 | 0 | if (months >= 10) { |
67 | 0 | months -= 12; |
68 | 0 | years++; |
69 | 0 | } |
70 | |
|
71 | 0 | if (years+100 > INT_MAX || years+100 < INT_MIN) |
72 | 0 | return -1; |
73 | | |
74 | 0 | tm->tm_year = (int)(years + 100); |
75 | 0 | tm->tm_mon = months + 2; |
76 | 0 | tm->tm_mday = remdays + 1; |
77 | 0 | tm->tm_wday = wday; |
78 | 0 | tm->tm_yday = yday; |
79 | |
|
80 | 0 | tm->tm_hour = remsecs / 3600; |
81 | 0 | tm->tm_min = remsecs / 60 % 60; |
82 | 0 | tm->tm_sec = remsecs % 60; |
83 | |
|
84 | 0 | return 0; |
85 | 0 | } |
86 | | |
87 | | static const int secs_through_month[] = |
88 | | {0, 31*86400, 59*86400, 90*86400, |
89 | | 120*86400, 151*86400, 181*86400, 212*86400, |
90 | | 243*86400, 273*86400, 304*86400, 334*86400 }; |
91 | | |
92 | | static int |
93 | 0 | musl_month_to_secs(int month, int is_leap) { |
94 | 0 | int t = secs_through_month[month]; |
95 | 0 | if (is_leap && month >= 2) |
96 | 0 | t+=86400; |
97 | 0 | return t; |
98 | 0 | } |
99 | | |
100 | | static long long |
101 | 0 | musl_year_to_secs(const long long year, int *is_leap) { |
102 | 0 | if (year-2ULL <= 136) { |
103 | 0 | int y = (int)year; |
104 | 0 | int leaps = (y-68)>>2; |
105 | 0 | if (!((y-68)&3)) { |
106 | 0 | leaps--; |
107 | 0 | if (is_leap) *is_leap = 1; |
108 | 0 | } else if (is_leap) *is_leap = 0; |
109 | 0 | return 31536000*(y-70) + 86400*leaps; |
110 | 0 | } |
111 | | |
112 | 0 | int cycles, centuries, leaps, rem, dummy; |
113 | |
|
114 | 0 | if (!is_leap) is_leap = &dummy; |
115 | 0 | cycles = (int)((year-100) / 400); |
116 | 0 | rem = (year-100) % 400; |
117 | 0 | if (rem < 0) { |
118 | 0 | cycles--; |
119 | 0 | rem += 400; |
120 | 0 | } |
121 | 0 | if (!rem) { |
122 | 0 | *is_leap = 1; |
123 | 0 | centuries = 0; |
124 | 0 | leaps = 0; |
125 | 0 | } else { |
126 | 0 | if (rem >= 200) { |
127 | 0 | if (rem >= 300) centuries = 3, rem -= 300; |
128 | 0 | else centuries = 2, rem -= 200; |
129 | 0 | } else { |
130 | 0 | if (rem >= 100) centuries = 1, rem -= 100; |
131 | 0 | else centuries = 0; |
132 | 0 | } |
133 | 0 | if (!rem) { |
134 | 0 | *is_leap = 0; |
135 | 0 | leaps = 0; |
136 | 0 | } else { |
137 | 0 | leaps = rem / 4; |
138 | 0 | rem %= 4; |
139 | 0 | *is_leap = !rem; |
140 | 0 | } |
141 | 0 | } |
142 | |
|
143 | 0 | leaps += 97*cycles + 24*centuries - *is_leap; |
144 | |
|
145 | 0 | return (year-100) * 31536000LL + leaps * 86400LL + 946684800 + 86400; |
146 | 0 | } |
147 | | |
148 | | long long |
149 | 0 | musl_tm_to_secs(const struct musl_tm *tm) { |
150 | 0 | int is_leap; |
151 | 0 | long long year = tm->tm_year; |
152 | 0 | int month = tm->tm_mon; |
153 | 0 | if (month >= 12 || month < 0) { |
154 | 0 | int adj = month / 12; |
155 | 0 | month %= 12; |
156 | 0 | if (month < 0) { |
157 | 0 | adj--; |
158 | 0 | month += 12; |
159 | 0 | } |
160 | 0 | year += adj; |
161 | 0 | } |
162 | 0 | long long t = musl_year_to_secs(year, &is_leap); |
163 | 0 | t += musl_month_to_secs(month, is_leap); |
164 | 0 | t += 86400LL * (tm->tm_mday-1); |
165 | 0 | t += 3600LL * tm->tm_hour; |
166 | 0 | t += 60LL * tm->tm_min; |
167 | 0 | t += tm->tm_sec; |
168 | 0 | return t; |
169 | 0 | } |