summaryrefslogtreecommitdiff
path: root/libc/misc/time/tm_conv.c
blob: 480cfa28bcf96bb2333501f29f5cf21e8e7e5a68 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138

#if 0
#include <time.h>

/* This is a translation from ALGOL in Collected Algorithms of CACM. */
/* Copied from Algorithm 199, Author: Robert G. Tantzen */

void __tm_conv(tmbuf, timep, offset)
struct tm *tmbuf;
time_t *timep;
time_t offset;
{
	static int moffset[] =
		{ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };

	long s;
	long j, d, m, y;

	offset += *timep;

	tmbuf->tm_isdst = 0;		/* Someone else can set this */

	j = offset / 86400L + 719469;
	s = offset % 86400L;

	if (s < 0) {
		s += 86400L;
		j--;
	}

	tmbuf->tm_sec = s % 60;
	tmbuf->tm_min = (s / 60) % 60;
	tmbuf->tm_hour = s / 3600;

	tmbuf->tm_wday = (j + 2) % 7;

	/*
	 * Julian date converter. Takes a julian date (the number of days since
	 * some distant epoch or other), and fills tmbuf.
	 */

	y = (4L * j - 1L) / 146097L;
	j = 4L * j - 1L - 146097L * y;
	d = j / 4L;
	j = (4L * d + 3L) / 1461L;
	d = 4L * d + 3L - 1461L * j;
	d = (d + 4L) / 4L;
	m = (5L * d - 3L) / 153L;
	d = 5L * d - 3 - 153L * m;
	d = (d + 5L) / 5L;
	y = 100L * y + j;
	if (m < 10)
		m += 2;
	else {
		m -= 10;
		++y;
	}

	tmbuf->tm_year = y - 1900;
	tmbuf->tm_mon = m;
	tmbuf->tm_mday = d;

	tmbuf->tm_yday = d + moffset[m];
	if (m > 1 && ((y) % 4 == 0 && ((y) % 100 != 0 || (y) % 400 == 0)))
		tmbuf->tm_yday++;
}

#else

/* This is adapted from glibc */
/* Copyright (C) 1991, 1993 Free Software Foundation, Inc */

#define SECS_PER_HOUR 3600L
#define SECS_PER_DAY  86400L

#include <time.h>

static const unsigned short int __mon_lengths[2][12] = {
	/* Normal years.  */
	{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
	/* Leap years.  */
	{31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
};
/* This global is exported to the wide world in keeping
 * with the interface in time.h */
long int timezone;


void __tm_conv(tmbuf, t, offset)
struct tm *tmbuf;
time_t *t;
time_t offset;
{
	long days, rem;
	register int y;
	register const unsigned short int *ip;

	timezone = -offset;

	days = *t / SECS_PER_DAY;
	rem = *t % SECS_PER_DAY;
	rem += offset;
	while (rem < 0) {
		rem += SECS_PER_DAY;
		--days;
	}
	while (rem >= SECS_PER_DAY) {
		rem -= SECS_PER_DAY;
		++days;
	}
	tmbuf->tm_hour = rem / SECS_PER_HOUR;
	rem %= SECS_PER_HOUR;
	tmbuf->tm_min = rem / 60;
	tmbuf->tm_sec = rem % 60;
	/* January 1, 1970 was a Thursday.  */
	tmbuf->tm_wday = (4 + days) % 7;
	if (tmbuf->tm_wday < 0)
		tmbuf->tm_wday += 7;
	y = 1970;
	while (days >= (rem = __isleap(y) ? 366 : 365)) {
		++y;
		days -= rem;
	}
	while (days < 0) {
		--y;
		days += __isleap(y) ? 366 : 365;
	}
	tmbuf->tm_year = y - 1900;
	tmbuf->tm_yday = days;
	ip = __mon_lengths[__isleap(y)];
	for (y = 0; days >= ip[y]; ++y)
		days -= ip[y];
	tmbuf->tm_mon = y;
	tmbuf->tm_mday = days + 1;
	tmbuf->tm_isdst = -1;
}

#endif