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