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