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