wined3d: Move the fill mode to wined3d_rasterizer_state.
[wine.git] / dlls / jscript / date.c
blob60591bb045bb8483481d4eb162c6800103a0301b
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
21 #include <limits.h>
22 #include <math.h>
23 #include <assert.h>
25 #include "jscript.h"
27 #include "wine/debug.h"
29 WINE_DEFAULT_DEBUG_CHANNEL(jscript);
31 /* 1601 to 1970 is 369 years plus 89 leap days */
32 #define TIME_EPOCH ((ULONGLONG)(369 * 365 + 89) * 86400 * 1000)
34 typedef struct {
35 jsdisp_t dispex;
37 /* ECMA-262 3rd Edition 15.9.1.1 */
38 DOUBLE time;
40 LONG bias;
41 SYSTEMTIME standardDate;
42 LONG standardBias;
43 SYSTEMTIME daylightDate;
44 LONG daylightBias;
45 } DateInstance;
47 static const WCHAR toStringW[] = {'t','o','S','t','r','i','n','g',0};
48 static const WCHAR toLocaleStringW[] = {'t','o','L','o','c','a','l','e','S','t','r','i','n','g',0};
49 static const WCHAR valueOfW[] = {'v','a','l','u','e','O','f',0};
50 static const WCHAR toISOStringW[] = {'t','o','I','S','O','S','t','r','i','n','g',0};
51 static const WCHAR toUTCStringW[] = {'t','o','U','T','C','S','t','r','i','n','g',0};
52 static const WCHAR toGMTStringW[] = {'t','o','G','M','T','S','t','r','i','n','g',0};
53 static const WCHAR toDateStringW[] = {'t','o','D','a','t','e','S','t','r','i','n','g',0};
54 static const WCHAR toTimeStringW[] = {'t','o','T','i','m','e','S','t','r','i','n','g',0};
55 static const WCHAR toLocaleDateStringW[] = {'t','o','L','o','c','a','l','e','D','a','t','e','S','t','r','i','n','g',0};
56 static const WCHAR toLocaleTimeStringW[] = {'t','o','L','o','c','a','l','e','T','i','m','e','S','t','r','i','n','g',0};
57 static const WCHAR getTimeW[] = {'g','e','t','T','i','m','e',0};
58 static const WCHAR getFullYearW[] = {'g','e','t','F','u','l','l','Y','e','a','r',0};
59 static const WCHAR getUTCFullYearW[] = {'g','e','t','U','T','C','F','u','l','l','Y','e','a','r',0};
60 static const WCHAR getMonthW[] = {'g','e','t','M','o','n','t','h',0};
61 static const WCHAR getUTCMonthW[] = {'g','e','t','U','T','C','M','o','n','t','h',0};
62 static const WCHAR getDateW[] = {'g','e','t','D','a','t','e',0};
63 static const WCHAR getUTCDateW[] = {'g','e','t','U','T','C','D','a','t','e',0};
64 static const WCHAR getDayW[] = {'g','e','t','D','a','y',0};
65 static const WCHAR getUTCDayW[] = {'g','e','t','U','T','C','D','a','y',0};
66 static const WCHAR getHoursW[] = {'g','e','t','H','o','u','r','s',0};
67 static const WCHAR getUTCHoursW[] = {'g','e','t','U','T','C','H','o','u','r','s',0};
68 static const WCHAR getMinutesW[] = {'g','e','t','M','i','n','u','t','e','s',0};
69 static const WCHAR getUTCMinutesW[] = {'g','e','t','U','T','C','M','i','n','u','t','e','s',0};
70 static const WCHAR getSecondsW[] = {'g','e','t','S','e','c','o','n','d','s',0};
71 static const WCHAR getUTCSecondsW[] = {'g','e','t','U','T','C','S','e','c','o','n','d','s',0};
72 static const WCHAR getMillisecondsW[] = {'g','e','t','M','i','l','l','i','s','e','c','o','n','d','s',0};
73 static const WCHAR getUTCMillisecondsW[] = {'g','e','t','U','T','C','M','i','l','l','i','s','e','c','o','n','d','s',0};
74 static const WCHAR getTimezoneOffsetW[] = {'g','e','t','T','i','m','e','z','o','n','e','O','f','f','s','e','t',0};
75 static const WCHAR setTimeW[] = {'s','e','t','T','i','m','e',0};
76 static const WCHAR setMillisecondsW[] = {'s','e','t','M','i','l','l','i','s','e','c','o','n','d','s',0};
77 static const WCHAR setUTCMillisecondsW[] = {'s','e','t','U','T','C','M','i','l','l','i','s','e','c','o','n','d','s',0};
78 static const WCHAR setSecondsW[] = {'s','e','t','S','e','c','o','n','d','s',0};
79 static const WCHAR setUTCSecondsW[] = {'s','e','t','U','T','C','S','e','c','o','n','d','s',0};
80 static const WCHAR setMinutesW[] = {'s','e','t','M','i','n','u','t','e','s',0};
81 static const WCHAR setUTCMinutesW[] = {'s','e','t','U','T','C','M','i','n','u','t','e','s',0};
82 static const WCHAR setHoursW[] = {'s','e','t','H','o','u','r','s',0};
83 static const WCHAR setUTCHoursW[] = {'s','e','t','U','T','C','H','o','u','r','s',0};
84 static const WCHAR setDateW[] = {'s','e','t','D','a','t','e',0};
85 static const WCHAR setUTCDateW[] = {'s','e','t','U','T','C','D','a','t','e',0};
86 static const WCHAR setMonthW[] = {'s','e','t','M','o','n','t','h',0};
87 static const WCHAR setUTCMonthW[] = {'s','e','t','U','T','C','M','o','n','t','h',0};
88 static const WCHAR setFullYearW[] = {'s','e','t','F','u','l','l','Y','e','a','r',0};
89 static const WCHAR setUTCFullYearW[] = {'s','e','t','U','T','C','F','u','l','l','Y','e','a','r',0};
90 static const WCHAR getYearW[] = {'g','e','t','Y','e','a','r',0};
91 static const WCHAR setYearW[] = {'s','e','t','Y','e','a','r',0};
93 static const WCHAR UTCW[] = {'U','T','C',0};
94 static const WCHAR nowW[] = {'n','o','w',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 double date_now(void)
457 FILETIME ftime;
458 LONGLONG time;
460 GetSystemTimeAsFileTime(&ftime);
461 time = ((LONGLONG)ftime.dwHighDateTime << 32) + ftime.dwLowDateTime;
463 return time/10000 - TIME_EPOCH;
466 static SYSTEMTIME create_systemtime(DOUBLE time)
468 SYSTEMTIME st;
470 st.wYear = year_from_time(time);
471 st.wMonth = month_from_time(time) + 1;
472 st.wDayOfWeek = week_day(time);
473 st.wDay = date_from_time(time);
474 st.wHour = hour_from_time(time);
475 st.wMinute = min_from_time(time);
476 st.wSecond = sec_from_time(time);
477 st.wMilliseconds = ms_from_time(time);
479 return st;
482 static inline HRESULT date_to_string(DOUBLE time, BOOL show_offset, int offset, jsval_t *r)
484 static const WCHAR formatW[] = { '%','s',' ','%','s',' ','%','d',' ',
485 '%','0','2','d',':','%','0','2','d',':','%','0','2','d',' ',
486 'U','T','C','%','c','%','0','2','d','%','0','2','d',' ','%','d','%','s',0 };
487 static const WCHAR formatUTCW[] = { '%','s',' ','%','s',' ','%','d',' ',
488 '%','0','2','d',':','%','0','2','d',':','%','0','2','d',' ',
489 'U','T','C',' ','%','d','%','s',0 };
490 static const WCHAR formatNoOffsetW[] = { '%','s',' ','%','s',' ',
491 '%','d',' ','%','0','2','d',':','%','0','2','d',':',
492 '%','0','2','d',' ','%','d','%','s',0 };
493 static const WCHAR ADW[] = { 0 };
494 static const WCHAR BCW[] = { ' ','B','.','C','.',0 };
496 static const DWORD week_ids[] = { LOCALE_SABBREVDAYNAME7, LOCALE_SABBREVDAYNAME1,
497 LOCALE_SABBREVDAYNAME2, LOCALE_SABBREVDAYNAME3, LOCALE_SABBREVDAYNAME4,
498 LOCALE_SABBREVDAYNAME5, LOCALE_SABBREVDAYNAME6 };
499 static const DWORD month_ids[] = { LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2,
500 LOCALE_SABBREVMONTHNAME3, LOCALE_SABBREVMONTHNAME4,
501 LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6,
502 LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8,
503 LOCALE_SABBREVMONTHNAME9, LOCALE_SABBREVMONTHNAME10,
504 LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12 };
506 BOOL formatAD = TRUE;
507 WCHAR week[64], month[64];
508 WCHAR buf[192];
509 jsstr_t *date_jsstr;
510 int year, day;
511 DWORD lcid_en;
512 WCHAR sign = '-';
514 if(isnan(time)) {
515 if(r)
516 *r = jsval_string(jsstr_nan());
517 return S_OK;
520 if(r) {
521 lcid_en = MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT);
523 week[0] = 0;
524 GetLocaleInfoW(lcid_en, week_ids[(int)week_day(time)], week, ARRAY_SIZE(week));
526 month[0] = 0;
527 GetLocaleInfoW(lcid_en, month_ids[(int)month_from_time(time)], month, ARRAY_SIZE(month));
529 year = year_from_time(time);
530 if(year<0) {
531 formatAD = FALSE;
532 year = -year+1;
535 day = date_from_time(time);
537 if(offset < 0) {
538 sign = '+';
539 offset = -offset;
542 if(!show_offset)
543 swprintf(buf, ARRAY_SIZE(buf), formatNoOffsetW, week, month, day,
544 (int)hour_from_time(time), (int)min_from_time(time),
545 (int)sec_from_time(time), year, formatAD?ADW:BCW);
546 else if(offset)
547 swprintf(buf, ARRAY_SIZE(buf), formatW, week, month, day,
548 (int)hour_from_time(time), (int)min_from_time(time),
549 (int)sec_from_time(time), sign, offset/60, offset%60,
550 year, formatAD?ADW:BCW);
551 else
552 swprintf(buf, ARRAY_SIZE(buf), formatUTCW, week, month, day,
553 (int)hour_from_time(time), (int)min_from_time(time),
554 (int)sec_from_time(time), year, formatAD?ADW:BCW);
556 date_jsstr = jsstr_alloc(buf);
557 if(!date_jsstr)
558 return E_OUTOFMEMORY;
560 *r = jsval_string(date_jsstr);
562 return S_OK;
565 /* ECMA-262 3rd Edition 15.9.1.2 */
566 static HRESULT dateobj_to_string(DateInstance *date, jsval_t *r)
568 DOUBLE time;
569 int offset;
571 time = local_time(date->time, date);
572 offset = date->bias +
573 daylight_saving_ta(time, date);
575 return date_to_string(time, TRUE, offset, r);
578 static HRESULT Date_toString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
580 DateInstance *date;
582 TRACE("\n");
584 if(!(date = date_this(jsthis)))
585 return JS_E_DATE_EXPECTED;
587 return dateobj_to_string(date, r);
590 /* ECMA-262 3rd Edition 15.9.1.5 */
591 static HRESULT Date_toLocaleString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
592 jsval_t *r)
594 SYSTEMTIME st;
595 DateInstance *date;
596 jsstr_t *date_str;
597 int date_len, time_len;
599 TRACE("\n");
601 if(!(date = date_this(jsthis)))
602 return JS_E_DATE_EXPECTED;
604 if(isnan(date->time)) {
605 if(r)
606 *r = jsval_string(jsstr_nan());
607 return S_OK;
610 st = create_systemtime(local_time(date->time, date));
612 if(st.wYear<1601 || st.wYear>9999)
613 return dateobj_to_string(date, r);
615 if(r) {
616 WCHAR *ptr;
618 date_len = GetDateFormatW(ctx->lcid, DATE_LONGDATE, &st, NULL, NULL, 0);
619 time_len = GetTimeFormatW(ctx->lcid, 0, &st, NULL, NULL, 0);
621 date_str = jsstr_alloc_buf(date_len+time_len-1, &ptr);
622 if(!date_str)
623 return E_OUTOFMEMORY;
625 GetDateFormatW(ctx->lcid, DATE_LONGDATE, &st, NULL, ptr, date_len);
626 GetTimeFormatW(ctx->lcid, 0, &st, NULL, ptr+date_len, time_len);
627 ptr[date_len-1] = ' ';
629 *r = jsval_string(date_str);
631 return S_OK;
634 static HRESULT Date_toISOString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
635 jsval_t *r)
637 DateInstance *date;
638 WCHAR buf[64], *p = buf;
639 double year;
641 static const WCHAR short_year_formatW[] = {'%','0','4','d',0};
642 static const WCHAR long_year_formatW[] = {'%','0','6','d',0};
643 static const WCHAR formatW[] = {'-','%','0','2','d','-','%','0','2','d',
644 'T','%','0','2','d',':','%','0','2','d',':','%','0','2','d','.','%','0','3','d','Z',0};
646 TRACE("\n");
648 if(!(date = date_this(jsthis)))
649 return JS_E_DATE_EXPECTED;
651 year = year_from_time(date->time);
652 if(isnan(year) || year > 999999 || year < -999999) {
653 FIXME("year %lf should throw an exception\n", year);
654 return E_FAIL;
657 if(year < 0) {
658 *p++ = '-';
659 p += swprintf(p, ARRAY_SIZE(buf) - 1, long_year_formatW, -(int)year);
660 }else if(year > 9999) {
661 *p++ = '+';
662 p += swprintf(p, ARRAY_SIZE(buf) - 1, long_year_formatW, (int)year);
663 }else {
664 p += swprintf(p, ARRAY_SIZE(buf), short_year_formatW, (int)year);
667 swprintf(p, ARRAY_SIZE(buf) - (p - buf), formatW,
668 (int)month_from_time(date->time) + 1, (int)date_from_time(date->time),
669 (int)hour_from_time(date->time), (int)min_from_time(date->time),
670 (int)sec_from_time(date->time), (int)ms_from_time(date->time));
672 if(r) {
673 jsstr_t *ret;
674 if(!(ret = jsstr_alloc(buf)))
675 return E_OUTOFMEMORY;
676 *r = jsval_string(ret);
678 return S_OK;
681 static HRESULT Date_valueOf(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
682 jsval_t *r)
684 DateInstance *date;
686 TRACE("\n");
688 if(!(date = date_this(jsthis)))
689 return JS_E_DATE_EXPECTED;
691 if(r)
692 *r = jsval_number(date->time);
693 return S_OK;
696 static inline HRESULT create_utc_string(script_ctx_t *ctx, vdisp_t *jsthis, jsval_t *r)
698 static const WCHAR formatADW[] = { '%','s',',',' ','%','d',' ','%','s',' ','%','d',' ',
699 '%','0','2','d',':','%','0','2','d',':','%','0','2','d',' ','U','T','C',0 };
700 static const WCHAR formatBCW[] = { '%','s',',',' ','%','d',' ','%','s',' ','%','d',' ','B','.','C','.',' ',
701 '%','0','2','d',':','%','0','2','d',':','%','0','2','d',' ','U','T','C',0 };
703 static const DWORD week_ids[] = { LOCALE_SABBREVDAYNAME7, LOCALE_SABBREVDAYNAME1,
704 LOCALE_SABBREVDAYNAME2, LOCALE_SABBREVDAYNAME3, LOCALE_SABBREVDAYNAME4,
705 LOCALE_SABBREVDAYNAME5, LOCALE_SABBREVDAYNAME6 };
706 static const DWORD month_ids[] = { LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2,
707 LOCALE_SABBREVMONTHNAME3, LOCALE_SABBREVMONTHNAME4,
708 LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6,
709 LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8,
710 LOCALE_SABBREVMONTHNAME9, LOCALE_SABBREVMONTHNAME10,
711 LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12 };
713 BOOL formatAD = TRUE;
714 WCHAR week[64], month[64];
715 WCHAR buf[192];
716 DateInstance *date;
717 jsstr_t *date_str;
718 int year, day;
719 DWORD lcid_en;
721 if(!(date = date_this(jsthis)))
722 return JS_E_DATE_EXPECTED;
724 if(isnan(date->time)) {
725 if(r)
726 *r = jsval_string(jsstr_nan());
727 return S_OK;
730 if(r) {
731 lcid_en = MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT);
733 week[0] = 0;
734 GetLocaleInfoW(lcid_en, week_ids[(int)week_day(date->time)], week, ARRAY_SIZE(week));
736 month[0] = 0;
737 GetLocaleInfoW(lcid_en, month_ids[(int)month_from_time(date->time)], month, ARRAY_SIZE(month));
739 year = year_from_time(date->time);
740 if(year<0) {
741 formatAD = FALSE;
742 year = -year+1;
745 day = date_from_time(date->time);
747 swprintf(buf, ARRAY_SIZE(buf), formatAD ? formatADW : formatBCW, week, day, month, year,
748 (int)hour_from_time(date->time), (int)min_from_time(date->time),
749 (int)sec_from_time(date->time));
751 date_str = jsstr_alloc(buf);
752 if(!date_str)
753 return E_OUTOFMEMORY;
755 *r = jsval_string(date_str);
757 return S_OK;
760 /* ECMA-262 3rd Edition 15.9.5.42 */
761 static HRESULT Date_toUTCString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
762 jsval_t *r)
764 TRACE("\n");
765 return create_utc_string(ctx, jsthis, r);
768 static HRESULT Date_toGMTString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
769 jsval_t *r)
771 TRACE("\n");
772 return create_utc_string(ctx, jsthis, r);
775 /* ECMA-262 3rd Edition 15.9.5.3 */
776 static HRESULT dateobj_to_date_string(DateInstance *date, jsval_t *r)
778 static const WCHAR formatADW[] = { '%','s',' ','%','s',' ','%','d',' ','%','d',0 };
779 static const WCHAR formatBCW[] = { '%','s',' ','%','s',' ','%','d',' ','%','d',' ','B','.','C','.',0 };
781 static const DWORD week_ids[] = { LOCALE_SABBREVDAYNAME7, LOCALE_SABBREVDAYNAME1,
782 LOCALE_SABBREVDAYNAME2, LOCALE_SABBREVDAYNAME3, LOCALE_SABBREVDAYNAME4,
783 LOCALE_SABBREVDAYNAME5, LOCALE_SABBREVDAYNAME6 };
784 static const DWORD month_ids[] = { LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2,
785 LOCALE_SABBREVMONTHNAME3, LOCALE_SABBREVMONTHNAME4,
786 LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6,
787 LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8,
788 LOCALE_SABBREVMONTHNAME9, LOCALE_SABBREVMONTHNAME10,
789 LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12 };
791 BOOL formatAD = TRUE;
792 WCHAR week[64], month[64];
793 WCHAR buf[192];
794 jsstr_t *date_str;
795 DOUBLE time;
796 int year, day;
797 DWORD lcid_en;
799 if(isnan(date->time)) {
800 if(r)
801 *r = jsval_string(jsstr_nan());
802 return S_OK;
805 time = local_time(date->time, date);
807 if(r) {
808 lcid_en = MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT);
810 week[0] = 0;
811 GetLocaleInfoW(lcid_en, week_ids[(int)week_day(time)], week, ARRAY_SIZE(week));
813 month[0] = 0;
814 GetLocaleInfoW(lcid_en, month_ids[(int)month_from_time(time)], month, ARRAY_SIZE(month));
816 year = year_from_time(time);
817 if(year<0) {
818 formatAD = FALSE;
819 year = -year+1;
822 day = date_from_time(time);
824 swprintf(buf, ARRAY_SIZE(buf), formatAD ? formatADW : formatBCW, week, month, day, year);
826 date_str = jsstr_alloc(buf);
827 if(!date_str)
828 return E_OUTOFMEMORY;
830 *r = jsval_string(date_str);
832 return S_OK;
835 static HRESULT Date_toDateString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
836 jsval_t *r)
838 DateInstance *date;
840 if(!(date = date_this(jsthis)))
841 return JS_E_DATE_EXPECTED;
843 return dateobj_to_date_string(date, r);
846 /* ECMA-262 3rd Edition 15.9.5.4 */
847 static HRESULT Date_toTimeString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
848 jsval_t *r)
850 static const WCHAR formatW[] = { '%','0','2','d',':','%','0','2','d',':','%','0','2','d',
851 ' ','U','T','C','%','c','%','0','2','d','%','0','2','d',0 };
852 static const WCHAR formatUTCW[] = { '%','0','2','d',':','%','0','2','d',
853 ':','%','0','2','d',' ','U','T','C',0 };
854 DateInstance *date;
855 jsstr_t *date_str;
856 WCHAR buf[32];
857 DOUBLE time;
858 WCHAR sign;
859 int offset;
861 TRACE("\n");
863 if(!(date = date_this(jsthis)))
864 return JS_E_DATE_EXPECTED;
866 if(isnan(date->time)) {
867 if(r)
868 *r = jsval_string(jsstr_nan());
869 return S_OK;
872 time = local_time(date->time, date);
874 if(r) {
875 offset = date->bias +
876 daylight_saving_ta(time, date);
878 if(offset < 0) {
879 sign = '+';
880 offset = -offset;
882 else sign = '-';
884 if(offset)
885 swprintf(buf, ARRAY_SIZE(buf), formatW, (int)hour_from_time(time),
886 (int)min_from_time(time), (int)sec_from_time(time),
887 sign, offset/60, offset%60);
888 else
889 swprintf(buf, ARRAY_SIZE(buf), formatUTCW, (int)hour_from_time(time),
890 (int)min_from_time(time), (int)sec_from_time(time));
892 date_str = jsstr_alloc(buf);
893 if(!date_str)
894 return E_OUTOFMEMORY;
896 *r = jsval_string(date_str);
898 return S_OK;
901 /* ECMA-262 3rd Edition 15.9.5.6 */
902 static HRESULT Date_toLocaleDateString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
903 jsval_t *r)
905 SYSTEMTIME st;
906 DateInstance *date;
907 jsstr_t *date_str;
908 int len;
910 TRACE("\n");
912 if(!(date = date_this(jsthis)))
913 return JS_E_DATE_EXPECTED;
915 if(isnan(date->time)) {
916 if(r)
917 *r = jsval_string(jsstr_nan());
918 return S_OK;
921 st = create_systemtime(local_time(date->time, date));
923 if(st.wYear<1601 || st.wYear>9999)
924 return dateobj_to_date_string(date, r);
926 if(r) {
927 WCHAR *ptr;
929 len = GetDateFormatW(ctx->lcid, DATE_LONGDATE, &st, NULL, NULL, 0);
930 date_str = jsstr_alloc_buf(len-1, &ptr);
931 if(!date_str)
932 return E_OUTOFMEMORY;
933 GetDateFormatW(ctx->lcid, DATE_LONGDATE, &st, NULL, ptr, len);
935 *r = jsval_string(date_str);
937 return S_OK;
940 /* ECMA-262 3rd Edition 15.9.5.7 */
941 static HRESULT Date_toLocaleTimeString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
942 jsval_t *r)
944 SYSTEMTIME st;
945 DateInstance *date;
946 jsstr_t *date_str;
947 int len;
949 TRACE("\n");
951 if(!(date = date_this(jsthis)))
952 return JS_E_DATE_EXPECTED;
954 if(isnan(date->time)) {
955 if(r)
956 *r = jsval_string(jsstr_nan());
957 return S_OK;
960 st = create_systemtime(local_time(date->time, date));
962 if(st.wYear<1601 || st.wYear>9999)
963 return Date_toTimeString(ctx, jsthis, flags, argc, argv, r);
965 if(r) {
966 WCHAR *ptr;
968 len = GetTimeFormatW(ctx->lcid, 0, &st, NULL, NULL, 0);
969 date_str = jsstr_alloc_buf(len-1, &ptr);
970 if(!date_str)
971 return E_OUTOFMEMORY;
972 GetTimeFormatW(ctx->lcid, 0, &st, NULL, ptr, len);
974 *r = jsval_string(date_str);
976 return S_OK;
979 /* ECMA-262 3rd Edition 15.9.5.9 */
980 static HRESULT Date_getTime(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
981 jsval_t *r)
983 DateInstance *date;
985 TRACE("\n");
987 if(!(date = date_this(jsthis)))
988 return JS_E_DATE_EXPECTED;
990 if(r)
991 *r = jsval_number(date->time);
992 return S_OK;
995 /* ECMA-262 3rd Edition 15.9.5.10 */
996 static HRESULT Date_getFullYear(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
997 jsval_t *r)
999 DateInstance *date;
1001 TRACE("\n");
1003 if(!(date = date_this(jsthis)))
1004 return JS_E_DATE_EXPECTED;
1006 if(r) {
1007 DOUBLE time = local_time(date->time, date);
1009 *r = jsval_number(year_from_time(time));
1011 return S_OK;
1014 /* ECMA-262 3rd Edition 15.9.5.11 */
1015 static HRESULT Date_getUTCFullYear(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1016 jsval_t *r)
1018 DateInstance *date;
1020 TRACE("\n");
1022 if(!(date = date_this(jsthis)))
1023 return JS_E_DATE_EXPECTED;
1025 if(r)
1026 *r = jsval_number(year_from_time(date->time));
1027 return S_OK;
1030 /* ECMA-262 3rd Edition 15.9.5.12 */
1031 static HRESULT Date_getMonth(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
1033 DateInstance *date;
1035 TRACE("\n");
1037 if(!(date = date_this(jsthis)))
1038 return JS_E_DATE_EXPECTED;
1040 if(r)
1041 *r = jsval_number(month_from_time(local_time(date->time, date)));
1042 return S_OK;
1045 /* ECMA-262 3rd Edition 15.9.5.13 */
1046 static HRESULT Date_getUTCMonth(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1047 jsval_t *r)
1049 DateInstance *date;
1051 TRACE("\n");
1053 if(!(date = date_this(jsthis)))
1054 return JS_E_DATE_EXPECTED;
1056 if(r)
1057 *r = jsval_number(month_from_time(date->time));
1058 return S_OK;
1061 /* ECMA-262 3rd Edition 15.9.5.14 */
1062 static HRESULT Date_getDate(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
1064 DateInstance *date;
1066 TRACE("\n");
1068 if(!(date = date_this(jsthis)))
1069 return JS_E_DATE_EXPECTED;
1071 if(r)
1072 *r = jsval_number(date_from_time(local_time(date->time, date)));
1073 return S_OK;
1076 /* ECMA-262 3rd Edition 15.9.5.15 */
1077 static HRESULT Date_getUTCDate(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1078 jsval_t *r)
1080 DateInstance *date;
1082 TRACE("\n");
1084 if(!(date = date_this(jsthis)))
1085 return JS_E_DATE_EXPECTED;
1087 if(r)
1088 *r = jsval_number(date_from_time(date->time));
1089 return S_OK;
1092 /* ECMA-262 3rd Edition 15.9.5.16 */
1093 static HRESULT Date_getDay(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1094 jsval_t *r)
1096 DateInstance *date;
1098 TRACE("\n");
1100 if(!(date = date_this(jsthis)))
1101 return JS_E_DATE_EXPECTED;
1103 if(r)
1104 *r = jsval_number(week_day(local_time(date->time, date)));
1105 return S_OK;
1108 /* ECMA-262 3rd Edition 15.9.5.17 */
1109 static HRESULT Date_getUTCDay(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1110 jsval_t *r)
1112 DateInstance *date;
1114 TRACE("\n");
1116 if(!(date = date_this(jsthis)))
1117 return JS_E_DATE_EXPECTED;
1119 if(r)
1120 *r = jsval_number(week_day(date->time));
1121 return S_OK;
1124 /* ECMA-262 3rd Edition 15.9.5.18 */
1125 static HRESULT Date_getHours(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1126 jsval_t *r)
1128 DateInstance *date;
1130 TRACE("\n");
1132 if(!(date = date_this(jsthis)))
1133 return JS_E_DATE_EXPECTED;
1135 if(r)
1136 *r = jsval_number(hour_from_time(local_time(date->time, date)));
1137 return S_OK;
1140 /* ECMA-262 3rd Edition 15.9.5.19 */
1141 static HRESULT Date_getUTCHours(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1142 jsval_t *r)
1144 DateInstance *date;
1146 TRACE("\n");
1148 if(!(date = date_this(jsthis)))
1149 return JS_E_DATE_EXPECTED;
1151 if(r)
1152 *r = jsval_number(hour_from_time(date->time));
1153 return S_OK;
1156 /* ECMA-262 3rd Edition 15.9.5.20 */
1157 static HRESULT Date_getMinutes(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1158 jsval_t *r)
1160 DateInstance *date;
1162 TRACE("\n");
1164 if(!(date = date_this(jsthis)))
1165 return JS_E_DATE_EXPECTED;
1167 if(r)
1168 *r = jsval_number(min_from_time(local_time(date->time, date)));
1169 return S_OK;
1172 /* ECMA-262 3rd Edition 15.9.5.21 */
1173 static HRESULT Date_getUTCMinutes(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1174 jsval_t *r)
1176 DateInstance *date;
1178 TRACE("\n");
1180 if(!(date = date_this(jsthis)))
1181 return JS_E_DATE_EXPECTED;
1183 if(r)
1184 *r = jsval_number(min_from_time(date->time));
1185 return S_OK;
1188 /* ECMA-262 3rd Edition 15.9.5.22 */
1189 static HRESULT Date_getSeconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
1191 DateInstance *date;
1193 TRACE("\n");
1195 if(!(date = date_this(jsthis)))
1196 return JS_E_DATE_EXPECTED;
1198 if(r)
1199 *r = jsval_number(sec_from_time(local_time(date->time, date)));
1200 return S_OK;
1203 /* ECMA-262 3rd Edition 15.9.5.23 */
1204 static HRESULT Date_getUTCSeconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1205 jsval_t *r)
1207 DateInstance *date;
1209 TRACE("\n");
1211 if(!(date = date_this(jsthis)))
1212 return JS_E_DATE_EXPECTED;
1214 if(r)
1215 *r = jsval_number(sec_from_time(date->time));
1216 return S_OK;
1219 /* ECMA-262 3rd Edition 15.9.5.24 */
1220 static HRESULT Date_getMilliseconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1221 jsval_t *r)
1223 DateInstance *date;
1225 TRACE("\n");
1227 if(!(date = date_this(jsthis)))
1228 return JS_E_DATE_EXPECTED;
1230 if(r)
1231 *r = jsval_number(ms_from_time(local_time(date->time, date)));
1232 return S_OK;
1235 /* ECMA-262 3rd Edition 15.9.5.25 */
1236 static HRESULT Date_getUTCMilliseconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1237 jsval_t *r)
1239 DateInstance *date;
1241 TRACE("\n");
1243 if(!(date = date_this(jsthis)))
1244 return JS_E_DATE_EXPECTED;
1246 if(r)
1247 *r = jsval_number(ms_from_time(date->time));
1248 return S_OK;
1251 /* ECMA-262 3rd Edition 15.9.5.26 */
1252 static HRESULT Date_getTimezoneOffset(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1253 jsval_t *r)
1255 DateInstance *date;
1257 TRACE("\n");
1259 if(!(date = date_this(jsthis)))
1260 return JS_E_DATE_EXPECTED;
1262 if(r)
1263 *r = jsval_number(floor((date->time-local_time(date->time, date))/MS_PER_MINUTE));
1264 return S_OK;
1267 /* ECMA-262 3rd Edition 15.9.5.27 */
1268 static HRESULT Date_setTime(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1269 jsval_t *r)
1271 double n;
1272 HRESULT hres;
1273 DateInstance *date;
1275 TRACE("\n");
1277 if(!(date = date_this(jsthis)))
1278 return JS_E_DATE_EXPECTED;
1280 if(!argc)
1281 return JS_E_MISSING_ARG;
1283 hres = to_number(ctx, argv[0], &n);
1284 if(FAILED(hres))
1285 return hres;
1287 date->time = time_clip(n);
1289 if(r)
1290 *r = jsval_number(date->time);
1291 return S_OK;
1294 /* ECMA-262 3rd Edition 15.9.5.28 */
1295 static HRESULT Date_setMilliseconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1296 jsval_t *r)
1298 DateInstance *date;
1299 double n, t;
1300 HRESULT hres;
1302 TRACE("\n");
1304 if(!(date = date_this(jsthis)))
1305 return JS_E_DATE_EXPECTED;
1307 if(!argc)
1308 return JS_E_MISSING_ARG;
1310 hres = to_number(ctx, argv[0], &n);
1311 if(FAILED(hres))
1312 return hres;
1314 t = local_time(date->time, date);
1315 t = make_date(day(t), make_time(hour_from_time(t), min_from_time(t),
1316 sec_from_time(t), n));
1317 date->time = time_clip(utc(t, date));
1319 if(r)
1320 *r = jsval_number(date->time);
1321 return S_OK;
1324 /* ECMA-262 3rd Edition 15.9.5.29 */
1325 static HRESULT Date_setUTCMilliseconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1326 jsval_t *r)
1328 DateInstance *date;
1329 double n, t;
1330 HRESULT hres;
1332 TRACE("\n");
1334 if(!(date = date_this(jsthis)))
1335 return JS_E_DATE_EXPECTED;
1337 if(!argc)
1338 return JS_E_MISSING_ARG;
1340 hres = to_number(ctx, argv[0], &n);
1341 if(FAILED(hres))
1342 return hres;
1344 t = date->time;
1345 t = make_date(day(t), make_time(hour_from_time(t), min_from_time(t),
1346 sec_from_time(t), n));
1347 date->time = time_clip(t);
1349 if(r)
1350 *r = jsval_number(date->time);
1351 return S_OK;
1354 /* ECMA-262 3rd Edition 15.9.5.30 */
1355 static HRESULT Date_setSeconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1356 jsval_t *r)
1358 DateInstance *date;
1359 double t, sec, ms;
1360 HRESULT hres;
1362 TRACE("\n");
1364 if(!(date = date_this(jsthis)))
1365 return JS_E_DATE_EXPECTED;
1367 if(!argc)
1368 return JS_E_MISSING_ARG;
1370 t = local_time(date->time, date);
1372 hres = to_number(ctx, argv[0], &sec);
1373 if(FAILED(hres))
1374 return hres;
1376 if(argc > 1) {
1377 hres = to_number(ctx, argv[1], &ms);
1378 if(FAILED(hres))
1379 return hres;
1380 }else {
1381 ms = ms_from_time(t);
1384 t = make_date(day(t), make_time(hour_from_time(t),
1385 min_from_time(t), sec, ms));
1386 date->time = time_clip(utc(t, date));
1388 if(r)
1389 *r = jsval_number(date->time);
1390 return S_OK;
1393 /* ECMA-262 3rd Edition 15.9.5.31 */
1394 static HRESULT Date_setUTCSeconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1395 jsval_t *r)
1397 DateInstance *date;
1398 double t, sec, ms;
1399 HRESULT hres;
1401 TRACE("\n");
1403 if(!(date = date_this(jsthis)))
1404 return JS_E_DATE_EXPECTED;
1406 if(!argc)
1407 return JS_E_MISSING_ARG;
1409 t = date->time;
1411 hres = to_number(ctx, argv[0], &sec);
1412 if(FAILED(hres))
1413 return hres;
1415 if(argc > 1) {
1416 hres = to_number(ctx, argv[1], &ms);
1417 if(FAILED(hres))
1418 return hres;
1419 }else {
1420 ms = ms_from_time(t);
1423 t = make_date(day(t), make_time(hour_from_time(t),
1424 min_from_time(t), sec, ms));
1425 date->time = time_clip(t);
1427 if(r)
1428 *r = jsval_number(date->time);
1429 return S_OK;
1432 /* ECMA-262 3rd Edition 15.9.5.33 */
1433 static HRESULT Date_setMinutes(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1434 jsval_t *r)
1436 DateInstance *date;
1437 double t, min, sec, ms;
1438 HRESULT hres;
1440 TRACE("\n");
1442 if(!(date = date_this(jsthis)))
1443 return JS_E_DATE_EXPECTED;
1445 if(!argc)
1446 return JS_E_MISSING_ARG;
1448 t = local_time(date->time, date);
1450 hres = to_number(ctx, argv[0], &min);
1451 if(FAILED(hres))
1452 return hres;
1454 if(argc > 1) {
1455 hres = to_number(ctx, argv[1], &sec);
1456 if(FAILED(hres))
1457 return hres;
1458 }else {
1459 sec = sec_from_time(t);
1462 if(argc > 2) {
1463 hres = to_number(ctx, argv[2], &ms);
1464 if(FAILED(hres))
1465 return hres;
1466 }else {
1467 ms = ms_from_time(t);
1470 t = make_date(day(t), make_time(hour_from_time(t),
1471 min, sec, ms));
1472 date->time = time_clip(utc(t, date));
1474 if(r)
1475 *r = jsval_number(date->time);
1476 return S_OK;
1479 /* ECMA-262 3rd Edition 15.9.5.34 */
1480 static HRESULT Date_setUTCMinutes(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1481 jsval_t *r)
1483 DateInstance *date;
1484 double t, min, sec, ms;
1485 HRESULT hres;
1487 TRACE("\n");
1489 if(!(date = date_this(jsthis)))
1490 return JS_E_DATE_EXPECTED;
1492 if(!argc)
1493 return JS_E_MISSING_ARG;
1495 t = date->time;
1497 hres = to_number(ctx, argv[0], &min);
1498 if(FAILED(hres))
1499 return hres;
1501 if(argc > 1) {
1502 hres = to_number(ctx, argv[1], &sec);
1503 if(FAILED(hres))
1504 return hres;
1505 }else {
1506 sec = sec_from_time(t);
1509 if(argc > 2) {
1510 hres = to_number(ctx, argv[2], &ms);
1511 if(FAILED(hres))
1512 return hres;
1513 }else {
1514 ms = ms_from_time(t);
1517 t = make_date(day(t), make_time(hour_from_time(t),
1518 min, sec, ms));
1519 date->time = time_clip(t);
1521 if(r)
1522 *r = jsval_number(date->time);
1523 return S_OK;
1526 /* ECMA-262 3rd Edition 15.9.5.35 */
1527 static HRESULT Date_setHours(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1528 jsval_t *r)
1530 DateInstance *date;
1531 double t, hour, min, sec, ms;
1532 HRESULT hres;
1534 TRACE("\n");
1536 if(!(date = date_this(jsthis)))
1537 return JS_E_DATE_EXPECTED;
1539 if(!argc)
1540 return JS_E_MISSING_ARG;
1542 t = local_time(date->time, date);
1544 hres = to_number(ctx, argv[0], &hour);
1545 if(FAILED(hres))
1546 return hres;
1548 if(argc > 1) {
1549 hres = to_number(ctx, argv[1], &min);
1550 if(FAILED(hres))
1551 return hres;
1552 }else {
1553 min = min_from_time(t);
1556 if(argc > 2) {
1557 hres = to_number(ctx, argv[2], &sec);
1558 if(FAILED(hres))
1559 return hres;
1560 }else {
1561 sec = sec_from_time(t);
1564 if(argc > 3) {
1565 hres = to_number(ctx, argv[3], &ms);
1566 if(FAILED(hres))
1567 return hres;
1568 }else {
1569 ms = ms_from_time(t);
1572 t = make_date(day(t), make_time(hour, min, sec, ms));
1573 date->time = time_clip(utc(t, date));
1575 if(r)
1576 *r = jsval_number(date->time);
1577 return S_OK;
1580 /* ECMA-262 3rd Edition 15.9.5.36 */
1581 static HRESULT Date_setUTCHours(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1582 jsval_t *r)
1584 DateInstance *date;
1585 double t, hour, min, sec, ms;
1586 HRESULT hres;
1588 TRACE("\n");
1590 if(!(date = date_this(jsthis)))
1591 return JS_E_DATE_EXPECTED;
1593 if(!argc)
1594 return JS_E_MISSING_ARG;
1596 t = date->time;
1598 hres = to_number(ctx, argv[0], &hour);
1599 if(FAILED(hres))
1600 return hres;
1602 if(argc > 1) {
1603 hres = to_number(ctx, argv[1], &min);
1604 if(FAILED(hres))
1605 return hres;
1606 }else {
1607 min = min_from_time(t);
1610 if(argc > 2) {
1611 hres = to_number(ctx, argv[2], &sec);
1612 if(FAILED(hres))
1613 return hres;
1614 }else {
1615 sec = sec_from_time(t);
1618 if(argc > 3) {
1619 hres = to_number(ctx, argv[3], &ms);
1620 if(FAILED(hres))
1621 return hres;
1622 }else {
1623 ms = ms_from_time(t);
1626 t = make_date(day(t), make_time(hour, min, sec, ms));
1627 date->time = time_clip(t);
1629 if(r)
1630 *r = jsval_number(date->time);
1631 return S_OK;
1634 /* ECMA-262 3rd Edition 15.9.5.36 */
1635 static HRESULT Date_setDate(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1636 jsval_t *r)
1638 DateInstance *date;
1639 double t, n;
1640 HRESULT hres;
1642 TRACE("\n");
1644 if(!(date = date_this(jsthis)))
1645 return JS_E_DATE_EXPECTED;
1647 if(!argc)
1648 return JS_E_MISSING_ARG;
1650 hres = to_number(ctx, argv[0], &n);
1651 if(FAILED(hres))
1652 return hres;
1654 t = local_time(date->time, date);
1655 t = make_date(make_day(year_from_time(t), month_from_time(t), n), time_within_day(t));
1656 date->time = time_clip(utc(t, date));
1658 if(r)
1659 *r = jsval_number(date->time);
1660 return S_OK;
1663 /* ECMA-262 3rd Edition 15.9.5.37 */
1664 static HRESULT Date_setUTCDate(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1665 jsval_t *r)
1667 DateInstance *date;
1668 double t, n;
1669 HRESULT hres;
1671 TRACE("\n");
1673 if(!(date = date_this(jsthis)))
1674 return JS_E_DATE_EXPECTED;
1676 if(!argc)
1677 return JS_E_MISSING_ARG;
1679 hres = to_number(ctx, argv[0], &n);
1680 if(FAILED(hres))
1681 return hres;
1683 t = date->time;
1684 t = make_date(make_day(year_from_time(t), month_from_time(t), n), time_within_day(t));
1685 date->time = time_clip(t);
1687 if(r)
1688 *r = jsval_number(date->time);
1689 return S_OK;
1692 /* ECMA-262 3rd Edition 15.9.5.38 */
1693 static HRESULT Date_setMonth(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1694 jsval_t *r)
1696 DateInstance *date;
1697 DOUBLE t, month, ddate;
1698 HRESULT hres;
1700 TRACE("\n");
1702 if(!(date = date_this(jsthis)))
1703 return JS_E_DATE_EXPECTED;
1705 if(!argc)
1706 return JS_E_MISSING_ARG;
1708 t = local_time(date->time, date);
1710 hres = to_number(ctx, argv[0], &month);
1711 if(FAILED(hres))
1712 return hres;
1714 if(argc > 1) {
1715 hres = to_number(ctx, argv[1], &ddate);
1716 if(FAILED(hres))
1717 return hres;
1718 }else {
1719 ddate = date_from_time(t);
1722 t = make_date(make_day(year_from_time(t), month, ddate),
1723 time_within_day(t));
1724 date->time = time_clip(utc(t, date));
1726 if(r)
1727 *r = jsval_number(date->time);
1728 return S_OK;
1731 /* ECMA-262 3rd Edition 15.9.5.39 */
1732 static HRESULT Date_setUTCMonth(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1733 jsval_t *r)
1735 DateInstance *date;
1736 double t, month, ddate;
1737 HRESULT hres;
1739 TRACE("\n");
1741 if(!(date = date_this(jsthis)))
1742 return JS_E_DATE_EXPECTED;
1744 if(!argc)
1745 return JS_E_MISSING_ARG;
1747 t = date->time;
1749 hres = to_number(ctx, argv[0], &month);
1750 if(FAILED(hres))
1751 return hres;
1753 if(argc > 1) {
1754 hres = to_number(ctx, argv[1], &ddate);
1755 if(FAILED(hres))
1756 return hres;
1757 }else {
1758 ddate = date_from_time(t);
1761 t = make_date(make_day(year_from_time(t), month, ddate),
1762 time_within_day(t));
1763 date->time = time_clip(t);
1765 if(r)
1766 *r = jsval_number(date->time);
1767 return S_OK;
1770 /* ECMA-262 3rd Edition 15.9.5.40 */
1771 static HRESULT Date_setFullYear(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1772 jsval_t *r)
1774 DateInstance *date;
1775 double t, year, month, ddate;
1776 HRESULT hres;
1778 TRACE("\n");
1780 if(!(date = date_this(jsthis)))
1781 return JS_E_DATE_EXPECTED;
1783 if(!argc)
1784 return JS_E_MISSING_ARG;
1786 t = local_time(date->time, date);
1788 hres = to_number(ctx, argv[0], &year);
1789 if(FAILED(hres))
1790 return hres;
1792 if(argc > 1) {
1793 hres = to_number(ctx, argv[1], &month);
1794 if(FAILED(hres))
1795 return hres;
1796 }else {
1797 month = month_from_time(t);
1800 if(argc > 2) {
1801 hres = to_number(ctx, argv[2], &ddate);
1802 if(FAILED(hres))
1803 return hres;
1804 }else {
1805 ddate = date_from_time(t);
1808 t = make_date(make_day(year, month, ddate), time_within_day(t));
1809 date->time = time_clip(utc(t, date));
1811 if(r)
1812 *r = jsval_number(date->time);
1813 return S_OK;
1816 /* ECMA-262 3rd Edition 15.9.5.41 */
1817 static HRESULT Date_setUTCFullYear(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1818 jsval_t *r)
1820 DateInstance *date;
1821 double t, year, month, ddate;
1822 HRESULT hres;
1824 TRACE("\n");
1826 if(!(date = date_this(jsthis)))
1827 return JS_E_DATE_EXPECTED;
1829 if(!argc)
1830 return JS_E_MISSING_ARG;
1832 t = date->time;
1834 hres = to_number(ctx, argv[0], &year);
1835 if(FAILED(hres))
1836 return hres;
1838 if(argc > 1) {
1839 hres = to_number(ctx, argv[1], &month);
1840 if(FAILED(hres))
1841 return hres;
1842 }else {
1843 month = month_from_time(t);
1846 if(argc > 2) {
1847 hres = to_number(ctx, argv[2], &ddate);
1848 if(FAILED(hres))
1849 return hres;
1850 }else {
1851 ddate = date_from_time(t);
1854 t = make_date(make_day(year, month, ddate), time_within_day(t));
1855 date->time = time_clip(t);
1857 if(r)
1858 *r = jsval_number(date->time);
1859 return S_OK;
1862 /* ECMA-262 3rd Edition B2.4 */
1863 static HRESULT Date_getYear(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1864 jsval_t *r)
1866 DateInstance *date;
1867 DOUBLE t, year;
1869 TRACE("\n");
1871 if(!(date = date_this(jsthis)))
1872 return JS_E_DATE_EXPECTED;
1874 t = local_time(date->time, date);
1875 if(isnan(t)) {
1876 if(r)
1877 *r = jsval_number(NAN);
1878 return S_OK;
1881 year = year_from_time(t);
1882 if(r)
1883 *r = jsval_number((1900<=year && year<2000)?year-1900:year);
1884 return S_OK;
1887 /* ECMA-262 3rd Edition B2.5 */
1888 static HRESULT Date_setYear(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1889 jsval_t *r)
1891 DateInstance *date;
1892 DOUBLE t, year;
1893 HRESULT hres;
1895 TRACE("\n");
1897 if(!(date = date_this(jsthis)))
1898 return JS_E_DATE_EXPECTED;
1900 if(!argc)
1901 return JS_E_MISSING_ARG;
1903 t = local_time(date->time, date);
1905 hres = to_number(ctx, argv[0], &year);
1906 if(FAILED(hres))
1907 return hres;
1909 if(isnan(year)) {
1910 date->time = year;
1911 if(r)
1912 *r = jsval_number(NAN);
1913 return S_OK;
1916 year = year >= 0.0 ? floor(year) : -floor(-year);
1917 if(-1.0 < year && year < 100.0)
1918 year += 1900.0;
1920 date->time = time_clip(utc(make_date(make_day(year, month_from_time(t), date_from_time(t)), time_within_day(t)), date));
1922 if(r)
1923 *r = jsval_number(date->time);
1924 return S_OK;
1927 static HRESULT Date_get_value(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r)
1929 TRACE("\n");
1931 return dateobj_to_string(date_from_jsdisp(jsthis), r);
1934 static const builtin_prop_t Date_props[] = {
1935 {getDateW, Date_getDate, PROPF_METHOD},
1936 {getDayW, Date_getDay, PROPF_METHOD},
1937 {getFullYearW, Date_getFullYear, PROPF_METHOD},
1938 {getHoursW, Date_getHours, PROPF_METHOD},
1939 {getMillisecondsW, Date_getMilliseconds, PROPF_METHOD},
1940 {getMinutesW, Date_getMinutes, PROPF_METHOD},
1941 {getMonthW, Date_getMonth, PROPF_METHOD},
1942 {getSecondsW, Date_getSeconds, PROPF_METHOD},
1943 {getTimeW, Date_getTime, PROPF_METHOD},
1944 {getTimezoneOffsetW, Date_getTimezoneOffset, PROPF_METHOD},
1945 {getUTCDateW, Date_getUTCDate, PROPF_METHOD},
1946 {getUTCDayW, Date_getUTCDay, PROPF_METHOD},
1947 {getUTCFullYearW, Date_getUTCFullYear, PROPF_METHOD},
1948 {getUTCHoursW, Date_getUTCHours, PROPF_METHOD},
1949 {getUTCMillisecondsW, Date_getUTCMilliseconds, PROPF_METHOD},
1950 {getUTCMinutesW, Date_getUTCMinutes, PROPF_METHOD},
1951 {getUTCMonthW, Date_getUTCMonth, PROPF_METHOD},
1952 {getUTCSecondsW, Date_getUTCSeconds, PROPF_METHOD},
1953 {getYearW, Date_getYear, PROPF_METHOD},
1954 {setDateW, Date_setDate, PROPF_METHOD|1},
1955 {setFullYearW, Date_setFullYear, PROPF_METHOD|3},
1956 {setHoursW, Date_setHours, PROPF_METHOD|4},
1957 {setMillisecondsW, Date_setMilliseconds, PROPF_METHOD|1},
1958 {setMinutesW, Date_setMinutes, PROPF_METHOD|3},
1959 {setMonthW, Date_setMonth, PROPF_METHOD|2},
1960 {setSecondsW, Date_setSeconds, PROPF_METHOD|2},
1961 {setTimeW, Date_setTime, PROPF_METHOD|1},
1962 {setUTCDateW, Date_setUTCDate, PROPF_METHOD|1},
1963 {setUTCFullYearW, Date_setUTCFullYear, PROPF_METHOD|3},
1964 {setUTCHoursW, Date_setUTCHours, PROPF_METHOD|4},
1965 {setUTCMillisecondsW, Date_setUTCMilliseconds, PROPF_METHOD|1},
1966 {setUTCMinutesW, Date_setUTCMinutes, PROPF_METHOD|3},
1967 {setUTCMonthW, Date_setUTCMonth, PROPF_METHOD|2},
1968 {setUTCSecondsW, Date_setUTCSeconds, PROPF_METHOD|2},
1969 {setYearW, Date_setYear, PROPF_METHOD|1},
1970 {toDateStringW, Date_toDateString, PROPF_METHOD},
1971 {toGMTStringW, Date_toGMTString, PROPF_METHOD},
1972 {toISOStringW, Date_toISOString, PROPF_METHOD|PROPF_ES5},
1973 {toLocaleDateStringW, Date_toLocaleDateString, PROPF_METHOD},
1974 {toLocaleStringW, Date_toLocaleString, PROPF_METHOD},
1975 {toLocaleTimeStringW, Date_toLocaleTimeString, PROPF_METHOD},
1976 {toStringW, Date_toString, PROPF_METHOD},
1977 {toTimeStringW, Date_toTimeString, PROPF_METHOD},
1978 {toUTCStringW, Date_toUTCString, PROPF_METHOD},
1979 {valueOfW, Date_valueOf, PROPF_METHOD},
1982 static const builtin_info_t Date_info = {
1983 JSCLASS_DATE,
1984 {NULL, NULL,0, Date_get_value},
1985 ARRAY_SIZE(Date_props),
1986 Date_props,
1987 NULL,
1988 NULL
1991 static const builtin_info_t DateInst_info = {
1992 JSCLASS_DATE,
1993 {NULL, NULL,0, Date_get_value},
1994 0, NULL,
1995 NULL,
1996 NULL
1999 static HRESULT create_date(script_ctx_t *ctx, jsdisp_t *object_prototype, DOUBLE time, jsdisp_t **ret)
2001 DateInstance *date;
2002 HRESULT hres;
2003 TIME_ZONE_INFORMATION tzi;
2005 GetTimeZoneInformation(&tzi);
2007 date = heap_alloc_zero(sizeof(DateInstance));
2008 if(!date)
2009 return E_OUTOFMEMORY;
2011 if(object_prototype)
2012 hres = init_dispex(&date->dispex, ctx, &Date_info, object_prototype);
2013 else
2014 hres = init_dispex_from_constr(&date->dispex, ctx, &DateInst_info, ctx->date_constr);
2015 if(FAILED(hres)) {
2016 heap_free(date);
2017 return hres;
2020 date->time = time;
2021 date->bias = tzi.Bias;
2022 date->standardDate = tzi.StandardDate;
2023 date->standardBias = tzi.StandardBias;
2024 date->daylightDate = tzi.DaylightDate;
2025 date->daylightBias = tzi.DaylightBias;
2027 *ret = &date->dispex;
2028 return S_OK;
2031 static inline HRESULT date_parse(jsstr_t *input_str, double *ret) {
2032 static const DWORD string_ids[] = { LOCALE_SMONTHNAME12, LOCALE_SMONTHNAME11,
2033 LOCALE_SMONTHNAME10, LOCALE_SMONTHNAME9, LOCALE_SMONTHNAME8,
2034 LOCALE_SMONTHNAME7, LOCALE_SMONTHNAME6, LOCALE_SMONTHNAME5,
2035 LOCALE_SMONTHNAME4, LOCALE_SMONTHNAME3, LOCALE_SMONTHNAME2,
2036 LOCALE_SMONTHNAME1, LOCALE_SDAYNAME7, LOCALE_SDAYNAME1,
2037 LOCALE_SDAYNAME2, LOCALE_SDAYNAME3, LOCALE_SDAYNAME4,
2038 LOCALE_SDAYNAME5, LOCALE_SDAYNAME6 };
2039 WCHAR *strings[ARRAY_SIZE(string_ids)];
2040 WCHAR *parse;
2041 int input_len, parse_len = 0, nest_level = 0, i, size;
2042 int year = 0, month = 0, day = 0, hour = 0, min = 0, sec = 0;
2043 int ms = 0, offset = 0, hour_adjust = 0;
2044 BOOL set_year = FALSE, set_month = FALSE, set_day = FALSE, set_hour = FALSE;
2045 BOOL set_offset = FALSE, set_era = FALSE, ad = TRUE, set_am = FALSE, am = TRUE;
2046 BOOL set_hour_adjust = TRUE;
2047 TIME_ZONE_INFORMATION tzi;
2048 const WCHAR *input;
2049 DateInstance di;
2050 DWORD lcid_en;
2052 input_len = jsstr_length(input_str);
2053 input = jsstr_flatten(input_str);
2054 if(!input)
2055 return E_OUTOFMEMORY;
2057 for(i=0; i<input_len; i++) {
2058 if(input[i] == '(') nest_level++;
2059 else if(input[i] == ')') {
2060 nest_level--;
2061 if(nest_level<0) {
2062 *ret = NAN;
2063 return S_OK;
2066 else if(!nest_level) parse_len++;
2069 parse = heap_alloc((parse_len+1)*sizeof(WCHAR));
2070 if(!parse)
2071 return E_OUTOFMEMORY;
2072 nest_level = 0;
2073 parse_len = 0;
2074 for(i=0; i<input_len; i++) {
2075 if(input[i] == '(') nest_level++;
2076 else if(input[i] == ')') nest_level--;
2077 else if(!nest_level) parse[parse_len++] = towupper(input[i]);
2079 parse[parse_len] = 0;
2081 GetTimeZoneInformation(&tzi);
2082 di.bias = tzi.Bias;
2083 di.standardDate = tzi.StandardDate;
2084 di.standardBias = tzi.StandardBias;
2085 di.daylightDate = tzi.DaylightDate;
2086 di.daylightBias = tzi.DaylightBias;
2088 /* FIXME: Cache strings */
2089 lcid_en = MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT);
2090 for(i=0; i<ARRAY_SIZE(string_ids); i++) {
2091 size = GetLocaleInfoW(lcid_en, string_ids[i], NULL, 0);
2092 strings[i] = heap_alloc((size+1)*sizeof(WCHAR));
2093 if(!strings[i]) {
2094 i--;
2095 while(i-- >= 0)
2096 heap_free(strings[i]);
2097 heap_free(parse);
2098 return E_OUTOFMEMORY;
2100 GetLocaleInfoW(lcid_en, string_ids[i], strings[i], size);
2103 for(i=0; i<parse_len;) {
2104 while(iswspace(parse[i])) i++;
2105 if(parse[i] == ',') {
2106 while(parse[i] == ',') i++;
2107 continue;
2110 if(parse[i]>='0' && parse[i]<='9') {
2111 int tmp = wcstol(&parse[i], NULL, 10);
2112 while(parse[i]>='0' && parse[i]<='9') i++;
2113 while(iswspace(parse[i])) i++;
2115 if(parse[i] == ':') {
2116 /* Time */
2117 if(set_hour) break;
2118 set_hour = TRUE;
2120 hour = tmp;
2122 while(parse[i] == ':') i++;
2123 while(iswspace(parse[i])) i++;
2124 if(parse[i]>='0' && parse[i]<='9') {
2125 min = wcstol(&parse[i], NULL, 10);
2126 while(parse[i]>='0' && parse[i]<='9') i++;
2129 while(iswspace(parse[i])) i++;
2130 while(parse[i] == ':') i++;
2131 while(iswspace(parse[i])) i++;
2132 if(parse[i]>='0' && parse[i]<='9') {
2133 sec = wcstol(&parse[i], NULL, 10);
2134 while(parse[i]>='0' && parse[i]<='9') i++;
2137 else if(parse[i]=='-' || parse[i]=='/') {
2138 /* Short or long date */
2139 if(set_day || set_month || set_year) break;
2140 set_day = TRUE;
2141 set_month = TRUE;
2142 set_year = TRUE;
2144 month = tmp-1;
2146 while(iswspace(parse[i])) i++;
2147 while(parse[i]=='-' || parse[i]=='/') i++;
2148 while(iswspace(parse[i])) i++;
2149 if(parse[i]<'0' || parse[i]>'9') break;
2150 day = wcstol(&parse[i], NULL, 10);
2151 while(parse[i]>='0' && parse[i]<='9') i++;
2153 while(parse[i]=='-' || parse[i]=='/') i++;
2154 while(iswspace(parse[i])) i++;
2155 if(parse[i]<'0' || parse[i]>'9') break;
2156 year = wcstol(&parse[i], NULL, 10);
2157 while(parse[i]>='0' && parse[i]<='9') i++;
2159 if(tmp >= 70){
2160 /* long date */
2161 month = day - 1;
2162 day = year;
2163 year = tmp;
2166 else if(tmp<0) break;
2167 else if(tmp<70) {
2168 /* Day */
2169 if(set_day) break;
2170 set_day = TRUE;
2171 day = tmp;
2173 else {
2174 /* Year */
2175 if(set_year) break;
2176 set_year = TRUE;
2177 year = tmp;
2180 else if(parse[i]=='+' || parse[i]=='-') {
2181 /* Timezone offset */
2182 BOOL positive = TRUE;
2184 if(set_offset && set_hour_adjust) break;
2185 set_offset = TRUE;
2186 set_hour_adjust = FALSE;
2188 if(parse[i] == '-') positive = FALSE;
2190 i++;
2191 while(iswspace(parse[i])) i++;
2192 if(parse[i]<'0' || parse[i]>'9') break;
2193 offset = wcstol(&parse[i], NULL, 10);
2194 while(parse[i]>='0' && parse[i]<='9') i++;
2196 if(offset<24) offset *= 60;
2197 else offset = (offset/100)*60 + offset%100;
2199 if(positive) offset = -offset;
2202 else {
2203 if(parse[i]<'A' || parse[i]>'Z') break;
2204 else if(parse[i]=='B' && (parse[i+1]=='C' ||
2205 (parse[i+1]=='.' && parse[i+2]=='C'))) {
2206 /* AD/BC */
2207 if(set_era) break;
2208 set_era = TRUE;
2209 ad = FALSE;
2211 i++;
2212 if(parse[i] == '.') i++;
2213 i++;
2214 if(parse[i] == '.') i++;
2216 else if(parse[i]=='A' && (parse[i+1]=='D' ||
2217 (parse[i+1]=='.' && parse[i+2]=='D'))) {
2218 /* AD/BC */
2219 if(set_era) break;
2220 set_era = TRUE;
2222 i++;
2223 if(parse[i] == '.') i++;
2224 i++;
2225 if(parse[i] == '.') i++;
2227 else if(parse[i+1]<'A' || parse[i+1]>'Z') {
2228 /* Timezone */
2229 if(set_offset) break;
2230 set_offset = TRUE;
2232 if(parse[i] <= 'I') hour_adjust = parse[i]-'A'+2;
2233 else if(parse[i] == 'J') break;
2234 else if(parse[i] <= 'M') hour_adjust = parse[i]-'K'+11;
2235 else if(parse[i] <= 'Y') hour_adjust = parse[i]-'N';
2236 else hour_adjust = 1;
2238 i++;
2239 if(parse[i] == '.') i++;
2241 else if(parse[i]=='A' && parse[i+1]=='M') {
2242 /* AM/PM */
2243 if(set_am) break;
2244 set_am = TRUE;
2245 am = TRUE;
2246 i += 2;
2248 else if(parse[i]=='P' && parse[i+1]=='M') {
2249 /* AM/PM */
2250 if(set_am) break;
2251 set_am = TRUE;
2252 am = FALSE;
2253 i += 2;
2255 else if((parse[i]=='U' && parse[i+1]=='T' && parse[i+2]=='C')
2256 || (parse[i]=='G' && parse[i+1]=='M' && parse[i+2]=='T')) {
2257 /* Timezone */
2258 if(set_offset) break;
2259 set_offset = TRUE;
2260 set_hour_adjust = FALSE;
2262 i += 3;
2264 else {
2265 /* Month or garbage */
2266 unsigned int j;
2268 for(size=i; parse[size]>='A' && parse[size]<='Z'; size++);
2269 size -= i;
2271 for(j=0; j<ARRAY_SIZE(string_ids); j++)
2272 if(!wcsnicmp(&parse[i], strings[j], size)) break;
2274 if(j < 12) {
2275 if(set_month) break;
2276 set_month = TRUE;
2277 month = 11-j;
2279 else if(j == ARRAY_SIZE(string_ids)) break;
2281 i += size;
2286 if(i == parse_len && set_year && set_month && set_day && (!set_am || hour<13)) {
2287 if(set_am) {
2288 if(hour == 12) hour = 0;
2289 if(!am) hour += 12;
2292 if(!ad) year = -year+1;
2293 else if(year<100) year += 1900;
2295 *ret = time_clip(make_date(make_day(year, month, day),
2296 make_time(hour+hour_adjust, min, sec, ms)) + offset*MS_PER_MINUTE);
2298 if(set_hour_adjust)
2299 *ret = utc(*ret, &di);
2300 }else {
2301 *ret = NAN;
2304 for(i=0; i<ARRAY_SIZE(string_ids); i++)
2305 heap_free(strings[i]);
2306 heap_free(parse);
2308 return S_OK;
2311 static HRESULT DateConstr_parse(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
2312 jsval_t *r)
2314 jsstr_t *parse_str;
2315 double n;
2316 HRESULT hres;
2318 TRACE("\n");
2320 if(!argc) {
2321 if(r)
2322 *r = jsval_number(NAN);
2323 return S_OK;
2326 hres = to_string(ctx, argv[0], &parse_str);
2327 if(FAILED(hres))
2328 return hres;
2330 hres = date_parse(parse_str, &n);
2331 jsstr_release(parse_str);
2332 if(FAILED(hres))
2333 return hres;
2335 *r = jsval_number(n);
2336 return S_OK;
2339 static HRESULT date_utc(script_ctx_t *ctx, unsigned argc, jsval_t *argv, double *ret)
2341 double year, month, vdate, hours, minutes, seconds, ms;
2342 HRESULT hres;
2344 TRACE("\n");
2346 if(argc) {
2347 hres = to_number(ctx, argv[0], &year);
2348 if(FAILED(hres))
2349 return hres;
2350 if(0 <= year && year <= 99)
2351 year += 1900;
2352 }else {
2353 year = 1900;
2356 if(argc>1) {
2357 hres = to_number(ctx, argv[1], &month);
2358 if(FAILED(hres))
2359 return hres;
2360 }else {
2361 month = 0;
2364 if(argc>2) {
2365 hres = to_number(ctx, argv[2], &vdate);
2366 if(FAILED(hres))
2367 return hres;
2368 }else {
2369 vdate = 1;
2372 if(argc>3) {
2373 hres = to_number(ctx, argv[3], &hours);
2374 if(FAILED(hres))
2375 return hres;
2376 }else {
2377 hours = 0;
2380 if(argc>4) {
2381 hres = to_number(ctx, argv[4], &minutes);
2382 if(FAILED(hres))
2383 return hres;
2384 }else {
2385 minutes = 0;
2388 if(argc>5) {
2389 hres = to_number(ctx, argv[5], &seconds);
2390 if(FAILED(hres))
2391 return hres;
2392 }else {
2393 seconds = 0;
2396 if(argc>6) {
2397 hres = to_number(ctx, argv[6], &ms);
2398 if(FAILED(hres))
2399 return hres;
2400 } else {
2401 ms = 0;
2404 *ret = time_clip(make_date(make_day(year, month, vdate),
2405 make_time(hours, minutes,seconds, ms)));
2406 return S_OK;
2409 static HRESULT DateConstr_UTC(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
2410 jsval_t *r)
2412 double n;
2413 HRESULT hres;
2415 TRACE("\n");
2417 hres = date_utc(ctx, argc, argv, &n);
2418 if(SUCCEEDED(hres) && r)
2419 *r = jsval_number(n);
2420 return hres;
2423 /* ECMA-262 5.1 Edition 15.9.4.4 */
2424 static HRESULT DateConstr_now(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
2426 TRACE("\n");
2428 if(r) *r = jsval_number(date_now());
2429 return S_OK;
2432 static HRESULT DateConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
2433 jsval_t *r)
2435 jsdisp_t *date;
2436 HRESULT hres;
2438 TRACE("\n");
2440 switch(flags) {
2441 case DISPATCH_CONSTRUCT:
2442 switch(argc) {
2443 /* ECMA-262 3rd Edition 15.9.3.3 */
2444 case 0:
2445 hres = create_date(ctx, NULL, date_now(), &date);
2446 if(FAILED(hres))
2447 return hres;
2448 break;
2450 /* ECMA-262 3rd Edition 15.9.3.2 */
2451 case 1: {
2452 jsval_t prim;
2453 double n;
2455 hres = to_primitive(ctx, argv[0], &prim, NO_HINT);
2456 if(FAILED(hres))
2457 return hres;
2459 if(is_string(prim))
2460 hres = date_parse(get_string(prim), &n);
2461 else
2462 hres = to_number(ctx, prim, &n);
2464 jsval_release(prim);
2465 if(FAILED(hres))
2466 return hres;
2468 hres = create_date(ctx, NULL, time_clip(n), &date);
2469 if(FAILED(hres))
2470 return hres;
2471 break;
2474 /* ECMA-262 3rd Edition 15.9.3.1 */
2475 default: {
2476 double ret_date;
2477 DateInstance *di;
2479 hres = date_utc(ctx, argc, argv, &ret_date);
2480 if(FAILED(hres))
2481 return hres;
2483 hres = create_date(ctx, NULL, ret_date, &date);
2484 if(FAILED(hres))
2485 return hres;
2487 di = date_from_jsdisp(date);
2488 di->time = utc(di->time, di);
2492 *r = jsval_obj(date);
2493 return S_OK;
2495 case INVOKE_FUNC: {
2496 FILETIME system_time, local_time;
2497 LONGLONG lltime;
2499 GetSystemTimeAsFileTime(&system_time);
2500 FileTimeToLocalFileTime(&system_time, &local_time);
2501 lltime = ((LONGLONG)local_time.dwHighDateTime<<32)
2502 + local_time.dwLowDateTime;
2504 return date_to_string(lltime/10000-TIME_EPOCH, FALSE, 0, r);
2507 default:
2508 FIXME("unimplemented flags %x\n", flags);
2509 return E_NOTIMPL;
2512 return S_OK;
2515 static const builtin_prop_t DateConstr_props[] = {
2516 {UTCW, DateConstr_UTC, PROPF_METHOD},
2517 {nowW, DateConstr_now, PROPF_HTML|PROPF_METHOD},
2518 {parseW, DateConstr_parse, PROPF_METHOD}
2521 static const builtin_info_t DateConstr_info = {
2522 JSCLASS_FUNCTION,
2523 DEFAULT_FUNCTION_VALUE,
2524 ARRAY_SIZE(DateConstr_props),
2525 DateConstr_props,
2526 NULL,
2527 NULL
2530 HRESULT create_date_constr(script_ctx_t *ctx, jsdisp_t *object_prototype, jsdisp_t **ret)
2532 jsdisp_t *date;
2533 HRESULT hres;
2535 static const WCHAR DateW[] = {'D','a','t','e',0};
2537 hres = create_date(ctx, object_prototype, 0.0, &date);
2538 if(FAILED(hres))
2539 return hres;
2541 hres = create_builtin_constructor(ctx, DateConstr_value, DateW, &DateConstr_info,
2542 PROPF_CONSTR|7, date, ret);
2544 jsdisp_release(date);
2545 return hres;