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