031f0f6321f1668b7c53a0a3e2cb310adc684dd0
[reactos.git] / reactos / lib / ntdll / rtl / time.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: kernel/rtl/time.c
5 * PURPOSE: Conversion between Time and TimeFields
6 * PROGRAMMER: Rex Jolliff (rex@lvcablemodem.com)
7 * UPDATE HISTORY:
8 * Created 22/05/98
9 * 08/03/98 RJJ Implemented these functions
10 */
11
12 /* INCLUDES *****************************************************************/
13
14 #include <ddk/ntddk.h>
15
16 #include <internal/debug.h>
17
18 #define TICKSPERSEC 10000000
19 #define TICKSPERMSEC 10000
20 #define SECSPERDAY 86400
21 #define SECSPERHOUR 3600
22 #define SECSPERMIN 60
23 #define MINSPERHOUR 60
24 #define HOURSPERDAY 24
25 #define EPOCHWEEKDAY 0
26 #define DAYSPERWEEK 7
27 #define EPOCHYEAR 1601
28 #define DAYSPERNORMALYEAR 365
29 #define DAYSPERLEAPYEAR 366
30 #define MONSPERYEAR 12
31
32 #define TICKSTO1970 0x019db1ded53e8000
33 #define TICKSTO1980 0x01a8e79fe1d58000
34
35 static const int YearLengths[2] = {DAYSPERNORMALYEAR, DAYSPERLEAPYEAR};
36 static const int MonthLengths[2][MONSPERYEAR] =
37 {
38 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
39 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
40 };
41
42 static __inline int IsLeapYear(int Year)
43 {
44 return Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0) ? 1 : 0;
45 }
46
47 static __inline void NormalizeTimeFields(CSHORT *FieldToNormalize,
48 CSHORT *CarryField,
49 int Modulus)
50 {
51 *FieldToNormalize = (CSHORT) (*FieldToNormalize - Modulus);
52 *CarryField = (CSHORT) (*CarryField + 1);
53 }
54
55 /* FUNCTIONS *****************************************************************/
56
57 VOID
58 STDCALL
59 RtlTimeToTimeFields (
60 PLARGE_INTEGER liTime,
61 PTIME_FIELDS TimeFields
62 )
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 /* FIXME: handle calendar modifications */
111 while (1)
112 {
113 LeapYear = IsLeapYear(CurYear);
114 if (Days < (long) YearLengths[LeapYear])
115 {
116 break;
117 }
118 CurYear++;
119 Days = Days - (long) YearLengths[LeapYear];
120 }
121 TimeFields->Year = (CSHORT) CurYear;
122
123 /* Compute month of year */
124 Months = MonthLengths[LeapYear];
125 for (CurMonth = 0; Days >= (long) Months[CurMonth]; CurMonth++)
126 Days = Days - (long) Months[CurMonth];
127 TimeFields->Month = (CSHORT) (CurMonth + 1);
128 TimeFields->Day = (CSHORT) (Days + 1);
129 }
130
131 BOOLEAN
132 STDCALL
133 RtlTimeFieldsToTime (
134 PTIME_FIELDS tfTimeFields,
135 PLARGE_INTEGER Time
136 )
137 {
138 int CurYear, CurMonth;
139 long long int rcTime;
140 TIME_FIELDS TimeFields = *tfTimeFields;
141
142 rcTime = 0;
143
144 /* FIXME: normalize the TIME_FIELDS structure here */
145 while (TimeFields.Second >= SECSPERMIN)
146 {
147 NormalizeTimeFields(&TimeFields.Second,
148 &TimeFields.Minute,
149 SECSPERMIN);
150 }
151 while (TimeFields.Minute >= MINSPERHOUR)
152 {
153 NormalizeTimeFields(&TimeFields.Minute,
154 &TimeFields.Hour,
155 MINSPERHOUR);
156 }
157 while (TimeFields.Hour >= HOURSPERDAY)
158 {
159 NormalizeTimeFields(&TimeFields.Hour,
160 &TimeFields.Day,
161 HOURSPERDAY);
162 }
163 while (TimeFields.Day >
164 MonthLengths[IsLeapYear(TimeFields.Year)][TimeFields.Month - 1])
165 {
166 NormalizeTimeFields(&TimeFields.Day,
167 &TimeFields.Month,
168 SECSPERMIN);
169 }
170 while (TimeFields.Month > MONSPERYEAR)
171 {
172 NormalizeTimeFields(&TimeFields.Month,
173 &TimeFields.Year,
174 MONSPERYEAR);
175 }
176
177 /* FIXME: handle calendar corrections here */
178 for (CurYear = EPOCHYEAR; CurYear < TimeFields.Year; CurYear++)
179 {
180 rcTime += YearLengths[IsLeapYear(CurYear)];
181 }
182 for (CurMonth = 1; CurMonth < TimeFields.Month; CurMonth++)
183 {
184 rcTime += MonthLengths[IsLeapYear(CurYear)][CurMonth - 1];
185 }
186 rcTime += TimeFields.Day - 1;
187 rcTime *= SECSPERDAY;
188 rcTime += TimeFields.Hour * SECSPERHOUR + TimeFields.Minute * SECSPERMIN +
189 TimeFields.Second;
190 rcTime *= TICKSPERSEC;
191 rcTime += TimeFields.Milliseconds * TICKSPERMSEC;
192 *Time = *(LARGE_INTEGER *)&rcTime;
193
194 return TRUE;
195 }
196
197
198 VOID
199 STDCALL
200 RtlSecondsSince1970ToTime (
201 ULONG SecondsSince1970,
202 PLARGE_INTEGER Time
203 )
204 {
205 LONGLONG llTime;
206
207 llTime = (SecondsSince1970 * TICKSPERSEC) + TICKSTO1970;
208
209 *Time = *(LARGE_INTEGER *)&llTime;
210 }
211
212
213 VOID
214 STDCALL
215 RtlSecondsSince1980ToTime (
216 ULONG SecondsSince1980,
217 PLARGE_INTEGER Time
218 )
219 {
220 LONGLONG llTime;
221
222 llTime = (SecondsSince1980 * TICKSPERSEC) + TICKSTO1980;
223
224 *Time = *(LARGE_INTEGER *)&llTime;
225 }
226
227
228 BOOLEAN
229 STDCALL
230 RtlTimeToSecondsSince1970 (
231 PLARGE_INTEGER Time,
232 PULONG SecondsSince1970
233 )
234 {
235 LARGE_INTEGER liTime;
236
237 liTime.QuadPart = Time->QuadPart - TICKSTO1970;
238 liTime.QuadPart = liTime.QuadPart / TICKSPERSEC;
239
240 if (liTime.u.HighPart != 0)
241 return FALSE;
242
243 *SecondsSince1970 = liTime.u.LowPart;
244
245 return TRUE;
246 }
247
248
249 BOOLEAN
250 STDCALL
251 RtlTimeToSecondsSince1980 (
252 PLARGE_INTEGER Time,
253 PULONG SecondsSince1980
254 )
255 {
256 LARGE_INTEGER liTime;
257
258 liTime.QuadPart = Time->QuadPart - TICKSTO1980;
259 liTime.QuadPart = liTime.QuadPart / TICKSPERSEC;
260
261 if (liTime.u.HighPart != 0)
262 return FALSE;
263
264 *SecondsSince1980 = liTime.u.LowPart;
265
266 return TRUE;
267 }
268
269 /* EOF */