jscript: Throw more SyntaxErrors in parser.
[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         return throw_type_error(dispex->ctx, ei, IDS_NOT_DATE, NULL);
595
596     date = (DateInstance*)dispex;
597     time = local_time(date->time, date);
598     offset = date->bias +
599         daylight_saving_ta(time, date);
600
601     return date_to_string(time, TRUE, offset, retv);
602 }
603
604 /* ECMA-262 3rd Edition    15.9.1.5 */
605 static HRESULT Date_toLocaleString(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
606         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
607 {
608     static const WCHAR NaNW[] = { 'N','a','N',0 };
609     SYSTEMTIME st;
610     DateInstance *date;
611     BSTR date_str;
612     int date_len, time_len;
613
614     TRACE("\n");
615
616     if(!is_class(dispex, JSCLASS_DATE))
617         return throw_type_error(dispex->ctx, ei, IDS_NOT_DATE, NULL);
618
619     date = (DateInstance*)dispex;
620
621     if(isnan(date->time)) {
622         if(retv) {
623             V_VT(retv) = VT_BSTR;
624             V_BSTR(retv) = SysAllocString(NaNW);
625             if(!V_BSTR(retv))
626                 return E_OUTOFMEMORY;
627         }
628         return S_OK;
629     }
630
631     st = create_systemtime(local_time(date->time, date));
632
633     if(st.wYear<1601 || st.wYear>9999)
634         return Date_toString(dispex, lcid, flags, dp, retv, ei, caller);
635
636     if(retv) {
637         date_len = GetDateFormatW(lcid, DATE_LONGDATE, &st, NULL, NULL, 0);
638         time_len = GetTimeFormatW(lcid, 0, &st, NULL, NULL, 0);
639         date_str = SysAllocStringLen(NULL, date_len+time_len-1);
640         if(!date_str)
641             return E_OUTOFMEMORY;
642         GetDateFormatW(lcid, DATE_LONGDATE, &st, NULL, date_str, date_len);
643         GetTimeFormatW(lcid, 0, &st, NULL, &date_str[date_len], time_len);
644         date_str[date_len-1] = ' ';
645
646         V_VT(retv) = VT_BSTR;
647         V_BSTR(retv) = date_str;
648     }
649     return S_OK;
650 }
651
652 static HRESULT Date_hasOwnProperty(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
653         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
654 {
655     FIXME("\n");
656     return E_NOTIMPL;
657 }
658
659 static HRESULT Date_propertyIsEnumerable(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
660         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
661 {
662     FIXME("\n");
663     return E_NOTIMPL;
664 }
665
666 static HRESULT Date_isPrototypeOf(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
667         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
668 {
669     FIXME("\n");
670     return E_NOTIMPL;
671 }
672
673 static HRESULT Date_valueOf(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
674         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
675 {
676     TRACE("\n");
677
678     if(!is_class(dispex, JSCLASS_DATE))
679         return throw_type_error(dispex->ctx, ei, IDS_NOT_DATE, NULL);
680
681     if(retv) {
682         DateInstance *date = (DateInstance*)dispex;
683         num_set_val(retv, date->time);
684     }
685     return S_OK;
686 }
687
688 /* ECMA-262 3rd Edition    15.9.5.42 */
689 static HRESULT Date_toUTCString(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
690         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
691 {
692     static const WCHAR NaNW[] = { 'N','a','N',0 };
693     static const WCHAR formatADW[] = { '%','s',',',' ','%','d',' ','%','s',' ','%','d',' ',
694         '%','0','2','d',':','%','0','2','d',':','%','0','2','d',' ','U','T','C',0 };
695     static const WCHAR formatBCW[] = { '%','s',',',' ','%','d',' ','%','s',' ','%','d',' ','B','.','C','.',' ',
696         '%','0','2','d',':','%','0','2','d',':','%','0','2','d',' ','U','T','C',0 };
697
698     static const DWORD week_ids[] = { LOCALE_SABBREVDAYNAME7, LOCALE_SABBREVDAYNAME1,
699         LOCALE_SABBREVDAYNAME2, LOCALE_SABBREVDAYNAME3, LOCALE_SABBREVDAYNAME4,
700         LOCALE_SABBREVDAYNAME5, LOCALE_SABBREVDAYNAME6 };
701     static const DWORD month_ids[] = { LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2,
702         LOCALE_SABBREVMONTHNAME3, LOCALE_SABBREVMONTHNAME4,
703         LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6,
704         LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8,
705         LOCALE_SABBREVMONTHNAME9, LOCALE_SABBREVMONTHNAME10,
706         LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12 };
707
708     BOOL formatAD = TRUE;
709     BSTR week, month;
710     DateInstance *date;
711     BSTR date_str;
712     int len, size, year, day;
713     DWORD lcid_en, week_id, month_id;
714
715     TRACE("\n");
716
717     if(!is_class(dispex, JSCLASS_DATE))
718         return throw_type_error(dispex->ctx, ei, IDS_NOT_DATE, NULL);
719
720     date = (DateInstance*)dispex;
721
722     if(isnan(date->time)) {
723         if(retv) {
724             V_VT(retv) = VT_BSTR;
725             V_BSTR(retv) = SysAllocString(NaNW);
726             if(!V_BSTR(retv))
727                 return E_OUTOFMEMORY;
728         }
729         return S_OK;
730     }
731
732     if(retv) {
733         len = 17;
734
735         lcid_en = MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT);
736
737         week_id = week_ids[(int)week_day(date->time)];
738         size = GetLocaleInfoW(lcid_en, week_id, NULL, 0);
739         week = SysAllocStringLen(NULL, size);
740         if(!week)
741             return E_OUTOFMEMORY;
742         GetLocaleInfoW(lcid_en, week_id, week, size);
743         len += size-1;
744
745         month_id = month_ids[(int)month_from_time(date->time)];
746         size = GetLocaleInfoW(lcid_en, month_id, NULL, 0);
747         month = SysAllocStringLen(NULL, size);
748         if(!month) {
749             SysFreeString(week);
750             return E_OUTOFMEMORY;
751         }
752         GetLocaleInfoW(lcid_en, month_id, month, size);
753         len += size-1;
754
755         year = year_from_time(date->time);
756         if(year<0)
757             year = -year+1;
758         do {
759             year /= 10;
760             len++;
761         } while(year);
762
763         year = year_from_time(date->time);
764         if(year<0) {
765             formatAD = FALSE;
766             year = -year+1;
767             len += 5;
768         }
769
770         day = date_from_time(date->time);
771         do {
772             day /= 10;
773             len++;
774         } while(day);
775         day = date_from_time(date->time);
776
777         date_str = SysAllocStringLen(NULL, len);
778         if(!date_str) {
779             SysFreeString(week);
780             SysFreeString(month);
781             return E_OUTOFMEMORY;
782         }
783         sprintfW(date_str, formatAD?formatADW:formatBCW, week, day, month, year,
784                 (int)hour_from_time(date->time), (int)min_from_time(date->time),
785                 (int)sec_from_time(date->time));
786
787         SysFreeString(week);
788         SysFreeString(month);
789
790         V_VT(retv) = VT_BSTR;
791         V_BSTR(retv) = date_str;
792     }
793     return S_OK;
794 }
795
796 /* ECMA-262 3rd Edition    15.9.5.3 */
797 static HRESULT Date_toDateString(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
798         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
799 {
800     static const WCHAR NaNW[] = { 'N','a','N',0 };
801     static const WCHAR formatADW[] = { '%','s',' ','%','s',' ','%','d',' ','%','d',0 };
802     static const WCHAR formatBCW[] = { '%','s',' ','%','s',' ','%','d',' ','%','d',' ','B','.','C','.',0 };
803
804     static const DWORD week_ids[] = { LOCALE_SABBREVDAYNAME7, LOCALE_SABBREVDAYNAME1,
805         LOCALE_SABBREVDAYNAME2, LOCALE_SABBREVDAYNAME3, LOCALE_SABBREVDAYNAME4,
806         LOCALE_SABBREVDAYNAME5, LOCALE_SABBREVDAYNAME6 };
807     static const DWORD month_ids[] = { LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2,
808         LOCALE_SABBREVMONTHNAME3, LOCALE_SABBREVMONTHNAME4,
809         LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6,
810         LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8,
811         LOCALE_SABBREVMONTHNAME9, LOCALE_SABBREVMONTHNAME10,
812         LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12 };
813
814     BOOL formatAD = TRUE;
815     BSTR week, month;
816     DateInstance *date;
817     BSTR date_str;
818     DOUBLE time;
819     int len, size, year, day;
820     DWORD lcid_en, week_id, month_id;
821
822     TRACE("\n");
823
824     if(!is_class(dispex, JSCLASS_DATE))
825         return throw_type_error(dispex->ctx, ei, IDS_NOT_DATE, NULL);
826
827     date = (DateInstance*)dispex;
828
829     if(isnan(date->time)) {
830         if(retv) {
831             V_VT(retv) = VT_BSTR;
832             V_BSTR(retv) = SysAllocString(NaNW);
833             if(!V_BSTR(retv))
834                 return E_OUTOFMEMORY;
835         }
836         return S_OK;
837     }
838
839     time = local_time(date->time, date);
840
841     if(retv) {
842         len = 5;
843
844         lcid_en = MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT);
845
846         week_id = week_ids[(int)week_day(time)];
847         size = GetLocaleInfoW(lcid_en, week_id, NULL, 0);
848         week = SysAllocStringLen(NULL, size);
849         if(!week)
850             return E_OUTOFMEMORY;
851         GetLocaleInfoW(lcid_en, week_id, week, size);
852         len += size-1;
853
854         month_id = month_ids[(int)month_from_time(time)];
855         size = GetLocaleInfoW(lcid_en, month_id, NULL, 0);
856         month = SysAllocStringLen(NULL, size);
857         if(!month) {
858             SysFreeString(week);
859             return E_OUTOFMEMORY;
860         }
861         GetLocaleInfoW(lcid_en, month_id, month, size);
862         len += size-1;
863
864         year = year_from_time(time);
865         if(year<0)
866             year = -year+1;
867         do {
868             year /= 10;
869             len++;
870         } while(year);
871
872         year = year_from_time(time);
873         if(year<0) {
874             formatAD = FALSE;
875             year = -year+1;
876             len += 5;
877         }
878
879         day = date_from_time(time);
880         do {
881             day /= 10;
882             len++;
883         } while(day);
884         day = date_from_time(time);
885
886         date_str = SysAllocStringLen(NULL, len);
887         if(!date_str) {
888             SysFreeString(week);
889             SysFreeString(month);
890             return E_OUTOFMEMORY;
891         }
892         sprintfW(date_str, formatAD?formatADW:formatBCW, week, month, day, year);
893
894         SysFreeString(week);
895         SysFreeString(month);
896
897         V_VT(retv) = VT_BSTR;
898         V_BSTR(retv) = date_str;
899     }
900     return S_OK;
901 }
902
903 /* ECMA-262 3rd Edition    15.9.5.4 */
904 static HRESULT Date_toTimeString(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
905         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
906 {
907     static const WCHAR NaNW[] = { 'N','a','N',0 };
908     static const WCHAR formatW[] = { '%','0','2','d',':','%','0','2','d',':','%','0','2','d',
909         ' ','U','T','C','%','c','%','0','2','d','%','0','2','d',0 };
910     static const WCHAR formatUTCW[] = { '%','0','2','d',':','%','0','2','d',
911         ':','%','0','2','d',' ','U','T','C',0 };
912     DateInstance *date;
913     BSTR date_str;
914     DOUBLE time;
915     WCHAR sign;
916     int offset;
917
918     TRACE("\n");
919
920     if(!is_class(dispex, JSCLASS_DATE))
921         return throw_type_error(dispex->ctx, ei, IDS_NOT_DATE, NULL);
922
923     date = (DateInstance*)dispex;
924
925     if(isnan(date->time)) {
926         if(retv) {
927             V_VT(retv) = VT_BSTR;
928             V_BSTR(retv) = SysAllocString(NaNW);
929             if(!V_BSTR(retv))
930                 return E_OUTOFMEMORY;
931         }
932         return S_OK;
933     }
934
935     time = local_time(date->time, date);
936
937     if(retv) {
938         date_str = SysAllocStringLen(NULL, 17);
939         if(!date_str)
940             return E_OUTOFMEMORY;
941
942         offset = date->bias +
943             daylight_saving_ta(time, date);
944
945         if(offset < 0) {
946             sign = '+';
947             offset = -offset;
948         }
949         else sign = '-';
950
951         if(offset)
952             sprintfW(date_str, formatW, (int)hour_from_time(time),
953                     (int)min_from_time(time), (int)sec_from_time(time),
954                     sign, offset/60, offset%60);
955         else
956             sprintfW(date_str, formatUTCW, (int)hour_from_time(time),
957                     (int)min_from_time(time), (int)sec_from_time(time));
958
959         V_VT(retv) = VT_BSTR;
960         V_BSTR(retv) = date_str;
961     }
962     return S_OK;
963 }
964
965 /* ECMA-262 3rd Edition    15.9.5.6 */
966 static HRESULT Date_toLocaleDateString(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
967         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
968 {
969     static const WCHAR NaNW[] = { 'N','a','N',0 };
970     SYSTEMTIME st;
971     DateInstance *date;
972     BSTR date_str;
973     int len;
974
975     TRACE("\n");
976
977     if(!is_class(dispex, JSCLASS_DATE))
978         return throw_type_error(dispex->ctx, ei, IDS_NOT_DATE, NULL);
979
980     date = (DateInstance*)dispex;
981
982     if(isnan(date->time)) {
983         if(retv) {
984             V_VT(retv) = VT_BSTR;
985             V_BSTR(retv) = SysAllocString(NaNW);
986             if(!V_BSTR(retv))
987                 return E_OUTOFMEMORY;
988         }
989         return S_OK;
990     }
991
992     st = create_systemtime(local_time(date->time, date));
993
994     if(st.wYear<1601 || st.wYear>9999)
995         return Date_toDateString(dispex, lcid, flags, dp, retv, ei, caller);
996
997     if(retv) {
998         len = GetDateFormatW(lcid, DATE_LONGDATE, &st, NULL, NULL, 0);
999         date_str = SysAllocStringLen(NULL, len);
1000         if(!date_str)
1001             return E_OUTOFMEMORY;
1002         GetDateFormatW(lcid, DATE_LONGDATE, &st, NULL, date_str, len);
1003
1004         V_VT(retv) = VT_BSTR;
1005         V_BSTR(retv) = date_str;
1006     }
1007     return S_OK;
1008 }
1009
1010 /* ECMA-262 3rd Edition    15.9.5.7 */
1011 static HRESULT Date_toLocaleTimeString(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
1012         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
1013 {
1014     static const WCHAR NaNW[] = { 'N','a','N',0 };
1015     SYSTEMTIME st;
1016     DateInstance *date;
1017     BSTR date_str;
1018     int len;
1019
1020     TRACE("\n");
1021
1022     if(!is_class(dispex, JSCLASS_DATE))
1023         return throw_type_error(dispex->ctx, ei, IDS_NOT_DATE, NULL);
1024
1025     date = (DateInstance*)dispex;
1026
1027     if(isnan(date->time)) {
1028         if(retv) {
1029             V_VT(retv) = VT_BSTR;
1030             V_BSTR(retv) = SysAllocString(NaNW);
1031             if(!V_BSTR(retv))
1032                 return E_OUTOFMEMORY;
1033         }
1034         return S_OK;
1035     }
1036
1037     st = create_systemtime(local_time(date->time, date));
1038
1039     if(st.wYear<1601 || st.wYear>9999)
1040         return Date_toTimeString(dispex, lcid, flags, dp, retv, ei, caller);
1041
1042     if(retv) {
1043         len = GetTimeFormatW(lcid, 0, &st, NULL, NULL, 0);
1044         date_str = SysAllocStringLen(NULL, len);
1045         if(!date_str)
1046             return E_OUTOFMEMORY;
1047         GetTimeFormatW(lcid, 0, &st, NULL, date_str, len);
1048
1049         V_VT(retv) = VT_BSTR;
1050         V_BSTR(retv) = date_str;
1051     }
1052     return S_OK;
1053 }
1054
1055 /* ECMA-262 3rd Edition    15.9.5.9 */
1056 static HRESULT Date_getTime(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
1057         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
1058 {
1059     TRACE("\n");
1060
1061     if(!is_class(dispex, JSCLASS_DATE))
1062         return throw_type_error(dispex->ctx, ei, IDS_NOT_DATE, NULL);
1063
1064     if(retv) {
1065         DateInstance *date = (DateInstance*)dispex;
1066         num_set_val(retv, date->time);
1067     }
1068     return S_OK;
1069 }
1070
1071 /* ECMA-262 3rd Edition    15.9.5.10 */
1072 static HRESULT Date_getFullYear(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         return throw_type_error(dispex->ctx, ei, IDS_NOT_DATE, NULL);
1079
1080     if(retv) {
1081         DateInstance *date = (DateInstance*)dispex;
1082         DOUBLE time = local_time(date->time, date);
1083
1084         num_set_val(retv, year_from_time(time));
1085     }
1086     return S_OK;
1087 }
1088
1089 /* ECMA-262 3rd Edition    15.9.5.11 */
1090 static HRESULT Date_getUTCFullYear(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         return throw_type_error(dispex->ctx, ei, IDS_NOT_DATE, NULL);
1097
1098     if(retv) {
1099         DateInstance *date = (DateInstance*)dispex;
1100         num_set_val(retv, year_from_time(date->time));
1101     }
1102     return S_OK;
1103 }
1104
1105 /* ECMA-262 3rd Edition    15.9.5.12 */
1106 static HRESULT Date_getMonth(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
1107         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
1108 {
1109     TRACE("\n");
1110
1111     if(!is_class(dispex, JSCLASS_DATE))
1112         return throw_type_error(dispex->ctx, ei, IDS_NOT_DATE, NULL);
1113
1114     if(retv) {
1115         DateInstance *date = (DateInstance*)dispex;
1116         DOUBLE time = local_time(date->time, date);
1117
1118         num_set_val(retv, month_from_time(time));
1119     }
1120     return S_OK;
1121 }
1122
1123 /* ECMA-262 3rd Edition    15.9.5.13 */
1124 static HRESULT Date_getUTCMonth(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
1125         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
1126 {
1127     TRACE("\n");
1128
1129     if(!is_class(dispex, JSCLASS_DATE))
1130         return throw_type_error(dispex->ctx, ei, IDS_NOT_DATE, NULL);
1131
1132     if(retv) {
1133         DateInstance *date = (DateInstance*)dispex;
1134         num_set_val(retv, month_from_time(date->time));
1135     }
1136     return S_OK;
1137 }
1138
1139 /* ECMA-262 3rd Edition    15.9.5.14 */
1140 static HRESULT Date_getDate(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
1141         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
1142 {
1143     TRACE("\n");
1144
1145     if(!is_class(dispex, JSCLASS_DATE))
1146         return throw_type_error(dispex->ctx, ei, IDS_NOT_DATE, NULL);
1147
1148     if(retv) {
1149         DateInstance *date = (DateInstance*)dispex;
1150         DOUBLE time = local_time(date->time, date);
1151
1152         num_set_val(retv, date_from_time(time));
1153     }
1154     return S_OK;
1155 }
1156
1157 /* ECMA-262 3rd Edition    15.9.5.15 */
1158 static HRESULT Date_getUTCDate(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
1159         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
1160 {
1161     TRACE("\n");
1162
1163     if(!is_class(dispex, JSCLASS_DATE))
1164         return throw_type_error(dispex->ctx, ei, IDS_NOT_DATE, NULL);
1165
1166     if(retv) {
1167         DateInstance *date = (DateInstance*)dispex;
1168         num_set_val(retv, date_from_time(date->time));
1169     }
1170     return S_OK;
1171 }
1172
1173 /* ECMA-262 3rd Edition    15.9.5.16 */
1174 static HRESULT Date_getDay(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
1175         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
1176 {
1177     TRACE("\n");
1178
1179     if(!is_class(dispex, JSCLASS_DATE))
1180         return throw_type_error(dispex->ctx, ei, IDS_NOT_DATE, NULL);
1181
1182     if(retv) {
1183         DateInstance *date = (DateInstance*)dispex;
1184         DOUBLE time = local_time(date->time, date);
1185
1186         num_set_val(retv, week_day(time));
1187     }
1188     return S_OK;
1189 }
1190
1191 /* ECMA-262 3rd Edition    15.9.5.17 */
1192 static HRESULT Date_getUTCDay(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
1193         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
1194 {
1195     TRACE("\n");
1196
1197     if(!is_class(dispex, JSCLASS_DATE))
1198         return throw_type_error(dispex->ctx, ei, IDS_NOT_DATE, NULL);
1199
1200     if(retv) {
1201         DateInstance *date = (DateInstance*)dispex;
1202         num_set_val(retv, week_day(date->time));
1203     }
1204     return S_OK;
1205 }
1206
1207 /* ECMA-262 3rd Edition    15.9.5.18 */
1208 static HRESULT Date_getHours(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
1209         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
1210 {
1211     TRACE("\n");
1212
1213     if(!is_class(dispex, JSCLASS_DATE))
1214         return throw_type_error(dispex->ctx, ei, IDS_NOT_DATE, NULL);
1215
1216     if(retv) {
1217         DateInstance *date = (DateInstance*)dispex;
1218         DOUBLE time = local_time(date->time, date);
1219
1220         num_set_val(retv, hour_from_time(time));
1221     }
1222     return S_OK;
1223 }
1224
1225 /* ECMA-262 3rd Edition    15.9.5.19 */
1226 static HRESULT Date_getUTCHours(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
1227         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
1228 {
1229     TRACE("\n");
1230
1231     if(!is_class(dispex, JSCLASS_DATE))
1232         return throw_type_error(dispex->ctx, ei, IDS_NOT_DATE, NULL);
1233
1234     if(retv) {
1235         DateInstance *date = (DateInstance*)dispex;
1236         num_set_val(retv, hour_from_time(date->time));
1237     }
1238     return S_OK;
1239 }
1240
1241 /* ECMA-262 3rd Edition    15.9.5.20 */
1242 static HRESULT Date_getMinutes(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         return throw_type_error(dispex->ctx, ei, IDS_NOT_DATE, NULL);
1249
1250     if(retv) {
1251         DateInstance *date = (DateInstance*)dispex;
1252         DOUBLE time = local_time(date->time, date);
1253
1254         num_set_val(retv, min_from_time(time));
1255     }
1256     return S_OK;
1257 }
1258
1259 /* ECMA-262 3rd Edition    15.9.5.21 */
1260 static HRESULT Date_getUTCMinutes(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
1261         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
1262 {
1263     TRACE("\n");
1264
1265     if(!is_class(dispex, JSCLASS_DATE))
1266         return throw_type_error(dispex->ctx, ei, IDS_NOT_DATE, NULL);
1267
1268     if(retv) {
1269         DateInstance *date = (DateInstance*)dispex;
1270         num_set_val(retv, min_from_time(date->time));
1271     }
1272     return S_OK;
1273 }
1274
1275 /* ECMA-262 3rd Edition    15.9.5.22 */
1276 static HRESULT Date_getSeconds(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
1277         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
1278 {
1279     TRACE("\n");
1280
1281     if(!is_class(dispex, JSCLASS_DATE))
1282         return throw_type_error(dispex->ctx, ei, IDS_NOT_DATE, NULL);
1283
1284     if(retv) {
1285         DateInstance *date = (DateInstance*)dispex;
1286         DOUBLE time = local_time(date->time, date);
1287
1288         num_set_val(retv, sec_from_time(time));
1289     }
1290     return S_OK;
1291 }
1292
1293 /* ECMA-262 3rd Edition    15.9.5.23 */
1294 static HRESULT Date_getUTCSeconds(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
1295         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
1296 {
1297     TRACE("\n");
1298
1299     if(!is_class(dispex, JSCLASS_DATE))
1300         return throw_type_error(dispex->ctx, ei, IDS_NOT_DATE, NULL);
1301
1302     if(retv) {
1303         DateInstance *date = (DateInstance*)dispex;
1304         num_set_val(retv, sec_from_time(date->time));
1305     }
1306     return S_OK;
1307 }
1308
1309 /* ECMA-262 3rd Edition    15.9.5.24 */
1310 static HRESULT Date_getMilliseconds(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
1311         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
1312 {
1313     TRACE("\n");
1314
1315     if(!is_class(dispex, JSCLASS_DATE))
1316         return throw_type_error(dispex->ctx, ei, IDS_NOT_DATE, NULL);
1317
1318     if(retv) {
1319         DateInstance *date = (DateInstance*)dispex;
1320         DOUBLE time = local_time(date->time, date);
1321
1322         num_set_val(retv, ms_from_time(time));
1323     }
1324     return S_OK;
1325 }
1326
1327 /* ECMA-262 3rd Edition    15.9.5.25 */
1328 static HRESULT Date_getUTCMilliseconds(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
1329         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
1330 {
1331     TRACE("\n");
1332
1333     if(!is_class(dispex, JSCLASS_DATE))
1334         return throw_type_error(dispex->ctx, ei, IDS_NOT_DATE, NULL);
1335
1336     if(retv) {
1337         DateInstance *date = (DateInstance*)dispex;
1338         num_set_val(retv, ms_from_time(date->time));
1339     }
1340     return S_OK;
1341 }
1342
1343 /* ECMA-262 3rd Edition    15.9.5.26 */
1344 static HRESULT Date_getTimezoneOffset(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
1345         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
1346 {
1347     TRACE("\n");
1348
1349     if(!is_class(dispex, JSCLASS_DATE))
1350         return throw_type_error(dispex->ctx, ei, IDS_NOT_DATE, NULL);
1351
1352     if(retv) {
1353         DateInstance *date = (DateInstance*)dispex;
1354         num_set_val(retv, floor(
1355                     (date->time-local_time(date->time, date))/MS_PER_MINUTE));
1356     }
1357     return S_OK;
1358 }
1359
1360 /* ECMA-262 3rd Edition    15.9.5.27 */
1361 static HRESULT Date_setTime(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
1362         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
1363 {
1364     VARIANT v;
1365     HRESULT hres;
1366     DateInstance *date;
1367
1368     TRACE("\n");
1369
1370     if(!is_class(dispex, JSCLASS_DATE))
1371         return throw_type_error(dispex->ctx, ei, IDS_NOT_DATE, NULL);
1372
1373     if(!arg_cnt(dp))
1374         return throw_type_error(dispex->ctx, ei, IDS_ARG_NOT_OPT, NULL);
1375
1376     hres = to_number(dispex->ctx, get_arg(dp, 0), ei, &v);
1377     if(FAILED(hres))
1378         return hres;
1379
1380     date = (DateInstance*)dispex;
1381     date->time = time_clip(num_val(&v));
1382
1383     if(retv)
1384         num_set_val(retv, date->time);
1385
1386     return S_OK;
1387 }
1388
1389 /* ECMA-262 3rd Edition    15.9.5.28 */
1390 static HRESULT Date_setMilliseconds(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
1391         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
1392 {
1393     VARIANT v;
1394     HRESULT hres;
1395     DateInstance *date;
1396     DOUBLE t;
1397
1398     TRACE("\n");
1399
1400     if(!is_class(dispex, JSCLASS_DATE))
1401         return throw_type_error(dispex->ctx, ei, IDS_NOT_DATE, NULL);
1402
1403     if(!arg_cnt(dp))
1404         return throw_type_error(dispex->ctx, ei, IDS_ARG_NOT_OPT, NULL);
1405
1406     hres = to_number(dispex->ctx, get_arg(dp, 0), ei, &v);
1407     if(FAILED(hres))
1408         return hres;
1409
1410     date = (DateInstance*)dispex;
1411     t = local_time(date->time, date);
1412     t = make_date(day(t), make_time(hour_from_time(t), min_from_time(t),
1413                 sec_from_time(t), num_val(&v)));
1414     date->time = time_clip(utc(t, date));
1415
1416     if(retv)
1417         num_set_val(retv, date->time);
1418
1419     return S_OK;
1420 }
1421
1422 /* ECMA-262 3rd Edition    15.9.5.29 */
1423 static HRESULT Date_setUTCMilliseconds(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
1424         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
1425 {
1426     VARIANT v;
1427     HRESULT hres;
1428     DateInstance *date;
1429     DOUBLE t;
1430
1431     TRACE("\n");
1432
1433     if(!is_class(dispex, JSCLASS_DATE))
1434         return throw_type_error(dispex->ctx, ei, IDS_NOT_DATE, NULL);
1435
1436     if(!arg_cnt(dp))
1437         return throw_type_error(dispex->ctx, ei, IDS_ARG_NOT_OPT, NULL);
1438
1439     hres = to_number(dispex->ctx, get_arg(dp, 0), ei, &v);
1440     if(FAILED(hres))
1441         return hres;
1442
1443     date = (DateInstance*)dispex;
1444     t = date->time;
1445     t = make_date(day(t), make_time(hour_from_time(t), min_from_time(t),
1446                 sec_from_time(t), num_val(&v)));
1447     date->time = time_clip(t);
1448
1449     if(retv)
1450         num_set_val(retv, date->time);
1451
1452     return S_OK;
1453 }
1454
1455 /* ECMA-262 3rd Edition    15.9.5.30 */
1456 static HRESULT Date_setSeconds(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
1457         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
1458 {
1459     VARIANT v;
1460     HRESULT hres;
1461     DateInstance *date;
1462     DOUBLE t, sec, ms;
1463
1464     TRACE("\n");
1465
1466     if(!is_class(dispex, JSCLASS_DATE))
1467         return throw_type_error(dispex->ctx, ei, IDS_NOT_DATE, NULL);
1468
1469     if(!arg_cnt(dp))
1470         return throw_type_error(dispex->ctx, ei, IDS_ARG_NOT_OPT, NULL);
1471
1472     date = (DateInstance*)dispex;
1473     t = local_time(date->time, date);
1474
1475     hres = to_number(dispex->ctx, get_arg(dp, 0), ei, &v);
1476     if(FAILED(hres))
1477         return hres;
1478     sec = num_val(&v);
1479
1480     if(arg_cnt(dp) > 1) {
1481         hres = to_number(dispex->ctx, get_arg(dp, 1), ei, &v);
1482         if(FAILED(hres))
1483             return hres;
1484         ms = num_val(&v);
1485     }
1486     else ms = ms_from_time(t);
1487
1488     t = make_date(day(t), make_time(hour_from_time(t),
1489                 min_from_time(t), sec, ms));
1490     date->time = time_clip(utc(t, date));
1491
1492     if(retv)
1493         num_set_val(retv, date->time);
1494
1495     return S_OK;
1496 }
1497
1498 /* ECMA-262 3rd Edition    15.9.5.31 */
1499 static HRESULT Date_setUTCSeconds(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
1500         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
1501 {
1502     VARIANT v;
1503     HRESULT hres;
1504     DateInstance *date;
1505     DOUBLE t, sec, ms;
1506
1507     TRACE("\n");
1508
1509     if(!is_class(dispex, JSCLASS_DATE))
1510         return throw_type_error(dispex->ctx, ei, IDS_NOT_DATE, NULL);
1511
1512     if(!arg_cnt(dp))
1513         return throw_type_error(dispex->ctx, ei, IDS_ARG_NOT_OPT, NULL);
1514
1515     date = (DateInstance*)dispex;
1516     t = date->time;
1517
1518     hres = to_number(dispex->ctx, get_arg(dp, 0), ei, &v);
1519     if(FAILED(hres))
1520         return hres;
1521     sec = num_val(&v);
1522
1523     if(arg_cnt(dp) > 1) {
1524         hres = to_number(dispex->ctx, get_arg(dp, 1), ei, &v);
1525         if(FAILED(hres))
1526             return hres;
1527         ms = num_val(&v);
1528     }
1529     else ms = ms_from_time(t);
1530
1531     t = make_date(day(t), make_time(hour_from_time(t),
1532                 min_from_time(t), sec, ms));
1533     date->time = time_clip(t);
1534
1535     if(retv)
1536         num_set_val(retv, date->time);
1537
1538     return S_OK;
1539 }
1540
1541 /* ECMA-262 3rd Edition    15.9.5.33 */
1542 static HRESULT Date_setMinutes(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
1543         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
1544 {
1545     VARIANT v;
1546     HRESULT hres;
1547     DateInstance *date;
1548     DOUBLE t, min, sec, ms;
1549
1550     TRACE("\n");
1551
1552     if(!is_class(dispex, JSCLASS_DATE))
1553         return throw_type_error(dispex->ctx, ei, IDS_NOT_DATE, NULL);
1554
1555     if(!arg_cnt(dp))
1556         return throw_type_error(dispex->ctx, ei, IDS_ARG_NOT_OPT, NULL);
1557
1558     date = (DateInstance*)dispex;
1559     t = local_time(date->time, date);
1560
1561     hres = to_number(dispex->ctx, get_arg(dp, 0), ei, &v);
1562     if(FAILED(hres))
1563         return hres;
1564     min = num_val(&v);
1565
1566     if(arg_cnt(dp) > 1) {
1567         hres = to_number(dispex->ctx, get_arg(dp, 1), ei, &v);
1568         if(FAILED(hres))
1569             return hres;
1570         sec = num_val(&v);
1571     }
1572     else sec = sec_from_time(t);
1573
1574     if(arg_cnt(dp) > 2) {
1575         hres = to_number(dispex->ctx, get_arg(dp, 2), ei, &v);
1576         if(FAILED(hres))
1577             return hres;
1578         ms = num_val(&v);
1579     }
1580     else ms = ms_from_time(t);
1581
1582     t = make_date(day(t), make_time(hour_from_time(t),
1583                 min, sec, ms));
1584     date->time = time_clip(utc(t, date));
1585
1586     if(retv)
1587         num_set_val(retv, date->time);
1588
1589     return S_OK;
1590 }
1591
1592 /* ECMA-262 3rd Edition    15.9.5.34 */
1593 static HRESULT Date_setUTCMinutes(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
1594         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
1595 {
1596     VARIANT v;
1597     HRESULT hres;
1598     DateInstance *date;
1599     DOUBLE t, min, sec, ms;
1600
1601     TRACE("\n");
1602
1603     if(!is_class(dispex, JSCLASS_DATE))
1604         return throw_type_error(dispex->ctx, ei, IDS_NOT_DATE, NULL);
1605
1606     if(!arg_cnt(dp))
1607         return throw_type_error(dispex->ctx, ei, IDS_ARG_NOT_OPT, NULL);
1608
1609     date = (DateInstance*)dispex;
1610     t = date->time;
1611
1612     hres = to_number(dispex->ctx, get_arg(dp, 0), ei, &v);
1613     if(FAILED(hres))
1614         return hres;
1615     min = num_val(&v);
1616
1617     if(arg_cnt(dp) > 1) {
1618         hres = to_number(dispex->ctx, get_arg(dp, 1), ei, &v);
1619         if(FAILED(hres))
1620             return hres;
1621         sec = num_val(&v);
1622     }
1623     else sec = sec_from_time(t);
1624
1625     if(arg_cnt(dp) > 2) {
1626         hres = to_number(dispex->ctx, get_arg(dp, 2), ei, &v);
1627         if(FAILED(hres))
1628             return hres;
1629         ms = num_val(&v);
1630     }
1631     else ms = ms_from_time(t);
1632
1633     t = make_date(day(t), make_time(hour_from_time(t),
1634                 min, sec, ms));
1635     date->time = time_clip(t);
1636
1637     if(retv)
1638         num_set_val(retv, date->time);
1639
1640     return S_OK;
1641 }
1642
1643 /* ECMA-262 3rd Edition    15.9.5.35 */
1644 static HRESULT Date_setHours(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
1645         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
1646 {
1647     VARIANT v;
1648     HRESULT hres;
1649     DateInstance *date;
1650     DOUBLE t, hour, min, sec, ms;
1651
1652     TRACE("\n");
1653
1654     if(!is_class(dispex, JSCLASS_DATE))
1655         return throw_type_error(dispex->ctx, ei, IDS_NOT_DATE, NULL);
1656
1657     if(!arg_cnt(dp))
1658         return throw_type_error(dispex->ctx, ei, IDS_ARG_NOT_OPT, NULL);
1659
1660     date = (DateInstance*)dispex;
1661     t = local_time(date->time, date);
1662
1663     hres = to_number(dispex->ctx, get_arg(dp, 0), ei, &v);
1664     if(FAILED(hres))
1665         return hres;
1666     hour = num_val(&v);
1667
1668     if(arg_cnt(dp) > 1) {
1669         hres = to_number(dispex->ctx, get_arg(dp, 1), ei, &v);
1670         if(FAILED(hres))
1671             return hres;
1672         min = num_val(&v);
1673     }
1674     else min = min_from_time(t);
1675
1676     if(arg_cnt(dp) > 2) {
1677         hres = to_number(dispex->ctx, get_arg(dp, 2), ei, &v);
1678         if(FAILED(hres))
1679             return hres;
1680         sec = num_val(&v);
1681     }
1682     else sec = sec_from_time(t);
1683
1684     if(arg_cnt(dp) > 3) {
1685         hres = to_number(dispex->ctx, get_arg(dp, 3), ei, &v);
1686         if(FAILED(hres))
1687             return hres;
1688         ms = num_val(&v);
1689     }
1690     else ms = ms_from_time(t);
1691
1692     t = make_date(day(t), make_time(hour, min, sec, ms));
1693     date->time = time_clip(utc(t, date));
1694
1695     if(retv)
1696         num_set_val(retv, date->time);
1697
1698     return S_OK;
1699 }
1700
1701 /* ECMA-262 3rd Edition    15.9.5.36 */
1702 static HRESULT Date_setUTCHours(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
1703         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
1704 {
1705     VARIANT v;
1706     HRESULT hres;
1707     DateInstance *date;
1708     DOUBLE t, hour, min, sec, ms;
1709
1710     TRACE("\n");
1711
1712     if(!is_class(dispex, JSCLASS_DATE))
1713         return throw_type_error(dispex->ctx, ei, IDS_NOT_DATE, NULL);
1714
1715     if(!arg_cnt(dp))
1716         return throw_type_error(dispex->ctx, ei, IDS_ARG_NOT_OPT, NULL);
1717
1718     date = (DateInstance*)dispex;
1719     t = date->time;
1720
1721     hres = to_number(dispex->ctx, get_arg(dp, 0), ei, &v);
1722     if(FAILED(hres))
1723         return hres;
1724     hour = num_val(&v);
1725
1726     if(arg_cnt(dp) > 1) {
1727         hres = to_number(dispex->ctx, get_arg(dp, 1), ei, &v);
1728         if(FAILED(hres))
1729             return hres;
1730         min = num_val(&v);
1731     }
1732     else min = min_from_time(t);
1733
1734     if(arg_cnt(dp) > 2) {
1735         hres = to_number(dispex->ctx, get_arg(dp, 2), ei, &v);
1736         if(FAILED(hres))
1737             return hres;
1738         sec = num_val(&v);
1739     }
1740     else sec = sec_from_time(t);
1741
1742     if(arg_cnt(dp) > 3) {
1743         hres = to_number(dispex->ctx, get_arg(dp, 3), ei, &v);
1744         if(FAILED(hres))
1745             return hres;
1746         ms = num_val(&v);
1747     }
1748     else ms = ms_from_time(t);
1749
1750     t = make_date(day(t), make_time(hour, min, sec, ms));
1751     date->time = time_clip(t);
1752
1753     if(retv)
1754         num_set_val(retv, date->time);
1755
1756     return S_OK;
1757 }
1758
1759 /* ECMA-262 3rd Edition    15.9.5.36 */
1760 static HRESULT Date_setDate(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
1761         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
1762 {
1763     VARIANT v;
1764     HRESULT hres;
1765     DateInstance *date;
1766     DOUBLE t;
1767
1768     TRACE("\n");
1769
1770     if(!is_class(dispex, JSCLASS_DATE))
1771         return throw_type_error(dispex->ctx, ei, IDS_NOT_DATE, NULL);
1772
1773     if(!arg_cnt(dp))
1774         return throw_type_error(dispex->ctx, ei, IDS_ARG_NOT_OPT, NULL);
1775
1776     hres = to_number(dispex->ctx, get_arg(dp, 0), ei, &v);
1777     if(FAILED(hres))
1778         return hres;
1779
1780     date = (DateInstance*)dispex;
1781     t = local_time(date->time, date);
1782     t = make_date(make_day(year_from_time(t), month_from_time(t),
1783                 num_val(&v)), time_within_day(t));
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.37 */
1793 static HRESULT Date_setUTCDate(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;
1800
1801     TRACE("\n");
1802
1803     if(!is_class(dispex, JSCLASS_DATE))
1804         return throw_type_error(dispex->ctx, ei, IDS_NOT_DATE, NULL);
1805
1806     if(!arg_cnt(dp))
1807         return throw_type_error(dispex->ctx, ei, IDS_ARG_NOT_OPT, NULL);
1808
1809     hres = to_number(dispex->ctx, get_arg(dp, 0), ei, &v);
1810     if(FAILED(hres))
1811         return hres;
1812
1813     date = (DateInstance*)dispex;
1814     t = date->time;
1815     t = make_date(make_day(year_from_time(t), month_from_time(t),
1816                 num_val(&v)), time_within_day(t));
1817     date->time = time_clip(t);
1818
1819     if(retv)
1820         num_set_val(retv, date->time);
1821
1822     return S_OK;
1823 }
1824
1825 /* ECMA-262 3rd Edition    15.9.5.38 */
1826 static HRESULT Date_setMonth(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
1827         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
1828 {
1829     VARIANT v;
1830     HRESULT hres;
1831     DateInstance *date;
1832     DOUBLE t, month, ddate;
1833
1834     TRACE("\n");
1835
1836     if(!is_class(dispex, JSCLASS_DATE))
1837         return throw_type_error(dispex->ctx, ei, IDS_NOT_DATE, NULL);
1838
1839     if(!arg_cnt(dp))
1840         return throw_type_error(dispex->ctx, ei, IDS_ARG_NOT_OPT, NULL);
1841
1842     date = (DateInstance*)dispex;
1843     t = local_time(date->time, date);
1844
1845     hres = to_number(dispex->ctx, get_arg(dp, 0), ei, &v);
1846     if(FAILED(hres))
1847         return hres;
1848     month = num_val(&v);
1849
1850     if(arg_cnt(dp) > 1) {
1851         hres = to_number(dispex->ctx, get_arg(dp, 1), ei, &v);
1852         if(FAILED(hres))
1853             return hres;
1854         ddate = num_val(&v);
1855     }
1856     else ddate = date_from_time(t);
1857
1858     t = make_date(make_day(year_from_time(t), month, ddate),
1859             time_within_day(t));
1860     date->time = time_clip(utc(t, date));
1861
1862     if(retv)
1863         num_set_val(retv, date->time);
1864
1865     return S_OK;
1866 }
1867
1868 /* ECMA-262 3rd Edition    15.9.5.39 */
1869 static HRESULT Date_setUTCMonth(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
1870         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
1871 {
1872     VARIANT v;
1873     HRESULT hres;
1874     DateInstance *date;
1875     DOUBLE t, month, ddate;
1876
1877     TRACE("\n");
1878
1879     if(!is_class(dispex, JSCLASS_DATE))
1880         return throw_type_error(dispex->ctx, ei, IDS_NOT_DATE, NULL);
1881
1882     if(!arg_cnt(dp))
1883         return throw_type_error(dispex->ctx, ei, IDS_ARG_NOT_OPT, NULL);
1884
1885     date = (DateInstance*)dispex;
1886     t = date->time;
1887
1888     hres = to_number(dispex->ctx, get_arg(dp, 0), ei, &v);
1889     if(FAILED(hres))
1890         return hres;
1891     month = num_val(&v);
1892
1893     if(arg_cnt(dp) > 1) {
1894         hres = to_number(dispex->ctx, get_arg(dp, 1), ei, &v);
1895         if(FAILED(hres))
1896             return hres;
1897         ddate = num_val(&v);
1898     }
1899     else ddate = date_from_time(t);
1900
1901     t = make_date(make_day(year_from_time(t), month, ddate),
1902             time_within_day(t));
1903     date->time = time_clip(t);
1904
1905     if(retv)
1906         num_set_val(retv, date->time);
1907
1908     return S_OK;
1909 }
1910
1911 /* ECMA-262 3rd Edition    15.9.5.40 */
1912 static HRESULT Date_setFullYear(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
1913         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
1914 {
1915     VARIANT v;
1916     HRESULT hres;
1917     DateInstance *date;
1918     DOUBLE t, year, month, ddate;
1919
1920     TRACE("\n");
1921
1922     if(!is_class(dispex, JSCLASS_DATE))
1923         return throw_type_error(dispex->ctx, ei, IDS_NOT_DATE, NULL);
1924
1925     if(!arg_cnt(dp))
1926         return throw_type_error(dispex->ctx, ei, IDS_ARG_NOT_OPT, NULL);
1927
1928     date = (DateInstance*)dispex;
1929     t = local_time(date->time, date);
1930
1931     hres = to_number(dispex->ctx, get_arg(dp, 0), ei, &v);
1932     if(FAILED(hres))
1933         return hres;
1934     year = num_val(&v);
1935
1936     if(arg_cnt(dp) > 1) {
1937         hres = to_number(dispex->ctx, get_arg(dp, 1), ei, &v);
1938         if(FAILED(hres))
1939             return hres;
1940         month = num_val(&v);
1941     }
1942     else month = month_from_time(t);
1943
1944     if(arg_cnt(dp) > 2) {
1945         hres = to_number(dispex->ctx, get_arg(dp, 2), ei, &v);
1946         if(FAILED(hres))
1947             return hres;
1948         ddate = num_val(&v);
1949     }
1950     else ddate = date_from_time(t);
1951
1952     t = make_date(make_day(year, month, ddate), time_within_day(t));
1953     date->time = time_clip(utc(t, date));
1954
1955     if(retv)
1956         num_set_val(retv, date->time);
1957
1958     return S_OK;
1959 }
1960
1961 /* ECMA-262 3rd Edition    15.9.5.41 */
1962 static HRESULT Date_setUTCFullYear(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
1963         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
1964 {
1965     VARIANT v;
1966     HRESULT hres;
1967     DateInstance *date;
1968     DOUBLE t, year, month, ddate;
1969
1970     TRACE("\n");
1971
1972     if(!is_class(dispex, JSCLASS_DATE))
1973         return throw_type_error(dispex->ctx, ei, IDS_NOT_DATE, NULL);
1974
1975     if(!arg_cnt(dp))
1976         return throw_type_error(dispex->ctx, ei, IDS_ARG_NOT_OPT, NULL);
1977
1978     date = (DateInstance*)dispex;
1979     t = date->time;
1980
1981     hres = to_number(dispex->ctx, get_arg(dp, 0), ei, &v);
1982     if(FAILED(hres))
1983         return hres;
1984     year = num_val(&v);
1985
1986     if(arg_cnt(dp) > 1) {
1987         hres = to_number(dispex->ctx, get_arg(dp, 1), ei, &v);
1988         if(FAILED(hres))
1989             return hres;
1990         month = num_val(&v);
1991     }
1992     else month = month_from_time(t);
1993
1994     if(arg_cnt(dp) > 2) {
1995         hres = to_number(dispex->ctx, get_arg(dp, 2), ei, &v);
1996         if(FAILED(hres))
1997             return hres;
1998         ddate = num_val(&v);
1999     }
2000     else ddate = date_from_time(t);
2001
2002     t = make_date(make_day(year, month, ddate), time_within_day(t));
2003     date->time = time_clip(t);
2004
2005     if(retv)
2006         num_set_val(retv, date->time);
2007
2008     return S_OK;
2009 }
2010
2011 /* ECMA-262 3rd Edition    B2.4 */
2012 static HRESULT Date_getYear(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
2013         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
2014 {
2015     DateInstance *date;
2016     DOUBLE t, year;
2017
2018     TRACE("\n");
2019
2020     if(!is_class(dispex, JSCLASS_DATE))
2021         return throw_type_error(dispex->ctx, ei, IDS_NOT_DATE, NULL);
2022
2023     date = (DateInstance*)dispex;
2024     t = local_time(date->time, date);
2025
2026
2027     if(isnan(t)) {
2028         if(retv)
2029             num_set_nan(retv);
2030         return S_OK;
2031     }
2032
2033     year = year_from_time(t);
2034     if(retv)
2035         num_set_val(retv, (1900<=year && year<2000)?year-1900:year);
2036
2037     return S_OK;
2038 }
2039
2040 static HRESULT Date_value(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
2041         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
2042 {
2043     TRACE("\n");
2044
2045     switch(flags) {
2046     case INVOKE_FUNC:
2047         return throw_type_error(dispex->ctx, ei, IDS_NOT_FUNC, NULL);
2048     default:
2049         FIXME("unimplemented flags %x\n", flags);
2050         return E_NOTIMPL;
2051     }
2052
2053     return S_OK;
2054 }
2055
2056 static const builtin_prop_t Date_props[] = {
2057     {getDateW,               Date_getDate,               PROPF_METHOD},
2058     {getDayW,                Date_getDay,                PROPF_METHOD},
2059     {getFullYearW,           Date_getFullYear,           PROPF_METHOD},
2060     {getHoursW,              Date_getHours,              PROPF_METHOD},
2061     {getMillisecondsW,       Date_getMilliseconds,       PROPF_METHOD},
2062     {getMinutesW,            Date_getMinutes,            PROPF_METHOD},
2063     {getMonthW,              Date_getMonth,              PROPF_METHOD},
2064     {getSecondsW,            Date_getSeconds,            PROPF_METHOD},
2065     {getTimeW,               Date_getTime,               PROPF_METHOD},
2066     {getTimezoneOffsetW,     Date_getTimezoneOffset,     PROPF_METHOD},
2067     {getUTCDateW,            Date_getUTCDate,            PROPF_METHOD},
2068     {getUTCDayW,             Date_getUTCDay,             PROPF_METHOD},
2069     {getUTCFullYearW,        Date_getUTCFullYear,        PROPF_METHOD},
2070     {getUTCHoursW,           Date_getUTCHours,           PROPF_METHOD},
2071     {getUTCMillisecondsW,    Date_getUTCMilliseconds,    PROPF_METHOD},
2072     {getUTCMinutesW,         Date_getUTCMinutes,         PROPF_METHOD},
2073     {getUTCMonthW,           Date_getUTCMonth,           PROPF_METHOD},
2074     {getUTCSecondsW,         Date_getUTCSeconds,         PROPF_METHOD},
2075     {getYearW,               Date_getYear,               PROPF_METHOD},
2076     {hasOwnPropertyW,        Date_hasOwnProperty,        PROPF_METHOD},
2077     {isPrototypeOfW,         Date_isPrototypeOf,         PROPF_METHOD},
2078     {propertyIsEnumerableW,  Date_propertyIsEnumerable,  PROPF_METHOD},
2079     {setDateW,               Date_setDate,               PROPF_METHOD},
2080     {setFullYearW,           Date_setFullYear,           PROPF_METHOD},
2081     {setHoursW,              Date_setHours,              PROPF_METHOD},
2082     {setMillisecondsW,       Date_setMilliseconds,       PROPF_METHOD},
2083     {setMinutesW,            Date_setMinutes,            PROPF_METHOD},
2084     {setMonthW,              Date_setMonth,              PROPF_METHOD},
2085     {setSecondsW,            Date_setSeconds,            PROPF_METHOD},
2086     {setTimeW,               Date_setTime,               PROPF_METHOD},
2087     {setUTCDateW,            Date_setUTCDate,            PROPF_METHOD},
2088     {setUTCFullYearW,        Date_setUTCFullYear,        PROPF_METHOD},
2089     {setUTCHoursW,           Date_setUTCHours,           PROPF_METHOD},
2090     {setUTCMillisecondsW,    Date_setUTCMilliseconds,    PROPF_METHOD},
2091     {setUTCMinutesW,         Date_setUTCMinutes,         PROPF_METHOD},
2092     {setUTCMonthW,           Date_setUTCMonth,           PROPF_METHOD},
2093     {setUTCSecondsW,         Date_setUTCSeconds,         PROPF_METHOD},
2094     {toDateStringW,          Date_toDateString,          PROPF_METHOD},
2095     {toLocaleDateStringW,    Date_toLocaleDateString,    PROPF_METHOD},
2096     {toLocaleStringW,        Date_toLocaleString,        PROPF_METHOD},
2097     {toLocaleTimeStringW,    Date_toLocaleTimeString,    PROPF_METHOD},
2098     {toStringW,              Date_toString,              PROPF_METHOD},
2099     {toTimeStringW,          Date_toTimeString,          PROPF_METHOD},
2100     {toUTCStringW,           Date_toUTCString,           PROPF_METHOD},
2101     {valueOfW,               Date_valueOf,               PROPF_METHOD},
2102 };
2103
2104 static const builtin_info_t Date_info = {
2105     JSCLASS_DATE,
2106     {NULL, Date_value, 0},
2107     sizeof(Date_props)/sizeof(*Date_props),
2108     Date_props,
2109     NULL,
2110     NULL
2111 };
2112
2113 static HRESULT create_date(script_ctx_t *ctx, BOOL use_constr, DOUBLE time, DispatchEx **ret)
2114 {
2115     DateInstance *date;
2116     HRESULT hres;
2117     TIME_ZONE_INFORMATION tzi;
2118
2119     GetTimeZoneInformation(&tzi);
2120
2121     date = heap_alloc_zero(sizeof(DateInstance));
2122     if(!date)
2123         return E_OUTOFMEMORY;
2124
2125     if(use_constr)
2126         hres = init_dispex_from_constr(&date->dispex, ctx, &Date_info, ctx->date_constr);
2127     else
2128         hres = init_dispex(&date->dispex, ctx, &Date_info, NULL);
2129     if(FAILED(hres)) {
2130         heap_free(date);
2131         return hres;
2132     }
2133
2134     date->time = time;
2135     date->bias = tzi.Bias;
2136     date->standardDate = tzi.StandardDate;
2137     date->standardBias = tzi.StandardBias;
2138     date->daylightDate = tzi.DaylightDate;
2139     date->daylightBias = tzi.DaylightBias;
2140
2141     *ret = &date->dispex;
2142     return S_OK;
2143 }
2144
2145 static inline HRESULT date_parse(BSTR input, VARIANT *retv) {
2146     static const DWORD string_ids[] = { LOCALE_SMONTHNAME12, LOCALE_SMONTHNAME11,
2147         LOCALE_SMONTHNAME10, LOCALE_SMONTHNAME9, LOCALE_SMONTHNAME8,
2148         LOCALE_SMONTHNAME7, LOCALE_SMONTHNAME6, LOCALE_SMONTHNAME5,
2149         LOCALE_SMONTHNAME4, LOCALE_SMONTHNAME3, LOCALE_SMONTHNAME2,
2150         LOCALE_SMONTHNAME1, LOCALE_SDAYNAME7, LOCALE_SDAYNAME1,
2151         LOCALE_SDAYNAME2, LOCALE_SDAYNAME3, LOCALE_SDAYNAME4,
2152         LOCALE_SDAYNAME5, LOCALE_SDAYNAME6 };
2153     BSTR strings[sizeof(string_ids)/sizeof(DWORD)];
2154
2155     BSTR parse;
2156     int input_len, parse_len = 0, nest_level = 0, i, size;
2157     int year = 0, month = 0, day = 0, hour = 0, min = 0, sec = 0;
2158     int ms = 0, offset = 0, hour_adjust = 0;
2159     BOOL set_year = FALSE, set_month = FALSE, set_day = FALSE, set_hour = FALSE;
2160     BOOL set_offset = FALSE, set_era = FALSE, ad = TRUE, set_am = FALSE, am = TRUE;
2161     BOOL set_hour_adjust = TRUE;
2162     TIME_ZONE_INFORMATION tzi;
2163     DateInstance di;
2164     DWORD lcid_en;
2165
2166     if(retv) num_set_nan(retv);
2167
2168     input_len = SysStringLen(input);
2169     for(i=0; i<input_len; i++) {
2170         if(input[i] == '(') nest_level++;
2171         else if(input[i] == ')') {
2172             nest_level--;
2173             if(nest_level<0)
2174                 return S_OK;
2175         }
2176         else if(!nest_level) parse_len++;
2177     }
2178
2179     parse = SysAllocStringLen(NULL, parse_len);
2180     if(!parse)
2181         return E_OUTOFMEMORY;
2182     nest_level = 0;
2183     parse_len = 0;
2184     for(i=0; i<input_len; i++) {
2185         if(input[i] == '(') nest_level++;
2186         else if(input[i] == ')') nest_level--;
2187         else if(!nest_level) parse[parse_len++] = toupperW(input[i]);
2188     }
2189
2190     GetTimeZoneInformation(&tzi);
2191     di.bias = tzi.Bias;
2192     di.standardDate = tzi.StandardDate;
2193     di.standardBias = tzi.StandardBias;
2194     di.daylightDate = tzi.DaylightDate;
2195     di.daylightBias = tzi.DaylightBias;
2196
2197     lcid_en = MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT);
2198     for(i=0; i<sizeof(string_ids)/sizeof(DWORD); i++) {
2199         size = GetLocaleInfoW(lcid_en, string_ids[i], NULL, 0);
2200         strings[i] = SysAllocStringLen(NULL, size);
2201         if(!strings[i]) {
2202             i--;
2203             while(i-- >= 0)
2204                 SysFreeString(strings[i]);
2205             SysFreeString(parse);
2206             return E_OUTOFMEMORY;
2207         }
2208         GetLocaleInfoW(lcid_en, string_ids[i], strings[i], size);
2209     }
2210
2211     for(i=0; i<parse_len;) {
2212         while(isspaceW(parse[i])) i++;
2213         if(parse[i] == ',') {
2214             while(parse[i] == ',') i++;
2215             continue;
2216         }
2217
2218         if(parse[i]>='0' && parse[i]<='9') {
2219             int tmp = atoiW(&parse[i]);
2220             while(parse[i]>='0' && parse[i]<='9') i++;
2221             while(isspaceW(parse[i])) i++;
2222
2223             if(parse[i] == ':') {
2224                 /* Time */
2225                 if(set_hour) break;
2226                 set_hour = TRUE;
2227
2228                 hour = tmp;
2229
2230                 while(parse[i] == ':') i++;
2231                 while(isspaceW(parse[i])) i++;
2232                 if(parse[i]>='0' && parse[i]<='9') {
2233                     min = atoiW(&parse[i]);
2234                     while(parse[i]>='0' && parse[i]<='9') i++;
2235                 }
2236
2237                 while(isspaceW(parse[i])) i++;
2238                 while(parse[i] == ':') i++;
2239                 while(isspaceW(parse[i])) i++;
2240                 if(parse[i]>='0' && parse[i]<='9') {
2241                     sec = atoiW(&parse[i]);
2242                     while(parse[i]>='0' && parse[i]<='9') i++;
2243                 }
2244             }
2245             else if(parse[i]=='-' || parse[i]=='/') {
2246                 /* Short date */
2247                 if(set_day || set_month || set_year) break;
2248                 set_day = TRUE;
2249                 set_month = TRUE;
2250                 set_year = TRUE;
2251
2252                 month = tmp-1;
2253
2254                 while(isspaceW(parse[i])) i++;
2255                 while(parse[i]=='-' || parse[i]=='/') i++;
2256                 while(isspaceW(parse[i])) i++;
2257                 if(parse[i]<'0' || parse[i]>'9') break;
2258                 day = atoiW(&parse[i]);
2259                 while(parse[i]>='0' && parse[i]<='9') i++;
2260
2261                 while(parse[i]=='-' || parse[i]=='/') i++;
2262                 while(isspaceW(parse[i])) i++;
2263                 if(parse[i]<'0' || parse[i]>'9') break;
2264                 year = atoiW(&parse[i]);
2265                 while(parse[i]>='0' && parse[i]<='9') i++;
2266             }
2267             else if(tmp<0) break;
2268             else if(tmp<70) {
2269                 /* Day */
2270                 if(set_day) break;
2271                 set_day = TRUE;
2272                 day = tmp;
2273             }
2274             else {
2275                 /* Year */
2276                 if(set_year) break;
2277                 set_year = TRUE;
2278                 year = tmp;
2279             }
2280         }
2281         else {
2282             if(parse[i]<'A' || parse[i]>'Z') break;
2283             else if(parse[i]=='B' && (parse[i+1]=='C' ||
2284                         (parse[i+1]=='.' && parse[i+2]=='C'))) {
2285                 /* AD/BC */
2286                 if(set_era) break;
2287                 set_era = TRUE;
2288                 ad = FALSE;
2289
2290                 i++;
2291                 if(parse[i] == '.') i++;
2292                 i++;
2293                 if(parse[i] == '.') i++;
2294             }
2295             else if(parse[i]=='A' && (parse[i+1]=='D' ||
2296                         (parse[i+1]=='.' && parse[i+2]=='D'))) {
2297                 /* AD/BC */
2298                 if(set_era) break;
2299                 set_era = TRUE;
2300
2301                 i++;
2302                 if(parse[i] == '.') i++;
2303                 i++;
2304                 if(parse[i] == '.') i++;
2305             }
2306             else if(parse[i+1]<'A' || parse[i+1]>'Z') {
2307                 /* Timezone */
2308                 if(set_offset) break;
2309                 set_offset = TRUE;
2310
2311                 if(parse[i] <= 'I') hour_adjust = parse[i]-'A'+2;
2312                 else if(parse[i] == 'J') break;
2313                 else if(parse[i] <= 'M') hour_adjust = parse[i]-'K'+11;
2314                 else if(parse[i] <= 'Y') hour_adjust = parse[i]-'N';
2315                 else hour_adjust = 1;
2316
2317                 i++;
2318                 if(parse[i] == '.') i++;
2319             }
2320             else if(parse[i]=='A' && parse[i+1]=='M') {
2321                 /* AM/PM */
2322                 if(set_am) break;
2323                 set_am = TRUE;
2324                 am = TRUE;
2325                 i += 2;
2326             }
2327             else if(parse[i]=='P' && parse[i+1]=='M') {
2328                 /* AM/PM */
2329                 if(set_am) break;
2330                 set_am = TRUE;
2331                 am = FALSE;
2332                 i += 2;
2333             }
2334             else if((parse[i]=='U' && parse[i+1]=='T' && parse[i+2]=='C')
2335                     || (parse[i]=='G' && parse[i+1]=='M' && parse[i+2]=='T')) {
2336                 /* Timezone */
2337                 BOOL positive = TRUE;
2338
2339                 if(set_offset) break;
2340                 set_offset = TRUE;
2341                 set_hour_adjust = FALSE;
2342
2343                 i += 3;
2344                 while(isspaceW(parse[i])) i++;
2345                 if(parse[i] == '-')  positive = FALSE;
2346                 else if(parse[i] != '+') continue;
2347
2348                 i++;
2349                 while(isspaceW(parse[i])) i++;
2350                 if(parse[i]<'0' || parse[i]>'9') break;
2351                 offset = atoiW(&parse[i]);
2352                 while(parse[i]>='0' && parse[i]<='9') i++;
2353
2354                 if(offset<24) offset *= 60;
2355                 else offset = (offset/100)*60 + offset%100;
2356
2357                 if(positive) offset = -offset;
2358             }
2359             else {
2360                 /* Month or garbage */
2361                 int j;
2362
2363                 for(size=i; parse[size]>='A' && parse[size]<='Z'; size++);
2364                 size -= i;
2365
2366                 for(j=0; j<sizeof(string_ids)/sizeof(DWORD); j++)
2367                     if(!memicmpW(&parse[i], strings[j], size)) break;
2368
2369                 if(j < 12) {
2370                     if(set_month) break;
2371                     set_month = TRUE;
2372                     month = 11-j;
2373                 }
2374                 else if(j == sizeof(string_ids)/sizeof(DWORD)) break;
2375
2376                 i += size;
2377             }
2378         }
2379     }
2380
2381     if(retv && i==parse_len && set_year && set_month
2382             && set_day && (!set_am || hour<13)) {
2383         if(set_am) {
2384             if(hour == 12) hour = 0;
2385             if(!am) hour += 12;
2386         }
2387
2388         if(!ad) year = -year+1;
2389         else if(year<100) year += 1900;
2390
2391         V_VT(retv) = VT_R8;
2392         V_R8(retv) = time_clip(make_date(make_day(year, month, day),
2393                     make_time(hour+hour_adjust, min, sec, ms)) + offset*MS_PER_MINUTE);
2394
2395         if(set_hour_adjust) V_R8(retv) = utc(V_R8(retv), &di);
2396     }
2397
2398     for(i=0; i<sizeof(string_ids)/sizeof(DWORD); i++)
2399         SysFreeString(strings[i]);
2400     SysFreeString(parse);
2401
2402     return S_OK;
2403 }
2404
2405 static HRESULT DateConstr_parse(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
2406         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
2407 {
2408     BSTR parse_str;
2409     HRESULT hres;
2410
2411     TRACE("\n");
2412
2413     if(!arg_cnt(dp)) {
2414         if(retv)
2415             num_set_nan(retv);
2416         return S_OK;
2417     }
2418
2419     hres = to_string(dispex->ctx, get_arg(dp,0), ei, &parse_str);
2420     if(FAILED(hres))
2421         return hres;
2422
2423     hres = date_parse(parse_str, retv);
2424
2425     SysFreeString(parse_str);
2426     return hres;
2427 }
2428
2429 static HRESULT DateConstr_UTC(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
2430         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
2431 {
2432     VARIANT year, month, vdate, hours, minutes, seconds, ms;
2433     DOUBLE y;
2434     int arg_no = arg_cnt(dp);
2435     HRESULT hres;
2436
2437     TRACE("\n");
2438
2439     if(arg_no>0) {
2440         hres = to_number(dispex->ctx, get_arg(dp, 0), ei, &year);
2441         if(FAILED(hres))
2442             return hres;
2443         y = num_val(&year);
2444         if(0<=y && y<=99)
2445             y += 1900;
2446     }
2447     else y = 1900;
2448
2449     if(arg_no>1) {
2450         hres = to_number(dispex->ctx, get_arg(dp, 1), ei, &month);
2451         if(FAILED(hres))
2452             return hres;
2453     }
2454     else {
2455         V_VT(&month) = VT_R8;
2456         V_R8(&month) = 0;
2457     }
2458
2459     if(arg_no>2) {
2460         hres = to_number(dispex->ctx, get_arg(dp, 2), ei, &vdate);
2461         if(FAILED(hres))
2462             return hres;
2463     }
2464     else {
2465         V_VT(&vdate) = VT_R8;
2466         V_R8(&vdate) = 1;
2467     }
2468
2469     if(arg_no>3) {
2470         hres = to_number(dispex->ctx, get_arg(dp, 3), ei, &hours);
2471         if(FAILED(hres))
2472             return hres;
2473     }
2474     else {
2475         V_VT(&hours) = VT_R8;
2476         V_R8(&hours) = 0;
2477     }
2478
2479     if(arg_no>4) {
2480         hres = to_number(dispex->ctx, get_arg(dp, 4), ei, &minutes);
2481         if(FAILED(hres))
2482             return hres;
2483     }
2484     else {
2485         V_VT(&minutes) = VT_R8;
2486         V_R8(&minutes) = 0;
2487     }
2488
2489     if(arg_no>5) {
2490         hres = to_number(dispex->ctx, get_arg(dp, 5), ei, &seconds);
2491         if(FAILED(hres))
2492             return hres;
2493     }
2494     else {
2495         V_VT(&seconds) = VT_R8;
2496         V_R8(&seconds) = 0;
2497     }
2498
2499     if(arg_no>6) {
2500         hres = to_number(dispex->ctx, get_arg(dp, 6), ei, &ms);
2501         if(FAILED(hres))
2502             return hres;
2503     }
2504     else {
2505         V_VT(&ms) = VT_R8;
2506         V_R8(&ms) = 0;
2507     }
2508
2509     if(retv) {
2510         V_VT(retv) = VT_R8;
2511         V_R8(retv) = time_clip(make_date(
2512                     make_day(y, num_val(&month), num_val(&vdate)),
2513                     make_time(num_val(&hours), num_val(&minutes),
2514                     num_val(&seconds), num_val(&ms))));
2515     }
2516
2517     return S_OK;
2518 }
2519
2520 static HRESULT DateConstr_value(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
2521         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
2522 {
2523     DispatchEx *date;
2524     HRESULT hres;
2525
2526     TRACE("\n");
2527
2528     switch(flags) {
2529     case DISPATCH_CONSTRUCT:
2530         switch(arg_cnt(dp)) {
2531         /* ECMA-262 3rd Edition    15.9.3.3 */
2532         case 0: {
2533             FILETIME time;
2534             LONGLONG lltime;
2535
2536             GetSystemTimeAsFileTime(&time);
2537             lltime = ((LONGLONG)time.dwHighDateTime<<32)
2538                 + time.dwLowDateTime;
2539
2540             hres = create_date(dispex->ctx, TRUE, lltime/10000-TIME_EPOCH, &date);
2541             if(FAILED(hres))
2542                 return hres;
2543             break;
2544         }
2545
2546         /* ECMA-262 3rd Edition    15.9.3.2 */
2547         case 1: {
2548             VARIANT prim, num;
2549
2550             hres = to_primitive(dispex->ctx, get_arg(dp,0), ei, &prim, NO_HINT);
2551             if(FAILED(hres))
2552                 return hres;
2553
2554             if(V_VT(&prim) == VT_BSTR)
2555                 hres = date_parse(V_BSTR(&prim), &num);
2556             else
2557                 hres = to_number(dispex->ctx, &prim, ei, &num);
2558
2559             VariantClear(&prim);
2560             if(FAILED(hres))
2561                 return hres;
2562
2563             hres = create_date(dispex->ctx, TRUE, time_clip(num_val(&num)), &date);
2564             if(FAILED(hres))
2565                 return hres;
2566             break;
2567         }
2568
2569         /* ECMA-262 3rd Edition    15.9.3.1 */
2570         default: {
2571             VARIANT ret_date;
2572             DateInstance *di;
2573
2574             DateConstr_UTC(dispex, lcid, flags, dp, &ret_date, ei, sp);
2575
2576             hres = create_date(dispex->ctx, TRUE, num_val(&ret_date), &date);
2577             if(FAILED(hres))
2578                 return hres;
2579
2580             di = (DateInstance*)date;
2581             di->time = utc(di->time, di);
2582         }
2583         }
2584
2585         V_VT(retv) = VT_DISPATCH;
2586         V_DISPATCH(retv) = (IDispatch*)_IDispatchEx_(date);
2587         return S_OK;
2588
2589     case INVOKE_FUNC: {
2590         FILETIME system_time, local_time;
2591         LONGLONG lltime;
2592
2593         GetSystemTimeAsFileTime(&system_time);
2594         FileTimeToLocalFileTime(&system_time, &local_time);
2595         lltime = ((LONGLONG)local_time.dwHighDateTime<<32)
2596             + local_time.dwLowDateTime;
2597
2598         return date_to_string(lltime/10000-TIME_EPOCH, FALSE, 0, retv);
2599     }
2600
2601     default:
2602         FIXME("unimplemented flags %x\n", flags);
2603         return E_NOTIMPL;
2604     }
2605
2606     return S_OK;
2607 }
2608
2609 static const builtin_prop_t DateConstr_props[] = {
2610     {UTCW,    DateConstr_UTC,    PROPF_METHOD},
2611     {parseW,  DateConstr_parse,  PROPF_METHOD}
2612 };
2613
2614 static const builtin_info_t DateConstr_info = {
2615     JSCLASS_FUNCTION,
2616     {NULL, Function_value, 0},
2617     sizeof(DateConstr_props)/sizeof(*DateConstr_props),
2618     DateConstr_props,
2619     NULL,
2620     NULL
2621 };
2622
2623 HRESULT create_date_constr(script_ctx_t *ctx, DispatchEx **ret)
2624 {
2625     DispatchEx *date;
2626     HRESULT hres;
2627
2628     hres = create_date(ctx, FALSE, 0.0, &date);
2629     if(FAILED(hres))
2630         return hres;
2631
2632     hres = create_builtin_function(ctx, DateConstr_value, &DateConstr_info, PROPF_CONSTR, date, ret);
2633
2634     jsdisp_release(date);
2635     return hres;
2636 }