ReactOS 0.4.15-dev-7918-g2a2556c
time.c
Go to the documentation of this file.
1/*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS system libraries
4 * FILE: lib/rtl/time.c
5 * PURPOSE: Conversion between Time and TimeFields
6 * PROGRAMMER: Rex Jolliff (rex@lvcablemodem.com)
7 */
8
9/* INCLUDES *****************************************************************/
10
11#include <rtl.h>
12
13#define NDEBUG
14#include <debug.h>
15
16#define TICKSPERMIN 600000000
17#define TICKSPERSEC 10000000
18#define TICKSPERMSEC 10000
19#define SECSPERDAY 86400
20#define SECSPERHOUR 3600
21#define SECSPERMIN 60
22#define MINSPERHOUR 60
23#define HOURSPERDAY 24
24#define EPOCHWEEKDAY 1
25#define DAYSPERWEEK 7
26#define EPOCHYEAR 1601
27#define DAYSPERNORMALYEAR 365
28#define DAYSPERLEAPYEAR 366
29#define MONSPERYEAR 12
30
31#if defined(__GNUC__)
32#define TICKSTO1970 0x019db1ded53e8000LL
33#define TICKSTO1980 0x01a8e79fe1d58000LL
34#else
35#define TICKSTO1970 0x019db1ded53e8000i64
36#define TICKSTO1980 0x01a8e79fe1d58000i64
37#endif
38
39
40static const unsigned int YearLengths[2] =
41{
43};
44static const UCHAR MonthLengths[2][MONSPERYEAR] =
45{
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 }
48};
49
50static __inline int IsLeapYear(int Year)
51{
52 return Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0) ? 1 : 0;
53}
54
55static int DaysSinceEpoch(int Year)
56{
57 int Days;
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;
61 return Days;
62}
63
64/* FUNCTIONS *****************************************************************/
65
66/*
67 * @implemented
68 */
71 OUT PLARGE_INTEGER SystemTime,
72 IN PLARGE_INTEGER CurrentTime,
73 IN BOOLEAN ThisYearsCutoverOnly)
74{
75 TIME_FIELDS AdjustedTimeFields;
76 TIME_FIELDS CurrentTimeFields;
77 TIME_FIELDS CutoverSystemTimeFields;
78 LARGE_INTEGER CutoverSystemTime;
79 UCHAR MonthLength;
80 CSHORT Days;
81 BOOLEAN NextYearsCutover = FALSE;
82
83 /* Check fixed cutover time */
84 if (CutoverTimeFields->Year != 0)
85 {
86 if (!RtlTimeFieldsToTime(CutoverTimeFields, SystemTime))
87 return FALSE;
88
89 if (SystemTime->QuadPart < CurrentTime->QuadPart)
90 return FALSE;
91
92 return TRUE;
93 }
94
95 /*
96 * Compute recurring cutover time
97 */
98
99 /* Day must be between 1(first) and 5(last) */
100 if (CutoverTimeFields->Day == 0 || CutoverTimeFields->Day > 5)
101 return FALSE;
102
103 RtlTimeToTimeFields(CurrentTime, &CurrentTimeFields);
104
105 while (TRUE)
106 {
107 /* Compute the cutover time of the first day of the current month */
108 AdjustedTimeFields.Year = CurrentTimeFields.Year;
109 if (NextYearsCutover)
110 AdjustedTimeFields.Year++;
111
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;
118
119 if (!RtlTimeFieldsToTime(&AdjustedTimeFields, &CutoverSystemTime))
120 return FALSE;
121
122 RtlTimeToTimeFields(&CutoverSystemTime, &CutoverSystemTimeFields);
123
124 /* Adjust day to first matching weekday */
125 if (CutoverSystemTimeFields.Weekday != CutoverTimeFields->Weekday)
126 {
127 if (CutoverSystemTimeFields.Weekday < CutoverTimeFields->Weekday)
128 Days = CutoverTimeFields->Weekday - CutoverSystemTimeFields.Weekday;
129 else
130 Days = DAYSPERWEEK - (CutoverSystemTimeFields.Weekday - CutoverTimeFields->Weekday);
131
132 AdjustedTimeFields.Day += Days;
133 }
134
135 /* Adjust the number of weeks */
136 if (CutoverTimeFields->Day > 1)
137 {
138 Days = DAYSPERWEEK * (CutoverTimeFields->Day - 1);
139 MonthLength = MonthLengths[IsLeapYear(AdjustedTimeFields.Year)][AdjustedTimeFields.Month - 1];
140 if ((AdjustedTimeFields.Day + Days) > MonthLength)
141 Days -= DAYSPERWEEK;
142
143 AdjustedTimeFields.Day += Days;
144 }
145
146 if (!RtlTimeFieldsToTime(&AdjustedTimeFields, &CutoverSystemTime))
147 return FALSE;
148
149 if (ThisYearsCutoverOnly ||
150 NextYearsCutover ||
151 CutoverSystemTime.QuadPart >= CurrentTime->QuadPart)
152 {
153 break;
154 }
155
156 NextYearsCutover = TRUE;
157 }
158
159 SystemTime->QuadPart = CutoverSystemTime.QuadPart;
160
161 return TRUE;
162}
163
164
165/*
166 * @implemented
167 */
169NTAPI
172{
173 ULONG CurMonth;
174 TIME_FIELDS IntTimeFields;
175
176 RtlCopyMemory(&IntTimeFields,
178 sizeof(TIME_FIELDS));
179
180 if (TimeFields->Milliseconds < 0 || TimeFields->Milliseconds > 999 ||
181 TimeFields->Second < 0 || TimeFields->Second > 59 ||
182 TimeFields->Minute < 0 || TimeFields->Minute > 59 ||
183 TimeFields->Hour < 0 || TimeFields->Hour > 23 ||
184 TimeFields->Month < 1 || TimeFields->Month > 12 ||
185 TimeFields->Day < 1 ||
186 TimeFields->Day >
188 TimeFields->Year < 1601)
189 {
190 return FALSE;
191 }
192
193 /* Compute the time */
194 Time->QuadPart = DaysSinceEpoch(IntTimeFields.Year);
195 for (CurMonth = 1; CurMonth < IntTimeFields.Month; CurMonth++)
196 {
197 Time->QuadPart += MonthLengths[IsLeapYear(IntTimeFields.Year)][CurMonth - 1];
198 }
199 Time->QuadPart += IntTimeFields.Day - 1;
201 Time->QuadPart += IntTimeFields.Hour * SECSPERHOUR + IntTimeFields.Minute * SECSPERMIN +
202 IntTimeFields.Second;
204 Time->QuadPart += IntTimeFields.Milliseconds * TICKSPERMSEC;
205
206 return TRUE;
207}
208
209
210/*
211 * @implemented
212 */
213VOID
214NTAPI
217{
219 ULONG SecondsInDay;
220 ULONG SecondsInMinute;
221
222 /* Extract millisecond from time */
224
225 /* Compute elapsed seconds */
227
228 /* Compute seconds within the day */
229 SecondsInDay = ElapsedSeconds % SECSPERDAY;
230
231 /* Compute elapsed minutes within the day */
232 SecondsInMinute = SecondsInDay % SECSPERHOUR;
233
234 /* Compute elapsed time of day */
235 TimeFields->Hour = (CSHORT)(SecondsInDay / SECSPERHOUR);
236 TimeFields->Minute = (CSHORT)(SecondsInMinute / SECSPERMIN);
237 TimeFields->Second = (CSHORT)(SecondsInMinute % SECSPERMIN);
238
239 /* Compute elapsed days */
241
242 /* The elapsed number of months and days cannot be calculated */
243 TimeFields->Month = 0;
244 TimeFields->Year = 0;
245}
246
247
248/*
249 * @implemented
250 */
251VOID
252NTAPI
255{
256 const UCHAR *Months;
257 ULONG SecondsInDay, CurYear;
258 ULONG LeapYear, CurMonth;
259 ULONG Days;
260 ULONGLONG IntTime = Time->QuadPart;
261
262 /* Extract millisecond from time and convert time into seconds */
264 IntTime = IntTime / TICKSPERSEC;
265
266 /* Split the time into days and seconds within the day */
267 Days = (ULONG)(IntTime / SECSPERDAY);
268 SecondsInDay = IntTime % SECSPERDAY;
269
270 /* Compute time of day */
271 TimeFields->Hour = (CSHORT)(SecondsInDay / SECSPERHOUR);
272 SecondsInDay = SecondsInDay % SECSPERHOUR;
273 TimeFields->Minute = (CSHORT)(SecondsInDay / SECSPERMIN);
274 TimeFields->Second = (CSHORT)(SecondsInDay % SECSPERMIN);
275
276 /* Compute day of week */
278
279 /* Compute year */
280 CurYear = EPOCHYEAR;
281 CurYear += Days / DAYSPERLEAPYEAR;
282 Days -= DaysSinceEpoch(CurYear);
283 while (TRUE)
284 {
285 LeapYear = IsLeapYear(CurYear);
286 if (Days < YearLengths[LeapYear])
287 {
288 break;
289 }
290 CurYear++;
291 Days = Days - YearLengths[LeapYear];
292 }
293 TimeFields->Year = (CSHORT)CurYear;
294
295 /* Compute month of year */
296 LeapYear = IsLeapYear(CurYear);
297 Months = MonthLengths[LeapYear];
298 for (CurMonth = 0; Days >= Months[CurMonth]; CurMonth++)
299 {
300 Days = Days - Months[CurMonth];
301 }
302 TimeFields->Month = (CSHORT)(CurMonth + 1);
303 TimeFields->Day = (CSHORT)(Days + 1);
304}
305
306
307/*
308 * @implemented
309 */
311NTAPI
313 OUT PULONG SecondsSince1970)
314{
315 LARGE_INTEGER IntTime;
316
317 IntTime.QuadPart = Time->QuadPart - TICKSTO1970;
318 IntTime.QuadPart = IntTime.QuadPart / TICKSPERSEC;
319
320 if (IntTime.u.HighPart != 0)
321 return FALSE;
322
323 *SecondsSince1970 = IntTime.u.LowPart;
324
325 return TRUE;
326}
327
328
329/*
330 * @implemented
331 */
333NTAPI
335 OUT PULONG SecondsSince1980)
336{
337 LARGE_INTEGER IntTime;
338
339 IntTime.QuadPart = Time->QuadPart - TICKSTO1980;
340 IntTime.QuadPart = IntTime.QuadPart / TICKSPERSEC;
341
342 if (IntTime.u.HighPart != 0)
343 return FALSE;
344
345 *SecondsSince1980 = IntTime.u.LowPart;
346
347 return TRUE;
348}
349
350
351/*
352 * @implemented
353 */
355NTAPI
357 OUT PLARGE_INTEGER SystemTime)
358{
359 SYSTEM_TIMEOFDAY_INFORMATION TimeInformation;
361
363 &TimeInformation,
364 sizeof(TimeInformation),
365 NULL);
366 if (!NT_SUCCESS(Status))
367 return Status;
368
369 SystemTime->QuadPart = LocalTime->QuadPart +
370 TimeInformation.TimeZoneBias.QuadPart;
371
372 return STATUS_SUCCESS;
373}
374
375
376/*
377 * @implemented
378 */
380NTAPI
382 OUT PLARGE_INTEGER LocalTime)
383{
384 SYSTEM_TIMEOFDAY_INFORMATION TimeInformation;
386
388 &TimeInformation,
389 sizeof(TimeInformation),
390 NULL);
391 if (!NT_SUCCESS(Status))
392 return Status;
393
394 LocalTime->QuadPart = SystemTime->QuadPart -
395 TimeInformation.TimeZoneBias.QuadPart;
396
397 return STATUS_SUCCESS;
398}
399
400
401/*
402 * @implemented
403 */
404VOID
405NTAPI
408{
409 Time->QuadPart = ((LONGLONG)SecondsSince1970 * TICKSPERSEC) + TICKSTO1970;
410}
411
412
413/*
414 * @implemented
415 */
419{
420 Time->QuadPart = ((LONGLONG)SecondsSince1980 * TICKSPERSEC) + TICKSTO1980;
421}
422
423/* EOF */
unsigned char BOOLEAN
LONG NTSTATUS
Definition: precomp.h:26
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
static WORD LeapYear(IN WORD Year)
Definition: monthcal.c:84
BOOLEAN RtlTimeToTimeFields(IN PLARGE_INTEGER Time, IN PTIME_FIELDS TimeFields)
BOOLEAN RtlTimeFieldsToTime(IN PTIME_FIELDS TimeFields, IN PLARGE_INTEGER Time)
NTSYSAPI NTSTATUS NTAPI ZwQuerySystemInformation(IN SYSTEM_INFORMATION_CLASS SystemInfoClass, OUT PVOID SystemInfoBuffer, IN ULONG SystemInfoBufferSize, OUT PULONG BytesReturned OPTIONAL)
@ SystemTimeOfDayInformation
Definition: ntddk_ex.h:14
Status
Definition: gdiplustypes.h:25
#define TICKSPERSEC
Definition: time.c:40
#define SECSPERMIN
Definition: time.c:36
#define SECSPERDAY
Definition: time.c:33
#define SECSPERHOUR
Definition: time.c:34
static PLARGE_INTEGER Time
Definition: time.c:105
static const int MonthLengths[2][12]
Definition: time.c:111
static PTIME_FIELDS TimeFields
Definition: time.c:104
_Out_ PULONG ElapsedSeconds
Definition: rtlfuncs.h:4646
NTSYSAPI BOOLEAN NTAPI RtlCutoverTimeToSystemTime(_In_ PTIME_FIELDS CutoverTimeFields, _Out_ PLARGE_INTEGER SystemTime, _In_ PLARGE_INTEGER CurrentTime, _In_ BOOLEAN ThisYearsCutoverOnly)
#define TICKSTO1980
Definition: time.c:36
NTSTATUS NTAPI RtlLocalTimeToSystemTime(IN PLARGE_INTEGER LocalTime, OUT PLARGE_INTEGER SystemTime)
Definition: time.c:356
VOID NTAPI RtlSecondsSince1980ToTime(IN ULONG SecondsSince1980, OUT PLARGE_INTEGER Time)
Definition: time.c:417
#define EPOCHWEEKDAY
Definition: time.c:24
VOID NTAPI RtlSecondsSince1970ToTime(IN ULONG SecondsSince1970, OUT PLARGE_INTEGER Time)
Definition: time.c:406
static const unsigned int YearLengths[2]
Definition: time.c:40
#define MONSPERYEAR
Definition: time.c:29
VOID NTAPI RtlTimeToElapsedTimeFields(IN PLARGE_INTEGER Time, OUT PTIME_FIELDS TimeFields)
Definition: time.c:215
#define EPOCHYEAR
Definition: time.c:26
#define DAYSPERWEEK
Definition: time.c:25
static int DaysSinceEpoch(int Year)
Definition: time.c:55
#define TICKSTO1970
Definition: time.c:35
BOOLEAN NTAPI RtlTimeToSecondsSince1970(IN PLARGE_INTEGER Time, OUT PULONG SecondsSince1970)
Definition: time.c:312
NTSTATUS NTAPI RtlSystemTimeToLocalTime(IN PLARGE_INTEGER SystemTime, OUT PLARGE_INTEGER LocalTime)
Definition: time.c:381
#define DAYSPERNORMALYEAR
Definition: time.c:27
#define DAYSPERLEAPYEAR
Definition: time.c:28
#define TICKSPERMSEC
Definition: time.c:18
BOOLEAN NTAPI RtlTimeToSecondsSince1980(IN PLARGE_INTEGER Time, OUT PULONG SecondsSince1980)
Definition: time.c:334
#define STATUS_SUCCESS
Definition: shellext.h:65
LARGE_INTEGER TimeZoneBias
Definition: extypes.h:859
USHORT Milliseconds
Definition: env_spec_w32.h:717
USHORT Weekday
Definition: env_spec_w32.h:718
uint32_t * PULONG
Definition: typedefs.h:59
int64_t LONGLONG
Definition: typedefs.h:68
#define NTAPI
Definition: typedefs.h:36
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263
#define IN
Definition: typedefs.h:39
uint32_t ULONG
Definition: typedefs.h:59
uint64_t ULONGLONG
Definition: typedefs.h:67
#define OUT
Definition: typedefs.h:40
short CSHORT
Definition: umtypes.h:127
LONGLONG QuadPart
Definition: typedefs.h:114
struct _LARGE_INTEGER::@2295 u
#define IsLeapYear(y)
Definition: variant.c:1048
unsigned char UCHAR
Definition: xmlstorage.h:181