version 0.2.23
[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         SetT(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 const bool DateTime::operator<(const struct tm &rhs) const\r
191 {\r
192         return (m_tm.tm_year<rhs.tm_year || (m_tm.tm_year==rhs.tm_year && m_tm.tm_mon<rhs.tm_mon) || (m_tm.tm_year==rhs.tm_year && m_tm.tm_mon==rhs.tm_mon && m_tm.tm_mday<rhs.tm_mday) || (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_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_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));\r
193 }\r
194 \r
195 void DateTime::Set(const int year, const int month, const int day, const int hour, const int minute, const int second)\r
196 {\r
197         m_tm.tm_year=year-1900;\r
198         m_tm.tm_mon=month-1;\r
199         m_tm.tm_mday=day;\r
200         m_tm.tm_hour=hour;\r
201         m_tm.tm_min=minute;\r
202         m_tm.tm_sec=second;\r
203 \r
204         Normalize();\r
205 }\r
206 \r
207 void DateTime::SetT(const time_t &timet)\r
208 {\r
209         m_timet=timet;\r
210 \r
211         m_tm=*gmtime(&m_timet);\r
212         Normalize();\r
213 }\r
214 \r
215 void DateTime::Set(const struct tm *stm)\r
216 {\r
217         m_tm=*stm;\r
218         m_timet=mktime(&m_tm);\r
219         Normalize();\r
220 }\r
221 \r
222 void DateTime::Set(const std::string &datestring)\r
223 {\r
224         int year,month,day,hour,minute,second;\r
225         std::vector<std::string> tokens;\r
226         std::vector<std::string>::size_type vecpos;\r
227         int tempint;\r
228 \r
229         year=month=day=hour=minute=second=-1;\r
230 \r
231         // reset to 1900-01-01 00:00:00\r
232         Set();\r
233 \r
234         StringFunctions::SplitMultiple(datestring,"-/\\., :",tokens);\r
235 \r
236         // loop through 1st time to try to find 4 digit year and month (if it is a text month)\r
237         vecpos=0;\r
238         for(std::vector<std::string>::iterator i=tokens.begin(); i!=tokens.end(); i++,vecpos++)\r
239         {\r
240                 StringFunctions::UpperCase((*i),(*i));\r
241 \r
242                 if((*i).find("JAN")==0)\r
243                 {\r
244                         SetMonth(1);\r
245                         month=vecpos;\r
246                 }\r
247                 if((*i).find("FEB")==0)\r
248                 {\r
249                         SetMonth(2);\r
250                         month=vecpos;\r
251                 }\r
252                 if((*i).find("MAR")==0)\r
253                 {\r
254                         SetMonth(3);\r
255                         month=vecpos;\r
256                 }\r
257                 if((*i).find("APR")==0)\r
258                 {\r
259                         SetMonth(4);\r
260                         month=vecpos;\r
261                 }\r
262                 if((*i).find("MAY")==0)\r
263                 {\r
264                         SetMonth(5);\r
265                         month=vecpos;\r
266                 }\r
267                 if((*i).find("JUN")==0)\r
268                 {\r
269                         SetMonth(6);\r
270                         month=vecpos;\r
271                 }\r
272                 if((*i).find("JUL")==0)\r
273                 {\r
274                         SetMonth(7);\r
275                         month=vecpos;\r
276                 }\r
277                 if((*i).find("AUG")==0)\r
278                 {\r
279                         SetMonth(8);\r
280                         month=vecpos;\r
281                 }\r
282                 if((*i).find("SEP")==0)\r
283                 {\r
284                         SetMonth(9);\r
285                         month=vecpos;\r
286                 }\r
287                 if((*i).find("OCT")==0)\r
288                 {\r
289                         SetMonth(10);\r
290                         month=vecpos;\r
291                 }\r
292                 if((*i).find("NOV")==0)\r
293                 {\r
294                         SetMonth(11);\r
295                         month=vecpos;\r
296                 }\r
297                 if((*i).find("DEC")==0)\r
298                 {\r
299                         SetMonth(12);\r
300                         month=vecpos;\r
301                 }\r
302 \r
303                 // if we just got month - day is probaby in the next position\r
304                 if(month==vecpos && vecpos+1<tokens.size() && tokens[vecpos+1].size()>0)\r
305                 {\r
306                         tempint=-1;\r
307                         StringFunctions::Convert(tokens[vecpos+1],tempint);\r
308                         if(tempint>0 && tempint<32)\r
309                         {\r
310                                 SetDay(tempint);\r
311                                 day=vecpos+1;\r
312                         }\r
313                 }\r
314 \r
315                 // if this is not month or day, and the size is 4 then it is probably the year\r
316                 if(month!=vecpos && day!=vecpos && (*i).size()==4)\r
317                 {\r
318                         tempint=-1;\r
319                         StringFunctions::Convert((*i),tempint);\r
320 \r
321                         SetYear(tempint);\r
322                         year=vecpos;\r
323                 }\r
324         }\r
325 \r
326         // month is probably right after year\r
327         if(year!=-1 && month==-1 && year+1<tokens.size())\r
328         {\r
329                 tempint=-1;\r
330                 StringFunctions::Convert(tokens[year+1],tempint);\r
331                 if(tempint>=1 && tempint<=12)\r
332                 {\r
333                         SetMonth(tempint);\r
334                         month=year+1;\r
335                 }\r
336         }\r
337 \r
338         // otherwise it is probably 2 steps back (m/d/y)\r
339         if(year!=-1 && month==-1 && year-2>=0)\r
340         {\r
341                 tempint=-1;\r
342                 StringFunctions::Convert(tokens[year-2],tempint);\r
343                 if(tempint>=1 && tempint<=12)\r
344                 {\r
345                         SetMonth(tempint);\r
346                         month=year-2;\r
347                 }\r
348         }\r
349 \r
350         // day is probably right after month\r
351         if(month!=-1 && month+1<tokens.size())\r
352         {\r
353                 tempint=-1;\r
354                 StringFunctions::Convert(tokens[month+1],tempint);\r
355                 if(tempint>=1 && tempint<32)\r
356                 {\r
357                         SetDay(tempint);\r
358                         day=month+1;\r
359                 }\r
360         }\r
361 \r
362         // loop through another time to find hour\r
363         vecpos=0;\r
364         for(std::vector<std::string>::iterator i=tokens.begin(); i!=tokens.end(); i++,vecpos++)\r
365         {\r
366                 if(vecpos!=year && vecpos!=month && vecpos!=day && hour==-1)\r
367                 {\r
368                         tempint=-1;\r
369                         StringFunctions::Convert((*i),tempint);\r
370                         if(tempint>=0 && tempint<24)\r
371                         {\r
372                                 SetHour(tempint);\r
373                                 hour=vecpos;\r
374                         }\r
375                 }\r
376         }\r
377 \r
378         // minute right after hour\r
379         if(hour!=-1 && hour+1<tokens.size())\r
380         {\r
381                 tempint=-1;\r
382                 StringFunctions::Convert(tokens[hour+1],tempint);\r
383                 if(tempint>=0 && tempint<60)\r
384                 {\r
385                         SetMinute(tempint);\r
386                         minute=hour+1;\r
387                 }\r
388         }\r
389 \r
390         //second right after minute\r
391         if(minute!=-1 && minute+1<tokens.size())\r
392         {\r
393                 tempint=-1;\r
394                 StringFunctions::Convert(tokens[minute+1],tempint);\r
395                 if(tempint>=0 && tempint<60)\r
396                 {\r
397                         SetSecond(tempint);\r
398                         second=minute+1;\r
399                 }\r
400         }\r
401 \r
402 }\r
403 \r
404 void DateTime::SetToGMTime()\r
405 {\r
406         m_timet=time(NULL);\r
407 \r
408         m_tm=*gmtime(&m_timet);\r
409         Normalize();\r
410 }\r
411 \r
412 void DateTime::SetToLocalTime()\r
413 {\r
414         m_timet=time(NULL);\r
415         m_tm=*localtime(&m_timet);\r
416         Normalize();\r
417 }\r
418 \r
419 const time_t DateTime::TimeGM(struct tm *gmtimein)\r
420 {\r
421         //This looks good but I don't think will work when TZ isn't set (Windows)\r
422         //http://developer.apple.com/documentation/Darwin/Reference/ManPages/man3/timegm.3.html\r
423         \r
424         //This should work\r
425         //http://lists2.ais.fraunhofer.de/pipermail/emx/1999-September/000874.html\r
426 \r
427         struct tm ttm;\r
428         time_t t, t2;\r
429 \r
430         ttm = *gmtimein;       /* make a local copy to fiddle with */\r
431         ttm.tm_isdst = 0;      /* treat it as standard time */\r
432 \r
433         t2 = t = mktime(&ttm); /* calculate the time as a local time */\r
434 \r
435         ttm = *gmtime(&t2);    /* now calculate the difference between */\r
436         ttm.tm_isdst = 0;      /* gm and local time */\r
437         t2 = mktime(&ttm);\r
438 \r
439         t += t - t2;          /* and adjust our answer by that difference */\r
440         return t;\r
441 }\r