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