3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
6 * PURPOSE: Conversion between Time and TimeFields
7 * PROGRAMMER: Rex Jolliff (rex@lvcablemodem.com)
10 * 08/03/98 RJJ Implemented these functions
13 /* INCLUDES *****************************************************************/
15 #include <ddk/ntddk.h>
16 #include <ntdll/rtl.h>
21 #define TICKSPERMIN 600000000
22 #define TICKSPERSEC 10000000
23 #define TICKSPERMSEC 10000
24 #define SECSPERDAY 86400
25 #define SECSPERHOUR 3600
27 #define MINSPERHOUR 60
28 #define HOURSPERDAY 24
29 #define EPOCHWEEKDAY 1
31 #define EPOCHYEAR 1601
32 #define DAYSPERNORMALYEAR 365
33 #define DAYSPERLEAPYEAR 366
34 #define MONSPERYEAR 12
37 #define TICKSTO1970 0x019db1ded53e8000LL
38 #define TICKSTO1980 0x01a8e79fe1d58000LL
40 #define TICKSTO1970 0x019db1ded53e8000i64
41 #define TICKSTO1980 0x01a8e79fe1d58000i64
45 static const int YearLengths
[2] =
47 DAYSPERNORMALYEAR
, DAYSPERLEAPYEAR
49 static const int MonthLengths
[2][MONSPERYEAR
] =
51 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
52 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
55 static __inline
int IsLeapYear(int Year
)
57 return Year
% 4 == 0 && (Year
% 100 != 0 || Year
% 400 == 0) ? 1 : 0;
60 static __inline
void NormalizeTimeFields(CSHORT
*FieldToNormalize
,
64 *FieldToNormalize
= (CSHORT
) (*FieldToNormalize
- Modulus
);
65 *CarryField
= (CSHORT
) (*CarryField
+ 1);
68 /* FUNCTIONS *****************************************************************/
74 RtlCutoverTimeToSystemTime(IN PTIME_FIELDS CutoverTimeFields
,
75 OUT PLARGE_INTEGER SystemTime
,
76 IN PLARGE_INTEGER CurrentTime
,
77 IN BOOLEAN ThisYearsCutoverOnly
)
79 TIME_FIELDS AdjustedTimeFields
;
80 TIME_FIELDS CurrentTimeFields
;
81 TIME_FIELDS CutoverSystemTimeFields
;
82 LARGE_INTEGER CutoverSystemTime
;
85 BOOLEAN NextYearsCutover
= FALSE
;
87 /* Check fixed cutover time */
88 if (CutoverTimeFields
->Year
!= 0)
90 if (!RtlTimeFieldsToTime(CutoverTimeFields
, SystemTime
))
93 if (SystemTime
->QuadPart
< CurrentTime
->QuadPart
)
100 * Compute recurring cutover time
103 /* Day must be between 1(first) and 5(last) */
104 if (CutoverTimeFields
->Day
== 0 || CutoverTimeFields
->Day
> 5)
107 RtlTimeToTimeFields(CurrentTime
, &CurrentTimeFields
);
111 /* Compute the cutover time of the first day of the current month */
112 AdjustedTimeFields
.Year
= CurrentTimeFields
.Year
;
113 if (NextYearsCutover
== TRUE
)
114 AdjustedTimeFields
.Year
++;
116 AdjustedTimeFields
.Month
= CutoverTimeFields
->Month
;
117 AdjustedTimeFields
.Day
= 1;
118 AdjustedTimeFields
.Hour
= CutoverTimeFields
->Hour
;
119 AdjustedTimeFields
.Minute
= CutoverTimeFields
->Minute
;
120 AdjustedTimeFields
.Second
= CutoverTimeFields
->Second
;
121 AdjustedTimeFields
.Milliseconds
= CutoverTimeFields
->Milliseconds
;
123 if (!RtlTimeFieldsToTime(&AdjustedTimeFields
, &CutoverSystemTime
))
126 RtlTimeToTimeFields(&CutoverSystemTime
, &CutoverSystemTimeFields
);
128 /* Adjust day to first matching weekday */
129 if (CutoverSystemTimeFields
.Weekday
!= CutoverTimeFields
->Weekday
)
131 if (CutoverSystemTimeFields
.Weekday
< CutoverTimeFields
->Weekday
)
132 Days
= CutoverTimeFields
->Weekday
- CutoverSystemTimeFields
.Weekday
;
134 Days
= DAYSPERWEEK
- (CutoverSystemTimeFields
.Weekday
- CutoverTimeFields
->Weekday
);
136 AdjustedTimeFields
.Day
+= Days
;
139 /* Adjust the number of weeks */
140 if (CutoverTimeFields
->Day
> 1)
142 Days
= DAYSPERWEEK
* (CutoverTimeFields
->Day
- 1);
143 MonthLength
= MonthLengths
[IsLeapYear(AdjustedTimeFields
.Year
)][AdjustedTimeFields
.Month
- 1];
144 if ((AdjustedTimeFields
.Day
+ Days
) > MonthLength
)
147 AdjustedTimeFields
.Day
+= Days
;
150 if (!RtlTimeFieldsToTime(&AdjustedTimeFields
, &CutoverSystemTime
))
153 if (ThisYearsCutoverOnly
== TRUE
||
154 NextYearsCutover
== TRUE
||
155 CutoverSystemTime
.QuadPart
>= CurrentTime
->QuadPart
)
160 NextYearsCutover
= TRUE
;
163 SystemTime
->QuadPart
= CutoverSystemTime
.QuadPart
;
175 IN PTIME_FIELDS TimeFields
,
176 OUT PLARGE_INTEGER Time
)
180 TIME_FIELDS IntTimeFields
;
183 memcpy(&IntTimeFields
,
185 sizeof(TIME_FIELDS
));
187 /* Normalize the TIME_FIELDS structure here */
188 while (IntTimeFields
.Second
>= SECSPERMIN
)
190 NormalizeTimeFields(&IntTimeFields
.Second
,
191 &IntTimeFields
.Minute
,
194 while (IntTimeFields
.Minute
>= MINSPERHOUR
)
196 NormalizeTimeFields(&IntTimeFields
.Minute
,
200 while (IntTimeFields
.Hour
>= HOURSPERDAY
)
202 NormalizeTimeFields(&IntTimeFields
.Hour
,
206 while (IntTimeFields
.Day
>
207 MonthLengths
[IsLeapYear(IntTimeFields
.Year
)][IntTimeFields
.Month
- 1])
209 NormalizeTimeFields(&IntTimeFields
.Day
,
210 &IntTimeFields
.Month
,
213 while (IntTimeFields
.Month
> MONSPERYEAR
)
215 NormalizeTimeFields(&IntTimeFields
.Month
,
220 /* Compute the time */
221 for (CurYear
= EPOCHYEAR
; CurYear
< IntTimeFields
.Year
; CurYear
++)
223 Time
->QuadPart
+= YearLengths
[IsLeapYear(CurYear
)];
225 for (CurMonth
= 1; CurMonth
< IntTimeFields
.Month
; CurMonth
++)
227 Time
->QuadPart
+= MonthLengths
[IsLeapYear(CurYear
)][CurMonth
- 1];
229 Time
->QuadPart
+= IntTimeFields
.Day
- 1;
230 Time
->QuadPart
*= SECSPERDAY
;
231 Time
->QuadPart
+= IntTimeFields
.Hour
* SECSPERHOUR
+ IntTimeFields
.Minute
* SECSPERMIN
+
232 IntTimeFields
.Second
;
233 Time
->QuadPart
*= TICKSPERSEC
;
234 Time
->QuadPart
+= IntTimeFields
.Milliseconds
* TICKSPERMSEC
;
245 RtlTimeToElapsedTimeFields(IN PLARGE_INTEGER Time
,
246 OUT PTIME_FIELDS TimeFields
)
248 ULONGLONG ElapsedSeconds
;
250 ULONG SecondsInMinute
;
252 /* Extract millisecond from time */
253 TimeFields
->Milliseconds
= (CSHORT
)((Time
->QuadPart
% TICKSPERSEC
) / TICKSPERMSEC
);
255 /* Compute elapsed seconds */
256 ElapsedSeconds
= (ULONGLONG
)Time
->QuadPart
/ TICKSPERSEC
;
258 /* Compute seconds within the day */
259 SecondsInDay
= ElapsedSeconds
% SECSPERDAY
;
261 /* Compute elapsed minutes within the day */
262 SecondsInMinute
= SecondsInDay
% SECSPERHOUR
;
264 /* Compute elapsed time of day */
265 TimeFields
->Hour
= (CSHORT
)(SecondsInDay
/ SECSPERHOUR
);
266 TimeFields
->Minute
= (CSHORT
)(SecondsInMinute
/ SECSPERMIN
);
267 TimeFields
->Second
= (CSHORT
)(SecondsInMinute
% SECSPERMIN
);
269 /* Compute elapsed days */
270 TimeFields
->Day
= (CSHORT
)(ElapsedSeconds
/ SECSPERDAY
);
272 /* The elapsed number of months and days cannot be calculated */
273 TimeFields
->Month
= 0;
274 TimeFields
->Year
= 0;
284 IN PLARGE_INTEGER Time
,
285 OUT PTIME_FIELDS TimeFields
)
288 int SecondsInDay
, CurYear
;
289 int LeapYear
, CurMonth
;
291 LONGLONG IntTime
= (LONGLONG
)Time
->QuadPart
;
293 /* Extract millisecond from time and convert time into seconds */
294 TimeFields
->Milliseconds
= (CSHORT
) ((IntTime
% TICKSPERSEC
) / TICKSPERMSEC
);
295 IntTime
= IntTime
/ TICKSPERSEC
;
297 /* Split the time into days and seconds within the day */
298 Days
= IntTime
/ SECSPERDAY
;
299 SecondsInDay
= IntTime
% SECSPERDAY
;
301 /* Adjust the values for days and seconds in day */
302 while (SecondsInDay
< 0)
304 SecondsInDay
+= SECSPERDAY
;
307 while (SecondsInDay
>= SECSPERDAY
)
309 SecondsInDay
-= SECSPERDAY
;
313 /* compute time of day */
314 TimeFields
->Hour
= (CSHORT
) (SecondsInDay
/ SECSPERHOUR
);
315 SecondsInDay
= SecondsInDay
% SECSPERHOUR
;
316 TimeFields
->Minute
= (CSHORT
) (SecondsInDay
/ SECSPERMIN
);
317 TimeFields
->Second
= (CSHORT
) (SecondsInDay
% SECSPERMIN
);
319 /* compute day of week */
320 TimeFields
->Weekday
= (CSHORT
) ((EPOCHWEEKDAY
+ Days
) % DAYSPERWEEK
);
324 CurYear
+= Days
/ DAYSPERLEAPYEAR
;
325 Days
-= (CurYear
- EPOCHYEAR
) * DAYSPERLEAPYEAR
;
326 CurYear
--; /* The next calculation needs CurYear - 1 */
327 Days
+= CurYear
- CurYear
/ 4 + CurYear
/ 100 - CurYear
/ 400;
329 Days
-= EPOCHYEAR
- 1 - (EPOCHYEAR
-1) / 4 + (EPOCHYEAR
-1) / 100 - (EPOCHYEAR
- 1) / 400;
332 LeapYear
= IsLeapYear(CurYear
);
333 if (Days
< (long) YearLengths
[LeapYear
])
338 Days
= Days
- (long) YearLengths
[LeapYear
];
340 TimeFields
->Year
= (CSHORT
) CurYear
;
342 /* Compute month of year */
343 LeapYear
= IsLeapYear(CurYear
);
344 Months
= MonthLengths
[LeapYear
];
345 for (CurMonth
= 0; Days
>= (long) Months
[CurMonth
]; CurMonth
++)
346 Days
= Days
- (long) Months
[CurMonth
];
347 TimeFields
->Month
= (CSHORT
) (CurMonth
+ 1);
348 TimeFields
->Day
= (CSHORT
) (Days
+ 1);
357 RtlTimeToSecondsSince1970(
358 IN PLARGE_INTEGER Time
,
359 OUT PULONG SecondsSince1970
)
361 LARGE_INTEGER IntTime
;
363 IntTime
.QuadPart
= Time
->QuadPart
- TICKSTO1970
;
364 IntTime
.QuadPart
= IntTime
.QuadPart
/ TICKSPERSEC
;
366 if (IntTime
.u
.HighPart
!= 0)
369 *SecondsSince1970
= IntTime
.u
.LowPart
;
380 RtlTimeToSecondsSince1980(
381 IN PLARGE_INTEGER Time
,
382 OUT PULONG SecondsSince1980
)
384 LARGE_INTEGER IntTime
;
386 IntTime
.QuadPart
= Time
->QuadPart
- TICKSTO1980
;
387 IntTime
.QuadPart
= IntTime
.QuadPart
/ TICKSPERSEC
;
389 if (IntTime
.u
.HighPart
!= 0)
392 *SecondsSince1980
= IntTime
.u
.LowPart
;
403 RtlLocalTimeToSystemTime(IN PLARGE_INTEGER LocalTime
,
404 OUT PLARGE_INTEGER SystemTime
)
406 SYSTEM_TIMEOFDAY_INFORMATION TimeInformation
;
409 Status
= NtQuerySystemInformation(SystemTimeOfDayInformation
,
411 sizeof(SYSTEM_TIMEOFDAY_INFORMATION
),
413 if (!NT_SUCCESS(Status
))
416 SystemTime
->QuadPart
= LocalTime
->QuadPart
+
417 TimeInformation
.TimeZoneBias
.QuadPart
;
419 return STATUS_SUCCESS
;
428 RtlSystemTimeToLocalTime(IN PLARGE_INTEGER SystemTime
,
429 OUT PLARGE_INTEGER LocalTime
)
431 SYSTEM_TIMEOFDAY_INFORMATION TimeInformation
;
434 Status
= NtQuerySystemInformation(SystemTimeOfDayInformation
,
436 sizeof(SYSTEM_TIMEOFDAY_INFORMATION
),
438 if (!NT_SUCCESS(Status
))
441 LocalTime
->QuadPart
= SystemTime
->QuadPart
-
442 TimeInformation
.TimeZoneBias
.QuadPart
;
444 return STATUS_SUCCESS
;
452 RtlSecondsSince1970ToTime(
453 IN ULONG SecondsSince1970
,
454 OUT PLARGE_INTEGER Time
)
456 Time
->QuadPart
= ((LONGLONG
)SecondsSince1970
* TICKSPERSEC
) + TICKSTO1970
;
464 RtlSecondsSince1980ToTime(
465 IN ULONG SecondsSince1980
,
466 OUT PLARGE_INTEGER Time
)
468 Time
->QuadPart
= ((LONGLONG
)SecondsSince1980
* TICKSPERSEC
) + TICKSTO1980
;