ReactOS  0.4.14-dev-98-gb0d4763
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 
40 static const unsigned int YearLengths[2] =
41 {
43 };
44 static 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 
50 static __inline int IsLeapYear(int Year)
51 {
52  return Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0) ? 1 : 0;
53 }
54 
55 static 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  */
168 BOOLEAN
169 NTAPI
172 {
173  ULONG CurMonth;
174  TIME_FIELDS IntTimeFields;
175 
176  RtlCopyMemory(&IntTimeFields,
177  TimeFields,
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  */
213 VOID
214 NTAPI
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  */
251 VOID
252 NTAPI
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  */
310 BOOLEAN
311 NTAPI
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  */
332 BOOLEAN
333 NTAPI
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  */
354 NTSTATUS
355 NTAPI
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  */
379 NTSTATUS
380 NTAPI
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  */
404 VOID
405 NTAPI
408 {
409  Time->QuadPart = ((LONGLONG)SecondsSince1970 * TICKSPERSEC) + TICKSTO1970;
410 }
411 
412 
413 /*
414  * @implemented
415  */
416 VOID NTAPI
419 {
420  Time->QuadPart = ((LONGLONG)SecondsSince1980 * TICKSPERSEC) + TICKSTO1980;
421 }
422 
423 /* EOF */
USHORT Weekday
Definition: env_spec_w32.h:718
#define DAYSPERWEEK
Definition: time.c:25
#define IN
Definition: typedefs.h:38
#define TRUE
Definition: types.h:120
NTSYSAPI VOID NTAPI RtlCopyMemory(VOID UNALIGNED *Destination, CONST VOID UNALIGNED *Source, ULONG Length)
#define TICKSTO1980
Definition: time.c:36
VOID NTAPI RtlTimeToTimeFields(IN PLARGE_INTEGER Time, OUT PTIME_FIELDS TimeFields)
Definition: time.c:253
#define DAYSPERLEAPYEAR
Definition: time.c:28
NTSTATUS NTAPI RtlLocalTimeToSystemTime(IN PLARGE_INTEGER LocalTime, OUT PLARGE_INTEGER SystemTime)
Definition: time.c:356
LONG NTSTATUS
Definition: precomp.h:26
static WORD LeapYear(IN WORD Year)
Definition: monthcal.c:84
static const unsigned int YearLengths[2]
Definition: time.c:40
static __inline int IsLeapYear(int Year)
Definition: time.c:50
static int DaysSinceEpoch(int Year)
Definition: time.c:55
#define SECSPERHOUR
Definition: time.c:20
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
#define EPOCHYEAR
Definition: time.c:26
NTSYSAPI NTSTATUS NTAPI ZwQuerySystemInformation(IN SYSTEM_INFORMATION_CLASS SystemInfoClass, OUT PVOID SystemInfoBuffer, IN ULONG SystemInfoBufferSize, OUT PULONG BytesReturned OPTIONAL)
#define TICKSTO1970
Definition: time.c:35
unsigned char BOOLEAN
struct _LARGE_INTEGER::@2205 u
smooth NULL
Definition: ftsmooth.c:416
static const UCHAR MonthLengths[2][MONSPERYEAR]
Definition: time.c:44
VOID NTAPI RtlSecondsSince1980ToTime(IN ULONG SecondsSince1980, OUT PLARGE_INTEGER Time)
Definition: time.c:417
USHORT Milliseconds
Definition: env_spec_w32.h:717
#define DAYSPERNORMALYEAR
Definition: time.c:27
int64_t LONGLONG
Definition: typedefs.h:66
VOID NTAPI RtlTimeToElapsedTimeFields(IN PLARGE_INTEGER Time, OUT PTIME_FIELDS TimeFields)
Definition: time.c:215
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
uint64_t ULONGLONG
Definition: typedefs.h:65
#define SECSPERMIN
Definition: time.c:21
#define EPOCHWEEKDAY
Definition: time.c:24
unsigned char UCHAR
Definition: xmlstorage.h:181
#define TICKSPERMSEC
Definition: time.c:18
Status
Definition: gdiplustypes.h:24
VOID NTAPI RtlSecondsSince1970ToTime(IN ULONG SecondsSince1970, OUT PLARGE_INTEGER Time)
Definition: time.c:406
#define MONSPERYEAR
Definition: time.c:29
LARGE_INTEGER TimeZoneBias
Definition: extypes.h:847
BOOLEAN NTAPI RtlTimeToSecondsSince1970(IN PLARGE_INTEGER Time, OUT PULONG SecondsSince1970)
Definition: time.c:312
static ULONG(WINAPI *pNtGetTickCount)(void)
unsigned int * PULONG
Definition: retypes.h:1
BOOLEAN NTAPI RtlTimeFieldsToTime(IN PTIME_FIELDS TimeFields, OUT PLARGE_INTEGER Time)
Definition: time.c:170
#define TICKSPERSEC
Definition: time.c:17
NTSTATUS NTAPI RtlSystemTimeToLocalTime(IN PLARGE_INTEGER SystemTime, OUT PLARGE_INTEGER LocalTime)
Definition: time.c:381
BOOLEAN NTAPI RtlTimeToSecondsSince1980(IN PLARGE_INTEGER Time, OUT PULONG SecondsSince1980)
Definition: time.c:334
#define OUT
Definition: typedefs.h:39
#define SECSPERDAY
Definition: time.c:19
unsigned int ULONG
Definition: retypes.h:1
static PTIME_FIELDS TimeFields
Definition: time.c:104
return STATUS_SUCCESS
Definition: btrfs.c:2966
short CSHORT
Definition: umtypes.h:127
_Out_ PULONG ElapsedSeconds
Definition: rtlfuncs.h:4436
static PLARGE_INTEGER Time
Definition: time.c:105
LONGLONG QuadPart
Definition: typedefs.h:112
BOOLEAN NTAPI RtlCutoverTimeToSystemTime(IN PTIME_FIELDS CutoverTimeFields, OUT PLARGE_INTEGER SystemTime, IN PLARGE_INTEGER CurrentTime, IN BOOLEAN ThisYearsCutoverOnly)
Definition: time.c:70