1 /*
2  *  Copyright (C) 2005-2018 Team Kodi
3  *  This file is part of Kodi - https://kodi.tv
4  *
5  *  SPDX-License-Identifier: GPL-2.0-or-later
6  *  See LICENSES/README.md for more information.
7  */
8 
9 #include "XBDateTime.h"
10 
11 #include "LangInfo.h"
12 #include "guilib/LocalizeStrings.h"
13 #include "utils/Archive.h"
14 #include "utils/StringUtils.h"
15 #include "utils/XTimeUtils.h"
16 #include "utils/log.h"
17 
18 #include <cstdlib>
19 
20 #define SECONDS_PER_DAY 86400L
21 #define SECONDS_PER_HOUR 3600L
22 #define SECONDS_PER_MINUTE 60L
23 #define SECONDS_TO_FILETIME 10000000L
24 
25 static const char *DAY_NAMES[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
26 static const char *MONTH_NAMES[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
27 
28 /////////////////////////////////////////////////
29 //
30 // CDateTimeSpan
31 //
32 
CDateTimeSpan()33 CDateTimeSpan::CDateTimeSpan()
34 {
35   m_timeSpan.highDateTime = 0;
36   m_timeSpan.lowDateTime = 0;
37 }
38 
CDateTimeSpan(const CDateTimeSpan & span)39 CDateTimeSpan::CDateTimeSpan(const CDateTimeSpan& span)
40 {
41   m_timeSpan.highDateTime = span.m_timeSpan.highDateTime;
42   m_timeSpan.lowDateTime = span.m_timeSpan.lowDateTime;
43 }
44 
CDateTimeSpan(int day,int hour,int minute,int second)45 CDateTimeSpan::CDateTimeSpan(int day, int hour, int minute, int second)
46 {
47   SetDateTimeSpan(day, hour, minute, second);
48 }
49 
operator >(const CDateTimeSpan & right) const50 bool CDateTimeSpan::operator >(const CDateTimeSpan& right) const
51 {
52   return KODI::TIME::CompareFileTime(&m_timeSpan, &right.m_timeSpan) > 0;
53 }
54 
operator >=(const CDateTimeSpan & right) const55 bool CDateTimeSpan::operator >=(const CDateTimeSpan& right) const
56 {
57   return operator >(right) || operator ==(right);
58 }
59 
operator <(const CDateTimeSpan & right) const60 bool CDateTimeSpan::operator <(const CDateTimeSpan& right) const
61 {
62   return KODI::TIME::CompareFileTime(&m_timeSpan, &right.m_timeSpan) < 0;
63 }
64 
operator <=(const CDateTimeSpan & right) const65 bool CDateTimeSpan::operator <=(const CDateTimeSpan& right) const
66 {
67   return operator <(right) || operator ==(right);
68 }
69 
operator ==(const CDateTimeSpan & right) const70 bool CDateTimeSpan::operator ==(const CDateTimeSpan& right) const
71 {
72   return KODI::TIME::CompareFileTime(&m_timeSpan, &right.m_timeSpan) == 0;
73 }
74 
operator !=(const CDateTimeSpan & right) const75 bool CDateTimeSpan::operator !=(const CDateTimeSpan& right) const
76 {
77   return !operator ==(right);
78 }
79 
operator +(const CDateTimeSpan & right) const80 CDateTimeSpan CDateTimeSpan::operator +(const CDateTimeSpan& right) const
81 {
82   CDateTimeSpan left(*this);
83 
84   LARGE_INTEGER timeLeft;
85   left.ToLargeInt(timeLeft);
86 
87   LARGE_INTEGER timeRight;
88   right.ToLargeInt(timeRight);
89 
90   timeLeft.QuadPart+=timeRight.QuadPart;
91 
92   left.FromLargeInt(timeLeft);
93 
94   return left;
95 }
96 
operator -(const CDateTimeSpan & right) const97 CDateTimeSpan CDateTimeSpan::operator -(const CDateTimeSpan& right) const
98 {
99   CDateTimeSpan left(*this);
100 
101   LARGE_INTEGER timeLeft;
102   left.ToLargeInt(timeLeft);
103 
104   LARGE_INTEGER timeRight;
105   right.ToLargeInt(timeRight);
106 
107   timeLeft.QuadPart-=timeRight.QuadPart;
108 
109   left.FromLargeInt(timeLeft);
110 
111   return left;
112 }
113 
operator +=(const CDateTimeSpan & right)114 const CDateTimeSpan& CDateTimeSpan::operator +=(const CDateTimeSpan& right)
115 {
116   LARGE_INTEGER timeThis;
117   ToLargeInt(timeThis);
118 
119   LARGE_INTEGER timeRight;
120   right.ToLargeInt(timeRight);
121 
122   timeThis.QuadPart+=timeRight.QuadPart;
123 
124   FromLargeInt(timeThis);
125 
126   return *this;
127 }
128 
operator -=(const CDateTimeSpan & right)129 const CDateTimeSpan& CDateTimeSpan::operator -=(const CDateTimeSpan& right)
130 {
131   LARGE_INTEGER timeThis;
132   ToLargeInt(timeThis);
133 
134   LARGE_INTEGER timeRight;
135   right.ToLargeInt(timeRight);
136 
137   timeThis.QuadPart-=timeRight.QuadPart;
138 
139   FromLargeInt(timeThis);
140 
141   return *this;
142 }
143 
ToLargeInt(LARGE_INTEGER & time) const144 void CDateTimeSpan::ToLargeInt(LARGE_INTEGER& time) const
145 {
146   time.u.HighPart = m_timeSpan.highDateTime;
147   time.u.LowPart = m_timeSpan.lowDateTime;
148 }
149 
FromLargeInt(const LARGE_INTEGER & time)150 void CDateTimeSpan::FromLargeInt(const LARGE_INTEGER& time)
151 {
152   m_timeSpan.highDateTime = time.u.HighPart;
153   m_timeSpan.lowDateTime = time.u.LowPart;
154 }
155 
SetDateTimeSpan(int day,int hour,int minute,int second)156 void CDateTimeSpan::SetDateTimeSpan(int day, int hour, int minute, int second)
157 {
158   LARGE_INTEGER time;
159   ToLargeInt(time);
160 
161   time.QuadPart= static_cast<long long>(day) *SECONDS_PER_DAY*SECONDS_TO_FILETIME;
162   time.QuadPart+= static_cast<long long>(hour) *SECONDS_PER_HOUR*SECONDS_TO_FILETIME;
163   time.QuadPart+= static_cast<long long>(minute) *SECONDS_PER_MINUTE*SECONDS_TO_FILETIME;
164   time.QuadPart+= static_cast<long long>(second) *SECONDS_TO_FILETIME;
165 
166   FromLargeInt(time);
167 }
168 
SetFromTimeString(const std::string & time)169 void CDateTimeSpan::SetFromTimeString(const std::string& time) // hh:mm
170 {
171   if (time.size() >= 5 && time[2] == ':')
172   {
173     int hour    = atoi(time.substr(0, 2).c_str());
174     int minutes = atoi(time.substr(3, 2).c_str());
175     SetDateTimeSpan(0,hour,minutes,0);
176   }
177 }
178 
GetDays() const179 int CDateTimeSpan::GetDays() const
180 {
181   LARGE_INTEGER time;
182   ToLargeInt(time);
183 
184   return (int)(time.QuadPart/SECONDS_TO_FILETIME)/SECONDS_PER_DAY;
185 }
186 
GetHours() const187 int CDateTimeSpan::GetHours() const
188 {
189   LARGE_INTEGER time;
190   ToLargeInt(time);
191 
192   return (int)((time.QuadPart/SECONDS_TO_FILETIME)%SECONDS_PER_DAY)/SECONDS_PER_HOUR;
193 }
194 
GetMinutes() const195 int CDateTimeSpan::GetMinutes() const
196 {
197   LARGE_INTEGER time;
198   ToLargeInt(time);
199 
200   return (int)((time.QuadPart/SECONDS_TO_FILETIME%SECONDS_PER_DAY)%SECONDS_PER_HOUR)/SECONDS_PER_MINUTE;
201 }
202 
GetSeconds() const203 int CDateTimeSpan::GetSeconds() const
204 {
205   LARGE_INTEGER time;
206   ToLargeInt(time);
207 
208   return (int)(((time.QuadPart/SECONDS_TO_FILETIME%SECONDS_PER_DAY)%SECONDS_PER_HOUR)%SECONDS_PER_MINUTE)%SECONDS_PER_MINUTE;
209 }
210 
GetSecondsTotal() const211 int CDateTimeSpan::GetSecondsTotal() const
212 {
213   LARGE_INTEGER time;
214   ToLargeInt(time);
215 
216   return (int)(time.QuadPart/SECONDS_TO_FILETIME);
217 }
218 
SetFromPeriod(const std::string & period)219 void CDateTimeSpan::SetFromPeriod(const std::string &period)
220 {
221   long days = atoi(period.c_str());
222   // find the first non-space and non-number
223   size_t pos = period.find_first_not_of("0123456789 ", 0);
224   if (pos != std::string::npos)
225   {
226     std::string units = period.substr(pos, 3);
227     if (StringUtils::EqualsNoCase(units, "wee"))
228       days *= 7;
229     else if (StringUtils::EqualsNoCase(units, "mon"))
230       days *= 31;
231   }
232 
233   SetDateTimeSpan(days, 0, 0, 0);
234 }
235 
236 /////////////////////////////////////////////////
237 //
238 // CDateTime
239 //
240 
CDateTime()241 CDateTime::CDateTime()
242 {
243   Reset();
244 }
245 
CDateTime(const KODI::TIME::SystemTime & time)246 CDateTime::CDateTime(const KODI::TIME::SystemTime& time)
247 {
248   // we store internally as a FileTime
249   m_state = ToFileTime(time, m_time) ? valid : invalid;
250 }
251 
CDateTime(const KODI::TIME::FileTime & time)252 CDateTime::CDateTime(const KODI::TIME::FileTime& time)
253 {
254   m_time=time;
255   SetValid(true);
256 }
257 
CDateTime(const CDateTime & time)258 CDateTime::CDateTime(const CDateTime& time)
259 {
260   m_time=time.m_time;
261   m_state=time.m_state;
262 }
263 
CDateTime(const time_t & time)264 CDateTime::CDateTime(const time_t& time)
265 {
266   m_state = ToFileTime(time, m_time) ? valid : invalid;
267 }
268 
CDateTime(const tm & time)269 CDateTime::CDateTime(const tm& time)
270 {
271   m_state = ToFileTime(time, m_time) ? valid : invalid;
272 }
273 
CDateTime(int year,int month,int day,int hour,int minute,int second)274 CDateTime::CDateTime(int year, int month, int day, int hour, int minute, int second)
275 {
276   SetDateTime(year, month, day, hour, minute, second);
277 }
278 
GetCurrentDateTime()279 CDateTime CDateTime::GetCurrentDateTime()
280 {
281   // get the current time
282   KODI::TIME::SystemTime time;
283   KODI::TIME::GetLocalTime(&time);
284 
285   return CDateTime(time);
286 }
287 
GetUTCDateTime()288 CDateTime CDateTime::GetUTCDateTime()
289 {
290   CDateTime time(GetCurrentDateTime());
291   time += GetTimezoneBias();
292   return time;
293 }
294 
operator =(const KODI::TIME::SystemTime & right)295 const CDateTime& CDateTime::operator=(const KODI::TIME::SystemTime& right)
296 {
297   m_state = ToFileTime(right, m_time) ? valid : invalid;
298 
299   return *this;
300 }
301 
operator =(const KODI::TIME::FileTime & right)302 const CDateTime& CDateTime::operator=(const KODI::TIME::FileTime& right)
303 {
304   m_time=right;
305   SetValid(true);
306 
307   return *this;
308 }
309 
operator =(const time_t & right)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 
operator =(const tm & right)317 const CDateTime& CDateTime::operator =(const tm& right)
318 {
319   m_state = ToFileTime(right, m_time) ? valid : invalid;
320 
321   return *this;
322 }
323 
operator >(const CDateTime & right) const324 bool CDateTime::operator >(const CDateTime& right) const
325 {
326   return operator >(right.m_time);
327 }
328 
operator >=(const CDateTime & right) const329 bool CDateTime::operator >=(const CDateTime& right) const
330 {
331   return operator >(right) || operator ==(right);
332 }
333 
operator <(const CDateTime & right) const334 bool CDateTime::operator <(const CDateTime& right) const
335 {
336   return operator <(right.m_time);
337 }
338 
operator <=(const CDateTime & right) const339 bool CDateTime::operator <=(const CDateTime& right) const
340 {
341   return operator <(right) || operator ==(right);
342 }
343 
operator ==(const CDateTime & right) const344 bool CDateTime::operator ==(const CDateTime& right) const
345 {
346   return operator ==(right.m_time);
347 }
348 
operator !=(const CDateTime & right) const349 bool CDateTime::operator !=(const CDateTime& right) const
350 {
351   return !operator ==(right);
352 }
353 
operator >(const KODI::TIME::FileTime & right) const354 bool CDateTime::operator>(const KODI::TIME::FileTime& right) const
355 {
356   return KODI::TIME::CompareFileTime(&m_time, &right) > 0;
357 }
358 
operator >=(const KODI::TIME::FileTime & right) const359 bool CDateTime::operator>=(const KODI::TIME::FileTime& right) const
360 {
361   return operator >(right) || operator ==(right);
362 }
363 
operator <(const KODI::TIME::FileTime & right) const364 bool CDateTime::operator<(const KODI::TIME::FileTime& right) const
365 {
366   return KODI::TIME::CompareFileTime(&m_time, &right) < 0;
367 }
368 
operator <=(const KODI::TIME::FileTime & right) const369 bool CDateTime::operator<=(const KODI::TIME::FileTime& right) const
370 {
371   return operator <(right) || operator ==(right);
372 }
373 
operator ==(const KODI::TIME::FileTime & right) const374 bool CDateTime::operator==(const KODI::TIME::FileTime& right) const
375 {
376   return KODI::TIME::CompareFileTime(&m_time, &right) == 0;
377 }
378 
operator !=(const KODI::TIME::FileTime & right) const379 bool CDateTime::operator!=(const KODI::TIME::FileTime& right) const
380 {
381   return !operator ==(right);
382 }
383 
operator >(const KODI::TIME::SystemTime & right) const384 bool CDateTime::operator>(const KODI::TIME::SystemTime& right) const
385 {
386   KODI::TIME::FileTime time;
387   ToFileTime(right, time);
388 
389   return operator >(time);
390 }
391 
operator >=(const KODI::TIME::SystemTime & right) const392 bool CDateTime::operator>=(const KODI::TIME::SystemTime& right) const
393 {
394   return operator >(right) || operator ==(right);
395 }
396 
operator <(const KODI::TIME::SystemTime & right) const397 bool CDateTime::operator<(const KODI::TIME::SystemTime& right) const
398 {
399   KODI::TIME::FileTime time;
400   ToFileTime(right, time);
401 
402   return operator <(time);
403 }
404 
operator <=(const KODI::TIME::SystemTime & right) const405 bool CDateTime::operator<=(const KODI::TIME::SystemTime& right) const
406 {
407   return operator <(right) || operator ==(right);
408 }
409 
operator ==(const KODI::TIME::SystemTime & right) const410 bool CDateTime::operator==(const KODI::TIME::SystemTime& right) const
411 {
412   KODI::TIME::FileTime time;
413   ToFileTime(right, time);
414 
415   return operator ==(time);
416 }
417 
operator !=(const KODI::TIME::SystemTime & right) const418 bool CDateTime::operator!=(const KODI::TIME::SystemTime& right) const
419 {
420   return !operator ==(right);
421 }
422 
operator >(const time_t & right) const423 bool CDateTime::operator >(const time_t& right) const
424 {
425   KODI::TIME::FileTime time;
426   ToFileTime(right, time);
427 
428   return operator >(time);
429 }
430 
operator >=(const time_t & right) const431 bool CDateTime::operator >=(const time_t& right) const
432 {
433   return operator >(right) || operator ==(right);
434 }
435 
operator <(const time_t & right) const436 bool CDateTime::operator <(const time_t& right) const
437 {
438   KODI::TIME::FileTime time;
439   ToFileTime(right, time);
440 
441   return operator <(time);
442 }
443 
operator <=(const time_t & right) const444 bool CDateTime::operator <=(const time_t& right) const
445 {
446   return operator <(right) || operator ==(right);
447 }
448 
operator ==(const time_t & right) const449 bool CDateTime::operator ==(const time_t& right) const
450 {
451   KODI::TIME::FileTime time;
452   ToFileTime(right, time);
453 
454   return operator ==(time);
455 }
456 
operator !=(const time_t & right) const457 bool CDateTime::operator !=(const time_t& right) const
458 {
459   return !operator ==(right);
460 }
461 
operator >(const tm & right) const462 bool CDateTime::operator >(const tm& right) const
463 {
464   KODI::TIME::FileTime time;
465   ToFileTime(right, time);
466 
467   return operator >(time);
468 }
469 
operator >=(const tm & right) const470 bool CDateTime::operator >=(const tm& right) const
471 {
472   return operator >(right) || operator ==(right);
473 }
474 
operator <(const tm & right) const475 bool CDateTime::operator <(const tm& right) const
476 {
477   KODI::TIME::FileTime time;
478   ToFileTime(right, time);
479 
480   return operator <(time);
481 }
482 
operator <=(const tm & right) const483 bool CDateTime::operator <=(const tm& right) const
484 {
485   return operator <(right) || operator ==(right);
486 }
487 
operator ==(const tm & right) const488 bool CDateTime::operator ==(const tm& right) const
489 {
490   KODI::TIME::FileTime time;
491   ToFileTime(right, time);
492 
493   return operator ==(time);
494 }
495 
operator !=(const tm & right) const496 bool CDateTime::operator !=(const tm& right) const
497 {
498   return !operator ==(right);
499 }
500 
operator +(const CDateTimeSpan & right) const501 CDateTime CDateTime::operator +(const CDateTimeSpan& right) const
502 {
503   CDateTime left(*this);
504 
505   LARGE_INTEGER timeLeft;
506   left.ToLargeInt(timeLeft);
507 
508   LARGE_INTEGER timeRight;
509   right.ToLargeInt(timeRight);
510 
511   timeLeft.QuadPart+=timeRight.QuadPart;
512 
513   left.FromLargeInt(timeLeft);
514 
515   return left;
516 }
517 
operator -(const CDateTimeSpan & right) const518 CDateTime CDateTime::operator -(const CDateTimeSpan& right) const
519 {
520   CDateTime left(*this);
521 
522   LARGE_INTEGER timeLeft;
523   left.ToLargeInt(timeLeft);
524 
525   LARGE_INTEGER timeRight;
526   right.ToLargeInt(timeRight);
527 
528   timeLeft.QuadPart-=timeRight.QuadPart;
529 
530   left.FromLargeInt(timeLeft);
531 
532   return left;
533 }
534 
operator +=(const CDateTimeSpan & right)535 const CDateTime& CDateTime::operator +=(const CDateTimeSpan& right)
536 {
537   LARGE_INTEGER timeThis;
538   ToLargeInt(timeThis);
539 
540   LARGE_INTEGER timeRight;
541   right.ToLargeInt(timeRight);
542 
543   timeThis.QuadPart+=timeRight.QuadPart;
544 
545   FromLargeInt(timeThis);
546 
547   return *this;
548 }
549 
operator -=(const CDateTimeSpan & right)550 const CDateTime& CDateTime::operator -=(const CDateTimeSpan& right)
551 {
552   LARGE_INTEGER timeThis;
553   ToLargeInt(timeThis);
554 
555   LARGE_INTEGER timeRight;
556   right.ToLargeInt(timeRight);
557 
558   timeThis.QuadPart-=timeRight.QuadPart;
559 
560   FromLargeInt(timeThis);
561 
562   return *this;
563 }
564 
operator -(const CDateTime & right) const565 CDateTimeSpan CDateTime::operator -(const CDateTime& right) const
566 {
567   CDateTimeSpan left;
568 
569   LARGE_INTEGER timeLeft;
570   left.ToLargeInt(timeLeft);
571 
572   LARGE_INTEGER timeThis;
573   ToLargeInt(timeThis);
574 
575   LARGE_INTEGER timeRight;
576   right.ToLargeInt(timeRight);
577 
578   timeLeft.QuadPart=timeThis.QuadPart-timeRight.QuadPart;
579 
580   left.FromLargeInt(timeLeft);
581 
582   return left;
583 }
584 
operator KODI::TIME::FileTime() const585 CDateTime::operator KODI::TIME::FileTime() const
586 {
587   return m_time;
588 }
589 
Archive(CArchive & ar)590 void CDateTime::Archive(CArchive& ar)
591 {
592   if (ar.IsStoring())
593   {
594     ar<<(int)m_state;
595     if (m_state==valid)
596     {
597       KODI::TIME::SystemTime st;
598       GetAsSystemTime(st);
599       ar<<st;
600     }
601   }
602   else
603   {
604     Reset();
605     int state;
606     ar >> state;
607     m_state = CDateTime::STATE(state);
608     if (m_state==valid)
609     {
610       KODI::TIME::SystemTime st;
611       ar>>st;
612       ToFileTime(st, m_time);
613     }
614   }
615 }
616 
Reset()617 void CDateTime::Reset()
618 {
619   SetDateTime(1601, 1, 1, 0, 0, 0);
620   SetValid(false);
621 }
622 
SetValid(bool yesNo)623 void CDateTime::SetValid(bool yesNo)
624 {
625   m_state=yesNo ? valid : invalid;
626 }
627 
IsValid() const628 bool CDateTime::IsValid() const
629 {
630   return m_state==valid;
631 }
632 
ToFileTime(const KODI::TIME::SystemTime & time,KODI::TIME::FileTime & fileTime) const633 bool CDateTime::ToFileTime(const KODI::TIME::SystemTime& time, KODI::TIME::FileTime& fileTime) const
634 {
635   return KODI::TIME::SystemTimeToFileTime(&time, &fileTime) == 1 &&
636          (fileTime.lowDateTime > 0 || fileTime.highDateTime > 0);
637 }
638 
ToFileTime(const time_t & time,KODI::TIME::FileTime & fileTime) const639 bool CDateTime::ToFileTime(const time_t& time, KODI::TIME::FileTime& fileTime) const
640 {
641   long long ll = time;
642   ll *= 10000000ll;
643   ll += 0x19DB1DED53E8000LL;
644 
645   fileTime.lowDateTime = (DWORD)(ll & 0xFFFFFFFF);
646   fileTime.highDateTime = (DWORD)(ll >> 32);
647 
648   return true;
649 }
650 
ToFileTime(const tm & time,KODI::TIME::FileTime & fileTime) const651 bool CDateTime::ToFileTime(const tm& time, KODI::TIME::FileTime& fileTime) const
652 {
653   KODI::TIME::SystemTime st = {0};
654 
655   st.year = time.tm_year + 1900;
656   st.month = time.tm_mon + 1;
657   st.dayOfWeek = time.tm_wday;
658   st.day = time.tm_mday;
659   st.hour = time.tm_hour;
660   st.minute = time.tm_min;
661   st.second = time.tm_sec;
662 
663   return SystemTimeToFileTime(&st, &fileTime) == 1;
664 }
665 
ToLargeInt(LARGE_INTEGER & time) const666 void CDateTime::ToLargeInt(LARGE_INTEGER& time) const
667 {
668   time.u.HighPart = m_time.highDateTime;
669   time.u.LowPart = m_time.lowDateTime;
670 }
671 
FromLargeInt(const LARGE_INTEGER & time)672 void CDateTime::FromLargeInt(const LARGE_INTEGER& time)
673 {
674   m_time.highDateTime = time.u.HighPart;
675   m_time.lowDateTime = time.u.LowPart;
676 }
677 
SetFromDateString(const std::string & date)678 bool CDateTime::SetFromDateString(const std::string &date)
679 {
680   //! @todo STRING_CLEANUP
681   if (date.empty())
682   {
683     SetValid(false);
684     return false;
685   }
686 
687   if (SetFromDBDate(date))
688     return true;
689 
690   const char* months[] = {"january","february","march","april","may","june","july","august","september","october","november","december",NULL};
691   int j=0;
692   size_t iDayPos = date.find("day");
693   size_t iPos = date.find(' ');
694   if (iDayPos < iPos && iDayPos != std::string::npos)
695   {
696     iDayPos = iPos + 1;
697     iPos = date.find(' ', iPos+1);
698   }
699   else
700     iDayPos = 0;
701 
702   std::string strMonth = date.substr(iDayPos, iPos - iDayPos);
703   if (strMonth.empty())
704     return false;
705 
706   size_t iPos2 = date.find(',');
707   std::string strDay = (date.size() >= iPos) ? date.substr(iPos, iPos2-iPos) : "";
708   std::string strYear = date.substr(date.find(' ', iPos2) + 1);
709   while (months[j] && StringUtils::CompareNoCase(strMonth, months[j]) != 0)
710     j++;
711   if (!months[j])
712     return false;
713 
714   return SetDateTime(atol(strYear.c_str()),j+1,atol(strDay.c_str()),0,0,0);
715 }
716 
GetDay() const717 int CDateTime::GetDay() const
718 {
719   KODI::TIME::SystemTime st;
720   GetAsSystemTime(st);
721 
722   return st.day;
723 }
724 
GetMonth() const725 int CDateTime::GetMonth() const
726 {
727   KODI::TIME::SystemTime st;
728   GetAsSystemTime(st);
729 
730   return st.month;
731 }
732 
GetYear() const733 int CDateTime::GetYear() const
734 {
735   KODI::TIME::SystemTime st;
736   GetAsSystemTime(st);
737 
738   return st.year;
739 }
740 
GetHour() const741 int CDateTime::GetHour() const
742 {
743   KODI::TIME::SystemTime st;
744   GetAsSystemTime(st);
745 
746   return st.hour;
747 }
748 
GetMinute() const749 int CDateTime::GetMinute() const
750 {
751   KODI::TIME::SystemTime st;
752   GetAsSystemTime(st);
753 
754   return st.minute;
755 }
756 
GetSecond() const757 int CDateTime::GetSecond() const
758 {
759   KODI::TIME::SystemTime st;
760   GetAsSystemTime(st);
761 
762   return st.second;
763 }
764 
GetDayOfWeek() const765 int CDateTime::GetDayOfWeek() const
766 {
767   KODI::TIME::SystemTime st;
768   GetAsSystemTime(st);
769 
770   return st.dayOfWeek;
771 }
772 
GetMinuteOfDay() const773 int CDateTime::GetMinuteOfDay() const
774 {
775   KODI::TIME::SystemTime st;
776   GetAsSystemTime(st);
777   return st.hour * 60 + st.minute;
778 }
779 
SetDateTime(int year,int month,int day,int hour,int minute,int second)780 bool CDateTime::SetDateTime(int year, int month, int day, int hour, int minute, int second)
781 {
782   KODI::TIME::SystemTime st = {0};
783 
784   st.year = year;
785   st.month = month;
786   st.day = day;
787   st.hour = hour;
788   st.minute = minute;
789   st.second = second;
790 
791   m_state = ToFileTime(st, m_time) ? valid : invalid;
792   return m_state == valid;
793 }
794 
SetDate(int year,int month,int day)795 bool CDateTime::SetDate(int year, int month, int day)
796 {
797   return SetDateTime(year, month, day, 0, 0, 0);
798 }
799 
SetTime(int hour,int minute,int second)800 bool CDateTime::SetTime(int hour, int minute, int second)
801 {
802   // 01.01.1601 00:00:00 is 0 as filetime
803   return SetDateTime(1601, 1, 1, hour, minute, second);
804 }
805 
GetAsSystemTime(KODI::TIME::SystemTime & time) const806 void CDateTime::GetAsSystemTime(KODI::TIME::SystemTime& time) const
807 {
808   FileTimeToSystemTime(&m_time, &time);
809 }
810 
811 #define UNIX_BASE_TIME 116444736000000000LL /* nanoseconds since epoch */
GetAsTime(time_t & time) const812 void CDateTime::GetAsTime(time_t& time) const
813 {
814   long long ll = (static_cast<long long>(m_time.highDateTime) << 32) + m_time.lowDateTime;
815   time=(time_t)((ll - UNIX_BASE_TIME) / 10000000);
816 }
817 
GetAsTm(tm & time) const818 void CDateTime::GetAsTm(tm& time) const
819 {
820   KODI::TIME::SystemTime st;
821   GetAsSystemTime(st);
822 
823   time.tm_year = st.year - 1900;
824   time.tm_mon = st.month - 1;
825   time.tm_wday = st.dayOfWeek;
826   time.tm_mday = st.day;
827   time.tm_hour = st.hour;
828   time.tm_min = st.minute;
829   time.tm_sec = st.second;
830 
831   mktime(&time);
832 }
833 
GetAsTimeStamp(KODI::TIME::FileTime & time) const834 void CDateTime::GetAsTimeStamp(KODI::TIME::FileTime& time) const
835 {
836   KODI::TIME::LocalFileTimeToFileTime(&m_time, &time);
837 }
838 
GetAsDBDate() const839 std::string CDateTime::GetAsDBDate() const
840 {
841   KODI::TIME::SystemTime st;
842   GetAsSystemTime(st);
843 
844   return StringUtils::Format("%04i-%02i-%02i", st.year, st.month, st.day);
845 }
846 
GetAsDBTime() const847 std::string CDateTime::GetAsDBTime() const
848 {
849   KODI::TIME::SystemTime st;
850   GetAsSystemTime(st);
851 
852   return StringUtils::Format("%02i:%02i:%02i", st.hour, st.minute, st.second);
853 }
854 
GetAsDBDateTime() const855 std::string CDateTime::GetAsDBDateTime() const
856 {
857   KODI::TIME::SystemTime st;
858   GetAsSystemTime(st);
859 
860   return StringUtils::Format("%04i-%02i-%02i %02i:%02i:%02i", st.year, st.month, st.day, st.hour,
861                              st.minute, st.second);
862 }
863 
GetAsSaveString() const864 std::string CDateTime::GetAsSaveString() const
865 {
866   KODI::TIME::SystemTime st;
867   GetAsSystemTime(st);
868 
869   return StringUtils::Format("%04i%02i%02i_%02i%02i%02i", st.year, st.month, st.day, st.hour,
870                              st.minute, st.second);
871 }
872 
SetFromUTCDateTime(const CDateTime & dateTime)873 bool CDateTime::SetFromUTCDateTime(const CDateTime &dateTime)
874 {
875   CDateTime tmp(dateTime);
876   tmp -= GetTimezoneBias();
877 
878   m_time = tmp.m_time;
879   m_state = tmp.m_state;
880   return m_state == valid;
881 }
882 
883 static bool bGotTimezoneBias = false;
884 
ResetTimezoneBias(void)885 void CDateTime::ResetTimezoneBias(void)
886 {
887   bGotTimezoneBias = false;
888 }
889 
GetTimezoneBias(void)890 CDateTimeSpan CDateTime::GetTimezoneBias(void)
891 {
892   static CDateTimeSpan timezoneBias;
893 
894   if (!bGotTimezoneBias)
895   {
896     bGotTimezoneBias = true;
897     KODI::TIME::TimeZoneInformation tz;
898     switch (KODI::TIME::GetTimeZoneInformation(&tz))
899     {
900       case KODI::TIME::KODI_TIME_ZONE_ID_DAYLIGHT:
901         timezoneBias = CDateTimeSpan(0, 0, tz.bias + tz.daylightBias, 0);
902         break;
903       case KODI::TIME::KODI_TIME_ZONE_ID_STANDARD:
904         timezoneBias = CDateTimeSpan(0, 0, tz.bias + tz.standardBias, 0);
905         break;
906       case KODI::TIME::KODI_TIME_ZONE_ID_UNKNOWN:
907         timezoneBias = CDateTimeSpan(0, 0, tz.bias, 0);
908         break;
909     }
910   }
911 
912   return timezoneBias;
913 }
914 
SetFromUTCDateTime(const time_t & dateTime)915 bool CDateTime::SetFromUTCDateTime(const time_t &dateTime)
916 {
917   CDateTime tmp(dateTime);
918   return SetFromUTCDateTime(tmp);
919 }
920 
SetFromW3CDate(const std::string & dateTime)921 bool CDateTime::SetFromW3CDate(const std::string &dateTime)
922 {
923   std::string date;
924 
925   size_t posT = dateTime.find('T');
926   if(posT != std::string::npos)
927     date = dateTime.substr(0, posT);
928   else
929     date = dateTime;
930 
931   int year = 0, month = 1, day = 1;
932 
933   if (date.size() >= 4)
934     year  = atoi(date.substr(0, 4).c_str());
935 
936   if (date.size() >= 10)
937   {
938     month = atoi(date.substr(5, 2).c_str());
939     day   = atoi(date.substr(8, 2).c_str());
940   }
941 
942   CDateTime tmpDateTime(year, month, day, 0, 0, 0);
943   if (tmpDateTime.IsValid())
944     *this = tmpDateTime;
945 
946   return IsValid();
947 }
948 
SetFromW3CDateTime(const std::string & dateTime,bool ignoreTimezone)949 bool CDateTime::SetFromW3CDateTime(const std::string &dateTime, bool ignoreTimezone /* = false */)
950 {
951   std::string date, time, zone;
952 
953   size_t posT = dateTime.find('T');
954   if(posT != std::string::npos)
955   {
956     date = dateTime.substr(0, posT);
957     std::string::size_type posZ = dateTime.find_first_of("+-Z", posT);
958     if(posZ == std::string::npos)
959       time = dateTime.substr(posT + 1);
960     else
961     {
962       time = dateTime.substr(posT + 1, posZ - posT - 1);
963       zone = dateTime.substr(posZ);
964     }
965   }
966   else
967     date = dateTime;
968 
969   int year = 0, month = 1, day = 1, hour = 0, min = 0, sec = 0;
970 
971   if (date.size() >= 4)
972     year  = atoi(date.substr(0, 4).c_str());
973 
974   if (date.size() >= 10)
975   {
976     month = atoi(date.substr(5, 2).c_str());
977     day   = atoi(date.substr(8, 2).c_str());
978   }
979 
980   if (time.length() >= 5)
981   {
982     hour = atoi(time.substr(0, 2).c_str());
983     min  = atoi(time.substr(3, 2).c_str());
984   }
985 
986   if (time.length() >= 8)
987     sec  = atoi(time.substr(6, 2).c_str());
988 
989   CDateTime tmpDateTime(year, month, day, hour, min, sec);
990   if (!tmpDateTime.IsValid())
991     return false;
992 
993   if (!ignoreTimezone && !zone.empty())
994   {
995     // check if the timezone is UTC
996     if (StringUtils::StartsWith(zone, "Z"))
997       return SetFromUTCDateTime(tmpDateTime);
998     else
999     {
1000       // retrieve the timezone offset (ignoring the + or -)
1001       CDateTimeSpan zoneSpan; zoneSpan.SetFromTimeString(zone.substr(1));
1002       if (zoneSpan.GetSecondsTotal() != 0)
1003       {
1004         if (StringUtils::StartsWith(zone, "+"))
1005           tmpDateTime -= zoneSpan;
1006         else if (StringUtils::StartsWith(zone, "-"))
1007           tmpDateTime += zoneSpan;
1008       }
1009     }
1010   }
1011 
1012   *this = tmpDateTime;
1013   return IsValid();
1014 }
1015 
SetFromDBDateTime(const std::string & dateTime)1016 bool CDateTime::SetFromDBDateTime(const std::string &dateTime)
1017 {
1018   // assumes format YYYY-MM-DD HH:MM:SS
1019   if (dateTime.size() == 19)
1020   {
1021     int year  = atoi(dateTime.substr(0, 4).c_str());
1022     int month = atoi(dateTime.substr(5, 2).c_str());
1023     int day   = atoi(dateTime.substr(8, 2).c_str());
1024     int hour  = atoi(dateTime.substr(11, 2).c_str());
1025     int min   = atoi(dateTime.substr(14, 2).c_str());
1026     int sec   = atoi(dateTime.substr(17, 2).c_str());
1027     return SetDateTime(year, month, day, hour, min, sec);
1028   }
1029   return false;
1030 }
1031 
SetFromDBDate(const std::string & date)1032 bool CDateTime::SetFromDBDate(const std::string &date)
1033 {
1034   if (date.size() < 10)
1035     return false;
1036   // assumes format:
1037   // YYYY-MM-DD or DD-MM-YYYY
1038   const static std::string sep_chars = "-./";
1039   int year = 0, month = 0, day = 0;
1040   if (sep_chars.find(date[2]) != std::string::npos)
1041   {
1042     day = atoi(date.substr(0, 2).c_str());
1043     month = atoi(date.substr(3, 2).c_str());
1044     year = atoi(date.substr(6, 4).c_str());
1045   }
1046   else if (sep_chars.find(date[4]) != std::string::npos)
1047   {
1048     year = atoi(date.substr(0, 4).c_str());
1049     month = atoi(date.substr(5, 2).c_str());
1050     day = atoi(date.substr(8, 2).c_str());
1051   }
1052   return SetDate(year, month, day);
1053 }
1054 
SetFromDBTime(const std::string & time)1055 bool CDateTime::SetFromDBTime(const std::string &time)
1056 {
1057   if (time.size() < 5)
1058     return false;
1059 
1060   int hour;
1061   int minute;
1062 
1063   int second = 0;
1064   // HH:MM or HH:MM:SS
1065   hour   = atoi(time.substr(0, 2).c_str());
1066   minute = atoi(time.substr(3, 2).c_str());
1067   // HH:MM:SS
1068   if (time.size() == 8)
1069     second = atoi(time.substr(6, 2).c_str());
1070 
1071   return SetTime(hour, minute, second);
1072 }
1073 
SetFromRFC1123DateTime(const std::string & dateTime)1074 bool CDateTime::SetFromRFC1123DateTime(const std::string &dateTime)
1075 {
1076   std::string date = dateTime;
1077   StringUtils::Trim(date);
1078 
1079   if (date.size() != 29)
1080     return false;
1081 
1082   int day  = strtol(date.substr(5, 2).c_str(), NULL, 10);
1083 
1084   std::string strMonth = date.substr(8, 3);
1085   int month = 0;
1086   for (unsigned int index = 0; index < 12; index++)
1087   {
1088     if (strMonth == MONTH_NAMES[index])
1089     {
1090       month = index + 1;
1091       break;
1092     }
1093   }
1094 
1095   if (month < 1)
1096     return false;
1097 
1098   int year = strtol(date.substr(12, 4).c_str(), NULL, 10);
1099   int hour = strtol(date.substr(17, 2).c_str(), NULL, 10);
1100   int min  = strtol(date.substr(20, 2).c_str(), NULL, 10);
1101   int sec  = strtol(date.substr(23, 2).c_str(), NULL, 10);
1102 
1103   return SetDateTime(year, month, day, hour, min, sec);
1104 }
1105 
FromDateString(const std::string & date)1106 CDateTime CDateTime::FromDateString(const std::string &date)
1107 {
1108   CDateTime dt;
1109   dt.SetFromDateString(date);
1110   return dt;
1111 }
1112 
FromDBDateTime(const std::string & dateTime)1113 CDateTime CDateTime::FromDBDateTime(const std::string &dateTime)
1114 {
1115   CDateTime dt;
1116   dt.SetFromDBDateTime(dateTime);
1117   return dt;
1118 }
1119 
FromDBDate(const std::string & date)1120 CDateTime CDateTime::FromDBDate(const std::string &date)
1121 {
1122   CDateTime dt;
1123   dt.SetFromDBDate(date);
1124   return dt;
1125 }
1126 
FromDBTime(const std::string & time)1127 CDateTime CDateTime::FromDBTime(const std::string &time)
1128 {
1129   CDateTime dt;
1130   dt.SetFromDBTime(time);
1131   return dt;
1132 }
1133 
FromW3CDate(const std::string & date)1134 CDateTime CDateTime::FromW3CDate(const std::string &date)
1135 {
1136   CDateTime dt;
1137   dt.SetFromW3CDate(date);
1138   return dt;
1139 }
1140 
FromW3CDateTime(const std::string & date,bool ignoreTimezone)1141 CDateTime CDateTime::FromW3CDateTime(const std::string &date, bool ignoreTimezone /* = false */)
1142 {
1143   CDateTime dt;
1144   dt.SetFromW3CDateTime(date, ignoreTimezone);
1145   return dt;
1146 }
1147 
FromUTCDateTime(const CDateTime & dateTime)1148 CDateTime CDateTime::FromUTCDateTime(const CDateTime &dateTime)
1149 {
1150   CDateTime dt;
1151   dt.SetFromUTCDateTime(dateTime);
1152   return dt;
1153 }
1154 
FromUTCDateTime(const time_t & dateTime)1155 CDateTime CDateTime::FromUTCDateTime(const time_t &dateTime)
1156 {
1157   CDateTime dt;
1158   dt.SetFromUTCDateTime(dateTime);
1159   return dt;
1160 }
1161 
FromRFC1123DateTime(const std::string & dateTime)1162 CDateTime CDateTime::FromRFC1123DateTime(const std::string &dateTime)
1163 {
1164   CDateTime dt;
1165   dt.SetFromRFC1123DateTime(dateTime);
1166   return dt;
1167 }
1168 
GetAsLocalizedTime(const std::string & format,bool withSeconds) const1169 std::string CDateTime::GetAsLocalizedTime(const std::string &format, bool withSeconds) const
1170 {
1171   std::string strOut;
1172   const std::string& strFormat = format.empty() ? g_langInfo.GetTimeFormat() : format;
1173 
1174   KODI::TIME::SystemTime dateTime;
1175   GetAsSystemTime(dateTime);
1176 
1177   // Prefetch meridiem symbol
1178   const std::string& strMeridiem =
1179       CLangInfo::MeridiemSymbolToString(dateTime.hour > 11 ? MeridiemSymbolPM : MeridiemSymbolAM);
1180 
1181   size_t length = strFormat.size();
1182   for (size_t i=0; i < length; ++i)
1183   {
1184     char c=strFormat[i];
1185     if (c=='\'')
1186     {
1187       // To be able to display a "'" in the string,
1188       // find the last "'" that doesn't follow a "'"
1189       size_t pos=i + 1;
1190       while(((pos = strFormat.find(c, pos + 1)) != std::string::npos &&
1191              pos<strFormat.size()) && strFormat[pos+1]=='\'') {}
1192 
1193       std::string strPart;
1194       if (pos != std::string::npos)
1195       {
1196         // Extract string between ' '
1197         strPart=strFormat.substr(i + 1, pos - i - 1);
1198         i=pos;
1199       }
1200       else
1201       {
1202         strPart=strFormat.substr(i + 1, length - i - 1);
1203         i=length;
1204       }
1205 
1206       StringUtils::Replace(strPart, "''", "'");
1207 
1208       strOut+=strPart;
1209     }
1210     else if (c=='h' || c=='H') // parse hour (H="24 hour clock")
1211     {
1212       int partLength=0;
1213 
1214       int pos=strFormat.find_first_not_of(c,i+1);
1215       if (pos>-1)
1216       {
1217         // Get length of the hour mask, eg. HH
1218         partLength=pos-i;
1219         i=pos-1;
1220       }
1221       else
1222       {
1223         // mask ends at the end of the string, extract it
1224         partLength=length-i;
1225         i=length;
1226       }
1227 
1228       int hour = dateTime.hour;
1229       if (c=='h')
1230       { // recalc to 12 hour clock
1231         if (hour > 11)
1232           hour -= (12 * (hour > 12));
1233         else
1234           hour += (12 * (hour < 1));
1235       }
1236 
1237       // Format hour string with the length of the mask
1238       std::string str;
1239       if (partLength==1)
1240         str = StringUtils::Format("%d", hour);
1241       else
1242         str = StringUtils::Format("%02d", hour);
1243 
1244       strOut+=str;
1245     }
1246     else if (c=='m') // parse minutes
1247     {
1248       int partLength=0;
1249 
1250       int pos=strFormat.find_first_not_of(c,i+1);
1251       if (pos>-1)
1252       {
1253         // Get length of the minute mask, eg. mm
1254         partLength=pos-i;
1255         i=pos-1;
1256       }
1257       else
1258       {
1259         // mask ends at the end of the string, extract it
1260         partLength=length-i;
1261         i=length;
1262       }
1263 
1264       // Format minute string with the length of the mask
1265       std::string str;
1266       if (partLength==1)
1267         str = StringUtils::Format("%d", dateTime.minute);
1268       else
1269         str = StringUtils::Format("%02d", dateTime.minute);
1270 
1271       strOut+=str;
1272     }
1273     else if (c=='s') // parse seconds
1274     {
1275       int partLength=0;
1276 
1277       int pos=strFormat.find_first_not_of(c,i+1);
1278       if (pos>-1)
1279       {
1280         // Get length of the seconds mask, eg. ss
1281         partLength=pos-i;
1282         i=pos-1;
1283       }
1284       else
1285       {
1286         // mask ends at the end of the string, extract it
1287         partLength=length-i;
1288         i=length;
1289       }
1290 
1291       if (withSeconds)
1292       {
1293         // Format seconds string with the length of the mask
1294         std::string str;
1295         if (partLength==1)
1296           str = StringUtils::Format("%d", dateTime.second);
1297         else
1298           str = StringUtils::Format("%02d", dateTime.second);
1299 
1300         strOut+=str;
1301       }
1302       else
1303         strOut.erase(strOut.size()-1,1);
1304     }
1305     else if (c=='x') // add meridiem symbol
1306     {
1307       int pos=strFormat.find_first_not_of(c,i+1);
1308       if (pos>-1)
1309       {
1310         // Get length of the meridiem mask
1311         i=pos-1;
1312       }
1313       else
1314       {
1315         // mask ends at the end of the string, extract it
1316         i=length;
1317       }
1318 
1319       strOut+=strMeridiem;
1320     }
1321     else // everything else pass to output
1322       strOut+=c;
1323   }
1324 
1325   return strOut;
1326 }
1327 
GetAsLocalizedDate(bool longDate) const1328 std::string CDateTime::GetAsLocalizedDate(bool longDate/*=false*/) const
1329 {
1330   return GetAsLocalizedDate(g_langInfo.GetDateFormat(longDate));
1331 }
1332 
GetAsLocalizedDate(const std::string & strFormat) const1333 std::string CDateTime::GetAsLocalizedDate(const std::string &strFormat) const
1334 {
1335   std::string strOut;
1336 
1337   KODI::TIME::SystemTime dateTime;
1338   GetAsSystemTime(dateTime);
1339 
1340   size_t length = strFormat.size();
1341   for (size_t i = 0; i < length; ++i)
1342   {
1343     char c=strFormat[i];
1344     if (c=='\'')
1345     {
1346       // To be able to display a "'" in the string,
1347       // find the last "'" that doesn't follow a "'"
1348       size_t pos = i + 1;
1349       while(((pos = strFormat.find(c, pos + 1)) != std::string::npos &&
1350              pos < strFormat.size()) &&
1351             strFormat[pos + 1] == '\'') {}
1352 
1353       std::string strPart;
1354       if (pos != std::string::npos)
1355       {
1356         // Extract string between ' '
1357         strPart = strFormat.substr(i + 1, pos - i - 1);
1358         i = pos;
1359       }
1360       else
1361       {
1362         strPart = strFormat.substr(i + 1, length - i - 1);
1363         i = length;
1364       }
1365       StringUtils::Replace(strPart, "''", "'");
1366       strOut+=strPart;
1367     }
1368     else if (c=='D' || c=='d') // parse days
1369     {
1370       size_t partLength=0;
1371 
1372       size_t pos = strFormat.find_first_not_of(c, i+1);
1373       if (pos != std::string::npos)
1374       {
1375         // Get length of the day mask, eg. DDDD
1376         partLength=pos-i;
1377         i=pos-1;
1378       }
1379       else
1380       {
1381         // mask ends at the end of the string, extract it
1382         partLength=length-i;
1383         i=length;
1384       }
1385 
1386       // Format string with the length of the mask
1387       std::string str;
1388       if (partLength==1) // single-digit number
1389         str = StringUtils::Format("%d", dateTime.day);
1390       else if (partLength==2) // two-digit number
1391         str = StringUtils::Format("%02d", dateTime.day);
1392       else // Day of week string
1393       {
1394         int wday = dateTime.dayOfWeek;
1395         if (wday < 1 || wday > 7) wday = 7;
1396         str = g_localizeStrings.Get((c =='d' ? 40 : 10) + wday);
1397       }
1398       strOut+=str;
1399     }
1400     else if (c=='M' || c=='m') // parse month
1401     {
1402       size_t partLength=0;
1403 
1404       size_t pos=strFormat.find_first_not_of(c,i+1);
1405       if (pos != std::string::npos)
1406       {
1407         // Get length of the month mask, eg. MMMM
1408         partLength=pos-i;
1409         i=pos-1;
1410       }
1411       else
1412       {
1413         // mask ends at the end of the string, extract it
1414         partLength=length-i;
1415         i=length;
1416       }
1417 
1418       // Format string with the length of the mask
1419       std::string str;
1420       if (partLength==1) // single-digit number
1421         str = StringUtils::Format("%d", dateTime.month);
1422       else if (partLength==2) // two-digit number
1423         str = StringUtils::Format("%02d", dateTime.month);
1424       else // Month string
1425       {
1426         int wmonth = dateTime.month;
1427         if (wmonth < 1 || wmonth > 12) wmonth = 12;
1428         str = g_localizeStrings.Get((c =='m' ? 50 : 20) + wmonth);
1429       }
1430       strOut+=str;
1431     }
1432     else if (c=='Y' || c =='y') // parse year
1433     {
1434       size_t partLength = 0;
1435 
1436       size_t pos = strFormat.find_first_not_of(c,i+1);
1437       if (pos != std::string::npos)
1438       {
1439         // Get length of the year mask, eg. YYYY
1440         partLength=pos-i;
1441         i=pos-1;
1442       }
1443       else
1444       {
1445         // mask ends at the end of the string, extract it
1446         partLength=length-i;
1447         i=length;
1448       }
1449 
1450       // Format string with the length of the mask
1451       std::string str = StringUtils::Format("%d", dateTime.year); // four-digit number
1452       if (partLength <= 2)
1453         str.erase(0, 2); // two-digit number
1454 
1455       strOut+=str;
1456     }
1457     else // everything else pass to output
1458       strOut+=c;
1459   }
1460 
1461   return strOut;
1462 }
1463 
GetAsLocalizedDateTime(bool longDate,bool withSeconds) const1464 std::string CDateTime::GetAsLocalizedDateTime(bool longDate/*=false*/, bool withSeconds/*=true*/) const
1465 {
1466   return GetAsLocalizedDate(longDate) + ' ' + GetAsLocalizedTime("", withSeconds);
1467 }
1468 
GetAsLocalizedTime(TIME_FORMAT format,bool withSeconds) const1469 std::string CDateTime::GetAsLocalizedTime(TIME_FORMAT format, bool withSeconds /* = false */) const
1470 {
1471   const std::string timeFormat = g_langInfo.GetTimeFormat();
1472   bool use12hourclock = timeFormat.find('h') != std::string::npos;
1473   switch (format)
1474   {
1475     case TIME_FORMAT_GUESS:
1476       return GetAsLocalizedTime("", withSeconds);
1477     case TIME_FORMAT_SS:
1478       return GetAsLocalizedTime("ss", true);
1479     case TIME_FORMAT_MM:
1480       return GetAsLocalizedTime("mm", true);
1481     case TIME_FORMAT_MM_SS:
1482       return GetAsLocalizedTime("mm:ss", true);
1483     case TIME_FORMAT_HH:  // this forces it to a 12 hour clock
1484       return GetAsLocalizedTime(use12hourclock ? "h" : "HH", false);
1485     case TIME_FORMAT_HH_SS:
1486       return GetAsLocalizedTime(use12hourclock ? "h:ss" : "HH:ss", true);
1487     case TIME_FORMAT_HH_MM:
1488       return GetAsLocalizedTime(use12hourclock ? "h:mm" : "HH:mm", false);
1489     case TIME_FORMAT_HH_MM_XX:
1490       return GetAsLocalizedTime(use12hourclock ? "h:mm xx" : "HH:mm", false);
1491     case TIME_FORMAT_HH_MM_SS:
1492       return GetAsLocalizedTime(use12hourclock ? "hh:mm:ss" : "HH:mm:ss", true);
1493     case TIME_FORMAT_HH_MM_SS_XX:
1494       return GetAsLocalizedTime(use12hourclock ? "hh:mm:ss xx" : "HH:mm:ss", true);
1495     case TIME_FORMAT_H:
1496       return GetAsLocalizedTime("h", false);
1497     case TIME_FORMAT_M:
1498       return GetAsLocalizedTime("m", false);
1499     case TIME_FORMAT_H_MM_SS:
1500       return GetAsLocalizedTime("h:mm:ss", true);
1501     case TIME_FORMAT_H_MM_SS_XX:
1502       return GetAsLocalizedTime("h:mm:ss xx", true);
1503     case TIME_FORMAT_XX:
1504       return use12hourclock ? GetAsLocalizedTime("xx", false) : "";
1505     default:
1506       break;
1507   }
1508   return GetAsLocalizedTime("", false);
1509 }
1510 
GetAsUTCDateTime() const1511 CDateTime CDateTime::GetAsUTCDateTime() const
1512 {
1513   CDateTime time(m_time);
1514   time += GetTimezoneBias();
1515   return time;
1516 }
1517 
GetAsRFC1123DateTime() const1518 std::string CDateTime::GetAsRFC1123DateTime() const
1519 {
1520   CDateTime time(GetAsUTCDateTime());
1521 
1522   int weekDay = time.GetDayOfWeek();
1523   if (weekDay < 0)
1524     weekDay = 0;
1525   else if (weekDay > 6)
1526     weekDay = 6;
1527   if (weekDay != time.GetDayOfWeek())
1528     CLog::Log(LOGWARNING, "Invalid day of week %d in %s", time.GetDayOfWeek(), time.GetAsDBDateTime().c_str());
1529 
1530   int month = time.GetMonth();
1531   if (month < 1)
1532     month = 1;
1533   else if (month > 12)
1534     month = 12;
1535   if (month != time.GetMonth())
1536     CLog::Log(LOGWARNING, "Invalid month %d in %s", time.GetMonth(), time.GetAsDBDateTime().c_str());
1537 
1538   return 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());
1539 }
1540 
GetAsW3CDate() const1541 std::string CDateTime::GetAsW3CDate() const
1542 {
1543   KODI::TIME::SystemTime st;
1544   GetAsSystemTime(st);
1545 
1546   return StringUtils::Format("%04i-%02i-%02i", st.year, st.month, st.day);
1547 }
1548 
GetAsW3CDateTime(bool asUtc) const1549 std::string CDateTime::GetAsW3CDateTime(bool asUtc /* = false */) const
1550 {
1551   CDateTime w3cDate = *this;
1552   if (asUtc)
1553     w3cDate = GetAsUTCDateTime();
1554   KODI::TIME::SystemTime st;
1555   w3cDate.GetAsSystemTime(st);
1556 
1557   std::string result = StringUtils::Format("%04i-%02i-%02iT%02i:%02i:%02i", st.year, st.month,
1558                                            st.day, st.hour, st.minute, st.second);
1559   if (asUtc)
1560     return result + "Z";
1561 
1562   CDateTimeSpan bias = GetTimezoneBias();
1563   return result + StringUtils::Format("%c%02i:%02i", (bias.GetSecondsTotal() >= 0 ? '+' : '-'), abs(bias.GetHours()), abs(bias.GetMinutes())).c_str();
1564 }
1565 
MonthStringToMonthNum(const std::string & month)1566 int CDateTime::MonthStringToMonthNum(const std::string& month)
1567 {
1568   const char* months[] = {"january","february","march","april","may","june","july","august","september","october","november","december"};
1569   const char* abr_months[] = {"jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec"};
1570 
1571   int i = 0;
1572   for (; i < 12 && !StringUtils::EqualsNoCase(month, months[i]) && !StringUtils::EqualsNoCase(month, abr_months[i]); i++);
1573   i++;
1574 
1575   return i;
1576 }
1577