/* $OpenBSD: timetest.c,v 1.4 2023/04/13 11:32:06 mbuhl Exp $ */ /* * Copyright (c) 2022 Bob Beck * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #include #include struct timetest { char *descr; char *timezone; time_t time; struct tm local_tm; struct tm gmt_tm; }; static int tm_match(struct tm * tm1, struct tm *tm2) { if (tm2->tm_year != tm1->tm_year || tm2->tm_mon != tm1->tm_mon || tm2->tm_mday != tm1->tm_mday || tm2->tm_hour != tm1->tm_hour || tm2->tm_min != tm1->tm_min || tm2->tm_sec != tm1->tm_sec || tm2->tm_wday != tm1->tm_wday || tm2->tm_yday != tm1->tm_yday || tm2->tm_yday != tm1->tm_yday || tm2->tm_isdst != tm1->tm_isdst || tm2->tm_gmtoff != tm1->tm_gmtoff || strcmp(tm2->tm_zone, tm1->tm_zone) != 0) return 0; return 1; } struct timetest timetests[] = { { .descr="moon", .timezone="posix/America/Edmonton", .time=-16751025, .local_tm= { .tm_year=69, .tm_mon=5, .tm_mday=20, .tm_hour=19, .tm_min=56, .tm_sec=15, .tm_wday=5, .tm_yday=170, .tm_isdst=0, .tm_gmtoff=-25200, .tm_zone="MST" }, .gmt_tm= { .tm_year=69, .tm_mon=5, .tm_mday=21, .tm_hour=2, .tm_min=56, .tm_sec=15, .tm_wday=6, .tm_yday=171, .tm_isdst=0, .tm_gmtoff=0, .tm_zone="GMT" }, }, { .descr="moon", .timezone="right/UTC", .time=-16751025, .local_tm= { .tm_year=69, .tm_mon=5, .tm_mday=21, .tm_hour=2, .tm_min=56, .tm_sec=15, .tm_wday=6, .tm_yday=171, .tm_isdst=0, .tm_gmtoff=0, .tm_zone="UTC" }, .gmt_tm= { .tm_year=69, .tm_mon=5, .tm_mday=21, .tm_hour=2, .tm_min=56, .tm_sec=15, .tm_wday=6, .tm_yday=171, .tm_isdst=0, .tm_gmtoff=0, .tm_zone="GMT" }, }, { .descr="moon", .timezone="right/America/Edmonton", .time=-16751025, .local_tm= { .tm_year=69, .tm_mon=5, .tm_mday=20, .tm_hour=19, .tm_min=56, .tm_sec=15, .tm_wday=5, .tm_yday=170, .tm_isdst=0, .tm_gmtoff=-25200, .tm_zone="MST" }, .gmt_tm= { .tm_year=69, .tm_mon=5, .tm_mday=21, .tm_hour=2, .tm_min=56, .tm_sec=15, .tm_wday=6, .tm_yday=171, .tm_isdst=0, .tm_gmtoff=0, .tm_zone="GMT" }, }, { .descr="epoch", .timezone="posix/America/Edmonton", .time=0, .local_tm= { .tm_year=69, .tm_mon=11, .tm_mday=31, .tm_hour=17, .tm_min=0, .tm_sec=0, .tm_wday=3, .tm_yday=364, .tm_isdst=0, .tm_gmtoff=-25200, .tm_zone="MST" }, .gmt_tm= { .tm_year=70, .tm_mon=0, .tm_mday=1, .tm_hour=0, .tm_min=0, .tm_sec=0, .tm_wday=4, .tm_yday=0, .tm_isdst=0, .tm_gmtoff=0, .tm_zone="GMT" }, }, { .descr="epoch", .timezone="right/UTC", .time=0, .local_tm= { .tm_year=70, .tm_mon=0, .tm_mday=1, .tm_hour=0, .tm_min=0, .tm_sec=0, .tm_wday=4, .tm_yday=0, .tm_isdst=0, .tm_gmtoff=0, .tm_zone="UTC" }, .gmt_tm= { .tm_year=70, .tm_mon=0, .tm_mday=1, .tm_hour=0, .tm_min=0, .tm_sec=0, .tm_wday=4, .tm_yday=0, .tm_isdst=0, .tm_gmtoff=0, .tm_zone="GMT" }, }, { .descr="epoch", .timezone="right/America/Edmonton", .time=0, .local_tm= { .tm_year=69, .tm_mon=11, .tm_mday=31, .tm_hour=17, .tm_min=0, .tm_sec=0, .tm_wday=3, .tm_yday=364, .tm_isdst=0, .tm_gmtoff=-25200, .tm_zone="MST" }, .gmt_tm= { .tm_year=70, .tm_mon=0, .tm_mday=1, .tm_hour=0, .tm_min=0, .tm_sec=0, .tm_wday=4, .tm_yday=0, .tm_isdst=0, .tm_gmtoff=0, .tm_zone="GMT" }, }, { .descr="epoch - 1", .timezone="posix/America/Edmonton", .time=-1, .local_tm= { .tm_year=69, .tm_mon=11, .tm_mday=31, .tm_hour=16, .tm_min=59, .tm_sec=59, .tm_wday=3, .tm_yday=364, .tm_isdst=0, .tm_gmtoff=-25200, .tm_zone="MST" }, .gmt_tm= { .tm_year=69, .tm_mon=11, .tm_mday=31, .tm_hour=23, .tm_min=59, .tm_sec=59, .tm_wday=3, .tm_yday=364, .tm_isdst=0, .tm_gmtoff=0, .tm_zone="GMT" }, }, { .descr="epoch - 1", .timezone="right/UTC", .time=-1, .local_tm= { .tm_year=69, .tm_mon=11, .tm_mday=31, .tm_hour=23, .tm_min=59, .tm_sec=59, .tm_wday=3, .tm_yday=364, .tm_isdst=0, .tm_gmtoff=0, .tm_zone="UTC" }, .gmt_tm= { .tm_year=69, .tm_mon=11, .tm_mday=31, .tm_hour=23, .tm_min=59, .tm_sec=59, .tm_wday=3, .tm_yday=364, .tm_isdst=0, .tm_gmtoff=0, .tm_zone="GMT" }, }, { .descr="epoch - 1", .timezone="right/America/Edmonton", .time=-1, .local_tm= { .tm_year=69, .tm_mon=11, .tm_mday=31, .tm_hour=16, .tm_min=59, .tm_sec=59, .tm_wday=3, .tm_yday=364, .tm_isdst=0, .tm_gmtoff=-25200, .tm_zone="MST" }, .gmt_tm= { .tm_year=69, .tm_mon=11, .tm_mday=31, .tm_hour=23, .tm_min=59, .tm_sec=59, .tm_wday=3, .tm_yday=364, .tm_isdst=0, .tm_gmtoff=0, .tm_zone="GMT" }, }, { .descr="legacy min", .timezone="posix/America/Edmonton", .time=-2147483648, .local_tm= { .tm_year=1, .tm_mon=11, .tm_mday=13, .tm_hour=13, .tm_min=12, .tm_sec=0, .tm_wday=5, .tm_yday=346, .tm_isdst=0, .tm_gmtoff=-27232, .tm_zone="LMT" }, .gmt_tm= { .tm_year=1, .tm_mon=11, .tm_mday=13, .tm_hour=20, .tm_min=45, .tm_sec=52, .tm_wday=5, .tm_yday=346, .tm_isdst=0, .tm_gmtoff=0, .tm_zone="GMT" }, }, { .descr="legacy min", .timezone="right/UTC", .time=-2147483648, .local_tm= { .tm_year=1, .tm_mon=11, .tm_mday=13, .tm_hour=20, .tm_min=45, .tm_sec=52, .tm_wday=5, .tm_yday=346, .tm_isdst=0, .tm_gmtoff=0, .tm_zone="UTC" }, .gmt_tm= { .tm_year=1, .tm_mon=11, .tm_mday=13, .tm_hour=20, .tm_min=45, .tm_sec=52, .tm_wday=5, .tm_yday=346, .tm_isdst=0, .tm_gmtoff=0, .tm_zone="GMT" }, }, { .descr="legacy min - 1", .timezone="posix/America/Edmonton", .time=-2147483649, .local_tm= { .tm_year=1, .tm_mon=11, .tm_mday=13, .tm_hour=13, .tm_min=11, .tm_sec=59, .tm_wday=5, .tm_yday=346, .tm_isdst=0, .tm_gmtoff=-27232, .tm_zone="LMT" }, .gmt_tm= { .tm_year=1, .tm_mon=11, .tm_mday=13, .tm_hour=20, .tm_min=45, .tm_sec=51, .tm_wday=5, .tm_yday=346, .tm_isdst=0, .tm_gmtoff=0, .tm_zone="GMT" }, }, { .descr="legacy min - 1", .timezone="right/UTC", .time=-2147483649, .local_tm= { .tm_year=1, .tm_mon=11, .tm_mday=13, .tm_hour=20, .tm_min=45, .tm_sec=51, .tm_wday=5, .tm_yday=346, .tm_isdst=0, .tm_gmtoff=0, .tm_zone="UTC" }, .gmt_tm= { .tm_year=1, .tm_mon=11, .tm_mday=13, .tm_hour=20, .tm_min=45, .tm_sec=51, .tm_wday=5, .tm_yday=346, .tm_isdst=0, .tm_gmtoff=0, .tm_zone="GMT" }, }, { .descr="legacy max", .timezone="posix/America/Edmonton", .time=2147483647, .local_tm= { .tm_year=138, .tm_mon=0, .tm_mday=18, .tm_hour=20, .tm_min=14, .tm_sec=7, .tm_wday=1, .tm_yday=17, .tm_isdst=0, .tm_gmtoff=-25200, .tm_zone="MST" }, .gmt_tm= { .tm_year=138, .tm_mon=0, .tm_mday=19, .tm_hour=3, .tm_min=14, .tm_sec=7, .tm_wday=2, .tm_yday=18, .tm_isdst=0, .tm_gmtoff=0, .tm_zone="GMT" }, }, { .descr="legacy max", .timezone="right/UTC", .time=2147483647, .local_tm= { .tm_year=138, .tm_mon=0, .tm_mday=19, .tm_hour=3, .tm_min=13, .tm_sec=40, .tm_wday=2, .tm_yday=18, .tm_isdst=0, .tm_gmtoff=0, .tm_zone="UTC" }, .gmt_tm= { .tm_year=138, .tm_mon=0, .tm_mday=19, .tm_hour=3, .tm_min=14, .tm_sec=7, .tm_wday=2, .tm_yday=18, .tm_isdst=0, .tm_gmtoff=0, .tm_zone="GMT" }, }, { .descr="legacy max + 1", .timezone="posix/America/Edmonton", .time=2147483648, .local_tm= { .tm_year=138, .tm_mon=0, .tm_mday=18, .tm_hour=20, .tm_min=14, .tm_sec=8, .tm_wday=1, .tm_yday=17, .tm_isdst=0, .tm_gmtoff=-25200, .tm_zone="MST" }, .gmt_tm= { .tm_year=138, .tm_mon=0, .tm_mday=19, .tm_hour=3, .tm_min=14, .tm_sec=8, .tm_wday=2, .tm_yday=18, .tm_isdst=0, .tm_gmtoff=0, .tm_zone="GMT" }, }, { .descr="legacy max + 1", .timezone="right/UTC", .time=2147483648, .local_tm= { .tm_year=138, .tm_mon=0, .tm_mday=19, .tm_hour=3, .tm_min=13, .tm_sec=41, .tm_wday=2, .tm_yday=18, .tm_isdst=0, .tm_gmtoff=0, .tm_zone="UTC" }, .gmt_tm= { .tm_year=138, .tm_mon=0, .tm_mday=19, .tm_hour=3, .tm_min=14, .tm_sec=8, .tm_wday=2, .tm_yday=18, .tm_isdst=0, .tm_gmtoff=0, .tm_zone="GMT" }, }, { .descr="min", .timezone="posix/America/Edmonton", .time=INT64_MIN, .local_tm= { .tm_year=0, .tm_mon=0, .tm_mday=0, .tm_hour=0, .tm_min=0, .tm_sec=0, .tm_wday=0, .tm_yday=0, .tm_isdst=0, .tm_gmtoff=0, .tm_zone="FAILURE" }, .gmt_tm= { .tm_year=0, .tm_mon=0, .tm_mday=0, .tm_hour=0, .tm_min=0, .tm_sec=0, .tm_wday=0, .tm_yday=0, .tm_isdst=0, .tm_gmtoff=0, .tm_zone="FAILURE" }, }, { .descr="min", .timezone="right/UTC", .time=INT64_MIN, .local_tm= { .tm_year=0, .tm_mon=0, .tm_mday=0, .tm_hour=0, .tm_min=0, .tm_sec=0, .tm_wday=0, .tm_yday=0, .tm_isdst=0, .tm_gmtoff=0, .tm_zone="FAILURE" }, .gmt_tm= { .tm_year=0, .tm_mon=0, .tm_mday=0, .tm_hour=0, .tm_min=0, .tm_sec=0, .tm_wday=0, .tm_yday=0, .tm_isdst=0, .tm_gmtoff=0, .tm_zone="FAILURE" }, }, { .descr="max", .timezone="right/America/Edmonton", .time=9223372036854775807, .local_tm= { .tm_year=0, .tm_mon=0, .tm_mday=0, .tm_hour=0, .tm_min=0, .tm_sec=0, .tm_wday=0, .tm_yday=0, .tm_isdst=0, .tm_gmtoff=0, .tm_zone="FAILURE" }, .gmt_tm= { .tm_year=0, .tm_mon=0, .tm_mday=0, .tm_hour=0, .tm_min=0, .tm_sec=0, .tm_wday=0, .tm_yday=0, .tm_isdst=0, .tm_gmtoff=0, .tm_zone="FAILURE" }, }, { .descr="max", .timezone="posix/America/Edmonton", .time=9223372036854775807, .local_tm= { .tm_year=0, .tm_mon=0, .tm_mday=0, .tm_hour=0, .tm_min=0, .tm_sec=0, .tm_wday=0, .tm_yday=0, .tm_isdst=0, .tm_gmtoff=0, .tm_zone="FAILURE" }, .gmt_tm= { .tm_year=0, .tm_mon=0, .tm_mday=0, .tm_hour=0, .tm_min=0, .tm_sec=0, .tm_wday=0, .tm_yday=0, .tm_isdst=0, .tm_gmtoff=0, .tm_zone="FAILURE" }, }, { .descr="max", .timezone="right/UTC", .time=9223372036854775807, .local_tm= { .tm_year=0, .tm_mon=0, .tm_mday=0, .tm_hour=0, .tm_min=0, .tm_sec=0, .tm_wday=0, .tm_yday=0, .tm_isdst=0, .tm_gmtoff=0, .tm_zone="FAILURE" }, .gmt_tm= { .tm_year=0, .tm_mon=0, .tm_mday=0, .tm_hour=0, .tm_min=0, .tm_sec=0, .tm_wday=0, .tm_yday=0, .tm_isdst=0, .tm_gmtoff=0, .tm_zone="FAILURE" }, }, { .descr="min", .timezone="right/America/Edmonton", .time=INT64_MIN, .local_tm= { .tm_year=0, .tm_mon=0, .tm_mday=0, .tm_hour=0, .tm_min=0, .tm_sec=0, .tm_wday=0, .tm_yday=0, .tm_isdst=0, .tm_gmtoff=0, .tm_zone="FAILURE" }, .gmt_tm= { .tm_year=0, .tm_mon=0, .tm_mday=0, .tm_hour=0, .tm_min=0, .tm_sec=0, .tm_wday=0, .tm_yday=0, .tm_isdst=0, .tm_gmtoff=0, .tm_zone="FAILURE" }, }, { .descr="maxint struct tm", .timezone="right/America/Edmonton", .time=67767976204675199, .local_tm= { .tm_year=2147481747, .tm_mon=0, .tm_mday=31, .tm_hour=16, .tm_min=59, .tm_sec=32, .tm_wday=4, .tm_yday=30, .tm_isdst=0, .tm_gmtoff=-25200, .tm_zone="MST" }, .gmt_tm= { .tm_year=2147481747, .tm_mon=0, .tm_mday=31, .tm_hour=23, .tm_min=59, .tm_sec=59, .tm_wday=4, .tm_yday=30, .tm_isdst=0, .tm_gmtoff=0, .tm_zone="GMT" }, }, { .descr="minint struct tm", .timezone="right/America/Edmonton", .time=-67768038398073601, .local_tm= { .tm_year=-2147483578, .tm_mon=0, .tm_mday=31, .tm_hour=16, .tm_min=26, .tm_sec=7, .tm_wday=2, .tm_yday=30, .tm_isdst=0, .tm_gmtoff=-27232, .tm_zone="LMT" }, .gmt_tm= { .tm_year=-2147483578, .tm_mon=0, .tm_mday=31, .tm_hour=23, .tm_min=59, .tm_sec=59, .tm_wday=2, .tm_yday=30, .tm_isdst=0, .tm_gmtoff=0, .tm_zone="GMT" }, }, { .descr="maxint struct tm", .timezone="right/UTC", .time=67767976204675199, .local_tm= { .tm_year=2147481747, .tm_mon=0, .tm_mday=31, .tm_hour=23, .tm_min=59, .tm_sec=32, .tm_wday=4, .tm_yday=30, .tm_isdst=0, .tm_gmtoff=0, .tm_zone="UTC" }, .gmt_tm= { .tm_year=2147481747, .tm_mon=0, .tm_mday=31, .tm_hour=23, .tm_min=59, .tm_sec=59, .tm_wday=4, .tm_yday=30, .tm_isdst=0, .tm_gmtoff=0, .tm_zone="GMT" }, }, { .descr="minint struct tm", .timezone="right/UTC", .time=-67768038398073601, .local_tm= { .tm_year=-2147483578, .tm_mon=0, .tm_mday=31, .tm_hour=23, .tm_min=59, .tm_sec=59, .tm_wday=2, .tm_yday=30, .tm_isdst=0, .tm_gmtoff=0, .tm_zone="UTC" }, .gmt_tm= { .tm_year=-2147483578, .tm_mon=0, .tm_mday=31, .tm_hour=23, .tm_min=59, .tm_sec=59, .tm_wday=2, .tm_yday=30, .tm_isdst=0, .tm_gmtoff=0, .tm_zone="GMT" }, }, { .descr="0000", .timezone="posix/America/Edmonton", .time=-62167219200, .local_tm= { .tm_year=-1901, .tm_mon=11, .tm_mday=31, .tm_hour=16, .tm_min=26, .tm_sec=8, .tm_wday=5, .tm_yday=364, .tm_isdst=0, .tm_gmtoff=-27232, .tm_zone="LMT" }, .gmt_tm= { .tm_year=-1900, .tm_mon=0, .tm_mday=1, .tm_hour=0, .tm_min=0, .tm_sec=0, .tm_wday=6, .tm_yday=0, .tm_isdst=0, .tm_gmtoff=0, .tm_zone="GMT" }, }, { .descr="0000", .timezone="right/UTC", .time=-62167219200, .local_tm= { .tm_year=-1900, .tm_mon=0, .tm_mday=1, .tm_hour=0, .tm_min=0, .tm_sec=0, .tm_wday=6, .tm_yday=0, .tm_isdst=0, .tm_gmtoff=0, .tm_zone="UTC" }, .gmt_tm= { .tm_year=-1900, .tm_mon=0, .tm_mday=1, .tm_hour=0, .tm_min=0, .tm_sec=0, .tm_wday=6, .tm_yday=0, .tm_isdst=0, .tm_gmtoff=0, .tm_zone="GMT" }, }, { .descr="0000", .timezone="right/America/Edmonton", .time=-62167219200, .local_tm= { .tm_year=-1901, .tm_mon=11, .tm_mday=31, .tm_hour=16, .tm_min=26, .tm_sec=8, .tm_wday=5, .tm_yday=364, .tm_isdst=0, .tm_gmtoff=-27232, .tm_zone="LMT" }, .gmt_tm= { .tm_year=-1900, .tm_mon=0, .tm_mday=1, .tm_hour=0, .tm_min=0, .tm_sec=0, .tm_wday=6, .tm_yday=0, .tm_isdst=0, .tm_gmtoff=0, .tm_zone="GMT" }, }, { .descr="9999", .timezone="posix/America/Edmonton", .time=253402300799, .local_tm= { .tm_year=8099, .tm_mon=11, .tm_mday=31, .tm_hour=16, .tm_min=59, .tm_sec=59, .tm_wday=5, .tm_yday=364, .tm_isdst=0, .tm_gmtoff=-25200, .tm_zone="MST" }, .gmt_tm= { .tm_year=8099, .tm_mon=11, .tm_mday=31, .tm_hour=23, .tm_min=59, .tm_sec=59, .tm_wday=5, .tm_yday=364, .tm_isdst=0, .tm_gmtoff=0, .tm_zone="GMT" }, }, { .descr="9999", .timezone="right/UTC", .time=253402300799, .local_tm= { .tm_year=8099, .tm_mon=11, .tm_mday=31, .tm_hour=23, .tm_min=59, .tm_sec=32, .tm_wday=5, .tm_yday=364, .tm_isdst=0, .tm_gmtoff=0, .tm_zone="UTC" }, .gmt_tm= { .tm_year=8099, .tm_mon=11, .tm_mday=31, .tm_hour=23, .tm_min=59, .tm_sec=59, .tm_wday=5, .tm_yday=364, .tm_isdst=0, .tm_gmtoff=0, .tm_zone="GMT" }, }, { .descr="9999", .timezone="right/America/Edmonton", .time=253402300799, .local_tm= { .tm_year=8099, .tm_mon=11, .tm_mday=31, .tm_hour=16, .tm_min=59, .tm_sec=32, .tm_wday=5, .tm_yday=364, .tm_isdst=0, .tm_gmtoff=-25200, .tm_zone="MST" }, .gmt_tm= { .tm_year=8099, .tm_mon=11, .tm_mday=31, .tm_hour=23, .tm_min=59, .tm_sec=59, .tm_wday=5, .tm_yday=364, .tm_isdst=0, .tm_gmtoff=0, .tm_zone="GMT" }, }, { .descr="leap second - 1", .timezone="posix/America/Edmonton", .time=1483228825, .local_tm= { .tm_year=116, .tm_mon=11, .tm_mday=31, .tm_hour=17, .tm_min=0, .tm_sec=25, .tm_wday=6, .tm_yday=365, .tm_isdst=0, .tm_gmtoff=-25200, .tm_zone="MST" }, .gmt_tm= { .tm_year=117, .tm_mon=0, .tm_mday=1, .tm_hour=0, .tm_min=0, .tm_sec=25, .tm_wday=0, .tm_yday=0, .tm_isdst=0, .tm_gmtoff=0, .tm_zone="GMT" }, }, { .descr="leap second", .timezone="posix/America/Edmonton", .time=1483228826, .local_tm= { .tm_year=116, .tm_mon=11, .tm_mday=31, .tm_hour=17, .tm_min=0, .tm_sec=26, .tm_wday=6, .tm_yday=365, .tm_isdst=0, .tm_gmtoff=-25200, .tm_zone="MST" }, .gmt_tm= { .tm_year=117, .tm_mon=0, .tm_mday=1, .tm_hour=0, .tm_min=0, .tm_sec=26, .tm_wday=0, .tm_yday=0, .tm_isdst=0, .tm_gmtoff=0, .tm_zone="GMT" }, }, { .descr="leap second + 1", .timezone="posix/America/Edmonton", .time=1483228827, .local_tm= { .tm_year=116, .tm_mon=11, .tm_mday=31, .tm_hour=17, .tm_min=0, .tm_sec=27, .tm_wday=6, .tm_yday=365, .tm_isdst=0, .tm_gmtoff=-25200, .tm_zone="MST" }, .gmt_tm= { .tm_year=117, .tm_mon=0, .tm_mday=1, .tm_hour=0, .tm_min=0, .tm_sec=27, .tm_wday=0, .tm_yday=0, .tm_isdst=0, .tm_gmtoff=0, .tm_zone="GMT" }, }, { .descr="leap second - 1", .timezone="right/UTC", .time=1483228825, .local_tm= { .tm_year=116, .tm_mon=11, .tm_mday=31, .tm_hour=23, .tm_min=59, .tm_sec=59, .tm_wday=6, .tm_yday=365, .tm_isdst=0, .tm_gmtoff=0, .tm_zone="UTC" }, .gmt_tm= { .tm_year=117, .tm_mon=0, .tm_mday=1, .tm_hour=0, .tm_min=0, .tm_sec=25, .tm_wday=0, .tm_yday=0, .tm_isdst=0, .tm_gmtoff=0, .tm_zone="GMT" }, }, { .descr="leap second", .timezone="right/UTC", .time=1483228826, .local_tm= { .tm_year=116, .tm_mon=11, .tm_mday=31, .tm_hour=23, .tm_min=59, .tm_sec=60, .tm_wday=6, .tm_yday=365, .tm_isdst=0, .tm_gmtoff=0, .tm_zone="UTC" }, .gmt_tm= { .tm_year=117, .tm_mon=0, .tm_mday=1, .tm_hour=0, .tm_min=0, .tm_sec=26, .tm_wday=0, .tm_yday=0, .tm_isdst=0, .tm_gmtoff=0, .tm_zone="GMT" }, }, { .descr="leap second + 1", .timezone="right/UTC", .time=1483228827, .local_tm= { .tm_year=117, .tm_mon=0, .tm_mday=1, .tm_hour=0, .tm_min=0, .tm_sec=0, .tm_wday=0, .tm_yday=0, .tm_isdst=0, .tm_gmtoff=0, .tm_zone="UTC" }, .gmt_tm= { .tm_year=117, .tm_mon=0, .tm_mday=1, .tm_hour=0, .tm_min=0, .tm_sec=27, .tm_wday=0, .tm_yday=0, .tm_isdst=0, .tm_gmtoff=0, .tm_zone="GMT" }, }, { .descr="leap second - 1", .timezone="right/America/Edmonton", .time=1483228825, .local_tm= { .tm_year=116, .tm_mon=11, .tm_mday=31, .tm_hour=16, .tm_min=59, .tm_sec=59, .tm_wday=6, .tm_yday=365, .tm_isdst=0, .tm_gmtoff=-25200, .tm_zone="MST" }, .gmt_tm= { .tm_year=117, .tm_mon=0, .tm_mday=1, .tm_hour=0, .tm_min=0, .tm_sec=25, .tm_wday=0, .tm_yday=0, .tm_isdst=0, .tm_gmtoff=0, .tm_zone="GMT" }, }, { .descr="leap second", .timezone="right/America/Edmonton", .time=1483228826, .local_tm= { .tm_year=116, .tm_mon=11, .tm_mday=31, .tm_hour=16, .tm_min=59, .tm_sec=60, .tm_wday=6, .tm_yday=365, .tm_isdst=0, .tm_gmtoff=-25200, .tm_zone="MST" }, .gmt_tm= { .tm_year=117, .tm_mon=0, .tm_mday=1, .tm_hour=0, .tm_min=0, .tm_sec=26, .tm_wday=0, .tm_yday=0, .tm_isdst=0, .tm_gmtoff=0, .tm_zone="GMT" }, }, { .descr="leap second + 1", .timezone="right/America/Edmonton", .time=1483228827, .local_tm= { .tm_year=116, .tm_mon=11, .tm_mday=31, .tm_hour=17, .tm_min=0, .tm_sec=0, .tm_wday=6, .tm_yday=365, .tm_isdst=0, .tm_gmtoff=-25200, .tm_zone="MST" }, .gmt_tm= { .tm_year=117, .tm_mon=0, .tm_mday=1, .tm_hour=0, .tm_min=0, .tm_sec=27, .tm_wday=0, .tm_yday=0, .tm_isdst=0, .tm_gmtoff=0, .tm_zone="GMT" }, }, { .descr="transition standard to daylight - 1", .timezone="posix/America/Edmonton", .time=1457859599, .local_tm= { .tm_year=116, .tm_mon=2, .tm_mday=13, .tm_hour=1, .tm_min=59, .tm_sec=59, .tm_wday=0, .tm_yday=72, .tm_isdst=0, .tm_gmtoff=-25200, .tm_zone="MST" }, .gmt_tm= { .tm_year=116, .tm_mon=2, .tm_mday=13, .tm_hour=8, .tm_min=59, .tm_sec=59, .tm_wday=0, .tm_yday=72, .tm_isdst=0, .tm_gmtoff=0, .tm_zone="GMT" }, }, { .descr="transition standard to daylight", .timezone="posix/America/Edmonton", .time=1457859600, .local_tm= { .tm_year=116, .tm_mon=2, .tm_mday=13, .tm_hour=3, .tm_min=0, .tm_sec=0, .tm_wday=0, .tm_yday=72, .tm_isdst=1, .tm_gmtoff=-21600, .tm_zone="MDT" }, .gmt_tm= { .tm_year=116, .tm_mon=2, .tm_mday=13, .tm_hour=9, .tm_min=0, .tm_sec=0, .tm_wday=0, .tm_yday=72, .tm_isdst=0, .tm_gmtoff=0, .tm_zone="GMT" }, }, { .descr="transition standard to daylight + 1", .timezone="posix/America/Edmonton", .time=1457859601, .local_tm= { .tm_year=116, .tm_mon=2, .tm_mday=13, .tm_hour=3, .tm_min=0, .tm_sec=1, .tm_wday=0, .tm_yday=72, .tm_isdst=1, .tm_gmtoff=-21600, .tm_zone="MDT" }, .gmt_tm= { .tm_year=116, .tm_mon=2, .tm_mday=13, .tm_hour=9, .tm_min=0, .tm_sec=1, .tm_wday=0, .tm_yday=72, .tm_isdst=0, .tm_gmtoff=0, .tm_zone="GMT" }, }, { .descr="transition standard to daylight - 1", .timezone="right/America/Edmonton", .time=1457859625, .local_tm= { .tm_year=116, .tm_mon=2, .tm_mday=13, .tm_hour=1, .tm_min=59, .tm_sec=59, .tm_wday=0, .tm_yday=72, .tm_isdst=0, .tm_gmtoff=-25200, .tm_zone="MST" }, .gmt_tm= { .tm_year=116, .tm_mon=2, .tm_mday=13, .tm_hour=9, .tm_min=0, .tm_sec=25, .tm_wday=0, .tm_yday=72, .tm_isdst=0, .tm_gmtoff=0, .tm_zone="GMT" }, }, { .descr="transition standard to daylight", .timezone="right/America/Edmonton", .time=1457859626, .local_tm= { .tm_year=116, .tm_mon=2, .tm_mday=13, .tm_hour=3, .tm_min=0, .tm_sec=0, .tm_wday=0, .tm_yday=72, .tm_isdst=1, .tm_gmtoff=-21600, .tm_zone="MDT" }, .gmt_tm= { .tm_year=116, .tm_mon=2, .tm_mday=13, .tm_hour=9, .tm_min=0, .tm_sec=26, .tm_wday=0, .tm_yday=72, .tm_isdst=0, .tm_gmtoff=0, .tm_zone="GMT" }, }, { .descr="transition standard to daylight + 1", .timezone="right/America/Edmonton", .time=1457859627, .local_tm= { .tm_year=116, .tm_mon=2, .tm_mday=13, .tm_hour=3, .tm_min=0, .tm_sec=1, .tm_wday=0, .tm_yday=72, .tm_isdst=1, .tm_gmtoff=-21600, .tm_zone="MDT" }, .gmt_tm= { .tm_year=116, .tm_mon=2, .tm_mday=13, .tm_hour=9, .tm_min=0, .tm_sec=27, .tm_wday=0, .tm_yday=72, .tm_isdst=0, .tm_gmtoff=0, .tm_zone="GMT" }, }, { .descr="transition daylight to standard - 1", .timezone="posix/America/Edmonton", .time=1478419199, .local_tm= { .tm_year=116, .tm_mon=10, .tm_mday=6, .tm_hour=1, .tm_min=59, .tm_sec=59, .tm_wday=0, .tm_yday=310, .tm_isdst=1, .tm_gmtoff=-21600, .tm_zone="MDT" }, .gmt_tm= { .tm_year=116, .tm_mon=10, .tm_mday=6, .tm_hour=7, .tm_min=59, .tm_sec=59, .tm_wday=0, .tm_yday=310, .tm_isdst=0, .tm_gmtoff=0, .tm_zone="GMT" }, }, { .descr="transition daylight to standard", .timezone="posix/America/Edmonton", .time=1478419200, .local_tm= { .tm_year=116, .tm_mon=10, .tm_mday=6, .tm_hour=1, .tm_min=0, .tm_sec=0, .tm_wday=0, .tm_yday=310, .tm_isdst=0, .tm_gmtoff=-25200, .tm_zone="MST" }, .gmt_tm= { .tm_year=116, .tm_mon=10, .tm_mday=6, .tm_hour=8, .tm_min=0, .tm_sec=0, .tm_wday=0, .tm_yday=310, .tm_isdst=0, .tm_gmtoff=0, .tm_zone="GMT" }, }, { .descr="transition daylight to standard + 1", .timezone="posix/America/Edmonton", .time=1478419201, .local_tm= { .tm_year=116, .tm_mon=10, .tm_mday=6, .tm_hour=1, .tm_min=0, .tm_sec=1, .tm_wday=0, .tm_yday=310, .tm_isdst=0, .tm_gmtoff=-25200, .tm_zone="MST" }, .gmt_tm= { .tm_year=116, .tm_mon=10, .tm_mday=6, .tm_hour=8, .tm_min=0, .tm_sec=1, .tm_wday=0, .tm_yday=310, .tm_isdst=0, .tm_gmtoff=0, .tm_zone="GMT" }, }, { .descr="transition daylight to standard - 1", .timezone="right/America/Edmonton", .time=1478419225, .local_tm= { .tm_year=116, .tm_mon=10, .tm_mday=6, .tm_hour=1, .tm_min=59, .tm_sec=59, .tm_wday=0, .tm_yday=310, .tm_isdst=1, .tm_gmtoff=-21600, .tm_zone="MDT" }, .gmt_tm= { .tm_year=116, .tm_mon=10, .tm_mday=6, .tm_hour=8, .tm_min=0, .tm_sec=25, .tm_wday=0, .tm_yday=310, .tm_isdst=0, .tm_gmtoff=0, .tm_zone="GMT" }, }, { .descr="transition daylight to standard", .timezone="right/America/Edmonton", .time=1478419226, .local_tm= { .tm_year=116, .tm_mon=10, .tm_mday=6, .tm_hour=1, .tm_min=0, .tm_sec=0, .tm_wday=0, .tm_yday=310, .tm_isdst=0, .tm_gmtoff=-25200, .tm_zone="MST" }, .gmt_tm= { .tm_year=116, .tm_mon=10, .tm_mday=6, .tm_hour=8, .tm_min=0, .tm_sec=26, .tm_wday=0, .tm_yday=310, .tm_isdst=0, .tm_gmtoff=0, .tm_zone="GMT" }, }, { .descr="transition daylight to standard + 1", .timezone="right/America/Edmonton", .time=1478419227, .local_tm= { .tm_year=116, .tm_mon=10, .tm_mday=6, .tm_hour=1, .tm_min=0, .tm_sec=1, .tm_wday=0, .tm_yday=310, .tm_isdst=0, .tm_gmtoff=-25200, .tm_zone="MST" }, .gmt_tm= { .tm_year=116, .tm_mon=10, .tm_mday=6, .tm_hour=8, .tm_min=0, .tm_sec=27, .tm_wday=0, .tm_yday=310, .tm_isdst=0, .tm_gmtoff=0, .tm_zone="GMT" }, }, { .descr = NULL, }, }; void printtm(FILE *f, struct tm *tm) { fprintf(f, "\t\t{\n\t\t\t.tm_year=%d,\n\t\t\t.tm_mon=%d,\n\t\t\t" ".tm_mday=%d,\n\t\t\t.tm_hour=%d,\n\t\t\t.tm_min=%d,\n\t\t\t" ".tm_sec=%d,\n\t\t\t.tm_wday=%d,\n\t\t\t.tm_yday=%d,\n\t\t\t" ".tm_isdst=%d,\n\t\t\t.tm_gmtoff=%ld,\n\t\t\t.tm_zone=\"%s\"" "\n\t\t},\n", tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, tm->tm_wday, tm->tm_yday, tm->tm_isdst, tm->tm_gmtoff, tm->tm_zone); } int dotimetest(struct timetest *test, int print) { int failures = 0; struct tm local = {}, gmt = {}; time_t converted; if (gmtime_r(&test->time, &gmt) == NULL) { memset(&gmt, 0, sizeof(gmt)); gmt.tm_zone="FAILURE"; } else { converted = timegm(&gmt); if (converted != test->time) { fprintf(stderr, "FAIL: test \"%s\", tz \"%s\" timegm " "does not match expected value\n", test->descr, test->timezone); fprintf(stderr, "expected: %lld\n", test->time); fprintf(stderr, "actual: %lld\n", converted); failures++; } } if (!tm_match(&test->gmt_tm, &gmt)) { fprintf(stderr, "FAIL: test \"%s\", tz \"%s\" gmtime_r does not" " match expected value\n", test->descr, test->timezone); fprintf(stderr, "expected: "); printtm(stderr, &test->gmt_tm); fprintf(stderr, "actual: "); printtm(stderr, &gmt); failures++; } setenv("TZ", test->timezone, 1); if (localtime_r(&test->time, &local) == NULL) { memset(&local, 0, sizeof(local)); local.tm_zone="FAILURE"; } else { converted = mktime(&local); if (converted != test->time) { fprintf(stderr, "FAIL: test \"%s\", tz \"%s\" mktime " "does not match expected value\n", test->descr, test->timezone); fprintf(stderr, "expected: %lld\n", test->time); fprintf(stderr, "actual: %lld\n", converted); failures++; } } if (!tm_match(&test->local_tm, &local)) { fprintf(stderr, "FAIL: test \"%s\", tz \"%s\" localtime_r does " "not match expected value\n", test->descr, test->timezone); fprintf(stderr, "expected: "); printtm(stderr, &test->local_tm); fprintf(stderr, "actual: "); printtm(stderr, &local); failures++; } if (print) { printf("\t{\n\t\t.descr=\"%s\",\n\t\t.timezone=\"%s\",\n\t\t" ".time=%lld,\n", test->descr, test->timezone, test->time); printf("\t\t.local_tm="); printtm(stdout, &local); printf("\t\t.gmt_tm="); printtm(stdout, &gmt); printf("\t},\n"); } return failures; } void printtmdescr(FILE *f, struct tm *tm, char * descr) { fprintf(f, "%s: ", descr); printtm(f, tm); } int main() { int failures = 0; int verbose = 0; struct stat sb; size_t i; if (stat("/usr/share/zoneinfo/posix", &sb) == -1 || stat("/usr/share/zoneinfo/right", &sb) == -1) { fprintf(stderr, "POSIX time zones missing, run the following command:\n\n" "\tmake -C ../../../../../share/zoneinfo other_two\n\n" "SKIPPED\n"); exit(0); } for (i = 0; timetests[i].descr != NULL; i++) { failures += dotimetest(&timetests[i], verbose); } if (failures) fprintf(stderr, "FAIL: %d time test failures\n", failures); else printf("SUCCESS: no time test failures\n"); exit(failures); }