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