1570af302Sopenharmony_ci#define _XOPEN_SOURCE 700
2570af302Sopenharmony_ci#include <stdlib.h>
3570af302Sopenharmony_ci#include <stdio.h>
4570af302Sopenharmony_ci#include <time.h>
5570af302Sopenharmony_ci#include <string.h>
6570af302Sopenharmony_ci#include <errno.h>
7570af302Sopenharmony_ci#include <limits.h>
8570af302Sopenharmony_ci#include "test.h"
9570af302Sopenharmony_ci
10570af302Sopenharmony_ci/* We use this instead of memcmp because some broken C libraries
11570af302Sopenharmony_ci * add additional nonstandard fields to struct tm... */
12570af302Sopenharmony_ci
13570af302Sopenharmony_ciint tm_cmp(struct tm tm1, struct tm tm2)
14570af302Sopenharmony_ci{
15570af302Sopenharmony_ci	return  tm1.tm_sec  != tm2.tm_sec  ||
16570af302Sopenharmony_ci		tm1.tm_min  != tm2.tm_min  ||
17570af302Sopenharmony_ci		tm1.tm_hour != tm2.tm_hour ||
18570af302Sopenharmony_ci		tm1.tm_mday != tm2.tm_mday ||
19570af302Sopenharmony_ci		tm1.tm_mon  != tm2.tm_mon  ||
20570af302Sopenharmony_ci		tm1.tm_year != tm2.tm_year ||
21570af302Sopenharmony_ci		tm1.tm_wday != tm2.tm_wday ||
22570af302Sopenharmony_ci		tm1.tm_yday != tm2.tm_yday ||
23570af302Sopenharmony_ci		tm1.tm_isdst!= tm2.tm_isdst;
24570af302Sopenharmony_ci}
25570af302Sopenharmony_ci
26570af302Sopenharmony_cichar *tm_str(struct tm tm)
27570af302Sopenharmony_ci{
28570af302Sopenharmony_ci	static int i;
29570af302Sopenharmony_ci	static char b[4][64];
30570af302Sopenharmony_ci	i = (i+1)%4;
31570af302Sopenharmony_ci	snprintf(b[i], sizeof b[i],
32570af302Sopenharmony_ci		"s=%02d m=%02d h=%02d mday=%02d mon=%02d year=%04d wday=%d yday=%d isdst=%d",
33570af302Sopenharmony_ci		tm.tm_sec, tm.tm_min, tm.tm_hour,
34570af302Sopenharmony_ci		tm.tm_mday, tm.tm_mon, tm.tm_year,
35570af302Sopenharmony_ci		tm.tm_wday, tm.tm_yday, tm.tm_isdst);
36570af302Sopenharmony_ci	return b[i];
37570af302Sopenharmony_ci}
38570af302Sopenharmony_ci
39570af302Sopenharmony_ci#define TM(ss,mm,hh,md,mo,yr,wd,yd,dst) (struct tm){ \
40570af302Sopenharmony_ci	.tm_sec = ss, .tm_min = mm, .tm_hour = hh,    \
41570af302Sopenharmony_ci	.tm_mday = md, .tm_mon = mo, .tm_year = yr,    \
42570af302Sopenharmony_ci	.tm_wday = wd, .tm_yday = yd, .tm_isdst = dst }
43570af302Sopenharmony_ci
44570af302Sopenharmony_ci#define TM_EPOCH    TM(0,0,0,1,0,70,4,0,0)
45570af302Sopenharmony_ci#define TM_Y2038_1S TM(7,14,3,19,0,138,2,18,0)
46570af302Sopenharmony_ci#define TM_Y2038    TM(8,14,3,19,0,138,2,18,0)
47570af302Sopenharmony_ci
48570af302Sopenharmony_cistatic void sec2tm(time_t t, char *m)
49570af302Sopenharmony_ci{
50570af302Sopenharmony_ci	struct tm *tm;
51570af302Sopenharmony_ci	time_t r;
52570af302Sopenharmony_ci
53570af302Sopenharmony_ci	errno = 0;
54570af302Sopenharmony_ci	tm = gmtime(&t);
55570af302Sopenharmony_ci	if (errno != 0)
56570af302Sopenharmony_ci		t_error("%s: gmtime((time_t)%lld) should not set errno, got %s\n",
57570af302Sopenharmony_ci			m, (long long)t, strerror(errno));
58570af302Sopenharmony_ci	errno = 0;
59570af302Sopenharmony_ci	r = mktime(tm);
60570af302Sopenharmony_ci	if (errno != 0)
61570af302Sopenharmony_ci		t_error("%s: mktime(%s) should not set errno, got %s\n",
62570af302Sopenharmony_ci			m, tm_str(*tm), strerror(errno));
63570af302Sopenharmony_ci	if (t != r)
64570af302Sopenharmony_ci		t_error("%s: mktime(gmtime(%lld)) roundtrip failed: got %lld (gmtime is %s)\n",
65570af302Sopenharmony_ci			m, (long long)t, (long long)r, tm_str(*tm));
66570af302Sopenharmony_ci}
67570af302Sopenharmony_ci
68570af302Sopenharmony_cistatic void tm2sec(struct tm *tm, int big, char *m)
69570af302Sopenharmony_ci{
70570af302Sopenharmony_ci	struct tm *r;
71570af302Sopenharmony_ci	time_t t;
72570af302Sopenharmony_ci	int overflow = big && (time_t)LLONG_MAX!=LLONG_MAX;
73570af302Sopenharmony_ci
74570af302Sopenharmony_ci	errno = 0;
75570af302Sopenharmony_ci	t = mktime(tm);
76570af302Sopenharmony_ci	if (overflow && t != -1)
77570af302Sopenharmony_ci		t_error("%s: mktime(%s) expected -1, got (time_t)%ld\n",
78570af302Sopenharmony_ci			m, tm_str(*tm), (long)t);
79570af302Sopenharmony_ci	if (overflow && errno != EOVERFLOW)
80570af302Sopenharmony_ci		t_error("%s: mktime(%s) expected EOVERFLOW (%s), got (%s)\n",
81570af302Sopenharmony_ci			m, tm_str(*tm), strerror(EOVERFLOW), strerror(errno));
82570af302Sopenharmony_ci	if (!overflow && t == -1)
83570af302Sopenharmony_ci		t_error("%s: mktime(%s) expected success, got (time_t)-1\n",
84570af302Sopenharmony_ci			m, tm_str(*tm));
85570af302Sopenharmony_ci	if (!overflow && errno)
86570af302Sopenharmony_ci		t_error("%s: mktime(%s) expected no error, got (%s)\n",
87570af302Sopenharmony_ci			m, tm_str(*tm), strerror(errno));
88570af302Sopenharmony_ci	r = gmtime(&t);
89570af302Sopenharmony_ci	if (!overflow && tm_cmp(*r, *tm))
90570af302Sopenharmony_ci		t_error("%s: gmtime(mktime(%s)) roundtrip failed: got %s\n",
91570af302Sopenharmony_ci			m, tm_str(*tm), tm_str(*r));
92570af302Sopenharmony_ci}
93570af302Sopenharmony_ci
94570af302Sopenharmony_ciint main(void)
95570af302Sopenharmony_ci{
96570af302Sopenharmony_ci	time_t t;
97570af302Sopenharmony_ci
98570af302Sopenharmony_ci	putenv("TZ=GMT");
99570af302Sopenharmony_ci	tzset();
100570af302Sopenharmony_ci	tm2sec(&TM_EPOCH, 0, "gmtime(0)");
101570af302Sopenharmony_ci	tm2sec(&TM_Y2038_1S, 0, "2038-1s");
102570af302Sopenharmony_ci	tm2sec(&TM_Y2038, 1, "2038");
103570af302Sopenharmony_ci
104570af302Sopenharmony_ci	sec2tm(0, "EPOCH");
105570af302Sopenharmony_ci	for (t = 1; t < 1000; t++)
106570af302Sopenharmony_ci		sec2tm(t*100003, "EPOCH+eps");
107570af302Sopenharmony_ci
108570af302Sopenharmony_ci	/* FIXME: set a TZ var and check DST boundary conditions */
109570af302Sopenharmony_ci	return t_status;
110570af302Sopenharmony_ci}
111