2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS system libraries
4 * FILE: lib/crtdll/conio/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 <crtdll/time.h>
20 #include <crtdll/internal/file.h>
22 VOID STDCALL GetSystemTimeAsFileTime(LPFILETIME lpSystemTimeAsFileTime );
29 GetSystemTimeAsFileTime(&SystemTime);
30 return FileTimeToUnixTime( &SystemTime,&Remainder );
33 /***********************************************************************
34 * DOSFS_UnixTimeToFileTime
36 * Convert a Unix time to FILETIME format.
37 * The FILETIME structure is a 64-bit value representing the number of
38 * 100-nanosecond intervals since January 1, 1601, 0:00.
39 * 'remainder' is the nonnegative number of 100-ns intervals
40 * corresponding to the time fraction smaller than 1 second that
41 * couldn't be stored in the time_t value.
43 void UnixTimeToFileTime( time_t unix_time, FILETIME *filetime,
49 The time difference between 1 January 1601, 00:00:00 and
50 1 January 1970, 00:00:00 is 369 years, plus the leap years
51 from 1604 to 1968, excluding 1700, 1800, 1900.
52 This makes (1968 - 1600) / 4 - 3 = 89 leap days, and a total
55 Any day in that period had 24 * 60 * 60 = 86400 seconds.
57 The time difference is 134774 * 86400 * 10000000, which can be written
59 27111902 * 2^32 + 3577643008
60 413 * 2^48 + 45534 * 2^32 + 54590 * 2^16 + 32768
62 If you find that these constants are buggy, please change them in all
63 instances in both conversion functions.
66 There are two versions, one of them uses long long variables and
67 is presumably faster but not ISO C. The other one uses standard C
68 data types and operations but relies on the assumption that negative
69 numbers are stored as 2's complement (-1 is 0xffff....). If this
70 assumption is violated, dates before 1970 will not convert correctly.
71 This should however work on any reasonable architecture where WINE
76 Take care not to remove the casts. I have tested these functions
77 (in both versions) for a lot of numbers. I would be interested in
78 results on other compilers than GCC.
80 The operations have been designed to account for the possibility
81 of 64-bit time_t in future UNICES. Even the versions without
82 internal long long numbers will work if time_t only is 64 bit.
83 A 32-bit shift, which was necessary for that operation, turned out
84 not to work correctly in GCC, besides giving the warning. So I
85 used a double 16-bit shift instead. Numbers are in the ISO version
86 represented by three limbs, the most significant with 32 bit, the
87 other two with 16 bit each.
89 As the modulo-operator % is not well-defined for negative numbers,
90 negative divisors have been avoided in DOSFS_FileTimeToUnixTime.
92 There might be quicker ways to do this in C. Certainly so in
95 Claus Fischer, fischer@iue.tuwien.ac.at
101 unsigned long a0; /* 16 bit, low bits */
102 unsigned long a1; /* 16 bit, medium bits */
103 unsigned long a2; /* 32 bit, high bits */
105 /* Copy the unix time to a2/a1/a0 */
106 a0 = unix_time & 0xffff;
107 a1 = (unix_time >> 16) & 0xffff;
108 /* This is obsolete if unix_time is only 32 bits, but it does not hurt.
109 Do not replace this by >> 32, it gives a compiler warning and it does
111 a2 = (unix_time >= 0 ? (unix_time >> 16) >> 16 :
112 ~((~unix_time >> 16) >> 16));
114 /* Multiply a by 10000000 (a = a2/a1/a0)
115 Split the factor into 10000 * 1000 which are both less than 0xffff. */
117 a1 = a1 * 10000 + (a0 >> 16);
118 a2 = a2 * 10000 + (a1 >> 16);
123 a1 = a1 * 1000 + (a0 >> 16);
124 a2 = a2 * 1000 + (a1 >> 16);
128 /* Add the time difference and the remainder */
129 a0 += 32768 + (remainder & 0xffff);
130 a1 += 54590 + (remainder >> 16 ) + (a0 >> 16);
131 a2 += 27111902 + (a1 >> 16);
136 filetime->dwLowDateTime = (a1 << 16) + a0;
137 filetime->dwHighDateTime = a2;
141 /***********************************************************************
142 * DOSFS_FileTimeToUnixTime
144 * Convert a FILETIME format to Unix time.
145 * If not NULL, 'remainder' contains the fractional part of the filetime,
146 * in the range of [0..9999999] (even if time_t is negative).
148 time_t FileTimeToUnixTime( const FILETIME *filetime, DWORD *remainder )
150 /* Read the comment in the function DOSFS_UnixTimeToFileTime. */
152 unsigned long a0; /* 16 bit, low bits */
153 unsigned long a1; /* 16 bit, medium bits */
154 unsigned long a2; /* 32 bit, high bits */
155 unsigned long r; /* remainder of division */
156 unsigned int carry; /* carry bit for subtraction */
157 int negative; /* whether a represents a negative value */
159 /* Copy the time values to a2/a1/a0 */
160 a2 = (unsigned long)filetime->dwHighDateTime;
161 a1 = ((unsigned long)filetime->dwLowDateTime ) >> 16;
162 a0 = ((unsigned long)filetime->dwLowDateTime ) & 0xffff;
164 /* Subtract the time difference */
165 if (a0 >= 32768 ) a0 -= 32768 , carry = 0;
166 else a0 += (1 << 16) - 32768 , carry = 1;
168 if (a1 >= 54590 + carry) a1 -= 54590 + carry, carry = 0;
169 else a1 += (1 << 16) - 54590 - carry, carry = 1;
171 a2 -= 27111902 + carry;
173 /* If a is negative, replace a by (-1-a) */
174 negative = (a2 >= ((unsigned long)1) << 31);
177 /* Set a to -a - 1 (a is a2/a1/a0) */
183 /* Divide a by 10000000 (a = a2/a1/a0), put the rest into r.
184 Split the divisor into 10000 * 1000 which are both less than 0xffff. */
185 a1 += (a2 % 10000) << 16;
187 a0 += (a1 % 10000) << 16;
192 a1 += (a2 % 1000) << 16;
194 a0 += (a1 % 1000) << 16;
196 r += (a0 % 1000) * 10000;
199 /* If a was negative, replace a by (-1-a) and r by (9999999 - r) */
202 /* Set a to -a - 1 (a is a2/a1/a0) */
210 if (remainder) *remainder = r;
212 /* Do not replace this by << 32, it gives a compiler warning and it does
214 return ((((time_t)a2) << 16) << 16) + (a1 << 16) + a0;