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