1 | /*
|
---|
2 | =============================================================================
|
---|
3 | lctime.c -- a Unix(tm)-like time and date package
|
---|
4 | Version 1 -- 1988-01-14 -- D.N. Lynx Crowe
|
---|
5 |
|
---|
6 | These are similar in function to the Unix functions, but are
|
---|
7 | able to be used in re-entrant code.
|
---|
8 | =============================================================================
|
---|
9 | */
|
---|
10 |
|
---|
11 | #include "stddefs.h"
|
---|
12 | #include "time.h"
|
---|
13 |
|
---|
14 | #define void int /* define to handle lack of 'void's */
|
---|
15 |
|
---|
16 | #define HASENV 0 /* non-zero if getenv() is available */
|
---|
17 |
|
---|
18 | #if HASENV
|
---|
19 | extern char *getenv();
|
---|
20 | #endif
|
---|
21 |
|
---|
22 | long timezn = 8*60*60; /* PST offset from GMT */
|
---|
23 | int daylite = 1; /* daylight savings time = ON */
|
---|
24 | char *ltzname[] = {"PST", "PDT"};
|
---|
25 |
|
---|
26 | /*
|
---|
27 | =============================================================================
|
---|
28 | These routines convert time as follows:
|
---|
29 |
|
---|
30 | The epoch is 0000 Jan 1 1970 GMT.
|
---|
31 | The argument time is in seconds since then.
|
---|
32 |
|
---|
33 | struct tm *
|
---|
34 | lcltime(tim, tmsp)
|
---|
35 | long *tim;
|
---|
36 | struct tm *tmsp;
|
---|
37 |
|
---|
38 | returns a pointer to a filled in structure containing:
|
---|
39 |
|
---|
40 | tm_sec seconds (0..59)
|
---|
41 | tm_min minutes (0..59)
|
---|
42 | tm_hour hours (0..23)
|
---|
43 | tm_mday day of month (1..31)
|
---|
44 | tm_mon month (0..11)
|
---|
45 | tm_year year - 1900
|
---|
46 | tm_wday weekday (0..6, Sun is 0)
|
---|
47 | tm_yday day of the year
|
---|
48 | tm_dst daylight savings time flag
|
---|
49 |
|
---|
50 | The routine corrects for daylight savings time and will work in
|
---|
51 | any time zone provided "timezn" is adjusted to the difference
|
---|
52 | between Greenwich and local standard time (measured in seconds).
|
---|
53 |
|
---|
54 | In places like Michigan "daylite" must be initialized to 0
|
---|
55 | to prevent the conversion to daylight time.
|
---|
56 |
|
---|
57 | There is a table which accounts for the peculiarities
|
---|
58 | undergone by daylight savings time in 1974-1975.
|
---|
59 |
|
---|
60 | The routine does not work in Saudi Arabia,
|
---|
61 | which runs on Solar time.
|
---|
62 |
|
---|
63 | char *
|
---|
64 | latime(t, cbuf)
|
---|
65 | struct tm *t;
|
---|
66 | char *cbuf;
|
---|
67 |
|
---|
68 | Where t is produced by lcltime(), and cbuf points to a
|
---|
69 | character string of at least 26 bytes.
|
---|
70 |
|
---|
71 | Fills in a character string with the ascii time in the form:
|
---|
72 |
|
---|
73 | Thu Jan 01 00:00:00 1970\n\0
|
---|
74 | 012345678901234567890123
|
---|
75 | 0 1 2
|
---|
76 |
|
---|
77 | The string is terminated with a new-line and a zero byte.
|
---|
78 |
|
---|
79 | struct tm *
|
---|
80 | lgmtime(tim, xtime)
|
---|
81 | long *tim;
|
---|
82 | struct tm *xtime;
|
---|
83 |
|
---|
84 | Fills in a tm structure with GMT and returns a pointer to it.
|
---|
85 |
|
---|
86 | char *
|
---|
87 | lctime(t, tmsp, cbuf)
|
---|
88 | long *t;
|
---|
89 | struct tm *tmsp;
|
---|
90 | char *cbuf;
|
---|
91 |
|
---|
92 | Fills in a tm structure and a character string with the
|
---|
93 | current local time.
|
---|
94 |
|
---|
95 | void
|
---|
96 | ltzset()
|
---|
97 |
|
---|
98 | Looks for an environment variable named TZ.
|
---|
99 |
|
---|
100 | It should be in the form "ESTn" or "ESTnEDT",
|
---|
101 | where "n" represents a string of digits with an optional
|
---|
102 | negative sign (for locations east of Greenwich, England).
|
---|
103 |
|
---|
104 | If the variable is present, it will set the external
|
---|
105 | variables "timezn", "daylite", and "ltzname"
|
---|
106 | appropriately. It is called by lcltime(), and
|
---|
107 | may also be called explicitly by the user.
|
---|
108 | =============================================================================
|
---|
109 | */
|
---|
110 |
|
---|
111 | /* |
---|
112 | */
|
---|
113 |
|
---|
114 | #define dysize(A) (((A) % 4) ? 365 : 366)
|
---|
115 |
|
---|
116 | static int xdmsize[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
|
---|
117 |
|
---|
118 | /*
|
---|
119 | Daylight savings time change table:
|
---|
120 |
|
---|
121 | The following table is used for 1974 and 1975 and gives the day number
|
---|
122 | of the first day after the Sunday of the change.
|
---|
123 | */
|
---|
124 |
|
---|
125 | static struct {
|
---|
126 |
|
---|
127 | int daylb;
|
---|
128 | int dayle;
|
---|
129 |
|
---|
130 | } daytab[] = {
|
---|
131 |
|
---|
132 | 5, 333, /* 1974: Jan 6 - last Sun. in Nov */
|
---|
133 | 58, 303, /* 1975: Last Sun. in Feb - last Sun in Oct */
|
---|
134 | };
|
---|
135 |
|
---|
136 | /* |
---|
137 | */
|
---|
138 |
|
---|
139 | /*
|
---|
140 | =============================================================================
|
---|
141 | ct_numb(cp, n) -- convert n to a 2 character string at cp (RJBF)
|
---|
142 | =============================================================================
|
---|
143 | */
|
---|
144 |
|
---|
145 | static char *
|
---|
146 | ct_numb(cp, n)
|
---|
147 | register char *cp;
|
---|
148 | int n;
|
---|
149 | {
|
---|
150 | cp++;
|
---|
151 |
|
---|
152 | if (n GE 10)
|
---|
153 | *cp++ = (n / 10) % 10 + '0';
|
---|
154 | else
|
---|
155 | *cp++ = ' ';
|
---|
156 |
|
---|
157 | *cp++ = n % 10 + '0';
|
---|
158 |
|
---|
159 | return(cp);
|
---|
160 | }
|
---|
161 |
|
---|
162 | /* |
---|
163 | */
|
---|
164 |
|
---|
165 | /*
|
---|
166 | =============================================================================
|
---|
167 | sunday(t, d)
|
---|
168 |
|
---|
169 | The argument d is a 0-origin day number.
|
---|
170 | The value is the day number of the first Sunday on or after the day.
|
---|
171 | =============================================================================
|
---|
172 | */
|
---|
173 |
|
---|
174 | static
|
---|
175 | int
|
---|
176 | sunday(t, d)
|
---|
177 | register struct tm *t;
|
---|
178 | register int d;
|
---|
179 | {
|
---|
180 | if (d GE 58)
|
---|
181 | d += dysize(t->tm_year) - 365;
|
---|
182 |
|
---|
183 | return(d - (d - t->tm_yday + t->tm_wday + 700) % 7);
|
---|
184 | }
|
---|
185 |
|
---|
186 | /* |
---|
187 | */
|
---|
188 |
|
---|
189 | /*
|
---|
190 | =============================================================================
|
---|
191 | ltzset() -- set time variables based on TZ environment variable
|
---|
192 | =============================================================================
|
---|
193 | */
|
---|
194 |
|
---|
195 | void
|
---|
196 | ltzset()
|
---|
197 | {
|
---|
198 | register char *p, *q;
|
---|
199 | register int n;
|
---|
200 | int sign;
|
---|
201 |
|
---|
202 | #if HASENV
|
---|
203 |
|
---|
204 | if ((p = getenv("TZ")) AND *p) {
|
---|
205 |
|
---|
206 | n = 3;
|
---|
207 | q = ltzname[0];
|
---|
208 |
|
---|
209 | do {
|
---|
210 |
|
---|
211 | *q++ = *p ? *p++ : ' ';
|
---|
212 |
|
---|
213 | } while (--n);
|
---|
214 |
|
---|
215 | if (sign = *p EQ '-')
|
---|
216 | p++;
|
---|
217 |
|
---|
218 | n = 0;
|
---|
219 |
|
---|
220 | while (*p GE '0' AND *p LE '9')
|
---|
221 | n = (n * 10) + *p++ - '0';
|
---|
222 |
|
---|
223 | if (sign)
|
---|
224 | n = -n;
|
---|
225 |
|
---|
226 | timezn = ((long)(n * 60)) * 60;
|
---|
227 |
|
---|
228 | if (daylite = *p NE '\0') {
|
---|
229 |
|
---|
230 | q = ltzname[1];
|
---|
231 | n = 3;
|
---|
232 |
|
---|
233 | do {
|
---|
234 |
|
---|
235 | *q++ = *p ? *p++ : ' ';
|
---|
236 |
|
---|
237 | } while (--n);
|
---|
238 | }
|
---|
239 | }
|
---|
240 |
|
---|
241 | #endif
|
---|
242 | }
|
---|
243 |
|
---|
244 | /* |
---|
245 | */
|
---|
246 |
|
---|
247 | /*
|
---|
248 | =============================================================================
|
---|
249 | lgmtime(tim, xtime) -- get Greenwich Mean Time from system time
|
---|
250 | =============================================================================
|
---|
251 | */
|
---|
252 |
|
---|
253 | struct tm *
|
---|
254 | lgmtime(tim, xtime)
|
---|
255 | register long *tim;
|
---|
256 | register struct tm *xtime;
|
---|
257 | {
|
---|
258 | register int d0, d1, i;
|
---|
259 | register long hms, day;
|
---|
260 | int dmsize[12];
|
---|
261 |
|
---|
262 | /* break initial number into days */
|
---|
263 |
|
---|
264 | hms = *tim % 86400L;
|
---|
265 | day = *tim / 86400L;
|
---|
266 |
|
---|
267 | if (hms < 0) {
|
---|
268 |
|
---|
269 | hms += 86400L;
|
---|
270 | day -= 1;
|
---|
271 | }
|
---|
272 |
|
---|
273 | /* generate hours:minutes:seconds */
|
---|
274 |
|
---|
275 | xtime->tm_sec = hms % 60;
|
---|
276 | d1 = hms / 60;
|
---|
277 | xtime->tm_min = d1 % 60;
|
---|
278 | d1 /= 60;
|
---|
279 | xtime->tm_hour = d1;
|
---|
280 |
|
---|
281 | /*
|
---|
282 | day is the day number.
|
---|
283 | generate day of the week.
|
---|
284 | The addend is 4 mod 7 (1/1/1970 was Thursday)
|
---|
285 | */
|
---|
286 |
|
---|
287 | xtime->tm_wday = (day + 7340036L) % 7;
|
---|
288 |
|
---|
289 | /* year number */
|
---|
290 |
|
---|
291 | if (day GE 0)
|
---|
292 | for (d1 = 70; day GE dysize(d1); d1++)
|
---|
293 | day -= dysize(d1);
|
---|
294 | else
|
---|
295 | for (d1 = 70; day < 0; d1--)
|
---|
296 | day += dysize(d1 - 1);
|
---|
297 |
|
---|
298 | xtime->tm_year = d1;
|
---|
299 | xtime->tm_yday = d0 = day;
|
---|
300 |
|
---|
301 | /* generate month */
|
---|
302 |
|
---|
303 | for (i = 0; i < 12; i++)
|
---|
304 | xdmsize[i] = dmsize[i];
|
---|
305 |
|
---|
306 | if (dysize(d1) EQ 366)
|
---|
307 | xdmsize[1] = 29;
|
---|
308 | else
|
---|
309 | xdmsize[1] = 28;
|
---|
310 |
|
---|
311 | for (d1 = 0; d0 GE xdmsize[d1]; d1++)
|
---|
312 | d0 -= xdmsize[d1];
|
---|
313 |
|
---|
314 | xtime->tm_mday = d0+1;
|
---|
315 | xtime->tm_mon = d1;
|
---|
316 | xtime->tm_dst = 0;
|
---|
317 |
|
---|
318 | return(xtime);
|
---|
319 | }
|
---|
320 |
|
---|
321 | /* |
---|
322 | */
|
---|
323 |
|
---|
324 | /*
|
---|
325 | =============================================================================
|
---|
326 | lcltime(tim, tmsp) -- get local time from system time
|
---|
327 | =============================================================================
|
---|
328 | */
|
---|
329 |
|
---|
330 | struct tm *
|
---|
331 | lcltime(tim, tmsp)
|
---|
332 | long *tim;
|
---|
333 | struct tm *tmsp;
|
---|
334 | {
|
---|
335 | register int dayno, daylbgn, daylend;
|
---|
336 | int daylbtm, dayletm;
|
---|
337 | register struct tm *ct;
|
---|
338 | long copyt;
|
---|
339 |
|
---|
340 | ltzset();
|
---|
341 | copyt = *tim - timezn;
|
---|
342 | ct = lgmtime(©t, tmsp);
|
---|
343 |
|
---|
344 | dayno = ct->tm_yday;
|
---|
345 |
|
---|
346 | daylbgn = 119; /* Last Sun in Apr */
|
---|
347 | daylend = 303; /* Last Sun in Oct */
|
---|
348 | daylbtm = 2; /* 02:00 */
|
---|
349 | dayletm = 1; /* 01:00 */
|
---|
350 |
|
---|
351 | if (ct->tm_year EQ 74 OR ct->tm_year EQ 75) {
|
---|
352 |
|
---|
353 | daylbgn = daytab[ct->tm_year-74].daylb;
|
---|
354 | daylend = daytab[ct->tm_year-74].dayle;
|
---|
355 | }
|
---|
356 |
|
---|
357 | if (ct->tm_year EQ 88) {
|
---|
358 |
|
---|
359 | /* NOTE: this will need to accomodate the change
|
---|
360 | to the first sunday in Apr in 1988 */
|
---|
361 |
|
---|
362 | dayletm = 2;
|
---|
363 | }
|
---|
364 |
|
---|
365 | daylbgn = sunday(ct, daylbgn);
|
---|
366 | daylend = sunday(ct, daylend);
|
---|
367 |
|
---|
368 | if (daylite AND
|
---|
369 | (dayno > daylbgn OR (dayno EQ daylbgn AND ct->tm_hour GE daylbtm)) AND
|
---|
370 | (dayno < daylend OR (dayno EQ daylend AND ct->tm_hour < dayletm))) {
|
---|
371 |
|
---|
372 | copyt += 1 * 60 * 60;
|
---|
373 | ct = lgmtime(©t, tmsp);
|
---|
374 | ct->tm_dst++;
|
---|
375 | }
|
---|
376 |
|
---|
377 | return(ct);
|
---|
378 | }
|
---|
379 |
|
---|
380 | /* |
---|
381 | */
|
---|
382 |
|
---|
383 | /*
|
---|
384 | =============================================================================
|
---|
385 | latime(t, cbuf) -- convert a tm structure to an ASCII string
|
---|
386 | =============================================================================
|
---|
387 | */
|
---|
388 |
|
---|
389 | char *
|
---|
390 | latime(t, cbuf)
|
---|
391 | struct tm *t;
|
---|
392 | char *cbuf;
|
---|
393 | {
|
---|
394 | register char *cp, *ncp;
|
---|
395 | register int *tp;
|
---|
396 |
|
---|
397 | cp = cbuf;
|
---|
398 |
|
---|
399 | for (ncp = "Day Mon 00 00:00:00 1900\n"; *cp++ = *ncp++; );
|
---|
400 |
|
---|
401 | ncp = &"SunMonTueWedThuFriSat"[3 * t->tm_wday];
|
---|
402 | cp = cbuf;
|
---|
403 | *cp++ = *ncp++;
|
---|
404 | *cp++ = *ncp++;
|
---|
405 | *cp++ = *ncp++;
|
---|
406 | cp++;
|
---|
407 | tp = &t->tm_mon;
|
---|
408 | ncp = &"JanFebMarAprMayJunJulAugSepOctNovDec"[(*tp) * 3];
|
---|
409 | *cp++ = *ncp++;
|
---|
410 | *cp++ = *ncp++;
|
---|
411 | *cp++ = *ncp++;
|
---|
412 | cp = ct_numb(cp, *--tp);
|
---|
413 | cp = ct_numb(cp, *--tp + 100);
|
---|
414 | cp = ct_numb(cp, *--tp + 100);
|
---|
415 | cp = ct_numb(cp, *--tp + 100);
|
---|
416 |
|
---|
417 | if (t->tm_year GE 100) {
|
---|
418 |
|
---|
419 | cp[1] = '2';
|
---|
420 | cp[2] = '0';
|
---|
421 | }
|
---|
422 |
|
---|
423 | cp += 2;
|
---|
424 | cp = ct_numb(cp, t->tm_year + 100);
|
---|
425 |
|
---|
426 | return(cbuf);
|
---|
427 | }
|
---|
428 |
|
---|
429 | /* |
---|
430 | */
|
---|
431 |
|
---|
432 | /*
|
---|
433 | =============================================================================
|
---|
434 | lctime() -- get the current time as a tm structure and an ASCII string
|
---|
435 | =============================================================================
|
---|
436 | */
|
---|
437 |
|
---|
438 | char *
|
---|
439 | lctime(t, tmsp, cbuf)
|
---|
440 | long *t;
|
---|
441 | struct tm *tmsp;
|
---|
442 | char *cbuf;
|
---|
443 | {
|
---|
444 | return(latime(lcltime(t, tmsp), cbuf));
|
---|
445 | }
|
---|