The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
MODULE = Panda::Date                PACKAGE = Panda::Time
PROTOTYPES: DISABLE
#///////////////////////////// STATIC FUNCTIONS ///////////////////////////////////

#ifdef _WIN32
#  define LT_FORMAT "%a %b %d %H:%M:%S %Y"
#else
#  define LT_FORMAT "%a %b %e %H:%M:%S %Y"
#endif

void tzset (SV* newzone = NULL) {
    if (newzone) panda::time::tzset(SvPV_nolen(newzone));
    else panda::time::tzset();
}

const char* tzdir (SV* newdirSV = NULL) {
    if (newdirSV) {
        const char* newdir = SvOK(newdirSV) ? SvPV_nolen(newdirSV) : NULL;
        if (tzdir(newdir)) RETVAL = "1";
        else XSRETURN_UNDEF;
    } else
        RETVAL = tzdir();
}

const char* tzsysdir () {
    RETVAL = tzsysdir();
}
    
void gmtime (SV* epochSV = NULL) : ALIAS(localtime=1) {
    ptime_t epoch;
    if (epochSV) epoch = (ptime_t) SvMIV(epochSV);
    else epoch = (ptime_t) time(NULL);
    
    datetime date;
    if (ix == 0) gmtime(epoch, &date);
    else localtime(epoch, &date);
    
    if (GIMME_V == G_ARRAY) {
        EXTEND(SP, 9);
        EXTEND_MORTAL(9);
        mPUSHu(date.sec);
        mPUSHu(date.min);
        mPUSHu(date.hour);
        mPUSHu(date.mday);
        mPUSHu(date.mon);
        mPUSHi(date.year);
        mPUSHu(date.wday);
        mPUSHu(date.yday);
        mPUSHu(date.isdst);
        XSRETURN(9);
    } else {
        EXTEND(SP, 1);
        SV* ret = newSV(1000);
        SvPOK_on(ret);
        char* str = SvPVX(ret);
        size_t strlen = strftime(str, 1000, LT_FORMAT, &date);
        SvCUR_set(ret, strlen);
        mPUSHs(ret);
        XSRETURN(1);
    }
}

ptime_t timegm (SV* sec, SV* min, SV* hour, SV* mday, SV* mon, SV* year, SV* isdst = NULL) : ALIAS(timelocal=1, timegmn=2, timelocaln=3) {
    datetime date;
    date.sec  = SvMIV(sec);
    date.min  = SvMIV(min);
    date.hour = SvMIV(hour);
    date.mday = SvMIV(mday);
    date.mon  = SvMIV(mon);
    date.year = SvMIV(year);
    
    if (isdst) date.isdst = SvIV(isdst);
    else date.isdst = -1;
    
    switch (ix) {
        case 0:
            RETVAL = timegml(&date);
            break;
        case 1:
            RETVAL = timelocall(&date);
            break;
        case 2:
            RETVAL = timegm(&date);
            break;
        case 3:
            RETVAL = timelocal(&date);
            break;
    }
    
    if (ix & 2) {
        sv_setiv(sec, date.sec);
        sv_setiv(min, date.min);
        sv_setiv(hour, date.hour);
        sv_setiv(mday, date.mday);
        sv_setiv(mon, date.mon);
        sv_setiv(year, date.year);
        if (isdst) sv_setiv(isdst, date.isdst);
    }
}

time_t systimegm (int64_t sec, int64_t min, int64_t hour, int64_t mday, int64_t mon, int64_t year, int64_t isdst = -1) : ALIAS(systimelocal=1) {
    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;
    date.tm_isdst = isdst;
    if (ix == 0) RETVAL = SYSTIMEGM(&date);
    else RETVAL = SYSTIMELOCAL(&date);
}

HV* tzget (const char* zonename = NULL) {
    RETVAL = export_timezone(tzget(zonename));
}

const char* tzname () {
    RETVAL = tzlocal()->name;
}