OLD | NEW |
| (Empty) |
1 // Copyright 2004-2009 Google Inc. | |
2 // | |
3 // Licensed under the Apache License, Version 2.0 (the "License"); | |
4 // you may not use this file except in compliance with the License. | |
5 // You may obtain a copy of the License at | |
6 // | |
7 // http://www.apache.org/licenses/LICENSE-2.0 | |
8 // | |
9 // Unless required by applicable law or agreed to in writing, software | |
10 // distributed under the License is distributed on an "AS IS" BASIS, | |
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
12 // See the License for the specific language governing permissions and | |
13 // limitations under the License. | |
14 // ======================================================================== | |
15 // | |
16 // Time functions | |
17 | |
18 #include "omaha/base/time.h" | |
19 #include "omaha/base/commontypes.h" | |
20 #include "omaha/base/debug.h" | |
21 #include "omaha/base/error.h" | |
22 #include "omaha/base/logging.h" | |
23 #include "omaha/base/string.h" | |
24 #include "omaha/base/utils.h" | |
25 | |
26 namespace omaha { | |
27 | |
28 // Date Constants | |
29 | |
30 #define kNumOfDays 7 | |
31 #define kNumOfMonth 12 | |
32 | |
33 static const TCHAR kRFC822_DateDelimiters[] = _T(" ,:"); | |
34 static const TCHAR kRFC822_TimeDelimiter[] = _T(":"); | |
35 SELECTANY const TCHAR* kRFC822_Day[kNumOfDays] = { | |
36 _T("Mon"), | |
37 _T("Tue"), | |
38 _T("Wed"), | |
39 _T("Thu"), | |
40 _T("Fri"), | |
41 _T("Sat"), | |
42 _T("Sun") }; | |
43 | |
44 SELECTANY const TCHAR* kRFC822_Month[kNumOfMonth] = { | |
45 _T("Jan"), | |
46 _T("Feb"), | |
47 _T("Mar"), | |
48 _T("Apr"), | |
49 _T("May"), | |
50 _T("Jun"), | |
51 _T("Jul"), | |
52 _T("Aug"), | |
53 _T("Sep"), | |
54 _T("Oct"), | |
55 _T("Nov"), | |
56 _T("Dec") }; | |
57 | |
58 struct TimeZoneInfo { | |
59 const TCHAR* zone_name; | |
60 int hour_dif; | |
61 }; | |
62 | |
63 SELECTANY TimeZoneInfo kRFC822_TimeZone[] = { | |
64 { _T("UT"), 0 }, | |
65 { _T("GMT"), 0 }, | |
66 { _T("EST"), -5 }, | |
67 { _T("EDT"), -4 }, | |
68 { _T("CST"), -6 }, | |
69 { _T("CDT"), -5 }, | |
70 { _T("MST"), -7 }, | |
71 { _T("MDT"), -6 }, | |
72 { _T("PST"), -8 }, | |
73 { _T("PDT"), -7 }, | |
74 { _T("A"), -1 }, // Military time zones | |
75 { _T("B"), -2 }, | |
76 { _T("C"), -3 }, | |
77 { _T("D"), -4 }, | |
78 { _T("E"), -5 }, | |
79 { _T("F"), -6 }, | |
80 { _T("G"), -7 }, | |
81 { _T("H"), -8 }, | |
82 { _T("I"), -9 }, | |
83 { _T("K"), -10 }, | |
84 { _T("L"), -11 }, | |
85 { _T("M"), -12 }, | |
86 { _T("N"), 1 }, | |
87 { _T("O"), 2 }, | |
88 { _T("P"), 3 }, | |
89 { _T("Q"), 4 }, | |
90 { _T("R"), 5 }, | |
91 { _T("S"), 6 }, | |
92 { _T("T"), 7 }, | |
93 { _T("U"), 8 }, | |
94 { _T("V"), 9 }, | |
95 { _T("W"), 10 }, | |
96 { _T("X"), 11 }, | |
97 { _T("Y"), 12 }, | |
98 { _T("Z"), 0 }, | |
99 }; | |
100 | |
101 SELECTANY const TCHAR *days[] = | |
102 { L"Sun", L"Mon", L"Tue", L"Wed", L"Thu", L"Fri", L"Sat" }; | |
103 | |
104 SELECTANY const TCHAR *months[] = { | |
105 L"Jan", | |
106 L"Feb", | |
107 L"Mar", | |
108 L"Apr", | |
109 L"May", | |
110 L"Jun", | |
111 L"Jul", | |
112 L"Aug", | |
113 L"Sep", | |
114 L"Oct", | |
115 L"Nov", | |
116 L"Dec" | |
117 }; | |
118 | |
119 // NOTE: so long as the output is used internally only, no localization is | |
120 // needed here. | |
121 CString ConvertTimeToGMTString(const FILETIME *ft) { | |
122 ASSERT(ft, (L"")); | |
123 | |
124 CString s; | |
125 SYSTEMTIME st; | |
126 if (!FileTimeToSystemTime(ft, &st)) { | |
127 return L""; | |
128 } | |
129 | |
130 // same as FormatGmt(_T("%a, %d %b %Y %H:%M:%S GMT")); | |
131 s.Format(NOTRANSL(L"%s, %02d %s %d %02d:%02d:%02d GMT"), days[st.wDayOfWeek], | |
132 st.wDay, months[st.wMonth-1], st.wYear, st.wHour, st.wMinute, st.wSecond); | |
133 return s; | |
134 } | |
135 | |
136 time64 ConvertTime16ToTime64(uint16 time16) { | |
137 return time16 * kTimeGranularity + kStart100NsTime; | |
138 } | |
139 | |
140 uint16 ConvertTime64ToTime16(time64 time) { | |
141 ASSERT1(time >= kStart100NsTime); | |
142 | |
143 time64 t64 = (time - kStart100NsTime) / kTimeGranularity; | |
144 ASSERT1(t64 <= kTime16Max); | |
145 | |
146 return static_cast<uint16>(t64); | |
147 } | |
148 | |
149 time64 TimeTToTime64(const time_t& old_value) { | |
150 FILETIME file_time; | |
151 TimeTToFileTime(old_value, &file_time); | |
152 return FileTimeToTime64(file_time); | |
153 } | |
154 | |
155 #ifdef _DEBUG | |
156 void ComputeStartTime() { | |
157 SYSTEMTIME start_system_time = kStartSystemTime; | |
158 time64 start_100ns_time = SystemTimeToTime64(&start_system_time); | |
159 UTIL_LOG(L1, (_T("posting list starting time = %s\n"), | |
160 String_Int64ToString(start_100ns_time, 10))); | |
161 } | |
162 #endif | |
163 | |
164 // Time management | |
165 | |
166 // Allow the unittest to override. | |
167 static time64 time_override = 0; | |
168 | |
169 // #ifdef UNITTEST | |
170 void SetTimeOverride(const time64 & time_new) { | |
171 time_override = time_new; | |
172 } | |
173 | |
174 // #endif | |
175 | |
176 time64 GetCurrent100NSTime() { | |
177 if (time_override != 0) | |
178 return time_override; | |
179 | |
180 // In order gte the 100ns time we shouldn't use SystemTime | |
181 // as it's granularity is 1 ms. Below is the correct implementation. | |
182 // On the other hand the system clock granularity is 15 ms, so we | |
183 // are not gaining much by having the timestamp in nano-sec | |
184 // If we decide to go with ms, divide "time64 time" by 10000 | |
185 // SYSTEMTIME sys_time; | |
186 // GetLocalTime(&sys_time); | |
187 // return SystemTimeToTime64(&sys_time); | |
188 | |
189 // get the current time in 100-nanoseconds intervals | |
190 FILETIME file_time; | |
191 ::GetSystemTimeAsFileTime(&file_time); | |
192 | |
193 time64 time = FileTimeToTime64(file_time); | |
194 return time; | |
195 } | |
196 | |
197 time64 GetCurrentMsTime() { | |
198 return GetCurrent100NSTime() / kMillisecsTo100ns; | |
199 } | |
200 | |
201 time64 SystemTimeToTime64(const SYSTEMTIME* sys_time) { | |
202 ASSERT1(sys_time); | |
203 | |
204 FILETIME file_time; | |
205 SetZero(file_time); | |
206 | |
207 if (!::SystemTimeToFileTime(sys_time, &file_time)) { | |
208 UTIL_LOG(LE, | |
209 (_T("[SystemTimeToTime64 - failed to SystemTimeToFileTime][0x%x]"), | |
210 HRESULTFromLastError())); | |
211 return 0; | |
212 } | |
213 | |
214 return FileTimeToTime64(file_time); | |
215 } | |
216 | |
217 // returns a value compatible with EXE/DLL timestamps | |
218 // and the C time() function | |
219 // NOTE: behavior is independent of wMilliseconds value | |
220 int32 SystemTimeToInt32(const SYSTEMTIME *sys_time) { | |
221 ASSERT(sys_time, (L"")); | |
222 | |
223 time64 t64 = SystemTimeToTime64(sys_time); | |
224 int32 t32 = 0; | |
225 | |
226 if (t64 != 0) { | |
227 t32 = Time64ToInt32(t64); | |
228 } | |
229 return t32; | |
230 } | |
231 | |
232 int32 Time64ToInt32(const time64 & time) { | |
233 // convert to 32-bit format | |
234 // time() (32-bit) measures seconds since 1970/01/01 00:00:00 (UTC) | |
235 // FILETIME (64-bit) measures 100-ns intervals since 1601/01/01 00:00:00 (UTC) | |
236 | |
237 // seconds between 1601 and 1970 | |
238 time64 t32 = (time / kSecsTo100ns) - | |
239 ((time64(60*60*24) * time64(365*369 + 89))); | |
240 ASSERT(t32 == (t32 & 0x7FFFFFFF), (L"")); // make sure it fits | |
241 | |
242 // cast at the end (avoids overflow/underflow when computing 32-bit value) | |
243 return static_cast<int32>(t32); | |
244 } | |
245 | |
246 time64 Int32ToTime64(const int32 & time) { | |
247 // convert to 64-bit format | |
248 // time() (32-bit) measures seconds since 1970/01/01 00:00:00 (UTC) | |
249 // FILETIME (64-bit) measures 100-ns intervals since 1601/01/01 00:00:00 (UTC) | |
250 | |
251 // seconds between 1601 and 1970 | |
252 time64 t64 = (static_cast<time64>(time) + | |
253 (time64(60*60*24) * time64(365*369 + 89))) * kSecsTo100ns; | |
254 return t64; | |
255 } | |
256 | |
257 // TODO(omaha): The next 2 functions can fail if FileTimeToLocalFileTime or | |
258 // FileTimeToSystemTime fails. | |
259 // Consider having it return a HRESULT. Right now if FileTimeToSystemTime fails, | |
260 // it returns an undefined value. | |
261 | |
262 // Convert a uint to a genuine systemtime | |
263 SYSTEMTIME Time64ToSystemTime(const time64& time) { | |
264 FILETIME file_time; | |
265 SetZero(file_time); | |
266 Time64ToFileTime(time, &file_time); | |
267 | |
268 SYSTEMTIME sys_time; | |
269 SetZero(sys_time); | |
270 if (!FileTimeToSystemTime(&file_time, &sys_time)) { | |
271 UTIL_LOG(LE, (_T("[Time64ToSystemTime]") | |
272 _T("[failed to FileTimeToSystemTime][0x%x]"), | |
273 HRESULTFromLastError())); | |
274 } | |
275 | |
276 return sys_time; | |
277 } | |
278 | |
279 | |
280 // Convert a uint to a genuine localtime | |
281 // Should ONLY be used for display, since internally we use only UTC | |
282 SYSTEMTIME Time64ToLocalTime(const time64& time) { | |
283 FILETIME file_time; | |
284 SetZero(file_time); | |
285 Time64ToFileTime(time, &file_time); | |
286 | |
287 FILETIME local_file_time; | |
288 SetZero(local_file_time); | |
289 if (!FileTimeToLocalFileTime(&file_time, &local_file_time)) { | |
290 UTIL_LOG(LE, (_T("[Time64ToLocalTime]") | |
291 _T("[failed to FileTimeToLocalFileTime][0x%x]"), | |
292 HRESULTFromLastError())); | |
293 } | |
294 | |
295 SYSTEMTIME local_time; | |
296 SetZero(local_time); | |
297 if (!FileTimeToSystemTime(&local_file_time, &local_time)) { | |
298 UTIL_LOG(LE, (_T("[Time64ToLocalTime]") | |
299 _T("[failed to FileTimeToSystemTime][0x%x]"), | |
300 HRESULTFromLastError())); | |
301 } | |
302 | |
303 return local_time; | |
304 } | |
305 | |
306 time64 FileTimeToTime64(const FILETIME & file_time) { | |
307 return static_cast<time64>( | |
308 file_time.dwHighDateTime) << 32 | file_time.dwLowDateTime; | |
309 } | |
310 | |
311 void Time64ToFileTime(const time64 & time, FILETIME *ft) { | |
312 ASSERT(ft, (L"")); | |
313 | |
314 ft->dwHighDateTime = static_cast<DWORD>(time >> 32); | |
315 ft->dwLowDateTime = static_cast<DWORD>(time & 0xffffffff); | |
316 } | |
317 | |
318 // Convert from FILETIME to time_t | |
319 time_t FileTimeToTimeT(const FILETIME& file_time) { | |
320 return static_cast<time_t>( | |
321 (FileTimeToTime64(file_time) - kTimeTConvValue) / kSecsTo100ns); | |
322 } | |
323 | |
324 // Convert from time_t to FILETIME | |
325 void TimeTToFileTime(const time_t& time, FILETIME* file_time) { | |
326 ASSERT1(file_time); | |
327 | |
328 LONGLONG ll = Int32x32To64(time, kSecsTo100ns) + kTimeTConvValue; | |
329 file_time->dwLowDateTime = static_cast<DWORD>(ll); | |
330 file_time->dwHighDateTime = static_cast<DWORD>(ll >> 32); | |
331 } | |
332 | |
333 // Parses RFC 822 Date/Time format | |
334 // 5. DATE AND TIME SPECIFICATION | |
335 // 5.1. SYNTAX | |
336 // | |
337 // date-time = [ day "," ] date time ; dd mm yy | |
338 // ; hh:mm:ss zzz | |
339 // day = "Mon" / "Tue" / "Wed" / "Thu" | |
340 // / "Fri" / "Sat" / "Sun" | |
341 // | |
342 // date = 1*2DIGIT month 2DIGIT ; day month year | |
343 // ; e.g. 20 Jun 82 | |
344 // | |
345 // month = "Jan" / "Feb" / "Mar" / "Apr" | |
346 // / "May" / "Jun" / "Jul" / "Aug" | |
347 // / "Sep" / "Oct" / "Nov" / "Dec" | |
348 // | |
349 // time = hour zone ; ANSI and Military | |
350 // | |
351 // hour = 2DIGIT ":" 2DIGIT [":" 2DIGIT] | |
352 // ; 00:00:00 - 23:59:59 | |
353 // | |
354 // zone = "UT" / "GMT" ; Universal Time | |
355 // ; North American : UT | |
356 // / "EST" / "EDT" ; Eastern: - 5/ - 4 | |
357 // / "CST" / "CDT" ; Central: - 6/ - 5 | |
358 // / "MST" / "MDT" ; Mountain: - 7/ - 6 | |
359 // / "PST" / "PDT" ; Pacific: - 8/ - 7 | |
360 // / 1ALPHA ; Military: Z = UT; | |
361 // ; A:-1; (J not used) | |
362 // ; M:-12; N:+1; Y:+12 | |
363 // / ( ("+" / "-") 4DIGIT ) ; Local differential | |
364 // ; hours+min. (HHMM) | |
365 // return local time if ret_local_time == true, | |
366 // return time is GMT / UTC time otherwise | |
367 bool RFC822DateToSystemTime(const TCHAR* str_RFC822_date, | |
368 SYSTEMTIME* psys_time, | |
369 bool ret_local_time) { | |
370 ASSERT(str_RFC822_date != NULL, (L"")); | |
371 ASSERT(psys_time != NULL, (L"")); | |
372 | |
373 CString str_date = str_RFC822_date; | |
374 CString str_token; | |
375 int cur_pos = 0; | |
376 | |
377 str_token= str_date.Tokenize(kRFC822_DateDelimiters, cur_pos); | |
378 if (str_token == "") | |
379 return false; | |
380 | |
381 int i = 0; | |
382 for (i = 0; i < kNumOfDays; i++) { | |
383 if (str_token == kRFC822_Day[i]) { | |
384 str_token = str_date.Tokenize(kRFC822_DateDelimiters, cur_pos); | |
385 if (str_token == "") | |
386 return false; | |
387 break; | |
388 } | |
389 } | |
390 | |
391 int day = String_StringToInt(str_token); | |
392 if (day < 0 || day > 31) | |
393 return false; | |
394 | |
395 str_token = str_date.Tokenize(kRFC822_DateDelimiters, cur_pos); | |
396 if (str_token == "") | |
397 return false; | |
398 | |
399 int month = -1; | |
400 for (i = 0; i < kNumOfMonth; i++) { | |
401 if (str_token == kRFC822_Month[i]) { | |
402 month = i+1; // month is 1 based number | |
403 break; | |
404 } | |
405 } | |
406 if (month == -1) // month not found | |
407 return false; | |
408 | |
409 str_token = str_date.Tokenize(kRFC822_DateDelimiters, cur_pos); | |
410 if (str_token == "") | |
411 return false; | |
412 | |
413 int year = String_StringToInt(str_token); | |
414 if (year < 100) // two digit year format, convert to 1950 - 2050 range | |
415 if (year < 50) | |
416 year += 2000; | |
417 else | |
418 year += 1900; | |
419 | |
420 str_token = str_date.Tokenize(kRFC822_DateDelimiters, cur_pos); | |
421 if (str_token == "") | |
422 return false; | |
423 | |
424 int hour = String_StringToInt(str_token); | |
425 if (hour < 0 || hour > 23) | |
426 return false; | |
427 | |
428 str_token = str_date.Tokenize(kRFC822_DateDelimiters, cur_pos); | |
429 if (str_token == "") | |
430 return false; | |
431 | |
432 int minute = String_StringToInt(str_token); | |
433 if (minute < 0 || minute > 59) | |
434 return false; | |
435 | |
436 str_token = str_date.Tokenize(kRFC822_DateDelimiters, cur_pos); | |
437 if (str_token == "") | |
438 return false; | |
439 | |
440 int second = 0; | |
441 // distingushed between XX:XX and XX:XX:XX time formats | |
442 if (str_token.GetLength() == 2 && | |
443 String_IsDigit(str_token[0]) && | |
444 String_IsDigit(str_token[1])) { | |
445 second = String_StringToInt(str_token); | |
446 if (second < 0 || second > 59) | |
447 return false; | |
448 | |
449 str_token = str_date.Tokenize(kRFC822_DateDelimiters, cur_pos); | |
450 if (str_token == "") | |
451 return false; | |
452 } | |
453 | |
454 int bias = 0; | |
455 if (str_token[0] == '+' || | |
456 str_token[0] == '-' || | |
457 String_IsDigit(str_token[0])) { // numeric format | |
458 int zone = String_StringToInt(str_token); | |
459 | |
460 // zone is in HHMM format, need to convert to the number of minutes | |
461 bias = (zone / 100) * 60 + (zone % 100); | |
462 } else { // text format | |
463 for (i = 0; i < sizeof(kRFC822_TimeZone) / sizeof(TimeZoneInfo); i++) | |
464 if (str_token == kRFC822_TimeZone[i].zone_name) { | |
465 bias = kRFC822_TimeZone[i].hour_dif * 60; | |
466 break; | |
467 } | |
468 } | |
469 | |
470 SYSTEMTIME mail_time; | |
471 memset(&mail_time, 0, sizeof(mail_time)); | |
472 | |
473 mail_time.wYear = static_cast<WORD>(year); | |
474 mail_time.wMonth = static_cast<WORD>(month); | |
475 mail_time.wDay = static_cast<WORD>(day); | |
476 mail_time.wHour = static_cast<WORD>(hour); | |
477 mail_time.wMinute = static_cast<WORD>(minute); | |
478 mail_time.wSecond = static_cast<WORD>(second); | |
479 | |
480 // TzSpecificLocalTimeToSystemTime() is incompatible with Win 2000, | |
481 // convert time manually here | |
482 time64 time_64 = SystemTimeToTime64(&mail_time); | |
483 time_64 = time_64 - (bias*kMinsTo100ns); | |
484 | |
485 *psys_time = Time64ToSystemTime(time_64); | |
486 | |
487 if (ret_local_time) { | |
488 TIME_ZONE_INFORMATION local_time_zone_info; | |
489 SYSTEMTIME universal_time = *psys_time; | |
490 | |
491 if (GetTimeZoneInformation(&local_time_zone_info) == TIME_ZONE_ID_INVALID) { | |
492 return false; | |
493 } | |
494 if (!SystemTimeToTzSpecificLocalTime(&local_time_zone_info, | |
495 &universal_time, | |
496 psys_time)) { | |
497 return false; | |
498 } | |
499 } | |
500 return true; | |
501 } | |
502 | |
503 } // namespace omaha | |
504 | |
OLD | NEW |