• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, NULL) == 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, NULL) == 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