GCC Code Coverage Report


Directory: src/solver/
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 78.6% 147 / 0 / 187
Functions: 95.2% 20 / 0 / 21
Branches: 54.6% 59 / 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 20817502 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 20817502 times.
20817502 if (d == 0)
61 {
62 *result = 0;
63 *remainder = 0;
64 }
65 else
66 {
67 20817502 *result = n/d;
68 20817502 *remainder = n - d*(*result);
69 }
70 20817502 }
71
72 //=============================================================================
73
74 4126066 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 468805 times.
✓ Branch 1 taken 3657261 times.
4126066 if ((year % 4 == 0)
82
2/2
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 468771 times.
468805 && ((year % 100 != 0)
83
1/2
✓ Branch 0 taken 34 times.
✗ Branch 1 not taken.
468805 || (year % 400 == 0))) return 1;
84 3657261 else return 0;
85 }
86
87 //=============================================================================
88
89 45 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 474 times.
✓ Branch 1 taken 39 times.
513 for (i = 0; i < 12; i++)
98 {
99
3/6
✗ Branch 0 not taken.
✓ Branch 1 taken 474 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 84 times.
✓ Branch 5 taken 390 times.
474 if (UCHAR(month[0]) == MonthTxt[i][0]
100
5/6
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 24 times.
✓ Branch 2 taken 60 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
✓ Branch 5 taken 78 times.
84 && UCHAR(month[1]) == MonthTxt[i][1]
101
3/6
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
6 && UCHAR(month[2]) == MonthTxt[i][2]) return i+1;
102 }
103 39 return 0;
104 }
105
106 //=============================================================================
107
108 32116 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 32116 i = isLeapYear(year);
119
1/2
✓ Branch 0 taken 32116 times.
✗ Branch 1 not taken.
32116 if ((year >= 1)
120
1/2
✓ Branch 0 taken 32116 times.
✗ Branch 1 not taken.
32116 && (year <= 9999)
121
1/2
✓ Branch 0 taken 32116 times.
✗ Branch 1 not taken.
32116 && (month >= 1)
122
1/2
✓ Branch 0 taken 32116 times.
✗ Branch 1 not taken.
32116 && (month <= 12)
123
1/2
✓ Branch 0 taken 32116 times.
✗ Branch 1 not taken.
32116 && (day >= 1)
124
1/2
✓ Branch 0 taken 32116 times.
✗ Branch 1 not taken.
32116 && (day <= DaysPerMonth[i][month-1]))
125 {
126
2/2
✓ Branch 0 taken 3517 times.
✓ Branch 1 taken 32116 times.
35633 for (j = 0; j < month-1; j++) day += DaysPerMonth[i][j];
127 32116 i = year - 1;
128 32116 i = i*365 + i/4 - i/100 + i/400 + day - DateDelta;
129 32116 return i;
130 }
131 else return -DateDelta;
132 }
133
134 //=============================================================================
135
136 7702 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 7702 times.
✗ Branch 1 not taken.
7702 if ((hour >= 0)
147
1/2
✓ Branch 0 taken 7702 times.
✗ Branch 1 not taken.
7702 && (minute >= 0)
148
1/2
✓ Branch 0 taken 7702 times.
✗ Branch 1 not taken.
7702 && (second >= 0))
149 {
150 7702 s = (hour * 3600 + minute * 60 + second);
151 7702 return (double)s/SecsPerDay;
152 }
153 else return 0.0;
154 }
155
156 //=============================================================================
157
158 4093946 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 4093946 D1 = 365; //365
171 4093946 D4 = D1 * 4 + 1; //1461
172 4093946 D100 = D4 * 25 - 1; //36524
173 4093946 D400 = D100 * 4 + 1; //146097
174
175 4093946 t = (int)(floor (date)) + DateDelta;
176
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4093946 times.
4093946 if (t <= 0)
177 {
178 *year = 0;
179 *month = 1;
180 *day = 1;
181 }
182 else
183 {
184 4093946 t--;
185 4093946 y = 1;
186
2/2
✓ Branch 0 taken 19721212 times.
✓ Branch 1 taken 4093946 times.
23815158 while (t >= D400)
187 {
188 19721212 t -= D400;
189 19721212 y += 400;
190 }
191 4093946 divMod(t, D100, &i, &d);
192
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4093946 times.
4093946 if (i == 4)
193 {
194 i--;
195 d += D100;
196 }
197 4093946 y += i*100;
198 4093946 divMod(d, D4, &i, &d);
199 4093946 y += i*4;
200 4093946 divMod(d, D1, &i, &d);
201
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4093946 times.
4093946 if (i == 4)
202 {
203 i--;
204 d += D1;
205 }
206 4093946 y += i;
207 4093946 k = isLeapYear(y);
208 4093946 m = 1;
209 for (;;)
210 {
211 8907528 i = DaysPerMonth[k][m-1];
212
2/2
✓ Branch 0 taken 4093946 times.
✓ Branch 1 taken 4813582 times.
8907528 if (d < i) break;
213 4813582 d -= i;
214 4813582 m++;
215 }
216 4093946 *year = y;
217 4093946 *month = m;
218 4093946 *day = d + 1;
219 }
220 4093946 }
221
222 //=============================================================================
223
224 4267832 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 4267832 double fracDay = (time - floor(time)) * SecsPerDay;
236 4267832 secs = (int)(floor(fracDay + 0.5));
237
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4267832 times.
4267832 if ( secs >= 86400 ) secs = 86399;
238 4267832 divMod(secs, 60, &mins, s);
239 4267832 divMod(mins, 60, h, m);
240
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4267832 times.
4267832 if ( *h > 23 ) *h = 0;
241 4267832 }
242
243 //=============================================================================
244
245 1876 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 1876 datetime_decodeDate(date, &y, &m, &d);
254
1/3
✗ Branch 0 not taken.
✓ Branch 1 taken 1876 times.
✗ Branch 2 not taken.
1876 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 1876 case M_D_Y:
261 //sprintf(dateStr, "%3s-%02d-%4d", MonthTxt[m-1], d, y);
262 1876 snprintf(s, DATE_STR_SIZE, "%02d/%02d/%04d", m, d, y);
263 1876 break;
264
265 default:
266 snprintf(s, DATE_STR_SIZE, "%02d-%3s-%4d", d, MonthTxt[m-1], y);
267 }
268 1876 }
269
270 2002 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 2002 datetime_decodeTime(time, &hr, &min, &sec);
279 2002 snprintf(s, TIME_STR_SIZE, "%02d:%02d:%02d", hr, min, sec);
280 2002 }
281
282 //=============================================================================
283
284 7504 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 7504 int yr = 0, mon = 0, day = 0, n;
293 char month[4];
294 char sep1, sep2;
295 7504 *d = -DateDelta;
296
3/4
✓ Branch 0 taken 7504 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5624 times.
✓ Branch 3 taken 1880 times.
7504 if (strchr(s, '-') || strchr(s, '/'))
297 {
298
1/3
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 5624 times.
5624 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 5624 default: // M_D_Y
321 5624 n = sscanf(s, "%d%c%d%c%d", &mon, &sep1, &day, &sep2, &yr);
322
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5624 times.
5624 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 5624 times.
5624 if (mon == 0) mon = datetime_findMonth(month);
330 5624 *d = datetime_encodeDate(yr, mon, day);
331 }
332
2/2
✓ Branch 0 taken 1880 times.
✓ Branch 1 taken 5624 times.
7504 if (*d == -DateDelta) return 0;
333 5624 else return 1;
334 }
335
336 //=============================================================================
337
338 7439 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 7439 int n, hr, min = 0, sec = 0;
348 char *endptr;
349
350 // Attempt to read time as decimal hours
351 7439 *t = strtod(s, &endptr);
352
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 7425 times.
7439 if ( *endptr == 0 )
353 {
354 14 *t /= 24.0;
355 14 return 1;
356 }
357
358 // Read time in hr:min:sec format
359 7425 *t = 0.0;
360 7425 n = sscanf(s, "%d:%d:%d", &hr, &min, &sec);
361
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7425 times.
7425 if ( n == 0 ) return 0;
362 7425 *t = datetime_encodeTime(hr, min, sec);
363
3/6
✓ Branch 0 taken 7425 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7425 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 7425 times.
✗ Branch 5 not taken.
7425 if ( (hr >= 0) && (min >= 0) && (sec >= 0) ) return 1;
364 else return 0;
365 }
366
367 //=============================================================================
368
369 1789 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 1789 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1789 times.
✗ Branch 3 not taken.
1789 if ( fmt >= Y_M_D && fmt <= M_D_Y) DateFormat = fmt;
377 1789 }
378
379 //=============================================================================
380
381 3053687 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 3053687 double d = floor(date1);
390 int h, m, s;
391 3053687 datetime_decodeTime(date1, &h, &m, &s);
392 3053687 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 52159 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 52159 double d1 = floor(date1);
425 52159 double d2 = floor(date2);
426 int h, m, s;
427 long s1, s2, secs;
428 52159 datetime_decodeTime(date1, &h, &m, &s);
429 52159 s1 = 3600*h + 60*m + s;
430 52159 datetime_decodeTime(date2, &h, &m, &s);
431 52159 s2 = 3600*h + 60*m + s;
432 52159 secs = (int)(floor((d1 - d2)*SecsPerDay + 0.5));
433 52159 secs += (s1 - s2);
434 52159 return secs;
435 }
436
437 //=============================================================================
438
439 3334435 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 3334435 datetime_decodeDate(date, &year, &month, &day);
448 3334435 return month;
449 }
450
451 //=============================================================================
452
453 25797 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 25797 datetime_decodeDate(date, &year, &month, &day);
463 25797 startOfYear = datetime_encodeDate(year, 1, 1);
464 25797 return (int)(floor(date - startOfYear)) + 1;
465 }
466
467 //=============================================================================
468
469 1106301 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 1106301 int t = (int)(floor(date)) + DateDelta;
477 1106301 return (t % 7) + 1;
478 }
479
480 //=============================================================================
481
482 1106301 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 1106301 datetime_decodeTime(date, &hour, &min, &sec);
491 1106301 return hour;
492 }
493
494 //=============================================================================
495
496 4 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 4 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
4 if ( month < 1 || month > 12 ) return 0;
505 4 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