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