1 /* $Id: time.c,v 1.16 2002/12/08 16:23:32 robd Exp $
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: kernel/rtl/time.c
6 * PURPOSE: Conversion between Time and TimeFields
7 * PROGRAMMER: Rex Jolliff (rex@lvcablemodem.com)
10 * 08/03/98 RJJ Implemented these functions
13 /* INCLUDES *****************************************************************/
15 #include <ddk/ntddk.h>
18 #include <internal/debug.h>
20 #define TICKSPERMIN 600000000
21 #define TICKSPERSEC 10000000
22 #define TICKSPERMSEC 10000
23 #define SECSPERDAY 86400
24 #define SECSPERHOUR 3600
26 #define MINSPERHOUR 60
27 #define HOURSPERDAY 24
28 #define EPOCHWEEKDAY 1
30 #define EPOCHYEAR 1601
31 #define DAYSPERNORMALYEAR 365
32 #define DAYSPERLEAPYEAR 366
33 #define MONSPERYEAR 12
35 #define TICKSTO1970 0x019db1ded53e8000LL
36 #define TICKSTO1980 0x01a8e79fe1d58000LL
39 static const int YearLengths
[2] = {DAYSPERNORMALYEAR
, DAYSPERLEAPYEAR
};
40 static const int MonthLengths
[2][MONSPERYEAR
] =
42 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
43 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
46 static __inline
int IsLeapYear(int Year
)
48 return Year
% 4 == 0 && (Year
% 100 != 0 || Year
% 400 == 0) ? 1 : 0;
51 static __inline
void NormalizeTimeFields(CSHORT
*FieldToNormalize
,
55 *FieldToNormalize
= (CSHORT
) (*FieldToNormalize
- Modulus
);
56 *CarryField
= (CSHORT
) (*CarryField
+ 1);
59 /* FUNCTIONS *****************************************************************/
64 PLARGE_INTEGER liTime
,
65 PTIME_FIELDS TimeFields
)
68 int LeapSecondCorrections
, SecondsInDay
, CurYear
;
69 int LeapYear
, CurMonth
, GMTOffset
;
71 long long int Time
= (long long int)liTime
->QuadPart
;
73 /* Extract millisecond from time and convert time into seconds */
74 TimeFields
->Milliseconds
= (CSHORT
) ((Time
% TICKSPERSEC
) / TICKSPERMSEC
);
75 Time
= Time
/ TICKSPERSEC
;
77 /* FIXME: Compute the number of leap second corrections here */
78 LeapSecondCorrections
= 0;
80 /* FIXME: get the GMT offset here */
83 /* Split the time into days and seconds within the day */
84 Days
= Time
/ SECSPERDAY
;
85 SecondsInDay
= Time
% SECSPERDAY
;
87 /* Adjust the values for GMT and leap seconds */
88 SecondsInDay
+= (GMTOffset
- LeapSecondCorrections
);
89 while (SecondsInDay
< 0)
91 SecondsInDay
+= SECSPERDAY
;
94 while (SecondsInDay
>= SECSPERDAY
)
96 SecondsInDay
-= SECSPERDAY
;
100 /* compute time of day */
101 TimeFields
->Hour
= (CSHORT
) (SecondsInDay
/ SECSPERHOUR
);
102 SecondsInDay
= SecondsInDay
% SECSPERHOUR
;
103 TimeFields
->Minute
= (CSHORT
) (SecondsInDay
/ SECSPERMIN
);
104 TimeFields
->Second
= (CSHORT
) (SecondsInDay
% SECSPERMIN
);
106 /* FIXME: handle the possibility that we are on a leap second (i.e. Second = 60) */
108 /* compute day of week */
109 TimeFields
->Weekday
= (CSHORT
) ((EPOCHWEEKDAY
+ Days
) % DAYSPERWEEK
);
113 CurYear
+= Days
/ DAYSPERLEAPYEAR
;
114 Days
-= (CurYear
- EPOCHYEAR
) * DAYSPERLEAPYEAR
;
115 CurYear
--; /* The next calculation needs CurYear - 1 */
116 Days
+= CurYear
- CurYear
/ 4 + CurYear
/ 100 - CurYear
/ 400;
118 Days
-= EPOCHYEAR
- 1 - (EPOCHYEAR
-1) / 4 + (EPOCHYEAR
-1) / 100 - (EPOCHYEAR
- 1) / 400;
119 /* FIXME: handle calendar modifications */
122 LeapYear
= IsLeapYear(CurYear
);
123 if (Days
< (long) YearLengths
[LeapYear
])
128 Days
= Days
- (long) YearLengths
[LeapYear
];
130 TimeFields
->Year
= (CSHORT
) CurYear
;
132 /* Compute month of year */
133 LeapYear
= IsLeapYear(CurYear
);
134 Months
= MonthLengths
[LeapYear
];
135 for (CurMonth
= 0; Days
>= (long) Months
[CurMonth
]; CurMonth
++)
136 Days
= Days
- (long) Months
[CurMonth
];
137 TimeFields
->Month
= (CSHORT
) (CurMonth
+ 1);
138 TimeFields
->Day
= (CSHORT
) (Days
+ 1);
144 PTIME_FIELDS tfTimeFields
,
148 long long int rcTime
;
149 TIME_FIELDS TimeFields
= *tfTimeFields
;
154 /* Normalize the month value, because we don't know the length for month -1, 0, 13, 14, ... */
155 if (TimeFields
.Month
< 1 || TimeFields
.Month
> 12)
157 TimeFields
.Year
+= (TimeFields
.Month
- 1) / MONSPERYEAR
;
158 TimeFields
.Month
= ((TimeFields
.Month
- 1) % MONSPERYEAR
) + 1;
159 if (TimeFields
.Month
< 1)
162 TimeFields
.Month
+= MONSPERYEAR
;
165 /* FIXME: handle calendar corrections here */
167 rcTime
+= (TimeFields
.Year
- EPOCHYEAR
) * DAYSPERNORMALYEAR
;
168 /* Adjust leap years */
169 rcTime
+= (TimeFields
.Year
- 1)/ 4 - (TimeFields
.Year
- 1) / 100 + (TimeFields
.Year
- 1) / 400;
170 rcTime
-= EPOCHYEAR
/ 4 - EPOCHYEAR
/ 100 + EPOCHYEAR
/ 400;
172 /* FIXME: handle calendar corrections here */
173 Months
= MonthLengths
[IsLeapYear(TimeFields
.Year
)];
174 for (CurMonth
= 1; CurMonth
< TimeFields
.Month
; CurMonth
++)
176 rcTime
+= Months
[CurMonth
- 1];
178 rcTime
+= TimeFields
.Day
- 1;
179 rcTime
*= SECSPERDAY
;
180 rcTime
+= TimeFields
.Hour
* SECSPERHOUR
+ TimeFields
.Minute
* SECSPERMIN
+
182 rcTime
*= TICKSPERSEC
;
183 rcTime
+= TimeFields
.Milliseconds
* TICKSPERMSEC
;
185 /* FIXME: handle UTC bias here */
186 // rcTime += UTCBias * TICKSPERMIN;
188 *Time
= *(LARGE_INTEGER
*)&rcTime
;
196 RtlSecondsSince1970ToTime(
197 ULONG SecondsSince1970
,
202 llTime
= (SecondsSince1970
* TICKSPERSEC
) + TICKSTO1970
;
204 *Time
= *(LARGE_INTEGER
*)&llTime
;
210 RtlSecondsSince1980ToTime(
211 ULONG SecondsSince1980
,
216 llTime
= (SecondsSince1980
* TICKSPERSEC
) + TICKSTO1980
;
218 *Time
= *(LARGE_INTEGER
*)&llTime
;
224 RtlTimeToSecondsSince1970(
226 PULONG SecondsSince1970
)
228 LARGE_INTEGER liTime
;
230 liTime
.QuadPart
= Time
->QuadPart
- TICKSTO1970
;
231 liTime
.QuadPart
= liTime
.QuadPart
/ TICKSPERSEC
;
233 if (liTime
.u
.HighPart
!= 0)
236 *SecondsSince1970
= liTime
.u
.LowPart
;
244 RtlTimeToSecondsSince1980(
246 PULONG SecondsSince1980
)
248 LARGE_INTEGER liTime
;
250 liTime
.QuadPart
= Time
->QuadPart
- TICKSTO1980
;
251 liTime
.QuadPart
= liTime
.QuadPart
/ TICKSPERSEC
;
253 if (liTime
.u
.HighPart
!= 0)
256 *SecondsSince1980
= liTime
.u
.LowPart
;