1 // Windows/TimeUtils.cpp
2
3 #include "StdAfx.h"
4
5 #ifndef _WIN32
6 #include <sys/time.h>
7 #endif
8
9 #include "Defs.h"
10 #include "TimeUtils.h"
11
12 namespace NWindows {
13 namespace NTime {
14
15 static const UInt32 kNumTimeQuantumsInSecond = 10000000;
16 static const UInt32 kFileTimeStartYear = 1601;
17 #if !defined(_WIN32) || defined(UNDER_CE)
18 static const UInt32 kDosTimeStartYear = 1980;
19 #endif
20 static const UInt32 kUnixTimeStartYear = 1970;
21 static const UInt64 kUnixTimeOffset =
22 (UInt64)60 * 60 * 24 * (89 + 365 * (kUnixTimeStartYear - kFileTimeStartYear));
23 static const UInt64 kNumSecondsInFileTime = (UInt64)(Int64)-1 / kNumTimeQuantumsInSecond;
24
DosTime_To_FileTime(UInt32 dosTime,FILETIME & ft)25 bool DosTime_To_FileTime(UInt32 dosTime, FILETIME &ft) throw()
26 {
27 #if defined(_WIN32) && !defined(UNDER_CE)
28 return BOOLToBool(::DosDateTimeToFileTime((UInt16)(dosTime >> 16), (UInt16)(dosTime & 0xFFFF), &ft));
29 #else
30 ft.dwLowDateTime = 0;
31 ft.dwHighDateTime = 0;
32 UInt64 res;
33 if (!GetSecondsSince1601(kDosTimeStartYear + (dosTime >> 25), (dosTime >> 21) & 0xF, (dosTime >> 16) & 0x1F,
34 (dosTime >> 11) & 0x1F, (dosTime >> 5) & 0x3F, (dosTime & 0x1F) * 2, res))
35 return false;
36 res *= kNumTimeQuantumsInSecond;
37 ft.dwLowDateTime = (UInt32)res;
38 ft.dwHighDateTime = (UInt32)(res >> 32);
39 return true;
40 #endif
41 }
42
43 static const UInt32 kHighDosTime = 0xFF9FBF7D;
44 static const UInt32 kLowDosTime = 0x210000;
45
FileTime_To_DosTime(const FILETIME & ft,UInt32 & dosTime)46 bool FileTime_To_DosTime(const FILETIME &ft, UInt32 &dosTime) throw()
47 {
48 #if defined(_WIN32) && !defined(UNDER_CE)
49
50 WORD datePart, timePart;
51 if (!::FileTimeToDosDateTime(&ft, &datePart, &timePart))
52 {
53 dosTime = (ft.dwHighDateTime >= 0x01C00000) ? kHighDosTime : kLowDosTime;
54 return false;
55 }
56 dosTime = (((UInt32)datePart) << 16) + timePart;
57
58 #else
59
60 #define PERIOD_4 (4 * 365 + 1)
61 #define PERIOD_100 (PERIOD_4 * 25 - 1)
62 #define PERIOD_400 (PERIOD_100 * 4 + 1)
63
64 unsigned year, mon, day, hour, min, sec;
65 UInt64 v64 = ft.dwLowDateTime | ((UInt64)ft.dwHighDateTime << 32);
66 Byte ms[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
67 unsigned temp;
68 UInt32 v;
69 v64 += (kNumTimeQuantumsInSecond * 2 - 1);
70 v64 /= kNumTimeQuantumsInSecond;
71 sec = (unsigned)(v64 % 60);
72 v64 /= 60;
73 min = (unsigned)(v64 % 60);
74 v64 /= 60;
75 hour = (unsigned)(v64 % 24);
76 v64 /= 24;
77
78 v = (UInt32)v64;
79
80 year = (unsigned)(kFileTimeStartYear + v / PERIOD_400 * 400);
81 v %= PERIOD_400;
82
83 temp = (unsigned)(v / PERIOD_100);
84 if (temp == 4)
85 temp = 3;
86 year += temp * 100;
87 v -= temp * PERIOD_100;
88
89 temp = v / PERIOD_4;
90 if (temp == 25)
91 temp = 24;
92 year += temp * 4;
93 v -= temp * PERIOD_4;
94
95 temp = v / 365;
96 if (temp == 4)
97 temp = 3;
98 year += temp;
99 v -= temp * 365;
100
101 if (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0))
102 ms[1] = 29;
103 for (mon = 1; mon <= 12; mon++)
104 {
105 unsigned s = ms[mon - 1];
106 if (v < s)
107 break;
108 v -= s;
109 }
110 day = (unsigned)v + 1;
111
112 dosTime = kLowDosTime;
113 if (year < kDosTimeStartYear)
114 return false;
115 year -= kDosTimeStartYear;
116 dosTime = kHighDosTime;
117 if (year >= 128)
118 return false;
119 dosTime = (year << 25) | (mon << 21) | (day << 16) | (hour << 11) | (min << 5) | (sec >> 1);
120 #endif
121 return true;
122 }
123
124
UtcFileTime_To_LocalDosTime(const FILETIME & utc,UInt32 & dosTime)125 bool UtcFileTime_To_LocalDosTime(const FILETIME &utc, UInt32 &dosTime) throw()
126 {
127 FILETIME loc = { 0, 0 };
128 const UInt64 u1 = FILETIME_To_UInt64(utc);
129 const UInt64 kDelta = ((UInt64)1 << 41); // it's larger than quantums in 1 sec.
130 if (u1 >= kDelta)
131 {
132 if (!FileTimeToLocalFileTime(&utc, &loc))
133 loc = utc;
134 else
135 {
136 const UInt64 u2 = FILETIME_To_UInt64(loc);
137 const UInt64 delta = u1 < u2 ? (u2 - u1) : (u1 - u2);
138 if (delta > kDelta) // if FileTimeToLocalFileTime() overflow, we use UTC time
139 loc = utc;
140 }
141 }
142 return FileTime_To_DosTime(loc, dosTime);
143 }
144
UnixTime_To_FileTime64(UInt32 unixTime)145 UInt64 UnixTime_To_FileTime64(UInt32 unixTime) throw()
146 {
147 return (kUnixTimeOffset + (UInt64)unixTime) * kNumTimeQuantumsInSecond;
148 }
149
UnixTime_To_FileTime(UInt32 unixTime,FILETIME & ft)150 void UnixTime_To_FileTime(UInt32 unixTime, FILETIME &ft) throw()
151 {
152 const UInt64 v = UnixTime_To_FileTime64(unixTime);
153 ft.dwLowDateTime = (DWORD)v;
154 ft.dwHighDateTime = (DWORD)(v >> 32);
155 }
156
UnixTime64_To_FileTime64(Int64 unixTime)157 UInt64 UnixTime64_To_FileTime64(Int64 unixTime) throw()
158 {
159 return (UInt64)((Int64)kUnixTimeOffset + unixTime) * kNumTimeQuantumsInSecond;
160 }
161
162
UnixTime64_To_FileTime64(Int64 unixTime,UInt64 & fileTime)163 bool UnixTime64_To_FileTime64(Int64 unixTime, UInt64 &fileTime) throw()
164 {
165 if (unixTime > (Int64)(kNumSecondsInFileTime - kUnixTimeOffset))
166 {
167 fileTime = (UInt64)(Int64)-1;
168 return false;
169 }
170 if (unixTime < -(Int64)kUnixTimeOffset)
171 {
172 fileTime = 0;
173 return false;
174 }
175 fileTime = UnixTime64_To_FileTime64(unixTime);
176 return true;
177 }
178
179
UnixTime64_To_FileTime(Int64 unixTime,FILETIME & ft)180 bool UnixTime64_To_FileTime(Int64 unixTime, FILETIME &ft) throw()
181 {
182 UInt64 v;
183 const bool res = UnixTime64_To_FileTime64(unixTime, v);
184 ft.dwLowDateTime = (DWORD)v;
185 ft.dwHighDateTime = (DWORD)(v >> 32);
186 return res;
187 }
188
189
FileTime_To_UnixTime64(const FILETIME & ft)190 Int64 FileTime_To_UnixTime64(const FILETIME &ft) throw()
191 {
192 const UInt64 winTime = (((UInt64)ft.dwHighDateTime) << 32) + ft.dwLowDateTime;
193 return (Int64)(winTime / kNumTimeQuantumsInSecond) - (Int64)kUnixTimeOffset;
194 }
195
FileTime_To_UnixTime64_and_Quantums(const FILETIME & ft,UInt32 & quantums)196 Int64 FileTime_To_UnixTime64_and_Quantums(const FILETIME &ft, UInt32 &quantums) throw()
197 {
198 const UInt64 winTime = (((UInt64)ft.dwHighDateTime) << 32) + ft.dwLowDateTime;
199 quantums = (UInt32)(winTime % kNumTimeQuantumsInSecond);
200 return (Int64)(winTime / kNumTimeQuantumsInSecond) - (Int64)kUnixTimeOffset;
201 }
202
FileTime_To_UnixTime(const FILETIME & ft,UInt32 & unixTime)203 bool FileTime_To_UnixTime(const FILETIME &ft, UInt32 &unixTime) throw()
204 {
205 UInt64 winTime = (((UInt64)ft.dwHighDateTime) << 32) + ft.dwLowDateTime;
206 winTime /= kNumTimeQuantumsInSecond;
207 if (winTime < kUnixTimeOffset)
208 {
209 unixTime = 0;
210 return false;
211 }
212 winTime -= kUnixTimeOffset;
213 if (winTime > (UInt32)0xFFFFFFFF)
214 {
215 unixTime = (UInt32)0xFFFFFFFF;
216 return false;
217 }
218 unixTime = (UInt32)winTime;
219 return true;
220 }
221
GetSecondsSince1601(unsigned year,unsigned month,unsigned day,unsigned hour,unsigned min,unsigned sec,UInt64 & resSeconds)222 bool GetSecondsSince1601(unsigned year, unsigned month, unsigned day,
223 unsigned hour, unsigned min, unsigned sec, UInt64 &resSeconds) throw()
224 {
225 resSeconds = 0;
226 if (year < kFileTimeStartYear || year >= 10000 || month < 1 || month > 12 ||
227 day < 1 || day > 31 || hour > 23 || min > 59 || sec > 59)
228 return false;
229 UInt32 numYears = year - kFileTimeStartYear;
230 UInt32 numDays = numYears * 365 + numYears / 4 - numYears / 100 + numYears / 400;
231 Byte ms[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
232 if (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0))
233 ms[1] = 29;
234 month--;
235 for (unsigned i = 0; i < month; i++)
236 numDays += ms[i];
237 numDays += day - 1;
238 resSeconds = ((UInt64)(numDays * 24 + hour) * 60 + min) * 60 + sec;
239 return true;
240 }
241
242
GetCurUtc_FiTime(CFiTime & ft)243 void GetCurUtc_FiTime(CFiTime &ft) throw()
244 {
245 #ifdef _WIN32
246
247 // Both variants provide same low resolution on WinXP: about 15 ms.
248 // But GetSystemTimeAsFileTime is much faster.
249 #ifdef UNDER_CE
250 SYSTEMTIME st;
251 GetSystemTime(&st);
252 SystemTimeToFileTime(&st, &ft);
253 #else
254 GetSystemTimeAsFileTime(&ft);
255 #endif
256
257 #else
258
259 FiTime_Clear(ft);
260 struct timeval now;
261 if (gettimeofday(&now, 0 ) == 0)
262 {
263 ft.tv_sec = now.tv_sec;
264 ft.tv_nsec = now.tv_usec * 1000;
265 }
266
267 #endif
268 }
269
270 #ifndef _WIN32
GetCurUtcFileTime(FILETIME & ft)271 void GetCurUtcFileTime(FILETIME &ft) throw()
272 {
273 UInt64 v = 0;
274 struct timeval now;
275 if (gettimeofday(&now, 0 ) == 0)
276 {
277 v = ((UInt64)now.tv_sec + kUnixTimeOffset) *
278 kNumTimeQuantumsInSecond + (UInt64)now.tv_usec * 10;
279 }
280 ft.dwLowDateTime = (DWORD)v;
281 ft.dwHighDateTime = (DWORD)(v >> 32);
282 }
283 #endif
284
285
286 }}
287
288
289 #ifdef _WIN32
290
291 /*
292 void FiTime_Normalize_With_Prec(CFiTime &ft, unsigned prec)
293 {
294 if (prec == k_PropVar_TimePrec_0
295 || prec == k_PropVar_TimePrec_HighPrec
296 || prec >= k_PropVar_TimePrec_100ns)
297 return;
298 UInt64 v = (((UInt64)ft.dwHighDateTime) << 32) + ft.dwLowDateTime;
299
300 int numDigits = (int)prec - (int)k_PropVar_TimePrec_Base;
301 UInt32 d;
302 if (prec == k_PropVar_TimePrec_DOS)
303 {
304 // we round up as windows DosDateTimeToFileTime()
305 v += NWindows::NTime::kNumTimeQuantumsInSecond * 2 - 1;
306 d = NWindows::NTime::kNumTimeQuantumsInSecond * 2;
307 }
308 else
309 {
310 if (prec == k_PropVar_TimePrec_Unix)
311 numDigits = 0;
312 else if (numDigits < 0)
313 return;
314 d = 1;
315 for (unsigned k = numDigits; k < 7; k++)
316 d *= 10;
317 }
318 v /= d;
319 v *= d;
320 ft.dwLowDateTime = (DWORD)v;
321 ft.dwHighDateTime = (DWORD)(v >> 32);
322 }
323 */
324
325 #else
326
327 /*
328 void FiTime_Normalize_With_Prec(CFiTime &ft, unsigned prec)
329 {
330 if (prec >= k_PropVar_TimePrec_1ns
331 || prec == k_PropVar_TimePrec_HighPrec)
332 return;
333
334 int numDigits = (int)prec - (int)k_PropVar_TimePrec_Base;
335 UInt32 d;
336 if (prec == k_PropVar_TimePrec_Unix ||
337 prec == (int)k_PropVar_TimePrec_Base)
338 {
339 ft.tv_nsec = 0;
340 return;
341 }
342 if (prec == k_PropVar_TimePrec_DOS)
343 {
344 // we round up as windows DosDateTimeToFileTime()
345 const unsigned sec1 = (ft.tv_sec & 1);
346 if (ft.tv_nsec == 0 && sec1 == 0)
347 return;
348 ft.tv_nsec = 0;
349 ft.tv_sec += 2 - sec1;
350 return;
351 }
352 {
353 if (prec == k_PropVar_TimePrec_0
354 || numDigits < 0)
355 numDigits = 7;
356 d = 1;
357 for (unsigned k = numDigits; k < 9; k++)
358 d *= 10;
359 ft.tv_nsec /= d;
360 ft.tv_nsec *= d;
361 }
362 }
363 */
364
Compare_FiTime(const CFiTime * a1,const CFiTime * a2)365 int Compare_FiTime(const CFiTime *a1, const CFiTime *a2)
366 {
367 if (a1->tv_sec < a2->tv_sec) return -1;
368 if (a1->tv_sec > a2->tv_sec) return 1;
369 if (a1->tv_nsec < a2->tv_nsec) return -1;
370 if (a1->tv_nsec > a2->tv_nsec) return 1;
371 return 0;
372 }
373
FILETIME_To_timespec(const FILETIME & ft,timespec & ts)374 bool FILETIME_To_timespec(const FILETIME &ft, timespec &ts)
375 {
376 UInt32 quantums;
377 const Int64 sec = NWindows::NTime::FileTime_To_UnixTime64_and_Quantums(ft, quantums);
378 // time_t is long
379 const time_t sec2 = (time_t)sec;
380 if (sec2 == sec)
381 {
382 ts.tv_sec = sec2;
383 ts.tv_nsec = (long)(quantums * 100);
384 return true;
385 }
386 return false;
387 }
388
FiTime_To_FILETIME_ns100(const CFiTime & ts,FILETIME & ft,unsigned & ns100)389 void FiTime_To_FILETIME_ns100(const CFiTime &ts, FILETIME &ft, unsigned &ns100)
390 {
391 const UInt64 v = NWindows::NTime::UnixTime64_To_FileTime64(ts.tv_sec) + ((UInt64)ts.tv_nsec / 100);
392 ns100 = (unsigned)((UInt64)ts.tv_nsec % 100);
393 ft.dwLowDateTime = (DWORD)v;
394 ft.dwHighDateTime = (DWORD)(v >> 32);
395 }
396
FiTime_To_FILETIME(const CFiTime & ts,FILETIME & ft)397 void FiTime_To_FILETIME(const CFiTime &ts, FILETIME &ft)
398 {
399 const UInt64 v = NWindows::NTime::UnixTime64_To_FileTime64(ts.tv_sec) + ((UInt64)ts.tv_nsec / 100);
400 ft.dwLowDateTime = (DWORD)v;
401 ft.dwHighDateTime = (DWORD)(v >> 32);
402 }
403
404 #endif
405