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
12 * DOS file system functions
14 * Copyright 1993 Erik Bos
15 * Copyright 1996 Alexandre Julliard
19 #include <msvcrt/time.h>
20 #include <msvcrt/internal/file.h>
23 VOID STDCALL GetSystemTimeAsFileTime(LPFILETIME lpSystemTimeAsFileTime);
28 time_t time(time_t* t)
33 GetSystemTimeAsFileTime(&SystemTime);
34 tt = FileTimeToUnixTime(&SystemTime,&Remainder);
40 /***********************************************************************
41 * DOSFS_UnixTimeToFileTime
43 * Convert a Unix time to FILETIME format.
44 * The FILETIME structure is a 64-bit value representing the number of
45 * 100-nanosecond intervals since January 1, 1601, 0:00.
46 * 'remainder' is the nonnegative number of 100-ns intervals
47 * corresponding to the time fraction smaller than 1 second that
48 * couldn't be stored in the time_t value.
50 void UnixTimeToFileTime( time_t unix_time, FILETIME *filetime,
56 The time difference between 1 January 1601, 00:00:00 and
57 1 January 1970, 00:00:00 is 369 years, plus the leap years
58 from 1604 to 1968, excluding 1700, 1800, 1900.
59 This makes (1968 - 1600) / 4 - 3 = 89 leap days, and a total
62 Any day in that period had 24 * 60 * 60 = 86400 seconds.
64 The time difference is 134774 * 86400 * 10000000, which can be written
66 27111902 * 2^32 + 3577643008
67 413 * 2^48 + 45534 * 2^32 + 54590 * 2^16 + 32768
69 If you find that these constants are buggy, please change them in all
70 instances in both conversion functions.
73 There are two versions, one of them uses long long variables and
74 is presumably faster but not ISO C. The other one uses standard C
75 data types and operations but relies on the assumption that negative
76 numbers are stored as 2's complement (-1 is 0xffff....). If this
77 assumption is violated, dates before 1970 will not convert correctly.
78 This should however work on any reasonable architecture where WINE
83 Take care not to remove the casts. I have tested these functions
84 (in both versions) for a lot of numbers. I would be interested in
85 results on other compilers than GCC.
87 The operations have been designed to account for the possibility
88 of 64-bit time_t in future UNICES. Even the versions without
89 internal long long numbers will work if time_t only is 64 bit.
90 A 32-bit shift, which was necessary for that operation, turned out
91 not to work correctly in GCC, besides giving the warning. So I
92 used a double 16-bit shift instead. Numbers are in the ISO version
93 represented by three limbs, the most significant with 32 bit, the
94 other two with 16 bit each.
96 As the modulo-operator % is not well-defined for negative numbers,
97 negative divisors have been avoided in DOSFS_FileTimeToUnixTime.
99 There might be quicker ways to do this in C. Certainly so in
102 Claus Fischer, fischer@iue.tuwien.ac.at
108 unsigned long a0; /* 16 bit, low bits */
109 unsigned long a1; /* 16 bit, medium bits */
110 unsigned long a2; /* 32 bit, high bits */
112 /* Copy the unix time to a2/a1/a0 */
113 a0 = unix_time & 0xffff;
114 a1 = (unix_time >> 16) & 0xffff;
115 /* This is obsolete if unix_time is only 32 bits, but it does not hurt.
116 Do not replace this by >> 32, it gives a compiler warning and it does
118 a2 = (unix_time >= 0 ? (unix_time >> 16) >> 16 :
119 ~((~unix_time >> 16) >> 16));
121 /* Multiply a by 10000000 (a = a2/a1/a0)
122 Split the factor into 10000 * 1000 which are both less than 0xffff. */
124 a1 = a1 * 10000 + (a0 >> 16);
125 a2 = a2 * 10000 + (a1 >> 16);
130 a1 = a1 * 1000 + (a0 >> 16);
131 a2 = a2 * 1000 + (a1 >> 16);
135 /* Add the time difference and the remainder */
136 a0 += 32768 + (remainder & 0xffff);
137 a1 += 54590 + (remainder >> 16 ) + (a0 >> 16);
138 a2 += 27111902 + (a1 >> 16);
143 filetime->dwLowDateTime = (a1 << 16) + a0;
144 filetime->dwHighDateTime = a2;
148 /***********************************************************************
149 * DOSFS_FileTimeToUnixTime
151 * Convert a FILETIME format to Unix time.
152 * If not NULL, 'remainder' contains the fractional part of the filetime,
153 * in the range of [0..9999999] (even if time_t is negative).
155 time_t FileTimeToUnixTime( const FILETIME *filetime, DWORD *remainder )
157 /* Read the comment in the function DOSFS_UnixTimeToFileTime. */
159 unsigned long a0; /* 16 bit, low bits */
160 unsigned long a1; /* 16 bit, medium bits */
161 unsigned long a2; /* 32 bit, high bits */
162 unsigned long r; /* remainder of division */
163 unsigned int carry; /* carry bit for subtraction */
164 int negative; /* whether a represents a negative value */
166 /* Copy the time values to a2/a1/a0 */
167 a2 = (unsigned long)filetime->dwHighDateTime;
168 a1 = ((unsigned long)filetime->dwLowDateTime ) >> 16;
169 a0 = ((unsigned long)filetime->dwLowDateTime ) & 0xffff;
171 /* Subtract the time difference */
172 if (a0 >= 32768 ) a0 -= 32768 , carry = 0;
173 else a0 += (1 << 16) - 32768 , carry = 1;
175 if (a1 >= 54590 + carry) a1 -= 54590 + carry, carry = 0;
176 else a1 += (1 << 16) - 54590 - carry, carry = 1;
178 a2 -= 27111902 + carry;
180 /* If a is negative, replace a by (-1-a) */
181 negative = (a2 >= ((unsigned long)1) << 31);
184 /* Set a to -a - 1 (a is a2/a1/a0) */
190 /* Divide a by 10000000 (a = a2/a1/a0), put the rest into r.
191 Split the divisor into 10000 * 1000 which are both less than 0xffff. */
192 a1 += (a2 % 10000) << 16;
194 a0 += (a1 % 10000) << 16;
199 a1 += (a2 % 1000) << 16;
201 a0 += (a1 % 1000) << 16;
203 r += (a0 % 1000) * 10000;
206 /* If a was negative, replace a by (-1-a) and r by (9999999 - r) */
209 /* Set a to -a - 1 (a is a2/a1/a0) */
217 if (remainder) *remainder = r;
219 /* Do not replace this by << 32, it gives a compiler warning and it does
221 return ((((time_t)a2) << 16) << 16) + (a1 << 16) + a0;