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