1 /***********************************************************************************************************************************
2 Time Management
3 ***********************************************************************************************************************************/
4 #include "build.auto.h"
5
6 #include <stdio.h>
7 #include <sys/time.h>
8
9 #include "common/debug.h"
10 #include "common/time.h"
11
12 /***********************************************************************************************************************************
13 Constants describing number of sub-units in an interval
14 ***********************************************************************************************************************************/
15 #define MSEC_PER_USEC ((TimeMSec)1000)
16
17 /**********************************************************************************************************************************/
18 TimeMSec
timeMSec(void)19 timeMSec(void)
20 {
21 FUNCTION_TEST_VOID();
22
23 struct timeval currentTime;
24 gettimeofday(¤tTime, NULL);
25
26 FUNCTION_TEST_RETURN(((TimeMSec)currentTime.tv_sec * MSEC_PER_SEC) + (TimeMSec)currentTime.tv_usec / MSEC_PER_USEC);
27 }
28
29 /**********************************************************************************************************************************/
30 void
sleepMSec(TimeMSec sleepMSec)31 sleepMSec(TimeMSec sleepMSec)
32 {
33 FUNCTION_TEST_BEGIN();
34 FUNCTION_TEST_PARAM(UINT64, sleepMSec);
35 FUNCTION_TEST_END();
36
37 if (sleepMSec > 0)
38 {
39 struct timeval delay;
40 delay.tv_sec = (time_t)(sleepMSec / MSEC_PER_SEC);
41 delay.tv_usec = (suseconds_t)(sleepMSec % MSEC_PER_SEC * 1000);
42 select(0, NULL, NULL, NULL, &delay);
43 }
44
45 FUNCTION_TEST_RETURN_VOID();
46 }
47
48 /**********************************************************************************************************************************/
49 void
datePartsValid(int year,int month,int day)50 datePartsValid(int year, int month, int day)
51 {
52 FUNCTION_TEST_BEGIN();
53 FUNCTION_TEST_PARAM(INT, year);
54 FUNCTION_TEST_PARAM(INT, month);
55 FUNCTION_TEST_PARAM(INT, day);
56 FUNCTION_TEST_END();
57
58 static const int daysPerMonth[2][12] =
59 {
60 {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
61 {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
62 };
63
64 if (!(year >= 1970 && month > 0 && month <= 12 && day > 0 && day <= daysPerMonth[yearIsLeap(year) ? 1 : 0][month - 1]))
65 THROW_FMT(FormatError, "invalid date %04d-%02d-%02d", year, month, day);
66
67 FUNCTION_TEST_RETURN_VOID();
68 }
69
70 /**********************************************************************************************************************************/
71 void
timePartsValid(int hour,int minute,int second)72 timePartsValid(int hour, int minute, int second)
73 {
74 FUNCTION_TEST_BEGIN();
75 FUNCTION_TEST_PARAM(INT, hour);
76 FUNCTION_TEST_PARAM(INT, minute);
77 FUNCTION_TEST_PARAM(INT, second);
78 FUNCTION_TEST_END();
79
80 if (!(hour >= 0 && hour < 24 && minute >= 0 && minute < 60 && second >= 0 && second < 60))
81 THROW_FMT(FormatError, "invalid time %02d:%02d:%02d", hour, minute, second);
82
83 FUNCTION_TEST_RETURN_VOID();
84 }
85
86 /**********************************************************************************************************************************/
87 void
tzPartsValid(int tzHour,int tzMinute)88 tzPartsValid(int tzHour, int tzMinute)
89 {
90 FUNCTION_TEST_BEGIN();
91 FUNCTION_TEST_PARAM(INT, tzHour); // signed hour part of timezone
92 FUNCTION_TEST_PARAM(INT, tzMinute); // minutes part of timezone
93 FUNCTION_TEST_END();
94
95 // Valid time zones range from GMT-12 all the way to GMT+14 (i.e. -1200 and +1400 are the min/max).
96 // ??? This is only a sanity check for basic validity of timezone offset of 15 minute intervals until the timezone
97 // database is implemented.
98 if (!(((tzHour > -12 && tzHour < 14) && (tzMinute % 15 == 0)) || (tzHour == -12 && tzMinute == 0) ||
99 (tzHour == 14 && tzMinute == 0)))
100 {
101 THROW_FMT(FormatError, "invalid timezone %02d%02d", tzHour, tzMinute);
102 }
103
104 FUNCTION_TEST_RETURN_VOID();
105 }
106
107 /**********************************************************************************************************************************/
108 int
tzOffsetSeconds(int tzHour,int tzMinute)109 tzOffsetSeconds(int tzHour, int tzMinute)
110 {
111 FUNCTION_TEST_BEGIN();
112 FUNCTION_TEST_PARAM(INT, tzHour); // signed hour part of timezone (e.g. -7)
113 FUNCTION_TEST_PARAM(INT, tzMinute); // minutes part of timezone
114 FUNCTION_TEST_END();
115
116 // Validate the timezone hour and minute
117 tzPartsValid(tzHour, tzMinute);
118
119 int sign = 1;
120
121 // Preserve the sign and convert the hours to a positive number for calculating seconds
122 if (tzHour < 0)
123 {
124 sign = -1;
125 tzHour = sign * tzHour;
126 }
127
128 FUNCTION_TEST_RETURN(sign * (tzHour * 3600 + tzMinute * 60));
129 }
130
131 /**********************************************************************************************************************************/
132 bool
yearIsLeap(int year)133 yearIsLeap(int year)
134 {
135 FUNCTION_TEST_BEGIN();
136 FUNCTION_TEST_PARAM(INT, year);
137 FUNCTION_TEST_END();
138
139 FUNCTION_TEST_RETURN((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0));
140 }
141
142 /**********************************************************************************************************************************/
143 int
dayOfYear(int year,int month,int day)144 dayOfYear(int year, int month, int day)
145 {
146 FUNCTION_TEST_BEGIN();
147 FUNCTION_TEST_PARAM(INT, year);
148 FUNCTION_TEST_PARAM(INT, month);
149 FUNCTION_TEST_PARAM(INT, day);
150 FUNCTION_TEST_END();
151
152 datePartsValid(year, month, day);
153
154 static const int cumulativeDaysPerMonth[2][12] =
155 {
156 {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334},
157 {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335},
158 };
159
160 FUNCTION_TEST_RETURN(cumulativeDaysPerMonth[yearIsLeap(year) ? 1 : 0][month - 1] + day);
161 }
162
163 /**********************************************************************************************************************************/
164 time_t
epochFromParts(int year,int month,int day,int hour,int minute,int second,int tzOffsetSecond)165 epochFromParts(int year, int month, int day, int hour, int minute, int second, int tzOffsetSecond)
166 {
167 FUNCTION_TEST_BEGIN();
168 FUNCTION_TEST_PARAM(INT, year);
169 FUNCTION_TEST_PARAM(INT, month);
170 FUNCTION_TEST_PARAM(INT, day);
171 FUNCTION_TEST_PARAM(INT, hour);
172 FUNCTION_TEST_PARAM(INT, minute);
173 FUNCTION_TEST_PARAM(INT, second);
174 FUNCTION_TEST_PARAM(INT, tzOffsetSecond);
175 FUNCTION_TEST_END();
176
177 timePartsValid(hour, minute, second);
178
179 // Return epoch using calculation from https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_16
180 FUNCTION_TEST_RETURN(
181 -1 * tzOffsetSecond + second + minute * 60 + hour * 3600 +
182 (dayOfYear(year, month, day) - 1) * 86400 + (year - 1900 - 70) * 31536000 +
183 ((year - 1900 - 69) / 4) * 86400 - ((year - 1900 - 1) / 100) * 86400 + ((year - 1900 + 299) / 400) * 86400);
184 }
185