TESTING -- override pthreads to fix gstreamer v5
[wine/multimedia.git] / dlls / jscript / date.c
blob6d98fcde3b5d4c515044e73c51ae5f8293305457
1 /*
2 * Copyright 2008 Jacek Caban for CodeWeavers
3 * Copyright 2009 Piotr Caban
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.
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.
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
20 #include "config.h"
21 #include "wine/port.h"
23 #include <limits.h>
24 #include <math.h>
25 #include <assert.h>
27 #include "jscript.h"
29 #include "wine/debug.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(jscript);
33 /* 1601 to 1970 is 369 years plus 89 leap days */
34 #define TIME_EPOCH ((ULONGLONG)(369 * 365 + 89) * 86400 * 1000)
36 typedef struct {
37 jsdisp_t dispex;
39 /* ECMA-262 3rd Edition 15.9.1.1 */
40 DOUBLE time;
42 LONG bias;
43 SYSTEMTIME standardDate;
44 LONG standardBias;
45 SYSTEMTIME daylightDate;
46 LONG daylightBias;
47 } DateInstance;
49 static const WCHAR toStringW[] = {'t','o','S','t','r','i','n','g',0};
50 static const WCHAR toLocaleStringW[] = {'t','o','L','o','c','a','l','e','S','t','r','i','n','g',0};
51 static const WCHAR valueOfW[] = {'v','a','l','u','e','O','f',0};
52 static const WCHAR toUTCStringW[] = {'t','o','U','T','C','S','t','r','i','n','g',0};
53 static const WCHAR toGMTStringW[] = {'t','o','G','M','T','S','t','r','i','n','g',0};
54 static const WCHAR toDateStringW[] = {'t','o','D','a','t','e','S','t','r','i','n','g',0};
55 static const WCHAR toTimeStringW[] = {'t','o','T','i','m','e','S','t','r','i','n','g',0};
56 static const WCHAR toLocaleDateStringW[] = {'t','o','L','o','c','a','l','e','D','a','t','e','S','t','r','i','n','g',0};
57 static const WCHAR toLocaleTimeStringW[] = {'t','o','L','o','c','a','l','e','T','i','m','e','S','t','r','i','n','g',0};
58 static const WCHAR getTimeW[] = {'g','e','t','T','i','m','e',0};
59 static const WCHAR getFullYearW[] = {'g','e','t','F','u','l','l','Y','e','a','r',0};
60 static const WCHAR getUTCFullYearW[] = {'g','e','t','U','T','C','F','u','l','l','Y','e','a','r',0};
61 static const WCHAR getMonthW[] = {'g','e','t','M','o','n','t','h',0};
62 static const WCHAR getUTCMonthW[] = {'g','e','t','U','T','C','M','o','n','t','h',0};
63 static const WCHAR getDateW[] = {'g','e','t','D','a','t','e',0};
64 static const WCHAR getUTCDateW[] = {'g','e','t','U','T','C','D','a','t','e',0};
65 static const WCHAR getDayW[] = {'g','e','t','D','a','y',0};
66 static const WCHAR getUTCDayW[] = {'g','e','t','U','T','C','D','a','y',0};
67 static const WCHAR getHoursW[] = {'g','e','t','H','o','u','r','s',0};
68 static const WCHAR getUTCHoursW[] = {'g','e','t','U','T','C','H','o','u','r','s',0};
69 static const WCHAR getMinutesW[] = {'g','e','t','M','i','n','u','t','e','s',0};
70 static const WCHAR getUTCMinutesW[] = {'g','e','t','U','T','C','M','i','n','u','t','e','s',0};
71 static const WCHAR getSecondsW[] = {'g','e','t','S','e','c','o','n','d','s',0};
72 static const WCHAR getUTCSecondsW[] = {'g','e','t','U','T','C','S','e','c','o','n','d','s',0};
73 static const WCHAR getMillisecondsW[] = {'g','e','t','M','i','l','l','i','s','e','c','o','n','d','s',0};
74 static const WCHAR getUTCMillisecondsW[] = {'g','e','t','U','T','C','M','i','l','l','i','s','e','c','o','n','d','s',0};
75 static const WCHAR getTimezoneOffsetW[] = {'g','e','t','T','i','m','e','z','o','n','e','O','f','f','s','e','t',0};
76 static const WCHAR setTimeW[] = {'s','e','t','T','i','m','e',0};
77 static const WCHAR setMillisecondsW[] = {'s','e','t','M','i','l','l','i','s','e','c','o','n','d','s',0};
78 static const WCHAR setUTCMillisecondsW[] = {'s','e','t','U','T','C','M','i','l','l','i','s','e','c','o','n','d','s',0};
79 static const WCHAR setSecondsW[] = {'s','e','t','S','e','c','o','n','d','s',0};
80 static const WCHAR setUTCSecondsW[] = {'s','e','t','U','T','C','S','e','c','o','n','d','s',0};
81 static const WCHAR setMinutesW[] = {'s','e','t','M','i','n','u','t','e','s',0};
82 static const WCHAR setUTCMinutesW[] = {'s','e','t','U','T','C','M','i','n','u','t','e','s',0};
83 static const WCHAR setHoursW[] = {'s','e','t','H','o','u','r','s',0};
84 static const WCHAR setUTCHoursW[] = {'s','e','t','U','T','C','H','o','u','r','s',0};
85 static const WCHAR setDateW[] = {'s','e','t','D','a','t','e',0};
86 static const WCHAR setUTCDateW[] = {'s','e','t','U','T','C','D','a','t','e',0};
87 static const WCHAR setMonthW[] = {'s','e','t','M','o','n','t','h',0};
88 static const WCHAR setUTCMonthW[] = {'s','e','t','U','T','C','M','o','n','t','h',0};
89 static const WCHAR setFullYearW[] = {'s','e','t','F','u','l','l','Y','e','a','r',0};
90 static const WCHAR setUTCFullYearW[] = {'s','e','t','U','T','C','F','u','l','l','Y','e','a','r',0};
91 static const WCHAR getYearW[] = {'g','e','t','Y','e','a','r',0};
92 static const WCHAR setYearW[] = {'s','e','t','Y','e','a','r',0};
94 static const WCHAR UTCW[] = {'U','T','C',0};
95 static const WCHAR parseW[] = {'p','a','r','s','e',0};
97 static inline DateInstance *date_from_jsdisp(jsdisp_t *jsdisp)
99 return CONTAINING_RECORD(jsdisp, DateInstance, dispex);
102 static inline DateInstance *date_this(vdisp_t *jsthis)
104 return is_vclass(jsthis, JSCLASS_DATE) ? date_from_jsdisp(jsthis->u.jsdisp) : NULL;
107 /*ECMA-262 3rd Edition 15.9.1.2 */
108 #define MS_PER_DAY 86400000
109 #define MS_PER_HOUR 3600000
110 #define MS_PER_MINUTE 60000
112 /* ECMA-262 3rd Edition 15.9.1.2 */
113 static inline DOUBLE day(DOUBLE time)
115 return floor(time / MS_PER_DAY);
118 /* ECMA-262 3rd Edition 15.9.1.2 */
119 static inline DOUBLE time_within_day(DOUBLE time)
121 DOUBLE ret;
123 ret = fmod(time, MS_PER_DAY);
124 if(ret < 0)
125 ret += MS_PER_DAY;
127 return ret;
130 /* ECMA-262 3rd Edition 15.9.1.3 */
131 static inline DOUBLE days_in_year(DOUBLE year)
133 int y;
135 if(year != (int)year)
136 return NAN;
138 y = year;
139 if(y%4 != 0) return 365;
140 if(y%100 != 0) return 366;
141 if(y%400 != 0) return 365;
142 return 366;
145 /* ECMA-262 3rd Edition 15.9.1.3 */
146 static inline DOUBLE day_from_year(DOUBLE year)
148 if(year != (int)year)
149 return NAN;
151 return floor(365.0*(year-1970) + floor((year-1969)/4)
152 - floor((year-1901)/100) + floor((year-1601)/400));
155 static inline int day_from_month(int month, int in_leap_year)
157 switch(month)
159 case 0:
160 return 0;
161 case 1:
162 return 31;
163 case 2:
164 return 59+in_leap_year;
165 case 3:
166 return 90+in_leap_year;
167 case 4:
168 return 120+in_leap_year;
169 case 5:
170 return 151+in_leap_year;
171 case 6:
172 return 181+in_leap_year;
173 case 7:
174 return 212+in_leap_year;
175 case 8:
176 return 243+in_leap_year;
177 case 9:
178 return 273+in_leap_year;
179 case 10:
180 return 304+in_leap_year;
181 default:
182 return 334+in_leap_year;
186 /* ECMA-262 3rd Edition 15.9.1.3 */
187 static inline DOUBLE time_from_year(DOUBLE year)
189 return MS_PER_DAY*day_from_year(year);
192 /* ECMA-262 3rd Edition 15.9.1.3 */
193 static inline DOUBLE year_from_time(DOUBLE time)
195 int y;
197 if(isnan(time))
198 return NAN;
200 y = 1970 + time/365.25/MS_PER_DAY;
202 if(time_from_year(y) > time)
203 while(time_from_year(y) > time) y--;
204 else
205 while(time_from_year(y+1)<=time) y++;
207 return y;
210 /* ECMA-262 3rd Edition 15.9.1.3 */
211 static inline int in_leap_year(DOUBLE time)
213 if(days_in_year(year_from_time(time))==366)
214 return 1;
215 return 0;
218 /* ECMA-262 3rd Edition 15.9.1.4 */
219 static inline int day_within_year(DOUBLE time)
221 return day(time) - day_from_year(year_from_time(time));
224 /* ECMA-262 3rd Edition 15.9.1.4 */
225 static inline DOUBLE month_from_time(DOUBLE time)
227 int ily = in_leap_year(time);
228 int dwy = day_within_year(time);
230 if(isnan(time))
231 return NAN;
233 if(0<=dwy && dwy<31) return 0;
234 if(dwy < 59+ily) return 1;
235 if(dwy < 90+ily) return 2;
236 if(dwy < 120+ily) return 3;
237 if(dwy < 151+ily) return 4;
238 if(dwy < 181+ily) return 5;
239 if(dwy < 212+ily) return 6;
240 if(dwy < 243+ily) return 7;
241 if(dwy < 273+ily) return 8;
242 if(dwy < 304+ily) return 9;
243 if(dwy < 334+ily) return 10;
244 return 11;
247 /* ECMA-262 3rd Edition 15.9.1.5 */
248 static inline DOUBLE date_from_time(DOUBLE time)
250 int dwy = day_within_year(time);
251 int ily = in_leap_year(time);
252 int mft = month_from_time(time);
254 if(isnan(time))
255 return NAN;
257 if(mft==0) return dwy+1;
258 if(mft==1) return dwy-30;
259 if(mft==2) return dwy-58-ily;
260 if(mft==3) return dwy-89-ily;
261 if(mft==4) return dwy-119-ily;
262 if(mft==5) return dwy-150-ily;
263 if(mft==6) return dwy-180-ily;
264 if(mft==7) return dwy-211-ily;
265 if(mft==8) return dwy-242-ily;
266 if(mft==9) return dwy-272-ily;
267 if(mft==10) return dwy-303-ily;
268 return dwy-333-ily;
271 /* ECMA-262 3rd Edition 15.9.1.6 */
272 static inline DOUBLE week_day(DOUBLE time)
274 DOUBLE ret;
276 if(isnan(time))
277 return NAN;
279 ret = fmod(day(time)+4, 7);
280 if(ret<0) ret += 7;
282 return ret;
285 static inline DOUBLE convert_time(int year, SYSTEMTIME st)
287 DOUBLE time;
288 int set_week_day;
290 if(st.wMonth == 0)
291 return NAN;
293 if(st.wYear != 0)
294 year = st.wYear;
296 time = time_from_year(year);
297 time += (DOUBLE)day_from_month(st.wMonth-1, in_leap_year(time)) * MS_PER_DAY;
299 if(st.wYear == 0) {
300 set_week_day = st.wDayOfWeek-week_day(time);
301 if(set_week_day < 0)
302 set_week_day += 7;
303 time += set_week_day * MS_PER_DAY;
305 time += (DOUBLE)(st.wDay-1) * 7 * MS_PER_DAY;
306 if(month_from_time(time) != st.wMonth-1)
307 time -= 7 * MS_PER_DAY;
309 else
310 time += st.wDay * MS_PER_DAY;
312 time += st.wHour * MS_PER_HOUR;
313 time += st.wMinute * MS_PER_MINUTE;
315 return time;
318 /* ECMA-262 3rd Edition 15.9.1.9 */
319 static inline DOUBLE daylight_saving_ta(DOUBLE time, DateInstance *date)
321 int year = year_from_time(time);
322 DOUBLE standardTime, daylightTime;
324 if(isnan(time))
325 return 0;
327 standardTime = convert_time(year, date->standardDate);
328 daylightTime = convert_time(year, date->daylightDate);
330 if(isnan(standardTime) || isnan(daylightTime))
331 return 0;
332 else if(standardTime > daylightTime) {
333 if(daylightTime <= time && time < standardTime)
334 return date->daylightBias;
336 return date->standardBias;
338 else {
339 if(standardTime <= time && time < daylightTime)
340 return date->standardBias;
342 return date->daylightBias;
346 /* ECMA-262 3rd Edition 15.9.1.9 */
347 static inline DOUBLE local_time(DOUBLE time, DateInstance *date)
349 return time - (daylight_saving_ta(time, date)+date->bias)*MS_PER_MINUTE;
352 /* ECMA-262 3rd Edition 15.9.1.9 */
353 static inline DOUBLE utc(DOUBLE time, DateInstance *date)
355 time += date->bias * MS_PER_MINUTE;
356 return time + daylight_saving_ta(time, date)*MS_PER_MINUTE;
359 /* ECMA-262 3rd Edition 15.9.1.10 */
360 static inline DOUBLE hour_from_time(DOUBLE time)
362 DOUBLE ret;
364 if(isnan(time))
365 return NAN;
367 ret = fmod(floor(time/MS_PER_HOUR), 24);
368 if(ret<0) ret += 24;
370 return ret;
373 /* ECMA-262 3rd Edition 15.9.1.10 */
374 static inline DOUBLE min_from_time(DOUBLE time)
376 DOUBLE ret;
378 if(isnan(time))
379 return NAN;
381 ret = fmod(floor(time/MS_PER_MINUTE), 60);
382 if(ret<0) ret += 60;
384 return ret;
387 /* ECMA-262 3rd Edition 15.9.1.10 */
388 static inline DOUBLE sec_from_time(DOUBLE time)
390 DOUBLE ret;
392 if(isnan(time))
393 return NAN;
395 ret = fmod(floor(time/1000), 60);
396 if(ret<0) ret += 60;
398 return ret;
401 /* ECMA-262 3rd Edition 15.9.1.10 */
402 static inline DOUBLE ms_from_time(DOUBLE time)
404 DOUBLE ret;
406 if(isnan(time))
407 return NAN;
409 ret = fmod(time, 1000);
410 if(ret<0) ret += 1000;
412 return ret;
415 /* ECMA-262 3rd Edition 15.9.1.11 */
416 static inline DOUBLE make_time(DOUBLE hour, DOUBLE min, DOUBLE sec, DOUBLE ms)
418 return hour*MS_PER_HOUR + min*MS_PER_MINUTE + sec*1000 + ms;
421 /* ECMA-262 3rd Edition 15.9.1.12 */
422 static inline DOUBLE make_day(DOUBLE year, DOUBLE month, DOUBLE day)
424 DOUBLE time;
426 year += floor(month/12);
428 month = fmod(month, 12);
429 if(month<0) month += 12;
431 time = time_from_year(year);
433 day += floor(time / MS_PER_DAY);
434 day += day_from_month(month, in_leap_year(time));
436 return day-1;
439 /* ECMA-262 3rd Edition 15.9.1.13 */
440 static inline DOUBLE make_date(DOUBLE day, DOUBLE time)
442 return day*MS_PER_DAY + time;
445 /* ECMA-262 3rd Edition 15.9.1.14 */
446 static inline DOUBLE time_clip(DOUBLE time)
448 if(8.64e15 < time || time < -8.64e15) {
449 return NAN;
452 return floor(time);
455 static SYSTEMTIME create_systemtime(DOUBLE time)
457 SYSTEMTIME st;
459 st.wYear = year_from_time(time);
460 st.wMonth = month_from_time(time) + 1;
461 st.wDayOfWeek = week_day(time);
462 st.wDay = date_from_time(time);
463 st.wHour = hour_from_time(time);
464 st.wMinute = min_from_time(time);
465 st.wSecond = sec_from_time(time);
466 st.wMilliseconds = ms_from_time(time);
468 return st;
471 static inline HRESULT date_to_string(DOUBLE time, BOOL show_offset, int offset, jsval_t *r)
473 static const WCHAR formatW[] = { '%','s',' ','%','s',' ','%','d',' ',
474 '%','0','2','d',':','%','0','2','d',':','%','0','2','d',' ',
475 'U','T','C','%','c','%','0','2','d','%','0','2','d',' ','%','d','%','s',0 };
476 static const WCHAR formatUTCW[] = { '%','s',' ','%','s',' ','%','d',' ',
477 '%','0','2','d',':','%','0','2','d',':','%','0','2','d',' ',
478 'U','T','C',' ','%','d','%','s',0 };
479 static const WCHAR formatNoOffsetW[] = { '%','s',' ','%','s',' ',
480 '%','d',' ','%','0','2','d',':','%','0','2','d',':',
481 '%','0','2','d',' ','%','d','%','s',0 };
482 static const WCHAR ADW[] = { 0 };
483 static const WCHAR BCW[] = { ' ','B','.','C','.',0 };
485 static const DWORD week_ids[] = { LOCALE_SABBREVDAYNAME7, LOCALE_SABBREVDAYNAME1,
486 LOCALE_SABBREVDAYNAME2, LOCALE_SABBREVDAYNAME3, LOCALE_SABBREVDAYNAME4,
487 LOCALE_SABBREVDAYNAME5, LOCALE_SABBREVDAYNAME6 };
488 static const DWORD month_ids[] = { LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2,
489 LOCALE_SABBREVMONTHNAME3, LOCALE_SABBREVMONTHNAME4,
490 LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6,
491 LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8,
492 LOCALE_SABBREVMONTHNAME9, LOCALE_SABBREVMONTHNAME10,
493 LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12 };
495 BOOL formatAD = TRUE;
496 WCHAR week[64], month[64];
497 jsstr_t *date_jsstr;
498 int len, size, year, day;
499 DWORD lcid_en;
500 WCHAR sign = '-';
502 if(isnan(time)) {
503 if(r)
504 *r = jsval_string(jsstr_nan());
505 return S_OK;
508 if(r) {
509 WCHAR *date_str;
511 len = 21;
513 lcid_en = MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT);
515 size = GetLocaleInfoW(lcid_en, week_ids[(int)week_day(time)], week, sizeof(week)/sizeof(*week));
516 assert(size);
517 len += size-1;
519 size = GetLocaleInfoW(lcid_en, month_ids[(int)month_from_time(time)], month, sizeof(month)/sizeof(*month));
520 len += size-1;
522 year = year_from_time(time);
523 if(year<0)
524 year = -year+1;
525 do {
526 year /= 10;
527 len++;
528 } while(year);
530 year = year_from_time(time);
531 if(year<0) {
532 formatAD = FALSE;
533 year = -year+1;
534 len += 5;
537 day = date_from_time(time);
538 do {
539 day /= 10;
540 len++;
541 } while(day);
542 day = date_from_time(time);
544 if(!show_offset) len -= 9;
545 else if(offset == 0) len -= 5;
546 else if(offset < 0) {
547 sign = '+';
548 offset = -offset;
551 date_str = jsstr_alloc_buf(len, &date_jsstr);
552 if(!date_str)
553 return E_OUTOFMEMORY;
555 if(!show_offset)
556 sprintfW(date_str, formatNoOffsetW, week, month, day,
557 (int)hour_from_time(time), (int)min_from_time(time),
558 (int)sec_from_time(time), year, formatAD?ADW:BCW);
559 else if(offset)
560 sprintfW(date_str, formatW, week, month, day,
561 (int)hour_from_time(time), (int)min_from_time(time),
562 (int)sec_from_time(time), sign, offset/60, offset%60,
563 year, formatAD?ADW:BCW);
564 else
565 sprintfW(date_str, formatUTCW, week, month, day,
566 (int)hour_from_time(time), (int)min_from_time(time),
567 (int)sec_from_time(time), year, formatAD?ADW:BCW);
569 *r = jsval_string(date_jsstr);
571 return S_OK;
574 /* ECMA-262 3rd Edition 15.9.1.2 */
575 static HRESULT dateobj_to_string(DateInstance *date, jsval_t *r)
577 DOUBLE time;
578 int offset;
580 time = local_time(date->time, date);
581 offset = date->bias +
582 daylight_saving_ta(time, date);
584 return date_to_string(time, TRUE, offset, r);
587 static HRESULT Date_toString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
589 DateInstance *date;
591 TRACE("\n");
593 if(!(date = date_this(jsthis)))
594 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
596 return dateobj_to_string(date, r);
599 /* ECMA-262 3rd Edition 15.9.1.5 */
600 static HRESULT Date_toLocaleString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
601 jsval_t *r)
603 SYSTEMTIME st;
604 DateInstance *date;
605 jsstr_t *date_str;
606 int date_len, time_len;
608 TRACE("\n");
610 if(!(date = date_this(jsthis)))
611 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
613 if(isnan(date->time)) {
614 if(r)
615 *r = jsval_string(jsstr_nan());
616 return S_OK;
619 st = create_systemtime(local_time(date->time, date));
621 if(st.wYear<1601 || st.wYear>9999)
622 return dateobj_to_string(date, r);
624 if(r) {
625 WCHAR *ptr;
627 date_len = GetDateFormatW(ctx->lcid, DATE_LONGDATE, &st, NULL, NULL, 0);
628 time_len = GetTimeFormatW(ctx->lcid, 0, &st, NULL, NULL, 0);
630 ptr = jsstr_alloc_buf(date_len+time_len-1, &date_str);
631 if(!date_str)
632 return E_OUTOFMEMORY;
634 GetDateFormatW(ctx->lcid, DATE_LONGDATE, &st, NULL, ptr, date_len);
635 GetTimeFormatW(ctx->lcid, 0, &st, NULL, ptr+date_len, time_len);
636 ptr[date_len-1] = ' ';
638 *r = jsval_string(date_str);
640 return S_OK;
643 static HRESULT Date_valueOf(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
644 jsval_t *r)
646 DateInstance *date;
648 TRACE("\n");
650 if(!(date = date_this(jsthis)))
651 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
653 if(r)
654 *r = jsval_number(date->time);
655 return S_OK;
658 static inline HRESULT create_utc_string(script_ctx_t *ctx, vdisp_t *jsthis, jsval_t *r)
660 static const WCHAR formatADW[] = { '%','s',',',' ','%','d',' ','%','s',' ','%','d',' ',
661 '%','0','2','d',':','%','0','2','d',':','%','0','2','d',' ','U','T','C',0 };
662 static const WCHAR formatBCW[] = { '%','s',',',' ','%','d',' ','%','s',' ','%','d',' ','B','.','C','.',' ',
663 '%','0','2','d',':','%','0','2','d',':','%','0','2','d',' ','U','T','C',0 };
665 static const DWORD week_ids[] = { LOCALE_SABBREVDAYNAME7, LOCALE_SABBREVDAYNAME1,
666 LOCALE_SABBREVDAYNAME2, LOCALE_SABBREVDAYNAME3, LOCALE_SABBREVDAYNAME4,
667 LOCALE_SABBREVDAYNAME5, LOCALE_SABBREVDAYNAME6 };
668 static const DWORD month_ids[] = { LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2,
669 LOCALE_SABBREVMONTHNAME3, LOCALE_SABBREVMONTHNAME4,
670 LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6,
671 LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8,
672 LOCALE_SABBREVMONTHNAME9, LOCALE_SABBREVMONTHNAME10,
673 LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12 };
675 BOOL formatAD = TRUE;
676 WCHAR week[64], month[64];
677 DateInstance *date;
678 jsstr_t *date_str;
679 int len, size, year, day;
680 DWORD lcid_en;
682 if(!(date = date_this(jsthis)))
683 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
685 if(isnan(date->time)) {
686 if(r)
687 *r = jsval_string(jsstr_nan());
688 return S_OK;
691 if(r) {
692 WCHAR *ptr;
694 len = 17;
696 lcid_en = MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT);
698 size = GetLocaleInfoW(lcid_en, week_ids[(int)week_day(date->time)], week, sizeof(week)/sizeof(*week));
699 len += size-1;
701 size = GetLocaleInfoW(lcid_en, month_ids[(int)month_from_time(date->time)], month, sizeof(month)/sizeof(*month));
702 len += size-1;
704 year = year_from_time(date->time);
705 if(year<0)
706 year = -year+1;
707 do {
708 year /= 10;
709 len++;
710 } while(year);
712 year = year_from_time(date->time);
713 if(year<0) {
714 formatAD = FALSE;
715 year = -year+1;
716 len += 5;
719 day = date_from_time(date->time);
720 do {
721 day /= 10;
722 len++;
723 } while(day);
724 day = date_from_time(date->time);
726 ptr = jsstr_alloc_buf(len, &date_str);
727 if(!date_str)
728 return E_OUTOFMEMORY;
730 sprintfW(ptr, formatAD?formatADW:formatBCW, week, day, month, year,
731 (int)hour_from_time(date->time), (int)min_from_time(date->time),
732 (int)sec_from_time(date->time));
734 *r = jsval_string(date_str);
736 return S_OK;
739 /* ECMA-262 3rd Edition 15.9.5.42 */
740 static HRESULT Date_toUTCString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
741 jsval_t *r)
743 TRACE("\n");
744 return create_utc_string(ctx, jsthis, r);
747 static HRESULT Date_toGMTString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
748 jsval_t *r)
750 TRACE("\n");
751 return create_utc_string(ctx, jsthis, r);
754 /* ECMA-262 3rd Edition 15.9.5.3 */
755 static HRESULT dateobj_to_date_string(DateInstance *date, jsval_t *r)
757 static const WCHAR formatADW[] = { '%','s',' ','%','s',' ','%','d',' ','%','d',0 };
758 static const WCHAR formatBCW[] = { '%','s',' ','%','s',' ','%','d',' ','%','d',' ','B','.','C','.',0 };
760 static const DWORD week_ids[] = { LOCALE_SABBREVDAYNAME7, LOCALE_SABBREVDAYNAME1,
761 LOCALE_SABBREVDAYNAME2, LOCALE_SABBREVDAYNAME3, LOCALE_SABBREVDAYNAME4,
762 LOCALE_SABBREVDAYNAME5, LOCALE_SABBREVDAYNAME6 };
763 static const DWORD month_ids[] = { LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2,
764 LOCALE_SABBREVMONTHNAME3, LOCALE_SABBREVMONTHNAME4,
765 LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6,
766 LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8,
767 LOCALE_SABBREVMONTHNAME9, LOCALE_SABBREVMONTHNAME10,
768 LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12 };
770 BOOL formatAD = TRUE;
771 WCHAR week[64], month[64];
772 jsstr_t *date_str;
773 DOUBLE time;
774 int len, size, year, day;
775 DWORD lcid_en;
777 if(isnan(date->time)) {
778 if(r)
779 *r = jsval_string(jsstr_nan());
780 return S_OK;
783 time = local_time(date->time, date);
785 if(r) {
786 WCHAR *ptr;
788 len = 5;
790 lcid_en = MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT);
792 size = GetLocaleInfoW(lcid_en, week_ids[(int)week_day(time)], week, sizeof(week)/sizeof(*week));
793 assert(size);
794 len += size-1;
796 size = GetLocaleInfoW(lcid_en, month_ids[(int)month_from_time(time)], month, sizeof(month)/sizeof(*month));
797 assert(size);
798 len += size-1;
800 year = year_from_time(time);
801 if(year<0)
802 year = -year+1;
803 do {
804 year /= 10;
805 len++;
806 } while(year);
808 year = year_from_time(time);
809 if(year<0) {
810 formatAD = FALSE;
811 year = -year+1;
812 len += 5;
815 day = date_from_time(time);
816 do {
817 day /= 10;
818 len++;
819 } while(day);
820 day = date_from_time(time);
822 ptr = jsstr_alloc_buf(len, &date_str);
823 if(!ptr)
824 return E_OUTOFMEMORY;
825 sprintfW(ptr, formatAD?formatADW:formatBCW, week, month, day, year);
827 *r = jsval_string(date_str);
829 return S_OK;
832 static HRESULT Date_toDateString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
833 jsval_t *r)
835 DateInstance *date;
837 if(!(date = date_this(jsthis)))
838 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
840 return dateobj_to_date_string(date, r);
843 /* ECMA-262 3rd Edition 15.9.5.4 */
844 static HRESULT Date_toTimeString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
845 jsval_t *r)
847 static const WCHAR formatW[] = { '%','0','2','d',':','%','0','2','d',':','%','0','2','d',
848 ' ','U','T','C','%','c','%','0','2','d','%','0','2','d',0 };
849 static const WCHAR formatUTCW[] = { '%','0','2','d',':','%','0','2','d',
850 ':','%','0','2','d',' ','U','T','C',0 };
851 DateInstance *date;
852 jsstr_t *date_str;
853 DOUBLE time;
854 WCHAR sign;
855 int offset;
857 TRACE("\n");
859 if(!(date = date_this(jsthis)))
860 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
862 if(isnan(date->time)) {
863 if(r)
864 *r = jsval_string(jsstr_nan());
865 return S_OK;
868 time = local_time(date->time, date);
870 if(r) {
871 WCHAR *ptr;
873 ptr = jsstr_alloc_buf(17, &date_str);
874 if(!date_str)
875 return E_OUTOFMEMORY;
877 offset = date->bias +
878 daylight_saving_ta(time, date);
880 if(offset < 0) {
881 sign = '+';
882 offset = -offset;
884 else sign = '-';
886 if(offset)
887 sprintfW(ptr, formatW, (int)hour_from_time(time),
888 (int)min_from_time(time), (int)sec_from_time(time),
889 sign, offset/60, offset%60);
890 else
891 sprintfW(ptr, formatUTCW, (int)hour_from_time(time),
892 (int)min_from_time(time), (int)sec_from_time(time));
894 *r = jsval_string(date_str);
896 return S_OK;
899 /* ECMA-262 3rd Edition 15.9.5.6 */
900 static HRESULT Date_toLocaleDateString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
901 jsval_t *r)
903 SYSTEMTIME st;
904 DateInstance *date;
905 jsstr_t *date_str;
906 int len;
908 TRACE("\n");
910 if(!(date = date_this(jsthis)))
911 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
913 if(isnan(date->time)) {
914 if(r)
915 *r = jsval_string(jsstr_nan());
916 return S_OK;
919 st = create_systemtime(local_time(date->time, date));
921 if(st.wYear<1601 || st.wYear>9999)
922 return dateobj_to_date_string(date, r);
924 if(r) {
925 WCHAR *ptr;
927 len = GetDateFormatW(ctx->lcid, DATE_LONGDATE, &st, NULL, NULL, 0);
928 ptr = jsstr_alloc_buf(len, &date_str);
929 if(!ptr)
930 return E_OUTOFMEMORY;
931 GetDateFormatW(ctx->lcid, DATE_LONGDATE, &st, NULL, ptr, len);
933 *r = jsval_string(date_str);
935 return S_OK;
938 /* ECMA-262 3rd Edition 15.9.5.7 */
939 static HRESULT Date_toLocaleTimeString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
940 jsval_t *r)
942 SYSTEMTIME st;
943 DateInstance *date;
944 jsstr_t *date_str;
945 int len;
947 TRACE("\n");
949 if(!(date = date_this(jsthis)))
950 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
952 if(isnan(date->time)) {
953 if(r)
954 *r = jsval_string(jsstr_nan());
955 return S_OK;
958 st = create_systemtime(local_time(date->time, date));
960 if(st.wYear<1601 || st.wYear>9999)
961 return Date_toTimeString(ctx, jsthis, flags, argc, argv, r);
963 if(r) {
964 WCHAR *ptr;
966 len = GetTimeFormatW(ctx->lcid, 0, &st, NULL, NULL, 0);
967 ptr = jsstr_alloc_buf(len, &date_str);
968 if(!ptr)
969 return E_OUTOFMEMORY;
970 GetTimeFormatW(ctx->lcid, 0, &st, NULL, ptr, len);
972 *r = jsval_string(date_str);
974 return S_OK;
977 /* ECMA-262 3rd Edition 15.9.5.9 */
978 static HRESULT Date_getTime(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
979 jsval_t *r)
981 DateInstance *date;
983 TRACE("\n");
985 if(!(date = date_this(jsthis)))
986 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
988 if(r)
989 *r = jsval_number(date->time);
990 return S_OK;
993 /* ECMA-262 3rd Edition 15.9.5.10 */
994 static HRESULT Date_getFullYear(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
995 jsval_t *r)
997 DateInstance *date;
999 TRACE("\n");
1001 if(!(date = date_this(jsthis)))
1002 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1004 if(r) {
1005 DOUBLE time = local_time(date->time, date);
1007 *r = jsval_number(year_from_time(time));
1009 return S_OK;
1012 /* ECMA-262 3rd Edition 15.9.5.11 */
1013 static HRESULT Date_getUTCFullYear(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1014 jsval_t *r)
1016 DateInstance *date;
1018 TRACE("\n");
1020 if(!(date = date_this(jsthis)))
1021 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1023 if(r)
1024 *r = jsval_number(year_from_time(date->time));
1025 return S_OK;
1028 /* ECMA-262 3rd Edition 15.9.5.12 */
1029 static HRESULT Date_getMonth(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
1031 DateInstance *date;
1033 TRACE("\n");
1035 if(!(date = date_this(jsthis)))
1036 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1038 if(r)
1039 *r = jsval_number(month_from_time(local_time(date->time, date)));
1040 return S_OK;
1043 /* ECMA-262 3rd Edition 15.9.5.13 */
1044 static HRESULT Date_getUTCMonth(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1045 jsval_t *r)
1047 DateInstance *date;
1049 TRACE("\n");
1051 if(!(date = date_this(jsthis)))
1052 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1054 if(r)
1055 *r = jsval_number(month_from_time(date->time));
1056 return S_OK;
1059 /* ECMA-262 3rd Edition 15.9.5.14 */
1060 static HRESULT Date_getDate(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
1062 DateInstance *date;
1064 TRACE("\n");
1066 if(!(date = date_this(jsthis)))
1067 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1069 if(r)
1070 *r = jsval_number(date_from_time(local_time(date->time, date)));
1071 return S_OK;
1074 /* ECMA-262 3rd Edition 15.9.5.15 */
1075 static HRESULT Date_getUTCDate(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1076 jsval_t *r)
1078 DateInstance *date;
1080 TRACE("\n");
1082 if(!(date = date_this(jsthis)))
1083 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1085 if(r)
1086 *r = jsval_number(date_from_time(date->time));
1087 return S_OK;
1090 /* ECMA-262 3rd Edition 15.9.5.16 */
1091 static HRESULT Date_getDay(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1092 jsval_t *r)
1094 DateInstance *date;
1096 TRACE("\n");
1098 if(!(date = date_this(jsthis)))
1099 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1101 if(r)
1102 *r = jsval_number(week_day(local_time(date->time, date)));
1103 return S_OK;
1106 /* ECMA-262 3rd Edition 15.9.5.17 */
1107 static HRESULT Date_getUTCDay(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1108 jsval_t *r)
1110 DateInstance *date;
1112 TRACE("\n");
1114 if(!(date = date_this(jsthis)))
1115 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1117 if(r)
1118 *r = jsval_number(week_day(date->time));
1119 return S_OK;
1122 /* ECMA-262 3rd Edition 15.9.5.18 */
1123 static HRESULT Date_getHours(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1124 jsval_t *r)
1126 DateInstance *date;
1128 TRACE("\n");
1130 if(!(date = date_this(jsthis)))
1131 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1133 if(r)
1134 *r = jsval_number(hour_from_time(local_time(date->time, date)));
1135 return S_OK;
1138 /* ECMA-262 3rd Edition 15.9.5.19 */
1139 static HRESULT Date_getUTCHours(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1140 jsval_t *r)
1142 DateInstance *date;
1144 TRACE("\n");
1146 if(!(date = date_this(jsthis)))
1147 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1149 if(r)
1150 *r = jsval_number(hour_from_time(date->time));
1151 return S_OK;
1154 /* ECMA-262 3rd Edition 15.9.5.20 */
1155 static HRESULT Date_getMinutes(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1156 jsval_t *r)
1158 DateInstance *date;
1160 TRACE("\n");
1162 if(!(date = date_this(jsthis)))
1163 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1165 if(r)
1166 *r = jsval_number(min_from_time(local_time(date->time, date)));
1167 return S_OK;
1170 /* ECMA-262 3rd Edition 15.9.5.21 */
1171 static HRESULT Date_getUTCMinutes(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1172 jsval_t *r)
1174 DateInstance *date;
1176 TRACE("\n");
1178 if(!(date = date_this(jsthis)))
1179 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1181 if(r)
1182 *r = jsval_number(min_from_time(date->time));
1183 return S_OK;
1186 /* ECMA-262 3rd Edition 15.9.5.22 */
1187 static HRESULT Date_getSeconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
1189 DateInstance *date;
1191 TRACE("\n");
1193 if(!(date = date_this(jsthis)))
1194 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1196 if(r)
1197 *r = jsval_number(sec_from_time(local_time(date->time, date)));
1198 return S_OK;
1201 /* ECMA-262 3rd Edition 15.9.5.23 */
1202 static HRESULT Date_getUTCSeconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1203 jsval_t *r)
1205 DateInstance *date;
1207 TRACE("\n");
1209 if(!(date = date_this(jsthis)))
1210 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1212 if(r)
1213 *r = jsval_number(sec_from_time(date->time));
1214 return S_OK;
1217 /* ECMA-262 3rd Edition 15.9.5.24 */
1218 static HRESULT Date_getMilliseconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1219 jsval_t *r)
1221 DateInstance *date;
1223 TRACE("\n");
1225 if(!(date = date_this(jsthis)))
1226 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1228 if(r)
1229 *r = jsval_number(ms_from_time(local_time(date->time, date)));
1230 return S_OK;
1233 /* ECMA-262 3rd Edition 15.9.5.25 */
1234 static HRESULT Date_getUTCMilliseconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1235 jsval_t *r)
1237 DateInstance *date;
1239 TRACE("\n");
1241 if(!(date = date_this(jsthis)))
1242 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1244 if(r)
1245 *r = jsval_number(ms_from_time(date->time));
1246 return S_OK;
1249 /* ECMA-262 3rd Edition 15.9.5.26 */
1250 static HRESULT Date_getTimezoneOffset(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1251 jsval_t *r)
1253 DateInstance *date;
1255 TRACE("\n");
1257 if(!(date = date_this(jsthis)))
1258 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1260 if(r)
1261 *r = jsval_number(floor((date->time-local_time(date->time, date))/MS_PER_MINUTE));
1262 return S_OK;
1265 /* ECMA-262 3rd Edition 15.9.5.27 */
1266 static HRESULT Date_setTime(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1267 jsval_t *r)
1269 double n;
1270 HRESULT hres;
1271 DateInstance *date;
1273 TRACE("\n");
1275 if(!(date = date_this(jsthis)))
1276 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1278 if(!argc)
1279 return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
1281 hres = to_number(ctx, argv[0], &n);
1282 if(FAILED(hres))
1283 return hres;
1285 date->time = time_clip(n);
1287 if(r)
1288 *r = jsval_number(date->time);
1289 return S_OK;
1292 /* ECMA-262 3rd Edition 15.9.5.28 */
1293 static HRESULT Date_setMilliseconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1294 jsval_t *r)
1296 DateInstance *date;
1297 double n, t;
1298 HRESULT hres;
1300 TRACE("\n");
1302 if(!(date = date_this(jsthis)))
1303 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1305 if(!argc)
1306 return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
1308 hres = to_number(ctx, argv[0], &n);
1309 if(FAILED(hres))
1310 return hres;
1312 t = local_time(date->time, date);
1313 t = make_date(day(t), make_time(hour_from_time(t), min_from_time(t),
1314 sec_from_time(t), n));
1315 date->time = time_clip(utc(t, date));
1317 if(r)
1318 *r = jsval_number(date->time);
1319 return S_OK;
1322 /* ECMA-262 3rd Edition 15.9.5.29 */
1323 static HRESULT Date_setUTCMilliseconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1324 jsval_t *r)
1326 DateInstance *date;
1327 double n, t;
1328 HRESULT hres;
1330 TRACE("\n");
1332 if(!(date = date_this(jsthis)))
1333 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1335 if(!argc)
1336 return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
1338 hres = to_number(ctx, argv[0], &n);
1339 if(FAILED(hres))
1340 return hres;
1342 t = date->time;
1343 t = make_date(day(t), make_time(hour_from_time(t), min_from_time(t),
1344 sec_from_time(t), n));
1345 date->time = time_clip(t);
1347 if(r)
1348 *r = jsval_number(date->time);
1349 return S_OK;
1352 /* ECMA-262 3rd Edition 15.9.5.30 */
1353 static HRESULT Date_setSeconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1354 jsval_t *r)
1356 DateInstance *date;
1357 double t, sec, ms;
1358 HRESULT hres;
1360 TRACE("\n");
1362 if(!(date = date_this(jsthis)))
1363 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1365 if(!argc)
1366 return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
1368 t = local_time(date->time, date);
1370 hres = to_number(ctx, argv[0], &sec);
1371 if(FAILED(hres))
1372 return hres;
1374 if(argc > 1) {
1375 hres = to_number(ctx, argv[1], &ms);
1376 if(FAILED(hres))
1377 return hres;
1378 }else {
1379 ms = ms_from_time(t);
1382 t = make_date(day(t), make_time(hour_from_time(t),
1383 min_from_time(t), sec, ms));
1384 date->time = time_clip(utc(t, date));
1386 if(r)
1387 *r = jsval_number(date->time);
1388 return S_OK;
1391 /* ECMA-262 3rd Edition 15.9.5.31 */
1392 static HRESULT Date_setUTCSeconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1393 jsval_t *r)
1395 DateInstance *date;
1396 double t, sec, ms;
1397 HRESULT hres;
1399 TRACE("\n");
1401 if(!(date = date_this(jsthis)))
1402 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1404 if(!argc)
1405 return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
1407 t = date->time;
1409 hres = to_number(ctx, argv[0], &sec);
1410 if(FAILED(hres))
1411 return hres;
1413 if(argc > 1) {
1414 hres = to_number(ctx, argv[1], &ms);
1415 if(FAILED(hres))
1416 return hres;
1417 }else {
1418 ms = ms_from_time(t);
1421 t = make_date(day(t), make_time(hour_from_time(t),
1422 min_from_time(t), sec, ms));
1423 date->time = time_clip(t);
1425 if(r)
1426 *r = jsval_number(date->time);
1427 return S_OK;
1430 /* ECMA-262 3rd Edition 15.9.5.33 */
1431 static HRESULT Date_setMinutes(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1432 jsval_t *r)
1434 DateInstance *date;
1435 double t, min, sec, ms;
1436 HRESULT hres;
1438 TRACE("\n");
1440 if(!(date = date_this(jsthis)))
1441 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1443 if(!argc)
1444 return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
1446 t = local_time(date->time, date);
1448 hres = to_number(ctx, argv[0], &min);
1449 if(FAILED(hres))
1450 return hres;
1452 if(argc > 1) {
1453 hres = to_number(ctx, argv[1], &sec);
1454 if(FAILED(hres))
1455 return hres;
1456 }else {
1457 sec = sec_from_time(t);
1460 if(argc > 2) {
1461 hres = to_number(ctx, argv[2], &ms);
1462 if(FAILED(hres))
1463 return hres;
1464 }else {
1465 ms = ms_from_time(t);
1468 t = make_date(day(t), make_time(hour_from_time(t),
1469 min, sec, ms));
1470 date->time = time_clip(utc(t, date));
1472 if(r)
1473 *r = jsval_number(date->time);
1474 return S_OK;
1477 /* ECMA-262 3rd Edition 15.9.5.34 */
1478 static HRESULT Date_setUTCMinutes(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1479 jsval_t *r)
1481 DateInstance *date;
1482 double t, min, sec, ms;
1483 HRESULT hres;
1485 TRACE("\n");
1487 if(!(date = date_this(jsthis)))
1488 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1490 if(!argc)
1491 return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
1493 t = date->time;
1495 hres = to_number(ctx, argv[0], &min);
1496 if(FAILED(hres))
1497 return hres;
1499 if(argc > 1) {
1500 hres = to_number(ctx, argv[1], &sec);
1501 if(FAILED(hres))
1502 return hres;
1503 }else {
1504 sec = sec_from_time(t);
1507 if(argc > 2) {
1508 hres = to_number(ctx, argv[2], &ms);
1509 if(FAILED(hres))
1510 return hres;
1511 }else {
1512 ms = ms_from_time(t);
1515 t = make_date(day(t), make_time(hour_from_time(t),
1516 min, sec, ms));
1517 date->time = time_clip(t);
1519 if(r)
1520 *r = jsval_number(date->time);
1521 return S_OK;
1524 /* ECMA-262 3rd Edition 15.9.5.35 */
1525 static HRESULT Date_setHours(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1526 jsval_t *r)
1528 DateInstance *date;
1529 double t, hour, min, sec, ms;
1530 HRESULT hres;
1532 TRACE("\n");
1534 if(!(date = date_this(jsthis)))
1535 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1537 if(!argc)
1538 return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
1540 t = local_time(date->time, date);
1542 hres = to_number(ctx, argv[0], &hour);
1543 if(FAILED(hres))
1544 return hres;
1546 if(argc > 1) {
1547 hres = to_number(ctx, argv[1], &min);
1548 if(FAILED(hres))
1549 return hres;
1550 }else {
1551 min = min_from_time(t);
1554 if(argc > 2) {
1555 hres = to_number(ctx, argv[2], &sec);
1556 if(FAILED(hres))
1557 return hres;
1558 }else {
1559 sec = sec_from_time(t);
1562 if(argc > 3) {
1563 hres = to_number(ctx, argv[3], &ms);
1564 if(FAILED(hres))
1565 return hres;
1566 }else {
1567 ms = ms_from_time(t);
1570 t = make_date(day(t), make_time(hour, min, sec, ms));
1571 date->time = time_clip(utc(t, date));
1573 if(r)
1574 *r = jsval_number(date->time);
1575 return S_OK;
1578 /* ECMA-262 3rd Edition 15.9.5.36 */
1579 static HRESULT Date_setUTCHours(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1580 jsval_t *r)
1582 DateInstance *date;
1583 double t, hour, min, sec, ms;
1584 HRESULT hres;
1586 TRACE("\n");
1588 if(!(date = date_this(jsthis)))
1589 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1591 if(!argc)
1592 return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
1594 t = date->time;
1596 hres = to_number(ctx, argv[0], &hour);
1597 if(FAILED(hres))
1598 return hres;
1600 if(argc > 1) {
1601 hres = to_number(ctx, argv[1], &min);
1602 if(FAILED(hres))
1603 return hres;
1604 }else {
1605 min = min_from_time(t);
1608 if(argc > 2) {
1609 hres = to_number(ctx, argv[2], &sec);
1610 if(FAILED(hres))
1611 return hres;
1612 }else {
1613 sec = sec_from_time(t);
1616 if(argc > 3) {
1617 hres = to_number(ctx, argv[3], &ms);
1618 if(FAILED(hres))
1619 return hres;
1620 }else {
1621 ms = ms_from_time(t);
1624 t = make_date(day(t), make_time(hour, min, sec, ms));
1625 date->time = time_clip(t);
1627 if(r)
1628 *r = jsval_number(date->time);
1629 return S_OK;
1632 /* ECMA-262 3rd Edition 15.9.5.36 */
1633 static HRESULT Date_setDate(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1634 jsval_t *r)
1636 DateInstance *date;
1637 double t, n;
1638 HRESULT hres;
1640 TRACE("\n");
1642 if(!(date = date_this(jsthis)))
1643 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1645 if(!argc)
1646 return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
1648 hres = to_number(ctx, argv[0], &n);
1649 if(FAILED(hres))
1650 return hres;
1652 t = local_time(date->time, date);
1653 t = make_date(make_day(year_from_time(t), month_from_time(t), n), time_within_day(t));
1654 date->time = time_clip(utc(t, date));
1656 if(r)
1657 *r = jsval_number(date->time);
1658 return S_OK;
1661 /* ECMA-262 3rd Edition 15.9.5.37 */
1662 static HRESULT Date_setUTCDate(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1663 jsval_t *r)
1665 DateInstance *date;
1666 double t, n;
1667 HRESULT hres;
1669 TRACE("\n");
1671 if(!(date = date_this(jsthis)))
1672 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1674 if(!argc)
1675 return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
1677 hres = to_number(ctx, argv[0], &n);
1678 if(FAILED(hres))
1679 return hres;
1681 t = date->time;
1682 t = make_date(make_day(year_from_time(t), month_from_time(t), n), time_within_day(t));
1683 date->time = time_clip(t);
1685 if(r)
1686 *r = jsval_number(date->time);
1687 return S_OK;
1690 /* ECMA-262 3rd Edition 15.9.5.38 */
1691 static HRESULT Date_setMonth(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1692 jsval_t *r)
1694 DateInstance *date;
1695 DOUBLE t, month, ddate;
1696 HRESULT hres;
1698 TRACE("\n");
1700 if(!(date = date_this(jsthis)))
1701 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1703 if(!argc)
1704 return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
1706 t = local_time(date->time, date);
1708 hres = to_number(ctx, argv[0], &month);
1709 if(FAILED(hres))
1710 return hres;
1712 if(argc > 1) {
1713 hres = to_number(ctx, argv[1], &ddate);
1714 if(FAILED(hres))
1715 return hres;
1716 }else {
1717 ddate = date_from_time(t);
1720 t = make_date(make_day(year_from_time(t), month, ddate),
1721 time_within_day(t));
1722 date->time = time_clip(utc(t, date));
1724 if(r)
1725 *r = jsval_number(date->time);
1726 return S_OK;
1729 /* ECMA-262 3rd Edition 15.9.5.39 */
1730 static HRESULT Date_setUTCMonth(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1731 jsval_t *r)
1733 DateInstance *date;
1734 double t, month, ddate;
1735 HRESULT hres;
1737 TRACE("\n");
1739 if(!(date = date_this(jsthis)))
1740 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1742 if(!argc)
1743 return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
1745 t = date->time;
1747 hres = to_number(ctx, argv[0], &month);
1748 if(FAILED(hres))
1749 return hres;
1751 if(argc > 1) {
1752 hres = to_number(ctx, argv[1], &ddate);
1753 if(FAILED(hres))
1754 return hres;
1755 }else {
1756 ddate = date_from_time(t);
1759 t = make_date(make_day(year_from_time(t), month, ddate),
1760 time_within_day(t));
1761 date->time = time_clip(t);
1763 if(r)
1764 *r = jsval_number(date->time);
1765 return S_OK;
1768 /* ECMA-262 3rd Edition 15.9.5.40 */
1769 static HRESULT Date_setFullYear(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1770 jsval_t *r)
1772 DateInstance *date;
1773 double t, year, month, ddate;
1774 HRESULT hres;
1776 TRACE("\n");
1778 if(!(date = date_this(jsthis)))
1779 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1781 if(!argc)
1782 return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
1784 t = local_time(date->time, date);
1786 hres = to_number(ctx, argv[0], &year);
1787 if(FAILED(hres))
1788 return hres;
1790 if(argc > 1) {
1791 hres = to_number(ctx, argv[1], &month);
1792 if(FAILED(hres))
1793 return hres;
1794 }else {
1795 month = month_from_time(t);
1798 if(argc > 2) {
1799 hres = to_number(ctx, argv[2], &ddate);
1800 if(FAILED(hres))
1801 return hres;
1802 }else {
1803 ddate = date_from_time(t);
1806 t = make_date(make_day(year, month, ddate), time_within_day(t));
1807 date->time = time_clip(utc(t, date));
1809 if(r)
1810 *r = jsval_number(date->time);
1811 return S_OK;
1814 /* ECMA-262 3rd Edition 15.9.5.41 */
1815 static HRESULT Date_setUTCFullYear(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1816 jsval_t *r)
1818 DateInstance *date;
1819 double t, year, month, ddate;
1820 HRESULT hres;
1822 TRACE("\n");
1824 if(!(date = date_this(jsthis)))
1825 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1827 if(!argc)
1828 return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
1830 t = date->time;
1832 hres = to_number(ctx, argv[0], &year);
1833 if(FAILED(hres))
1834 return hres;
1836 if(argc > 1) {
1837 hres = to_number(ctx, argv[1], &month);
1838 if(FAILED(hres))
1839 return hres;
1840 }else {
1841 month = month_from_time(t);
1844 if(argc > 2) {
1845 hres = to_number(ctx, argv[2], &ddate);
1846 if(FAILED(hres))
1847 return hres;
1848 }else {
1849 ddate = date_from_time(t);
1852 t = make_date(make_day(year, month, ddate), time_within_day(t));
1853 date->time = time_clip(t);
1855 if(r)
1856 *r = jsval_number(date->time);
1857 return S_OK;
1860 /* ECMA-262 3rd Edition B2.4 */
1861 static HRESULT Date_getYear(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1862 jsval_t *r)
1864 DateInstance *date;
1865 DOUBLE t, year;
1867 TRACE("\n");
1869 if(!(date = date_this(jsthis)))
1870 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1872 t = local_time(date->time, date);
1873 if(isnan(t)) {
1874 if(r)
1875 *r = jsval_number(NAN);
1876 return S_OK;
1879 year = year_from_time(t);
1880 if(r)
1881 *r = jsval_number((1900<=year && year<2000)?year-1900:year);
1882 return S_OK;
1885 /* ECMA-262 3rd Edition B2.5 */
1886 static HRESULT Date_setYear(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1887 jsval_t *r)
1889 DateInstance *date;
1890 DOUBLE t, year;
1891 HRESULT hres;
1893 TRACE("\n");
1895 if(!(date = date_this(jsthis)))
1896 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1898 if(!argc)
1899 return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
1901 t = local_time(date->time, date);
1903 hres = to_number(ctx, argv[0], &year);
1904 if(FAILED(hres))
1905 return hres;
1907 if(isnan(year)) {
1908 date->time = year;
1909 if(r)
1910 *r = jsval_number(NAN);
1911 return S_OK;
1914 year = year >= 0.0 ? floor(year) : -floor(-year);
1915 if(-1.0 < year && year < 100.0)
1916 year += 1900.0;
1918 date->time = time_clip(utc(make_date(make_day(year, month_from_time(t), date_from_time(t)), time_within_day(t)), date));
1920 if(r)
1921 *r = jsval_number(date->time);
1922 return S_OK;
1925 static HRESULT Date_get_value(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r)
1927 TRACE("\n");
1929 return dateobj_to_string(date_from_jsdisp(jsthis), r);
1932 static const builtin_prop_t Date_props[] = {
1933 {getDateW, Date_getDate, PROPF_METHOD},
1934 {getDayW, Date_getDay, PROPF_METHOD},
1935 {getFullYearW, Date_getFullYear, PROPF_METHOD},
1936 {getHoursW, Date_getHours, PROPF_METHOD},
1937 {getMillisecondsW, Date_getMilliseconds, PROPF_METHOD},
1938 {getMinutesW, Date_getMinutes, PROPF_METHOD},
1939 {getMonthW, Date_getMonth, PROPF_METHOD},
1940 {getSecondsW, Date_getSeconds, PROPF_METHOD},
1941 {getTimeW, Date_getTime, PROPF_METHOD},
1942 {getTimezoneOffsetW, Date_getTimezoneOffset, PROPF_METHOD},
1943 {getUTCDateW, Date_getUTCDate, PROPF_METHOD},
1944 {getUTCDayW, Date_getUTCDay, PROPF_METHOD},
1945 {getUTCFullYearW, Date_getUTCFullYear, PROPF_METHOD},
1946 {getUTCHoursW, Date_getUTCHours, PROPF_METHOD},
1947 {getUTCMillisecondsW, Date_getUTCMilliseconds, PROPF_METHOD},
1948 {getUTCMinutesW, Date_getUTCMinutes, PROPF_METHOD},
1949 {getUTCMonthW, Date_getUTCMonth, PROPF_METHOD},
1950 {getUTCSecondsW, Date_getUTCSeconds, PROPF_METHOD},
1951 {getYearW, Date_getYear, PROPF_METHOD},
1952 {setDateW, Date_setDate, PROPF_METHOD|1},
1953 {setFullYearW, Date_setFullYear, PROPF_METHOD|3},
1954 {setHoursW, Date_setHours, PROPF_METHOD|4},
1955 {setMillisecondsW, Date_setMilliseconds, PROPF_METHOD|1},
1956 {setMinutesW, Date_setMinutes, PROPF_METHOD|3},
1957 {setMonthW, Date_setMonth, PROPF_METHOD|2},
1958 {setSecondsW, Date_setSeconds, PROPF_METHOD|2},
1959 {setTimeW, Date_setTime, PROPF_METHOD|1},
1960 {setUTCDateW, Date_setUTCDate, PROPF_METHOD|1},
1961 {setUTCFullYearW, Date_setUTCFullYear, PROPF_METHOD|3},
1962 {setUTCHoursW, Date_setUTCHours, PROPF_METHOD|4},
1963 {setUTCMillisecondsW, Date_setUTCMilliseconds, PROPF_METHOD|1},
1964 {setUTCMinutesW, Date_setUTCMinutes, PROPF_METHOD|3},
1965 {setUTCMonthW, Date_setUTCMonth, PROPF_METHOD|2},
1966 {setUTCSecondsW, Date_setUTCSeconds, PROPF_METHOD|2},
1967 {setYearW, Date_setYear, PROPF_METHOD|1},
1968 {toDateStringW, Date_toDateString, PROPF_METHOD},
1969 {toGMTStringW, Date_toGMTString, PROPF_METHOD},
1970 {toLocaleDateStringW, Date_toLocaleDateString, PROPF_METHOD},
1971 {toLocaleStringW, Date_toLocaleString, PROPF_METHOD},
1972 {toLocaleTimeStringW, Date_toLocaleTimeString, PROPF_METHOD},
1973 {toStringW, Date_toString, PROPF_METHOD},
1974 {toTimeStringW, Date_toTimeString, PROPF_METHOD},
1975 {toUTCStringW, Date_toUTCString, PROPF_METHOD},
1976 {valueOfW, Date_valueOf, PROPF_METHOD},
1979 static const builtin_info_t Date_info = {
1980 JSCLASS_DATE,
1981 {NULL, NULL,0, Date_get_value},
1982 sizeof(Date_props)/sizeof(*Date_props),
1983 Date_props,
1984 NULL,
1985 NULL
1988 static const builtin_info_t DateInst_info = {
1989 JSCLASS_DATE,
1990 {NULL, NULL,0, Date_get_value},
1991 0, NULL,
1992 NULL,
1993 NULL
1996 static HRESULT create_date(script_ctx_t *ctx, jsdisp_t *object_prototype, DOUBLE time, jsdisp_t **ret)
1998 DateInstance *date;
1999 HRESULT hres;
2000 TIME_ZONE_INFORMATION tzi;
2002 GetTimeZoneInformation(&tzi);
2004 date = heap_alloc_zero(sizeof(DateInstance));
2005 if(!date)
2006 return E_OUTOFMEMORY;
2008 if(object_prototype)
2009 hres = init_dispex(&date->dispex, ctx, &Date_info, object_prototype);
2010 else
2011 hres = init_dispex_from_constr(&date->dispex, ctx, &DateInst_info, ctx->date_constr);
2012 if(FAILED(hres)) {
2013 heap_free(date);
2014 return hres;
2017 date->time = time;
2018 date->bias = tzi.Bias;
2019 date->standardDate = tzi.StandardDate;
2020 date->standardBias = tzi.StandardBias;
2021 date->daylightDate = tzi.DaylightDate;
2022 date->daylightBias = tzi.DaylightBias;
2024 *ret = &date->dispex;
2025 return S_OK;
2028 static inline HRESULT date_parse(jsstr_t *input_str, double *ret) {
2029 static const DWORD string_ids[] = { LOCALE_SMONTHNAME12, LOCALE_SMONTHNAME11,
2030 LOCALE_SMONTHNAME10, LOCALE_SMONTHNAME9, LOCALE_SMONTHNAME8,
2031 LOCALE_SMONTHNAME7, LOCALE_SMONTHNAME6, LOCALE_SMONTHNAME5,
2032 LOCALE_SMONTHNAME4, LOCALE_SMONTHNAME3, LOCALE_SMONTHNAME2,
2033 LOCALE_SMONTHNAME1, LOCALE_SDAYNAME7, LOCALE_SDAYNAME1,
2034 LOCALE_SDAYNAME2, LOCALE_SDAYNAME3, LOCALE_SDAYNAME4,
2035 LOCALE_SDAYNAME5, LOCALE_SDAYNAME6 };
2036 WCHAR *strings[sizeof(string_ids)/sizeof(DWORD)];
2037 WCHAR *parse;
2038 int input_len, parse_len = 0, nest_level = 0, i, size;
2039 int year = 0, month = 0, day = 0, hour = 0, min = 0, sec = 0;
2040 int ms = 0, offset = 0, hour_adjust = 0;
2041 BOOL set_year = FALSE, set_month = FALSE, set_day = FALSE, set_hour = FALSE;
2042 BOOL set_offset = FALSE, set_era = FALSE, ad = TRUE, set_am = FALSE, am = TRUE;
2043 BOOL set_hour_adjust = TRUE;
2044 TIME_ZONE_INFORMATION tzi;
2045 const WCHAR *input;
2046 DateInstance di;
2047 DWORD lcid_en;
2049 input_len = jsstr_length(input_str);
2050 input = jsstr_flatten(input_str);
2051 if(!input)
2052 return E_OUTOFMEMORY;
2054 for(i=0; i<input_len; i++) {
2055 if(input[i] == '(') nest_level++;
2056 else if(input[i] == ')') {
2057 nest_level--;
2058 if(nest_level<0) {
2059 *ret = NAN;
2060 return S_OK;
2063 else if(!nest_level) parse_len++;
2066 parse = heap_alloc((parse_len+1)*sizeof(WCHAR));
2067 if(!parse)
2068 return E_OUTOFMEMORY;
2069 nest_level = 0;
2070 parse_len = 0;
2071 for(i=0; i<input_len; i++) {
2072 if(input[i] == '(') nest_level++;
2073 else if(input[i] == ')') nest_level--;
2074 else if(!nest_level) parse[parse_len++] = toupperW(input[i]);
2076 parse[parse_len] = 0;
2078 GetTimeZoneInformation(&tzi);
2079 di.bias = tzi.Bias;
2080 di.standardDate = tzi.StandardDate;
2081 di.standardBias = tzi.StandardBias;
2082 di.daylightDate = tzi.DaylightDate;
2083 di.daylightBias = tzi.DaylightBias;
2085 /* FIXME: Cache strings */
2086 lcid_en = MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT);
2087 for(i=0; i<sizeof(string_ids)/sizeof(DWORD); i++) {
2088 size = GetLocaleInfoW(lcid_en, string_ids[i], NULL, 0);
2089 strings[i] = heap_alloc((size+1)*sizeof(WCHAR));
2090 if(!strings[i]) {
2091 i--;
2092 while(i-- >= 0)
2093 heap_free(strings[i]);
2094 heap_free(parse);
2095 return E_OUTOFMEMORY;
2097 GetLocaleInfoW(lcid_en, string_ids[i], strings[i], size);
2100 for(i=0; i<parse_len;) {
2101 while(isspaceW(parse[i])) i++;
2102 if(parse[i] == ',') {
2103 while(parse[i] == ',') i++;
2104 continue;
2107 if(parse[i]>='0' && parse[i]<='9') {
2108 int tmp = atoiW(&parse[i]);
2109 while(parse[i]>='0' && parse[i]<='9') i++;
2110 while(isspaceW(parse[i])) i++;
2112 if(parse[i] == ':') {
2113 /* Time */
2114 if(set_hour) break;
2115 set_hour = TRUE;
2117 hour = tmp;
2119 while(parse[i] == ':') i++;
2120 while(isspaceW(parse[i])) i++;
2121 if(parse[i]>='0' && parse[i]<='9') {
2122 min = atoiW(&parse[i]);
2123 while(parse[i]>='0' && parse[i]<='9') i++;
2126 while(isspaceW(parse[i])) i++;
2127 while(parse[i] == ':') i++;
2128 while(isspaceW(parse[i])) i++;
2129 if(parse[i]>='0' && parse[i]<='9') {
2130 sec = atoiW(&parse[i]);
2131 while(parse[i]>='0' && parse[i]<='9') i++;
2134 else if(parse[i]=='-' || parse[i]=='/') {
2135 /* Short or long date */
2136 if(set_day || set_month || set_year) break;
2137 set_day = TRUE;
2138 set_month = TRUE;
2139 set_year = TRUE;
2141 month = tmp-1;
2143 while(isspaceW(parse[i])) i++;
2144 while(parse[i]=='-' || parse[i]=='/') i++;
2145 while(isspaceW(parse[i])) i++;
2146 if(parse[i]<'0' || parse[i]>'9') break;
2147 day = atoiW(&parse[i]);
2148 while(parse[i]>='0' && parse[i]<='9') i++;
2150 while(parse[i]=='-' || parse[i]=='/') i++;
2151 while(isspaceW(parse[i])) i++;
2152 if(parse[i]<'0' || parse[i]>'9') break;
2153 year = atoiW(&parse[i]);
2154 while(parse[i]>='0' && parse[i]<='9') i++;
2156 if(tmp >= 70){
2157 /* long date */
2158 month = day - 1;
2159 day = year;
2160 year = tmp;
2163 else if(tmp<0) break;
2164 else if(tmp<70) {
2165 /* Day */
2166 if(set_day) break;
2167 set_day = TRUE;
2168 day = tmp;
2170 else {
2171 /* Year */
2172 if(set_year) break;
2173 set_year = TRUE;
2174 year = tmp;
2177 else {
2178 if(parse[i]<'A' || parse[i]>'Z') break;
2179 else if(parse[i]=='B' && (parse[i+1]=='C' ||
2180 (parse[i+1]=='.' && parse[i+2]=='C'))) {
2181 /* AD/BC */
2182 if(set_era) break;
2183 set_era = TRUE;
2184 ad = FALSE;
2186 i++;
2187 if(parse[i] == '.') i++;
2188 i++;
2189 if(parse[i] == '.') i++;
2191 else if(parse[i]=='A' && (parse[i+1]=='D' ||
2192 (parse[i+1]=='.' && parse[i+2]=='D'))) {
2193 /* AD/BC */
2194 if(set_era) break;
2195 set_era = TRUE;
2197 i++;
2198 if(parse[i] == '.') i++;
2199 i++;
2200 if(parse[i] == '.') i++;
2202 else if(parse[i+1]<'A' || parse[i+1]>'Z') {
2203 /* Timezone */
2204 if(set_offset) break;
2205 set_offset = TRUE;
2207 if(parse[i] <= 'I') hour_adjust = parse[i]-'A'+2;
2208 else if(parse[i] == 'J') break;
2209 else if(parse[i] <= 'M') hour_adjust = parse[i]-'K'+11;
2210 else if(parse[i] <= 'Y') hour_adjust = parse[i]-'N';
2211 else hour_adjust = 1;
2213 i++;
2214 if(parse[i] == '.') i++;
2216 else if(parse[i]=='A' && parse[i+1]=='M') {
2217 /* AM/PM */
2218 if(set_am) break;
2219 set_am = TRUE;
2220 am = TRUE;
2221 i += 2;
2223 else if(parse[i]=='P' && parse[i+1]=='M') {
2224 /* AM/PM */
2225 if(set_am) break;
2226 set_am = TRUE;
2227 am = FALSE;
2228 i += 2;
2230 else if((parse[i]=='U' && parse[i+1]=='T' && parse[i+2]=='C')
2231 || (parse[i]=='G' && parse[i+1]=='M' && parse[i+2]=='T')) {
2232 /* Timezone */
2233 BOOL positive = TRUE;
2235 if(set_offset) break;
2236 set_offset = TRUE;
2237 set_hour_adjust = FALSE;
2239 i += 3;
2240 while(isspaceW(parse[i])) i++;
2241 if(parse[i] == '-') positive = FALSE;
2242 else if(parse[i] != '+') continue;
2244 i++;
2245 while(isspaceW(parse[i])) i++;
2246 if(parse[i]<'0' || parse[i]>'9') break;
2247 offset = atoiW(&parse[i]);
2248 while(parse[i]>='0' && parse[i]<='9') i++;
2250 if(offset<24) offset *= 60;
2251 else offset = (offset/100)*60 + offset%100;
2253 if(positive) offset = -offset;
2255 else {
2256 /* Month or garbage */
2257 unsigned int j;
2259 for(size=i; parse[size]>='A' && parse[size]<='Z'; size++);
2260 size -= i;
2262 for(j=0; j<sizeof(string_ids)/sizeof(DWORD); j++)
2263 if(!strncmpiW(&parse[i], strings[j], size)) break;
2265 if(j < 12) {
2266 if(set_month) break;
2267 set_month = TRUE;
2268 month = 11-j;
2270 else if(j == sizeof(string_ids)/sizeof(DWORD)) break;
2272 i += size;
2277 if(i == parse_len && set_year && set_month && set_day && (!set_am || hour<13)) {
2278 if(set_am) {
2279 if(hour == 12) hour = 0;
2280 if(!am) hour += 12;
2283 if(!ad) year = -year+1;
2284 else if(year<100) year += 1900;
2286 *ret = time_clip(make_date(make_day(year, month, day),
2287 make_time(hour+hour_adjust, min, sec, ms)) + offset*MS_PER_MINUTE);
2289 if(set_hour_adjust)
2290 *ret = utc(*ret, &di);
2291 }else {
2292 *ret = NAN;
2295 for(i=0; i<sizeof(string_ids)/sizeof(DWORD); i++)
2296 heap_free(strings[i]);
2297 heap_free(parse);
2299 return S_OK;
2302 static HRESULT DateConstr_parse(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
2303 jsval_t *r)
2305 jsstr_t *parse_str;
2306 double n;
2307 HRESULT hres;
2309 TRACE("\n");
2311 if(!argc) {
2312 if(r)
2313 *r = jsval_number(NAN);
2314 return S_OK;
2317 hres = to_string(ctx, argv[0], &parse_str);
2318 if(FAILED(hres))
2319 return hres;
2321 hres = date_parse(parse_str, &n);
2322 jsstr_release(parse_str);
2323 if(FAILED(hres))
2324 return hres;
2326 *r = jsval_number(n);
2327 return S_OK;
2330 static HRESULT date_utc(script_ctx_t *ctx, unsigned argc, jsval_t *argv, double *ret)
2332 double year, month, vdate, hours, minutes, seconds, ms;
2333 HRESULT hres;
2335 TRACE("\n");
2337 if(argc) {
2338 hres = to_number(ctx, argv[0], &year);
2339 if(FAILED(hres))
2340 return hres;
2341 if(0 <= year && year <= 99)
2342 year += 1900;
2343 }else {
2344 year = 1900;
2347 if(argc>1) {
2348 hres = to_number(ctx, argv[1], &month);
2349 if(FAILED(hres))
2350 return hres;
2351 }else {
2352 month = 0;
2355 if(argc>2) {
2356 hres = to_number(ctx, argv[2], &vdate);
2357 if(FAILED(hres))
2358 return hres;
2359 }else {
2360 vdate = 1;
2363 if(argc>3) {
2364 hres = to_number(ctx, argv[3], &hours);
2365 if(FAILED(hres))
2366 return hres;
2367 }else {
2368 hours = 0;
2371 if(argc>4) {
2372 hres = to_number(ctx, argv[4], &minutes);
2373 if(FAILED(hres))
2374 return hres;
2375 }else {
2376 minutes = 0;
2379 if(argc>5) {
2380 hres = to_number(ctx, argv[5], &seconds);
2381 if(FAILED(hres))
2382 return hres;
2383 }else {
2384 seconds = 0;
2387 if(argc>6) {
2388 hres = to_number(ctx, argv[6], &ms);
2389 if(FAILED(hres))
2390 return hres;
2391 } else {
2392 ms = 0;
2395 *ret = time_clip(make_date(make_day(year, month, vdate),
2396 make_time(hours, minutes,seconds, ms)));
2397 return S_OK;
2400 static HRESULT DateConstr_UTC(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
2401 jsval_t *r)
2403 double n;
2404 HRESULT hres;
2406 TRACE("\n");
2408 hres = date_utc(ctx, argc, argv, &n);
2409 if(SUCCEEDED(hres) && r)
2410 *r = jsval_number(n);
2411 return hres;
2414 static HRESULT DateConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
2415 jsval_t *r)
2417 jsdisp_t *date;
2418 HRESULT hres;
2420 TRACE("\n");
2422 switch(flags) {
2423 case DISPATCH_CONSTRUCT:
2424 switch(argc) {
2425 /* ECMA-262 3rd Edition 15.9.3.3 */
2426 case 0: {
2427 FILETIME time;
2428 LONGLONG lltime;
2430 GetSystemTimeAsFileTime(&time);
2431 lltime = ((LONGLONG)time.dwHighDateTime<<32)
2432 + time.dwLowDateTime;
2434 hres = create_date(ctx, NULL, lltime/10000-TIME_EPOCH, &date);
2435 if(FAILED(hres))
2436 return hres;
2437 break;
2440 /* ECMA-262 3rd Edition 15.9.3.2 */
2441 case 1: {
2442 jsval_t prim;
2443 double n;
2445 hres = to_primitive(ctx, argv[0], &prim, NO_HINT);
2446 if(FAILED(hres))
2447 return hres;
2449 if(is_string(prim))
2450 hres = date_parse(get_string(prim), &n);
2451 else
2452 hres = to_number(ctx, prim, &n);
2454 jsval_release(prim);
2455 if(FAILED(hres))
2456 return hres;
2458 hres = create_date(ctx, NULL, time_clip(n), &date);
2459 if(FAILED(hres))
2460 return hres;
2461 break;
2464 /* ECMA-262 3rd Edition 15.9.3.1 */
2465 default: {
2466 double ret_date;
2467 DateInstance *di;
2469 hres = date_utc(ctx, argc, argv, &ret_date);
2470 if(FAILED(hres))
2471 return hres;
2473 hres = create_date(ctx, NULL, ret_date, &date);
2474 if(FAILED(hres))
2475 return hres;
2477 di = (DateInstance*)date;
2478 di->time = utc(di->time, di);
2482 *r = jsval_obj(date);
2483 return S_OK;
2485 case INVOKE_FUNC: {
2486 FILETIME system_time, local_time;
2487 LONGLONG lltime;
2489 GetSystemTimeAsFileTime(&system_time);
2490 FileTimeToLocalFileTime(&system_time, &local_time);
2491 lltime = ((LONGLONG)local_time.dwHighDateTime<<32)
2492 + local_time.dwLowDateTime;
2494 return date_to_string(lltime/10000-TIME_EPOCH, FALSE, 0, r);
2497 default:
2498 FIXME("unimplemented flags %x\n", flags);
2499 return E_NOTIMPL;
2502 return S_OK;
2505 static const builtin_prop_t DateConstr_props[] = {
2506 {UTCW, DateConstr_UTC, PROPF_METHOD},
2507 {parseW, DateConstr_parse, PROPF_METHOD}
2510 static const builtin_info_t DateConstr_info = {
2511 JSCLASS_FUNCTION,
2512 DEFAULT_FUNCTION_VALUE,
2513 sizeof(DateConstr_props)/sizeof(*DateConstr_props),
2514 DateConstr_props,
2515 NULL,
2516 NULL
2519 HRESULT create_date_constr(script_ctx_t *ctx, jsdisp_t *object_prototype, jsdisp_t **ret)
2521 jsdisp_t *date;
2522 HRESULT hres;
2524 static const WCHAR DateW[] = {'D','a','t','e',0};
2526 hres = create_date(ctx, object_prototype, 0.0, &date);
2527 if(FAILED(hres))
2528 return hres;
2530 hres = create_builtin_constructor(ctx, DateConstr_value, DateW, &DateConstr_info,
2531 PROPF_CONSTR|7, date, ret);
2533 jsdisp_release(date);
2534 return hres;