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