the window strings is NOT quoted at this point; other cleanups
[unix-history] / usr / src / lib / libc / gen / ctime.c
CommitLineData
b8f253e8
KM
1/*
2 * Copyright (c) 1980 Regents of the University of California.
3 * All rights reserved. The Berkeley software License Agreement
4 * specifies the terms and conditions for redistribution.
5 */
6
2ce81398
DS
7#if defined(LIBC_SCCS) && !defined(lint)
8static char sccsid[] = "@(#)ctime.c 5.5 (Berkeley) %G%";
9#endif LIBC_SCCS and not lint
b8f253e8 10
674afc9d
BJ
11/*
12 * This routine converts time as follows.
13 * The epoch is 0000 Jan 1 1970 GMT.
14 * The argument time is in seconds since then.
15 * The localtime(t) entry returns a pointer to an array
16 * containing
17 * seconds (0-59)
18 * minutes (0-59)
19 * hours (0-23)
20 * day of month (1-31)
21 * month (0-11)
22 * year-1970
23 * weekday (0-6, Sun is 0)
24 * day of the year
25 * daylight savings flag
26 *
27 * The routine calls the system to determine the local
28 * timezone and whether Daylight Saving Time is permitted locally.
7f253f66 29 * (DST is then determined by the current local rules)
674afc9d
BJ
30 *
31 * The routine does not work
32 * in Saudi Arabia which runs on Solar time.
33 *
34 * asctime(tvec))
35 * where tvec is produced by localtime
36 * returns a ptr to a character string
37 * that has the ascii time in the form
2169a56f
RC
38 * Thu Jan 01 00:00:00 1970\n\0
39 * 0123456789012345678901234 5
674afc9d
BJ
40 * 0 1 2
41 *
42 * ctime(t) just calls localtime, then asctime.
43 */
44
455b164d 45#include <sys/time.h>
674afc9d
BJ
46#include <sys/types.h>
47#include <sys/timeb.h>
48
49static char cbuf[26];
50static int dmsize[12] =
51{
52 31,
53 28,
54 31,
55 30,
56 31,
57 30,
58 31,
59 31,
60 30,
61 31,
62 30,
63 31
64};
65
66/*
67 * The following table is used for 1974 and 1975 and
68 * gives the day number of the first day after the Sunday of the
69 * change.
70 */
bdea7503
SL
71struct dstab {
72 int dayyr;
674afc9d
BJ
73 int daylb;
74 int dayle;
bdea7503
SL
75};
76
77static struct dstab usdaytab[] = {
78 1974, 5, 333, /* 1974: Jan 6 - last Sun. in Nov */
79 1975, 58, 303, /* 1975: Last Sun. in Feb - last Sun in Oct */
80 0, 119, 303, /* all other years: end Apr - end Oct */
81};
82static struct dstab ausdaytab[] = {
83 1970, 400, 0, /* 1970: no daylight saving at all */
84 1971, 303, 0, /* 1971: daylight saving from Oct 31 */
85 1972, 303, 58, /* 1972: Jan 1 -> Feb 27 & Oct 31 -> dec 31 */
86 0, 303, 65, /* others: -> Mar 7, Oct 31 -> */
87};
88
7f253f66
SL
89/*
90 * The European tables ... based on hearsay
91 * Believed correct for:
4e884c92 92 * WE: Great Britain, Portugal?
7f253f66
SL
93 * ME: Belgium, Luxembourg, Netherlands, Denmark, Norway,
94 * Austria, Poland, Czechoslovakia, Sweden, Switzerland,
95 * DDR, DBR, France, Spain, Hungary, Italy, Jugoslavia
4e884c92 96 * Finland (EE timezone, but ME dst rules)
7f253f66 97 * Eastern European dst is unknown, we'll make it ME until someone speaks up.
4e884c92
RE
98 * EE: Bulgaria, Greece, Rumania, Turkey, Western Russia
99 *
100 * Ireland is unpredictable. (Years when Easter Sunday just happens ...)
101 * Years before 1983 are suspect.
7f253f66
SL
102 */
103static struct dstab wedaytab[] = {
4e884c92
RE
104 1983, 89, 296, /* 1983: end March - end Oct */
105 0, 89, 303, /* others: end March - end Oct */
7f253f66
SL
106};
107
108static struct dstab medaytab[] = {
4e884c92
RE
109 1983, 89, 296, /* 1983: end March - end Oct */
110 0, 89, 272, /* others: end March - end Sep */
111};
112
113/*
114 * Canada, same as the US, except no early 70's fluctuations.
115 * Can this really be right ??
116 */
117static struct dstab candaytab[] = {
118 0, 119, 303, /* all years: end Apr - end Oct */
7f253f66
SL
119};
120
bdea7503
SL
121static struct dayrules {
122 int dst_type; /* number obtained from system */
123 int dst_hrs; /* hours to add when dst on */
124 struct dstab * dst_rules; /* one of the above */
125 enum {STH,NTH} dst_hemi; /* southern, northern hemisphere */
126} dayrules [] = {
127 DST_USA, 1, usdaytab, NTH,
128 DST_AUST, 1, ausdaytab, STH,
7f253f66
SL
129 DST_WET, 1, wedaytab, NTH,
130 DST_MET, 1, medaytab, NTH,
131 DST_EET, 1, medaytab, NTH, /* XXX */
4e884c92 132 DST_CAN, 1, candaytab, NTH,
bdea7503 133 -1,
674afc9d
BJ
134};
135
136struct tm *gmtime();
137char *ct_numb();
138struct tm *localtime();
139char *ctime();
140char *ct_num();
141char *asctime();
142
143char *
144ctime(t)
2169a56f 145time_t *t;
674afc9d
BJ
146{
147 return(asctime(localtime(t)));
148}
149
150struct tm *
151localtime(tim)
2169a56f 152time_t *tim;
674afc9d
BJ
153{
154 register int dayno;
155 register struct tm *ct;
bdea7503
SL
156 register dalybeg, daylend;
157 register struct dayrules *dr;
158 register struct dstab *ds;
159 int year;
2169a56f 160 time_t copyt;
bdea7503 161 struct timeval curtime;
3d0f8b49
JB
162 static struct timezone zone;
163 static int init = 0;
674afc9d 164
3d0f8b49
JB
165 if (!init) {
166 gettimeofday(&curtime, &zone);
167 init++;
168 }
2169a56f 169 copyt = *tim - (time_t)zone.tz_minuteswest*60;
674afc9d
BJ
170 ct = gmtime(&copyt);
171 dayno = ct->tm_yday;
bdea7503
SL
172 for (dr = dayrules; dr->dst_type >= 0; dr++)
173 if (dr->dst_type == zone.tz_dsttime)
174 break;
175 if (dr->dst_type >= 0) {
176 year = ct->tm_year + 1900;
177 for (ds = dr->dst_rules; ds->dayyr; ds++)
178 if (ds->dayyr == year)
179 break;
180 dalybeg = ds->daylb; /* first Sun after dst starts */
181 daylend = ds->dayle; /* first Sun after dst ends */
182 dalybeg = sunday(ct, dalybeg);
183 daylend = sunday(ct, daylend);
184 switch (dr->dst_hemi) {
185 case NTH:
186 if (!(
187 (dayno>dalybeg || (dayno==dalybeg && ct->tm_hour>=2)) &&
188 (dayno<daylend || (dayno==daylend && ct->tm_hour<1))
189 ))
190 return(ct);
191 break;
192 case STH:
193 if (!(
194 (dayno>dalybeg || (dayno==dalybeg && ct->tm_hour>=2)) ||
195 (dayno<daylend || (dayno==daylend && ct->tm_hour<2))
196 ))
197 return(ct);
198 break;
199 default:
200 return(ct);
201 }
202 copyt += dr->dst_hrs*60*60;
674afc9d
BJ
203 ct = gmtime(&copyt);
204 ct->tm_isdst++;
205 }
206 return(ct);
207}
208
209/*
210 * The argument is a 0-origin day number.
83b7f1ba 211 * The value is the day number of the last
4e884c92 212 * Sunday on or before the day.
674afc9d
BJ
213 */
214static
215sunday(t, d)
216register struct tm *t;
217register int d;
218{
219 if (d >= 58)
220 d += dysize(t->tm_year) - 365;
221 return(d - (d - t->tm_yday + t->tm_wday + 700) % 7);
222}
223
224struct tm *
225gmtime(tim)
2169a56f 226time_t *tim;
674afc9d
BJ
227{
228 register int d0, d1;
2b5f753c 229 long hms, day;
674afc9d
BJ
230 register int *tp;
231 static struct tm xtime;
232
233 /*
234 * break initial number into days
235 */
236 hms = *tim % 86400;
237 day = *tim / 86400;
238 if (hms<0) {
239 hms += 86400;
240 day -= 1;
241 }
242 tp = (int *)&xtime;
243
244 /*
245 * generate hours:minutes:seconds
246 */
247 *tp++ = hms%60;
248 d1 = hms/60;
249 *tp++ = d1%60;
250 d1 /= 60;
251 *tp++ = d1;
252
253 /*
254 * day is the day number.
255 * generate day of the week.
256 * The addend is 4 mod 7 (1/1/1970 was Thursday)
257 */
258
259 xtime.tm_wday = (day+7340036)%7;
260
261 /*
262 * year number
263 */
264 if (day>=0) for(d1=70; day >= dysize(d1); d1++)
265 day -= dysize(d1);
266 else for (d1=70; day<0; d1--)
267 day += dysize(d1-1);
268 xtime.tm_year = d1;
269 xtime.tm_yday = d0 = day;
270
271 /*
272 * generate month
273 */
274
275 if (dysize(d1)==366)
276 dmsize[1] = 29;
277 for(d1=0; d0 >= dmsize[d1]; d1++)
278 d0 -= dmsize[d1];
279 dmsize[1] = 28;
280 *tp++ = d0+1;
281 *tp++ = d1;
282 xtime.tm_isdst = 0;
283 return(&xtime);
284}
285
286char *
287asctime(t)
288struct tm *t;
289{
290 register char *cp, *ncp;
291 register int *tp;
292
293 cp = cbuf;
294 for (ncp = "Day Mon 00 00:00:00 1900\n"; *cp++ = *ncp++;);
295 ncp = &"SunMonTueWedThuFriSat"[3*t->tm_wday];
296 cp = cbuf;
297 *cp++ = *ncp++;
298 *cp++ = *ncp++;
299 *cp++ = *ncp++;
300 cp++;
301 tp = &t->tm_mon;
302 ncp = &"JanFebMarAprMayJunJulAugSepOctNovDec"[(*tp)*3];
303 *cp++ = *ncp++;
304 *cp++ = *ncp++;
305 *cp++ = *ncp++;
306 cp = ct_numb(cp, *--tp);
307 cp = ct_numb(cp, *--tp+100);
308 cp = ct_numb(cp, *--tp+100);
309 cp = ct_numb(cp, *--tp+100);
310 if (t->tm_year>=100) {
311 cp[1] = '2';
2169a56f 312 cp[2] = '0' + (t->tm_year-100) / 100;
674afc9d
BJ
313 }
314 cp += 2;
315 cp = ct_numb(cp, t->tm_year+100);
316 return(cbuf);
317}
318
319dysize(y)
320{
321 if((y%4) == 0)
322 return(366);
323 return(365);
324}
325
326static char *
327ct_numb(cp, n)
328register char *cp;
329{
330 cp++;
331 if (n>=10)
332 *cp++ = (n/10)%10 + '0';
333 else
334 *cp++ = ' ';
335 *cp++ = n%10 + '0';
336 return(cp);
337}