1238106Sdes/*
2238106Sdes * Taken from FreeBSD src / lib / libc / stdtime / localtime.c 1.43 revision.
3238106Sdes * localtime.c 7.78.
4238106Sdes * tzfile.h 1.8
5238106Sdes * adapted to be replacement gmtime_r.
6238106Sdes */
7238106Sdes#include "config.h"
8238106Sdes
9238106Sdes#ifdef HAVE_TIME_H
10238106Sdes#include <time.h>
11238106Sdes#endif
12238106Sdes
13238106Sdes#define MONSPERYEAR 12
14238106Sdes#define DAYSPERNYEAR 365
15238106Sdes#define DAYSPERLYEAR 366
16238106Sdes#define SECSPERMIN 60
17238106Sdes#define SECSPERHOUR (60*60)
18238106Sdes#define SECSPERDAY (24*60*60)
19238106Sdes#define DAYSPERWEEK 7
20238106Sdes#define TM_SUNDAY	0
21238106Sdes#define TM_MONDAY	1
22238106Sdes#define TM_TUESDAY	2
23238106Sdes#define TM_WEDNESDAY	3
24238106Sdes#define TM_THURSDAY	4
25238106Sdes#define TM_FRIDAY	5
26238106Sdes#define TM_SATURDAY	6
27238106Sdes
28238106Sdes#define TM_YEAR_BASE	1900
29238106Sdes
30238106Sdes#define EPOCH_YEAR	1970
31238106Sdes#define EPOCH_WDAY	TM_THURSDAY
32238106Sdes
33238106Sdes#define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0))
34238106Sdes
35238106Sdesstatic const int	mon_lengths[2][MONSPERYEAR] = {
36238106Sdes	{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
37238106Sdes	{ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
38238106Sdes};
39238106Sdes
40238106Sdesstatic const int	year_lengths[2] = {
41238106Sdes	DAYSPERNYEAR, DAYSPERLYEAR
42238106Sdes};
43238106Sdes
44238106Sdesstatic void
45238106Sdestimesub(timep, offset, tmp)
46238106Sdesconst time_t * const			timep;
47238106Sdesconst long				offset;
48238106Sdesstruct tm * const		tmp;
49238106Sdes{
50238106Sdes	long			days;
51238106Sdes	long			rem;
52238106Sdes	long			y;
53238106Sdes	int			yleap;
54238106Sdes	const int *		ip;
55238106Sdes
56238106Sdes	days = *timep / SECSPERDAY;
57238106Sdes	rem = *timep % SECSPERDAY;
58238106Sdes	rem += (offset);
59238106Sdes	while (rem < 0) {
60238106Sdes		rem += SECSPERDAY;
61238106Sdes		--days;
62238106Sdes	}
63238106Sdes	while (rem >= SECSPERDAY) {
64238106Sdes		rem -= SECSPERDAY;
65238106Sdes		++days;
66238106Sdes	}
67238106Sdes	tmp->tm_hour = (int) (rem / SECSPERHOUR);
68238106Sdes	rem = rem % SECSPERHOUR;
69238106Sdes	tmp->tm_min = (int) (rem / SECSPERMIN);
70238106Sdes	/*
71238106Sdes	** A positive leap second requires a special
72238106Sdes	** representation.  This uses "... ??:59:60" et seq.
73238106Sdes	*/
74238106Sdes	tmp->tm_sec = (int) (rem % SECSPERMIN) ;
75238106Sdes	tmp->tm_wday = (int) ((EPOCH_WDAY + days) % DAYSPERWEEK);
76238106Sdes	if (tmp->tm_wday < 0)
77238106Sdes		tmp->tm_wday += DAYSPERWEEK;
78238106Sdes	y = EPOCH_YEAR;
79238106Sdes#define LEAPS_THRU_END_OF(y)	((y) / 4 - (y) / 100 + (y) / 400)
80238106Sdes	while (days < 0 || days >= (long) year_lengths[yleap = isleap(y)]) {
81238106Sdes		long	newy;
82238106Sdes
83238106Sdes		newy = y + days / DAYSPERNYEAR;
84238106Sdes		if (days < 0)
85238106Sdes			--newy;
86238106Sdes		days -= (newy - y) * DAYSPERNYEAR +
87238106Sdes			LEAPS_THRU_END_OF(newy - 1) -
88238106Sdes			LEAPS_THRU_END_OF(y - 1);
89238106Sdes		y = newy;
90238106Sdes	}
91238106Sdes	tmp->tm_year = y - TM_YEAR_BASE;
92238106Sdes	tmp->tm_yday = (int) days;
93238106Sdes	ip = mon_lengths[yleap];
94238106Sdes	for (tmp->tm_mon = 0; days >= (long) ip[tmp->tm_mon]; ++(tmp->tm_mon))
95238106Sdes		days = days - (long) ip[tmp->tm_mon];
96238106Sdes	tmp->tm_mday = (int) (days + 1);
97238106Sdes	tmp->tm_isdst = 0;
98238106Sdes}
99238106Sdes
100238106Sdes/*
101238106Sdes* Re-entrant version of gmtime.
102238106Sdes*/
103238106Sdesstruct tm * gmtime_r(const time_t* timep, struct tm *tm)
104238106Sdes{
105238106Sdes	timesub(timep, 0L, tm);
106238106Sdes	return tm;
107238106Sdes}
108