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