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