jscript: Fix Date_setSeconds implementation.
[wine] / dlls / jscript / date.c
1 /*
2  * Copyright 2008 Jacek Caban for CodeWeavers
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18
19 #include <limits.h>
20 #include <math.h>
21
22 #include "jscript.h"
23
24 #include "wine/debug.h"
25
26 WINE_DEFAULT_DEBUG_CHANNEL(jscript);
27
28 /* 1601 to 1970 is 369 years plus 89 leap days */
29 #define TIME_EPOCH  ((ULONGLONG)(369 * 365 + 89) * 86400 * 1000)
30
31 typedef struct {
32     DispatchEx dispex;
33
34     /* ECMA-262 3rd Edition    15.9.1.1 */
35     DOUBLE time;
36
37     LONG bias;
38     SYSTEMTIME standardDate;
39     LONG standardBias;
40     SYSTEMTIME daylightDate;
41     LONG daylightBias;
42 } DateInstance;
43
44 static const WCHAR toStringW[] = {'t','o','S','t','r','i','n','g',0};
45 static const WCHAR toLocaleStringW[] = {'t','o','L','o','c','a','l','e','S','t','r','i','n','g',0};
46 static const WCHAR hasOwnPropertyW[] = {'h','a','s','O','w','n','P','r','o','p','e','r','t','y',0};
47 static const WCHAR propertyIsEnumerableW[] =
48     {'p','r','o','p','e','r','t','y','I','s','E','n','u','m','e','r','a','b','l','e',0};
49 static const WCHAR isPrototypeOfW[] = {'i','s','P','r','o','t','o','t','y','p','e','O','f',0};
50 static const WCHAR valueOfW[] = {'v','a','l','u','e','O','f',0};
51 static const WCHAR toUTCStringW[] = {'t','o','U','T','C','S','t','r','i','n','g',0};
52 static const WCHAR toDateStringW[] = {'t','o','D','a','t','e','S','t','r','i','n','g',0};
53 static const WCHAR toTimeStringW[] = {'t','o','T','i','m','e','S','t','r','i','n','g',0};
54 static const WCHAR toLocaleDateStringW[] = {'t','o','L','o','c','a','l','e','D','a','t','e','S','t','r','i','n','g',0};
55 static const WCHAR toLocaleTimeStringW[] = {'t','o','L','o','c','a','l','e','T','i','m','e','S','t','r','i','n','g',0};
56 static const WCHAR getTimeW[] = {'g','e','t','T','i','m','e',0};
57 static const WCHAR getFullYearW[] = {'g','e','t','F','u','l','l','Y','e','a','r',0};
58 static const WCHAR getUTCFullYearW[] = {'g','e','t','U','T','C','F','u','l','l','Y','e','a','r',0};
59 static const WCHAR getMonthW[] = {'g','e','t','M','o','n','t','h',0};
60 static const WCHAR getUTCMonthW[] = {'g','e','t','U','T','C','M','o','n','t','h',0};
61 static const WCHAR getDateW[] = {'g','e','t','D','a','t','e',0};
62 static const WCHAR getUTCDateW[] = {'g','e','t','U','T','C','D','a','t','e',0};
63 static const WCHAR getDayW[] = {'g','e','t','D','a','y',0};
64 static const WCHAR getUTCDayW[] = {'g','e','t','U','T','C','D','a','y',0};
65 static const WCHAR getHoursW[] = {'g','e','t','H','o','u','r','s',0};
66 static const WCHAR getUTCHoursW[] = {'g','e','t','U','T','C','H','o','u','r','s',0};
67 static const WCHAR getMinutesW[] = {'g','e','t','M','i','n','u','t','e','s',0};
68 static const WCHAR getUTCMinutesW[] = {'g','e','t','U','T','C','M','i','n','u','t','e','s',0};
69 static const WCHAR getSecondsW[] = {'g','e','t','S','e','c','o','n','d','s',0};
70 static const WCHAR getUTCSecondsW[] = {'g','e','t','U','T','C','S','e','c','o','n','d','s',0};
71 static const WCHAR getMillisecondsW[] = {'g','e','t','M','i','l','l','i','s','e','c','o','n','d','s',0};
72 static const WCHAR getUTCMillisecondsW[] = {'g','e','t','U','T','C','M','i','l','l','i','s','e','c','o','n','d','s',0};
73 static const WCHAR getTimezoneOffsetW[] = {'g','e','t','T','i','m','e','z','o','n','e','O','f','f','s','e','t',0};
74 static const WCHAR setTimeW[] = {'s','e','t','T','i','m','e',0};
75 static const WCHAR setMillisecondsW[] = {'s','e','t','M','i','l','l','i','s','e','c','o','n','d','s',0};
76 static const WCHAR setUTCMillisecondsW[] = {'s','e','t','U','T','C','M','i','l','l','i','s','e','c','o','n','d','s',0};
77 static const WCHAR setSecondsW[] = {'s','e','t','S','e','c','o','n','d','s',0};
78 static const WCHAR setUTCSecondsW[] = {'s','e','t','U','T','C','S','e','c','o','n','d','s',0};
79 static const WCHAR setMinutesW[] = {'s','e','t','M','i','n','u','t','e','s',0};
80 static const WCHAR setUTCMinutesW[] = {'s','e','t','U','T','C','M','i','n','u','t','e','s',0};
81 static const WCHAR setHoursW[] = {'s','e','t','H','o','u','r','s',0};
82 static const WCHAR setUTCHoursW[] = {'s','e','t','U','T','C','H','o','u','r','s',0};
83 static const WCHAR setDateW[] = {'s','e','t','D','a','t','e',0};
84 static const WCHAR setUTCDateW[] = {'s','e','t','U','T','C','D','a','t','e',0};
85 static const WCHAR setMonthW[] = {'s','e','t','M','o','n','t','h',0};
86 static const WCHAR setUTCMonthW[] = {'s','e','t','U','T','C','M','o','n','t','h',0};
87 static const WCHAR setFullYearW[] = {'s','e','t','F','u','l','l','Y','e','a','r',0};
88 static const WCHAR setUTCFullYearW[] = {'s','e','t','U','T','C','F','u','l','l','Y','e','a','r',0};
89
90 /*ECMA-262 3rd Edition    15.9.1.2 */
91 #define MS_PER_DAY 86400000
92 #define MS_PER_HOUR 3600000
93 #define MS_PER_MINUTE 60000
94
95 /* ECMA-262 3rd Edition    15.9.1.2 */
96 static inline DOUBLE day(DOUBLE time)
97 {
98     return floor(time / MS_PER_DAY);
99 }
100
101 /* ECMA-262 3rd Edition    15.9.1.3 */
102 static inline DOUBLE days_in_year(DOUBLE year)
103 {
104     int y;
105
106     if(year != (int)year)
107         return ret_nan();
108
109     y = year;
110     if(y%4 != 0) return 365;
111     if(y%100 != 0) return 366;
112     if(y%400 != 0) return 365;
113     return 366;
114 }
115
116 /* ECMA-262 3rd Edition    15.9.1.3 */
117 static inline DOUBLE day_from_year(DOUBLE year)
118 {
119     if(year != (int)year)
120         return ret_nan();
121
122     return floor(365.0*(year-1970) + floor((year-1969)/4)
123         - floor((year-1901)/100) + floor((year-1601)/400));
124 }
125
126 static inline int day_from_month(int month, int in_leap_year)
127 {
128     switch(month)
129     {
130         case 0:
131             return 0;
132         case 1:
133             return 31;
134         case 2:
135             return 59+in_leap_year;
136         case 3:
137             return 90+in_leap_year;
138         case 4:
139             return 120+in_leap_year;
140         case 5:
141             return 151+in_leap_year;
142         case 6:
143             return 181+in_leap_year;
144         case 7:
145             return 212+in_leap_year;
146         case 8:
147             return 243+in_leap_year;
148         case 9:
149             return 273+in_leap_year;
150         case 10:
151             return 304+in_leap_year;
152         default:
153             return 334+in_leap_year;
154     }
155 }
156
157 /* ECMA-262 3rd Edition    15.9.1.3 */
158 static inline DOUBLE time_from_year(DOUBLE year)
159 {
160     return MS_PER_DAY*day_from_year(year);
161 }
162
163 /* ECMA-262 3rd Edition    15.9.1.3 */
164 static inline DOUBLE year_from_time(DOUBLE time)
165 {
166     int y;
167
168     if(isnan(time))
169         return ret_nan();
170
171     y = 1970 + time/365.25/MS_PER_DAY;
172
173     if(time_from_year(y) > time)
174         while(time_from_year(y) > time) y--;
175     else
176         while(time_from_year(y+1)<=time) y++;
177
178     return y;
179 }
180
181 /* ECMA-262 3rd Edition    15.9.1.3 */
182 static inline int in_leap_year(DOUBLE time)
183 {
184     if(days_in_year(year_from_time(time))==366)
185         return 1;
186     return 0;
187 }
188
189 /* ECMA-262 3rd Edition    15.9.1.4 */
190 static inline int day_within_year(DOUBLE time)
191 {
192     return day(time) - day_from_year(year_from_time(time));
193 }
194
195 /* ECMA-262 3rd Edition    15.9.1.4 */
196 static inline DOUBLE month_from_time(DOUBLE time)
197 {
198     int ily = in_leap_year(time);
199     int dwy = day_within_year(time);
200
201     if(isnan(time))
202         return ret_nan();
203
204     if(0<=dwy && dwy<31) return 0;
205     if(dwy < 59+ily) return 1;
206     if(dwy < 90+ily) return 2;
207     if(dwy < 120+ily) return 3;
208     if(dwy < 151+ily) return 4;
209     if(dwy < 181+ily) return 5;
210     if(dwy < 212+ily) return 6;
211     if(dwy < 243+ily) return 7;
212     if(dwy < 273+ily) return 8;
213     if(dwy < 304+ily) return  9;
214     if(dwy < 334+ily) return  10;
215     return  11;
216 }
217
218 /* ECMA-262 3rd Edition    15.9.1.5 */
219 static inline DOUBLE date_from_time(DOUBLE time)
220 {
221     int dwy = day_within_year(time);
222     int ily = in_leap_year(time);
223     int mft = month_from_time(time);
224
225     if(isnan(time))
226         return ret_nan();
227
228     if(mft==0) return dwy+1;
229     if(mft==1) return dwy-30;
230     if(mft==2) return dwy-58-ily;
231     if(mft==3) return dwy-89-ily;
232     if(mft==4) return dwy-119-ily;
233     if(mft==5) return dwy-150-ily;
234     if(mft==6) return dwy-180-ily;
235     if(mft==7) return dwy-211-ily;
236     if(mft==8) return dwy-242-ily;
237     if(mft==9) return dwy-272-ily;
238     if(mft==10) return dwy-303-ily;
239     return dwy-333-ily;
240 }
241
242 /* ECMA-262 3rd Edition    15.9.1.6 */
243 static inline DOUBLE week_day(DOUBLE time)
244 {
245     DOUBLE ret;
246
247     if(isnan(time))
248         return ret_nan();
249
250     ret = fmod(day(time)+4, 7);
251     if(ret<0) ret += 7;
252
253     return ret;
254 }
255
256 static inline DOUBLE convert_time(int year, SYSTEMTIME st)
257 {
258     DOUBLE time;
259     int set_week_day;
260
261     if(st.wMonth == 0)
262         return ret_nan();
263
264     if(st.wYear != 0)
265         year = st.wYear;
266
267     time = time_from_year(year);
268     time += (DOUBLE)day_from_month(st.wMonth-1, in_leap_year(time)) * MS_PER_DAY;
269
270     if(st.wYear == 0) {
271         set_week_day = st.wDayOfWeek-week_day(time);
272         if(set_week_day < 0)
273             set_week_day += 7;
274         time += set_week_day * MS_PER_DAY;
275
276         time += (DOUBLE)(st.wDay-1) * 7 * MS_PER_DAY;
277         if(month_from_time(time) != st.wMonth-1)
278             time -= 7 * MS_PER_DAY;
279     }
280     else
281         time += st.wDay * MS_PER_DAY;
282
283     time += st.wHour * MS_PER_HOUR;
284     time += st.wMinute * MS_PER_MINUTE;
285
286     return time;
287 }
288
289 /* ECMA-262 3rd Edition    15.9.1.9 */
290 static inline DOUBLE daylight_saving_ta(DOUBLE time, DateInstance *date)
291 {
292     int year = year_from_time(time);
293     DOUBLE standardTime, daylightTime;
294
295     if(isnan(time))
296         return 0;
297
298     standardTime = convert_time(year, date->standardDate);
299     daylightTime = convert_time(year, date->daylightDate);
300
301     if(isnan(standardTime) || isnan(daylightTime))
302         return 0;
303     else if(standardTime > daylightTime) {
304         if(daylightTime <= time && time < standardTime)
305             return date->daylightBias;
306
307         return date->standardBias;
308     }
309     else {
310         if(standardTime <= time && time < daylightTime)
311             return date->standardBias;
312
313         return date->daylightBias;
314     }
315 }
316
317 /* ECMA-262 3rd Edition    15.9.1.9 */
318 static inline DOUBLE local_time(DOUBLE time, DateInstance *date)
319 {
320     return time - (daylight_saving_ta(time, date)+date->bias)*MS_PER_MINUTE;
321 }
322
323 /* ECMA-262 3rd Edition    15.9.1.9 */
324 static inline DOUBLE utc(DOUBLE time, DateInstance *date)
325 {
326     time += date->bias * MS_PER_MINUTE;
327     return time + daylight_saving_ta(time, date)*MS_PER_MINUTE;
328 }
329
330 /* ECMA-262 3rd Edition    15.9.1.10 */
331 static inline DOUBLE hour_from_time(DOUBLE time)
332 {
333     DOUBLE ret;
334
335     if(isnan(time))
336         return ret_nan();
337
338     ret = fmod(floor(time/MS_PER_HOUR), 24);
339     if(ret<0) ret += 24;
340
341     return ret;
342 }
343
344 /* ECMA-262 3rd Edition    15.9.1.10 */
345 static inline DOUBLE min_from_time(DOUBLE time)
346 {
347     DOUBLE ret;
348
349     if(isnan(time))
350         return ret_nan();
351
352     ret = fmod(floor(time/MS_PER_MINUTE), 60);
353     if(ret<0) ret += 60;
354
355     return ret;
356 }
357
358 /* ECMA-262 3rd Edition    15.9.1.10 */
359 static inline DOUBLE sec_from_time(DOUBLE time)
360 {
361     DOUBLE ret;
362
363     if(isnan(time))
364         return ret_nan();
365
366     ret = fmod(floor(time/1000), 60);
367     if(ret<0) ret += 60;
368
369     return ret;
370 }
371
372 /* ECMA-262 3rd Edition    15.9.1.10 */
373 static inline DOUBLE ms_from_time(DOUBLE time)
374 {
375     DOUBLE ret;
376
377     if(isnan(time))
378         return ret_nan();
379
380     ret = fmod(time, 1000);
381     if(ret<0) ret += 1000;
382
383     return ret;
384 }
385
386 /* ECMA-262 3rd Edition    15.9.1.11 */
387 static inline DOUBLE make_time(DOUBLE hour, DOUBLE min, DOUBLE sec, DOUBLE ms)
388 {
389     return hour*MS_PER_HOUR + min*MS_PER_MINUTE + sec*1000 + ms;
390 }
391
392 /* ECMA-262 3rd Edition    15.9.1.12 */
393 static inline DOUBLE make_day(DOUBLE year, DOUBLE month, DOUBLE day)
394 {
395     DOUBLE time;
396
397     year += floor(month/12);
398
399     month = fmod(month, 12);
400     if(month<0) month += 12;
401
402     time = time_from_year(year);
403
404     day += floor(time / MS_PER_DAY);
405     day += day_from_month(month, in_leap_year(time));
406
407     return day-1;
408 }
409
410 /* ECMA-262 3rd Edition    15.9.1.13 */
411 static inline DOUBLE make_date(DOUBLE day, DOUBLE time)
412 {
413     return day*MS_PER_DAY + time;
414 }
415
416 /* ECMA-262 3rd Edition    15.9.1.14 */
417 static inline DOUBLE time_clip(DOUBLE time)
418 {
419     if(8.64e15 < time || time < -8.64e15) {
420         return ret_nan();
421     }
422
423     return floor(time);
424 }
425
426 static HRESULT Date_toString(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
427         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
428 {
429     FIXME("\n");
430     return E_NOTIMPL;
431 }
432
433 static HRESULT Date_toLocaleString(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
434         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
435 {
436     FIXME("\n");
437     return E_NOTIMPL;
438 }
439
440 static HRESULT Date_hasOwnProperty(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
441         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
442 {
443     FIXME("\n");
444     return E_NOTIMPL;
445 }
446
447 static HRESULT Date_propertyIsEnumerable(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
448         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
449 {
450     FIXME("\n");
451     return E_NOTIMPL;
452 }
453
454 static HRESULT Date_isPrototypeOf(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
455         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
456 {
457     FIXME("\n");
458     return E_NOTIMPL;
459 }
460
461 static HRESULT Date_valueOf(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
462         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
463 {
464     FIXME("\n");
465     return E_NOTIMPL;
466 }
467
468 static HRESULT Date_toUTCString(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
469         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
470 {
471     FIXME("\n");
472     return E_NOTIMPL;
473 }
474
475 static HRESULT Date_toDateString(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
476         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
477 {
478     FIXME("\n");
479     return E_NOTIMPL;
480 }
481
482 static HRESULT Date_toTimeString(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
483         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
484 {
485     FIXME("\n");
486     return E_NOTIMPL;
487 }
488
489 static HRESULT Date_toLocaleDateString(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
490         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
491 {
492     FIXME("\n");
493     return E_NOTIMPL;
494 }
495
496 static HRESULT Date_toLocaleTimeString(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
497         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
498 {
499     FIXME("\n");
500     return E_NOTIMPL;
501 }
502
503 /* ECMA-262 3rd Edition    15.9.5.9 */
504 static HRESULT Date_getTime(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
505         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
506 {
507     TRACE("\n");
508
509     if(!is_class(dispex, JSCLASS_DATE)) {
510         FIXME("throw TypeError\n");
511         return E_FAIL;
512     }
513
514     if(retv) {
515         DateInstance *date = (DateInstance*)dispex;
516         num_set_val(retv, date->time);
517     }
518     return S_OK;
519 }
520
521 /* ECMA-262 3rd Edition    15.9.5.10 */
522 static HRESULT Date_getFullYear(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
523         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
524 {
525     TRACE("\n");
526
527     if(!is_class(dispex, JSCLASS_DATE)) {
528         FIXME("throw TypeError\n");
529         return E_FAIL;
530     }
531
532     if(retv) {
533         DateInstance *date = (DateInstance*)dispex;
534         DOUBLE time = local_time(date->time, date);
535
536         num_set_val(retv, year_from_time(time));
537     }
538     return S_OK;
539 }
540
541 /* ECMA-262 3rd Edition    15.9.5.11 */
542 static HRESULT Date_getUTCFullYear(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
543         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
544 {
545     TRACE("\n");
546
547     if(!is_class(dispex, JSCLASS_DATE)) {
548         FIXME("throw TypeError\n");
549         return E_FAIL;
550     }
551
552     if(retv) {
553         DateInstance *date = (DateInstance*)dispex;
554         num_set_val(retv, year_from_time(date->time));
555     }
556     return S_OK;
557 }
558
559 /* ECMA-262 3rd Edition    15.9.5.12 */
560 static HRESULT Date_getMonth(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
561         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
562 {
563     TRACE("\n");
564
565     if(!is_class(dispex, JSCLASS_DATE)) {
566         FIXME("throw TypeError\n");
567         return E_FAIL;
568     }
569
570     if(retv) {
571         DateInstance *date = (DateInstance*)dispex;
572         DOUBLE time = local_time(date->time, date);
573
574         num_set_val(retv, month_from_time(time));
575     }
576     return S_OK;
577 }
578
579 /* ECMA-262 3rd Edition    15.9.5.13 */
580 static HRESULT Date_getUTCMonth(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
581         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
582 {
583     TRACE("\n");
584
585     if(!is_class(dispex, JSCLASS_DATE)) {
586         FIXME("throw TypeError\n");
587         return E_FAIL;
588     }
589
590     if(retv) {
591         DateInstance *date = (DateInstance*)dispex;
592         num_set_val(retv, month_from_time(date->time));
593     }
594     return S_OK;
595 }
596
597 /* ECMA-262 3rd Edition    15.9.5.14 */
598 static HRESULT Date_getDate(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
599         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
600 {
601     TRACE("\n");
602
603     if(!is_class(dispex, JSCLASS_DATE)) {
604         FIXME("throw TypeError\n");
605         return E_FAIL;
606     }
607
608     if(retv) {
609         DateInstance *date = (DateInstance*)dispex;
610         DOUBLE time = local_time(date->time, date);
611
612         num_set_val(retv, date_from_time(time));
613     }
614     return S_OK;
615 }
616
617 /* ECMA-262 3rd Edition    15.9.5.15 */
618 static HRESULT Date_getUTCDate(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
619         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
620 {
621     TRACE("\n");
622
623     if(!is_class(dispex, JSCLASS_DATE)) {
624         FIXME("throw TypeError\n");
625         return E_FAIL;
626     }
627
628     if(retv) {
629         DateInstance *date = (DateInstance*)dispex;
630         num_set_val(retv, date_from_time(date->time));
631     }
632     return S_OK;
633 }
634
635 /* ECMA-262 3rd Edition    15.9.5.16 */
636 static HRESULT Date_getDay(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
637         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
638 {
639     TRACE("\n");
640
641     if(!is_class(dispex, JSCLASS_DATE)) {
642         FIXME("throw TypeError\n");
643         return E_FAIL;
644     }
645
646     if(retv) {
647         DateInstance *date = (DateInstance*)dispex;
648         DOUBLE time = local_time(date->time, date);
649
650         num_set_val(retv, week_day(time));
651     }
652     return S_OK;
653 }
654
655 /* ECMA-262 3rd Edition    15.9.5.17 */
656 static HRESULT Date_getUTCDay(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
657         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
658 {
659     TRACE("\n");
660
661     if(!is_class(dispex, JSCLASS_DATE)) {
662         FIXME("throw TypeError\n");
663         return E_FAIL;
664     }
665
666     if(retv) {
667         DateInstance *date = (DateInstance*)dispex;
668         num_set_val(retv, week_day(date->time));
669     }
670     return S_OK;
671 }
672
673 /* ECMA-262 3rd Edition    15.9.5.18 */
674 static HRESULT Date_getHours(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
675         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
676 {
677     TRACE("\n");
678
679     if(!is_class(dispex, JSCLASS_DATE)) {
680         FIXME("throw TypeError\n");
681         return E_FAIL;
682     }
683
684     if(retv) {
685         DateInstance *date = (DateInstance*)dispex;
686         DOUBLE time = local_time(date->time, date);
687
688         num_set_val(retv, hour_from_time(time));
689     }
690     return S_OK;
691 }
692
693 /* ECMA-262 3rd Edition    15.9.5.19 */
694 static HRESULT Date_getUTCHours(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
695         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
696 {
697     TRACE("\n");
698
699     if(!is_class(dispex, JSCLASS_DATE)) {
700         FIXME("throw TypeError\n");
701         return E_FAIL;
702     }
703
704     if(retv) {
705         DateInstance *date = (DateInstance*)dispex;
706         num_set_val(retv, hour_from_time(date->time));
707     }
708     return S_OK;
709 }
710
711 /* ECMA-262 3rd Edition    15.9.5.20 */
712 static HRESULT Date_getMinutes(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
713         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
714 {
715     TRACE("\n");
716
717     if(!is_class(dispex, JSCLASS_DATE)) {
718         FIXME("throw TypeError\n");
719         return E_FAIL;
720     }
721
722     if(retv) {
723         DateInstance *date = (DateInstance*)dispex;
724         DOUBLE time = local_time(date->time, date);
725
726         num_set_val(retv, min_from_time(time));
727     }
728     return S_OK;
729 }
730
731 /* ECMA-262 3rd Edition    15.9.5.21 */
732 static HRESULT Date_getUTCMinutes(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
733         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
734 {
735     TRACE("\n");
736
737     if(!is_class(dispex, JSCLASS_DATE)) {
738         FIXME("throw TypeError\n");
739         return E_FAIL;
740     }
741
742     if(retv) {
743         DateInstance *date = (DateInstance*)dispex;
744         num_set_val(retv, min_from_time(date->time));
745     }
746     return S_OK;
747 }
748
749 /* ECMA-262 3rd Edition    15.9.5.22 */
750 static HRESULT Date_getSeconds(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
751         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
752 {
753     TRACE("\n");
754
755     if(!is_class(dispex, JSCLASS_DATE)) {
756         FIXME("throw TypeError\n");
757         return E_FAIL;
758     }
759
760     if(retv) {
761         DateInstance *date = (DateInstance*)dispex;
762         DOUBLE time = local_time(date->time, date);
763
764         num_set_val(retv, sec_from_time(time));
765     }
766     return S_OK;
767 }
768
769 /* ECMA-262 3rd Edition    15.9.5.23 */
770 static HRESULT Date_getUTCSeconds(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
771         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
772 {
773     TRACE("\n");
774
775     if(!is_class(dispex, JSCLASS_DATE)) {
776         FIXME("throw TypeError\n");
777         return E_FAIL;
778     }
779
780     if(retv) {
781         DateInstance *date = (DateInstance*)dispex;
782         num_set_val(retv, sec_from_time(date->time));
783     }
784     return S_OK;
785 }
786
787 /* ECMA-262 3rd Edition    15.9.5.24 */
788 static HRESULT Date_getMilliseconds(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
789         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
790 {
791     TRACE("\n");
792
793     if(!is_class(dispex, JSCLASS_DATE)) {
794         FIXME("throw TypeError\n");
795         return E_FAIL;
796     }
797
798     if(retv) {
799         DateInstance *date = (DateInstance*)dispex;
800         DOUBLE time = local_time(date->time, date);
801
802         num_set_val(retv, ms_from_time(time));
803     }
804     return S_OK;
805 }
806
807 /* ECMA-262 3rd Edition    15.9.5.25 */
808 static HRESULT Date_getUTCMilliseconds(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
809         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
810 {
811     TRACE("\n");
812
813     if(!is_class(dispex, JSCLASS_DATE)) {
814         FIXME("throw TypeError\n");
815         return E_FAIL;
816     }
817
818     if(retv) {
819         DateInstance *date = (DateInstance*)dispex;
820         num_set_val(retv, ms_from_time(date->time));
821     }
822     return S_OK;
823 }
824
825 /* ECMA-262 3rd Edition    15.9.5.26 */
826 static HRESULT Date_getTimezoneOffset(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
827         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
828 {
829     TRACE("\n");
830
831     if(!is_class(dispex, JSCLASS_DATE)) {
832         FIXME("throw TypeError\n");
833         return E_FAIL;
834     }
835
836     if(retv) {
837         DateInstance *date = (DateInstance*)dispex;
838         num_set_val(retv, floor(
839                     (date->time-local_time(date->time, date))/MS_PER_MINUTE));
840     }
841     return S_OK;
842 }
843
844 /* ECMA-262 3rd Edition    15.9.5.27 */
845 static HRESULT Date_setTime(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
846         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
847 {
848     VARIANT v;
849     HRESULT hres;
850     DateInstance *date;
851
852     TRACE("\n");
853
854     if(!is_class(dispex, JSCLASS_DATE)) {
855         FIXME("throw TypeError\n");
856         return E_FAIL;
857     }
858
859     if(!arg_cnt(dp)) {
860         FIXME("throw ArgumentNotOptional\n");
861         if(retv) num_set_nan(retv);
862         return S_OK;
863     }
864
865     hres = to_number(dispex->ctx, get_arg(dp, 0), ei, &v);
866     if(FAILED(hres))
867         return hres;
868
869     date = (DateInstance*)dispex;
870     date->time = time_clip(num_val(&v));
871
872     if(retv)
873         num_set_val(retv, date->time);
874
875     return S_OK;
876 }
877
878 /* ECMA-262 3rd Edition    15.9.5.28 */
879 static HRESULT Date_setMilliseconds(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
880         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
881 {
882     VARIANT v;
883     HRESULT hres;
884     DateInstance *date;
885     DOUBLE t;
886
887     TRACE("\n");
888
889     if(!is_class(dispex, JSCLASS_DATE)) {
890         FIXME("throw TypeError\n");
891         return E_FAIL;
892     }
893
894     if(!arg_cnt(dp)) {
895         FIXME("throw ArgumentNotOptional\n");
896         if(retv) num_set_nan(retv);
897         return S_OK;
898     }
899
900     hres = to_number(dispex->ctx, get_arg(dp, 0), ei, &v);
901     if(FAILED(hres))
902         return hres;
903
904     date = (DateInstance*)dispex;
905     t = local_time(date->time, date);
906     t = make_date(day(t), make_time(hour_from_time(t), min_from_time(t),
907                 sec_from_time(t), num_val(&v)));
908     date->time = time_clip(utc(t, date));
909
910     if(retv)
911         num_set_val(retv, date->time);
912
913     return S_OK;
914 }
915
916 /* ECMA-262 3rd Edition    15.9.5.29 */
917 static HRESULT Date_setUTCMilliseconds(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
918         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
919 {
920     VARIANT v;
921     HRESULT hres;
922     DateInstance *date;
923     DOUBLE t;
924
925     TRACE("\n");
926
927     if(!is_class(dispex, JSCLASS_DATE)) {
928         FIXME("throw TypeError\n");
929         return E_FAIL;
930     }
931
932     if(!arg_cnt(dp)) {
933         FIXME("throw ArgumentNotOptional\n");
934         if(retv) num_set_nan(retv);
935         return S_OK;
936     }
937
938     hres = to_number(dispex->ctx, get_arg(dp, 0), ei, &v);
939     if(FAILED(hres))
940         return hres;
941
942     date = (DateInstance*)dispex;
943     t = date->time;
944     t = make_date(day(t), make_time(hour_from_time(t), min_from_time(t),
945                 sec_from_time(t), num_val(&v)));
946     date->time = time_clip(t);
947
948     if(retv)
949         num_set_val(retv, date->time);
950
951     return S_OK;
952 }
953
954 /* ECMA-262 3rd Edition    15.9.5.30 */
955 static HRESULT Date_setSeconds(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
956         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
957 {
958     VARIANT v;
959     HRESULT hres;
960     DateInstance *date;
961     DOUBLE t, sec, ms;
962
963     TRACE("\n");
964
965     if(!is_class(dispex, JSCLASS_DATE)) {
966         FIXME("throw TypeError\n");
967         return E_FAIL;
968     }
969
970     if(!arg_cnt(dp)) {
971         FIXME("throw ArgumentNotOptional\n");
972         if(retv) num_set_nan(retv);
973         return S_OK;
974     }
975
976     date = (DateInstance*)dispex;
977     t = local_time(date->time, date);
978
979     hres = to_number(dispex->ctx, get_arg(dp, 0), ei, &v);
980     if(FAILED(hres))
981         return hres;
982     sec = num_val(&v);
983
984     if(arg_cnt(dp) > 1) {
985         hres = to_number(dispex->ctx, get_arg(dp, 1), ei, &v);
986         if(FAILED(hres))
987             return hres;
988         ms = num_val(&v);
989     }
990     else ms = ms_from_time(t);
991
992     t = make_date(day(t), make_time(hour_from_time(t),
993                 min_from_time(t), sec, ms));
994     date->time = time_clip(utc(t, date));
995
996     if(retv)
997         num_set_val(retv, date->time);
998
999     return S_OK;
1000 }
1001
1002 /* ECMA-262 3rd Edition    15.9.5.31 */
1003 static HRESULT Date_setUTCSeconds(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
1004         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
1005 {
1006     VARIANT v;
1007     HRESULT hres;
1008     DateInstance *date;
1009     DOUBLE t, sec, ms;
1010
1011     TRACE("\n");
1012
1013     if(!is_class(dispex, JSCLASS_DATE)) {
1014         FIXME("throw TypeError\n");
1015         return E_FAIL;
1016     }
1017
1018     if(!arg_cnt(dp)) {
1019         FIXME("throw ArgumentNotOptional\n");
1020         if(retv) num_set_nan(retv);
1021         return S_OK;
1022     }
1023
1024     date = (DateInstance*)dispex;
1025     t = date->time;
1026
1027     hres = to_number(dispex->ctx, get_arg(dp, 0), ei, &v);
1028     if(FAILED(hres))
1029         return hres;
1030     sec = num_val(&v);
1031
1032     if(arg_cnt(dp) > 1) {
1033         hres = to_number(dispex->ctx, get_arg(dp, 1), ei, &v);
1034         if(FAILED(hres))
1035             return hres;
1036         ms = num_val(&v);
1037     }
1038     else ms = ms_from_time(t);
1039
1040     t = make_date(day(t), make_time(hour_from_time(t),
1041                 min_from_time(t), sec, ms));
1042     date->time = time_clip(t);
1043
1044     if(retv)
1045         num_set_val(retv, date->time);
1046
1047     return S_OK;
1048 }
1049
1050 /* ECMA-262 3rd Edition    15.9.5.33 */
1051 static HRESULT Date_setMinutes(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
1052         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
1053 {
1054     VARIANT v;
1055     HRESULT hres;
1056     DateInstance *date;
1057
1058     TRACE("\n");
1059
1060     if(!is_class(dispex, JSCLASS_DATE)) {
1061         FIXME("throw TypeError\n");
1062         return E_FAIL;
1063     }
1064
1065     if(!arg_cnt(dp)) {
1066         FIXME("throw ArgumentNotOptional\n");
1067         if(retv) num_set_nan(retv);
1068         return S_OK;
1069     }
1070
1071     hres = to_number(dispex->ctx, get_arg(dp, 0), ei, &v);
1072     if(FAILED(hres))
1073         return hres;
1074
1075     date = (DateInstance*)dispex;
1076     date->time = time_clip(date->time - (min_from_time(date->time) - num_val(&v))*MS_PER_MINUTE);
1077
1078     if(retv)
1079         num_set_val(retv, date->time);
1080
1081     return S_OK;
1082 }
1083
1084 /* ECMA-262 3rd Edition    15.9.5.34 */
1085 static HRESULT Date_setUTCMinutes(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
1086         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
1087 {
1088     return Date_setMinutes(dispex, lcid, flags, dp, retv, ei, caller);
1089 }
1090
1091 /* ECMA-262 3rd Edition    15.9.5.35 */
1092 static HRESULT Date_setHours(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
1093         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
1094 {
1095     VARIANT v;
1096     HRESULT hres;
1097     DateInstance *date;
1098
1099     TRACE("\n");
1100
1101     if(!is_class(dispex, JSCLASS_DATE)) {
1102         FIXME("throw TypeError\n");
1103         return E_FAIL;
1104     }
1105
1106     if(!arg_cnt(dp)) {
1107         FIXME("throw ArgumentNotOptional\n");
1108         if(retv) num_set_nan(retv);
1109         return S_OK;
1110     }
1111
1112     hres = to_number(dispex->ctx, get_arg(dp, 0), ei, &v);
1113     if(FAILED(hres))
1114         return hres;
1115
1116     date = (DateInstance*)dispex;
1117     date->time = time_clip(date->time
1118             - (hour_from_time(date->time - date->bias*MS_PER_MINUTE)
1119                 - num_val(&v))*MS_PER_HOUR);
1120
1121     if(retv)
1122         num_set_val(retv, date->time);
1123
1124     return S_OK;
1125 }
1126
1127 /* ECMA-262 3rd Edition    15.9.5.36 */
1128 static HRESULT Date_setUTCHours(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
1129         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
1130 {
1131     VARIANT v;
1132     HRESULT hres;
1133     DateInstance *date;
1134
1135     TRACE("\n");
1136
1137     if(!is_class(dispex, JSCLASS_DATE)) {
1138         FIXME("throw TypeError\n");
1139         return E_FAIL;
1140     }
1141
1142     if(!arg_cnt(dp)) {
1143         FIXME("throw ArgumentNotOptional\n");
1144         if(retv) num_set_nan(retv);
1145         return S_OK;
1146     }
1147
1148     hres = to_number(dispex->ctx, get_arg(dp, 0), ei, &v);
1149     if(FAILED(hres))
1150         return hres;
1151
1152     date = (DateInstance*)dispex;
1153     date->time = time_clip(date->time
1154             - (hour_from_time(date->time) - num_val(&v))*MS_PER_HOUR);
1155
1156     if(retv)
1157         num_set_val(retv, date->time);
1158
1159     return S_OK;
1160 }
1161
1162 /* ECMA-262 3rd Edition    15.9.5.36 */
1163 static HRESULT Date_setDate(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
1164         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
1165 {
1166     FIXME("\n");
1167     return E_NOTIMPL;
1168 }
1169
1170 /* ECMA-262 3rd Edition    15.9.5.37 */
1171 static HRESULT Date_setUTCDate(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
1172         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
1173 {
1174     FIXME("\n");
1175     return E_NOTIMPL;
1176 }
1177
1178 static HRESULT Date_setMonth(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
1179         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
1180 {
1181     FIXME("\n");
1182     return E_NOTIMPL;
1183 }
1184
1185 static HRESULT Date_setUTCMonth(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
1186         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
1187 {
1188     FIXME("\n");
1189     return E_NOTIMPL;
1190 }
1191
1192 static HRESULT Date_setFullYear(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
1193         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
1194 {
1195     FIXME("\n");
1196     return E_NOTIMPL;
1197 }
1198
1199 static HRESULT Date_setUTCFullYear(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
1200         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
1201 {
1202     FIXME("\n");
1203     return E_NOTIMPL;
1204 }
1205
1206 static HRESULT Date_value(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
1207         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
1208 {
1209     FIXME("\n");
1210     return E_NOTIMPL;
1211 }
1212
1213 static const builtin_prop_t Date_props[] = {
1214     {getDateW,               Date_getDate,               PROPF_METHOD},
1215     {getDayW,                Date_getDay,                PROPF_METHOD},
1216     {getFullYearW,           Date_getFullYear,           PROPF_METHOD},
1217     {getHoursW,              Date_getHours,              PROPF_METHOD},
1218     {getMillisecondsW,       Date_getMilliseconds,       PROPF_METHOD},
1219     {getMinutesW,            Date_getMinutes,            PROPF_METHOD},
1220     {getMonthW,              Date_getMonth,              PROPF_METHOD},
1221     {getSecondsW,            Date_getSeconds,            PROPF_METHOD},
1222     {getTimeW,               Date_getTime,               PROPF_METHOD},
1223     {getTimezoneOffsetW,     Date_getTimezoneOffset,     PROPF_METHOD},
1224     {getUTCDateW,            Date_getUTCDate,            PROPF_METHOD},
1225     {getUTCDayW,             Date_getUTCDay,             PROPF_METHOD},
1226     {getUTCFullYearW,        Date_getUTCFullYear,        PROPF_METHOD},
1227     {getUTCHoursW,           Date_getUTCHours,           PROPF_METHOD},
1228     {getUTCMillisecondsW,    Date_getUTCMilliseconds,    PROPF_METHOD},
1229     {getUTCMinutesW,         Date_getUTCMinutes,         PROPF_METHOD},
1230     {getUTCMonthW,           Date_getUTCMonth,           PROPF_METHOD},
1231     {getUTCSecondsW,         Date_getUTCSeconds,         PROPF_METHOD},
1232     {hasOwnPropertyW,        Date_hasOwnProperty,        PROPF_METHOD},
1233     {isPrototypeOfW,         Date_isPrototypeOf,         PROPF_METHOD},
1234     {propertyIsEnumerableW,  Date_propertyIsEnumerable,  PROPF_METHOD},
1235     {setDateW,               Date_setDate,               PROPF_METHOD},
1236     {setFullYearW,           Date_setFullYear,           PROPF_METHOD},
1237     {setHoursW,              Date_setHours,              PROPF_METHOD},
1238     {setMillisecondsW,       Date_setMilliseconds,       PROPF_METHOD},
1239     {setMinutesW,            Date_setMinutes,            PROPF_METHOD},
1240     {setMonthW,              Date_setMonth,              PROPF_METHOD},
1241     {setSecondsW,            Date_setSeconds,            PROPF_METHOD},
1242     {setTimeW,               Date_setTime,               PROPF_METHOD},
1243     {setUTCDateW,            Date_setUTCDate,            PROPF_METHOD},
1244     {setUTCFullYearW,        Date_setUTCFullYear,        PROPF_METHOD},
1245     {setUTCHoursW,           Date_setUTCHours,           PROPF_METHOD},
1246     {setUTCMillisecondsW,    Date_setUTCMilliseconds,    PROPF_METHOD},
1247     {setUTCMinutesW,         Date_setUTCMinutes,         PROPF_METHOD},
1248     {setUTCMonthW,           Date_setUTCMonth,           PROPF_METHOD},
1249     {setUTCSecondsW,         Date_setUTCSeconds,         PROPF_METHOD},
1250     {toDateStringW,          Date_toDateString,          PROPF_METHOD},
1251     {toLocaleDateStringW,    Date_toLocaleDateString,    PROPF_METHOD},
1252     {toLocaleStringW,        Date_toLocaleString,        PROPF_METHOD},
1253     {toLocaleTimeStringW,    Date_toLocaleTimeString,    PROPF_METHOD},
1254     {toStringW,              Date_toString,              PROPF_METHOD},
1255     {toTimeStringW,          Date_toTimeString,          PROPF_METHOD},
1256     {toUTCStringW,           Date_toUTCString,           PROPF_METHOD},
1257     {valueOfW,               Date_valueOf,               PROPF_METHOD},
1258 };
1259
1260 static const builtin_info_t Date_info = {
1261     JSCLASS_DATE,
1262     {NULL, Date_value, 0},
1263     sizeof(Date_props)/sizeof(*Date_props),
1264     Date_props,
1265     NULL,
1266     NULL
1267 };
1268
1269 static HRESULT create_date(script_ctx_t *ctx, BOOL use_constr, DOUBLE time, DispatchEx **ret)
1270 {
1271     DateInstance *date;
1272     HRESULT hres;
1273     TIME_ZONE_INFORMATION tzi;
1274     DWORD dret;
1275
1276     dret = GetTimeZoneInformation(&tzi);
1277
1278     date = heap_alloc_zero(sizeof(DateInstance));
1279     if(!date)
1280         return E_OUTOFMEMORY;
1281
1282     if(use_constr)
1283         hres = init_dispex_from_constr(&date->dispex, ctx, &Date_info, ctx->date_constr);
1284     else
1285         hres = init_dispex(&date->dispex, ctx, &Date_info, NULL);
1286     if(FAILED(hres)) {
1287         heap_free(date);
1288         return hres;
1289     }
1290
1291     date->time = time;
1292     date->bias = tzi.Bias;
1293     date->standardDate = tzi.StandardDate;
1294     date->standardBias = tzi.StandardBias;
1295     date->daylightDate = tzi.DaylightDate;
1296     date->daylightBias = tzi.DaylightBias;
1297
1298     *ret = &date->dispex;
1299     return S_OK;
1300 }
1301
1302 static HRESULT DateConstr_value(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
1303         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
1304 {
1305     DispatchEx *date;
1306     HRESULT hres;
1307
1308     TRACE("\n");
1309
1310     switch(flags) {
1311     case DISPATCH_CONSTRUCT:
1312         switch(arg_cnt(dp)) {
1313         /* ECMA-262 3rd Edition    15.9.3.3 */
1314         case 0: {
1315             FILETIME time;
1316             LONGLONG lltime;
1317
1318             GetSystemTimeAsFileTime(&time);
1319             lltime = ((LONGLONG)time.dwHighDateTime<<32)
1320                 + time.dwLowDateTime;
1321
1322             hres = create_date(dispex->ctx, TRUE, lltime/10000-TIME_EPOCH, &date);
1323             if(FAILED(hres))
1324                 return hres;
1325             break;
1326         }
1327
1328         /* ECMA-262 3rd Edition    15.9.3.2 */
1329         case 1: {
1330             VARIANT prim, num;
1331
1332             hres = to_primitive(dispex->ctx, get_arg(dp,0), ei, &prim);
1333             if(FAILED(hres))
1334                 return hres;
1335
1336             if(V_VT(&prim) == VT_BSTR) {
1337                 FIXME("VT_BSTR not supported\n");
1338                 return E_NOTIMPL;
1339             }
1340
1341             hres = to_number(dispex->ctx, &prim, ei, &num);
1342             VariantClear(&prim);
1343             if(FAILED(hres))
1344                 return hres;
1345
1346             hres = create_date(dispex->ctx, TRUE, time_clip(num_val(&num)), &date);
1347             if(FAILED(hres))
1348                 return hres;
1349             break;
1350         }
1351
1352         /* ECMA-262 3rd Edition    15.9.3.1 */
1353         default: {
1354             VARIANT year, month, vdate, hours, minutes, seconds, ms;
1355             DateInstance *di;
1356             int arg_no = arg_cnt(dp), y;
1357
1358             hres = to_number(dispex->ctx, get_arg(dp, 0), ei, &year);
1359             if(FAILED(hres))
1360                 return hres;
1361             y = num_val(&year);
1362             if(0<=y && y<=99)
1363                 y += 1900;
1364
1365
1366             hres = to_number(dispex->ctx, get_arg(dp, 1), ei, &month);
1367             if(FAILED(hres))
1368                 return hres;
1369
1370             if(arg_no>2) {
1371                 hres = to_number(dispex->ctx, get_arg(dp, 2), ei, &vdate);
1372                 if(FAILED(hres))
1373                     return hres;
1374             }
1375             else {
1376                 V_VT(&vdate) = VT_R8;
1377                 V_R8(&vdate) = 1;
1378             }
1379
1380             if(arg_no>3) {
1381                 hres = to_number(dispex->ctx, get_arg(dp, 3), ei, &hours);
1382                 if(FAILED(hres))
1383                     return hres;
1384             }
1385             else {
1386                 V_VT(&hours) = VT_R8;
1387                 V_R8(&hours) = 0;
1388             }
1389
1390             if(arg_no>4) {
1391                 hres = to_number(dispex->ctx, get_arg(dp, 4), ei, &minutes);
1392                 if(FAILED(hres))
1393                     return hres;
1394             }
1395             else {
1396                 V_VT(&minutes) = VT_R8;
1397                 V_R8(&minutes) = 0;
1398             }
1399
1400             if(arg_no>5) {
1401                 hres = to_number(dispex->ctx, get_arg(dp, 5), ei, &seconds);
1402                 if(FAILED(hres))
1403                     return hres;
1404             }
1405             else {
1406                 V_VT(&seconds) = VT_R8;
1407                 V_R8(&seconds) = 0;
1408             }
1409
1410             if(arg_no>6) {
1411                 hres = to_number(dispex->ctx, get_arg(dp, 6), ei, &ms);
1412                 if(FAILED(hres))
1413                     return hres;
1414             }
1415             else {
1416                 V_VT(&ms) = VT_R8;
1417                 V_R8(&ms) = 0;
1418             }
1419
1420             hres = create_date(dispex->ctx, TRUE, time_clip(
1421                         make_date(make_day(y, num_val(&month), num_val(&vdate)),
1422                         make_time(num_val(&hours), num_val(&minutes),
1423                         num_val(&seconds), num_val(&ms)))), &date);
1424             if(FAILED(hres))
1425                 return hres;
1426
1427             di = (DateInstance*)date;
1428             di->time = utc(di->time, di);
1429         }
1430         }
1431
1432         V_VT(retv) = VT_DISPATCH;
1433         V_DISPATCH(retv) = (IDispatch*)_IDispatchEx_(date);
1434         return S_OK;
1435
1436     default:
1437         FIXME("unimplemented flags %x\n", flags);
1438         return E_NOTIMPL;
1439     }
1440
1441     return S_OK;
1442 }
1443
1444 HRESULT create_date_constr(script_ctx_t *ctx, DispatchEx **ret)
1445 {
1446     DispatchEx *date;
1447     HRESULT hres;
1448
1449     hres = create_date(ctx, FALSE, 0.0, &date);
1450     if(FAILED(hres))
1451         return hres;
1452
1453     hres = create_builtin_function(ctx, DateConstr_value, PROPF_CONSTR, date, ret);
1454
1455     jsdisp_release(date);
1456     return hres;
1457 }