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