diff options
Diffstat (limited to 'win32/timegm.c')
-rw-r--r-- | win32/timegm.c | 133 |
1 files changed, 133 insertions, 0 deletions
diff --git a/win32/timegm.c b/win32/timegm.c new file mode 100644 index 000000000..ac39a26f5 --- /dev/null +++ b/win32/timegm.c | |||
@@ -0,0 +1,133 @@ | |||
1 | /* | ||
2 | timegm from musl (https://www.musl-libc.org/). | ||
3 | |||
4 | MIT licensed: | ||
5 | |||
6 | ---------------------------------------------------------------------- | ||
7 | Copyright © 2005-2020 Rich Felker, et al. | ||
8 | |||
9 | Permission is hereby granted, free of charge, to any person obtaining | ||
10 | a copy of this software and associated documentation files (the | ||
11 | "Software"), to deal in the Software without restriction, including | ||
12 | without limitation the rights to use, copy, modify, merge, publish, | ||
13 | distribute, sublicense, and/or sell copies of the Software, and to | ||
14 | permit persons to whom the Software is furnished to do so, subject to | ||
15 | the following conditions: | ||
16 | |||
17 | The above copyright notice and this permission notice shall be | ||
18 | included in all copies or substantial portions of the Software. | ||
19 | |||
20 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
21 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
22 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | ||
23 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY | ||
24 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, | ||
25 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE | ||
26 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
27 | ---------------------------------------------------------------------- | ||
28 | */ | ||
29 | #include "libbb.h" | ||
30 | |||
31 | static long long __year_to_secs(long long year, int *is_leap) | ||
32 | { | ||
33 | int cycles, centuries, leaps, rem; | ||
34 | |||
35 | if (year-2ULL <= 136) { | ||
36 | int y = year; | ||
37 | leaps = (y-68)>>2; | ||
38 | if (!((y-68)&3)) { | ||
39 | leaps--; | ||
40 | if (is_leap) *is_leap = 1; | ||
41 | } else if (is_leap) *is_leap = 0; | ||
42 | return 31536000*(y-70) + 86400*leaps; | ||
43 | } | ||
44 | |||
45 | cycles = (year-100) / 400; | ||
46 | rem = (year-100) % 400; | ||
47 | if (rem < 0) { | ||
48 | cycles--; | ||
49 | rem += 400; | ||
50 | } | ||
51 | if (!rem) { | ||
52 | *is_leap = 1; | ||
53 | centuries = 0; | ||
54 | leaps = 0; | ||
55 | } else { | ||
56 | if (rem >= 200) { | ||
57 | if (rem >= 300) centuries = 3, rem -= 300; | ||
58 | else centuries = 2, rem -= 200; | ||
59 | } else { | ||
60 | if (rem >= 100) centuries = 1, rem -= 100; | ||
61 | else centuries = 0; | ||
62 | } | ||
63 | if (!rem) { | ||
64 | *is_leap = 0; | ||
65 | leaps = 0; | ||
66 | } else { | ||
67 | leaps = rem / 4U; | ||
68 | rem %= 4U; | ||
69 | *is_leap = !rem; | ||
70 | } | ||
71 | } | ||
72 | |||
73 | leaps += 97*cycles + 24*centuries - *is_leap; | ||
74 | |||
75 | return (year-100) * 31536000LL + leaps * 86400LL + 946684800 + 86400; | ||
76 | } | ||
77 | |||
78 | static int __month_to_secs(int month, int is_leap) | ||
79 | { | ||
80 | static const int secs_through_month[] = { | ||
81 | 0, 31*86400, 59*86400, 90*86400, | ||
82 | 120*86400, 151*86400, 181*86400, 212*86400, | ||
83 | 243*86400, 273*86400, 304*86400, 334*86400 }; | ||
84 | int t = secs_through_month[month]; | ||
85 | if (is_leap && month >= 2) t+=86400; | ||
86 | return t; | ||
87 | } | ||
88 | |||
89 | static long long __tm_to_secs(const struct tm *tm) | ||
90 | { | ||
91 | int is_leap; | ||
92 | long long t; | ||
93 | long long year = tm->tm_year; | ||
94 | int month = tm->tm_mon; | ||
95 | if (month >= 12 || month < 0) { | ||
96 | int adj = month / 12; | ||
97 | month %= 12; | ||
98 | if (month < 0) { | ||
99 | adj--; | ||
100 | month += 12; | ||
101 | } | ||
102 | year += adj; | ||
103 | } | ||
104 | t = __year_to_secs(year, &is_leap); | ||
105 | t += __month_to_secs(month, is_leap); | ||
106 | t += 86400LL * (tm->tm_mday-1); | ||
107 | t += 3600LL * tm->tm_hour; | ||
108 | t += 60LL * tm->tm_min; | ||
109 | t += tm->tm_sec; | ||
110 | return t; | ||
111 | } | ||
112 | |||
113 | /* | ||
114 | * Restricted version of timegm: | ||
115 | * | ||
116 | * it doesn't normalise its argument | ||
117 | * its return value is limited to the range Microsoft supports | ||
118 | */ | ||
119 | time_t timegm(struct tm *tm) | ||
120 | { | ||
121 | long long t = __tm_to_secs(tm); | ||
122 | if (t < 0 || | ||
123 | #ifdef _USE_32BIT_TIME_T | ||
124 | t > INT_MAX /* 2038-01-19 03:14:07Z */ | ||
125 | #else | ||
126 | t > 32535215999 /* 3000-12-31 23:59:59Z */ | ||
127 | #endif | ||
128 | ) { | ||
129 | errno = EOVERFLOW; | ||
130 | return -1; | ||
131 | } | ||
132 | return t; | ||
133 | } | ||