1570af302Sopenharmony_ci#include <limits.h>
2570af302Sopenharmony_ci#include <stdlib.h>
3570af302Sopenharmony_ci#include <string.h>
4570af302Sopenharmony_ci#include <time.h>
5570af302Sopenharmony_ci#include "test.h"
6570af302Sopenharmony_ci
7570af302Sopenharmony_cistatic char buffer[100];
8570af302Sopenharmony_ci
9570af302Sopenharmony_cistatic void checkStrftime(const char* format, const struct tm* tm,
10570af302Sopenharmony_ci		const char* expected) {
11570af302Sopenharmony_ci	size_t resultLength = strftime(buffer, sizeof(buffer), format, tm);
12570af302Sopenharmony_ci
13570af302Sopenharmony_ci	if (resultLength != 0 && strcmp(buffer, expected) != 0) {
14570af302Sopenharmony_ci		t_error("\"%s\": expected \"%s\", got \"%s\"\n", format, expected, buffer);
15570af302Sopenharmony_ci	} else if (resultLength == 0 && strlen(expected) != 0) {
16570af302Sopenharmony_ci		t_error("\"%s\": expected \"%s\", got nothing\n", format, expected);
17570af302Sopenharmony_ci	}
18570af302Sopenharmony_ci}
19570af302Sopenharmony_ci
20570af302Sopenharmony_cistatic struct tm tm1 = {
21570af302Sopenharmony_ci	.tm_sec = 45,
22570af302Sopenharmony_ci	.tm_min = 23,
23570af302Sopenharmony_ci	.tm_hour = 13,
24570af302Sopenharmony_ci	.tm_mday = 3,
25570af302Sopenharmony_ci	.tm_mon = 0,
26570af302Sopenharmony_ci	.tm_year = 2016 - 1900,
27570af302Sopenharmony_ci	.tm_wday = 0,
28570af302Sopenharmony_ci	.tm_yday = 2,
29570af302Sopenharmony_ci	.tm_isdst = 0
30570af302Sopenharmony_ci};
31570af302Sopenharmony_ci
32570af302Sopenharmony_cistatic struct tm tm2 = {
33570af302Sopenharmony_ci	.tm_sec = 53,
34570af302Sopenharmony_ci	.tm_min = 17,
35570af302Sopenharmony_ci	.tm_hour = 5,
36570af302Sopenharmony_ci	.tm_mday = 5,
37570af302Sopenharmony_ci	.tm_mon = 0,
38570af302Sopenharmony_ci	.tm_year = 10009 - 1900,
39570af302Sopenharmony_ci	.tm_wday = 1,
40570af302Sopenharmony_ci	.tm_yday = 4,
41570af302Sopenharmony_ci	.tm_isdst = 0
42570af302Sopenharmony_ci};
43570af302Sopenharmony_ci
44570af302Sopenharmony_cistatic struct tm tm3 = {
45570af302Sopenharmony_ci	.tm_sec = 0,
46570af302Sopenharmony_ci	.tm_min = 0,
47570af302Sopenharmony_ci	.tm_hour = 12,
48570af302Sopenharmony_ci	.tm_mday = 23,
49570af302Sopenharmony_ci	.tm_mon = 1,
50570af302Sopenharmony_ci	.tm_year = 0 - 1900,
51570af302Sopenharmony_ci	.tm_wday = 3,
52570af302Sopenharmony_ci	.tm_yday = 53,
53570af302Sopenharmony_ci	.tm_isdst = 0
54570af302Sopenharmony_ci};
55570af302Sopenharmony_ci
56570af302Sopenharmony_cistatic struct tm tm4 = {
57570af302Sopenharmony_ci	.tm_sec = 0,
58570af302Sopenharmony_ci	.tm_min = 0,
59570af302Sopenharmony_ci	.tm_hour = 0,
60570af302Sopenharmony_ci	.tm_mday = 1,
61570af302Sopenharmony_ci	.tm_mon = 0,
62570af302Sopenharmony_ci	.tm_year = -123 - 1900,
63570af302Sopenharmony_ci	.tm_wday = 1,
64570af302Sopenharmony_ci	.tm_yday = 0,
65570af302Sopenharmony_ci	.tm_isdst = 0
66570af302Sopenharmony_ci};
67570af302Sopenharmony_ci
68570af302Sopenharmony_cistatic struct tm tm5 = {
69570af302Sopenharmony_ci	.tm_sec = 0,
70570af302Sopenharmony_ci	.tm_min = 0,
71570af302Sopenharmony_ci	.tm_hour = 0,
72570af302Sopenharmony_ci	.tm_mday = 1,
73570af302Sopenharmony_ci	.tm_mon = 0,
74570af302Sopenharmony_ci	.tm_year = INT_MAX,
75570af302Sopenharmony_ci	.tm_wday = 3,
76570af302Sopenharmony_ci	.tm_yday = 0,
77570af302Sopenharmony_ci	.tm_isdst = 0
78570af302Sopenharmony_ci};
79570af302Sopenharmony_ci
80570af302Sopenharmony_ciint main() {
81570af302Sopenharmony_ci	setenv("TZ", "UTC0", 1);
82570af302Sopenharmony_ci
83570af302Sopenharmony_ci	checkStrftime("%c", &tm1, "Sun Jan  3 13:23:45 2016");
84570af302Sopenharmony_ci	checkStrftime("%c", &tm2, "Mon Jan  5 05:17:53 +10009");
85570af302Sopenharmony_ci	checkStrftime("%c", &tm3, "Wed Feb 23 12:00:00 0000");
86570af302Sopenharmony_ci
87570af302Sopenharmony_ci	// The POSIX.1-2008 standard does not specify the padding character for
88570af302Sopenharmony_ci	// "%C". The C standard requires that the number is padded by '0'.
89570af302Sopenharmony_ci	// See also http://austingroupbugs.net/view.php?id=1184
90570af302Sopenharmony_ci	checkStrftime("%C", &tm1, "20");
91570af302Sopenharmony_ci	checkStrftime("%03C", &tm1, "020");
92570af302Sopenharmony_ci	checkStrftime("%+3C", &tm1, "+20");
93570af302Sopenharmony_ci	checkStrftime("%C", &tm2, "100");
94570af302Sopenharmony_ci	checkStrftime("%C", &tm3, "00");
95570af302Sopenharmony_ci	checkStrftime("%01C", &tm3, "0");
96570af302Sopenharmony_ci
97570af302Sopenharmony_ci	checkStrftime("%F", &tm1, "2016-01-03");
98570af302Sopenharmony_ci	checkStrftime("%012F", &tm1, "002016-01-03");
99570af302Sopenharmony_ci	checkStrftime("%+10F", &tm1, "2016-01-03");
100570af302Sopenharmony_ci	checkStrftime("%+11F", &tm1, "+2016-01-03");
101570af302Sopenharmony_ci	checkStrftime("%F", &tm2, "+10009-01-05");
102570af302Sopenharmony_ci	checkStrftime("%011F", &tm2, "10009-01-05");
103570af302Sopenharmony_ci	checkStrftime("%F", &tm3, "0000-02-23");
104570af302Sopenharmony_ci	checkStrftime("%01F", &tm3, "0-02-23");
105570af302Sopenharmony_ci	checkStrftime("%06F", &tm3, "0-02-23");
106570af302Sopenharmony_ci	checkStrftime("%010F", &tm3, "0000-02-23");
107570af302Sopenharmony_ci	checkStrftime("%F", &tm4, "-123-01-01");
108570af302Sopenharmony_ci	checkStrftime("%011F", &tm4, "-0123-01-01");
109570af302Sopenharmony_ci
110570af302Sopenharmony_ci	checkStrftime("%g", &tm1, "15");
111570af302Sopenharmony_ci	checkStrftime("%g", &tm2, "09");
112570af302Sopenharmony_ci
113570af302Sopenharmony_ci	checkStrftime("%G", &tm1, "2015");
114570af302Sopenharmony_ci	checkStrftime("%+5G", &tm1, "+2015");
115570af302Sopenharmony_ci	checkStrftime("%04G", &tm2, "10009");
116570af302Sopenharmony_ci
117570af302Sopenharmony_ci	checkStrftime("%r", &tm1, "01:23:45 PM");
118570af302Sopenharmony_ci	checkStrftime("%r", &tm2, "05:17:53 AM");
119570af302Sopenharmony_ci	checkStrftime("%r", &tm3, "12:00:00 PM");
120570af302Sopenharmony_ci	checkStrftime("%r", &tm4, "12:00:00 AM");
121570af302Sopenharmony_ci
122570af302Sopenharmony_ci	// The "%s" specifier was accepted by the Austin Group for the next POSIX.1
123570af302Sopenharmony_ci	// revision. See http://austingroupbugs.net/view.php?id=169
124570af302Sopenharmony_ci	checkStrftime("%s", &tm1, "1451827425");
125570af302Sopenharmony_ci	if (sizeof(time_t) * CHAR_BIT >= 64) {
126570af302Sopenharmony_ci		checkStrftime("%s", &tm2, "253686748673");
127570af302Sopenharmony_ci	}
128570af302Sopenharmony_ci
129570af302Sopenharmony_ci	checkStrftime("%T", &tm1, "13:23:45");
130570af302Sopenharmony_ci	checkStrftime("%T", &tm2, "05:17:53");
131570af302Sopenharmony_ci	checkStrftime("%T", &tm3, "12:00:00");
132570af302Sopenharmony_ci	checkStrftime("%T", &tm4, "00:00:00");
133570af302Sopenharmony_ci
134570af302Sopenharmony_ci	checkStrftime("%U", &tm1, "01");
135570af302Sopenharmony_ci	checkStrftime("%U", &tm2, "01");
136570af302Sopenharmony_ci	checkStrftime("%U", &tm3, "08");
137570af302Sopenharmony_ci
138570af302Sopenharmony_ci	checkStrftime("%V", &tm1, "53");
139570af302Sopenharmony_ci	checkStrftime("%V", &tm2, "02");
140570af302Sopenharmony_ci	checkStrftime("%V", &tm3, "08");
141570af302Sopenharmony_ci
142570af302Sopenharmony_ci	checkStrftime("%W", &tm1, "00");
143570af302Sopenharmony_ci	checkStrftime("%W", &tm2, "01");
144570af302Sopenharmony_ci	checkStrftime("%W", &tm3, "08");
145570af302Sopenharmony_ci
146570af302Sopenharmony_ci	checkStrftime("%x", &tm1, "01/03/16");
147570af302Sopenharmony_ci	checkStrftime("%X", &tm1, "13:23:45");
148570af302Sopenharmony_ci	checkStrftime("%y", &tm1, "16");
149570af302Sopenharmony_ci
150570af302Sopenharmony_ci	// There is no standard that explicitly specifies the exact format of "%Y".
151570af302Sopenharmony_ci	// The C standard says that "%F" is equivalent to "%Y-%m-%d". The
152570af302Sopenharmony_ci	// POSIX.1-2008 standard says that "%F" is equivalent to "%+4Y-%m-%d".
153570af302Sopenharmony_ci	// This implies that to conform to both standards "%Y" needs to be
154570af302Sopenharmony_ci	// equivalent to "%+4Y".
155570af302Sopenharmony_ci	// See also http://austingroupbugs.net/view.php?id=739
156570af302Sopenharmony_ci	checkStrftime("%Y", &tm1, "2016");
157570af302Sopenharmony_ci	checkStrftime("%05Y", &tm1, "02016");
158570af302Sopenharmony_ci	checkStrftime("%+4Y", &tm1, "2016");
159570af302Sopenharmony_ci	checkStrftime("%+5Y", &tm1, "+2016");
160570af302Sopenharmony_ci	checkStrftime("%Y", &tm2, "+10009");
161570af302Sopenharmony_ci	checkStrftime("%05Y", &tm2, "10009");
162570af302Sopenharmony_ci	checkStrftime("%Y", &tm3, "0000");
163570af302Sopenharmony_ci	checkStrftime("%02Y", &tm3, "00");
164570af302Sopenharmony_ci	checkStrftime("%+5Y", &tm3, "+0000");
165570af302Sopenharmony_ci	checkStrftime("%Y", &tm4, "-123");
166570af302Sopenharmony_ci	checkStrftime("%+4Y", &tm4, "-123");
167570af302Sopenharmony_ci	checkStrftime("%+5Y", &tm4, "-0123");
168570af302Sopenharmony_ci
169570af302Sopenharmony_ci	if (INT_MAX == 0x7FFFFFFF) {
170570af302Sopenharmony_ci		// The standard does not specify any range for tm_year, so INT_MAX
171570af302Sopenharmony_ci		// should be valid.
172570af302Sopenharmony_ci		checkStrftime("%y", &tm5, "47");
173570af302Sopenharmony_ci		checkStrftime("%Y", &tm5, "+2147485547");
174570af302Sopenharmony_ci		checkStrftime("%011Y", &tm5, "02147485547");
175570af302Sopenharmony_ci		if (sizeof(time_t) * CHAR_BIT >= 64) {
176570af302Sopenharmony_ci			checkStrftime("%s", &tm5, "67768036160140800");
177570af302Sopenharmony_ci		}
178570af302Sopenharmony_ci	}
179570af302Sopenharmony_ci
180570af302Sopenharmony_ci	return t_status;
181570af302Sopenharmony_ci}
182