source: trunk/third/nmh/zotnet/tws/dtime.c @ 12455

Revision 12455, 9.9 KB checked in by danw, 26 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r12454, which included commits to RCS files with non-trunk default branches.
Line 
1
2/*
3 * dtime.c -- time/date routines
4 *
5 * $Id: dtime.c,v 1.1.1.1 1999-02-07 18:14:11 danw Exp $
6 */
7
8#include <h/nmh.h>
9#include <tws.h>
10
11#if !defined(HAVE_TM_GMTOFF) && !defined(HAVE_TZSET)
12# include <sys/timeb.h>
13#endif
14
15#ifdef TIME_WITH_SYS_TIME
16# include <sys/time.h>
17# include <time.h>
18#else
19# ifdef HAVE_SYS_TIME_H
20# include <sys/time.h>
21# else
22#  include <time.h>
23# endif
24#endif
25
26#if !defined(HAVE_TM_GMTOFF) && defined(HAVE_TZSET)
27extern int daylight;
28extern long timezone;
29extern char *tzname[];
30#endif
31
32#ifndef abs
33# define abs(a) (a >= 0 ? a : -a)
34#endif
35
36/*
37 * The number of days in the year, accounting for leap years
38 */
39#define dysize(y)       \
40        (((y) % 4) ? 365 : (((y) % 100) ? 366 : (((y) % 400) ? 365 : 366)))
41
42char *tw_moty[] = {
43    "Jan", "Feb", "Mar", "Apr",
44    "May", "Jun", "Jul", "Aug",
45    "Sep", "Oct", "Nov", "Dec",
46    NULL
47};
48
49char *tw_dotw[] = {
50    "Sun", "Mon", "Tue",
51    "Wed", "Thu", "Fri",
52    "Sat", NULL
53};
54
55char *tw_ldotw[] = {
56    "Sunday",    "Monday",   "Tuesday",
57    "Wednesday", "Thursday", "Friday",
58    "Saturday",  NULL
59};
60
61struct zone {
62    char *std;
63    char *dst;
64    int shift;
65};
66
67static struct zone zones[] = {
68    { "GMT", "BST", 0 },
69    { "EST", "EDT", -5 },
70    { "CST", "CDT", -6 },
71    { "MST", "MDT", -7 },
72    { "PST", "PDT", -8 },
73#if 0
74/* RFC1123 specifies do not use military TZs */
75    { "A", NULL, -1 },
76    { "B", NULL, -2 },
77    { "C", NULL, -3 },
78    { "D", NULL, -4 },
79    { "E", NULL, -5 },
80    { "F", NULL, -6 },
81    { "G", NULL, -7 },
82    { "H", NULL, -8 },
83    { "I", NULL, -9 },
84    { "K", NULL, -10 },
85    { "L", NULL, -11 },
86    { "M", NULL, -12 },
87    { "N", NULL, 1 },
88#ifndef HUJI
89    { "O", NULL, 2 },
90#else
91    { "JST", "JDT", 2 },
92#endif
93    { "P", NULL, 3 },
94    { "Q", NULL, 4 },
95    { "R", NULL, 5 },
96    { "S", NULL, 6 },
97    { "T", NULL, 7 },
98    { "U", NULL, 8 },
99    { "V", NULL, 9 },
100    { "W", NULL, 10 },
101    { "X", NULL, 11 },
102    { "Y", NULL, 12 },
103#endif
104    { NULL, NULL, 0 }
105};
106
107static int dmsize[] = {
108    31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
109};
110
111
112/*
113 * Get current time (adjusted for local time
114 * zone and daylight savings time) expressed
115 * as nmh "broken-down" time structure.
116 */
117
118struct tws *
119dlocaltimenow (void)
120{
121    time_t clock;
122
123    time (&clock);
124    return dlocaltime (&clock);
125}
126
127
128/*
129 * Take clock value and return pointer to nmh time structure
130 * containing "broken-down" time.  The time is adjusted for
131 * local time zone and daylight savings time.
132 */
133
134struct tws *
135dlocaltime (time_t *clock)
136{
137    static struct tws tw;
138    struct tm *tm;
139
140#if !defined(HAVE_TM_GMTOFF) && !defined(HAVE_TZSET)
141    struct timeb tb;
142#endif
143
144    if (!clock)
145        return NULL;
146
147    tm = localtime (clock);
148
149    tw.tw_sec  = tm->tm_sec;
150    tw.tw_min  = tm->tm_min;
151    tw.tw_hour = tm->tm_hour;
152    tw.tw_mday = tm->tm_mday;
153    tw.tw_mon  = tm->tm_mon;
154
155    /*
156     * tm_year is always "year - 1900".
157     * So we correct for this.
158     */
159    tw.tw_year = tm->tm_year + 1900;
160    tw.tw_wday = tm->tm_wday;
161    tw.tw_yday = tm->tm_yday;
162
163    tw.tw_flags = TW_NULL;
164    if (tm->tm_isdst)
165        tw.tw_flags |= TW_DST;
166
167#ifdef HAVE_TM_GMTOFF
168    tw.tw_zone = tm->tm_gmtoff / 60;
169    if (tm->tm_isdst)                   /* if DST is in effect */
170        tw.tw_zone -= 60;               /* reset to normal offset */
171#else
172# ifdef HAVE_TZSET
173    tzset();
174    tw.tw_zone = -(timezone / 60);
175# else
176    ftime (&tb);
177    tw.tw_zone = -tb.timezone;
178# endif
179#endif
180
181    tw.tw_flags &= ~TW_SDAY;
182    tw.tw_flags |= TW_SEXP;
183    tw.tw_flags &= ~TW_SZONE;
184    tw.tw_flags |= TW_SZEXP;
185
186    tw.tw_clock = *clock;
187
188    return (&tw);
189}
190
191
192/*
193 * Take clock value and return pointer to nmh time
194 * structure containing "broken-down" time.  Time is
195 * expressed in UTC (Coordinated Universal Time).
196 */
197
198struct tws *
199dgmtime (time_t *clock)
200{
201    static struct tws tw;
202    struct tm *tm;
203
204    if (!clock)
205        return NULL;
206
207    tm = gmtime (clock);
208
209    tw.tw_sec  = tm->tm_sec;
210    tw.tw_min  = tm->tm_min;
211    tw.tw_hour = tm->tm_hour;
212    tw.tw_mday = tm->tm_mday;
213    tw.tw_mon  = tm->tm_mon;
214
215    /*
216     * tm_year is always "year - 1900"
217     * So we correct for this.
218     */
219    tw.tw_year = tm->tm_year + 1900;
220    tw.tw_wday = tm->tm_wday;
221    tw.tw_yday = tm->tm_yday;
222
223    tw.tw_flags = TW_NULL;
224    if (tm->tm_isdst)
225        tw.tw_flags |= TW_DST;
226
227    tw.tw_zone = 0;
228
229    tw.tw_flags &= ~TW_SDAY;
230    tw.tw_flags |= TW_SEXP;
231    tw.tw_flags &= ~TW_SZONE;
232    tw.tw_flags |= TW_SZEXP;
233
234    tw.tw_clock = *clock;
235
236    return (&tw);
237}
238
239
240/*
241 * Using a nmh "broken-down" time structure,
242 * produce a 26-byte date/time string, such as
243 *
244 *      Tue Jan 14 17:49:03 1992\n\0
245 */
246
247char *
248dctime (struct tws *tw)
249{
250    static char buffer[25];
251
252    if (!tw)
253        return NULL;
254
255    snprintf (buffer, sizeof(buffer), "%.3s %.3s %02d %02d:%02d:%02d %.4d\n",
256            tw_dotw[tw->tw_wday], tw_moty[tw->tw_mon], tw->tw_mday,
257            tw->tw_hour, tw->tw_min, tw->tw_sec,
258            tw->tw_year < 100 ? tw->tw_year + 1900 : tw->tw_year);
259
260    return buffer;
261}
262
263
264/*
265 * Produce a date/time string of the form
266 *
267 *      Mon, 16 Jun 1992 15:30:48 -700 (or)
268 *      Mon, 16 Jun 1992 15:30:48 EDT
269 *
270 * for the current time, as specified by rfc822.
271 * The first form is required by rfc1123.
272 */
273
274char *
275dtimenow (int alpha_timezone)
276{
277    time_t clock;
278
279    time (&clock);
280    return dtime (&clock, alpha_timezone);
281}
282
283
284/*
285 * Using a local calendar time value, produce
286 * a date/time string of the form
287 *
288 *      Mon, 16 Jun 1992 15:30:48 -700  (or)
289 *      Mon, 16 Jun 1992 15:30:48 EDT
290 *
291 * as specified by rfc822.  The first form is required
292 * by rfc1123 for outgoing messages.
293 */
294
295char *
296dtime (time_t *clock, int alpha_timezone)
297{
298    if (alpha_timezone)
299        /* use alpha-numeric timezones */
300        return dasctime (dlocaltime (clock), TW_NULL);
301    else
302        /* use numeric timezones */
303        return dasctime (dlocaltime (clock), TW_ZONE);
304}
305
306
307/*
308 * Using a nmh "broken-down" time structure, produce
309 * a date/time string of the form
310 *
311 *      Mon, 16 Jun 1992 15:30:48 -0700
312 *
313 * as specified by rfc822 and rfc1123.
314 */
315
316char *
317dasctime (struct tws *tw, int flags)
318{
319    char buffer[80];
320    static char result[80];
321
322    if (!tw)
323        return NULL;
324
325    /* Display timezone if known */
326    if ((tw->tw_flags & TW_SZONE) == TW_SZNIL)
327        result[0] = '\0';
328    else
329        snprintf(result, sizeof(result), " %s", dtimezone(tw->tw_zone, tw->tw_flags | flags));
330
331    snprintf(buffer, sizeof(buffer), "%02d %s %0*d %02d:%02d:%02d%s",
332            tw->tw_mday, tw_moty[tw->tw_mon],
333            tw->tw_year < 100 ? 2 : 4, tw->tw_year,
334            tw->tw_hour, tw->tw_min, tw->tw_sec, result);
335
336    if ((tw->tw_flags & TW_SDAY) == TW_SEXP)
337        snprintf (result, sizeof(result), "%s, %s", tw_dotw[tw->tw_wday], buffer);
338    else
339        if ((tw->tw_flags & TW_SDAY) == TW_SNIL)
340            strncpy (result, buffer, sizeof(result));
341        else
342            snprintf (result, sizeof(result), "%s (%s)", buffer, tw_dotw[tw->tw_wday]);
343
344    return result;
345}
346
347
348/*
349 * Get the timezone for given offset
350 */
351
352char *
353dtimezone (int offset, int flags)
354{
355    int hours, mins;
356    struct zone *z;
357    static char buffer[10];
358
359    if (offset < 0) {
360        mins = -((-offset) % 60);
361        hours = -((-offset) / 60);
362    } else {
363        mins = offset % 60;
364        hours = offset / 60;
365    }
366
367    if (!(flags & TW_ZONE) && mins == 0) {
368#if defined(HAVE_TZSET) && defined(HAVE_TZNAME)
369        tzset();
370        return ((flags & TW_DST) ? tzname[1] : tzname[0]);
371#else
372        for (z = zones; z->std; z++)
373            if (z->shift == hours)
374                return (z->dst && (flags & TW_DST) ? z->dst : z->std);
375#endif
376    }
377
378#if defined(DSTXXX)
379    if (flags & TW_DST)
380        hours += 1;
381#endif /* defined(DSTXXX) */
382    snprintf (buffer, sizeof(buffer), "%s%02d%02d",
383                offset < 0 ? "-" : "+", abs (hours), abs (mins));
384    return buffer;
385}
386
387
388/*
389 * Convert nmh time structure for local "broken-down"
390 * time to calendar time (clock value).  This routine
391 * is based on the gtime() routine written by Steven Shafer
392 * at CMU.  It was forwarded to MTR by Jay Lepreau at Utah-CS.
393 */
394
395time_t
396dmktime (struct tws *tw)
397{
398    int i, sec, min, hour, mday, mon, year;
399    time_t result;
400
401    if (tw->tw_clock != 0)
402        return tw->tw_clock;
403
404    if ((sec = tw->tw_sec) < 0 || sec > 61
405            || (min = tw->tw_min) < 0 || min > 59
406            || (hour = tw->tw_hour) < 0 || hour > 23
407            || (mday = tw->tw_mday) < 1 || mday > 31
408            || (mon = tw->tw_mon + 1) < 1 || mon > 12)
409        return (tw->tw_clock = (time_t) -1);
410
411    year = tw->tw_year;
412
413    result = 0;
414    if (year < 100)
415        year += 1900;
416
417    for (i = 1970; i < year; i++)
418        result += dysize (i);
419    if (dysize (year) == 366 && mon >= 3)
420        result++;
421    while (--mon)
422        result += dmsize[mon - 1];
423    result += mday - 1;
424    result = 24 * result + hour;
425    result = 60 * result + min;
426    result = 60 * result + sec;
427    result -= 60 * tw->tw_zone;
428    if (tw->tw_flags & TW_DST)
429        result -= 60 * 60;
430
431    return (tw->tw_clock = result);
432}
433
434
435/*
436 * Simple calculation of day of the week.  Algorithm
437 * used is Zeller's congruence.  We assume that
438 * if tw->tw_year < 100, then the century = 19.
439 */
440
441void
442set_dotw (struct tws *tw)
443{
444    int month, day, year, century;
445
446    month = tw->tw_mon - 1;
447    day = tw->tw_mday;
448    year = tw->tw_year % 100;
449    century = tw->tw_year < 100 ? 19 : tw->tw_year / 100;
450
451    if (month <= 0) {
452        month += 12;
453        if (--year < 0) {
454            year += 100;
455            century--;
456        }
457    }
458
459    tw->tw_wday =
460        ((26 * month - 2) / 10 + day + year + year / 4
461            - 3 * century / 4 + 1) % 7;
462
463    tw->tw_flags &= ~TW_SDAY, tw->tw_flags |= TW_SIMP;
464}
465
466
467/*
468 * Copy nmh time structure
469 */
470
471void
472twscopy (struct tws *tb, struct tws *tw)
473{
474    *tb = *tw;  /* struct copy */
475
476#if 0
477    tb->tw_sec   = tw->tw_sec;
478    tb->tw_min   = tw->tw_min;
479    tb->tw_hour  = tw->tw_hour;
480    tb->tw_mday  = tw->tw_mday;
481    tb->tw_mon   = tw->tw_mon;
482    tb->tw_year  = tw->tw_year;
483    tb->tw_wday  = tw->tw_wday;
484    tb->tw_yday  = tw->tw_yday;
485    tb->tw_zone  = tw->tw_zone;
486    tb->tw_clock = tw->tw_clock;
487    tb->tw_flags = tw->tw_flags;
488#endif
489}
490
491
492/*
493 * Compare two nmh time structures
494 */
495
496int
497twsort (struct tws *tw1, struct tws *tw2)
498{
499    time_t c1, c2;
500
501    if (tw1->tw_clock == 0)
502        dmktime (tw1);
503    if (tw2->tw_clock == 0)
504        dmktime (tw2);
505
506    return ((c1 = tw1->tw_clock) > (c2 = tw2->tw_clock) ? 1
507            : c1 == c2 ? 0 : -1);
508}
Note: See TracBrowser for help on using the repository browser.