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