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