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 "utils/XTimeUtils.h"
10 
11 #include "PosixTimezone.h"
12 
13 #include <errno.h>
14 #include <time.h>
15 
16 #include <sched.h>
17 #include <sys/times.h>
18 #include <unistd.h>
19 
20 #if defined(TARGET_DARWIN)
21 #include "threads/Atomics.h"
22 #endif
23 
24 #if defined(TARGET_ANDROID) && !defined(__LP64__)
25 #include <time64.h>
26 #endif
27 
28 #define WIN32_TIME_OFFSET ((unsigned long long)(369 * 365 + 89) * 24 * 3600 * 10000000)
29 
30 namespace KODI
31 {
32 namespace TIME
33 {
34 
35 /*
36  * A Leap year is any year that is divisible by four, but not by 100 unless also
37  * divisible by 400
38  */
39 #define IsLeapYear(y) ((!(y % 4)) ? (((!(y % 400)) && (y % 100)) ? 1 : 0) : 0)
40 
Sleep(uint32_t milliSeconds)41 void Sleep(uint32_t milliSeconds)
42 {
43 #if _POSIX_PRIORITY_SCHEDULING
44   if (milliSeconds == 0)
45   {
46     sched_yield();
47     return;
48   }
49 #endif
50 
51   usleep(milliSeconds * 1000);
52 }
53 
GetTimeZoneInformation(TimeZoneInformation * timeZoneInformation)54 uint32_t GetTimeZoneInformation(TimeZoneInformation* timeZoneInformation)
55 {
56   if (!timeZoneInformation)
57     return KODI_TIME_ZONE_ID_INVALID;
58 
59   struct tm t;
60   time_t tt = time(NULL);
61   if (localtime_r(&tt, &t))
62     timeZoneInformation->bias = -t.tm_gmtoff / 60;
63 
64   timeZoneInformation->standardName = tzname[0];
65   timeZoneInformation->daylightName = tzname[1];
66 
67   return KODI_TIME_ZONE_ID_UNKNOWN;
68 }
69 
GetLocalTime(SystemTime * systemTime)70 void GetLocalTime(SystemTime* systemTime)
71 {
72   const time_t t = time(NULL);
73   struct tm now;
74 
75   localtime_r(&t, &now);
76   systemTime->year = now.tm_year + 1900;
77   systemTime->month = now.tm_mon + 1;
78   systemTime->dayOfWeek = now.tm_wday;
79   systemTime->day = now.tm_mday;
80   systemTime->hour = now.tm_hour;
81   systemTime->minute = now.tm_min;
82   systemTime->second = now.tm_sec;
83   systemTime->milliseconds = 0;
84   // NOTE: localtime_r() is not required to set this, but we Assume that it's set here.
85   g_timezone.m_IsDST = now.tm_isdst;
86 }
87 
FileTimeToLocalFileTime(const FileTime * fileTime,FileTime * localFileTime)88 int FileTimeToLocalFileTime(const FileTime* fileTime, FileTime* localFileTime)
89 {
90   ULARGE_INTEGER l;
91   l.u.LowPart = fileTime->lowDateTime;
92   l.u.HighPart = fileTime->highDateTime;
93 
94   time_t ft;
95   struct tm tm_ft;
96   FileTimeToTimeT(fileTime, &ft);
97   localtime_r(&ft, &tm_ft);
98 
99   l.QuadPart += static_cast<unsigned long long>(tm_ft.tm_gmtoff) * 10000000;
100 
101   localFileTime->lowDateTime = l.u.LowPart;
102   localFileTime->highDateTime = l.u.HighPart;
103   return 1;
104 }
105 
SystemTimeToFileTime(const SystemTime * systemTime,FileTime * fileTime)106 int SystemTimeToFileTime(const SystemTime* systemTime, FileTime* fileTime)
107 {
108   static const int dayoffset[12] = {0, 31, 59, 90, 120, 151, 182, 212, 243, 273, 304, 334};
109 #if defined(TARGET_DARWIN)
110   static std::atomic_flag timegm_lock = ATOMIC_FLAG_INIT;
111 #endif
112 
113   struct tm sysTime = {};
114   sysTime.tm_year = systemTime->year - 1900;
115   sysTime.tm_mon = systemTime->month - 1;
116   sysTime.tm_wday = systemTime->dayOfWeek;
117   sysTime.tm_mday = systemTime->day;
118   sysTime.tm_hour = systemTime->hour;
119   sysTime.tm_min = systemTime->minute;
120   sysTime.tm_sec = systemTime->second;
121   sysTime.tm_yday = dayoffset[sysTime.tm_mon] + (sysTime.tm_mday - 1);
122   sysTime.tm_isdst = g_timezone.m_IsDST;
123 
124   // If this is a leap year, and we're past the 28th of Feb, increment tm_yday.
125   if (IsLeapYear(systemTime->year) && (sysTime.tm_yday > 58))
126     sysTime.tm_yday++;
127 
128 #if defined(TARGET_DARWIN)
129   CAtomicSpinLock lock(timegm_lock);
130 #endif
131 
132 #if defined(TARGET_ANDROID) && !defined(__LP64__)
133   time64_t t = timegm64(&sysTime);
134 #else
135   time_t t = timegm(&sysTime);
136 #endif
137 
138   LARGE_INTEGER result;
139   result.QuadPart = (long long)t * 10000000 + (long long)systemTime->milliseconds * 10000;
140   result.QuadPart += WIN32_TIME_OFFSET;
141 
142   fileTime->lowDateTime = result.u.LowPart;
143   fileTime->highDateTime = result.u.HighPart;
144 
145   return 1;
146 }
147 
CompareFileTime(const FileTime * fileTime1,const FileTime * fileTime2)148 long CompareFileTime(const FileTime* fileTime1, const FileTime* fileTime2)
149 {
150   ULARGE_INTEGER t1;
151   t1.u.LowPart = fileTime1->lowDateTime;
152   t1.u.HighPart = fileTime1->highDateTime;
153 
154   ULARGE_INTEGER t2;
155   t2.u.LowPart = fileTime2->lowDateTime;
156   t2.u.HighPart = fileTime2->highDateTime;
157 
158   if (t1.QuadPart == t2.QuadPart)
159      return 0;
160   else if (t1.QuadPart < t2.QuadPart)
161      return -1;
162   else
163      return 1;
164 }
165 
FileTimeToSystemTime(const FileTime * fileTime,SystemTime * systemTime)166 int FileTimeToSystemTime(const FileTime* fileTime, SystemTime* systemTime)
167 {
168   LARGE_INTEGER file;
169   file.u.LowPart = fileTime->lowDateTime;
170   file.u.HighPart = fileTime->highDateTime;
171 
172   file.QuadPart -= WIN32_TIME_OFFSET;
173   file.QuadPart /= 10000; /* to milliseconds */
174   systemTime->milliseconds = file.QuadPart % 1000;
175   file.QuadPart /= 1000; /* to seconds */
176 
177   time_t ft = file.QuadPart;
178 
179   struct tm tm_ft;
180   gmtime_r(&ft,&tm_ft);
181 
182   systemTime->year = tm_ft.tm_year + 1900;
183   systemTime->month = tm_ft.tm_mon + 1;
184   systemTime->dayOfWeek = tm_ft.tm_wday;
185   systemTime->day = tm_ft.tm_mday;
186   systemTime->hour = tm_ft.tm_hour;
187   systemTime->minute = tm_ft.tm_min;
188   systemTime->second = tm_ft.tm_sec;
189 
190   return 1;
191 }
192 
LocalFileTimeToFileTime(const FileTime * localFileTime,FileTime * fileTime)193 int LocalFileTimeToFileTime(const FileTime* localFileTime, FileTime* fileTime)
194 {
195   ULARGE_INTEGER l;
196   l.u.LowPart = localFileTime->lowDateTime;
197   l.u.HighPart = localFileTime->highDateTime;
198 
199   l.QuadPart += (unsigned long long) timezone * 10000000;
200 
201   fileTime->lowDateTime = l.u.LowPart;
202   fileTime->highDateTime = l.u.HighPart;
203 
204   return 1;
205 }
206 
207 
FileTimeToTimeT(const FileTime * localFileTime,time_t * pTimeT)208 int FileTimeToTimeT(const FileTime* localFileTime, time_t* pTimeT)
209 {
210   if (!localFileTime || !pTimeT)
211     return false;
212 
213   ULARGE_INTEGER fileTime;
214   fileTime.u.LowPart = localFileTime->lowDateTime;
215   fileTime.u.HighPart = localFileTime->highDateTime;
216 
217   fileTime.QuadPart -= WIN32_TIME_OFFSET;
218   fileTime.QuadPart /= 10000; /* to milliseconds */
219   fileTime.QuadPart /= 1000; /* to seconds */
220 
221   time_t ft = fileTime.QuadPart;
222 
223   struct tm tm_ft;
224   localtime_r(&ft,&tm_ft);
225 
226   *pTimeT = mktime(&tm_ft);
227   return 1;
228 }
229 
TimeTToFileTime(time_t timeT,FileTime * localFileTime)230 int TimeTToFileTime(time_t timeT, FileTime* localFileTime)
231 {
232   if (!localFileTime)
233     return false;
234 
235   ULARGE_INTEGER result;
236   result.QuadPart = (unsigned long long) timeT * 10000000;
237   result.QuadPart += WIN32_TIME_OFFSET;
238 
239   localFileTime->lowDateTime = result.u.LowPart;
240   localFileTime->highDateTime = result.u.HighPart;
241 
242   return 1;
243 }
244 
245 } // namespace TIME
246 } // namespace KODI
247