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