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: