1570af302Sopenharmony_ci// SPDX-License-Identifier: MIT
2570af302Sopenharmony_ci
3570af302Sopenharmony_ci#define _GNU_SOURCE	/* For tm_gmtoff */
4570af302Sopenharmony_ci#include <stddef.h>
5570af302Sopenharmony_ci#include <stdlib.h>
6570af302Sopenharmony_ci#include <string.h>
7570af302Sopenharmony_ci#include <time.h>
8570af302Sopenharmony_ci#include "test.h"
9570af302Sopenharmony_ci
10570af302Sopenharmony_ci/**
11570af302Sopenharmony_ci * checkStrptime - parse time and check if it matches expected value
12570af302Sopenharmony_ci *
13570af302Sopenharmony_ci * This function compares time and date fields of tm structure only.
14570af302Sopenharmony_ci * It's because tm_wday and tm_yday may - but don't have to - be set
15570af302Sopenharmony_ci * while parsing a date.
16570af302Sopenharmony_ci */
17570af302Sopenharmony_cistatic void checkStrptime(const char *s, const char *format, const struct tm *expected) {
18570af302Sopenharmony_ci	struct tm tm = { };
19570af302Sopenharmony_ci	const char *ret;
20570af302Sopenharmony_ci
21570af302Sopenharmony_ci	ret = strptime(s, format, &tm);
22570af302Sopenharmony_ci	if (!ret || *ret != '\0') {
23570af302Sopenharmony_ci		t_error("\"%s\": failed to parse \"%s\"\n", format, s);
24570af302Sopenharmony_ci	} else if (tm.tm_sec != expected->tm_sec ||
25570af302Sopenharmony_ci		   tm.tm_min != expected->tm_min ||
26570af302Sopenharmony_ci		   tm.tm_hour != expected->tm_hour ||
27570af302Sopenharmony_ci		   tm.tm_mday != expected->tm_mday ||
28570af302Sopenharmony_ci		   tm.tm_mon != expected->tm_mon ||
29570af302Sopenharmony_ci		   tm.tm_year != expected->tm_year) {
30570af302Sopenharmony_ci		char buf1[64];
31570af302Sopenharmony_ci		char buf2[64];
32570af302Sopenharmony_ci
33570af302Sopenharmony_ci		strftime(buf1, sizeof(buf1), "%FT%H:%M:%S%Z", expected);
34570af302Sopenharmony_ci		strftime(buf2, sizeof(buf2), "%FT%H:%M:%S%Z", &tm);
35570af302Sopenharmony_ci
36570af302Sopenharmony_ci		t_error("\"%s\": for \"%s\" expected %s but got %s\n", format, s, buf1, buf2);
37570af302Sopenharmony_ci	}
38570af302Sopenharmony_ci}
39570af302Sopenharmony_ci
40570af302Sopenharmony_cistatic void checkStrptimeTz(const char *s, int h, int m) {
41570af302Sopenharmony_ci	long int expected = h * 3600 + m * 60;
42570af302Sopenharmony_ci	struct tm tm = { };
43570af302Sopenharmony_ci	const char *ret;
44570af302Sopenharmony_ci
45570af302Sopenharmony_ci	ret = strptime(s, "%z", &tm);
46570af302Sopenharmony_ci	if (!ret || *ret != '\0') {
47570af302Sopenharmony_ci		t_error("\"%%z\": failed to parse \"%s\"\n", s);
48570af302Sopenharmony_ci	} else if (tm.tm_gmtoff != expected) {
49570af302Sopenharmony_ci		t_error("\"%%z\": for \"%s\" expected tm_gmtoff %ld but got %ld\n", s, tm.tm_gmtoff, expected);
50570af302Sopenharmony_ci	}
51570af302Sopenharmony_ci}
52570af302Sopenharmony_ci
53570af302Sopenharmony_cistatic struct tm tm1 = {
54570af302Sopenharmony_ci	.tm_sec = 8,
55570af302Sopenharmony_ci	.tm_min = 57,
56570af302Sopenharmony_ci	.tm_hour = 20,
57570af302Sopenharmony_ci	.tm_mday = 0,
58570af302Sopenharmony_ci	.tm_mon = 0,
59570af302Sopenharmony_ci	.tm_year = 0,
60570af302Sopenharmony_ci};
61570af302Sopenharmony_ci
62570af302Sopenharmony_cistatic struct tm tm2 = {
63570af302Sopenharmony_ci	.tm_sec = 0,
64570af302Sopenharmony_ci	.tm_min = 0,
65570af302Sopenharmony_ci	.tm_hour = 0,
66570af302Sopenharmony_ci	.tm_mday = 25,
67570af302Sopenharmony_ci	.tm_mon = 8 - 1,
68570af302Sopenharmony_ci	.tm_year = 1991 - 1900,
69570af302Sopenharmony_ci};
70570af302Sopenharmony_ci
71570af302Sopenharmony_cistatic struct tm tm3 = {
72570af302Sopenharmony_ci	.tm_sec = 0,
73570af302Sopenharmony_ci	.tm_min = 0,
74570af302Sopenharmony_ci	.tm_hour = 0,
75570af302Sopenharmony_ci	.tm_mday = 21,
76570af302Sopenharmony_ci	.tm_mon = 10 - 1,
77570af302Sopenharmony_ci	.tm_year = 2015 - 1900,
78570af302Sopenharmony_ci};
79570af302Sopenharmony_ci
80570af302Sopenharmony_cistatic struct tm tm4 = {
81570af302Sopenharmony_ci	.tm_sec = 0,
82570af302Sopenharmony_ci	.tm_min = 0,
83570af302Sopenharmony_ci	.tm_hour = 0,
84570af302Sopenharmony_ci	.tm_mday = 10,
85570af302Sopenharmony_ci	.tm_mon = 7 - 1,
86570af302Sopenharmony_ci	.tm_year = 1856 - 1900,
87570af302Sopenharmony_ci};
88570af302Sopenharmony_ci
89570af302Sopenharmony_ciint main() {
90570af302Sopenharmony_ci	setenv("TZ", "UTC0", 1);
91570af302Sopenharmony_ci
92570af302Sopenharmony_ci	/* Time */
93570af302Sopenharmony_ci	checkStrptime("20:57:08", "%H:%M:%S", &tm1);
94570af302Sopenharmony_ci	checkStrptime("20:57:8", "%R:%S", &tm1);
95570af302Sopenharmony_ci	checkStrptime("20:57:08", "%T", &tm1);
96570af302Sopenharmony_ci
97570af302Sopenharmony_ci	/* Format */
98570af302Sopenharmony_ci	checkStrptime("20:57:08", "%H : %M  :  %S", &tm1);
99570af302Sopenharmony_ci	checkStrptime("20 57  08", "%H %M %S", &tm1);
100570af302Sopenharmony_ci	checkStrptime("20%57%08", "%H %% %M%%%S", &tm1);
101570af302Sopenharmony_ci	checkStrptime("foo20bar57qux08      ", "foo %Hbar %M qux%S ", &tm1);
102570af302Sopenharmony_ci
103570af302Sopenharmony_ci	/* Date */
104570af302Sopenharmony_ci	checkStrptime("1991-08-25", "%Y-%m-%d", &tm2);
105570af302Sopenharmony_ci	checkStrptime("25.08.91", "%d.%m.%y", &tm2);
106570af302Sopenharmony_ci	checkStrptime("08/25/91", "%D", &tm2);
107570af302Sopenharmony_ci	checkStrptime("21.10.15", "%d.%m.%y", &tm3);
108570af302Sopenharmony_ci	checkStrptime("10.7.56 in 18th", "%d.%m.%y in %C th", &tm4);
109570af302Sopenharmony_ci
110570af302Sopenharmony_ci	/* Glibc */
111570af302Sopenharmony_ci	checkStrptime("1856-07-10", "%F", &tm4);
112570af302Sopenharmony_ci	checkStrptime("683078400", "%s", &tm2);
113570af302Sopenharmony_ci	checkStrptimeTz("+0200", 2, 0);
114570af302Sopenharmony_ci	checkStrptimeTz("-0530", -5, -30);
115570af302Sopenharmony_ci	checkStrptimeTz("-06", -6, 0);
116570af302Sopenharmony_ci
117570af302Sopenharmony_ci	return t_status;
118570af302Sopenharmony_ci}
119