aboutsummaryrefslogtreecommitdiff
path: root/win32/timegm.c
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2021-09-17 09:18:58 +0100
committerRon Yorston <rmy@pobox.com>2021-09-17 11:41:25 +0100
commit9e16eecc70020e9a603d637f6a8fdfc7c95c30e1 (patch)
tree5700c068c09ad6028551449c2c9deac13b5c3b32 /win32/timegm.c
parent46299d0c4f4c9a4bbad38bbbe26f196e1bccdc52 (diff)
downloadbusybox-w32-9e16eecc70020e9a603d637f6a8fdfc7c95c30e1.tar.gz
busybox-w32-9e16eecc70020e9a603d637f6a8fdfc7c95c30e1.tar.bz2
busybox-w32-9e16eecc70020e9a603d637f6a8fdfc7c95c30e1.zip
win32: changes to allow timezones in dates
Create mingw_strptime() to return timezone offset as a separate argument (since Microsoft's struct tm doesn't have the required member). Import timegm() from musl. Update parse_datestr() to use mingw_strptime(). Enable FEATURE_TIMEZONE in the default configuration. GitHub issue #230.
Diffstat (limited to 'win32/timegm.c')
-rw-r--r--win32/timegm.c205
1 files changed, 205 insertions, 0 deletions
diff --git a/win32/timegm.c b/win32/timegm.c
new file mode 100644
index 000000000..abba2579f
--- /dev/null
+++ b/win32/timegm.c
@@ -0,0 +1,205 @@
1/*
2 timegm from musl (https://www.musl-libc.org/).
3
4 MIT licensed:
5
6----------------------------------------------------------------------
7Copyright © 2005-2020 Rich Felker, et al.
8
9Permission is hereby granted, free of charge, to any person obtaining
10a copy of this software and associated documentation files (the
11"Software"), to deal in the Software without restriction, including
12without limitation the rights to use, copy, modify, merge, publish,
13distribute, sublicense, and/or sell copies of the Software, and to
14permit persons to whom the Software is furnished to do so, subject to
15the following conditions:
16
17The above copyright notice and this permission notice shall be
18included in all copies or substantial portions of the Software.
19
20THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
23IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
24CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
25TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
26SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27----------------------------------------------------------------------
28*/
29#include "libbb.h"
30
31static 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 if (!is_leap) is_leap = &(int){0};
46 cycles = (year-100) / 400;
47 rem = (year-100) % 400;
48 if (rem < 0) {
49 cycles--;
50 rem += 400;
51 }
52 if (!rem) {
53 *is_leap = 1;
54 centuries = 0;
55 leaps = 0;
56 } else {
57 if (rem >= 200) {
58 if (rem >= 300) centuries = 3, rem -= 300;
59 else centuries = 2, rem -= 200;
60 } else {
61 if (rem >= 100) centuries = 1, rem -= 100;
62 else centuries = 0;
63 }
64 if (!rem) {
65 *is_leap = 0;
66 leaps = 0;
67 } else {
68 leaps = rem / 4U;
69 rem %= 4U;
70 *is_leap = !rem;
71 }
72 }
73
74 leaps += 97*cycles + 24*centuries - *is_leap;
75
76 return (year-100) * 31536000LL + leaps * 86400LL + 946684800 + 86400;
77}
78
79static int __month_to_secs(int month, int is_leap)
80{
81 static const int secs_through_month[] = {
82 0, 31*86400, 59*86400, 90*86400,
83 120*86400, 151*86400, 181*86400, 212*86400,
84 243*86400, 273*86400, 304*86400, 334*86400 };
85 int t = secs_through_month[month];
86 if (is_leap && month >= 2) t+=86400;
87 return t;
88}
89
90static long long __tm_to_secs(const struct tm *tm)
91{
92 int is_leap;
93 long long t;
94 long long year = tm->tm_year;
95 int month = tm->tm_mon;
96 if (month >= 12 || month < 0) {
97 int adj = month / 12;
98 month %= 12;
99 if (month < 0) {
100 adj--;
101 month += 12;
102 }
103 year += adj;
104 }
105 t = __year_to_secs(year, &is_leap);
106 t += __month_to_secs(month, is_leap);
107 t += 86400LL * (tm->tm_mday-1);
108 t += 3600LL * tm->tm_hour;
109 t += 60LL * tm->tm_min;
110 t += tm->tm_sec;
111 return t;
112}
113
114/* 2000-03-01 (mod 400 year, immediately after feb29 */
115#define LEAPOCH (946684800LL + 86400*(31+29))
116
117#define DAYS_PER_400Y (365*400 + 97)
118#define DAYS_PER_100Y (365*100 + 24)
119#define DAYS_PER_4Y (365*4 + 1)
120
121static int __secs_to_tm(long long t, struct tm *tm)
122{
123 long long days, secs, years;
124 int remdays, remsecs, remyears;
125 int qc_cycles, c_cycles, q_cycles;
126 int months;
127 int wday, yday, leap;
128 static const char days_in_month[] = {31,30,31,30,31,31,30,31,30,31,31,29};
129
130 /* Reject time_t values whose year would overflow int */
131 if (t < INT_MIN * 31622400LL || t > INT_MAX * 31622400LL)
132 return -1;
133
134 secs = t - LEAPOCH;
135 days = secs / 86400;
136 remsecs = secs % 86400;
137 if (remsecs < 0) {
138 remsecs += 86400;
139 days--;
140 }
141
142 wday = (3+days)%7;
143 if (wday < 0) wday += 7;
144
145 qc_cycles = days / DAYS_PER_400Y;
146 remdays = days % DAYS_PER_400Y;
147 if (remdays < 0) {
148 remdays += DAYS_PER_400Y;
149 qc_cycles--;
150 }
151
152 c_cycles = remdays / DAYS_PER_100Y;
153 if (c_cycles == 4) c_cycles--;
154 remdays -= c_cycles * DAYS_PER_100Y;
155
156 q_cycles = remdays / DAYS_PER_4Y;
157 if (q_cycles == 25) q_cycles--;
158 remdays -= q_cycles * DAYS_PER_4Y;
159
160 remyears = remdays / 365;
161 if (remyears == 4) remyears--;
162 remdays -= remyears * 365;
163
164 leap = !remyears && (q_cycles || !c_cycles);
165 yday = remdays + 31 + 28 + leap;
166 if (yday >= 365+leap) yday -= 365+leap;
167
168 years = remyears + 4*q_cycles + 100*c_cycles + 400LL*qc_cycles;
169
170 for (months=0; days_in_month[months] <= remdays; months++)
171 remdays -= days_in_month[months];
172
173 if (months >= 10) {
174 months -= 12;
175 years++;
176 }
177
178 if (years+100 > INT_MAX || years+100 < INT_MIN)
179 return -1;
180
181 tm->tm_year = years + 100;
182 tm->tm_mon = months + 2;
183 tm->tm_mday = remdays + 1;
184 tm->tm_wday = wday;
185 tm->tm_yday = yday;
186
187 tm->tm_hour = remsecs / 3600;
188 tm->tm_min = remsecs / 60 % 60;
189 tm->tm_sec = remsecs % 60;
190
191 return 0;
192}
193
194time_t timegm(struct tm *tm)
195{
196 struct tm new;
197 long long t = __tm_to_secs(tm);
198 if (__secs_to_tm(t, &new) < 0) {
199 errno = EOVERFLOW;
200 return -1;
201 }
202 *tm = new;
203 tm->tm_isdst = 0;
204 return t;
205}