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
38 #include "wine/exception.h"
39 #include "wine/debug.h"
40 #include "ntdll_misc.h"
42 WINE_DEFAULT_DEBUG_CHANNEL(ntdll
);
44 #define TICKSPERSEC 10000000
45 #define TICKSPERMSEC 10000
46 #define SECSPERDAY 86400
47 #define SECSPERHOUR 3600
49 #define MINSPERHOUR 60
50 #define HOURSPERDAY 24
51 #define EPOCHWEEKDAY 1 /* Jan 1, 1601 was Monday */
53 #define MONSPERYEAR 12
54 #define DAYSPERQUADRICENTENNIUM (365 * 400 + 97)
55 #define DAYSPERNORMALQUADRENNIUM (365 * 4 + 1)
57 /* 1601 to 1970 is 369 years plus 89 leap days */
58 #define SECS_1601_TO_1970 ((369 * 365 + 89) * (ULONGLONG)SECSPERDAY)
59 #define TICKS_1601_TO_1970 (SECS_1601_TO_1970 * TICKSPERSEC)
60 /* 1601 to 1980 is 379 years plus 91 leap days */
61 #define SECS_1601_TO_1980 ((379 * 365 + 91) * (ULONGLONG)SECSPERDAY)
62 #define TICKS_1601_TO_1980 (SECS_1601_TO_1980 * TICKSPERSEC)
65 static const int MonthLengths
[2][MONSPERYEAR
] =
67 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
68 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
71 static inline BOOL
IsLeapYear(int Year
)
73 return Year
% 4 == 0 && (Year
% 100 != 0 || Year
% 400 == 0);
77 /******************************************************************************
78 * RtlTimeToTimeFields [NTDLL.@]
80 * Convert a time into a TIME_FIELDS structure.
83 * liTime [I] Time to convert.
84 * TimeFields [O] Destination for the converted time.
89 VOID WINAPI
RtlTimeToTimeFields(
90 const LARGE_INTEGER
*liTime
,
91 PTIME_FIELDS TimeFields
)
94 long int cleaps
, years
, yearday
, months
;
98 /* Extract millisecond from time and convert time into seconds */
99 TimeFields
->Milliseconds
=
100 (CSHORT
) (( liTime
->QuadPart
% TICKSPERSEC
) / TICKSPERMSEC
);
101 Time
= liTime
->QuadPart
/ TICKSPERSEC
;
103 /* The native version of RtlTimeToTimeFields does not take leap seconds
106 /* Split the time into days and seconds within the day */
107 Days
= Time
/ SECSPERDAY
;
108 SecondsInDay
= Time
% SECSPERDAY
;
110 /* compute time of day */
111 TimeFields
->Hour
= (CSHORT
) (SecondsInDay
/ SECSPERHOUR
);
112 SecondsInDay
= SecondsInDay
% SECSPERHOUR
;
113 TimeFields
->Minute
= (CSHORT
) (SecondsInDay
/ SECSPERMIN
);
114 TimeFields
->Second
= (CSHORT
) (SecondsInDay
% SECSPERMIN
);
116 /* compute day of week */
117 TimeFields
->Weekday
= (CSHORT
) ((EPOCHWEEKDAY
+ Days
) % DAYSPERWEEK
);
119 /* compute year, month and day of month. */
120 cleaps
=( 3 * ((4 * Days
+ 1227) / DAYSPERQUADRICENTENNIUM
) + 3 ) / 4;
121 Days
+= 28188 + cleaps
;
122 years
= (20 * Days
- 2442) / (5 * DAYSPERNORMALQUADRENNIUM
);
123 yearday
= Days
- (years
* DAYSPERNORMALQUADRENNIUM
)/4;
124 months
= (64 * yearday
) / 1959;
125 /* the result is based on a year starting on March.
126 * To convert take 12 from Januari and Februari and
127 * increase the year by one. */
129 TimeFields
->Month
= months
- 1;
130 TimeFields
->Year
= years
+ 1524;
132 TimeFields
->Month
= months
- 13;
133 TimeFields
->Year
= years
+ 1525;
135 /* calculation of day of month is based on the wonderful
136 * sequence of INT( n * 30.6): it reproduces the
137 * 31-30-31-30-31-31 month lengths exactly for small n's */
138 TimeFields
->Day
= yearday
- (1959 * months
) / 64 ;
142 /******************************************************************************
143 * RtlTimeFieldsToTime [NTDLL.@]
145 * Convert a TIME_FIELDS structure into a time.
148 * ftTimeFields [I] TIME_FIELDS structure to convert.
149 * Time [O] Destination for the converted time.
155 BOOLEAN WINAPI
RtlTimeFieldsToTime(
156 PTIME_FIELDS tfTimeFields
,
159 int month
, year
, cleaps
, day
;
161 /* FIXME: normalize the TIME_FIELDS structure here */
162 /* No, native just returns 0 (error) if the fields are not */
163 if( tfTimeFields
->Milliseconds
< 0 || tfTimeFields
->Milliseconds
> 999 ||
164 tfTimeFields
->Second
< 0 || tfTimeFields
->Second
> 59 ||
165 tfTimeFields
->Minute
< 0 || tfTimeFields
->Minute
> 59 ||
166 tfTimeFields
->Hour
< 0 || tfTimeFields
->Hour
> 23 ||
167 tfTimeFields
->Month
< 1 || tfTimeFields
->Month
> 12 ||
168 tfTimeFields
->Day
< 1 ||
169 tfTimeFields
->Day
> MonthLengths
170 [ tfTimeFields
->Month
==2 || IsLeapYear(tfTimeFields
->Year
)]
171 [ tfTimeFields
->Month
- 1] ||
172 tfTimeFields
->Year
< 1601 )
175 /* now calculate a day count from the date
176 * First start counting years from March. This way the leap days
177 * are added at the end of the year, not somewhere in the middle.
178 * Formula's become so much less complicate that way.
179 * To convert: add 12 to the month numbers of Jan and Feb, and
180 * take 1 from the year */
181 if(tfTimeFields
->Month
< 3) {
182 month
= tfTimeFields
->Month
+ 13;
183 year
= tfTimeFields
->Year
- 1;
185 month
= tfTimeFields
->Month
+ 1;
186 year
= tfTimeFields
->Year
;
188 cleaps
= (3 * (year
/ 100) + 3) / 4; /* nr of "century leap years"*/
189 day
= (36525 * year
) / 100 - cleaps
+ /* year * dayperyr, corrected */
190 (1959 * month
) / 64 + /* months * daypermonth */
191 tfTimeFields
->Day
- /* day of the month */
192 584817 ; /* zero that on 1601-01-01 */
195 Time
->QuadPart
= (((((LONGLONG
) day
* HOURSPERDAY
+
196 tfTimeFields
->Hour
) * MINSPERHOUR
+
197 tfTimeFields
->Minute
) * SECSPERMIN
+
198 tfTimeFields
->Second
) * 1000 +
199 tfTimeFields
->Milliseconds
) * TICKSPERMSEC
;
205 /******************************************************************************
206 * RtlLocalTimeToSystemTime [NTDLL.@]
208 * Convert a local time into system time.
211 * LocalTime [I] Local time to convert.
212 * SystemTime [O] Destination for the converted time.
215 * Success: STATUS_SUCCESS.
216 * Failure: An NTSTATUS error code indicating the problem.
218 NTSTATUS WINAPI
RtlLocalTimeToSystemTime( const LARGE_INTEGER
*LocalTime
,
219 PLARGE_INTEGER SystemTime
)
221 SYSTEM_TIMEOFDAY_INFORMATION info
;
223 TRACE("(%p, %p)\n", LocalTime
, SystemTime
);
225 NtQuerySystemInformation( SystemTimeOfDayInformation
, &info
, sizeof(info
), NULL
);
226 SystemTime
->QuadPart
= LocalTime
->QuadPart
+ info
.TimeZoneBias
.QuadPart
;
227 return STATUS_SUCCESS
;
230 /******************************************************************************
231 * RtlSystemTimeToLocalTime [NTDLL.@]
233 * Convert a system time into a local time.
236 * SystemTime [I] System time to convert.
237 * LocalTime [O] Destination for the converted time.
240 * Success: STATUS_SUCCESS.
241 * Failure: An NTSTATUS error code indicating the problem.
243 NTSTATUS WINAPI
RtlSystemTimeToLocalTime( const LARGE_INTEGER
*SystemTime
,
244 PLARGE_INTEGER LocalTime
)
246 SYSTEM_TIMEOFDAY_INFORMATION info
;
248 TRACE("(%p, %p)\n", SystemTime
, LocalTime
);
250 NtQuerySystemInformation( SystemTimeOfDayInformation
, &info
, sizeof(info
), NULL
);
251 LocalTime
->QuadPart
= SystemTime
->QuadPart
- info
.TimeZoneBias
.QuadPart
;
252 return STATUS_SUCCESS
;
255 /******************************************************************************
256 * RtlTimeToSecondsSince1970 [NTDLL.@]
258 * Convert a time into a count of seconds since 1970.
261 * Time [I] Time to convert.
262 * Seconds [O] Destination for the converted time.
266 * Failure: FALSE, if the resulting value will not fit in a DWORD.
268 BOOLEAN WINAPI
RtlTimeToSecondsSince1970( const LARGE_INTEGER
*Time
, LPDWORD Seconds
)
270 ULONGLONG tmp
= Time
->QuadPart
/ TICKSPERSEC
- SECS_1601_TO_1970
;
271 if (tmp
> 0xffffffff) return FALSE
;
276 /******************************************************************************
277 * RtlTimeToSecondsSince1980 [NTDLL.@]
279 * Convert a time into a count of seconds since 1980.
282 * Time [I] Time to convert.
283 * Seconds [O] Destination for the converted time.
287 * Failure: FALSE, if the resulting value will not fit in a DWORD.
289 BOOLEAN WINAPI
RtlTimeToSecondsSince1980( const LARGE_INTEGER
*Time
, LPDWORD Seconds
)
291 ULONGLONG tmp
= Time
->QuadPart
/ TICKSPERSEC
- SECS_1601_TO_1980
;
292 if (tmp
> 0xffffffff) return FALSE
;
297 /******************************************************************************
298 * RtlSecondsSince1970ToTime [NTDLL.@]
300 * Convert a count of seconds since 1970 to a time.
303 * Seconds [I] Time to convert.
304 * Time [O] Destination for the converted time.
309 void WINAPI
RtlSecondsSince1970ToTime( DWORD Seconds
, LARGE_INTEGER
*Time
)
311 Time
->QuadPart
= Seconds
* (ULONGLONG
)TICKSPERSEC
+ TICKS_1601_TO_1970
;
314 /******************************************************************************
315 * RtlSecondsSince1980ToTime [NTDLL.@]
317 * Convert a count of seconds since 1980 to a time.
320 * Seconds [I] Time to convert.
321 * Time [O] Destination for the converted time.
326 void WINAPI
RtlSecondsSince1980ToTime( DWORD Seconds
, LARGE_INTEGER
*Time
)
328 Time
->QuadPart
= Seconds
* (ULONGLONG
)TICKSPERSEC
+ TICKS_1601_TO_1980
;
331 /******************************************************************************
332 * RtlTimeToElapsedTimeFields [NTDLL.@]
334 * Convert a time to a count of elapsed seconds.
337 * Time [I] Time to convert.
338 * TimeFields [O] Destination for the converted time.
343 void WINAPI
RtlTimeToElapsedTimeFields( const LARGE_INTEGER
*Time
, PTIME_FIELDS TimeFields
)
348 time
= Time
->QuadPart
/ TICKSPERSEC
;
349 TimeFields
->Milliseconds
= (Time
->QuadPart
% TICKSPERSEC
) / TICKSPERMSEC
;
351 /* time is now in seconds */
352 TimeFields
->Year
= 0;
353 TimeFields
->Month
= 0;
354 TimeFields
->Day
= time
/ SECSPERDAY
;
356 /* rem is now the remaining seconds in the last day */
357 rem
= time
% SECSPERDAY
;
358 TimeFields
->Second
= rem
% 60;
360 TimeFields
->Minute
= rem
% 60;
361 TimeFields
->Hour
= rem
/ 60;
364 /***********************************************************************
365 * RtlGetSystemTimePrecise [NTDLL.@]
367 * Get a more accurate current system time.
370 * The current system time.
372 LONGLONG WINAPI
RtlGetSystemTimePrecise( void )
376 WINE_UNIX_CALL( unix_system_time_precise
, &ret
);
380 /******************************************************************************
381 * RtlQueryPerformanceCounter [NTDLL.@]
383 BOOL WINAPI DECLSPEC_HOTPATCH
RtlQueryPerformanceCounter( LARGE_INTEGER
*counter
)
385 NtQueryPerformanceCounter( counter
, NULL
);
389 /******************************************************************************
390 * RtlQueryPerformanceFrequency [NTDLL.@]
392 BOOL WINAPI DECLSPEC_HOTPATCH
RtlQueryPerformanceFrequency( LARGE_INTEGER
*frequency
)
394 frequency
->QuadPart
= TICKSPERSEC
;
398 /******************************************************************************
399 * NtGetTickCount (NTDLL.@)
400 * ZwGetTickCount (NTDLL.@)
402 ULONG WINAPI DECLSPEC_HOTPATCH
NtGetTickCount(void)
404 /* note: we ignore TickCountMultiplier */
405 return user_shared_data
->TickCount
.LowPart
;
408 /***********************************************************************
409 * RtlQueryTimeZoneInformation [NTDLL.@]
411 * Get information about the current timezone.
414 * tzinfo [O] Destination for the retrieved timezone info.
417 * Success: STATUS_SUCCESS.
418 * Failure: An NTSTATUS error code indicating the problem.
420 NTSTATUS WINAPI
RtlQueryTimeZoneInformation(RTL_TIME_ZONE_INFORMATION
*ret
)
422 return NtQuerySystemInformation( SystemCurrentTimeZoneInformation
, ret
, sizeof(*ret
), NULL
);
425 /***********************************************************************
426 * RtlQueryDynamicTimeZoneInformation [NTDLL.@]
428 * Get information about the current timezone.
431 * tzinfo [O] Destination for the retrieved timezone info.
434 * Success: STATUS_SUCCESS.
435 * Failure: An NTSTATUS error code indicating the problem.
437 NTSTATUS WINAPI
RtlQueryDynamicTimeZoneInformation(RTL_DYNAMIC_TIME_ZONE_INFORMATION
*ret
)
439 return NtQuerySystemInformation( SystemDynamicTimeZoneInformation
, ret
, sizeof(*ret
), NULL
);
442 /***********************************************************************
443 * RtlSetTimeZoneInformation [NTDLL.@]
445 * Set the current time zone information.
448 * tzinfo [I] Timezone information to set.
451 * Success: STATUS_SUCCESS.
452 * Failure: An NTSTATUS error code indicating the problem.
455 NTSTATUS WINAPI
RtlSetTimeZoneInformation( const RTL_TIME_ZONE_INFORMATION
*tzinfo
)
457 return STATUS_PRIVILEGE_NOT_HELD
;
460 /***********************************************************************
461 * RtlQueryUnbiasedInterruptTime [NTDLL.@]
463 BOOL WINAPI
RtlQueryUnbiasedInterruptTime(ULONGLONG
*time
)
469 RtlSetLastWin32ErrorAndNtStatusFromNtStatus( STATUS_INVALID_PARAMETER
);
475 high
= user_shared_data
->InterruptTime
.High1Time
;
476 low
= user_shared_data
->InterruptTime
.LowPart
;
478 while (high
!= user_shared_data
->InterruptTime
.High2Time
);
479 /* FIXME: should probably subtract InterruptTimeBias */
480 *time
= (ULONGLONG
)high
<< 32 | low
;