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