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