/src/php-src/ext/date/lib/tm2unixtime.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * The MIT License (MIT) |
3 | | * |
4 | | * Copyright (c) 2015-2019 Derick Rethans |
5 | | * |
6 | | * Permission is hereby granted, free of charge, to any person obtaining a copy |
7 | | * of this software and associated documentation files (the "Software"), to deal |
8 | | * in the Software without restriction, including without limitation the rights |
9 | | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
10 | | * copies of the Software, and to permit persons to whom the Software is |
11 | | * furnished to do so, subject to the following conditions: |
12 | | * |
13 | | * The above copyright notice and this permission notice shall be included in |
14 | | * all copies or substantial portions of the Software. |
15 | | * |
16 | | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
17 | | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
18 | | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
19 | | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
20 | | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
21 | | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
22 | | * THE SOFTWARE. |
23 | | */ |
24 | | |
25 | | #include "timelib.h" |
26 | | #include "timelib_private.h" |
27 | | |
28 | | /* dec jan feb mrt apr may jun jul aug sep oct nov dec */ |
29 | | static int days_in_month_leap[13] = { 31, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; |
30 | | static int days_in_month[13] = { 31, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; |
31 | | |
32 | | static void do_range_limit(timelib_sll start, timelib_sll end, timelib_sll adj, timelib_sll *a, timelib_sll *b) |
33 | 7.01k | { |
34 | 7.01k | if (*a < start) { |
35 | | /* We calculate 'a + 1' first as 'start - *a - 1' causes an int64_t overflows if *a is |
36 | | * LONG_MIN. 'start' is 0 in this context, and '0 - LONG_MIN > LONG_MAX'. */ |
37 | 1 | timelib_sll a_plus_1 = *a + 1; |
38 | | |
39 | 1 | *b -= (start - a_plus_1) / adj + 1; |
40 | | |
41 | | /* This code add the extra 'adj' separately, as otherwise this can overflow int64_t in |
42 | | * situations where *b is near LONG_MIN. */ |
43 | 1 | *a += adj * ((start - a_plus_1) / adj); |
44 | 1 | *a += adj; |
45 | 1 | } |
46 | 7.01k | if (*a >= end) { |
47 | 5 | *b += *a / adj; |
48 | 5 | *a -= adj * (*a / adj); |
49 | 5 | } |
50 | 7.01k | } |
51 | | |
52 | | static void inc_month(timelib_sll *y, timelib_sll *m) |
53 | 0 | { |
54 | 0 | (*m)++; |
55 | 0 | if (*m > 12) { |
56 | 0 | *m -= 12; |
57 | 0 | (*y)++; |
58 | 0 | } |
59 | 0 | } |
60 | | |
61 | | static void dec_month(timelib_sll *y, timelib_sll *m) |
62 | 0 | { |
63 | 0 | (*m)--; |
64 | 0 | if (*m < 1) { |
65 | 0 | *m += 12; |
66 | 0 | (*y)--; |
67 | 0 | } |
68 | 0 | } |
69 | | |
70 | | static void do_range_limit_days_relative(timelib_sll *base_y, timelib_sll *base_m, timelib_sll *y, timelib_sll *m, timelib_sll *d, timelib_sll invert) |
71 | 5 | { |
72 | 5 | timelib_sll leapyear; |
73 | 5 | timelib_sll month, year; |
74 | 5 | timelib_sll days; |
75 | | |
76 | 5 | do_range_limit(1, 13, 12, base_m, base_y); |
77 | | |
78 | 5 | year = *base_y; |
79 | 5 | month = *base_m; |
80 | | |
81 | | /* |
82 | | printf( "S: Y%d M%d %d %d %d %d\n", year, month, *y, *m, *d, days); |
83 | | */ |
84 | 5 | if (!invert) { |
85 | 5 | while (*d < 0) { |
86 | 0 | dec_month(&year, &month); |
87 | 0 | leapyear = timelib_is_leap(year); |
88 | 0 | days = leapyear ? days_in_month_leap[month] : days_in_month[month]; |
89 | | |
90 | | /* printf( "I Y%d M%d %d %d %d %d\n", year, month, *y, *m, *d, days); */ |
91 | |
|
92 | 0 | *d += days; |
93 | 0 | (*m)--; |
94 | 0 | } |
95 | 5 | } else { |
96 | 0 | while (*d < 0) { |
97 | 0 | leapyear = timelib_is_leap(year); |
98 | 0 | days = leapyear ? days_in_month_leap[month] : days_in_month[month]; |
99 | | |
100 | | /* printf( "I Y%d M%d %d %d %d %d\n", year, month, *y, *m, *d, days); */ |
101 | |
|
102 | 0 | *d += days; |
103 | 0 | (*m)--; |
104 | 0 | inc_month(&year, &month); |
105 | 0 | } |
106 | 0 | } |
107 | | /* |
108 | | printf( "E: Y%d M%d %d %d %d %d\n", year, month, *y, *m, *d, days); |
109 | | */ |
110 | 5 | } |
111 | | |
112 | | static int do_range_limit_days(timelib_sll *y, timelib_sll *m, timelib_sll *d) |
113 | 999 | { |
114 | 999 | timelib_sll leapyear; |
115 | 999 | timelib_sll previous_month, previous_year; |
116 | 999 | timelib_sll days_in_previous_month; |
117 | 999 | int retval = 0; |
118 | 999 | int *days_per_month_current_year; |
119 | | |
120 | | /* can jump an entire leap year period quickly */ |
121 | 999 | if (*d >= DAYS_PER_ERA || *d <= -DAYS_PER_ERA) { |
122 | 0 | *y += YEARS_PER_ERA * (*d / DAYS_PER_ERA); |
123 | 0 | *d -= DAYS_PER_ERA * (*d / DAYS_PER_ERA); |
124 | 0 | } |
125 | | |
126 | 999 | do_range_limit(1, 13, 12, m, y); |
127 | | |
128 | 999 | leapyear = timelib_is_leap(*y); |
129 | 999 | days_per_month_current_year = leapyear ? days_in_month_leap : days_in_month; |
130 | | |
131 | 1.00k | while (*d <= 0 && *m > 0) { |
132 | 1 | previous_month = (*m) - 1; |
133 | 1 | if (previous_month < 1) { |
134 | 0 | previous_month += 12; |
135 | 0 | previous_year = (*y) - 1; |
136 | 1 | } else { |
137 | 1 | previous_year = (*y); |
138 | 1 | } |
139 | 1 | leapyear = timelib_is_leap(previous_year); |
140 | 1 | days_in_previous_month = leapyear ? days_in_month_leap[previous_month] : days_in_month[previous_month]; |
141 | | |
142 | 1 | *d += days_in_previous_month; |
143 | 1 | (*m)--; |
144 | 1 | retval = 1; |
145 | 1 | } |
146 | 1.00k | while (*d > 0 && *m <= 12 && *d > days_per_month_current_year[*m]) { |
147 | 6 | *d -= days_per_month_current_year[*m]; |
148 | 6 | (*m)++; |
149 | 6 | retval = 1; |
150 | 6 | } |
151 | 999 | return retval; |
152 | 999 | } |
153 | | |
154 | | static void do_adjust_for_weekday(timelib_time* time) |
155 | 0 | { |
156 | 0 | timelib_sll current_dow, difference; |
157 | |
|
158 | 0 | current_dow = timelib_day_of_week(time->y, time->m, time->d); |
159 | 0 | if (time->relative.weekday_behavior == 2) |
160 | 0 | { |
161 | | /* To make "this week" work, where the current DOW is a "sunday" */ |
162 | 0 | if (current_dow == 0 && time->relative.weekday != 0) { |
163 | 0 | time->relative.weekday -= 7; |
164 | 0 | } |
165 | | |
166 | | /* To make "sunday this week" work, where the current DOW is not a |
167 | | * "sunday" */ |
168 | 0 | if (time->relative.weekday == 0 && current_dow != 0) { |
169 | 0 | time->relative.weekday = 7; |
170 | 0 | } |
171 | |
|
172 | 0 | time->d -= current_dow; |
173 | 0 | time->d += time->relative.weekday; |
174 | 0 | return; |
175 | 0 | } |
176 | 0 | difference = time->relative.weekday - current_dow; |
177 | 0 | if ((time->relative.d < 0 && difference < 0) || (time->relative.d >= 0 && difference <= -time->relative.weekday_behavior)) { |
178 | 0 | difference += 7; |
179 | 0 | } |
180 | 0 | if (time->relative.weekday >= 0) { |
181 | 0 | time->d += difference; |
182 | 0 | } else { |
183 | 0 | time->d -= (7 - (abs(time->relative.weekday) - current_dow)); |
184 | 0 | } |
185 | 0 | time->relative.have_weekday_relative = 0; |
186 | 0 | } |
187 | | |
188 | | void timelib_do_rel_normalize(timelib_time *base, timelib_rel_time *rt) |
189 | 5 | { |
190 | 5 | do_range_limit(0, 1000000, 1000000, &rt->us, &rt->s); |
191 | 5 | do_range_limit(0, 60, 60, &rt->s, &rt->i); |
192 | 5 | do_range_limit(0, 60, 60, &rt->i, &rt->h); |
193 | 5 | do_range_limit(0, 24, 24, &rt->h, &rt->d); |
194 | 5 | do_range_limit(0, 12, 12, &rt->m, &rt->y); |
195 | | |
196 | 5 | do_range_limit_days_relative(&base->y, &base->m, &rt->y, &rt->m, &rt->d, rt->invert); |
197 | 5 | do_range_limit(0, 12, 12, &rt->m, &rt->y); |
198 | 5 | } |
199 | | |
200 | | static void magic_date_calc(timelib_time *time) |
201 | 0 | { |
202 | 0 | timelib_sll y, ddd, mi, mm, dd, g; |
203 | | |
204 | | /* The algorithm doesn't work before the year 1 */ |
205 | 0 | if (time->d < -719498) { |
206 | 0 | return; |
207 | 0 | } |
208 | | |
209 | 0 | g = time->d + HINNANT_EPOCH_SHIFT - 1; |
210 | |
|
211 | 0 | y = (10000 * g + 14780) / 3652425; |
212 | 0 | ddd = g - ((365*y) + (y/4) - (y/100) + (y/400)); |
213 | 0 | if (ddd < 0) { |
214 | 0 | y--; |
215 | 0 | ddd = g - ((365*y) + (y/4) - (y/100) + (y/400)); |
216 | 0 | } |
217 | 0 | mi = (100 * ddd + 52) / 3060; |
218 | 0 | mm = ((mi + 2) % 12) + 1; |
219 | 0 | y = y + (mi + 2) / 12; |
220 | 0 | dd = ddd - ((mi * 306 + 5) / 10) + 1; |
221 | 0 | time->y = y; |
222 | 0 | time->m = mm; |
223 | 0 | time->d = dd; |
224 | 0 | } |
225 | | |
226 | | void timelib_do_normalize(timelib_time* time) |
227 | 996 | { |
228 | 996 | if (time->us != TIMELIB_UNSET) do_range_limit(0, 1000000, 1000000, &time->us, &time->s); |
229 | 996 | if (time->s != TIMELIB_UNSET) do_range_limit(0, 60, 60, &time->s, &time->i); |
230 | 996 | if (time->s != TIMELIB_UNSET) do_range_limit(0, 60, 60, &time->i, &time->h); |
231 | 996 | if (time->s != TIMELIB_UNSET) do_range_limit(0, 24, 24, &time->h, &time->d); |
232 | 996 | do_range_limit(1, 13, 12, &time->m, &time->y); |
233 | | |
234 | | /* Short cut if we're doing things against the Epoch */ |
235 | 996 | if (time->y == 1970 && time->m == 1 && time->d != 1) { |
236 | 0 | magic_date_calc(time); |
237 | 0 | } |
238 | | |
239 | 999 | do {} while (do_range_limit_days(&time->y, &time->m, &time->d)); |
240 | 996 | do_range_limit(1, 13, 12, &time->m, &time->y); |
241 | 996 | } |
242 | | |
243 | | static void do_adjust_relative(timelib_time* time) |
244 | 249 | { |
245 | 249 | if (time->relative.have_weekday_relative) { |
246 | 0 | do_adjust_for_weekday(time); |
247 | 0 | } |
248 | 249 | timelib_do_normalize(time); |
249 | | |
250 | 249 | if (time->have_relative) { |
251 | 5 | time->us += time->relative.us; |
252 | | |
253 | 5 | time->s += time->relative.s; |
254 | 5 | time->i += time->relative.i; |
255 | 5 | time->h += time->relative.h; |
256 | | |
257 | 5 | time->d += time->relative.d; |
258 | 5 | time->m += time->relative.m; |
259 | 5 | time->y += time->relative.y; |
260 | 5 | } |
261 | | |
262 | 249 | switch (time->relative.first_last_day_of) { |
263 | 0 | case TIMELIB_SPECIAL_FIRST_DAY_OF_MONTH: /* first */ |
264 | 0 | time->d = 1; |
265 | 0 | break; |
266 | 0 | case TIMELIB_SPECIAL_LAST_DAY_OF_MONTH: /* last */ |
267 | 0 | time->d = 0; |
268 | 0 | time->m++; |
269 | 0 | break; |
270 | 249 | } |
271 | | |
272 | 249 | timelib_do_normalize(time); |
273 | 249 | } |
274 | | |
275 | | static void do_adjust_special_weekday(timelib_time* time) |
276 | 0 | { |
277 | 0 | timelib_sll count, dow, rem; |
278 | |
|
279 | 0 | count = time->relative.special.amount; |
280 | 0 | dow = timelib_day_of_week(time->y, time->m, time->d); |
281 | | |
282 | | /* Add increments of 5 weekdays as a week, leaving the DOW unchanged. */ |
283 | 0 | time->d += (count / 5) * 7; |
284 | | |
285 | | /* Deal with the remainder. */ |
286 | 0 | rem = (count % 5); |
287 | |
|
288 | 0 | if (count > 0) { |
289 | 0 | if (rem == 0) { |
290 | | /* Head back to Friday if we stop on the weekend. */ |
291 | 0 | if (dow == 0) { |
292 | 0 | time->d -= 2; |
293 | 0 | } else if (dow == 6) { |
294 | 0 | time->d -= 1; |
295 | 0 | } |
296 | 0 | } else if (dow == 6) { |
297 | | /* We ended up on Saturday, but there's still work to do, so move |
298 | | * to Sunday and continue from there. */ |
299 | 0 | time->d += 1; |
300 | 0 | } else if (dow + rem > 5) { |
301 | | /* We're on a weekday, but we're going past Friday, so skip right |
302 | | * over the weekend. */ |
303 | 0 | time->d += 2; |
304 | 0 | } |
305 | 0 | } else { |
306 | | /* Completely mirror the forward direction. This also covers the 0 |
307 | | * case, since if we start on the weekend, we want to move forward as |
308 | | * if we stopped there while going backwards. */ |
309 | 0 | if (rem == 0) { |
310 | 0 | if (dow == 6) { |
311 | 0 | time->d += 2; |
312 | 0 | } else if (dow == 0) { |
313 | 0 | time->d += 1; |
314 | 0 | } |
315 | 0 | } else if (dow == 0) { |
316 | 0 | time->d -= 1; |
317 | 0 | } else if (dow + rem < 1) { |
318 | 0 | time->d -= 2; |
319 | 0 | } |
320 | 0 | } |
321 | |
|
322 | 0 | time->d += rem; |
323 | 0 | } |
324 | | |
325 | | static void do_adjust_special(timelib_time* time) |
326 | 249 | { |
327 | 249 | if (time->relative.have_special_relative) { |
328 | 0 | switch (time->relative.special.type) { |
329 | 0 | case TIMELIB_SPECIAL_WEEKDAY: |
330 | 0 | do_adjust_special_weekday(time); |
331 | 0 | break; |
332 | 0 | } |
333 | 0 | } |
334 | 249 | timelib_do_normalize(time); |
335 | 249 | memset(&(time->relative.special), 0, sizeof(time->relative.special)); |
336 | 249 | } |
337 | | |
338 | | static void do_adjust_special_early(timelib_time* time) |
339 | 249 | { |
340 | 249 | if (time->relative.have_special_relative) { |
341 | 0 | switch (time->relative.special.type) { |
342 | 0 | case TIMELIB_SPECIAL_DAY_OF_WEEK_IN_MONTH: |
343 | 0 | time->d = 1; |
344 | 0 | time->m += time->relative.m; |
345 | 0 | time->relative.m = 0; |
346 | 0 | break; |
347 | 0 | case TIMELIB_SPECIAL_LAST_DAY_OF_WEEK_IN_MONTH: |
348 | 0 | time->d = 1; |
349 | 0 | time->m += time->relative.m + 1; |
350 | 0 | time->relative.m = 0; |
351 | 0 | break; |
352 | 0 | } |
353 | 0 | } |
354 | 249 | switch (time->relative.first_last_day_of) { |
355 | 0 | case TIMELIB_SPECIAL_FIRST_DAY_OF_MONTH: /* first */ |
356 | 0 | time->d = 1; |
357 | 0 | break; |
358 | 0 | case TIMELIB_SPECIAL_LAST_DAY_OF_MONTH: /* last */ |
359 | 0 | time->d = 0; |
360 | 0 | time->m++; |
361 | 0 | break; |
362 | 249 | } |
363 | 249 | timelib_do_normalize(time); |
364 | 249 | } |
365 | | |
366 | | static void do_adjust_timezone(timelib_time *tz, timelib_tzinfo *tzi) |
367 | 249 | { |
368 | 249 | switch (tz->zone_type) { |
369 | 13 | case TIMELIB_ZONETYPE_OFFSET: |
370 | | |
371 | 13 | tz->is_localtime = 1; |
372 | 13 | tz->sse += -tz->z; |
373 | 13 | return; |
374 | | |
375 | 0 | case TIMELIB_ZONETYPE_ABBR: { |
376 | |
|
377 | 0 | tz->is_localtime = 1; |
378 | 0 | tz->sse += (-tz->z - tz->dst * SECS_PER_HOUR); |
379 | 0 | return; |
380 | 0 | } |
381 | | |
382 | 236 | case TIMELIB_ZONETYPE_ID: |
383 | 236 | tzi = tz->tz_info; |
384 | 236 | TIMELIB_BREAK_INTENTIONALLY_MISSING |
385 | | |
386 | 236 | default: { |
387 | | /* No timezone in struct, fallback to reference if possible */ |
388 | 236 | int32_t current_offset = 0; |
389 | 236 | timelib_sll current_transition_time = 0; |
390 | 236 | unsigned int current_is_dst = 0; |
391 | 236 | int32_t after_offset = 0; |
392 | 236 | timelib_sll after_transition_time = 0; |
393 | 236 | timelib_sll adjustment; |
394 | 236 | int in_transition; |
395 | 236 | int32_t actual_offset; |
396 | 236 | timelib_sll actual_transition_time; |
397 | | |
398 | 236 | if (!tzi) { |
399 | 0 | return; |
400 | 0 | } |
401 | | |
402 | 236 | timelib_get_time_zone_offset_info(tz->sse, tzi, ¤t_offset, ¤t_transition_time, ¤t_is_dst); |
403 | 236 | timelib_get_time_zone_offset_info(tz->sse - current_offset, tzi, &after_offset, &after_transition_time, NULL); |
404 | 236 | actual_offset = after_offset; |
405 | 236 | actual_transition_time = after_transition_time; |
406 | 236 | if (current_offset == after_offset && tz->have_zone) { |
407 | | /* Make sure we're not missing a DST change because we don't know the actual offset yet */ |
408 | 5 | if (current_offset >= 0 && tz->dst && !current_is_dst) { |
409 | | /* Timezone or its DST at or east of UTC, so the local time, interpreted as UTC, leaves DST (as defined in the actual timezone) before the actual local time */ |
410 | 0 | int32_t earlier_offset; |
411 | 0 | timelib_sll earlier_transition_time; |
412 | 0 | timelib_get_time_zone_offset_info(tz->sse - current_offset - 7200, tzi, &earlier_offset, &earlier_transition_time, NULL); |
413 | 0 | if ((earlier_offset != after_offset) && (tz->sse - earlier_offset < after_transition_time)) { |
414 | | /* Looking behind a bit clarified the actual offset to use */ |
415 | 0 | actual_offset = earlier_offset; |
416 | 0 | actual_transition_time = earlier_transition_time; |
417 | 0 | } |
418 | 5 | } else if (current_offset <= 0 && current_is_dst && !tz->dst) { |
419 | | /* Timezone west of UTC, so the local time, interpreted as UTC, leaves DST (as defined in the actual timezone) after the actual local time */ |
420 | 0 | int32_t later_offset; |
421 | 0 | timelib_sll later_transition_time; |
422 | 0 | timelib_get_time_zone_offset_info(tz->sse - current_offset + 7200, tzi, &later_offset, &later_transition_time, NULL); |
423 | 0 | if ((later_offset != after_offset) && (tz->sse - later_offset >= later_transition_time)) { |
424 | | /* Looking ahead a bit clarified the actual offset to use */ |
425 | 0 | actual_offset = later_offset; |
426 | 0 | actual_transition_time = later_transition_time; |
427 | 0 | } |
428 | 0 | } |
429 | 5 | } |
430 | | |
431 | 236 | tz->is_localtime = 1; |
432 | | |
433 | 236 | in_transition = ( |
434 | 236 | actual_transition_time != INT64_MIN && |
435 | 236 | ((tz->sse - actual_offset) >= (actual_transition_time + (current_offset - actual_offset))) && |
436 | 236 | ((tz->sse - actual_offset) < actual_transition_time) |
437 | 236 | ); |
438 | | |
439 | 236 | if ((current_offset != actual_offset) && !in_transition) { |
440 | 0 | adjustment = -actual_offset; |
441 | 236 | } else { |
442 | 236 | adjustment = -current_offset; |
443 | 236 | } |
444 | | |
445 | 236 | tz->sse += adjustment; |
446 | 236 | timelib_set_timezone(tz, tzi); |
447 | 236 | return; |
448 | 236 | } |
449 | 249 | } |
450 | 0 | return; |
451 | 249 | } |
452 | | |
453 | | timelib_sll timelib_epoch_days_from_time(timelib_time *time) |
454 | 508 | { |
455 | 508 | timelib_sll y = time->y; // Make copy, as we don't want to change the original one |
456 | 508 | timelib_sll era, year_of_era, day_of_year, day_of_era; |
457 | | |
458 | 508 | y -= time->m <= 2; |
459 | 508 | era = (y >= 0 ? y : y - 399) / YEARS_PER_ERA; |
460 | 508 | year_of_era = y - era * YEARS_PER_ERA; // [0, 399] |
461 | 508 | day_of_year = (153 * (time->m + (time->m > 2 ? -3 : 9)) + 2)/5 + time->d - 1; // [0, 365] |
462 | 508 | day_of_era = year_of_era * DAYS_PER_YEAR + year_of_era / 4 - year_of_era / 100 + day_of_year; // [0, 146096] |
463 | | |
464 | 508 | return era * DAYS_PER_ERA + day_of_era - HINNANT_EPOCH_SHIFT; |
465 | 508 | } |
466 | | |
467 | | void timelib_update_ts(timelib_time* time, timelib_tzinfo* tzi) |
468 | 249 | { |
469 | 249 | do_adjust_special_early(time); |
470 | 249 | do_adjust_relative(time); |
471 | 249 | do_adjust_special(time); |
472 | | |
473 | | /* You might be wondering, why this code does this in two steps. This is because |
474 | | * timelib_epoch_days_from_time(time) * SECS_PER_DAY with the lowest limit of |
475 | | * timelib_epoch_days_from_time() is less than the range of an int64_t. This then overflows. In |
476 | | * order to be able to still allow for any time in that day that only halfly fits in the int64_t |
477 | | * range, we add the time element first, which is always positive, and then twice half the value |
478 | | * of the earliest day as expressed as unix timestamp. */ |
479 | 249 | time->sse = timelib_hms_to_seconds(time->h, time->i, time->s); |
480 | 249 | time->sse += timelib_epoch_days_from_time(time) * (SECS_PER_DAY / 2); |
481 | 249 | time->sse += timelib_epoch_days_from_time(time) * (SECS_PER_DAY / 2); |
482 | | |
483 | | // This modifies time->sse, if needed |
484 | 249 | do_adjust_timezone(time, tzi); |
485 | | |
486 | 249 | time->sse_uptodate = 1; |
487 | 249 | time->have_relative = time->relative.have_weekday_relative = time->relative.have_special_relative = time->relative.first_last_day_of = 0; |
488 | 249 | } |
489 | | |
490 | | #if 0 |
491 | | int main(void) |
492 | | { |
493 | | timelib_sll res; |
494 | | timelib_time time; |
495 | | |
496 | | time = timelib_strtotime("10 Feb 2005 06:07:03 PM CET"); /* 1108055223 */ |
497 | | printf ("%04d-%02d-%02d %02d:%02d:%02d.%-5d %+04d %1d", |
498 | | time.y, time.m, time.d, time.h, time.i, time.s, time.f, time.z, time.dst); |
499 | | if (time.have_relative) { |
500 | | printf ("%3dY %3dM %3dD / %3dH %3dM %3dS", |
501 | | time.relative.y, time.relative.m, time.relative.d, time.relative.h, time.relative.i, time.relative.s); |
502 | | } |
503 | | if (time.have_weekday_relative) { |
504 | | printf (" / %d", time.relative.weekday); |
505 | | } |
506 | | res = time2unixtime(&time); |
507 | | printf("%Ld\n", res); |
508 | | |
509 | | return 0; |
510 | | } |
511 | | #endif |