Annotation of parser3/src/classes/date.C, revision 1.24
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.1 parser 6:
1.24 ! paf 7: $Id: date.C,v 1.23 2002/03/28 14:26:48 paf Exp $
1.1 parser 8: */
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: // defines
17:
18: #define DATE_CLASS_NAME "date"
19:
20: // class
21:
22: class MDate : public Methoded {
23: public: // VStateless_class
24: Value *create_new_value(Pool& pool) { return new(pool) VDate(pool, 0); }
25:
26: public:
27: MDate(Pool& pool);
28: public: // Methoded
29: bool used_directly() { return true; }
30: };
31:
32: // methods
33:
1.23 paf 34: static void _now(Request& r, const String& method_name, MethodParams *params) {
1.1 parser 35: Pool& pool=r.pool();
36: VDate *vdate=static_cast<VDate *>(r.self);
1.23 paf 37:
38: time_t t=time(0);
39: if(params->size()==1) // ^now(offset)
40: t+=(time_t)(params->as_double(0, "offset must be double", r)*SECS_PER_DAY);
41:
42: vdate->set_time(t);
1.1 parser 43: }
44:
1.17 paf 45: static void _create(Request& r, const String& method_name, MethodParams *params) {
1.1 parser 46: Pool& pool=r.pool();
47: VDate *vdate=static_cast<VDate *>(r.self);
48:
1.23 paf 49: time_t t;
1.1 parser 50: if(params->size()==1) // ^set(float days)
1.23 paf 51: t=(time_t)(params->as_double(0, "float days must be double", r)*SECS_PER_DAY);
1.24 ! paf 52: else if(params->size()>=2) { // ^set(y;m;d[;h[;m[;s]]])
1.1 parser 53: tm tmIn={0};
54: tmIn.tm_isdst=-1;
1.9 parser 55: int year=params->as_int(0, "year must be int", r);
1.1 parser 56: if(year<70) // 0..69 -> 100..169 [2000..2069]
57: year+=100;
1.3 parser 58: if(year>=1900)
59: year-=1900;
1.1 parser 60: tmIn.tm_year=year;
1.9 parser 61: tmIn.tm_mon=params->as_int(1, "month must be int", r)-1;
1.24 ! paf 62: tmIn.tm_mday=params->size()>2?params->as_int(2, "mday must be int", r):1;
1.9 parser 63: if(params->size()>3) tmIn.tm_hour=params->as_int(3, "hour must be int", r);
64: if(params->size()>4) tmIn.tm_min=params->as_int(4, "minutes must be int", r);
65: if(params->size()>5) tmIn.tm_sec=params->as_int(5, "seconds must be int", r);
1.23 paf 66: t=mktime(&tmIn);
67: if(t<0)
1.22 paf 68: throw Exception(0,
1.1 parser 69: &method_name,
70: "invalid datetime");
71: } else
1.22 paf 72: throw Exception("parser.runtime",
1.1 parser 73: &method_name,
1.24 ! paf 74: "invalid params count, must be 1 or >=2");
1.23 paf 75: vdate->set_time(t);
1.1 parser 76: }
77:
1.5 parser 78: static void _sql_string(Request& r, const String& method_name, MethodParams *) {
1.1 parser 79: Pool& pool=r.pool();
80: VDate *vdate=static_cast<VDate *>(r.self);
1.2 parser 81: int size=1+ 4+1+2+1+2 +1+ 2+1+2+1+2 +1 +1;
1.1 parser 82: char *buf=(char *)pool.malloc(size);
83: time_t time=vdate->get_time();
1.14 paf 84: size=strftime(buf, size, "%Y-%m-%d %H:%M:%S", localtime(&time));
1.1 parser 85:
1.4 parser 86: String& string=*new(pool) String(pool);
87: string.APPEND_CLEAN(buf, size,
88: method_name.origin().file,
89: method_name.origin().line);
90: Value& result=*new(pool) VString(string);
1.1 parser 91: r.write_assign_lang(result);
92: }
93:
94:
95: static void _roll(Request& r, const String& method_name, MethodParams *params) {
96: Pool& pool=r.pool();
97: VDate *vdate=static_cast<VDate *>(r.self);
98:
99: const String& what=params->as_string(0, "'what' must be string");
100: int oyear=0;
101: int omonth=0;
102: int oday=0;
103: int *offset;
104: if(what=="year") offset=&oyear;
105: else if(what=="month") offset=&omonth;
106: else if(what=="day") offset=&oday;
107: else
1.22 paf 108: throw Exception("parser.runtime",
1.1 parser 109: &what,
110: "must be year|month|day");
111:
1.9 parser 112: *offset=params->as_int(1, "offset must be int", r);
1.1 parser 113:
1.13 paf 114: time_t self_time=vdate->get_time();
115: tm tmIn=*localtime(&self_time);
116: tm tmSaved=tmIn;
117:
1.21 paf 118: tmIn.tm_year+=oyear;
119: tmIn.tm_mon+=omonth;
120: tmIn.tm_mday+=oday;
121: tmIn.tm_hour=24/2;
122: tmIn.tm_min=0;
123: tmIn.tm_sec=0;
124: time_t t=mktime/*normalizetime*/(&tmIn);
125: if(t<0)
1.22 paf 126: throw Exception(0,
1.21 paf 127: &method_name,
128: "bad resulting time (after roll)");
1.24 ! paf 129: if(oday==0 && tmIn.tm_mday!=tmSaved.tm_mday)
! 130: throw Exception(0,
! 131: &method_name,
! 132: "bad resulting time (day hole)", t);
1.21 paf 133:
1.13 paf 134: tm *tmOut=localtime(&t);
135: if(!tmOut)
1.22 paf 136: throw Exception(0,
1.1 parser 137: &method_name,
1.13 paf 138: "bad resulting time (seconds from epoch=%ld)", t);
139:
140: tmOut->tm_hour=tmSaved.tm_hour;
141: tmOut->tm_min=tmSaved.tm_min;
142: tmOut->tm_sec=tmSaved.tm_sec;
1.20 paf 143: tmOut->tm_isdst=-1;
1.13 paf 144: {
1.21 paf 145: time_t t=mktime/*normalizetime*/(tmOut);
146: if(
147: tmOut->tm_hour!=tmSaved.tm_hour
148: ||tmOut->tm_min!=tmSaved.tm_min)
1.22 paf 149: throw Exception(0,
1.21 paf 150: &method_name,
1.24 ! paf 151: "bad resulting time (hour hole)");
1.21 paf 152:
1.13 paf 153: if(t<0)
1.22 paf 154: throw Exception(0,
1.21 paf 155: &method_name,
156: "bad resulting time (after reconstruction)");
1.13 paf 157:
158: vdate->set_time(t);
159: }
1.1 parser 160: }
161:
1.10 parser 162: static Table *fill_month_days(Request& r,
163: const String& method_name, MethodParams *params, bool rus){
164: Pool& pool=r.pool();
165: Table *result=new(pool) Table(pool, &method_name, 0/*&columns*/);
166:
167: int year=params->as_int(1, "year must be int", r);
168: int month=max(1, min(params->as_int(2, "month must be int", r), 12)) -1;
169:
170: tm tmIn={0, 0, 0, 1, month, year-1900};
171: time_t t=mktime(&tmIn);
172: if(t<0)
1.22 paf 173: throw Exception(0,
1.10 parser 174: &method_name,
175: "invalid date");
176: tm *tmOut=localtime(&t);
177:
178: int weekDay1=tmOut->tm_wday;
179: if(rus)
180: weekDay1=weekDay1?weekDay1-1:6; //sunday last
181: int monthDays=getMonthDays(year, month);
182:
183: for(int _day=1-weekDay1; _day<=monthDays;) {
184: Array& row=*new(pool) Array(pool, 7);
185: for(int wday=0; wday<7; wday++, _day++) {
186: String *cell=new(pool) String(pool);
187: if(_day>=1 && _day<=monthDays) {
188: char *buf=(char *)pool.malloc(2+1);
189: cell->APPEND_CLEAN(buf, sprintf(buf, "%02d", _day),
190: method_name.origin().file, method_name.origin().line);
191: }
192: row+=cell;
193: }
194: *result+=&row;
195: }
196:
197: return result;
198: }
199:
200: static Table *fill_week_days(Request& r,
201: const String& method_name, MethodParams *params, bool rus){
202: Pool& pool=r.pool();
203: Array& columns=*new(pool) Array(pool, 4);
1.18 paf 204: columns+=new(pool) String(pool, "year");
205: columns+=new(pool) String(pool, "month");
206: columns+=new(pool) String(pool, "day");
1.19 paf 207: columns+=new(pool) String(pool, "weekday");
1.10 parser 208: Table *result=new(pool) Table(pool, &method_name, &columns);
209:
210: int year=params->as_int(1, "year must be int", r);
211: int month=max(1, min(params->as_int(2, "month must be int", r), 12)) -1;
212: int day=params->as_int(3, "day must be int", r);
213:
214: tm tmIn={0, 0, 18, day, 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 baseWeekDay=tmOut->tm_wday;
223: if(rus)
224: baseWeekDay=baseWeekDay?baseWeekDay-1:6; //sunday last
225:
226: t-=baseWeekDay*SECS_PER_DAY;
227:
228: for(int curWeekDay=0; curWeekDay<7; curWeekDay++, t+=SECS_PER_DAY) {
229: tm *tmOut=localtime(&t);
230: Array& row=*new(pool) Array(pool, 4);
231: #define WDFILL(size, value) { \
232: char *buf=(char *)pool.malloc(size+1); \
233: String *cell=new(pool) String(pool); \
234: cell->APPEND_CLEAN(buf, sprintf(buf, "%0"#size"d", value), \
235: method_name.origin().file, \
236: method_name.origin().line); \
237: row+=cell; \
238: }
239: WDFILL(4, 1900+tmOut->tm_year);
240: WDFILL(2, 1+tmOut->tm_mon);
241: WDFILL(2, tmOut->tm_mday);
242: WDFILL(2, tmOut->tm_wday);
243: *result+=&row;
244: }
245:
246: return result;
247: }
248:
249: static void _calendar(Request& r, const String& method_name, MethodParams *params) {
250: Pool& pool=r.pool();
251:
252: const String& what=params->as_string(0, "format must be strig");
253: bool rus=false;
254: if(what=="rus")
255: rus=true;
256: else if(what=="eng")
257: rus=false;
258: else
1.22 paf 259: throw Exception("parser.runtime",
1.10 parser 260: &what,
261: "must be rus|eng");
262:
263: Table *table;
264: if(params->size()==1+2)
265: table=fill_month_days(r, method_name, params, rus);
266: else // 1+3
267: table=fill_week_days(r, method_name, params, rus);
268:
269: VTable& result=*new(pool) VTable(pool, table);
270: result.set_name(method_name);
271: r.write_no_lang(result);
272: }
273:
1.1 parser 274: // constructor
275:
276: MDate::MDate(Pool& apool) : Methoded(apool) {
277: set_name(*NEW String(pool(), DATE_CLASS_NAME));
278:
279:
280: // ^now[]
1.23 paf 281: add_native_method("now", Method::CT_DYNAMIC, _now, 0, 1);
1.1 parser 282:
283: // ^set(float days)
1.17 paf 284: add_native_method("create", Method::CT_DYNAMIC, _create, 1, 6);
285: add_native_method("set", Method::CT_DYNAMIC, _create, 1, 6);
1.1 parser 286:
1.6 parser 287: // ^sql-string[]
1.5 parser 288: add_native_method("sql-string", Method::CT_DYNAMIC, _sql_string, 0, 0);
1.1 parser 289:
290: // ^roll(year|month|day;+/- 1)
291: add_native_method("roll", Method::CT_DYNAMIC, _roll, 2, 2);
1.10 parser 292:
293: // ^date:calendar[month|montheng;year;month] = table
294: // ^date:calendar[week|weekeng;year;month;day] = table
295: add_native_method("calendar", Method::CT_STATIC, _calendar, 3, 4);
1.1 parser 296:
297: }
298: // global variable
299:
300: Methoded *date_class;
301:
302: // creator
303:
304: Methoded *MDate_create(Pool& pool) {
305: return date_class=new(pool) MDate(pool);
306: }
E-mail: