/src/open62541/deps/libc_time.c
Line | Count | Source |
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 | 10.9k | #define LEAPOCH (946684800LL + 86400*(31+29)) |
9 | | |
10 | 28.7k | #define DAYS_PER_400Y (365*400 + 97) |
11 | 21.9k | #define DAYS_PER_100Y (365*100 + 24) |
12 | 21.9k | #define DAYS_PER_4Y (365*4 + 1) |
13 | | |
14 | | int |
15 | 10.9k | musl_secs_to_tm(long long t, struct musl_tm *tm) { |
16 | 10.9k | long long days, secs, years; |
17 | 10.9k | int remdays, remsecs, remyears; |
18 | 10.9k | int qc_cycles, c_cycles, q_cycles; |
19 | 10.9k | int months; |
20 | 10.9k | int wday, yday, leap; |
21 | 10.9k | 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 | 10.9k | if (t < INT_MIN * 31622400LL || t > INT_MAX * 31622400LL) |
25 | 0 | return -1; |
26 | | |
27 | 10.9k | secs = t - LEAPOCH; |
28 | 10.9k | days = secs / 86400LL; |
29 | 10.9k | remsecs = (int)(secs % 86400); |
30 | 10.9k | if (remsecs < 0) { |
31 | 3.68k | remsecs += 86400; |
32 | 3.68k | --days; |
33 | 3.68k | } |
34 | | |
35 | 10.9k | wday = (int)((3+days)%7); |
36 | 10.9k | if (wday < 0) wday += 7; |
37 | | |
38 | 10.9k | qc_cycles = (int)(days / DAYS_PER_400Y); |
39 | 10.9k | remdays = (int)(days % DAYS_PER_400Y); |
40 | 10.9k | if (remdays < 0) { |
41 | 6.75k | remdays += DAYS_PER_400Y; |
42 | 6.75k | --qc_cycles; |
43 | 6.75k | } |
44 | | |
45 | 10.9k | c_cycles = remdays / DAYS_PER_100Y; |
46 | 10.9k | if (c_cycles == 4) --c_cycles; |
47 | 10.9k | remdays -= c_cycles * DAYS_PER_100Y; |
48 | | |
49 | 10.9k | q_cycles = remdays / DAYS_PER_4Y; |
50 | 10.9k | if (q_cycles == 25) --q_cycles; |
51 | 10.9k | remdays -= q_cycles * DAYS_PER_4Y; |
52 | | |
53 | 10.9k | remyears = remdays / 365; |
54 | 10.9k | if (remyears == 4) --remyears; |
55 | 10.9k | remdays -= remyears * 365; |
56 | | |
57 | 10.9k | leap = !remyears && (q_cycles || !c_cycles); |
58 | 10.9k | yday = remdays + 31 + 28 + leap; |
59 | 10.9k | if (yday >= 365+leap) yday -= 365+leap; |
60 | | |
61 | 10.9k | years = remyears + 4*q_cycles + 100*c_cycles + 400LL*qc_cycles; |
62 | | |
63 | 107k | for (months=0; days_in_month[months] <= remdays; months++) |
64 | 96.9k | remdays -= days_in_month[months]; |
65 | | |
66 | 10.9k | if (months >= 10) { |
67 | 7.57k | months -= 12; |
68 | 7.57k | years++; |
69 | 7.57k | } |
70 | | |
71 | 10.9k | if (years+100 > INT_MAX || years+100 < INT_MIN) |
72 | 0 | return -1; |
73 | | |
74 | 10.9k | tm->tm_year = (int)(years + 100); |
75 | 10.9k | tm->tm_mon = months + 2; |
76 | 10.9k | tm->tm_mday = remdays + 1; |
77 | 10.9k | tm->tm_wday = wday; |
78 | 10.9k | tm->tm_yday = yday; |
79 | | |
80 | 10.9k | tm->tm_hour = remsecs / 3600; |
81 | 10.9k | tm->tm_min = remsecs / 60 % 60; |
82 | 10.9k | tm->tm_sec = remsecs % 60; |
83 | | |
84 | 10.9k | return 0; |
85 | 10.9k | } |
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 | 11.9k | musl_month_to_secs(int month, int is_leap) { |
94 | 11.9k | int t = secs_through_month[month]; |
95 | 11.9k | if (is_leap && month >= 2) |
96 | 2.74k | t+=86400; |
97 | 11.9k | return t; |
98 | 11.9k | } |
99 | | |
100 | | static long long |
101 | 11.9k | musl_year_to_secs(const long long year, int *is_leap) { |
102 | 11.9k | if (year-2ULL <= 136) { |
103 | 417 | int y = (int)year; |
104 | 417 | int leaps = (y-68)>>2; |
105 | 417 | if (!((y-68)&3)) { |
106 | 247 | leaps--; |
107 | 247 | if (is_leap) *is_leap = 1; |
108 | 247 | } else if (is_leap) *is_leap = 0; |
109 | 417 | return 31536000*(y-70) + 86400*leaps; |
110 | 417 | } |
111 | | |
112 | 11.5k | int cycles, centuries, leaps, rem, dummy; |
113 | | |
114 | 11.5k | if (!is_leap) is_leap = &dummy; |
115 | 11.5k | cycles = (int)((year-100) / 400); |
116 | 11.5k | rem = (int)((year-100) % 400); |
117 | 11.5k | if (rem < 0) { |
118 | 6.07k | cycles--; |
119 | 6.07k | rem += 400; |
120 | 6.07k | } |
121 | 11.5k | if (!rem) { |
122 | 1.76k | *is_leap = 1; |
123 | 1.76k | centuries = 0; |
124 | 1.76k | leaps = 0; |
125 | 9.75k | } else { |
126 | 9.75k | if (rem >= 200) { |
127 | 1.60k | if (rem >= 300) centuries = 3, rem -= 300; |
128 | 637 | else centuries = 2, rem -= 200; |
129 | 8.14k | } else { |
130 | 8.14k | if (rem >= 100) centuries = 1, rem -= 100; |
131 | 7.00k | else centuries = 0; |
132 | 8.14k | } |
133 | 9.75k | if (!rem) { |
134 | 325 | *is_leap = 0; |
135 | 325 | leaps = 0; |
136 | 9.42k | } else { |
137 | 9.42k | leaps = rem / 4; |
138 | 9.42k | rem %= 4; |
139 | 9.42k | *is_leap = !rem; |
140 | 9.42k | } |
141 | 9.75k | } |
142 | | |
143 | 11.5k | leaps += 97*cycles + 24*centuries - *is_leap; |
144 | | |
145 | 11.5k | return (year-100) * 31536000LL + leaps * 86400LL + 946684800 + 86400; |
146 | 11.9k | } |
147 | | |
148 | | long long |
149 | 11.9k | musl_tm_to_secs(const struct musl_tm *tm) { |
150 | 11.9k | int is_leap; |
151 | 11.9k | long long year = tm->tm_year; |
152 | 11.9k | int month = tm->tm_mon; |
153 | 11.9k | if (month >= 12 || month < 0) { |
154 | 4.59k | int adj = month / 12; |
155 | 4.59k | month %= 12; |
156 | 4.59k | if (month < 0) { |
157 | 1.22k | adj--; |
158 | 1.22k | month += 12; |
159 | 1.22k | } |
160 | 4.59k | year += adj; |
161 | 4.59k | } |
162 | 11.9k | long long t = musl_year_to_secs(year, &is_leap); |
163 | 11.9k | t += musl_month_to_secs(month, is_leap); |
164 | 11.9k | t += 86400LL * (tm->tm_mday-1); |
165 | 11.9k | t += 3600LL * tm->tm_hour; |
166 | 11.9k | t += 60LL * tm->tm_min; |
167 | 11.9k | t += tm->tm_sec; |
168 | 11.9k | return t; |
169 | 11.9k | } |