migrate substitution keywords to SVN
[reactos.git] / reactos / lib / rtl / time.c
1 /* $Id$
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 TimeFields,
79 PLARGE_INTEGER Time)
80 {
81 int CurYear;
82 int CurMonth;
83 TIME_FIELDS IntTimeFields;
84
85 Time->QuadPart = 0;
86 memcpy(&IntTimeFields,
87 TimeFields,
88 sizeof(TIME_FIELDS));
89
90 /* Normalize the TIME_FIELDS structure here */
91 while (IntTimeFields.Second >= SECSPERMIN)
92 {
93 NormalizeTimeFields(&IntTimeFields.Second,
94 &IntTimeFields.Minute,
95 SECSPERMIN);
96 }
97 while (IntTimeFields.Minute >= MINSPERHOUR)
98 {
99 NormalizeTimeFields(&IntTimeFields.Minute,
100 &IntTimeFields.Hour,
101 MINSPERHOUR);
102 }
103 while (IntTimeFields.Hour >= HOURSPERDAY)
104 {
105 NormalizeTimeFields(&IntTimeFields.Hour,
106 &IntTimeFields.Day,
107 HOURSPERDAY);
108 }
109 while (IntTimeFields.Day >
110 MonthLengths[IsLeapYear(IntTimeFields.Year)][IntTimeFields.Month - 1])
111 {
112 NormalizeTimeFields(&IntTimeFields.Day,
113 &IntTimeFields.Month,
114 SECSPERMIN);
115 }
116 while (IntTimeFields.Month > MONSPERYEAR)
117 {
118 NormalizeTimeFields(&IntTimeFields.Month,
119 &IntTimeFields.Year,
120 MONSPERYEAR);
121 }
122
123 /* Compute the time */
124 for (CurYear = EPOCHYEAR; CurYear < IntTimeFields.Year; CurYear++)
125 {
126 Time->QuadPart += YearLengths[IsLeapYear(CurYear)];
127 }
128 for (CurMonth = 1; CurMonth < IntTimeFields.Month; CurMonth++)
129 {
130 Time->QuadPart += MonthLengths[IsLeapYear(CurYear)][CurMonth - 1];
131 }
132 Time->QuadPart += IntTimeFields.Day - 1;
133 Time->QuadPart *= SECSPERDAY;
134 Time->QuadPart += IntTimeFields.Hour * SECSPERHOUR + IntTimeFields.Minute * SECSPERMIN +
135 IntTimeFields.Second;
136 Time->QuadPart *= TICKSPERSEC;
137 Time->QuadPart += IntTimeFields.Milliseconds * TICKSPERMSEC;
138
139 return TRUE;
140 }
141
142
143 /*
144 * @implemented
145 */
146 VOID
147 STDCALL
148 RtlTimeToElapsedTimeFields(IN PLARGE_INTEGER Time,
149 OUT PTIME_FIELDS TimeFields)
150 {
151 ULONGLONG ElapsedSeconds;
152 ULONG SecondsInDay;
153 ULONG SecondsInMinute;
154
155 /* Extract millisecond from time */
156 TimeFields->Milliseconds = (CSHORT)((Time->QuadPart % TICKSPERSEC) / TICKSPERMSEC);
157
158 /* Compute elapsed seconds */
159 ElapsedSeconds = (ULONGLONG)Time->QuadPart / TICKSPERSEC;
160
161 /* Compute seconds within the day */
162 SecondsInDay = ElapsedSeconds % SECSPERDAY;
163
164 /* Compute elapsed minutes within the day */
165 SecondsInMinute = SecondsInDay % SECSPERHOUR;
166
167 /* Compute elapsed time of day */
168 TimeFields->Hour = (CSHORT)(SecondsInDay / SECSPERHOUR);
169 TimeFields->Minute = (CSHORT)(SecondsInMinute / SECSPERMIN);
170 TimeFields->Second = (CSHORT)(SecondsInMinute % SECSPERMIN);
171
172 /* Compute elapsed days */
173 TimeFields->Day = (CSHORT)(ElapsedSeconds / SECSPERDAY);
174
175 /* The elapsed number of months and days cannot be calculated */
176 TimeFields->Month = 0;
177 TimeFields->Year = 0;
178 }
179
180
181 /*
182 * @unimplemented
183 */
184 VOID
185 STDCALL
186 RtlTimeToTimeFields(
187 PLARGE_INTEGER Time,
188 PTIME_FIELDS TimeFields)
189 {
190 const int *Months;
191 int SecondsInDay, CurYear;
192 int LeapYear, CurMonth;
193 long int Days;
194 LONGLONG IntTime = (LONGLONG)Time->QuadPart;
195
196 /* Extract millisecond from time and convert time into seconds */
197 TimeFields->Milliseconds = (CSHORT) ((IntTime % TICKSPERSEC) / TICKSPERMSEC);
198 IntTime = IntTime / TICKSPERSEC;
199
200 /* Split the time into days and seconds within the day */
201 Days = IntTime / SECSPERDAY;
202 SecondsInDay = IntTime % SECSPERDAY;
203
204 /* Adjust the values for days and seconds in day */
205 while (SecondsInDay < 0)
206 {
207 SecondsInDay += SECSPERDAY;
208 Days--;
209 }
210 while (SecondsInDay >= SECSPERDAY)
211 {
212 SecondsInDay -= SECSPERDAY;
213 Days++;
214 }
215
216 /* compute time of day */
217 TimeFields->Hour = (CSHORT) (SecondsInDay / SECSPERHOUR);
218 SecondsInDay = SecondsInDay % SECSPERHOUR;
219 TimeFields->Minute = (CSHORT) (SecondsInDay / SECSPERMIN);
220 TimeFields->Second = (CSHORT) (SecondsInDay % SECSPERMIN);
221
222 /* compute day of week */
223 TimeFields->Weekday = (CSHORT) ((EPOCHWEEKDAY + Days) % DAYSPERWEEK);
224
225 /* compute year */
226 CurYear = EPOCHYEAR;
227 CurYear += Days / DAYSPERLEAPYEAR;
228 Days -= (CurYear - EPOCHYEAR) * DAYSPERLEAPYEAR;
229 CurYear--; /* The next calculation needs CurYear - 1 */
230 Days += CurYear - CurYear / 4 + CurYear / 100 - CurYear / 400;
231 CurYear++;
232 Days -= EPOCHYEAR - 1 - (EPOCHYEAR -1) / 4 + (EPOCHYEAR -1) / 100 - (EPOCHYEAR - 1) / 400;
233 /* FIXME: handle calendar modifications */
234 while (1)
235 {
236 LeapYear = IsLeapYear(CurYear);
237 if (Days < (long) YearLengths[LeapYear])
238 {
239 break;
240 }
241 CurYear++;
242 Days = Days - (long) YearLengths[LeapYear];
243 }
244 TimeFields->Year = (CSHORT) CurYear;
245
246 /* Compute month of year */
247 LeapYear = IsLeapYear(CurYear);
248 Months = MonthLengths[LeapYear];
249 for (CurMonth = 0; Days >= (long) Months[CurMonth]; CurMonth++)
250 Days = Days - (long) Months[CurMonth];
251 TimeFields->Month = (CSHORT) (CurMonth + 1);
252 TimeFields->Day = (CSHORT) (Days + 1);
253 }
254
255
256 /*
257 * @implemented
258 */
259 BOOLEAN
260 STDCALL
261 RtlTimeToSecondsSince1970(
262 PLARGE_INTEGER Time,
263 PULONG SecondsSince1970)
264 {
265 LARGE_INTEGER IntTime;
266
267 IntTime.QuadPart = Time->QuadPart - TICKSTO1970;
268 IntTime.QuadPart = IntTime.QuadPart / TICKSPERSEC;
269
270 if (IntTime.u.HighPart != 0)
271 return FALSE;
272
273 *SecondsSince1970 = IntTime.u.LowPart;
274
275 return TRUE;
276 }
277
278
279 /*
280 * @implemented
281 */
282 BOOLEAN
283 STDCALL
284 RtlTimeToSecondsSince1980(
285 PLARGE_INTEGER Time,
286 PULONG SecondsSince1980)
287 {
288 LARGE_INTEGER IntTime;
289
290 IntTime.QuadPart = Time->QuadPart - TICKSTO1980;
291 IntTime.QuadPart = IntTime.QuadPart / TICKSPERSEC;
292
293 if (IntTime.u.HighPart != 0)
294 return FALSE;
295
296 *SecondsSince1980 = IntTime.u.LowPart;
297
298 return TRUE;
299 }
300
301
302 /*
303 * @implemented
304 */
305 NTSTATUS
306 STDCALL
307 RtlLocalTimeToSystemTime(PLARGE_INTEGER LocalTime,
308 PLARGE_INTEGER SystemTime)
309 {
310 SYSTEM_TIMEOFDAY_INFORMATION TimeInformation;
311 NTSTATUS Status;
312
313 Status = NtQuerySystemInformation(SystemTimeOfDayInformation,
314 &TimeInformation,
315 sizeof(SYSTEM_TIMEOFDAY_INFORMATION),
316 NULL);
317 if (!NT_SUCCESS(Status))
318 return(Status);
319
320 SystemTime->QuadPart = LocalTime->QuadPart +
321 TimeInformation.TimeZoneBias.QuadPart;
322
323 return(STATUS_SUCCESS);
324 }
325
326
327 /*
328 * @implemented
329 */
330 NTSTATUS
331 STDCALL
332 RtlSystemTimeToLocalTime(PLARGE_INTEGER SystemTime,
333 PLARGE_INTEGER LocalTime)
334 {
335 SYSTEM_TIMEOFDAY_INFORMATION TimeInformation;
336 NTSTATUS Status;
337
338 Status = NtQuerySystemInformation(SystemTimeOfDayInformation,
339 &TimeInformation,
340 sizeof(SYSTEM_TIMEOFDAY_INFORMATION),
341 NULL);
342 if (!NT_SUCCESS(Status))
343 return(Status);
344
345 LocalTime->QuadPart = SystemTime->QuadPart -
346 TimeInformation.TimeZoneBias.QuadPart;
347
348 return(STATUS_SUCCESS);
349 }
350
351
352 /*
353 * @implemented
354 */
355 VOID
356 STDCALL
357 RtlSecondsSince1970ToTime(
358 ULONG SecondsSince1970,
359 PLARGE_INTEGER Time)
360 {
361 Time->QuadPart = ((LONGLONG)SecondsSince1970 * TICKSPERSEC) + TICKSTO1970;
362 }
363
364
365 /*
366 * @implemented
367 */
368 VOID
369 STDCALL
370 RtlSecondsSince1980ToTime(
371 ULONG SecondsSince1980,
372 PLARGE_INTEGER Time)
373 {
374 Time->QuadPart = ((LONGLONG)SecondsSince1980 * TICKSPERSEC) + TICKSTO1980;
375 }
376
377 /* EOF */