1/*	$NetBSD: lsf-times.c,v 1.2 2024/08/18 20:47:27 christos Exp $	*/
2
3#include "config.h"
4#include "ntp_calendar.h"
5
6#include <stdlib.h>
7#include <errno.h>
8
9#include "ntp_types.h"
10#include "ntp_fp.h"
11#include "vint64ops.h"
12
13/*
14 * If we're called with 1 arg, it's a u_long timestamp.
15 * If we're called with 3 args, we're expecting YYYY MM DD,
16 *   and MM must be 6 or 12, and DD must be 28,
17 * If we're called with 2 args, we're expecting YYYY MM, and
18 *   MM mst be 6 or 12, and we assume DD is 28.
19 */
20
21char *progname;
22static const char *MONTHS[] =
23                { "January", "February", "March", "April", "May", "June",
24		  "July", "August", "September", "October", "November",
25		  "December" };
26
27void usage(void);
28
29void
30usage(void)
31{
32	printf("Usage:\n");
33	printf(" %s nnnnnn\n", progname);
34	printf(" %s YYYY [6|12]\n", progname);
35	printf(" %s YYYY [6|12] 28\n", progname);
36
37	return;
38}
39
40
41int
42main(
43	int	argc,		/* command line options */
44	char	**argv		/* poiniter to list of tokens */
45	)
46{
47	int err = 0;
48	vint64 expires;
49	unsigned int year = 0;
50	unsigned int mon = 0;
51	unsigned int dom = 0;
52	int scount;
53	char *ep;
54	struct calendar cal = {0};
55
56	progname = argv[0];
57
58	switch(argc) {
59	 case 2:	/* 1 arg, must be a string of digits */
60		expires = strtouv64(argv[1], &ep, 10);
61
62		if (0 == *ep) {
63			ntpcal_ntp64_to_date(&cal, &expires);
64
65			printf("%02u %s %04u %02u:%02u:%02u\n"
66				, cal.monthday
67				, MONTHS[cal.month - 1]
68				, cal.year
69				, cal.hour
70				, cal.minute
71				, cal.second
72				);
73
74			exit(0);
75		} else {
76			printf("1 arg, but not a string of digits: <%s>\n",
77				argv[1]);
78			err = 1;
79		}
80		break;
81		;;
82	 case 3:	/* 2 args, must be YY MM, where MM is 6 or 12 */
83		dom = 28;
84		scount = sscanf(argv[1], "%u", &year);
85		if (1 == scount) {
86			// printf("2 args: year %u\n", year);
87		} else {
88			printf("2 args, but #1 is not a string of digits: <%s>\n", argv[1]);
89			err = 1;
90		}
91
92		scount = sscanf(argv[2], "%u", &mon);
93		if (1 == scount) {
94			if (6 == mon || 12 == mon) {
95				// printf("2 args: month %u\n", mon);
96			} else {
97				printf("2 arg, but #2 is not 6 or 12: <%d>\n", mon);
98				err = 1;
99			}
100		} else {
101			printf("2 arg, but #2 is not a string of digits: <%s>\n", argv[2]);
102			err = 1;
103		}
104
105		break;
106		;;
107	 case 4:	/* 3 args, YY MM DD, where MM is 6 or 12, DD is 28 */
108		scount = sscanf(argv[1], "%u", &year);
109		if (1 == scount) {
110			// printf("3 args: year %u\n", year);
111		} else {
112			printf("3 args, but #1 is not a string of digits: <%s>\n", argv[1]);
113			err = 1;
114		}
115
116		scount = sscanf(argv[2], "%u", &mon);
117		if (1 == scount) {
118			if (6 == mon || 12 == mon) {
119				// printf("3 args: month %u\n", mon);
120			} else {
121				printf("3 arg, but #2 is not 6 or 12: <%d>\n", mon);
122				err = 1;
123			}
124		} else {
125			printf("3 arg, but #2 is not a string of digits: <%s>\n", argv[2]);
126			err = 1;
127		}
128
129		scount = sscanf(argv[3], "%u", &dom);
130		if (1 == scount) {
131			if (28 == dom) {
132				// printf("3 args: dom %u\n", dom);
133			} else {
134				printf("3 arg, but #3 is not 28: <%d>\n", dom);
135				err = 1;
136			}
137		} else {
138			printf("3 arg, but #3 is not a string of digits: <%s>\n", argv[2]);
139			err = 1;
140		}
141
142		break;
143		;;
144	 default:
145		err = 1;
146		break;
147		;;
148	}
149
150	if (err) {
151		usage();
152		exit(err);
153	}
154
155	cal.year = year;
156	cal.month = mon;
157	cal.monthday = dom;
158	cal.hour = 0;
159	cal.minute = 0;
160	cal.second = 0;
161
162	printf("%u ", ntpcal_date_to_ntp(&cal));
163
164	printf("%02d %s %04d "
165		, cal.monthday
166		, MONTHS[cal.month - 1]
167		, cal.year
168		);
169	printf("\n");
170
171	exit(err);
172}
173
174#if 0
175
176
177void
178test_DateGivenMonthDay(void) {
179	// 2010-06-24 12:50:00
180	struct calendar input = {2010, 0, 6, 24, 12, 50, 0};
181
182	u_long expected = 3486372600UL; // This is the timestamp above.
183
184	TEST_ASSERT_EQUAL_UINT(expected, caltontp(&input));
185}
186
187void
188test_DateGivenYearDay(void) {
189	// 2010-06-24 12:50:00
190	// This is the 175th day of 2010.
191	struct calendar input = {2010, 175, 0, 0, 12, 50, 0};
192
193	u_long expected = 3486372600UL; // This is the timestamp above.
194
195	TEST_ASSERT_EQUAL_UINT(expected, caltontp(&input));
196}
197
198void
199test_DateLeapYear(void) {
200	// 2012-06-24 12:00:00
201	// This is the 176th day of 2012 (since 2012 is a leap year).
202	struct calendar inputYd = {2012, 176, 0, 0, 12, 00, 00};
203	struct calendar inputMd = {2012, 0, 6, 24, 12, 00, 00};
204
205	u_long expected = 3549528000UL;
206
207	TEST_ASSERT_EQUAL_UINT(expected, caltontp(&inputYd));
208	TEST_ASSERT_EQUAL_UINT(expected, caltontp(&inputMd));
209}
210
211void
212test_WraparoundDateIn2036(void) {
213	// 2036-02-07 06:28:16
214	// This is (one) wrapping boundary where we go from ULONG_MAX to 0.
215	struct calendar input = {2036, 0, 2, 7, 6, 28, 16};
216
217	u_long expected = 0UL;
218
219	TEST_ASSERT_EQUAL_UINT(expected, caltontp(&input));
220}
221
222#endif
223