1 1.33 christos /* $NetBSD: t_parsedate.c,v 1.33 2022/05/02 19:57:50 christos Exp $ */ 2 1.1 njoly /*- 3 1.14 christos * Copyright (c) 2010, 2015 The NetBSD Foundation, Inc. 4 1.1 njoly * All rights reserved. 5 1.1 njoly * 6 1.1 njoly * Redistribution and use in source and binary forms, with or without 7 1.1 njoly * modification, are permitted provided that the following conditions 8 1.1 njoly * are met: 9 1.1 njoly * 10 1.1 njoly * 1. Redistributions of source code must retain the above copyright 11 1.1 njoly * notice, this list of conditions and the following disclaimer. 12 1.1 njoly * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 njoly * notice, this list of conditions and the following disclaimer in 14 1.1 njoly * the documentation and/or other materials provided with the 15 1.1 njoly * distribution. 16 1.1 njoly * 17 1.1 njoly * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 1.1 njoly * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 1.1 njoly * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 20 1.1 njoly * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 21 1.1 njoly * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 22 1.1 njoly * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 23 1.1 njoly * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 1.1 njoly * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 25 1.1 njoly * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 1.1 njoly * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 27 1.1 njoly * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 1.1 njoly * SUCH DAMAGE. 29 1.1 njoly */ 30 1.1 njoly 31 1.1 njoly #include <sys/cdefs.h> 32 1.33 christos __RCSID("$NetBSD: t_parsedate.c,v 1.33 2022/05/02 19:57:50 christos Exp $"); 33 1.1 njoly 34 1.1 njoly #include <atf-c.h> 35 1.6 apb #include <errno.h> 36 1.12 apb #include <stdio.h> 37 1.6 apb #include <stdlib.h> 38 1.6 apb #include <time.h> 39 1.1 njoly #include <util.h> 40 1.1 njoly 41 1.8 apb /* 42 1.8 apb * ANY is used as a placeholder for values that do not need to be 43 1.8 apb * checked. The actual value is arbitrary. We don't use -1 44 1.8 apb * because some tests might want to use -1 as a literal value. 45 1.8 apb */ 46 1.8 apb #define ANY -30215 47 1.8 apb 48 1.8 apb /* parsecheck -- 49 1.8 apb * call parsedate(), then call time_to_tm() on the result, 50 1.8 apb * and check that year/month/day/hour/minute/second are as expected. 51 1.8 apb * 52 1.8 apb * time_to_tm should usually be localtime_r or gmtime_r. 53 1.8 apb * 54 1.8 apb * Don't check values specified as ANY. 55 1.8 apb */ 56 1.8 apb static void 57 1.8 apb parsecheck(const char *datestr, const time_t *reftime, const int *zoff, 58 1.8 apb struct tm * time_to_tm(const time_t *, struct tm *), 59 1.8 apb int year, int month, int day, int hour, int minute, int second) 60 1.8 apb { 61 1.8 apb time_t t; 62 1.8 apb struct tm tm; 63 1.12 apb char argstr[128]; 64 1.12 apb 65 1.12 apb /* 66 1.12 apb * printable version of the args. 67 1.12 apb * 68 1.12 apb * Note that printf("%.*d", 0, 0)) prints nothing at all, 69 1.12 apb * while printf("%.*d", 1, val) prints the value as usual. 70 1.12 apb */ 71 1.12 apb snprintf(argstr, sizeof(argstr), "%s%s%s, %s%.*jd, %s%.*d", 72 1.12 apb /* NULL or \"<datestr>\" */ 73 1.12 apb (datestr ? "\"" : ""), 74 1.12 apb (datestr ? datestr : "NULL"), 75 1.12 apb (datestr ? "\"" : ""), 76 1.12 apb /* NULL or *reftime */ 77 1.12 apb (reftime ? "" : "NULL"), 78 1.12 apb (reftime ? 1 : 0), 79 1.12 apb (reftime ? (intmax_t)*reftime : (intmax_t)0), 80 1.12 apb /* NULL or *zoff */ 81 1.12 apb (zoff ? "" : "NULL"), 82 1.12 apb (zoff ? 1 : 0), 83 1.12 apb (zoff ? *zoff : 0)); 84 1.8 apb 85 1.8 apb ATF_CHECK_MSG((t = parsedate(datestr, reftime, zoff)) != -1, 86 1.12 apb "parsedate(%s) returned -1\n", argstr); 87 1.26 kre if (t == -1) 88 1.26 kre return; 89 1.26 kre 90 1.8 apb ATF_CHECK(time_to_tm(&t, &tm) != NULL); 91 1.8 apb if (year != ANY) 92 1.8 apb ATF_CHECK_MSG(tm.tm_year + 1900 == year, 93 1.12 apb "parsedate(%s) expected year %d got %d (+1900)\n", 94 1.12 apb argstr, year, (int)tm.tm_year); 95 1.8 apb if (month != ANY) 96 1.8 apb ATF_CHECK_MSG(tm.tm_mon + 1 == month, 97 1.12 apb "parsedate(%s) expected month %d got %d (+1)\n", 98 1.12 apb argstr, month, (int)tm.tm_mon); 99 1.8 apb if (day != ANY) 100 1.8 apb ATF_CHECK_MSG(tm.tm_mday == day, 101 1.12 apb "parsedate(%s) expected day %d got %d\n", 102 1.12 apb argstr, day, (int)tm.tm_mday); 103 1.8 apb if (hour != ANY) 104 1.8 apb ATF_CHECK_MSG(tm.tm_hour == hour, 105 1.12 apb "parsedate(%s) expected hour %d got %d\n", 106 1.12 apb argstr, hour, (int)tm.tm_hour); 107 1.8 apb if (minute != ANY) 108 1.8 apb ATF_CHECK_MSG(tm.tm_min == minute, 109 1.12 apb "parsedate(%s) expected minute %d got %d\n", 110 1.12 apb argstr, minute, (int)tm.tm_min); 111 1.8 apb if (second != ANY) 112 1.8 apb ATF_CHECK_MSG(tm.tm_sec == second, 113 1.12 apb "parsedate(%s) expected second %d got %d\n", 114 1.12 apb argstr, second, (int)tm.tm_sec); 115 1.8 apb } 116 1.8 apb 117 1.1 njoly ATF_TC(dates); 118 1.1 njoly 119 1.1 njoly ATF_TC_HEAD(dates, tc) 120 1.1 njoly { 121 1.4 christos atf_tc_set_md_var(tc, "descr", "Test unambiguous dates" 122 1.5 jruoho " (PR lib/44255)"); 123 1.1 njoly } 124 1.1 njoly 125 1.1 njoly ATF_TC_BODY(dates, tc) 126 1.1 njoly { 127 1.1 njoly 128 1.31 kre parsecheck("9/10/68", NULL, NULL, localtime_r, 129 1.31 kre 2068, 9, 10, 0, 0, 0); /* year < 69: add 2000 */ 130 1.10 apb parsecheck("9/10/69", NULL, NULL, localtime_r, 131 1.31 kre 1969, 9, 10, 0, 0, 0); /* 69 <= year < 100: add 1900 */ 132 1.31 kre parsecheck("68-09-10", NULL, NULL, localtime_r, 133 1.31 kre 68, 9, 10, 0, 0, 0); /* ISO8601 year remains unchanged */ 134 1.9 apb parsecheck("70-09-10", NULL, NULL, localtime_r, 135 1.10 apb 70, 9, 10, 0, 0, 0); /* ISO8601 year remains unchanged */ 136 1.8 apb parsecheck("2006-11-17", NULL, NULL, localtime_r, 137 1.8 apb 2006, 11, 17, 0, 0, 0); 138 1.8 apb parsecheck("10/1/2000", NULL, NULL, localtime_r, 139 1.9 apb 2000, 10, 1, 0, 0, 0); /* month/day/year */ 140 1.32 christos parsecheck("12/01/2022", NULL, NULL, localtime_r, 141 1.32 christos 2022, 12, 1, 0, 0, 0); /* month/day/year, December */ 142 1.8 apb parsecheck("20 Jun 1994", NULL, NULL, localtime_r, 143 1.8 apb 1994, 6, 20, 0, 0, 0); 144 1.14 christos parsecheck("97 September 2", NULL, NULL, localtime_r, 145 1.14 christos 1997, 9, 2, 0, 0, 0); 146 1.8 apb parsecheck("23jun2001", NULL, NULL, localtime_r, 147 1.8 apb 2001, 6, 23, 0, 0, 0); 148 1.8 apb parsecheck("1-sep-06", NULL, NULL, localtime_r, 149 1.8 apb 2006, 9, 1, 0, 0, 0); 150 1.8 apb parsecheck("1/11", NULL, NULL, localtime_r, 151 1.9 apb ANY, 1, 11, 0, 0, 0); /* month/day */ 152 1.8 apb parsecheck("1500-01-02", NULL, NULL, localtime_r, 153 1.8 apb 1500, 1, 2, 0, 0, 0); 154 1.8 apb parsecheck("9999-12-21", NULL, NULL, localtime_r, 155 1.8 apb 9999, 12, 21, 0, 0, 0); 156 1.14 christos parsecheck("2015.12.07.08.07.35", NULL, NULL, localtime_r, 157 1.14 christos 2015, 12, 7, 8, 7, 35); 158 1.1 njoly } 159 1.1 njoly 160 1.1 njoly ATF_TC(times); 161 1.1 njoly 162 1.1 njoly ATF_TC_HEAD(times, tc) 163 1.1 njoly { 164 1.4 christos atf_tc_set_md_var(tc, "descr", "Test times" 165 1.5 jruoho " (PR lib/44255)"); 166 1.1 njoly } 167 1.1 njoly 168 1.1 njoly ATF_TC_BODY(times, tc) 169 1.1 njoly { 170 1.1 njoly 171 1.8 apb parsecheck("10:01", NULL, NULL, localtime_r, 172 1.8 apb ANY, ANY, ANY, 10, 1, 0); 173 1.8 apb parsecheck("10:12pm", NULL, NULL, localtime_r, 174 1.8 apb ANY, ANY, ANY, 22, 12, 0); 175 1.8 apb parsecheck("12:11:01.000012", NULL, NULL, localtime_r, 176 1.8 apb ANY, ANY, ANY, 12, 11, 1); 177 1.8 apb parsecheck("12:21-0500", NULL, NULL, gmtime_r, 178 1.8 apb ANY, ANY, ANY, 12+5, 21, 0); 179 1.14 christos /* numeric zones not permitted with am/pm ... */ 180 1.14 christos parsecheck("7 a.m. ICT", NULL, NULL, gmtime_r, 181 1.14 christos ANY, ANY, ANY, 7-7, 0, 0); 182 1.14 christos parsecheck("midnight", NULL, NULL, localtime_r, 183 1.14 christos ANY, ANY, ANY, 0, 0, 0); 184 1.14 christos parsecheck("mn", NULL, NULL, localtime_r, 185 1.14 christos ANY, ANY, ANY, 0, 0, 0); 186 1.14 christos parsecheck("noon", NULL, NULL, localtime_r, 187 1.14 christos ANY, ANY, ANY, 12, 0, 0); 188 1.26 kre 189 1.28 kre /* 190 1.28 kre * The following tests used to trigger the bug from PR lib/52101 191 1.28 kre * but that is fixed now. 192 1.28 kre * 193 1.26 kre atf_tc_expect_fail("PR lib/52101"); 194 1.28 kre */ 195 1.26 kre 196 1.26 kre parsecheck("12:30 am", NULL, NULL, localtime_r, 197 1.26 kre ANY, ANY, ANY, 0, 30, 0); 198 1.26 kre parsecheck("12:30 pm", NULL, NULL, localtime_r, 199 1.27 kre ANY, ANY, ANY, 12, 30, 0); 200 1.26 kre 201 1.26 kre /* 202 1.26 kre * Technically, these are invalid, noon and midnight 203 1.26 kre * are neither am, nor pm, but this is what people expect... 204 1.26 kre */ 205 1.26 kre parsecheck("12:00:00 am", NULL, NULL, localtime_r, 206 1.26 kre ANY, ANY, ANY, 0, 0, 0); 207 1.26 kre parsecheck("12:00:00 pm", NULL, NULL, localtime_r, 208 1.26 kre ANY, ANY, ANY, 12, 0, 0); 209 1.26 kre parsecheck("12am", NULL, NULL, localtime_r, 210 1.26 kre ANY, ANY, ANY, 0, 0, 0); 211 1.26 kre parsecheck("12pm", NULL, NULL, localtime_r, 212 1.26 kre ANY, ANY, ANY, 12, 0, 0); 213 1.28 kre 214 1.30 kre /* end 52101 bug tests */ 215 1.29 kre 216 1.29 kre parsecheck("12 noon", NULL, NULL, localtime_r, 217 1.29 kre ANY, ANY, ANY, 12, 0, 0); 218 1.29 kre parsecheck("12 midnight", NULL, NULL, localtime_r, 219 1.29 kre ANY, ANY, ANY, 0, 0, 0); 220 1.29 kre parsecheck("12 midday", NULL, NULL, localtime_r, /* unlikely! */ 221 1.29 kre ANY, ANY, ANY, 12, 0, 0); 222 1.29 kre parsecheck("12 mn", NULL, NULL, localtime_r, 223 1.29 kre ANY, ANY, ANY, 0, 0, 0); 224 1.29 kre 225 1.29 kre parsecheck("12:00 noon", NULL, NULL, localtime_r, 226 1.29 kre ANY, ANY, ANY, 12, 0, 0); 227 1.29 kre parsecheck("12:00 midnight", NULL, NULL, localtime_r, 228 1.29 kre ANY, ANY, ANY, 0, 0, 0); 229 1.29 kre parsecheck("12:00:00 noon", NULL, NULL, localtime_r, 230 1.29 kre ANY, ANY, ANY, 12, 0, 0); 231 1.29 kre parsecheck("12:00:00 midnight", NULL, NULL, localtime_r, 232 1.29 kre ANY, ANY, ANY, 0, 0, 0); 233 1.1 njoly } 234 1.1 njoly 235 1.11 apb ATF_TC(dsttimes); 236 1.11 apb 237 1.11 apb ATF_TC_HEAD(dsttimes, tc) 238 1.11 apb { 239 1.11 apb atf_tc_set_md_var(tc, "descr", "Test DST transition times" 240 1.11 apb " (PR lib/47916)"); 241 1.11 apb } 242 1.11 apb 243 1.11 apb ATF_TC_BODY(dsttimes, tc) 244 1.11 apb { 245 1.11 apb struct tm tm; 246 1.11 apb time_t t; 247 1.11 apb int tzoff; 248 1.11 apb 249 1.11 apb putenv(__UNCONST("TZ=EST")); 250 1.11 apb tzset(); 251 1.11 apb parsecheck("12:0", NULL, NULL, localtime_r, 252 1.11 apb ANY, ANY, ANY, 12, 0, 0); 253 1.11 apb 254 1.14 christos putenv(__UNCONST("TZ=Asia/Tokyo")); 255 1.11 apb tzset(); 256 1.11 apb parsecheck("12:0", NULL, NULL, localtime_r, 257 1.11 apb ANY, ANY, ANY, 12, 0, 0); 258 1.11 apb 259 1.11 apb /* 260 1.11 apb * When the effective local time is Tue Jul 9 13:21:53 BST 2013, 261 1.11 apb * check mktime("14:00") 262 1.11 apb */ 263 1.11 apb putenv(__UNCONST("TZ=Europe/London")); 264 1.11 apb tzset(); 265 1.11 apb tm = (struct tm){ 266 1.11 apb .tm_year = 2013-1900, .tm_mon = 7-1, .tm_mday = 9, 267 1.11 apb .tm_hour = 13, .tm_min = 21, .tm_sec = 53, 268 1.11 apb .tm_isdst = 0 }; 269 1.11 apb t = mktime(&tm); 270 1.11 apb ATF_CHECK(t != (time_t)-1); 271 1.11 apb parsecheck("14:00", &t, NULL, localtime_r, 272 1.11 apb 2013, 7, 9, 14, 0, 0); 273 1.13 apb tzoff = -60; /* British Summer Time */ 274 1.11 apb parsecheck("14:00", &t, &tzoff, localtime_r, 275 1.11 apb 2013, 7, 9, 14, 0, 0); 276 1.11 apb } 277 1.11 apb 278 1.1 njoly ATF_TC(relative); 279 1.1 njoly 280 1.1 njoly ATF_TC_HEAD(relative, tc) 281 1.1 njoly { 282 1.4 christos atf_tc_set_md_var(tc, "descr", "Test relative items" 283 1.5 jruoho " (PR lib/44255)"); 284 1.1 njoly } 285 1.1 njoly 286 1.1 njoly ATF_TC_BODY(relative, tc) 287 1.1 njoly { 288 1.14 christos struct tm tm; 289 1.14 christos time_t now; 290 1.14 christos 291 1.14 christos #define REL_CHECK(s, now, tm) do { \ 292 1.14 christos time_t p, q; \ 293 1.22 kre char nb[30], pb[30], qb[30]; \ 294 1.19 dholland p = parsedate(s, &now, NULL); \ 295 1.19 dholland q = mktime(&tm); \ 296 1.19 dholland ATF_CHECK_EQ_MSG(p, q, \ 297 1.22 kre "From %jd (%24.24s) using \"%s\", obtained %jd (%24.24s); expected %jd (%24.24s)", \ 298 1.24 kre (uintmax_t)now, ctime_r(&now, nb), \ 299 1.19 dholland s, (uintmax_t)p, ctime_r(&p, pb), (uintmax_t)q, \ 300 1.14 christos ctime_r(&q, qb)); \ 301 1.14 christos } while (/*CONSTCOND*/0) 302 1.1 njoly 303 1.22 kre #define isleap(yr) (((yr) & 3) == 0 && (((yr) % 100) != 0 || \ 304 1.22 kre ((1900+(yr)) % 400) == 0)) 305 1.22 kre 306 1.1 njoly ATF_CHECK(parsedate("-1 month", NULL, NULL) != -1); 307 1.1 njoly ATF_CHECK(parsedate("last friday", NULL, NULL) != -1); 308 1.1 njoly ATF_CHECK(parsedate("one week ago", NULL, NULL) != -1); 309 1.1 njoly ATF_CHECK(parsedate("this thursday", NULL, NULL) != -1); 310 1.1 njoly ATF_CHECK(parsedate("next sunday", NULL, NULL) != -1); 311 1.1 njoly ATF_CHECK(parsedate("+2 years", NULL, NULL) != -1); 312 1.14 christos 313 1.20 gson /* 314 1.20 gson * Test relative to a number of fixed dates. Avoid the 315 1.20 gson * edges of the time_t range to avert under- or overflow 316 1.20 gson * of the relative date, and use a prime step for maximum 317 1.20 gson * coverage of different times of day/week/month/year. 318 1.20 gson */ 319 1.23 gson for (now = 0x00FFFFFF; now < 0xFF000000; now += 3777779) { 320 1.20 gson ATF_CHECK(localtime_r(&now, &tm) != NULL); 321 1.20 gson tm.tm_mday--; 322 1.20 gson /* "yesterday" leaves time untouched */ 323 1.20 gson tm.tm_isdst = -1; 324 1.20 gson REL_CHECK("yesterday", now, tm); 325 1.20 gson 326 1.20 gson ATF_CHECK(localtime_r(&now, &tm) != NULL); 327 1.20 gson tm.tm_mday++; 328 1.20 gson /* as does "tomorrow" */ 329 1.20 gson tm.tm_isdst = -1; 330 1.20 gson REL_CHECK("tomorrow", now, tm); 331 1.20 gson 332 1.20 gson ATF_CHECK(localtime_r(&now, &tm) != NULL); 333 1.20 gson if (tm.tm_wday > 4) 334 1.21 kre tm.tm_mday += 7; 335 1.21 kre tm.tm_mday += 4 - tm.tm_wday; 336 1.21 kre /* if a day name is mentioned, it means midnight (by default) */ 337 1.21 kre tm.tm_sec = tm.tm_min = tm.tm_hour = 0; 338 1.21 kre tm.tm_isdst = -1; 339 1.21 kre REL_CHECK("this thursday", now, tm); 340 1.21 kre 341 1.21 kre ATF_CHECK(localtime_r(&now, &tm) != NULL); 342 1.21 kre tm.tm_mday += 14 - (tm.tm_wday ? tm.tm_wday : 7); 343 1.21 kre tm.tm_sec = tm.tm_min = tm.tm_hour = 0; 344 1.21 kre tm.tm_isdst = -1; 345 1.21 kre REL_CHECK("next sunday", now, tm); 346 1.21 kre 347 1.21 kre ATF_CHECK(localtime_r(&now, &tm) != NULL); 348 1.21 kre if (tm.tm_wday <= 5) 349 1.21 kre tm.tm_mday -= 7; 350 1.21 kre tm.tm_mday += 5 - tm.tm_wday; 351 1.21 kre tm.tm_sec = tm.tm_min = 0; 352 1.21 kre tm.tm_hour = 16; 353 1.21 kre tm.tm_isdst = -1; 354 1.21 kre REL_CHECK("last friday 4 p.m.", now, tm); 355 1.21 kre 356 1.21 kre ATF_CHECK(localtime_r(&now, &tm) != NULL); 357 1.21 kre tm.tm_mday += 14; 358 1.21 kre if (tm.tm_wday > 3) 359 1.21 kre tm.tm_mday += 7; 360 1.21 kre tm.tm_mday += 3 - tm.tm_wday; 361 1.21 kre tm.tm_sec = tm.tm_min = 0; 362 1.21 kre tm.tm_hour = 3; 363 1.21 kre tm.tm_isdst = -1; 364 1.21 kre REL_CHECK("we fortnight 3 a.m.", now, tm); 365 1.21 kre 366 1.21 kre ATF_CHECK(localtime_r(&now, &tm) != NULL); 367 1.21 kre tm.tm_min -= 5; 368 1.21 kre tm.tm_isdst = -1; 369 1.21 kre REL_CHECK("5 minutes ago", now, tm); 370 1.21 kre 371 1.21 kre ATF_CHECK(localtime_r(&now, &tm) != NULL); 372 1.21 kre tm.tm_hour++; 373 1.21 kre tm.tm_min += 37; 374 1.21 kre tm.tm_isdst = -1; 375 1.21 kre REL_CHECK("97 minutes", now, tm); 376 1.21 kre 377 1.21 kre ATF_CHECK(localtime_r(&now, &tm) != NULL); 378 1.21 kre tm.tm_mon++; 379 1.22 kre if (tm.tm_mon == 1 && 380 1.22 kre tm.tm_mday > 28 + isleap(tm.tm_year)) 381 1.22 kre tm.tm_mday = 28 + isleap(tm.tm_year); 382 1.22 kre else if ((tm.tm_mon == 3 || tm.tm_mon == 5 || 383 1.22 kre tm.tm_mon == 8 || tm.tm_mon == 10) && tm.tm_mday == 31) 384 1.22 kre tm.tm_mday = 30; 385 1.21 kre tm.tm_isdst = -1; 386 1.21 kre REL_CHECK("month", now, tm); 387 1.21 kre 388 1.21 kre ATF_CHECK(localtime_r(&now, &tm) != NULL); 389 1.21 kre tm.tm_mon += 2; /* "next" means add 2 ... */ 390 1.22 kre if (tm.tm_mon == 13 && 391 1.22 kre tm.tm_mday > 28 + isleap(tm.tm_year + 1)) 392 1.22 kre tm.tm_mday = 28 + isleap(tm.tm_year + 1); 393 1.22 kre else if (tm.tm_mon == 8 && tm.tm_mday == 31) 394 1.22 kre tm.tm_mday = 30; 395 1.21 kre tm.tm_isdst = -1; 396 1.21 kre REL_CHECK("next month", now, tm); 397 1.21 kre 398 1.21 kre ATF_CHECK(localtime_r(&now, &tm) != NULL); 399 1.21 kre tm.tm_mon--; 400 1.22 kre if (tm.tm_mon == 1 && 401 1.22 kre tm.tm_mday > 28 + isleap(tm.tm_year)) 402 1.22 kre tm.tm_mday = 28 + isleap(tm.tm_year); 403 1.22 kre else if ((tm.tm_mon == 3 || tm.tm_mon == 5 || 404 1.22 kre tm.tm_mon == 8 || tm.tm_mon == 10) && tm.tm_mday == 31) 405 1.22 kre tm.tm_mday = 30; 406 1.21 kre tm.tm_isdst = -1; 407 1.21 kre REL_CHECK("last month", now, tm); 408 1.21 kre 409 1.21 kre ATF_CHECK(localtime_r(&now, &tm) != NULL); 410 1.21 kre tm.tm_mon += 6; 411 1.22 kre if (tm.tm_mon == 13 && 412 1.22 kre tm.tm_mday > 28 + isleap(tm.tm_year + 1)) 413 1.22 kre tm.tm_mday = 28 + isleap(tm.tm_year + 1); 414 1.22 kre else if ((tm.tm_mon == 15 || tm.tm_mon == 17 || 415 1.22 kre tm.tm_mon == 8 || tm.tm_mon == 10) && tm.tm_mday == 31) 416 1.22 kre tm.tm_mday = 30; 417 1.21 kre tm.tm_mday += 2; 418 1.21 kre tm.tm_isdst = -1; 419 1.21 kre REL_CHECK("+6 months 2 days", now, tm); 420 1.21 kre 421 1.21 kre ATF_CHECK(localtime_r(&now, &tm) != NULL); 422 1.21 kre tm.tm_mon -= 9; 423 1.22 kre if (tm.tm_mon == 1 && tm.tm_mday > 28 + isleap(tm.tm_year)) 424 1.24 kre tm.tm_mday = 28 + isleap(tm.tm_year); 425 1.22 kre else if ((tm.tm_mon == -9 || tm.tm_mon == -7 || 426 1.22 kre tm.tm_mon == -2) && tm.tm_mday == 31) 427 1.22 kre tm.tm_mday = 30; 428 1.21 kre tm.tm_isdst = -1; 429 1.21 kre REL_CHECK("9 months ago", now, tm); 430 1.21 kre 431 1.21 kre ATF_CHECK(localtime_r(&now, &tm) != NULL); 432 1.21 kre if (tm.tm_wday <= 2) 433 1.21 kre tm.tm_mday -= 7; 434 1.21 kre tm.tm_mday += 2 - tm.tm_wday; 435 1.21 kre tm.tm_isdst = -1; 436 1.21 kre tm.tm_hour = tm.tm_min = tm.tm_sec = 0; 437 1.21 kre REL_CHECK("1 week ago Tu", now, tm); 438 1.21 kre 439 1.21 kre ATF_CHECK(localtime_r(&now, &tm) != NULL); 440 1.21 kre tm.tm_isdst = -1; 441 1.21 kre tm.tm_mday++; 442 1.21 kre tm.tm_hour = tm.tm_min = tm.tm_sec = 0; 443 1.21 kre REL_CHECK("midnight tomorrow", now, tm); 444 1.21 kre 445 1.21 kre ATF_CHECK(localtime_r(&now, &tm) != NULL); 446 1.21 kre tm.tm_isdst = -1; 447 1.21 kre tm.tm_mday++; 448 1.21 kre tm.tm_hour = tm.tm_min = tm.tm_sec = 0; 449 1.21 kre REL_CHECK("tomorrow midnight", now, tm); 450 1.21 kre 451 1.21 kre ATF_CHECK(localtime_r(&now, &tm) != NULL); 452 1.21 kre tm.tm_isdst = -1; 453 1.21 kre tm.tm_mday++; 454 1.21 kre tm.tm_hour = 12; 455 1.21 kre tm.tm_min = tm.tm_sec = 0; 456 1.21 kre REL_CHECK("noon tomorrow", now, tm); 457 1.21 kre 458 1.21 kre ATF_CHECK(localtime_r(&now, &tm) != NULL); 459 1.21 kre if (tm.tm_wday > 2) 460 1.21 kre tm.tm_mday += 7; 461 1.21 kre tm.tm_mday += 2 - tm.tm_wday; 462 1.21 kre tm.tm_sec = tm.tm_min = tm.tm_hour = 0; 463 1.21 kre tm.tm_isdst = -1; 464 1.21 kre REL_CHECK("midnight Tuesday", now, tm); 465 1.21 kre 466 1.21 kre ATF_CHECK(localtime_r(&now, &tm) != NULL); 467 1.21 kre if (tm.tm_wday > 2 + 1) 468 1.21 kre tm.tm_mday += 7; 469 1.21 kre tm.tm_mday += 2 - tm.tm_wday; 470 1.21 kre tm.tm_mday++; /* xxx midnight --> the next day */ 471 1.21 kre tm.tm_sec = tm.tm_min = tm.tm_hour = 0; 472 1.21 kre tm.tm_isdst = -1; 473 1.21 kre REL_CHECK("Tuesday midnight", now, tm); 474 1.21 kre } 475 1.1 njoly } 476 1.1 njoly 477 1.6 apb ATF_TC(atsecs); 478 1.6 apb 479 1.6 apb ATF_TC_HEAD(atsecs, tc) 480 1.6 apb { 481 1.6 apb atf_tc_set_md_var(tc, "descr", "Test seconds past the epoch"); 482 1.6 apb } 483 1.6 apb 484 1.6 apb ATF_TC_BODY(atsecs, tc) 485 1.6 apb { 486 1.6 apb int tzoff; 487 1.6 apb 488 1.6 apb /* "@0" -> (time_t)0, regardless of timezone */ 489 1.6 apb ATF_CHECK(parsedate("@0", NULL, NULL) == (time_t)0); 490 1.6 apb putenv(__UNCONST("TZ=Europe/Berlin")); 491 1.6 apb tzset(); 492 1.6 apb ATF_CHECK(parsedate("@0", NULL, NULL) == (time_t)0); 493 1.6 apb putenv(__UNCONST("TZ=America/New_York")); 494 1.6 apb tzset(); 495 1.6 apb ATF_CHECK(parsedate("@0", NULL, NULL) == (time_t)0); 496 1.6 apb tzoff = 0; 497 1.6 apb ATF_CHECK(parsedate("@0", NULL, &tzoff) == (time_t)0); 498 1.6 apb tzoff = 3600; 499 1.6 apb ATF_CHECK(parsedate("@0", NULL, &tzoff) == (time_t)0); 500 1.6 apb tzoff = -3600; 501 1.6 apb ATF_CHECK(parsedate("@0", NULL, &tzoff) == (time_t)0); 502 1.6 apb 503 1.7 apb /* -1 or other negative numbers are not errors */ 504 1.6 apb errno = 0; 505 1.6 apb ATF_CHECK(parsedate("@-1", NULL, &tzoff) == (time_t)-1 && errno == 0); 506 1.7 apb ATF_CHECK(parsedate("@-2", NULL, &tzoff) == (time_t)-2 && errno == 0); 507 1.7 apb 508 1.7 apb /* junk is an error */ 509 1.7 apb errno = 0; 510 1.7 apb ATF_CHECK(parsedate("@junk", NULL, NULL) == (time_t)-1 && errno != 0); 511 1.6 apb } 512 1.6 apb 513 1.14 christos ATF_TC(zones); 514 1.14 christos 515 1.14 christos ATF_TC_HEAD(zones, tc) 516 1.14 christos { 517 1.14 christos atf_tc_set_md_var(tc, "descr", "Test parsing dates with zones"); 518 1.14 christos } 519 1.14 christos 520 1.14 christos ATF_TC_BODY(zones, tc) 521 1.14 christos { 522 1.14 christos parsecheck("2015-12-06 16:11:48 UTC", NULL, NULL, gmtime_r, 523 1.14 christos 2015, 12, 6, 16, 11, 48); 524 1.14 christos parsecheck("2015-12-06 16:11:48 UT", NULL, NULL, gmtime_r, 525 1.14 christos 2015, 12, 6, 16, 11, 48); 526 1.14 christos parsecheck("2015-12-06 16:11:48 GMT", NULL, NULL, gmtime_r, 527 1.14 christos 2015, 12, 6, 16, 11, 48); 528 1.14 christos parsecheck("2015-12-06 16:11:48 +0000", NULL, NULL, gmtime_r, 529 1.14 christos 2015, 12, 6, 16, 11, 48); 530 1.14 christos 531 1.14 christos parsecheck("2015-12-06 16:11:48 -0500", NULL, NULL, gmtime_r, 532 1.14 christos 2015, 12, 6, 21, 11, 48); 533 1.14 christos parsecheck("2015-12-06 16:11:48 EST", NULL, NULL, gmtime_r, 534 1.14 christos 2015, 12, 6, 21, 11, 48); 535 1.14 christos parsecheck("2015-12-06 16:11:48 EDT", NULL, NULL, gmtime_r, 536 1.14 christos 2015, 12, 6, 20, 11, 48); 537 1.14 christos parsecheck("2015-12-06 16:11:48 +0500", NULL, NULL, gmtime_r, 538 1.14 christos 2015, 12, 6, 11, 11, 48); 539 1.14 christos 540 1.14 christos parsecheck("2015-12-06 16:11:48 +1000", NULL, NULL, gmtime_r, 541 1.14 christos 2015, 12, 6, 6, 11, 48); 542 1.14 christos parsecheck("2015-12-06 16:11:48 AEST", NULL, NULL, gmtime_r, 543 1.14 christos 2015, 12, 6, 6, 11, 48); 544 1.14 christos parsecheck("2015-12-06 16:11:48 -1000", NULL, NULL, gmtime_r, 545 1.14 christos 2015, 12, 7, 2, 11, 48); 546 1.14 christos parsecheck("2015-12-06 16:11:48 HST", NULL, NULL, gmtime_r, 547 1.14 christos 2015, 12, 7, 2, 11, 48); 548 1.14 christos 549 1.14 christos parsecheck("2015-12-06 16:11:48 AWST", NULL, NULL, gmtime_r, 550 1.14 christos 2015, 12, 6, 8, 11, 48); 551 1.14 christos parsecheck("2015-12-06 16:11:48 NZDT", NULL, NULL, gmtime_r, 552 1.14 christos 2015, 12, 6, 3, 11, 48); 553 1.14 christos 554 1.14 christos parsecheck("Sun, 6 Dec 2015 09:43:16 -0500", NULL, NULL, gmtime_r, 555 1.14 christos 2015, 12, 6, 14, 43, 16); 556 1.14 christos parsecheck("Mon Dec 7 03:13:31 ICT 2015", NULL, NULL, gmtime_r, 557 1.14 christos 2015, 12, 6, 20, 13, 31); 558 1.14 christos /* the day name is ignored when a day of month (etc) is given... */ 559 1.14 christos parsecheck("Sat Dec 7 03:13:31 ICT 2015", NULL, NULL, gmtime_r, 560 1.14 christos 2015, 12, 6, 20, 13, 31); 561 1.14 christos 562 1.14 christos 563 1.14 christos parsecheck("2015-12-06 12:00:00 IDLW", NULL, NULL, gmtime_r, 564 1.14 christos 2015, 12, 7, 0, 0, 0); 565 1.14 christos parsecheck("2015-12-06 12:00:00 IDLE", NULL, NULL, gmtime_r, 566 1.14 christos 2015, 12, 6, 0, 0, 0); 567 1.14 christos 568 1.14 christos parsecheck("2015-12-06 21:17:33 NFT", NULL, NULL, gmtime_r, 569 1.14 christos 2015, 12, 7, 0, 47, 33); 570 1.14 christos parsecheck("2015-12-06 21:17:33 ACST", NULL, NULL, gmtime_r, 571 1.14 christos 2015, 12, 6, 11, 47, 33); 572 1.14 christos parsecheck("2015-12-06 21:17:33 +0717", NULL, NULL, gmtime_r, 573 1.14 christos 2015, 12, 6, 14, 0, 33); 574 1.14 christos 575 1.14 christos parsecheck("2015-12-06 21:21:21 Z", NULL, NULL, gmtime_r, 576 1.14 christos 2015, 12, 6, 21, 21, 21); 577 1.14 christos parsecheck("2015-12-06 21:21:21 A", NULL, NULL, gmtime_r, 578 1.14 christos 2015, 12, 6, 22, 21, 21); 579 1.14 christos parsecheck("2015-12-06 21:21:21 G", NULL, NULL, gmtime_r, 580 1.14 christos 2015, 12, 7, 4, 21, 21); 581 1.14 christos parsecheck("2015-12-06 21:21:21 M", NULL, NULL, gmtime_r, 582 1.14 christos 2015, 12, 7, 9, 21, 21); 583 1.14 christos parsecheck("2015-12-06 21:21:21 N", NULL, NULL, gmtime_r, 584 1.14 christos 2015, 12, 6, 20, 21, 21); 585 1.14 christos parsecheck("2015-12-06 21:21:21 T", NULL, NULL, gmtime_r, 586 1.14 christos 2015, 12, 6, 14, 21, 21); 587 1.14 christos parsecheck("2015-12-06 21:21:21 Y", NULL, NULL, gmtime_r, 588 1.14 christos 2015, 12, 6, 9, 21, 21); 589 1.14 christos 590 1.14 christos } 591 1.14 christos 592 1.14 christos ATF_TC(gibberish); 593 1.14 christos 594 1.14 christos ATF_TC_HEAD(gibberish, tc) 595 1.14 christos { 596 1.14 christos atf_tc_set_md_var(tc, "descr", "Test (not) parsing nonsense"); 597 1.14 christos } 598 1.14 christos 599 1.14 christos ATF_TC_BODY(gibberish, tc) 600 1.14 christos { 601 1.14 christos errno = 0; 602 1.14 christos ATF_CHECK(parsedate("invalid nonsense", NULL, NULL) == (time_t)-1 603 1.14 christos && errno != 0); 604 1.14 christos errno = 0; 605 1.14 christos ATF_CHECK(parsedate("12th day of Christmas", NULL, NULL) == (time_t)-1 606 1.14 christos && errno != 0); 607 1.14 christos errno = 0; 608 1.14 christos ATF_CHECK(parsedate("2015-31-07 15:00", NULL, NULL) == (time_t)-1 609 1.14 christos && errno != 0); 610 1.14 christos errno = 0; 611 1.14 christos ATF_CHECK(parsedate("2015-02-29 10:01", NULL, NULL) == (time_t)-1 612 1.14 christos && errno != 0); 613 1.14 christos errno = 0; 614 1.14 christos ATF_CHECK(parsedate("2015-12-06 24:01", NULL, NULL) == (time_t)-1 615 1.14 christos && errno != 0); 616 1.14 christos errno = 0; 617 1.14 christos ATF_CHECK(parsedate("2015-12-06 14:61", NULL, NULL) == (time_t)-1 618 1.14 christos && errno != 0); 619 1.14 christos } 620 1.14 christos 621 1.1 njoly ATF_TP_ADD_TCS(tp) 622 1.1 njoly { 623 1.33 christos setenv("TZ", "UTC", 1); 624 1.33 christos tzset(); 625 1.1 njoly ATF_TP_ADD_TC(tp, dates); 626 1.1 njoly ATF_TP_ADD_TC(tp, times); 627 1.11 apb ATF_TP_ADD_TC(tp, dsttimes); 628 1.1 njoly ATF_TP_ADD_TC(tp, relative); 629 1.6 apb ATF_TP_ADD_TC(tp, atsecs); 630 1.14 christos ATF_TP_ADD_TC(tp, zones); 631 1.14 christos ATF_TP_ADD_TC(tp, gibberish); 632 1.1 njoly 633 1.1 njoly return atf_no_error(); 634 1.1 njoly } 635 1.14 christos 636