xref: /original-bsd/lib/libc/gen/ctime.c (revision 6b7db209)
1 /* @(#)ctime.c	4.1 (Berkeley) 12/21/80 */
2 /*
3  * This routine converts time as follows.
4  * The epoch is 0000 Jan 1 1970 GMT.
5  * The argument time is in seconds since then.
6  * The localtime(t) entry returns a pointer to an array
7  * containing
8  *  seconds (0-59)
9  *  minutes (0-59)
10  *  hours (0-23)
11  *  day of month (1-31)
12  *  month (0-11)
13  *  year-1970
14  *  weekday (0-6, Sun is 0)
15  *  day of the year
16  *  daylight savings flag
17  *
18  * The routine calls the system to determine the local
19  * timezone and whether Daylight Saving Time is permitted locally.
20  * (DST is then determined by the current US standard rules)
21  * There is a table that accounts for the peculiarities
22  * undergone by daylight time in 1974-1975.
23  *
24  * The routine does not work
25  * in Saudi Arabia which runs on Solar time.
26  *
27  * asctime(tvec))
28  * where tvec is produced by localtime
29  * returns a ptr to a character string
30  * that has the ascii time in the form
31  *	Thu Jan 01 00:00:00 1970n0\\
32  *	01234567890123456789012345
33  *	0	  1	    2
34  *
35  * ctime(t) just calls localtime, then asctime.
36  */
37 
38 #include <time.h>
39 #include <sys/types.h>
40 #include <sys/timeb.h>
41 
42 static	char	cbuf[26];
43 static	int	dmsize[12] =
44 {
45 	31,
46 	28,
47 	31,
48 	30,
49 	31,
50 	30,
51 	31,
52 	31,
53 	30,
54 	31,
55 	30,
56 	31
57 };
58 
59 /*
60  * The following table is used for 1974 and 1975 and
61  * gives the day number of the first day after the Sunday of the
62  * change.
63  */
64 static struct {
65 	int	daylb;
66 	int	dayle;
67 } daytab[] = {
68 	5,	333,	/* 1974: Jan 6 - last Sun. in Nov */
69 	58,	303,	/* 1975: Last Sun. in Feb - last Sun in Oct */
70 };
71 
72 struct tm	*gmtime();
73 char		*ct_numb();
74 struct tm	*localtime();
75 char	*ctime();
76 char	*ct_num();
77 char	*asctime();
78 
79 char *
80 ctime(t)
81 long *t;
82 {
83 	return(asctime(localtime(t)));
84 }
85 
86 struct tm *
87 localtime(tim)
88 long *tim;
89 {
90 	register int dayno;
91 	register struct tm *ct;
92 	register daylbegin, daylend;
93 	long copyt;
94 	struct timeb systime;
95 
96 	ftime(&systime);
97 	copyt = *tim - (long)systime.timezone*60;
98 	ct = gmtime(&copyt);
99 	dayno = ct->tm_yday;
100 	daylbegin = 119;	/* last Sun in Apr */
101 	daylend = 303;		/* Last Sun in Oct */
102 	if (ct->tm_year==74 || ct->tm_year==75) {
103 		daylbegin = daytab[ct->tm_year-74].daylb;
104 		daylend = daytab[ct->tm_year-74].dayle;
105 	}
106 	daylbegin = sunday(ct, daylbegin);
107 	daylend = sunday(ct, daylend);
108 	if (systime.dstflag &&
109 	    (dayno>daylbegin || (dayno==daylbegin && ct->tm_hour>=2)) &&
110 	    (dayno<daylend || (dayno==daylend && ct->tm_hour<1))) {
111 		copyt += 1*60*60;
112 		ct = gmtime(&copyt);
113 		ct->tm_isdst++;
114 	}
115 	return(ct);
116 }
117 
118 /*
119  * The argument is a 0-origin day number.
120  * The value is the day number of the first
121  * Sunday on or after the day.
122  */
123 static
124 sunday(t, d)
125 register struct tm *t;
126 register int d;
127 {
128 	if (d >= 58)
129 		d += dysize(t->tm_year) - 365;
130 	return(d - (d - t->tm_yday + t->tm_wday + 700) % 7);
131 }
132 
133 struct tm *
134 gmtime(tim)
135 long *tim;
136 {
137 	register int d0, d1;
138 	long hms, day;
139 	register int *tp;
140 	static struct tm xtime;
141 
142 	/*
143 	 * break initial number into days
144 	 */
145 	hms = *tim % 86400;
146 	day = *tim / 86400;
147 	if (hms<0) {
148 		hms += 86400;
149 		day -= 1;
150 	}
151 	tp = (int *)&xtime;
152 
153 	/*
154 	 * generate hours:minutes:seconds
155 	 */
156 	*tp++ = hms%60;
157 	d1 = hms/60;
158 	*tp++ = d1%60;
159 	d1 /= 60;
160 	*tp++ = d1;
161 
162 	/*
163 	 * day is the day number.
164 	 * generate day of the week.
165 	 * The addend is 4 mod 7 (1/1/1970 was Thursday)
166 	 */
167 
168 	xtime.tm_wday = (day+7340036)%7;
169 
170 	/*
171 	 * year number
172 	 */
173 	if (day>=0) for(d1=70; day >= dysize(d1); d1++)
174 		day -= dysize(d1);
175 	else for (d1=70; day<0; d1--)
176 		day += dysize(d1-1);
177 	xtime.tm_year = d1;
178 	xtime.tm_yday = d0 = day;
179 
180 	/*
181 	 * generate month
182 	 */
183 
184 	if (dysize(d1)==366)
185 		dmsize[1] = 29;
186 	for(d1=0; d0 >= dmsize[d1]; d1++)
187 		d0 -= dmsize[d1];
188 	dmsize[1] = 28;
189 	*tp++ = d0+1;
190 	*tp++ = d1;
191 	xtime.tm_isdst = 0;
192 	return(&xtime);
193 }
194 
195 char *
196 asctime(t)
197 struct tm *t;
198 {
199 	register char *cp, *ncp;
200 	register int *tp;
201 
202 	cp = cbuf;
203 	for (ncp = "Day Mon 00 00:00:00 1900\n"; *cp++ = *ncp++;);
204 	ncp = &"SunMonTueWedThuFriSat"[3*t->tm_wday];
205 	cp = cbuf;
206 	*cp++ = *ncp++;
207 	*cp++ = *ncp++;
208 	*cp++ = *ncp++;
209 	cp++;
210 	tp = &t->tm_mon;
211 	ncp = &"JanFebMarAprMayJunJulAugSepOctNovDec"[(*tp)*3];
212 	*cp++ = *ncp++;
213 	*cp++ = *ncp++;
214 	*cp++ = *ncp++;
215 	cp = ct_numb(cp, *--tp);
216 	cp = ct_numb(cp, *--tp+100);
217 	cp = ct_numb(cp, *--tp+100);
218 	cp = ct_numb(cp, *--tp+100);
219 	if (t->tm_year>=100) {
220 		cp[1] = '2';
221 		cp[2] = '0';
222 	}
223 	cp += 2;
224 	cp = ct_numb(cp, t->tm_year+100);
225 	return(cbuf);
226 }
227 
228 dysize(y)
229 {
230 	if((y%4) == 0)
231 		return(366);
232 	return(365);
233 }
234 
235 static char *
236 ct_numb(cp, n)
237 register char *cp;
238 {
239 	cp++;
240 	if (n>=10)
241 		*cp++ = (n/10)%10 + '0';
242 	else
243 		*cp++ = ' ';
244 	*cp++ = n%10 + '0';
245 	return(cp);
246 }
247