create rtl for stuff common to ntdll/ntoskrnl
[reactos.git] / reactos / lib / rtl / time.c
1 /* $Id: time.c,v 1.1 2004/05/31 19:29:02 gdalsnes Exp $
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: lib/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 #define NDEBUG
19 #include <debug.h>
20
21 #define TICKSPERMIN 600000000
22 #define TICKSPERSEC 10000000
23 #define TICKSPERMSEC 10000
24 #define SECSPERDAY 86400
25 #define SECSPERHOUR 3600
26 #define SECSPERMIN 60
27 #define MINSPERHOUR 60
28 #define HOURSPERDAY 24
29 #define EPOCHWEEKDAY 1
30 #define DAYSPERWEEK 7
31 #define EPOCHYEAR 1601
32 #define DAYSPERNORMALYEAR 365
33 #define DAYSPERLEAPYEAR 366
34 #define MONSPERYEAR 12
35
36 #if defined(__GNUC__)
37 #define TICKSTO1970 0x019db1ded53e8000LL
38 #define TICKSTO1980 0x01a8e79fe1d58000LL
39 #else
40 #define TICKSTO1970 0x019db1ded53e8000i64
41 #define TICKSTO1980 0x01a8e79fe1d58000i64
42 #endif
43
44
45 static const int YearLengths[2] =
46 {
47 DAYSPERNORMALYEAR, DAYSPERLEAPYEAR
48 };
49 static const int MonthLengths[2][MONSPERYEAR] =
50 {
51 {
52 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
53 },
54 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
55 };
56
57 static __inline int IsLeapYear(int Year)
58 {
59 return Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0) ? 1 : 0;
60 }
61
62 static __inline void NormalizeTimeFields(CSHORT *FieldToNormalize,
63 CSHORT *CarryField,
64 int Modulus)
65 {
66 *FieldToNormalize = (CSHORT) (*FieldToNormalize - Modulus);
67 *CarryField = (CSHORT) (*CarryField + 1);
68 }
69
70 /* FUNCTIONS *****************************************************************/
71
72 /*
73 * @implemented
74 */
75 BOOLEAN
76 STDCALL
77 RtlTimeFieldsToTime(
78 PTIME_FIELDS tfTimeFields,
79 PLARGE_INTEGER Time)
80 {
81 int CurYear;
82 int CurMonth;
83 #if defined(__GNUC__)
84
85 long long int rcTime;
86 #else
87
88 __int64 rcTime;
89 #endif
90
91 TIME_FIELDS TimeFields = *tfTimeFields;
92
93 rcTime = 0;
94
95 /* FIXME: normalize the TIME_FIELDS structure here */
96 while (TimeFields.Second >= SECSPERMIN)
97 {
98 NormalizeTimeFields(&TimeFields.Second,
99 &TimeFields.Minute,
100 SECSPERMIN);
101 }
102 while (TimeFields.Minute >= MINSPERHOUR)
103 {
104 NormalizeTimeFields(&TimeFields.Minute,
105 &TimeFields.Hour,
106 MINSPERHOUR);
107 }
108 while (TimeFields.Hour >= HOURSPERDAY)
109 {
110 NormalizeTimeFields(&TimeFields.Hour,
111 &TimeFields.Day,
112 HOURSPERDAY);
113 }
114 while (TimeFields.Day >
115 MonthLengths[IsLeapYear(TimeFields.Year)][TimeFields.Month - 1])
116 {
117 NormalizeTimeFields(&TimeFields.Day,
118 &TimeFields.Month,
119 SECSPERMIN);
120 }
121 while (TimeFields.Month > MONSPERYEAR)
122 {
123 NormalizeTimeFields(&TimeFields.Month,
124 &TimeFields.Year,
125 MONSPERYEAR);
126 }
127
128 /* FIXME: handle calendar corrections here */
129 for (CurYear = EPOCHYEAR; CurYear < TimeFields.Year; CurYear++)
130 {
131 rcTime += YearLengths[IsLeapYear(CurYear)];
132 }
133 for (CurMonth = 1; CurMonth < TimeFields.Month; CurMonth++)
134 {
135 rcTime += MonthLengths[IsLeapYear(CurYear)][CurMonth - 1];
136 }
137 rcTime += TimeFields.Day - 1;
138 rcTime *= SECSPERDAY;
139 rcTime += TimeFields.Hour * SECSPERHOUR + TimeFields.Minute * SECSPERMIN +
140 TimeFields.Second;
141 rcTime *= TICKSPERSEC;
142 rcTime += TimeFields.Milliseconds * TICKSPERMSEC;
143 *Time = *(LARGE_INTEGER *)&rcTime;
144
145 return TRUE;
146 }
147
148
149
150 /*
151 * @implemented
152 */
153 VOID
154 STDCALL
155 RtlTimeToElapsedTimeFields(IN PLARGE_INTEGER Time,
156 OUT PTIME_FIELDS TimeFields)
157 {
158 ULONGLONG ElapsedSeconds;
159 ULONG SecondsInDay;
160 ULONG SecondsInMinute;
161
162 /* Extract millisecond from time */
163 TimeFields->Milliseconds = (CSHORT)((Time->QuadPart % TICKSPERSEC) / TICKSPERMSEC);
164
165 /* Compute elapsed seconds */
166 ElapsedSeconds = (ULONGLONG)Time->QuadPart / TICKSPERSEC;
167
168 /* Compute seconds within the day */
169 SecondsInDay = ElapsedSeconds % SECSPERDAY;
170
171 /* Compute elapsed minutes within the day */
172 SecondsInMinute = SecondsInDay % SECSPERHOUR;
173
174 /* Compute elapsed time of day */
175 TimeFields->Hour = (CSHORT)(SecondsInDay / SECSPERHOUR);
176 TimeFields->Minute = (CSHORT)(SecondsInMinute / SECSPERMIN);
177 TimeFields->Second = (CSHORT)(SecondsInMinute % SECSPERMIN);
178
179 /* Compute elapsed days */
180 TimeFields->Day = (CSHORT)(ElapsedSeconds / SECSPERDAY);
181
182 /* The elapsed number of months and days cannot be calculated */
183 TimeFields->Month = 0;
184 TimeFields->Year = 0;
185 }
186
187
188
189 /*
190 * @unimplemented
191 */
192 VOID
193 STDCALL
194 RtlTimeToTimeFields(
195 PLARGE_INTEGER liTime,
196 PTIME_FIELDS TimeFields)
197 {
198 const int *Months;
199 int LeapSecondCorrections, SecondsInDay, CurYear;
200 int LeapYear, CurMonth, GMTOffset;
201 long int Days;
202 #if defined(__GNUC__)
203
204 long long int Time = (long long int)liTime->QuadPart;
205 #else
206
207 __int64 Time = (__int64)liTime->QuadPart;
208 #endif
209
210 /* Extract millisecond from time and convert time into seconds */
211 TimeFields->Milliseconds = (CSHORT) ((Time % TICKSPERSEC) / TICKSPERMSEC);
212 Time = Time / TICKSPERSEC;
213
214 /* FIXME: Compute the number of leap second corrections here */
215 LeapSecondCorrections = 0;
216
217 /* FIXME: get the GMT offset here */
218 GMTOffset = 0;
219
220 /* Split the time into days and seconds within the day */
221 Days = Time / SECSPERDAY;
222 SecondsInDay = Time % SECSPERDAY;
223
224 /* Adjust the values for GMT and leap seconds */
225 SecondsInDay += (GMTOffset - LeapSecondCorrections);
226 while (SecondsInDay < 0)
227 {
228 SecondsInDay += SECSPERDAY;
229 Days--;
230 }
231 while (SecondsInDay >= SECSPERDAY)
232 {
233 SecondsInDay -= SECSPERDAY;
234 Days++;
235 }
236
237 /* compute time of day */
238 TimeFields->Hour = (CSHORT) (SecondsInDay / SECSPERHOUR);
239 SecondsInDay = SecondsInDay % SECSPERHOUR;
240 TimeFields->Minute = (CSHORT) (SecondsInDay / SECSPERMIN);
241 TimeFields->Second = (CSHORT) (SecondsInDay % SECSPERMIN);
242
243 /* FIXME: handle the possibility that we are on a leap second (i.e. Second = 60) */
244
245 /* compute day of week */
246 TimeFields->Weekday = (CSHORT) ((EPOCHWEEKDAY + Days) % DAYSPERWEEK);
247
248 /* compute year */
249 CurYear = EPOCHYEAR;
250 CurYear += Days / DAYSPERLEAPYEAR;
251 Days -= (CurYear - EPOCHYEAR) * DAYSPERLEAPYEAR;
252 CurYear--; /* The next calculation needs CurYear - 1 */
253 Days += CurYear - CurYear / 4 + CurYear / 100 - CurYear / 400;
254 CurYear++;
255 Days -= EPOCHYEAR - 1 - (EPOCHYEAR -1) / 4 + (EPOCHYEAR -1) / 100 - (EPOCHYEAR - 1) / 400;
256 /* FIXME: handle calendar modifications */
257 while (1)
258 {
259 LeapYear = IsLeapYear(CurYear);
260 if (Days < (long) YearLengths[LeapYear])
261 {
262 break;
263 }
264 CurYear++;
265 Days = Days - (long) YearLengths[LeapYear];
266 }
267 TimeFields->Year = (CSHORT) CurYear;
268
269 /* Compute month of year */
270 LeapYear = IsLeapYear(CurYear);
271 Months = MonthLengths[LeapYear];
272 for (CurMonth = 0; Days >= (long) Months[CurMonth]; CurMonth++)
273 Days = Days - (long) Months[CurMonth];
274 TimeFields->Month = (CSHORT) (CurMonth + 1);
275 TimeFields->Day = (CSHORT) (Days + 1);
276 }
277
278
279 /*
280 * @implemented
281 */
282 BOOLEAN
283 STDCALL
284 RtlTimeToSecondsSince1970(
285 PLARGE_INTEGER Time,
286 PULONG SecondsSince1970)
287 {
288 LARGE_INTEGER liTime;
289
290 liTime.QuadPart = Time->QuadPart - TICKSTO1970;
291 liTime.QuadPart = liTime.QuadPart / TICKSPERSEC;
292
293 if (liTime.u.HighPart != 0)
294 return FALSE;
295
296 *SecondsSince1970 = liTime.u.LowPart;
297
298 return TRUE;
299 }
300
301
302 /*
303 * @implemented
304 */
305 BOOLEAN
306 STDCALL
307 RtlTimeToSecondsSince1980(
308 PLARGE_INTEGER Time,
309 PULONG SecondsSince1980)
310 {
311 LARGE_INTEGER liTime;
312
313 liTime.QuadPart = Time->QuadPart - TICKSTO1980;
314 liTime.QuadPart = liTime.QuadPart / TICKSPERSEC;
315
316 if (liTime.u.HighPart != 0)
317 return FALSE;
318
319 *SecondsSince1980 = liTime.u.LowPart;
320
321 return TRUE;
322 }
323
324
325 /*
326 * @implemented
327 */
328 NTSTATUS
329 STDCALL
330 RtlLocalTimeToSystemTime(PLARGE_INTEGER LocalTime,
331 PLARGE_INTEGER SystemTime)
332 {
333 SYSTEM_TIMEOFDAY_INFORMATION TimeInformation;
334 NTSTATUS Status;
335
336 Status = NtQuerySystemInformation(SystemTimeOfDayInformation,
337 &TimeInformation,
338 sizeof(SYSTEM_TIMEOFDAY_INFORMATION),
339 NULL);
340 if (!NT_SUCCESS(Status))
341 return(Status);
342
343 SystemTime->QuadPart = LocalTime->QuadPart +
344 TimeInformation.TimeZoneBias.QuadPart;
345
346 return(STATUS_SUCCESS);
347 }
348
349
350
351
352 /*
353 * @implemented
354 */
355 NTSTATUS
356 STDCALL
357 RtlSystemTimeToLocalTime(PLARGE_INTEGER SystemTime,
358 PLARGE_INTEGER LocalTime)
359 {
360 SYSTEM_TIMEOFDAY_INFORMATION TimeInformation;
361 NTSTATUS Status;
362
363 Status = NtQuerySystemInformation(SystemTimeOfDayInformation,
364 &TimeInformation,
365 sizeof(SYSTEM_TIMEOFDAY_INFORMATION),
366 NULL);
367 if (!NT_SUCCESS(Status))
368 return(Status);
369
370 LocalTime->QuadPart = SystemTime->QuadPart -
371 TimeInformation.TimeZoneBias.QuadPart;
372
373 return(STATUS_SUCCESS);
374 }
375
376
377 /*
378 * @implemented
379 */
380 VOID
381 STDCALL
382 RtlSecondsSince1970ToTime(
383 ULONG SecondsSince1970,
384 PLARGE_INTEGER Time)
385 {
386 LONGLONG llTime;
387
388 llTime = (SecondsSince1970 * TICKSPERSEC) + TICKSTO1970;
389
390 *Time = *(LARGE_INTEGER *)&llTime;
391 }
392
393
394 /*
395 * @implemented
396 */
397 VOID
398 STDCALL
399 RtlSecondsSince1980ToTime(
400 ULONG SecondsSince1980,
401 PLARGE_INTEGER Time)
402 {
403 LONGLONG llTime;
404
405 llTime = (SecondsSince1980 * TICKSPERSEC) + TICKSTO1980;
406
407 *Time = *(LARGE_INTEGER *)&llTime;
408 }
409
410
411
412 /* EOF */