[cstdstring] demise Format, replacing with StringUtils::Format
[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 #include "utils/StringUtils.h"
26
27 #define SECONDS_PER_DAY 86400UL
28 #define SECONDS_PER_HOUR 3600UL
29 #define SECONDS_PER_MINUTE 60UL
30 #define SECONDS_TO_FILETIME 10000000UL
31
32 static const char *DAY_NAMES[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
33 static const char *MONTH_NAMES[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
34
35 /////////////////////////////////////////////////
36 //
37 // CDateTimeSpan
38 //
39
40 CDateTimeSpan::CDateTimeSpan()
41 {
42   m_timeSpan.dwHighDateTime=0;
43   m_timeSpan.dwLowDateTime=0;
44 }
45
46 CDateTimeSpan::CDateTimeSpan(const CDateTimeSpan& span)
47 {
48   m_timeSpan.dwHighDateTime=span.m_timeSpan.dwHighDateTime;
49   m_timeSpan.dwLowDateTime=span.m_timeSpan.dwLowDateTime;
50 }
51
52 CDateTimeSpan::CDateTimeSpan(int day, int hour, int minute, int second)
53 {
54   SetDateTimeSpan(day, hour, minute, second);
55 }
56
57 bool CDateTimeSpan::operator >(const CDateTimeSpan& right) const
58 {
59   return CompareFileTime(&m_timeSpan, &right.m_timeSpan)>0;
60 }
61
62 bool CDateTimeSpan::operator >=(const CDateTimeSpan& right) const
63 {
64   return operator >(right) || operator ==(right);
65 }
66
67 bool CDateTimeSpan::operator <(const CDateTimeSpan& right) const
68 {
69   return CompareFileTime(&m_timeSpan, &right.m_timeSpan)<0;
70 }
71
72 bool CDateTimeSpan::operator <=(const CDateTimeSpan& right) const
73 {
74   return operator <(right) || operator ==(right);
75 }
76
77 bool CDateTimeSpan::operator ==(const CDateTimeSpan& right) const
78 {
79   return CompareFileTime(&m_timeSpan, &right.m_timeSpan)==0;
80 }
81
82 bool CDateTimeSpan::operator !=(const CDateTimeSpan& right) const
83 {
84   return !operator ==(right);
85 }
86
87 CDateTimeSpan CDateTimeSpan::operator +(const CDateTimeSpan& right) const
88 {
89   CDateTimeSpan left(*this);
90
91   ULARGE_INTEGER timeLeft;
92   left.ToULargeInt(timeLeft);
93
94   ULARGE_INTEGER timeRight;
95   right.ToULargeInt(timeRight);
96
97   timeLeft.QuadPart+=timeRight.QuadPart;
98
99   left.FromULargeInt(timeLeft);
100
101   return left;
102 }
103
104 CDateTimeSpan CDateTimeSpan::operator -(const CDateTimeSpan& right) const
105 {
106   CDateTimeSpan left(*this);
107
108   ULARGE_INTEGER timeLeft;
109   left.ToULargeInt(timeLeft);
110
111   ULARGE_INTEGER timeRight;
112   right.ToULargeInt(timeRight);
113
114   timeLeft.QuadPart-=timeRight.QuadPart;
115
116   left.FromULargeInt(timeLeft);
117
118   return left;
119 }
120
121 const CDateTimeSpan& CDateTimeSpan::operator +=(const CDateTimeSpan& right)
122 {
123   ULARGE_INTEGER timeThis;
124   ToULargeInt(timeThis);
125
126   ULARGE_INTEGER timeRight;
127   right.ToULargeInt(timeRight);
128
129   timeThis.QuadPart+=timeRight.QuadPart;
130
131   FromULargeInt(timeThis);
132
133   return *this;
134 }
135
136 const CDateTimeSpan& CDateTimeSpan::operator -=(const CDateTimeSpan& right)
137 {
138   ULARGE_INTEGER timeThis;
139   ToULargeInt(timeThis);
140
141   ULARGE_INTEGER timeRight;
142   right.ToULargeInt(timeRight);
143
144   timeThis.QuadPart-=timeRight.QuadPart;
145
146   FromULargeInt(timeThis);
147
148   return *this;
149 }
150
151 void CDateTimeSpan::ToULargeInt(ULARGE_INTEGER& time) const
152 {
153   time.u.HighPart=m_timeSpan.dwHighDateTime;
154   time.u.LowPart=m_timeSpan.dwLowDateTime;
155 }
156
157 void CDateTimeSpan::FromULargeInt(const ULARGE_INTEGER& time)
158 {
159   m_timeSpan.dwHighDateTime=time.u.HighPart;
160   m_timeSpan.dwLowDateTime=time.u.LowPart;
161 }
162
163 void CDateTimeSpan::SetDateTimeSpan(int day, int hour, int minute, int second)
164 {
165   ULARGE_INTEGER time;
166   ToULargeInt(time);
167
168   time.QuadPart=(LONGLONG)day*SECONDS_PER_DAY*SECONDS_TO_FILETIME;
169   time.QuadPart+=(LONGLONG)hour*SECONDS_PER_HOUR*SECONDS_TO_FILETIME;
170   time.QuadPart+=(LONGLONG)minute*SECONDS_PER_MINUTE*SECONDS_TO_FILETIME;
171   time.QuadPart+=(LONGLONG)second*SECONDS_TO_FILETIME;
172
173   FromULargeInt(time);
174 }
175
176 void CDateTimeSpan::SetFromTimeString(const CStdString& time) // hh:mm
177 {
178   int hour    = atoi(time.Mid(0,2).c_str());
179   int minutes = atoi(time.Mid(3,2).c_str());
180   SetDateTimeSpan(0,hour,minutes,0);
181 }
182
183 int CDateTimeSpan::GetDays() const
184 {
185   ULARGE_INTEGER time;
186   ToULargeInt(time);
187
188   return (int)(time.QuadPart/SECONDS_TO_FILETIME)/SECONDS_PER_DAY;
189 }
190
191 int CDateTimeSpan::GetHours() const
192 {
193   ULARGE_INTEGER time;
194   ToULargeInt(time);
195
196   return (int)((time.QuadPart/SECONDS_TO_FILETIME)%SECONDS_PER_DAY)/SECONDS_PER_HOUR;
197 }
198
199 int CDateTimeSpan::GetMinutes() const
200 {
201   ULARGE_INTEGER time;
202   ToULargeInt(time);
203
204   return (int)((time.QuadPart/SECONDS_TO_FILETIME%SECONDS_PER_DAY)%SECONDS_PER_HOUR)/SECONDS_PER_MINUTE;
205 }
206
207 int CDateTimeSpan::GetSeconds() const
208 {
209   ULARGE_INTEGER time;
210   ToULargeInt(time);
211
212   return (int)(((time.QuadPart/SECONDS_TO_FILETIME%SECONDS_PER_DAY)%SECONDS_PER_HOUR)%SECONDS_PER_MINUTE)%SECONDS_PER_MINUTE;
213 }
214
215 int CDateTimeSpan::GetSecondsTotal() const
216 {
217   ULARGE_INTEGER time;
218   ToULargeInt(time);
219   
220   return (int)(time.QuadPart/SECONDS_TO_FILETIME);
221 }
222
223 void CDateTimeSpan::SetFromPeriod(const CStdString &period)
224 {
225   long days = atoi(period.c_str());
226   // find the first non-space and non-number
227   int pos = period.find_first_not_of("0123456789 ", 0);
228   if (pos >= 0)
229   {
230     CStdString units = period.Mid(pos, 3);
231     if (units.CompareNoCase("wee") == 0)
232       days *= 7;
233     else if (units.CompareNoCase("mon") == 0)
234       days *= 31;
235   }
236
237   SetDateTimeSpan(days, 0, 0, 0);
238 }
239
240 /////////////////////////////////////////////////
241 //
242 // CDateTime
243 //
244
245 CDateTime::CDateTime()
246 {
247   Reset();
248 }
249
250 CDateTime::CDateTime(const SYSTEMTIME &time)
251 {
252   // we store internally as a FILETIME
253   m_state = ToFileTime(time, m_time) ? valid : invalid;
254 }
255
256 CDateTime::CDateTime(const FILETIME &time)
257 {
258   m_time=time;
259   SetValid(true);
260 }
261
262 CDateTime::CDateTime(const CDateTime& time)
263 {
264   m_time=time.m_time;
265   m_state=time.m_state;
266 }
267
268 CDateTime::CDateTime(const time_t& time)
269 {
270   m_state = ToFileTime(time, m_time) ? valid : invalid;
271 }
272
273 CDateTime::CDateTime(const tm& time)
274 {
275   m_state = ToFileTime(time, m_time) ? valid : invalid;
276 }
277
278 CDateTime::CDateTime(int year, int month, int day, int hour, int minute, int second)
279 {
280   SetDateTime(year, month, day, hour, minute, second);
281 }
282
283 CDateTime CDateTime::GetCurrentDateTime()
284 {
285   // get the current time
286   SYSTEMTIME time;
287   GetLocalTime(&time);
288
289   return CDateTime(time);
290 }
291
292 CDateTime CDateTime::GetUTCDateTime()
293 {
294   CDateTime time(GetCurrentDateTime());
295   time += GetTimezoneBias();
296   return time;
297 }
298
299 const CDateTime& CDateTime::operator =(const SYSTEMTIME& right)
300 {
301   m_state = ToFileTime(right, m_time) ? valid : invalid;
302
303   return *this;
304 }
305
306 const CDateTime& CDateTime::operator =(const FILETIME& right)
307 {
308   m_time=right;
309   SetValid(true);
310
311   return *this;
312 }
313
314 const CDateTime& CDateTime::operator =(const time_t& right)
315 {
316   m_state = ToFileTime(right, m_time) ? valid : invalid;
317
318   return *this;
319 }
320
321 const CDateTime& CDateTime::operator =(const tm& right)
322 {
323   m_state = ToFileTime(right, m_time) ? valid : invalid;
324
325   return *this;
326 }
327
328 bool CDateTime::operator >(const CDateTime& right) const
329 {
330   return operator >(right.m_time);
331 }
332
333 bool CDateTime::operator >=(const CDateTime& right) const
334 {
335   return operator >(right) || operator ==(right);
336 }
337
338 bool CDateTime::operator <(const CDateTime& right) const
339 {
340   return operator <(right.m_time);
341 }
342
343 bool CDateTime::operator <=(const CDateTime& right) const
344 {
345   return operator <(right) || operator ==(right);
346 }
347
348 bool CDateTime::operator ==(const CDateTime& right) const
349 {
350   return operator ==(right.m_time);
351 }
352
353 bool CDateTime::operator !=(const CDateTime& right) const
354 {
355   return !operator ==(right);
356 }
357
358 bool CDateTime::operator >(const FILETIME& right) const
359 {
360   return CompareFileTime(&m_time, &right)>0;
361 }
362
363 bool CDateTime::operator >=(const FILETIME& right) const
364 {
365   return operator >(right) || operator ==(right);
366 }
367
368 bool CDateTime::operator <(const FILETIME& right) const
369 {
370   return CompareFileTime(&m_time, &right)<0;
371 }
372
373 bool CDateTime::operator <=(const FILETIME& right) const
374 {
375   return operator <(right) || operator ==(right);
376 }
377
378 bool CDateTime::operator ==(const FILETIME& right) const
379 {
380   return CompareFileTime(&m_time, &right)==0;
381 }
382
383 bool CDateTime::operator !=(const FILETIME& right) const
384 {
385   return !operator ==(right);
386 }
387
388 bool CDateTime::operator >(const SYSTEMTIME& right) const
389 {
390   FILETIME time;
391   ToFileTime(right, time);
392
393   return operator >(time);
394 }
395
396 bool CDateTime::operator >=(const SYSTEMTIME& right) const
397 {
398   return operator >(right) || operator ==(right);
399 }
400
401 bool CDateTime::operator <(const SYSTEMTIME& right) const
402 {
403   FILETIME time;
404   ToFileTime(right, time);
405
406   return operator <(time);
407 }
408
409 bool CDateTime::operator <=(const SYSTEMTIME& right) const
410 {
411   return operator <(right) || operator ==(right);
412 }
413
414 bool CDateTime::operator ==(const SYSTEMTIME& right) const
415 {
416   FILETIME time;
417   ToFileTime(right, time);
418
419   return operator ==(time);
420 }
421
422 bool CDateTime::operator !=(const SYSTEMTIME& right) const
423 {
424   return !operator ==(right);
425 }
426
427 bool CDateTime::operator >(const time_t& right) const
428 {
429   FILETIME time;
430   ToFileTime(right, time);
431
432   return operator >(time);
433 }
434
435 bool CDateTime::operator >=(const time_t& right) const
436 {
437   return operator >(right) || operator ==(right);
438 }
439
440 bool CDateTime::operator <(const time_t& right) const
441 {
442   FILETIME time;
443   ToFileTime(right, time);
444
445   return operator <(time);
446 }
447
448 bool CDateTime::operator <=(const time_t& right) const
449 {
450   return operator <(right) || operator ==(right);
451 }
452
453 bool CDateTime::operator ==(const time_t& right) const
454 {
455   FILETIME time;
456   ToFileTime(right, time);
457
458   return operator ==(time);
459 }
460
461 bool CDateTime::operator !=(const time_t& right) const
462 {
463   return !operator ==(right);
464 }
465
466 bool CDateTime::operator >(const tm& right) const
467 {
468   FILETIME time;
469   ToFileTime(right, time);
470
471   return operator >(time);
472 }
473
474 bool CDateTime::operator >=(const tm& right) const
475 {
476   return operator >(right) || operator ==(right);
477 }
478
479 bool CDateTime::operator <(const tm& right) const
480 {
481   FILETIME time;
482   ToFileTime(right, time);
483
484   return operator <(time);
485 }
486
487 bool CDateTime::operator <=(const tm& right) const
488 {
489   return operator <(right) || operator ==(right);
490 }
491
492 bool CDateTime::operator ==(const tm& right) const
493 {
494   FILETIME time;
495   ToFileTime(right, time);
496
497   return operator ==(time);
498 }
499
500 bool CDateTime::operator !=(const tm& right) const
501 {
502   return !operator ==(right);
503 }
504
505 CDateTime CDateTime::operator +(const CDateTimeSpan& right) const
506 {
507   CDateTime left(*this);
508
509   ULARGE_INTEGER timeLeft;
510   left.ToULargeInt(timeLeft);
511
512   ULARGE_INTEGER timeRight;
513   right.ToULargeInt(timeRight);
514
515   timeLeft.QuadPart+=timeRight.QuadPart;
516
517   left.FromULargeInt(timeLeft);
518
519   return left;
520 }
521
522 CDateTime CDateTime::operator -(const CDateTimeSpan& right) const
523 {
524   CDateTime left(*this);
525
526   ULARGE_INTEGER timeLeft;
527   left.ToULargeInt(timeLeft);
528
529   ULARGE_INTEGER timeRight;
530   right.ToULargeInt(timeRight);
531
532   timeLeft.QuadPart-=timeRight.QuadPart;
533
534   left.FromULargeInt(timeLeft);
535
536   return left;
537 }
538
539 const CDateTime& CDateTime::operator +=(const CDateTimeSpan& right)
540 {
541   ULARGE_INTEGER timeThis;
542   ToULargeInt(timeThis);
543
544   ULARGE_INTEGER timeRight;
545   right.ToULargeInt(timeRight);
546
547   timeThis.QuadPart+=timeRight.QuadPart;
548
549   FromULargeInt(timeThis);
550
551   return *this;
552 }
553
554 const CDateTime& CDateTime::operator -=(const CDateTimeSpan& right)
555 {
556   ULARGE_INTEGER timeThis;
557   ToULargeInt(timeThis);
558
559   ULARGE_INTEGER timeRight;
560   right.ToULargeInt(timeRight);
561
562   timeThis.QuadPart-=timeRight.QuadPart;
563
564   FromULargeInt(timeThis);
565
566   return *this;
567 }
568
569 CDateTimeSpan CDateTime::operator -(const CDateTime& right) const
570 {
571   CDateTimeSpan left;
572
573   ULARGE_INTEGER timeLeft;
574   left.ToULargeInt(timeLeft);
575
576   ULARGE_INTEGER timeThis;
577   ToULargeInt(timeThis);
578
579   ULARGE_INTEGER timeRight;
580   right.ToULargeInt(timeRight);
581
582   timeLeft.QuadPart=timeThis.QuadPart-timeRight.QuadPart;
583
584   left.FromULargeInt(timeLeft);
585
586   return left;
587 }
588
589 CDateTime::operator FILETIME() const
590 {
591   return m_time;
592 }
593
594 void CDateTime::Archive(CArchive& ar)
595 {
596   if (ar.IsStoring())
597   {
598     ar<<(int)m_state;
599     if (m_state==valid)
600     {
601       SYSTEMTIME st;
602       GetAsSystemTime(st);
603       ar<<st;
604     }
605   }
606   else
607   {
608     Reset();
609     int state;
610     ar >> (int &)state;
611     m_state = CDateTime::STATE(state);
612     if (m_state==valid)
613     {
614       SYSTEMTIME st;
615       ar>>st;
616       ToFileTime(st, m_time);
617     }
618   }
619 }
620
621 void CDateTime::Reset()
622 {
623   SetDateTime(1601, 1, 1, 0, 0, 0);
624   SetValid(false);
625 }
626
627 void CDateTime::SetValid(bool yesNo)
628 {
629   m_state=yesNo ? valid : invalid;
630 }
631
632 bool CDateTime::IsValid() const
633 {
634   return m_state==valid;
635 }
636
637 bool CDateTime::ToFileTime(const SYSTEMTIME& time, FILETIME& fileTime) const
638 {
639   return SystemTimeToFileTime(&time, &fileTime) == TRUE &&
640          (fileTime.dwLowDateTime > 0 || fileTime.dwHighDateTime > 0);
641 }
642
643 bool CDateTime::ToFileTime(const time_t& time, FILETIME& fileTime) const
644 {
645   LONGLONG ll = Int32x32To64(time, 10000000)+0x19DB1DED53E8000LL;
646
647   fileTime.dwLowDateTime  = (DWORD)(ll & 0xFFFFFFFF);
648   fileTime.dwHighDateTime = (DWORD)(ll >> 32);
649
650   return true;
651 }
652
653 bool CDateTime::ToFileTime(const tm& time, FILETIME& fileTime) const
654 {
655   SYSTEMTIME st;
656   ZeroMemory(&st, sizeof(SYSTEMTIME));
657
658   st.wYear=time.tm_year+1900;
659   st.wMonth=time.tm_mon+1;
660   st.wDayOfWeek=time.tm_wday;
661   st.wDay=time.tm_mday;
662   st.wHour=time.tm_hour;
663   st.wMinute=time.tm_min;
664   st.wSecond=time.tm_sec;
665
666   return SystemTimeToFileTime(&st, &fileTime)==TRUE;
667 }
668
669 void CDateTime::ToULargeInt(ULARGE_INTEGER& time) const
670 {
671   time.u.HighPart=m_time.dwHighDateTime;
672   time.u.LowPart=m_time.dwLowDateTime;
673 }
674
675 void CDateTime::FromULargeInt(const ULARGE_INTEGER& time)
676 {
677   m_time.dwHighDateTime=time.u.HighPart;
678   m_time.dwLowDateTime=time.u.LowPart;
679 }
680
681 void CDateTime::SetFromDateString(const CStdString &date)
682 {
683   if (date.IsEmpty())
684   {
685     SetValid(false);
686     return;
687   }
688
689   const char* months[] = {"january","february","march","april","may","june","july","august","september","october","november","december",NULL};
690   int j=0;
691   int iDayPos = date.Find("day");
692   int iPos = date.Find(" ");
693   if (iDayPos < iPos && iDayPos > -1)
694   {
695     iDayPos = iPos+1;
696     iPos = date.Find(" ",iPos+1);
697   }
698   else
699     iDayPos = 0;
700
701   CStdString strMonth = date.Mid(iDayPos,iPos-iDayPos);
702   if (strMonth.IsEmpty()) // assume dbdate format
703   {
704     SetFromDBDate(date);
705     return;
706   }
707
708   int iPos2 = date.Find(",");
709   CStdString strDay = date.Mid(iPos,iPos2-iPos);
710   CStdString strYear = date.Mid(date.Find(" ",iPos2)+1);
711   while (months[j] && stricmp(strMonth.c_str(),months[j]) != 0)
712     j++;
713   if (!months[j])
714     return;
715
716   SetDateTime(atol(strYear.c_str()),j+1,atol(strDay.c_str()),0,0,0);
717 }
718
719 int CDateTime::GetDay() const
720 {
721   SYSTEMTIME st;
722   GetAsSystemTime(st);
723
724   return st.wDay;
725 }
726
727 int CDateTime::GetMonth() const
728 {
729   SYSTEMTIME st;
730   GetAsSystemTime(st);
731
732   return st.wMonth;
733 }
734
735 int CDateTime::GetYear() const
736 {
737   SYSTEMTIME st;
738   GetAsSystemTime(st);
739
740   return st.wYear;
741 }
742
743 int CDateTime::GetHour() const
744 {
745   SYSTEMTIME st;
746   GetAsSystemTime(st);
747
748   return st.wHour;
749 }
750
751 int CDateTime::GetMinute() const
752 {
753   SYSTEMTIME st;
754   GetAsSystemTime(st);
755
756   return st.wMinute;
757 }
758
759 int CDateTime::GetSecond() const
760 {
761   SYSTEMTIME st;
762   GetAsSystemTime(st);
763
764   return st.wSecond;
765 }
766
767 int CDateTime::GetDayOfWeek() const
768 {
769   SYSTEMTIME st;
770   GetAsSystemTime(st);
771
772   return st.wDayOfWeek;
773 }
774
775 int CDateTime::GetMinuteOfDay() const
776 {
777   SYSTEMTIME st;
778   GetAsSystemTime(st);
779   return st.wHour*60+st.wMinute;
780 }
781
782 void CDateTime::SetDateTime(int year, int month, int day, int hour, int minute, int second)
783 {
784   SYSTEMTIME st;
785   ZeroMemory(&st, sizeof(SYSTEMTIME));
786
787   st.wYear=year;
788   st.wMonth=month;
789   st.wDay=day;
790   st.wHour=hour;
791   st.wMinute=minute;
792   st.wSecond=second;
793
794   m_state = ToFileTime(st, m_time) ? valid : invalid;
795 }
796
797 void CDateTime::SetDate(int year, int month, int day)
798 {
799   SetDateTime(year, month, day, 0, 0, 0);
800 }
801
802 void CDateTime::SetTime(int hour, int minute, int second)
803 {
804   // 01.01.1601 00:00:00 is 0 as filetime
805   SetDateTime(1601, 1, 1, hour, minute, second);
806 }
807
808 void CDateTime::GetAsSystemTime(SYSTEMTIME& time) const
809 {
810   FileTimeToSystemTime(&m_time, &time);
811 }
812
813 #define UNIX_BASE_TIME 116444736000000000LL /* nanoseconds since epoch */
814 void CDateTime::GetAsTime(time_t& time) const
815 {
816   LONGLONG ll;
817   ll = ((LONGLONG)m_time.dwHighDateTime << 32) + m_time.dwLowDateTime;
818   time=(time_t)((ll - UNIX_BASE_TIME) / 10000000);
819 }
820
821 void CDateTime::GetAsTm(tm& time) const
822 {
823   SYSTEMTIME st;
824   GetAsSystemTime(st);
825
826   time.tm_year=st.wYear-1900;
827   time.tm_mon=st.wMonth-1;
828   time.tm_wday=st.wDayOfWeek;
829   time.tm_mday=st.wDay;
830   time.tm_hour=st.wHour;
831   time.tm_min=st.wMinute;
832   time.tm_sec=st.wSecond;
833
834   mktime(&time);
835 }
836
837 void CDateTime::GetAsTimeStamp(FILETIME& time) const
838 {
839   ::LocalFileTimeToFileTime(&m_time, &time);
840 }
841
842 CStdString CDateTime::GetAsDBDate() const
843 {
844   SYSTEMTIME st;
845   GetAsSystemTime(st);
846
847   return StringUtils::Format("%04i-%02i-%02i", st.wYear, st.wMonth, st.wDay);
848 }
849
850 CStdString CDateTime::GetAsDBDateTime() const
851 {
852   SYSTEMTIME st;
853   GetAsSystemTime(st);
854
855   return StringUtils::Format("%04i-%02i-%02i %02i:%02i:%02i", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
856 }
857
858 CStdString CDateTime::GetAsSaveString() const
859 {
860   SYSTEMTIME st;
861   GetAsSystemTime(st);
862
863   return StringUtils::Format("%04i%02i%02i_%02i%02i%02i", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);;
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 = StringUtils::Format("%d", hour);
1106       else
1107         str = StringUtils::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 = StringUtils::Format("%d", dateTime.wMinute);
1133       else
1134         str = StringUtils::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 = StringUtils::Format("%d", dateTime.wSecond);
1162         else
1163           str = StringUtils::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 = StringUtils::Format("%d", dateTime.wDay);
1254       else if (partLength==2) // two-digit number
1255         str = StringUtils::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 = StringUtils::Format("%d", dateTime.wMonth);
1286       else if (partLength==2) // two-digit number
1287         str = StringUtils::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 = StringUtils::Format("%d", dateTime.wYear); // four-digit number
1316       if (partLength<=2)
1317         str.Delete(0, 2); // two-digit number
1318
1319       strOut+=str;
1320     }
1321     else // everything else pass to output
1322       strOut+=c;
1323   }
1324
1325   return strOut;
1326 }
1327
1328 CStdString CDateTime::GetAsLocalizedDateTime(bool longDate/*=false*/, bool withSeconds/*=true*/) const
1329 {
1330   return GetAsLocalizedDate(longDate)+" "+GetAsLocalizedTime("", withSeconds);
1331 }
1332
1333 CDateTime CDateTime::GetAsUTCDateTime() const
1334 {
1335   CDateTime time(m_time);
1336   time += GetTimezoneBias();
1337   return time;
1338 }
1339
1340 CStdString CDateTime::GetAsRFC1123DateTime() const
1341 {
1342   CDateTime time(GetAsUTCDateTime());
1343
1344   int weekDay = time.GetDayOfWeek();
1345   if (weekDay < 0)
1346     weekDay = 0;
1347   else if (weekDay > 6)
1348     weekDay = 6;
1349   if (weekDay != time.GetDayOfWeek())
1350     CLog::Log(LOGWARNING, "Invalid day of week %d in %s", time.GetDayOfWeek(), time.GetAsDBDateTime().c_str());
1351
1352   int month = time.GetMonth();
1353   if (month < 1)
1354     month = 1;
1355   else if (month > 12)
1356     month = 12;
1357   if (month != time.GetMonth())
1358     CLog::Log(LOGWARNING, "Invalid month %d in %s", time.GetMonth(), time.GetAsDBDateTime().c_str());
1359
1360   CStdString result = StringUtils::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());
1361   return result;
1362 }
1363
1364 int CDateTime::MonthStringToMonthNum(const CStdString& month)
1365 {
1366   const char* months[] = {"january","february","march","april","may","june","july","august","september","october","november","december"};
1367   const char* abr_months[] = {"jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec"};
1368
1369   int i = 0;
1370   for (; i < 12 && month.CompareNoCase(months[i]) != 0 && month.CompareNoCase(abr_months[i]) != 0; i++);
1371   i++;
1372
1373   return i;
1374 }