2 * Copyright (C) 2005-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
9 #include "XBDateTime.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"
20 #define SECONDS_PER_DAY 86400L
21 #define SECONDS_PER_HOUR 3600L
22 #define SECONDS_PER_MINUTE 60L
23 #define SECONDS_TO_FILETIME 10000000L
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" };
28 /////////////////////////////////////////////////
33 CDateTimeSpan::CDateTimeSpan()
35 m_timeSpan
.highDateTime
= 0;
36 m_timeSpan
.lowDateTime
= 0;
39 CDateTimeSpan::CDateTimeSpan(const CDateTimeSpan
& span
)
41 m_timeSpan
.highDateTime
= span
.m_timeSpan
.highDateTime
;
42 m_timeSpan
.lowDateTime
= span
.m_timeSpan
.lowDateTime
;
45 CDateTimeSpan::CDateTimeSpan(int day
, int hour
, int minute
, int second
)
47 SetDateTimeSpan(day
, hour
, minute
, second
);
50 bool CDateTimeSpan::operator >(const CDateTimeSpan
& right
) const
52 return KODI::TIME::CompareFileTime(&m_timeSpan
, &right
.m_timeSpan
) > 0;
55 bool CDateTimeSpan::operator >=(const CDateTimeSpan
& right
) const
57 return operator >(right
) || operator ==(right
);
60 bool CDateTimeSpan::operator <(const CDateTimeSpan
& right
) const
62 return KODI::TIME::CompareFileTime(&m_timeSpan
, &right
.m_timeSpan
) < 0;
65 bool CDateTimeSpan::operator <=(const CDateTimeSpan
& right
) const
67 return operator <(right
) || operator ==(right
);
70 bool CDateTimeSpan::operator ==(const CDateTimeSpan
& right
) const
72 return KODI::TIME::CompareFileTime(&m_timeSpan
, &right
.m_timeSpan
) == 0;
75 bool CDateTimeSpan::operator !=(const CDateTimeSpan
& right
) const
77 return !operator ==(right
);
80 CDateTimeSpan
CDateTimeSpan::operator +(const CDateTimeSpan
& right
) const
82 CDateTimeSpan
left(*this);
84 LARGE_INTEGER timeLeft
;
85 left
.ToLargeInt(timeLeft
);
87 LARGE_INTEGER timeRight
;
88 right
.ToLargeInt(timeRight
);
90 timeLeft
.QuadPart
+=timeRight
.QuadPart
;
92 left
.FromLargeInt(timeLeft
);
97 CDateTimeSpan
CDateTimeSpan::operator -(const CDateTimeSpan
& right
) const
99 CDateTimeSpan
left(*this);
101 LARGE_INTEGER timeLeft
;
102 left
.ToLargeInt(timeLeft
);
104 LARGE_INTEGER timeRight
;
105 right
.ToLargeInt(timeRight
);
107 timeLeft
.QuadPart
-=timeRight
.QuadPart
;
109 left
.FromLargeInt(timeLeft
);
114 const CDateTimeSpan
& CDateTimeSpan::operator +=(const CDateTimeSpan
& right
)
116 LARGE_INTEGER timeThis
;
117 ToLargeInt(timeThis
);
119 LARGE_INTEGER timeRight
;
120 right
.ToLargeInt(timeRight
);
122 timeThis
.QuadPart
+=timeRight
.QuadPart
;
124 FromLargeInt(timeThis
);
129 const CDateTimeSpan
& CDateTimeSpan::operator -=(const CDateTimeSpan
& right
)
131 LARGE_INTEGER timeThis
;
132 ToLargeInt(timeThis
);
134 LARGE_INTEGER timeRight
;
135 right
.ToLargeInt(timeRight
);
137 timeThis
.QuadPart
-=timeRight
.QuadPart
;
139 FromLargeInt(timeThis
);
144 void CDateTimeSpan::ToLargeInt(LARGE_INTEGER
& time
) const
146 time
.u
.HighPart
= m_timeSpan
.highDateTime
;
147 time
.u
.LowPart
= m_timeSpan
.lowDateTime
;
150 void CDateTimeSpan::FromLargeInt(const LARGE_INTEGER
& time
)
152 m_timeSpan
.highDateTime
= time
.u
.HighPart
;
153 m_timeSpan
.lowDateTime
= time
.u
.LowPart
;
156 void CDateTimeSpan::SetDateTimeSpan(int day
, int hour
, int minute
, int second
)
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
;
169 void CDateTimeSpan::SetFromTimeString(const std::string
& time
) // hh:mm
171 if (time
.size() >= 5 && time
[2] == ':')
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);
179 int CDateTimeSpan::GetDays() const
184 return (int)(time
.QuadPart
/SECONDS_TO_FILETIME
)/SECONDS_PER_DAY
;
187 int CDateTimeSpan::GetHours() const
192 return (int)((time
.QuadPart
/SECONDS_TO_FILETIME
)%SECONDS_PER_DAY
)/SECONDS_PER_HOUR
;
195 int CDateTimeSpan::GetMinutes() const
200 return (int)((time
.QuadPart
/SECONDS_TO_FILETIME
%SECONDS_PER_DAY
)%SECONDS_PER_HOUR
)/SECONDS_PER_MINUTE
;
203 int CDateTimeSpan::GetSeconds() const
208 return (int)(((time
.QuadPart
/SECONDS_TO_FILETIME
%SECONDS_PER_DAY
)%SECONDS_PER_HOUR
)%SECONDS_PER_MINUTE
)%SECONDS_PER_MINUTE
;
211 int CDateTimeSpan::GetSecondsTotal() const
216 return (int)(time
.QuadPart
/SECONDS_TO_FILETIME
);
219 void CDateTimeSpan::SetFromPeriod(const std::string
&period
)
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
)
226 std::string units
= period
.substr(pos
, 3);
227 if (StringUtils::EqualsNoCase(units
, "wee"))
229 else if (StringUtils::EqualsNoCase(units
, "mon"))
233 SetDateTimeSpan(days
, 0, 0, 0);
236 /////////////////////////////////////////////////
241 CDateTime::CDateTime()
246 CDateTime::CDateTime(const KODI::TIME::SystemTime
& time
)
248 // we store internally as a FileTime
249 m_state
= ToFileTime(time
, m_time
) ? valid
: invalid
;
252 CDateTime::CDateTime(const KODI::TIME::FileTime
& time
) : m_time(time
)
257 CDateTime::CDateTime(const CDateTime
& time
) : m_time(time
.m_time
)
259 m_state
=time
.m_state
;
262 CDateTime::CDateTime(const time_t& time
)
264 m_state
= ToFileTime(time
, m_time
) ? valid
: invalid
;
267 CDateTime::CDateTime(const tm
& time
)
269 m_state
= ToFileTime(time
, m_time
) ? valid
: invalid
;
272 CDateTime::CDateTime(int year
, int month
, int day
, int hour
, int minute
, int second
)
274 SetDateTime(year
, month
, day
, hour
, minute
, second
);
277 CDateTime
CDateTime::GetCurrentDateTime()
279 // get the current time
280 KODI::TIME::SystemTime time
;
281 KODI::TIME::GetLocalTime(&time
);
283 return CDateTime(time
);
286 CDateTime
CDateTime::GetUTCDateTime()
288 CDateTime
time(GetCurrentDateTime());
289 time
+= GetTimezoneBias();
293 const CDateTime
& CDateTime::operator=(const KODI::TIME::SystemTime
& right
)
295 m_state
= ToFileTime(right
, m_time
) ? valid
: invalid
;
300 const CDateTime
& CDateTime::operator=(const KODI::TIME::FileTime
& right
)
308 const CDateTime
& CDateTime::operator =(const time_t& right
)
310 m_state
= ToFileTime(right
, m_time
) ? valid
: invalid
;
315 const CDateTime
& CDateTime::operator =(const tm
& right
)
317 m_state
= ToFileTime(right
, m_time
) ? valid
: invalid
;
322 bool CDateTime::operator >(const CDateTime
& right
) const
324 return operator >(right
.m_time
);
327 bool CDateTime::operator >=(const CDateTime
& right
) const
329 return operator >(right
) || operator ==(right
);
332 bool CDateTime::operator <(const CDateTime
& right
) const
334 return operator <(right
.m_time
);
337 bool CDateTime::operator <=(const CDateTime
& right
) const
339 return operator <(right
) || operator ==(right
);
342 bool CDateTime::operator ==(const CDateTime
& right
) const
344 return operator ==(right
.m_time
);
347 bool CDateTime::operator !=(const CDateTime
& right
) const
349 return !operator ==(right
);
352 bool CDateTime::operator>(const KODI::TIME::FileTime
& right
) const
354 return KODI::TIME::CompareFileTime(&m_time
, &right
) > 0;
357 bool CDateTime::operator>=(const KODI::TIME::FileTime
& right
) const
359 return operator >(right
) || operator ==(right
);
362 bool CDateTime::operator<(const KODI::TIME::FileTime
& right
) const
364 return KODI::TIME::CompareFileTime(&m_time
, &right
) < 0;
367 bool CDateTime::operator<=(const KODI::TIME::FileTime
& right
) const
369 return operator <(right
) || operator ==(right
);
372 bool CDateTime::operator==(const KODI::TIME::FileTime
& right
) const
374 return KODI::TIME::CompareFileTime(&m_time
, &right
) == 0;
377 bool CDateTime::operator!=(const KODI::TIME::FileTime
& right
) const
379 return !operator ==(right
);
382 bool CDateTime::operator>(const KODI::TIME::SystemTime
& right
) const
384 KODI::TIME::FileTime time
;
385 ToFileTime(right
, time
);
387 return operator >(time
);
390 bool CDateTime::operator>=(const KODI::TIME::SystemTime
& right
) const
392 return operator >(right
) || operator ==(right
);
395 bool CDateTime::operator<(const KODI::TIME::SystemTime
& right
) const
397 KODI::TIME::FileTime time
;
398 ToFileTime(right
, time
);
400 return operator <(time
);
403 bool CDateTime::operator<=(const KODI::TIME::SystemTime
& right
) const
405 return operator <(right
) || operator ==(right
);
408 bool CDateTime::operator==(const KODI::TIME::SystemTime
& right
) const
410 KODI::TIME::FileTime time
;
411 ToFileTime(right
, time
);
413 return operator ==(time
);
416 bool CDateTime::operator!=(const KODI::TIME::SystemTime
& right
) const
418 return !operator ==(right
);
421 bool CDateTime::operator >(const time_t& right
) const
423 KODI::TIME::FileTime time
;
424 ToFileTime(right
, time
);
426 return operator >(time
);
429 bool CDateTime::operator >=(const time_t& right
) const
431 return operator >(right
) || operator ==(right
);
434 bool CDateTime::operator <(const time_t& right
) const
436 KODI::TIME::FileTime time
;
437 ToFileTime(right
, time
);
439 return operator <(time
);
442 bool CDateTime::operator <=(const time_t& right
) const
444 return operator <(right
) || operator ==(right
);
447 bool CDateTime::operator ==(const time_t& right
) const
449 KODI::TIME::FileTime time
;
450 ToFileTime(right
, time
);
452 return operator ==(time
);
455 bool CDateTime::operator !=(const time_t& right
) const
457 return !operator ==(right
);
460 bool CDateTime::operator >(const tm
& right
) const
462 KODI::TIME::FileTime time
;
463 ToFileTime(right
, time
);
465 return operator >(time
);
468 bool CDateTime::operator >=(const tm
& right
) const
470 return operator >(right
) || operator ==(right
);
473 bool CDateTime::operator <(const tm
& right
) const
475 KODI::TIME::FileTime time
;
476 ToFileTime(right
, time
);
478 return operator <(time
);
481 bool CDateTime::operator <=(const tm
& right
) const
483 return operator <(right
) || operator ==(right
);
486 bool CDateTime::operator ==(const tm
& right
) const
488 KODI::TIME::FileTime time
;
489 ToFileTime(right
, time
);
491 return operator ==(time
);
494 bool CDateTime::operator !=(const tm
& right
) const
496 return !operator ==(right
);
499 CDateTime
CDateTime::operator +(const CDateTimeSpan
& right
) const
501 CDateTime
left(*this);
503 LARGE_INTEGER timeLeft
;
504 left
.ToLargeInt(timeLeft
);
506 LARGE_INTEGER timeRight
;
507 right
.ToLargeInt(timeRight
);
509 timeLeft
.QuadPart
+=timeRight
.QuadPart
;
511 left
.FromLargeInt(timeLeft
);
516 CDateTime
CDateTime::operator -(const CDateTimeSpan
& right
) const
518 CDateTime
left(*this);
520 LARGE_INTEGER timeLeft
;
521 left
.ToLargeInt(timeLeft
);
523 LARGE_INTEGER timeRight
;
524 right
.ToLargeInt(timeRight
);
526 timeLeft
.QuadPart
-=timeRight
.QuadPart
;
528 left
.FromLargeInt(timeLeft
);
533 const CDateTime
& CDateTime::operator +=(const CDateTimeSpan
& right
)
535 LARGE_INTEGER timeThis
;
536 ToLargeInt(timeThis
);
538 LARGE_INTEGER timeRight
;
539 right
.ToLargeInt(timeRight
);
541 timeThis
.QuadPart
+=timeRight
.QuadPart
;
543 FromLargeInt(timeThis
);
548 const CDateTime
& CDateTime::operator -=(const CDateTimeSpan
& right
)
550 LARGE_INTEGER timeThis
;
551 ToLargeInt(timeThis
);
553 LARGE_INTEGER timeRight
;
554 right
.ToLargeInt(timeRight
);
556 timeThis
.QuadPart
-=timeRight
.QuadPart
;
558 FromLargeInt(timeThis
);
563 CDateTimeSpan
CDateTime::operator -(const CDateTime
& right
) const
567 LARGE_INTEGER timeLeft
;
568 left
.ToLargeInt(timeLeft
);
570 LARGE_INTEGER timeThis
;
571 ToLargeInt(timeThis
);
573 LARGE_INTEGER timeRight
;
574 right
.ToLargeInt(timeRight
);
576 timeLeft
.QuadPart
=timeThis
.QuadPart
-timeRight
.QuadPart
;
578 left
.FromLargeInt(timeLeft
);
583 CDateTime::operator KODI::TIME::FileTime() const
588 void CDateTime::Archive(CArchive
& ar
)
595 KODI::TIME::SystemTime st
;
605 m_state
= CDateTime::STATE(state
);
608 KODI::TIME::SystemTime st
;
610 ToFileTime(st
, m_time
);
615 void CDateTime::Reset()
617 SetDateTime(1601, 1, 1, 0, 0, 0);
621 void CDateTime::SetValid(bool yesNo
)
623 m_state
=yesNo
? valid
: invalid
;
626 bool CDateTime::IsValid() const
628 return m_state
==valid
;
631 bool CDateTime::ToFileTime(const KODI::TIME::SystemTime
& time
, KODI::TIME::FileTime
& fileTime
) const
633 return KODI::TIME::SystemTimeToFileTime(&time
, &fileTime
) == 1 &&
634 (fileTime
.lowDateTime
> 0 || fileTime
.highDateTime
> 0);
637 bool CDateTime::ToFileTime(const time_t& time
, KODI::TIME::FileTime
& fileTime
) const
641 ll
+= 0x19DB1DED53E8000LL
;
643 fileTime
.lowDateTime
= (DWORD
)(ll
& 0xFFFFFFFF);
644 fileTime
.highDateTime
= (DWORD
)(ll
>> 32);
649 bool CDateTime::ToFileTime(const tm
& time
, KODI::TIME::FileTime
& fileTime
) const
651 KODI::TIME::SystemTime st
= {};
653 st
.year
= time
.tm_year
+ 1900;
654 st
.month
= time
.tm_mon
+ 1;
655 st
.dayOfWeek
= time
.tm_wday
;
656 st
.day
= time
.tm_mday
;
657 st
.hour
= time
.tm_hour
;
658 st
.minute
= time
.tm_min
;
659 st
.second
= time
.tm_sec
;
661 return SystemTimeToFileTime(&st
, &fileTime
) == 1;
664 void CDateTime::ToLargeInt(LARGE_INTEGER
& time
) const
666 time
.u
.HighPart
= m_time
.highDateTime
;
667 time
.u
.LowPart
= m_time
.lowDateTime
;
670 void CDateTime::FromLargeInt(const LARGE_INTEGER
& time
)
672 m_time
.highDateTime
= time
.u
.HighPart
;
673 m_time
.lowDateTime
= time
.u
.LowPart
;
676 bool CDateTime::SetFromDateString(const std::string
&date
)
678 //! @todo STRING_CLEANUP
685 if (SetFromDBDate(date
))
688 const char* months
[] = {"january","february","march","april","may","june","july","august","september","october","november","december",NULL
};
690 size_t iDayPos
= date
.find("day");
691 size_t iPos
= date
.find(' ');
692 if (iDayPos
< iPos
&& iDayPos
!= std::string::npos
)
695 iPos
= date
.find(' ', iPos
+1);
700 std::string strMonth
= date
.substr(iDayPos
, iPos
- iDayPos
);
701 if (strMonth
.empty())
704 size_t iPos2
= date
.find(',');
705 std::string strDay
= (date
.size() >= iPos
) ? date
.substr(iPos
, iPos2
-iPos
) : "";
706 std::string strYear
= date
.substr(date
.find(' ', iPos2
) + 1);
707 while (months
[j
] && StringUtils::CompareNoCase(strMonth
, months
[j
]) != 0)
712 return SetDateTime(atol(strYear
.c_str()),j
+1,atol(strDay
.c_str()),0,0,0);
715 int CDateTime::GetDay() const
717 KODI::TIME::SystemTime st
;
723 int CDateTime::GetMonth() const
725 KODI::TIME::SystemTime st
;
731 int CDateTime::GetYear() const
733 KODI::TIME::SystemTime st
;
739 int CDateTime::GetHour() const
741 KODI::TIME::SystemTime st
;
747 int CDateTime::GetMinute() const
749 KODI::TIME::SystemTime st
;
755 int CDateTime::GetSecond() const
757 KODI::TIME::SystemTime st
;
763 int CDateTime::GetDayOfWeek() const
765 KODI::TIME::SystemTime st
;
771 int CDateTime::GetMinuteOfDay() const
773 KODI::TIME::SystemTime st
;
775 return st
.hour
* 60 + st
.minute
;
778 bool CDateTime::SetDateTime(int year
, int month
, int day
, int hour
, int minute
, int second
)
780 KODI::TIME::SystemTime st
= {};
789 m_state
= ToFileTime(st
, m_time
) ? valid
: invalid
;
790 return m_state
== valid
;
793 bool CDateTime::SetDate(int year
, int month
, int day
)
795 return SetDateTime(year
, month
, day
, 0, 0, 0);
798 bool CDateTime::SetTime(int hour
, int minute
, int second
)
800 // 01.01.1601 00:00:00 is 0 as filetime
801 return SetDateTime(1601, 1, 1, hour
, minute
, second
);
804 void CDateTime::GetAsSystemTime(KODI::TIME::SystemTime
& time
) const
806 FileTimeToSystemTime(&m_time
, &time
);
809 #define UNIX_BASE_TIME 116444736000000000LL /* nanoseconds since epoch */
810 void CDateTime::GetAsTime(time_t& time
) const
812 long long ll
= (static_cast<long long>(m_time
.highDateTime
) << 32) + m_time
.lowDateTime
;
813 time
=(time_t)((ll
- UNIX_BASE_TIME
) / 10000000);
816 void CDateTime::GetAsTm(tm
& time
) const
818 KODI::TIME::SystemTime st
;
822 time
.tm_year
= st
.year
- 1900;
823 time
.tm_mon
= st
.month
- 1;
824 time
.tm_wday
= st
.dayOfWeek
;
825 time
.tm_mday
= st
.day
;
826 time
.tm_hour
= st
.hour
;
827 time
.tm_min
= st
.minute
;
828 time
.tm_sec
= st
.second
;
834 void CDateTime::GetAsTimeStamp(KODI::TIME::FileTime
& time
) const
836 KODI::TIME::LocalFileTimeToFileTime(&m_time
, &time
);
839 std::string
CDateTime::GetAsDBDate() const
841 KODI::TIME::SystemTime st
;
844 return StringUtils::Format("{:04}-{:02}-{:02}", st
.year
, st
.month
, st
.day
);
847 std::string
CDateTime::GetAsDBTime() const
849 KODI::TIME::SystemTime st
;
852 return StringUtils::Format("{:02}:{:02}:{:02}", st
.hour
, st
.minute
, st
.second
);
855 std::string
CDateTime::GetAsDBDateTime() const
857 KODI::TIME::SystemTime st
;
860 return StringUtils::Format("{:04}-{:02}-{:02} {:02}:{:02}:{:02}", st
.year
, st
.month
, st
.day
,
861 st
.hour
, st
.minute
, st
.second
);
864 std::string
CDateTime::GetAsSaveString() const
866 KODI::TIME::SystemTime st
;
869 return StringUtils::Format("{:04}{:02}{:02}_{:02}{:02}{:02}", st
.year
, st
.month
, st
.day
, st
.hour
,
870 st
.minute
, st
.second
);
873 bool CDateTime::SetFromUTCDateTime(const CDateTime
&dateTime
)
875 CDateTime
tmp(dateTime
);
876 tmp
-= GetTimezoneBias();
879 m_state
= tmp
.m_state
;
880 return m_state
== valid
;
883 static bool bGotTimezoneBias
= false;
885 void CDateTime::ResetTimezoneBias(void)
887 bGotTimezoneBias
= false;
890 CDateTimeSpan
CDateTime::GetTimezoneBias(void)
892 static CDateTimeSpan timezoneBias
;
894 if (!bGotTimezoneBias
)
896 bGotTimezoneBias
= true;
897 KODI::TIME::TimeZoneInformation tz
;
898 switch (KODI::TIME::GetTimeZoneInformation(&tz
))
900 case KODI::TIME::KODI_TIME_ZONE_ID_DAYLIGHT
:
901 timezoneBias
= CDateTimeSpan(0, 0, tz
.bias
+ tz
.daylightBias
, 0);
903 case KODI::TIME::KODI_TIME_ZONE_ID_STANDARD
:
904 timezoneBias
= CDateTimeSpan(0, 0, tz
.bias
+ tz
.standardBias
, 0);
906 case KODI::TIME::KODI_TIME_ZONE_ID_UNKNOWN
:
907 timezoneBias
= CDateTimeSpan(0, 0, tz
.bias
, 0);
915 bool CDateTime::SetFromUTCDateTime(const time_t &dateTime
)
917 CDateTime
tmp(dateTime
);
918 return SetFromUTCDateTime(tmp
);
921 bool CDateTime::SetFromW3CDate(const std::string
&dateTime
)
925 size_t posT
= dateTime
.find('T');
926 if(posT
!= std::string::npos
)
927 date
= dateTime
.substr(0, posT
);
931 int year
= 0, month
= 1, day
= 1;
933 if (date
.size() >= 4)
934 year
= atoi(date
.substr(0, 4).c_str());
936 if (date
.size() >= 10)
938 month
= atoi(date
.substr(5, 2).c_str());
939 day
= atoi(date
.substr(8, 2).c_str());
942 CDateTime
tmpDateTime(year
, month
, day
, 0, 0, 0);
943 if (tmpDateTime
.IsValid())
949 bool CDateTime::SetFromW3CDateTime(const std::string
&dateTime
, bool ignoreTimezone
/* = false */)
951 std::string date
, time
, zone
;
953 size_t posT
= dateTime
.find('T');
954 if(posT
!= std::string::npos
)
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);
962 time
= dateTime
.substr(posT
+ 1, posZ
- posT
- 1);
963 zone
= dateTime
.substr(posZ
);
969 int year
= 0, month
= 1, day
= 1, hour
= 0, min
= 0, sec
= 0;
971 if (date
.size() >= 4)
972 year
= atoi(date
.substr(0, 4).c_str());
974 if (date
.size() >= 10)
976 month
= atoi(date
.substr(5, 2).c_str());
977 day
= atoi(date
.substr(8, 2).c_str());
980 if (time
.length() >= 5)
982 hour
= atoi(time
.substr(0, 2).c_str());
983 min
= atoi(time
.substr(3, 2).c_str());
986 if (time
.length() >= 8)
987 sec
= atoi(time
.substr(6, 2).c_str());
989 CDateTime
tmpDateTime(year
, month
, day
, hour
, min
, sec
);
990 if (!tmpDateTime
.IsValid())
993 if (!ignoreTimezone
&& !zone
.empty())
995 // check if the timezone is UTC
996 if (StringUtils::StartsWith(zone
, "Z"))
997 return SetFromUTCDateTime(tmpDateTime
);
1000 // retrieve the timezone offset (ignoring the + or -)
1001 CDateTimeSpan zoneSpan
; zoneSpan
.SetFromTimeString(zone
.substr(1));
1002 if (zoneSpan
.GetSecondsTotal() != 0)
1004 if (StringUtils::StartsWith(zone
, "+"))
1005 tmpDateTime
-= zoneSpan
;
1006 else if (StringUtils::StartsWith(zone
, "-"))
1007 tmpDateTime
+= zoneSpan
;
1012 *this = tmpDateTime
;
1016 bool CDateTime::SetFromDBDateTime(const std::string
&dateTime
)
1018 // assumes format YYYY-MM-DD HH:MM:SS
1019 if (dateTime
.size() == 19)
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
);
1032 bool CDateTime::SetFromDBDate(const std::string
&date
)
1034 if (date
.size() < 10)
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
)
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());
1046 else if (sep_chars
.find(date
[4]) != std::string::npos
)
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());
1052 return SetDate(year
, month
, day
);
1055 bool CDateTime::SetFromDBTime(const std::string
&time
)
1057 if (time
.size() < 5)
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());
1068 if (time
.size() == 8)
1069 second
= atoi(time
.substr(6, 2).c_str());
1071 return SetTime(hour
, minute
, second
);
1074 bool CDateTime::SetFromRFC1123DateTime(const std::string
&dateTime
)
1076 std::string date
= dateTime
;
1077 StringUtils::Trim(date
);
1079 if (date
.size() != 29)
1082 int day
= strtol(date
.substr(5, 2).c_str(), NULL
, 10);
1084 std::string strMonth
= date
.substr(8, 3);
1086 for (unsigned int index
= 0; index
< 12; index
++)
1088 if (strMonth
== MONTH_NAMES
[index
])
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);
1103 return SetDateTime(year
, month
, day
, hour
, min
, sec
);
1106 CDateTime
CDateTime::FromDateString(const std::string
&date
)
1109 dt
.SetFromDateString(date
);
1113 CDateTime
CDateTime::FromDBDateTime(const std::string
&dateTime
)
1116 dt
.SetFromDBDateTime(dateTime
);
1120 CDateTime
CDateTime::FromDBDate(const std::string
&date
)
1123 dt
.SetFromDBDate(date
);
1127 CDateTime
CDateTime::FromDBTime(const std::string
&time
)
1130 dt
.SetFromDBTime(time
);
1134 CDateTime
CDateTime::FromW3CDate(const std::string
&date
)
1137 dt
.SetFromW3CDate(date
);
1141 CDateTime
CDateTime::FromW3CDateTime(const std::string
&date
, bool ignoreTimezone
/* = false */)
1144 dt
.SetFromW3CDateTime(date
, ignoreTimezone
);
1148 CDateTime
CDateTime::FromUTCDateTime(const CDateTime
&dateTime
)
1151 dt
.SetFromUTCDateTime(dateTime
);
1155 CDateTime
CDateTime::FromUTCDateTime(const time_t &dateTime
)
1158 dt
.SetFromUTCDateTime(dateTime
);
1162 CDateTime
CDateTime::FromRFC1123DateTime(const std::string
&dateTime
)
1165 dt
.SetFromRFC1123DateTime(dateTime
);
1169 std::string
CDateTime::GetAsLocalizedTime(const std::string
&format
, bool withSeconds
) const
1172 const std::string
& strFormat
= format
.empty() ? g_langInfo
.GetTimeFormat() : format
;
1174 KODI::TIME::SystemTime dateTime
;
1175 GetAsSystemTime(dateTime
);
1177 // Prefetch meridiem symbol
1178 const std::string
& strMeridiem
=
1179 CLangInfo::MeridiemSymbolToString(dateTime
.hour
> 11 ? MeridiemSymbolPM
: MeridiemSymbolAM
);
1181 size_t length
= strFormat
.size();
1182 for (size_t i
=0; i
< length
; ++i
)
1184 char c
=strFormat
[i
];
1187 // To be able to display a "'" in the string,
1188 // find the last "'" that doesn't follow a "'"
1190 while(((pos
= strFormat
.find(c
, pos
+ 1)) != std::string::npos
&&
1191 pos
<strFormat
.size()) && strFormat
[pos
+1]=='\'') {}
1193 std::string strPart
;
1194 if (pos
!= std::string::npos
)
1196 // Extract string between ' '
1197 strPart
=strFormat
.substr(i
+ 1, pos
- i
- 1);
1202 strPart
=strFormat
.substr(i
+ 1, length
- i
- 1);
1206 StringUtils::Replace(strPart
, "''", "'");
1210 else if (c
=='h' || c
=='H') // parse hour (H="24 hour clock")
1214 int pos
=strFormat
.find_first_not_of(c
,i
+1);
1217 // Get length of the hour mask, eg. HH
1223 // mask ends at the end of the string, extract it
1224 partLength
=length
-i
;
1228 int hour
= dateTime
.hour
;
1230 { // recalc to 12 hour clock
1232 hour
-= (12 * (hour
> 12));
1234 hour
+= (12 * (hour
< 1));
1237 // Format hour string with the length of the mask
1240 str
= std::to_string(hour
);
1242 str
= StringUtils::Format("{:02}", hour
);
1246 else if (c
=='m') // parse minutes
1250 int pos
=strFormat
.find_first_not_of(c
,i
+1);
1253 // Get length of the minute mask, eg. mm
1259 // mask ends at the end of the string, extract it
1260 partLength
=length
-i
;
1264 // Format minute string with the length of the mask
1267 str
= std::to_string(dateTime
.minute
);
1269 str
= StringUtils::Format("{:02}", dateTime
.minute
);
1273 else if (c
=='s') // parse seconds
1277 int pos
=strFormat
.find_first_not_of(c
,i
+1);
1280 // Get length of the seconds mask, eg. ss
1286 // mask ends at the end of the string, extract it
1287 partLength
=length
-i
;
1293 // Format seconds string with the length of the mask
1296 str
= std::to_string(dateTime
.second
);
1298 str
= StringUtils::Format("{:02}", dateTime
.second
);
1303 strOut
.erase(strOut
.size()-1,1);
1305 else if (c
=='x') // add meridiem symbol
1307 int pos
=strFormat
.find_first_not_of(c
,i
+1);
1310 // Get length of the meridiem mask
1315 // mask ends at the end of the string, extract it
1319 strOut
+=strMeridiem
;
1321 else // everything else pass to output
1328 std::string
CDateTime::GetAsLocalizedDate(bool longDate
/*=false*/) const
1330 return GetAsLocalizedDate(g_langInfo
.GetDateFormat(longDate
));
1333 std::string
CDateTime::GetAsLocalizedDate(const std::string
&strFormat
) const
1335 return GetAsLocalizedDate(strFormat
, ReturnFormat::CHOICE_NO
);
1338 std::string
CDateTime::GetAsLocalizedDate(const std::string
& strFormat
,
1339 ReturnFormat returnFormat
) const
1344 KODI::TIME::SystemTime dateTime
;
1345 GetAsSystemTime(dateTime
);
1347 size_t length
= strFormat
.size();
1348 for (size_t i
= 0; i
< length
; ++i
)
1350 char c
=strFormat
[i
];
1353 // To be able to display a "'" in the string,
1354 // find the last "'" that doesn't follow a "'"
1356 while(((pos
= strFormat
.find(c
, pos
+ 1)) != std::string::npos
&&
1357 pos
< strFormat
.size()) &&
1358 strFormat
[pos
+ 1] == '\'') {}
1360 std::string strPart
;
1361 if (pos
!= std::string::npos
)
1363 // Extract string between ' '
1364 strPart
= strFormat
.substr(i
+ 1, pos
- i
- 1);
1369 strPart
= strFormat
.substr(i
+ 1, length
- i
- 1);
1372 StringUtils::Replace(strPart
, "''", "'");
1376 else if (c
=='D' || c
=='d') // parse days
1378 size_t partLength
=0;
1380 size_t pos
= strFormat
.find_first_not_of(c
, i
+1);
1381 if (pos
!= std::string::npos
)
1383 // Get length of the day mask, eg. DDDD
1389 // mask ends at the end of the string, extract it
1390 partLength
=length
-i
;
1394 // Format string with the length of the mask
1396 if (partLength
==1) // single-digit number
1398 str
= std::to_string(dateTime
.day
);
1401 else if (partLength
==2) // two-digit number
1403 str
= StringUtils::Format("{:02}", dateTime
.day
);
1406 else // Day of week string
1408 int wday
= dateTime
.dayOfWeek
;
1409 if (wday
< 1 || wday
> 7) wday
= 7;
1411 str
= g_localizeStrings
.Get((c
== 'd' ? 40 : 10) + wday
);
1412 fmtOut
+= (c
== 'd' ? "%a" : "%A");
1417 else if (c
=='M' || c
=='m') // parse month
1419 size_t partLength
=0;
1421 size_t pos
=strFormat
.find_first_not_of(c
,i
+1);
1422 if (pos
!= std::string::npos
)
1424 // Get length of the month mask, eg. MMMM
1430 // mask ends at the end of the string, extract it
1431 partLength
=length
-i
;
1435 // Format string with the length of the mask
1437 if (partLength
==1) // single-digit number
1439 str
= std::to_string(dateTime
.month
);
1442 else if (partLength
==2) // two-digit number
1444 str
= StringUtils::Format("{:02}", dateTime
.month
);
1447 else // Month string
1449 int wmonth
= dateTime
.month
;
1450 if (wmonth
< 1 || wmonth
> 12) wmonth
= 12;
1452 str
= g_localizeStrings
.Get((c
== 'm' ? 50 : 20) + wmonth
);
1453 fmtOut
+= (c
== 'm' ? "%b" : "%B");
1458 else if (c
=='Y' || c
=='y') // parse year
1460 size_t partLength
= 0;
1462 size_t pos
= strFormat
.find_first_not_of(c
,i
+1);
1463 if (pos
!= std::string::npos
)
1465 // Get length of the year mask, eg. YYYY
1471 // mask ends at the end of the string, extract it
1472 partLength
=length
-i
;
1476 // Format string with the length of the mask
1477 std::string str
= std::to_string(dateTime
.year
); // four-digit number
1478 if (partLength
<= 2)
1480 str
.erase(0, 2); // two-digit number
1490 else // everything else pass to output
1497 return (returnFormat
== ReturnFormat::CHOICE_YES
? fmtOut
: strOut
);
1500 std::string
CDateTime::GetAsLocalizedDateTime(bool longDate
/*=false*/, bool withSeconds
/*=true*/) const
1502 return GetAsLocalizedDate(longDate
) + ' ' + GetAsLocalizedTime("", withSeconds
);
1505 std::string
CDateTime::GetAsLocalizedTime(TIME_FORMAT format
, bool withSeconds
/* = false */) const
1507 const std::string timeFormat
= g_langInfo
.GetTimeFormat();
1508 bool use12hourclock
= timeFormat
.find('h') != std::string::npos
;
1511 case TIME_FORMAT_GUESS
:
1512 return GetAsLocalizedTime("", withSeconds
);
1513 case TIME_FORMAT_SS
:
1514 return GetAsLocalizedTime("ss", true);
1515 case TIME_FORMAT_MM
:
1516 return GetAsLocalizedTime("mm", true);
1517 case TIME_FORMAT_MM_SS
:
1518 return GetAsLocalizedTime("mm:ss", true);
1519 case TIME_FORMAT_HH
: // this forces it to a 12 hour clock
1520 return GetAsLocalizedTime(use12hourclock
? "h" : "HH", false);
1521 case TIME_FORMAT_HH_SS
:
1522 return GetAsLocalizedTime(use12hourclock
? "h:ss" : "HH:ss", true);
1523 case TIME_FORMAT_HH_MM
:
1524 return GetAsLocalizedTime(use12hourclock
? "h:mm" : "HH:mm", false);
1525 case TIME_FORMAT_HH_MM_XX
:
1526 return GetAsLocalizedTime(use12hourclock
? "h:mm xx" : "HH:mm", false);
1527 case TIME_FORMAT_HH_MM_SS
:
1528 return GetAsLocalizedTime(use12hourclock
? "hh:mm:ss" : "HH:mm:ss", true);
1529 case TIME_FORMAT_HH_MM_SS_XX
:
1530 return GetAsLocalizedTime(use12hourclock
? "hh:mm:ss xx" : "HH:mm:ss", true);
1532 return GetAsLocalizedTime("h", false);
1534 return GetAsLocalizedTime("m", false);
1535 case TIME_FORMAT_H_MM_SS
:
1536 return GetAsLocalizedTime("h:mm:ss", true);
1537 case TIME_FORMAT_H_MM_SS_XX
:
1538 return GetAsLocalizedTime("h:mm:ss xx", true);
1539 case TIME_FORMAT_XX
:
1540 return use12hourclock
? GetAsLocalizedTime("xx", false) : "";
1544 return GetAsLocalizedTime("", false);
1547 CDateTime
CDateTime::GetAsUTCDateTime() const
1549 CDateTime
time(m_time
);
1550 time
+= GetTimezoneBias();
1554 std::string
CDateTime::GetAsRFC1123DateTime() const
1556 CDateTime
time(GetAsUTCDateTime());
1558 int weekDay
= time
.GetDayOfWeek();
1561 else if (weekDay
> 6)
1563 if (weekDay
!= time
.GetDayOfWeek())
1564 CLog::Log(LOGWARNING
, "Invalid day of week {} in {}", time
.GetDayOfWeek(),
1565 time
.GetAsDBDateTime());
1567 int month
= time
.GetMonth();
1570 else if (month
> 12)
1572 if (month
!= time
.GetMonth())
1573 CLog::Log(LOGWARNING
, "Invalid month {} in {}", time
.GetMonth(), time
.GetAsDBDateTime());
1575 return StringUtils::Format("{}, {:02} {} {:04} {:02}:{:02}:{:02} GMT", DAY_NAMES
[weekDay
],
1576 time
.GetDay(), MONTH_NAMES
[month
- 1], time
.GetYear(), time
.GetHour(),
1577 time
.GetMinute(), time
.GetSecond());
1580 std::string
CDateTime::GetAsW3CDate() const
1582 KODI::TIME::SystemTime st
;
1583 GetAsSystemTime(st
);
1585 return StringUtils::Format("{:04}-{:02}-{:02}", st
.year
, st
.month
, st
.day
);
1588 std::string
CDateTime::GetAsW3CDateTime(bool asUtc
/* = false */) const
1590 CDateTime w3cDate
= *this;
1592 w3cDate
= GetAsUTCDateTime();
1593 KODI::TIME::SystemTime st
;
1594 w3cDate
.GetAsSystemTime(st
);
1596 std::string result
= StringUtils::Format("{:04}-{:02}-{:02}T{:02}:{:02}:{:02}", st
.year
, st
.month
,
1597 st
.day
, st
.hour
, st
.minute
, st
.second
);
1599 return result
+ "Z";
1601 CDateTimeSpan bias
= GetTimezoneBias();
1602 return result
+ StringUtils::Format("{}{:02}:{:02}", (bias
.GetSecondsTotal() >= 0 ? '+' : '-'),
1603 abs(bias
.GetHours()), abs(bias
.GetMinutes()));
1606 int CDateTime::MonthStringToMonthNum(const std::string
& month
)
1608 const char* months
[] = {"january","february","march","april","may","june","july","august","september","october","november","december"};
1609 const char* abr_months
[] = {"jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec"};
1612 for (; i
< 12 && !StringUtils::EqualsNoCase(month
, months
[i
]) && !StringUtils::EqualsNoCase(month
, abr_months
[i
]); i
++);