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