Synchronize with trunk revision 59636 (just before Alex's CreateProcess revamp).
[reactos.git] / dll / win32 / kernel32 / client / time.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS system libraries
4 * FILE: lib/kernel32/misc/time.c
5 * PURPOSE: Time conversion functions
6 * PROGRAMMER: Ariadne
7 * DOSDATE and DOSTIME structures from Onno Hovers
8 * UPDATE HISTORY:
9 * Created 19/01/99
10 */
11
12 /* INCLUDES *******************************************************************/
13
14 #include <k32.h>
15
16 #define NDEBUG
17 #include <debug.h>
18
19 /* FUNCTIONS ******************************************************************/
20
21 /*
22 * @implemented
23 */
24 BOOL
25 WINAPI
26 IsTimeZoneRedirectionEnabled(VOID)
27 {
28 /* Return if a TS Timezone ID is active */
29 return (BaseStaticServerData->TermsrvClientTimeZoneId != TIME_ZONE_ID_INVALID);
30 }
31
32 /*
33 * @implemented
34 */
35 BOOL
36 WINAPI
37 FileTimeToDosDateTime(IN CONST FILETIME *lpFileTime,
38 OUT LPWORD lpFatDate,
39 OUT LPWORD lpFatTime)
40 {
41 LARGE_INTEGER FileTime;
42 TIME_FIELDS TimeFields;
43
44 FileTime.HighPart = lpFileTime->dwHighDateTime;
45 FileTime.LowPart = lpFileTime->dwLowDateTime;
46
47 if (FileTime.QuadPart < 0)
48 {
49 SetLastError(ERROR_INVALID_PARAMETER);
50 return FALSE;
51 }
52
53 RtlTimeToTimeFields(&FileTime, &TimeFields);
54 if ((TimeFields.Year < 1980) || (TimeFields.Year > 2107))
55 {
56 BaseSetLastNTError(STATUS_INVALID_PARAMETER);
57 return FALSE;
58 }
59
60 *lpFatDate = (TimeFields.Day) |
61 (TimeFields.Month << 5) |
62 ((TimeFields.Year - 1980) << 9);
63 *lpFatTime = (TimeFields.Second >> 1) |
64 (TimeFields.Minute << 5) |
65 (TimeFields.Hour << 16);
66
67 return TRUE;
68 }
69
70 /*
71 * @implemented
72 */
73 BOOL
74 WINAPI
75 DosDateTimeToFileTime(IN WORD wFatDate,
76 IN WORD wFatTime,
77 OUT LPFILETIME lpFileTime)
78 {
79 TIME_FIELDS TimeFields;
80 LARGE_INTEGER SystemTime;
81
82 TimeFields.Year = (wFatDate >> 9) + 1980;
83 TimeFields.Month = (wFatDate >> 5) & 0xF;
84 TimeFields.Day = (wFatDate & 0x1F);
85 TimeFields.Hour = (wFatTime >> 11);
86 TimeFields.Minute = (wFatTime >> 5) & 0x3F;
87 TimeFields.Second = (wFatTime & 0x1F) << 1;
88 TimeFields.Milliseconds = 0;
89
90 if (RtlTimeFieldsToTime(&TimeFields, &SystemTime))
91 {
92 lpFileTime->dwLowDateTime = SystemTime.LowPart;
93 lpFileTime->dwHighDateTime = SystemTime.HighPart;
94 return TRUE;
95 }
96
97 BaseSetLastNTError(STATUS_INVALID_PARAMETER);
98 return FALSE;
99 }
100
101 /*
102 * @implemented
103 */
104 LONG
105 WINAPI
106 CompareFileTime(IN CONST FILETIME *lpFileTime1,
107 IN CONST FILETIME *lpFileTime2)
108 {
109 LARGE_INTEGER Time1, Time2, Diff;
110
111 Time1.LowPart = lpFileTime1->dwLowDateTime;
112 Time2.LowPart = lpFileTime2->dwLowDateTime;
113 Time1.HighPart = lpFileTime1->dwHighDateTime;
114 Time2.HighPart = lpFileTime2->dwHighDateTime;
115
116 Diff.QuadPart = Time1.QuadPart - Time2.QuadPart;
117
118 if (Diff.HighPart < 0) return -1;
119 if (Diff.QuadPart == 0) return 0;
120 return 1;
121 }
122
123 /*
124 * @implemented
125 */
126 VOID
127 WINAPI
128 GetSystemTimeAsFileTime(OUT PFILETIME lpFileTime)
129 {
130 LARGE_INTEGER SystemTime;
131
132 do
133 {
134 SystemTime.HighPart = SharedUserData->SystemTime.High1Time;
135 SystemTime.LowPart = SharedUserData->SystemTime.LowPart;
136 }
137 while (SystemTime.HighPart != SharedUserData->SystemTime.High2Time);
138
139 lpFileTime->dwLowDateTime = SystemTime.LowPart;
140 lpFileTime->dwHighDateTime = SystemTime.HighPart;
141 }
142
143 /*
144 * @implemented
145 */
146 BOOL
147 WINAPI
148 SystemTimeToFileTime(IN CONST SYSTEMTIME *lpSystemTime,
149 OUT LPFILETIME lpFileTime)
150 {
151 TIME_FIELDS TimeFields;
152 LARGE_INTEGER liTime;
153
154 TimeFields.Year = lpSystemTime->wYear;
155 TimeFields.Month = lpSystemTime->wMonth;
156 TimeFields.Day = lpSystemTime->wDay;
157 TimeFields.Hour = lpSystemTime->wHour;
158 TimeFields.Minute = lpSystemTime->wMinute;
159 TimeFields.Second = lpSystemTime->wSecond;
160 TimeFields.Milliseconds = lpSystemTime->wMilliseconds;
161
162 if (RtlTimeFieldsToTime(&TimeFields, &liTime))
163 {
164 lpFileTime->dwLowDateTime = liTime.u.LowPart;
165 lpFileTime->dwHighDateTime = liTime.u.HighPart;
166 return TRUE;
167 }
168
169 BaseSetLastNTError(STATUS_INVALID_PARAMETER);
170 return FALSE;
171 }
172
173 /*
174 * @implemented
175 */
176 BOOL
177 WINAPI
178 FileTimeToSystemTime(IN CONST FILETIME *lpFileTime,
179 OUT LPSYSTEMTIME lpSystemTime)
180 {
181 TIME_FIELDS TimeFields;
182 LARGE_INTEGER liTime;
183
184 liTime.u.LowPart = lpFileTime->dwLowDateTime;
185 liTime.u.HighPart = lpFileTime->dwHighDateTime;
186 if (liTime.QuadPart < 0)
187 {
188 SetLastError(ERROR_INVALID_PARAMETER);
189 return FALSE;
190 }
191
192 RtlTimeToTimeFields(&liTime, &TimeFields);
193
194 lpSystemTime->wYear = TimeFields.Year;
195 lpSystemTime->wMonth = TimeFields.Month;
196 lpSystemTime->wDay = TimeFields.Day;
197 lpSystemTime->wHour = TimeFields.Hour;
198 lpSystemTime->wMinute = TimeFields.Minute;
199 lpSystemTime->wSecond = TimeFields.Second;
200 lpSystemTime->wMilliseconds = TimeFields.Milliseconds;
201 lpSystemTime->wDayOfWeek = TimeFields.Weekday;
202
203 return TRUE;
204 }
205
206 /*
207 * @implemented
208 */
209 BOOL
210 WINAPI
211 FileTimeToLocalFileTime(IN CONST FILETIME *lpFileTime,
212 OUT LPFILETIME lpLocalFileTime)
213 {
214 LARGE_INTEGER TimeZoneBias, FileTime;
215 volatile KSYSTEM_TIME *TimePtr;
216
217 TimePtr = IsTimeZoneRedirectionEnabled() ?
218 &BaseStaticServerData->ktTermsrvClientBias :
219 &SharedUserData->TimeZoneBias;
220 do
221 {
222 TimeZoneBias.HighPart = TimePtr->High1Time;
223 TimeZoneBias.LowPart = TimePtr->LowPart;
224 }
225 while (TimeZoneBias.HighPart != TimePtr->High2Time);
226
227 FileTime.LowPart = lpFileTime->dwLowDateTime;
228 FileTime.HighPart = lpFileTime->dwHighDateTime;
229
230 FileTime.QuadPart -= TimeZoneBias.QuadPart;
231
232 lpLocalFileTime->dwLowDateTime = FileTime.LowPart;
233 lpLocalFileTime->dwHighDateTime = FileTime.HighPart;
234
235 return TRUE;
236 }
237
238 /*
239 * @implemented
240 */
241 BOOL
242 WINAPI
243 LocalFileTimeToFileTime(IN CONST FILETIME *lpLocalFileTime,
244 OUT LPFILETIME lpFileTime)
245 {
246 LARGE_INTEGER TimeZoneBias, FileTime;
247 volatile KSYSTEM_TIME *TimePtr;
248
249 TimePtr = IsTimeZoneRedirectionEnabled() ?
250 &BaseStaticServerData->ktTermsrvClientBias :
251 &SharedUserData->TimeZoneBias;
252
253 do
254 {
255 TimeZoneBias.HighPart = TimePtr->High1Time;
256 TimeZoneBias.LowPart = TimePtr->LowPart;
257 }
258 while (TimeZoneBias.HighPart != TimePtr->High2Time);
259
260 FileTime.LowPart = lpLocalFileTime->dwLowDateTime;
261 FileTime.HighPart = lpLocalFileTime->dwHighDateTime;
262
263 FileTime.QuadPart += TimeZoneBias.QuadPart;
264
265 lpFileTime->dwLowDateTime = FileTime.LowPart;
266 lpFileTime->dwHighDateTime = FileTime.HighPart;
267
268 return TRUE;
269 }
270
271 /*
272 * @implemented
273 */
274 VOID
275 WINAPI
276 GetLocalTime(OUT LPSYSTEMTIME lpSystemTime)
277 {
278 LARGE_INTEGER SystemTime, TimeZoneBias;
279 TIME_FIELDS TimeFields;
280 volatile KSYSTEM_TIME *TimePtr;
281
282 do
283 {
284 SystemTime.HighPart = SharedUserData->SystemTime.High1Time;
285 SystemTime.LowPart = SharedUserData->SystemTime.LowPart;
286 }
287 while (SystemTime.HighPart != SharedUserData->SystemTime.High2Time);
288
289 TimePtr = IsTimeZoneRedirectionEnabled() ?
290 &BaseStaticServerData->ktTermsrvClientBias :
291 &SharedUserData->TimeZoneBias;
292 do
293 {
294 TimeZoneBias.HighPart = TimePtr->High1Time;
295 TimeZoneBias.LowPart = TimePtr->LowPart;
296 }
297 while (TimeZoneBias.HighPart != TimePtr->High2Time);
298
299 SystemTime.QuadPart -= TimeZoneBias.QuadPart;
300 RtlTimeToTimeFields(&SystemTime, &TimeFields);
301
302 lpSystemTime->wYear = TimeFields.Year;
303 lpSystemTime->wMonth = TimeFields.Month;
304 lpSystemTime->wDay = TimeFields.Day;
305 lpSystemTime->wHour = TimeFields.Hour;
306 lpSystemTime->wMinute = TimeFields.Minute;
307 lpSystemTime->wSecond = TimeFields.Second;
308 lpSystemTime->wMilliseconds = TimeFields.Milliseconds;
309 lpSystemTime->wDayOfWeek = TimeFields.Weekday;
310 }
311
312 /*
313 * @implemented
314 */
315 VOID
316 WINAPI
317 GetSystemTime(OUT LPSYSTEMTIME lpSystemTime)
318 {
319 LARGE_INTEGER SystemTime;
320 TIME_FIELDS TimeFields;
321
322 do
323 {
324 SystemTime.HighPart = SharedUserData->SystemTime.High1Time;
325 SystemTime.LowPart = SharedUserData->SystemTime.LowPart;
326 }
327 while (SystemTime.HighPart != SharedUserData->SystemTime.High2Time);
328
329 RtlTimeToTimeFields(&SystemTime, &TimeFields);
330
331 lpSystemTime->wYear = TimeFields.Year;
332 lpSystemTime->wMonth = TimeFields.Month;
333 lpSystemTime->wDay = TimeFields.Day;
334 lpSystemTime->wHour = TimeFields.Hour;
335 lpSystemTime->wMinute = TimeFields.Minute;
336 lpSystemTime->wSecond = TimeFields.Second;
337 lpSystemTime->wMilliseconds = TimeFields.Milliseconds;
338 lpSystemTime->wDayOfWeek = TimeFields.Weekday;
339 }
340
341 /*
342 * @implemented
343 */
344 BOOL
345 WINAPI
346 SetLocalTime(IN CONST SYSTEMTIME *lpSystemTime)
347 {
348 LARGE_INTEGER NewSystemTime, TimeZoneBias;
349 NTSTATUS Status;
350 ULONG Privilege = SE_SYSTEMTIME_PRIVILEGE;
351 TIME_FIELDS TimeFields;
352 PVOID State;
353 volatile KSYSTEM_TIME *TimePtr;
354
355 TimePtr = IsTimeZoneRedirectionEnabled() ?
356 &BaseStaticServerData->ktTermsrvClientBias :
357 &SharedUserData->TimeZoneBias;
358 do
359 {
360 TimeZoneBias.HighPart = TimePtr->High1Time;
361 TimeZoneBias.LowPart = TimePtr->LowPart;
362 }
363 while (TimeZoneBias.HighPart != TimePtr->High2Time);
364
365 TimeFields.Year = lpSystemTime->wYear;
366 TimeFields.Month = lpSystemTime->wMonth;
367 TimeFields.Day = lpSystemTime->wDay;
368 TimeFields.Hour = lpSystemTime->wHour;
369 TimeFields.Minute = lpSystemTime->wMinute;
370 TimeFields.Second = lpSystemTime->wSecond;
371 TimeFields.Milliseconds = lpSystemTime->wMilliseconds;
372
373 if (!RtlTimeFieldsToTime(&TimeFields, &NewSystemTime))
374 {
375 BaseSetLastNTError(STATUS_INVALID_PARAMETER);
376 return FALSE;
377 }
378
379 NewSystemTime.QuadPart += TimeZoneBias.QuadPart;
380
381 Status = RtlAcquirePrivilege(&Privilege, 1, 0, &State);
382 if (NT_SUCCESS(Status))
383 {
384 Status = NtSetSystemTime(&NewSystemTime, NULL);
385 RtlReleasePrivilege(State);
386 }
387
388 if (!NT_SUCCESS(Status))
389 {
390 BaseSetLastNTError(Status);
391 return FALSE;
392 }
393
394 return TRUE;
395 }
396
397 /*
398 * @implemented
399 */
400 BOOL
401 WINAPI
402 SetSystemTime(IN CONST SYSTEMTIME *lpSystemTime)
403 {
404 LARGE_INTEGER NewSystemTime;
405 NTSTATUS Status;
406 ULONG Privilege = SE_SYSTEMTIME_PRIVILEGE;
407 TIME_FIELDS TimeFields;
408 PVOID State;
409
410 TimeFields.Year = lpSystemTime->wYear;
411 TimeFields.Month = lpSystemTime->wMonth;
412 TimeFields.Day = lpSystemTime->wDay;
413 TimeFields.Hour = lpSystemTime->wHour;
414 TimeFields.Minute = lpSystemTime->wMinute;
415 TimeFields.Second = lpSystemTime->wSecond;
416 TimeFields.Milliseconds = lpSystemTime->wMilliseconds;
417
418 if (!RtlTimeFieldsToTime(&TimeFields, &NewSystemTime))
419 {
420 BaseSetLastNTError(STATUS_INVALID_PARAMETER);
421 return FALSE;
422 }
423
424 Status = RtlAcquirePrivilege(&Privilege, 1, 0, &State);
425 if (NT_SUCCESS(Status))
426 {
427 Status = NtSetSystemTime(&NewSystemTime, NULL);
428 RtlReleasePrivilege(State);
429 }
430
431 if (!NT_SUCCESS(Status))
432 {
433 BaseSetLastNTError(Status);
434 return FALSE;
435 }
436
437 return TRUE;
438 }
439
440 /*
441 * @implemented
442 */
443 DWORD
444 WINAPI
445 GetTickCount(VOID)
446 {
447 ULARGE_INTEGER TickCount;
448
449 while (TRUE)
450 {
451 TickCount.HighPart = (ULONG)SharedUserData->TickCount.High1Time;
452 TickCount.LowPart = SharedUserData->TickCount.LowPart;
453
454 if (TickCount.HighPart == (ULONG)SharedUserData->TickCount.High2Time)
455 break;
456
457 YieldProcessor();
458 }
459
460 return (ULONG)((UInt32x32To64(TickCount.LowPart,
461 SharedUserData->TickCountMultiplier) >> 24) +
462 UInt32x32To64((TickCount.HighPart << 8) & 0xFFFFFFFF,
463 SharedUserData->TickCountMultiplier));
464
465 }
466
467 /*
468 * @implemented
469 */
470 BOOL
471 WINAPI
472 GetSystemTimeAdjustment(OUT PDWORD lpTimeAdjustment,
473 OUT PDWORD lpTimeIncrement,
474 OUT PBOOL lpTimeAdjustmentDisabled)
475 {
476 SYSTEM_QUERY_TIME_ADJUST_INFORMATION TimeInfo;
477 NTSTATUS Status;
478
479 Status = NtQuerySystemInformation(SystemTimeAdjustmentInformation,
480 &TimeInfo,
481 sizeof(TimeInfo),
482 NULL);
483 if (!NT_SUCCESS(Status))
484 {
485 BaseSetLastNTError(Status);
486 return FALSE;
487 }
488
489 *lpTimeAdjustment = (DWORD)TimeInfo.TimeAdjustment;
490 *lpTimeIncrement = (DWORD)TimeInfo.TimeIncrement;
491 *lpTimeAdjustmentDisabled = (BOOL)TimeInfo.Enable;
492
493 return TRUE;
494 }
495
496 /*
497 * @implemented
498 */
499 BOOL
500 WINAPI
501 SetSystemTimeAdjustment(IN DWORD dwTimeAdjustment,
502 IN BOOL bTimeAdjustmentDisabled)
503 {
504 NTSTATUS Status;
505 SYSTEM_SET_TIME_ADJUST_INFORMATION TimeInfo;
506
507 TimeInfo.TimeAdjustment = (ULONG)dwTimeAdjustment;
508 TimeInfo.Enable = (BOOLEAN)bTimeAdjustmentDisabled;
509
510 Status = NtSetSystemInformation(SystemTimeAdjustmentInformation,
511 &TimeInfo,
512 sizeof(TimeInfo));
513 if (!NT_SUCCESS(Status))
514 {
515 BaseSetLastNTError(Status);
516 return FALSE;
517 }
518
519 return TRUE;
520 }
521
522 /*
523 * @implemented
524 */
525 BOOL
526 WINAPI
527 GetSystemTimes(OUT LPFILETIME lpIdleTime OPTIONAL,
528 OUT LPFILETIME lpKernelTime OPTIONAL,
529 OUT LPFILETIME lpUserTime OPTIONAL)
530 {
531 PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION ProcPerfInfo;
532 LARGE_INTEGER TotalUserTime, TotalKernTime, TotalIdleTime;
533 SIZE_T BufferSize, ReturnLength;
534 ULONG i;
535 NTSTATUS Status;
536
537 TotalUserTime.QuadPart = TotalKernTime.QuadPart = TotalIdleTime.QuadPart = 0;
538
539 BufferSize = sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION) *
540 BaseStaticServerData->SysInfo.NumberOfProcessors;
541
542 ProcPerfInfo = RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferSize);
543 if (!ProcPerfInfo)
544 {
545 BaseSetLastNTError(STATUS_NO_MEMORY);
546 return FALSE;
547 }
548
549 Status = NtQuerySystemInformation(SystemProcessorPerformanceInformation,
550 ProcPerfInfo,
551 BufferSize,
552 &ReturnLength);
553 if ((NT_SUCCESS(Status)) && (ReturnLength == BufferSize))
554 {
555 if (lpIdleTime)
556 {
557 for (i = 0; i < BaseStaticServerData->SysInfo.NumberOfProcessors; i++)
558 {
559 TotalIdleTime.QuadPart += ProcPerfInfo[i].IdleTime.QuadPart;
560 }
561
562 lpIdleTime->dwLowDateTime = TotalIdleTime.LowPart;
563 lpIdleTime->dwHighDateTime = TotalIdleTime.HighPart;
564 }
565
566 if (lpKernelTime)
567 {
568 for (i = 0; i < BaseStaticServerData->SysInfo.NumberOfProcessors; i++)
569 {
570 TotalKernTime.QuadPart += ProcPerfInfo[i].KernelTime.QuadPart;
571 }
572
573 lpKernelTime->dwLowDateTime = TotalKernTime.LowPart;
574 lpKernelTime->dwHighDateTime = TotalKernTime.HighPart;
575 }
576
577 if (lpUserTime)
578 {
579 for (i = 0; i < BaseStaticServerData->SysInfo.NumberOfProcessors; i++)
580 {
581 TotalUserTime.QuadPart += ProcPerfInfo[i].UserTime.QuadPart;
582 }
583
584 lpUserTime->dwLowDateTime = TotalUserTime.LowPart;
585 lpUserTime->dwHighDateTime = TotalUserTime.HighPart;
586 }
587 }
588 else if (NT_SUCCESS(Status))
589 {
590 Status = STATUS_INTERNAL_ERROR;
591 }
592
593 RtlFreeHeap(RtlGetProcessHeap(), 0, ProcPerfInfo);
594 if (!NT_SUCCESS(Status))
595 {
596 BaseSetLastNTError(Status);
597 return FALSE;
598 }
599
600 return TRUE;
601 }
602
603 /*
604 * @unimplemented
605 */
606 BOOL
607 WINAPI
608 SetClientTimeZoneInformation(IN CONST TIME_ZONE_INFORMATION *lpTimeZoneInformation)
609 {
610 STUB;
611 return 0;
612 }
613
614 /* EOF */