blob: 90b82ac71372c6be47d8b0d804f1026bd476582d [file] [log] [blame]
Juergen Schmied026d9db1999-03-09 17:47:51 +00001/*
György 'Nog' Jeney6f3015b2002-11-25 01:12:39 +00002 * Nt time functions.
Juergen Schmied026d9db1999-03-09 17:47:51 +00003 *
Vincent Béron9a624912002-05-31 23:06:46 +00004 * RtlTimeToTimeFields, RtlTimeFieldsToTime and defines are taken from ReactOS and
Jon Griffiths08922852003-08-19 00:56:34 +00005 * adapted to wine with special permissions of the author. This code is
6 * Copyright 2002 Rex Jolliff (rex@lvcablemodem.com)
Vincent Béron9a624912002-05-31 23:06:46 +00007 *
Alexandre Julliard0799c1a2002-03-09 23:29:33 +00008 * Copyright 1999 Juergen Schmied
9 *
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
14 *
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
19 *
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Juergen Schmied026d9db1999-03-09 17:47:51 +000023 */
24
Patrik Stridvalld016f812002-08-17 00:43:16 +000025#include "config.h"
Patrik Stridvall51e6c0c2002-08-31 19:04:14 +000026#include "wine/port.h"
Patrik Stridvalld016f812002-08-17 00:43:16 +000027
Alexandre Julliarde37c6e12003-09-05 23:08:26 +000028#include <stdarg.h>
Vincent Béronea966aa2002-11-27 20:14:45 +000029#include <stdlib.h>
David Luyer26cd7a11999-03-25 15:57:35 +000030#include <string.h>
Alexandre Julliard25b23a02004-09-07 23:01:34 +000031#include <limits.h>
Alexandre Julliardd76f9f92000-10-01 01:40:42 +000032#include <time.h>
Patrik Stridvalld016f812002-08-17 00:43:16 +000033#ifdef HAVE_SYS_TIME_H
34# include <sys/time.h>
35#endif
36#ifdef HAVE_UNISTD_H
37# include <unistd.h>
38#endif
Dimitrie O. Paun297f3d82003-01-07 20:36:20 +000039
40#define NONAMELESSUNION
41#define NONAMELESSSTRUCT
Alexandre Julliarde37c6e12003-09-05 23:08:26 +000042#include "windef.h"
43#include "winbase.h"
44#include "winreg.h"
Patrik Stridvall9c1de6d2002-09-12 22:07:02 +000045#include "winternl.h"
György 'Nog' Jeney6f3015b2002-11-25 01:12:39 +000046#include "wine/unicode.h"
Alexandre Julliard0799c1a2002-03-09 23:29:33 +000047#include "wine/debug.h"
Alexandre Julliard462172a2003-04-02 22:48:59 +000048#include "ntdll_misc.h"
Patrik Stridvallb4b9fae1999-04-19 14:56:29 +000049
Alexandre Julliard0799c1a2002-03-09 23:29:33 +000050WINE_DEFAULT_DEBUG_CHANNEL(ntdll);
Juergen Schmied026d9db1999-03-09 17:47:51 +000051
Huw Davies67e2d6c2004-02-27 00:43:20 +000052static CRITICAL_SECTION TIME_GetBias_section;
53static CRITICAL_SECTION_DEBUG critsect_debug =
54{
55 0, 0, &TIME_GetBias_section,
56 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
57 0, 0, { 0, (DWORD)(__FILE__ ": TIME_GetBias_section") }
58};
59static CRITICAL_SECTION TIME_GetBias_section = { &critsect_debug, -1, 0, 0, 0, 0 };
60
Rein Klazesc5c93d12004-10-18 21:19:28 +000061/* TimeZone registry key values */
62static const WCHAR TZInformationKeyW[] = { 'M','a','c','h','i','n','e','\\',
63 'S','Y','S','T','E','M','\\','C','u','r','r','e','n','t','C','o','n','t','r',
64 'o','l','S','e','t','\\','C','o','n','t','r','o','l','\\','T','i','m','e','z',
65 'o','n','e','I','n','f','o','r','m','a','t','i','o','n', 0};
66static const WCHAR TZStandardStartW[] = {
67 'S','t','a','n','d','a','r','d','s','t','a','r','t', 0};
68static const WCHAR TZDaylightStartW[] = {
69 'D','a','y','l','i','g','h','t','s','t','a','r','t', 0};
70static const WCHAR TZDaylightBiasW[] = {
71 'D','a','y','l','i','g','h','t','B','i','a','s', 0};
72static const WCHAR TZStandardBiasW[] = {
73 'S','t','a','n','d','a','r','d','B','i','a','s', 0};
74static const WCHAR TZBiasW[] = {'B','i','a','s', 0};
75static const WCHAR TZDaylightNameW[] = {
76 'D','a','y','l','i','g','h','t','N','a','m','e', 0};
77static const WCHAR TZStandardNameW[] = {
78 'S','t','a','n','d','a','r','d','N','a','m','e', 0};
79
Huw Davies67e2d6c2004-02-27 00:43:20 +000080
György 'Nog' Jeney6f3015b2002-11-25 01:12:39 +000081#define SETTIME_MAX_ADJUST 120
82
83/* This structure is used to store strings that represent all of the time zones
84 * in the world. (This is used to help GetTimeZoneInformation)
85 */
86struct tagTZ_INFO
87{
88 const char *psTZFromUnix;
89 WCHAR psTZWindows[32];
90 int bias;
91 int dst;
92};
93
94static const struct tagTZ_INFO TZ_INFO[] =
95{
96 {"MHT",
97 {'D','a','t','e','l','i','n','e',' ','S','t','a','n','d','a','r','d',' ',
98 'T','i','m','e','\0'}, -720, 0},
99 {"SST",
100 {'S','a','m','o','a',' ','S','t','a','n','d','a','r','d',' ','T','i','m',
101 'e','\0'}, 660, 0},
102 {"HST",
103 {'H','a','w','a','i','i','a','n',' ','S','t','a','n','d','a','r','d',' ',
104 'T','i','m','e','\0'}, 600, 0},
105 {"AKDT",
106 {'A','l','a','s','k','a','n',' ','S','t','a','n','d','a','r','d',' ','T',
107 'i','m','e','\0'}, 480, 1},
108 {"PDT",
109 {'P','a','c','i','f','i','c',' ','S','t','a','n','d','a','r','d',' ','T',
110 'i','m','e','\0'}, 420, 1},
111 {"MST",
112 {'U','S',' ','M','o','u','n','t','a','i','n',' ','S','t','a','n','d','a',
113 'r','d',' ','T','i','m','e','\0'}, 420, 0},
114 {"MDT",
115 {'M','o','u','n','t','a','i','n',' ','S','t','a','n','d','a','r','d',' ',
116 'T','i','m','e','\0'}, 360, 1},
117 {"CST",
118 {'C','e','n','t','r','a','l',' ','A','m','e','r','i','c','a',' ','S','t',
119 'a','n','d','a','r','d',' ','T','i','m','e','\0'}, 360, 0},
120 {"CDT",
121 {'C','e','n','t','r','a','l',' ','S','t','a','n','d','a','r','d',' ','T',
122 'i','m','e','\0'}, 300, 1},
123 {"COT",
124 {'S','A',' ','P','a','c','i','f','i','c',' ','S','t','a','n','d','a','r',
125 'd',' ','T','i','m','e','\0'}, 300, 0},
126 {"EDT",
127 {'E','a','s','t','e','r','n',' ','S','t','a','n','d','a','r','d',' ','T',
128 'i','m','e','\0'}, 240, 1},
129 {"EST",
130 {'U','S',' ','E','a','s','t','e','r','n',' ','S','t','a','n','d','a','r',
131 'd',' ','T','i','m','e','\0'}, 300, 0},
132 {"ADT",
133 {'A','t','l','a','n','t','i','c',' ','S','t','a','n','d','a','r','d',' ',
134 'T','i','m','e','\0'}, 180, 1},
135 {"VET",
136 {'S','A',' ','W','e','s','t','e','r','n',' ','S','t','a','n','d','a','r',
137 'd',' ','T','i','m','e','\0'}, 240, 0},
138 {"CLT",
139 {'P','a','c','i','f','i','c',' ','S','A',' ','S','t','a','n','d','a','r',
140 'd',' ','T','i','m','e','\0'}, 240, 0},
141 {"NDT",
142 {'N','e','w','f','o','u','n','d','l','a','n','d',' ','S','t','a','n','d',
143 'a','r','d',' ','T','i','m','e','\0'}, 150, 1},
144 {"BRT",
145 {'E','.',' ','S','o','u','t','h',' ','A','m','e','r','i','c','a',' ','S',
146 't','a','n','d','a','r','d',' ','T','i','m','e','\0'}, 180, 0},
147 {"ART",
148 {'S','A',' ','E','a','s','t','e','r','n',' ','S','t','a','n','d','a','r',
149 'd',' ','T','i','m','e','\0'}, 180, 0},
150 {"WGST",
151 {'G','r','e','e','n','l','a','n','d',' ','S','t','a','n','d','a','r','d',
152 ' ','T','i','m','e','\0'}, 120, 1},
153 {"GST",
154 {'M','i','d','-','A','t','l','a','n','t','i','c',' ','S','t','a','n','d',
155 'a','r','d',' ','T','i','m','e','\0'}, 120, 0},
156 {"AZOST",
157 {'A','z','o','r','e','s',' ','S','t','a','n','d','a','r','d',' ','T','i',
158 'm','e','\0'}, 0, 1},
159 {"CVT",
160 {'C','a','p','e',' ','V','e','r','d','e',' ','S','t','a','n','d','a','r',
161 'd',' ','T','i','m','e','\0'}, 60, 0},
162 {"WET",
163 {'G','r','e','e','n','w','i','c','h',' ','S','t','a','n','d','a','r','d',
164 ' ','T','i','m','e','\0'}, 0, 0},
165 {"BST",
166 {'G','M','T',' ','S','t','a','n','d','a','r','d',' ','T','i','m','e','\0'},
167 -60, 1},
168 {"GMT",
169 {'G','M','T',' ','S','t','a','n','d','a','r','d',' ','T','i','m','e','\0'},
170 0, 0},
Filip Navara63c63592004-10-04 19:29:16 +0000171 {"UTC",
172 {'G','M','T',' ','S','t','a','n','d','a','r','d',' ','T','i','m','e','\0'},
173 0, 0},
György 'Nog' Jeney6f3015b2002-11-25 01:12:39 +0000174 {"CEST",
175 {'C','e','n','t','r','a','l',' ','E','u','r','o','p','e',' ','S','t','a',
176 'n','d','a','r','d',' ','T','i','m','e','\0'}, -120, 1},
Uwe Bonnesd3499082004-09-06 21:26:37 +0000177 {"MET",
178 {'C','e','n','t','r','a','l',' ','E','u','r','o','p','e',' ','S','t','a',
179 'n','d','a','r','d',' ','T','i','m','e','\0'}, -60, 0},
180 {"MEST",
181 {'C','e','n','t','r','a','l',' ','E','u','r','o','p','e',' ','D','a','y',
182 'l','i','g','h','t',' ','T','i','m','e','\0'}, -120, 1},
György 'Nog' Jeney6f3015b2002-11-25 01:12:39 +0000183 {"WAT",
184 {'W','.',' ','C','e','n','t','r','a','l',' ','A','f','r','i','c','a',' ',
185 'S','t','a','n','d','a','r','d',' ','T','i','m','e','\0'}, -60, 0},
186 {"EEST",
187 {'E','.',' ','E','u','r','o','p','e',' ','S','t','a','n','d','a','r','d',
188 ' ','T','i','m','e','\0'}, -180, 1},
189 {"EET",
190 {'E','g','y','p','t',' ','S','t','a','n','d','a','r','d',' ','T','i','m',
191 'e','\0'}, -120, 0},
192 {"CAT",
193 {'S','o','u','t','h',' ','A','f','r','i','c','a',' ','S','t','a','n','d',
194 'a','r','d',' ','T','i','m','e','\0'}, -120, 0},
195 {"IST",
196 {'I','s','r','a','e','l',' ','S','t','a','n','d','a','r','d',' ','T','i',
197 'm','e','\0'}, -120, 0},
198 {"ADT",
199 {'A','r','a','b','i','c',' ','S','t','a','n','d','a','r','d',' ','T','i',
200 'm','e','\0'}, -240, 1},
201 {"AST",
202 {'A','r','a','b',' ','S','t','a','n','d','a','r','d',' ','T','i','m','e',
203 '\0'}, -180, 0},
204 {"MSD",
205 {'R','u','s','s','i','a','n',' ','S','t','a','n','d','a','r','d',' ','T',
206 'i','m','e','\0'}, -240, 1},
207 {"EAT",
208 {'E','.',' ','A','f','r','i','c','a',' ','S','t','a','n','d','a','r','d',
209 ' ','T','i','m','e','\0'}, -180, 0},
210 {"IRST",
211 {'I','r','a','n',' ','S','t','a','n','d','a','r','d',' ','T','i','m','e',
212 '\0'}, -270, 1},
213 {"GST",
214 {'A','r','a','b','i','a','n',' ','S','t','a','n','d','a','r','d',' ','T',
215 'i','m','e','\0'}, -240, 0},
216 {"AZST",
217 {'C','a','u','c','a','s','u','s',' ','S','t','a','n','d','a','r','d',' ',
218 'T','i','m','e','\0'}, -300, 1},
219 {"AFT",
220 {'A','f','g','h','a','n','i','s','t','a','n',' ','S','t','a','n','d','a',
221 'r','d',' ','T','i','m','e','\0'}, -270, 0},
222 {"YEKST",
223 {'E','k','a','t','e','r','i','n','b','u','r','g',' ','S','t','a','n','d',
224 'a','r','d',' ','T','i','m','e','\0'}, -360, 1},
225 {"PKT",
226 {'W','e','s','t',' ','A','s','i','a',' ','S','t','a','n','d','a','r','d',
227 ' ','T','i','m','e','\0'}, -300, 0},
228 {"IST",
229 {'I','n','d','i','a',' ','S','t','a','n','d','a','r','d',' ','T','i','m',
230 'e','\0'}, -330, 0},
231 {"NPT",
232 {'N','e','p','a','l',' ','S','t','a','n','d','a','r','d',' ','T','i','m',
233 'e','\0'}, -345, 0},
234 {"ALMST",
235 {'N','.',' ','C','e','n','t','r','a','l',' ','A','s','i','a',' ','S','t',
236 'a','n','d','a','r','d',' ','T','i','m','e','\0'}, -420, 1},
237 {"BDT",
238 {'C','e','n','t','r','a','l',' ','A','s','i','a',' ','S','t','a','n','d',
239 'a','r','d',' ','T','i','m','e','\0'}, -360, 0},
240 {"LKT",
241 {'S','r','i',' ','L','a','n','k','a',' ','S','t','a','n','d','a','r','d',
242 ' ','T','i','m','e','\0'}, -360, 0},
243 {"MMT",
244 {'M','y','a','n','m','a','r',' ','S','t','a','n','d','a','r','d',' ','T',
245 'i','m','e','\0'}, -390, 0},
246 {"ICT",
247 {'S','E',' ','A','s','i','a',' ','S','t','a','n','d','a','r','d',' ','T',
248 'i','m','e','\0'}, -420, 0},
249 {"KRAST",
250 {'N','o','r','t','h',' ','A','s','i','a',' ','S','t','a','n','d','a','r',
251 'd',' ','T','i','m','e','\0'}, -480, 1},
252 {"CST",
253 {'C','h','i','n','a',' ','S','t','a','n','d','a','r','d',' ','T','i','m',
254 'e','\0'}, -480, 0},
255 {"IRKST",
256 {'N','o','r','t','h',' ','A','s','i','a',' ','E','a','s','t',' ','S','t',
257 'a','n','d','a','r','d',' ','T','i','m','e','\0'}, -540, 1},
258 {"SGT",
259 {'M','a','l','a','y',' ','P','e','n','i','n','s','u','l','a',' ','S','t',
260 'a','n','d','a','r','d',' ','T','i','m','e','\0'}, -480, 0},
261 {"WST",
262 {'W','.',' ','A','u','s','t','r','a','l','i','a',' ','S','t','a','n','d',
263 'a','r','d',' ','T','i','m','e','\0'}, -480, 0},
264 {"JST",
265 {'T','o','k','y','o',' ','S','t','a','n','d','a','r','d',' ','T','i','m',
266 'e','\0'}, -540, 0},
267 {"KST",
268 {'K','o','r','e','a',' ','S','t','a','n','d','a','r','d',' ','T','i','m',
269 'e','\0'}, -540, 0},
270 {"YAKST",
271 {'Y','a','k','u','t','s','k',' ','S','t','a','n','d','a','r','d',' ','T',
272 'i','m','e','\0'}, -600, 1},
273 {"CST",
274 {'C','e','n','.',' ','A','u','s','t','r','a','l','i','a',' ','S','t','a',
275 'n','d','a','r','d',' ','T','i','m','e','\0'}, -570, 0},
276 {"EST",
277 {'E','.',' ','A','u','s','t','r','a','l','i','a',' ','S','t','a','n','d',
278 'a','r','d',' ','T','i','m','e','\0'}, -600, 0},
279 {"GST",
280 {'W','e','s','t',' ','P','a','c','i','f','i','c',' ','S','t','a','n','d',
281 'a','r','d',' ','T','i','m','e','\0'}, -600, 0},
282 {"VLAST",
283 {'V','l','a','d','i','v','o','s','t','o','k',' ','S','t','a','n','d','a',
284 'r','d',' ','T','i','m','e','\0'}, -660, 1},
285 {"MAGST",
286 {'C','e','n','t','r','a','l',' ','P','a','c','i','f','i','c',' ','S','t',
287 'a','n','d','a','r','d',' ','T','i','m','e','\0'}, -720, 1},
288 {"NZST",
289 {'N','e','w',' ','Z','e','a','l','a','n','d',' ','S','t','a','n','d','a',
290 'r','d',' ','T','i','m','e','\0'}, -720, 0},
291 {"FJT",
292 {'F','i','j','i',' ','S','t','a','n','d','a','r','d',' ','T','i','m','e',
293 '\0'}, -720, 0},
294 {"TOT",
295 {'T','o','n','g','a',' ','S','t','a','n','d','a','r','d',' ','T','i','m',
296 'e','\0'}, -780, 0}
297};
298
Juergen Schmied026d9db1999-03-09 17:47:51 +0000299#define TICKSPERSEC 10000000
300#define TICKSPERMSEC 10000
301#define SECSPERDAY 86400
302#define SECSPERHOUR 3600
303#define SECSPERMIN 60
304#define MINSPERHOUR 60
305#define HOURSPERDAY 24
Alexandre Julliarddcc3afd2002-12-13 20:53:04 +0000306#define EPOCHWEEKDAY 1 /* Jan 1, 1601 was Monday */
Juergen Schmied026d9db1999-03-09 17:47:51 +0000307#define DAYSPERWEEK 7
308#define EPOCHYEAR 1601
309#define DAYSPERNORMALYEAR 365
310#define DAYSPERLEAPYEAR 366
311#define MONSPERYEAR 12
Huw Davies166faa42004-02-24 01:01:27 +0000312#define DAYSPERQUADRICENTENNIUM (365 * 400 + 97)
313#define DAYSPERNORMALCENTURY (365 * 100 + 24)
314#define DAYSPERNORMALQUADRENNIUM (365 * 4 + 1)
Juergen Schmied026d9db1999-03-09 17:47:51 +0000315
Alexandre Julliardd76f9f92000-10-01 01:40:42 +0000316/* 1601 to 1970 is 369 years plus 89 leap days */
Alexandre Julliardfbef57c2003-03-31 01:37:04 +0000317#define SECS_1601_TO_1970 ((369 * 365 + 89) * (ULONGLONG)SECSPERDAY)
318#define TICKS_1601_TO_1970 (SECS_1601_TO_1970 * TICKSPERSEC)
Alexandre Julliardd76f9f92000-10-01 01:40:42 +0000319/* 1601 to 1980 is 379 years plus 91 leap days */
Alexandre Julliardfbef57c2003-03-31 01:37:04 +0000320#define SECS_1601_TO_1980 ((379 * 365 + 91) * (ULONGLONG)SECSPERDAY)
321#define TICKS_1601_TO_1980 (SECS_1601_TO_1980 * TICKSPERSEC)
Alexandre Julliard25b23a02004-09-07 23:01:34 +0000322/* max ticks that can be represented as Unix time */
323#define TICKS_1601_TO_UNIX_MAX ((SECS_1601_TO_1970 + INT_MAX) * TICKSPERSEC)
Alexandre Julliardd76f9f92000-10-01 01:40:42 +0000324
325
Juergen Schmied026d9db1999-03-09 17:47:51 +0000326static const int MonthLengths[2][MONSPERYEAR] =
327{
328 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
329 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
330};
331
Alexandre Julliard9aef0772004-04-02 20:28:07 +0000332static const int YearDays[2][MONSPERYEAR+1] =
333{
334 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
335 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
336};
337
Patrik Stridvall896889f1999-05-08 12:50:36 +0000338static inline int IsLeapYear(int Year)
Juergen Schmied026d9db1999-03-09 17:47:51 +0000339{
340 return Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0) ? 1 : 0;
341}
342
Patrik Stridvall896889f1999-05-08 12:50:36 +0000343static inline void NormalizeTimeFields(CSHORT *FieldToNormalize, CSHORT *CarryField,int Modulus)
Juergen Schmied026d9db1999-03-09 17:47:51 +0000344{
345 *FieldToNormalize = (CSHORT) (*FieldToNormalize - Modulus);
346 *CarryField = (CSHORT) (*CarryField + 1);
347}
348
Alexandre Julliardfbef57c2003-03-31 01:37:04 +0000349/***********************************************************************
350 * NTDLL_get_server_timeout
351 *
352 * Convert a NTDLL timeout into a timeval struct to send to the server.
353 */
Alexandre Julliard462172a2003-04-02 22:48:59 +0000354void NTDLL_get_server_timeout( abs_time_t *when, const LARGE_INTEGER *timeout )
Alexandre Julliardfbef57c2003-03-31 01:37:04 +0000355{
356 UINT remainder;
357
358 if (!timeout) /* infinite timeout */
359 {
Alexandre Julliard462172a2003-04-02 22:48:59 +0000360 when->sec = when->usec = 0;
Alexandre Julliardfbef57c2003-03-31 01:37:04 +0000361 }
362 else if (timeout->QuadPart <= 0) /* relative timeout */
363 {
Alexandre Julliard462172a2003-04-02 22:48:59 +0000364 struct timeval tv;
Alexandre Julliard25b23a02004-09-07 23:01:34 +0000365
366 if (-timeout->QuadPart > (LONGLONG)INT_MAX * TICKSPERSEC)
367 when->sec = when->usec = INT_MAX;
368 else
Alexandre Julliardfbef57c2003-03-31 01:37:04 +0000369 {
Alexandre Julliard25b23a02004-09-07 23:01:34 +0000370 ULONG sec = RtlEnlargedUnsignedDivide( -timeout->QuadPart, TICKSPERSEC, &remainder );
371 gettimeofday( &tv, 0 );
372 when->sec = tv.tv_sec + sec;
373 if ((when->usec = tv.tv_usec + (remainder / 10)) >= 1000000)
374 {
375 when->usec -= 1000000;
376 when->sec++;
377 }
378 if (when->sec < tv.tv_sec) /* overflow */
379 when->sec = when->usec = INT_MAX;
Alexandre Julliardfbef57c2003-03-31 01:37:04 +0000380 }
Alexandre Julliardfbef57c2003-03-31 01:37:04 +0000381 }
382 else /* absolute time */
383 {
Alexandre Julliard25b23a02004-09-07 23:01:34 +0000384 if (timeout->QuadPart < TICKS_1601_TO_1970)
385 when->sec = when->usec = 0;
386 else if (timeout->QuadPart > TICKS_1601_TO_UNIX_MAX)
387 when->sec = when->usec = INT_MAX;
388 else
389 {
390 when->sec = RtlEnlargedUnsignedDivide( timeout->QuadPart - TICKS_1601_TO_1970,
391 TICKSPERSEC, &remainder );
392 when->usec = remainder / 10;
393 }
Alexandre Julliardfbef57c2003-03-31 01:37:04 +0000394 }
395}
396
397
Juergen Schmied026d9db1999-03-09 17:47:51 +0000398/******************************************************************************
György 'Nog' Jeney6f3015b2002-11-25 01:12:39 +0000399 * RtlTimeToTimeFields [NTDLL.@]
Juergen Schmied026d9db1999-03-09 17:47:51 +0000400 *
Jon Griffiths08922852003-08-19 00:56:34 +0000401 * Convert a time into a TIME_FIELDS structure.
György 'Nog' Jeney6f3015b2002-11-25 01:12:39 +0000402 *
Jon Griffithscd4234a2003-03-18 18:35:48 +0000403 * PARAMS
Jon Griffiths08922852003-08-19 00:56:34 +0000404 * liTime [I] Time to convert.
405 * TimeFields [O] Destination for the converted time.
György 'Nog' Jeney6f3015b2002-11-25 01:12:39 +0000406 *
Jon Griffithscd4234a2003-03-18 18:35:48 +0000407 * RETURNS
György 'Nog' Jeney6f3015b2002-11-25 01:12:39 +0000408 * Nothing.
Juergen Schmied026d9db1999-03-09 17:47:51 +0000409 */
Juergen Schmied026d9db1999-03-09 17:47:51 +0000410VOID WINAPI RtlTimeToTimeFields(
György 'Nog' Jeney6f3015b2002-11-25 01:12:39 +0000411 const LARGE_INTEGER *liTime,
Juergen Schmied026d9db1999-03-09 17:47:51 +0000412 PTIME_FIELDS TimeFields)
413{
Huw Davies166faa42004-02-24 01:01:27 +0000414 int SecondsInDay, DeltaYear;
György 'Nog' Jeney39433b92002-11-06 21:57:23 +0000415 int LeapYear, CurMonth;
Juergen Schmied026d9db1999-03-09 17:47:51 +0000416 long int Days;
Alexandre Julliarddcc3afd2002-12-13 20:53:04 +0000417 LONGLONG Time = liTime->QuadPart;
Juergen Schmied026d9db1999-03-09 17:47:51 +0000418
419 /* Extract millisecond from time and convert time into seconds */
420 TimeFields->Milliseconds = (CSHORT) ((Time % TICKSPERSEC) / TICKSPERMSEC);
421 Time = Time / TICKSPERSEC;
422
György 'Nog' Jeney39433b92002-11-06 21:57:23 +0000423 /* The native version of RtlTimeToTimeFields does not take leap seconds
424 * into account */
Juergen Schmied026d9db1999-03-09 17:47:51 +0000425
426 /* Split the time into days and seconds within the day */
427 Days = Time / SECSPERDAY;
428 SecondsInDay = Time % SECSPERDAY;
429
Juergen Schmied026d9db1999-03-09 17:47:51 +0000430 /* compute time of day */
431 TimeFields->Hour = (CSHORT) (SecondsInDay / SECSPERHOUR);
432 SecondsInDay = SecondsInDay % SECSPERHOUR;
433 TimeFields->Minute = (CSHORT) (SecondsInDay / SECSPERMIN);
434 TimeFields->Second = (CSHORT) (SecondsInDay % SECSPERMIN);
435
Juergen Schmied026d9db1999-03-09 17:47:51 +0000436 /* compute day of week */
437 TimeFields->Weekday = (CSHORT) ((EPOCHWEEKDAY + Days) % DAYSPERWEEK);
438
439 /* compute year */
Juergen Schmied026d9db1999-03-09 17:47:51 +0000440 /* FIXME: handle calendar modifications */
Huw Davies166faa42004-02-24 01:01:27 +0000441 TimeFields->Year = EPOCHYEAR;
442 DeltaYear = Days / DAYSPERQUADRICENTENNIUM;
443 TimeFields->Year += DeltaYear * 400;
444 Days -= DeltaYear * DAYSPERQUADRICENTENNIUM;
445 DeltaYear = Days / DAYSPERNORMALCENTURY;
446 TimeFields->Year += DeltaYear * 100;
447 Days -= DeltaYear * DAYSPERNORMALCENTURY;
448 DeltaYear = Days / DAYSPERNORMALQUADRENNIUM;
449 TimeFields->Year += DeltaYear * 4;
450 Days -= DeltaYear * DAYSPERNORMALQUADRENNIUM;
451 DeltaYear = Days / DAYSPERNORMALYEAR;
452 TimeFields->Year += DeltaYear;
453 Days -= DeltaYear * DAYSPERNORMALYEAR;
454
455 LeapYear = IsLeapYear(TimeFields->Year);
Juergen Schmied026d9db1999-03-09 17:47:51 +0000456
457 /* Compute month of year */
Alexandre Julliard9aef0772004-04-02 20:28:07 +0000458 CurMonth = 1;
459 while (Days >= YearDays[LeapYear][CurMonth]) CurMonth++;
460 TimeFields->Day = Days - YearDays[LeapYear][CurMonth-1] + 1;
461 TimeFields->Month = CurMonth;
Juergen Schmied026d9db1999-03-09 17:47:51 +0000462}
György 'Nog' Jeney39433b92002-11-06 21:57:23 +0000463
Juergen Schmied026d9db1999-03-09 17:47:51 +0000464/******************************************************************************
György 'Nog' Jeney6f3015b2002-11-25 01:12:39 +0000465 * RtlTimeFieldsToTime [NTDLL.@]
Juergen Schmied026d9db1999-03-09 17:47:51 +0000466 *
Jon Griffiths08922852003-08-19 00:56:34 +0000467 * Convert a TIME_FIELDS structure into a time.
György 'Nog' Jeney6f3015b2002-11-25 01:12:39 +0000468 *
Jon Griffithscd4234a2003-03-18 18:35:48 +0000469 * PARAMS
Jon Griffiths08922852003-08-19 00:56:34 +0000470 * ftTimeFields [I] TIME_FIELDS structure to convert.
471 * Time [O] Destination for the converted time.
György 'Nog' Jeney6f3015b2002-11-25 01:12:39 +0000472 *
Jon Griffithscd4234a2003-03-18 18:35:48 +0000473 * RETURNS
Jon Griffiths08922852003-08-19 00:56:34 +0000474 * Success: TRUE.
475 * Failure: FALSE.
Juergen Schmied026d9db1999-03-09 17:47:51 +0000476 */
477BOOLEAN WINAPI RtlTimeFieldsToTime(
478 PTIME_FIELDS tfTimeFields,
479 PLARGE_INTEGER Time)
480{
Alexandre Julliard9aef0772004-04-02 20:28:07 +0000481 int CurYear, DeltaYear;
Patrik Stridvallef0e2af2002-08-27 18:17:49 +0000482 LONGLONG rcTime;
Juergen Schmied026d9db1999-03-09 17:47:51 +0000483 TIME_FIELDS TimeFields = *tfTimeFields;
484
485 rcTime = 0;
486
487 /* FIXME: normalize the TIME_FIELDS structure here */
488 while (TimeFields.Second >= SECSPERMIN)
489 { NormalizeTimeFields(&TimeFields.Second, &TimeFields.Minute, SECSPERMIN);
490 }
491 while (TimeFields.Minute >= MINSPERHOUR)
492 { NormalizeTimeFields(&TimeFields.Minute, &TimeFields.Hour, MINSPERHOUR);
493 }
494 while (TimeFields.Hour >= HOURSPERDAY)
495 { NormalizeTimeFields(&TimeFields.Hour, &TimeFields.Day, HOURSPERDAY);
496 }
497 while (TimeFields.Day > MonthLengths[IsLeapYear(TimeFields.Year)][TimeFields.Month - 1])
Alexandre Julliard9aef0772004-04-02 20:28:07 +0000498 { NormalizeTimeFields(&TimeFields.Day, &TimeFields.Month,
499 MonthLengths[IsLeapYear(TimeFields.Year)][TimeFields.Month - 1]);
Juergen Schmied026d9db1999-03-09 17:47:51 +0000500 }
501 while (TimeFields.Month > MONSPERYEAR)
502 { NormalizeTimeFields(&TimeFields.Month, &TimeFields.Year, MONSPERYEAR);
503 }
504
505 /* FIXME: handle calendar corrections here */
Huw Daviesf66af592004-02-25 01:25:00 +0000506 CurYear = TimeFields.Year - EPOCHYEAR;
507 DeltaYear = CurYear / 400;
508 CurYear -= DeltaYear * 400;
509 rcTime += DeltaYear * DAYSPERQUADRICENTENNIUM;
510 DeltaYear = CurYear / 100;
511 CurYear -= DeltaYear * 100;
512 rcTime += DeltaYear * DAYSPERNORMALCENTURY;
513 DeltaYear = CurYear / 4;
514 CurYear -= DeltaYear * 4;
515 rcTime += DeltaYear * DAYSPERNORMALQUADRENNIUM;
516 rcTime += CurYear * DAYSPERNORMALYEAR;
Alexandre Julliard9aef0772004-04-02 20:28:07 +0000517 rcTime += YearDays[IsLeapYear(TimeFields.Year)][TimeFields.Month - 1];
Juergen Schmied026d9db1999-03-09 17:47:51 +0000518 rcTime += TimeFields.Day - 1;
519 rcTime *= SECSPERDAY;
520 rcTime += TimeFields.Hour * SECSPERHOUR + TimeFields.Minute * SECSPERMIN + TimeFields.Second;
521 rcTime *= TICKSPERSEC;
522 rcTime += TimeFields.Milliseconds * TICKSPERMSEC;
Alexandre Julliarddcc3afd2002-12-13 20:53:04 +0000523 Time->QuadPart = rcTime;
Juergen Schmied026d9db1999-03-09 17:47:51 +0000524
525 return TRUE;
526}
György 'Nog' Jeney6f3015b2002-11-25 01:12:39 +0000527
Huw Davies64ed8482004-02-26 05:26:34 +0000528/***********************************************************************
529 * TIME_GetBias [internal]
530 *
531 * Helper function calculates delta local time from UTC.
532 *
533 * PARAMS
534 * utc [I] The current utc time.
535 * pdaylight [I] Local daylight.
536 *
537 * RETURNS
538 * The bias for the current timezone.
539 */
540static int TIME_GetBias(time_t utc, int *pdaylight)
541{
Huw Davies67e2d6c2004-02-27 00:43:20 +0000542 struct tm *ptm;
543 static time_t last_utc;
544 static int last_bias;
Rein Klazes50403092004-03-01 21:23:18 +0000545 static int last_daylight;
Huw Davies67e2d6c2004-02-27 00:43:20 +0000546 int ret;
547
548 RtlEnterCriticalSection( &TIME_GetBias_section );
549 if(utc == last_utc)
Rein Klazes50403092004-03-01 21:23:18 +0000550 {
551 *pdaylight = last_daylight;
Huw Davies67e2d6c2004-02-27 00:43:20 +0000552 ret = last_bias;
Rein Klazes50403092004-03-01 21:23:18 +0000553 } else
Huw Davies67e2d6c2004-02-27 00:43:20 +0000554 {
555 ptm = localtime(&utc);
Rein Klazes50403092004-03-01 21:23:18 +0000556 *pdaylight = last_daylight =
557 ptm->tm_isdst; /* daylight for local timezone */
Huw Davies67e2d6c2004-02-27 00:43:20 +0000558 ptm = gmtime(&utc);
559 ptm->tm_isdst = *pdaylight; /* use local daylight, not that of Greenwich */
560 last_utc = utc;
561 ret = last_bias = (int)(utc-mktime(ptm));
562 }
563 RtlLeaveCriticalSection( &TIME_GetBias_section );
564 return ret;
Huw Davies64ed8482004-02-26 05:26:34 +0000565}
566
György 'Nog' Jeney4d6ba252002-12-11 00:19:56 +0000567/******************************************************************************
568 * RtlLocalTimeToSystemTime [NTDLL.@]
569 *
Jon Griffiths08922852003-08-19 00:56:34 +0000570 * Convert a local time into system time.
György 'Nog' Jeney4d6ba252002-12-11 00:19:56 +0000571 *
Jon Griffithscd4234a2003-03-18 18:35:48 +0000572 * PARAMS
Jon Griffiths08922852003-08-19 00:56:34 +0000573 * LocalTime [I] Local time to convert.
574 * SystemTime [O] Destination for the converted time.
György 'Nog' Jeney4d6ba252002-12-11 00:19:56 +0000575 *
Jon Griffithscd4234a2003-03-18 18:35:48 +0000576 * RETURNS
Jon Griffiths08922852003-08-19 00:56:34 +0000577 * Success: STATUS_SUCCESS.
578 * Failure: An NTSTATUS error code indicating the problem.
György 'Nog' Jeney4d6ba252002-12-11 00:19:56 +0000579 */
580NTSTATUS WINAPI RtlLocalTimeToSystemTime( const LARGE_INTEGER *LocalTime,
581 PLARGE_INTEGER SystemTime)
582{
Huw Davies64ed8482004-02-26 05:26:34 +0000583 time_t gmt;
584 int bias, daylight;
György 'Nog' Jeney4d6ba252002-12-11 00:19:56 +0000585
586 TRACE("(%p, %p)\n", LocalTime, SystemTime);
587
Huw Davies64ed8482004-02-26 05:26:34 +0000588 gmt = time(NULL);
589 bias = TIME_GetBias(gmt, &daylight);
590
591 SystemTime->QuadPart = LocalTime->QuadPart - bias * (LONGLONG)10000000;
György 'Nog' Jeney4d6ba252002-12-11 00:19:56 +0000592 return STATUS_SUCCESS;
593}
Juergen Schmied026d9db1999-03-09 17:47:51 +0000594
595/******************************************************************************
György 'Nog' Jeney6f3015b2002-11-25 01:12:39 +0000596 * RtlSystemTimeToLocalTime [NTDLL.@]
597 *
Jon Griffiths08922852003-08-19 00:56:34 +0000598 * Convert a system time into a local time.
György 'Nog' Jeney6f3015b2002-11-25 01:12:39 +0000599 *
Jon Griffithscd4234a2003-03-18 18:35:48 +0000600 * PARAMS
601 * SystemTime [I] System time to convert.
Jon Griffiths08922852003-08-19 00:56:34 +0000602 * LocalTime [O] Destination for the converted time.
György 'Nog' Jeney6f3015b2002-11-25 01:12:39 +0000603 *
Jon Griffithscd4234a2003-03-18 18:35:48 +0000604 * RETURNS
Jon Griffiths08922852003-08-19 00:56:34 +0000605 * Success: STATUS_SUCCESS.
606 * Failure: An NTSTATUS error code indicating the problem.
Juergen Schmied026d9db1999-03-09 17:47:51 +0000607 */
György 'Nog' Jeney4d6ba252002-12-11 00:19:56 +0000608NTSTATUS WINAPI RtlSystemTimeToLocalTime( const LARGE_INTEGER *SystemTime,
609 PLARGE_INTEGER LocalTime )
Juergen Schmied026d9db1999-03-09 17:47:51 +0000610{
Huw Davies64ed8482004-02-26 05:26:34 +0000611 time_t gmt;
612 int bias, daylight;
Juergen Schmied026d9db1999-03-09 17:47:51 +0000613
György 'Nog' Jeney4d6ba252002-12-11 00:19:56 +0000614 TRACE("(%p, %p)\n", SystemTime, LocalTime);
615
Huw Davies64ed8482004-02-26 05:26:34 +0000616 gmt = time(NULL);
617 bias = TIME_GetBias(gmt, &daylight);
618
619 LocalTime->QuadPart = SystemTime->QuadPart + bias * (LONGLONG)10000000;
György 'Nog' Jeney4d6ba252002-12-11 00:19:56 +0000620 return STATUS_SUCCESS;
Juergen Schmied026d9db1999-03-09 17:47:51 +0000621}
Juergen Schmied026d9db1999-03-09 17:47:51 +0000622
623/******************************************************************************
György 'Nog' Jeney6f3015b2002-11-25 01:12:39 +0000624 * RtlTimeToSecondsSince1970 [NTDLL.@]
625 *
Jon Griffiths08922852003-08-19 00:56:34 +0000626 * Convert a time into a count of seconds since 1970.
György 'Nog' Jeney6f3015b2002-11-25 01:12:39 +0000627 *
Jon Griffithscd4234a2003-03-18 18:35:48 +0000628 * PARAMS
Jon Griffiths08922852003-08-19 00:56:34 +0000629 * Time [I] Time to convert.
630 * Seconds [O] Destination for the converted time.
György 'Nog' Jeney6f3015b2002-11-25 01:12:39 +0000631 *
Jon Griffithscd4234a2003-03-18 18:35:48 +0000632 * RETURNS
Jon Griffiths08922852003-08-19 00:56:34 +0000633 * Success: TRUE.
634 * Failure: FALSE, if the resulting value will not fit in a DWORD.
Juergen Schmied026d9db1999-03-09 17:47:51 +0000635 */
Jon Griffiths08922852003-08-19 00:56:34 +0000636BOOLEAN WINAPI RtlTimeToSecondsSince1970( const LARGE_INTEGER *Time, LPDWORD Seconds )
Juergen Schmied026d9db1999-03-09 17:47:51 +0000637{
Ge van Geldorp399901e2004-01-23 01:51:33 +0000638 ULONGLONG tmp = ((ULONGLONG)Time->u.HighPart << 32) | Time->u.LowPart;
Patrik Stridvallef0e2af2002-08-27 18:17:49 +0000639 tmp = RtlLargeIntegerDivide( tmp, 10000000, NULL );
Alexandre Julliardd76f9f92000-10-01 01:40:42 +0000640 tmp -= SECS_1601_TO_1970;
641 if (tmp > 0xffffffff) return FALSE;
Jon Griffiths08922852003-08-19 00:56:34 +0000642 *Seconds = (DWORD)tmp;
Alexandre Julliard0aa6cc22000-07-29 21:56:59 +0000643 return TRUE;
644}
645
646/******************************************************************************
György 'Nog' Jeney6f3015b2002-11-25 01:12:39 +0000647 * RtlTimeToSecondsSince1980 [NTDLL.@]
648 *
Jon Griffiths08922852003-08-19 00:56:34 +0000649 * Convert a time into a count of seconds since 1980.
György 'Nog' Jeney6f3015b2002-11-25 01:12:39 +0000650 *
Jon Griffithscd4234a2003-03-18 18:35:48 +0000651 * PARAMS
Jon Griffiths08922852003-08-19 00:56:34 +0000652 * Time [I] Time to convert.
653 * Seconds [O] Destination for the converted time.
György 'Nog' Jeney6f3015b2002-11-25 01:12:39 +0000654 *
Jon Griffithscd4234a2003-03-18 18:35:48 +0000655 * RETURNS
Jon Griffiths08922852003-08-19 00:56:34 +0000656 * Success: TRUE.
657 * Failure: FALSE, if the resulting value will not fit in a DWORD.
Alexandre Julliard0aa6cc22000-07-29 21:56:59 +0000658 */
Jon Griffiths08922852003-08-19 00:56:34 +0000659BOOLEAN WINAPI RtlTimeToSecondsSince1980( const LARGE_INTEGER *Time, LPDWORD Seconds )
Alexandre Julliard0aa6cc22000-07-29 21:56:59 +0000660{
Ge van Geldorp399901e2004-01-23 01:51:33 +0000661 ULONGLONG tmp = ((ULONGLONG)Time->u.HighPart << 32) | Time->u.LowPart;
Patrik Stridvallef0e2af2002-08-27 18:17:49 +0000662 tmp = RtlLargeIntegerDivide( tmp, 10000000, NULL );
Alexandre Julliardfbef57c2003-03-31 01:37:04 +0000663 tmp -= SECS_1601_TO_1980;
Alexandre Julliardd76f9f92000-10-01 01:40:42 +0000664 if (tmp > 0xffffffff) return FALSE;
Jon Griffiths08922852003-08-19 00:56:34 +0000665 *Seconds = (DWORD)tmp;
Alexandre Julliard0aa6cc22000-07-29 21:56:59 +0000666 return TRUE;
667}
668
669/******************************************************************************
György 'Nog' Jeney6f3015b2002-11-25 01:12:39 +0000670 * RtlSecondsSince1970ToTime [NTDLL.@]
671 *
Jon Griffiths08922852003-08-19 00:56:34 +0000672 * Convert a count of seconds since 1970 to a time.
György 'Nog' Jeney6f3015b2002-11-25 01:12:39 +0000673 *
Jon Griffithscd4234a2003-03-18 18:35:48 +0000674 * PARAMS
Jon Griffiths08922852003-08-19 00:56:34 +0000675 * Seconds [I] Time to convert.
676 * Time [O] Destination for the converted time.
György 'Nog' Jeney6f3015b2002-11-25 01:12:39 +0000677 *
Jon Griffithscd4234a2003-03-18 18:35:48 +0000678 * RETURNS
György 'Nog' Jeney6f3015b2002-11-25 01:12:39 +0000679 * Nothing.
Alexandre Julliard0aa6cc22000-07-29 21:56:59 +0000680 */
Jon Griffiths08922852003-08-19 00:56:34 +0000681void WINAPI RtlSecondsSince1970ToTime( DWORD Seconds, LARGE_INTEGER *Time )
Alexandre Julliard0aa6cc22000-07-29 21:56:59 +0000682{
Jon Griffiths08922852003-08-19 00:56:34 +0000683 ULONGLONG secs = Seconds * (ULONGLONG)TICKSPERSEC + TICKS_1601_TO_1970;
Ge van Geldorp399901e2004-01-23 01:51:33 +0000684 Time->u.LowPart = (DWORD)secs;
685 Time->u.HighPart = (DWORD)(secs >> 32);
Alexandre Julliard0aa6cc22000-07-29 21:56:59 +0000686}
687
688/******************************************************************************
György 'Nog' Jeney6f3015b2002-11-25 01:12:39 +0000689 * RtlSecondsSince1980ToTime [NTDLL.@]
690 *
Jon Griffiths08922852003-08-19 00:56:34 +0000691 * Convert a count of seconds since 1980 to a time.
György 'Nog' Jeney6f3015b2002-11-25 01:12:39 +0000692 *
Jon Griffithscd4234a2003-03-18 18:35:48 +0000693 * PARAMS
Jon Griffiths08922852003-08-19 00:56:34 +0000694 * Seconds [I] Time to convert.
695 * Time [O] Destination for the converted time.
György 'Nog' Jeney6f3015b2002-11-25 01:12:39 +0000696 *
Jon Griffithscd4234a2003-03-18 18:35:48 +0000697 * RETURNS
György 'Nog' Jeney6f3015b2002-11-25 01:12:39 +0000698 * Nothing.
Alexandre Julliard0aa6cc22000-07-29 21:56:59 +0000699 */
Jon Griffiths08922852003-08-19 00:56:34 +0000700void WINAPI RtlSecondsSince1980ToTime( DWORD Seconds, LARGE_INTEGER *Time )
Alexandre Julliard0aa6cc22000-07-29 21:56:59 +0000701{
Jon Griffiths08922852003-08-19 00:56:34 +0000702 ULONGLONG secs = Seconds * (ULONGLONG)TICKSPERSEC + TICKS_1601_TO_1980;
Ge van Geldorp399901e2004-01-23 01:51:33 +0000703 Time->u.LowPart = (DWORD)secs;
704 Time->u.HighPart = (DWORD)(secs >> 32);
Juergen Schmied026d9db1999-03-09 17:47:51 +0000705}
706
707/******************************************************************************
György 'Nog' Jeney6f3015b2002-11-25 01:12:39 +0000708 * RtlTimeToElapsedTimeFields [NTDLL.@]
709 *
Jon Griffiths08922852003-08-19 00:56:34 +0000710 * Convert a time to a count of elapsed seconds.
711 *
712 * PARAMS
713 * Time [I] Time to convert.
714 * TimeFields [O] Destination for the converted time.
715 *
Jon Griffithscd4234a2003-03-18 18:35:48 +0000716 * RETURNS
György 'Nog' Jeney6f3015b2002-11-25 01:12:39 +0000717 * Nothing.
Juergen Schmied026d9db1999-03-09 17:47:51 +0000718 */
Alexandre Julliarda16ed902002-12-18 02:31:33 +0000719void WINAPI RtlTimeToElapsedTimeFields( const LARGE_INTEGER *Time, PTIME_FIELDS TimeFields )
Juergen Schmied026d9db1999-03-09 17:47:51 +0000720{
Alexandre Julliarda16ed902002-12-18 02:31:33 +0000721 LONGLONG time;
722 UINT rem;
723
724 time = RtlExtendedLargeIntegerDivide( Time->QuadPart, TICKSPERSEC, &rem );
725 TimeFields->Milliseconds = rem / TICKSPERMSEC;
726
727 /* time is now in seconds */
728 TimeFields->Year = 0;
729 TimeFields->Month = 0;
730 TimeFields->Day = RtlExtendedLargeIntegerDivide( time, SECSPERDAY, &rem );
731
732 /* rem is now the remaining seconds in the last day */
733 TimeFields->Second = rem % 60;
734 rem /= 60;
735 TimeFields->Minute = rem % 60;
736 TimeFields->Hour = rem / 60;
Juergen Schmied026d9db1999-03-09 17:47:51 +0000737}
Alexandre Julliardd76f9f92000-10-01 01:40:42 +0000738
739/***********************************************************************
György 'Nog' Jeney6f3015b2002-11-25 01:12:39 +0000740 * NtQuerySystemTime [NTDLL.@]
741 * ZwQuerySystemTime [NTDLL.@]
742 *
Jon Griffiths08922852003-08-19 00:56:34 +0000743 * Get the current system time.
György 'Nog' Jeney6f3015b2002-11-25 01:12:39 +0000744 *
Jon Griffithscd4234a2003-03-18 18:35:48 +0000745 * PARAMS
Jon Griffiths08922852003-08-19 00:56:34 +0000746 * Time [O] Destination for the current system time.
György 'Nog' Jeney6f3015b2002-11-25 01:12:39 +0000747 *
Jon Griffithscd4234a2003-03-18 18:35:48 +0000748 * RETURNS
Jon Griffiths08922852003-08-19 00:56:34 +0000749 * Success: STATUS_SUCCESS.
750 * Failure: An NTSTATUS error code indicating the problem.
Alexandre Julliardd76f9f92000-10-01 01:40:42 +0000751 */
Jon Griffiths08922852003-08-19 00:56:34 +0000752NTSTATUS WINAPI NtQuerySystemTime( PLARGE_INTEGER Time )
Alexandre Julliardd76f9f92000-10-01 01:40:42 +0000753{
Alexandre Julliardd76f9f92000-10-01 01:40:42 +0000754 struct timeval now;
755
756 gettimeofday( &now, 0 );
Jon Griffiths08922852003-08-19 00:56:34 +0000757 Time->QuadPart = now.tv_sec * (ULONGLONG)TICKSPERSEC + TICKS_1601_TO_1970;
758 Time->QuadPart += now.tv_usec * 10;
Patrik Stridvall9c1de6d2002-09-12 22:07:02 +0000759 return STATUS_SUCCESS;
Alexandre Julliardd76f9f92000-10-01 01:40:42 +0000760}
György 'Nog' Jeney6f3015b2002-11-25 01:12:39 +0000761
762/***********************************************************************
György 'Nog' Jeney6f3015b2002-11-25 01:12:39 +0000763 * TIME_GetTZAsStr [internal]
764 *
765 * Helper function that returns the given timezone as a string.
766 *
Jon Griffithscd4234a2003-03-18 18:35:48 +0000767 * PARAMS
768 * utc [I] The current utc time.
769 * bias [I] The bias of the current timezone.
770 * dst [I] ??
György 'Nog' Jeney6f3015b2002-11-25 01:12:39 +0000771 *
Jon Griffithscd4234a2003-03-18 18:35:48 +0000772 * RETURNS
György 'Nog' Jeney6f3015b2002-11-25 01:12:39 +0000773 * Timezone name.
774 *
775 * NOTES:
776 * This could be done with a hash table instead of merely iterating through a
777 * table, however with the small amount of entries (60 or so) I didn't think
778 * it was worth it.
779 */
780static const WCHAR* TIME_GetTZAsStr (time_t utc, int bias, int dst)
781{
782 char psTZName[7];
783 struct tm *ptm = localtime(&utc);
Hans Leidekkera9b4a472004-08-13 23:53:44 +0000784 unsigned int i;
György 'Nog' Jeney6f3015b2002-11-25 01:12:39 +0000785
786 if (!strftime (psTZName, 7, "%Z", ptm))
787 return (NULL);
788
789 for (i=0; i<(sizeof(TZ_INFO) / sizeof(struct tagTZ_INFO)); i++)
790 {
791 if ( strcmp(TZ_INFO[i].psTZFromUnix, psTZName) == 0 &&
792 TZ_INFO[i].bias == bias &&
793 TZ_INFO[i].dst == dst
794 )
795 return TZ_INFO[i].psTZWindows;
796 }
Uwe Bonnesd3499082004-09-06 21:26:37 +0000797 FIXME("Can't match system time zone name \"%s\" to an entry in TZ_INFO\n",psTZName);
798 FIXME(" Please add appropriate entry to TZ_INFO and submit as patch to wine-patches\n");
Jon Griffiths08922852003-08-19 00:56:34 +0000799 return NULL;
György 'Nog' Jeney6f3015b2002-11-25 01:12:39 +0000800}
801
Rein Klazesc5c93d12004-10-18 21:19:28 +0000802/*** TIME_GetTimeZoneInfoFromReg: helper for GetTimeZoneInformation ***/
803
804
805static int TIME_GetTimeZoneInfoFromReg(LPTIME_ZONE_INFORMATION tzinfo)
806{
807 BYTE buf[90];
808 KEY_VALUE_PARTIAL_INFORMATION * KpInfo =
809 (KEY_VALUE_PARTIAL_INFORMATION *) buf;
810 HKEY hkey;
811 DWORD size;
812 OBJECT_ATTRIBUTES attr;
813 UNICODE_STRING nameW;
814
815 attr.Length = sizeof(attr);
816 attr.RootDirectory = 0;
817 attr.ObjectName = &nameW;
818 attr.Attributes = 0;
819 attr.SecurityDescriptor = NULL;
820 attr.SecurityQualityOfService = NULL;
821 RtlInitUnicodeString( &nameW, TZInformationKeyW);
822 if (!NtOpenKey( &hkey, KEY_ALL_ACCESS, &attr )) {
823
824#define GTZIFR_N( valkey, tofield) \
825 RtlInitUnicodeString( &nameW, valkey );\
826 if (!NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, KpInfo,\
827 sizeof(buf), &size )) { \
828 if( size >= (sizeof((tofield)) + \
829 offsetof(KEY_VALUE_PARTIAL_INFORMATION,Data))); { \
830 memcpy(&(tofield), \
831 KpInfo->Data, sizeof(tofield)); \
832 } \
833 }
834#define GTZIFR_S( valkey, tofield) \
835 RtlInitUnicodeString( &nameW, valkey );\
836 if (!NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, KpInfo,\
837 sizeof(buf), &size )) { \
838 strncpyW( tofield, (WCHAR*) KpInfo->Data, \
839 sizeof( tofield) / sizeof(WCHAR) ); \
840 }
841
842 GTZIFR_N( TZStandardStartW, tzinfo->StandardDate)
843 GTZIFR_N( TZDaylightStartW, tzinfo->DaylightDate)
844 GTZIFR_N( TZBiasW, tzinfo->Bias)
845 GTZIFR_N( TZStandardBiasW, tzinfo->StandardBias)
846 GTZIFR_N( TZDaylightBiasW, tzinfo->DaylightBias)
847 GTZIFR_S( TZStandardNameW, tzinfo->StandardName)
848 GTZIFR_S( TZDaylightNameW, tzinfo->DaylightName)
849
850#undef GTZIFR_N
851#undef GTZIFR_S
852 NtClose( hkey );
853 return 1;
854 }
855 return 0;
856}
857
György 'Nog' Jeney6f3015b2002-11-25 01:12:39 +0000858/***********************************************************************
859 * RtlQueryTimeZoneInformation [NTDLL.@]
860 *
Jon Griffiths08922852003-08-19 00:56:34 +0000861 * Get information about the current timezone.
György 'Nog' Jeney6f3015b2002-11-25 01:12:39 +0000862 *
Jon Griffithscd4234a2003-03-18 18:35:48 +0000863 * PARAMS
Jon Griffiths08922852003-08-19 00:56:34 +0000864 * tzinfo [O] Destination for the retrieved timezone info.
György 'Nog' Jeney6f3015b2002-11-25 01:12:39 +0000865 *
Jon Griffithscd4234a2003-03-18 18:35:48 +0000866 * RETURNS
Jon Griffiths08922852003-08-19 00:56:34 +0000867 * Success: STATUS_SUCCESS.
868 * Failure: An NTSTATUS error code indicating the problem.
György 'Nog' Jeney6f3015b2002-11-25 01:12:39 +0000869 */
870NTSTATUS WINAPI RtlQueryTimeZoneInformation(LPTIME_ZONE_INFORMATION tzinfo)
871{
872 time_t gmt;
873 int bias, daylight;
874 const WCHAR *psTZ;
875
876 memset(tzinfo, 0, sizeof(TIME_ZONE_INFORMATION));
877
Rein Klazesc5c93d12004-10-18 21:19:28 +0000878 if( !TIME_GetTimeZoneInfoFromReg(tzinfo)) {
György 'Nog' Jeney6f3015b2002-11-25 01:12:39 +0000879
Rein Klazesc5c93d12004-10-18 21:19:28 +0000880 gmt = time(NULL);
881 bias = TIME_GetBias(gmt, &daylight);
882
883 tzinfo->Bias = -bias / 60;
884 tzinfo->StandardBias = 0;
885 tzinfo->DaylightBias = -60;
886 tzinfo->StandardName[0]='\0';
887 tzinfo->DaylightName[0]='\0';
888 psTZ = TIME_GetTZAsStr (gmt, (-bias/60), daylight);
889 if (psTZ) strcpyW( tzinfo->StandardName, psTZ );
890 }
György 'Nog' Jeney6f3015b2002-11-25 01:12:39 +0000891 return STATUS_SUCCESS;
892}
893
894/***********************************************************************
895 * RtlSetTimeZoneInformation [NTDLL.@]
896 *
Jon Griffiths08922852003-08-19 00:56:34 +0000897 * Set the current time zone information.
György 'Nog' Jeney6f3015b2002-11-25 01:12:39 +0000898 *
Jon Griffithscd4234a2003-03-18 18:35:48 +0000899 * PARAMS
Jon Griffiths08922852003-08-19 00:56:34 +0000900 * tzinfo [I] Timezone information to set.
György 'Nog' Jeney6f3015b2002-11-25 01:12:39 +0000901 *
Jon Griffithscd4234a2003-03-18 18:35:48 +0000902 * RETURNS
Jon Griffiths08922852003-08-19 00:56:34 +0000903 * Success: STATUS_SUCCESS.
904 * Failure: An NTSTATUS error code indicating the problem.
György 'Nog' Jeney6f3015b2002-11-25 01:12:39 +0000905 *
Jon Griffiths08922852003-08-19 00:56:34 +0000906 * BUGS
György 'Nog' Jeney6f3015b2002-11-25 01:12:39 +0000907 * Uses the obsolete unix timezone structure and tz_dsttime member.
908 */
909NTSTATUS WINAPI RtlSetTimeZoneInformation( const TIME_ZONE_INFORMATION *tzinfo )
910{
Alexandre Julliard8548fc22004-03-11 00:46:09 +0000911#ifdef HAVE_SETTIMEOFDAY
György 'Nog' Jeney6f3015b2002-11-25 01:12:39 +0000912 struct timezone tz;
913
914 tz.tz_minuteswest = tzinfo->Bias;
915#ifdef DST_NONE
916 tz.tz_dsttime = DST_NONE;
917#else
918 tz.tz_dsttime = 0;
919#endif
920 if(!settimeofday(NULL, &tz))
921 return STATUS_SUCCESS;
Alexandre Julliard8548fc22004-03-11 00:46:09 +0000922#endif
György 'Nog' Jeney6f3015b2002-11-25 01:12:39 +0000923 return STATUS_PRIVILEGE_NOT_HELD;
924}
925
926/***********************************************************************
927 * NtSetSystemTime [NTDLL.@]
928 * ZwSetSystemTime [NTDLL.@]
929 *
Jon Griffiths08922852003-08-19 00:56:34 +0000930 * Set the system time.
György 'Nog' Jeney6f3015b2002-11-25 01:12:39 +0000931 *
Jon Griffiths08922852003-08-19 00:56:34 +0000932 * PARAMS
933 * NewTime [I] The time to set.
934 * OldTime [O] Optional destination for the previous system time.
György 'Nog' Jeney6f3015b2002-11-25 01:12:39 +0000935 *
Jon Griffithscd4234a2003-03-18 18:35:48 +0000936 * RETURNS
Jon Griffiths08922852003-08-19 00:56:34 +0000937 * Success: STATUS_SUCCESS.
938 * Failure: An NTSTATUS error code indicating the problem.
György 'Nog' Jeney6f3015b2002-11-25 01:12:39 +0000939 */
940NTSTATUS WINAPI NtSetSystemTime(const LARGE_INTEGER *NewTime, LARGE_INTEGER *OldTime)
941{
942 TIME_FIELDS tf;
943 struct timeval tv;
944 struct timezone tz;
945 struct tm t;
946 time_t sec, oldsec;
947 int dst, bias;
948 int err;
949
950 /* Return the old time if necessary */
951 if(OldTime)
952 NtQuerySystemTime(OldTime);
953
954 RtlTimeToTimeFields(NewTime, &tf);
955
956 /* call gettimeofday to get the current timezone */
957 gettimeofday(&tv, &tz);
958 oldsec = tv.tv_sec;
959 /* get delta local time from utc */
960 bias = TIME_GetBias(oldsec, &dst);
961
962 /* get the number of seconds */
963 t.tm_sec = tf.Second;
964 t.tm_min = tf.Minute;
965 t.tm_hour = tf.Hour;
966 t.tm_mday = tf.Day;
967 t.tm_mon = tf.Month - 1;
968 t.tm_year = tf.Year - 1900;
969 t.tm_isdst = dst;
970 sec = mktime (&t);
971 /* correct for timezone and daylight */
972 sec += bias;
973
974 /* set the new time */
975 tv.tv_sec = sec;
976 tv.tv_usec = tf.Milliseconds * 1000;
977
978 /* error and sanity check*/
979 if(sec == (time_t)-1 || abs((int)(sec-oldsec)) > SETTIME_MAX_ADJUST) {
980 err = 2;
981 } else {
982#ifdef HAVE_SETTIMEOFDAY
983 err = settimeofday(&tv, NULL); /* 0 is OK, -1 is error */
984 if(err == 0)
985 return STATUS_SUCCESS;
986#else
987 err = 1;
988#endif
989 }
990
991 ERR("Cannot set time to %d/%d/%d %d:%d:%d Time adjustment %ld %s\n",
992 tf.Year, tf.Month, tf.Day, tf.Hour, tf.Minute, tf.Second,
Gerald Pfeiferaa0f3792003-10-02 04:29:30 +0000993 (long)(sec-oldsec),
994 err == -1 ? "No Permission"
995 : sec == (time_t)-1 ? "" : "is too large." );
György 'Nog' Jeney6f3015b2002-11-25 01:12:39 +0000996
997 if(err == 2)
998 return STATUS_INVALID_PARAMETER;
999 else if(err == -1)
1000 return STATUS_PRIVILEGE_NOT_HELD;
1001 else
1002 return STATUS_NOT_IMPLEMENTED;
1003}