Annotation of parser3/src/types/pa_vdate.h, revision 1.54
1.1 parser 1: /** @file
2: Parser: @b date parser class decl.
3:
1.53 moko 4: Copyright (c) 2001-2012 Art. Lebedev Studio (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.54 ! moko 11: #define IDENT_PA_VDATE_H "$Id: pa_vdate.h,v 1.53 2012-03-16 09:24:17 moko Exp $"
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
1.45 misha 34: #ifdef HAVE_UNSETENV
35: unsetenv("TZ");
36: #else
1.43 paf 37: putenv("TZ");
38: #endif
1.45 misha 39: #endif
1.27 paf 40: tzset();
41: }
42:
1.1 parser 43: /// value of type 'date'. implemented with @c time_t
1.25 paf 44: class VDate: public VStateless_object {
1.1 parser 45: public: // Value
46:
1.25 paf 47: override const char* type() const { return VDATE_TYPE; }
48: override VStateless_class *get_class() { return date_class; }
1.10 paf 49:
1.51 misha 50: /// VDate: json-string
51: override const String* get_json_string(Json_options* options=0) {
52: String* result=new String();
53: switch(options->date){
54: case Json_options::D_SQL:
55: result->append_quoted(get_sql_string());
56: break;
57: case Json_options::D_GMT:
58: result->append_quoted(get_gmt_string());
59: break;
60: case Json_options::D_TIMESTAMP:
61: *result << format((int)ftime, 0);
62: break;
63: }
64: return result;
65: }
66:
1.1 parser 67: /// VDate: ftime -> float days
1.54 ! moko 68: override Value& as_expr_result() { return *new VDouble(as_double()); }
1.1 parser 69:
1.46 misha 70: /// VDate: true
71: override bool is_evaluated_expr() const { return true; }
72:
1.1 parser 73: /// VDate: ftime -> float days
1.25 paf 74: override double as_double() const { return ((double)ftime)/ SECS_PER_DAY; }
1.46 misha 75:
1.1 parser 76: /// VDate: 0 or !0
1.25 paf 77: override bool as_bool() const { return ftime!=0; }
1.1 parser 78:
1.41 paf 79: /// @TODO 'static' approach is NOT thread safe!
1.40 paf 80: tm& get_localtime()
1.35 paf 81: {
1.41 paf 82: char saved_tz[MAX_STRING];
1.48 misha 83: static char saved_tz_pair[MAX_STRING]; // @TODO: this is NOT thread safe!
1.35 paf 84: static char temp_tz_pair[MAX_STRING];
85: if(ftz_cstr) {
1.41 paf 86: if(const char* ltz=getenv("TZ")) {
87: strncpy(saved_tz, ltz, sizeof(saved_tz)-1);
88: saved_tz[sizeof(saved_tz)-1]=0;
89: } else
90: saved_tz[0]=0;
91:
1.35 paf 92: ::set_tz(ftz_cstr, temp_tz_pair, sizeof(temp_tz_pair));
93: }
94: tm *result=::localtime(&ftime);
1.38 paf 95: if(ftz_cstr) {
1.35 paf 96: ::set_tz(saved_tz, saved_tz_pair, sizeof(saved_tz_pair));
1.38 paf 97: }
1.35 paf 98: if(!result)
1.47 misha 99: throw Exception(DATE_RANGE_EXCEPTION_TYPE,
1.35 paf 100: 0,
101: "invalid datetime (after changing TZ)");
102:
1.40 paf 103: return *result;
1.35 paf 104: }
105:
1.52 misha 106: enum sql_string_type {sql_string_datetime, sql_string_date, sql_string_time};
107:
108: const String* get_sql_string(sql_string_type format = sql_string_datetime) {
109: static const char* formats[]={
110: "%Y-%m-%d %H:%M:%S",
111: "%Y-%m-%d",
112: "%H:%M:%S"
113: };
114: static int sizes[]={
115: 4+1+2+1+2 +1+ 2+1+2+1+2 +1/*terminator*/,
116: 4+1+2+1+2 +1/*terminator*/,
117: 2+1+2+1+2 +1/*terminator*/
118: };
119: size_t size=sizes[format];
1.50 misha 120: char *buf=new(PointerFreeGC) char[size];
1.52 misha 121: strftime(buf, size, formats[format], &get_localtime());
122:
1.50 misha 123: return new String(buf);
124: }
125:
126: const String* get_gmt_string(){
127: return new String(date_gmt_string(gmtime(&ftime)));
128: }
1.1 parser 129:
1.15 paf 130: /// VDate: method,field
1.49 misha 131: override Value* get_element(const String& aname) {
1.15 paf 132: // $method
1.49 misha 133: if(Value* result=VStateless_object::get_element(aname))
1.1 parser 134: return result;
135:
1.27 paf 136: // $TZ
137: if(aname=="TZ")
1.37 paf 138: return ftz? new VString(*ftz): new VString();
1.27 paf 139:
1.1 parser 140: // $year month day hour minute second weekday
1.40 paf 141: tm& tms=get_localtime();
1.27 paf 142:
1.1 parser 143: int result;
1.40 paf 144: if(aname=="year") result=1900+tms.tm_year;
145: else if(aname=="month") result=1+tms.tm_mon;
146: else if(aname=="day") result=tms.tm_mday;
147: else if(aname=="hour") result=tms.tm_hour;
148: else if(aname=="minute") result=tms.tm_min;
149: else if(aname=="second") result=tms.tm_sec;
150: else if(aname=="weekday") result=tms.tm_wday;
151: else if(aname=="yearday") result=tms.tm_yday;
152: else if(aname=="daylightsaving") result=tms.tm_isdst;
1.44 misha 153: else if(aname=="week") {
154: yw week = CalcWeek(tms);
155: result=week.week;
156: }
157: else if(aname=="weekyear") {
158: yw week = CalcWeek(tms);
159: result=1900+week.year;
160: } else { return bark("%s field not found", &aname); }
1.25 paf 161: return new VInt(result);
1.1 parser 162: }
163:
164: public: // usage
165:
1.27 paf 166: VDate(time_t adate) :
167: ftz(0),
168: ftz_cstr(0) {
1.33 paf 169: set_time(adate);
1.27 paf 170: }
1.1 parser 171:
1.32 paf 172: VDate(tm tmIn) :
173: ftime(0),
174: ftz(0),
175: ftz_cstr(0) {
176: set_time(tmIn);
177: }
178:
1.19 paf 179: time_t get_time() const { return ftime; }
1.32 paf 180: void set_time(time_t atime) {
181: if(atime<0)
1.47 misha 182: throw Exception(DATE_RANGE_EXCEPTION_TYPE,
1.32 paf 183: 0,
184: "invalid datetime");
185: ftime=atime;
186: }
187: void set_time(tm tmIn) {
188: time_t t=mktime(&tmIn);
189: if(t<0) {
190: // on some platforms mktime does not fix spring daylightsaving time hole
191: // in russia -- last sunday of march, 2am->3am hole
192: // trying to recover:
193: tmIn.tm_hour--;
194: t=mktime(&tmIn);
195: }
196: set_time(t);
197: }
1.27 paf 198: void set_tz(const String* atz) {
1.30 paf 199: if((ftz=atz))
1.27 paf 200: ftz_cstr=ftz->cstr();
1.40 paf 201: }
202:
1.44 misha 203: struct yw {
204: int year;
205: int week;
206: };
207:
208: static yw CalcWeek(tm& tms) {
209: yw week = {tms.tm_year, 0};
210:
1.40 paf 211: // http://www.merlyn.demon.co.uk/weekinfo.htm
1.44 misha 212: 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};
213: int diff = tms.tm_yday-(FirstThurs[(tms.tm_year+1900) % 28]-4);
214: if (diff < 0){
215: tms.tm_mday = diff;
1.45 misha 216: mktime(&tms); // normalize
1.44 misha 217: week = CalcWeek(tms);
218: } else {
219: week.week = 1 + diff/7;
220: if ( week.week > 52 && ISOWeekCount(week.year) < week.week ){
221: week.year++;
222: week.week = 1;
223: }
224: }
225: return week;
226: }
227:
228: static int ISOWeekCount (int year) {
229: static const unsigned int YearWeeks[] = {
230: 52,52,52,52,53, 52,52,52,52,52,
231: 53,52,52,52,52, 52,53,52,52,52,
232: 52,53,52,52,52, 52,52,53
233: };
234: return YearWeeks[(year+1900) % 28];
1.27 paf 235: }
1.1 parser 236:
237: private:
238: time_t ftime;
1.27 paf 239: const String* ftz;
240: const char* ftz_cstr;
1.1 parser 241:
242: };
243:
244: #endif
E-mail: