2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS system libraries
4 * FILE: lib/msvcrt/time/time.c
5 * PURPOSE: Get system time
6 * PROGRAMER: Boudewijn Dekker
11 * DOS file system functions
13 * Copyright 1993 Erik Bos
14 * Copyright 1996 Alexandre Julliard
19 VOID STDCALL
GetSystemTimeAsFileTime(LPFILETIME lpSystemTimeAsFileTime
);
24 time_t time(time_t* t
)
29 GetSystemTimeAsFileTime(&SystemTime
);
30 tt
= FileTimeToUnixTime(&SystemTime
,&Remainder
);
36 /***********************************************************************
37 * DOSFS_UnixTimeToFileTime
39 * Convert a Unix time to FILETIME format.
40 * The FILETIME structure is a 64-bit value representing the number of
41 * 100-nanosecond intervals since January 1, 1601, 0:00.
42 * 'remainder' is the nonnegative number of 100-ns intervals
43 * corresponding to the time fraction smaller than 1 second that
44 * couldn't be stored in the time_t value.
46 void UnixTimeToFileTime( time_t unix_time
, FILETIME
*filetime
,
52 The time difference between 1 January 1601, 00:00:00 and
53 1 January 1970, 00:00:00 is 369 years, plus the leap years
54 from 1604 to 1968, excluding 1700, 1800, 1900.
55 This makes (1968 - 1600) / 4 - 3 = 89 leap days, and a total
58 Any day in that period had 24 * 60 * 60 = 86400 seconds.
60 The time difference is 134774 * 86400 * 10000000, which can be written
62 27111902 * 2^32 + 3577643008
63 413 * 2^48 + 45534 * 2^32 + 54590 * 2^16 + 32768
65 If you find that these constants are buggy, please change them in all
66 instances in both conversion functions.
69 There are two versions, one of them uses long long variables and
70 is presumably faster but not ISO C. The other one uses standard C
71 data types and operations but relies on the assumption that negative
72 numbers are stored as 2's complement (-1 is 0xffff....). If this
73 assumption is violated, dates before 1970 will not convert correctly.
74 This should however work on any reasonable architecture where WINE
79 Take care not to remove the casts. I have tested these functions
80 (in both versions) for a lot of numbers. I would be interested in
81 results on other compilers than GCC.
83 The operations have been designed to account for the possibility
84 of 64-bit time_t in future UNICES. Even the versions without
85 internal long long numbers will work if time_t only is 64 bit.
86 A 32-bit shift, which was necessary for that operation, turned out
87 not to work correctly in GCC, besides giving the warning. So I
88 used a double 16-bit shift instead. Numbers are in the ISO version
89 represented by three limbs, the most significant with 32 bit, the
90 other two with 16 bit each.
92 As the modulo-operator % is not well-defined for negative numbers,
93 negative divisors have been avoided in DOSFS_FileTimeToUnixTime.
95 There might be quicker ways to do this in C. Certainly so in
98 Claus Fischer, fischer@iue.tuwien.ac.at
104 unsigned long a0
; /* 16 bit, low bits */
105 unsigned long a1
; /* 16 bit, medium bits */
106 unsigned long a2
; /* 32 bit, high bits */
108 /* Copy the unix time to a2/a1/a0 */
109 a0
= unix_time
& 0xffff;
110 a1
= (unix_time
>> 16) & 0xffff;
111 /* This is obsolete if unix_time is only 32 bits, but it does not hurt.
112 Do not replace this by >> 32, it gives a compiler warning and it does
114 a2
= (unix_time
>= 0 ? (unix_time
>> 16) >> 16 :
115 ~((~unix_time
>> 16) >> 16));
117 /* Multiply a by 10000000 (a = a2/a1/a0)
118 Split the factor into 10000 * 1000 which are both less than 0xffff. */
120 a1
= a1
* 10000 + (a0
>> 16);
121 a2
= a2
* 10000 + (a1
>> 16);
126 a1
= a1
* 1000 + (a0
>> 16);
127 a2
= a2
* 1000 + (a1
>> 16);
131 /* Add the time difference and the remainder */
132 a0
+= 32768 + (remainder
& 0xffff);
133 a1
+= 54590 + (remainder
>> 16 ) + (a0
>> 16);
134 a2
+= 27111902 + (a1
>> 16);
139 filetime
->dwLowDateTime
= (a1
<< 16) + a0
;
140 filetime
->dwHighDateTime
= a2
;
144 /***********************************************************************
145 * DOSFS_FileTimeToUnixTime
147 * Convert a FILETIME format to Unix time.
148 * If not NULL, 'remainder' contains the fractional part of the filetime,
149 * in the range of [0..9999999] (even if time_t is negative).
151 time_t FileTimeToUnixTime( const FILETIME
*filetime
, DWORD
*remainder
)
153 /* Read the comment in the function DOSFS_UnixTimeToFileTime. */
155 unsigned long a0
; /* 16 bit, low bits */
156 unsigned long a1
; /* 16 bit, medium bits */
157 unsigned long a2
; /* 32 bit, high bits */
158 unsigned long r
; /* remainder of division */
159 unsigned int carry
; /* carry bit for subtraction */
160 int negative
; /* whether a represents a negative value */
162 /* Copy the time values to a2/a1/a0 */
163 a2
= (unsigned long)filetime
->dwHighDateTime
;
164 a1
= ((unsigned long)filetime
->dwLowDateTime
) >> 16;
165 a0
= ((unsigned long)filetime
->dwLowDateTime
) & 0xffff;
167 /* Subtract the time difference */
168 if (a0
>= 32768 ) a0
-= 32768 , carry
= 0;
169 else a0
+= (1 << 16) - 32768 , carry
= 1;
171 if (a1
>= 54590 + carry
) a1
-= 54590 + carry
, carry
= 0;
172 else a1
+= (1 << 16) - 54590 - carry
, carry
= 1;
174 a2
-= 27111902 + carry
;
176 /* If a is negative, replace a by (-1-a) */
177 negative
= (a2
>= ((unsigned long)1) << 31);
180 /* Set a to -a - 1 (a is a2/a1/a0) */
186 /* Divide a by 10000000 (a = a2/a1/a0), put the rest into r.
187 Split the divisor into 10000 * 1000 which are both less than 0xffff. */
188 a1
+= (a2
% 10000) << 16;
190 a0
+= (a1
% 10000) << 16;
195 a1
+= (a2
% 1000) << 16;
197 a0
+= (a1
% 1000) << 16;
199 r
+= (a0
% 1000) * 10000;
202 /* If a was negative, replace a by (-1-a) and r by (9999999 - r) */
205 /* Set a to -a - 1 (a is a2/a1/a0) */
213 if (remainder
) *remainder
= r
;
215 /* Do not replace this by << 32, it gives a compiler warning and it does
217 return ((((time_t)a2
) << 16) << 16) + (a1
<< 16) + a0
;