Added -clobber switch to mhstore(1) [Bug #11160].
[mmh] / docs / historical / mh-6.8.5 / zotnet / tws / phoon / dtime.c
1 /* dtime.c - routines to do ``ARPA-style'' time structures
2
3 ver  date   who remarks
4 --- ------- --- -------------------------------------------------------------
5 01B 15nov86 JP  Thouroughly hacked by Jef Poskanzer.
6 01A ??????? MTR Original version from the MH 6.5 distribution, courtesy
7                   of Marshall Rose.
8
9 */
10
11
12 #include "tws.h"
13 #include <stdio.h>
14 #include <sys/types.h>
15 #include <sys/time.h>
16 #ifdef  SYS5
17 #include <string.h>
18 #else SYS5
19 #include <strings.h>
20 #include <sys/timeb.h>
21 #endif SYS5
22
23 #ifdef  SYS5
24 extern int  daylight;
25 extern long timezone;
26 extern char *tzname[];
27 #endif  SYS5
28
29 /* \f */
30
31 #define abs(a) ( a >= 0 ? a : -a )
32
33 char *tw_moty[] = {
34     "Jan", "Feb", "Mar", "Apr", "May", "Jun",
35     "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", NULL };
36
37 char *tw_dotw[] = {
38     "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", NULL };
39
40 char *tw_ldotw[] = {
41     "Sunday", "Monday", "Tuesday", "Wednesday",
42     "Thursday", "Friday", "Saturday", NULL };
43
44 /* \f */
45
46 static struct zone
47     {
48     char *std;
49     char *dst;
50     int shift;
51     }
52     zones[] = {
53         "GMT", "BST", 0,
54         "EST", "EDT", -5,
55         "CST", "CDT", -6,
56         "MST", NULL, -7,
57         "PST", "PDT", -8,
58         "A", NULL, -1,
59         "B", NULL, -2,
60         "C", NULL, -3,
61         "D", NULL, -4,
62         "E", NULL, -5,
63         "F", NULL, -6,
64         "G", NULL, -7,
65         "H", NULL, -8,
66         "I", NULL, -9,
67         "K", NULL, -10,
68         "L", NULL, -11,
69         "M", NULL, -12,
70         "N", NULL, 1,
71 #ifndef HUJI
72         "O", NULL, 2,
73 #else   HUJI
74         "JST", "JDT", 2,
75 #endif  HUJI
76         "P", NULL, 3,
77         "Q", NULL, 4,
78         "R", NULL, 5,
79         "S", NULL, 6,
80         "T", NULL, 7,
81         "U", NULL, 8,
82         "V", NULL, 9,
83         "W", NULL, 10,
84         "X", NULL, 11,
85         "Y", NULL, 12,
86         NULL };
87
88 #define CENTURY 19
89
90 long time( );
91 struct tm *localtime( );
92
93 /* \f */
94
95 char *dtimenow( )
96     {
97     long clock;
98
99     (void) time( &clock );
100     return ( dtime( &clock ) );
101     }
102
103
104 char *
105 dctime( tw )
106 struct tws *tw;
107     {
108     static char buffer[25];
109
110     if ( tw == NULL )
111         return ( NULL );
112
113     (void) sprintf( buffer, "%.3s %.3s %02d %02d:%02d:%02d %.4d\n",
114             tw_dotw[tw -> tw_wday], tw_moty[tw -> tw_mon], tw -> tw_mday,
115             tw -> tw_hour, tw -> tw_min, tw -> tw_sec,
116             tw -> tw_year >= 100 ? tw -> tw_year : 1900 + tw -> tw_year );
117
118     return ( buffer );
119     }
120
121 /* \f */
122
123 struct tws *
124 dtwstime( )
125     {
126     long clock;
127
128     (void) time( &clock );
129     return ( dlocaltime( &clock ) );
130     }
131
132
133 struct tws *
134 dlocaltime( clock )
135 long *clock;
136     {
137     register struct tm *tm;
138 #ifndef SYS5
139     struct timeb tb;
140 #endif not SYS5
141     static struct tws tw;
142
143     if ( clock == NULL )
144         return ( NULL );
145     tw.tw_flags = TW_NULL;
146
147     tm = localtime( clock );
148     tw.tw_sec = tm -> tm_sec;
149     tw.tw_min = tm -> tm_min;
150     tw.tw_hour = tm -> tm_hour;
151     tw.tw_mday = tm -> tm_mday;
152     tw.tw_mon = tm -> tm_mon;
153     tw.tw_year = tm -> tm_year;
154     tw.tw_wday = tm -> tm_wday;
155     tw.tw_yday = tm -> tm_yday;
156     if ( tm -> tm_isdst )
157         tw.tw_flags |= TW_DST;
158 #ifndef  SYS5
159     ftime( &tb );
160     tw.tw_zone = -tb.timezone;
161 #else   SYS5
162     tzset( );
163     tw.tw_zone = -(timezone / 60);
164 #endif  SYS5
165     tw.tw_flags &= ~TW_SDAY;
166     tw.tw_flags |= TW_SEXP;
167     tw.tw_clock = *clock;
168
169     return ( &tw );
170     }
171
172
173 struct tws *
174 dgmtime( clock )
175 long *clock;
176     {
177     register struct tm *tm;
178     static struct tws tw;
179
180     if ( clock == NULL )
181         return ( NULL );
182     tw.tw_flags = TW_NULL;
183
184     tm = gmtime( clock );
185     tw.tw_sec = tm -> tm_sec;
186     tw.tw_min = tm -> tm_min;
187     tw.tw_hour = tm -> tm_hour;
188     tw.tw_mday = tm -> tm_mday;
189     tw.tw_mon = tm -> tm_mon;
190     tw.tw_year = tm -> tm_year;
191     tw.tw_wday = tm -> tm_wday;
192     tw.tw_yday = tm -> tm_yday;
193     if ( tm -> tm_isdst )
194         tw.tw_flags |= TW_DST;
195     tw.tw_zone = 0;
196     tw.tw_flags &= ~TW_SDAY;
197     tw.tw_flags |= TW_SEXP;
198     tw.tw_clock = *clock;
199
200     return( &tw );
201     }
202
203 /* \f */
204
205 char *
206 dasctime( tw, flags )
207 struct tws *tw;
208 int flags;
209     {
210     static char buffer[80], result[80];
211
212     if ( tw == NULL )
213         return ( NULL );
214
215     (void) sprintf( buffer, "%02d %s %02d %02d:%02d:%02d %s",
216             tw -> tw_mday, tw_moty[tw -> tw_mon], tw -> tw_year,
217             tw -> tw_hour, tw -> tw_min, tw -> tw_sec,
218             dtimezone( tw -> tw_zone, tw -> tw_flags | flags ) );
219
220     if ( (tw -> tw_flags & TW_SDAY) == TW_SEXP )
221         (void) sprintf( result, "%s, %s", tw_dotw[tw -> tw_wday], buffer );
222     else
223         if ( (tw -> tw_flags & TW_SDAY) == TW_SNIL )
224             (void) strcpy( result, buffer );
225         else
226             (void) sprintf( result, "%s (%s)", buffer, tw_dotw[tw -> tw_wday] );
227
228     return ( result );
229     }
230
231 /* \f */
232
233 char *
234 dtimezone( offset, flags )
235 int offset, flags;
236     {
237     register int hours, mins;
238     register struct zone *z;
239     static char buffer[10];
240
241     if ( offset < 0 )
242         {
243         mins = -((-offset) % 60);
244         hours = -((-offset) / 60);
245         }
246     else
247         {
248         mins = offset % 60;
249         hours = offset / 60;
250         }
251
252     if ( !(flags & TW_ZONE) && mins == 0 )
253         for ( z = zones; z -> std; z++ )
254             if ( z -> shift == hours )
255                 return ( z -> dst && (flags & TW_DST) ? z -> dst : z -> std );
256
257 #ifdef  DSTXXX
258     if ( flags & TW_DST )
259         hours += 1;
260 #endif  DSTXXX
261     (void) sprintf( buffer, "%s%02d%02d",
262             offset < 0 ? "-" : "+", abs( hours ), abs( mins ) );
263     return ( buffer );
264     }
265
266 /* \f */
267
268 void
269 twscopy( tb, tw )
270 struct tws *tb, *tw;
271     {
272 #ifdef  notdef
273     tb -> tw_sec = tw -> tw_sec;
274     tb -> tw_min = tw -> tw_min;
275     tb -> tw_hour = tw -> tw_hour;
276     tb -> tw_mday = tw -> tw_mday;
277     tb -> tw_mon = tw -> tw_mon;
278     tb -> tw_year = tw -> tw_year;
279     tb -> tw_wday = tw -> tw_wday;
280     tb -> tw_yday = tw -> tw_yday;
281     tb -> tw_zone = tw -> tw_zone;
282     tb -> tw_clock = tw -> tw_clock;
283     tb -> tw_flags = tw -> tw_flags;
284 #else   not notdef
285     *tb = *tw;
286 #endif  not notdef
287     }
288
289
290 int
291 twsort( tw1, tw2 )
292 struct tws *tw1, *tw2;
293     {
294     register long c1, c2;
295
296     (void) twclock( tw1 );
297     (void) twclock( tw2 );
298
299     return ( (c1 = tw1 -> tw_clock) > (c2 = tw2 -> tw_clock) ? 1
300             : c1 == c2 ? 0 : -1 );
301     }
302
303 /* \f */
304
305
306 /* Julian day number of the Unix clock's origin, 01 Jan 1970. */
307 #define JD1970 2440587L
308
309
310 long
311 twjuliandate( tw )
312 struct tws *tw;
313     {
314     register int mday, mon, year;
315     register long a, b;
316     double jd;
317
318     if ( (mday = tw -> tw_mday) < 1 || mday > 31 ||
319             (mon = tw -> tw_mon + 1) < 1 || mon > 12 ||
320             (year = tw -> tw_year) < 1 || year > 10000 )
321         return ( -1L );
322     if ( year < 100 )
323         year += CENTURY * 100;
324
325     if ( mon == 1 || mon == 2 )
326         {
327         --year;
328         mon += 12;
329         }
330     if ( year < 1583 )
331         return ( -1L );
332     a = year / 100;
333     b = 2 - a + a / 4;
334     b += (long) ( (double) year * 365.25 );
335     b += (long) ( 30.6001 * ( (double) mon + 1.0 ) );
336     jd = mday + b + 1720994.5;
337     return ( (long) jd );
338     }
339
340
341 long
342 twsubdayclock( tw )
343 struct tws *tw;
344     {
345     register int i, sec, min, hour;
346     register long result;
347
348     if ( (sec = tw -> tw_sec) < 0 || sec > 59 ||
349             (min = tw -> tw_min) < 0 || min > 59 ||
350             (hour = tw -> tw_hour) < 0 || hour > 23 )
351         return ( -1L );
352
353     result = ( hour * 60 + min ) * 60 + sec;
354     result -= 60 * tw -> tw_zone;
355     if ( tw -> tw_flags & TW_DST )
356         result -= 60 * 60;
357
358     return ( result );
359     }
360
361
362 long
363 twclock( tw )
364 struct tws *tw;
365     {
366     register long jd, sdc, result;
367
368     if ( tw -> tw_clock != 0L )
369         return ( tw -> tw_clock );
370
371     if ( ( jd = twjuliandate( tw ) ) == -1L )
372         return ( tw -> tw_clock = -1L );
373     if ( ( sdc = twsubdayclock( tw ) ) == -1L )
374         return ( tw -> tw_clock = -1L );
375
376     result = ( jd - JD1970 ) * 24 * 60 * 60 + sdc;
377
378     return ( tw -> tw_clock = result );
379     }
380
381 /* \f */
382
383 /*** twsubtract - subtract tw2 from tw1, returning result in seconds
384
385 The point of this routine is that using twclock( tw1 ) - twclock( tw2 )
386 would limit you to dates after the Unix Epoch ( 01 January 1970 ).  This
387 routine avoids that limit.  However, because the result is represented
388 by 32 bits, it is still limited to a span of two billion seconds, which is
389 about 66 years.
390
391 */
392
393 long
394 twsubtract( tw1, tw2 )
395 struct tws *tw1, *tw2;
396     {
397     register long jd1, jd2, sdc1, sdc2, result;
398
399     if ( ( jd1 = twjuliandate( tw1 ) ) == -1L )
400         return ( 0L );
401     if ( ( sdc1 = twsubdayclock( tw1 ) ) == -1L )
402         return ( 0L );
403
404     if ( ( jd2 = twjuliandate( tw2 ) ) == -1L )
405         return ( 0L );
406     if ( ( sdc2 = twsubdayclock( tw2 ) ) == -1L )
407         return ( 0L );
408     
409     result = ( jd1 - jd2 ) * 24 * 60 * 60 + ( sdc1 - sdc2 );
410
411     return ( result );
412     }
413
414 /* \f */
415
416 /*
417  *    Simple calculation of day of the week.  Algorithm used is Zeller's
418  *    congruence.  Currently, we assume if tw -> tw_year < 100
419  *    then the century is CENTURY.
420  */
421
422 set_dotw( tw )
423 struct tws *tw;
424     {
425     register int month, day, year, century;
426
427     month = tw -> tw_mon - 1;
428     day = tw -> tw_mday;
429     year = tw -> tw_year % 100;
430     century = tw -> tw_year >= 100 ? tw -> tw_year / 100 : CENTURY;
431
432     if ( month <= 0 )
433         {
434         month += 12;
435         if ( --year < 0 )
436             {
437             year += 100;
438             century--;
439             }
440         }
441
442     tw -> tw_wday =
443         ((26 * month - 2) / 10 + day + year + year / 4
444             - 3 * century / 4 + 1) % 7;
445
446     tw -> tw_flags &= ~TW_SDAY;
447     tw -> tw_flags |= TW_SIMP;
448     }