3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: lib/ntdll/rtl/time.c
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>
19 #define TICKSPERSEC 10000000
20 #define TICKSPERMSEC 10000
21 #define SECSPERDAY 86400
22 #define SECSPERHOUR 3600
24 #define MINSPERHOUR 60
25 #define HOURSPERDAY 24
26 #define EPOCHWEEKDAY 1
28 #define EPOCHYEAR 1601
29 #define DAYSPERNORMALYEAR 365
30 #define DAYSPERLEAPYEAR 366
31 #define MONSPERYEAR 12
33 #define TICKSTO1970 0x019db1ded53e8000
34 #define TICKSTO1980 0x01a8e79fe1d58000
36 static const int YearLengths[2] = {DAYSPERNORMALYEAR, DAYSPERLEAPYEAR};
37 static const int MonthLengths[2][MONSPERYEAR] =
39 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
40 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
43 static __inline int IsLeapYear(int Year)
45 return Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0) ? 1 : 0;
48 static __inline void NormalizeTimeFields(CSHORT *FieldToNormalize,
52 *FieldToNormalize = (CSHORT) (*FieldToNormalize - Modulus);
53 *CarryField = (CSHORT) (*CarryField + 1);
56 /* FUNCTIONS *****************************************************************/
61 PLARGE_INTEGER liTime,
62 PTIME_FIELDS TimeFields)
65 int LeapSecondCorrections, SecondsInDay, CurYear;
66 int LeapYear, CurMonth, GMTOffset;
68 long long int Time = (long long int)liTime->QuadPart;
70 /* Extract millisecond from time and convert time into seconds */
71 TimeFields->Milliseconds = (CSHORT) ((Time % TICKSPERSEC) / TICKSPERMSEC);
72 Time = Time / TICKSPERSEC;
74 /* FIXME: Compute the number of leap second corrections here */
75 LeapSecondCorrections = 0;
77 /* FIXME: get the GMT offset here */
80 /* Split the time into days and seconds within the day */
81 Days = Time / SECSPERDAY;
82 SecondsInDay = Time % SECSPERDAY;
84 /* Adjust the values for GMT and leap seconds */
85 SecondsInDay += (GMTOffset - LeapSecondCorrections);
86 while (SecondsInDay < 0)
88 SecondsInDay += SECSPERDAY;
91 while (SecondsInDay >= SECSPERDAY)
93 SecondsInDay -= SECSPERDAY;
97 /* compute time of day */
98 TimeFields->Hour = (CSHORT) (SecondsInDay / SECSPERHOUR);
99 SecondsInDay = SecondsInDay % SECSPERHOUR;
100 TimeFields->Minute = (CSHORT) (SecondsInDay / SECSPERMIN);
101 TimeFields->Second = (CSHORT) (SecondsInDay % SECSPERMIN);
103 /* FIXME: handle the possibility that we are on a leap second (i.e. Second = 60) */
105 /* compute day of week */
106 TimeFields->Weekday = (CSHORT) ((EPOCHWEEKDAY + Days) % DAYSPERWEEK);
110 CurYear += Days / DAYSPERLEAPYEAR;
111 Days -= (CurYear - EPOCHYEAR) * DAYSPERLEAPYEAR;
112 CurYear--; /* The next calculation needs CurYear - 1 */
113 Days += CurYear - CurYear / 4 + CurYear / 100 - CurYear / 400;
115 Days -= EPOCHYEAR - 1 - (EPOCHYEAR -1) / 4 + (EPOCHYEAR -1) / 100 - (EPOCHYEAR - 1) / 400;
117 /* FIXME: handle calendar modifications */
120 LeapYear = IsLeapYear(CurYear);
121 if (Days < (long) YearLengths[LeapYear])
126 Days = Days - (long) YearLengths[LeapYear];
128 TimeFields->Year = (CSHORT) CurYear;
130 /* Compute month of year */
131 LeapYear = IsLeapYear(CurYear);
132 Months = MonthLengths[LeapYear];
133 for (CurMonth = 0; Days >= (long) Months[CurMonth]; CurMonth++)
134 Days = Days - (long) Months[CurMonth];
135 TimeFields->Month = (CSHORT) (CurMonth + 1);
136 TimeFields->Day = (CSHORT) (Days + 1);
143 PTIME_FIELDS tfTimeFields,
148 long long int rcTime;
149 TIME_FIELDS TimeFields = *tfTimeFields;
153 /* FIXME: normalize the TIME_FIELDS structure here */
154 while (TimeFields.Second >= SECSPERMIN)
156 NormalizeTimeFields(&TimeFields.Second,
160 while (TimeFields.Minute >= MINSPERHOUR)
162 NormalizeTimeFields(&TimeFields.Minute,
166 while (TimeFields.Hour >= HOURSPERDAY)
168 NormalizeTimeFields(&TimeFields.Hour,
172 while (TimeFields.Day >
173 MonthLengths[IsLeapYear(TimeFields.Year)][TimeFields.Month - 1])
175 NormalizeTimeFields(&TimeFields.Day,
179 while (TimeFields.Month > MONSPERYEAR)
181 NormalizeTimeFields(&TimeFields.Month,
186 /* FIXME: handle calendar corrections here */
187 for (CurYear = EPOCHYEAR; CurYear < TimeFields.Year; CurYear++)
189 rcTime += YearLengths[IsLeapYear(CurYear)];
191 for (CurMonth = 1; CurMonth < TimeFields.Month; CurMonth++)
193 rcTime += MonthLengths[IsLeapYear(CurYear)][CurMonth - 1];
195 rcTime += TimeFields.Day - 1;
196 rcTime *= SECSPERDAY;
197 rcTime += TimeFields.Hour * SECSPERHOUR + TimeFields.Minute * SECSPERMIN +
199 rcTime *= TICKSPERSEC;
200 rcTime += TimeFields.Milliseconds * TICKSPERMSEC;
201 *Time = *(LARGE_INTEGER *)&rcTime;
209 RtlSecondsSince1970ToTime(
210 ULONG SecondsSince1970,
215 llTime = (SecondsSince1970 * TICKSPERSEC) + TICKSTO1970;
217 *Time = *(LARGE_INTEGER *)&llTime;
223 RtlSecondsSince1980ToTime(
224 ULONG SecondsSince1980,
229 llTime = (SecondsSince1980 * TICKSPERSEC) + TICKSTO1980;
231 *Time = *(LARGE_INTEGER *)&llTime;
237 RtlTimeToSecondsSince1970(
239 PULONG SecondsSince1970)
241 LARGE_INTEGER liTime;
243 liTime.QuadPart = Time->QuadPart - TICKSTO1970;
244 liTime.QuadPart = liTime.QuadPart / TICKSPERSEC;
246 if (liTime.u.HighPart != 0)
249 *SecondsSince1970 = liTime.u.LowPart;
257 RtlTimeToSecondsSince1980(
259 PULONG SecondsSince1980)
261 LARGE_INTEGER liTime;
263 liTime.QuadPart = Time->QuadPart - TICKSTO1980;
264 liTime.QuadPart = liTime.QuadPart / TICKSPERSEC;
266 if (liTime.u.HighPart != 0)
269 *SecondsSince1980 = liTime.u.LowPart;
277 RtlLocalTimeToSystemTime(PLARGE_INTEGER LocalTime,
278 PLARGE_INTEGER SystemTime)
280 SYSTEM_TIMEOFDAY_INFORMATION TimeInformation;
283 Status = NtQuerySystemInformation(SystemTimeOfDayInformation,
285 sizeof(SYSTEM_TIMEOFDAY_INFORMATION),
287 if (!NT_SUCCESS(Status))
290 SystemTime->QuadPart = LocalTime->QuadPart +
291 TimeInformation.TimeZoneBias.QuadPart;
293 return(STATUS_SUCCESS);
299 RtlSystemTimeToLocalTime(PLARGE_INTEGER SystemTime,
300 PLARGE_INTEGER LocalTime)
302 SYSTEM_TIMEOFDAY_INFORMATION TimeInformation;
305 Status = NtQuerySystemInformation(SystemTimeOfDayInformation,
307 sizeof(SYSTEM_TIMEOFDAY_INFORMATION),
309 if (!NT_SUCCESS(Status))
312 LocalTime->QuadPart = SystemTime->QuadPart -
313 TimeInformation.TimeZoneBias.QuadPart;
315 return(STATUS_SUCCESS);
321 RtlTimeToElapsedTimeFields(IN PLARGE_INTEGER Time,
322 OUT PTIME_FIELDS TimeFields)
324 ULONGLONG ElapsedSeconds;
326 ULONG SecondsInMinute;
328 /* Extract millisecond from time */
329 TimeFields->Milliseconds = (CSHORT)((Time->QuadPart % TICKSPERSEC) / TICKSPERMSEC);
331 /* Compute elapsed seconds */
332 ElapsedSeconds = (ULONGLONG)Time->QuadPart / TICKSPERSEC;
334 /* Compute seconds within the day */
335 SecondsInDay = ElapsedSeconds % SECSPERDAY;
337 /* Compute elapsed minutes within the day */
338 SecondsInMinute = SecondsInDay % SECSPERHOUR;
340 /* Compute elapsed time of day */
341 TimeFields->Hour = (CSHORT)(SecondsInDay / SECSPERHOUR);
342 TimeFields->Minute = (CSHORT)(SecondsInMinute / SECSPERMIN);
343 TimeFields->Second = (CSHORT)(SecondsInMinute % SECSPERMIN);
345 /* Compute elapsed days */
346 TimeFields->Day = (CSHORT)(ElapsedSeconds / SECSPERDAY);
348 /* The elapsed number of months and days cannot be calculated */
349 TimeFields->Month = 0;
350 TimeFields->Year = 0;