lh | 9ed821d | 2023-04-07 01:36:19 -0700 | [diff] [blame] | 1 | #include <stdlib.h> |
| 2 | #include <stdio.h> |
| 3 | #include <time.h> |
| 4 | |
| 5 | /* We use this instead of memcmp because some broken C libraries |
| 6 | * add additional nonstandard fields to struct tm... */ |
| 7 | |
| 8 | int tm_cmp(struct tm tm1, struct tm tm2) |
| 9 | { |
| 10 | return tm1.tm_sec != tm2.tm_sec || |
| 11 | tm1.tm_min != tm2.tm_min || |
| 12 | tm1.tm_hour != tm2.tm_hour || |
| 13 | tm1.tm_mday != tm2.tm_mday || |
| 14 | tm1.tm_mon != tm2.tm_mon || |
| 15 | tm1.tm_year != tm2.tm_year || |
| 16 | tm1.tm_wday != tm2.tm_wday || |
| 17 | tm1.tm_yday != tm2.tm_yday || |
| 18 | tm1.tm_isdst!= tm2.tm_isdst; |
| 19 | } |
| 20 | |
| 21 | char *tm_str(struct tm tm) |
| 22 | { |
| 23 | static int i; |
| 24 | static char b[4][64]; |
| 25 | i = (i+1)%4; |
| 26 | snprintf(b[i], sizeof b[i], |
| 27 | "s=%.2d m=%.2d h=%.2d mday=%.2d mon=%.2d year=%.4d wday=%d yday=%d isdst=%d", |
| 28 | tm.tm_sec, tm.tm_min, tm.tm_hour, |
| 29 | tm.tm_mday, tm.tm_mon, tm.tm_year, |
| 30 | tm.tm_wday, tm.tm_yday, tm.tm_isdst); |
| 31 | return b[i]; |
| 32 | } |
| 33 | |
| 34 | #define TM(ss,mm,hh,md,mo,yr,wd,yd,dst) (struct tm){ \ |
| 35 | .tm_sec = ss, .tm_min = mm, .tm_hour = hh, \ |
| 36 | .tm_mday = md, .tm_mon = mo, .tm_year = yr, \ |
| 37 | .tm_wday = wd, .tm_yday = yd, .tm_isdst = dst } |
| 38 | |
| 39 | #define TM_EPOCH TM(0,0,0,1,0,70,4,0,0) |
| 40 | #define TM_Y2038_1S TM(7,14,3,19,0,138,2,18,0) |
| 41 | #define TM_Y2038 TM(8,14,3,19,0,138,2,18,0) |
| 42 | |
| 43 | #define TEST_TM(r,x,m) (!tm_cmp((r),(x)) || \ |
| 44 | (printf(__FILE__ ":%d: %s failed:\n\tresult: %s\n\texpect: %s\n", __LINE__, \ |
| 45 | m, tm_str((r)), tm_str((x))), err++, 0) ) |
| 46 | |
| 47 | #define TEST(r, f, x, m) ( \ |
| 48 | ((r) = (f)) == (x) || \ |
| 49 | (printf(__FILE__ ":%d: %s failed (" m ")\n", __LINE__, #f, r, x), err++, 0) ) |
| 50 | |
| 51 | int main(void) |
| 52 | { |
| 53 | struct tm tm, *tm_p; |
| 54 | time_t t; |
| 55 | int err=0; |
| 56 | |
| 57 | putenv("TZ=GMT"); |
| 58 | tzset(); |
| 59 | |
| 60 | t=0; tm_p = gmtime(&t); |
| 61 | TEST_TM(*tm_p, TM_EPOCH, "gmtime(0)"); |
| 62 | |
| 63 | tm = TM_Y2038_1S; |
| 64 | t = mktime(&tm); |
| 65 | tm = *(gmtime(&t)); |
| 66 | TEST_TM(*tm_p, TM_Y2038_1S, "mktime/gmtime(Y2038-1)"); |
| 67 | |
| 68 | tm = TM_Y2038; |
| 69 | t = mktime(&tm); |
| 70 | tm = *(gmtime(&t)); |
| 71 | TEST_TM(*tm_p, TM_Y2038, "mktime/gmtime(Y2038)"); |
| 72 | |
| 73 | /* FIXME: set a TZ var and check DST boundary conditions */ |
| 74 | |
| 75 | return err; |
| 76 | } |