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