4 * RtlTimeToTimeFields, RtlTimeFieldsToTime and defines are taken from ReactOS and
5 * adapted to wine with special permissions of the author. This code is
6 * Copyright 2002 Rex Jolliff (rex@lvcablemodem.com)
8 * Copyright 1999 Juergen Schmied
9 * Copyright 2007 Dmitry Timoshkov
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
34 #define WIN32_NO_STATUS
35 #define NONAMELESSUNION
39 #include "wine/exception.h"
40 #include "wine/debug.h"
41 #include "ntdll_misc.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(ntdll
);
45 #define TICKSPERSEC 10000000
46 #define TICKSPERMSEC 10000
47 #define SECSPERDAY 86400
48 #define SECSPERHOUR 3600
50 #define MINSPERHOUR 60
51 #define HOURSPERDAY 24
52 #define EPOCHWEEKDAY 1 /* Jan 1, 1601 was Monday */
54 #define MONSPERYEAR 12
55 #define DAYSPERQUADRICENTENNIUM (365 * 400 + 97)
56 #define DAYSPERNORMALQUADRENNIUM (365 * 4 + 1)
58 /* 1601 to 1970 is 369 years plus 89 leap days */
59 #define SECS_1601_TO_1970 ((369 * 365 + 89) * (ULONGLONG)SECSPERDAY)
60 #define TICKS_1601_TO_1970 (SECS_1601_TO_1970 * TICKSPERSEC)
61 /* 1601 to 1980 is 379 years plus 91 leap days */
62 #define SECS_1601_TO_1980 ((379 * 365 + 91) * (ULONGLONG)SECSPERDAY)
63 #define TICKS_1601_TO_1980 (SECS_1601_TO_1980 * TICKSPERSEC)
66 static const int MonthLengths
[2][MONSPERYEAR
] =
68 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
69 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
72 static inline BOOL
IsLeapYear(int Year
)
74 return Year
% 4 == 0 && (Year
% 100 != 0 || Year
% 400 == 0);
78 /******************************************************************************
79 * RtlTimeToTimeFields [NTDLL.@]
81 * Convert a time into a TIME_FIELDS structure.
84 * liTime [I] Time to convert.
85 * TimeFields [O] Destination for the converted time.
90 VOID WINAPI
RtlTimeToTimeFields(
91 const LARGE_INTEGER
*liTime
,
92 PTIME_FIELDS TimeFields
)
95 long int cleaps
, years
, yearday
, months
;
99 /* Extract millisecond from time and convert time into seconds */
100 TimeFields
->Milliseconds
=
101 (CSHORT
) (( liTime
->QuadPart
% TICKSPERSEC
) / TICKSPERMSEC
);
102 Time
= liTime
->QuadPart
/ TICKSPERSEC
;
104 /* The native version of RtlTimeToTimeFields does not take leap seconds
107 /* Split the time into days and seconds within the day */
108 Days
= Time
/ SECSPERDAY
;
109 SecondsInDay
= Time
% SECSPERDAY
;
111 /* compute time of day */
112 TimeFields
->Hour
= (CSHORT
) (SecondsInDay
/ SECSPERHOUR
);
113 SecondsInDay
= SecondsInDay
% SECSPERHOUR
;
114 TimeFields
->Minute
= (CSHORT
) (SecondsInDay
/ SECSPERMIN
);
115 TimeFields
->Second
= (CSHORT
) (SecondsInDay
% SECSPERMIN
);
117 /* compute day of week */
118 TimeFields
->Weekday
= (CSHORT
) ((EPOCHWEEKDAY
+ Days
) % DAYSPERWEEK
);
120 /* compute year, month and day of month. */
121 cleaps
=( 3 * ((4 * Days
+ 1227) / DAYSPERQUADRICENTENNIUM
) + 3 ) / 4;
122 Days
+= 28188 + cleaps
;
123 years
= (20 * Days
- 2442) / (5 * DAYSPERNORMALQUADRENNIUM
);
124 yearday
= Days
- (years
* DAYSPERNORMALQUADRENNIUM
)/4;
125 months
= (64 * yearday
) / 1959;
126 /* the result is based on a year starting on March.
127 * To convert take 12 from Januari and Februari and
128 * increase the year by one. */
130 TimeFields
->Month
= months
- 1;
131 TimeFields
->Year
= years
+ 1524;
133 TimeFields
->Month
= months
- 13;
134 TimeFields
->Year
= years
+ 1525;
136 /* calculation of day of month is based on the wonderful
137 * sequence of INT( n * 30.6): it reproduces the
138 * 31-30-31-30-31-31 month lengths exactly for small n's */
139 TimeFields
->Day
= yearday
- (1959 * months
) / 64 ;
143 /******************************************************************************
144 * RtlTimeFieldsToTime [NTDLL.@]
146 * Convert a TIME_FIELDS structure into a time.
149 * ftTimeFields [I] TIME_FIELDS structure to convert.
150 * Time [O] Destination for the converted time.
156 BOOLEAN WINAPI
RtlTimeFieldsToTime(
157 PTIME_FIELDS tfTimeFields
,
160 int month
, year
, cleaps
, day
;
162 /* FIXME: normalize the TIME_FIELDS structure here */
163 /* No, native just returns 0 (error) if the fields are not */
164 if( tfTimeFields
->Milliseconds
< 0 || tfTimeFields
->Milliseconds
> 999 ||
165 tfTimeFields
->Second
< 0 || tfTimeFields
->Second
> 59 ||
166 tfTimeFields
->Minute
< 0 || tfTimeFields
->Minute
> 59 ||
167 tfTimeFields
->Hour
< 0 || tfTimeFields
->Hour
> 23 ||
168 tfTimeFields
->Month
< 1 || tfTimeFields
->Month
> 12 ||
169 tfTimeFields
->Day
< 1 ||
170 tfTimeFields
->Day
> MonthLengths
171 [ tfTimeFields
->Month
==2 || IsLeapYear(tfTimeFields
->Year
)]
172 [ tfTimeFields
->Month
- 1] ||
173 tfTimeFields
->Year
< 1601 )
176 /* now calculate a day count from the date
177 * First start counting years from March. This way the leap days
178 * are added at the end of the year, not somewhere in the middle.
179 * Formula's become so much less complicate that way.
180 * To convert: add 12 to the month numbers of Jan and Feb, and
181 * take 1 from the year */
182 if(tfTimeFields
->Month
< 3) {
183 month
= tfTimeFields
->Month
+ 13;
184 year
= tfTimeFields
->Year
- 1;
186 month
= tfTimeFields
->Month
+ 1;
187 year
= tfTimeFields
->Year
;
189 cleaps
= (3 * (year
/ 100) + 3) / 4; /* nr of "century leap years"*/
190 day
= (36525 * year
) / 100 - cleaps
+ /* year * dayperyr, corrected */
191 (1959 * month
) / 64 + /* months * daypermonth */
192 tfTimeFields
->Day
- /* day of the month */
193 584817 ; /* zero that on 1601-01-01 */
196 Time
->QuadPart
= (((((LONGLONG
) day
* HOURSPERDAY
+
197 tfTimeFields
->Hour
) * MINSPERHOUR
+
198 tfTimeFields
->Minute
) * SECSPERMIN
+
199 tfTimeFields
->Second
) * 1000 +
200 tfTimeFields
->Milliseconds
) * TICKSPERMSEC
;
206 /******************************************************************************
207 * RtlLocalTimeToSystemTime [NTDLL.@]
209 * Convert a local time into system time.
212 * LocalTime [I] Local time to convert.
213 * SystemTime [O] Destination for the converted time.
216 * Success: STATUS_SUCCESS.
217 * Failure: An NTSTATUS error code indicating the problem.
219 NTSTATUS WINAPI
RtlLocalTimeToSystemTime( const LARGE_INTEGER
*LocalTime
,
220 PLARGE_INTEGER SystemTime
)
222 SYSTEM_TIMEOFDAY_INFORMATION info
;
224 TRACE("(%p, %p)\n", LocalTime
, SystemTime
);
226 NtQuerySystemInformation( SystemTimeOfDayInformation
, &info
, sizeof(info
), NULL
);
227 SystemTime
->QuadPart
= LocalTime
->QuadPart
+ info
.TimeZoneBias
.QuadPart
;
228 return STATUS_SUCCESS
;
231 /******************************************************************************
232 * RtlSystemTimeToLocalTime [NTDLL.@]
234 * Convert a system time into a local time.
237 * SystemTime [I] System time to convert.
238 * LocalTime [O] Destination for the converted time.
241 * Success: STATUS_SUCCESS.
242 * Failure: An NTSTATUS error code indicating the problem.
244 NTSTATUS WINAPI
RtlSystemTimeToLocalTime( const LARGE_INTEGER
*SystemTime
,
245 PLARGE_INTEGER LocalTime
)
247 SYSTEM_TIMEOFDAY_INFORMATION info
;
249 TRACE("(%p, %p)\n", SystemTime
, LocalTime
);
251 NtQuerySystemInformation( SystemTimeOfDayInformation
, &info
, sizeof(info
), NULL
);
252 LocalTime
->QuadPart
= SystemTime
->QuadPart
- info
.TimeZoneBias
.QuadPart
;
253 return STATUS_SUCCESS
;
256 /******************************************************************************
257 * RtlTimeToSecondsSince1970 [NTDLL.@]
259 * Convert a time into a count of seconds since 1970.
262 * Time [I] Time to convert.
263 * Seconds [O] Destination for the converted time.
267 * Failure: FALSE, if the resulting value will not fit in a DWORD.
269 BOOLEAN WINAPI
RtlTimeToSecondsSince1970( const LARGE_INTEGER
*Time
, LPDWORD Seconds
)
271 ULONGLONG tmp
= Time
->QuadPart
/ TICKSPERSEC
- SECS_1601_TO_1970
;
272 if (tmp
> 0xffffffff) return FALSE
;
277 /******************************************************************************
278 * RtlTimeToSecondsSince1980 [NTDLL.@]
280 * Convert a time into a count of seconds since 1980.
283 * Time [I] Time to convert.
284 * Seconds [O] Destination for the converted time.
288 * Failure: FALSE, if the resulting value will not fit in a DWORD.
290 BOOLEAN WINAPI
RtlTimeToSecondsSince1980( const LARGE_INTEGER
*Time
, LPDWORD Seconds
)
292 ULONGLONG tmp
= Time
->QuadPart
/ TICKSPERSEC
- SECS_1601_TO_1980
;
293 if (tmp
> 0xffffffff) return FALSE
;
298 /******************************************************************************
299 * RtlSecondsSince1970ToTime [NTDLL.@]
301 * Convert a count of seconds since 1970 to a time.
304 * Seconds [I] Time to convert.
305 * Time [O] Destination for the converted time.
310 void WINAPI
RtlSecondsSince1970ToTime( DWORD Seconds
, LARGE_INTEGER
*Time
)
312 Time
->QuadPart
= Seconds
* (ULONGLONG
)TICKSPERSEC
+ TICKS_1601_TO_1970
;
315 /******************************************************************************
316 * RtlSecondsSince1980ToTime [NTDLL.@]
318 * Convert a count of seconds since 1980 to a time.
321 * Seconds [I] Time to convert.
322 * Time [O] Destination for the converted time.
327 void WINAPI
RtlSecondsSince1980ToTime( DWORD Seconds
, LARGE_INTEGER
*Time
)
329 Time
->QuadPart
= Seconds
* (ULONGLONG
)TICKSPERSEC
+ TICKS_1601_TO_1980
;
332 /******************************************************************************
333 * RtlTimeToElapsedTimeFields [NTDLL.@]
335 * Convert a time to a count of elapsed seconds.
338 * Time [I] Time to convert.
339 * TimeFields [O] Destination for the converted time.
344 void WINAPI
RtlTimeToElapsedTimeFields( const LARGE_INTEGER
*Time
, PTIME_FIELDS TimeFields
)
349 time
= Time
->QuadPart
/ TICKSPERSEC
;
350 TimeFields
->Milliseconds
= (Time
->QuadPart
% TICKSPERSEC
) / TICKSPERMSEC
;
352 /* time is now in seconds */
353 TimeFields
->Year
= 0;
354 TimeFields
->Month
= 0;
355 TimeFields
->Day
= time
/ SECSPERDAY
;
357 /* rem is now the remaining seconds in the last day */
358 rem
= time
% SECSPERDAY
;
359 TimeFields
->Second
= rem
% 60;
361 TimeFields
->Minute
= rem
% 60;
362 TimeFields
->Hour
= rem
/ 60;
365 /***********************************************************************
366 * RtlGetSystemTimePrecise [NTDLL.@]
368 * Get a more accurate current system time.
371 * The current system time.
373 LONGLONG WINAPI
RtlGetSystemTimePrecise( void )
375 return unix_funcs
->RtlGetSystemTimePrecise();
378 /******************************************************************************
379 * RtlQueryPerformanceCounter [NTDLL.@]
381 BOOL WINAPI DECLSPEC_HOTPATCH
RtlQueryPerformanceCounter( LARGE_INTEGER
*counter
)
383 NtQueryPerformanceCounter( counter
, NULL
);
387 /******************************************************************************
388 * RtlQueryPerformanceFrequency [NTDLL.@]
390 BOOL WINAPI DECLSPEC_HOTPATCH
RtlQueryPerformanceFrequency( LARGE_INTEGER
*frequency
)
392 frequency
->QuadPart
= TICKSPERSEC
;
396 /******************************************************************************
397 * NtGetTickCount (NTDLL.@)
398 * ZwGetTickCount (NTDLL.@)
400 ULONG WINAPI DECLSPEC_HOTPATCH
NtGetTickCount(void)
402 /* note: we ignore TickCountMultiplier */
403 return user_shared_data
->u
.TickCount
.LowPart
;
406 /***********************************************************************
407 * RtlQueryTimeZoneInformation [NTDLL.@]
409 * Get information about the current timezone.
412 * tzinfo [O] Destination for the retrieved timezone info.
415 * Success: STATUS_SUCCESS.
416 * Failure: An NTSTATUS error code indicating the problem.
418 NTSTATUS WINAPI
RtlQueryTimeZoneInformation(RTL_TIME_ZONE_INFORMATION
*ret
)
420 return NtQuerySystemInformation( SystemCurrentTimeZoneInformation
, ret
, sizeof(*ret
), NULL
);
423 /***********************************************************************
424 * RtlQueryDynamicTimeZoneInformation [NTDLL.@]
426 * Get information about the current timezone.
429 * tzinfo [O] Destination for the retrieved timezone info.
432 * Success: STATUS_SUCCESS.
433 * Failure: An NTSTATUS error code indicating the problem.
435 NTSTATUS WINAPI
RtlQueryDynamicTimeZoneInformation(RTL_DYNAMIC_TIME_ZONE_INFORMATION
*ret
)
437 return NtQuerySystemInformation( SystemDynamicTimeZoneInformation
, ret
, sizeof(*ret
), NULL
);
440 /***********************************************************************
441 * RtlSetTimeZoneInformation [NTDLL.@]
443 * Set the current time zone information.
446 * tzinfo [I] Timezone information to set.
449 * Success: STATUS_SUCCESS.
450 * Failure: An NTSTATUS error code indicating the problem.
453 NTSTATUS WINAPI
RtlSetTimeZoneInformation( const RTL_TIME_ZONE_INFORMATION
*tzinfo
)
455 return STATUS_PRIVILEGE_NOT_HELD
;
458 /***********************************************************************
459 * RtlQueryUnbiasedInterruptTime [NTDLL.@]
461 BOOL WINAPI
RtlQueryUnbiasedInterruptTime(ULONGLONG
*time
)
467 RtlSetLastWin32ErrorAndNtStatusFromNtStatus( STATUS_INVALID_PARAMETER
);
473 high
= user_shared_data
->InterruptTime
.High1Time
;
474 low
= user_shared_data
->InterruptTime
.LowPart
;
476 while (high
!= user_shared_data
->InterruptTime
.High2Time
);
477 /* FIXME: should probably subtract InterruptTimeBias */
478 *time
= (ULONGLONG
)high
<< 32 | low
;