1 #include <ctype.h>
2 #include <limits.h>
3 #include <math.h>
4 #include <stdio.h>
5 #include <string.h>
6 #include <stdlib.h>
7 #include <time.h>
8 #include "clock.h"
9 #include "myutil.h"
10 #include "myassert.h"
11 #ifdef MEMWATCH
12 #include "memwatch.h"
13 #endif
14 
15 #include "cpl_port.h"
16 
17 /* Take a look at the options in:
18  * http://www.unet.univie.ac.at/aix/cmds/aixcmds2/date.htm#A270961
19  */
20 /* Timezone is defined through out as the time needed to add to local time
21  * to get UTC, rather than the reverse.  So EST is +5 not -5. */
22 
23 #define PERIOD_YEARS 146097L
24 #define SEC_DAY 86400L
25 #define ISLEAPYEAR(y) (((y)%400 == 0) || (((y)%4 == 0) && ((y)%100 != 0)))
26 
27 /*****************************************************************************
28  * ThirdMonday() --
29  *
30  * Carl McCalla / MDL
31  *
32  * PURPOSE
33  *   Compute the day-of-the-month which is the third Monday of the month.
34  *
35  * ARGUMENTS
36  * monthStartDOW = starting day of the week (e.g., 0 = Sunday, 1 = Monday,
37  *                 etc.) (Input)
38  *
39  * RETURNS
40  *   int (the day-of-the-month which is the third Monday of the month)
41  *
42  * HISTORY
43  *   6/2006 Carl McCalla, Sr. (MDL):  Created
44  *
45  * NOTES
46  * ***************************************************************************
47  */
ThirdMonday(int monthStartDOW)48 static int ThirdMonday (int monthStartDOW)
49 {
50    if (monthStartDOW == 0) {
51       return 16;
52    } else if (monthStartDOW == 1) {
53       return 15;
54    } else {
55       return ((7 - monthStartDOW) + 16);
56    }
57 }
58 
59 /*****************************************************************************
60  * Memorialday() --
61  *
62  * Carl McCalla / MDL
63  *
64  * PURPOSE
65  *   For the month of May, compute the day-of-the-month which is Memorial Day.
66  *
67  * ARGUMENTS
68  * monthStartDOW = starting day of the week (e.g., 0 = Sunday, 1 = Monday,
69  *                 etc.) (Input)
70  *
71  * RETURNS
72  *   int (the day-of-the-month which is Memorial Day)
73  *
74  * HISTORY
75  *   6/2006 Carl McCalla, Sr. (MDL):  Created
76  *
77  * NOTES
78  * ***************************************************************************
79  */
Memorialday(int monthStartDOW)80 static int Memorialday (int monthStartDOW)
81 {
82    if (monthStartDOW == 0) {
83       return 30;
84    } else if (monthStartDOW == 6) {
85       return 31;
86    } else {
87       return ((5 - monthStartDOW) + 25);
88    }
89 }
90 
91 /*****************************************************************************
92  * Laborday() --
93  *
94  * Carl McCalla / MDL
95  *
96  * PURPOSE
97  *   For the month of September, compute the day-of-the-month which is Labor
98  * Day.
99  *
100  * ARGUMENTS
101  * monthStartDOW = starting day of the week (e.g., 0 = Sunday, 1 = Monday,
102  *                 etc.) (Input)
103  *
104  * RETURNS
105  *   int (the day-of-the-month which is Labor Day)
106  *
107  * HISTORY
108  *   6/2006 Carl McCalla, Sr. (MDL):  Created
109  *
110  * NOTES
111  * ***************************************************************************
112  */
Laborday(int monthStartDOW)113 static int Laborday (int monthStartDOW)
114 {
115    if (monthStartDOW == 0) {
116       return 2;
117    } else if (monthStartDOW == 1) {
118       return 1;
119    } else {
120       return ((6 - monthStartDOW) + 3);
121    }
122 }
123 
124 /*****************************************************************************
125  * Columbusday() --
126  *
127  * Carl McCalla /MDL
128  *
129  * PURPOSE
130  *   For the month of October, compute the day-of-the-month which is Columbus
131  * Day.
132  *
133  * ARGUMENTS
134  * monthStartDOW = starting day of the week (e.g., 0 = Sunday, 1 = Monday,
135  *                 etc.) (Input)
136  *
137  * RETURNS
138  *   int (the day-of-the-month which is Columbus Day)
139  *
140  * HISTORY
141  *   6/2006 Carl McCalla, Sr. (MDL):  Created
142  *
143  * NOTES
144  * ***************************************************************************
145  */
Columbusday(int monthStartDOW)146 static int Columbusday (int monthStartDOW)
147 {
148    if ((monthStartDOW == 0) || (monthStartDOW == 1)) {
149       return (9 - monthStartDOW);
150    } else {
151       return (16 - monthStartDOW);
152    }
153 }
154 
155 /*****************************************************************************
156  * Thanksgivingday() --
157  *
158  * Carl McCalla /MDL
159  *
160  * PURPOSE
161  *   For the month of November, compute the day-of-the-month which is
162  * Thanksgiving Day.
163  *
164  * ARGUMENTS
165  * monthStartDOW = starting day of the week (e.g., 0 = Sunday, 1 = Monday,
166  *                 etc.) (Input)
167  *
168  * RETURNS
169  *   int (the day-of-the-month which is Thanksgiving Day)
170  *
171  * HISTORY
172  *   6/2006 Carl McCalla, Sr. (MDL):  Created
173  *
174  * NOTES
175  * ***************************************************************************
176  */
Thanksgivingday(int monthStartDOW)177 static int Thanksgivingday (int monthStartDOW)
178 {
179    if ((monthStartDOW >= 0) && (monthStartDOW <= 4)) {
180       return (26 - monthStartDOW);
181    } else if (monthStartDOW == 5) {
182       return 28;
183    } else {
184       return 27;
185    }
186 }
187 
188 /*****************************************************************************
189  * Clock_Holiday() --
190  *
191  * Carl McCalla /MDL
192  *
193  * PURPOSE
194  *   Return a holiday string (e.g., Christmas Day, Thanksgiving Day, etc.), if
195  * the current day of the month is a federal holiday.
196  *
197  * ARGUMENTS
198  *         month = month of the year (e.g., 1 = Jan, 2 = Feb, etc.) (Input)
199  *           day = the current day of the month (e.g., 1, 2, 3 ...) (Input)
200  * monthStartDOW = the day-of-the-month which is the first day of the month
201  *                 (e.g., 0 = Sunday, 1 = Monday, etc.)
202  *        answer = String containing the holiday string, if the current day is
203  *                 a federal holiday, or a "", if the current day is not a
204  *                 federal holiday.
205  *
206  * RETURNS
207  *   void
208  *
209  * HISTORY
210  *   6/2006 Carl McCalla, Sr. (MDL):  Created
211  *
212  * NOTES
213  * ***************************************************************************
214  */
Clock_Holiday(int month,int day,int monthStartDOW,char answer[100])215 static void Clock_Holiday (int month, int day, int monthStartDOW,
216                            char answer[100])
217 {
218    switch (month) {
219       case 1:          /* January */
220          if (day == 1) {
221             strcpy (answer, "New Years Day");
222             return;
223          } else if (ThirdMonday (monthStartDOW) == day) {
224             strcpy (answer, "Martin Luther King Jr Day");
225             return;
226          }
227          break;
228       case 2:          /* February */
229          if (ThirdMonday (monthStartDOW) == day) {
230             strcpy (answer, "Presidents Day");
231             return;
232          }
233          break;
234       case 5:          /* May */
235          if (Memorialday (monthStartDOW) == day) {
236             strcpy (answer, "Memorial Day");
237             return;
238          }
239          break;
240       case 7:          /* July */
241          if (day == 4) {
242             strcpy (answer, "Independence Day");
243             return;
244          }
245          break;
246       case 9:          /* September */
247          if (Laborday (monthStartDOW) == day) {
248             strcpy (answer, "Labor Day");
249             return;
250          }
251          break;
252       case 10:         /* October */
253          if (Columbusday (monthStartDOW) == day) {
254             strcpy (answer, "Columbus Day");
255             return;
256          }
257          break;
258       case 11:         /* November */
259          if (day == 11) {
260             strcpy (answer, "Veterans Day");
261             return;
262          } else if (Thanksgivingday (monthStartDOW) == day) {
263             strcpy (answer, "Thanksgiving Day");
264             return;
265          }
266          break;
267       case 12:         /* December */
268          if (day == 25) {
269             strcpy (answer, "Christmas Day");
270             return;
271          }
272          break;
273    }
274    strcpy (answer, "");
275    return;
276 }
277 
278 /*****************************************************************************
279  * Clock_Epock2YearDay() --
280  *
281  * Arthur Taylor / MDL
282  *
283  * PURPOSE
284  *   To convert the days since the beginning of the epoch to days since
285  * beginning of the year and years since the beginning of the epoch.
286  *
287  * ARGUMENTS
288  * totDay = Number of days since the beginning of the epoch. (Input)
289  *    Day = The days since the beginning of the year. (Output)
290  *     Yr = The years since the epoch. (Output)
291  *
292  * RETURNS: void
293  *
294  * HISTORY
295  *   9/2002 Arthur Taylor (MDL/RSIS): Created.
296  *   6/2004 AAT (MDL): Updated.
297  *
298  * NOTES
299  *****************************************************************************
300  */
Clock_Epoch2YearDay(sInt4 totDay,int * Day,sInt4 * Yr)301 void Clock_Epoch2YearDay (sInt4 totDay, int *Day, sInt4 *Yr)
302 {
303    sInt4 year;          /* Local copy of the year. */
304 
305    year = 1970;
306    /* Jump to the correct 400 year period of time. */
307    if ((totDay <= -PERIOD_YEARS) || (totDay >= PERIOD_YEARS)) {
308       year += 400 * (totDay / PERIOD_YEARS);
309       totDay -= PERIOD_YEARS * (totDay / PERIOD_YEARS);
310    }
311    if (totDay >= 0) {
312       while (totDay >= 366) {
313          if (ISLEAPYEAR (year)) {
314             if (totDay >= 1461) {
315                year += 4;
316                totDay -= 1461;
317             } else if (totDay >= 1096) {
318                year += 3;
319                totDay -= 1096;
320             } else if (totDay >= 731) {
321                year += 2;
322                totDay -= 731;
323             } else {
324                year++;
325                totDay -= 366;
326             }
327          } else {
328             year++;
329             totDay -= 365;
330          }
331       }
332       if ((totDay == 365) && (!ISLEAPYEAR (year))) {
333          year++;
334          totDay -= 365;
335       }
336    } else {
337       while (totDay <= -366) {
338          year--;
339          if (ISLEAPYEAR (year)) {
340             if (totDay <= -1461) {
341                year -= 3;
342                totDay += 1461;
343             } else if (totDay <= -1096) {
344                year -= 2;
345                totDay += 1096;
346             } else if (totDay <= -731) {
347                year--;
348                totDay += 731;
349             } else {
350                totDay += 366;
351             }
352          } else {
353             totDay += 365;
354          }
355       }
356       if (totDay < 0) {
357          year--;
358          if (ISLEAPYEAR (year)) {
359             totDay += 366;
360          } else {
361             totDay += 365;
362          }
363       }
364    }
365    *Day = (int) totDay;
366    *Yr = year;
367 }
368 
369 /*****************************************************************************
370  * Clock_MonthNum() --
371  *
372  * Arthur Taylor / MDL
373  *
374  * PURPOSE
375  *   Determine which numbered month it is given the day since the beginning of
376  * the year, and the year since the beginning of the epoch.
377  *
378  * ARGUMENTS
379  *  day = Day since the beginning of the year. (Input)
380  * year = Year since the beginning of the epoch. (Input)
381  *
382  * RETURNS: int (which month it is)
383  *
384  * HISTORY
385  *   9/2002 Arthur Taylor (MDL/RSIS): Created.
386  *   6/2004 AAT (MDL): Updated.
387  *
388  * NOTES
389  *****************************************************************************
390  */
Clock_MonthNum(int day,sInt4 year)391 int Clock_MonthNum (int day, sInt4 year)
392 {
393    if (day < 31)
394       return 1;
395    if (ISLEAPYEAR (year))
396       day -= 1;
397    if (day < 59)
398       return 2;
399    if (day <= 89)
400       return 3;
401    if (day == 242)
402       return 8;
403    return ((day + 64) * 5) / 153 - 1;
404 }
405 
406 /*****************************************************************************
407  * Clock_NumDay() --
408  *
409  * Arthur Taylor / MDL
410  *
411  * PURPOSE
412  *   Returns either the number of days in the month or the number of days
413  * since the beginning of the year.
414  *
415  * ARGUMENTS
416  * month = Month in question. (Input)
417  *   day = Day of month in question (Input)
418  *  year = years since the epoch (Input)
419  * f_tot = 1 if we want total days from beginning of year,
420  *         0 if we want total days in the month. (Input)
421  *
422  * RETURNS: int
423  *  Either the number of days in the month, or
424  *  the number of days since the beginning of they year.
425  *
426  * HISTORY
427  *   9/2002 Arthur Taylor (MDL/RSIS): Created.
428  *
429  * NOTES
430  *****************************************************************************
431  */
Clock_NumDay(int month,int day,sInt4 year,char f_tot)432 int Clock_NumDay (int month, int day, sInt4 year, char f_tot)
433 {
434    if (f_tot == 1) {
435       if (month > 2) {
436          if (ISLEAPYEAR (year)) {
437             return ((month + 1) * 153) / 5 - 63 + day;
438          } else {
439             return ((month + 1) * 153) / 5 - 64 + day;
440          }
441       } else {
442          return (month - 1) * 31 + day - 1;
443       }
444    } else {
445       if (month == 1) {
446          return 31;
447       } else if (month != 2) {
448          if ((((month - 3) % 5) % 2) == 1) {
449             return 30;
450          } else {
451             return 31;
452          }
453       } else {
454          if (ISLEAPYEAR (year)) {
455             return 29;
456          } else {
457             return 28;
458          }
459       }
460    }
461 }
462 
463 /*****************************************************************************
464  * Clock_FormatParse() --
465  *
466  * Arthur Taylor / MDL
467  *
468  * PURPOSE
469  *   To format part of the output clock string.
470  *
471  * ARGUMENTS
472  *    buffer = The output string to write to. (Output)
473  *       sec = Seconds since beginning of day. (Input)
474  * floatSec = Part of a second since beginning of second. (Input)
475  *   totDay = Days since the beginning of the epoch. (Input)
476  *      year = Years since the beginning of the epoch (Input)
477  *     month = Month since the beginning of the year (Input)
478  *       day = Days since the beginning of the year (Input)
479  *    format = Which part of the format string we are working on. (Input)
480  *
481  * RETURNS: void
482  *
483  * HISTORY
484  *   9/2002 Arthur Taylor (MDL/RSIS): Created.
485  *   6/2004 AAT (MDL): Updated.
486  *
487  * NOTES
488  *****************************************************************************
489  */
490 #define SIZEOF_BUFFER   100
Clock_FormatParse(char buffer[SIZEOF_BUFFER],sInt4 sec,float floatSec,sInt4 totDay,sInt4 year,int month,int day,char format)491 static void Clock_FormatParse (char buffer[SIZEOF_BUFFER], sInt4 sec, float floatSec,
492                                sInt4 totDay, sInt4 year, int month, int day,
493                                char format)
494 {
495    static const char * const MonthName[] = {
496       "January", "February", "March", "April", "May", "June", "July",
497       "August", "September", "October", "November", "December"
498    };
499    static const char * const DayName[] = {
500       "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday",
501       "Saturday"
502    };
503    int dy;              /* # of days from start of year to start of month. */
504    int i;               /* Temporary variable to help with computations. */
505    int DOM;             /* Day of the Month (e.g., 1-31) */
506    int DOW;             /* Numeric day of the week (e.g., 0 = Sunday, 1 =
507                          * Monday, etc. */
508    int monthStartDOW;   /* Numeric day of the week of the 1st day of the
509                          * month */
510    char temp[100];      /* Helps parse the %D, %T, %r, and %R options. */
511 
512    switch (format) {
513       case 'd':
514          dy = (Clock_NumDay (month, 1, year, 1) - 1);
515          snprintf(buffer, SIZEOF_BUFFER, "%02d", day - dy);
516          return;
517       case 'm':
518          snprintf(buffer, SIZEOF_BUFFER, "%02d", month);
519          return;
520       case 'E':
521          snprintf(buffer, SIZEOF_BUFFER, "%2d", month);
522          return;
523       case 'Y':
524          snprintf(buffer, SIZEOF_BUFFER, "%04d", year);
525          return;
526       case 'H':
527          snprintf(buffer, SIZEOF_BUFFER, "%02d", (int) ((sec % 86400L) / 3600));
528          return;
529       case 'G':
530          snprintf(buffer, SIZEOF_BUFFER, "%2d", (int) ((sec % 86400L) / 3600));
531          return;
532       case 'M':
533          snprintf(buffer, SIZEOF_BUFFER, "%02d", (int) ((sec % 3600) / 60));
534          return;
535       case 'S':
536          snprintf(buffer, SIZEOF_BUFFER, "%02d", (int) (sec % 60));
537          return;
538       case 'f':
539          snprintf(buffer, SIZEOF_BUFFER, "%05.2f", ((int) (sec % 60)) + floatSec);
540          return;
541       case 'n':
542          snprintf(buffer, SIZEOF_BUFFER, "\n");
543          return;
544       case '%':
545          snprintf(buffer, SIZEOF_BUFFER, "%%");
546          return;
547       case 't':
548          snprintf(buffer, SIZEOF_BUFFER, "\t");
549          return;
550       case 'y':
551          snprintf(buffer, SIZEOF_BUFFER, "%02d", (int) (year % 100));
552          return;
553       case 'I':
554          i = ((sec % 43200L) / 3600);
555          if (i == 0) {
556             snprintf(buffer, SIZEOF_BUFFER, "12");
557          } else {
558             snprintf(buffer, SIZEOF_BUFFER, "%02d", i);
559          }
560          return;
561       case 'p':
562          if (((sec % 86400L) / 3600) >= 12) {
563             snprintf(buffer, SIZEOF_BUFFER, "PM");
564          } else {
565             snprintf(buffer, SIZEOF_BUFFER, "AM");
566          }
567          return;
568       case 'B':
569          strcpy (buffer, MonthName[month - 1]);
570          return;
571       case 'A':
572          strcpy (buffer, DayName[(4 + totDay) % 7]);
573          return;
574       case 'b':
575       case 'h':
576          strcpy (buffer, MonthName[month - 1]);
577          buffer[3] = '\0';
578          return;
579       case 'a':
580          strcpy (buffer, DayName[(4 + totDay) % 7]);
581          buffer[3] = '\0';
582          return;
583       case 'w':
584          snprintf(buffer, SIZEOF_BUFFER, "%d", (int) ((4 + totDay) % 7));
585          return;
586       case 'j':
587          snprintf(buffer, SIZEOF_BUFFER, "%03d", day + 1);
588          return;
589       case 'e':
590          dy = (Clock_NumDay (month, 1, year, 1) - 1);
591          snprintf(buffer, SIZEOF_BUFFER, "%d", (int) (day - dy));
592          return;
593       case 'W':
594          i = (1 - ((4 + totDay - day) % 7)) % 7;
595          if (day < i)
596             snprintf(buffer, SIZEOF_BUFFER, "00");
597          else
598             snprintf(buffer, SIZEOF_BUFFER, "%02d", ((day - i) / 7) + 1);
599          return;
600       case 'U':
601          i = (-((4 + totDay - day) % 7)) % 7;
602          if (day < i)
603             snprintf(buffer, SIZEOF_BUFFER, "00");
604          else
605             snprintf(buffer, SIZEOF_BUFFER, "%02d", ((day - i) / 7) + 1);
606          return;
607       case 'D':
608          Clock_FormatParse (buffer, sec, floatSec, totDay, year, month,
609                             day, 'm');
610          strcat (buffer, "/");
611          Clock_FormatParse (temp, sec, floatSec, totDay, year, month,
612                             day, 'd');
613          strcat (buffer, temp);
614          strcat (buffer, "/");
615          Clock_FormatParse (temp, sec, floatSec, totDay, year, month,
616                             day, 'Y');
617          strcat (buffer, temp);
618          return;
619       case 'T':
620          Clock_FormatParse (buffer, sec, floatSec, totDay, year, month,
621                             day, 'H');
622          strcat (buffer, ":");
623          Clock_FormatParse (temp, sec, floatSec, totDay, year, month,
624                             day, 'M');
625          strcat (buffer, temp);
626          strcat (buffer, ":");
627          Clock_FormatParse (temp, sec, floatSec, totDay, year, month,
628                             day, 'S');
629          strcat (buffer, temp);
630          return;
631       case 'r':
632          Clock_FormatParse (buffer, sec, floatSec, totDay, year, month,
633                             day, 'I');
634          strcat (buffer, ":");
635          Clock_FormatParse (temp, sec, floatSec, totDay, year, month,
636                             day, 'M');
637          strcat (buffer, temp);
638          strcat (buffer, ":");
639          Clock_FormatParse (temp, sec, floatSec, totDay, year, month,
640                             day, 'S');
641          strcat (buffer, temp);
642          strcat (buffer, " ");
643          Clock_FormatParse (temp, sec, floatSec, totDay, year, month,
644                             day, 'p');
645          strcat (buffer, temp);
646          return;
647       case 'R':
648          Clock_FormatParse (buffer, sec, floatSec, totDay, year, month,
649                             day, 'H');
650          strcat (buffer, ":");
651          Clock_FormatParse (temp, sec, floatSec, totDay, year, month,
652                             day, 'M');
653          strcat (buffer, temp);
654          return;
655 
656          /* If the current day is a federal holiday, then return a pointer to
657           * the appropriate holiday string (e.g., "Martin Luther King Day") */
658       case 'v':
659          /* Clock_FormatParse 'd' */
660          dy = (Clock_NumDay (month, 1, year, 1) - 1);
661          DOM = day - dy;
662          /* Clock_FormatParse 'w' */
663          DOW = (int) ((4 + totDay) % 7);
664 
665          if ((DOM % 7) != 1) {
666             monthStartDOW = DOW - ((DOM % 7) - 1);
667             if (monthStartDOW < 0) {
668                monthStartDOW = 7 + monthStartDOW;
669             }
670          } else {
671             monthStartDOW = DOW;
672          }
673 
674          Clock_Holiday (month, DOM, monthStartDOW, temp);
675          if (temp[0] != '\0') {
676             strcpy (buffer, temp);
677          } else {
678             Clock_FormatParse (buffer, sec, floatSec, totDay, year, month,
679                                day, 'A');
680          }
681          return;
682       default:
683          snprintf(buffer, SIZEOF_BUFFER, "unknown %c", format);
684          return;
685    }
686 }
687 
688 /*****************************************************************************
689  * Clock_GetTimeZone() --
690  *
691  * Arthur Taylor / MDL
692  *
693  * PURPOSE
694  *   Returns the time zone offset in hours to add to local time to get UTC.
695  * So EST is +5 not -5.
696  *
697  * ARGUMENTS
698  *
699  * RETURNS: int
700  *
701  * HISTORY
702  *   6/2004 Arthur Taylor (MDL): Created.
703  *   3/2005 AAT: Found bug... Used to use 1/1/1970 00Z and find the local
704  *        hour.  If CET, this means use 1969 date, which causes it to die.
705  *        Switched to 1/2/1970 00Z.
706  *   3/2005 AAT: timeZone (see CET) can be < 0. don't add 24 if timeZone < 0
707  *
708  * NOTES
709  *****************************************************************************
710  */
Clock_GetTimeZone()711 sChar Clock_GetTimeZone ()
712 {
713    struct tm l_time;
714    time_t ansTime;
715    struct tm *gmTime;
716    static int timeZone = 9999;
717 
718    if (timeZone == 9999) {
719       /* Cheap method of getting global time_zone variable. */
720       memset (&l_time, 0, sizeof (struct tm));
721       l_time.tm_year = 70;
722       l_time.tm_mday = 2;
723       ansTime = mktime (&l_time);
724       gmTime = gmtime (&ansTime);
725       timeZone = gmTime->tm_hour;
726       if (gmTime->tm_mday != 2) {
727          timeZone -= 24;
728       }
729    }
730    return timeZone;
731 }
732 
733 /*****************************************************************************
734  * Clock_IsDaylightSaving() --
735  *
736  * Arthur Taylor / MDL
737  *
738  * PURPOSE
739  *   To determine if daylight savings is in effect.  Daylight savings is in
740  * effect from the first sunday in April to the last sunday in October.
741  * At 2 AM ST (or 3 AM DT) in April   -> 3 AM DT (and we return 1)
742  * At 2 AM DT (or 1 AM ST) in October -> 1 AM ST (and we return 0)
743  *
744  * ARGUMENTS
745  *    l_clock = The time stored as a double. (Input)
746  * TimeZone = hours to add to local time to get UTC. (Input)
747  *
748  * RETURNS: int
749  *   0 if not in daylight savings time.
750  *   1 if in daylight savings time.
751  *
752  * HISTORY
753  *   9/2002 Arthur Taylor (MDL/RSIS): Created.
754  *   6/2004 AAT (MDL): Updated.
755  *   2/2007 AAT : Updated yet again.
756  *
757  * NOTES
758  *    From 1987 through 2006, the start and end dates were the first Sunday in
759  * April and the last Sunday in October.
760  *
761  *    Since 1996 the European Union has observed DST from the last Sunday in
762  * March to the last Sunday in October, with transitions at 01:00 UTC.
763  *
764  *    On August 8, 2005, President George W. Bush signed the Energy Policy Act
765  * of 2005. This Act changed the time change dates for Daylight Saving Time in
766  * the U.S. Beginning in 2007, DST will begin on the second Sunday in March
767  * and end the first Sunday in November.
768 
769  *    The Secretary of Energy will report the impact of this change to
770  * Congress. Congress retains the right to resume the 2005 Daylight Saving
771  * Time schedule once the Department of Energy study is complete.
772  *
773  *                   1st-apr last-oct  2nd-mar 1st-nov
774  * 1/1/1995 Sun (0)   4/2     10/29     3/12    11/5
775  * 1/1/2001 mon (1)   4/1     10/28     3/11    11/4
776  * 1/1/1991 tue (2)   4/7     10/27     3/10    11/3
777  * 1/1/2003 Wed (3)   4/6     10/26     3/9     11/2
778  * 1/1/1987 thu (4)   4/5     10/25     3/8     11/1
779  * 1/1/1999 fri (5)   4/4     10/31     3/14    11/7
780  * 1/1/2005 Sat (6)   4/3     10/30     3/13    11/6
781  *
782  * Leap years:
783  * 1/1/2012 Sun (0)
784  * 1/1/1996 Mon (1)   4/7     10/27     3/10    11/3
785  * 1/1/2008 Tue (2)   4/6     10/26     3/9     11/2
786  * 1/1/2020 Wed (3)   4/5     10/25     3/8     11/1
787 
788  * 1/1/2004 Thu (4)   4/4     10/31     3/14    11/7
789  * 1/1/2032 Thu (4)   4/4     10/31     3/14    11/7
790 
791  * 1/1/2016 Fri (5)
792  * 1/1/2028 Sat (6)
793  *   --- Since there is an extra day, the delta is the same
794  *   --- Problems occur with leap years pre 2007 which start on Mon or Thur
795  *       (delta shift by 7 days = 604,800 seconds) After 2007, it was leap
796  *       years starting only on Thur.
797  *****************************************************************************
798  */
Clock_IsDaylightSaving2(double l_clock,sChar TimeZone)799 int Clock_IsDaylightSaving2 (double l_clock, sChar TimeZone)
800 {
801    sInt4 totDay, year;
802    int day, first;
803    double secs;
804    sInt4 start, end;
805 
806    /* These are the deltas between the 1st sun in apr and beginning of year
807     * in seconds + 2 hours. */
808    static const sInt4 start2006[7] = {7869600, 7783200, 8301600, 8215200,
809                                 8128800, 8042400, 7956000};
810    /* These are the deltas between the last sun in oct and beginning of year
811     * in seconds + 1 hour. */
812    static const sInt4 end2006[7] = {26010000, 25923600, 25837200, 25750800,
813                               25664400, 26182800, 26096400};
814    /* Previous version had typo ...26664400 -> 25664400 */
815 
816    /* These are the deltas between the 2nd sun in mar and beginning of year
817     * in seconds + 2 hours. */
818    static const sInt4 start2007[7] = {6055200, 5968800, 5882400, 5796000,
819                                 5709600, 6228000, 6141600};
820    /* These are the deltas between the 1st sun in nov and beginning of year
821     * in seconds + 1 hour. */
822    static const sInt4 end2007[7] = {26614800, 26528400, 26442000, 26355600,
823                               26269200, 26787600, 26701200};
824 
825    l_clock = l_clock - TimeZone * 3600.;
826    /* Clock should now be in Standard Time, so comparisons later have to be
827     * based on Standard Time. */
828 
829    totDay = (sInt4) floor (l_clock / SEC_DAY);
830    Clock_Epoch2YearDay (totDay, &day, &year);
831    /* Figure out number of seconds since beginning of year. */
832    secs = l_clock - (totDay - day) * SEC_DAY;
833 
834    /* figure out if 1/1/year is mon/tue/.../sun */
835    first = ((4 + (totDay - day)) % 7); /* -day should get 1/1 but may need
836                                         * -day+1 => sun == 0, ... sat == 6 */
837 
838    if (year >= 2007) {
839       start = start2007[first];
840       end = end2007[first];
841       if (((year % 4) == 0) && (((year % 100) != 0) || ((year % 400) == 0))) {
842          if (first == 4) {
843             start += 604800;
844             end += 604800;
845          }
846       }
847    } else {
848       start = start2006[first];
849       end = end2006[first];
850       if (((year % 4) == 0) && (((year % 100) != 0) || ((year % 400) == 0))) {
851          if (first == 1) {
852             start += 604800;
853          } else if (first == 4) {
854             end += 604800;
855          }
856       }
857    }
858    if ((secs >= start) && (secs <= end)) {
859       return 1;
860    } else {
861       return 0;
862    }
863 }
864 
865 /*****************************************************************************
866  * Clock_PrintDate() --
867  *
868  * Arthur Taylor / MDL
869  *
870  * PURPOSE
871  *
872  * ARGUMENTS
873  * l_clock = The time stored as a double. (Input)
874  *  year = The year. (Output)
875  * month = The month. (Output)
876  *   day = The day. (Output)
877  *  hour = The hour. (Output)
878  *   min = The min. (Output)
879  *   sec = The second. (Output)
880  *
881  * RETURNS: void
882  *
883  * HISTORY
884  *   3/2005 Arthur Taylor (MDL): Commented.
885  *
886  * NOTES
887  *****************************************************************************
888  */
Clock_PrintDate(double l_clock,sInt4 * year,int * month,int * day,int * hour,int * min,double * sec)889 void Clock_PrintDate (double l_clock, sInt4 *year, int *month, int *day,
890                       int *hour, int *min, double *sec)
891 {
892    sInt4 totDay;
893    sInt4 intSec;
894 
895    totDay = (sInt4) floor (l_clock / SEC_DAY);
896    Clock_Epoch2YearDay (totDay, day, year);
897    *month = Clock_MonthNum (*day, *year);
898    *day = *day - Clock_NumDay (*month, 1, *year, 1) + 1;
899    *sec = l_clock - ((double) totDay) * SEC_DAY;
900    intSec = (sInt4) (*sec);
901    *hour = (int) ((intSec % 86400L) / 3600);
902    *min = (int) ((intSec % 3600) / 60);
903    *sec = (intSec % 60) + (*sec - intSec);
904 }
905 
906 /*****************************************************************************
907  * Clock_Print() --
908  *
909  * Arthur Taylor / MDL
910  *
911  * PURPOSE
912  *   To create formatted output from a time structure that is stored as a
913  * double.
914  *
915  * ARGUMENTS
916  * buffer = Destination to write the format to. (Output)
917  *      n = The number of characters in buffer. (Input)
918  *  l_clock = The time stored as a double. (Input)
919  * format = The desired output format. (Input)
920  *  f_gmt = 0 output GMT, 1 output LDT, 2 output LST. (Input)
921  *
922  * RETURNS: void
923  *
924  * HISTORY
925  *   9/2002 Arthur Taylor (MDL/RSIS): Created.
926  *   6/2004 AAT (MDL): Updated.
927  *
928  * NOTES
929  *****************************************************************************
930  */
Clock_Print(char * buffer,int n,double l_clock,const char * format,char f_gmt)931 void Clock_Print (char *buffer, int n, double l_clock, const char *format,
932                   char f_gmt)
933 {
934    sInt4 totDay, year;
935    sInt4 sec;
936    double floatSec;
937    int month, day;
938    size_t i;
939    int j;
940    char f_perc;
941    char locBuff[100];
942    sChar timeZone;      /* Hours to add to local time to get UTC. */
943 
944    /* Handle gmt problems. */
945    if (f_gmt != 0) {
946       timeZone = Clock_GetTimeZone ();
947       /* l_clock is currently in UTC */
948       l_clock -= timeZone * 3600;
949       /* l_clock is now in local standard time Note: A 0 is passed to
950        * DaylightSavings so it converts from local to local standard time. */
951       if ((f_gmt == 1) && (Clock_IsDaylightSaving2 (l_clock, 0) == 1)) {
952          l_clock = l_clock + 3600;
953       }
954    }
955    /* Convert from seconds to days and seconds. */
956    totDay = (sInt4) floor (l_clock / SEC_DAY);
957    Clock_Epoch2YearDay (totDay, &day, &year);
958    month = Clock_MonthNum (day, year);
959    floatSec = l_clock - ((double) totDay) * SEC_DAY;
960    sec = (sInt4) floatSec;
961    floatSec = floatSec - sec;
962 
963    f_perc = 0;
964    j = 0;
965    for (i = 0; i < strlen (format); i++) {
966       if (j >= n)
967          return;
968       if (format[i] == '%') {
969          f_perc = 1;
970       } else {
971          if (f_perc == 0) {
972             buffer[j] = format[i];
973             j++;
974             buffer[j] = '\0';
975          } else {
976             Clock_FormatParse (locBuff, sec, (float)floatSec, totDay, year, month,
977                                day, format[i]);
978             buffer[j] = '\0';
979             strncat (buffer, locBuff, n - j);
980             j += (int)strlen (locBuff);
981             f_perc = 0;
982          }
983       }
984    }
985 }
986 
987 /*****************************************************************************
988  * Clock_Print2() --
989  *
990  * Arthur Taylor / MDL
991  *
992  * PURPOSE
993  *   To create formatted output from a time structure that is stored as a
994  * double.  This is similar to Clock_Print, except it bases the timezone
995  * shift on what the user supplies rather than the system timezone, and
996  * accepts a flag that indicates whether to inquire about daylight savings.
997  *   If f_dayCheck, then it looks at the local time and see's if daylight is
998  * in effect.  This allows for points where daylight is never in effect
999  * (f_dayCheck = 0).
1000  *
1001  * ARGUMENTS
1002  *     buffer = Destination to write the format to. (Output)
1003  *          n = The number of characters in buffer. (Input)
1004  *      l_clock = The time stored as a double (asumed in UTC). (Input)
1005  *     format = The desired output format. (Input)
1006  *   timeZone = Hours to add to local time to get UTC. (Input)
1007  * f_dayCheck = True if we should check if daylight savings is in effect,
1008  *              after converting to LST. (Input)
1009  *
1010  * RETURNS: void
1011  *
1012  * HISTORY
1013  *   1/2006 Arthur Taylor (MDL/RSIS): Created.
1014  *
1015  * NOTES
1016  *****************************************************************************
1017  */
Clock_Print2(char * buffer,int n,double l_clock,char * format,sChar timeZone,sChar f_dayCheck)1018 void Clock_Print2 (char *buffer, int n, double l_clock, char *format,
1019                    sChar timeZone, sChar f_dayCheck)
1020 {
1021    sInt4 totDay, year;
1022    sInt4 sec;
1023    double floatSec;
1024    int month, day;
1025    size_t i;
1026    int j;
1027    char f_perc;
1028    char locBuff[100];
1029 
1030    /* l_clock is currently in UTC */
1031    l_clock -= timeZone * 3600;
1032    /* l_clock is now in local standard time */
1033    if (f_dayCheck) {
1034       /* Note: A 0 is passed to DaylightSavings so it converts from local to
1035        * local standard time. */
1036       if (Clock_IsDaylightSaving2 (l_clock, 0) == 1) {
1037          l_clock += 3600;
1038       }
1039    }
1040 
1041    /* Convert from seconds to days and seconds. */
1042    totDay = (sInt4) floor (l_clock / SEC_DAY);
1043    Clock_Epoch2YearDay (totDay, &day, &year);
1044    month = Clock_MonthNum (day, year);
1045    floatSec = l_clock - ((double) totDay) * SEC_DAY;
1046    sec = (sInt4) floatSec;
1047    floatSec = floatSec - sec;
1048 
1049    f_perc = 0;
1050    j = 0;
1051    for (i = 0; i < strlen (format); i++) {
1052       if (j >= n)
1053          return;
1054       if (format[i] == '%') {
1055          f_perc = 1;
1056       } else {
1057          if (f_perc == 0) {
1058             buffer[j] = format[i];
1059             j++;
1060             buffer[j] = '\0';
1061          } else {
1062             Clock_FormatParse (locBuff, sec, (float)floatSec, totDay, year, month,
1063                                day, format[i]);
1064             buffer[j] = '\0';
1065             strncat (buffer, locBuff, n - j);
1066             j += (int)strlen (locBuff);
1067             f_perc = 0;
1068          }
1069       }
1070    }
1071 }
1072 
1073 /*****************************************************************************
1074  * Clock_Clicks() --
1075  *
1076  * Arthur Taylor / MDL
1077  *
1078  * PURPOSE
1079  *   Returns the number of clicks since the program started execution.
1080  *
1081  * ARGUMENTS
1082  *
1083  * RETURNS: double
1084  *  Number of clicks since the beginning of the program.
1085  *
1086  * HISTORY
1087  *   6/2004 Arthur Taylor (MDL): Created.
1088  *
1089  * NOTES
1090  *****************************************************************************
1091  */
Clock_Clicks(void)1092 double Clock_Clicks (void)
1093 {
1094    double ans;
1095 
1096    ans = (double) clock ();
1097    return ans;
1098 }
1099 
1100 /*****************************************************************************
1101  * Clock_Seconds() --
1102  *
1103  * Arthur Taylor / MDL
1104  *
1105  * PURPOSE
1106  *   Returns the current number of seconds since the beginning of the epoch.
1107  * Using the local system time zone.
1108  *
1109  * ARGUMENTS
1110  *
1111  * RETURNS: double
1112  *  Number of seconds since beginning of the epoch.
1113  *
1114  * HISTORY
1115  *   6/2004 Arthur Taylor (MDL): Created.
1116  *
1117  * NOTES
1118  *****************************************************************************
1119  */
Clock_SetSeconds(double * ptime,sChar f_set)1120 int Clock_SetSeconds (double *ptime, sChar f_set)
1121 {
1122    static double ans = 0;
1123    static int f_ansSet = 0;
1124 
1125    if (f_set) {
1126       ans = *ptime;
1127       f_ansSet = 1;
1128    } else if (f_ansSet) {
1129       *ptime = ans;
1130    }
1131    return f_ansSet;
1132 }
1133 
Clock_Seconds(void)1134 double Clock_Seconds (void)
1135 {
1136    double ans;
1137 
1138    if (Clock_SetSeconds (&ans, 0) == 0) {
1139       ans = time (NULL);
1140    }
1141    return ans;
1142 }
1143 
1144 /*****************************************************************************
1145  * Clock_PrintZone() --
1146  *
1147  * Arthur Taylor / MDL
1148  *
1149  * PURPOSE
1150  *   Prints the time zone based on the shift from UTC and if it is daylight
1151  * savings or not.
1152  *
1153  * ARGUMENTS
1154  *      ptr = The character string to scan. (Output)
1155  * TimeZone = Hours to add to local time to get UTC. (Input)
1156  *    f_day = True if we are dealing with daylight savings. (Input)
1157  *
1158  * RETURNS: int
1159  *  0 if we read TimeZone, -1 if not.
1160  *
1161  * HISTORY
1162  *   9/2002 Arthur Taylor (MDL/RSIS): Created.
1163  *   6/2004 AAT (MDL): Updated.
1164  *
1165  * NOTES
1166  *****************************************************************************
1167  */
Clock_PrintZone2(char * ptr,sChar TimeZone,char f_day)1168 int Clock_PrintZone2 (char *ptr, sChar TimeZone, char f_day)
1169 {
1170    if (TimeZone == 0) {
1171       strcpy (ptr, "UTC");
1172       return 0;
1173    } else if (TimeZone == 5) {
1174       if (f_day) {
1175          strcpy (ptr, "EDT");
1176       } else {
1177          strcpy (ptr, "EST");
1178       }
1179       return 0;
1180    } else if (TimeZone == 6) {
1181       if (f_day) {
1182          strcpy (ptr, "CDT");
1183       } else {
1184          strcpy (ptr, "CST");
1185       }
1186       return 0;
1187    } else if (TimeZone == 7) {
1188       if (f_day) {
1189          strcpy (ptr, "MDT");
1190       } else {
1191          strcpy (ptr, "MST");
1192       }
1193       return 0;
1194    } else if (TimeZone == 8) {
1195       if (f_day) {
1196          strcpy (ptr, "PDT");
1197       } else {
1198          strcpy (ptr, "PST");
1199       }
1200       return 0;
1201    } else if (TimeZone == 9) {
1202       if (f_day) {
1203          strcpy (ptr, "YDT");
1204       } else {
1205          strcpy (ptr, "YST");
1206       }
1207       return 0;
1208    }
1209    ptr[0] = '\0';
1210    return -1;
1211 }
1212 
1213 /*****************************************************************************
1214  * Clock_ScanZone() --
1215  *
1216  * Arthur Taylor / MDL
1217  *
1218  * PURPOSE
1219  *   Scans a character string to determine the timezone.
1220  *
1221  * ARGUMENTS
1222  *      ptr = The character string to scan. (Input)
1223  * TimeZone = Hours to add to local time to get UTC. (Output)
1224  *    f_day = True if we are dealing with daylight savings. (Output)
1225  *
1226  * RETURNS: int
1227  *  0 if we read TimeZone, -1 if not.
1228  *
1229  * HISTORY
1230  *   9/2002 Arthur Taylor (MDL/RSIS): Created.
1231  *   6/2004 AAT (MDL): Updated.
1232  *
1233  * NOTES
1234  *****************************************************************************
1235  */
Clock_ScanZone2(char * ptr,sChar * TimeZone,char * f_day)1236 int Clock_ScanZone2 (char *ptr, sChar *TimeZone, char *f_day)
1237 {
1238    switch (ptr[0]) {
1239       case 'G':
1240          if (strcmp (ptr, "GMT") == 0) {
1241             *f_day = 0;
1242             *TimeZone = 0;
1243             return 0;
1244          }
1245          return -1;
1246       case 'U':
1247          if (strcmp (ptr, "UTC") == 0) {
1248             *f_day = 0;
1249             *TimeZone = 0;
1250             return 0;
1251          }
1252          return -1;
1253       case 'E':
1254          if (strcmp (ptr, "EDT") == 0) {
1255             *f_day = 1;
1256             *TimeZone = 5;
1257             return 0;
1258          } else if (strcmp (ptr, "EST") == 0) {
1259             *f_day = 0;
1260             *TimeZone = 5;
1261             return 0;
1262          }
1263          return -1;
1264       case 'C':
1265          if (strcmp (ptr, "CDT") == 0) {
1266             *f_day = 1;
1267             *TimeZone = 6;
1268             return 0;
1269          } else if (strcmp (ptr, "CST") == 0) {
1270             *f_day = 0;
1271             *TimeZone = 6;
1272             return 0;
1273          }
1274          return -1;
1275       case 'M':
1276          if (strcmp (ptr, "MDT") == 0) {
1277             *f_day = 1;
1278             *TimeZone = 7;
1279             return 0;
1280          } else if (strcmp (ptr, "MST") == 0) {
1281             *f_day = 0;
1282             *TimeZone = 7;
1283             return 0;
1284          }
1285          return -1;
1286       case 'P':
1287          if (strcmp (ptr, "PDT") == 0) {
1288             *f_day = 1;
1289             *TimeZone = 8;
1290             return 0;
1291          } else if (strcmp (ptr, "PST") == 0) {
1292             *f_day = 0;
1293             *TimeZone = 8;
1294             return 0;
1295          }
1296          return -1;
1297       case 'Y':
1298          if (strcmp (ptr, "YDT") == 0) {
1299             *f_day = 1;
1300             *TimeZone = 9;
1301             return 0;
1302          } else if (strcmp (ptr, "YST") == 0) {
1303             *f_day = 0;
1304             *TimeZone = 9;
1305             return 0;
1306          }
1307          return -1;
1308       case 'Z':
1309          if (strcmp (ptr, "Z") == 0) {
1310             *f_day = 0;
1311             *TimeZone = 0;
1312             return 0;
1313          }
1314          return -1;
1315    }
1316    return -1;
1317 }
1318 
1319 /*****************************************************************************
1320  * Clock_ScanMonth() --
1321  *
1322  * Arthur Taylor / MDL
1323  *
1324  * PURPOSE
1325  *   Scans a string looking for a month word.  Assumes string is all caps.
1326  *
1327  * ARGUMENTS
1328  * ptr = The character string to scan. (Input)
1329  *
1330  * RETURNS: int
1331  * Returns the month number read, or -1 if no month word seen.
1332  *
1333  * HISTORY
1334  *   9/2002 Arthur Taylor (MDL/RSIS): Created.
1335  *   6/2004 AAT (MDL): Updated.
1336  *
1337  * NOTES
1338  *****************************************************************************
1339  */
Clock_ScanMonth(char * ptr)1340 int Clock_ScanMonth (char *ptr)
1341 {
1342    switch (*ptr) {
1343       case 'A':
1344          if ((strcmp (ptr, "APR") == 0) || (strcmp (ptr, "APRIL") == 0))
1345             return 4;
1346          else if ((strcmp (ptr, "AUG") == 0) || (strcmp (ptr, "AUGUST") == 0))
1347             return 8;
1348          return -1;
1349       case 'D':
1350          if ((strcmp (ptr, "DEC") == 0) || (strcmp (ptr, "DECEMBER") == 0))
1351             return 12;
1352          return -1;
1353       case 'F':
1354          if ((strcmp (ptr, "FEB") == 0) || (strcmp (ptr, "FEBRUARY") == 0))
1355             return 2;
1356          return -1;
1357       case 'J':
1358          if ((strcmp (ptr, "JAN") == 0) || (strcmp (ptr, "JANUARY") == 0))
1359             return 1;
1360          else if ((strcmp (ptr, "JUN") == 0) || (strcmp (ptr, "JUNE") == 0))
1361             return 6;
1362          else if ((strcmp (ptr, "JUL") == 0) || (strcmp (ptr, "JULY") == 0))
1363             return 7;
1364          return -1;
1365       case 'M':
1366          if ((strcmp (ptr, "MAR") == 0) || (strcmp (ptr, "MARCH") == 0))
1367             return 3;
1368          else if (strcmp (ptr, "MAY") == 0)
1369             return 5;
1370          return -1;
1371       case 'N':
1372          if ((strcmp (ptr, "NOV") == 0) || (strcmp (ptr, "NOVEMBER") == 0))
1373             return 11;
1374          return -1;
1375       case 'O':
1376          if ((strcmp (ptr, "OCT") == 0) || (strcmp (ptr, "OCTOBER") == 0))
1377             return 10;
1378          return -1;
1379       case 'S':
1380          if ((strcmp (ptr, "SEP") == 0) || (strcmp (ptr, "SEPTEMBER") == 0))
1381             return 9;
1382          return -1;
1383    }
1384    return -1;
1385 }
1386 
1387 /*****************************************************************************
1388  * Clock_PrintMonth3() --
1389  *
1390  * Arthur Taylor / MDL
1391  *
1392  * PURPOSE
1393  *
1394  * ARGUMENTS
1395  *
1396  * RETURNS: void
1397  *
1398  * HISTORY
1399  *   3/2005 Arthur Taylor (MDL/RSIS): Commented.
1400  *
1401  * NOTES
1402  *****************************************************************************
1403  */
Clock_PrintMonth3(int mon,char * buffer,CPL_UNUSED int buffLen)1404 void Clock_PrintMonth3 (int mon, char *buffer, CPL_UNUSED int buffLen)
1405 {
1406    static const char * const MonthName[] = {
1407       "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT",
1408       "NOV", "DEC"
1409    };
1410    myAssert ((mon > 0) && (mon < 13));
1411    myAssert (buffLen > 3);
1412    strcpy (buffer, MonthName[mon - 1]);
1413 }
1414 
1415 /*****************************************************************************
1416  * Clock_PrintMonth() --
1417  *
1418  * Arthur Taylor / MDL
1419  *
1420  * PURPOSE
1421  *
1422  * ARGUMENTS
1423  *
1424  * RETURNS: void
1425  *
1426  * HISTORY
1427  *   3/2005 Arthur Taylor (MDL/RSIS): Commented.
1428  *
1429  * NOTES
1430  *****************************************************************************
1431  */
Clock_PrintMonth(int mon,char * buffer,CPL_UNUSED int buffLen)1432 void Clock_PrintMonth (int mon, char *buffer, CPL_UNUSED int buffLen)
1433 {
1434    static const char * const MonthName[] = {
1435       "January", "February", "March", "April", "May", "June", "July",
1436       "August", "September", "October", "November", "December"
1437    };
1438    myAssert ((mon > 0) && (mon < 13));
1439    myAssert (buffLen > 9);
1440    strcpy (buffer, MonthName[mon - 1]);
1441 }
1442 
1443 /*****************************************************************************
1444  * Clock_ScanWeekday() --
1445  *
1446  * Arthur Taylor / MDL
1447  *
1448  * PURPOSE
1449  *   Scans a string looking for a day word.  Assumes string is all caps.
1450  *
1451  * ARGUMENTS
1452  * ptr = The character string to scan. (Input)
1453  *
1454  * RETURNS: int
1455  * Returns the day number read, or -1 if no day word seen.
1456  *
1457  * HISTORY
1458  *   9/2002 Arthur Taylor (MDL/RSIS): Created.
1459  *   6/2004 AAT (MDL): Updated.
1460  *
1461  * NOTES
1462  *****************************************************************************
1463  */
1464 
1465 #ifdef unused_by_GDAL
Clock_ScanWeekday(char * ptr)1466 static int Clock_ScanWeekday (char *ptr)
1467 {
1468    switch (*ptr) {
1469       case 'S':
1470          if ((strcmp (ptr, "SUN") == 0) || (strcmp (ptr, "SUNDAY") == 0))
1471             return 0;
1472          else if ((strcmp (ptr, "SAT") == 0) ||
1473                   (strcmp (ptr, "SATURDAY") == 0))
1474             return 6;
1475          return -1;
1476       case 'M':
1477          if ((strcmp (ptr, "MON") == 0) || (strcmp (ptr, "MONDAY") == 0))
1478             return 1;
1479          return -1;
1480       case 'T':
1481          if ((strcmp (ptr, "TUE") == 0) || (strcmp (ptr, "TUESDAY") == 0))
1482             return 2;
1483          else if ((strcmp (ptr, "THU") == 0) ||
1484                   (strcmp (ptr, "THURSDAY") == 0))
1485             return 4;
1486          return -1;
1487       case 'W':
1488          if ((strcmp (ptr, "WED") == 0) || (strcmp (ptr, "WEDNESDAY") == 0))
1489             return 3;
1490          return -1;
1491       case 'F':
1492          if ((strcmp (ptr, "FRI") == 0) || (strcmp (ptr, "FRIDAY") == 0))
1493             return 5;
1494          return -1;
1495    }
1496    return -1;
1497 }
1498 
1499 /*****************************************************************************
1500  * Clock_ScanColon() --
1501  *
1502  * Arthur Taylor / MDL
1503  *
1504  * PURPOSE
1505  *   Parses a word assuming it is : separated and is dealing with
1506  * hours:minutes:seconds or hours:minutes.  Returns the resulting time as
1507  * a double.
1508  *
1509  * ARGUMENTS
1510  * ptr = The character string to scan. (Input)
1511  *
1512  * RETURNS: double
1513  * The time after converting the : separated string.
1514  *
1515  * HISTORY
1516  *   9/2002 Arthur Taylor (MDL/RSIS): Created.
1517  *   6/2004 AAT (MDL): Updated.
1518  *
1519  * NOTES
1520  *****************************************************************************
1521  */
1522 
Clock_ScanColon(char * ptr)1523 static double Clock_ScanColon (char *ptr)
1524 {
1525    sInt4 hour, min;
1526    double sec;
1527    char *ptr3;
1528 
1529    ptr3 = strchr (ptr, ':');
1530    if( !ptr3 ) return 0;
1531    *ptr3 = '\0';
1532    hour = atoi (ptr);
1533    *ptr3 = ':';
1534    ptr = ptr3 + 1;
1535    /* Check for second :, other wise it is hh:mm */
1536    if ((ptr3 = strchr (ptr, ':')) == NULL) {
1537       min = atoi (ptr);
1538       sec = 0;
1539    } else {
1540       *ptr3 = '\0';
1541       min = atoi (ptr);
1542       *ptr3 = ':';
1543       ptr = ptr3 + 1;
1544       sec = atof (ptr);
1545    }
1546    return (sec + 60 * min + 3600 * hour);
1547 }
1548 
1549 /*****************************************************************************
1550  * Clock_ScanSlash() --
1551  *
1552  * Arthur Taylor / MDL
1553  *
1554  * PURPOSE
1555  *   Parses a word assuming it is / separated and is dealing with
1556  * months/days/years or months/days.
1557  *
1558  * ARGUMENTS
1559  *   word = The character string to scan. (Input)
1560  *    mon = The month that was seen. (Output)
1561  *    day = The day that was seen. (Output)
1562  *   year = The year that was seen. (Output)
1563  * f_year = True if the year is valid. (Output)
1564  *
1565  * RETURNS: int
1566  * -1 if mon or day is out of range.
1567  *  0 if no problems.
1568  *
1569  * HISTORY
1570  *   9/2002 Arthur Taylor (MDL/RSIS): Created.
1571  *   6/2004 AAT (MDL): Updated.
1572  *
1573  * NOTES
1574  *****************************************************************************
1575  */
1576 
Clock_ScanSlash(char * word,int * mon,int * day,sInt4 * year,char * f_year)1577 static int Clock_ScanSlash (char *word, int *mon, int *day, sInt4 *year,
1578                             char *f_year)
1579 {
1580    char *ptr3;
1581    char *ptr = word;
1582 
1583    ptr3 = strchr (ptr, '/');
1584    if( !ptr3 ) return -1;
1585    *ptr3 = '\0';
1586    *mon = atoi (ptr);
1587    *ptr3 = '/';
1588    ptr = ptr3 + 1;
1589    /* Check for second /, other wise it is mm/dd */
1590    if ((ptr3 = strchr (ptr, '/')) == NULL) {
1591       *day = atoi (ptr);
1592       *year = 1970;
1593       *f_year = 0;
1594    } else {
1595       *ptr3 = '\0';
1596       *day = atoi (ptr);
1597       *ptr3 = '/';
1598       ptr = ptr3 + 1;
1599       *year = atoi (ptr);
1600       *f_year = 1;
1601    }
1602    if ((*mon < 1) || (*mon > 12) || (*day < 1) || (*day > 31)) {
1603       printf ("Errors parsing %s\n", word);
1604       return -1;
1605    }
1606    return 0;
1607 }
1608 
1609 /* http://www.w3.org/TR/NOTE-datetime
1610    Year and month:
1611       YYYY-MM (eg 1997-07)
1612    Complete date:
1613       YYYY-MM-DD (eg 1997-07-16)
1614    Complete date plus hours and minutes:
1615       YYYY-MM-DDThh:mmTZD (eg 1997-07-16T19:20+01:00)
1616    Complete date plus hours, minutes and seconds:
1617       YYYY-MM-DDThh:mm:ssTZD (eg 1997-07-16T19:20:30+01:00)
1618    Complete date plus hours, minutes, seconds and a decimal fraction of a
1619 second
1620       YYYY-MM-DDThh:mm:ss.sTZD (eg 1997-07-16T19:20:30.45+01:00)
1621 
1622 Example:
1623 1994-11-05T08:15:30-05:00 corresponds to November 5, 1994, 8:15:30 am,
1624    US Eastern Standard Time.
1625 1994-11-05T13:15:30Z corresponds to the same instant.
1626 */
1627 
Clock_ScanDash(char * word,int * mon,int * day,sInt4 * year,double * ptime,char * f_time)1628 static int Clock_ScanDash (char *word, int *mon, int *day, sInt4 *year,
1629                            double *ptime, char *f_time)
1630 {
1631    char *ptr3;
1632    char *ptr = word;
1633    sInt4 hour, min;
1634    double sec;
1635    char temp;
1636    sInt4 offset;
1637 
1638    ptr3 = strchr (ptr, '-');
1639    if( !ptr3 ) return -1;
1640    *ptr3 = '\0';
1641    *year = atoi (ptr);
1642    *ptr3 = '-';
1643    ptr = ptr3 + 1;
1644    /* Check for second -, other wise it is yyyy-mm */
1645    if ((ptr3 = strchr (ptr, '-')) == NULL) {
1646       /* Don't touch time or f_time */
1647       *mon = atoi (ptr);
1648       *day = 1;
1649       if ((*mon < 1) || (*mon > 12)) {
1650          printf ("Errors parsing %s\n", word);
1651          return -1;
1652       }
1653       return 0;
1654    }
1655    *ptr3 = '\0';
1656    *mon = atoi (ptr);
1657    *ptr3 = '-';
1658    ptr = ptr3 + 1;
1659    if ((ptr3 = strchr (ptr, 'T')) == NULL) {
1660       /* Don't touch time or f_time */
1661       *day = atoi (ptr);
1662       if ((*mon < 1) || (*mon > 12) || (*day < 1) || (*day > 31)) {
1663          printf ("Errors parsing %s\n", word);
1664          return -1;
1665       }
1666       return 0;
1667    }
1668    *ptr3 = '\0';
1669    *day = atoi (ptr);
1670    *ptr3 = 'T';
1671    ptr = ptr3 + 1;
1672    /* hh:mmTZD */
1673    /* hh:mm:ssTZD */
1674    /* hh:mm:ss.sTZD */
1675    if (strlen (ptr) < 5) {
1676       printf ("Errors parsing %s\n", word);
1677       return -1;
1678    }
1679    ptr[2] = '\0';
1680    hour = atoi (ptr);
1681    ptr[2] = ':';
1682    ptr += 3;
1683    offset = 0;
1684    sec = 0;
1685    if (strlen (ptr) == 2) {
1686       min = atoi (ptr);
1687    } else {
1688       temp = ptr[2];
1689       ptr[2] = '\0';
1690       min = atoi (ptr);
1691       ptr[2] = temp;
1692       if (temp == ':') {
1693          ptr += 3;
1694          if ((ptr3 = strchr (ptr, '+')) == NULL) {
1695             if ((ptr3 = strchr (ptr, '-')) == NULL) {
1696                ptr3 = strchr (ptr, 'Z');
1697             }
1698          }
1699          if (ptr3 == NULL) {
1700             sec = atof (ptr);
1701          } else {
1702             temp = *ptr3;
1703             *ptr3 = '\0';
1704             sec = atof (ptr);
1705             *ptr3 = temp;
1706             if (temp != 'Z') {
1707                ptr = ptr3;
1708                ptr[3] = '\0';
1709                offset = atoi (ptr) * 3600;
1710                ptr[3] = ':';
1711                ptr += 4;
1712                offset += atoi (ptr) * 60;
1713             }
1714          }
1715       } else if (temp != 'Z') {
1716          ptr += 2;
1717          ptr[3] = '\0';
1718          offset = atoi (ptr) * 3600;
1719          ptr[3] = ':';
1720          ptr += 4;
1721          offset += atoi (ptr) * 60;
1722       }
1723    }
1724    *f_time = 1;
1725    *ptime = sec + min * 60 + hour * 3600 - offset;
1726    return 0;
1727 }
1728 #endif // unused_by_GDAL
1729 
1730 /*****************************************************************************
1731  * Clock_ScanDate() --
1732  *
1733  * Arthur Taylor / MDL
1734  *
1735  * PURPOSE
1736  *
1737  * ARGUMENTS
1738  *
1739  * RETURNS: void
1740  *
1741  * HISTORY
1742  *   3/2005 Arthur Taylor (MDL/RSIS): Commented.
1743  *
1744  * NOTES
1745  *****************************************************************************
1746  */
1747 /* prj::slosh prj::stm2trk and prj::degrib use this with l_clock zero'ed
1748    out, so I have now made sure l_clock is zero'ed. */
Clock_ScanDate(double * l_clock,sInt4 year,int mon,int day)1749 void Clock_ScanDate (double *l_clock, sInt4 year, int mon, int day)
1750 {
1751    int i;
1752    sInt4 delt, temp, totDay;
1753 
1754    /* Makes sure l_clock is zero'ed out. */
1755    *l_clock = 0;
1756 
1757    if ((mon < 1) || (mon > 12) || (day < 0) || (day > 31))
1758       return;
1759    if( year < -10000 || year > 10000 )
1760        return;
1761    totDay = Clock_NumDay (mon, day, year, 0);
1762    if (day > totDay)
1763       return;
1764    totDay = Clock_NumDay (mon, day, year, 1);
1765    temp = 1970;
1766    delt = year - temp;
1767    if ((delt >= 400) || (delt <= -400)) {
1768       i = (delt / 400);
1769       temp += 400 * i;
1770       totDay += 146097L * i;
1771    }
1772    if (temp < year) {
1773       while (temp < year) {
1774          if (((temp % 4) == 0) &&
1775              (((temp % 100) != 0) || ((temp % 400) == 0))) {
1776             if ((temp + 4) < year) {
1777                totDay += 1461;
1778                temp += 4;
1779             } else if ((temp + 3) < year) {
1780                totDay += 1096;
1781                temp += 3;
1782             } else if ((temp + 2) < year) {
1783                totDay += 731;
1784                temp += 2;
1785             } else {
1786                totDay += 366;
1787                temp++;
1788             }
1789          } else {
1790             totDay += 365;
1791             temp++;
1792          }
1793       }
1794    } else if (temp > year) {
1795       while (temp > year) {
1796          temp--;
1797          if (((temp % 4) == 0) &&
1798              (((temp % 100) != 0) || ((temp % 400) == 0))) {
1799             if (year < temp - 3) {
1800                totDay -= 1461;
1801                temp -= 3;
1802             } else if (year < (temp - 2)) {
1803                totDay -= 1096;
1804                temp -= 2;
1805             } else if (year < (temp - 1)) {
1806                totDay -= 731;
1807                temp--;
1808             } else {
1809                totDay -= 366;
1810             }
1811          } else {
1812             totDay -= 365;
1813          }
1814       }
1815    }
1816    *l_clock = *l_clock + ((double) (totDay)) * 24 * 3600;
1817 }
1818 
1819 #ifdef unused_by_GDAL
1820 
Clock_ScanDateNumber(double * l_clock,char * buffer)1821 int Clock_ScanDateNumber (double *l_clock, char *buffer)
1822 {
1823    int buffLen = (int)strlen (buffer);
1824    sInt4 year;
1825    int mon = 1;
1826    int day = 1;
1827    int hour = 0;
1828    int min = 0;
1829    int sec = 0;
1830    char c_temp;
1831 
1832    *l_clock = 0;
1833    if ((buffLen != 4) && (buffLen != 6) && (buffLen != 8) &&
1834        (buffLen != 10) && (buffLen != 12) && (buffLen != 14)) {
1835       return 1;
1836    }
1837    c_temp = buffer[4];
1838    buffer[4] = '\0';
1839    year = atoi (buffer);
1840    buffer[4] = c_temp;
1841    if (buffLen > 4) {
1842       c_temp = buffer[6];
1843       buffer[6] = '\0';
1844       mon = atoi (buffer + 4);
1845       buffer[6] = c_temp;
1846    }
1847    if (buffLen > 6) {
1848       c_temp = buffer[8];
1849       buffer[8] = '\0';
1850       day = atoi (buffer + 6);
1851       buffer[8] = c_temp;
1852    }
1853    if (buffLen > 8) {
1854       c_temp = buffer[10];
1855       buffer[10] = '\0';
1856       hour = atoi (buffer + 8);
1857       buffer[10] = c_temp;
1858    }
1859    if (buffLen > 10) {
1860       c_temp = buffer[12];
1861       buffer[12] = '\0';
1862       min = atoi (buffer + 10);
1863       buffer[12] = c_temp;
1864    }
1865    if (buffLen > 12) {
1866       c_temp = buffer[14];
1867       buffer[14] = '\0';
1868       sec = atoi (buffer + 12);
1869       buffer[14] = c_temp;
1870    }
1871    Clock_ScanDate (l_clock, year, mon, day);
1872    *l_clock = *l_clock + sec + min * 60 + hour * 3600;
1873    return 0;
1874 }
1875 
Clock_PrintDateNumber(double l_clock,char buffer[15])1876 void Clock_PrintDateNumber (double l_clock, char buffer[15])
1877 {
1878    sInt4 year;
1879    int month, day, hour, min, sec;
1880    double d_sec;
1881 
1882    Clock_PrintDate (l_clock, &year, &month, &day, &hour, &min, &d_sec);
1883    sec = (int) d_sec;
1884    snprintf(buffer, 15, "%04d%02d%02d%02d%02d%02d", year, month, day, hour, min,
1885             sec);
1886 }
1887 
1888 /* Word_types: none, ':' word, '/' word, '-' word, integer word, 'AM'/'PM'
1889  * word, timeZone word, month word, weekDay word, Preceeder to a relativeDate
1890  * word, Postceeder to a relativeDate word, relativeDate word unit, Adjust Day
1891  * word
1892  */
1893 enum {
1894    WT_NONE, WT_COLON, WT_SLASH, WT_DASH, WT_INTEGER, WT_AMPM, WT_TIMEZONE,
1895    WT_MONTH, WT_DAY, WT_PRE_RELATIVE, WT_POST_RELATIVE, WT_RELATIVE_UNIT,
1896    WT_ADJDAY
1897 };
1898 
1899 /*****************************************************************************
1900  * Clock_GetWord() --
1901  *
1902  * Arthur Taylor / MDL
1903  *
1904  * PURPOSE
1905  *
1906  * ARGUMENTS
1907  *
1908  * RETURNS: void
1909  *
1910  * HISTORY
1911  *   3/2005 Arthur Taylor (MDL/RSIS): Commented.
1912  *
1913  * NOTES
1914  *****************************************************************************
1915  */
1916 /* Start at *Start.  Advance Start until it is at first non-space,
1917  * non-',' non-'.' character.  Move End to first space, ',' or '.' after
1918  * new Start location.  Copy up to 30 characters (in caps) into word. */
1919 /* return -1 if no next word, 0 otherwise */
1920 
Clock_GetWord(char ** Start,char ** End,char word[30],int * wordType)1921 static int Clock_GetWord (char **Start, char **End, char word[30],
1922                           int *wordType)
1923 {
1924    char *ptr;
1925    int cnt;
1926    int f_integer;
1927 
1928    *wordType = WT_NONE;
1929    if (*Start == NULL) {
1930       return -1;
1931    }
1932    ptr = *Start;
1933    /* Find start of next word (first non-space non-',' non-'.' char.) */
1934    while ((*ptr == ' ') || (*ptr == ',') || (*ptr == '.')) {
1935       ptr++;
1936    }
1937    /* There is no next word. */
1938    if (*ptr == '\0') {
1939       return -1;
1940    }
1941    *Start = ptr;
1942    /* Find end of next word. */
1943    cnt = 0;
1944    f_integer = 1;
1945    while ((*ptr != ' ') && (*ptr != ',') && (*ptr != '\0')) {
1946       if (cnt < 29) {
1947          word[cnt] = (char) toupper (*ptr);
1948          cnt++;
1949       }
1950       if (*ptr == ':') {
1951          if (*wordType == WT_NONE)
1952             *wordType = WT_COLON;
1953          f_integer = 0;
1954       } else if (*ptr == '/') {
1955          if (*wordType == WT_NONE)
1956             *wordType = WT_SLASH;
1957          f_integer = 0;
1958       } else if (*ptr == '-') {
1959          if (ptr != *Start) {
1960             if (*wordType == WT_NONE)
1961                *wordType = WT_DASH;
1962             f_integer = 0;
1963          }
1964       } else if (*ptr == '.') {
1965          if (!isdigit (*(ptr + 1))) {
1966             break;
1967          } else {
1968             f_integer = 0;
1969          }
1970       } else if (!isdigit (*ptr)) {
1971          f_integer = 0;
1972       }
1973       ptr++;
1974    }
1975    word[cnt] = '\0';
1976    *End = ptr;
1977    if (f_integer) {
1978       *wordType = WT_INTEGER;
1979    }
1980    return 0;
1981 }
1982 
1983 typedef struct {
1984    sInt4 val;
1985    int len;             /* read from len char string? */
1986 } stackType;
1987 
1988 typedef struct {
1989    int relUnit;
1990    int f_negate;
1991    int amount;
1992 } relType;
1993 
1994 /*****************************************************************************
1995  * Clock_Scan() --
1996  *
1997  * Arthur Taylor / MDL
1998  *
1999  * PURPOSE
2000  *
2001  * ARGUMENTS
2002  *
2003  * RETURNS: void
2004  *
2005  * HISTORY
2006  *
2007  * NOTES
2008  * * f_gmt == 0 no adjust, 1 adjust as LDT, 2 adjust as LST *
2009  *  Adjusted from:
2010  * if ((f_gmt == 2) && (Clock_IsDaylightSaving2 (*l_clock, 0) == 1)) {
2011  * to:
2012  * if ((f_gmt == 1) && (Clock_IsDaylightSaving2 (*l_clock, 0) == 1)) {
2013 
2014  *****************************************************************************
2015  */
2016 
Clock_Scan(double * l_clock,char * buffer,char f_gmt)2017 int Clock_Scan (double *l_clock, char *buffer, char f_gmt)
2018 {
2019    char *ptr, *ptr2;
2020    char *ptr3;
2021    char word[30];
2022    int wordType;
2023    int lastWordType;
2024    sChar TimeZone = Clock_GetTimeZone ();
2025    /* hours to add to local time to get UTC. */
2026    char f_dayLight = 0;
2027    int month = 0;
2028    int day;
2029    sInt4 year;
2030    char f_year = 0;
2031    int l_index;
2032    int ans;
2033    stackType *Stack = NULL;
2034    relType *Rel = NULL;
2035    int lenRel = 0;
2036    int lenStack = 0;
2037    static const char * const PreRel[] = { "LAST", "THIS", "NEXT", NULL };
2038    static const char * const RelUnit[] = {
2039       "YEAR", "YEARS", "MONTH", "MONTHS", "FORTNIGHT", "FORTNIGHTS", "WEEK",
2040       "WEEKS", "DAY", "DAYS", "HOUR", "HOURS", "MIN", "MINS", "MINUTE",
2041       "MINUTES", "SEC", "SECS", "SECOND", "SECONDS", NULL
2042    };
2043    static const char * const AdjDay[] = { "YESTERDAY", "TODAY", "TOMORROW", NULL };
2044    sChar f_ampm = -1;
2045    char f_timeZone = 0;
2046    char f_time = 0;
2047    /* char f_date = 0; */
2048    char f_slashWord = 0;
2049    char f_dateWord = 0;
2050    char f_monthWord = 0;
2051    char f_dayWord = 0;
2052    double curTime;
2053    sInt4 sec;
2054    int i;
2055    int monthAdj;
2056    int yearAdj;
2057 
2058    /* Check that they gave us a string */
2059    ptr = buffer;
2060    if (*ptr == '\0')
2061       return 0;
2062 
2063    f_time = 0;
2064    /* f_date = 0; */
2065    lastWordType = WT_NONE;
2066    curTime = 0;
2067    while (Clock_GetWord (&ptr, &ptr2, word, &wordType) == 0) {
2068       if (wordType == WT_COLON) {
2069          if (f_time) {
2070             printf ("Detected multiple time pieces\n");
2071             goto errorReturn;
2072          }
2073          curTime = Clock_ScanColon (word);
2074          f_time = 1;
2075       } else if (wordType == WT_SLASH) {
2076          if ((f_slashWord) || (f_dateWord)) {
2077             printf ("Detected multiple date pieces\n");
2078             goto errorReturn;
2079          }
2080          Clock_ScanSlash (word, &month, &day, &year, &f_year);
2081          f_slashWord = 1;
2082       } else if (wordType == WT_DASH) {
2083          if ((f_slashWord) || (f_dateWord)) {
2084             printf ("Detected multiple date pieces\n");
2085             goto errorReturn;
2086          }
2087          Clock_ScanDash (word, &month, &day, &year, &curTime, &f_time);
2088          f_year = 1;
2089          f_slashWord = 1;
2090          TimeZone = 0;
2091       } else if (wordType == WT_INTEGER) {
2092          lenStack++;
2093          Stack = (stackType *) realloc ((void *) Stack,
2094                                         lenStack * sizeof (stackType));
2095          Stack[lenStack - 1].val = atoi (word);
2096          Stack[lenStack - 1].len = (int)strlen (word);
2097       } else if (strcmp (word, "AM") == 0) {
2098          if (f_ampm != -1) {
2099             printf ("Detected multiple am/pm\n");
2100             goto errorReturn;
2101          }
2102          f_ampm = 1;
2103          wordType = WT_AMPM;
2104       } else if (strcmp (word, "PM") == 0) {
2105          if (f_ampm != -1) {
2106             printf ("Detected multiple am/pm\n");
2107             goto errorReturn;
2108          }
2109          f_ampm = 2;
2110          wordType = WT_AMPM;
2111       } else if (Clock_ScanZone2 (word, &TimeZone, &f_dayLight) == 0) {
2112          if (f_timeZone) {
2113             printf ("Detected multiple time zones.\n");
2114             goto errorReturn;
2115          }
2116          if (f_dayLight == 0) {
2117             f_gmt = 2;
2118          } else {
2119             f_gmt = 1;
2120          }
2121          f_timeZone = 1;
2122          wordType = WT_TIMEZONE;
2123       } else if ((l_index = Clock_ScanMonth (word)) != -1) {
2124          if ((f_slashWord) || (f_monthWord)) {
2125             printf ("Detected multiple months or already defined month.\n");
2126             goto errorReturn;
2127          }
2128          month = l_index;
2129          /* Get the next word? First preserve the pointer */
2130          ptr3 = ptr2;
2131          ptr = ptr2;
2132          ans = Clock_GetWord (&ptr, &ptr2, word, &wordType);
2133          if ((ans != 0) || (wordType != WT_INTEGER)) {
2134             /* Next word not integer, so previous word is integral day. */
2135             if (lastWordType != WT_INTEGER) {
2136                printf ("Problems with month word and finding the day.\n");
2137                goto errorReturn;
2138             }
2139             lenStack--;
2140             if( Stack ) day = Stack[lenStack].val;
2141             /* Put the next word back under consideration. */
2142             wordType = WT_MONTH;
2143             ptr2 = ptr3;
2144          } else {
2145             /* If word is trailed by comma, then it is day, and the next one
2146              * is the year, otherwise it is a year, and the number before the
2147              * month is the day.  */
2148             if (*ptr2 == ',') {
2149                day = atoi (word);
2150                ptr = ptr2;
2151                ans = Clock_GetWord (&ptr, &ptr2, word, &wordType);
2152                if ((ans != 0) || (wordType != WT_INTEGER)) {
2153                   printf ("Couldn't find the year after the day.\n");
2154                   goto errorReturn;
2155                }
2156                year = atoi (word);
2157                f_year = 1;
2158             } else {
2159                year = atoi (word);
2160                f_year = 1;
2161                if (lastWordType != WT_INTEGER) {
2162                   printf ("Problems with month word and finding the day.\n");
2163                   goto errorReturn;
2164                }
2165                lenStack--;
2166                if( Stack ) day = Stack[lenStack].val;
2167             }
2168          }
2169          f_monthWord = 1;
2170          f_dateWord = 1;
2171 
2172          /* Ignore the day of the week info? */
2173       } else if ((l_index = Clock_ScanWeekday (word)) != -1) {
2174          if ((f_slashWord) || (f_dayWord)) {
2175             printf ("Detected multiple day of week or already defined "
2176                     "day.\n");
2177             goto errorReturn;
2178          }
2179          wordType = WT_DAY;
2180          f_dayWord = 1;
2181          f_dateWord = 1;
2182       } else if (GetIndexFromStr (word, PreRel, &l_index) != -1) {
2183          wordType = WT_PRE_RELATIVE;
2184          /* Next word must be a unit word. */
2185          ptr = ptr2;
2186          if (Clock_GetWord (&ptr, &ptr2, word, &wordType) != 0) {
2187             printf ("Couldn't get the next word after Pre-Relative time "
2188                     "word\n");
2189             goto errorReturn;
2190          }
2191          if (GetIndexFromStr (word, RelUnit, &ans) == -1) {
2192             printf ("Couldn't get the Relative unit\n");
2193             goto errorReturn;
2194          }
2195          if (l_index != 1) {
2196             lenRel++;
2197             Rel = (relType *) realloc ((void *) Rel,
2198                                        lenRel * sizeof (relType));
2199             Rel[lenRel - 1].relUnit = ans;
2200             Rel[lenRel - 1].amount = 1;
2201             if (l_index == 0) {
2202                Rel[lenRel - 1].f_negate = 1;
2203             } else {
2204                Rel[lenRel - 1].f_negate = 0;
2205             }
2206          }
2207          printf ("Pre Relative Word: %s %d\n", word, l_index);
2208 
2209       } else if (strcmp (word, "AGO") == 0) {
2210          if ((lastWordType != WT_PRE_RELATIVE) &&
2211              (lastWordType != WT_RELATIVE_UNIT)) {
2212             printf ("Ago did not follow relative words\n");
2213             goto errorReturn;
2214          }
2215          Rel[lenRel - 1].f_negate = 1;
2216          wordType = WT_POST_RELATIVE;
2217       } else if (GetIndexFromStr (word, RelUnit, &l_index) != -1) {
2218          lenRel++;
2219          Rel = (relType *) realloc ((void *) Rel, lenRel * sizeof (relType));
2220          Rel[lenRel - 1].relUnit = l_index;
2221          Rel[lenRel - 1].amount = 1;
2222          Rel[lenRel - 1].f_negate = 0;
2223          if (lastWordType == WT_INTEGER && Stack) {
2224             lenStack--;
2225             Rel[lenRel - 1].amount = Stack[lenStack].val;
2226          }
2227          wordType = WT_RELATIVE_UNIT;
2228       } else if (GetIndexFromStr (word, AdjDay, &l_index) != -1) {
2229          if (l_index != 1) {
2230             lenRel++;
2231             Rel = (relType *) realloc ((void *) Rel,
2232                                        lenRel * sizeof (relType));
2233             Rel[lenRel - 1].relUnit = 13; /* DAY in RelUnit list */
2234             Rel[lenRel - 1].amount = 1;
2235             if (l_index == 0) {
2236                Rel[lenRel - 1].f_negate = 1;
2237             } else {
2238                Rel[lenRel - 1].f_negate = 0;
2239             }
2240          }
2241          wordType = WT_ADJDAY;
2242       } else {
2243          printf ("unknown: %s\n", word);
2244          goto errorReturn;
2245       }
2246       ptr = ptr2;
2247       lastWordType = wordType;
2248    }
2249 
2250    /* Deal with time left on the integer stack. */
2251    if (lenStack > 1) {
2252       printf ("Too many integers on the stack?\n");
2253       goto errorReturn;
2254    }
2255    if (lenStack == 1) {
2256       if (Stack[0].val < 0) {
2257          printf ("Unable to deduce a negative time?\n");
2258          goto errorReturn;
2259       }
2260       if (f_time) {
2261          if (f_dateWord || f_slashWord) {
2262             printf ("Already have date and time...\n");
2263             goto errorReturn;
2264          }
2265          if ((Stack[0].len == 6) || (Stack[0].len == 8)) {
2266             year = Stack[0].val / 10000;
2267             f_year = 1;
2268             month = (Stack[0].val % 10000) / 100;
2269             day = Stack[0].val % 100;
2270             f_slashWord = 1;
2271             if ((month < 1) || (month > 12) || (day < 1) || (day > 31)) {
2272                printf ("Unable to deduce the integer value\n");
2273                return -1;
2274             }
2275          } else {
2276             printf ("Unable to deduce the integer value\n");
2277             goto errorReturn;
2278          }
2279       } else {
2280          if (Stack[0].len < 3) {
2281             curTime = Stack[0].val * 3600;
2282             f_time = 1;
2283          } else if (Stack[0].len < 5) {
2284             curTime = ((Stack[0].val / 100) * 3600. +
2285                        (Stack[0].val % 100) * 60.);
2286             f_time = 1;
2287          } else if ((Stack[0].len == 6) || (Stack[0].len == 8)) {
2288             year = Stack[0].val / 10000;
2289             f_year = 1;
2290             month = (Stack[0].val % 10000) / 100;
2291             day = Stack[0].val % 100;
2292             f_slashWord = 1;
2293             if ((month < 1) || (month > 12) || (day < 1) || (day > 31)) {
2294                printf ("Unable to deduce the integer value\n");
2295                free( Rel );
2296                free( Stack );
2297                return -1;
2298             }
2299          } else {
2300             printf ("Unable to deduce the time\n");
2301             goto errorReturn;
2302          }
2303       }
2304       /*lenStack = 0;*/
2305    }
2306    if (!f_time) {
2307       if (f_ampm != -1) {
2308          printf ("Problems setting the time to 0\n");
2309          goto errorReturn;
2310       }
2311       curTime = 0;
2312    }
2313    if (f_ampm == 1) {
2314       /* Adjust for 12 am */
2315       sec = (sInt4) (curTime - (floor (curTime / SEC_DAY)) * SEC_DAY);
2316       if (((sec % 43200L) / 3600) == 0) {
2317          curTime -= 43200L;
2318       }
2319    } else if (f_ampm == 2) {
2320       /* Adjust for 12 pm */
2321       curTime += 43200L;
2322       sec = (sInt4) (curTime - (floor (curTime / SEC_DAY)) * SEC_DAY);
2323       if (((sec % 43200L) / 3600) == 0) {
2324          curTime -= 43200L;
2325       }
2326    }
2327    for (i = 0; i < lenRel; i++) {
2328       if (Rel[i].f_negate) {
2329          Rel[i].amount = -1 * Rel[i].amount;
2330       }
2331    }
2332    /* Deal with adjustments by year or month. */
2333    if (f_dateWord || f_slashWord) {
2334       /* Check if we don't have the year. */
2335       if (!f_year) {
2336          *l_clock = Clock_Seconds ();
2337          Clock_Epoch2YearDay ((sInt4) (floor (*l_clock / SEC_DAY)), &i, &year);
2338       }
2339       /* Deal with relative adjust by year and month. */
2340       for (i = 0; i < lenRel; i++) {
2341          if ((Rel[i].relUnit == 0) || (Rel[i].relUnit == 1)) {
2342             year += Rel[i].amount;
2343          } else if ((Rel[i].relUnit == 2) || (Rel[i].relUnit == 3)) {
2344             month += Rel[i].amount;
2345          }
2346       }
2347       if (month > 12) {
2348          int incrYearDueToMonth = (month-1) / 12;
2349          year += incrYearDueToMonth;
2350          month -= 12 * incrYearDueToMonth;
2351       }
2352       else if( month <= 0) {
2353          int incrYearDueToMonth = (month-12) / 12;
2354          year += incrYearDueToMonth;
2355          month -= 12 * incrYearDueToMonth;
2356       }
2357       *l_clock = 0;
2358       Clock_ScanDate (l_clock, year, month, day);
2359 
2360    } else {
2361       /* Pure Time words. */
2362       *l_clock = Clock_Seconds ();
2363       /* round off to start of day */
2364       *l_clock = (floor (*l_clock / SEC_DAY)) * SEC_DAY;
2365       /* Deal with relative adjust by year and month. */
2366       monthAdj = 0;
2367       yearAdj = 0;
2368       for (i = 0; i < lenRel; i++) {
2369          if ((Rel[i].relUnit == 0) || (Rel[i].relUnit == 1)) {
2370             if (Rel[i].f_negate) {
2371                yearAdj -= Rel[i].amount;
2372             } else {
2373                yearAdj += Rel[i].amount;
2374             }
2375          } else if ((Rel[i].relUnit == 2) || (Rel[i].relUnit == 3)) {
2376             if (Rel[i].f_negate) {
2377                monthAdj -= Rel[i].amount;
2378             } else {
2379                monthAdj += Rel[i].amount;
2380             }
2381          }
2382       }
2383       if ((monthAdj != 0) || (yearAdj != 0)) {
2384          /* Break l_clock into mon/day/year */
2385          Clock_Epoch2YearDay ((sInt4) (floor (*l_clock / SEC_DAY)),
2386                               &day, &year);
2387          month = Clock_MonthNum (day, year);
2388          day -= (Clock_NumDay (month, 1, year, 1) - 1);
2389          month += monthAdj;
2390          year += yearAdj;
2391          if (month > 12) {
2392             int incrYearDueToMonth = (month-1) / 12;
2393             year += incrYearDueToMonth;
2394             month -= 12 * incrYearDueToMonth;
2395          }
2396          else if( month <= 0) {
2397             int incrYearDueToMonth = (month-12) / 12;
2398             year += incrYearDueToMonth;
2399             month -= 12 * incrYearDueToMonth;
2400          }
2401          *l_clock = 0;
2402          Clock_ScanDate (l_clock, year, month, day);
2403       }
2404    }
2405 
2406    /* Join the date and the time. */
2407    *l_clock += curTime;
2408 
2409    /* Finish the relative adjustments. */
2410    for (i = 0; i < lenRel; i++) {
2411       switch (Rel[i].relUnit) {
2412          case 3:       /* Fortnight. */
2413          case 4:
2414             *l_clock += (Rel[i].amount * 14 * 24 * 3600.);
2415             break;
2416          case 5:       /* Week. */
2417          case 6:
2418             *l_clock += (Rel[i].amount * 7 * 24 * 3600.);
2419             break;
2420          case 7:       /* Day. */
2421          case 8:
2422             *l_clock += (Rel[i].amount * 24 * 3600.);
2423             break;
2424          case 9:       /* Hour. */
2425          case 10:
2426             *l_clock += (Rel[i].amount * 3600.);
2427             break;
2428          case 11:      /* Minute. */
2429          case 12:
2430          case 13:
2431          case 14:
2432             *l_clock += (Rel[i].amount * 60.);
2433             break;
2434          case 15:      /* Second. */
2435          case 16:
2436          case 17:
2437          case 18:
2438             *l_clock += Rel[i].amount;
2439             break;
2440       }
2441    }
2442 
2443    if (f_gmt != 0) {
2444       /* IsDaylightSaving takes l_clock in GMT, and Timezone. */
2445       /* Note: A 0 is passed to DaylightSavings so it converts from LST to
2446        * LST. */
2447       if ((f_gmt == 1) && (Clock_IsDaylightSaving2 (*l_clock, 0) == 1)) {
2448          *l_clock = *l_clock - 3600;
2449       }
2450       /* Handle gmt problems. We are going from Local time to GMT so we add
2451        * the TimeZone here. */
2452       *l_clock = *l_clock + TimeZone * 3600;
2453    }
2454 
2455    free (Stack);
2456    free (Rel);
2457    return 0;
2458 
2459  errorReturn:
2460    free (Stack);
2461    free (Rel);
2462    return -1;
2463 }
2464 
2465 #endif // unused_by_GDAL
2466 
Clock_AddMonthYear(double refTime,int incrMonth,int incrYear)2467 double Clock_AddMonthYear (double refTime, int incrMonth, int incrYear)
2468 {
2469    sInt4 totDay;
2470    int day;
2471    sInt4 year;
2472    int month;
2473    double d_remain;
2474    int i;
2475 
2476    if( !(fabs(refTime) < (double)SEC_DAY * 365 * 10000) )
2477    {
2478        fprintf(stderr, "invalid refTime = %f\n", refTime);
2479        return 0;
2480    }
2481 
2482    totDay = (sInt4) floor (refTime / SEC_DAY);
2483    Clock_Epoch2YearDay (totDay, &day, &year);
2484    month = Clock_MonthNum (day, year);
2485    day = day - Clock_NumDay (month, 1, year, 1) + 1;
2486    d_remain = refTime - (double)totDay * 3600 * 24.0;
2487 
2488    /* Add the month */
2489    if (incrMonth != 0) {
2490       if( incrMonth > 0 && month > INT_MAX - incrMonth )
2491       {
2492           fprintf(stderr, "invalid incrMonth = %d\n", incrMonth);
2493           return 0;
2494       }
2495       if( incrMonth < 0 && month < INT_MIN-(-12) - incrMonth )
2496       {
2497           fprintf(stderr, "invalid incrMonth = %d\n", incrMonth);
2498           return 0;
2499       }
2500       month += incrMonth;
2501       if (month > 12) {
2502          int incrYearDueToMonth = (month-1) / 12;
2503          year += incrYearDueToMonth;
2504          month -= 12 * incrYearDueToMonth;
2505       }
2506       else if( month <= 0) {
2507          int incrYearDueToMonth = (month-12) / 12;
2508          year += incrYearDueToMonth;
2509          month -= 12 * incrYearDueToMonth;
2510       }
2511    }
2512    /* Add the year. */
2513    if (incrYear != 0) {
2514       if (incrYear > 0 && year > INT_MAX - incrYear) {
2515          fprintf(stderr, "overflow. year: %d incrYear: %d\n", year, incrYear);
2516          return 0;
2517       }
2518       if (incrYear < 0 && year < INT_MIN - incrYear) {
2519          fprintf(stderr, "overflow. year: %d incrYear: %d\n", year, incrYear);
2520          return 0;
2521       }
2522       year += incrYear;
2523    }
2524 
2525    /* Recompose the date */
2526    i = Clock_NumDay (month, 1, year, 0);
2527    if (day > i) {
2528       day = i;
2529    }
2530    refTime = 0;
2531    Clock_ScanDate (&refTime, year, month, day);
2532    refTime += d_remain;
2533    return refTime;
2534 }
2535 
2536 #ifdef CLOCK_PROGRAM
2537 /* See clockstart.c */
2538 #endif
2539