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