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