jscript: Changed to_primitive implementation.
[wine] / dlls / jscript / date.c
1 /*
2  * Copyright 2008 Jacek Caban for CodeWeavers
3  * Copyright 2009 Piotr Caban
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18  */
19
20 #include <limits.h>
21 #include <math.h>
22
23 #include "jscript.h"
24
25 #include "wine/debug.h"
26
27 WINE_DEFAULT_DEBUG_CHANNEL(jscript);
28
29 /* 1601 to 1970 is 369 years plus 89 leap days */
30 #define TIME_EPOCH  ((ULONGLONG)(369 * 365 + 89) * 86400 * 1000)
31
32 typedef struct {
33     DispatchEx dispex;
34
35     /* ECMA-262 3rd Edition    15.9.1.1 */
36     DOUBLE time;
37
38     LONG bias;
39     SYSTEMTIME standardDate;
40     LONG standardBias;
41     SYSTEMTIME daylightDate;
42     LONG daylightBias;
43 } DateInstance;
44
45 static const WCHAR toStringW[] = {'t','o','S','t','r','i','n','g',0};
46 static const WCHAR toLocaleStringW[] = {'t','o','L','o','c','a','l','e','S','t','r','i','n','g',0};
47 static const WCHAR hasOwnPropertyW[] = {'h','a','s','O','w','n','P','r','o','p','e','r','t','y',0};
48 static const WCHAR propertyIsEnumerableW[] =
49     {'p','r','o','p','e','r','t','y','I','s','E','n','u','m','e','r','a','b','l','e',0};
50 static const WCHAR isPrototypeOfW[] = {'i','s','P','r','o','t','o','t','y','p','e','O','f',0};
51 static const WCHAR valueOfW[] = {'v','a','l','u','e','O','f',0};
52 static const WCHAR toUTCStringW[] = {'t','o','U','T','C','S','t','r','i','n','g',0};
53 static const WCHAR toDateStringW[] = {'t','o','D','a','t','e','S','t','r','i','n','g',0};
54 static const WCHAR toTimeStringW[] = {'t','o','T','i','m','e','S','t','r','i','n','g',0};
55 static const WCHAR toLocaleDateStringW[] = {'t','o','L','o','c','a','l','e','D','a','t','e','S','t','r','i','n','g',0};
56 static const WCHAR toLocaleTimeStringW[] = {'t','o','L','o','c','a','l','e','T','i','m','e','S','t','r','i','n','g',0};
57 static const WCHAR getTimeW[] = {'g','e','t','T','i','m','e',0};
58 static const WCHAR getFullYearW[] = {'g','e','t','F','u','l','l','Y','e','a','r',0};
59 static const WCHAR getUTCFullYearW[] = {'g','e','t','U','T','C','F','u','l','l','Y','e','a','r',0};
60 static const WCHAR getMonthW[] = {'g','e','t','M','o','n','t','h',0};
61 static const WCHAR getUTCMonthW[] = {'g','e','t','U','T','C','M','o','n','t','h',0};
62 static const WCHAR getDateW[] = {'g','e','t','D','a','t','e',0};
63 static const WCHAR getUTCDateW[] = {'g','e','t','U','T','C','D','a','t','e',0};
64 static const WCHAR getDayW[] = {'g','e','t','D','a','y',0};
65 static const WCHAR getUTCDayW[] = {'g','e','t','U','T','C','D','a','y',0};
66 static const WCHAR getHoursW[] = {'g','e','t','H','o','u','r','s',0};
67 static const WCHAR getUTCHoursW[] = {'g','e','t','U','T','C','H','o','u','r','s',0};
68 static const WCHAR getMinutesW[] = {'g','e','t','M','i','n','u','t','e','s',0};
69 static const WCHAR getUTCMinutesW[] = {'g','e','t','U','T','C','M','i','n','u','t','e','s',0};
70 static const WCHAR getSecondsW[] = {'g','e','t','S','e','c','o','n','d','s',0};
71 static const WCHAR getUTCSecondsW[] = {'g','e','t','U','T','C','S','e','c','o','n','d','s',0};
72 static const WCHAR getMillisecondsW[] = {'g','e','t','M','i','l','l','i','s','e','c','o','n','d','s',0};
73 static const WCHAR getUTCMillisecondsW[] = {'g','e','t','U','T','C','M','i','l','l','i','s','e','c','o','n','d','s',0};
74 static const WCHAR getTimezoneOffsetW[] = {'g','e','t','T','i','m','e','z','o','n','e','O','f','f','s','e','t',0};
75 static const WCHAR setTimeW[] = {'s','e','t','T','i','m','e',0};
76 static const WCHAR setMillisecondsW[] = {'s','e','t','M','i','l','l','i','s','e','c','o','n','d','s',0};
77 static const WCHAR setUTCMillisecondsW[] = {'s','e','t','U','T','C','M','i','l','l','i','s','e','c','o','n','d','s',0};
78 static const WCHAR setSecondsW[] = {'s','e','t','S','e','c','o','n','d','s',0};
79 static const WCHAR setUTCSecondsW[] = {'s','e','t','U','T','C','S','e','c','o','n','d','s',0};
80 static const WCHAR setMinutesW[] = {'s','e','t','M','i','n','u','t','e','s',0};
81 static const WCHAR setUTCMinutesW[] = {'s','e','t','U','T','C','M','i','n','u','t','e','s',0};
82 static const WCHAR setHoursW[] = {'s','e','t','H','o','u','r','s',0};
83 static const WCHAR setUTCHoursW[] = {'s','e','t','U','T','C','H','o','u','r','s',0};
84 static const WCHAR setDateW[] = {'s','e','t','D','a','t','e',0};
85 static const WCHAR setUTCDateW[] = {'s','e','t','U','T','C','D','a','t','e',0};
86 static const WCHAR setMonthW[] = {'s','e','t','M','o','n','t','h',0};
87 static const WCHAR setUTCMonthW[] = {'s','e','t','U','T','C','M','o','n','t','h',0};
88 static const WCHAR setFullYearW[] = {'s','e','t','F','u','l','l','Y','e','a','r',0};
89 static const WCHAR setUTCFullYearW[] = {'s','e','t','U','T','C','F','u','l','l','Y','e','a','r',0};
90
91 static const WCHAR UTCW[] = {'U','T','C',0};
92 static const WCHAR parseW[] = {'p','a','r','s','e',0};
93
94 /*ECMA-262 3rd Edition    15.9.1.2 */
95 #define MS_PER_DAY 86400000
96 #define MS_PER_HOUR 3600000
97 #define MS_PER_MINUTE 60000
98
99 /* ECMA-262 3rd Edition    15.9.1.2 */
100 static inline DOUBLE day(DOUBLE time)
101 {
102     return floor(time / MS_PER_DAY);
103 }
104
105 /* ECMA-262 3rd Edition    15.9.1.2 */
106 static inline DOUBLE time_within_day(DOUBLE time)
107 {
108     DOUBLE ret;
109
110     ret = fmod(time, MS_PER_DAY);
111     if(ret < 0)
112         ret += MS_PER_DAY;
113
114     return ret;
115 }
116
117 /* ECMA-262 3rd Edition    15.9.1.3 */
118 static inline DOUBLE days_in_year(DOUBLE year)
119 {
120     int y;
121
122     if(year != (int)year)
123         return ret_nan();
124
125     y = year;
126     if(y%4 != 0) return 365;
127     if(y%100 != 0) return 366;
128     if(y%400 != 0) return 365;
129     return 366;
130 }
131
132 /* ECMA-262 3rd Edition    15.9.1.3 */
133 static inline DOUBLE day_from_year(DOUBLE year)
134 {
135     if(year != (int)year)
136         return ret_nan();
137
138     return floor(365.0*(year-1970) + floor((year-1969)/4)
139         - floor((year-1901)/100) + floor((year-1601)/400));
140 }
141
142 static inline int day_from_month(int month, int in_leap_year)
143 {
144     switch(month)
145     {
146         case 0:
147             return 0;
148         case 1:
149             return 31;
150         case 2:
151             return 59+in_leap_year;
152         case 3:
153             return 90+in_leap_year;
154         case 4:
155             return 120+in_leap_year;
156         case 5:
157             return 151+in_leap_year;
158         case 6:
159             return 181+in_leap_year;
160         case 7:
161             return 212+in_leap_year;
162         case 8:
163             return 243+in_leap_year;
164         case 9:
165             return 273+in_leap_year;
166         case 10:
167             return 304+in_leap_year;
168         default:
169             return 334+in_leap_year;
170     }
171 }
172
173 /* ECMA-262 3rd Edition    15.9.1.3 */
174 static inline DOUBLE time_from_year(DOUBLE year)
175 {
176     return MS_PER_DAY*day_from_year(year);
177 }
178
179 /* ECMA-262 3rd Edition    15.9.1.3 */
180 static inline DOUBLE year_from_time(DOUBLE time)
181 {
182     int y;
183
184     if(isnan(time))
185         return ret_nan();
186
187     y = 1970 + time/365.25/MS_PER_DAY;
188
189     if(time_from_year(y) > time)
190         while(time_from_year(y) > time) y--;
191     else
192         while(time_from_year(y+1)<=time) y++;
193
194     return y;
195 }
196
197 /* ECMA-262 3rd Edition    15.9.1.3 */
198 static inline int in_leap_year(DOUBLE time)
199 {
200     if(days_in_year(year_from_time(time))==366)
201         return 1;
202     return 0;
203 }
204
205 /* ECMA-262 3rd Edition    15.9.1.4 */
206 static inline int day_within_year(DOUBLE time)
207 {
208     return day(time) - day_from_year(year_from_time(time));
209 }
210
211 /* ECMA-262 3rd Edition    15.9.1.4 */
212 static inline DOUBLE month_from_time(DOUBLE time)
213 {
214     int ily = in_leap_year(time);
215     int dwy = day_within_year(time);
216
217     if(isnan(time))
218         return ret_nan();
219
220     if(0<=dwy && dwy<31) return 0;
221     if(dwy < 59+ily) return 1;
222     if(dwy < 90+ily) return 2;
223     if(dwy < 120+ily) return 3;
224     if(dwy < 151+ily) return 4;
225     if(dwy < 181+ily) return 5;
226     if(dwy < 212+ily) return 6;
227     if(dwy < 243+ily) return 7;
228     if(dwy < 273+ily) return 8;
229     if(dwy < 304+ily) return  9;
230     if(dwy < 334+ily) return  10;
231     return  11;
232 }
233
234 /* ECMA-262 3rd Edition    15.9.1.5 */
235 static inline DOUBLE date_from_time(DOUBLE time)
236 {
237     int dwy = day_within_year(time);
238     int ily = in_leap_year(time);
239     int mft = month_from_time(time);
240
241     if(isnan(time))
242         return ret_nan();
243
244     if(mft==0) return dwy+1;
245     if(mft==1) return dwy-30;
246     if(mft==2) return dwy-58-ily;
247     if(mft==3) return dwy-89-ily;
248     if(mft==4) return dwy-119-ily;
249     if(mft==5) return dwy-150-ily;
250     if(mft==6) return dwy-180-ily;
251     if(mft==7) return dwy-211-ily;
252     if(mft==8) return dwy-242-ily;
253     if(mft==9) return dwy-272-ily;
254     if(mft==10) return dwy-303-ily;
255     return dwy-333-ily;
256 }
257
258 /* ECMA-262 3rd Edition    15.9.1.6 */
259 static inline DOUBLE week_day(DOUBLE time)
260 {
261     DOUBLE ret;
262
263     if(isnan(time))
264         return ret_nan();
265
266     ret = fmod(day(time)+4, 7);
267     if(ret<0) ret += 7;
268
269     return ret;
270 }
271
272 static inline DOUBLE convert_time(int year, SYSTEMTIME st)
273 {
274     DOUBLE time;
275     int set_week_day;
276
277     if(st.wMonth == 0)
278         return ret_nan();
279
280     if(st.wYear != 0)
281         year = st.wYear;
282
283     time = time_from_year(year);
284     time += (DOUBLE)day_from_month(st.wMonth-1, in_leap_year(time)) * MS_PER_DAY;
285
286     if(st.wYear == 0) {
287         set_week_day = st.wDayOfWeek-week_day(time);
288         if(set_week_day < 0)
289             set_week_day += 7;
290         time += set_week_day * MS_PER_DAY;
291
292         time += (DOUBLE)(st.wDay-1) * 7 * MS_PER_DAY;
293         if(month_from_time(time) != st.wMonth-1)
294             time -= 7 * MS_PER_DAY;
295     }
296     else
297         time += st.wDay * MS_PER_DAY;
298
299     time += st.wHour * MS_PER_HOUR;
300     time += st.wMinute * MS_PER_MINUTE;
301
302     return time;
303 }
304
305 /* ECMA-262 3rd Edition    15.9.1.9 */
306 static inline DOUBLE daylight_saving_ta(DOUBLE time, DateInstance *date)
307 {
308     int year = year_from_time(time);
309     DOUBLE standardTime, daylightTime;
310
311     if(isnan(time))
312         return 0;
313
314     standardTime = convert_time(year, date->standardDate);
315     daylightTime = convert_time(year, date->daylightDate);
316
317     if(isnan(standardTime) || isnan(daylightTime))
318         return 0;
319     else if(standardTime > daylightTime) {
320         if(daylightTime <= time && time < standardTime)
321             return date->daylightBias;
322
323         return date->standardBias;
324     }
325     else {
326         if(standardTime <= time && time < daylightTime)
327             return date->standardBias;
328
329         return date->daylightBias;
330     }
331 }
332
333 /* ECMA-262 3rd Edition    15.9.1.9 */
334 static inline DOUBLE local_time(DOUBLE time, DateInstance *date)
335 {
336     return time - (daylight_saving_ta(time, date)+date->bias)*MS_PER_MINUTE;
337 }
338
339 /* ECMA-262 3rd Edition    15.9.1.9 */
340 static inline DOUBLE utc(DOUBLE time, DateInstance *date)
341 {
342     time += date->bias * MS_PER_MINUTE;
343     return time + daylight_saving_ta(time, date)*MS_PER_MINUTE;
344 }
345
346 /* ECMA-262 3rd Edition    15.9.1.10 */
347 static inline DOUBLE hour_from_time(DOUBLE time)
348 {
349     DOUBLE ret;
350
351     if(isnan(time))
352         return ret_nan();
353
354     ret = fmod(floor(time/MS_PER_HOUR), 24);
355     if(ret<0) ret += 24;
356
357     return ret;
358 }
359
360 /* ECMA-262 3rd Edition    15.9.1.10 */
361 static inline DOUBLE min_from_time(DOUBLE time)
362 {
363     DOUBLE ret;
364
365     if(isnan(time))
366         return ret_nan();
367
368     ret = fmod(floor(time/MS_PER_MINUTE), 60);
369     if(ret<0) ret += 60;
370
371     return ret;
372 }
373
374 /* ECMA-262 3rd Edition    15.9.1.10 */
375 static inline DOUBLE sec_from_time(DOUBLE time)
376 {
377     DOUBLE ret;
378
379     if(isnan(time))
380         return ret_nan();
381
382     ret = fmod(floor(time/1000), 60);
383     if(ret<0) ret += 60;
384
385     return ret;
386 }
387
388 /* ECMA-262 3rd Edition    15.9.1.10 */
389 static inline DOUBLE ms_from_time(DOUBLE time)
390 {
391     DOUBLE ret;
392
393     if(isnan(time))
394         return ret_nan();
395
396     ret = fmod(time, 1000);
397     if(ret<0) ret += 1000;
398
399     return ret;
400 }
401
402 /* ECMA-262 3rd Edition    15.9.1.11 */
403 static inline DOUBLE make_time(DOUBLE hour, DOUBLE min, DOUBLE sec, DOUBLE ms)
404 {
405     return hour*MS_PER_HOUR + min*MS_PER_MINUTE + sec*1000 + ms;
406 }
407
408 /* ECMA-262 3rd Edition    15.9.1.12 */
409 static inline DOUBLE make_day(DOUBLE year, DOUBLE month, DOUBLE day)
410 {
411     DOUBLE time;
412
413     year += floor(month/12);
414
415     month = fmod(month, 12);
416     if(month<0) month += 12;
417
418     time = time_from_year(year);
419
420     day += floor(time / MS_PER_DAY);
421     day += day_from_month(month, in_leap_year(time));
422
423     return day-1;
424 }
425
426 /* ECMA-262 3rd Edition    15.9.1.13 */
427 static inline DOUBLE make_date(DOUBLE day, DOUBLE time)
428 {
429     return day*MS_PER_DAY + time;
430 }
431
432 /* ECMA-262 3rd Edition    15.9.1.14 */
433 static inline DOUBLE time_clip(DOUBLE time)
434 {
435     if(8.64e15 < time || time < -8.64e15) {
436         return ret_nan();
437     }
438
439     return floor(time);
440 }
441
442 static SYSTEMTIME create_systemtime(DOUBLE time)
443 {
444     SYSTEMTIME st;
445
446     st.wYear = year_from_time(time);
447     st.wMonth = month_from_time(time) + 1;
448     st.wDayOfWeek = week_day(time);
449     st.wDay = date_from_time(time);
450     st.wHour = hour_from_time(time);
451     st.wMinute = min_from_time(time);
452     st.wSecond = sec_from_time(time);
453     st.wMilliseconds = ms_from_time(time);
454
455     return st;
456 }
457
458 static inline HRESULT date_to_string(DOUBLE time, BOOL show_offset, int offset, VARIANT *retv)
459 {
460     static const WCHAR NaNW[] = { 'N','a','N',0 };
461     static const WCHAR formatW[] = { '%','s',' ','%','s',' ','%','d',' ',
462         '%','0','2','d',':','%','0','2','d',':','%','0','2','d',' ',
463         'U','T','C','%','c','%','0','2','d','%','0','2','d',' ','%','d','%','s',0 };
464     static const WCHAR formatUTCW[] = { '%','s',' ','%','s',' ','%','d',' ',
465         '%','0','2','d',':','%','0','2','d',':','%','0','2','d',' ',
466         'U','T','C',' ','%','d','%','s',0 };
467     static const WCHAR formatNoOffsetW[] = { '%','s',' ','%','s',' ',
468         '%','d',' ','%','0','2','d',':','%','0','2','d',':',
469         '%','0','2','d',' ','%','d','%','s',0 };
470     static const WCHAR ADW[] = { 0 };
471     static const WCHAR BCW[] = { ' ','B','.','C','.',0 };
472
473     static const DWORD week_ids[] = { LOCALE_SABBREVDAYNAME7, LOCALE_SABBREVDAYNAME1,
474         LOCALE_SABBREVDAYNAME2, LOCALE_SABBREVDAYNAME3, LOCALE_SABBREVDAYNAME4,
475         LOCALE_SABBREVDAYNAME5, LOCALE_SABBREVDAYNAME6 };
476     static const DWORD month_ids[] = { LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2,
477         LOCALE_SABBREVMONTHNAME3, LOCALE_SABBREVMONTHNAME4,
478         LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6,
479         LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8,
480         LOCALE_SABBREVMONTHNAME9, LOCALE_SABBREVMONTHNAME10,
481         LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12 };
482
483     BOOL formatAD = TRUE;
484     BSTR week, month;
485     BSTR date_str;
486     int len, size, year, day;
487     DWORD lcid_en, week_id, month_id;
488     WCHAR sign = '-';
489
490     if(isnan(time)) {
491         if(retv) {
492             V_VT(retv) = VT_BSTR;
493             V_BSTR(retv) = SysAllocString(NaNW);
494             if(!V_BSTR(retv))
495                 return E_OUTOFMEMORY;
496         }
497         return S_OK;
498     }
499
500     if(retv) {
501         len = 21;
502
503         lcid_en = MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT);
504
505         week_id = week_ids[(int)week_day(time)];
506         size = GetLocaleInfoW(lcid_en, week_id, NULL, 0);
507         week = SysAllocStringLen(NULL, size);
508         if(!week)
509             return E_OUTOFMEMORY;
510         GetLocaleInfoW(lcid_en, week_id, week, size);
511         len += size-1;
512
513         month_id = month_ids[(int)month_from_time(time)];
514         size = GetLocaleInfoW(lcid_en, month_id, NULL, 0);
515         month = SysAllocStringLen(NULL, size);
516         if(!month) {
517             SysFreeString(week);
518             return E_OUTOFMEMORY;
519         }
520         GetLocaleInfoW(lcid_en, month_id, month, size);
521         len += size-1;
522
523         year = year_from_time(time);
524         if(year<0)
525             year = -year+1;
526         do {
527             year /= 10;
528             len++;
529         } while(year);
530
531         year = year_from_time(time);
532         if(year<0) {
533             formatAD = FALSE;
534             year = -year+1;
535             len += 5;
536         }
537
538         day = date_from_time(time);
539         do {
540             day /= 10;
541             len++;
542         } while(day);
543         day = date_from_time(time);
544
545         if(!show_offset) len -= 9;
546         else if(offset == 0) len -= 5;
547         else if(offset < 0) {
548             sign = '+';
549             offset = -offset;
550         }
551
552         date_str = SysAllocStringLen(NULL, len);
553         if(!date_str) {
554             SysFreeString(week);
555             SysFreeString(month);
556             return E_OUTOFMEMORY;
557         }
558
559         if(!show_offset)
560             sprintfW(date_str, formatNoOffsetW, week, month, day,
561                     (int)hour_from_time(time), (int)min_from_time(time),
562                     (int)sec_from_time(time), year, formatAD?ADW:BCW);
563         else if(offset)
564             sprintfW(date_str, formatW, week, month, day,
565                     (int)hour_from_time(time), (int)min_from_time(time),
566                     (int)sec_from_time(time), sign, offset/60, offset%60,
567                     year, formatAD?ADW:BCW);
568         else
569             sprintfW(date_str, formatUTCW, week, month, day,
570                     (int)hour_from_time(time), (int)min_from_time(time),
571                     (int)sec_from_time(time), year, formatAD?ADW:BCW);
572
573         SysFreeString(week);
574         SysFreeString(month);
575
576         V_VT(retv) = VT_BSTR;
577         V_BSTR(retv) = date_str;
578     }
579     return S_OK;
580 }
581
582 /* ECMA-262 3rd Edition    15.9.1.2 */
583 static HRESULT Date_toString(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
584         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
585 {
586     DateInstance *date;
587     DOUBLE time;
588     int offset;
589
590     TRACE("\n");
591
592     if(!is_class(dispex, JSCLASS_DATE)) {
593         FIXME("throw TypeError\n");
594         return E_FAIL;
595     }
596
597     date = (DateInstance*)dispex;
598     time = local_time(date->time, date);
599     offset = date->bias +
600         daylight_saving_ta(time, date);
601
602     return date_to_string(time, TRUE, offset, retv);
603 }
604
605 /* ECMA-262 3rd Edition    15.9.1.5 */
606 static HRESULT Date_toLocaleString(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
607         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
608 {
609     static const WCHAR NaNW[] = { 'N','a','N',0 };
610     SYSTEMTIME st;
611     DateInstance *date;
612     BSTR date_str;
613     int date_len, time_len;
614
615     TRACE("\n");
616
617     if(!is_class(dispex, JSCLASS_DATE)) {
618         FIXME("throw TypeError\n");
619         return E_FAIL;
620     }
621
622     date = (DateInstance*)dispex;
623
624     if(isnan(date->time)) {
625         if(retv) {
626             V_VT(retv) = VT_BSTR;
627             V_BSTR(retv) = SysAllocString(NaNW);
628             if(!V_BSTR(retv))
629                 return E_OUTOFMEMORY;
630         }
631         return S_OK;
632     }
633
634     st = create_systemtime(local_time(date->time, date));
635
636     if(st.wYear<1601 || st.wYear>9999)
637         return Date_toString(dispex, lcid, flags, dp, retv, ei, caller);
638
639     if(retv) {
640         date_len = GetDateFormatW(lcid, DATE_LONGDATE, &st, NULL, NULL, 0);
641         time_len = GetTimeFormatW(lcid, 0, &st, NULL, NULL, 0);
642         date_str = SysAllocStringLen(NULL, date_len+time_len-1);
643         if(!date_str)
644             return E_OUTOFMEMORY;
645         GetDateFormatW(lcid, DATE_LONGDATE, &st, NULL, date_str, date_len);
646         GetTimeFormatW(lcid, 0, &st, NULL, &date_str[date_len], time_len);
647         date_str[date_len-1] = ' ';
648
649         V_VT(retv) = VT_BSTR;
650         V_BSTR(retv) = date_str;
651     }
652     return S_OK;
653 }
654
655 static HRESULT Date_hasOwnProperty(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
656         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
657 {
658     FIXME("\n");
659     return E_NOTIMPL;
660 }
661
662 static HRESULT Date_propertyIsEnumerable(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
663         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
664 {
665     FIXME("\n");
666     return E_NOTIMPL;
667 }
668
669 static HRESULT Date_isPrototypeOf(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
670         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
671 {
672     FIXME("\n");
673     return E_NOTIMPL;
674 }
675
676 static HRESULT Date_valueOf(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
677         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
678 {
679     TRACE("\n");
680
681     if(!is_class(dispex, JSCLASS_DATE)) {
682         FIXME("throw TypeError\n");
683         return E_FAIL;
684     }
685
686     if(retv) {
687         DateInstance *date = (DateInstance*)dispex;
688         num_set_val(retv, date->time);
689     }
690     return S_OK;
691 }
692
693 /* ECMA-262 3rd Edition    15.9.5.42 */
694 static HRESULT Date_toUTCString(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
695         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
696 {
697     static const WCHAR NaNW[] = { 'N','a','N',0 };
698     static const WCHAR formatADW[] = { '%','s',',',' ','%','d',' ','%','s',' ','%','d',' ',
699         '%','0','2','d',':','%','0','2','d',':','%','0','2','d',' ','U','T','C',0 };
700     static const WCHAR formatBCW[] = { '%','s',',',' ','%','d',' ','%','s',' ','%','d',' ','B','.','C','.',' ',
701         '%','0','2','d',':','%','0','2','d',':','%','0','2','d',' ','U','T','C',0 };
702
703     static const DWORD week_ids[] = { LOCALE_SABBREVDAYNAME7, LOCALE_SABBREVDAYNAME1,
704         LOCALE_SABBREVDAYNAME2, LOCALE_SABBREVDAYNAME3, LOCALE_SABBREVDAYNAME4,
705         LOCALE_SABBREVDAYNAME5, LOCALE_SABBREVDAYNAME6 };
706     static const DWORD month_ids[] = { LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2,
707         LOCALE_SABBREVMONTHNAME3, LOCALE_SABBREVMONTHNAME4,
708         LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6,
709         LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8,
710         LOCALE_SABBREVMONTHNAME9, LOCALE_SABBREVMONTHNAME10,
711         LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12 };
712
713     BOOL formatAD = TRUE;
714     BSTR week, month;
715     DateInstance *date;
716     BSTR date_str;
717     int len, size, year, day;
718     DWORD lcid_en, week_id, month_id;
719
720     TRACE("\n");
721
722     if(!is_class(dispex, JSCLASS_DATE)) {
723         FIXME("throw TypeError\n");
724         return E_FAIL;
725     }
726
727     date = (DateInstance*)dispex;
728
729     if(isnan(date->time)) {
730         if(retv) {
731             V_VT(retv) = VT_BSTR;
732             V_BSTR(retv) = SysAllocString(NaNW);
733             if(!V_BSTR(retv))
734                 return E_OUTOFMEMORY;
735         }
736         return S_OK;
737     }
738
739     if(retv) {
740         len = 17;
741
742         lcid_en = MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT);
743
744         week_id = week_ids[(int)week_day(date->time)];
745         size = GetLocaleInfoW(lcid_en, week_id, NULL, 0);
746         week = SysAllocStringLen(NULL, size);
747         if(!week)
748             return E_OUTOFMEMORY;
749         GetLocaleInfoW(lcid_en, week_id, week, size);
750         len += size-1;
751
752         month_id = month_ids[(int)month_from_time(date->time)];
753         size = GetLocaleInfoW(lcid_en, month_id, NULL, 0);
754         month = SysAllocStringLen(NULL, size);
755         if(!month) {
756             SysFreeString(week);
757             return E_OUTOFMEMORY;
758         }
759         GetLocaleInfoW(lcid_en, month_id, month, size);
760         len += size-1;
761
762         year = year_from_time(date->time);
763         if(year<0)
764             year = -year+1;
765         do {
766             year /= 10;
767             len++;
768         } while(year);
769
770         year = year_from_time(date->time);
771         if(year<0) {
772             formatAD = FALSE;
773             year = -year+1;
774             len += 5;
775         }
776
777         day = date_from_time(date->time);
778         do {
779             day /= 10;
780             len++;
781         } while(day);
782         day = date_from_time(date->time);
783
784         date_str = SysAllocStringLen(NULL, len);
785         if(!date_str) {
786             SysFreeString(week);
787             SysFreeString(month);
788             return E_OUTOFMEMORY;
789         }
790         sprintfW(date_str, formatAD?formatADW:formatBCW, week, day, month, year,
791                 (int)hour_from_time(date->time), (int)min_from_time(date->time),
792                 (int)sec_from_time(date->time));
793
794         SysFreeString(week);
795         SysFreeString(month);
796
797         V_VT(retv) = VT_BSTR;
798         V_BSTR(retv) = date_str;
799     }
800     return S_OK;
801 }
802
803 /* ECMA-262 3rd Edition    15.9.5.3 */
804 static HRESULT Date_toDateString(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
805         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
806 {
807     static const WCHAR NaNW[] = { 'N','a','N',0 };
808     static const WCHAR formatADW[] = { '%','s',' ','%','s',' ','%','d',' ','%','d',0 };
809     static const WCHAR formatBCW[] = { '%','s',' ','%','s',' ','%','d',' ','%','d',' ','B','.','C','.',0 };
810
811     static const DWORD week_ids[] = { LOCALE_SABBREVDAYNAME7, LOCALE_SABBREVDAYNAME1,
812         LOCALE_SABBREVDAYNAME2, LOCALE_SABBREVDAYNAME3, LOCALE_SABBREVDAYNAME4,
813         LOCALE_SABBREVDAYNAME5, LOCALE_SABBREVDAYNAME6 };
814     static const DWORD month_ids[] = { LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2,
815         LOCALE_SABBREVMONTHNAME3, LOCALE_SABBREVMONTHNAME4,
816         LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6,
817         LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8,
818         LOCALE_SABBREVMONTHNAME9, LOCALE_SABBREVMONTHNAME10,
819         LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12 };
820
821     BOOL formatAD = TRUE;
822     BSTR week, month;
823     DateInstance *date;
824     BSTR date_str;
825     DOUBLE time;
826     int len, size, year, day;
827     DWORD lcid_en, week_id, month_id;
828
829     TRACE("\n");
830
831     if(!is_class(dispex, JSCLASS_DATE)) {
832         FIXME("throw TypeError\n");
833         return E_FAIL;
834     }
835
836     date = (DateInstance*)dispex;
837
838     if(isnan(date->time)) {
839         if(retv) {
840             V_VT(retv) = VT_BSTR;
841             V_BSTR(retv) = SysAllocString(NaNW);
842             if(!V_BSTR(retv))
843                 return E_OUTOFMEMORY;
844         }
845         return S_OK;
846     }
847
848     time = local_time(date->time, date);
849
850     if(retv) {
851         len = 5;
852
853         lcid_en = MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT);
854
855         week_id = week_ids[(int)week_day(time)];
856         size = GetLocaleInfoW(lcid_en, week_id, NULL, 0);
857         week = SysAllocStringLen(NULL, size);
858         if(!week)
859             return E_OUTOFMEMORY;
860         GetLocaleInfoW(lcid_en, week_id, week, size);
861         len += size-1;
862
863         month_id = month_ids[(int)month_from_time(time)];
864         size = GetLocaleInfoW(lcid_en, month_id, NULL, 0);
865         month = SysAllocStringLen(NULL, size);
866         if(!month) {
867             SysFreeString(week);
868             return E_OUTOFMEMORY;
869         }
870         GetLocaleInfoW(lcid_en, month_id, month, size);
871         len += size-1;
872
873         year = year_from_time(time);
874         if(year<0)
875             year = -year+1;
876         do {
877             year /= 10;
878             len++;
879         } while(year);
880
881         year = year_from_time(time);
882         if(year<0) {
883             formatAD = FALSE;
884             year = -year+1;
885             len += 5;
886         }
887
888         day = date_from_time(time);
889         do {
890             day /= 10;
891             len++;
892         } while(day);
893         day = date_from_time(time);
894
895         date_str = SysAllocStringLen(NULL, len);
896         if(!date_str) {
897             SysFreeString(week);
898             SysFreeString(month);
899             return E_OUTOFMEMORY;
900         }
901         sprintfW(date_str, formatAD?formatADW:formatBCW, week, month, day, year);
902
903         SysFreeString(week);
904         SysFreeString(month);
905
906         V_VT(retv) = VT_BSTR;
907         V_BSTR(retv) = date_str;
908     }
909     return S_OK;
910 }
911
912 /* ECMA-262 3rd Edition    15.9.5.4 */
913 static HRESULT Date_toTimeString(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
914         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
915 {
916     static const WCHAR NaNW[] = { 'N','a','N',0 };
917     static const WCHAR formatW[] = { '%','0','2','d',':','%','0','2','d',':','%','0','2','d',
918         ' ','U','T','C','%','c','%','0','2','d','%','0','2','d',0 };
919     static const WCHAR formatUTCW[] = { '%','0','2','d',':','%','0','2','d',
920         ':','%','0','2','d',' ','U','T','C',0 };
921     DateInstance *date;
922     BSTR date_str;
923     DOUBLE time;
924     WCHAR sign;
925     int offset;
926
927     TRACE("\n");
928
929     if(!is_class(dispex, JSCLASS_DATE)) {
930         FIXME("throw TypeError\n");
931         return E_FAIL;
932     }
933
934     date = (DateInstance*)dispex;
935
936     if(isnan(date->time)) {
937         if(retv) {
938             V_VT(retv) = VT_BSTR;
939             V_BSTR(retv) = SysAllocString(NaNW);
940             if(!V_BSTR(retv))
941                 return E_OUTOFMEMORY;
942         }
943         return S_OK;
944     }
945
946     time = local_time(date->time, date);
947
948     if(retv) {
949         date_str = SysAllocStringLen(NULL, 17);
950         if(!date_str)
951             return E_OUTOFMEMORY;
952
953         offset = date->bias +
954             daylight_saving_ta(time, date);
955
956         if(offset < 0) {
957             sign = '+';
958             offset = -offset;
959         }
960         else sign = '-';
961
962         if(offset)
963             sprintfW(date_str, formatW, (int)hour_from_time(time),
964                     (int)min_from_time(time), (int)sec_from_time(time),
965                     sign, offset/60, offset%60);
966         else
967             sprintfW(date_str, formatUTCW, (int)hour_from_time(time),
968                     (int)min_from_time(time), (int)sec_from_time(time));
969
970         V_VT(retv) = VT_BSTR;
971         V_BSTR(retv) = date_str;
972     }
973     return S_OK;
974 }
975
976 /* ECMA-262 3rd Edition    15.9.5.6 */
977 static HRESULT Date_toLocaleDateString(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
978         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
979 {
980     static const WCHAR NaNW[] = { 'N','a','N',0 };
981     SYSTEMTIME st;
982     DateInstance *date;
983     BSTR date_str;
984     int len;
985
986     TRACE("\n");
987
988     if(!is_class(dispex, JSCLASS_DATE)) {
989         FIXME("throw TypeError\n");
990         return E_FAIL;
991     }
992
993     date = (DateInstance*)dispex;
994
995     if(isnan(date->time)) {
996         if(retv) {
997             V_VT(retv) = VT_BSTR;
998             V_BSTR(retv) = SysAllocString(NaNW);
999             if(!V_BSTR(retv))
1000                 return E_OUTOFMEMORY;
1001         }
1002         return S_OK;
1003     }
1004
1005     st = create_systemtime(local_time(date->time, date));
1006
1007     if(st.wYear<1601 || st.wYear>9999)
1008         return Date_toDateString(dispex, lcid, flags, dp, retv, ei, caller);
1009
1010     if(retv) {
1011         len = GetDateFormatW(lcid, DATE_LONGDATE, &st, NULL, NULL, 0);
1012         date_str = SysAllocStringLen(NULL, len);
1013         if(!date_str)
1014             return E_OUTOFMEMORY;
1015         GetDateFormatW(lcid, DATE_LONGDATE, &st, NULL, date_str, len);
1016
1017         V_VT(retv) = VT_BSTR;
1018         V_BSTR(retv) = date_str;
1019     }
1020     return S_OK;
1021 }
1022
1023 /* ECMA-262 3rd Edition    15.9.5.7 */
1024 static HRESULT Date_toLocaleTimeString(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
1025         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
1026 {
1027     static const WCHAR NaNW[] = { 'N','a','N',0 };
1028     SYSTEMTIME st;
1029     DateInstance *date;
1030     BSTR date_str;
1031     int len;
1032
1033     TRACE("\n");
1034
1035     if(!is_class(dispex, JSCLASS_DATE)) {
1036         FIXME("throw TypeError\n");
1037         return E_FAIL;
1038     }
1039
1040     date = (DateInstance*)dispex;
1041
1042     if(isnan(date->time)) {
1043         if(retv) {
1044             V_VT(retv) = VT_BSTR;
1045             V_BSTR(retv) = SysAllocString(NaNW);
1046             if(!V_BSTR(retv))
1047                 return E_OUTOFMEMORY;
1048         }
1049         return S_OK;
1050     }
1051
1052     st = create_systemtime(local_time(date->time, date));
1053
1054     if(st.wYear<1601 || st.wYear>9999)
1055         return Date_toTimeString(dispex, lcid, flags, dp, retv, ei, caller);
1056
1057     if(retv) {
1058         len = GetTimeFormatW(lcid, 0, &st, NULL, NULL, 0);
1059         date_str = SysAllocStringLen(NULL, len);
1060         if(!date_str)
1061             return E_OUTOFMEMORY;
1062         GetTimeFormatW(lcid, 0, &st, NULL, date_str, len);
1063
1064         V_VT(retv) = VT_BSTR;
1065         V_BSTR(retv) = date_str;
1066     }
1067     return S_OK;
1068 }
1069
1070 /* ECMA-262 3rd Edition    15.9.5.9 */
1071 static HRESULT Date_getTime(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
1072         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
1073 {
1074     TRACE("\n");
1075
1076     if(!is_class(dispex, JSCLASS_DATE)) {
1077         FIXME("throw TypeError\n");
1078         return E_FAIL;
1079     }
1080
1081     if(retv) {
1082         DateInstance *date = (DateInstance*)dispex;
1083         num_set_val(retv, date->time);
1084     }
1085     return S_OK;
1086 }
1087
1088 /* ECMA-262 3rd Edition    15.9.5.10 */
1089 static HRESULT Date_getFullYear(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
1090         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
1091 {
1092     TRACE("\n");
1093
1094     if(!is_class(dispex, JSCLASS_DATE)) {
1095         FIXME("throw TypeError\n");
1096         return E_FAIL;
1097     }
1098
1099     if(retv) {
1100         DateInstance *date = (DateInstance*)dispex;
1101         DOUBLE time = local_time(date->time, date);
1102
1103         num_set_val(retv, year_from_time(time));
1104     }
1105     return S_OK;
1106 }
1107
1108 /* ECMA-262 3rd Edition    15.9.5.11 */
1109 static HRESULT Date_getUTCFullYear(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
1110         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
1111 {
1112     TRACE("\n");
1113
1114     if(!is_class(dispex, JSCLASS_DATE)) {
1115         FIXME("throw TypeError\n");
1116         return E_FAIL;
1117     }
1118
1119     if(retv) {
1120         DateInstance *date = (DateInstance*)dispex;
1121         num_set_val(retv, year_from_time(date->time));
1122     }
1123     return S_OK;
1124 }
1125
1126 /* ECMA-262 3rd Edition    15.9.5.12 */
1127 static HRESULT Date_getMonth(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
1128         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
1129 {
1130     TRACE("\n");
1131
1132     if(!is_class(dispex, JSCLASS_DATE)) {
1133         FIXME("throw TypeError\n");
1134         return E_FAIL;
1135     }
1136
1137     if(retv) {
1138         DateInstance *date = (DateInstance*)dispex;
1139         DOUBLE time = local_time(date->time, date);
1140
1141         num_set_val(retv, month_from_time(time));
1142     }
1143     return S_OK;
1144 }
1145
1146 /* ECMA-262 3rd Edition    15.9.5.13 */
1147 static HRESULT Date_getUTCMonth(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
1148         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
1149 {
1150     TRACE("\n");
1151
1152     if(!is_class(dispex, JSCLASS_DATE)) {
1153         FIXME("throw TypeError\n");
1154         return E_FAIL;
1155     }
1156
1157     if(retv) {
1158         DateInstance *date = (DateInstance*)dispex;
1159         num_set_val(retv, month_from_time(date->time));
1160     }
1161     return S_OK;
1162 }
1163
1164 /* ECMA-262 3rd Edition    15.9.5.14 */
1165 static HRESULT Date_getDate(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
1166         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
1167 {
1168     TRACE("\n");
1169
1170     if(!is_class(dispex, JSCLASS_DATE)) {
1171         FIXME("throw TypeError\n");
1172         return E_FAIL;
1173     }
1174
1175     if(retv) {
1176         DateInstance *date = (DateInstance*)dispex;
1177         DOUBLE time = local_time(date->time, date);
1178
1179         num_set_val(retv, date_from_time(time));
1180     }
1181     return S_OK;
1182 }
1183
1184 /* ECMA-262 3rd Edition    15.9.5.15 */
1185 static HRESULT Date_getUTCDate(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
1186         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
1187 {
1188     TRACE("\n");
1189
1190     if(!is_class(dispex, JSCLASS_DATE)) {
1191         FIXME("throw TypeError\n");
1192         return E_FAIL;
1193     }
1194
1195     if(retv) {
1196         DateInstance *date = (DateInstance*)dispex;
1197         num_set_val(retv, date_from_time(date->time));
1198     }
1199     return S_OK;
1200 }
1201
1202 /* ECMA-262 3rd Edition    15.9.5.16 */
1203 static HRESULT Date_getDay(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
1204         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
1205 {
1206     TRACE("\n");
1207
1208     if(!is_class(dispex, JSCLASS_DATE)) {
1209         FIXME("throw TypeError\n");
1210         return E_FAIL;
1211     }
1212
1213     if(retv) {
1214         DateInstance *date = (DateInstance*)dispex;
1215         DOUBLE time = local_time(date->time, date);
1216
1217         num_set_val(retv, week_day(time));
1218     }
1219     return S_OK;
1220 }
1221
1222 /* ECMA-262 3rd Edition    15.9.5.17 */
1223 static HRESULT Date_getUTCDay(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
1224         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
1225 {
1226     TRACE("\n");
1227
1228     if(!is_class(dispex, JSCLASS_DATE)) {
1229         FIXME("throw TypeError\n");
1230         return E_FAIL;
1231     }
1232
1233     if(retv) {
1234         DateInstance *date = (DateInstance*)dispex;
1235         num_set_val(retv, week_day(date->time));
1236     }
1237     return S_OK;
1238 }
1239
1240 /* ECMA-262 3rd Edition    15.9.5.18 */
1241 static HRESULT Date_getHours(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
1242         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
1243 {
1244     TRACE("\n");
1245
1246     if(!is_class(dispex, JSCLASS_DATE)) {
1247         FIXME("throw TypeError\n");
1248         return E_FAIL;
1249     }
1250
1251     if(retv) {
1252         DateInstance *date = (DateInstance*)dispex;
1253         DOUBLE time = local_time(date->time, date);
1254
1255         num_set_val(retv, hour_from_time(time));
1256     }
1257     return S_OK;
1258 }
1259
1260 /* ECMA-262 3rd Edition    15.9.5.19 */
1261 static HRESULT Date_getUTCHours(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
1262         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
1263 {
1264     TRACE("\n");
1265
1266     if(!is_class(dispex, JSCLASS_DATE)) {
1267         FIXME("throw TypeError\n");
1268         return E_FAIL;
1269     }
1270
1271     if(retv) {
1272         DateInstance *date = (DateInstance*)dispex;
1273         num_set_val(retv, hour_from_time(date->time));
1274     }
1275     return S_OK;
1276 }
1277
1278 /* ECMA-262 3rd Edition    15.9.5.20 */
1279 static HRESULT Date_getMinutes(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
1280         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
1281 {
1282     TRACE("\n");
1283
1284     if(!is_class(dispex, JSCLASS_DATE)) {
1285         FIXME("throw TypeError\n");
1286         return E_FAIL;
1287     }
1288
1289     if(retv) {
1290         DateInstance *date = (DateInstance*)dispex;
1291         DOUBLE time = local_time(date->time, date);
1292
1293         num_set_val(retv, min_from_time(time));
1294     }
1295     return S_OK;
1296 }
1297
1298 /* ECMA-262 3rd Edition    15.9.5.21 */
1299 static HRESULT Date_getUTCMinutes(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
1300         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
1301 {
1302     TRACE("\n");
1303
1304     if(!is_class(dispex, JSCLASS_DATE)) {
1305         FIXME("throw TypeError\n");
1306         return E_FAIL;
1307     }
1308
1309     if(retv) {
1310         DateInstance *date = (DateInstance*)dispex;
1311         num_set_val(retv, min_from_time(date->time));
1312     }
1313     return S_OK;
1314 }
1315
1316 /* ECMA-262 3rd Edition    15.9.5.22 */
1317 static HRESULT Date_getSeconds(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
1318         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
1319 {
1320     TRACE("\n");
1321
1322     if(!is_class(dispex, JSCLASS_DATE)) {
1323         FIXME("throw TypeError\n");
1324         return E_FAIL;
1325     }
1326
1327     if(retv) {
1328         DateInstance *date = (DateInstance*)dispex;
1329         DOUBLE time = local_time(date->time, date);
1330
1331         num_set_val(retv, sec_from_time(time));
1332     }
1333     return S_OK;
1334 }
1335
1336 /* ECMA-262 3rd Edition    15.9.5.23 */
1337 static HRESULT Date_getUTCSeconds(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
1338         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
1339 {
1340     TRACE("\n");
1341
1342     if(!is_class(dispex, JSCLASS_DATE)) {
1343         FIXME("throw TypeError\n");
1344         return E_FAIL;
1345     }
1346
1347     if(retv) {
1348         DateInstance *date = (DateInstance*)dispex;
1349         num_set_val(retv, sec_from_time(date->time));
1350     }
1351     return S_OK;
1352 }
1353
1354 /* ECMA-262 3rd Edition    15.9.5.24 */
1355 static HRESULT Date_getMilliseconds(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
1356         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
1357 {
1358     TRACE("\n");
1359
1360     if(!is_class(dispex, JSCLASS_DATE)) {
1361         FIXME("throw TypeError\n");
1362         return E_FAIL;
1363     }
1364
1365     if(retv) {
1366         DateInstance *date = (DateInstance*)dispex;
1367         DOUBLE time = local_time(date->time, date);
1368
1369         num_set_val(retv, ms_from_time(time));
1370     }
1371     return S_OK;
1372 }
1373
1374 /* ECMA-262 3rd Edition    15.9.5.25 */
1375 static HRESULT Date_getUTCMilliseconds(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
1376         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
1377 {
1378     TRACE("\n");
1379
1380     if(!is_class(dispex, JSCLASS_DATE)) {
1381         FIXME("throw TypeError\n");
1382         return E_FAIL;
1383     }
1384
1385     if(retv) {
1386         DateInstance *date = (DateInstance*)dispex;
1387         num_set_val(retv, ms_from_time(date->time));
1388     }
1389     return S_OK;
1390 }
1391
1392 /* ECMA-262 3rd Edition    15.9.5.26 */
1393 static HRESULT Date_getTimezoneOffset(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
1394         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
1395 {
1396     TRACE("\n");
1397
1398     if(!is_class(dispex, JSCLASS_DATE)) {
1399         FIXME("throw TypeError\n");
1400         return E_FAIL;
1401     }
1402
1403     if(retv) {
1404         DateInstance *date = (DateInstance*)dispex;
1405         num_set_val(retv, floor(
1406                     (date->time-local_time(date->time, date))/MS_PER_MINUTE));
1407     }
1408     return S_OK;
1409 }
1410
1411 /* ECMA-262 3rd Edition    15.9.5.27 */
1412 static HRESULT Date_setTime(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
1413         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
1414 {
1415     VARIANT v;
1416     HRESULT hres;
1417     DateInstance *date;
1418
1419     TRACE("\n");
1420
1421     if(!is_class(dispex, JSCLASS_DATE)) {
1422         FIXME("throw TypeError\n");
1423         return E_FAIL;
1424     }
1425
1426     if(!arg_cnt(dp)) {
1427         FIXME("throw ArgumentNotOptional\n");
1428         if(retv) num_set_nan(retv);
1429         return S_OK;
1430     }
1431
1432     hres = to_number(dispex->ctx, get_arg(dp, 0), ei, &v);
1433     if(FAILED(hres))
1434         return hres;
1435
1436     date = (DateInstance*)dispex;
1437     date->time = time_clip(num_val(&v));
1438
1439     if(retv)
1440         num_set_val(retv, date->time);
1441
1442     return S_OK;
1443 }
1444
1445 /* ECMA-262 3rd Edition    15.9.5.28 */
1446 static HRESULT Date_setMilliseconds(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
1447         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
1448 {
1449     VARIANT v;
1450     HRESULT hres;
1451     DateInstance *date;
1452     DOUBLE t;
1453
1454     TRACE("\n");
1455
1456     if(!is_class(dispex, JSCLASS_DATE)) {
1457         FIXME("throw TypeError\n");
1458         return E_FAIL;
1459     }
1460
1461     if(!arg_cnt(dp)) {
1462         FIXME("throw ArgumentNotOptional\n");
1463         if(retv) num_set_nan(retv);
1464         return S_OK;
1465     }
1466
1467     hres = to_number(dispex->ctx, get_arg(dp, 0), ei, &v);
1468     if(FAILED(hres))
1469         return hres;
1470
1471     date = (DateInstance*)dispex;
1472     t = local_time(date->time, date);
1473     t = make_date(day(t), make_time(hour_from_time(t), min_from_time(t),
1474                 sec_from_time(t), num_val(&v)));
1475     date->time = time_clip(utc(t, date));
1476
1477     if(retv)
1478         num_set_val(retv, date->time);
1479
1480     return S_OK;
1481 }
1482
1483 /* ECMA-262 3rd Edition    15.9.5.29 */
1484 static HRESULT Date_setUTCMilliseconds(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
1485         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
1486 {
1487     VARIANT v;
1488     HRESULT hres;
1489     DateInstance *date;
1490     DOUBLE t;
1491
1492     TRACE("\n");
1493
1494     if(!is_class(dispex, JSCLASS_DATE)) {
1495         FIXME("throw TypeError\n");
1496         return E_FAIL;
1497     }
1498
1499     if(!arg_cnt(dp)) {
1500         FIXME("throw ArgumentNotOptional\n");
1501         if(retv) num_set_nan(retv);
1502         return S_OK;
1503     }
1504
1505     hres = to_number(dispex->ctx, get_arg(dp, 0), ei, &v);
1506     if(FAILED(hres))
1507         return hres;
1508
1509     date = (DateInstance*)dispex;
1510     t = date->time;
1511     t = make_date(day(t), make_time(hour_from_time(t), min_from_time(t),
1512                 sec_from_time(t), num_val(&v)));
1513     date->time = time_clip(t);
1514
1515     if(retv)
1516         num_set_val(retv, date->time);
1517
1518     return S_OK;
1519 }
1520
1521 /* ECMA-262 3rd Edition    15.9.5.30 */
1522 static HRESULT Date_setSeconds(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
1523         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
1524 {
1525     VARIANT v;
1526     HRESULT hres;
1527     DateInstance *date;
1528     DOUBLE t, sec, ms;
1529
1530     TRACE("\n");
1531
1532     if(!is_class(dispex, JSCLASS_DATE)) {
1533         FIXME("throw TypeError\n");
1534         return E_FAIL;
1535     }
1536
1537     if(!arg_cnt(dp)) {
1538         FIXME("throw ArgumentNotOptional\n");
1539         if(retv) num_set_nan(retv);
1540         return S_OK;
1541     }
1542
1543     date = (DateInstance*)dispex;
1544     t = local_time(date->time, date);
1545
1546     hres = to_number(dispex->ctx, get_arg(dp, 0), ei, &v);
1547     if(FAILED(hres))
1548         return hres;
1549     sec = num_val(&v);
1550
1551     if(arg_cnt(dp) > 1) {
1552         hres = to_number(dispex->ctx, get_arg(dp, 1), ei, &v);
1553         if(FAILED(hres))
1554             return hres;
1555         ms = num_val(&v);
1556     }
1557     else ms = ms_from_time(t);
1558
1559     t = make_date(day(t), make_time(hour_from_time(t),
1560                 min_from_time(t), sec, ms));
1561     date->time = time_clip(utc(t, date));
1562
1563     if(retv)
1564         num_set_val(retv, date->time);
1565
1566     return S_OK;
1567 }
1568
1569 /* ECMA-262 3rd Edition    15.9.5.31 */
1570 static HRESULT Date_setUTCSeconds(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
1571         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
1572 {
1573     VARIANT v;
1574     HRESULT hres;
1575     DateInstance *date;
1576     DOUBLE t, sec, ms;
1577
1578     TRACE("\n");
1579
1580     if(!is_class(dispex, JSCLASS_DATE)) {
1581         FIXME("throw TypeError\n");
1582         return E_FAIL;
1583     }
1584
1585     if(!arg_cnt(dp)) {
1586         FIXME("throw ArgumentNotOptional\n");
1587         if(retv) num_set_nan(retv);
1588         return S_OK;
1589     }
1590
1591     date = (DateInstance*)dispex;
1592     t = date->time;
1593
1594     hres = to_number(dispex->ctx, get_arg(dp, 0), ei, &v);
1595     if(FAILED(hres))
1596         return hres;
1597     sec = num_val(&v);
1598
1599     if(arg_cnt(dp) > 1) {
1600         hres = to_number(dispex->ctx, get_arg(dp, 1), ei, &v);
1601         if(FAILED(hres))
1602             return hres;
1603         ms = num_val(&v);
1604     }
1605     else ms = ms_from_time(t);
1606
1607     t = make_date(day(t), make_time(hour_from_time(t),
1608                 min_from_time(t), sec, ms));
1609     date->time = time_clip(t);
1610
1611     if(retv)
1612         num_set_val(retv, date->time);
1613
1614     return S_OK;
1615 }
1616
1617 /* ECMA-262 3rd Edition    15.9.5.33 */
1618 static HRESULT Date_setMinutes(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
1619         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
1620 {
1621     VARIANT v;
1622     HRESULT hres;
1623     DateInstance *date;
1624     DOUBLE t, min, sec, ms;
1625
1626     TRACE("\n");
1627
1628     if(!is_class(dispex, JSCLASS_DATE)) {
1629         FIXME("throw TypeError\n");
1630         return E_FAIL;
1631     }
1632
1633     if(!arg_cnt(dp)) {
1634         FIXME("throw ArgumentNotOptional\n");
1635         if(retv) num_set_nan(retv);
1636         return S_OK;
1637     }
1638
1639     date = (DateInstance*)dispex;
1640     t = local_time(date->time, date);
1641
1642     hres = to_number(dispex->ctx, get_arg(dp, 0), ei, &v);
1643     if(FAILED(hres))
1644         return hres;
1645     min = num_val(&v);
1646
1647     if(arg_cnt(dp) > 1) {
1648         hres = to_number(dispex->ctx, get_arg(dp, 1), ei, &v);
1649         if(FAILED(hres))
1650             return hres;
1651         sec = num_val(&v);
1652     }
1653     else sec = sec_from_time(t);
1654
1655     if(arg_cnt(dp) > 2) {
1656         hres = to_number(dispex->ctx, get_arg(dp, 2), ei, &v);
1657         if(FAILED(hres))
1658             return hres;
1659         ms = num_val(&v);
1660     }
1661     else ms = ms_from_time(t);
1662
1663     t = make_date(day(t), make_time(hour_from_time(t),
1664                 min, sec, ms));
1665     date->time = time_clip(utc(t, date));
1666
1667     if(retv)
1668         num_set_val(retv, date->time);
1669
1670     return S_OK;
1671 }
1672
1673 /* ECMA-262 3rd Edition    15.9.5.34 */
1674 static HRESULT Date_setUTCMinutes(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
1675         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
1676 {
1677     VARIANT v;
1678     HRESULT hres;
1679     DateInstance *date;
1680     DOUBLE t, min, sec, ms;
1681
1682     TRACE("\n");
1683
1684     if(!is_class(dispex, JSCLASS_DATE)) {
1685         FIXME("throw TypeError\n");
1686         return E_FAIL;
1687     }
1688
1689     if(!arg_cnt(dp)) {
1690         FIXME("throw ArgumentNotOptional\n");
1691         if(retv) num_set_nan(retv);
1692         return S_OK;
1693     }
1694
1695     date = (DateInstance*)dispex;
1696     t = date->time;
1697
1698     hres = to_number(dispex->ctx, get_arg(dp, 0), ei, &v);
1699     if(FAILED(hres))
1700         return hres;
1701     min = num_val(&v);
1702
1703     if(arg_cnt(dp) > 1) {
1704         hres = to_number(dispex->ctx, get_arg(dp, 1), ei, &v);
1705         if(FAILED(hres))
1706             return hres;
1707         sec = num_val(&v);
1708     }
1709     else sec = sec_from_time(t);
1710
1711     if(arg_cnt(dp) > 2) {
1712         hres = to_number(dispex->ctx, get_arg(dp, 2), ei, &v);
1713         if(FAILED(hres))
1714             return hres;
1715         ms = num_val(&v);
1716     }
1717     else ms = ms_from_time(t);
1718
1719     t = make_date(day(t), make_time(hour_from_time(t),
1720                 min, sec, ms));
1721     date->time = time_clip(t);
1722
1723     if(retv)
1724         num_set_val(retv, date->time);
1725
1726     return S_OK;
1727 }
1728
1729 /* ECMA-262 3rd Edition    15.9.5.35 */
1730 static HRESULT Date_setHours(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
1731         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
1732 {
1733     VARIANT v;
1734     HRESULT hres;
1735     DateInstance *date;
1736     DOUBLE t, hour, min, sec, ms;
1737
1738     TRACE("\n");
1739
1740     if(!is_class(dispex, JSCLASS_DATE)) {
1741         FIXME("throw TypeError\n");
1742         return E_FAIL;
1743     }
1744
1745     if(!arg_cnt(dp)) {
1746         FIXME("throw ArgumentNotOptional\n");
1747         if(retv) num_set_nan(retv);
1748         return S_OK;
1749     }
1750
1751     date = (DateInstance*)dispex;
1752     t = local_time(date->time, date);
1753
1754     hres = to_number(dispex->ctx, get_arg(dp, 0), ei, &v);
1755     if(FAILED(hres))
1756         return hres;
1757     hour = num_val(&v);
1758
1759     if(arg_cnt(dp) > 1) {
1760         hres = to_number(dispex->ctx, get_arg(dp, 1), ei, &v);
1761         if(FAILED(hres))
1762             return hres;
1763         min = num_val(&v);
1764     }
1765     else min = min_from_time(t);
1766
1767     if(arg_cnt(dp) > 2) {
1768         hres = to_number(dispex->ctx, get_arg(dp, 2), ei, &v);
1769         if(FAILED(hres))
1770             return hres;
1771         sec = num_val(&v);
1772     }
1773     else sec = sec_from_time(t);
1774
1775     if(arg_cnt(dp) > 3) {
1776         hres = to_number(dispex->ctx, get_arg(dp, 3), ei, &v);
1777         if(FAILED(hres))
1778             return hres;
1779         ms = num_val(&v);
1780     }
1781     else ms = ms_from_time(t);
1782
1783     t = make_date(day(t), make_time(hour, min, sec, ms));
1784     date->time = time_clip(utc(t, date));
1785
1786     if(retv)
1787         num_set_val(retv, date->time);
1788
1789     return S_OK;
1790 }
1791
1792 /* ECMA-262 3rd Edition    15.9.5.36 */
1793 static HRESULT Date_setUTCHours(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
1794         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
1795 {
1796     VARIANT v;
1797     HRESULT hres;
1798     DateInstance *date;
1799     DOUBLE t, hour, min, sec, ms;
1800
1801     TRACE("\n");
1802
1803     if(!is_class(dispex, JSCLASS_DATE)) {
1804         FIXME("throw TypeError\n");
1805         return E_FAIL;
1806     }
1807
1808     if(!arg_cnt(dp)) {
1809         FIXME("throw ArgumentNotOptional\n");
1810         if(retv) num_set_nan(retv);
1811         return S_OK;
1812     }
1813
1814     date = (DateInstance*)dispex;
1815     t = date->time;
1816
1817     hres = to_number(dispex->ctx, get_arg(dp, 0), ei, &v);
1818     if(FAILED(hres))
1819         return hres;
1820     hour = num_val(&v);
1821
1822     if(arg_cnt(dp) > 1) {
1823         hres = to_number(dispex->ctx, get_arg(dp, 1), ei, &v);
1824         if(FAILED(hres))
1825             return hres;
1826         min = num_val(&v);
1827     }
1828     else min = min_from_time(t);
1829
1830     if(arg_cnt(dp) > 2) {
1831         hres = to_number(dispex->ctx, get_arg(dp, 2), ei, &v);
1832         if(FAILED(hres))
1833             return hres;
1834         sec = num_val(&v);
1835     }
1836     else sec = sec_from_time(t);
1837
1838     if(arg_cnt(dp) > 3) {
1839         hres = to_number(dispex->ctx, get_arg(dp, 3), ei, &v);
1840         if(FAILED(hres))
1841             return hres;
1842         ms = num_val(&v);
1843     }
1844     else ms = ms_from_time(t);
1845
1846     t = make_date(day(t), make_time(hour, min, sec, ms));
1847     date->time = time_clip(t);
1848
1849     if(retv)
1850         num_set_val(retv, date->time);
1851
1852     return S_OK;
1853 }
1854
1855 /* ECMA-262 3rd Edition    15.9.5.36 */
1856 static HRESULT Date_setDate(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
1857         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
1858 {
1859     VARIANT v;
1860     HRESULT hres;
1861     DateInstance *date;
1862     DOUBLE t;
1863
1864     TRACE("\n");
1865
1866     if(!is_class(dispex, JSCLASS_DATE)) {
1867         FIXME("throw TypeError\n");
1868         return E_FAIL;
1869     }
1870
1871     if(!arg_cnt(dp)) {
1872         FIXME("throw ArgumentNotOptional\n");
1873         if(retv) num_set_nan(retv);
1874         return S_OK;
1875     }
1876
1877     hres = to_number(dispex->ctx, get_arg(dp, 0), ei, &v);
1878     if(FAILED(hres))
1879         return hres;
1880
1881     date = (DateInstance*)dispex;
1882     t = local_time(date->time, date);
1883     t = make_date(make_day(year_from_time(t), month_from_time(t),
1884                 num_val(&v)), time_within_day(t));
1885     date->time = time_clip(utc(t, date));
1886
1887     if(retv)
1888         num_set_val(retv, date->time);
1889
1890     return S_OK;
1891 }
1892
1893 /* ECMA-262 3rd Edition    15.9.5.37 */
1894 static HRESULT Date_setUTCDate(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
1895         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
1896 {
1897     VARIANT v;
1898     HRESULT hres;
1899     DateInstance *date;
1900     DOUBLE t;
1901
1902     TRACE("\n");
1903
1904     if(!is_class(dispex, JSCLASS_DATE)) {
1905         FIXME("throw TypeError\n");
1906         return E_FAIL;
1907     }
1908
1909     if(!arg_cnt(dp)) {
1910         FIXME("throw ArgumentNotOptional\n");
1911         if(retv) num_set_nan(retv);
1912         return S_OK;
1913     }
1914
1915     hres = to_number(dispex->ctx, get_arg(dp, 0), ei, &v);
1916     if(FAILED(hres))
1917         return hres;
1918
1919     date = (DateInstance*)dispex;
1920     t = date->time;
1921     t = make_date(make_day(year_from_time(t), month_from_time(t),
1922                 num_val(&v)), time_within_day(t));
1923     date->time = time_clip(t);
1924
1925     if(retv)
1926         num_set_val(retv, date->time);
1927
1928     return S_OK;
1929 }
1930
1931 /* ECMA-262 3rd Edition    15.9.5.38 */
1932 static HRESULT Date_setMonth(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
1933         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
1934 {
1935     VARIANT v;
1936     HRESULT hres;
1937     DateInstance *date;
1938     DOUBLE t, month, ddate;
1939
1940     TRACE("\n");
1941
1942     if(!is_class(dispex, JSCLASS_DATE)) {
1943         FIXME("throw TypeError\n");
1944         return E_FAIL;
1945     }
1946
1947     if(!arg_cnt(dp)) {
1948         FIXME("throw ArgumentNotOptional\n");
1949         if(retv) num_set_nan(retv);
1950         return S_OK;
1951     }
1952
1953     date = (DateInstance*)dispex;
1954     t = local_time(date->time, date);
1955
1956     hres = to_number(dispex->ctx, get_arg(dp, 0), ei, &v);
1957     if(FAILED(hres))
1958         return hres;
1959     month = num_val(&v);
1960
1961     if(arg_cnt(dp) > 1) {
1962         hres = to_number(dispex->ctx, get_arg(dp, 1), ei, &v);
1963         if(FAILED(hres))
1964             return hres;
1965         ddate = num_val(&v);
1966     }
1967     else ddate = date_from_time(t);
1968
1969     t = make_date(make_day(year_from_time(t), month, ddate),
1970             time_within_day(t));
1971     date->time = time_clip(utc(t, date));
1972
1973     if(retv)
1974         num_set_val(retv, date->time);
1975
1976     return S_OK;
1977 }
1978
1979 /* ECMA-262 3rd Edition    15.9.5.39 */
1980 static HRESULT Date_setUTCMonth(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
1981         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
1982 {
1983     VARIANT v;
1984     HRESULT hres;
1985     DateInstance *date;
1986     DOUBLE t, month, ddate;
1987
1988     TRACE("\n");
1989
1990     if(!is_class(dispex, JSCLASS_DATE)) {
1991         FIXME("throw TypeError\n");
1992         return E_FAIL;
1993     }
1994
1995     if(!arg_cnt(dp)) {
1996         FIXME("throw ArgumentNotOptional\n");
1997         if(retv) num_set_nan(retv);
1998         return S_OK;
1999     }
2000
2001     date = (DateInstance*)dispex;
2002     t = date->time;
2003
2004     hres = to_number(dispex->ctx, get_arg(dp, 0), ei, &v);
2005     if(FAILED(hres))
2006         return hres;
2007     month = num_val(&v);
2008
2009     if(arg_cnt(dp) > 1) {
2010         hres = to_number(dispex->ctx, get_arg(dp, 1), ei, &v);
2011         if(FAILED(hres))
2012             return hres;
2013         ddate = num_val(&v);
2014     }
2015     else ddate = date_from_time(t);
2016
2017     t = make_date(make_day(year_from_time(t), month, ddate),
2018             time_within_day(t));
2019     date->time = time_clip(t);
2020
2021     if(retv)
2022         num_set_val(retv, date->time);
2023
2024     return S_OK;
2025 }
2026
2027 /* ECMA-262 3rd Edition    15.9.5.40 */
2028 static HRESULT Date_setFullYear(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
2029         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
2030 {
2031     VARIANT v;
2032     HRESULT hres;
2033     DateInstance *date;
2034     DOUBLE t, year, month, ddate;
2035
2036     TRACE("\n");
2037
2038     if(!is_class(dispex, JSCLASS_DATE)) {
2039         FIXME("throw TypeError\n");
2040         return E_FAIL;
2041     }
2042
2043     if(!arg_cnt(dp)) {
2044         FIXME("throw ArgumentNotOptional\n");
2045         if(retv) num_set_nan(retv);
2046         return S_OK;
2047     }
2048
2049     date = (DateInstance*)dispex;
2050     t = local_time(date->time, date);
2051
2052     hres = to_number(dispex->ctx, get_arg(dp, 0), ei, &v);
2053     if(FAILED(hres))
2054         return hres;
2055     year = num_val(&v);
2056
2057     if(arg_cnt(dp) > 1) {
2058         hres = to_number(dispex->ctx, get_arg(dp, 1), ei, &v);
2059         if(FAILED(hres))
2060             return hres;
2061         month = num_val(&v);
2062     }
2063     else month = month_from_time(t);
2064
2065     if(arg_cnt(dp) > 2) {
2066         hres = to_number(dispex->ctx, get_arg(dp, 2), ei, &v);
2067         if(FAILED(hres))
2068             return hres;
2069         ddate = num_val(&v);
2070     }
2071     else ddate = date_from_time(t);
2072
2073     t = make_date(make_day(year, month, ddate), time_within_day(t));
2074     date->time = time_clip(utc(t, date));
2075
2076     if(retv)
2077         num_set_val(retv, date->time);
2078
2079     return S_OK;
2080 }
2081
2082 /* ECMA-262 3rd Edition    15.9.5.41 */
2083 static HRESULT Date_setUTCFullYear(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
2084         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
2085 {
2086     VARIANT v;
2087     HRESULT hres;
2088     DateInstance *date;
2089     DOUBLE t, year, month, ddate;
2090
2091     TRACE("\n");
2092
2093     if(!is_class(dispex, JSCLASS_DATE)) {
2094         FIXME("throw TypeError\n");
2095         return E_FAIL;
2096     }
2097
2098     if(!arg_cnt(dp)) {
2099         FIXME("throw ArgumentNotOptional\n");
2100         if(retv) num_set_nan(retv);
2101         return S_OK;
2102     }
2103
2104     date = (DateInstance*)dispex;
2105     t = date->time;
2106
2107     hres = to_number(dispex->ctx, get_arg(dp, 0), ei, &v);
2108     if(FAILED(hres))
2109         return hres;
2110     year = num_val(&v);
2111
2112     if(arg_cnt(dp) > 1) {
2113         hres = to_number(dispex->ctx, get_arg(dp, 1), ei, &v);
2114         if(FAILED(hres))
2115             return hres;
2116         month = num_val(&v);
2117     }
2118     else month = month_from_time(t);
2119
2120     if(arg_cnt(dp) > 2) {
2121         hres = to_number(dispex->ctx, get_arg(dp, 2), ei, &v);
2122         if(FAILED(hres))
2123             return hres;
2124         ddate = num_val(&v);
2125     }
2126     else ddate = date_from_time(t);
2127
2128     t = make_date(make_day(year, month, ddate), time_within_day(t));
2129     date->time = time_clip(t);
2130
2131     if(retv)
2132         num_set_val(retv, date->time);
2133
2134     return S_OK;
2135 }
2136
2137 static HRESULT Date_value(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
2138         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
2139 {
2140     FIXME("\n");
2141     return E_NOTIMPL;
2142 }
2143
2144 static const builtin_prop_t Date_props[] = {
2145     {getDateW,               Date_getDate,               PROPF_METHOD},
2146     {getDayW,                Date_getDay,                PROPF_METHOD},
2147     {getFullYearW,           Date_getFullYear,           PROPF_METHOD},
2148     {getHoursW,              Date_getHours,              PROPF_METHOD},
2149     {getMillisecondsW,       Date_getMilliseconds,       PROPF_METHOD},
2150     {getMinutesW,            Date_getMinutes,            PROPF_METHOD},
2151     {getMonthW,              Date_getMonth,              PROPF_METHOD},
2152     {getSecondsW,            Date_getSeconds,            PROPF_METHOD},
2153     {getTimeW,               Date_getTime,               PROPF_METHOD},
2154     {getTimezoneOffsetW,     Date_getTimezoneOffset,     PROPF_METHOD},
2155     {getUTCDateW,            Date_getUTCDate,            PROPF_METHOD},
2156     {getUTCDayW,             Date_getUTCDay,             PROPF_METHOD},
2157     {getUTCFullYearW,        Date_getUTCFullYear,        PROPF_METHOD},
2158     {getUTCHoursW,           Date_getUTCHours,           PROPF_METHOD},
2159     {getUTCMillisecondsW,    Date_getUTCMilliseconds,    PROPF_METHOD},
2160     {getUTCMinutesW,         Date_getUTCMinutes,         PROPF_METHOD},
2161     {getUTCMonthW,           Date_getUTCMonth,           PROPF_METHOD},
2162     {getUTCSecondsW,         Date_getUTCSeconds,         PROPF_METHOD},
2163     {hasOwnPropertyW,        Date_hasOwnProperty,        PROPF_METHOD},
2164     {isPrototypeOfW,         Date_isPrototypeOf,         PROPF_METHOD},
2165     {propertyIsEnumerableW,  Date_propertyIsEnumerable,  PROPF_METHOD},
2166     {setDateW,               Date_setDate,               PROPF_METHOD},
2167     {setFullYearW,           Date_setFullYear,           PROPF_METHOD},
2168     {setHoursW,              Date_setHours,              PROPF_METHOD},
2169     {setMillisecondsW,       Date_setMilliseconds,       PROPF_METHOD},
2170     {setMinutesW,            Date_setMinutes,            PROPF_METHOD},
2171     {setMonthW,              Date_setMonth,              PROPF_METHOD},
2172     {setSecondsW,            Date_setSeconds,            PROPF_METHOD},
2173     {setTimeW,               Date_setTime,               PROPF_METHOD},
2174     {setUTCDateW,            Date_setUTCDate,            PROPF_METHOD},
2175     {setUTCFullYearW,        Date_setUTCFullYear,        PROPF_METHOD},
2176     {setUTCHoursW,           Date_setUTCHours,           PROPF_METHOD},
2177     {setUTCMillisecondsW,    Date_setUTCMilliseconds,    PROPF_METHOD},
2178     {setUTCMinutesW,         Date_setUTCMinutes,         PROPF_METHOD},
2179     {setUTCMonthW,           Date_setUTCMonth,           PROPF_METHOD},
2180     {setUTCSecondsW,         Date_setUTCSeconds,         PROPF_METHOD},
2181     {toDateStringW,          Date_toDateString,          PROPF_METHOD},
2182     {toLocaleDateStringW,    Date_toLocaleDateString,    PROPF_METHOD},
2183     {toLocaleStringW,        Date_toLocaleString,        PROPF_METHOD},
2184     {toLocaleTimeStringW,    Date_toLocaleTimeString,    PROPF_METHOD},
2185     {toStringW,              Date_toString,              PROPF_METHOD},
2186     {toTimeStringW,          Date_toTimeString,          PROPF_METHOD},
2187     {toUTCStringW,           Date_toUTCString,           PROPF_METHOD},
2188     {valueOfW,               Date_valueOf,               PROPF_METHOD},
2189 };
2190
2191 static const builtin_info_t Date_info = {
2192     JSCLASS_DATE,
2193     {NULL, Date_value, 0},
2194     sizeof(Date_props)/sizeof(*Date_props),
2195     Date_props,
2196     NULL,
2197     NULL
2198 };
2199
2200 static HRESULT create_date(script_ctx_t *ctx, BOOL use_constr, DOUBLE time, DispatchEx **ret)
2201 {
2202     DateInstance *date;
2203     HRESULT hres;
2204     TIME_ZONE_INFORMATION tzi;
2205
2206     GetTimeZoneInformation(&tzi);
2207
2208     date = heap_alloc_zero(sizeof(DateInstance));
2209     if(!date)
2210         return E_OUTOFMEMORY;
2211
2212     if(use_constr)
2213         hres = init_dispex_from_constr(&date->dispex, ctx, &Date_info, ctx->date_constr);
2214     else
2215         hres = init_dispex(&date->dispex, ctx, &Date_info, NULL);
2216     if(FAILED(hres)) {
2217         heap_free(date);
2218         return hres;
2219     }
2220
2221     date->time = time;
2222     date->bias = tzi.Bias;
2223     date->standardDate = tzi.StandardDate;
2224     date->standardBias = tzi.StandardBias;
2225     date->daylightDate = tzi.DaylightDate;
2226     date->daylightBias = tzi.DaylightBias;
2227
2228     *ret = &date->dispex;
2229     return S_OK;
2230 }
2231
2232 static inline HRESULT date_parse(BSTR input, VARIANT *retv) {
2233     static const DWORD string_ids[] = { LOCALE_SMONTHNAME12, LOCALE_SMONTHNAME11,
2234         LOCALE_SMONTHNAME10, LOCALE_SMONTHNAME9, LOCALE_SMONTHNAME8,
2235         LOCALE_SMONTHNAME7, LOCALE_SMONTHNAME6, LOCALE_SMONTHNAME5,
2236         LOCALE_SMONTHNAME4, LOCALE_SMONTHNAME3, LOCALE_SMONTHNAME2,
2237         LOCALE_SMONTHNAME1, LOCALE_SDAYNAME7, LOCALE_SDAYNAME1,
2238         LOCALE_SDAYNAME2, LOCALE_SDAYNAME3, LOCALE_SDAYNAME4,
2239         LOCALE_SDAYNAME5, LOCALE_SDAYNAME6 };
2240     BSTR strings[sizeof(string_ids)/sizeof(DWORD)];
2241
2242     BSTR parse;
2243     int input_len, parse_len = 0, nest_level = 0, i, size;
2244     int year = 0, month = 0, day = 0, hour = 0, min = 0, sec = 0;
2245     int ms = 0, offset = 0, hour_adjust = 0;
2246     BOOL set_year = FALSE, set_month = FALSE, set_day = FALSE, set_hour = FALSE;
2247     BOOL set_offset = FALSE, set_era = FALSE, ad = TRUE, set_am = FALSE, am = TRUE;
2248     BOOL set_hour_adjust = TRUE;
2249     TIME_ZONE_INFORMATION tzi;
2250     DateInstance di;
2251     DWORD lcid_en;
2252
2253     if(retv) num_set_nan(retv);
2254
2255     input_len = SysStringLen(input);
2256     for(i=0; i<input_len; i++) {
2257         if(input[i] == '(') nest_level++;
2258         else if(input[i] == ')') {
2259             nest_level--;
2260             if(nest_level<0)
2261                 return S_OK;
2262         }
2263         else if(!nest_level) parse_len++;
2264     }
2265
2266     parse = SysAllocStringLen(NULL, parse_len);
2267     if(!parse)
2268         return E_OUTOFMEMORY;
2269     nest_level = 0;
2270     parse_len = 0;
2271     for(i=0; i<input_len; i++) {
2272         if(input[i] == '(') nest_level++;
2273         else if(input[i] == ')') nest_level--;
2274         else if(!nest_level) parse[parse_len++] = toupperW(input[i]);
2275     }
2276
2277     GetTimeZoneInformation(&tzi);
2278     di.bias = tzi.Bias;
2279     di.standardDate = tzi.StandardDate;
2280     di.standardBias = tzi.StandardBias;
2281     di.daylightDate = tzi.DaylightDate;
2282     di.daylightBias = tzi.DaylightBias;
2283
2284     lcid_en = MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT);
2285     for(i=0; i<sizeof(string_ids)/sizeof(DWORD); i++) {
2286         size = GetLocaleInfoW(lcid_en, string_ids[i], NULL, 0);
2287         strings[i] = SysAllocStringLen(NULL, size);
2288         if(!strings[i]) {
2289             i--;
2290             while(i-- >= 0)
2291                 SysFreeString(strings[i]);
2292             SysFreeString(parse);
2293             return E_OUTOFMEMORY;
2294         }
2295         GetLocaleInfoW(lcid_en, string_ids[i], strings[i], size);
2296     }
2297
2298     for(i=0; i<parse_len;) {
2299         while(isspaceW(parse[i])) i++;
2300         if(parse[i] == ',') {
2301             while(parse[i] == ',') i++;
2302             continue;
2303         }
2304
2305         if(parse[i]>='0' && parse[i]<='9') {
2306             int tmp = atoiW(&parse[i]);
2307             while(parse[i]>='0' && parse[i]<='9') i++;
2308             while(isspaceW(parse[i])) i++;
2309
2310             if(parse[i] == ':') {
2311                 /* Time */
2312                 if(set_hour) break;
2313                 set_hour = TRUE;
2314
2315                 hour = tmp;
2316
2317                 while(parse[i] == ':') i++;
2318                 while(isspaceW(parse[i])) i++;
2319                 if(parse[i]>='0' && parse[i]<='9') {
2320                     min = atoiW(&parse[i]);
2321                     while(parse[i]>='0' && parse[i]<='9') i++;
2322                 }
2323
2324                 while(isspaceW(parse[i])) i++;
2325                 while(parse[i] == ':') i++;
2326                 while(isspaceW(parse[i])) i++;
2327                 if(parse[i]>='0' && parse[i]<='9') {
2328                     sec = atoiW(&parse[i]);
2329                     while(parse[i]>='0' && parse[i]<='9') i++;
2330                 }
2331             }
2332             else if(parse[i]=='-' || parse[i]=='/') {
2333                 /* Short date */
2334                 if(set_day || set_month || set_year) break;
2335                 set_day = TRUE;
2336                 set_month = TRUE;
2337                 set_year = TRUE;
2338
2339                 month = tmp-1;
2340
2341                 while(isspaceW(parse[i])) i++;
2342                 while(parse[i]=='-' || parse[i]=='/') i++;
2343                 while(isspaceW(parse[i])) i++;
2344                 if(parse[i]<'0' || parse[i]>'9') break;
2345                 day = atoiW(&parse[i]);
2346                 while(parse[i]>='0' && parse[i]<='9') i++;
2347
2348                 while(parse[i]=='-' || parse[i]=='/') i++;
2349                 while(isspaceW(parse[i])) i++;
2350                 if(parse[i]<'0' || parse[i]>'9') break;
2351                 year = atoiW(&parse[i]);
2352                 while(parse[i]>='0' && parse[i]<='9') i++;
2353             }
2354             else if(tmp<0) break;
2355             else if(tmp<70) {
2356                 /* Day */
2357                 if(set_day) break;
2358                 set_day = TRUE;
2359                 day = tmp;
2360             }
2361             else {
2362                 /* Year */
2363                 if(set_year) break;
2364                 set_year = TRUE;
2365                 year = tmp;
2366             }
2367         }
2368         else {
2369             if(parse[i]<'A' || parse[i]>'Z') break;
2370             else if(parse[i]=='B' && (parse[i+1]=='C' ||
2371                         (parse[i+1]=='.' && parse[i+2]=='C'))) {
2372                 /* AD/BC */
2373                 if(set_era) break;
2374                 set_era = TRUE;
2375                 ad = FALSE;
2376
2377                 i++;
2378                 if(parse[i] == '.') i++;
2379                 i++;
2380                 if(parse[i] == '.') i++;
2381             }
2382             else if(parse[i]=='A' && (parse[i+1]=='D' ||
2383                         (parse[i+1]=='.' && parse[i+2]=='D'))) {
2384                 /* AD/BC */
2385                 if(set_era) break;
2386                 set_era = TRUE;
2387
2388                 i++;
2389                 if(parse[i] == '.') i++;
2390                 i++;
2391                 if(parse[i] == '.') i++;
2392             }
2393             else if(parse[i+1]<'A' || parse[i+1]>'Z') {
2394                 /* Timezone */
2395                 if(set_offset) break;
2396                 set_offset = TRUE;
2397
2398                 if(parse[i] <= 'I') hour_adjust = parse[i]-'A'+2;
2399                 else if(parse[i] == 'J') break;
2400                 else if(parse[i] <= 'M') hour_adjust = parse[i]-'K'+11;
2401                 else if(parse[i] <= 'Y') hour_adjust = parse[i]-'N';
2402                 else hour_adjust = 1;
2403
2404                 i++;
2405                 if(parse[i] == '.') i++;
2406             }
2407             else if(parse[i]=='A' && parse[i+1]=='M') {
2408                 /* AM/PM */
2409                 if(set_am) break;
2410                 set_am = TRUE;
2411                 am = TRUE;
2412                 i += 2;
2413             }
2414             else if(parse[i]=='P' && parse[i+1]=='M') {
2415                 /* AM/PM */
2416                 if(set_am) break;
2417                 set_am = TRUE;
2418                 am = FALSE;
2419                 i += 2;
2420             }
2421             else if((parse[i]=='U' && parse[i+1]=='T' && parse[i+2]=='C')
2422                     || (parse[i]=='G' && parse[i+1]=='M' && parse[i+2]=='T')) {
2423                 /* Timezone */
2424                 BOOL positive = TRUE;
2425
2426                 if(set_offset) break;
2427                 set_offset = TRUE;
2428                 set_hour_adjust = FALSE;
2429
2430                 i += 3;
2431                 while(isspaceW(parse[i])) i++;
2432                 if(parse[i] == '-')  positive = FALSE;
2433                 else if(parse[i] != '+') continue;
2434
2435                 i++;
2436                 while(isspaceW(parse[i])) i++;
2437                 if(parse[i]<'0' || parse[i]>'9') break;
2438                 offset = atoiW(&parse[i]);
2439                 while(parse[i]>='0' && parse[i]<='9') i++;
2440
2441                 if(offset<24) offset *= 60;
2442                 else offset = (offset/100)*60 + offset%100;
2443
2444                 if(positive) offset = -offset;
2445             }
2446             else {
2447                 /* Month or garbage */
2448                 int j;
2449
2450                 for(size=i; parse[size]>='A' && parse[size]<='Z'; size++);
2451                 size -= i;
2452
2453                 for(j=0; j<sizeof(string_ids)/sizeof(DWORD); j++)
2454                     if(!memicmpW(&parse[i], strings[j], size)) break;
2455
2456                 if(j < 12) {
2457                     if(set_month) break;
2458                     set_month = TRUE;
2459                     month = 11-j;
2460                 }
2461                 else if(j == sizeof(string_ids)/sizeof(DWORD)) break;
2462
2463                 i += size;
2464             }
2465         }
2466     }
2467
2468     if(retv && i==parse_len && set_year && set_month
2469             && set_day && (!set_am || hour<13)) {
2470         if(set_am) {
2471             if(hour == 12) hour = 0;
2472             if(!am) hour += 12;
2473         }
2474
2475         if(!ad) year = -year+1;
2476         else if(year<100) year += 1900;
2477
2478         V_VT(retv) = VT_R8;
2479         V_R8(retv) = time_clip(make_date(make_day(year, month, day),
2480                     make_time(hour+hour_adjust, min, sec, ms)) + offset*MS_PER_MINUTE);
2481
2482         if(set_hour_adjust) V_R8(retv) = utc(V_R8(retv), &di);
2483     }
2484
2485     for(i=0; i<sizeof(string_ids)/sizeof(DWORD); i++)
2486         SysFreeString(strings[i]);
2487     SysFreeString(parse);
2488
2489     return S_OK;
2490 }
2491
2492 static HRESULT DateConstr_parse(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
2493         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
2494 {
2495     BSTR parse_str;
2496     HRESULT hres;
2497
2498     TRACE("\n");
2499
2500     if(!arg_cnt(dp)) {
2501         if(retv)
2502             num_set_nan(retv);
2503         return S_OK;
2504     }
2505
2506     hres = to_string(dispex->ctx, get_arg(dp,0), ei, &parse_str);
2507     if(FAILED(hres))
2508         return hres;
2509
2510     hres = date_parse(parse_str, retv);
2511
2512     SysFreeString(parse_str);
2513     return hres;
2514 }
2515
2516 static HRESULT DateConstr_UTC(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
2517         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
2518 {
2519     VARIANT year, month, vdate, hours, minutes, seconds, ms;
2520     DOUBLE y;
2521     int arg_no = arg_cnt(dp);
2522     HRESULT hres;
2523
2524     TRACE("\n");
2525
2526     if(arg_no>0) {
2527         hres = to_number(dispex->ctx, get_arg(dp, 0), ei, &year);
2528         if(FAILED(hres))
2529             return hres;
2530         y = num_val(&year);
2531         if(0<=y && y<=99)
2532             y += 1900;
2533     }
2534     else y = 1900;
2535
2536     if(arg_no>1) {
2537         hres = to_number(dispex->ctx, get_arg(dp, 1), ei, &month);
2538         if(FAILED(hres))
2539             return hres;
2540     }
2541     else {
2542         V_VT(&month) = VT_R8;
2543         V_R8(&month) = 0;
2544     }
2545
2546     if(arg_no>2) {
2547         hres = to_number(dispex->ctx, get_arg(dp, 2), ei, &vdate);
2548         if(FAILED(hres))
2549             return hres;
2550     }
2551     else {
2552         V_VT(&vdate) = VT_R8;
2553         V_R8(&vdate) = 1;
2554     }
2555
2556     if(arg_no>3) {
2557         hres = to_number(dispex->ctx, get_arg(dp, 3), ei, &hours);
2558         if(FAILED(hres))
2559             return hres;
2560     }
2561     else {
2562         V_VT(&hours) = VT_R8;
2563         V_R8(&hours) = 0;
2564     }
2565
2566     if(arg_no>4) {
2567         hres = to_number(dispex->ctx, get_arg(dp, 4), ei, &minutes);
2568         if(FAILED(hres))
2569             return hres;
2570     }
2571     else {
2572         V_VT(&minutes) = VT_R8;
2573         V_R8(&minutes) = 0;
2574     }
2575
2576     if(arg_no>5) {
2577         hres = to_number(dispex->ctx, get_arg(dp, 5), ei, &seconds);
2578         if(FAILED(hres))
2579             return hres;
2580     }
2581     else {
2582         V_VT(&seconds) = VT_R8;
2583         V_R8(&seconds) = 0;
2584     }
2585
2586     if(arg_no>6) {
2587         hres = to_number(dispex->ctx, get_arg(dp, 6), ei, &ms);
2588         if(FAILED(hres))
2589             return hres;
2590     }
2591     else {
2592         V_VT(&ms) = VT_R8;
2593         V_R8(&ms) = 0;
2594     }
2595
2596     if(retv) {
2597         V_VT(retv) = VT_R8;
2598         V_R8(retv) = time_clip(make_date(
2599                     make_day(y, num_val(&month), num_val(&vdate)),
2600                     make_time(num_val(&hours), num_val(&minutes),
2601                     num_val(&seconds), num_val(&ms))));
2602     }
2603
2604     return S_OK;
2605 }
2606
2607 static HRESULT DateConstr_value(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
2608         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
2609 {
2610     DispatchEx *date;
2611     HRESULT hres;
2612
2613     TRACE("\n");
2614
2615     switch(flags) {
2616     case DISPATCH_CONSTRUCT:
2617         switch(arg_cnt(dp)) {
2618         /* ECMA-262 3rd Edition    15.9.3.3 */
2619         case 0: {
2620             FILETIME time;
2621             LONGLONG lltime;
2622
2623             GetSystemTimeAsFileTime(&time);
2624             lltime = ((LONGLONG)time.dwHighDateTime<<32)
2625                 + time.dwLowDateTime;
2626
2627             hres = create_date(dispex->ctx, TRUE, lltime/10000-TIME_EPOCH, &date);
2628             if(FAILED(hres))
2629                 return hres;
2630             break;
2631         }
2632
2633         /* ECMA-262 3rd Edition    15.9.3.2 */
2634         case 1: {
2635             VARIANT prim, num;
2636
2637             hres = to_primitive(dispex->ctx, get_arg(dp,0), ei, &prim, NO_HINT);
2638             if(FAILED(hres))
2639                 return hres;
2640
2641             if(V_VT(&prim) == VT_BSTR)
2642                 hres = date_parse(V_BSTR(&prim), &num);
2643             else
2644                 hres = to_number(dispex->ctx, &prim, ei, &num);
2645
2646             VariantClear(&prim);
2647             if(FAILED(hres))
2648                 return hres;
2649
2650             hres = create_date(dispex->ctx, TRUE, time_clip(num_val(&num)), &date);
2651             if(FAILED(hres))
2652                 return hres;
2653             break;
2654         }
2655
2656         /* ECMA-262 3rd Edition    15.9.3.1 */
2657         default: {
2658             VARIANT ret_date;
2659             DateInstance *di;
2660
2661             DateConstr_UTC(dispex, lcid, flags, dp, &ret_date, ei, sp);
2662
2663             hres = create_date(dispex->ctx, TRUE, num_val(&ret_date), &date);
2664             if(FAILED(hres))
2665                 return hres;
2666
2667             di = (DateInstance*)date;
2668             di->time = utc(di->time, di);
2669         }
2670         }
2671
2672         V_VT(retv) = VT_DISPATCH;
2673         V_DISPATCH(retv) = (IDispatch*)_IDispatchEx_(date);
2674         return S_OK;
2675
2676     case INVOKE_FUNC: {
2677         FILETIME system_time, local_time;
2678         LONGLONG lltime;
2679
2680         GetSystemTimeAsFileTime(&system_time);
2681         FileTimeToLocalFileTime(&system_time, &local_time);
2682         lltime = ((LONGLONG)local_time.dwHighDateTime<<32)
2683             + local_time.dwLowDateTime;
2684
2685         return date_to_string(lltime/10000-TIME_EPOCH, FALSE, 0, retv);
2686     }
2687
2688     default:
2689         FIXME("unimplemented flags %x\n", flags);
2690         return E_NOTIMPL;
2691     }
2692
2693     return S_OK;
2694 }
2695
2696 static const builtin_prop_t DateConstr_props[] = {
2697     {UTCW,    DateConstr_UTC,    PROPF_METHOD},
2698     {parseW,  DateConstr_parse,  PROPF_METHOD}
2699 };
2700
2701 static const builtin_info_t DateConstr_info = {
2702     JSCLASS_FUNCTION,
2703     {NULL, Function_value, 0},
2704     sizeof(DateConstr_props)/sizeof(*DateConstr_props),
2705     DateConstr_props,
2706     NULL,
2707     NULL
2708 };
2709
2710 HRESULT create_date_constr(script_ctx_t *ctx, DispatchEx **ret)
2711 {
2712     DispatchEx *date;
2713     HRESULT hres;
2714
2715     hres = create_date(ctx, FALSE, 0.0, &date);
2716     if(FAILED(hres))
2717         return hres;
2718
2719     hres = create_builtin_function(ctx, DateConstr_value, &DateConstr_info, PROPF_CONSTR, date, ret);
2720
2721     jsdisp_release(date);
2722     return hres;
2723 }