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