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