1*0a6a1f1dSLionel Sambuc /* $NetBSD: t_parsedate.c,v 1.13 2014/10/08 17:23:03 apb Exp $ */
211be35a1SLionel Sambuc /*-
311be35a1SLionel Sambuc * Copyright (c) 2010 The NetBSD Foundation, Inc.
411be35a1SLionel Sambuc * All rights reserved.
511be35a1SLionel Sambuc *
611be35a1SLionel Sambuc * Redistribution and use in source and binary forms, with or without
711be35a1SLionel Sambuc * modification, are permitted provided that the following conditions
811be35a1SLionel Sambuc * are met:
911be35a1SLionel Sambuc *
1011be35a1SLionel Sambuc * 1. Redistributions of source code must retain the above copyright
1111be35a1SLionel Sambuc * notice, this list of conditions and the following disclaimer.
1211be35a1SLionel Sambuc * 2. Redistributions in binary form must reproduce the above copyright
1311be35a1SLionel Sambuc * notice, this list of conditions and the following disclaimer in
1411be35a1SLionel Sambuc * the documentation and/or other materials provided with the
1511be35a1SLionel Sambuc * distribution.
1611be35a1SLionel Sambuc *
1711be35a1SLionel Sambuc * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1811be35a1SLionel Sambuc * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1911be35a1SLionel Sambuc * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
2011be35a1SLionel Sambuc * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
2111be35a1SLionel Sambuc * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
2211be35a1SLionel Sambuc * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
2311be35a1SLionel Sambuc * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2411be35a1SLionel Sambuc * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
2511be35a1SLionel Sambuc * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
2611be35a1SLionel Sambuc * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
2711be35a1SLionel Sambuc * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2811be35a1SLionel Sambuc * SUCH DAMAGE.
2911be35a1SLionel Sambuc */
3011be35a1SLionel Sambuc
3111be35a1SLionel Sambuc #include <sys/cdefs.h>
32*0a6a1f1dSLionel Sambuc __RCSID("$NetBSD: t_parsedate.c,v 1.13 2014/10/08 17:23:03 apb Exp $");
3311be35a1SLionel Sambuc
3411be35a1SLionel Sambuc #include <atf-c.h>
3511be35a1SLionel Sambuc #include <errno.h>
36*0a6a1f1dSLionel Sambuc #include <stdio.h>
3711be35a1SLionel Sambuc #include <stdlib.h>
3811be35a1SLionel Sambuc #include <time.h>
3911be35a1SLionel Sambuc #include <util.h>
4011be35a1SLionel Sambuc
41*0a6a1f1dSLionel Sambuc /*
42*0a6a1f1dSLionel Sambuc * ANY is used as a placeholder for values that do not need to be
43*0a6a1f1dSLionel Sambuc * checked. The actual value is arbitrary. We don't use -1
44*0a6a1f1dSLionel Sambuc * because some tests might want to use -1 as a literal value.
45*0a6a1f1dSLionel Sambuc */
46*0a6a1f1dSLionel Sambuc #define ANY -30215
47*0a6a1f1dSLionel Sambuc
48*0a6a1f1dSLionel Sambuc /* parsecheck --
49*0a6a1f1dSLionel Sambuc * call parsedate(), then call time_to_tm() on the result,
50*0a6a1f1dSLionel Sambuc * and check that year/month/day/hour/minute/second are as expected.
51*0a6a1f1dSLionel Sambuc *
52*0a6a1f1dSLionel Sambuc * time_to_tm should usually be localtime_r or gmtime_r.
53*0a6a1f1dSLionel Sambuc *
54*0a6a1f1dSLionel Sambuc * Don't check values specified as ANY.
55*0a6a1f1dSLionel Sambuc */
56*0a6a1f1dSLionel Sambuc static void
parsecheck(const char * datestr,const time_t * reftime,const int * zoff,struct tm * time_to_tm (const time_t *,struct tm *),int year,int month,int day,int hour,int minute,int second)57*0a6a1f1dSLionel Sambuc parsecheck(const char *datestr, const time_t *reftime, const int *zoff,
58*0a6a1f1dSLionel Sambuc struct tm * time_to_tm(const time_t *, struct tm *),
59*0a6a1f1dSLionel Sambuc int year, int month, int day, int hour, int minute, int second)
60*0a6a1f1dSLionel Sambuc {
61*0a6a1f1dSLionel Sambuc time_t t;
62*0a6a1f1dSLionel Sambuc struct tm tm;
63*0a6a1f1dSLionel Sambuc char argstr[128];
64*0a6a1f1dSLionel Sambuc
65*0a6a1f1dSLionel Sambuc /*
66*0a6a1f1dSLionel Sambuc * printable version of the args.
67*0a6a1f1dSLionel Sambuc *
68*0a6a1f1dSLionel Sambuc * Note that printf("%.*d", 0, 0)) prints nothing at all,
69*0a6a1f1dSLionel Sambuc * while printf("%.*d", 1, val) prints the value as usual.
70*0a6a1f1dSLionel Sambuc */
71*0a6a1f1dSLionel Sambuc snprintf(argstr, sizeof(argstr), "%s%s%s, %s%.*jd, %s%.*d",
72*0a6a1f1dSLionel Sambuc /* NULL or \"<datestr>\" */
73*0a6a1f1dSLionel Sambuc (datestr ? "\"" : ""),
74*0a6a1f1dSLionel Sambuc (datestr ? datestr : "NULL"),
75*0a6a1f1dSLionel Sambuc (datestr ? "\"" : ""),
76*0a6a1f1dSLionel Sambuc /* NULL or *reftime */
77*0a6a1f1dSLionel Sambuc (reftime ? "" : "NULL"),
78*0a6a1f1dSLionel Sambuc (reftime ? 1 : 0),
79*0a6a1f1dSLionel Sambuc (reftime ? (intmax_t)*reftime : (intmax_t)0),
80*0a6a1f1dSLionel Sambuc /* NULL or *zoff */
81*0a6a1f1dSLionel Sambuc (zoff ? "" : "NULL"),
82*0a6a1f1dSLionel Sambuc (zoff ? 1 : 0),
83*0a6a1f1dSLionel Sambuc (zoff ? *zoff : 0));
84*0a6a1f1dSLionel Sambuc
85*0a6a1f1dSLionel Sambuc ATF_CHECK_MSG((t = parsedate(datestr, reftime, zoff)) != -1,
86*0a6a1f1dSLionel Sambuc "parsedate(%s) returned -1\n", argstr);
87*0a6a1f1dSLionel Sambuc ATF_CHECK(time_to_tm(&t, &tm) != NULL);
88*0a6a1f1dSLionel Sambuc if (year != ANY)
89*0a6a1f1dSLionel Sambuc ATF_CHECK_MSG(tm.tm_year + 1900 == year,
90*0a6a1f1dSLionel Sambuc "parsedate(%s) expected year %d got %d (+1900)\n",
91*0a6a1f1dSLionel Sambuc argstr, year, (int)tm.tm_year);
92*0a6a1f1dSLionel Sambuc if (month != ANY)
93*0a6a1f1dSLionel Sambuc ATF_CHECK_MSG(tm.tm_mon + 1 == month,
94*0a6a1f1dSLionel Sambuc "parsedate(%s) expected month %d got %d (+1)\n",
95*0a6a1f1dSLionel Sambuc argstr, month, (int)tm.tm_mon);
96*0a6a1f1dSLionel Sambuc if (day != ANY)
97*0a6a1f1dSLionel Sambuc ATF_CHECK_MSG(tm.tm_mday == day,
98*0a6a1f1dSLionel Sambuc "parsedate(%s) expected day %d got %d\n",
99*0a6a1f1dSLionel Sambuc argstr, day, (int)tm.tm_mday);
100*0a6a1f1dSLionel Sambuc if (hour != ANY)
101*0a6a1f1dSLionel Sambuc ATF_CHECK_MSG(tm.tm_hour == hour,
102*0a6a1f1dSLionel Sambuc "parsedate(%s) expected hour %d got %d\n",
103*0a6a1f1dSLionel Sambuc argstr, hour, (int)tm.tm_hour);
104*0a6a1f1dSLionel Sambuc if (minute != ANY)
105*0a6a1f1dSLionel Sambuc ATF_CHECK_MSG(tm.tm_min == minute,
106*0a6a1f1dSLionel Sambuc "parsedate(%s) expected minute %d got %d\n",
107*0a6a1f1dSLionel Sambuc argstr, minute, (int)tm.tm_min);
108*0a6a1f1dSLionel Sambuc if (second != ANY)
109*0a6a1f1dSLionel Sambuc ATF_CHECK_MSG(tm.tm_sec == second,
110*0a6a1f1dSLionel Sambuc "parsedate(%s) expected second %d got %d\n",
111*0a6a1f1dSLionel Sambuc argstr, second, (int)tm.tm_sec);
112*0a6a1f1dSLionel Sambuc }
113*0a6a1f1dSLionel Sambuc
11411be35a1SLionel Sambuc ATF_TC(dates);
11511be35a1SLionel Sambuc
ATF_TC_HEAD(dates,tc)11611be35a1SLionel Sambuc ATF_TC_HEAD(dates, tc)
11711be35a1SLionel Sambuc {
11811be35a1SLionel Sambuc atf_tc_set_md_var(tc, "descr", "Test unambiguous dates"
11911be35a1SLionel Sambuc " (PR lib/44255)");
12011be35a1SLionel Sambuc }
12111be35a1SLionel Sambuc
ATF_TC_BODY(dates,tc)12211be35a1SLionel Sambuc ATF_TC_BODY(dates, tc)
12311be35a1SLionel Sambuc {
12411be35a1SLionel Sambuc
125*0a6a1f1dSLionel Sambuc parsecheck("9/10/69", NULL, NULL, localtime_r,
126*0a6a1f1dSLionel Sambuc 2069, 9, 10, 0, 0, 0); /* year < 70: add 2000 */
127*0a6a1f1dSLionel Sambuc parsecheck("9/10/70", NULL, NULL, localtime_r,
128*0a6a1f1dSLionel Sambuc 1970, 9, 10, 0, 0, 0); /* 70 <= year < 100: add 1900 */
129*0a6a1f1dSLionel Sambuc parsecheck("69-09-10", NULL, NULL, localtime_r,
130*0a6a1f1dSLionel Sambuc 69, 9, 10, 0, 0, 0); /* ISO8601 year remains unchanged */
131*0a6a1f1dSLionel Sambuc parsecheck("70-09-10", NULL, NULL, localtime_r,
132*0a6a1f1dSLionel Sambuc 70, 9, 10, 0, 0, 0); /* ISO8601 year remains unchanged */
133*0a6a1f1dSLionel Sambuc parsecheck("2006-11-17", NULL, NULL, localtime_r,
134*0a6a1f1dSLionel Sambuc 2006, 11, 17, 0, 0, 0);
135*0a6a1f1dSLionel Sambuc parsecheck("10/1/2000", NULL, NULL, localtime_r,
136*0a6a1f1dSLionel Sambuc 2000, 10, 1, 0, 0, 0); /* month/day/year */
137*0a6a1f1dSLionel Sambuc parsecheck("20 Jun 1994", NULL, NULL, localtime_r,
138*0a6a1f1dSLionel Sambuc 1994, 6, 20, 0, 0, 0);
139*0a6a1f1dSLionel Sambuc parsecheck("23jun2001", NULL, NULL, localtime_r,
140*0a6a1f1dSLionel Sambuc 2001, 6, 23, 0, 0, 0);
141*0a6a1f1dSLionel Sambuc parsecheck("1-sep-06", NULL, NULL, localtime_r,
142*0a6a1f1dSLionel Sambuc 2006, 9, 1, 0, 0, 0);
143*0a6a1f1dSLionel Sambuc parsecheck("1/11", NULL, NULL, localtime_r,
144*0a6a1f1dSLionel Sambuc ANY, 1, 11, 0, 0, 0); /* month/day */
145*0a6a1f1dSLionel Sambuc parsecheck("1500-01-02", NULL, NULL, localtime_r,
146*0a6a1f1dSLionel Sambuc 1500, 1, 2, 0, 0, 0);
147*0a6a1f1dSLionel Sambuc parsecheck("9999-12-21", NULL, NULL, localtime_r,
148*0a6a1f1dSLionel Sambuc 9999, 12, 21, 0, 0, 0);
14911be35a1SLionel Sambuc }
15011be35a1SLionel Sambuc
15111be35a1SLionel Sambuc ATF_TC(times);
15211be35a1SLionel Sambuc
ATF_TC_HEAD(times,tc)15311be35a1SLionel Sambuc ATF_TC_HEAD(times, tc)
15411be35a1SLionel Sambuc {
15511be35a1SLionel Sambuc atf_tc_set_md_var(tc, "descr", "Test times"
15611be35a1SLionel Sambuc " (PR lib/44255)");
15711be35a1SLionel Sambuc }
15811be35a1SLionel Sambuc
ATF_TC_BODY(times,tc)15911be35a1SLionel Sambuc ATF_TC_BODY(times, tc)
16011be35a1SLionel Sambuc {
16111be35a1SLionel Sambuc
162*0a6a1f1dSLionel Sambuc parsecheck("10:01", NULL, NULL, localtime_r,
163*0a6a1f1dSLionel Sambuc ANY, ANY, ANY, 10, 1, 0);
164*0a6a1f1dSLionel Sambuc parsecheck("10:12pm", NULL, NULL, localtime_r,
165*0a6a1f1dSLionel Sambuc ANY, ANY, ANY, 22, 12, 0);
166*0a6a1f1dSLionel Sambuc parsecheck("12:11:01.000012", NULL, NULL, localtime_r,
167*0a6a1f1dSLionel Sambuc ANY, ANY, ANY, 12, 11, 1);
168*0a6a1f1dSLionel Sambuc parsecheck("12:21-0500", NULL, NULL, gmtime_r,
169*0a6a1f1dSLionel Sambuc ANY, ANY, ANY, 12+5, 21, 0);
170*0a6a1f1dSLionel Sambuc }
171*0a6a1f1dSLionel Sambuc
172*0a6a1f1dSLionel Sambuc ATF_TC(dsttimes);
173*0a6a1f1dSLionel Sambuc
ATF_TC_HEAD(dsttimes,tc)174*0a6a1f1dSLionel Sambuc ATF_TC_HEAD(dsttimes, tc)
175*0a6a1f1dSLionel Sambuc {
176*0a6a1f1dSLionel Sambuc atf_tc_set_md_var(tc, "descr", "Test DST transition times"
177*0a6a1f1dSLionel Sambuc " (PR lib/47916)");
178*0a6a1f1dSLionel Sambuc }
179*0a6a1f1dSLionel Sambuc
ATF_TC_BODY(dsttimes,tc)180*0a6a1f1dSLionel Sambuc ATF_TC_BODY(dsttimes, tc)
181*0a6a1f1dSLionel Sambuc {
182*0a6a1f1dSLionel Sambuc struct tm tm;
183*0a6a1f1dSLionel Sambuc time_t t;
184*0a6a1f1dSLionel Sambuc int tzoff;
185*0a6a1f1dSLionel Sambuc
186*0a6a1f1dSLionel Sambuc putenv(__UNCONST("TZ=EST"));
187*0a6a1f1dSLionel Sambuc tzset();
188*0a6a1f1dSLionel Sambuc parsecheck("12:0", NULL, NULL, localtime_r,
189*0a6a1f1dSLionel Sambuc ANY, ANY, ANY, 12, 0, 0);
190*0a6a1f1dSLionel Sambuc
191*0a6a1f1dSLionel Sambuc putenv(__UNCONST("TZ=Japan"));
192*0a6a1f1dSLionel Sambuc tzset();
193*0a6a1f1dSLionel Sambuc parsecheck("12:0", NULL, NULL, localtime_r,
194*0a6a1f1dSLionel Sambuc ANY, ANY, ANY, 12, 0, 0);
195*0a6a1f1dSLionel Sambuc
196*0a6a1f1dSLionel Sambuc /*
197*0a6a1f1dSLionel Sambuc * When the effective local time is Tue Jul 9 13:21:53 BST 2013,
198*0a6a1f1dSLionel Sambuc * check mktime("14:00")
199*0a6a1f1dSLionel Sambuc */
200*0a6a1f1dSLionel Sambuc putenv(__UNCONST("TZ=Europe/London"));
201*0a6a1f1dSLionel Sambuc tzset();
202*0a6a1f1dSLionel Sambuc tm = (struct tm){
203*0a6a1f1dSLionel Sambuc .tm_year = 2013-1900, .tm_mon = 7-1, .tm_mday = 9,
204*0a6a1f1dSLionel Sambuc .tm_hour = 13, .tm_min = 21, .tm_sec = 53,
205*0a6a1f1dSLionel Sambuc .tm_isdst = 0 };
206*0a6a1f1dSLionel Sambuc t = mktime(&tm);
207*0a6a1f1dSLionel Sambuc ATF_CHECK(t != (time_t)-1);
208*0a6a1f1dSLionel Sambuc parsecheck("14:00", &t, NULL, localtime_r,
209*0a6a1f1dSLionel Sambuc 2013, 7, 9, 14, 0, 0);
210*0a6a1f1dSLionel Sambuc tzoff = -60; /* British Summer Time */
211*0a6a1f1dSLionel Sambuc parsecheck("14:00", &t, &tzoff, localtime_r,
212*0a6a1f1dSLionel Sambuc 2013, 7, 9, 14, 0, 0);
21311be35a1SLionel Sambuc }
21411be35a1SLionel Sambuc
21511be35a1SLionel Sambuc ATF_TC(relative);
21611be35a1SLionel Sambuc
ATF_TC_HEAD(relative,tc)21711be35a1SLionel Sambuc ATF_TC_HEAD(relative, tc)
21811be35a1SLionel Sambuc {
21911be35a1SLionel Sambuc atf_tc_set_md_var(tc, "descr", "Test relative items"
22011be35a1SLionel Sambuc " (PR lib/44255)");
22111be35a1SLionel Sambuc }
22211be35a1SLionel Sambuc
ATF_TC_BODY(relative,tc)22311be35a1SLionel Sambuc ATF_TC_BODY(relative, tc)
22411be35a1SLionel Sambuc {
22511be35a1SLionel Sambuc
22611be35a1SLionel Sambuc ATF_CHECK(parsedate("-1 month", NULL, NULL) != -1);
22711be35a1SLionel Sambuc ATF_CHECK(parsedate("last friday", NULL, NULL) != -1);
22811be35a1SLionel Sambuc ATF_CHECK(parsedate("one week ago", NULL, NULL) != -1);
22911be35a1SLionel Sambuc ATF_CHECK(parsedate("this thursday", NULL, NULL) != -1);
23011be35a1SLionel Sambuc ATF_CHECK(parsedate("next sunday", NULL, NULL) != -1);
23111be35a1SLionel Sambuc ATF_CHECK(parsedate("+2 years", NULL, NULL) != -1);
23211be35a1SLionel Sambuc }
23311be35a1SLionel Sambuc
23411be35a1SLionel Sambuc ATF_TC(atsecs);
23511be35a1SLionel Sambuc
ATF_TC_HEAD(atsecs,tc)23611be35a1SLionel Sambuc ATF_TC_HEAD(atsecs, tc)
23711be35a1SLionel Sambuc {
23811be35a1SLionel Sambuc atf_tc_set_md_var(tc, "descr", "Test seconds past the epoch");
23911be35a1SLionel Sambuc }
24011be35a1SLionel Sambuc
ATF_TC_BODY(atsecs,tc)24111be35a1SLionel Sambuc ATF_TC_BODY(atsecs, tc)
24211be35a1SLionel Sambuc {
24311be35a1SLionel Sambuc int tzoff;
24411be35a1SLionel Sambuc
24511be35a1SLionel Sambuc /* "@0" -> (time_t)0, regardless of timezone */
24611be35a1SLionel Sambuc ATF_CHECK(parsedate("@0", NULL, NULL) == (time_t)0);
24711be35a1SLionel Sambuc putenv(__UNCONST("TZ=Europe/Berlin"));
24811be35a1SLionel Sambuc tzset();
24911be35a1SLionel Sambuc ATF_CHECK(parsedate("@0", NULL, NULL) == (time_t)0);
25011be35a1SLionel Sambuc putenv(__UNCONST("TZ=America/New_York"));
25111be35a1SLionel Sambuc tzset();
25211be35a1SLionel Sambuc ATF_CHECK(parsedate("@0", NULL, NULL) == (time_t)0);
25311be35a1SLionel Sambuc tzoff = 0;
25411be35a1SLionel Sambuc ATF_CHECK(parsedate("@0", NULL, &tzoff) == (time_t)0);
25511be35a1SLionel Sambuc tzoff = 3600;
25611be35a1SLionel Sambuc ATF_CHECK(parsedate("@0", NULL, &tzoff) == (time_t)0);
25711be35a1SLionel Sambuc tzoff = -3600;
25811be35a1SLionel Sambuc ATF_CHECK(parsedate("@0", NULL, &tzoff) == (time_t)0);
25911be35a1SLionel Sambuc
26011be35a1SLionel Sambuc /* -1 or other negative numbers are not errors */
26111be35a1SLionel Sambuc errno = 0;
26211be35a1SLionel Sambuc ATF_CHECK(parsedate("@-1", NULL, &tzoff) == (time_t)-1 && errno == 0);
26311be35a1SLionel Sambuc ATF_CHECK(parsedate("@-2", NULL, &tzoff) == (time_t)-2 && errno == 0);
26411be35a1SLionel Sambuc
26511be35a1SLionel Sambuc /* junk is an error */
26611be35a1SLionel Sambuc errno = 0;
26711be35a1SLionel Sambuc ATF_CHECK(parsedate("@junk", NULL, NULL) == (time_t)-1 && errno != 0);
26811be35a1SLionel Sambuc }
26911be35a1SLionel Sambuc
ATF_TP_ADD_TCS(tp)27011be35a1SLionel Sambuc ATF_TP_ADD_TCS(tp)
27111be35a1SLionel Sambuc {
27211be35a1SLionel Sambuc ATF_TP_ADD_TC(tp, dates);
27311be35a1SLionel Sambuc ATF_TP_ADD_TC(tp, times);
274*0a6a1f1dSLionel Sambuc ATF_TP_ADD_TC(tp, dsttimes);
27511be35a1SLionel Sambuc ATF_TP_ADD_TC(tp, relative);
27611be35a1SLionel Sambuc ATF_TP_ADD_TC(tp, atsecs);
27711be35a1SLionel Sambuc
27811be35a1SLionel Sambuc return atf_no_error();
27911be35a1SLionel Sambuc }
280