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