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