/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 | 0 | int __secs_to_tm(long long t, struct mytm *tm) { |
15 | 0 | long long days, secs, years; |
16 | 0 | int remdays, remsecs, remyears; |
17 | 0 | int qc_cycles, c_cycles, q_cycles; |
18 | 0 | int months; |
19 | 0 | static const char days_in_month[] = {31,30,31,30,31,31,30,31,30,31,31,29}; |
20 | | |
21 | | /* Reject time_t values whose year would overflow int */ |
22 | 0 | if (t < INT_MIN * 31622400LL || t > INT_MAX * 31622400LL) |
23 | 0 | return -1; |
24 | | |
25 | 0 | secs = t - LEAPOCH; |
26 | 0 | days = secs / 86400LL; |
27 | 0 | remsecs = (int)(secs % 86400); |
28 | 0 | if (remsecs < 0) { |
29 | 0 | remsecs += 86400; |
30 | 0 | --days; |
31 | 0 | } |
32 | |
|
33 | 0 | qc_cycles = (int)(days / DAYS_PER_400Y); |
34 | 0 | remdays = (int)(days % DAYS_PER_400Y); |
35 | 0 | if (remdays < 0) { |
36 | 0 | remdays += DAYS_PER_400Y; |
37 | 0 | --qc_cycles; |
38 | 0 | } |
39 | |
|
40 | 0 | c_cycles = remdays / DAYS_PER_100Y; |
41 | 0 | if (c_cycles == 4) --c_cycles; |
42 | 0 | remdays -= c_cycles * DAYS_PER_100Y; |
43 | |
|
44 | 0 | q_cycles = remdays / DAYS_PER_4Y; |
45 | 0 | if (q_cycles == 25) --q_cycles; |
46 | 0 | remdays -= q_cycles * DAYS_PER_4Y; |
47 | |
|
48 | 0 | remyears = remdays / 365; |
49 | 0 | if (remyears == 4) --remyears; |
50 | 0 | remdays -= remyears * 365; |
51 | |
|
52 | 0 | years = remyears + 4*q_cycles + 100*c_cycles + 400LL*qc_cycles; |
53 | |
|
54 | 0 | for (months=0; days_in_month[months] <= remdays; ++months) |
55 | 0 | remdays -= days_in_month[months]; |
56 | |
|
57 | 0 | if (years+100 > INT_MAX || years+100 < INT_MIN) |
58 | 0 | return -1; |
59 | | |
60 | 0 | tm->tm_year = (int)(years + 100); |
61 | 0 | tm->tm_mon = months + 2; |
62 | 0 | if (tm->tm_mon >= 12) { |
63 | 0 | tm->tm_mon -=12; |
64 | 0 | ++tm->tm_year; |
65 | 0 | } |
66 | 0 | tm->tm_mday = remdays + 1; |
67 | 0 | tm->tm_hour = remsecs / 3600; |
68 | 0 | tm->tm_min = remsecs / 60 % 60; |
69 | 0 | tm->tm_sec = remsecs % 60; |
70 | |
|
71 | 0 | return 0; |
72 | 0 | } |
73 | | |
74 | | static const int secs_through_month[] = |
75 | | {0, 31*86400, 59*86400, 90*86400, |
76 | | 120*86400, 151*86400, 181*86400, 212*86400, |
77 | | 243*86400, 273*86400, 304*86400, 334*86400 }; |
78 | | |
79 | | static int |
80 | 0 | __month_to_secs(int month, int is_leap) { |
81 | 0 | int t = secs_through_month[month]; |
82 | 0 | if (is_leap && month >= 2) |
83 | 0 | t+=86400; |
84 | 0 | return t; |
85 | 0 | } |
86 | | |
87 | | static long long |
88 | 0 | __year_to_secs(const long long year, int *is_leap) { |
89 | 0 | int cycles, centuries, leaps, rem; |
90 | 0 | int is_leap_val = 0; |
91 | 0 | if (!is_leap) { |
92 | 0 | is_leap = &is_leap_val; |
93 | 0 | } |
94 | 0 | cycles = (int)((year-100) / 400); |
95 | 0 | rem = (int)((year-100) % 400); |
96 | 0 | if (rem < 0) { |
97 | 0 | cycles--; |
98 | 0 | rem += 400; |
99 | 0 | } |
100 | 0 | if (!rem) { |
101 | 0 | *is_leap = 1; |
102 | 0 | centuries = 0; |
103 | 0 | leaps = 0; |
104 | 0 | } else { |
105 | 0 | if (rem >= 200) { |
106 | 0 | if (rem >= 300) centuries = 3, rem -= 300; |
107 | 0 | else centuries = 2, rem -= 200; |
108 | 0 | } else { |
109 | 0 | if (rem >= 100) centuries = 1, rem -= 100; |
110 | 0 | else centuries = 0; |
111 | 0 | } |
112 | 0 | if (!rem) { |
113 | 0 | *is_leap = 0; |
114 | 0 | leaps = 0; |
115 | 0 | } else { |
116 | 0 | leaps = (rem / (int)4U); |
117 | 0 | rem %= (int)4U; |
118 | 0 | *is_leap = !rem; |
119 | 0 | } |
120 | 0 | } |
121 | |
|
122 | 0 | leaps += 97*cycles + 24*centuries - *is_leap; |
123 | |
|
124 | 0 | return (year-100) * 31536000LL + leaps * 86400LL + 946684800 + 86400; |
125 | 0 | } |
126 | | |
127 | 0 | long long __tm_to_secs(const struct mytm *tm) { |
128 | 0 | int is_leap; |
129 | 0 | long long year = tm->tm_year; |
130 | 0 | int month = tm->tm_mon; |
131 | 0 | if (month >= 12 || month < 0) { |
132 | 0 | int adj = month / 12; |
133 | 0 | month %= 12; |
134 | 0 | if (month < 0) { |
135 | 0 | adj--; |
136 | 0 | month += 12; |
137 | 0 | } |
138 | 0 | year += adj; |
139 | 0 | } |
140 | 0 | long long t = __year_to_secs(year, &is_leap); |
141 | 0 | t += __month_to_secs(month, is_leap); |
142 | 0 | t += 86400LL * (tm->tm_mday-1); |
143 | 0 | t += 3600LL * tm->tm_hour; |
144 | 0 | t += 60LL * tm->tm_min; |
145 | 0 | t += tm->tm_sec; |
146 | 0 | return t; |
147 | 0 | } |