Merge remote branch 'mine/ext-python'
[vuplus_xbmc] / xbmc / XBDateTime.cpp
1 /*
2  *      Copyright (C) 2005-2008 Team XBMC
3  *      http://www.xbmc.org
4  *
5  *  This Program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2, or (at your option)
8  *  any later version.
9  *
10  *  This Program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with XBMC; see the file COPYING.  If not, write to
17  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18  *  http://www.gnu.org/copyleft/gpl.html
19  *
20  */
21
22 #include "XBDateTime.h"
23 #include "LangInfo.h"
24 #include "guilib/LocalizeStrings.h"
25
26 #define SECONDS_PER_DAY 86400UL
27 #define SECONDS_PER_HOUR 3600UL
28 #define SECONDS_PER_MINUTE 60UL
29 #define SECONDS_TO_FILETIME 10000000UL
30
31 /////////////////////////////////////////////////
32 //
33 // CDateTimeSpan
34 //
35
36 CDateTimeSpan::CDateTimeSpan()
37 {
38   m_timeSpan.dwHighDateTime=0;
39   m_timeSpan.dwLowDateTime=0;
40 }
41
42 CDateTimeSpan::CDateTimeSpan(const CDateTimeSpan& span)
43 {
44   m_timeSpan.dwHighDateTime=span.m_timeSpan.dwHighDateTime;
45   m_timeSpan.dwLowDateTime=span.m_timeSpan.dwLowDateTime;
46 }
47
48 CDateTimeSpan::CDateTimeSpan(int day, int hour, int minute, int second)
49 {
50   SetDateTimeSpan(day, hour, minute, second);
51 }
52
53 bool CDateTimeSpan::operator >(const CDateTimeSpan& right) const
54 {
55   return CompareFileTime(&m_timeSpan, &right.m_timeSpan)>0;
56 }
57
58 bool CDateTimeSpan::operator >=(const CDateTimeSpan& right) const
59 {
60   return operator >(right) || operator ==(right);
61 }
62
63 bool CDateTimeSpan::operator <(const CDateTimeSpan& right) const
64 {
65   return CompareFileTime(&m_timeSpan, &right.m_timeSpan)<0;
66 }
67
68 bool CDateTimeSpan::operator <=(const CDateTimeSpan& right) const
69 {
70   return operator <(right) || operator ==(right);
71 }
72
73 bool CDateTimeSpan::operator ==(const CDateTimeSpan& right) const
74 {
75   return CompareFileTime(&m_timeSpan, &right.m_timeSpan)==0;
76 }
77
78 bool CDateTimeSpan::operator !=(const CDateTimeSpan& right) const
79 {
80   return !operator ==(right);
81 }
82
83 CDateTimeSpan CDateTimeSpan::operator +(const CDateTimeSpan& right) const
84 {
85   CDateTimeSpan left(*this);
86
87   ULARGE_INTEGER timeLeft;
88   left.ToULargeInt(timeLeft);
89
90   ULARGE_INTEGER timeRight;
91   right.ToULargeInt(timeRight);
92
93   timeLeft.QuadPart+=timeRight.QuadPart;
94
95   left.FromULargeInt(timeLeft);
96
97   return left;
98 }
99
100 CDateTimeSpan CDateTimeSpan::operator -(const CDateTimeSpan& right) const
101 {
102   CDateTimeSpan left(*this);
103
104   ULARGE_INTEGER timeLeft;
105   left.ToULargeInt(timeLeft);
106
107   ULARGE_INTEGER timeRight;
108   right.ToULargeInt(timeRight);
109
110   timeLeft.QuadPart-=timeRight.QuadPart;
111
112   left.FromULargeInt(timeLeft);
113
114   return left;
115 }
116
117 const CDateTimeSpan& CDateTimeSpan::operator +=(const CDateTimeSpan& right)
118 {
119   ULARGE_INTEGER timeThis;
120   ToULargeInt(timeThis);
121
122   ULARGE_INTEGER timeRight;
123   right.ToULargeInt(timeRight);
124
125   timeThis.QuadPart+=timeRight.QuadPart;
126
127   FromULargeInt(timeThis);
128
129   return *this;
130 }
131
132 const CDateTimeSpan& CDateTimeSpan::operator -=(const CDateTimeSpan& right)
133 {
134   ULARGE_INTEGER timeThis;
135   ToULargeInt(timeThis);
136
137   ULARGE_INTEGER timeRight;
138   right.ToULargeInt(timeRight);
139
140   timeThis.QuadPart-=timeRight.QuadPart;
141
142   FromULargeInt(timeThis);
143
144   return *this;
145 }
146
147 void CDateTimeSpan::ToULargeInt(ULARGE_INTEGER& time) const
148 {
149   time.u.HighPart=m_timeSpan.dwHighDateTime;
150   time.u.LowPart=m_timeSpan.dwLowDateTime;
151 }
152
153 void CDateTimeSpan::FromULargeInt(const ULARGE_INTEGER& time)
154 {
155   m_timeSpan.dwHighDateTime=time.u.HighPart;
156   m_timeSpan.dwLowDateTime=time.u.LowPart;
157 }
158
159 void CDateTimeSpan::SetDateTimeSpan(int day, int hour, int minute, int second)
160 {
161   ULARGE_INTEGER time;
162   ToULargeInt(time);
163
164   time.QuadPart=(LONGLONG)day*SECONDS_PER_DAY*SECONDS_TO_FILETIME;
165   time.QuadPart+=(LONGLONG)hour*SECONDS_PER_HOUR*SECONDS_TO_FILETIME;
166   time.QuadPart+=(LONGLONG)minute*SECONDS_PER_MINUTE*SECONDS_TO_FILETIME;
167   time.QuadPart+=(LONGLONG)second*SECONDS_TO_FILETIME;
168
169   FromULargeInt(time);
170 }
171
172 void CDateTimeSpan::SetFromTimeString(const CStdString& time) // hh:mm
173 {
174   int hour    = atoi(time.Mid(0,2).c_str());
175   int minutes = atoi(time.Mid(3,2).c_str());
176   SetDateTimeSpan(0,hour,minutes,0);
177 }
178
179 int CDateTimeSpan::GetDays() const
180 {
181   ULARGE_INTEGER time;
182   ToULargeInt(time);
183
184   return (int)(time.QuadPart/SECONDS_TO_FILETIME)/SECONDS_PER_DAY;
185 }
186
187 int CDateTimeSpan::GetHours() const
188 {
189   ULARGE_INTEGER time;
190   ToULargeInt(time);
191
192   return (int)((time.QuadPart/SECONDS_TO_FILETIME)%SECONDS_PER_DAY)/SECONDS_PER_HOUR;
193 }
194
195 int CDateTimeSpan::GetMinutes() const
196 {
197   ULARGE_INTEGER time;
198   ToULargeInt(time);
199
200   return (int)((time.QuadPart/SECONDS_TO_FILETIME%SECONDS_PER_DAY)%SECONDS_PER_HOUR)/SECONDS_PER_MINUTE;
201 }
202
203 int CDateTimeSpan::GetSeconds() const
204 {
205   ULARGE_INTEGER time;
206   ToULargeInt(time);
207
208   return (int)(((time.QuadPart/SECONDS_TO_FILETIME%SECONDS_PER_DAY)%SECONDS_PER_HOUR)%SECONDS_PER_MINUTE)%SECONDS_PER_MINUTE;
209 }
210
211 void CDateTimeSpan::SetFromPeriod(const CStdString &period)
212 {
213   long days = atoi(period.c_str());
214   // find the first non-space and non-number
215   int pos = period.find_first_not_of("0123456789 ", 0);
216   if (pos >= 0)
217   {
218     CStdString units = period.Mid(pos, 3);
219     if (units.CompareNoCase("wee") == 0)
220       days *= 7;
221     else if (units.CompareNoCase("mon") == 0)
222       days *= 31;
223   }
224
225   SetDateTimeSpan(days, 0, 0, 0);
226 }
227
228 /////////////////////////////////////////////////
229 //
230 // CDateTime
231 //
232
233 CDateTime::CDateTime()
234 {
235   Reset();
236 }
237
238 CDateTime::CDateTime(const SYSTEMTIME &time)
239 {
240   // we store internally as a FILETIME
241   m_state = ToFileTime(time, m_time) ? valid : invalid;
242 }
243
244 CDateTime::CDateTime(const FILETIME &time)
245 {
246   m_time=time;
247   SetValid(true);
248 }
249
250 CDateTime::CDateTime(const CDateTime& time)
251 {
252   m_time=time.m_time;
253   m_state=time.m_state;
254 }
255
256 CDateTime::CDateTime(const time_t& time)
257 {
258   m_state = ToFileTime(time, m_time) ? valid : invalid;
259 }
260
261 CDateTime::CDateTime(const tm& time)
262 {
263   m_state = ToFileTime(time, m_time) ? valid : invalid;
264 }
265
266 CDateTime::CDateTime(int year, int month, int day, int hour, int minute, int second)
267 {
268   SetDateTime(year, month, day, hour, minute, second);
269 }
270
271 CDateTime CDateTime::GetCurrentDateTime()
272 {
273   // get the current time
274   SYSTEMTIME time;
275   GetLocalTime(&time);
276
277   return CDateTime(time);
278 }
279
280 CDateTime CDateTime::GetUTCDateTime()
281 {
282   TIME_ZONE_INFORMATION tz;
283
284   CDateTime time(GetCurrentDateTime());
285   switch(GetTimeZoneInformation(&tz))
286   {
287     case TIME_ZONE_ID_DAYLIGHT:
288         time += CDateTimeSpan(0, 0, tz.Bias + tz.DaylightBias, 0);
289         break;
290     case TIME_ZONE_ID_STANDARD:
291         time += CDateTimeSpan(0, 0, tz.Bias + tz.StandardBias, 0);
292         break;
293     case TIME_ZONE_ID_UNKNOWN:
294         time += CDateTimeSpan(0, 0, tz.Bias, 0);
295         break;
296   }
297
298   return time;
299 }
300
301 const CDateTime& CDateTime::operator =(const SYSTEMTIME& right)
302 {
303   m_state = ToFileTime(right, m_time) ? valid : invalid;
304
305   return *this;
306 }
307
308 const CDateTime& CDateTime::operator =(const FILETIME& right)
309 {
310   m_time=right;
311   SetValid(true);
312
313   return *this;
314 }
315
316 const CDateTime& CDateTime::operator =(const time_t& right)
317 {
318   m_state = ToFileTime(right, m_time) ? valid : invalid;
319
320   return *this;
321 }
322
323 const CDateTime& CDateTime::operator =(const tm& right)
324 {
325   m_state = ToFileTime(right, m_time) ? valid : invalid;
326
327   return *this;
328 }
329
330 bool CDateTime::operator >(const CDateTime& right) const
331 {
332   return operator >(right.m_time);
333 }
334
335 bool CDateTime::operator >=(const CDateTime& right) const
336 {
337   return operator >(right) || operator ==(right);
338 }
339
340 bool CDateTime::operator <(const CDateTime& right) const
341 {
342   return operator <(right.m_time);
343 }
344
345 bool CDateTime::operator <=(const CDateTime& right) const
346 {
347   return operator <(right) || operator ==(right);
348 }
349
350 bool CDateTime::operator ==(const CDateTime& right) const
351 {
352   return operator ==(right.m_time);
353 }
354
355 bool CDateTime::operator !=(const CDateTime& right) const
356 {
357   return !operator ==(right);
358 }
359
360 bool CDateTime::operator >(const FILETIME& right) const
361 {
362   return CompareFileTime(&m_time, &right)>0;
363 }
364
365 bool CDateTime::operator >=(const FILETIME& right) const
366 {
367   return operator >(right) || operator ==(right);
368 }
369
370 bool CDateTime::operator <(const FILETIME& right) const
371 {
372   return CompareFileTime(&m_time, &right)<0;
373 }
374
375 bool CDateTime::operator <=(const FILETIME& right) const
376 {
377   return operator <(right) || operator ==(right);
378 }
379
380 bool CDateTime::operator ==(const FILETIME& right) const
381 {
382   return CompareFileTime(&m_time, &right)==0;
383 }
384
385 bool CDateTime::operator !=(const FILETIME& right) const
386 {
387   return !operator ==(right);
388 }
389
390 bool CDateTime::operator >(const SYSTEMTIME& right) const
391 {
392   FILETIME time;
393   ToFileTime(right, time);
394
395   return operator >(time);
396 }
397
398 bool CDateTime::operator >=(const SYSTEMTIME& right) const
399 {
400   return operator >(right) || operator ==(right);
401 }
402
403 bool CDateTime::operator <(const SYSTEMTIME& right) const
404 {
405   FILETIME time;
406   ToFileTime(right, time);
407
408   return operator <(time);
409 }
410
411 bool CDateTime::operator <=(const SYSTEMTIME& right) const
412 {
413   return operator <(right) || operator ==(right);
414 }
415
416 bool CDateTime::operator ==(const SYSTEMTIME& right) const
417 {
418   FILETIME time;
419   ToFileTime(right, time);
420
421   return operator ==(time);
422 }
423
424 bool CDateTime::operator !=(const SYSTEMTIME& right) const
425 {
426   return !operator ==(right);
427 }
428
429 bool CDateTime::operator >(const time_t& right) const
430 {
431   FILETIME time;
432   ToFileTime(right, time);
433
434   return operator >(time);
435 }
436
437 bool CDateTime::operator >=(const time_t& right) const
438 {
439   return operator >(right) || operator ==(right);
440 }
441
442 bool CDateTime::operator <(const time_t& right) const
443 {
444   FILETIME time;
445   ToFileTime(right, time);
446
447   return operator <(time);
448 }
449
450 bool CDateTime::operator <=(const time_t& right) const
451 {
452   return operator <(right) || operator ==(right);
453 }
454
455 bool CDateTime::operator ==(const time_t& right) const
456 {
457   FILETIME time;
458   ToFileTime(right, time);
459
460   return operator ==(time);
461 }
462
463 bool CDateTime::operator !=(const time_t& right) const
464 {
465   return !operator ==(right);
466 }
467
468 bool CDateTime::operator >(const tm& right) const
469 {
470   FILETIME time;
471   ToFileTime(right, time);
472
473   return operator >(time);
474 }
475
476 bool CDateTime::operator >=(const tm& right) const
477 {
478   return operator >(right) || operator ==(right);
479 }
480
481 bool CDateTime::operator <(const tm& right) const
482 {
483   FILETIME time;
484   ToFileTime(right, time);
485
486   return operator <(time);
487 }
488
489 bool CDateTime::operator <=(const tm& right) const
490 {
491   return operator <(right) || operator ==(right);
492 }
493
494 bool CDateTime::operator ==(const tm& right) const
495 {
496   FILETIME time;
497   ToFileTime(right, time);
498
499   return operator ==(time);
500 }
501
502 bool CDateTime::operator !=(const tm& right) const
503 {
504   return !operator ==(right);
505 }
506
507 CDateTime CDateTime::operator +(const CDateTimeSpan& right) const
508 {
509   CDateTime left(*this);
510
511   ULARGE_INTEGER timeLeft;
512   left.ToULargeInt(timeLeft);
513
514   ULARGE_INTEGER timeRight;
515   right.ToULargeInt(timeRight);
516
517   timeLeft.QuadPart+=timeRight.QuadPart;
518
519   left.FromULargeInt(timeLeft);
520
521   return left;
522 }
523
524 CDateTime CDateTime::operator -(const CDateTimeSpan& right) const
525 {
526   CDateTime left(*this);
527
528   ULARGE_INTEGER timeLeft;
529   left.ToULargeInt(timeLeft);
530
531   ULARGE_INTEGER timeRight;
532   right.ToULargeInt(timeRight);
533
534   timeLeft.QuadPart-=timeRight.QuadPart;
535
536   left.FromULargeInt(timeLeft);
537
538   return left;
539 }
540
541 const CDateTime& CDateTime::operator +=(const CDateTimeSpan& right)
542 {
543   ULARGE_INTEGER timeThis;
544   ToULargeInt(timeThis);
545
546   ULARGE_INTEGER timeRight;
547   right.ToULargeInt(timeRight);
548
549   timeThis.QuadPart+=timeRight.QuadPart;
550
551   FromULargeInt(timeThis);
552
553   return *this;
554 }
555
556 const CDateTime& CDateTime::operator -=(const CDateTimeSpan& right)
557 {
558   ULARGE_INTEGER timeThis;
559   ToULargeInt(timeThis);
560
561   ULARGE_INTEGER timeRight;
562   right.ToULargeInt(timeRight);
563
564   timeThis.QuadPart-=timeRight.QuadPart;
565
566   FromULargeInt(timeThis);
567
568   return *this;
569 }
570
571 CDateTimeSpan CDateTime::operator -(const CDateTime& right) const
572 {
573   CDateTimeSpan left;
574
575   ULARGE_INTEGER timeLeft;
576   left.ToULargeInt(timeLeft);
577
578   ULARGE_INTEGER timeThis;
579   ToULargeInt(timeThis);
580
581   ULARGE_INTEGER timeRight;
582   right.ToULargeInt(timeRight);
583
584   timeLeft.QuadPart=timeThis.QuadPart-timeRight.QuadPart;
585
586   left.FromULargeInt(timeLeft);
587
588   return left;
589 }
590
591 CDateTime::operator FILETIME() const
592 {
593   return m_time;
594 }
595
596 void CDateTime::Archive(CArchive& ar)
597 {
598   if (ar.IsStoring())
599   {
600     ar<<(int)m_state;
601     if (m_state==valid)
602     {
603       SYSTEMTIME st;
604       GetAsSystemTime(st);
605       ar<<st;
606     }
607   }
608   else
609   {
610     Reset();
611     int state;
612     ar >> (int &)state;
613     m_state = CDateTime::STATE(state);
614     if (m_state==valid)
615     {
616       SYSTEMTIME st;
617       ar>>st;
618       ToFileTime(st, m_time);
619     }
620   }
621 }
622
623 void CDateTime::Reset()
624 {
625   SetDateTime(1601, 1, 1, 0, 0, 0);
626   SetValid(false);
627 }
628
629 void CDateTime::SetValid(bool yesNo)
630 {
631   m_state=yesNo ? valid : invalid;
632 }
633
634 bool CDateTime::IsValid() const
635 {
636   return m_state==valid;
637 }
638
639 bool CDateTime::ToFileTime(const SYSTEMTIME& time, FILETIME& fileTime) const
640 {
641   return SystemTimeToFileTime(&time, &fileTime)==TRUE;
642 }
643
644 bool CDateTime::ToFileTime(const time_t& time, FILETIME& fileTime) const
645 {
646   LONGLONG ll = Int32x32To64(time, 10000000)+0x19DB1DED53E8000LL;
647
648   fileTime.dwLowDateTime  = (DWORD)(ll & 0xFFFFFFFF);
649   fileTime.dwHighDateTime = (DWORD)(ll >> 32);
650
651   return true;
652 }
653
654 bool CDateTime::ToFileTime(const tm& time, FILETIME& fileTime) const
655 {
656   SYSTEMTIME st;
657   ZeroMemory(&st, sizeof(SYSTEMTIME));
658
659   st.wYear=time.tm_year+1900;
660   st.wMonth=time.tm_mon+1;
661   st.wDayOfWeek=time.tm_wday;
662   st.wDay=time.tm_mday;
663   st.wHour=time.tm_hour;
664   st.wMinute=time.tm_min;
665   st.wSecond=time.tm_sec;
666
667   return SystemTimeToFileTime(&st, &fileTime)==TRUE;
668 }
669
670 void CDateTime::ToULargeInt(ULARGE_INTEGER& time) const
671 {
672   time.u.HighPart=m_time.dwHighDateTime;
673   time.u.LowPart=m_time.dwLowDateTime;
674 }
675
676 void CDateTime::FromULargeInt(const ULARGE_INTEGER& time)
677 {
678   m_time.dwHighDateTime=time.u.HighPart;
679   m_time.dwLowDateTime=time.u.LowPart;
680 }
681
682 void CDateTime::SetFromDateString(const CStdString &date)
683 {
684   if (date.IsEmpty())
685   {
686     SetValid(false);
687     return;
688   }
689
690   const char* months[] = {"january","february","march","april","may","june","july","august","september","october","november","december",NULL};
691   int j=0;
692   int iDayPos = date.Find("day");
693   int iPos = date.Find(" ");
694   if (iDayPos < iPos && iDayPos > -1)
695   {
696     iDayPos = iPos+1;
697     iPos = date.Find(" ",iPos+1);
698   }
699   else
700     iDayPos = 0;
701
702   CStdString strMonth = date.Mid(iDayPos,iPos-iDayPos);
703   if (strMonth.IsEmpty()) // assume dbdate format
704   {
705     SetFromDBDate(date);
706     return;
707   }
708
709   int iPos2 = date.Find(",");
710   CStdString strDay = date.Mid(iPos,iPos2-iPos);
711   CStdString strYear = date.Mid(date.Find(" ",iPos2)+1);
712   while (months[j] && stricmp(strMonth.c_str(),months[j]) != 0)
713     j++;
714   if (!months[j])
715     return;
716
717   SetDateTime(atol(strYear.c_str()),j+1,atol(strDay.c_str()),0,0,0);
718 }
719
720 int CDateTime::GetDay() const
721 {
722   SYSTEMTIME st;
723   GetAsSystemTime(st);
724
725   return st.wDay;
726 }
727
728 int CDateTime::GetMonth() const
729 {
730   SYSTEMTIME st;
731   GetAsSystemTime(st);
732
733   return st.wMonth;
734 }
735
736 int CDateTime::GetYear() const
737 {
738   SYSTEMTIME st;
739   GetAsSystemTime(st);
740
741   return st.wYear;
742 }
743
744 int CDateTime::GetHour() const
745 {
746   SYSTEMTIME st;
747   GetAsSystemTime(st);
748
749   return st.wHour;
750 }
751
752 int CDateTime::GetMinute() const
753 {
754   SYSTEMTIME st;
755   GetAsSystemTime(st);
756
757   return st.wMinute;
758 }
759
760 int CDateTime::GetSecond() const
761 {
762   SYSTEMTIME st;
763   GetAsSystemTime(st);
764
765   return st.wSecond;
766 }
767
768 int CDateTime::GetDayOfWeek() const
769 {
770   SYSTEMTIME st;
771   GetAsSystemTime(st);
772
773   return st.wDayOfWeek;
774 }
775
776 int CDateTime::GetMinuteOfDay() const
777 {
778   SYSTEMTIME st;
779   GetAsSystemTime(st);
780   return st.wHour*60+st.wMinute;
781 }
782
783 void CDateTime::SetDateTime(int year, int month, int day, int hour, int minute, int second)
784 {
785   SYSTEMTIME st;
786   ZeroMemory(&st, sizeof(SYSTEMTIME));
787
788   st.wYear=year;
789   st.wMonth=month;
790   st.wDay=day;
791   st.wHour=hour;
792   st.wMinute=minute;
793   st.wSecond=second;
794
795   m_state = ToFileTime(st, m_time) ? valid : invalid;
796 }
797
798 void CDateTime::SetDate(int year, int month, int day)
799 {
800   SetDateTime(year, month, day, 0, 0, 0);
801 }
802
803 void CDateTime::SetTime(int hour, int minute, int second)
804 {
805   // 01.01.1601 00:00:00 is 0 as filetime
806   SetDateTime(1601, 1, 1, hour, minute, second);
807 }
808
809 void CDateTime::GetAsSystemTime(SYSTEMTIME& time) const
810 {
811   FileTimeToSystemTime(&m_time, &time);
812 }
813
814 #define UNIX_BASE_TIME 116444736000000000LL /* nanoseconds since epoch */
815 void CDateTime::GetAsTime(time_t& time) const
816 {
817   LONGLONG ll;
818   ll = ((LONGLONG)m_time.dwHighDateTime << 32) + m_time.dwLowDateTime;
819   time=(time_t)((ll - UNIX_BASE_TIME) / 10000000);
820 }
821
822 void CDateTime::GetAsTm(tm& time) const
823 {
824   SYSTEMTIME st;
825   GetAsSystemTime(st);
826
827   time.tm_year=st.wYear-1900;
828   time.tm_mon=st.wMonth-1;
829   time.tm_wday=st.wDayOfWeek;
830   time.tm_mday=st.wDay;
831   time.tm_hour=st.wHour;
832   time.tm_min=st.wMinute;
833   time.tm_sec=st.wSecond;
834
835   mktime(&time);
836 }
837
838 void CDateTime::GetAsTimeStamp(FILETIME& time) const
839 {
840   ::LocalFileTimeToFileTime(&m_time, &time);
841 }
842
843 CStdString CDateTime::GetAsDBDate() const
844 {
845   SYSTEMTIME st;
846   GetAsSystemTime(st);
847
848   CStdString date;
849   date.Format("%04i-%02i-%02i", st.wYear, st.wMonth, st.wDay);
850
851   return date;
852 }
853
854 CStdString CDateTime::GetAsDBDateTime() const
855 {
856   SYSTEMTIME st;
857   GetAsSystemTime(st);
858
859   CStdString date;
860   date.Format("%04i-%02i-%02i %02i:%02i:%02i", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
861
862   return date;
863 }
864
865 void CDateTime::SetFromW3CDate(const CStdString &dateTime)
866 {
867   CStdString date, time, zone;
868
869   int posT = dateTime.Find("T");
870   if(posT >= 0)
871   {
872     date = dateTime.Left(posT);
873     CStdString::size_type posZ = dateTime.find_first_of("+-Z", posT);
874     if(posZ == CStdString::npos)
875       time = dateTime.Mid(posT+1);
876     else
877     {
878       time = dateTime.Mid(posT+1, posZ-posT-1);
879       zone = dateTime.Mid(posZ);
880     }
881   }
882   else
883     date = dateTime;
884
885   int year = 0, month = 1, day = 1, hour = 0, min = 0, sec = 0;
886
887   if (date.size() >= 4)
888     year  = atoi(date.Mid(0,4).c_str());
889
890   if (date.size() >= 10)
891   {
892     month = atoi(date.Mid(5,2).c_str());
893     day   = atoi(date.Mid(8,2).c_str());
894   }
895
896   if (time.length() >= 5)
897   {
898     hour = atoi(time.Mid(0,2).c_str());
899     min  = atoi(time.Mid(3,2).c_str());
900   }
901
902   if (time.length() >= 8)
903     sec  = atoi(time.Mid(6,2).c_str());
904
905   SetDateTime(year, month, day, hour, min, sec);
906 }
907
908 void CDateTime::SetFromDBDateTime(const CStdString &dateTime)
909 {
910   // assumes format YYYY-MM-DD HH:MM:SS
911   if (dateTime.size() == 19)
912   {
913     int year  = atoi(dateTime.Mid(0,4).c_str());
914     int month = atoi(dateTime.Mid(5,2).c_str());
915     int day   = atoi(dateTime.Mid(8,2).c_str());
916     int hour  = atoi(dateTime.Mid(11,2).c_str());
917     int min   = atoi(dateTime.Mid(14,2).c_str());
918     int sec   = atoi(dateTime.Mid(17,2).c_str());
919     SetDateTime(year, month, day, hour, min, sec);
920   }
921 }
922
923 void CDateTime::SetFromDBDate(const CStdString &date)
924 {
925   // assumes format:
926   // YYYY-MM-DD or DD-MM-YYYY
927   int year = 0, month = 0, day = 0;
928   if (date.size() > 2 && (date[2] == '-' || date[2] == '.'))
929   {
930     day = atoi(date.Mid(0,2).c_str());
931     month = atoi(date.Mid(3,2).c_str());
932     year = atoi(date.Mid(6,4).c_str());
933   }
934   else
935   {
936     year = atoi(date.Mid(0,4).c_str());
937     month = atoi(date.Mid(5,2).c_str());
938     day = atoi(date.Mid(8,2).c_str());
939   }
940   SetDate(year, month, day);
941 }
942
943 void CDateTime::SetFromDBTime(const CStdString &time)
944 {
945   // assumes format:
946   // HH:MM:SS
947   int hour, minute, second;
948
949   hour   = atoi(time.Mid(0,2).c_str());
950   minute = atoi(time.Mid(3,2).c_str());
951   second = atoi(time.Mid(6,2).c_str());
952
953   SetTime(hour, minute, second);
954 }
955
956 CStdString CDateTime::GetAsLocalizedTime(const CStdString &format, bool withSeconds) const
957 {
958   CStdString strOut;
959   const CStdString& strFormat = format.IsEmpty() ? g_langInfo.GetTimeFormat() : format;
960
961   SYSTEMTIME dateTime;
962   GetAsSystemTime(dateTime);
963
964   // Prefetch meridiem symbol
965   const CStdString& strMeridiem=g_langInfo.GetMeridiemSymbol(dateTime.wHour > 11 ? CLangInfo::MERIDIEM_SYMBOL_PM : CLangInfo::MERIDIEM_SYMBOL_AM);
966
967   int length=strFormat.GetLength();
968   for (int i=0; i<length; ++i)
969   {
970     char c=strFormat[i];
971     if (c=='\'')
972     {
973       // To be able to display a "'" in the string,
974       // find the last "'" that doesn't follow a "'"
975       int pos=i+1;
976       while(((pos=strFormat.Find(c,pos+1))>-1 && pos<strFormat.GetLength()) && strFormat[pos+1]=='\'') {}
977
978       CStdString strPart;
979       if (pos>-1)
980       {
981         // Extract string between ' '
982         strPart=strFormat.Mid(i+1, pos-i-1);
983         i=pos;
984       }
985       else
986       {
987         strPart=strFormat.Mid(i+1, length-i-1);
988         i=length;
989       }
990
991       strPart.Replace("''", "'");
992
993       strOut+=strPart;
994     }
995     else if (c=='h' || c=='H') // parse hour (H="24 hour clock")
996     {
997       int partLength=0;
998
999       int pos=strFormat.find_first_not_of(c,i+1);
1000       if (pos>-1)
1001       {
1002         // Get length of the hour mask, eg. HH
1003         partLength=pos-i;
1004         i=pos-1;
1005       }
1006       else
1007       {
1008         // mask ends at the end of the string, extract it
1009         partLength=length-i;
1010         i=length;
1011       }
1012
1013       int hour=dateTime.wHour;
1014       if (c=='h')
1015       { // recalc to 12 hour clock
1016         if (hour > 11)
1017           hour -= (12 * (hour > 12));
1018         else
1019           hour += (12 * (hour < 1));
1020       }
1021
1022       // Format hour string with the length of the mask
1023       CStdString str;
1024       if (partLength==1)
1025         str.Format("%d", hour);
1026       else
1027         str.Format("%02d", hour);
1028
1029       strOut+=str;
1030     }
1031     else if (c=='m') // parse minutes
1032     {
1033       int partLength=0;
1034
1035       int pos=strFormat.find_first_not_of(c,i+1);
1036       if (pos>-1)
1037       {
1038         // Get length of the minute mask, eg. mm
1039         partLength=pos-i;
1040         i=pos-1;
1041       }
1042       else
1043       {
1044         // mask ends at the end of the string, extract it
1045         partLength=length-i;
1046         i=length;
1047       }
1048
1049       // Format minute string with the length of the mask
1050       CStdString str;
1051       if (partLength==1)
1052         str.Format("%d", dateTime.wMinute);
1053       else
1054         str.Format("%02d", dateTime.wMinute);
1055
1056       strOut+=str;
1057     }
1058     else if (c=='s') // parse seconds
1059     {
1060       int partLength=0;
1061
1062       int pos=strFormat.find_first_not_of(c,i+1);
1063       if (pos>-1)
1064       {
1065         // Get length of the seconds mask, eg. ss
1066         partLength=pos-i;
1067         i=pos-1;
1068       }
1069       else
1070       {
1071         // mask ends at the end of the string, extract it
1072         partLength=length-i;
1073         i=length;
1074       }
1075
1076       if (withSeconds)
1077       {
1078         // Format seconds string with the length of the mask
1079         CStdString str;
1080         if (partLength==1)
1081           str.Format("%d", dateTime.wSecond);
1082         else
1083           str.Format("%02d", dateTime.wSecond);
1084
1085         strOut+=str;
1086       }
1087       else
1088         strOut.Delete(strOut.GetLength()-1,1);
1089     }
1090     else if (c=='x') // add meridiem symbol
1091     {
1092       int partLength=0;
1093
1094       int pos=strFormat.find_first_not_of(c,i+1);
1095       if (pos>-1)
1096       {
1097         // Get length of the meridiem mask
1098         partLength=pos-i;
1099         i=pos-1;
1100       }
1101       else
1102       {
1103         // mask ends at the end of the string, extract it
1104         partLength=length-i;
1105         i=length;
1106       }
1107
1108       strOut+=strMeridiem;
1109     }
1110     else // everything else pass to output
1111       strOut+=c;
1112   }
1113
1114   return strOut;
1115 }
1116
1117 CStdString CDateTime::GetAsLocalizedDate(bool longDate/*=false*/, bool withShortNames/*=true*/) const
1118 {
1119   CStdString strOut;
1120
1121   const CStdString& strFormat=g_langInfo.GetDateFormat(longDate);
1122
1123   SYSTEMTIME dateTime;
1124   GetAsSystemTime(dateTime);
1125
1126   int length=strFormat.GetLength();
1127
1128   for (int i=0; i<length; ++i)
1129   {
1130     char c=strFormat[i];
1131     if (c=='\'')
1132     {
1133       // To be able to display a "'" in the string,
1134       // find the last "'" that doesn't follow a "'"
1135       int pos=i+1;
1136       while(((pos=strFormat.Find(c,pos+1))>-1 && pos<strFormat.GetLength()) && strFormat[pos+1]=='\'') {}
1137
1138       CStdString strPart;
1139       if (pos>-1)
1140       {
1141         // Extract string between ' '
1142         strPart=strFormat.Mid(i+1, pos-i-1);
1143         i=pos;
1144       }
1145       else
1146       {
1147         strPart=strFormat.Mid(i+1, length-i-1);
1148         i=length;
1149       }
1150       strPart.Replace("''", "'");
1151       strOut+=strPart;
1152     }
1153     else if (c=='D') // parse days
1154     {
1155       int partLength=0;
1156
1157       int pos=strFormat.find_first_not_of(c,i+1);
1158       if (pos>-1)
1159       {
1160         // Get length of the day mask, eg. DDDD
1161         partLength=pos-i;
1162         i=pos-1;
1163       }
1164       else
1165       {
1166         // mask ends at the end of the string, extract it
1167         partLength=length-i;
1168         i=length;
1169       }
1170
1171       // Format string with the length of the mask
1172       CStdString str;
1173       if (partLength==1) // single-digit number
1174         str.Format("%d", dateTime.wDay);
1175       else if (partLength==2) // two-digit number
1176         str.Format("%02d", dateTime.wDay);
1177       else // Day of week string
1178       {
1179         int wday = dateTime.wDayOfWeek;
1180         if (wday < 1 || wday > 7) wday = 7;
1181         str = g_localizeStrings.Get((withShortNames ? 40 : 10) + wday);
1182       }
1183       strOut+=str;
1184     }
1185     else if (c=='M') // parse month
1186     {
1187       int partLength=0;
1188
1189       int pos=strFormat.find_first_not_of(c,i+1);
1190       if (pos>-1)
1191       {
1192         // Get length of the month mask, eg. MMMM
1193         partLength=pos-i;
1194         i=pos-1;
1195       }
1196       else
1197       {
1198         // mask ends at the end of the string, extract it
1199         partLength=length-i;
1200         i=length;
1201       }
1202
1203       // Format string with the length of the mask
1204       CStdString str;
1205       if (partLength==1) // single-digit number
1206         str.Format("%d", dateTime.wMonth);
1207       else if (partLength==2) // two-digit number
1208         str.Format("%02d", dateTime.wMonth);
1209       else // Month string
1210       {
1211         int wmonth = dateTime.wMonth;
1212         if (wmonth < 1 || wmonth > 12) wmonth = 12;
1213         str = g_localizeStrings.Get((withShortNames ? 50 : 20) + wmonth);
1214       }
1215       strOut+=str;
1216     }
1217     else if (c=='Y') // parse year
1218     {
1219       int partLength=0;
1220
1221       int pos=strFormat.find_first_not_of(c,i+1);
1222       if (pos>-1)
1223       {
1224         // Get length of the year mask, eg. YYYY
1225         partLength=pos-i;
1226         i=pos-1;
1227       }
1228       else
1229       {
1230         // mask ends at the end of the string, extract it
1231         partLength=length-i;
1232         i=length;
1233       }
1234
1235       // Format string with the length of the mask
1236       CStdString str;
1237       str.Format("%d", dateTime.wYear); // four-digit number
1238       if (partLength<=2)
1239         str.Delete(0, 2); // two-digit number
1240
1241       strOut+=str;
1242     }
1243     else // everything else pass to output
1244       strOut+=c;
1245   }
1246
1247   return strOut;
1248 }
1249
1250 CStdString CDateTime::GetAsLocalizedDateTime(bool longDate/*=false*/, bool withSeconds/*=true*/) const
1251 {
1252   return GetAsLocalizedDate(longDate)+" "+GetAsLocalizedTime("", withSeconds);
1253 }
1254
1255 CDateTime CDateTime::GetAsUTCDateTime() const
1256 {
1257   TIME_ZONE_INFORMATION tz;
1258
1259   CDateTime time(m_time);
1260   switch(GetTimeZoneInformation(&tz))
1261   {
1262     case TIME_ZONE_ID_DAYLIGHT:
1263         time += CDateTimeSpan(0, 0, tz.Bias + tz.DaylightBias, 0);
1264         break;
1265     case TIME_ZONE_ID_STANDARD:
1266         time += CDateTimeSpan(0, 0, tz.Bias + tz.StandardBias, 0);
1267         break;
1268     case TIME_ZONE_ID_UNKNOWN:
1269         time += CDateTimeSpan(0, 0, tz.Bias, 0);
1270         break;
1271   }
1272
1273   return time;
1274 }
1275
1276 static const char *DAY_NAMES[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
1277 static const char *MONTH_NAMES[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
1278
1279 CStdString CDateTime::GetAsRFC1123DateTime() const
1280 {
1281   CDateTime time(GetAsUTCDateTime()); 
1282   CStdString result;
1283   result.Format("%s, %02i %s %04i %02i:%02i:%02i GMT", DAY_NAMES[time.GetDayOfWeek()], time.GetDay(), MONTH_NAMES[time.GetMonth()-1], time.GetYear(), time.GetHour(), time.GetMinute(), time.GetSecond());
1284   return result;
1285 }