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