Coverage Report

Created: 2025-06-09 08:44

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