Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
#include <time.h>
2
 
3
/*
4
 * BUG: Doesn't do leap years in full glory,
5
 * or calendar changes. In 2038 the sign bit
6
 * will be needed in time_t, but we say it
7
 * can't be represented.
8
 */
9
static int
10
dysize(int y)
11
{
12
	y += 1900; /* arg is a tm_year, number of years since 1900 */
13
	if((y%4) == 0 && ((y%100) !=0 || (y%400) == 0))
14
		return 366;
15
	return 365;
16
}
17
 
18
static int
19
dmsize(int m, int y)
20
{
21
	static	char	sizes[12] =
22
		{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
23
 
24
	if(m == 1)
25
		return (dysize(y)==366)? 29 : 28;
26
	else
27
		return sizes[m];
28
}
29
 
30
/* Reduce *v to [0, mult), adding 1 to *next for every mult
31
 * subtracted from *v, and return 1 if reduction worked (no overflow)
32
 */
33
static int
34
reduce(int *v, int *next, int mult)
35
{
36
	int oldnext;
37
 
38
	while(*v < 0){
39
		*v += mult;
40
		oldnext = *next;
41
		--*next;
42
		if(!(*next < oldnext))
43
			return 0;
44
	}
45
	while(*v >= mult){
46
		*v -= mult;
47
		oldnext = *next;
48
		++*next;
49
		if(!(*next > oldnext))
50
			return 0;
51
	}
52
	return 1;
53
}
54
 
55
static int
56
jan1(int yr)
57
{
58
	int y, d;
59
 
60
	y = yr+1900;
61
	d = (4+y+(y+3)/4-(y-1701)/100+(y-1601)/400+3)%7;
62
	return d;
63
}
64
 
65
time_t
66
mktime(struct tm *t)
67
{
68
	time_t a;
69
	int i, d;
70
	struct tm *ptm;
71
 
72
	if(!(reduce(&t->tm_sec, &t->tm_min, 60) &&
73
	     reduce(&t->tm_min, &t->tm_hour, 60) &&
74
	     reduce(&t->tm_hour, &t->tm_mday, 24) &&
75
	     reduce(&t->tm_mon, &t->tm_year, 12)))
76
		return -1;
77
	while(t->tm_mday < 1){
78
		if(--t->tm_mon == -1){
79
			t->tm_mon = 11;
80
			t->tm_year--;
81
		}
82
		t->tm_mday += dmsize(t->tm_mon, t->tm_year);
83
	}
84
	while(t->tm_mday > dmsize(t->tm_mon, t->tm_year)){
85
		t->tm_mday -= dmsize(t->tm_mon, t->tm_year);
86
		if(++t->tm_mon == 12){
87
			t->tm_mon = 0;
88
			t->tm_year++;
89
		}
90
	}
91
	a = t->tm_sec + 60*t->tm_min + 3600*t->tm_hour;
92
	t->tm_yday = t->tm_mday-1;
93
	for(i=0; i<t->tm_mon; i++)
94
		t->tm_yday += dmsize(i, t->tm_year);
95
	a += t->tm_yday*86400L;
96
	if(t->tm_year < 70){
97
		for(i=t->tm_year; i<70; i++)
98
			if((a -= dysize(i)*86400L) < 0)
99
				return -1;
100
	}else if(t->tm_year > 70){
101
		for(i=70; i<t->tm_year; i++)
102
			if((a += dysize(i)*86400L) < 0)
103
				return -1;
104
	}
105
	/*
106
	 * Now a is number of seconds past Jan 1 1970.
107
	 * Convert to GMT.
108
	 */
109
	ptm = gmtime(&a);
110
	d = ptm->tm_hour;
111
	ptm = localtime(&a);
112
	d -= ptm->tm_hour;
113
	if(d < 0)
114
		d += 24;
115
	if(t->tm_isdst == 0 && ptm->tm_isdst)
116
		d--;
117
	if(t->tm_isdst > 0 && !ptm->tm_isdst)
118
		d++;
119
	a += d*3600;
120
	t->tm_wday = (jan1(t->tm_year)+t->tm_yday)%7;
121
	return a;
122
}