-
-
Save richlowe/8a84030dfd360fabd2b508da26a4db06 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <limits.h> | |
#include <stdbool.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <strings.h> | |
#include <time.h> | |
#ifndef _LP64 | |
#error "This only works 64bit" | |
#endif | |
#ifdef __linux__ | |
#define UTC "GMT" | |
#else | |
#define UTC "UTC" | |
#endif /* __linux__ */ | |
bool | |
tm_eql(struct tm *a, struct tm *b) { | |
bool ret = true; | |
#define CMP_FIELD(a, b, field, fmt) \ | |
if (a->field != b->field) { \ | |
printf(" " #field " differs " fmt " v. " fmt "\n", a->field, b->field); \ | |
ret = false; \ | |
} | |
CMP_FIELD(a, b, tm_sec, "%d"); | |
CMP_FIELD(a, b, tm_min, "%d"); | |
CMP_FIELD(a, b, tm_hour, "%d"); | |
CMP_FIELD(a, b, tm_mday, "%d"); | |
CMP_FIELD(a, b, tm_mon, "%d"); | |
CMP_FIELD(a, b, tm_year, "%d"); | |
CMP_FIELD(a, b, tm_wday, "%d"); | |
CMP_FIELD(a, b, tm_yday, "%d"); | |
CMP_FIELD(a, b, tm_isdst, "%d"); | |
#ifdef NEW_FIELDS | |
CMP_FIELD(a, b, tm_gmtoff, "%ld"); | |
if ((a->tm_zone == NULL) || (b->tm_zone == NULL)) { | |
if (a->tm_zone != b->tm_zone) { | |
printf(" tm_zone differs %s v. %s\n", a->tm_zone, b->tm_zone); | |
ret = false; | |
} | |
} else if (strcmp(a->tm_zone, b->tm_zone) != 0) { | |
printf(" tm_zone differs %s v. %s\n", a->tm_zone, b->tm_zone); | |
ret = false; | |
} | |
#endif | |
return (ret); | |
} | |
/* | |
* XXX: Force timezones as necessary | |
* | |
* A time in summer time | |
* | |
* timezones to test: | |
* UTC | |
* EST | |
* | |
* check times that work based on UTC and local times -in- UTC agree | |
*/ | |
int | |
test_eastern(void) | |
{ | |
int ret = 0; | |
time_t t; | |
struct tm res; | |
char canary[1024] = {0}; | |
setenv("TZ", "EST5EDT", 1); | |
tzset(); | |
/* Arbitrary */ | |
printf("EST Arbitrary localtime\n"); | |
t = 1582764890; | |
bzero(&res, sizeof (struct tm)); | |
if (localtime_r(&t, &res) == NULL) { | |
perror(" error"); | |
ret = 1; | |
} else { | |
struct tm ref = { | |
.tm_sec = 50, | |
.tm_min = 54, | |
.tm_hour = 19, | |
.tm_mday = 26, | |
.tm_mon = 1, | |
.tm_year = 120, | |
.tm_wday = 3, | |
.tm_yday = 56, | |
.tm_isdst = 0, | |
#ifdef NEW_FIELDS | |
.tm_gmtoff = -18000, | |
.tm_zone = "EST", | |
#endif | |
}; | |
if (!tm_eql(&ref, &res)) | |
ret = 1; | |
} | |
printf("EST Arbitrary gmtime\n"); | |
t = 1582764890; | |
bzero(&res, sizeof (struct tm)); | |
if (gmtime_r(&t, &res) == NULL) { | |
perror(" error"); | |
ret = 1; | |
} else { | |
struct tm ref = { | |
.tm_sec = 50, | |
.tm_min = 54, | |
.tm_hour = 0, | |
.tm_mday = 27, | |
.tm_mon = 1, | |
.tm_year = 120, | |
.tm_wday = 4, | |
.tm_yday = 57, | |
.tm_isdst = 0, | |
#ifdef NEW_FIELDS | |
.tm_gmtoff = 0, | |
.tm_zone = UTC, | |
#endif | |
}; | |
if (!tm_eql(&ref, &res)) | |
ret = 1; | |
} | |
/* Epoch */ | |
printf("EST Epoch localtime\n"); | |
t = 0; | |
bzero(&res, sizeof (struct tm)); | |
if (localtime_r(&t, &res) == NULL) { | |
perror(" error"); | |
ret = 1; | |
} else { | |
struct tm ref = { | |
.tm_sec = 0, | |
.tm_min = 0, | |
.tm_hour = 19, | |
.tm_mday = 31, | |
.tm_mon = 11, | |
.tm_year = 69, | |
.tm_wday = 3, | |
.tm_yday = 364, | |
.tm_isdst = 0, | |
#ifdef NEW_FIELDS | |
.tm_gmtoff = -18000, | |
.tm_zone = "EST", | |
#endif | |
}; | |
if (!tm_eql(&ref, &res)) | |
ret = 1; | |
} | |
printf("EST Epoch gmtime\n"); | |
t = 0; | |
bzero(&res, sizeof (struct tm)); | |
if (gmtime_r(&t, &res) == NULL) { | |
perror(" error"); | |
ret = 1; | |
} else { | |
struct tm ref = { | |
.tm_sec = 0, | |
.tm_min = 0, | |
.tm_hour = 0, | |
.tm_mday = 1, | |
.tm_mon = 0, | |
.tm_year = 70, | |
.tm_wday = 4, | |
.tm_yday = 0, | |
.tm_isdst = 0, | |
#ifdef NEW_FIELDS | |
.tm_gmtoff = 0, | |
.tm_zone = UTC, | |
#endif | |
}; | |
if (!tm_eql(&ref, &res)) | |
ret = 1; | |
} | |
/* Minimal tm */ | |
printf("EST Minimal (tm) localtime\n"); | |
t = -67768040609722800; | |
bzero(&res, sizeof (struct tm)); | |
if (localtime_r(&t, &res) == NULL) { | |
perror(" error"); | |
ret = 1; | |
} else { | |
struct tm ref = { | |
.tm_sec = 0, | |
.tm_min = 0, | |
.tm_hour = 0, | |
.tm_mday = 1, | |
.tm_mon = 0, | |
.tm_year = -2147483648, | |
.tm_wday = 4, | |
.tm_yday = 0, | |
.tm_isdst = 0, | |
#ifdef NEW_FIELDS | |
.tm_gmtoff = -18000, | |
.tm_zone = "EST", | |
#endif | |
}; | |
if (!tm_eql(&ref, &res)) | |
ret = 1; | |
} | |
printf("EST Minimal (tm) gmtime\n"); | |
t = -67768040609740800; | |
bzero(&res, sizeof (struct tm)); | |
if (gmtime_r(&t, &res) == NULL) { | |
perror(" error"); | |
ret = 1; | |
} else { | |
struct tm ref = { | |
.tm_sec = 0, | |
.tm_min = 0, | |
.tm_hour = 0, | |
.tm_mday = 1, | |
.tm_mon = 0, | |
.tm_year = INT_MIN, | |
.tm_wday = 4, | |
.tm_yday = 0, | |
.tm_isdst = 0, | |
#ifdef NEW_FIELDS | |
.tm_gmtoff = 0, | |
.tm_zone = UTC, | |
#endif | |
}; | |
if (!tm_eql(&ref, &res)) | |
ret = 1; | |
} | |
/* Minimal 32bit */ | |
printf("EST Minimal (32bit) localtime\n"); | |
t = (time_t)INT_MIN; | |
bzero(&res, sizeof (struct tm)); | |
if (localtime_r(&t, &res) == NULL) { | |
perror(" error"); | |
ret = 1; | |
} else { | |
struct tm ref = { | |
.tm_sec = 52, | |
.tm_min = 45, | |
.tm_hour = 15, | |
.tm_mday = 13, | |
.tm_mon = 11, | |
.tm_year = 1, | |
.tm_wday = 5, | |
.tm_yday = 346, | |
.tm_isdst = 0, | |
#ifdef NEW_FIELDS | |
.tm_gmtoff = -18000, | |
.tm_zone = "EST", | |
#endif | |
}; | |
if (!tm_eql(&ref, &res)) | |
ret = 1; | |
} | |
printf("EST Minimal (32bit) gmtime\n"); | |
t = (time_t)INT_MIN; | |
bzero(&res, sizeof (struct tm)); | |
if (gmtime_r(&t, &res) == NULL) { | |
perror(" error"); | |
ret = 1; | |
} else { | |
struct tm ref = { | |
.tm_sec = 52, | |
.tm_min = 45, | |
.tm_hour = 20, | |
.tm_mday = 13, | |
.tm_mon = 11, | |
.tm_year = 1, | |
.tm_wday = 5, | |
.tm_yday = 346, | |
.tm_isdst = 0, | |
#ifdef NEW_FIELDS | |
.tm_gmtoff = 0, | |
.tm_zone = UTC, | |
#endif | |
}; | |
if (!tm_eql(&ref, &res)) | |
ret = 1; | |
} | |
/* Maximal tm*/ | |
printf("EST Maximal (tm) localtime\n"); | |
//t = 67768036160158799; | |
t = 67768036191694799; | |
bzero(&res, sizeof (struct tm)); | |
if (localtime_r(&t, &res) == NULL) { | |
perror(" error"); | |
ret = 1; | |
} else { | |
struct tm ref = { | |
.tm_sec = 59, | |
.tm_min = 59, | |
.tm_hour = 23, | |
.tm_mday = 31, | |
.tm_mon = 11, | |
.tm_year = INT_MAX, | |
.tm_wday = 3, | |
.tm_yday = 364, | |
.tm_isdst = 0, | |
#ifdef NEW_FIELDS | |
.tm_gmtoff = -18000, | |
.tm_zone = "EST", | |
#endif | |
}; | |
if (!tm_eql(&ref, &res)) | |
ret = 1; | |
} | |
printf("EST Maximal (tm) gmtime\n"); | |
t = 67768036191676799; | |
bzero(&res, sizeof (struct tm)); | |
if (gmtime_r(&t, &res) == NULL) { | |
perror(" error"); | |
ret = 1; | |
} else { | |
struct tm ref = { | |
.tm_sec = 59, | |
.tm_min = 59, | |
.tm_hour = 23, | |
.tm_mday = 31, | |
.tm_mon = 11, | |
.tm_year = INT_MAX, | |
.tm_wday = 3, | |
.tm_yday = 364, | |
.tm_isdst = 0, | |
#ifdef NEW_FIELDS | |
.tm_gmtoff = 0, | |
.tm_zone = UTC, | |
#endif | |
}; | |
if (!tm_eql(&ref, &res)) | |
ret = 1; | |
} | |
/* Maximal 32bit*/ | |
printf("EST Maximal (32bit) localtime\n"); | |
t = (time_t)INT_MAX; | |
bzero(&res, sizeof (struct tm)); | |
if (localtime_r(&t, &res) == NULL) { | |
perror(" error"); | |
ret = 1; | |
} else { | |
struct tm ref = { | |
.tm_sec = 7, | |
.tm_min = 14, | |
.tm_hour = 22, | |
.tm_mday = 18, | |
.tm_mon = 0, | |
.tm_year = 138, | |
.tm_wday = 1, | |
.tm_yday = 17, | |
.tm_isdst = 0, | |
#ifdef NEW_FIELDS | |
.tm_gmtoff = -18000, | |
.tm_zone = "EST", | |
#endif | |
}; | |
if (!tm_eql(&ref, &res)) | |
ret = 1; | |
} | |
printf("EST Maximal (32bit) gmtime\n"); | |
t = (time_t)INT_MAX; | |
bzero(&res, sizeof (struct tm)); | |
if (gmtime_r(&t, &res) == NULL) { | |
perror(" error"); | |
ret = 1; | |
} else { | |
struct tm ref = { | |
.tm_sec = 7, | |
.tm_min = 14, | |
.tm_hour = 3, | |
.tm_mday = 19, | |
.tm_mon = 0, | |
.tm_year = 138, | |
.tm_wday = 2, | |
.tm_yday = 18, | |
.tm_isdst = 0, | |
#ifdef NEW_FIELDS | |
.tm_gmtoff = 0, | |
.tm_zone = UTC, | |
#endif | |
}; | |
if (!tm_eql(&ref, &res)) | |
ret = 1; | |
} | |
/* A leap day */ | |
printf("EST Feb 29th localtime\n"); | |
t = 1582977600; | |
bzero(&res, sizeof (struct tm)); | |
if (localtime_r(&t, &res) == NULL) { | |
perror(" error"); | |
ret = 1; | |
} else { | |
struct tm ref = { | |
.tm_hour = 7, | |
.tm_mday = 29, | |
.tm_mon = 1, | |
.tm_year = 120, | |
.tm_wday = 6, | |
.tm_yday = 59, | |
.tm_isdst = 0, | |
#ifdef NEW_FIELDS | |
.tm_gmtoff = -18000, | |
.tm_zone = "EST" | |
#endif | |
}; | |
if (!tm_eql(&ref, &res)) | |
ret = 1; | |
} | |
printf("EST Feb 29th gmtime\n"); | |
t = 1582977600; | |
bzero(&res, sizeof (struct tm)); | |
if (gmtime_r(&t, &res) == NULL) { | |
perror(" error"); | |
ret = 1; | |
} else { | |
struct tm ref = { | |
.tm_hour = 12, | |
.tm_mday = 29, | |
.tm_mon = 1, | |
.tm_year = 120, | |
.tm_wday = 6, | |
.tm_yday = 59, | |
.tm_isdst = 0, | |
#ifdef NEW_FIELDS | |
.tm_gmtoff = 0, | |
.tm_zone = UTC | |
#endif | |
}; | |
if (!tm_eql(&ref, &res)) | |
ret = 1; | |
} | |
/* Summertime */ | |
printf("EST June 21st localtime\n"); | |
t = 1592715600; | |
bzero(&res, sizeof (struct tm)); | |
if (localtime_r(&t, &res) == NULL) { | |
perror(" error"); | |
ret = 1; | |
} else { | |
struct tm ref = { | |
.tm_hour = 1, | |
.tm_mday = 21, | |
.tm_mon = 5, | |
.tm_year = 120, | |
.tm_wday = 0, | |
.tm_yday = 172, | |
.tm_isdst = 1, | |
#ifdef NEW_FIELDS | |
.tm_gmtoff = -14400, | |
.tm_zone = "EDT" | |
#endif | |
}; | |
if (!tm_eql(&ref, &res)) | |
ret = 1; | |
} | |
printf("EST June 21st gmtime\n"); | |
t = 1592715600; | |
bzero(&res, sizeof (struct tm)); | |
if (gmtime_r(&t, &res) == NULL) { | |
perror(" error"); | |
ret = 1; | |
} else { | |
struct tm ref = { | |
.tm_hour = 5, | |
.tm_mday = 21, | |
.tm_mon = 5, | |
.tm_year = 120, | |
.tm_wday = 0, | |
.tm_yday = 172, | |
.tm_isdst = 0, | |
#ifdef NEW_FIELDS | |
.tm_gmtoff = 0, | |
.tm_zone = UTC | |
#endif | |
}; | |
if (!tm_eql(&ref, &res)) | |
ret = 1; | |
} | |
for (int i = 0; i < 1024; i++) { | |
if (canary[i] != 0) | |
printf("canary garbled at byte %d\n", i); | |
} | |
return (ret); | |
} | |
int | |
main(int argc, char **argv) | |
{ | |
int ret; | |
ret = test_eastern(); | |
return (ret); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment