| 2329 | } |
| 2330 | |
| 2331 | static struct tm * |
| 2332 | timesub(const time_t *timep, int_fast32_t offset, |
| 2333 | const struct state *sp, struct tm *tmp) |
| 2334 | { |
| 2335 | register time_t tdays; |
| 2336 | register const int * ip; |
| 2337 | int_fast32_2s corr; |
| 2338 | register int i; |
| 2339 | int_fast32_t idays, rem, dayoff, dayrem; |
| 2340 | time_t y; |
| 2341 | |
| 2342 | /* If less than SECSPERMIN, the number of seconds since the |
| 2343 | most recent positive leap second; otherwise, do not add 1 |
| 2344 | to localtime tm_sec because of leap seconds. */ |
| 2345 | time_t secs_since_posleap = SECSPERMIN; |
| 2346 | |
| 2347 | corr = 0; |
| 2348 | i = sp ? leapcount(sp) : 0; |
| 2349 | while (--i >= 0) { |
| 2350 | struct lsinfo ls = lsinfo(sp, i); |
| 2351 | if (ls.ls_trans <= *timep) { |
| 2352 | corr = ls.ls_corr; |
| 2353 | if ((i == 0 ? 0 : lsinfo(sp, i - 1).ls_corr) < corr) |
| 2354 | secs_since_posleap = *timep - ls.ls_trans; |
| 2355 | break; |
| 2356 | } |
| 2357 | } |
| 2358 | |
| 2359 | /* Calculate the year, avoiding integer overflow even if |
| 2360 | time_t is unsigned. */ |
| 2361 | tdays = *timep / SECSPERDAY; |
| 2362 | rem = *timep % SECSPERDAY; |
| 2363 | rem += offset % SECSPERDAY - corr % SECSPERDAY + 3 * SECSPERDAY; |
| 2364 | dayoff = offset / SECSPERDAY - corr / SECSPERDAY + rem / SECSPERDAY - 3; |
| 2365 | rem %= SECSPERDAY; |
| 2366 | /* y = (EPOCH_YEAR |
| 2367 | + floor((tdays + dayoff) / DAYSPERREPEAT) * YEARSPERREPEAT), |
| 2368 | sans overflow. But calculate against 1570 (EPOCH_YEAR - |
| 2369 | YEARSPERREPEAT) instead of against 1970 so that things work |
| 2370 | for localtime values before 1970 when time_t is unsigned. */ |
| 2371 | dayrem = tdays % DAYSPERREPEAT; |
| 2372 | dayrem += dayoff % DAYSPERREPEAT; |
| 2373 | y = (EPOCH_YEAR - YEARSPERREPEAT |
| 2374 | + ((1 + dayoff / DAYSPERREPEAT + dayrem / DAYSPERREPEAT |
| 2375 | - ((dayrem % DAYSPERREPEAT) < 0) |
| 2376 | + tdays / DAYSPERREPEAT) |
| 2377 | * YEARSPERREPEAT)); |
| 2378 | /* idays = (tdays + dayoff) mod DAYSPERREPEAT, sans overflow. */ |
| 2379 | idays = tdays % DAYSPERREPEAT; |
| 2380 | idays += dayoff % DAYSPERREPEAT + 2 * DAYSPERREPEAT; |
| 2381 | idays %= DAYSPERREPEAT; |
| 2382 | /* Increase Y and decrease IDAYS until IDAYS is in range for Y. */ |
| 2383 | while (year_lengths[isleap(y)] <= idays) { |
| 2384 | int tdelta = idays / DAYSPERLYEAR; |
| 2385 | int_fast32_t ydelta = tdelta + !tdelta; |
| 2386 | time_t newy = y + ydelta; |
| 2387 | register int leapdays; |
| 2388 | leapdays = leaps_thru_end_of(newy - 1) - |
no test coverage detected