Split out the resource functions for finer control of debug output.
[reactos.git] / reactos / lib / ntdll / rtl / time.c
1 /* $Id: time.c,v 1.14 2002/12/08 15:57:39 robd Exp $
2 *
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)
8 * UPDATE HISTORY:
9 * Created 22/05/98
10 * 08/03/98 RJJ Implemented these functions
11 */
12
13 /* INCLUDES *****************************************************************/
14
15 #include <ddk/ntddk.h>
16 #include <ntdll/rtl.h>
17
18
19 #define TICKSPERSEC 10000000
20 #define TICKSPERMSEC 10000
21 #define SECSPERDAY 86400
22 #define SECSPERHOUR 3600
23 #define SECSPERMIN 60
24 #define MINSPERHOUR 60
25 #define HOURSPERDAY 24
26 #define EPOCHWEEKDAY 1
27 #define DAYSPERWEEK 7
28 #define EPOCHYEAR 1601
29 #define DAYSPERNORMALYEAR 365
30 #define DAYSPERLEAPYEAR 366
31 #define MONSPERYEAR 12
32
33 #define TICKSTO1970 0x019db1ded53e8000
34 #define TICKSTO1980 0x01a8e79fe1d58000
35
36 static const int YearLengths[2] = {DAYSPERNORMALYEAR, DAYSPERLEAPYEAR};
37 static const int MonthLengths[2][MONSPERYEAR] =
38 {
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 }
41 };
42
43 static __inline int IsLeapYear(int Year)
44 {
45 return Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0) ? 1 : 0;
46 }
47
48 static __inline void NormalizeTimeFields(CSHORT *FieldToNormalize,
49 CSHORT *CarryField,
50 int Modulus)
51 {
52 *FieldToNormalize = (CSHORT) (*FieldToNormalize - Modulus);
53 *CarryField = (CSHORT) (*CarryField + 1);
54 }
55
56 /* FUNCTIONS *****************************************************************/
57
58 VOID
59 STDCALL
60 RtlTimeToTimeFields(
61 PLARGE_INTEGER liTime,
62 PTIME_FIELDS TimeFields)
63 {
64 const int *Months;
65 int LeapSecondCorrections, SecondsInDay, CurYear;
66 int LeapYear, CurMonth, GMTOffset;
67 long int Days;
68 long long int Time = (long long int)liTime->QuadPart;
69
70 /* Extract millisecond from time and convert time into seconds */
71 TimeFields->Milliseconds = (CSHORT) ((Time % TICKSPERSEC) / TICKSPERMSEC);
72 Time = Time / TICKSPERSEC;
73
74 /* FIXME: Compute the number of leap second corrections here */
75 LeapSecondCorrections = 0;
76
77 /* FIXME: get the GMT offset here */
78 GMTOffset = 0;
79
80 /* Split the time into days and seconds within the day */
81 Days = Time / SECSPERDAY;
82 SecondsInDay = Time % SECSPERDAY;
83
84 /* Adjust the values for GMT and leap seconds */
85 SecondsInDay += (GMTOffset - LeapSecondCorrections);
86 while (SecondsInDay < 0)
87 {
88 SecondsInDay += SECSPERDAY;
89 Days--;
90 }
91 while (SecondsInDay >= SECSPERDAY)
92 {
93 SecondsInDay -= SECSPERDAY;
94 Days++;
95 }
96
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);
102
103 /* FIXME: handle the possibility that we are on a leap second (i.e. Second = 60) */
104
105 /* compute day of week */
106 TimeFields->Weekday = (CSHORT) ((EPOCHWEEKDAY + Days) % DAYSPERWEEK);
107
108 /* compute year */
109 CurYear = EPOCHYEAR;
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;
114 CurYear++;
115 Days -= EPOCHYEAR - 1 - (EPOCHYEAR -1) / 4 + (EPOCHYEAR -1) / 100 - (EPOCHYEAR - 1) / 400;
116
117 /* FIXME: handle calendar modifications */
118 while (1)
119 {
120 LeapYear = IsLeapYear(CurYear);
121 if (Days < (long) YearLengths[LeapYear])
122 {
123 break;
124 }
125 CurYear++;
126 Days = Days - (long) YearLengths[LeapYear];
127 }
128 TimeFields->Year = (CSHORT) CurYear;
129
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);
137 }
138
139
140 BOOLEAN
141 STDCALL
142 RtlTimeFieldsToTime(
143 PTIME_FIELDS tfTimeFields,
144 PLARGE_INTEGER Time)
145 {
146 int CurYear;
147 int CurMonth;
148 long long int rcTime;
149 TIME_FIELDS TimeFields = *tfTimeFields;
150
151 rcTime = 0;
152
153 /* FIXME: normalize the TIME_FIELDS structure here */
154 while (TimeFields.Second >= SECSPERMIN)
155 {
156 NormalizeTimeFields(&TimeFields.Second,
157 &TimeFields.Minute,
158 SECSPERMIN);
159 }
160 while (TimeFields.Minute >= MINSPERHOUR)
161 {
162 NormalizeTimeFields(&TimeFields.Minute,
163 &TimeFields.Hour,
164 MINSPERHOUR);
165 }
166 while (TimeFields.Hour >= HOURSPERDAY)
167 {
168 NormalizeTimeFields(&TimeFields.Hour,
169 &TimeFields.Day,
170 HOURSPERDAY);
171 }
172 while (TimeFields.Day >
173 MonthLengths[IsLeapYear(TimeFields.Year)][TimeFields.Month - 1])
174 {
175 NormalizeTimeFields(&TimeFields.Day,
176 &TimeFields.Month,
177 SECSPERMIN);
178 }
179 while (TimeFields.Month > MONSPERYEAR)
180 {
181 NormalizeTimeFields(&TimeFields.Month,
182 &TimeFields.Year,
183 MONSPERYEAR);
184 }
185
186 /* FIXME: handle calendar corrections here */
187 for (CurYear = EPOCHYEAR; CurYear < TimeFields.Year; CurYear++)
188 {
189 rcTime += YearLengths[IsLeapYear(CurYear)];
190 }
191 for (CurMonth = 1; CurMonth < TimeFields.Month; CurMonth++)
192 {
193 rcTime += MonthLengths[IsLeapYear(CurYear)][CurMonth - 1];
194 }
195 rcTime += TimeFields.Day - 1;
196 rcTime *= SECSPERDAY;
197 rcTime += TimeFields.Hour * SECSPERHOUR + TimeFields.Minute * SECSPERMIN +
198 TimeFields.Second;
199 rcTime *= TICKSPERSEC;
200 rcTime += TimeFields.Milliseconds * TICKSPERMSEC;
201 *Time = *(LARGE_INTEGER *)&rcTime;
202
203 return TRUE;
204 }
205
206
207 VOID
208 STDCALL
209 RtlSecondsSince1970ToTime(
210 ULONG SecondsSince1970,
211 PLARGE_INTEGER Time)
212 {
213 LONGLONG llTime;
214
215 llTime = (SecondsSince1970 * TICKSPERSEC) + TICKSTO1970;
216
217 *Time = *(LARGE_INTEGER *)&llTime;
218 }
219
220
221 VOID
222 STDCALL
223 RtlSecondsSince1980ToTime(
224 ULONG SecondsSince1980,
225 PLARGE_INTEGER Time)
226 {
227 LONGLONG llTime;
228
229 llTime = (SecondsSince1980 * TICKSPERSEC) + TICKSTO1980;
230
231 *Time = *(LARGE_INTEGER *)&llTime;
232 }
233
234
235 BOOLEAN
236 STDCALL
237 RtlTimeToSecondsSince1970(
238 PLARGE_INTEGER Time,
239 PULONG SecondsSince1970)
240 {
241 LARGE_INTEGER liTime;
242
243 liTime.QuadPart = Time->QuadPart - TICKSTO1970;
244 liTime.QuadPart = liTime.QuadPart / TICKSPERSEC;
245
246 if (liTime.u.HighPart != 0)
247 return FALSE;
248
249 *SecondsSince1970 = liTime.u.LowPart;
250
251 return TRUE;
252 }
253
254
255 BOOLEAN
256 STDCALL
257 RtlTimeToSecondsSince1980(
258 PLARGE_INTEGER Time,
259 PULONG SecondsSince1980)
260 {
261 LARGE_INTEGER liTime;
262
263 liTime.QuadPart = Time->QuadPart - TICKSTO1980;
264 liTime.QuadPart = liTime.QuadPart / TICKSPERSEC;
265
266 if (liTime.u.HighPart != 0)
267 return FALSE;
268
269 *SecondsSince1980 = liTime.u.LowPart;
270
271 return TRUE;
272 }
273
274
275 NTSTATUS
276 STDCALL
277 RtlLocalTimeToSystemTime(PLARGE_INTEGER LocalTime,
278 PLARGE_INTEGER SystemTime)
279 {
280 SYSTEM_TIMEOFDAY_INFORMATION TimeInformation;
281 NTSTATUS Status;
282
283 Status = NtQuerySystemInformation(SystemTimeOfDayInformation,
284 &TimeInformation,
285 sizeof(SYSTEM_TIMEOFDAY_INFORMATION),
286 NULL);
287 if (!NT_SUCCESS(Status))
288 return(Status);
289
290 SystemTime->QuadPart = LocalTime->QuadPart +
291 TimeInformation.TimeZoneBias.QuadPart;
292
293 return(STATUS_SUCCESS);
294 }
295
296
297 NTSTATUS
298 STDCALL
299 RtlSystemTimeToLocalTime(PLARGE_INTEGER SystemTime,
300 PLARGE_INTEGER LocalTime)
301 {
302 SYSTEM_TIMEOFDAY_INFORMATION TimeInformation;
303 NTSTATUS Status;
304
305 Status = NtQuerySystemInformation(SystemTimeOfDayInformation,
306 &TimeInformation,
307 sizeof(SYSTEM_TIMEOFDAY_INFORMATION),
308 NULL);
309 if (!NT_SUCCESS(Status))
310 return(Status);
311
312 LocalTime->QuadPart = SystemTime->QuadPart -
313 TimeInformation.TimeZoneBias.QuadPart;
314
315 return(STATUS_SUCCESS);
316 }
317
318
319 VOID
320 STDCALL
321 RtlTimeToElapsedTimeFields(IN PLARGE_INTEGER Time,
322 OUT PTIME_FIELDS TimeFields)
323 {
324 ULONGLONG ElapsedSeconds;
325 ULONG SecondsInDay;
326 ULONG SecondsInMinute;
327
328 /* Extract millisecond from time */
329 TimeFields->Milliseconds = (CSHORT)((Time->QuadPart % TICKSPERSEC) / TICKSPERMSEC);
330
331 /* Compute elapsed seconds */
332 ElapsedSeconds = (ULONGLONG)Time->QuadPart / TICKSPERSEC;
333
334 /* Compute seconds within the day */
335 SecondsInDay = ElapsedSeconds % SECSPERDAY;
336
337 /* Compute elapsed minutes within the day */
338 SecondsInMinute = SecondsInDay % SECSPERHOUR;
339
340 /* Compute elapsed time of day */
341 TimeFields->Hour = (CSHORT)(SecondsInDay / SECSPERHOUR);
342 TimeFields->Minute = (CSHORT)(SecondsInMinute / SECSPERMIN);
343 TimeFields->Second = (CSHORT)(SecondsInMinute % SECSPERMIN);
344
345 /* Compute elapsed days */
346 TimeFields->Day = (CSHORT)(ElapsedSeconds / SECSPERDAY);
347
348 /* The elapsed number of months and days cannot be calculated */
349 TimeFields->Month = 0;
350 TimeFields->Year = 0;
351 }
352
353
354 /* EOF */