9efe40537e08562e703dded971408882ca4c49a3
[reactos.git] / reactos / lib / kernel32 / misc / time.c
1 /* $Id: time.c,v 1.13 2001/05/30 20:03:28 ekohl Exp $
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS system libraries
5 * FILE: lib/kernel32/misc/time.c
6 * PURPOSE: Time conversion functions
7 * PROGRAMMER: Boudewijn ( ariadne@xs4all.nl)
8 * DOSDATE and DOSTIME structures from Onno Hovers
9 * UPDATE HISTORY:
10 * Created 19/01/99
11 */
12
13 /* INCLUDES ******************************************************************/
14
15 #include <ddk/ntddk.h>
16 #include <windows.h>
17 #include <napi/shared_data.h>
18 #include <kernel32/error.h>
19 //#include <string.h>
20
21 #define NDEBUG
22 #include <kernel32/kernel32.h>
23
24 /* TYPES *********************************************************************/
25
26 typedef struct __DOSTIME
27 {
28 WORD Second:5;
29 WORD Minute:6;
30 WORD Hour:5;
31 } DOSTIME, *PDOSTIME;
32
33 typedef struct __DOSDATE
34 {
35 WORD Day:5;
36 WORD Month:4;
37 WORD Year:5;
38 } DOSDATE, *PDOSDATE;
39
40 #define TICKSPERMIN 600000000
41 #define TICKSPERSEC 10000000
42 #define TICKSPERMSEC 10000
43 #define SECSPERDAY 86400
44 #define SECSPERHOUR 3600
45 #define SECSPERMIN 60
46 #define MINSPERHOUR 60
47 #define HOURSPERDAY 24
48 #define EPOCHWEEKDAY 0
49 #define DAYSPERWEEK 7
50 #define EPOCHYEAR 1601
51 #define DAYSPERNORMALYEAR 365
52 #define DAYSPERLEAPYEAR 366
53 #define MONSPERYEAR 12
54
55 static const int YearLengths[2] = {DAYSPERNORMALYEAR, DAYSPERLEAPYEAR};
56 static const int MonthLengths[2][MONSPERYEAR] =
57 {
58 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
59 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
60 };
61
62 static __inline int IsLeapYear(int Year)
63 {
64 return Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0) ? 1 : 0;
65 }
66
67 static __inline void NormalizeTimeFields(WORD *FieldToNormalize,
68 WORD *CarryField,
69 int Modulus)
70 {
71 *FieldToNormalize = (WORD) (*FieldToNormalize - Modulus);
72 *CarryField = (WORD) (*CarryField + 1);
73 }
74
75 #define LISECOND RtlEnlargedUnsignedMultiply(SECOND,NSPERSEC)
76 #define LIMINUTE RtlEnlargedUnsignedMultiply(MINUTE,NSPERSEC)
77 #define LIHOUR RtlEnlargedUnsignedMultiply(HOUR,NSPERSEC)
78 #define LIDAY RtlEnlargedUnsignedMultiply(DAY,NSPERSEC)
79 #define LIYEAR RtlEnlargedUnsignedMultiply(YEAR,NSPERSEC)
80 #define LIFOURYEAR RtlEnlargedUnsignedMultiply(FOURYEAR,NSPERSEC)
81 #define LICENTURY RtlEnlargedUnsignedMultiply(CENTURY,NSPERSEC)
82 #define LIMILLENIUM RtlEnlargedUnsignedMultiply(CENTURY,10*NSPERSEC)
83
84
85
86
87 /* FUNCTIONS ****************************************************************/
88
89 WINBOOL
90 STDCALL
91 FileTimeToDosDateTime(
92 CONST FILETIME *lpFileTime,
93 LPWORD lpFatDate,
94 LPWORD lpFatTime
95 )
96 {
97 PDOSTIME pdtime=(PDOSTIME) lpFatTime;
98 PDOSDATE pddate=(PDOSDATE) lpFatDate;
99 SYSTEMTIME SystemTime;
100
101 if ( lpFileTime == NULL )
102 return FALSE;
103
104 if ( lpFatDate == NULL )
105 return FALSE;
106
107 if ( lpFatTime == NULL )
108 return FALSE;
109
110 FileTimeToSystemTime(
111 lpFileTime,
112 &SystemTime
113 );
114
115 pdtime->Second = SystemTime.wSecond;
116 pdtime->Minute = SystemTime.wMinute;
117 pdtime->Hour = SystemTime.wHour;
118
119 pddate->Day = SystemTime.wDay;
120 pddate->Month = SystemTime.wMonth;
121 pddate->Year = SystemTime.wYear - 1980;
122
123 return TRUE;
124 }
125
126 WINBOOL
127 STDCALL
128 DosDateTimeToFileTime(
129 WORD wFatDate,
130 WORD wFatTime,
131 LPFILETIME lpFileTime
132 )
133 {
134 PDOSTIME pdtime = (PDOSTIME) &wFatTime;
135 PDOSDATE pddate = (PDOSDATE) &wFatDate;
136 SYSTEMTIME SystemTime;
137
138 if ( lpFileTime == NULL )
139 return FALSE;
140
141 SystemTime.wMilliseconds = 0;
142 SystemTime.wSecond = pdtime->Second;
143 SystemTime.wMinute = pdtime->Minute;
144 SystemTime.wHour = pdtime->Hour;
145
146 SystemTime.wDay = pddate->Day;
147 SystemTime.wMonth = pddate->Month;
148 SystemTime.wYear = 1980 + pddate->Year;
149
150 SystemTimeToFileTime(&SystemTime,lpFileTime);
151
152 return TRUE;
153 }
154
155 LONG
156 STDCALL
157 CompareFileTime(
158 CONST FILETIME *lpFileTime1,
159 CONST FILETIME *lpFileTime2
160 )
161 {
162 if ( lpFileTime1 == NULL )
163 return 0;
164 if ( lpFileTime2 == NULL )
165 return 0;
166
167 if (*((PLONGLONG)lpFileTime1) > *((PLONGLONG)lpFileTime2))
168 return 1;
169 else if (*((PLONGLONG)lpFileTime1) < *((PLONGLONG)lpFileTime2))
170 return -1;
171
172 return 0;
173 }
174
175 VOID
176 STDCALL
177 GetSystemTimeAsFileTime(PFILETIME lpFileTime)
178 {
179 NtQuerySystemTime ((TIME *)lpFileTime);
180 }
181
182 WINBOOL
183 STDCALL
184 SystemTimeToFileTime(
185 CONST SYSTEMTIME * lpSystemTime,
186 LPFILETIME lpFileTime
187 )
188
189 {
190 int CurYear, CurMonth, MonthLength;
191 long long int rcTime;
192 SYSTEMTIME SystemTime;
193
194 memcpy (&SystemTime, lpSystemTime, sizeof(SYSTEMTIME));
195
196 rcTime = 0;
197
198 /* FIXME: normalize the TIME_FIELDS structure here */
199 while (SystemTime.wSecond >= SECSPERMIN)
200 {
201 NormalizeTimeFields(&SystemTime.wSecond,
202 &SystemTime.wMinute,
203 SECSPERMIN);
204 }
205 while (SystemTime.wMinute >= MINSPERHOUR)
206 {
207 NormalizeTimeFields(&SystemTime.wMinute,
208 &SystemTime.wHour,
209 MINSPERHOUR);
210 }
211 while (SystemTime.wHour >= HOURSPERDAY)
212 {
213 NormalizeTimeFields(&SystemTime.wHour,
214 &SystemTime.wDay,
215 HOURSPERDAY);
216 }
217 MonthLength =
218 MonthLengths[IsLeapYear(SystemTime.wYear)][SystemTime.wMonth - 1];
219 while (SystemTime.wDay > MonthLength)
220 {
221 NormalizeTimeFields(&SystemTime.wDay,
222 &SystemTime.wMonth,
223 MonthLength);
224 }
225 while (SystemTime.wMonth > MONSPERYEAR)
226 {
227 NormalizeTimeFields(&SystemTime.wMonth,
228 &SystemTime.wYear,
229 MONSPERYEAR);
230 }
231
232 /* FIXME: handle calendar corrections here */
233 for (CurYear = EPOCHYEAR; CurYear < SystemTime.wYear; CurYear++)
234 {
235 rcTime += YearLengths[IsLeapYear(CurYear)];
236 }
237 for (CurMonth = 1; CurMonth < SystemTime.wMonth; CurMonth++)
238 {
239 rcTime += MonthLengths[IsLeapYear(CurYear)][CurMonth - 1];
240 }
241 rcTime += SystemTime.wDay - 1;
242 rcTime *= SECSPERDAY;
243 rcTime += SystemTime.wHour * SECSPERHOUR +
244 SystemTime.wMinute * SECSPERMIN + SystemTime.wSecond;
245 rcTime *= TICKSPERSEC;
246 rcTime += SystemTime.wMilliseconds * TICKSPERMSEC;
247
248 *lpFileTime = *(FILETIME *)&rcTime;
249
250 return TRUE;
251 }
252
253 // dwDayOfWeek = RtlLargeIntegerDivide(FileTime,LIDAY,&dwRemDay);
254 // lpSystemTime->wDayOfWeek = 1 + GET_LARGE_INTEGER_LOW_PART(dwDayOfWeek) % 7;
255
256
257
258 WINBOOL
259 STDCALL
260 FileTimeToSystemTime(
261 CONST FILETIME *lpFileTime,
262 LPSYSTEMTIME lpSystemTime
263 )
264 {
265 const int *Months;
266 int LeapSecondCorrections, SecondsInDay, CurYear;
267 int LeapYear, CurMonth;
268 long int Days;
269 long long int Time = *((long long int*)lpFileTime);
270
271 /* Extract millisecond from time and convert time into seconds */
272 lpSystemTime->wMilliseconds = (WORD)((Time % TICKSPERSEC) / TICKSPERMSEC);
273 Time = Time / TICKSPERSEC;
274
275 /* FIXME: Compute the number of leap second corrections here */
276 LeapSecondCorrections = 0;
277
278 /* Split the time into days and seconds within the day */
279 Days = Time / SECSPERDAY;
280 SecondsInDay = Time % SECSPERDAY;
281
282 /* Adjust the values for GMT and leap seconds */
283 SecondsInDay += LeapSecondCorrections;
284 while (SecondsInDay < 0)
285 {
286 SecondsInDay += SECSPERDAY;
287 Days--;
288 }
289 while (SecondsInDay >= SECSPERDAY)
290 {
291 SecondsInDay -= SECSPERDAY;
292 Days++;
293 }
294
295 /* compute time of day */
296 lpSystemTime->wHour = (WORD) (SecondsInDay / SECSPERHOUR);
297 SecondsInDay = SecondsInDay % SECSPERHOUR;
298 lpSystemTime->wMinute = (WORD) (SecondsInDay / SECSPERMIN);
299 lpSystemTime->wSecond = (WORD) (SecondsInDay % SECSPERMIN);
300
301 /* FIXME: handle the possibility that we are on a leap second (i.e. Second = 60) */
302
303 /* compute day of week */
304 lpSystemTime->wDayOfWeek = (WORD) ((EPOCHWEEKDAY + Days) % DAYSPERWEEK);
305
306 /* compute year */
307 CurYear = EPOCHYEAR;
308 /* FIXME: handle calendar modifications */
309 while (1)
310 {
311 LeapYear = IsLeapYear(CurYear);
312 if (Days < (long) YearLengths[LeapYear])
313 {
314 break;
315 }
316 CurYear++;
317 Days = Days - (long) YearLengths[LeapYear];
318 }
319 lpSystemTime->wYear = (WORD) CurYear;
320
321 /* Compute month of year */
322 Months = MonthLengths[LeapYear];
323 for (CurMonth = 0; Days >= (long) Months[CurMonth]; CurMonth++)
324 Days = Days - (long) Months[CurMonth];
325 lpSystemTime->wMonth = (WORD) (CurMonth + 1);
326 lpSystemTime->wDay = (WORD) (Days + 1);
327
328 return TRUE;
329 }
330
331
332 WINBOOL
333 STDCALL
334 FileTimeToLocalFileTime(
335 CONST FILETIME *lpFileTime,
336 LPFILETIME lpLocalFileTime
337 )
338 {
339 // FIXME: include time bias
340 *((PLONGLONG)lpLocalFileTime) = *((PLONGLONG)lpFileTime);
341
342 return TRUE;
343 }
344
345 WINBOOL
346 STDCALL
347 LocalFileTimeToFileTime(
348 CONST FILETIME *lpLocalFileTime,
349 LPFILETIME lpFileTime
350 )
351 {
352 // FIXME: include time bias
353 *((PLONGLONG)lpFileTime) = *((PLONGLONG)lpLocalFileTime);
354
355 return TRUE;
356 }
357
358
359 VOID STDCALL
360 GetLocalTime(LPSYSTEMTIME lpSystemTime)
361 {
362 FILETIME FileTime;
363 FILETIME LocalFileTime;
364
365 NtQuerySystemTime ((TIME*)&FileTime);
366 FileTimeToLocalFileTime (&FileTime, &LocalFileTime);
367 FileTimeToSystemTime (&LocalFileTime, lpSystemTime);
368 }
369
370
371 VOID STDCALL
372 GetSystemTime(LPSYSTEMTIME lpSystemTime)
373 {
374 FILETIME FileTime;
375
376 NtQuerySystemTime ((TIME*)&FileTime);
377 FileTimeToSystemTime (&FileTime, lpSystemTime);
378 }
379
380
381 WINBOOL STDCALL
382 SetLocalTime(CONST SYSTEMTIME *lpSystemTime)
383 {
384 FILETIME LocalFileTime;
385 LARGE_INTEGER FileTime;
386 NTSTATUS errCode;
387
388 SystemTimeToFileTime (lpSystemTime, &LocalFileTime);
389 LocalFileTimeToFileTime (&LocalFileTime, (FILETIME *)&FileTime);
390 errCode = NtSetSystemTime (&FileTime, &FileTime);
391 if (!NT_SUCCESS(errCode))
392 return FALSE;
393 return TRUE;
394 }
395
396
397 WINBOOL STDCALL
398 SetSystemTime(CONST SYSTEMTIME *lpSystemTime)
399 {
400 LARGE_INTEGER NewSystemTime;
401 NTSTATUS errCode;
402
403 SystemTimeToFileTime (lpSystemTime, (PFILETIME)&NewSystemTime);
404 errCode = NtSetSystemTime (&NewSystemTime, &NewSystemTime);
405 if (!NT_SUCCESS(errCode))
406 return FALSE;
407 return TRUE;
408 }
409
410
411 DWORD STDCALL
412 GetTimeZoneInformation(LPTIME_ZONE_INFORMATION lpTimeZoneInformation)
413 {
414 TIME_ZONE_INFORMATION TimeZoneInformation;
415 NTSTATUS Status;
416
417 DPRINT("GetTimeZoneInformation()\n");
418
419 Status = NtQuerySystemInformation(SystemCurrentTimeZoneInformation,
420 &TimeZoneInformation,
421 sizeof(TIME_ZONE_INFORMATION),
422 NULL);
423 if (!NT_SUCCESS(Status))
424 {
425 SetLastErrorByStatus(Status);
426 return TIME_ZONE_ID_INVALID;
427 }
428
429 memcpy(lpTimeZoneInformation,
430 &TimeZoneInformation,
431 sizeof(TIME_ZONE_INFORMATION));
432
433 return ((PKUSER_SHARED_DATA)USER_SHARED_DATA_BASE)->TimeZoneId;
434 }
435
436
437 BOOL STDCALL
438 SetTimeZoneInformation(CONST TIME_ZONE_INFORMATION *lpTimeZoneInformation)
439 {
440 TIME_ZONE_INFORMATION TimeZoneInformation;
441 NTSTATUS Status;
442
443 DPRINT("SetTimeZoneInformation()\n");
444
445 memcpy(&TimeZoneInformation,
446 lpTimeZoneInformation,
447 sizeof(TIME_ZONE_INFORMATION));
448
449 Status = RtlSetTimeZoneInformation(&TimeZoneInformation);
450 if (!NT_SUCCESS(Status))
451 {
452 SetLastErrorByStatus(Status);
453 return FALSE;
454 }
455
456 NtSetSystemTime(0,0);
457
458 return TRUE;
459 }
460
461
462 DWORD STDCALL
463 GetCurrentTime(VOID)
464 {
465 return GetTickCount();
466 }
467
468
469 DWORD STDCALL
470 GetTickCount(VOID)
471 {
472 ULONG UpTime;
473 NtGetTickCount(&UpTime);
474 return UpTime;
475 }
476
477
478 WINBOOL STDCALL
479 SystemTimeToTzSpecificLocalTime(
480 LPTIME_ZONE_INFORMATION lpTimeZoneInformation,
481 LPSYSTEMTIME lpUniversalTime,
482 LPSYSTEMTIME lpLocalTime
483 )
484 {
485 TIME_ZONE_INFORMATION TimeZoneInformation;
486 LPTIME_ZONE_INFORMATION lpTzInfo;
487 LARGE_INTEGER FileTime;
488
489 if (!lpTimeZoneInformation)
490 {
491 GetTimeZoneInformation (&TimeZoneInformation);
492 lpTzInfo = &TimeZoneInformation;
493 }
494 else
495 lpTzInfo = lpTimeZoneInformation;
496
497 if (!lpUniversalTime)
498 return FALSE;
499
500 if (!lpLocalTime)
501 return FALSE;
502
503 SystemTimeToFileTime (lpUniversalTime, (PFILETIME)&FileTime);
504 FileTime.QuadPart -= (lpTzInfo->Bias * TICKSPERMIN);
505 FileTimeToSystemTime ((PFILETIME)&FileTime, lpLocalTime);
506
507 return TRUE;
508 }
509
510
511 WINBOOL STDCALL
512 GetSystemTimeAdjustment(PDWORD lpTimeAdjustment,
513 PDWORD lpTimeIncrement,
514 PWINBOOL lpTimeAdjustmentDisabled)
515 {
516 SYSTEM_QUERY_TIME_ADJUSTMENT Buffer;
517 NTSTATUS Status;
518
519 Status = NtQuerySystemInformation(SystemTimeAdjustmentInformation,
520 &Buffer,
521 sizeof(SYSTEM_QUERY_TIME_ADJUSTMENT),
522 NULL);
523 if (!NT_SUCCESS(Status))
524 {
525 SetLastErrorByStatus(Status);
526 return FALSE;
527 }
528
529 *lpTimeAdjustment = (DWORD)Buffer.TimeAdjustment;
530 *lpTimeIncrement = (DWORD)Buffer.MaximumIncrement;
531 *lpTimeAdjustmentDisabled = (WINBOOL)Buffer.TimeSynchronization;
532
533 return TRUE;
534 }
535
536
537 WINBOOL STDCALL
538 SetSystemTimeAdjustment(DWORD dwTimeAdjustment,
539 WINBOOL bTimeAdjustmentDisabled)
540 {
541 NTSTATUS Status;
542 SYSTEM_TIME_ADJUSTMENT_INFO Buffer;
543
544 Buffer.TimeAdjustment = (ULONG)dwTimeAdjustment;
545 Buffer.TimeSynchronization = (BOOLEAN)bTimeAdjustmentDisabled;
546
547 Status = NtSetSystemInformation(SystemTimeAdjustmentInformation,
548 &Buffer,
549 sizeof(SYSTEM_TIME_ADJUSTMENT_INFO));
550 if (!NT_SUCCESS(Status))
551 {
552 SetLastErrorByStatus(Status);
553 return FALSE;
554 }
555
556 return TRUE;
557 }
558
559 /* EOF */