7d3d4affedccf593a3ed3e4cca22cb09af654700
[fms.git] / src / datetime.cpp
1 #include "../include/datetime.h"\r
2 \r
3 #include <vector>\r
4 #include "../include/stringfunctions.h"\r
5 \r
6 #ifdef XMEM\r
7         #include <xmem.h>\r
8 #endif\r
9 \r
10 DateTime::DateTime()\r
11 {\r
12         Set();\r
13 }\r
14 \r
15 DateTime::DateTime(const time_t &timet)\r
16 {\r
17         Set(timet);\r
18 }\r
19 \r
20 DateTime::DateTime(const struct tm *stm)\r
21 {\r
22         Set(stm);\r
23 }\r
24 \r
25 void DateTime::Add(const int seconds, const int minutes, const int hours, const int days, const int months, const int years)\r
26 {\r
27         m_tm.tm_sec+=seconds;\r
28         m_tm.tm_min+=minutes;\r
29         m_tm.tm_hour+=hours;\r
30         m_tm.tm_mday+=days;\r
31         m_tm.tm_mon+=months;\r
32         m_tm.tm_year+=years;\r
33         \r
34         Normalize();\r
35 }\r
36 \r
37 std::string DateTime::Format(const std::string &formatstring) const\r
38 {\r
39         std::string returnval="";\r
40         char *str=new char[512];\r
41         memset(str,0,512);\r
42 \r
43         strftime(str,511,formatstring.c_str(),&m_tm);\r
44 \r
45         if(str)\r
46         {\r
47                 returnval=str;\r
48                 delete [] str;\r
49         }\r
50 \r
51         return returnval;\r
52 }\r
53 \r
54 void DateTime::Normalize()\r
55 {\r
56         // check for tm_isdst in local time and take appropriate action when normalizing\r
57         // thanks to http://www.erack.de/download/timetest.c for example\r
58         int isdst;\r
59         struct tm temptm;\r
60         time_t temptimet;\r
61         temptimet=time(NULL);\r
62         temptm=*localtime(&temptimet);\r
63         isdst=temptm.tm_isdst;\r
64 \r
65         temptm.tm_year=m_tm.tm_year;\r
66         temptm.tm_mon=m_tm.tm_mon;\r
67         temptm.tm_mday=m_tm.tm_mday;\r
68         temptm.tm_hour=m_tm.tm_hour;\r
69         temptm.tm_min=m_tm.tm_min;\r
70         temptm.tm_sec=m_tm.tm_sec;\r
71         temptm.tm_isdst=isdst;\r
72         temptimet=mktime(&temptm);\r
73 \r
74         if(temptm.tm_isdst!=isdst)\r
75         {\r
76                 // keep tm_isdst to whatever mktime returned and try again\r
77                 temptm.tm_year=m_tm.tm_year;\r
78                 temptm.tm_mon=m_tm.tm_mon;\r
79                 temptm.tm_mday=m_tm.tm_mday;\r
80                 temptm.tm_hour=m_tm.tm_hour;\r
81                 temptm.tm_min=m_tm.tm_min;\r
82                 temptm.tm_sec=m_tm.tm_sec;\r
83                 temptimet=mktime(&temptm);\r
84         }\r
85         else if(isdst && temptimet==-1)\r
86         {\r
87                 // isdst set, but TZ has no offset (e.g. GMT), try with isdst=0\r
88                 temptm.tm_year=m_tm.tm_year;\r
89                 temptm.tm_mon=m_tm.tm_mon;\r
90                 temptm.tm_mday=m_tm.tm_mday;\r
91                 temptm.tm_hour=m_tm.tm_hour;\r
92                 temptm.tm_min=m_tm.tm_min;\r
93                 temptm.tm_sec=m_tm.tm_sec;\r
94                 temptm.tm_isdst=0;\r
95                 temptimet=mktime(&temptm);\r
96         }\r
97 \r
98         m_tm=temptm;\r
99         m_timet=temptimet;\r
100 \r
101         // date is erroneous - set to default date\r
102         if(m_timet==-1 && (m_tm.tm_mon<0 || m_tm.tm_mon>11 || m_tm.tm_mday <1 || m_tm.tm_mday>31 || m_tm.tm_hour<0 || m_tm.tm_hour>23 || m_tm.tm_min<0 || m_tm.tm_min>59 || m_tm.tm_sec<0 || m_tm.tm_sec>59))\r
103         {\r
104                 Set();\r
105         }\r
106 \r
107 }\r
108 \r
109 DateTime DateTime::operator+(const double &rhs)\r
110 {\r
111         DateTime temp=*this;\r
112 \r
113         double val=rhs;\r
114         int days=(int)val;\r
115         val-=days;\r
116         val*=24.0;\r
117         int hours=(int)val;\r
118         val-=hours;\r
119         val*=60.0;\r
120         int minutes=(int)val;\r
121         val-=minutes;\r
122         val*=60.0;\r
123         int seconds=(int)val;\r
124 \r
125         temp.Add(seconds,minutes,hours,days);\r
126         return temp;\r
127 }\r
128 \r
129 DateTime DateTime::operator+(const DateTime &rhs)\r
130 {\r
131         DateTime temp=*this;\r
132 \r
133         temp.Add(rhs.m_tm.tm_sec,rhs.m_tm.tm_min,rhs.m_tm.tm_hour,rhs.m_tm.tm_mday,rhs.m_tm.tm_mon+1,rhs.m_tm.tm_year+1900);\r
134         return temp;\r
135 }\r
136 \r
137 DateTime &DateTime::operator+=(const double &rhs)\r
138 {\r
139         *this=*this+rhs;\r
140 \r
141         return *this;\r
142 }\r
143 \r
144 DateTime &DateTime::operator+=(const DateTime &rhs)\r
145 {\r
146         *this=*this+rhs;\r
147 \r
148         return *this;\r
149 }\r
150 \r
151 DateTime DateTime::operator-(const double &rhs)\r
152 {\r
153         DateTime temp=*this;\r
154 \r
155         double val=rhs;\r
156         int days=(int)val;\r
157         val-=days;\r
158         val*=24.0;\r
159         int hours=(int)val;\r
160         val-=hours;\r
161         val*=60.0;\r
162         int minutes=(int)val;\r
163         val-=minutes;\r
164         val*=60.0;\r
165         int seconds=(int)val;\r
166 \r
167         temp.Add(-seconds,-minutes,-hours,-days);\r
168         return temp;\r
169 }\r
170 \r
171 DateTime DateTime::operator-(const DateTime &rhs)\r
172 {\r
173         DateTime temp=*this;\r
174 \r
175         temp.Add(-rhs.m_tm.tm_sec,-rhs.m_tm.tm_min,-rhs.m_tm.tm_hour,-rhs.m_tm.tm_mday,-(rhs.m_tm.tm_mon+1),-(rhs.m_tm.tm_year+1900));\r
176         return temp;\r
177 }\r
178 \r
179 DateTime &DateTime::operator-=(const double &rhs)\r
180 {\r
181         *this=*this-rhs;\r
182 \r
183         return *this;\r
184 }\r
185 \r
186 DateTime &DateTime::operator-=(const DateTime &rhs)\r
187 {\r
188         *this=*this-rhs;\r
189 \r
190         return *this;\r
191 }\r
192 \r
193 const bool DateTime::operator==(const struct tm &rhs) const\r
194 {\r
195         return (m_tm.tm_year==rhs.tm_year && m_tm.tm_mon==rhs.tm_mon && m_tm.tm_mday==rhs.tm_mday && m_tm.tm_hour==rhs.tm_hour && m_tm.tm_min==rhs.tm_min && m_tm.tm_sec==rhs.tm_sec) ? true : false;\r
196 }\r
197 \r
198 void DateTime::Set(const int year, const int month, const int day, const int hour, const int minute, const int second)\r
199 {\r
200         m_tm.tm_year=year-1900;\r
201         m_tm.tm_mon=month-1;\r
202         m_tm.tm_mday=day;\r
203         m_tm.tm_hour=hour;\r
204         m_tm.tm_min=minute;\r
205         m_tm.tm_sec=second;\r
206 \r
207         Normalize();\r
208 }\r
209 \r
210 void DateTime::Set(const time_t &timet)\r
211 {\r
212         m_timet=timet;\r
213 \r
214         m_tm=*gmtime(&m_timet);\r
215         Normalize();\r
216 }\r
217 \r
218 void DateTime::Set(const struct tm *stm)\r
219 {\r
220         m_tm=*stm;\r
221         m_timet=mktime(&m_tm);\r
222         Normalize();\r
223 }\r
224 \r
225 void DateTime::Set(const std::string &datestring)\r
226 {\r
227         int year,month,day,hour,minute,second;\r
228         std::vector<std::string> tokens;\r
229         int vecpos;\r
230         int tempint;\r
231 \r
232         year=month=day=hour=minute=second=-1;\r
233 \r
234         // reset to 1900-01-01 00:00:00\r
235         Set();\r
236 \r
237         StringFunctions::SplitMultiple(datestring,"-/\\., :",tokens);\r
238 \r
239         // loop through 1st time to try to find 4 digit year and month (if it is a text month)\r
240         vecpos=0;\r
241         for(std::vector<std::string>::iterator i=tokens.begin(); i!=tokens.end(); i++,vecpos++)\r
242         {\r
243                 StringFunctions::UpperCase((*i),(*i));\r
244 \r
245                 if((*i).find("JAN")==0)\r
246                 {\r
247                         SetMonth(1);\r
248                         month=vecpos;\r
249                 }\r
250                 if((*i).find("FEB")==0)\r
251                 {\r
252                         SetMonth(2);\r
253                         month=vecpos;\r
254                 }\r
255                 if((*i).find("MAR")==0)\r
256                 {\r
257                         SetMonth(3);\r
258                         month=vecpos;\r
259                 }\r
260                 if((*i).find("APR")==0)\r
261                 {\r
262                         SetMonth(4);\r
263                         month=vecpos;\r
264                 }\r
265                 if((*i).find("MAY")==0)\r
266                 {\r
267                         SetMonth(5);\r
268                         month=vecpos;\r
269                 }\r
270                 if((*i).find("JUN")==0)\r
271                 {\r
272                         SetMonth(6);\r
273                         month=vecpos;\r
274                 }\r
275                 if((*i).find("JUL")==0)\r
276                 {\r
277                         SetMonth(7);\r
278                         month=vecpos;\r
279                 }\r
280                 if((*i).find("AUG")==0)\r
281                 {\r
282                         SetMonth(8);\r
283                         month=vecpos;\r
284                 }\r
285                 if((*i).find("SEP")==0)\r
286                 {\r
287                         SetMonth(9);\r
288                         month=vecpos;\r
289                 }\r
290                 if((*i).find("OCT")==0)\r
291                 {\r
292                         SetMonth(10);\r
293                         month=vecpos;\r
294                 }\r
295                 if((*i).find("NOV")==0)\r
296                 {\r
297                         SetMonth(11);\r
298                         month=vecpos;\r
299                 }\r
300                 if((*i).find("DEC")==0)\r
301                 {\r
302                         SetMonth(12);\r
303                         month=vecpos;\r
304                 }\r
305 \r
306                 // if we just got month - day is probaby in the next position\r
307                 if(month==vecpos && vecpos+1<tokens.size() && tokens[vecpos+1].size()>0)\r
308                 {\r
309                         tempint=-1;\r
310                         StringFunctions::Convert(tokens[vecpos+1],tempint);\r
311                         if(tempint>0 && tempint<32)\r
312                         {\r
313                                 SetDay(tempint);\r
314                                 day=vecpos+1;\r
315                         }\r
316                 }\r
317 \r
318                 // if this is not month or day, and the size is 4 then it is probably the year\r
319                 if(month!=vecpos && day!=vecpos && (*i).size()==4)\r
320                 {\r
321                         tempint=-1;\r
322                         StringFunctions::Convert((*i),tempint);\r
323 \r
324                         SetYear(tempint);\r
325                         year=vecpos;\r
326                 }\r
327         }\r
328 \r
329         // month is probably right after year\r
330         if(year!=-1 && month==-1 && year+1<tokens.size())\r
331         {\r
332                 tempint=-1;\r
333                 StringFunctions::Convert(tokens[year+1],tempint);\r
334                 if(tempint>=1 && tempint<=12)\r
335                 {\r
336                         SetMonth(tempint);\r
337                         month=year+1;\r
338                 }\r
339         }\r
340 \r
341         // otherwise it is probably 2 steps back (m/d/y)\r
342         if(year!=-1 && month==-1 && year-2>=0)\r
343         {\r
344                 tempint=-1;\r
345                 StringFunctions::Convert(tokens[year-2],tempint);\r
346                 if(tempint>=1 && tempint<=12)\r
347                 {\r
348                         SetMonth(tempint);\r
349                         month=year-2;\r
350                 }\r
351         }\r
352 \r
353         // day is probably right after month\r
354         if(month!=-1 && month+1<tokens.size())\r
355         {\r
356                 tempint=-1;\r
357                 StringFunctions::Convert(tokens[month+1],tempint);\r
358                 if(tempint>=1 && tempint<32)\r
359                 {\r
360                         SetDay(tempint);\r
361                         day=month+1;\r
362                 }\r
363         }\r
364 \r
365         // loop through another time to find hour\r
366         vecpos=0;\r
367         for(std::vector<std::string>::iterator i=tokens.begin(); i!=tokens.end(); i++,vecpos++)\r
368         {\r
369                 if(vecpos!=year && vecpos!=month && vecpos!=day && hour==-1)\r
370                 {\r
371                         tempint=-1;\r
372                         StringFunctions::Convert((*i),tempint);\r
373                         if(tempint>=0 && tempint<24)\r
374                         {\r
375                                 SetHour(tempint);\r
376                                 hour=vecpos;\r
377                         }\r
378                 }\r
379         }\r
380 \r
381         // minute right after hour\r
382         if(hour!=-1 && hour+1<tokens.size())\r
383         {\r
384                 tempint=-1;\r
385                 StringFunctions::Convert(tokens[hour+1],tempint);\r
386                 if(tempint>=0 && tempint<60)\r
387                 {\r
388                         SetMinute(tempint);\r
389                         minute=hour+1;\r
390                 }\r
391         }\r
392 \r
393         //second right after minute\r
394         if(minute!=-1 && minute+1<tokens.size())\r
395         {\r
396                 tempint=-1;\r
397                 StringFunctions::Convert(tokens[minute+1],tempint);\r
398                 if(tempint>=0 && tempint<60)\r
399                 {\r
400                         SetSecond(tempint);\r
401                         second=minute+1;\r
402                 }\r
403         }\r
404 \r
405 }\r
406 \r
407 void DateTime::SetToGMTime()\r
408 {\r
409         m_timet=time(NULL);\r
410 \r
411         m_tm=*gmtime(&m_timet);\r
412         Normalize();\r
413 }\r
414 \r
415 void DateTime::SetToLocalTime()\r
416 {\r
417         m_timet=time(NULL);\r
418         m_tm=*localtime(&m_timet);\r
419         Normalize();\r
420 }\r