[XAudio2] avoid leak + fix voice creation for closest match
[xbmc.git] / xbmc / XBDateTime.cpp
blobb0029af6816fcc2f70c1036fb51b8e6647e8ced2
1 /*
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.
7 */
9 #include "XBDateTime.h"
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"
18 #include <cstdlib>
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 /////////////////////////////////////////////////
30 // CDateTimeSpan
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);
94 return left;
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);
111 return left;
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);
126 return *this;
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);
141 return *this;
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)
158 LARGE_INTEGER time;
159 ToLargeInt(time);
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;
166 FromLargeInt(time);
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
181 LARGE_INTEGER time;
182 ToLargeInt(time);
184 return (int)(time.QuadPart/SECONDS_TO_FILETIME)/SECONDS_PER_DAY;
187 int CDateTimeSpan::GetHours() const
189 LARGE_INTEGER time;
190 ToLargeInt(time);
192 return (int)((time.QuadPart/SECONDS_TO_FILETIME)%SECONDS_PER_DAY)/SECONDS_PER_HOUR;
195 int CDateTimeSpan::GetMinutes() const
197 LARGE_INTEGER time;
198 ToLargeInt(time);
200 return (int)((time.QuadPart/SECONDS_TO_FILETIME%SECONDS_PER_DAY)%SECONDS_PER_HOUR)/SECONDS_PER_MINUTE;
203 int CDateTimeSpan::GetSeconds() const
205 LARGE_INTEGER time;
206 ToLargeInt(time);
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
213 LARGE_INTEGER time;
214 ToLargeInt(time);
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"))
228 days *= 7;
229 else if (StringUtils::EqualsNoCase(units, "mon"))
230 days *= 31;
233 SetDateTimeSpan(days, 0, 0, 0);
236 /////////////////////////////////////////////////
238 // CDateTime
241 CDateTime::CDateTime()
243 Reset();
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)
254 SetValid(true);
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();
290 return time;
293 const CDateTime& CDateTime::operator=(const KODI::TIME::SystemTime& right)
295 m_state = ToFileTime(right, m_time) ? valid : invalid;
297 return *this;
300 const CDateTime& CDateTime::operator=(const KODI::TIME::FileTime& right)
302 m_time=right;
303 SetValid(true);
305 return *this;
308 const CDateTime& CDateTime::operator =(const time_t& right)
310 m_state = ToFileTime(right, m_time) ? valid : invalid;
312 return *this;
315 const CDateTime& CDateTime::operator =(const tm& right)
317 m_state = ToFileTime(right, m_time) ? valid : invalid;
319 return *this;
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);
513 return left;
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);
530 return left;
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);
545 return *this;
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);
560 return *this;
563 CDateTimeSpan CDateTime::operator -(const CDateTime& right) const
565 CDateTimeSpan left;
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);
580 return left;
583 CDateTime::operator KODI::TIME::FileTime() const
585 return m_time;
588 void CDateTime::Archive(CArchive& ar)
590 if (ar.IsStoring())
592 ar<<(int)m_state;
593 if (m_state==valid)
595 KODI::TIME::SystemTime st;
596 GetAsSystemTime(st);
597 ar<<st;
600 else
602 Reset();
603 int state;
604 ar >> state;
605 m_state = CDateTime::STATE(state);
606 if (m_state==valid)
608 KODI::TIME::SystemTime st;
609 ar>>st;
610 ToFileTime(st, m_time);
615 void CDateTime::Reset()
617 SetDateTime(1601, 1, 1, 0, 0, 0);
618 SetValid(false);
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
639 long long ll = time;
640 ll *= 10000000ll;
641 ll += 0x19DB1DED53E8000LL;
643 fileTime.lowDateTime = (DWORD)(ll & 0xFFFFFFFF);
644 fileTime.highDateTime = (DWORD)(ll >> 32);
646 return true;
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
679 if (date.empty())
681 SetValid(false);
682 return false;
685 if (SetFromDBDate(date))
686 return true;
688 const char* months[] = {"january","february","march","april","may","june","july","august","september","october","november","december",NULL};
689 int j=0;
690 size_t iDayPos = date.find("day");
691 size_t iPos = date.find(' ');
692 if (iDayPos < iPos && iDayPos != std::string::npos)
694 iDayPos = iPos + 1;
695 iPos = date.find(' ', iPos+1);
697 else
698 iDayPos = 0;
700 std::string strMonth = date.substr(iDayPos, iPos - iDayPos);
701 if (strMonth.empty())
702 return false;
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)
708 j++;
709 if (!months[j])
710 return false;
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;
718 GetAsSystemTime(st);
720 return st.day;
723 int CDateTime::GetMonth() const
725 KODI::TIME::SystemTime st;
726 GetAsSystemTime(st);
728 return st.month;
731 int CDateTime::GetYear() const
733 KODI::TIME::SystemTime st;
734 GetAsSystemTime(st);
736 return st.year;
739 int CDateTime::GetHour() const
741 KODI::TIME::SystemTime st;
742 GetAsSystemTime(st);
744 return st.hour;
747 int CDateTime::GetMinute() const
749 KODI::TIME::SystemTime st;
750 GetAsSystemTime(st);
752 return st.minute;
755 int CDateTime::GetSecond() const
757 KODI::TIME::SystemTime st;
758 GetAsSystemTime(st);
760 return st.second;
763 int CDateTime::GetDayOfWeek() const
765 KODI::TIME::SystemTime st;
766 GetAsSystemTime(st);
768 return st.dayOfWeek;
771 int CDateTime::GetMinuteOfDay() const
773 KODI::TIME::SystemTime st;
774 GetAsSystemTime(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 = {};
782 st.year = year;
783 st.month = month;
784 st.day = day;
785 st.hour = hour;
786 st.minute = minute;
787 st.second = second;
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;
819 GetAsSystemTime(st);
821 time = {};
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;
829 time.tm_isdst = -1;
831 mktime(&time);
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;
842 GetAsSystemTime(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;
850 GetAsSystemTime(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;
858 GetAsSystemTime(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;
867 GetAsSystemTime(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();
878 m_time = tmp.m_time;
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);
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;
912 return timezoneBias;
915 bool CDateTime::SetFromUTCDateTime(const time_t &dateTime)
917 CDateTime tmp(dateTime);
918 return SetFromUTCDateTime(tmp);
921 bool CDateTime::SetFromW3CDate(const std::string &dateTime)
923 std::string date;
925 size_t posT = dateTime.find('T');
926 if(posT != std::string::npos)
927 date = dateTime.substr(0, posT);
928 else
929 date = dateTime;
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())
944 *this = tmpDateTime;
946 return 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);
960 else
962 time = dateTime.substr(posT + 1, posZ - posT - 1);
963 zone = dateTime.substr(posZ);
966 else
967 date = dateTime;
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())
991 return false;
993 if (!ignoreTimezone && !zone.empty())
995 // check if the timezone is UTC
996 if (StringUtils::StartsWith(zone, "Z"))
997 return SetFromUTCDateTime(tmpDateTime);
998 else
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;
1013 return IsValid();
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);
1029 return false;
1032 bool CDateTime::SetFromDBDate(const std::string &date)
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)
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)
1058 return false;
1060 int hour;
1061 int minute;
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());
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)
1080 return false;
1082 int day = strtol(date.substr(5, 2).c_str(), NULL, 10);
1084 std::string strMonth = date.substr(8, 3);
1085 int month = 0;
1086 for (unsigned int index = 0; index < 12; index++)
1088 if (strMonth == MONTH_NAMES[index])
1090 month = index + 1;
1091 break;
1095 if (month < 1)
1096 return false;
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)
1108 CDateTime dt;
1109 dt.SetFromDateString(date);
1110 return dt;
1113 CDateTime CDateTime::FromDBDateTime(const std::string &dateTime)
1115 CDateTime dt;
1116 dt.SetFromDBDateTime(dateTime);
1117 return dt;
1120 CDateTime CDateTime::FromDBDate(const std::string &date)
1122 CDateTime dt;
1123 dt.SetFromDBDate(date);
1124 return dt;
1127 CDateTime CDateTime::FromDBTime(const std::string &time)
1129 CDateTime dt;
1130 dt.SetFromDBTime(time);
1131 return dt;
1134 CDateTime CDateTime::FromW3CDate(const std::string &date)
1136 CDateTime dt;
1137 dt.SetFromW3CDate(date);
1138 return dt;
1141 CDateTime CDateTime::FromW3CDateTime(const std::string &date, bool ignoreTimezone /* = false */)
1143 CDateTime dt;
1144 dt.SetFromW3CDateTime(date, ignoreTimezone);
1145 return dt;
1148 CDateTime CDateTime::FromUTCDateTime(const CDateTime &dateTime)
1150 CDateTime dt;
1151 dt.SetFromUTCDateTime(dateTime);
1152 return dt;
1155 CDateTime CDateTime::FromUTCDateTime(const time_t &dateTime)
1157 CDateTime dt;
1158 dt.SetFromUTCDateTime(dateTime);
1159 return dt;
1162 CDateTime CDateTime::FromRFC1123DateTime(const std::string &dateTime)
1164 CDateTime dt;
1165 dt.SetFromRFC1123DateTime(dateTime);
1166 return dt;
1169 std::string CDateTime::GetAsLocalizedTime(const std::string &format, bool withSeconds) const
1171 std::string strOut;
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];
1185 if (c=='\'')
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]=='\'') {}
1193 std::string strPart;
1194 if (pos != std::string::npos)
1196 // Extract string between ' '
1197 strPart=strFormat.substr(i + 1, pos - i - 1);
1198 i=pos;
1200 else
1202 strPart=strFormat.substr(i + 1, length - i - 1);
1203 i=length;
1206 StringUtils::Replace(strPart, "''", "'");
1208 strOut+=strPart;
1210 else if (c=='h' || c=='H') // parse hour (H="24 hour clock")
1212 int partLength=0;
1214 int pos=strFormat.find_first_not_of(c,i+1);
1215 if (pos>-1)
1217 // Get length of the hour mask, eg. HH
1218 partLength=pos-i;
1219 i=pos-1;
1221 else
1223 // mask ends at the end of the string, extract it
1224 partLength=length-i;
1225 i=length;
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));
1237 // Format hour string with the length of the mask
1238 std::string str;
1239 if (partLength==1)
1240 str = std::to_string(hour);
1241 else
1242 str = StringUtils::Format("{:02}", hour);
1244 strOut+=str;
1246 else if (c=='m') // parse minutes
1248 int partLength=0;
1250 int pos=strFormat.find_first_not_of(c,i+1);
1251 if (pos>-1)
1253 // Get length of the minute mask, eg. mm
1254 partLength=pos-i;
1255 i=pos-1;
1257 else
1259 // mask ends at the end of the string, extract it
1260 partLength=length-i;
1261 i=length;
1264 // Format minute string with the length of the mask
1265 std::string str;
1266 if (partLength==1)
1267 str = std::to_string(dateTime.minute);
1268 else
1269 str = StringUtils::Format("{:02}", dateTime.minute);
1271 strOut+=str;
1273 else if (c=='s') // parse seconds
1275 int partLength=0;
1277 int pos=strFormat.find_first_not_of(c,i+1);
1278 if (pos>-1)
1280 // Get length of the seconds mask, eg. ss
1281 partLength=pos-i;
1282 i=pos-1;
1284 else
1286 // mask ends at the end of the string, extract it
1287 partLength=length-i;
1288 i=length;
1291 if (withSeconds)
1293 // Format seconds string with the length of the mask
1294 std::string str;
1295 if (partLength==1)
1296 str = std::to_string(dateTime.second);
1297 else
1298 str = StringUtils::Format("{:02}", dateTime.second);
1300 strOut+=str;
1302 else
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);
1308 if (pos>-1)
1310 // Get length of the meridiem mask
1311 i=pos-1;
1313 else
1315 // mask ends at the end of the string, extract it
1316 i=length;
1319 strOut+=strMeridiem;
1321 else // everything else pass to output
1322 strOut+=c;
1325 return strOut;
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
1341 std::string strOut;
1342 std::string fmtOut;
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];
1351 if (c=='\'')
1353 // To be able to display a "'" in the string,
1354 // find the last "'" that doesn't follow a "'"
1355 size_t pos = i + 1;
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);
1365 i = pos;
1367 else
1369 strPart = strFormat.substr(i + 1, length - i - 1);
1370 i = length;
1372 StringUtils::Replace(strPart, "''", "'");
1373 strOut+=strPart;
1374 fmtOut += 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
1384 partLength=pos-i;
1385 i=pos-1;
1387 else
1389 // mask ends at the end of the string, extract it
1390 partLength=length-i;
1391 i=length;
1394 // Format string with the length of the mask
1395 std::string str;
1396 if (partLength==1) // single-digit number
1398 str = std::to_string(dateTime.day);
1399 fmtOut += "%-d";
1401 else if (partLength==2) // two-digit number
1403 str = StringUtils::Format("{:02}", dateTime.day);
1404 fmtOut += "%d";
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");
1415 strOut+=str;
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
1425 partLength=pos-i;
1426 i=pos-1;
1428 else
1430 // mask ends at the end of the string, extract it
1431 partLength=length-i;
1432 i=length;
1435 // Format string with the length of the mask
1436 std::string str;
1437 if (partLength==1) // single-digit number
1439 str = std::to_string(dateTime.month);
1440 fmtOut += "%-m";
1442 else if (partLength==2) // two-digit number
1444 str = StringUtils::Format("{:02}", dateTime.month);
1445 fmtOut += "%m";
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");
1456 strOut+=str;
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
1466 partLength=pos-i;
1467 i=pos-1;
1469 else
1471 // mask ends at the end of the string, extract it
1472 partLength=length-i;
1473 i=length;
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
1481 fmtOut += "%y";
1483 else
1485 fmtOut += "%Y";
1488 strOut += str;
1490 else // everything else pass to output
1492 strOut+=c;
1493 fmtOut += c;
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;
1509 switch (format)
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);
1531 case TIME_FORMAT_H:
1532 return GetAsLocalizedTime("h", false);
1533 case TIME_FORMAT_M:
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) : "";
1541 default:
1542 break;
1544 return GetAsLocalizedTime("", false);
1547 CDateTime CDateTime::GetAsUTCDateTime() const
1549 CDateTime time(m_time);
1550 time += GetTimezoneBias();
1551 return time;
1554 std::string CDateTime::GetAsRFC1123DateTime() const
1556 CDateTime time(GetAsUTCDateTime());
1558 int weekDay = time.GetDayOfWeek();
1559 if (weekDay < 0)
1560 weekDay = 0;
1561 else if (weekDay > 6)
1562 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();
1568 if (month < 1)
1569 month = 1;
1570 else if (month > 12)
1571 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;
1591 if (asUtc)
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);
1598 if (asUtc)
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"};
1611 int i = 0;
1612 for (; i < 12 && !StringUtils::EqualsNoCase(month, months[i]) && !StringUtils::EqualsNoCase(month, abr_months[i]); i++);
1613 i++;
1615 return i;