Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

282 lines (228 sloc) 8.106 kb
/* A little program to test the limits of your system's time functions */
#include "time64_config.h"
#include <time.h>
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
struct tm Test_TM;
time_t Time_Max;
time_t Time_Min;
time_t Time_Zero = 0;
char *dump_date(const struct tm *date) {
char *dump = malloc(80 * sizeof(char));
sprintf(
dump,
"{ %d, %d, %d, %d, %d, %d }",
date->tm_sec, date->tm_min, date->tm_hour, date->tm_mday, date->tm_mon, date->tm_year
);
return dump;
}
/* Visual C++ 2008's difftime() can't do negative times */
double my_difftime(time_t left, time_t right) {
double diff = (double)left - (double)right;
return diff;
}
time_t check_date_max( struct tm * (*date_func)(const time_t *), const char *func_name ) {
struct tm *date;
time_t time = Time_Max;
time_t good_time = 0;
time_t time_change = Time_Max;
/* Binary search for the exact failure point */
do {
printf("# Trying %s(%.0f) max...", func_name, my_difftime(time, Time_Zero));
date = (*date_func)(&time);
time_change /= 2;
/* date_func() broke or tm_year overflowed or time_t overflowed */
if(date == NULL || date->tm_year < 69 || time < good_time) {
printf(" failed\n");
time -= time_change;
}
else {
printf(" success\n");
good_time = time;
time += time_change;
}
} while(time_change > 0 && good_time < Time_Max);
return(good_time);
}
time_t check_date_min( struct tm * (*date_func)(const time_t *), const char *func_name ) {
struct tm *date;
time_t time = Time_Min;
time_t good_time = 0;
time_t time_change = Time_Min;
/* Binary search for the exact failure point */
do {
printf("# Trying %s(%.0f) min...", func_name, my_difftime(time, Time_Zero));
date = (*date_func)(&time);
time_change /= 2;
/* date_func() broke or tm_year overflowed or time_t overflowed */
if(date == NULL || date->tm_year > 70 || time > good_time) {
printf(" failed\n");
time -= time_change;
}
else {
printf(" success\n");
good_time = time;
time += time_change;
}
} while((time_change < 0) && (good_time > Time_Min));
return(good_time);
}
struct tm * check_to_time_max( time_t (*to_time)(struct tm *), const char *func_name,
struct tm * (*to_date)(const time_t *) )
{
time_t round_trip;
time_t time = Time_Max;
time_t good_time = 0;
struct tm *date;
struct tm *good_date = malloc(sizeof(struct tm));
time_t time_change = Time_Max;
/* Binary search for the exact failure point */
do {
printf("# Trying %s(%.0f) max...", func_name, my_difftime(time, Time_Zero));
date = (*to_date)(&time);
round_trip = (*to_time)(date);
time_change /= 2;
/* date_func() broke or tm_year overflowed or time_t overflowed */
if(time != round_trip) {
printf(" failed\n");
time -= time_change;
}
else {
printf(" success\n");
good_time = time;
memcpy(good_date, date, sizeof(struct tm));
time += time_change;
}
} while(time_change > 0 && good_time < Time_Max);
return(good_date);
}
struct tm * check_to_time_min( time_t (*to_time)(struct tm *), const char *func_name,
struct tm * (*to_date)(const time_t *) )
{
time_t round_trip;
time_t time = Time_Min;
time_t good_time = 0;
struct tm *date;
struct tm *good_date = malloc(sizeof(struct tm));
time_t time_change = Time_Min;
/* Binary search for the exact failure point */
do {
printf("# Trying %s(%.0f) min...", func_name, my_difftime(time, Time_Zero));
date = (*to_date)(&time);
round_trip = (*to_time)(date);
time_change /= 2;
/* date_func() broke or tm_year overflowed or time_t overflowed */
if(time != round_trip) {
printf(" failed\n");
time -= time_change;
}
else {
printf(" success\n");
good_time = time;
memcpy(good_date, date, sizeof(struct tm));
time += time_change;
}
} while((time_change < 0) && (good_time > Time_Min));
return(good_date);
}
void guess_time_limits_from_types(void) {
if( sizeof(time_t) == 4 ) {
/* y2038 bug, out to 2**31-1 */
Time_Max = 2147483647;
Time_Min = -2147483647 - 1; /* "C90 doesn't have negative constants, only
positive ones that have been negated." */
}
else if( sizeof(time_t) >= 8 ) {
/* The compiler might warn about overflowing in the assignments
below. Don't worry, these won't get run in that case */
if( sizeof(Test_TM.tm_year) == 4 ) {
/* y2**31-1 bug */
Time_Max = 67768036160140799LL;
Time_Min = -67768036191676800LL;
}
else {
/* All the way out to 2**63-1 */
Time_Max = 9223372036854775807LL;
Time_Min = -9223372036854775807LL;
}
}
else {
printf("Weird sizeof(time_t): %ld\n", sizeof(time_t));
}
}
/* Dump a tm struct as a json fragment */
char * tm_as_json(const struct tm* date) {
char *date_json = malloc(sizeof(char) * 512);
#ifdef HAS_TM_TM_ZONE
char zone_json[32];
#endif
#ifdef HAS_TM_TM_GMTOFF
char gmtoff_json[32];
#endif
sprintf(date_json,
"\"tm_sec\": %d, \"tm_min\": %d, \"tm_hour\": %d, \"tm_mday\": %d, \"tm_mon\": %d, \"tm_year\": %d, \"tm_wday\": %d, \"tm_yday\": %d, \"tm_isdst\": %d",
date->tm_sec, date->tm_min, date->tm_hour, date->tm_mday,
date->tm_mon, date->tm_year, date->tm_wday, date->tm_yday, date->tm_isdst
);
#ifdef HAS_TM_TM_ZONE
sprintf(zone_json, ", \"tm_zone\": \"%s\"", date->tm_zone);
strcat(date_json, zone_json);
#endif
#ifdef HAS_TM_TM_GMTOFF
sprintf(gmtoff_json, ", \"tm_gmtoff\": %ld", date->tm_gmtoff);
strcat(date_json, gmtoff_json);
#endif
return date_json;
}
int main(void) {
time_t gmtime_max;
time_t gmtime_min;
time_t localtime_max;
time_t localtime_min;
#ifdef HAS_TIMEGM
struct tm* timegm_max;
struct tm* timegm_min;
#endif
struct tm* mktime_max;
struct tm* mktime_min;
guess_time_limits_from_types();
gmtime_max = check_date_max(gmtime, "gmtime");
gmtime_min = check_date_min(gmtime, "gmtime");
localtime_max = check_date_max(localtime, "localtime");
localtime_min = check_date_min(localtime, "localtime");
#ifdef HAS_TIMEGM
Time_Max = gmtime_max;
Time_Min = gmtime_min;
timegm_max = check_to_time_max(timegm, "timegm", gmtime);
timegm_min = check_to_time_min(timegm, "timegm", gmtime);
#endif
Time_Max = localtime_max;
Time_Min = localtime_min;
mktime_max = check_to_time_max(mktime, "mktime", localtime);
mktime_min = check_to_time_min(mktime, "mktime", localtime);
printf("# system time.h limits, as JSON\n");
printf("{\n");
printf(" \"gmtime\": { \"max\": %.0f, \"min\": %0.f },\n",
my_difftime(gmtime_max, Time_Zero),
my_difftime(gmtime_min, Time_Zero)
);
printf(" \"localtime\": { \"max\": %.0f, \"min\": %0.f },\n",
my_difftime(localtime_max, Time_Zero),
my_difftime(localtime_min, Time_Zero)
);
printf(" \"mktime\": {\n");
printf(" \"max\": { %s },\n", tm_as_json(mktime_max));
printf(" \"min\": { %s }\n", tm_as_json(mktime_min));
printf(" }\n");
#ifdef HAS_TIMEGM
printf(" ,\n");
printf(" \"timegm\": {\n");
printf(" \"max\": { %s },\n", tm_as_json(timegm_max));
printf(" \"min\": { %s }\n", tm_as_json(timegm_min));
printf(" }\n");
#endif
printf("}\n");
return 0;
}
Jump to Line
Something went wrong with that request. Please try again.