1 /*  File: timesubs.c
2  *  Author: Richard Durbin (rd@mrc-lmb.cam.ac.uk)
3  *  Copyright (C) J Thierry-Mieg and R Durbin, 1991
4  *-------------------------------------------------------------------
5  * This file is part of the ACEDB genome database package, written by
6  * 	Richard Durbin (MRC LMB, UK) rd@mrc-lmb.cam.ac.uk, and
7  *	Jean Thierry-Mieg (CRBM du CNRS, France) mieg@kaa.cnrs-mop.fr
8  *
9  * Description: functions to handle times/dates
10 
11    * mieg, mars 94: timeParse/timeShow
12       this pair of functions is to be used in conjunction
13       with the _DateType fundamental type which can
14       now be used in the same way as _Int _Float in models.wrm
15 
16  * HISTORY:
17  * Last edited: Nov 27 13:19 1998 (fw)
18  * * Jul  9 17:23 1998 (fw): added timeComparison() function for < , = and > operators
19  * * Jul  8 15:49 1998 (fw): added timeDiff functions for mins,hours,months,years
20                              as required by the new AQL date-functions
21  * * Jan 29 22:31 1995 (rd): allow "today"  like "now", for day only
22  * * Nov 13 19:04 1994 (rd): allow date abbreviations, and rename
23  	consistently, and removed timeStamp, dateStamp
24  * * Jun 21 17:12 1992 (mieg): changed : to _ in time stamped
25    : was preventing the file chooser from reading in a dump file
26  * * Jan 20 10:46 1992 (mieg): Fixed  timeStamp, dateStamp
27     and removed everything else with an ifdef
28  * Created: a long time ago
29  *-------------------------------------------------------------------
30  */
31 
32 /* $Id: timesubs.c,v 1.1 2002/11/14 20:00:06 lstein Exp $ */
33 
34 #include "regular.h"
35 #include "mytime.h"
36 #include <time.h>
37 
38 /*
39 ----------------------------------------------------------------------
40 Time string formats
41 1994-07-17_20:16:11     -- dumped and read
42 now                     -- replaced with current date and time
43 today                   -- replaced with current date only
44 94-07-17_20:16:11       -- interpreted as 1994-07-17_20:16:11
45 
46 any left abbreviation of the above, e.g. 94-07-17, or 94-07 is also
47 read, and when dumping any trailing 0 fields are ommitted.
48 
49 the _ is optional, can be one blank
50 
51 How to deal with timezones:
52 
53 The internal time is always in GMT (Greenwich Mean Time) (an
54 alias for GMT is UTC (Coordinated Universal Time)).
55 
56 For the external format I could not find a notation which shows
57 the local time and is easly convertable into internal time again on
58 every computer.
59 
60 Therefore I left out the timezone information from the external format.
61 I leave it to the user what he wants:
62 While working locally or exchanging data within one timezone, there
63 is no fuss at all.
64 When transfering data across the ocean with the wish to keep the time
65 accurate, one can use this scheme:
66 
67 1. in Montpellier:
68    csh                 // opening an extra shell saves the environment
69    setenv TZ GMT
70    start xace/tace and dump into file.ace
71    transfer file
72    exit                // back in local timezone
73 2. in Berkeley:
74    csh
75    setenv TZ GMT
76    use xace/tace to read file.ace
77    exit
78    start xace          // dates displayed will be correctly converted
79 
80 What about putting a comment to the dump file giving the value
81 of the Environment variable TZ at the time the dump was done?
82 
83 ----------------------------------------------------------------------
84   written by  D.Wolf@dkfz-heidelberg.de  Thu May  5 17:39:54 MDT 1994
85   tested ok on
86   OSF1  V1.3 111 alpha
87   IRIX  4.0.5F 08280217 IP12
88   SunOS 5.3 Generic sun4c sparc (Solaris)
89   SunOS 4.1.2 2 sun4c with gcc version 2.3.3
90   -- does not compile with /usr/ucb/cc on SunOS 4.1.2
91 */
92 
93 
aceTime(struct tm * tm,BOOL wantMonth,BOOL wantDay,BOOL wantHours,BOOL wantMins,BOOL wantSecs)94 static mytime_t aceTime(struct tm *tm,
95 			BOOL wantMonth, BOOL wantDay, BOOL wantHours,
96 			BOOL wantMins, BOOL wantSecs)
97 {
98   mytime_t t = 0;
99 
100   if (tm->tm_year < 91) /* use timeless format */
101     {
102       t |= tm->tm_year << 9;
103       if (wantMonth)
104 	t |= (tm->tm_mon + 1) << 5;
105       if (wantDay)
106 	t |= tm->tm_mday;
107     }
108   else
109     {
110       if (wantSecs)
111 	t |= 1 + tm->tm_sec;
112 
113       if (wantMins)
114 	t |= (tm->tm_min + 1) << 6;
115 
116       if (wantHours)
117 	t |= (tm->tm_hour + 1) << 12;
118 
119       if (wantDay)
120 	t |= tm->tm_mday << 17;
121 
122       if (wantMonth)
123 	t |= (tm->tm_mon + 1) << 22;
124 
125       t |= (tm->tm_year - 90) << 26;
126     }
127   return t;
128 }
129 
timeStruct(struct tm * tm,mytime_t t,BOOL * wantMonth,BOOL * wantDay,BOOL * wantHours,BOOL * wantMins,BOOL * wantSecs)130 static void timeStruct(struct tm *tm, mytime_t t,
131 		BOOL *wantMonth, BOOL *wantDay, BOOL *wantHours,
132 		BOOL *wantMins, BOOL *wantSecs)
133 {
134   unsigned int secs;
135   unsigned int mins;
136   unsigned int hours;
137   unsigned int day;
138   unsigned int month;
139   unsigned int year;
140 
141   if (!t)
142     {
143       /* fprintf (stderr, "timeStruct() warning: received null t\n"); */
144       tm->tm_year = 0;
145       tm->tm_mon = 0;
146       tm->tm_mday = 0;
147       tm->tm_hour = 0;
148       tm->tm_min = 0;
149       tm->tm_sec = 0;
150       tm->tm_wday = 0;
151       tm->tm_yday = 0;
152       tm->tm_isdst = -1;
153       return;
154     }
155 
156   secs = t & 0x3f;
157   mins = (t >> 6) & 0x3f;
158   hours = (t >> 12) & 0x1f;
159   day = (t >> 17) & 0x1f;
160   month = ( t >> 22) & 0xf;
161   year = ( t >> 26) &0x3f;
162 
163   if (year == 0) /* before 1990, use time-less format. */
164     {
165       secs = mins = hours = 0;
166       day = t & 0x1f;
167       month = (t >> 5) & 0x0f;
168       year = (t >> 9) & 0x7f;
169     }
170   else
171     year += 90;
172 
173   tm->tm_year = year;
174 
175   if (month == 0)
176     { *wantMonth  = FALSE;
177       tm->tm_mon = 0;
178     }
179   else
180     { *wantMonth = TRUE;
181       tm->tm_mon = month - 1;
182     }
183 
184   if (day == 0)
185     { *wantDay = FALSE;
186       tm->tm_mday = 1;
187     }
188   else
189     { *wantDay = TRUE;
190       tm->tm_mday = day;
191     }
192 
193   if (hours == 0)
194     { *wantHours = FALSE;
195       tm->tm_hour = 0;
196     }
197   else
198     { *wantHours = TRUE;
199       tm->tm_hour = hours - 1;
200     }
201 
202   if (mins == 0)
203     { *wantMins = FALSE;
204       tm->tm_min = 0;
205     }
206   else
207     { *wantMins = TRUE;
208       tm->tm_min = mins - 1;
209     }
210 
211   if (secs == 0)
212     { *wantSecs = FALSE;
213       tm->tm_sec = 0;
214     }
215   else
216     { *wantSecs = TRUE;
217       tm->tm_sec = secs -1;
218     }
219   tm->tm_isdst = -1;
220 
221   /*
222    * strftime() was crashing under various circumstances.  These
223    * lines force tm to be internally consistent - LS 2/17/98
224    */
225   tm->tm_wday = tm->tm_yday = 0;
226   mktime(tm); /* mhmp 21.10.98 */
227 }
228 
timeNow(void)229 mytime_t timeNow(void)
230 {
231   time_t t = time(0);
232   return aceTime(localtime(&t), TRUE, TRUE, TRUE, TRUE, TRUE);
233 }
234 
timeParse(char * ace_time)235 mytime_t timeParse (char *ace_time)
236 {
237   struct tm ts ;
238   char *cp = ace_time;
239   int v, n ;    /* number of chars read so far */
240   BOOL wantSecs = FALSE, wantDay = FALSE, wantMonth = FALSE;
241   BOOL wantMins = FALSE, wantHours = FALSE;
242   if (!cp)
243     return 0 ;
244 
245   if (!strcmp (cp, "now"))
246     { time_t t = time(0);
247       return aceTime(localtime(&t), TRUE, TRUE, TRUE, TRUE, TRUE);
248     }
249 
250   if (!strcmp (cp, "today"))
251     { time_t t = time(0) ;
252       return aceTime(localtime (&t), TRUE, TRUE, FALSE, FALSE, FALSE);
253     }
254 
255   if ((v = sscanf (cp, "%d%n", &ts.tm_year, &n)) != 1)
256     return 0;
257   if (ts.tm_year > 2053)
258     return 0;
259   cp += n ;
260   if ((v = sscanf (cp, "-%d%n", &ts.tm_mon, &n)) != 1)
261     goto done ;
262   if (ts.tm_mon > 12 || ts.tm_mon < 1)
263     return 0;
264   wantMonth = TRUE;
265   cp += n ;
266   if ((v = sscanf (cp, "-%d%n", &ts.tm_mday, &n)) != 1)
267     goto done ;
268   if (ts.tm_mday > 31)
269     return 0;
270   wantDay = TRUE;
271   cp += n ;
272   if (*cp == 0)
273     goto done ;
274   if (*cp != '_' && *cp != ' ') /* separator */
275     return 0;
276   ++cp ;
277   if ((v = sscanf (cp, "%d%n", &ts.tm_hour, &n)) != 1)
278     goto done ;
279   if (ts.tm_hour > 23)
280     return 0;
281   wantHours = TRUE;
282   ts.tm_min = 0;
283   ts.tm_sec = 0;
284   cp += n ;
285   if ((v = sscanf (cp, ":%d%n", &ts.tm_min, &n)) != 1)
286     goto done ;
287   if (ts.tm_min > 59)
288     return 0;
289   wantMins = TRUE;
290   cp += n ;
291   if ((v = sscanf (cp, ":%d%n", &ts.tm_sec, &n)) != 1)
292     goto done ;
293   if (ts.tm_sec > 59)
294     return 0;
295   wantSecs = TRUE;
296   cp += n ;
297 
298  done:
299   if (*cp) return 0;	/* incomplete */
300 
301   if (ts.tm_year < 1900)	/* convert into 4 digit-year */
302     { if (ts.tm_year > 50)
303 	ts.tm_year += 1900 ;
304       else
305 	ts.tm_year += 2000 ;
306     }
307 
308   ts.tm_year -= 1900 ;
309   ts.tm_mon-- ;			/* January is 0 */
310 
311   return aceTime(&ts, wantMonth, wantDay, wantHours, wantMins, wantSecs) ;
312 }
313 
314 /**********************************************/
315 
timeShowJava(mytime_t t)316 char *timeShowJava (mytime_t t)
317 {
318   static char ace_time[25] ;
319   struct tm ts;
320   BOOL wantMonth, wantDay, wantHours, wantMins, wantSecs;
321 
322 
323   if (!t)
324     {
325       /*   fprintf(stderr, "timeShowJava() warning: received NULL value\n"); */
326       return "" ;
327     }
328 
329   timeStruct(&ts, t, &wantMonth, &wantDay, &wantHours, &wantMins, &wantSecs);
330   if (!wantMonth)
331     strftime (ace_time, 25, "01 JAN %Y 00:00:00", &ts) ;
332   else if (!wantDay)
333     strftime (ace_time, 25, "01 %b %Y 00:00:00", &ts) ;
334   else if (!wantHours)
335     strftime (ace_time, 25, "%d %b %Y 00:00:00", &ts) ;
336   else if (!wantMins)
337     strftime(ace_time, 25, "%d %b %Y %H:00:00", &ts);
338   else if (!wantSecs)
339     strftime (ace_time, 25, "%d %b %Y %R:00", &ts);
340   else
341     strftime (ace_time, 25, "%d %b %Y %T", &ts) ;
342 
343   return ace_time ;
344 }
345 
346 /**********************************************/
347 
timeShow(mytime_t t)348 char *timeShow (mytime_t t)
349 {
350   static char ace_time[25] ;
351   struct tm ts;
352   BOOL wantMonth, wantDay, wantHours, wantMins, wantSecs;
353 
354   if (!t)
355     {
356       /*   fprintf(stderr, "timeShow() warning: received NULL value\n"); */
357       return "" ;
358     }
359 
360   timeStruct(&ts, t, &wantMonth, &wantDay, &wantHours, &wantMins, &wantSecs);
361   if (!wantMonth)
362     strftime (ace_time, 25, "%Y", &ts) ;
363   else if (!wantDay)
364     strftime (ace_time, 25, "%Y-%m", &ts) ;
365   else if (!wantHours)
366     strftime (ace_time, 25, "%Y-%m-%d", &ts) ;
367   else if (!wantMins)
368     strftime(ace_time, 25, "%Y-%m-%d_%H", &ts);
369   else if (!wantSecs)
370     strftime (ace_time, 25, "%Y-%m-%d_%R", &ts);
371   else
372     strftime (ace_time, 25, "%Y-%m-%d_%T", &ts) ;
373 
374   return ace_time ;
375 }
376 
377 /**********************************************/
378 
timeDiffSecs(mytime_t t1,mytime_t t2,int * diff)379 BOOL timeDiffSecs (mytime_t t1, mytime_t t2, int *diff)
380 {
381   struct tm ts1, ts2;
382   BOOL wantMonth1, wantDay1, wantHours1, wantMins1, wantSecs1;
383   BOOL wantMonth2, wantDay2, wantHours2, wantMins2, wantSecs2;
384   double d ;
385   time_t tt1, tt2 ;
386   timeStruct (&ts1, t1, &wantMonth1, &wantDay1, &wantHours1, &wantMins1, &wantSecs1) ;
387   timeStruct (&ts2, t2, &wantMonth2, &wantDay2, &wantHours2, &wantMins2, &wantSecs2) ;
388 
389   if (!wantSecs1 || !wantSecs2)
390     return FALSE ;
391   tt1 = mktime (&ts1) ;
392   tt2 = mktime (&ts2) ;
393   d = difftime (tt2, tt1) ;
394   /*  d = difftime (mktime (&ts2), mktime (&ts1)) ;*/
395   *diff = (int)d ;
396   return TRUE ;
397 }
398 
399 /**********************************************/
400 
timeDiffMins(mytime_t t1,mytime_t t2,int * diff)401 BOOL timeDiffMins (mytime_t t1, mytime_t t2, int *diff)
402 {
403   struct tm ts1, ts2;
404   BOOL wantMonth1, wantDay1, wantHours1, wantMins1, wantSecs1;
405   BOOL wantMonth2, wantDay2, wantHours2, wantMins2, wantSecs2;
406   double d;
407 
408   timeStruct (&ts1, t1, &wantMonth1, &wantDay1, &wantHours1, &wantMins1, &wantSecs1) ;
409   timeStruct (&ts2, t2, &wantMonth2, &wantDay2, &wantHours2, &wantMins2, &wantSecs2) ;
410 
411   if (!wantMins1 || !wantMins2)
412     return FALSE ;
413 
414   ts1.tm_sec = ts2.tm_sec = 0 ;
415 
416   d = difftime (mktime (&ts2), mktime (&ts1)) ;
417   d /= 60;
418   *diff = (int)d ;
419 
420   return TRUE ;
421 }
422 
423 /**********************************************/
424 
timeDiffHours(mytime_t t1,mytime_t t2,int * diff)425 BOOL timeDiffHours (mytime_t t1, mytime_t t2, int *diff)
426 {
427   struct tm ts1, ts2;
428   BOOL wantMonth1, wantDay1, wantHours1, wantMins1, wantSecs1;
429   BOOL wantMonth2, wantDay2, wantHours2, wantMins2, wantSecs2;
430   double d;
431 
432   timeStruct (&ts1, t1, &wantMonth1, &wantDay1, &wantHours1, &wantMins1, &wantSecs1) ;
433   timeStruct (&ts2, t2, &wantMonth2, &wantDay2, &wantHours2, &wantMins2, &wantSecs2) ;
434 
435   if (!wantHours1 || !wantHours2)
436     return FALSE ;
437 
438   ts1.tm_sec = ts2.tm_sec = 0 ;
439   ts1.tm_min = ts2.tm_min = 0 ;
440 
441   d = difftime (mktime (&ts2), mktime (&ts1)) ;
442   d /= (60 * 60);
443   *diff = (int)d ;
444 
445   return TRUE ;
446 }
447 
448 /**********************************************/
449 
timeDiffDays(mytime_t t1,mytime_t t2,int * diff)450 BOOL timeDiffDays (mytime_t t1, mytime_t t2, int *diff)
451 {
452   struct tm ts1, ts2;
453   BOOL wantMonth1, wantDay1, wantHours1, wantMins1, wantSecs1;
454   BOOL wantMonth2, wantDay2, wantHours2, wantMins2, wantSecs2;
455   double d ;
456 
457   timeStruct (&ts1, t1, &wantMonth1, &wantDay1, &wantHours1, &wantMins1, &wantSecs1) ;
458   timeStruct (&ts2, t2, &wantMonth2, &wantDay2, &wantHours2, &wantMins2, &wantSecs2) ;
459 
460   if (!wantDay1 || !wantDay2)
461     return FALSE ;
462 
463   ts1.tm_sec = ts2.tm_sec = 0 ;	/* zero hours:mins:secs so get calendar days */
464   ts1.tm_min = ts2.tm_min = 0 ;
465   ts1.tm_hour = ts2.tm_hour = 0 ;
466 
467   d = difftime (mktime (&ts2), mktime (&ts1)) ;
468 
469   d /= (24 * 3600) ;
470   *diff = (int)d ;
471 
472   return TRUE ;
473 }
474 
475 /**********************************************/
476 
timeDiffMonths(mytime_t t1,mytime_t t2,int * diff)477 BOOL timeDiffMonths (mytime_t t1, mytime_t t2, int *diff)
478 {
479   struct tm ts1, ts2;
480   BOOL wantMonth1, wantDay1, wantHours1, wantMins1, wantSecs1;
481   BOOL wantMonth2, wantDay2, wantHours2, wantMins2, wantSecs2;
482   int mdiff;
483 
484   timeStruct (&ts1, t1, &wantMonth1, &wantDay1, &wantHours1, &wantMins1, &wantSecs1) ;
485   timeStruct (&ts2, t2, &wantMonth2, &wantDay2, &wantHours2, &wantMins2, &wantSecs2) ;
486 
487   if (!wantMonth1 || !wantMonth2)
488     return FALSE ;
489 
490   mdiff = ts2.tm_mon - ts1.tm_mon ;
491 
492   *diff = mdiff ;
493 
494   return TRUE ;
495 }
496 
497 /**********************************************/
498 
timeDiffYears(mytime_t t1,mytime_t t2,int * diff)499 BOOL timeDiffYears (mytime_t t1, mytime_t t2, int *diff)
500 /* NOTE: is always true, i.e. every date/time has a year */
501 {
502   struct tm ts1, ts2;
503   BOOL wantMonth1, wantDay1, wantHours1, wantMins1, wantSecs1;
504   BOOL wantMonth2, wantDay2, wantHours2, wantMins2, wantSecs2;
505   int yeardiff;
506 
507   timeStruct (&ts1, t1, &wantMonth1, &wantDay1, &wantHours1, &wantMins1, &wantSecs1) ;
508   timeStruct (&ts2, t2, &wantMonth2, &wantDay2, &wantHours2, &wantMins2, &wantSecs2) ;
509 
510   yeardiff = ts2.tm_year - ts1.tm_year ;
511 
512   *diff = yeardiff ;
513 
514   return TRUE ;
515 }
516 
517 /**********************************************/
518 
519 /* compare two dates, returns boolean result of comparison depending on operator */
timeComparison(int op,mytime_t timeLeft,mytime_t timeRight)520 BOOL timeComparison (int      op,
521 		     mytime_t timeLeft,
522 		     mytime_t timeRight)
523 /* op is the operator and is one of
524    -1 = isLessThan
525     0 = isEqual
526     1 = isGreaterThan
527 
528    times can easily be compared, if they both specify the
529    same level of detail, e.g.
530         1996-03 < 1997-04        -> TRUE
531      1998-06-07 = 1998-06-12     -> FALSE
532 
533    Complications occur, if the level of detail given varies in both dates :-
534 
535         1998-06 < 1998-07-09_09:51:23 -> TRUE
536          the "lessthan" fact is decided on the months
537 
538            1990 = 1990-05-02   -> TRUE
539      in case of equality the comparison asks if the lesser detailed date
540      is completely contained within the other, and the above
541      comparison evaluates TRUE, because May 2nd 1990 is in the year 1990
542 
543          1998-07 < 1998-07-09   -> FALSE
544      because one date gives a specific day in July 1998, but as the
545      first date misses the day, we can't decide whether it is earlier.
546 
547      Example: the movie City Hall was released on 1996-02-16.
548 
549        select m->Title, m->Released from m in class Movie where m->Released < `1996-02
550        select m->Title, m->Released from m in class Movie where m->Released > `1996-02
551 
552      will BOTH EXnclude the movie 'City Hall', whereas
553 
554        select m->Title, m->Released from m in class Movie where m->Released < `1996-02-17
555        select m->Title, m->Released from m in class Movie where m->Released <= `1996-02
556 
557      will both INclude 'City Hall'.
558 */
559 /* mhmp 22.10.98
560 Ici, chaque date,  quel que soit son niveau de detail, est consideree
561 comme un intervalle.
562 1996-05  = [1996-05-01_00:00:00 , 1996-05-31_23:59:59] = INTER
563 date == 1996-05 <==> date appartient a INTER
564 date < 1996-05  <==> date < inf(INTER)
565 
566 Appliquer cette regle aux dates "completees" (avec hms) est discutable.
567 Pour beaucoup,  1998-10-22_11:07 > 1998-10-22_11
568 surtout quand on vient de louper le train de 11h.
569 Cela sous-entend qu'il faudrait completer les dates
570 hms jusqu'a la seconde avec des zeros.
571 1998-10-22_11 -> 1998-10-22_11:00:00
572 */
573 {
574   int yearDiff, monthDiff, dayDiff, hourDiff, minDiff, secDiff;
575 
576   /*******************/
577   /* year difference */
578   timeDiffYears (timeLeft, timeRight, &yearDiff);
579 
580   if (yearDiff > 0)
581     return (op < 0) ;
582 
583   if (yearDiff < 0)
584     return (op > 0) ;
585 
586   /* yearDiff == 0 */
587   /********************/
588   /* month difference */
589   if (!timeDiffMonths (timeLeft, timeRight, &monthDiff))
590     /* can't decide on months */
591     return (op == 0) ;
592 
593   if (monthDiff > 0)
594     return (op < 0) ;
595 
596   if (monthDiff < 0)
597     return  (op > 0) ;
598 
599   /* monthDiff == 0 */
600   /******************/
601   /* day difference */
602   if (!timeDiffDays (timeLeft, timeRight, &dayDiff))
603     /* can't decide on days */
604     return (op == 0) ;
605 
606   if (dayDiff > 0)
607     return (op < 0) ;
608 
609   if (dayDiff < 0)
610     return  (op > 0) ;
611 
612   /* dayDiff == 0 */
613   /*******************/
614   /* hour difference */
615   if (!timeDiffHours (timeLeft, timeRight, &hourDiff))
616     /* can't decide on hours */
617     return (op == 0) ;
618 
619   if (hourDiff > 0)
620     return (op < 0) ;
621 
622   if (hourDiff < 0)
623     return  (op > 0) ;
624 
625   /*  hourDiff == 0 */
626   /*********************/
627   /* minute difference */
628   if (!timeDiffMins (timeLeft, timeRight, &minDiff))
629     /* can't decide on minutes */
630     return (op == 0) ;
631 
632   if (minDiff > 0)
633     return (op < 0) ;
634 
635   if (minDiff < 0)
636     return  (op > 0) ;
637 
638   /* minDiff == 0 */
639   /*********************/
640   /* second difference */
641   if (!timeDiffSecs (timeLeft, timeRight, &secDiff))
642     /* can't decide on seconds */
643     return (op == 0) ;
644 
645   if (secDiff > 0)
646     return (op < 0) ;
647 
648   if (secDiff < 0)
649     return  (op > 0) ;
650 
651   /* secDiff == 0 */
652   /*********************/
653     /* can't decide on 1/10 of second */
654   return (op == 0) ;
655 } /* timeComparison */
656 
657 /*************************************************************/
658 
timeDiffShow(mytime_t t1,mytime_t t2)659 char *timeDiffShow (mytime_t t1, mytime_t t2)
660 {
661   static char buf[25] ;
662   struct tm ts1, ts2;
663   BOOL wantMonth1, wantDay1, wantHours1, wantMins1, wantSecs1;
664   BOOL wantMonth2, wantDay2, wantHours2, wantMins2, wantSecs2;
665   int ydiff, mdiff, ddiff, hdiff, mindiff, sdiff ;
666 
667   if (t2 < t1)
668     { mytime_t temp = t1 ;
669       t1 = t2 ;
670       t2 = temp ;
671       strcpy (buf, "-") ;
672     }
673   else
674     *buf = 0 ;
675 
676   timeStruct(&ts1, t1, &wantMonth1, &wantDay1, &wantHours1, &wantMins1, &wantSecs1);
677   timeStruct(&ts2, t2, &wantMonth2, &wantDay2, &wantHours2, &wantMins2, &wantSecs2);
678 
679   ydiff = ts2.tm_year - ts1.tm_year ;
680   mdiff = ts2.tm_mon - ts1.tm_mon ;
681   hdiff = ts2.tm_hour - ts1.tm_hour ;
682   mindiff = ts2.tm_min - ts1.tm_min ;
683   sdiff = ts2.tm_sec - ts1.tm_sec ;
684 
685   if (wantSecs1 && wantSecs2)
686     { if (sdiff < 0) { sdiff += 60 ; --mindiff ; } }
687   else
688     ts1.tm_sec = ts2.tm_sec = 0 ;
689   if (wantMins1 && wantMins2)
690     { if (mindiff < 0) { mindiff += 60 ; --hdiff ; } }
691   else
692     ts1.tm_min = ts2.tm_min = 0 ;
693   if (wantHours1 && wantHours2)
694     { if (hdiff < 0) { hdiff += 24 ; } }
695   else
696     ts1.tm_hour = ts2.tm_hour = 0 ;
697   if (wantDay1 && wantDay2)
698     {				/* convert months/years to days */
699       double d = difftime (mktime (&ts2), mktime (&ts1)) ;
700       d /= (24 * 3600) ;
701       ddiff = d ;
702       if (!wantHours1 || !wantHours2)
703 	strcat (buf, messprintf ("%d", ddiff)) ;
704       else
705 	{ if (ddiff)
706 	    strcat (buf, messprintf ("%d_", ddiff)) ;
707 	  strcat (buf, messprintf ("%02d:%02d", hdiff, mindiff)) ;
708 	  if (wantSecs1 && wantSecs2)
709 	    strcat (buf, messprintf (":%02d", sdiff)) ;
710 	}
711     }
712   else
713     { if (wantMonth1 && wantMonth2 && mdiff < 0)
714 	{ mdiff += 12 ; --ydiff ; }
715       if (ydiff)
716 	strcat (buf, messprintf ("%d-%02d-0", ydiff, mdiff)) ;
717       else
718 	strcat (buf, messprintf ("%d-0", mdiff)) ;
719     }
720 
721   return buf ;
722 }
723 
724 /***********************************************/
725 
726 /* suz added a more general version to format data strings */
727 
timeShowFormat(mytime_t t,char * format,char * buf,int bufsize)728 char* timeShowFormat (mytime_t t, char *format, char *buf, int bufsize)
729 { BOOL dummy;
730   struct tm ts;
731   timeStruct(&ts, t, &dummy, &dummy, &dummy, &dummy, &dummy);
732 
733   strftime (buf, bufsize, format, &ts) ;
734   return buf ;
735 }
736 
737 /**********************************/
738 /**********************************/
739 
740 
741