Annotation of parser3/src/types/pa_vdate.C, revision 1.2

1.1       moko        1: /** @file
                      2:        Parser: @b date parser class.
                      3: 
                      4:        Copyright (c) 2001-2012 Art. Lebedev Studio (http://www.artlebedev.com)
                      5: */
                      6: 
                      7: #include "pa_vstateless_object.h"
                      8: #include "pa_vdate.h"
                      9: #include "pa_vint.h"
                     10: #include "pa_vstring.h"
                     11: 
1.2     ! moko       12: volatile const char * IDENT_PA_PA_VDATE_C="$Id: pa_vdate.C,v 1.1 2015/08/05 22:07:16 moko Exp $" IDENT_PA_VDATE_H;
1.1       moko       13: 
                     14: static void set_tz(const char* tz, char* buf, size_t buf_size) {
                     15: #ifndef WIN32
                     16:        if(tz && *tz){
                     17: #endif
                     18:                snprintf(buf, buf_size, "TZ=%s", tz);
                     19:                putenv(buf);
                     20: #ifndef WIN32
                     21:        } else
                     22: #ifdef HAVE_UNSETENV
                     23:         unsetenv("TZ");
                     24: #else
                     25:                putenv("TZ");
                     26: #endif
                     27: #endif
                     28:        tzset();
                     29: }
                     30: 
                     31: const String* VDate::get_sql_string(sql_string_type format) {
                     32:        static const char* formats[]={
                     33:                "%Y-%m-%d %H:%M:%S",
                     34:                "%Y-%m-%d",
                     35:                "%H:%M:%S"
                     36:        };
                     37:        static int sizes[]={
                     38:                4+1+2+1+2 +1+ 2+1+2+1+2 +1/*terminator*/,
                     39:                4+1+2+1+2 +1/*terminator*/,
                     40:                2+1+2+1+2 +1/*terminator*/
                     41:        };
                     42:        size_t size=sizes[format];
                     43:        char *buf=new(PointerFreeGC) char[size];
                     44:        strftime(buf, size, formats[format], &get_localtime());
                     45: 
                     46:        return new String(buf);
                     47: }
                     48: 
                     49: const String* VDate::get_gmt_string(){
                     50:        return new String(date_gmt_string(gmtime(&ftime)));
                     51: }
                     52: 
                     53: /// @TODO 'static' approach is NOT thread safe!
                     54: tm&  VDate::get_localtime()
                     55: {
                     56:        char saved_tz[MAX_STRING];
                     57:        static char saved_tz_pair[MAX_STRING]; // @TODO: this is NOT thread safe!
                     58:        static char temp_tz_pair[MAX_STRING];
                     59:        if(ftz_cstr) {
                     60:                if(const char* ltz=getenv("TZ")) {
                     61:                        strncpy(saved_tz, ltz, sizeof(saved_tz)-1);
                     62:                        saved_tz[sizeof(saved_tz)-1]=0;
                     63:                } else 
                     64:                        saved_tz[0]=0;
                     65:                
                     66:                ::set_tz(ftz_cstr, temp_tz_pair, sizeof(temp_tz_pair));
                     67:        }
                     68:        tm *result=::localtime(&ftime);
                     69:        if(ftz_cstr) {
                     70:                ::set_tz(saved_tz, saved_tz_pair, sizeof(saved_tz_pair));
                     71:        }
                     72:        if(!result)
                     73:                throw Exception(DATE_RANGE_EXCEPTION_TYPE, 0, "invalid datetime (after changing TZ)");
                     74: 
                     75:        return *result;
                     76: }
                     77: 
                     78: override Value* VDate::get_element(const String& aname) {
                     79:        // $method
                     80:        if(Value* result=VStateless_object::get_element(aname))
                     81:                return result;
                     82: 
                     83:        // $TZ
                     84:        if(aname=="TZ") 
                     85:                return ftz? new VString(*ftz): new VString();
                     86: 
                     87:        // $year month day  hour minute second  weekday
                     88:        tm& tms=get_localtime();
                     89: 
                     90:        int result;
                     91:        if(aname=="year") result=1900+tms.tm_year;
                     92:        else if(aname=="month") result=1+tms.tm_mon;
                     93:        else if(aname=="day") result=tms.tm_mday;
                     94:        else if(aname=="hour") result=tms.tm_hour;
                     95:        else if(aname=="minute") result=tms.tm_min;
                     96:        else if(aname=="second") result=tms.tm_sec;
                     97:        else if(aname=="weekday") result=tms.tm_wday;
                     98:        else if(aname=="yearday") result=tms.tm_yday;
                     99:        else if(aname=="daylightsaving") result=tms.tm_isdst;
                    100:        else if(aname=="week") {
                    101:                yw week = CalcWeek(tms);
                    102:                result=week.week;
                    103:        }
                    104:        else if(aname=="weekyear") {
                    105:                yw week = CalcWeek(tms);
                    106:                result=1900+week.year;
                    107:        } else { return bark("%s field not found", &aname); }
                    108:        return new VInt(result);
                    109: }
                    110: 
                    111: const String* VDate::get_json_string(Json_options& options) {
                    112:        String* result=new String();
                    113:        switch(options.date){
                    114:                case Json_options::D_SQL:
                    115:                        result->append_quoted(get_sql_string());
                    116:                        break;
                    117:                case Json_options::D_GMT:
                    118:                        result->append_quoted(get_gmt_string());
                    119:                        break;
                    120:                case Json_options::D_TIMESTAMP:
                    121:                        *result << format((int)ftime, 0);
                    122:                        break;
                    123:        }
                    124:        return result;
                    125: }
1.2     ! moko      126: 
        !           127: void VDate::set_time(time_t atime) {
        !           128:        if(atime==-1)
        !           129:                throw Exception(DATE_RANGE_EXCEPTION_TYPE, 0, "invalid datetime");
        !           130:        ftime=atime;
        !           131: }
        !           132: 
        !           133: void VDate::set_time(tm tmIn) {
        !           134:        time_t t=mktime(&tmIn);
        !           135:        if(t==-1) {
        !           136:                // on some platforms mktime does not fix spring daylightsaving time hole
        !           137:                // in russia -- last sunday of march, 2am->3am hole
        !           138:                // trying to recover:
        !           139:                tmIn.tm_hour--;
        !           140:                t=mktime(&tmIn);
        !           141:        }
        !           142:        set_time(t);
        !           143: }
        !           144: 
        !           145: static int ISOWeekCount (int year) {
        !           146:        static const unsigned int YearWeeks[] = {
        !           147:                52,52,52,52,53, 52,52,52,52,52,
        !           148:                53,52,52,52,52, 52,53,52,52,52,
        !           149:                52,53,52,52,52, 52,52,53
        !           150:        };
        !           151:        return YearWeeks[(year+1900) % 28];
        !           152: }
        !           153: 
        !           154: VDate::yw VDate::CalcWeek(tm& tms) {
        !           155:        yw week = {tms.tm_year, 0};
        !           156: 
        !           157:        // http://www.merlyn.demon.co.uk/weekinfo.htm
        !           158:        static const unsigned int FirstThurs[] = {7,5,4,3,2,7,6,5,4,2,1,7,6,4,3,2,1,6,5,4,3,1,7,6,5,3,2,1};
        !           159:        int diff = tms.tm_yday-(FirstThurs[(tms.tm_year+1900) % 28]-4);
        !           160:        if (diff < 0){
        !           161:                tms.tm_mday = diff;
        !           162:                mktime(&tms); // normalize
        !           163:                week = CalcWeek(tms);
        !           164:        } else {
        !           165:                week.week = 1 + diff/7;
        !           166:                if ( week.week > 52 && ISOWeekCount(week.year) < week.week ){
        !           167:                        week.year++;
        !           168:                        week.week = 1;
        !           169:                }
        !           170:        }
        !           171:        return week;
        !           172: }

E-mail: