Annotation of parser3/src/classes/date.C, revision 1.42.2.11.2.2
1.1 parser 1: /** @file
2: Parser: @b date parser class.
3:
1.42.2.3 paf 4: Copyright (c) 2001-2003 ArtLebedev Group (http://www.artlebedev.com)
1.16 paf 5: Author: Alexandr Petrosian <paf@design.ru> (http://paf.design.ru)
1.32 paf 6: */
1.1 parser 7:
1.42.2.11.2.2! (paf 8:: static const char* IDENT_DATE_C="$Date: 2003/03/18 15:14:13 $";
1.1 parser 9:
10: #include "classes.h"
1.42.2.5 paf 11: #include "pa_vmethod_frame.h"
12:
1.1 parser 13: #include "pa_request.h"
14: #include "pa_vdouble.h"
15: #include "pa_vdate.h"
1.10 parser 16: #include "pa_vtable.h"
1.1 parser 17:
18: // class
19:
1.42.2.9 paf 20: class MDate: public Methoded {
1.1 parser 21: public: // VStateless_class
1.42.2.2 paf 22: ValuePtr create_new_value() { return ValuePtr(new VDate(0)); }
1.1 parser 23:
24: public:
1.42.2.6 paf 25: MDate();
1.1 parser 26: public: // Methoded
27: bool used_directly() { return true; }
28: };
1.42.2.1 paf 29:
1.42.2.6 paf 30: // global variable
31:
1.42.2.11 paf 32: DECLARE_CLASS_VAR(date, new MDate, 0);
1.42.2.6 paf 33:
1.42.2.1 paf 34: // helpers
35:
1.42.2.7 paf 36: class Date_calendar_table_template_columns: public ArrayString {
1.42.2.6 paf 37: Pool pool;
38: public:
1.42.2.7 paf 39: Date_calendar_table_template_columns(): ArrayString(6+2) {
1.42.2.1 paf 40: for(int i=0; i<=6; i++) {
1.42.2.11.2.1 (paf 41:: char *cname=new char[1/*strlen("6")*/+1/*terminating 0*/];
42:: const String& sname(new String(cname, sprintf(cname, "%d", i))); // .i column name
1.42.2.6 paf 43: *this+=sname;
1.42.2.1 paf 44: }
1.42.2.11.2.1 (paf 45:: *this+=String* (new String("week"));
46:: *this+=String* (new String("year"));
1.42.2.1 paf 47: }
1.42.2.6 paf 48: };
49:
50:
1.42.2.11.2.1 (paf 51:: Table* date_calendar_table_template(new Table(
1.42.2.6 paf 52: Exception::undefined_source,
53: Table::columns_type(new Date_calendar_table_template_columns)));
1.1 parser 54:
55: // methods
56:
1.42.2.11.2.1 (paf 57:: static void _now(Request& r, const String& method_name, MethodParams* params) {
1.42.2.6 paf 58: VDate& vdate=GET_SELF(r, VDate);
1.23 paf 59:
60: time_t t=time(0);
1.42.2.10 paf 61: if(params->count()==1) // ^now(offset)
62: t+=(time_t)round(params->as_double(0, "offset must be double", r)*SECS_PER_DAY);
1.23 paf 63:
1.42.2.6 paf 64: vdate.set_time(t);
1.1 parser 65: }
66:
1.28 paf 67: static int NN_year_to_NNNN(int year) {
68: if(year<70) // 0..69 -> 100..169 [2000..2069]
69: year+=100;
70: if(year>=1900)
71: year-=1900;
72: return year;
73: }
74:
1.41 paf 75: // 2002-04-25 18:14:00
76: // 18:14:00
77: // 2002:04:25 [+maybe time]
1.42.2.11.2.1 (paf 78:: time_t cstr_to_time_t(char *cstr, const String& report_error_origin) { // used in image.C
1.41 paf 79: char *cur=cstr;
80: int date_delim=isdigit(cur[0])&&isdigit(cur[1])&&isdigit(cur[2])&&isdigit(cur[3])&&cur[4]==':'?':'
81: :'-';
1.42.2.3 paf 82: const char* year=lsplit(&cur, date_delim);
83: const char* month=lsplit(&cur, date_delim);
84: const char* mday=lsplit(&cur, ' ');
1.41 paf 85: if(!month)
86: cur=cstr;
1.42.2.3 paf 87: const char* hour=lsplit(&cur, ':');
88: const char* min=lsplit(&cur, ':');
89: const char* sec=cur;
1.41 paf 90:
91: tm tmIn={0};
92: tmIn.tm_isdst=-1;
93: if(!month)
94: if(min) {
95: year=mday=0; // HH:MM
96: time_t t=time(0);
97: tm *tmNow=localtime(&t);
98: tmIn.tm_year=tmNow->tm_year;
99: tmIn.tm_mon=tmNow->tm_mon;
100: tmIn.tm_mday=tmNow->tm_mday;
101: goto date_part_set;
102: } else
103: hour=min=sec=0; // not YYYY- & not HH: = just YYYY
104: tmIn.tm_year=NN_year_to_NNNN(atoi(year));
105: tmIn.tm_mon=month?atoi(month)-1:0;
106: tmIn.tm_mday=mday?atoi(mday):1;
107: date_part_set:
108: tmIn.tm_hour=hour?atoi(hour):0;
109: tmIn.tm_min=min?atoi(min):0;
110: tmIn.tm_sec=sec?atoi(sec):0;
111: time_t result=mktime(&tmIn);
112: if(result<0)
113: if(report_error_origin)
114: throw Exception(0,
115: report_error_origin,
116: "invalid datetime");
117:
118: return result;
119: }
120:
1.42.2.11.2.1 (paf 121:: static void _create(Request& r, const String& method_name, MethodParams* params) {
1.42.2.6 paf 122: VDate& vdate=GET_SELF(r, VDate);
1.1 parser 123:
1.23 paf 124: time_t t;
1.42.2.10 paf 125: if(params->count()==1) {
1.31 paf 126: // ^create[2002-04-25 18:14:00]
127: // ^create[18:14:00]
1.42.2.11.2.1 (paf 128:: if(const String& sdate=params->get(0)->get_string(&pool))
1.41 paf 129: t=cstr_to_time_t(sdate->cstr(), sdate);
130: else { // ^create(float days)
1.42.2.10 paf 131: t=(time_t)round(params->as_double(0, "float days must be double", r)*SECS_PER_DAY);
1.28 paf 132: if(t<0 || !localtime(&t))
133: throw Exception(0,
1.42.2.6 paf 134: method_name,
1.28 paf 135: "invalid datetime");
136: }
1.42.2.10 paf 137: } else if(params->count()>=2) { // ^create(y;m;d[;h[;m[;s]]])
1.1 parser 138: tm tmIn={0};
139: tmIn.tm_isdst=-1;
1.42.2.10 paf 140: tmIn.tm_year=NN_year_to_NNNN(params->as_int(0, "year must be int", r));
141: tmIn.tm_mon=params->as_int(1, "month must be int", r)-1;
142: tmIn.tm_mday=params->count()>2?params->as_int(2, "mday must be int", r):1;
143: if(params->count()>3) tmIn.tm_hour=params->as_int(3, "hour must be int", r);
144: if(params->count()>4) tmIn.tm_min=params->as_int(4, "minutes must be int", r);
145: if(params->count()>5) tmIn.tm_sec=params->as_int(5, "seconds must be int", r);
1.23 paf 146: t=mktime(&tmIn);
147: if(t<0)
1.22 paf 148: throw Exception(0,
1.42.2.6 paf 149: method_name,
1.1 parser 150: "invalid datetime");
151: } else
1.22 paf 152: throw Exception("parser.runtime",
1.42.2.6 paf 153: method_name,
1.24 paf 154: "invalid params count, must be 1 or >=2");
1.42.2.6 paf 155: vdate.set_time(t);
1.1 parser 156: }
157:
1.42.2.11.2.1 (paf 158:: static void _sql_string(Request& r, const String& method_name, MethodParams*) {
1.42.2.6 paf 159: VDate& vdate=GET_SELF(r, VDate);
1.2 parser 160: int size=1+ 4+1+2+1+2 +1+ 2+1+2+1+2 +1 +1;
1.42.2.11.2.1 (paf 161:: char *buf=new char[size];
1.42.2.6 paf 162: time_t time=vdate.get_time();
1.14 paf 163: size=strftime(buf, size, "%Y-%m-%d %H:%M:%S", localtime(&time));
1.1 parser 164:
1.42.2.6 paf 165: String string;
1.4 parser 166: string.APPEND_CLEAN(buf, size,
1.42.2.6 paf 167: method_name->origin().file,
168: method_name->origin().line);
1.25 paf 169: r.write_assign_lang(string);
1.1 parser 170: }
171:
172:
1.42.2.11.2.1 (paf 173:: static void _roll(Request& r, const String& method_name, MethodParams* params) {
1.42.2.6 paf 174: VDate& vdate=GET_SELF(r, VDate);
1.1 parser 175:
1.42.2.11.2.1 (paf 176:: const String& what=params->as_string(0, "'what' must be string");
1.1 parser 177: int oyear=0;
178: int omonth=0;
179: int oday=0;
180: int *offset;
1.42.2.6 paf 181: if(*what=="year") offset=&oyear;
182: else if(*what=="month") offset=&omonth;
183: else if(*what=="day") offset=&oday;
1.1 parser 184: else
1.22 paf 185: throw Exception("parser.runtime",
1.42.2.6 paf 186: what,
1.1 parser 187: "must be year|month|day");
188:
1.42.2.10 paf 189: *offset=params->as_int(1, "offset must be int", r);
1.1 parser 190:
1.42.2.6 paf 191: time_t self_time=vdate.get_time();
1.13 paf 192: tm tmIn=*localtime(&self_time);
193: tm tmSaved=tmIn;
194:
1.21 paf 195: tmIn.tm_year+=oyear;
196: tmIn.tm_mon+=omonth;
197: tmIn.tm_mday+=oday;
198: tmIn.tm_hour=24/2;
199: tmIn.tm_min=0;
200: tmIn.tm_sec=0;
201: time_t t=mktime/*normalizetime*/(&tmIn);
202: if(t<0)
1.22 paf 203: throw Exception(0,
1.42.2.6 paf 204: method_name,
1.21 paf 205: "bad resulting time (after roll)");
1.24 paf 206: if(oday==0 && tmIn.tm_mday!=tmSaved.tm_mday)
207: throw Exception(0,
1.42.2.6 paf 208: method_name,
1.24 paf 209: "bad resulting time (day hole)", t);
1.21 paf 210:
1.13 paf 211: tm *tmOut=localtime(&t);
212: if(!tmOut)
1.22 paf 213: throw Exception(0,
1.42.2.6 paf 214: method_name,
1.13 paf 215: "bad resulting time (seconds from epoch=%ld)", t);
216:
217: tmOut->tm_hour=tmSaved.tm_hour;
218: tmOut->tm_min=tmSaved.tm_min;
219: tmOut->tm_sec=tmSaved.tm_sec;
1.20 paf 220: tmOut->tm_isdst=-1;
1.13 paf 221: {
1.21 paf 222: time_t t=mktime/*normalizetime*/(tmOut);
223: if(
224: tmOut->tm_hour!=tmSaved.tm_hour
225: ||tmOut->tm_min!=tmSaved.tm_min)
1.22 paf 226: throw Exception(0,
1.42.2.6 paf 227: method_name,
1.24 paf 228: "bad resulting time (hour hole)");
1.21 paf 229:
1.13 paf 230: if(t<0)
1.22 paf 231: throw Exception(0,
1.42.2.6 paf 232: method_name,
1.21 paf 233: "bad resulting time (after reconstruction)");
1.13 paf 234:
1.42.2.6 paf 235: vdate.set_time(t);
1.13 paf 236: }
1.1 parser 237: }
238:
1.42.2.11.2.1 (paf 239:: static Table* fill_month_days(Request& r,
240:: const String& method_name, MethodParams* params, bool rus){
241:: Table* result(new Table(*date_calendar_table_template));
1.10 parser 242:
1.42.2.10 paf 243: int year=params->as_int(1, "year must be int", r);
244: int month=max(1, min(params->as_int(2, "month must be int", r), 12)) -1;
1.10 parser 245:
246: tm tmIn={0, 0, 0, 1, month, year-1900};
247: time_t t=mktime(&tmIn);
248: if(t<0)
1.22 paf 249: throw Exception(0,
1.42.2.6 paf 250: method_name,
1.10 parser 251: "invalid date");
252: tm *tmOut=localtime(&t);
253:
254: int weekDay1=tmOut->tm_wday;
255: if(rus)
256: weekDay1=weekDay1?weekDay1-1:6; //sunday last
257: int monthDays=getMonthDays(year, month);
258:
259: for(int _day=1-weekDay1; _day<=monthDays;) {
1.42.2.7 paf 260: Table::element_type row(new ArrayString(7));
1.34 paf 261: // calculating year week no [1..54]
262: char *weekno_buf;
263: size_t weekno_size;
1.36 paf 264: int weekyear;
1.34 paf 265: // 0..6 week days-cells fill with month days
1.10 parser 266: for(int wday=0; wday<7; wday++, _day++) {
1.42.2.11.2.1 (paf 267:: const String& cell(new String);
1.10 parser 268: if(_day>=1 && _day<=monthDays) {
1.42.2.11.2.1 (paf 269:: char *buf=new char[2+1];
1.10 parser 270: cell->APPEND_CLEAN(buf, sprintf(buf, "%02d", _day),
1.42.2.6 paf 271: method_name->origin().file, method_name->origin().line);
1.10 parser 272: }
1.42.2.6 paf 273: *row+=cell;
1.34 paf 274:
275: if(wday==(rus?3:4)/*thursday*/) {
276: tm tms={0,0,0, _day, month, year-1900};
277: /*normalize*/mktime(&tms);
278:
1.36 paf 279: weekyear=tms.tm_year+1900;
280:
1.35 paf 281: const int weekno_buf_size=2+1/*for stupid snprintfs*/ +1;
1.34 paf 282:
283: // http://www.merlyn.demon.co.uk/weekinfo.htm
284: const 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};
1.36 paf 285: int n=1 + (tms.tm_yday-(FirstThurs[weekyear % 28]-3))/7;
1.42.2.11.2.1 (paf 286:: weekno_buf=new char[weekno_buf_size];
1.34 paf 287: weekno_size=snprintf(weekno_buf, weekno_buf_size, "%02d", n);
288: }
289:
1.10 parser 290: }
1.34 paf 291: // appending year week no
292: {
1.42.2.11.2.1 (paf 293:: const String& cell(new String);
1.34 paf 294: cell->APPEND_CLEAN(weekno_buf, weekno_size,
1.42.2.6 paf 295: method_name->origin().file, method_name->origin().line);
296: *row+=cell;
1.36 paf 297: }
298: // appending year week year
299: {
1.42.2.11.2.1 (paf 300:: const String& cell(new String);
301:: char *buf=new char[4+1];
1.36 paf 302: cell->APPEND_CLEAN(buf, sprintf(buf, "%02d", weekyear),
1.42.2.6 paf 303: method_name->origin().file, method_name->origin().line);
304: *row+=cell;
1.34 paf 305: }
1.42.2.6 paf 306: *result+=row;
1.10 parser 307: }
308:
309: return result;
310: }
311:
1.42.2.11.2.1 (paf 312:: static Table* fill_week_days(Request& r,
313:: const String& method_name, MethodParams* params, bool rus){
1.42.2.6 paf 314: Table::columns_type columns(new Table::columns_type::element_type(4));
1.42.2.11.2.1 (paf 315:: *columns+=String* (new String("year"));
316:: *columns+=String* (new String("month"));
317:: *columns+=String* (new String("day"));
318:: *columns+=String* (new String("weekday"));
319:: Table* result(new Table(method_name, columns));
1.10 parser 320:
1.42.2.10 paf 321: int year=params->as_int(1, "year must be int", r);
322: int month=max(1, min(params->as_int(2, "month must be int", r), 12)) -1;
323: int day=params->as_int(3, "day must be int", r);
1.10 parser 324:
325: tm tmIn={0, 0, 18, day, month, year-1900};
326: time_t t=mktime(&tmIn);
327: if(t<0)
1.22 paf 328: throw Exception(0,
1.42.2.6 paf 329: method_name,
1.10 parser 330: "invalid date");
331: tm *tmOut=localtime(&t);
332:
333: int baseWeekDay=tmOut->tm_wday;
334: if(rus)
335: baseWeekDay=baseWeekDay?baseWeekDay-1:6; //sunday last
336:
337: t-=baseWeekDay*SECS_PER_DAY;
338:
339: for(int curWeekDay=0; curWeekDay<7; curWeekDay++, t+=SECS_PER_DAY) {
340: tm *tmOut=localtime(&t);
1.42.2.7 paf 341: Table::element_type row(new ArrayString(4));
1.10 parser 342: #define WDFILL(size, value) { \
1.42.2.11.2.1 (paf 343:: char *buf=new char[size+1]; \
344:: const String& cell(new String); \
1.10 parser 345: cell->APPEND_CLEAN(buf, sprintf(buf, "%0"#size"d", value), \
1.42.2.6 paf 346: method_name->origin().file, \
347: method_name->origin().line); \
348: *row+=cell; \
1.10 parser 349: }
350: WDFILL(4, 1900+tmOut->tm_year);
351: WDFILL(2, 1+tmOut->tm_mon);
352: WDFILL(2, tmOut->tm_mday);
353: WDFILL(2, tmOut->tm_wday);
1.42.2.6 paf 354: *result+=row;
1.10 parser 355: }
356:
357: return result;
358: }
359:
1.42.2.11.2.1 (paf 360:: static void _calendar(Request& r, const String& method_name, MethodParams* params) {
361:: const String& what=params->as_string(0, "format must be strig");
1.10 parser 362: bool rus=false;
1.42.2.6 paf 363: if(*what=="rus")
1.10 parser 364: rus=true;
1.42.2.6 paf 365: else if(*what=="eng")
1.10 parser 366: rus=false;
367: else
1.22 paf 368: throw Exception("parser.runtime",
1.42.2.6 paf 369: what,
1.10 parser 370: "must be rus|eng");
371:
1.42.2.11.2.1 (paf 372:: Table* table;
1.42.2.10 paf 373: if(params->count()==1+2)
1.10 parser 374: table=fill_month_days(r, method_name, params, rus);
375: else // 1+3
376: table=fill_week_days(r, method_name, params, rus);
377:
1.42.2.6 paf 378: r.write_no_lang(ValuePtr(new VTable(table)));
1.10 parser 379: }
380:
1.1 parser 381: // constructor
382:
1.42.2.6 paf 383: MDate::MDate(): Methoded("date") {
1.1 parser 384: // ^now[]
1.23 paf 385: add_native_method("now", Method::CT_DYNAMIC, _now, 0, 1);
1.1 parser 386:
1.30 paf 387: // ^create(float days)
1.17 paf 388: add_native_method("create", Method::CT_DYNAMIC, _create, 1, 6);
1.28 paf 389: // old name for compatibility with <= v1.17 2002/2/18 12:13:42 paf
1.17 paf 390: add_native_method("set", Method::CT_DYNAMIC, _create, 1, 6);
1.1 parser 391:
1.6 parser 392: // ^sql-string[]
1.5 parser 393: add_native_method("sql-string", Method::CT_DYNAMIC, _sql_string, 0, 0);
1.1 parser 394:
395: // ^roll(year|month|day;+/- 1)
396: add_native_method("roll", Method::CT_DYNAMIC, _roll, 2, 2);
1.10 parser 397:
398: // ^date:calendar[month|montheng;year;month] = table
399: // ^date:calendar[week|weekeng;year;month;day] = table
400: add_native_method("calendar", Method::CT_STATIC, _calendar, 3, 4);
1.1 parser 401:
402: }
E-mail: