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