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