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