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