MODULE = Panda::Date PACKAGE = Panda::Time
PROTOTYPES: DISABLE
#///////////////////////////// STATIC FUNCTIONS ///////////////////////////////////
#ifdef TEST_FULL
#ifdef TEST_INLINE
#define GMTIME(a,b) igmtime(a,b)
#define TIMEGM(a) itimegm(a)
#define TIMEGML(a) itimegml(a)
#define LOCALTIME(a,b) ilocaltime(a,b)
#define TIMELOCAL(a) itimelocal(a)
#define TIMELOCALL(a) itimelocall(a)
#else
#define GMTIME(a,b) gmtime(a,b)
#define TIMEGM(a) timegm(a)
#define TIMEGML(a) timegml(a)
#define LOCALTIME(a,b) localtime(a,b)
#define TIMELOCAL(a) timelocal(a)
#define TIMELOCALL(a) timelocall(a)
#endif
void
bench_my (const char* str)
PPCODE:
XSRETURN_UNDEF;
HVR
test_my (const char* str)
CODE:
RETVAL = newHV();
OUTPUT:
RETVAL
bool
test_gmtime (ptime_t step, ptime_t from, ptime_t till)
ALIAS:
test_localtime = 1
CODE:
datetime date1;
struct tm date2;
const char* tzname = ix == 0 ? "GMT" : tzlocal()->name;
char* hstr = getenv("HARNESS_ACTIVE");
bool test = (hstr != NULL && strlen(hstr) > 0);
static bool sranded = false;
if (!sranded) { srand(time(NULL)); sranded = true; }
bool isrand = false;
ptime_t disperse, epoch;
if (step == 0) {
isrand = true;
disperse = from;
step = 1;
from = 0;
}
int cnt = 0;
for (ptime_t i = from; i < till; i += step) {
cnt++;
bzero(&date1, sizeof(date1));
bzero(&date2, sizeof(date2));
if (isrand) epoch = rand() % (2*disperse) - disperse;
else epoch = i;
time_t sys_epoch = (time_t) epoch;
if (ix == 0) {
gmtime(epoch, &date1);
gmtime_r(&sys_epoch, &date2);
} else {
localtime(epoch, &date1);
localtime_r(&sys_epoch, &date2);
}
if (cnt % 100000 == 0 && !test) printf("TESTED #%d, last %04i-%02i-%02i %02i:%02i:%02i (off:%ld, dst=%d, zone=%s)\n", cnt, date2.tm_year+1900, date2.tm_mon+1, date2.tm_mday, date2.tm_hour, date2.tm_min, date2.tm_sec, date2.tm_gmtoff, date2.tm_isdst, date2.tm_zone);
if (date1.year != (date2.tm_year + 1900) || date1.mon != date2.tm_mon || date1.mday != date2.tm_mday ||
date1.hour != date2.tm_hour || date1.min != date2.tm_min || date1.sec != date2.tm_sec ||
date1.isdst != date2.tm_isdst || date1.gmtoff != date2.tm_gmtoff || strcmp(date1.zone, date2.tm_zone) != 0) {
warn(
"zone=%s, epoch=%lli, got %d-%02lld-%02lld %02lld:%02lld:%02lld %d %d %d %d %s, should be %d-%02d-%02d %02d:%02d:%02d %d %d %d %ld %s",
tzname, epoch,
date1.year, date1.mon+1, date1.mday, date1.hour, date1.min, date1.sec, date1.wday, date1.yday, date1.isdst, date1.gmtoff, date1.zone,
date2.tm_year+1900, date2.tm_mon+1, date2.tm_mday, date2.tm_hour, date2.tm_min, date2.tm_sec, date2.tm_wday, date2.tm_yday, date2.tm_isdst, date2.tm_gmtoff, date2.tm_zone
);
XSRETURN_UNDEF;
}
}
if (!test) printf("TESTED %d TIMES\n", cnt);
RETVAL = true;
OUTPUT:
RETVAL
bool
test_timegm (ptime_t step, ptime_t from, ptime_t till)
ALIAS:
test_timelocal = 1
CODE:
datetime date1;
struct tm date2;
char* hstr = getenv("HARNESS_ACTIVE");
bool test = (hstr != NULL && strlen(hstr) > 0);
static bool sranded = false;
if (!sranded) { srand(time(NULL)); sranded = true; }
bool isrand = false;
ptime_t disperce_years;
if (step == 0) {
isrand = true;
step = 1;
disperce_years = from;
if (disperce_years > 200) disperce_years = 200;
from = 0;
}
int cnt = 0;
for (ptime_t i = from; step > 0 ? (i < till) : (i > till); i += step) {
cnt++;
bzero(&date1, sizeof(date1));
bzero(&date2, sizeof(date2));
if (isrand) {
if (ix == 0) {
int rnum = rand();
date1.sec = rnum % 10000 - 5000;
rnum /= 1000;
date1.min = rnum % 10000 - 5000;
rnum /= 1000;
date1.hour = rnum % 100 - 50;
rnum = rand();
date1.mday = rnum % 100 - 50;
rnum /= 100;
date1.mon = rnum % 100 - 50;
rnum /= 100;
date1.year = rnum % 200 + 1910;
} else { // dont test denormalized values (LINUX has bugs with them + when using leap seconds zone, our normalization may differ with OS)
int rnum = rand();
date1.sec = rnum % 60;
rnum /= 1000;
date1.min = rnum % 60;
rnum /= 1000;
date1.hour = rnum % 24;
rnum = rand();
date1.mday = rnum % 31 + 1;
rnum /= 100;
date1.mon = rnum % 11;
rnum /= 100;
date1.year = rnum % disperce_years + 1910;
}
}
else {
if (ix == 0) gmtime(i, &date1);
else localtime(i, &date1);
}
if (ix == 1) date1.isdst = -1;
dt2tm(date2, date1);
datetime copy1 = date1;
struct tm copy2 = date2;
ptime_t mytime;
time_t truetime;
if (ix == 0) {
truetime = timegm(&date2);
if (isrand) mytime = timegm(&date1); // need normalization
else mytime = timegml(&date1);
} else {
mytime = timelocal(&date1);
truetime = timelocal(&date2);
}
if (cnt % 100000 == 0 && !test) printf("TESTED #%d, last %04d-%02d-%02d %02d:%02d:%02d\n", cnt, date2.tm_year+1900, date2.tm_mon+1, date2.tm_mday, date2.tm_hour, date2.tm_min, date2.tm_sec);
bool same_ymdhms = (date1.year != (date2.tm_year + 1900) || date1.mon != date2.tm_mon || date1.mday != date2.tm_mday || date1.hour != date2.tm_hour || date1.min != date2.tm_min || date1.sec != date2.tm_sec) ? false : true;
bool same_zone = (date1.isdst != date2.tm_isdst || date1.gmtoff != date2.tm_gmtoff || strcmp(date1.zone, date2.tm_zone) != 0) ? false : true;
bool same_date = same_ymdhms && same_zone;
if (mytime != truetime || !same_date) {
if (truetime == -1) continue; // OS cannot handle such dates
if (same_ymdhms && ix == 1) { // if ambiguity, OS may return unpredicted results. Lets handle that.
datetime tmpdate = date1;
tmpdate.isdst = 1;
mytime = timelocal(&tmpdate);
if (mytime == truetime) continue;
}
warn(
"MY: epoch=%lli (%04d/%02lld/%02lld %02lld:%02lld:%02lld %4s %d) from %04d/%02lld/%02lld %02lld:%02lld:%02lld DST=%d (%s)",
mytime, date1.year, date1.mon+1, date1.mday, date1.hour, date1.min, date1.sec, date1.zone, date1.gmtoff,
copy1.year, copy1.mon+1, copy1.mday, copy1.hour, copy1.min, copy1.sec, copy1.isdst, tzlocal()->name
);
warn(
"OS: epoch=%li (%04d/%02d/%02d %02d:%02d:%02d %4s %ld) from %04d/%02d/%02d %02d:%02d:%02d DST=%d (%s)",
truetime, date2.tm_year+1900, date2.tm_mon+1, date2.tm_mday, date2.tm_hour, date2.tm_min, date2.tm_sec, date2.tm_zone, date2.tm_gmtoff,
copy2.tm_year+1900, copy2.tm_mon+1, copy2.tm_mday, copy2.tm_hour, copy2.tm_min, copy2.tm_sec, copy2.tm_isdst, tzlocal()->name
);
warn("diff is %lli", mytime - truetime);
XSRETURN_UNDEF;
}
}
if (!test) printf("TESTED %d TIMES\n", cnt);
RETVAL = true;
OUTPUT:
RETVAL
AVR
gmtime_bench (ptime_t epoch)
ALIAS:
localtime_bench = 1
CODE:
datetime date;
ptime_t max_epoch = epoch + 10000;
if (ix == 0) while(epoch++ < max_epoch) GMTIME(epoch, &date);
else if (ix == 1) while(epoch++ < max_epoch) LOCALTIME(epoch, &date);
RETVAL = newAV();
av_push(RETVAL, newSViv(date.sec));
av_push(RETVAL, newSViv(date.min));
av_push(RETVAL, newSViv(date.hour));
av_push(RETVAL, newSViv(date.mday));
av_push(RETVAL, newSViv(date.mon));
av_push(RETVAL, newSViv(date.year));
av_push(RETVAL, newSViv(date.wday));
av_push(RETVAL, newSViv(date.yday));
av_push(RETVAL, newSViv(date.isdst));
av_push(RETVAL, newSViv(date.gmtoff));
av_push(RETVAL, newSVpv(date.zone, 0));
OUTPUT:
RETVAL
AVR
posix_gmtime_bench (time_t epoch)
ALIAS:
posix_localtime_bench = 1
CODE:
struct tm date;
time_t max_epoch = epoch + 10000;
if (ix == 0) while(epoch++ < max_epoch) gmtime_r(&epoch, &date);
else if (ix == 1) while(epoch++ < max_epoch) localtime_r(&epoch, &date);
RETVAL = newAV();
av_push(RETVAL, newSViv(date.tm_sec));
av_push(RETVAL, newSViv(date.tm_min));
av_push(RETVAL, newSViv(date.tm_hour));
av_push(RETVAL, newSViv(date.tm_mday));
av_push(RETVAL, newSViv(date.tm_mon));
av_push(RETVAL, newSViv(date.tm_year));
av_push(RETVAL, newSViv(date.tm_wday));
av_push(RETVAL, newSViv(date.tm_yday));
av_push(RETVAL, newSViv(date.tm_isdst));
av_push(RETVAL, newSViv(date.tm_gmtoff));
av_push(RETVAL, newSVpv(date.tm_zone, 0));
OUTPUT:
RETVAL
ptime_t
timegm_bench (ptime_t sec, ptime_t min, ptime_t hour, ptime_t mday, ptime_t mon, ptime_t year)
ALIAS:
timegml_bench = 1
timelocal_bench = 2
timelocall_bench = 3
CODE:
datetime date;
date.sec = sec;
date.min = min;
date.hour = hour;
date.mday = mday;
date.mon = mon;
date.year = year;
date.isdst = -1;
int i = 0;
int cnt = 10000;
RETVAL = 0;
if (ix == 0) while (i++ < cnt) RETVAL += TIMEGM(&date);
else if (ix == 1) while (i++ < cnt) RETVAL += TIMEGML(&date);
else if (ix == 2) while (i++ < cnt) RETVAL += TIMELOCAL(&date);
else if (ix == 3) while (i++ < cnt) RETVAL += TIMELOCALL(&date);
OUTPUT:
RETVAL
time_t
posix_timegm_bench (int64_t sec, int64_t min, int64_t hour, int64_t mday, int64_t mon, int64_t year)
ALIAS:
posix_timelocal_bench = 1
CODE:
struct tm date;
date.tm_sec = sec;
date.tm_min = min;
date.tm_hour = hour;
date.tm_mday = mday;
date.tm_mon = mon;
date.tm_year = year-1900;
date.tm_isdst = -1;
int i = 0;
int cnt = 10000;
RETVAL = 0;
if (ix == 0) while (i++ < cnt) RETVAL += timegm(&date);
else if (ix == 1) while (i++ < cnt) RETVAL += timelocal(&date);
OUTPUT:
RETVAL
#endif