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