|
|
1.1 root 1: /*
2: * libc/gen/ctime.c
3: * Convert time to ASCII representation.
4: *
5: * Pseudo system-5, employs TIMEZONE environment for gmt offset,
6: * timezone abbreviations, and daylight savings time information.
7: * TIMEZONE=SSS:mmm:DDD:n.d.m:n.d.m:h:m
8: * SSS - Standard timezone abbreviation up to 31 characters long
9: * mmm - minutes west of GMT
10: * DDD - Daylight timezone abbreviation also 31 characters
11: * n.d.m - n'th occurrence of d'th day of week in m'th month of
12: * start and end of daylight savings time. Negative n indicates
13: * counting backwards from end of month. Zero n indicates absolute date,
14: * d'th day of m'th month. Days and months from 1 to n.
15: * h - Hour of change from standard to daylight.
16: * m - Minutes of adjustment at change.
17: * Example - Central standard in current US conventions:
18: * TIMEZONE=CST:3600:CDT:-1.1.4:-1.1.10:2:60
19: * Only the first two fields are required.
20: * If no daylight timezone is specified, then no daylight conversion is done.
21: * If no dates for daylight are given, they default to 83-05-10 US standard.
22: * If no hour of daylight time change is specified, it defaults to 2AM.
23: * If no minutes of adjustment is specified, it defaults to 60.
24: * These defaults can be changed by overwriting tzdstdef[].
25: */
26:
27:
28: #include <time.h>
29: #if 0
30: /* Required for ftime(), now conditionalized out, cf. comments below. */
31: #include <sys/timeb.h>
32: #endif
33:
34: #define FEB 1
35: #define NWDAY 7 /* Number of weekdays */
36: #define NMON 12 /* Number of months */
37: #define todigit(c) ((c)+'0')
38: #define NTZNAME 31 /* max time zone name size */
39:
40: /* Static data. */
41: static char daynames[3*NWDAY+1] = "SunMonTueWedThuFriSat";
42: static char dpm[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
43: static int dstadjust = 60*60; /* In seconds */
44: static char dsthour = 2;
45: static struct dsttimes {
46: char dst_occur, dst_day, dst_month;
47: } dsttimes[2] = {
48: { 1, 0, 3 }, /* First Sunday in April */
49: { -1, 0, 9 } /* Last Sunday in October */
50: };
51: static char months[3*NMON+1] = "JanFebMarAprMayJunJulAugSepOctNovDec";
52: static char timestr[] = "AAA AAA DD DD:DD:DD DDDD\n";
53: static struct tm tm;
54: static char tz0[NTZNAME+1] = "GMT";
55: static char tz1[NTZNAME+1] = "";
56:
57: /* Global data. */
58: long timezone = 0L;
59: char *tzname[2] = { tz0, tz1 };
60: char tzdstdef[] = "1.1.4:-1.1.10:2:60......";
61:
62: /* Set the timezone parameters, once is enough */
63: void
64: settz()
65: {
66: extern char *getenv();
67: register char *cp1, *cp2;
68: static int settz = 0;
69:
70: if (settz++ > 0)
71: return;
72: if ((cp1 = getenv("TIMEZONE")) == ((char *)0))
73: return;
74: timezone = 0;
75:
76: /* Read primary timezone name and nul terminate */
77: cp2 = tzname[0];
78: while (*cp1 && *cp1 != ':' && cp2 < &tzname[0][NTZNAME])
79: *cp2++ = *cp1++;
80: *cp2++ = '\0';
81: while (*cp1 && *cp1++ != ':');
82:
83: /* Read timezone offset and convert to seconds */
84: timezone = (long)atoi(cp1) * 60L;
85: while (*cp1 && *cp1++ != ':');
86:
87: /* Read daylight timezone name and nul terminate */
88: cp2 = tzname[1];
89: while (*cp1 && *cp1 != ':' && cp2 < &tzname[1][NTZNAME])
90: *cp2++ = *cp1++;
91: *cp2++ = '\0';
92: while (*cp1 && *cp1++ != ':');
93:
94: /* Exit if no daylight time */
95: if (tzname[1][0] == '\0')
96: return;
97:
98: /* Set default dst parameters */
99: setdst(tzdstdef);
100:
101: /* Set supplied dst parameters */
102: setdst(cp1);
103: }
104:
105: /* Parse and set dst parameters */
106: static
107: setdst(cp1) register char *cp1;
108: {
109: /* Get optional start of daylight time */
110: if (*cp1) {
111: dsttimes[0].dst_occur = atoi(cp1);
112: while (*cp1 && *cp1++ != '.');
113: dsttimes[0].dst_day = atoi(cp1)-1;
114: while (*cp1 && *cp1++ != '.');
115: dsttimes[0].dst_month = atoi(cp1)-1;
116: while (*cp1 && *cp1++ != ':');
117: }
118:
119: /* Get optional end of daylight time */
120: if (*cp1) {
121: dsttimes[1].dst_occur = atoi(cp1);
122: while (*cp1 && *cp1++ != '.');
123: dsttimes[1].dst_day = atoi(cp1)-1;
124: while (*cp1 && *cp1++ != '.');
125: dsttimes[1].dst_month = atoi(cp1)-1;
126: while (*cp1 && *cp1++ != ':');
127: }
128:
129: /* Get optional hour of daylight time advance */
130: if (*cp1) {
131: dsthour = atoi(cp1);
132: while (*cp1 && *cp1++ != ':');
133: }
134:
135: /* Get optional minutes of adjustment */
136: if (*cp1)
137: dstadjust = atoi(cp1) * 60;
138: }
139:
140: #if 0
141: /*
142: * This ftime() is not required for COH 4.0.1r78 or later,
143: * it is now a system call using the stub generated by sys/i386/scall.s5.
144: */
145: /*
146: * ftime()
147: */
148: ftime (tb) struct timeb *tb;
149: {
150: time_t t;
151:
152: tb->time = time(&t);
153: settz();
154: localtime(&t);
155: tb->millitm = 0;
156: tb->timezone = (short)(timezone / 60L);
157: tb->dstflag = isdaylight();
158: }
159: #endif
160:
161: /*
162: * Most common interface, returns a static string
163: * which is a printable version of the time and date.
164: */
165: char *
166: ctime(tp)
167: long *tp;
168: {
169: return asctime(localtime(tp));
170: }
171:
172: /*
173: * Do what gmtime does for the local timezone.
174: * And correct for daylight time.
175: */
176: struct tm *
177: localtime(tp)
178: long *tp;
179: {
180: long ltime;
181:
182: settz();
183: ltime = *tp - timezone;
184: gmtime(<ime);
185:
186: /*
187: * If necessary, adjust for daylight saving time.
188: */
189: if (isdaylight()) {
190: ltime = *tp - timezone + dstadjust;
191: gmtime(<ime);
192: tm.tm_isdst = 1;
193: } else
194: tm.tm_isdst = 0;
195: return &tm;
196: }
197:
198: /*
199: * Returns a printable version of the time
200: * which has been broken down as in the tm structure.
201: */
202: char *
203: asctime(tmp)
204: struct tm *tmp;
205: {
206: register char *cp, *xp;
207: register unsigned i;
208:
209: cp = timestr;
210: /*
211: * Day of week
212: */
213: if ((i = tmp->tm_wday) >= NWDAY)
214: i = 0;
215: xp = &daynames[i*3];
216: *cp++ = *xp++;
217: *cp++ = *xp++;
218: *cp++ = *xp++;
219: *cp++ = ' ';
220: /*
221: * Month
222: */
223: if ((i = tmp->tm_mon) >= NMON)
224: i = 0;
225: xp = &months[i*3];
226: *cp++ = *xp++;
227: *cp++ = *xp++;
228: *cp++ = *xp++;
229: *cp++ = ' ';
230: /*
231: * Day of month
232: */
233: if ((i = tmp->tm_mday) >= 10)
234: *cp++ = todigit(i/10);
235: else
236: *cp++ = ' ';
237: *cp++ = todigit(i%10);
238: *cp++ = ' ';
239: /*
240: * Hours:mins:seconds
241: */
242: *cp++ = todigit((i = tmp->tm_hour)/10);
243: *cp++ = todigit(i%10);
244: *cp++ = ':';
245: *cp++ = todigit((i = tmp->tm_min)/10);
246: *cp++ = todigit(i%10);
247: *cp++ = ':';
248: *cp++ = todigit((i = tmp->tm_sec)/10);
249: *cp++ = todigit(i%10);
250: *cp++ = ' ';
251: /*
252: * Year
253: */
254: i = tmp->tm_year + 1900;
255: *cp++ = todigit(i/1000);
256: i = i%1000;
257: *cp++ = todigit(i/100);
258: i = i%100;
259: *cp++ = todigit(i/10);
260: *cp++ = todigit(i%10);
261: *cp++ = '\n';
262: *cp++ = '\0';
263: return timestr;
264: }
265:
266: /*
267: * Do conversions for Greenwich Mean Time to
268: * the tm structure.
269: */
270: struct tm *
271: gmtime(tp)
272: long *tp;
273: {
274: long xtime;
275: unsigned days;
276: long secs;
277: int year;
278: int ydays;
279: int wday;
280: register char *mp;
281:
282: if ((xtime = *tp) < 0)
283: xtime = 0;
284: days = xtime/(60L*60L*24L);
285: secs = xtime%(60L*60L*24L);
286: tm.tm_hour = secs/(60L*60L);
287: secs = secs%(60L*60L);
288: tm.tm_min = secs/60;
289: tm.tm_sec = secs%60;
290: /*
291: * Start at Thursday (wday=4) Jan 1, 1970 (the Epoch)
292: * and calculate from there.
293: */
294: wday = (4+days)%NWDAY;
295: year = 1970;
296: for (;;) {
297: ydays = isleap(year) ? 366 : 365;
298: if (days < ydays)
299: break;
300: year++;
301: days -= ydays;
302: }
303: tm.tm_year = year-1900;
304: tm.tm_yday = days;
305: tm.tm_wday = wday;
306: /*
307: * Setup february's #days now.
308: */
309: if (isleap(year))
310: dpm[FEB] = 29;
311: else
312: dpm[FEB] = 28;
313: for (mp = &dpm[0]; mp < &dpm[NMON] && days >= *mp; mp++)
314: days -= *mp;
315: tm.tm_mon = mp-dpm;
316: tm.tm_mday = days+1;
317: return &tm;
318: }
319:
320: /*
321: * Return 1 on leap years; 0 otherwise.
322: */
323: static
324: isleap(yr)
325: register yr;
326: {
327: if (yr%4000 == 0)
328: return 0;
329: return (yr%400==0 || (yr%100!=0 && yr%4==0));
330: }
331:
332: /*
333: * Check for daylight savings time.
334: * Watch out for the Southern Hemisphere, where start month > end month.
335: * This does not do the case where start == end correctly for all cases.
336: */
337: static
338: isdaylight()
339: {
340: register int month, start, end, xday;
341:
342: if (tzname[1][0] == 0)
343: return 0; /* No name, no daylight time */
344: month = tm.tm_mon;
345: start = dsttimes[0].dst_month;
346: end = dsttimes[1].dst_month;
347: if ((start <= end && (month < start || month > end))
348: || (start > end && (month < start && month > end)))
349: return 0; /* current month is never DST */
350: else if (month == start) { /* DST starts this month */
351: xday = nthday(&dsttimes[0]); /* DST starts on xday */
352: if (tm.tm_mday != xday)
353: return (tm.tm_mday > xday);
354: return (tm.tm_hour >= dsthour);
355: } else if (month == end) { /* DST ends this month */
356: xday = nthday(&dsttimes[1]); /* DST ends on xday */
357: if (tm.tm_mday != xday)
358: return (tm.tm_mday < xday);
359: return (tm.tm_hour < dsthour-1);
360: } else
361: return 1; /* current month is always DST */
362: }
363:
364: static
365: nthday(dp)
366: register struct dsttimes *dp;
367: {
368: register int nthday;
369: register int nth;
370:
371: if ((nth = dp->dst_occur) == 0)
372: return dp->dst_day;
373: nthday = tm.tm_mday - tm.tm_wday + dp->dst_day;
374: if (nth > 0) {
375: while (nthday > 0)
376: nthday -= 7;
377: do
378: nthday += 7;
379: while (--nth > 0);
380: } else {
381: while (nthday < dpm[tm.tm_mon])
382: nthday += 7;
383: do
384: nthday -= 7;
385: while (++nth < 0);
386: }
387: return nthday;
388: }
389:
390: /* end of ctime.c */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.