xref: /reactos/dll/win32/kernel32/client/time.c (revision 84ccccab)
1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS system libraries
4  * FILE:            dll/win32/kernel32/client/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 << 11);
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 #ifdef _WIN64
450     TickCount.QuadPart = *((volatile ULONG64*)&SharedUserData->TickCount);
451 #else
452     while (TRUE)
453     {
454         TickCount.HighPart = (ULONG)SharedUserData->TickCount.High1Time;
455         TickCount.LowPart = SharedUserData->TickCount.LowPart;
456 
457         if (TickCount.HighPart == (ULONG)SharedUserData->TickCount.High2Time)
458             break;
459 
460         YieldProcessor();
461     }
462 #endif
463 
464     return (ULONG)((UInt32x32To64(TickCount.LowPart,
465                                   SharedUserData->TickCountMultiplier) >> 24) +
466                     UInt32x32To64((TickCount.HighPart << 8) & 0xFFFFFFFF,
467                                   SharedUserData->TickCountMultiplier));
468 
469 }
470 
471 /*
472  * @implemented
473  */
474 BOOL
475 WINAPI
476 GetSystemTimeAdjustment(OUT PDWORD lpTimeAdjustment,
477                         OUT PDWORD lpTimeIncrement,
478                         OUT PBOOL lpTimeAdjustmentDisabled)
479 {
480     SYSTEM_QUERY_TIME_ADJUST_INFORMATION TimeInfo;
481     NTSTATUS Status;
482 
483     Status = NtQuerySystemInformation(SystemTimeAdjustmentInformation,
484                                       &TimeInfo,
485                                       sizeof(TimeInfo),
486                                       NULL);
487     if (!NT_SUCCESS(Status))
488     {
489         BaseSetLastNTError(Status);
490         return FALSE;
491     }
492 
493     *lpTimeAdjustment = (DWORD)TimeInfo.TimeAdjustment;
494     *lpTimeIncrement = (DWORD)TimeInfo.TimeIncrement;
495     *lpTimeAdjustmentDisabled = (BOOL)TimeInfo.Enable;
496 
497     return TRUE;
498 }
499 
500 /*
501  * @implemented
502  */
503 BOOL
504 WINAPI
505 SetSystemTimeAdjustment(IN DWORD dwTimeAdjustment,
506                         IN BOOL bTimeAdjustmentDisabled)
507 {
508     NTSTATUS Status;
509     SYSTEM_SET_TIME_ADJUST_INFORMATION TimeInfo;
510 
511     TimeInfo.TimeAdjustment = (ULONG)dwTimeAdjustment;
512     TimeInfo.Enable = (BOOLEAN)bTimeAdjustmentDisabled;
513 
514     Status = NtSetSystemInformation(SystemTimeAdjustmentInformation,
515                                     &TimeInfo,
516                                     sizeof(TimeInfo));
517     if (!NT_SUCCESS(Status))
518     {
519         BaseSetLastNTError(Status);
520         return FALSE;
521     }
522 
523     return TRUE;
524 }
525 
526 /*
527  * @implemented
528  */
529 BOOL
530 WINAPI
531 GetSystemTimes(OUT LPFILETIME lpIdleTime OPTIONAL,
532                OUT LPFILETIME lpKernelTime OPTIONAL,
533                OUT LPFILETIME lpUserTime OPTIONAL)
534 {
535     PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION ProcPerfInfo;
536     LARGE_INTEGER TotalUserTime, TotalKernTime, TotalIdleTime;
537     ULONG BufferSize, ReturnLength;
538     CCHAR i;
539     NTSTATUS Status;
540 
541     TotalUserTime.QuadPart = TotalKernTime.QuadPart = TotalIdleTime.QuadPart = 0;
542 
543     BufferSize = sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION) *
544                  BaseStaticServerData->SysInfo.NumberOfProcessors;
545 
546     ProcPerfInfo = RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferSize);
547     if (!ProcPerfInfo)
548     {
549         BaseSetLastNTError(STATUS_NO_MEMORY);
550         return FALSE;
551     }
552 
553     Status = NtQuerySystemInformation(SystemProcessorPerformanceInformation,
554                                       ProcPerfInfo,
555                                       BufferSize,
556                                       &ReturnLength);
557     if ((NT_SUCCESS(Status)) && (ReturnLength == BufferSize))
558     {
559         if (lpIdleTime)
560         {
561             for (i = 0; i < BaseStaticServerData->SysInfo.NumberOfProcessors; i++)
562             {
563                 TotalIdleTime.QuadPart += ProcPerfInfo[i].IdleTime.QuadPart;
564             }
565 
566             lpIdleTime->dwLowDateTime = TotalIdleTime.LowPart;
567             lpIdleTime->dwHighDateTime = TotalIdleTime.HighPart;
568         }
569 
570         if (lpKernelTime)
571         {
572             for (i = 0; i < BaseStaticServerData->SysInfo.NumberOfProcessors; i++)
573             {
574                 TotalKernTime.QuadPart += ProcPerfInfo[i].KernelTime.QuadPart;
575             }
576 
577             lpKernelTime->dwLowDateTime = TotalKernTime.LowPart;
578             lpKernelTime->dwHighDateTime = TotalKernTime.HighPart;
579         }
580 
581         if (lpUserTime)
582         {
583             for (i = 0; i < BaseStaticServerData->SysInfo.NumberOfProcessors; i++)
584             {
585                 TotalUserTime.QuadPart += ProcPerfInfo[i].UserTime.QuadPart;
586             }
587 
588             lpUserTime->dwLowDateTime = TotalUserTime.LowPart;
589             lpUserTime->dwHighDateTime = TotalUserTime.HighPart;
590         }
591     }
592     else if (NT_SUCCESS(Status))
593     {
594          Status = STATUS_INTERNAL_ERROR;
595     }
596 
597     RtlFreeHeap(RtlGetProcessHeap(), 0, ProcPerfInfo);
598     if (!NT_SUCCESS(Status))
599     {
600         BaseSetLastNTError(Status);
601         return FALSE;
602     }
603 
604     return TRUE;
605 }
606 
607 /*
608  * @unimplemented
609  */
610 BOOL
611 WINAPI
612 SetClientTimeZoneInformation(IN CONST TIME_ZONE_INFORMATION *lpTimeZoneInformation)
613 {
614     STUB;
615     return 0;
616 }
617 
618 /* EOF */
619