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: