add test for strftime
[libc-test] / src / functional / strftime.c
1 #include <limits.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <time.h>
5 #include "test.h"
6
7 static char buffer[100];
8
9 static void checkStrftime(const char* format, const struct tm* tm,
10                 const char* expected) {
11         size_t resultLength = strftime(buffer, sizeof(buffer), format, tm);
12
13         if (resultLength != 0 && strcmp(buffer, expected) != 0) {
14                 t_error("\"%s\": expected \"%s\", got \"%s\"\n", format, expected, buffer);
15         } else if (resultLength == 0 && strlen(expected) != 0) {
16                 t_error("\"%s\": expected \"%s\", got nothing\n", format, expected);
17         }
18 }
19
20 static struct tm tm1 = {
21         .tm_sec = 45,
22         .tm_min = 23,
23         .tm_hour = 13,
24         .tm_mday = 3,
25         .tm_mon = 0,
26         .tm_year = 2016 - 1900,
27         .tm_wday = 0,
28         .tm_yday = 2,
29         .tm_isdst = 0
30 };
31
32 static struct tm tm2 = {
33         .tm_sec = 53,
34         .tm_min = 17,
35         .tm_hour = 5,
36         .tm_mday = 5,
37         .tm_mon = 0,
38         .tm_year = 10009 - 1900,
39         .tm_wday = 1,
40         .tm_yday = 4,
41         .tm_isdst = 0
42 };
43
44 static struct tm tm3 = {
45         .tm_sec = 0,
46         .tm_min = 0,
47         .tm_hour = 12,
48         .tm_mday = 23,
49         .tm_mon = 1,
50         .tm_year = 0 - 1900,
51         .tm_wday = 3,
52         .tm_yday = 53,
53         .tm_isdst = 0
54 };
55
56 static struct tm tm4 = {
57         .tm_sec = 0,
58         .tm_min = 0,
59         .tm_hour = 0,
60         .tm_mday = 1,
61         .tm_mon = 0,
62         .tm_year = -123 - 1900,
63         .tm_wday = 1,
64         .tm_yday = 0,
65         .tm_isdst = 0
66 };
67
68 static struct tm tm5 = {
69         .tm_sec = 0,
70         .tm_min = 0,
71         .tm_hour = 0,
72         .tm_mday = 1,
73         .tm_mon = 0,
74         .tm_year = INT_MAX,
75         .tm_wday = 3,
76         .tm_yday = 0,
77         .tm_isdst = 0
78 };
79
80 int main() {
81         setenv("TZ", "UTC0", 1);
82
83         checkStrftime("%c", &tm1, "Sun Jan  3 13:23:45 2016");
84         checkStrftime("%c", &tm2, "Mon Jan  5 05:17:53 +10009");
85         checkStrftime("%c", &tm3, "Wed Feb 23 12:00:00 0000");
86
87         // The POSIX.1-2008 standard does not specify the padding character for
88         // "%C". The C standard requires that the number is padded by '0'.
89         // See also http://austingroupbugs.net/view.php?id=1184
90         checkStrftime("%C", &tm1, "20");
91         checkStrftime("%03C", &tm1, "020");
92         checkStrftime("%+3C", &tm1, "+20");
93         checkStrftime("%C", &tm2, "100");
94         checkStrftime("%C", &tm3, "00");
95         checkStrftime("%01C", &tm3, "0");
96
97         checkStrftime("%F", &tm1, "2016-01-03");
98         checkStrftime("%012F", &tm1, "002016-01-03");
99         checkStrftime("%+10F", &tm1, "2016-01-03");
100         checkStrftime("%+11F", &tm1, "+2016-01-03");
101         checkStrftime("%F", &tm2, "+10009-01-05");
102         checkStrftime("%011F", &tm2, "10009-01-05");
103         checkStrftime("%F", &tm3, "0000-02-23");
104         checkStrftime("%01F", &tm3, "0-02-23");
105         checkStrftime("%06F", &tm3, "0-02-23");
106         checkStrftime("%010F", &tm3, "0000-02-23");
107         checkStrftime("%F", &tm4, "-123-01-01");
108         checkStrftime("%011F", &tm4, "-0123-01-01");
109
110         checkStrftime("%g", &tm1, "15");
111         checkStrftime("%g", &tm2, "09");
112
113         checkStrftime("%G", &tm1, "2015");
114         checkStrftime("%+5G", &tm1, "+2015");
115         checkStrftime("%04G", &tm2, "10009");
116
117         checkStrftime("%r", &tm1, "01:23:45 PM");
118         checkStrftime("%r", &tm2, "05:17:53 AM");
119         checkStrftime("%r", &tm3, "12:00:00 PM");
120         checkStrftime("%r", &tm4, "12:00:00 AM");
121
122         // The "%s" specifier was accepted by the Austin Group for the next POSIX.1
123         // revision. See http://austingroupbugs.net/view.php?id=169
124         checkStrftime("%s", &tm1, "1451827425");
125         if (sizeof(time_t) * CHAR_BIT >= 64) {
126                 checkStrftime("%s", &tm2, "253686748673");
127         }
128
129         checkStrftime("%T", &tm1, "13:23:45");
130         checkStrftime("%T", &tm2, "05:17:53");
131         checkStrftime("%T", &tm3, "12:00:00");
132         checkStrftime("%T", &tm4, "00:00:00");
133
134         checkStrftime("%U", &tm1, "01");
135         checkStrftime("%U", &tm2, "01");
136         checkStrftime("%U", &tm3, "08");
137
138         checkStrftime("%V", &tm1, "53");
139         checkStrftime("%V", &tm2, "02");
140         checkStrftime("%V", &tm3, "08");
141
142         checkStrftime("%W", &tm1, "00");
143         checkStrftime("%W", &tm2, "01");
144         checkStrftime("%W", &tm3, "08");
145
146         checkStrftime("%x", &tm1, "01/03/16");
147         checkStrftime("%X", &tm1, "13:23:45");
148         checkStrftime("%y", &tm1, "16");
149
150         // There is no standard that explicitly specifies the exact format of "%Y".
151         // The C standard says that "%F" is equivalent to "%Y-%m-%d". The
152         // POSIX.1-2008 standard says that "%F" is equivalent to "%+4Y-%m-%d".
153         // This implies that to conform to both standards "%Y" needs to be
154         // equivalent to "%+4Y".
155         // See also http://austingroupbugs.net/view.php?id=739
156         checkStrftime("%Y", &tm1, "2016");
157         checkStrftime("%05Y", &tm1, "02016");
158         checkStrftime("%+4Y", &tm1, "2016");
159         checkStrftime("%+5Y", &tm1, "+2016");
160         checkStrftime("%Y", &tm2, "+10009");
161         checkStrftime("%05Y", &tm2, "10009");
162         checkStrftime("%Y", &tm3, "0000");
163         checkStrftime("%02Y", &tm3, "00");
164         checkStrftime("%+5Y", &tm3, "+0000");
165         checkStrftime("%Y", &tm4, "-123");
166         checkStrftime("%+4Y", &tm4, "-123");
167         checkStrftime("%+5Y", &tm4, "-0123");
168
169         if (INT_MAX == 0x7FFFFFFF) {
170                 // The standard does not specify any range for tm_year, so INT_MAX
171                 // should be valid.
172                 checkStrftime("%y", &tm5, "47");
173                 checkStrftime("%Y", &tm5, "+2147485547");
174                 checkStrftime("%011Y", &tm5, "02147485547");
175                 if (sizeof(time_t) * CHAR_BIT >= 64) {
176                         checkStrftime("%s", &tm5, "67768036160140800");
177                 }
178         }
179
180         return t_status;
181 }