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