1*3b6c3722Schristos /*
2*3b6c3722Schristos * Taken from FreeBSD src / lib / libc / stdtime / localtime.c 1.43 revision.
3*3b6c3722Schristos * localtime.c 7.78.
4*3b6c3722Schristos * tzfile.h 1.8
5*3b6c3722Schristos * adapted to be replacement gmtime_r.
6*3b6c3722Schristos */
7*3b6c3722Schristos #include "config.h"
8*3b6c3722Schristos
9*3b6c3722Schristos #ifdef HAVE_TIME_H
10*3b6c3722Schristos #include <time.h>
11*3b6c3722Schristos #endif
12*3b6c3722Schristos
13*3b6c3722Schristos #define MONSPERYEAR 12
14*3b6c3722Schristos #define DAYSPERNYEAR 365
15*3b6c3722Schristos #define DAYSPERLYEAR 366
16*3b6c3722Schristos #define SECSPERMIN 60
17*3b6c3722Schristos #define SECSPERHOUR (60*60)
18*3b6c3722Schristos #define SECSPERDAY (24*60*60)
19*3b6c3722Schristos #define DAYSPERWEEK 7
20*3b6c3722Schristos #define TM_SUNDAY 0
21*3b6c3722Schristos #define TM_MONDAY 1
22*3b6c3722Schristos #define TM_TUESDAY 2
23*3b6c3722Schristos #define TM_WEDNESDAY 3
24*3b6c3722Schristos #define TM_THURSDAY 4
25*3b6c3722Schristos #define TM_FRIDAY 5
26*3b6c3722Schristos #define TM_SATURDAY 6
27*3b6c3722Schristos
28*3b6c3722Schristos #define TM_YEAR_BASE 1900
29*3b6c3722Schristos
30*3b6c3722Schristos #define EPOCH_YEAR 1970
31*3b6c3722Schristos #define EPOCH_WDAY TM_THURSDAY
32*3b6c3722Schristos
33*3b6c3722Schristos #define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0))
34*3b6c3722Schristos
35*3b6c3722Schristos static const int mon_lengths[2][MONSPERYEAR] = {
36*3b6c3722Schristos { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
37*3b6c3722Schristos { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
38*3b6c3722Schristos };
39*3b6c3722Schristos
40*3b6c3722Schristos static const int year_lengths[2] = {
41*3b6c3722Schristos DAYSPERNYEAR, DAYSPERLYEAR
42*3b6c3722Schristos };
43*3b6c3722Schristos
44*3b6c3722Schristos static void
timesub(timep,offset,tmp)45*3b6c3722Schristos timesub(timep, offset, tmp)
46*3b6c3722Schristos const time_t * const timep;
47*3b6c3722Schristos const long offset;
48*3b6c3722Schristos struct tm * const tmp;
49*3b6c3722Schristos {
50*3b6c3722Schristos long days;
51*3b6c3722Schristos long rem;
52*3b6c3722Schristos long y;
53*3b6c3722Schristos int yleap;
54*3b6c3722Schristos const int * ip;
55*3b6c3722Schristos
56*3b6c3722Schristos days = *timep / SECSPERDAY;
57*3b6c3722Schristos rem = *timep % SECSPERDAY;
58*3b6c3722Schristos rem += (offset);
59*3b6c3722Schristos while (rem < 0) {
60*3b6c3722Schristos rem += SECSPERDAY;
61*3b6c3722Schristos --days;
62*3b6c3722Schristos }
63*3b6c3722Schristos while (rem >= SECSPERDAY) {
64*3b6c3722Schristos rem -= SECSPERDAY;
65*3b6c3722Schristos ++days;
66*3b6c3722Schristos }
67*3b6c3722Schristos tmp->tm_hour = (int) (rem / SECSPERHOUR);
68*3b6c3722Schristos rem = rem % SECSPERHOUR;
69*3b6c3722Schristos tmp->tm_min = (int) (rem / SECSPERMIN);
70*3b6c3722Schristos /*
71*3b6c3722Schristos ** A positive leap second requires a special
72*3b6c3722Schristos ** representation. This uses "... ??:59:60" et seq.
73*3b6c3722Schristos */
74*3b6c3722Schristos tmp->tm_sec = (int) (rem % SECSPERMIN) ;
75*3b6c3722Schristos tmp->tm_wday = (int) ((EPOCH_WDAY + days) % DAYSPERWEEK);
76*3b6c3722Schristos if (tmp->tm_wday < 0)
77*3b6c3722Schristos tmp->tm_wday += DAYSPERWEEK;
78*3b6c3722Schristos y = EPOCH_YEAR;
79*3b6c3722Schristos #define LEAPS_THRU_END_OF(y) ((y) / 4 - (y) / 100 + (y) / 400)
80*3b6c3722Schristos while (days < 0 || days >= (long) year_lengths[yleap = isleap(y)]) {
81*3b6c3722Schristos long newy;
82*3b6c3722Schristos
83*3b6c3722Schristos newy = y + days / DAYSPERNYEAR;
84*3b6c3722Schristos if (days < 0)
85*3b6c3722Schristos --newy;
86*3b6c3722Schristos days -= (newy - y) * DAYSPERNYEAR +
87*3b6c3722Schristos LEAPS_THRU_END_OF(newy - 1) -
88*3b6c3722Schristos LEAPS_THRU_END_OF(y - 1);
89*3b6c3722Schristos y = newy;
90*3b6c3722Schristos }
91*3b6c3722Schristos tmp->tm_year = y - TM_YEAR_BASE;
92*3b6c3722Schristos tmp->tm_yday = (int) days;
93*3b6c3722Schristos ip = mon_lengths[yleap];
94*3b6c3722Schristos for (tmp->tm_mon = 0; days >= (long) ip[tmp->tm_mon]; ++(tmp->tm_mon))
95*3b6c3722Schristos days = days - (long) ip[tmp->tm_mon];
96*3b6c3722Schristos tmp->tm_mday = (int) (days + 1);
97*3b6c3722Schristos tmp->tm_isdst = 0;
98*3b6c3722Schristos }
99*3b6c3722Schristos
100*3b6c3722Schristos /*
101*3b6c3722Schristos * Re-entrant version of gmtime.
102*3b6c3722Schristos */
gmtime_r(const time_t * timep,struct tm * tm)103*3b6c3722Schristos struct tm * gmtime_r(const time_t* timep, struct tm *tm)
104*3b6c3722Schristos {
105*3b6c3722Schristos timesub(timep, 0L, tm);
106*3b6c3722Schristos return tm;
107*3b6c3722Schristos }
108