fd263351597dd450c934bd8f3f61eec659a3e7c1
[reactos.git] / reactos / lib / ntdll / rtl / time.c
1 /* $Id: time.c,v 1.13 2002/09/30 20:57:54 hbirr 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 STDCALL
59 RtlTimeToElapsedTimeFields(IN PLARGE_INTEGER Time,
60 OUT PTIME_FIELDS TimeFields)
61 {
62 ULONGLONG ElapsedSeconds;
63 ULONG SecondsInDay;
64 ULONG SecondsInMinute;
65
66 /* Extract millisecond from time */
67 TimeFields->Milliseconds = (CSHORT)((Time->QuadPart % TICKSPERSEC) / TICKSPERMSEC);
68
69 /* Compute elapsed seconds */
70 ElapsedSeconds = (ULONGLONG)Time->QuadPart / TICKSPERSEC;
71
72 /* Compute seconds within the day */
73 SecondsInDay = ElapsedSeconds % SECSPERDAY;
74
75 /* Compute elapsed minutes within the day */
76 SecondsInMinute = SecondsInDay % SECSPERHOUR;
77
78 /* Compute elapsed time of day */
79 TimeFields->Hour = (CSHORT)(SecondsInDay / SECSPERHOUR);
80 TimeFields->Minute = (CSHORT)(SecondsInMinute / SECSPERMIN);
81 TimeFields->Second = (CSHORT)(SecondsInMinute % SECSPERMIN);
82
83 /* Compute elapsed days */
84 TimeFields->Day = (CSHORT)(ElapsedSeconds / SECSPERDAY);
85
86 /* The elapsed number of months and days cannot be calculated */
87 TimeFields->Month = 0;
88 TimeFields->Year = 0;
89 }
90
91
92 VOID STDCALL
93 RtlTimeToTimeFields(PLARGE_INTEGER liTime,
94 PTIME_FIELDS TimeFields)
95 {
96 const int *Months;
97 int LeapSecondCorrections, SecondsInDay, CurYear;
98 int LeapYear, CurMonth, GMTOffset;
99 long int Days;
100 long long int Time = (long long int)liTime->QuadPart;
101
102 /* Extract millisecond from time and convert time into seconds */
103 TimeFields->Milliseconds = (CSHORT) ((Time % TICKSPERSEC) / TICKSPERMSEC);
104 Time = Time / TICKSPERSEC;
105
106 /* FIXME: Compute the number of leap second corrections here */
107 LeapSecondCorrections = 0;
108
109 /* FIXME: get the GMT offset here */
110 GMTOffset = 0;
111
112 /* Split the time into days and seconds within the day */
113 Days = Time / SECSPERDAY;
114 SecondsInDay = Time % SECSPERDAY;
115
116 /* Adjust the values for GMT and leap seconds */
117 SecondsInDay += (GMTOffset - LeapSecondCorrections);
118 while (SecondsInDay < 0)
119 {
120 SecondsInDay += SECSPERDAY;
121 Days--;
122 }
123 while (SecondsInDay >= SECSPERDAY)
124 {
125 SecondsInDay -= SECSPERDAY;
126 Days++;
127 }
128
129 /* compute time of day */
130 TimeFields->Hour = (CSHORT) (SecondsInDay / SECSPERHOUR);
131 SecondsInDay = SecondsInDay % SECSPERHOUR;
132 TimeFields->Minute = (CSHORT) (SecondsInDay / SECSPERMIN);
133 TimeFields->Second = (CSHORT) (SecondsInDay % SECSPERMIN);
134
135 /* FIXME: handle the possibility that we are on a leap second (i.e. Second = 60) */
136
137 /* compute day of week */
138 TimeFields->Weekday = (CSHORT) ((EPOCHWEEKDAY + Days) % DAYSPERWEEK);
139
140 /* compute year */
141 CurYear = EPOCHYEAR;
142 CurYear += Days / DAYSPERLEAPYEAR;
143 Days -= (CurYear - EPOCHYEAR) * DAYSPERLEAPYEAR;
144 CurYear--; /* The next calculation needs CurYear - 1 */
145 Days += CurYear - CurYear / 4 + CurYear / 100 - CurYear / 400;
146 CurYear++;
147 Days -= EPOCHYEAR - 1 - (EPOCHYEAR -1) / 4 + (EPOCHYEAR -1) / 100 - (EPOCHYEAR - 1) / 400;
148
149 /* FIXME: handle calendar modifications */
150 while (1)
151 {
152 LeapYear = IsLeapYear(CurYear);
153 if (Days < (long) YearLengths[LeapYear])
154 {
155 break;
156 }
157 CurYear++;
158 Days = Days - (long) YearLengths[LeapYear];
159 }
160 TimeFields->Year = (CSHORT) CurYear;
161
162 /* Compute month of year */
163 LeapYear = IsLeapYear(CurYear);
164 Months = MonthLengths[LeapYear];
165 for (CurMonth = 0; Days >= (long) Months[CurMonth]; CurMonth++)
166 Days = Days - (long) Months[CurMonth];
167 TimeFields->Month = (CSHORT) (CurMonth + 1);
168 TimeFields->Day = (CSHORT) (Days + 1);
169 }
170
171
172 BOOLEAN STDCALL
173 RtlTimeFieldsToTime(PTIME_FIELDS tfTimeFields,
174 PLARGE_INTEGER Time)
175 {
176 int CurYear, CurMonth;
177 long long int rcTime;
178 TIME_FIELDS TimeFields = *tfTimeFields;
179
180 rcTime = 0;
181
182 /* FIXME: normalize the TIME_FIELDS structure here */
183 while (TimeFields.Second >= SECSPERMIN)
184 {
185 NormalizeTimeFields(&TimeFields.Second,
186 &TimeFields.Minute,
187 SECSPERMIN);
188 }
189 while (TimeFields.Minute >= MINSPERHOUR)
190 {
191 NormalizeTimeFields(&TimeFields.Minute,
192 &TimeFields.Hour,
193 MINSPERHOUR);
194 }
195 while (TimeFields.Hour >= HOURSPERDAY)
196 {
197 NormalizeTimeFields(&TimeFields.Hour,
198 &TimeFields.Day,
199 HOURSPERDAY);
200 }
201 while (TimeFields.Day >
202 MonthLengths[IsLeapYear(TimeFields.Year)][TimeFields.Month - 1])
203 {
204 NormalizeTimeFields(&TimeFields.Day,
205 &TimeFields.Month,
206 SECSPERMIN);
207 }
208 while (TimeFields.Month > MONSPERYEAR)
209 {
210 NormalizeTimeFields(&TimeFields.Month,
211 &TimeFields.Year,
212 MONSPERYEAR);
213 }
214
215 /* FIXME: handle calendar corrections here */
216 for (CurYear = EPOCHYEAR; CurYear < TimeFields.Year; CurYear++)
217 {
218 rcTime += YearLengths[IsLeapYear(CurYear)];
219 }
220 for (CurMonth = 1; CurMonth < TimeFields.Month; CurMonth++)
221 {
222 rcTime += MonthLengths[IsLeapYear(CurYear)][CurMonth - 1];
223 }
224 rcTime += TimeFields.Day - 1;
225 rcTime *= SECSPERDAY;
226 rcTime += TimeFields.Hour * SECSPERHOUR + TimeFields.Minute * SECSPERMIN +
227 TimeFields.Second;
228 rcTime *= TICKSPERSEC;
229 rcTime += TimeFields.Milliseconds * TICKSPERMSEC;
230 *Time = *(LARGE_INTEGER *)&rcTime;
231
232 return TRUE;
233 }
234
235
236 VOID STDCALL
237 RtlSecondsSince1970ToTime(ULONG SecondsSince1970,
238 PLARGE_INTEGER Time)
239 {
240 LONGLONG llTime;
241
242 llTime = (SecondsSince1970 * TICKSPERSEC) + TICKSTO1970;
243
244 *Time = *(LARGE_INTEGER *)&llTime;
245 }
246
247
248 VOID STDCALL
249 RtlSecondsSince1980ToTime(ULONG SecondsSince1980,
250 PLARGE_INTEGER Time)
251 {
252 LONGLONG llTime;
253
254 llTime = (SecondsSince1980 * TICKSPERSEC) + TICKSTO1980;
255
256 *Time = *(LARGE_INTEGER *)&llTime;
257 }
258
259
260 BOOLEAN STDCALL
261 RtlTimeToSecondsSince1970(PLARGE_INTEGER Time,
262 PULONG SecondsSince1970)
263 {
264 LARGE_INTEGER liTime;
265
266 liTime.QuadPart = Time->QuadPart - TICKSTO1970;
267 liTime.QuadPart = liTime.QuadPart / TICKSPERSEC;
268
269 if (liTime.u.HighPart != 0)
270 return(FALSE);
271
272 *SecondsSince1970 = liTime.u.LowPart;
273
274 return(TRUE);
275 }
276
277
278 BOOLEAN STDCALL
279 RtlTimeToSecondsSince1980(PLARGE_INTEGER Time,
280 PULONG SecondsSince1980)
281 {
282 LARGE_INTEGER liTime;
283
284 liTime.QuadPart = Time->QuadPart - TICKSTO1980;
285 liTime.QuadPart = liTime.QuadPart / TICKSPERSEC;
286
287 if (liTime.u.HighPart != 0)
288 return(FALSE);
289
290 *SecondsSince1980 = liTime.u.LowPart;
291
292 return(TRUE);
293 }
294
295
296 NTSTATUS STDCALL
297 RtlLocalTimeToSystemTime(PLARGE_INTEGER LocalTime,
298 PLARGE_INTEGER SystemTime)
299 {
300 SYSTEM_TIMEOFDAY_INFORMATION TimeInformation;
301 NTSTATUS Status;
302
303 Status = NtQuerySystemInformation(SystemTimeOfDayInformation,
304 &TimeInformation,
305 sizeof(SYSTEM_TIMEOFDAY_INFORMATION),
306 NULL);
307 if (!NT_SUCCESS(Status))
308 return(Status);
309
310 SystemTime->QuadPart = LocalTime->QuadPart +
311 TimeInformation.TimeZoneBias.QuadPart;
312
313 return(STATUS_SUCCESS);
314 }
315
316
317 NTSTATUS STDCALL
318 RtlSystemTimeToLocalTime(PLARGE_INTEGER SystemTime,
319 PLARGE_INTEGER LocalTime)
320 {
321 SYSTEM_TIMEOFDAY_INFORMATION TimeInformation;
322 NTSTATUS Status;
323
324 Status = NtQuerySystemInformation(SystemTimeOfDayInformation,
325 &TimeInformation,
326 sizeof(SYSTEM_TIMEOFDAY_INFORMATION),
327 NULL);
328 if (!NT_SUCCESS(Status))
329 return(Status);
330
331 LocalTime->QuadPart = SystemTime->QuadPart -
332 TimeInformation.TimeZoneBias.QuadPart;
333
334 return(STATUS_SUCCESS);
335 }
336
337 /* EOF */