2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS system libraries
5 * PURPOSE: Conversion between Time and TimeFields
6 * PROGRAMMER: Rex Jolliff (rex@lvcablemodem.com)
9 /* INCLUDES *****************************************************************/
16 #define TICKSPERMIN 600000000
17 #define TICKSPERSEC 10000000
18 #define TICKSPERMSEC 10000
19 #define SECSPERDAY 86400
20 #define SECSPERHOUR 3600
22 #define MINSPERHOUR 60
23 #define HOURSPERDAY 24
24 #define EPOCHWEEKDAY 1
26 #define EPOCHYEAR 1601
27 #define DAYSPERNORMALYEAR 365
28 #define DAYSPERLEAPYEAR 366
29 #define MONSPERYEAR 12
32 #define TICKSTO1970 0x019db1ded53e8000LL
33 #define TICKSTO1980 0x01a8e79fe1d58000LL
35 #define TICKSTO1970 0x019db1ded53e8000i64
36 #define TICKSTO1980 0x01a8e79fe1d58000i64
40 static const unsigned int YearLengths
[2] =
42 DAYSPERNORMALYEAR
, DAYSPERLEAPYEAR
44 static const UCHAR MonthLengths
[2][MONSPERYEAR
] =
46 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
47 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
50 static __inline
int IsLeapYear(int Year
)
52 return Year
% 4 == 0 && (Year
% 100 != 0 || Year
% 400 == 0) ? 1 : 0;
55 static int DaysSinceEpoch(int Year
)
58 Year
--; /* Don't include a leap day from the current year */
59 Days
= Year
* DAYSPERNORMALYEAR
+ Year
/ 4 - Year
/ 100 + Year
/ 400;
60 Days
-= (EPOCHYEAR
- 1) * DAYSPERNORMALYEAR
+ (EPOCHYEAR
- 1) / 4 - (EPOCHYEAR
- 1) / 100 + (EPOCHYEAR
- 1) / 400;
64 /* FUNCTIONS *****************************************************************/
70 RtlCutoverTimeToSystemTime(IN PTIME_FIELDS CutoverTimeFields
,
71 OUT PLARGE_INTEGER SystemTime
,
72 IN PLARGE_INTEGER CurrentTime
,
73 IN BOOLEAN ThisYearsCutoverOnly
)
75 TIME_FIELDS AdjustedTimeFields
;
76 TIME_FIELDS CurrentTimeFields
;
77 TIME_FIELDS CutoverSystemTimeFields
;
78 LARGE_INTEGER CutoverSystemTime
;
81 BOOLEAN NextYearsCutover
= FALSE
;
83 /* Check fixed cutover time */
84 if (CutoverTimeFields
->Year
!= 0)
86 if (!RtlTimeFieldsToTime(CutoverTimeFields
, SystemTime
))
89 if (SystemTime
->QuadPart
< CurrentTime
->QuadPart
)
96 * Compute recurring cutover time
99 /* Day must be between 1(first) and 5(last) */
100 if (CutoverTimeFields
->Day
== 0 || CutoverTimeFields
->Day
> 5)
103 RtlTimeToTimeFields(CurrentTime
, &CurrentTimeFields
);
107 /* Compute the cutover time of the first day of the current month */
108 AdjustedTimeFields
.Year
= CurrentTimeFields
.Year
;
109 if (NextYearsCutover
== TRUE
)
110 AdjustedTimeFields
.Year
++;
112 AdjustedTimeFields
.Month
= CutoverTimeFields
->Month
;
113 AdjustedTimeFields
.Day
= 1;
114 AdjustedTimeFields
.Hour
= CutoverTimeFields
->Hour
;
115 AdjustedTimeFields
.Minute
= CutoverTimeFields
->Minute
;
116 AdjustedTimeFields
.Second
= CutoverTimeFields
->Second
;
117 AdjustedTimeFields
.Milliseconds
= CutoverTimeFields
->Milliseconds
;
119 if (!RtlTimeFieldsToTime(&AdjustedTimeFields
, &CutoverSystemTime
))
122 RtlTimeToTimeFields(&CutoverSystemTime
, &CutoverSystemTimeFields
);
124 /* Adjust day to first matching weekday */
125 if (CutoverSystemTimeFields
.Weekday
!= CutoverTimeFields
->Weekday
)
127 if (CutoverSystemTimeFields
.Weekday
< CutoverTimeFields
->Weekday
)
128 Days
= CutoverTimeFields
->Weekday
- CutoverSystemTimeFields
.Weekday
;
130 Days
= DAYSPERWEEK
- (CutoverSystemTimeFields
.Weekday
- CutoverTimeFields
->Weekday
);
132 AdjustedTimeFields
.Day
+= Days
;
135 /* Adjust the number of weeks */
136 if (CutoverTimeFields
->Day
> 1)
138 Days
= DAYSPERWEEK
* (CutoverTimeFields
->Day
- 1);
139 MonthLength
= MonthLengths
[IsLeapYear(AdjustedTimeFields
.Year
)][AdjustedTimeFields
.Month
- 1];
140 if ((AdjustedTimeFields
.Day
+ Days
) > MonthLength
)
143 AdjustedTimeFields
.Day
+= Days
;
146 if (!RtlTimeFieldsToTime(&AdjustedTimeFields
, &CutoverSystemTime
))
149 if (ThisYearsCutoverOnly
== TRUE
||
150 NextYearsCutover
== TRUE
||
151 CutoverSystemTime
.QuadPart
>= CurrentTime
->QuadPart
)
156 NextYearsCutover
= TRUE
;
159 SystemTime
->QuadPart
= CutoverSystemTime
.QuadPart
;
171 IN PTIME_FIELDS TimeFields
,
172 OUT PLARGE_INTEGER Time
)
175 TIME_FIELDS IntTimeFields
;
177 memcpy(&IntTimeFields
,
179 sizeof(TIME_FIELDS
));
181 if (TimeFields
->Milliseconds
< 0 || TimeFields
->Milliseconds
> 999 ||
182 TimeFields
->Second
< 0 || TimeFields
->Second
> 59 ||
183 TimeFields
->Minute
< 0 || TimeFields
->Minute
> 59 ||
184 TimeFields
->Hour
< 0 || TimeFields
->Hour
> 23 ||
185 TimeFields
->Month
< 1 || TimeFields
->Month
> 12 ||
186 TimeFields
->Day
< 1 ||
188 MonthLengths
[IsLeapYear(TimeFields
->Year
)][TimeFields
->Month
- 1] ||
189 TimeFields
->Year
< 1601)
194 /* Compute the time */
195 Time
->QuadPart
= DaysSinceEpoch(IntTimeFields
.Year
);
196 for (CurMonth
= 1; CurMonth
< IntTimeFields
.Month
; CurMonth
++)
198 Time
->QuadPart
+= MonthLengths
[IsLeapYear(IntTimeFields
.Year
)][CurMonth
- 1];
200 Time
->QuadPart
+= IntTimeFields
.Day
- 1;
201 Time
->QuadPart
*= SECSPERDAY
;
202 Time
->QuadPart
+= IntTimeFields
.Hour
* SECSPERHOUR
+ IntTimeFields
.Minute
* SECSPERMIN
+
203 IntTimeFields
.Second
;
204 Time
->QuadPart
*= TICKSPERSEC
;
205 Time
->QuadPart
+= IntTimeFields
.Milliseconds
* TICKSPERMSEC
;
216 RtlTimeToElapsedTimeFields(IN PLARGE_INTEGER Time
,
217 OUT PTIME_FIELDS TimeFields
)
219 ULONGLONG ElapsedSeconds
;
221 ULONG SecondsInMinute
;
223 /* Extract millisecond from time */
224 TimeFields
->Milliseconds
= (CSHORT
)((Time
->QuadPart
% TICKSPERSEC
) / TICKSPERMSEC
);
226 /* Compute elapsed seconds */
227 ElapsedSeconds
= (ULONGLONG
)Time
->QuadPart
/ TICKSPERSEC
;
229 /* Compute seconds within the day */
230 SecondsInDay
= ElapsedSeconds
% SECSPERDAY
;
232 /* Compute elapsed minutes within the day */
233 SecondsInMinute
= SecondsInDay
% SECSPERHOUR
;
235 /* Compute elapsed time of day */
236 TimeFields
->Hour
= (CSHORT
)(SecondsInDay
/ SECSPERHOUR
);
237 TimeFields
->Minute
= (CSHORT
)(SecondsInMinute
/ SECSPERMIN
);
238 TimeFields
->Second
= (CSHORT
)(SecondsInMinute
% SECSPERMIN
);
240 /* Compute elapsed days */
241 TimeFields
->Day
= (CSHORT
)(ElapsedSeconds
/ SECSPERDAY
);
243 /* The elapsed number of months and days cannot be calculated */
244 TimeFields
->Month
= 0;
245 TimeFields
->Year
= 0;
255 IN PLARGE_INTEGER Time
,
256 OUT PTIME_FIELDS TimeFields
)
259 ULONG SecondsInDay
, CurYear
;
260 ULONG LeapYear
, CurMonth
;
262 ULONGLONG IntTime
= Time
->QuadPart
;
264 /* Extract millisecond from time and convert time into seconds */
265 TimeFields
->Milliseconds
= (CSHORT
) ((IntTime
% TICKSPERSEC
) / TICKSPERMSEC
);
266 IntTime
= IntTime
/ TICKSPERSEC
;
268 /* Split the time into days and seconds within the day */
269 Days
= (ULONG
)(IntTime
/ SECSPERDAY
);
270 SecondsInDay
= IntTime
% SECSPERDAY
;
272 /* compute time of day */
273 TimeFields
->Hour
= (CSHORT
) (SecondsInDay
/ SECSPERHOUR
);
274 SecondsInDay
= SecondsInDay
% SECSPERHOUR
;
275 TimeFields
->Minute
= (CSHORT
) (SecondsInDay
/ SECSPERMIN
);
276 TimeFields
->Second
= (CSHORT
) (SecondsInDay
% SECSPERMIN
);
278 /* compute day of week */
279 TimeFields
->Weekday
= (CSHORT
) ((EPOCHWEEKDAY
+ Days
) % DAYSPERWEEK
);
283 CurYear
+= Days
/ DAYSPERLEAPYEAR
;
284 Days
-= DaysSinceEpoch(CurYear
);
287 LeapYear
= IsLeapYear(CurYear
);
288 if (Days
< YearLengths
[LeapYear
])
293 Days
= Days
- YearLengths
[LeapYear
];
295 TimeFields
->Year
= (CSHORT
) CurYear
;
297 /* Compute month of year */
298 LeapYear
= IsLeapYear(CurYear
);
299 Months
= MonthLengths
[LeapYear
];
300 for (CurMonth
= 0; Days
>= Months
[CurMonth
]; CurMonth
++)
301 Days
= Days
- Months
[CurMonth
];
302 TimeFields
->Month
= (CSHORT
) (CurMonth
+ 1);
303 TimeFields
->Day
= (CSHORT
) (Days
+ 1);
312 RtlTimeToSecondsSince1970(
313 IN PLARGE_INTEGER Time
,
314 OUT PULONG SecondsSince1970
)
316 LARGE_INTEGER IntTime
;
318 IntTime
.QuadPart
= Time
->QuadPart
- TICKSTO1970
;
319 IntTime
.QuadPart
= IntTime
.QuadPart
/ TICKSPERSEC
;
321 if (IntTime
.u
.HighPart
!= 0)
324 *SecondsSince1970
= IntTime
.u
.LowPart
;
335 RtlTimeToSecondsSince1980(
336 IN PLARGE_INTEGER Time
,
337 OUT PULONG SecondsSince1980
)
339 LARGE_INTEGER IntTime
;
341 IntTime
.QuadPart
= Time
->QuadPart
- TICKSTO1980
;
342 IntTime
.QuadPart
= IntTime
.QuadPart
/ TICKSPERSEC
;
344 if (IntTime
.u
.HighPart
!= 0)
347 *SecondsSince1980
= IntTime
.u
.LowPart
;
358 RtlLocalTimeToSystemTime(IN PLARGE_INTEGER LocalTime
,
359 OUT PLARGE_INTEGER SystemTime
)
361 SYSTEM_TIMEOFDAY_INFORMATION TimeInformation
;
364 Status
= ZwQuerySystemInformation(SystemTimeOfDayInformation
,
366 sizeof(SYSTEM_TIMEOFDAY_INFORMATION
),
368 if (!NT_SUCCESS(Status
))
371 SystemTime
->QuadPart
= LocalTime
->QuadPart
+
372 TimeInformation
.TimeZoneBias
.QuadPart
;
374 return STATUS_SUCCESS
;
383 RtlSystemTimeToLocalTime(IN PLARGE_INTEGER SystemTime
,
384 OUT PLARGE_INTEGER LocalTime
)
386 SYSTEM_TIMEOFDAY_INFORMATION TimeInformation
;
389 Status
= ZwQuerySystemInformation(SystemTimeOfDayInformation
,
391 sizeof(SYSTEM_TIMEOFDAY_INFORMATION
),
393 if (!NT_SUCCESS(Status
))
396 LocalTime
->QuadPart
= SystemTime
->QuadPart
-
397 TimeInformation
.TimeZoneBias
.QuadPart
;
399 return STATUS_SUCCESS
;
407 RtlSecondsSince1970ToTime(
408 IN ULONG SecondsSince1970
,
409 OUT PLARGE_INTEGER Time
)
411 Time
->QuadPart
= ((LONGLONG
)SecondsSince1970
* TICKSPERSEC
) + TICKSTO1970
;
419 RtlSecondsSince1980ToTime(
420 IN ULONG SecondsSince1980
,
421 OUT PLARGE_INTEGER Time
)
423 Time
->QuadPart
= ((LONGLONG
)SecondsSince1980
* TICKSPERSEC
) + TICKSTO1980
;