xref: /llvm-project/libc/test/src/time/mktime_test.cpp (revision eaae52c1fd459f9c0a147361bc3b962238faba5c)
1 //===-- Unittests for mktime ----------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "src/time/mktime.h"
10 #include "src/time/time_utils.h"
11 #include "test/ErrnoSetterMatcher.h"
12 #include "test/src/time/TmMatcher.h"
13 #include "utils/UnitTest/Test.h"
14 
15 #include <errno.h>
16 #include <limits.h>
17 #include <string.h>
18 
19 using __llvm_libc::testing::ErrnoSetterMatcher::Fails;
20 using __llvm_libc::testing::ErrnoSetterMatcher::Succeeds;
21 using __llvm_libc::time_utils::TimeConstants;
22 
23 // A helper function to initialize tm data structure.
24 static inline void initialize_tm_data(struct tm *tm_data, int year, int month,
25                                       int mday, int hour, int min, int sec,
26                                       int wday, int yday) {
27   struct tm temp = {.tm_sec = sec,
28                     .tm_min = min,
29                     .tm_hour = hour,
30                     .tm_mday = mday,
31                     .tm_mon = month - 1, // tm_mon starts with 0 for Jan
32                     // years since 1900
33                     .tm_year = year - TimeConstants::TimeYearBase,
34                     .tm_wday = wday,
35                     .tm_yday = yday};
36   *tm_data = temp;
37 }
38 
39 static inline time_t call_mktime(struct tm *tm_data, int year, int month,
40                                  int mday, int hour, int min, int sec, int wday,
41                                  int yday) {
42   initialize_tm_data(tm_data, year, month, mday, hour, min, sec, wday, yday);
43   return __llvm_libc::mktime(tm_data);
44 }
45 
46 TEST(LlvmLibcMkTime, FailureSetsErrno) {
47   struct tm tm_data;
48   initialize_tm_data(&tm_data, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, -1,
49                      0, 0);
50   EXPECT_THAT(__llvm_libc::mktime(&tm_data), Fails(EOVERFLOW));
51 }
52 
53 TEST(LlvmLibcMkTime, InvalidSeconds) {
54   struct tm tm_data;
55   // -1 second from 1970-01-01 00:00:00 returns 1969-12-31 23:59:59.
56   EXPECT_THAT(call_mktime(&tm_data,
57                           1970, // year
58                           1,    // month
59                           1,    // day
60                           0,    // hr
61                           0,    // min
62                           -1,   // sec
63                           0,    // wday
64                           0),   // yday
65               Succeeds(-1));
66   EXPECT_TM_EQ((tm{59,     // sec
67                    59,     // min
68                    23,     // hr
69                    31,     // day
70                    12 - 1, // tm_mon starts with 0 for Jan
71                    1969 - TimeConstants::TimeYearBase, // year
72                    3,                                  // wday
73                    364,                                // yday
74                    0}),
75                tm_data);
76   // 60 seconds from 1970-01-01 00:00:00 returns 1970-01-01 00:01:00.
77   EXPECT_THAT(call_mktime(&tm_data,
78                           1970, // year
79                           1,    // month
80                           1,    // day
81                           0,    // hr
82                           0,    // min
83                           60,   // sec
84                           0,    // wday
85                           0),   // yday
86               Succeeds(60));
87   EXPECT_TM_EQ((tm{0, // sec
88                    1, // min
89                    0, // hr
90                    1, // day
91                    0, // tm_mon starts with 0 for Jan
92                    1970 - TimeConstants::TimeYearBase, // year
93                    4,                                  // wday
94                    0,                                  // yday
95                    0}),
96                tm_data);
97 }
98 
99 TEST(LlvmLibcMkTime, InvalidMinutes) {
100   struct tm tm_data;
101   // -1 minute from 1970-01-01 00:00:00 returns 1969-12-31 23:59:00.
102   EXPECT_THAT(call_mktime(&tm_data,
103                           1970, // year
104                           1,    // month
105                           1,    // day
106                           0,    // hr
107                           -1,   // min
108                           0,    // sec
109                           0,    // wday
110                           0),   // yday
111               Succeeds(-TimeConstants::SecondsPerMin));
112   EXPECT_TM_EQ((tm{0,  // sec
113                    59, // min
114                    23, // hr
115                    31, // day
116                    11, // tm_mon starts with 0 for Jan
117                    1969 - TimeConstants::TimeYearBase, // year
118                    3,                                  // wday
119                    0,                                  // yday
120                    0}),
121                tm_data);
122   // 60 minutes from 1970-01-01 00:00:00 returns 1970-01-01 01:00:00.
123   EXPECT_THAT(call_mktime(&tm_data,
124                           1970, // year
125                           1,    // month
126                           1,    // day
127                           0,    // hr
128                           60,   // min
129                           0,    // sec
130                           0,    // wday
131                           0),   // yday
132               Succeeds(60 * TimeConstants::SecondsPerMin));
133   EXPECT_TM_EQ((tm{0, // sec
134                    0, // min
135                    1, // hr
136                    1, // day
137                    0, // tm_mon starts with 0 for Jan
138                    1970 - TimeConstants::TimeYearBase, // year
139                    4,                                  // wday
140                    0,                                  // yday
141                    0}),
142                tm_data);
143 }
144 
145 TEST(LlvmLibcMkTime, InvalidHours) {
146   struct tm tm_data;
147   // -1 hour from 1970-01-01 00:00:00 returns 1969-12-31 23:00:00.
148   EXPECT_THAT(call_mktime(&tm_data,
149                           1970, // year
150                           1,    // month
151                           1,    // day
152                           -1,   // hr
153                           0,    // min
154                           0,    // sec
155                           0,    // wday
156                           0),   // yday
157               Succeeds(-TimeConstants::SecondsPerHour));
158   EXPECT_TM_EQ((tm{0,  // sec
159                    0,  // min
160                    23, // hr
161                    31, // day
162                    11, // tm_mon starts with 0 for Jan
163                    1969 - TimeConstants::TimeYearBase, // year
164                    3,                                  // wday
165                    0,                                  // yday
166                    0}),
167                tm_data);
168   // 24 hours from 1970-01-01 00:00:00 returns 1970-01-02 00:00:00.
169   EXPECT_THAT(call_mktime(&tm_data,
170                           1970, // year
171                           1,    // month
172                           1,    // day
173                           24,   // hr
174                           0,    // min
175                           0,    // sec
176                           0,    // wday
177                           0),   // yday
178               Succeeds(24 * TimeConstants::SecondsPerHour));
179   EXPECT_TM_EQ((tm{0, // sec
180                    0, // min
181                    0, // hr
182                    2, // day
183                    0, // tm_mon starts with 0 for Jan
184                    1970 - TimeConstants::TimeYearBase, // year
185                    5,                                  // wday
186                    0,                                  // yday
187                    0}),
188                tm_data);
189 }
190 
191 TEST(LlvmLibcMkTime, InvalidYear) {
192   struct tm tm_data;
193   // -1 year from 1970-01-01 00:00:00 returns 1969-01-01 00:00:00.
194   EXPECT_THAT(call_mktime(&tm_data,
195                           1969, // year
196                           1,    // month
197                           1,    // day
198                           0,    // hr
199                           0,    // min
200                           0,    // sec
201                           0,    // wday
202                           0),   // yday
203               Succeeds(-TimeConstants::DaysPerNonLeapYear *
204                        TimeConstants::SecondsPerDay));
205   EXPECT_TM_EQ((tm{0, // sec
206                    0, // min
207                    0, // hr
208                    1, // day
209                    0, // tm_mon starts with 0 for Jan
210                    1969 - TimeConstants::TimeYearBase, // year
211                    3,                                  // wday
212                    0,                                  // yday
213                    0}),
214                tm_data);
215 }
216 
217 TEST(LlvmLibcMkTime, InvalidEndOf32BitEpochYear) {
218   if (sizeof(size_t) != 4)
219     return;
220   struct tm tm_data;
221   // 2038-01-19 03:14:08 tests overflow of the second in 2038.
222   EXPECT_THAT(call_mktime(&tm_data, 2038, 1, 19, 3, 14, 8, 0, 0),
223               Succeeds(TimeConstants::OutOfRangeReturnValue));
224   // 2038-01-19 03:15:07 tests overflow of the minute in 2038.
225   EXPECT_THAT(call_mktime(&tm_data, 2038, 1, 19, 3, 15, 7, 0, 0),
226               Succeeds(TimeConstants::OutOfRangeReturnValue));
227   // 2038-01-19 04:14:07 tests overflow of the hour in 2038.
228   EXPECT_THAT(call_mktime(&tm_data, 2038, 1, 19, 4, 14, 7, 0, 0),
229               Succeeds(TimeConstants::OutOfRangeReturnValue));
230   // 2038-01-20 03:14:07 tests overflow of the day in 2038.
231   EXPECT_THAT(call_mktime(&tm_data, 2038, 1, 20, 3, 14, 7, 0, 0),
232               Succeeds(TimeConstants::OutOfRangeReturnValue));
233   // 2038-02-19 03:14:07 tests overflow of the month in 2038.
234   EXPECT_THAT(call_mktime(&tm_data, 2038, 2, 19, 3, 14, 7, 0, 0),
235               Succeeds(TimeConstants::OutOfRangeReturnValue));
236   // 2039-01-19 03:14:07 tests overflow of the year.
237   EXPECT_THAT(call_mktime(&tm_data, 2039, 1, 19, 3, 14, 7, 0, 0),
238               Succeeds(TimeConstants::OutOfRangeReturnValue));
239 }
240 
241 TEST(LlvmLibcMkTime, InvalidMonths) {
242   struct tm tm_data;
243   // -1 month from 1970-01-01 00:00:00 returns 1969-12-01 00:00:00.
244   EXPECT_THAT(call_mktime(&tm_data,
245                           1970, // year
246                           0,    // month
247                           1,    // day
248                           0,    // hr
249                           0,    // min
250                           0,    // sec
251                           0,    // wday
252                           0),   // yday
253               Succeeds(-31 * TimeConstants::SecondsPerDay));
254   EXPECT_TM_EQ((tm{0,      // sec
255                    0,      // min
256                    0,      // hr
257                    1,      // day
258                    12 - 1, // tm_mon starts with 0 for Jan
259                    1969 - TimeConstants::TimeYearBase, // year
260                    1,                                  // wday
261                    0,                                  // yday
262                    0}),
263                tm_data);
264   // 1970-13-01 00:00:00 returns 1971-01-01 00:00:00.
265   EXPECT_THAT(call_mktime(&tm_data,
266                           1970, // year
267                           13,   // month
268                           1,    // day
269                           0,    // hr
270                           0,    // min
271                           0,    // sec
272                           0,    // wday
273                           0),   // yday
274               Succeeds(TimeConstants::DaysPerNonLeapYear *
275                        TimeConstants::SecondsPerDay));
276   EXPECT_TM_EQ((tm{0, // sec
277                    0, // min
278                    0, // hr
279                    1, // day
280                    0, // tm_mon starts with 0 for Jan
281                    1971 - TimeConstants::TimeYearBase, // year
282                    5,                                  // wday
283                    0,                                  // yday
284                    0}),
285                tm_data);
286 }
287 
288 TEST(LlvmLibcMkTime, InvalidDays) {
289   struct tm tm_data;
290   // -1 day from 1970-01-01 00:00:00 returns 1969-12-31 00:00:00.
291   EXPECT_THAT(call_mktime(&tm_data,
292                           1970, // year
293                           1,    // month
294                           0,    // day
295                           0,    // hr
296                           0,    // min
297                           0,    // sec
298                           0,    // wday
299                           0),   // yday
300               Succeeds(-1 * TimeConstants::SecondsPerDay));
301   EXPECT_TM_EQ((tm{0,  // sec
302                    0,  // min
303                    0,  // hr
304                    31, // day
305                    11, // tm_mon starts with 0 for Jan
306                    1969 - TimeConstants::TimeYearBase, // year
307                    3,                                  // wday
308                    0,                                  // yday
309                    0}),
310                tm_data);
311 
312   // 1970-01-32 00:00:00 returns 1970-02-01 00:00:00.
313   EXPECT_THAT(call_mktime(&tm_data,
314                           1970, // year
315                           1,    // month
316                           32,   // day
317                           0,    // hr
318                           0,    // min
319                           0,    // sec
320                           0,    // wday
321                           0),   // yday
322               Succeeds(31 * TimeConstants::SecondsPerDay));
323   EXPECT_TM_EQ((tm{0, // sec
324                    0, // min
325                    0, // hr
326                    1, // day
327                    0, // tm_mon starts with 0 for Jan
328                    1970 - TimeConstants::TimeYearBase, // year
329                    0,                                  // wday
330                    0,                                  // yday
331                    0}),
332                tm_data);
333 
334   // 1970-02-29 00:00:00 returns 1970-03-01 00:00:00.
335   EXPECT_THAT(call_mktime(&tm_data,
336                           1970, // year
337                           2,    // month
338                           29,   // day
339                           0,    // hr
340                           0,    // min
341                           0,    // sec
342                           0,    // wday
343                           0),   // yday
344               Succeeds(59 * TimeConstants::SecondsPerDay));
345   EXPECT_TM_EQ((tm{0, // sec
346                    0, // min
347                    0, // hr
348                    1, // day
349                    2, // tm_mon starts with 0 for Jan
350                    1970 - TimeConstants::TimeYearBase, // year
351                    0,                                  // wday
352                    0,                                  // yday
353                    0}),
354                tm_data);
355 
356   // 1972-02-30 00:00:00 returns 1972-03-01 00:00:00.
357   EXPECT_THAT(call_mktime(&tm_data,
358                           1972, // year
359                           2,    // month
360                           30,   // day
361                           0,    // hr
362                           0,    // min
363                           0,    // sec
364                           0,    // wday
365                           0),   // yday
366               Succeeds(((2 * TimeConstants::DaysPerNonLeapYear) + 60) *
367                        TimeConstants::SecondsPerDay));
368   EXPECT_TM_EQ((tm{0, // sec
369                    0, // min
370                    0, // hr
371                    1, // day
372                    2, // tm_mon starts with 0 for Jan
373                    1972 - TimeConstants::TimeYearBase, // year
374                    3,                                  // wday
375                    0,                                  // yday
376                    0}),
377                tm_data);
378 }
379 
380 TEST(LlvmLibcMkTime, EndOf32BitEpochYear) {
381   struct tm tm_data;
382   // Test for maximum value of a signed 32-bit integer.
383   // Test implementation can encode time for Tue 19 January 2038 03:14:07 UTC.
384   EXPECT_THAT(call_mktime(&tm_data,
385                           2038, // year
386                           1,    // month
387                           19,   // day
388                           3,    // hr
389                           14,   // min
390                           7,    // sec
391                           0,    // wday
392                           0),   // yday
393               Succeeds(0x7FFFFFFF));
394   EXPECT_TM_EQ((tm{7,  // sec
395                    14, // min
396                    3,  // hr
397                    19, // day
398                    0,  // tm_mon starts with 0 for Jan
399                    2038 - TimeConstants::TimeYearBase, // year
400                    2,                                  // wday
401                    7,                                  // yday
402                    0}),
403                tm_data);
404 }
405 
406 TEST(LlvmLibcMkTime, Max64BitYear) {
407   if (sizeof(time_t) == 4)
408     return;
409   // Mon Jan 1 12:50:50 2170 (200 years from 1970),
410   struct tm tm_data;
411   EXPECT_THAT(call_mktime(&tm_data,
412                           2170, // year
413                           1,    // month
414                           1,    // day
415                           12,   // hr
416                           50,   // min
417                           50,   // sec
418                           0,    // wday
419                           0),   // yday
420               Succeeds(6311479850));
421   EXPECT_TM_EQ((tm{50, // sec
422                    50, // min
423                    12, // hr
424                    1,  // day
425                    0,  // tm_mon starts with 0 for Jan
426                    2170 - TimeConstants::TimeYearBase, // year
427                    1,                                  // wday
428                    50,                                 // yday
429                    0}),
430                tm_data);
431 
432   // Test for Tue Jan 1 12:50:50 in 2,147,483,647th year.
433   EXPECT_THAT(call_mktime(&tm_data, 2147483647, 1, 1, 12, 50, 50, 0, 0),
434               Succeeds(67767976202043050));
435   EXPECT_TM_EQ((tm{50, // sec
436                    50, // min
437                    12, // hr
438                    1,  // day
439                    0,  // tm_mon starts with 0 for Jan
440                    2147483647 - TimeConstants::TimeYearBase, // year
441                    2,                                        // wday
442                    50,                                       // yday
443                    0}),
444                tm_data);
445 }
446