GCC Code Coverage Report


Directory: src/solver/
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 79.7% 149 / 0 / 187
Functions: 95.2% 20 / 0 / 21
Branches: 56.5% 61 / 0 / 108

datetime.c
Line Branch Exec Source
1 //-----------------------------------------------------------------------------
2 // datetime.c
3 //
4 // Project: EPA SWMM5
5 // Version: 5.2
6 // Date: 11/01/21 (Build 5.2.0)
7 // Author: L. Rossman
8 //
9 // DateTime functions.
10 //
11 // Update History
12 // ==============
13 // Build 5.1.011:
14 // - decodeTime() no longer rounds up.
15 // - New getTimeStamp function added.
16 //-----------------------------------------------------------------------------
17 #define _CRT_SECURE_NO_DEPRECATE
18
19 #include <math.h>
20 #include <string.h>
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include "datetime.h"
24
25 // Macro to convert charcter x to upper case
26 #define UCHAR(x) (((x) >= 'a' && (x) <= 'z') ? ((x)&~32) : (x))
27
28 //-----------------------------------------------------------------------------
29 // Constants
30 //-----------------------------------------------------------------------------
31 static const char* MonthTxt[] =
32 {"JAN", "FEB", "MAR", "APR",
33 "MAY", "JUN", "JUL", "AUG",
34 "SEP", "OCT", "NOV", "DEC"};
35 static const int DaysPerMonth[2][12] = // days per month
36 {{31, 28, 31, 30, 31, 30, // normal years
37 31, 31, 30, 31, 30, 31},
38 {31, 29, 31, 30, 31, 30, // leap years
39 31, 31, 30, 31, 30, 31}};
40 static const int DateDelta = 693594; // days since 01/01/00
41 static const double SecsPerDay = 86400.; // seconds per day
42
43 //-----------------------------------------------------------------------------
44 // Shared variables
45 //-----------------------------------------------------------------------------
46 static int DateFormat;
47
48
49 //=============================================================================
50
51 20398049 void divMod(int n, int d, int* result, int* remainder)
52
53 // Input: n = numerator
54 // d = denominator
55 // Output: result = integer part of n/d
56 // remainder = remainder of n/d
57 // Purpose: finds integer part and remainder of n/d.
58
59 {
60
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20398049 times.
20398049 if (d == 0)
61 {
62 *result = 0;
63 *remainder = 0;
64 }
65 else
66 {
67 20398049 *result = n/d;
68 20398049 *remainder = n - d*(*result);
69 }
70 20398049 }
71
72 //=============================================================================
73
74 4202559 int isLeapYear(int year)
75
76 // Input: year = a year
77 // Output: returns 1 if year is a leap year, 0 if not
78 // Purpose: determines if year is a leap year.
79
80 {
81
2/2
✓ Branch 0 taken 417356 times.
✓ Branch 1 taken 3785203 times.
4202559 if ((year % 4 == 0)
82
2/2
✓ Branch 0 taken 1559 times.
✓ Branch 1 taken 415797 times.
417356 && ((year % 100 != 0)
83
1/2
✓ Branch 0 taken 1559 times.
✗ Branch 1 not taken.
417356 || (year % 400 == 0))) return 1;
84 3785203 else return 0;
85 }
86
87 //=============================================================================
88
89 7786 int datetime_findMonth(char* month)
90
91 // Input: month = month of year as character string
92 // Output: returns: month of year as a number (1-12)
93 // Purpose: finds number (1-12) of month.
94
95 {
96 int i;
97
2/2
✓ Branch 0 taken 50676 times.
✓ Branch 1 taken 12 times.
50688 for (i = 0; i < 12; i++)
98 {
99
3/6
✗ Branch 0 not taken.
✓ Branch 1 taken 50676 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 11036 times.
✓ Branch 5 taken 39640 times.
50676 if (UCHAR(month[0]) == MonthTxt[i][0]
100
5/6
✓ Branch 0 taken 11012 times.
✓ Branch 1 taken 24 times.
✓ Branch 2 taken 11012 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 9070 times.
✓ Branch 5 taken 1966 times.
11036 && UCHAR(month[1]) == MonthTxt[i][1]
101
4/6
✓ Branch 0 taken 9070 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9070 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 7774 times.
✓ Branch 5 taken 1296 times.
9070 && UCHAR(month[2]) == MonthTxt[i][2]) return i+1;
102 }
103 12 return 0;
104 }
105
106 //=============================================================================
107
108 281716 DateTime datetime_encodeDate(int year, int month, int day)
109
110 // Input: year = a year
111 // month = a month (1 to 12)
112 // day = a day of month
113 // Output: returns encoded value of year-month-day
114 // Purpose: encodes year-month-day to a DateTime value.
115
116 {
117 int i, j;
118 281716 i = isLeapYear(year);
119
1/2
✓ Branch 0 taken 281716 times.
✗ Branch 1 not taken.
281716 if ((year >= 1)
120
1/2
✓ Branch 0 taken 281716 times.
✗ Branch 1 not taken.
281716 && (year <= 9999)
121
1/2
✓ Branch 0 taken 281716 times.
✗ Branch 1 not taken.
281716 && (month >= 1)
122
1/2
✓ Branch 0 taken 281716 times.
✗ Branch 1 not taken.
281716 && (month <= 12)
123
1/2
✓ Branch 0 taken 281716 times.
✗ Branch 1 not taken.
281716 && (day >= 1)
124
1/2
✓ Branch 0 taken 281716 times.
✗ Branch 1 not taken.
281716 && (day <= DaysPerMonth[i][month-1]))
125 {
126
2/2
✓ Branch 0 taken 1337041 times.
✓ Branch 1 taken 281716 times.
1618757 for (j = 0; j < month-1; j++) day += DaysPerMonth[i][j];
127 281716 i = year - 1;
128 281716 i = i*365 + i/4 - i/100 + i/400 + day - DateDelta;
129 281716 return i;
130 }
131 else return -DateDelta;
132 }
133
134 //=============================================================================
135
136 248945 DateTime datetime_encodeTime(int hour, int minute, int second)
137
138 // Input: hour = hour of day (0-24)
139 // minute = minute of hour (0-60)
140 // second = seconds of minute (0-60)
141 // Output: returns time encoded as fractional part of a day
142 // Purpose: encodes hour:minute:second to a DateTime value
143
144 {
145 int s;
146
1/2
✓ Branch 0 taken 248945 times.
✗ Branch 1 not taken.
248945 if ((hour >= 0)
147
1/2
✓ Branch 0 taken 248945 times.
✗ Branch 1 not taken.
248945 && (minute >= 0)
148
1/2
✓ Branch 0 taken 248945 times.
✗ Branch 1 not taken.
248945 && (second >= 0))
149 {
150 248945 s = (hour * 3600 + minute * 60 + second);
151 248945 return (double)s/SecsPerDay;
152 }
153 else return 0.0;
154 }
155
156 //=============================================================================
157
158 3920831 void datetime_decodeDate(DateTime date, int* year, int* month, int* day)
159
160 // Input: date = encoded date/time value
161 // Output: year = 4-digit year
162 // month = month of year (1-12)
163 // day = day of month
164 // Purpose: decodes DateTime value to year-month-day.
165
166 {
167 int D1, D4, D100, D400;
168 int y, m, d, i, k, t;
169
170 3920831 D1 = 365; //365
171 3920831 D4 = D1 * 4 + 1; //1461
172 3920831 D100 = D4 * 25 - 1; //36524
173 3920831 D400 = D100 * 4 + 1; //146097
174
175 3920831 t = (int)(floor (date)) + DateDelta;
176
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3920831 times.
3920831 if (t <= 0)
177 {
178 *year = 0;
179 *month = 1;
180 *day = 1;
181 }
182 else
183 {
184 3920831 t--;
185 3920831 y = 1;
186
2/2
✓ Branch 0 taken 19112532 times.
✓ Branch 1 taken 3920831 times.
23033363 while (t >= D400)
187 {
188 19112532 t -= D400;
189 19112532 y += 400;
190 }
191 3920831 divMod(t, D100, &i, &d);
192
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3920831 times.
3920831 if (i == 4)
193 {
194 i--;
195 d += D100;
196 }
197 3920831 y += i*100;
198 3920831 divMod(d, D4, &i, &d);
199 3920831 y += i*4;
200 3920831 divMod(d, D1, &i, &d);
201
2/2
✓ Branch 0 taken 1729 times.
✓ Branch 1 taken 3919102 times.
3920831 if (i == 4)
202 {
203 1729 i--;
204 1729 d += D1;
205 }
206 3920831 y += i;
207 3920831 k = isLeapYear(y);
208 3920831 m = 1;
209 for (;;)
210 {
211 9790373 i = DaysPerMonth[k][m-1];
212
2/2
✓ Branch 0 taken 3920831 times.
✓ Branch 1 taken 5869542 times.
9790373 if (d < i) break;
213 5869542 d -= i;
214 5869542 m++;
215 }
216 3920831 *year = y;
217 3920831 *month = m;
218 3920831 *day = d + 1;
219 }
220 3920831 }
221
222 //=============================================================================
223
224 4317778 void datetime_decodeTime(DateTime time, int* h, int* m, int* s)
225
226 // Input: time = decimal fraction of a day
227 // Output: h = hour of day (0-23)
228 // m = minute of hour (0-59)
229 // s = second of minute (0-59)
230 // Purpose: decodes DateTime value to hour:minute:second.
231
232 {
233 int secs;
234 int mins;
235 4317778 double fracDay = (time - floor(time)) * SecsPerDay;
236 4317778 secs = (int)(floor(fracDay + 0.5));
237
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4317778 times.
4317778 if ( secs >= 86400 ) secs = 86399;
238 4317778 divMod(secs, 60, &mins, s);
239 4317778 divMod(mins, 60, h, m);
240
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4317778 times.
4317778 if ( *h > 23 ) *h = 0;
241 4317778 }
242
243 //=============================================================================
244
245 1879 void datetime_dateToStr(DateTime date, char* s)
246
247 // Input: date = encoded date/time value
248 // Output: s = formatted date string
249 // Purpose: represents DateTime date value as a formatted string.
250
251 {
252 int y, m, d;
253 1879 datetime_decodeDate(date, &y, &m, &d);
254
1/3
✗ Branch 0 not taken.
✓ Branch 1 taken 1879 times.
✗ Branch 2 not taken.
1879 switch (DateFormat)
255 {
256 case Y_M_D:
257 snprintf(s, DATE_STR_SIZE, "%4d-%3s-%02d", y, MonthTxt[m-1], d);
258 break;
259
260 1879 case M_D_Y:
261 //sprintf(dateStr, "%3s-%02d-%4d", MonthTxt[m-1], d, y);
262 1879 snprintf(s, DATE_STR_SIZE, "%02d/%02d/%04d", m, d, y);
263 1879 break;
264
265 default:
266 snprintf(s, DATE_STR_SIZE, "%02d-%3s-%4d", d, MonthTxt[m-1], y);
267 }
268 1879 }
269
270 2000 void datetime_timeToStr(DateTime time, char* s)
271
272 // Input: time = decimal fraction of a day
273 // Output: s = time in hr:min:sec format
274 // Purpose: represents DateTime time value as a formatted string.
275
276 {
277 int hr, min, sec;
278 2000 datetime_decodeTime(time, &hr, &min, &sec);
279 2000 snprintf(s, TIME_STR_SIZE, "%02d:%02d:%02d", hr, min, sec);
280 2000 }
281
282 //=============================================================================
283
284 168850 int datetime_strToDate(char* s, DateTime* d)
285
286 // Input: s = date as string
287 // Output: d = encoded date;
288 // returns 1 if conversion successful, 0 if not
289 // Purpose: converts string date s to DateTime value.
290 //
291 {
292 168850 int yr = 0, mon = 0, day = 0, n;
293 char month[4];
294 char sep1, sep2;
295 168850 *d = -DateDelta;
296
3/4
✓ Branch 0 taken 168850 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 168018 times.
✓ Branch 3 taken 832 times.
168850 if (strchr(s, '-') || strchr(s, '/'))
297 {
298
1/3
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 168018 times.
168018 switch (DateFormat)
299 {
300 case Y_M_D:
301 n = sscanf(s, "%d%c%d%c%d", &yr, &sep1, &mon, &sep2, &day);
302 if ( n < 3 )
303 {
304 mon = 0;
305 n = sscanf(s, "%d%c%3s%c%d", &yr, &sep1, month, &sep2, &day);
306 if ( n < 3 ) return 0;
307 }
308 break;
309
310 case D_M_Y:
311 n = sscanf(s, "%d%c%d%c%d", &day, &sep1, &mon, &sep2, &yr);
312 if ( n < 3 )
313 {
314 mon = 0;
315 n = sscanf(s, "%d%c%3s%c%d", &day, &sep1, month, &sep2, &yr);
316 if ( n < 3 ) return 0;
317 }
318 break;
319
320 168018 default: // M_D_Y
321 168018 n = sscanf(s, "%d%c%d%c%d", &mon, &sep1, &day, &sep2, &yr);
322
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 168018 times.
168018 if ( n < 3 )
323 {
324 mon = 0;
325 n = sscanf(s, "%3s%c%d%c%d", month, &sep1, &day, &sep2, &yr);
326 if ( n < 3 ) return 0;
327 }
328 }
329
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 168018 times.
168018 if (mon == 0) mon = datetime_findMonth(month);
330 168018 *d = datetime_encodeDate(yr, mon, day);
331 }
332
2/2
✓ Branch 0 taken 832 times.
✓ Branch 1 taken 168018 times.
168850 if (*d == -DateDelta) return 0;
333 168018 else return 1;
334 }
335
336 //=============================================================================
337
338 168898 int datetime_strToTime(char* s, DateTime* t)
339
340 // Input: s = time as string
341 // Output: t = encoded time,
342 // returns 1 if conversion successful, 0 if not
343 // Purpose: converts a string time to a DateTime value.
344 // Note: accepts time as hr:min:sec or as decimal hours.
345
346 {
347 168898 int n, hr, min = 0, sec = 0;
348 char *endptr;
349
350 // Attempt to read time as decimal hours
351 168898 *t = strtod(s, &endptr);
352
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 168886 times.
168898 if ( *endptr == 0 )
353 {
354 12 *t /= 24.0;
355 12 return 1;
356 }
357
358 // Read time in hr:min:sec format
359 168886 *t = 0.0;
360 168886 n = sscanf(s, "%d:%d:%d", &hr, &min, &sec);
361
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 168886 times.
168886 if ( n == 0 ) return 0;
362 168886 *t = datetime_encodeTime(hr, min, sec);
363
3/6
✓ Branch 0 taken 168886 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 168886 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 168886 times.
✗ Branch 5 not taken.
168886 if ( (hr >= 0) && (min >= 0) && (sec >= 0) ) return 1;
364 else return 0;
365 }
366
367 //=============================================================================
368
369 1786 void datetime_setDateFormat(int fmt)
370
371 // Input: fmt = date format code
372 // Output: none
373 // Purpose: sets date format
374
375 {
376
2/4
✓ Branch 0 taken 1786 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1786 times.
✗ Branch 3 not taken.
1786 if ( fmt >= Y_M_D && fmt <= M_D_Y) DateFormat = fmt;
377 1786 }
378
379 //=============================================================================
380
381 3125468 DateTime datetime_addSeconds(DateTime date1, double seconds)
382
383 // Input: date1 = an encoded date/time value
384 // seconds = number of seconds to add to date1
385 // Output: returns updated value of date1
386 // Purpose: adds a given number of seconds to a date/time.
387
388 {
389 3125468 double d = floor(date1);
390 int h, m, s;
391 3125468 datetime_decodeTime(date1, &h, &m, &s);
392 3125468 return d + (3600.0*h + 60.0*m + s + seconds)/SecsPerDay;
393 }
394
395 //=============================================================================
396
397 DateTime datetime_addDays(DateTime date1, DateTime date2)
398
399 // Input: date1 = an encoded date/time value
400 // date2 = decimal days to be added to date1
401 // Output: returns date1 + date2
402 // Purpose: adds a given number of decimal days to a date/time.
403
404 {
405 double d1 = floor(date1);
406 double d2 = floor(date2);
407 int h1, m1, s1;
408 int h2, m2, s2;
409 datetime_decodeTime(date1, &h1, &m1, &s1);
410 datetime_decodeTime(date2, &h2, &m2, &s2);
411 return d1 + d2 + datetime_encodeTime(h1+h2, m1+m2, s1+s2);
412 }
413
414 //=============================================================================
415
416 66917 long datetime_timeDiff(DateTime date1, DateTime date2)
417
418 // Input: date1 = an encoded date/time value
419 // date2 = an encoded date/time value
420 // Output: returns date1 - date2 in seconds
421 // Purpose: finds number of seconds between two dates.
422
423 {
424 66917 double d1 = floor(date1);
425 66917 double d2 = floor(date2);
426 int h, m, s;
427 long s1, s2, secs;
428 66917 datetime_decodeTime(date1, &h, &m, &s);
429 66917 s1 = 3600*h + 60*m + s;
430 66917 datetime_decodeTime(date2, &h, &m, &s);
431 66917 s2 = 3600*h + 60*m + s;
432 66917 secs = (int)(floor((d1 - d2)*SecsPerDay + 0.5));
433 66917 secs += (s1 - s2);
434 66917 return secs;
435 }
436
437 //=============================================================================
438
439 3199582 int datetime_monthOfYear(DateTime date)
440
441 // Input: date = an encoded date/time value
442 // Output: returns index of month of year (1..12)
443 // Purpose: finds month of year (Jan = 1 ...) for a given date.
444
445 {
446 int year, month, day;
447 3199582 datetime_decodeDate(date, &year, &month, &day);
448 3199582 return month;
449 }
450
451 //=============================================================================
452
453 33222 int datetime_dayOfYear(DateTime date)
454
455 // Input: date = an encoded date/time value
456 // Output: returns day of year (1..365)
457 // Purpose: finds day of year (Jan 1 = 1) for a given date.
458
459 {
460 int year, month, day;
461 DateTime startOfYear;
462 33222 datetime_decodeDate(date, &year, &month, &day);
463 33222 startOfYear = datetime_encodeDate(year, 1, 1);
464 33222 return (int)(floor(date - startOfYear)) + 1;
465 }
466
467 //=============================================================================
468
469 1042780 int datetime_dayOfWeek(DateTime date)
470
471 // Input: date = an encoded date/time value
472 // Output: returns index of day of week (1..7)
473 // Purpose: finds day of week (Sun = 1, ... Sat = 7) for a given date.
474
475 {
476 1042780 int t = (int)(floor(date)) + DateDelta;
477 1042780 return (t % 7) + 1;
478 }
479
480 //=============================================================================
481
482 1042780 int datetime_hourOfDay(DateTime date)
483
484 // Input: date = an encoded date/time value
485 // Output: returns hour of day (0..23)
486 // Purpose: finds hour of day (0 = 12 AM, ..., 23 = 11 PM) for a given date.
487
488 {
489 int hour, min, sec;
490 1042780 datetime_decodeTime(date, &hour, &min, &sec);
491 1042780 return hour;
492 }
493
494 //=============================================================================
495
496 12 int datetime_daysPerMonth(int year, int month)
497
498 // Input: year = year in which month falls
499 // month = month of year (1..12)
500 // Output: returns number of days in the month
501 // Purpose: finds number of days in a given month of a specified year.
502
503 {
504
2/4
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 12 times.
12 if ( month < 1 || month > 12 ) return 0;
505 12 return DaysPerMonth[isLeapYear(year)][month-1];
506 }
507
508 //=============================================================================
509
510 1728 void datetime_getTimeStamp(int fmt, DateTime aDate, int stampSize, char* timeStamp)
511
512 // Input: fmt = desired date format code
513 // aDate = a date/time value in decimal days
514 // stampSize = the number of bytes allocated for the time stamp
515 // Output: returns a time stamp string (e.g., Year-Month-Day Hr:Min:Sec)
516 // Purpose: Expresses a decimal day date by a time stamp.
517 {
518 char dateStr[DATE_STR_SIZE];
519 char timeStr[TIME_STR_SIZE];
520 1728 int oldDateFormat = DateFormat;
521
522
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1728 times.
1728 if ( stampSize < TIME_STAMP_SIZE ) return;
523 1728 datetime_setDateFormat(fmt);
524 1728 datetime_dateToStr(aDate, dateStr);
525 1728 DateFormat = oldDateFormat;
526 1728 datetime_timeToStr(aDate, timeStr);
527 1728 snprintf(timeStamp, stampSize, "%s %s", dateStr, timeStr);
528 }
529