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);
25 time_t time(time_t* t)
30 GetSystemTimeAsFileTime(&SystemTime);
31 tt = FileTimeToUnixTime(&SystemTime,&Remainder);
37 /***********************************************************************
38 * DOSFS_UnixTimeToFileTime
40 * Convert a Unix time to FILETIME format.
41 * The FILETIME structure is a 64-bit value representing the number of
42 * 100-nanosecond intervals since January 1, 1601, 0:00.
43 * 'remainder' is the nonnegative number of 100-ns intervals
44 * corresponding to the time fraction smaller than 1 second that
45 * couldn't be stored in the time_t value.
47 void UnixTimeToFileTime( time_t unix_time, FILETIME *filetime,
53 The time difference between 1 January 1601, 00:00:00 and
54 1 January 1970, 00:00:00 is 369 years, plus the leap years
55 from 1604 to 1968, excluding 1700, 1800, 1900.
56 This makes (1968 - 1600) / 4 - 3 = 89 leap days, and a total
59 Any day in that period had 24 * 60 * 60 = 86400 seconds.
61 The time difference is 134774 * 86400 * 10000000, which can be written
63 27111902 * 2^32 + 3577643008
64 413 * 2^48 + 45534 * 2^32 + 54590 * 2^16 + 32768
66 If you find that these constants are buggy, please change them in all
67 instances in both conversion functions.
70 There are two versions, one of them uses long long variables and
71 is presumably faster but not ISO C. The other one uses standard C
72 data types and operations but relies on the assumption that negative
73 numbers are stored as 2's complement (-1 is 0xffff....). If this
74 assumption is violated, dates before 1970 will not convert correctly.
75 This should however work on any reasonable architecture where WINE
80 Take care not to remove the casts. I have tested these functions
81 (in both versions) for a lot of numbers. I would be interested in
82 results on other compilers than GCC.
84 The operations have been designed to account for the possibility
85 of 64-bit time_t in future UNICES. Even the versions without
86 internal long long numbers will work if time_t only is 64 bit.
87 A 32-bit shift, which was necessary for that operation, turned out
88 not to work correctly in GCC, besides giving the warning. So I
89 used a double 16-bit shift instead. Numbers are in the ISO version
90 represented by three limbs, the most significant with 32 bit, the
91 other two with 16 bit each.
93 As the modulo-operator % is not well-defined for negative numbers,
94 negative divisors have been avoided in DOSFS_FileTimeToUnixTime.
96 There might be quicker ways to do this in C. Certainly so in
99 Claus Fischer, fischer@iue.tuwien.ac.at
105 unsigned long a0; /* 16 bit, low bits */
106 unsigned long a1; /* 16 bit, medium bits */
107 unsigned long a2; /* 32 bit, high bits */
109 /* Copy the unix time to a2/a1/a0 */
110 a0 = unix_time & 0xffff;
111 a1 = (unix_time >> 16) & 0xffff;
112 /* This is obsolete if unix_time is only 32 bits, but it does not hurt.
113 Do not replace this by >> 32, it gives a compiler warning and it does
115 a2 = (unix_time >= 0 ? (unix_time >> 16) >> 16 :
116 ~((~unix_time >> 16) >> 16));
118 /* Multiply a by 10000000 (a = a2/a1/a0)
119 Split the factor into 10000 * 1000 which are both less than 0xffff. */
121 a1 = a1 * 10000 + (a0 >> 16);
122 a2 = a2 * 10000 + (a1 >> 16);
127 a1 = a1 * 1000 + (a0 >> 16);
128 a2 = a2 * 1000 + (a1 >> 16);
132 /* Add the time difference and the remainder */
133 a0 += 32768 + (remainder & 0xffff);
134 a1 += 54590 + (remainder >> 16 ) + (a0 >> 16);
135 a2 += 27111902 + (a1 >> 16);
140 filetime->dwLowDateTime = (a1 << 16) + a0;
141 filetime->dwHighDateTime = a2;
145 /***********************************************************************
146 * DOSFS_FileTimeToUnixTime
148 * Convert a FILETIME format to Unix time.
149 * If not NULL, 'remainder' contains the fractional part of the filetime,
150 * in the range of [0..9999999] (even if time_t is negative).
152 time_t FileTimeToUnixTime( const FILETIME *filetime, DWORD *remainder )
154 /* Read the comment in the function DOSFS_UnixTimeToFileTime. */
156 unsigned long a0; /* 16 bit, low bits */
157 unsigned long a1; /* 16 bit, medium bits */
158 unsigned long a2; /* 32 bit, high bits */
159 unsigned long r; /* remainder of division */
160 unsigned int carry; /* carry bit for subtraction */
161 int negative; /* whether a represents a negative value */
163 /* Copy the time values to a2/a1/a0 */
164 a2 = (unsigned long)filetime->dwHighDateTime;
165 a1 = ((unsigned long)filetime->dwLowDateTime ) >> 16;
166 a0 = ((unsigned long)filetime->dwLowDateTime ) & 0xffff;
168 /* Subtract the time difference */
169 if (a0 >= 32768 ) a0 -= 32768 , carry = 0;
170 else a0 += (1 << 16) - 32768 , carry = 1;
172 if (a1 >= 54590 + carry) a1 -= 54590 + carry, carry = 0;
173 else a1 += (1 << 16) - 54590 - carry, carry = 1;
175 a2 -= 27111902 + carry;
177 /* If a is negative, replace a by (-1-a) */
178 negative = (a2 >= ((unsigned long)1) << 31);
181 /* Set a to -a - 1 (a is a2/a1/a0) */
187 /* Divide a by 10000000 (a = a2/a1/a0), put the rest into r.
188 Split the divisor into 10000 * 1000 which are both less than 0xffff. */
189 a1 += (a2 % 10000) << 16;
191 a0 += (a1 % 10000) << 16;
196 a1 += (a2 % 1000) << 16;
198 a0 += (a1 % 1000) << 16;
200 r += (a0 % 1000) * 10000;
203 /* If a was negative, replace a by (-1-a) and r by (9999999 - r) */
206 /* Set a to -a - 1 (a is a2/a1/a0) */
214 if (remainder) *remainder = r;
216 /* Do not replace this by << 32, it gives a compiler warning and it does
218 return ((((time_t)a2) << 16) << 16) + (a1 << 16) + a0;