Annotation of parser3/src/types/pa_vdate.h, revision 1.44

1.1       parser      1: /** @file
                      2:        Parser: @b date parser class decl.
                      3: 
1.39      paf         4:        Copyright (c) 2001-2005 ArtLebedev Group (http://www.artlebedev.com)
1.8       paf         5:        Author: Alexandr Petrosian <paf@design.ru> (http://paf.design.ru)
1.1       parser      6: */
                      7: 
                      8: #ifndef PA_VDATE_H
                      9: #define PA_VDATE_H
1.11      paf        10: 
1.44    ! misha      11: static const char * const IDENT_VDATE_H="$Date: 2005/11/30 15:47:46 $";
1.1       parser     12: 
                     13: #include "classes.h"
                     14: #include "pa_common.h"
                     15: #include "pa_vstateless_object.h"
                     16: #include "pa_vint.h"
                     17: 
1.9       paf        18: // defines
                     19: 
                     20: #define VDATE_TYPE "date"
1.20      paf        21: 
1.9       paf        22: // externs
                     23: 
1.25      paf        24: extern Methoded* date_class;
1.1       parser     25: 
1.27      paf        26: inline void set_tz(const char* tz, char* buf, size_t buf_size) {
1.43      paf        27: #ifndef WIN32
                     28:        if(tz && *tz){
                     29: #endif
                     30:                snprintf(buf, buf_size, "TZ=%s", tz);
                     31:                putenv(buf);
                     32: #ifndef WIN32
                     33:        } else
                     34:                putenv("TZ");
                     35: #endif
1.27      paf        36:        tzset();
                     37: }
                     38: 
1.1       parser     39: /// value of type 'date'. implemented with @c time_t
1.25      paf        40: class VDate: public VStateless_object {
1.1       parser     41: public: // Value
                     42: 
1.25      paf        43:        override const char* type() const { return VDATE_TYPE; }
                     44:        override VStateless_class *get_class() { return date_class; }
1.10      paf        45:        
1.1       parser     46:        /// VDate: ftime -> float days
1.28      paf        47:        override Value& as_expr_result(bool /*return_string_as_is=false*/) { return *new VDouble(as_double()); }
1.1       parser     48: 
                     49:        /// VDate: ftime -> float days
1.25      paf        50:        override double as_double() const { return ((double)ftime)/ SECS_PER_DAY; }
1.1       parser     51:        /// VDate: 0 or !0
1.25      paf        52:        override bool as_bool() const { return ftime!=0; }
1.1       parser     53: 
1.41      paf        54:        /// @TODO 'static' approach is NOT thread safe!
1.40      paf        55:        tm& get_localtime()
1.35      paf        56:        {
1.41      paf        57:                char saved_tz[MAX_STRING];
                     58:                static char saved_tz_pair[MAX_STRING]; //TODO: this is NOT thread safe!
1.35      paf        59:                static char temp_tz_pair[MAX_STRING];
                     60:                if(ftz_cstr) {
1.41      paf        61:                        if(const char* ltz=getenv("TZ")) {
                     62:                                strncpy(saved_tz, ltz, sizeof(saved_tz)-1);
                     63:                                saved_tz[sizeof(saved_tz)-1]=0;
                     64:                        } else 
                     65:                                saved_tz[0]=0;
                     66:                        
1.35      paf        67:                        ::set_tz(ftz_cstr, temp_tz_pair, sizeof(temp_tz_pair));
                     68:                }
                     69:                tm *result=::localtime(&ftime);
1.38      paf        70:                if(ftz_cstr) {
1.35      paf        71:                        ::set_tz(saved_tz, saved_tz_pair, sizeof(saved_tz_pair));
1.38      paf        72:                }                       
1.35      paf        73:                if(!result)
                     74:                        throw Exception(0,
                     75:                                0,
                     76:                                "invalid datetime (after changing TZ)");
                     77: 
1.40      paf        78:                return *result;
1.35      paf        79:        }
                     80: 
1.1       parser     81: 
1.15      paf        82:        /// VDate: method,field
1.25      paf        83:        override Value* get_element(const String& aname, Value& aself, bool looking_up) {
1.15      paf        84:                // $method
1.25      paf        85:                if(Value* result=VStateless_object::get_element(aname, aself, looking_up))
1.1       parser     86:                        return result;
                     87: 
1.27      paf        88:                // $TZ
                     89:                if(aname=="TZ") 
1.37      paf        90:                        return ftz? new VString(*ftz): new VString();
1.27      paf        91: 
1.1       parser     92:                // $year month day  hour minute second  weekday
1.40      paf        93:                tm& tms=get_localtime();
1.27      paf        94: 
1.1       parser     95:                int result;
1.40      paf        96:                if(aname=="year") result=1900+tms.tm_year;
                     97:                else if(aname=="month") result=1+tms.tm_mon;
                     98:                else if(aname=="day") result=tms.tm_mday;
                     99:                else if(aname=="hour") result=tms.tm_hour;
                    100:                else if(aname=="minute") result=tms.tm_min;
                    101:                else if(aname=="second") result=tms.tm_sec;
                    102:                else if(aname=="weekday") result=tms.tm_wday;
                    103:                else if(aname=="yearday") result=tms.tm_yday;
                    104:                else if(aname=="daylightsaving") result=tms.tm_isdst;
1.44    ! misha     105:                else if(aname=="week") {
        !           106:                        yw week = CalcWeek(tms);
        !           107:                        result=week.week;
        !           108:                }
        !           109:                else if(aname=="weekyear") {
        !           110:                        yw week = CalcWeek(tms);
        !           111:                        result=1900+week.year;
        !           112:                } else { return bark("%s field not found", &aname); }
1.25      paf       113:                return new VInt(result);
1.1       parser    114:        }
                    115: 
                    116: public: // usage
                    117: 
1.27      paf       118:        VDate(time_t adate) : 
                    119:                ftz(0),
                    120:                ftz_cstr(0) {
1.33      paf       121:                set_time(adate);
1.27      paf       122:        }
1.1       parser    123: 
1.32      paf       124:        VDate(tm tmIn) : 
                    125:                ftime(0),
                    126:                ftz(0),
                    127:                ftz_cstr(0) {
                    128:                set_time(tmIn);
                    129:        }
                    130: 
1.19      paf       131:        time_t get_time() const { return ftime; }
1.32      paf       132:        void set_time(time_t atime) { 
                    133:                if(atime<0)
                    134:                        throw Exception(0,
                    135:                                0,
                    136:                                "invalid datetime");
                    137:                ftime=atime; 
                    138:        }
                    139:        void set_time(tm tmIn) { 
                    140:                time_t t=mktime(&tmIn);
                    141:                if(t<0) {
                    142:                        // on some platforms mktime does not fix spring daylightsaving time hole
                    143:                        // in russia -- last sunday of march, 2am->3am hole
                    144:                        // trying to recover:
                    145:                        tmIn.tm_hour--;
                    146:                        t=mktime(&tmIn);
                    147:                }
                    148:                set_time(t);
                    149:        }
1.27      paf       150:        void set_tz(const String* atz) { 
1.30      paf       151:                if((ftz=atz))
1.27      paf       152:                        ftz_cstr=ftz->cstr();
1.40      paf       153:        }
                    154: 
1.44    ! misha     155:        struct yw {
        !           156:                int year;
        !           157:                int week;
        !           158:        }; 
        !           159:        
        !           160:        static yw CalcWeek(tm& tms) {
        !           161:                yw week = {tms.tm_year, 0};
        !           162: 
1.40      paf       163:                // http://www.merlyn.demon.co.uk/weekinfo.htm
1.44    ! misha     164:                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};
        !           165:                int diff = tms.tm_yday-(FirstThurs[(tms.tm_year+1900) % 28]-4);
        !           166:                if (diff < 0){
        !           167:                        tms.tm_mday = diff;
        !           168:                        /*normalize*/mktime(&tms);
        !           169:                        week = CalcWeek(tms);
        !           170:                } else {
        !           171:                        week.week = 1 + diff/7;
        !           172:                        if ( week.week > 52 && ISOWeekCount(week.year) < week.week ){
        !           173:                                week.year++;
        !           174:                                week.week = 1;
        !           175:                        }
        !           176:        }
        !           177: 
        !           178:                return week;
        !           179:        }
        !           180: 
        !           181:        static int ISOWeekCount (int year) {
        !           182:                static const unsigned int YearWeeks[] = {
        !           183:                        52,52,52,52,53, 52,52,52,52,52,
        !           184:                        53,52,52,52,52, 52,53,52,52,52,
        !           185:                        52,53,52,52,52, 52,52,53
        !           186:                };
        !           187:                return YearWeeks[(year+1900) % 28];
1.27      paf       188:        }
1.1       parser    189: 
                    190: private:
                    191:        time_t ftime;
1.27      paf       192:        const String* ftz;
                    193:        const char* ftz_cstr;
1.1       parser    194: 
                    195: };
                    196: 
                    197: #endif

E-mail: