Release 4.0.4.
[wine.git] / dlls / jscript / date.c
blob2676cd1cb1cc52f8b25b4f46270cdd8998d5b746
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 toISOStringW[] = {'t','o','I','S','O','S','t','r','i','n','g',0};
53 static const WCHAR toUTCStringW[] = {'t','o','U','T','C','S','t','r','i','n','g',0};
54 static const WCHAR toGMTStringW[] = {'t','o','G','M','T','S','t','r','i','n','g',0};
55 static const WCHAR toDateStringW[] = {'t','o','D','a','t','e','S','t','r','i','n','g',0};
56 static const WCHAR toTimeStringW[] = {'t','o','T','i','m','e','S','t','r','i','n','g',0};
57 static const WCHAR toLocaleDateStringW[] = {'t','o','L','o','c','a','l','e','D','a','t','e','S','t','r','i','n','g',0};
58 static const WCHAR toLocaleTimeStringW[] = {'t','o','L','o','c','a','l','e','T','i','m','e','S','t','r','i','n','g',0};
59 static const WCHAR getTimeW[] = {'g','e','t','T','i','m','e',0};
60 static const WCHAR getFullYearW[] = {'g','e','t','F','u','l','l','Y','e','a','r',0};
61 static const WCHAR getUTCFullYearW[] = {'g','e','t','U','T','C','F','u','l','l','Y','e','a','r',0};
62 static const WCHAR getMonthW[] = {'g','e','t','M','o','n','t','h',0};
63 static const WCHAR getUTCMonthW[] = {'g','e','t','U','T','C','M','o','n','t','h',0};
64 static const WCHAR getDateW[] = {'g','e','t','D','a','t','e',0};
65 static const WCHAR getUTCDateW[] = {'g','e','t','U','T','C','D','a','t','e',0};
66 static const WCHAR getDayW[] = {'g','e','t','D','a','y',0};
67 static const WCHAR getUTCDayW[] = {'g','e','t','U','T','C','D','a','y',0};
68 static const WCHAR getHoursW[] = {'g','e','t','H','o','u','r','s',0};
69 static const WCHAR getUTCHoursW[] = {'g','e','t','U','T','C','H','o','u','r','s',0};
70 static const WCHAR getMinutesW[] = {'g','e','t','M','i','n','u','t','e','s',0};
71 static const WCHAR getUTCMinutesW[] = {'g','e','t','U','T','C','M','i','n','u','t','e','s',0};
72 static const WCHAR getSecondsW[] = {'g','e','t','S','e','c','o','n','d','s',0};
73 static const WCHAR getUTCSecondsW[] = {'g','e','t','U','T','C','S','e','c','o','n','d','s',0};
74 static const WCHAR getMillisecondsW[] = {'g','e','t','M','i','l','l','i','s','e','c','o','n','d','s',0};
75 static const WCHAR getUTCMillisecondsW[] = {'g','e','t','U','T','C','M','i','l','l','i','s','e','c','o','n','d','s',0};
76 static const WCHAR getTimezoneOffsetW[] = {'g','e','t','T','i','m','e','z','o','n','e','O','f','f','s','e','t',0};
77 static const WCHAR setTimeW[] = {'s','e','t','T','i','m','e',0};
78 static const WCHAR setMillisecondsW[] = {'s','e','t','M','i','l','l','i','s','e','c','o','n','d','s',0};
79 static const WCHAR setUTCMillisecondsW[] = {'s','e','t','U','T','C','M','i','l','l','i','s','e','c','o','n','d','s',0};
80 static const WCHAR setSecondsW[] = {'s','e','t','S','e','c','o','n','d','s',0};
81 static const WCHAR setUTCSecondsW[] = {'s','e','t','U','T','C','S','e','c','o','n','d','s',0};
82 static const WCHAR setMinutesW[] = {'s','e','t','M','i','n','u','t','e','s',0};
83 static const WCHAR setUTCMinutesW[] = {'s','e','t','U','T','C','M','i','n','u','t','e','s',0};
84 static const WCHAR setHoursW[] = {'s','e','t','H','o','u','r','s',0};
85 static const WCHAR setUTCHoursW[] = {'s','e','t','U','T','C','H','o','u','r','s',0};
86 static const WCHAR setDateW[] = {'s','e','t','D','a','t','e',0};
87 static const WCHAR setUTCDateW[] = {'s','e','t','U','T','C','D','a','t','e',0};
88 static const WCHAR setMonthW[] = {'s','e','t','M','o','n','t','h',0};
89 static const WCHAR setUTCMonthW[] = {'s','e','t','U','T','C','M','o','n','t','h',0};
90 static const WCHAR setFullYearW[] = {'s','e','t','F','u','l','l','Y','e','a','r',0};
91 static const WCHAR setUTCFullYearW[] = {'s','e','t','U','T','C','F','u','l','l','Y','e','a','r',0};
92 static const WCHAR getYearW[] = {'g','e','t','Y','e','a','r',0};
93 static const WCHAR setYearW[] = {'s','e','t','Y','e','a','r',0};
95 static const WCHAR UTCW[] = {'U','T','C',0};
96 static const WCHAR nowW[] = {'n','o','w',0};
97 static const WCHAR parseW[] = {'p','a','r','s','e',0};
99 static inline DateInstance *date_from_jsdisp(jsdisp_t *jsdisp)
101 return CONTAINING_RECORD(jsdisp, DateInstance, dispex);
104 static inline DateInstance *date_this(vdisp_t *jsthis)
106 return is_vclass(jsthis, JSCLASS_DATE) ? date_from_jsdisp(jsthis->u.jsdisp) : NULL;
109 /*ECMA-262 3rd Edition 15.9.1.2 */
110 #define MS_PER_DAY 86400000
111 #define MS_PER_HOUR 3600000
112 #define MS_PER_MINUTE 60000
114 /* ECMA-262 3rd Edition 15.9.1.2 */
115 static inline DOUBLE day(DOUBLE time)
117 return floor(time / MS_PER_DAY);
120 /* ECMA-262 3rd Edition 15.9.1.2 */
121 static inline DOUBLE time_within_day(DOUBLE time)
123 DOUBLE ret;
125 ret = fmod(time, MS_PER_DAY);
126 if(ret < 0)
127 ret += MS_PER_DAY;
129 return ret;
132 /* ECMA-262 3rd Edition 15.9.1.3 */
133 static inline DOUBLE days_in_year(DOUBLE year)
135 int y;
137 if(year != (int)year)
138 return NAN;
140 y = year;
141 if(y%4 != 0) return 365;
142 if(y%100 != 0) return 366;
143 if(y%400 != 0) return 365;
144 return 366;
147 /* ECMA-262 3rd Edition 15.9.1.3 */
148 static inline DOUBLE day_from_year(DOUBLE year)
150 if(year != (int)year)
151 return NAN;
153 return floor(365.0*(year-1970) + floor((year-1969)/4)
154 - floor((year-1901)/100) + floor((year-1601)/400));
157 static inline int day_from_month(int month, int in_leap_year)
159 switch(month)
161 case 0:
162 return 0;
163 case 1:
164 return 31;
165 case 2:
166 return 59+in_leap_year;
167 case 3:
168 return 90+in_leap_year;
169 case 4:
170 return 120+in_leap_year;
171 case 5:
172 return 151+in_leap_year;
173 case 6:
174 return 181+in_leap_year;
175 case 7:
176 return 212+in_leap_year;
177 case 8:
178 return 243+in_leap_year;
179 case 9:
180 return 273+in_leap_year;
181 case 10:
182 return 304+in_leap_year;
183 default:
184 return 334+in_leap_year;
188 /* ECMA-262 3rd Edition 15.9.1.3 */
189 static inline DOUBLE time_from_year(DOUBLE year)
191 return MS_PER_DAY*day_from_year(year);
194 /* ECMA-262 3rd Edition 15.9.1.3 */
195 static inline DOUBLE year_from_time(DOUBLE time)
197 int y;
199 if(isnan(time))
200 return NAN;
202 y = 1970 + time/365.25/MS_PER_DAY;
204 if(time_from_year(y) > time)
205 while(time_from_year(y) > time) y--;
206 else
207 while(time_from_year(y+1)<=time) y++;
209 return y;
212 /* ECMA-262 3rd Edition 15.9.1.3 */
213 static inline int in_leap_year(DOUBLE time)
215 if(days_in_year(year_from_time(time))==366)
216 return 1;
217 return 0;
220 /* ECMA-262 3rd Edition 15.9.1.4 */
221 static inline int day_within_year(DOUBLE time)
223 return day(time) - day_from_year(year_from_time(time));
226 /* ECMA-262 3rd Edition 15.9.1.4 */
227 static inline DOUBLE month_from_time(DOUBLE time)
229 int ily = in_leap_year(time);
230 int dwy = day_within_year(time);
232 if(isnan(time))
233 return NAN;
235 if(0<=dwy && dwy<31) return 0;
236 if(dwy < 59+ily) return 1;
237 if(dwy < 90+ily) return 2;
238 if(dwy < 120+ily) return 3;
239 if(dwy < 151+ily) return 4;
240 if(dwy < 181+ily) return 5;
241 if(dwy < 212+ily) return 6;
242 if(dwy < 243+ily) return 7;
243 if(dwy < 273+ily) return 8;
244 if(dwy < 304+ily) return 9;
245 if(dwy < 334+ily) return 10;
246 return 11;
249 /* ECMA-262 3rd Edition 15.9.1.5 */
250 static inline DOUBLE date_from_time(DOUBLE time)
252 int dwy = day_within_year(time);
253 int ily = in_leap_year(time);
254 int mft = month_from_time(time);
256 if(isnan(time))
257 return NAN;
259 if(mft==0) return dwy+1;
260 if(mft==1) return dwy-30;
261 if(mft==2) return dwy-58-ily;
262 if(mft==3) return dwy-89-ily;
263 if(mft==4) return dwy-119-ily;
264 if(mft==5) return dwy-150-ily;
265 if(mft==6) return dwy-180-ily;
266 if(mft==7) return dwy-211-ily;
267 if(mft==8) return dwy-242-ily;
268 if(mft==9) return dwy-272-ily;
269 if(mft==10) return dwy-303-ily;
270 return dwy-333-ily;
273 /* ECMA-262 3rd Edition 15.9.1.6 */
274 static inline DOUBLE week_day(DOUBLE time)
276 DOUBLE ret;
278 if(isnan(time))
279 return NAN;
281 ret = fmod(day(time)+4, 7);
282 if(ret<0) ret += 7;
284 return ret;
287 static inline DOUBLE convert_time(int year, SYSTEMTIME st)
289 DOUBLE time;
290 int set_week_day;
292 if(st.wMonth == 0)
293 return NAN;
295 if(st.wYear != 0)
296 year = st.wYear;
298 time = time_from_year(year);
299 time += (DOUBLE)day_from_month(st.wMonth-1, in_leap_year(time)) * MS_PER_DAY;
301 if(st.wYear == 0) {
302 set_week_day = st.wDayOfWeek-week_day(time);
303 if(set_week_day < 0)
304 set_week_day += 7;
305 time += set_week_day * MS_PER_DAY;
307 time += (DOUBLE)(st.wDay-1) * 7 * MS_PER_DAY;
308 if(month_from_time(time) != st.wMonth-1)
309 time -= 7 * MS_PER_DAY;
311 else
312 time += st.wDay * MS_PER_DAY;
314 time += st.wHour * MS_PER_HOUR;
315 time += st.wMinute * MS_PER_MINUTE;
317 return time;
320 /* ECMA-262 3rd Edition 15.9.1.9 */
321 static inline DOUBLE daylight_saving_ta(DOUBLE time, DateInstance *date)
323 int year = year_from_time(time);
324 DOUBLE standardTime, daylightTime;
326 if(isnan(time))
327 return 0;
329 standardTime = convert_time(year, date->standardDate);
330 daylightTime = convert_time(year, date->daylightDate);
332 if(isnan(standardTime) || isnan(daylightTime))
333 return 0;
334 else if(standardTime > daylightTime) {
335 if(daylightTime <= time && time < standardTime)
336 return date->daylightBias;
338 return date->standardBias;
340 else {
341 if(standardTime <= time && time < daylightTime)
342 return date->standardBias;
344 return date->daylightBias;
348 /* ECMA-262 3rd Edition 15.9.1.9 */
349 static inline DOUBLE local_time(DOUBLE time, DateInstance *date)
351 return time - (daylight_saving_ta(time, date)+date->bias)*MS_PER_MINUTE;
354 /* ECMA-262 3rd Edition 15.9.1.9 */
355 static inline DOUBLE utc(DOUBLE time, DateInstance *date)
357 time += date->bias * MS_PER_MINUTE;
358 return time + daylight_saving_ta(time, date)*MS_PER_MINUTE;
361 /* ECMA-262 3rd Edition 15.9.1.10 */
362 static inline DOUBLE hour_from_time(DOUBLE time)
364 DOUBLE ret;
366 if(isnan(time))
367 return NAN;
369 ret = fmod(floor(time/MS_PER_HOUR), 24);
370 if(ret<0) ret += 24;
372 return ret;
375 /* ECMA-262 3rd Edition 15.9.1.10 */
376 static inline DOUBLE min_from_time(DOUBLE time)
378 DOUBLE ret;
380 if(isnan(time))
381 return NAN;
383 ret = fmod(floor(time/MS_PER_MINUTE), 60);
384 if(ret<0) ret += 60;
386 return ret;
389 /* ECMA-262 3rd Edition 15.9.1.10 */
390 static inline DOUBLE sec_from_time(DOUBLE time)
392 DOUBLE ret;
394 if(isnan(time))
395 return NAN;
397 ret = fmod(floor(time/1000), 60);
398 if(ret<0) ret += 60;
400 return ret;
403 /* ECMA-262 3rd Edition 15.9.1.10 */
404 static inline DOUBLE ms_from_time(DOUBLE time)
406 DOUBLE ret;
408 if(isnan(time))
409 return NAN;
411 ret = fmod(time, 1000);
412 if(ret<0) ret += 1000;
414 return ret;
417 /* ECMA-262 3rd Edition 15.9.1.11 */
418 static inline DOUBLE make_time(DOUBLE hour, DOUBLE min, DOUBLE sec, DOUBLE ms)
420 return hour*MS_PER_HOUR + min*MS_PER_MINUTE + sec*1000 + ms;
423 /* ECMA-262 3rd Edition 15.9.1.12 */
424 static inline DOUBLE make_day(DOUBLE year, DOUBLE month, DOUBLE day)
426 DOUBLE time;
428 year += floor(month/12);
430 month = fmod(month, 12);
431 if(month<0) month += 12;
433 time = time_from_year(year);
435 day += floor(time / MS_PER_DAY);
436 day += day_from_month(month, in_leap_year(time));
438 return day-1;
441 /* ECMA-262 3rd Edition 15.9.1.13 */
442 static inline DOUBLE make_date(DOUBLE day, DOUBLE time)
444 return day*MS_PER_DAY + time;
447 /* ECMA-262 3rd Edition 15.9.1.14 */
448 static inline DOUBLE time_clip(DOUBLE time)
450 if(8.64e15 < time || time < -8.64e15) {
451 return NAN;
454 return floor(time);
457 static double date_now(void)
459 FILETIME ftime;
460 LONGLONG time;
462 GetSystemTimeAsFileTime(&ftime);
463 time = ((LONGLONG)ftime.dwHighDateTime << 32) + ftime.dwLowDateTime;
465 return time/10000 - TIME_EPOCH;
468 static SYSTEMTIME create_systemtime(DOUBLE time)
470 SYSTEMTIME st;
472 st.wYear = year_from_time(time);
473 st.wMonth = month_from_time(time) + 1;
474 st.wDayOfWeek = week_day(time);
475 st.wDay = date_from_time(time);
476 st.wHour = hour_from_time(time);
477 st.wMinute = min_from_time(time);
478 st.wSecond = sec_from_time(time);
479 st.wMilliseconds = ms_from_time(time);
481 return st;
484 static inline HRESULT date_to_string(DOUBLE time, BOOL show_offset, int offset, jsval_t *r)
486 static const WCHAR formatW[] = { '%','s',' ','%','s',' ','%','d',' ',
487 '%','0','2','d',':','%','0','2','d',':','%','0','2','d',' ',
488 'U','T','C','%','c','%','0','2','d','%','0','2','d',' ','%','d','%','s',0 };
489 static const WCHAR formatUTCW[] = { '%','s',' ','%','s',' ','%','d',' ',
490 '%','0','2','d',':','%','0','2','d',':','%','0','2','d',' ',
491 'U','T','C',' ','%','d','%','s',0 };
492 static const WCHAR formatNoOffsetW[] = { '%','s',' ','%','s',' ',
493 '%','d',' ','%','0','2','d',':','%','0','2','d',':',
494 '%','0','2','d',' ','%','d','%','s',0 };
495 static const WCHAR ADW[] = { 0 };
496 static const WCHAR BCW[] = { ' ','B','.','C','.',0 };
498 static const DWORD week_ids[] = { LOCALE_SABBREVDAYNAME7, LOCALE_SABBREVDAYNAME1,
499 LOCALE_SABBREVDAYNAME2, LOCALE_SABBREVDAYNAME3, LOCALE_SABBREVDAYNAME4,
500 LOCALE_SABBREVDAYNAME5, LOCALE_SABBREVDAYNAME6 };
501 static const DWORD month_ids[] = { LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2,
502 LOCALE_SABBREVMONTHNAME3, LOCALE_SABBREVMONTHNAME4,
503 LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6,
504 LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8,
505 LOCALE_SABBREVMONTHNAME9, LOCALE_SABBREVMONTHNAME10,
506 LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12 };
508 BOOL formatAD = TRUE;
509 WCHAR week[64], month[64];
510 WCHAR buf[192];
511 jsstr_t *date_jsstr;
512 int year, day;
513 DWORD lcid_en;
514 WCHAR sign = '-';
516 if(isnan(time)) {
517 if(r)
518 *r = jsval_string(jsstr_nan());
519 return S_OK;
522 if(r) {
523 lcid_en = MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT);
525 week[0] = 0;
526 GetLocaleInfoW(lcid_en, week_ids[(int)week_day(time)], week, ARRAY_SIZE(week));
528 month[0] = 0;
529 GetLocaleInfoW(lcid_en, month_ids[(int)month_from_time(time)], month, ARRAY_SIZE(month));
531 year = year_from_time(time);
532 if(year<0) {
533 formatAD = FALSE;
534 year = -year+1;
537 day = date_from_time(time);
539 if(offset < 0) {
540 sign = '+';
541 offset = -offset;
544 if(!show_offset)
545 sprintfW(buf, formatNoOffsetW, week, month, day,
546 (int)hour_from_time(time), (int)min_from_time(time),
547 (int)sec_from_time(time), year, formatAD?ADW:BCW);
548 else if(offset)
549 sprintfW(buf, formatW, week, month, day,
550 (int)hour_from_time(time), (int)min_from_time(time),
551 (int)sec_from_time(time), sign, offset/60, offset%60,
552 year, formatAD?ADW:BCW);
553 else
554 sprintfW(buf, formatUTCW, week, month, day,
555 (int)hour_from_time(time), (int)min_from_time(time),
556 (int)sec_from_time(time), year, formatAD?ADW:BCW);
558 date_jsstr = jsstr_alloc(buf);
559 if(!date_jsstr)
560 return E_OUTOFMEMORY;
562 *r = jsval_string(date_jsstr);
564 return S_OK;
567 /* ECMA-262 3rd Edition 15.9.1.2 */
568 static HRESULT dateobj_to_string(DateInstance *date, jsval_t *r)
570 DOUBLE time;
571 int offset;
573 time = local_time(date->time, date);
574 offset = date->bias +
575 daylight_saving_ta(time, date);
577 return date_to_string(time, TRUE, offset, r);
580 static HRESULT Date_toString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
582 DateInstance *date;
584 TRACE("\n");
586 if(!(date = date_this(jsthis)))
587 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
589 return dateobj_to_string(date, r);
592 /* ECMA-262 3rd Edition 15.9.1.5 */
593 static HRESULT Date_toLocaleString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
594 jsval_t *r)
596 SYSTEMTIME st;
597 DateInstance *date;
598 jsstr_t *date_str;
599 int date_len, time_len;
601 TRACE("\n");
603 if(!(date = date_this(jsthis)))
604 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
606 if(isnan(date->time)) {
607 if(r)
608 *r = jsval_string(jsstr_nan());
609 return S_OK;
612 st = create_systemtime(local_time(date->time, date));
614 if(st.wYear<1601 || st.wYear>9999)
615 return dateobj_to_string(date, r);
617 if(r) {
618 WCHAR *ptr;
620 date_len = GetDateFormatW(ctx->lcid, DATE_LONGDATE, &st, NULL, NULL, 0);
621 time_len = GetTimeFormatW(ctx->lcid, 0, &st, NULL, NULL, 0);
623 date_str = jsstr_alloc_buf(date_len+time_len-1, &ptr);
624 if(!date_str)
625 return E_OUTOFMEMORY;
627 GetDateFormatW(ctx->lcid, DATE_LONGDATE, &st, NULL, ptr, date_len);
628 GetTimeFormatW(ctx->lcid, 0, &st, NULL, ptr+date_len, time_len);
629 ptr[date_len-1] = ' ';
631 *r = jsval_string(date_str);
633 return S_OK;
636 static HRESULT Date_toISOString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
637 jsval_t *r)
639 DateInstance *date;
640 WCHAR buf[64], *p = buf;
641 double year;
643 static const WCHAR short_year_formatW[] = {'%','0','4','d',0};
644 static const WCHAR long_year_formatW[] = {'%','0','6','d',0};
645 static const WCHAR formatW[] = {'-','%','0','2','d','-','%','0','2','d',
646 'T','%','0','2','d',':','%','0','2','d',':','%','0','2','d','.','%','0','3','d','Z',0};
648 TRACE("\n");
650 if(!(date = date_this(jsthis)))
651 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
653 year = year_from_time(date->time);
654 if(isnan(year) || year > 999999 || year < -999999) {
655 FIXME("year %lf should throw an exception\n", year);
656 return E_FAIL;
659 if(year < 0) {
660 *p++ = '-';
661 p += sprintfW(p, long_year_formatW, -(int)year);
662 }else if(year > 9999) {
663 *p++ = '+';
664 p += sprintfW(p, long_year_formatW, (int)year);
665 }else {
666 p += sprintfW(p, short_year_formatW, (int)year);
669 sprintfW(p, formatW, (int)month_from_time(date->time) + 1, (int)date_from_time(date->time),
670 (int)hour_from_time(date->time), (int)min_from_time(date->time),
671 (int)sec_from_time(date->time), (int)ms_from_time(date->time));
673 if(r) {
674 jsstr_t *ret;
675 if(!(ret = jsstr_alloc(buf)))
676 return E_OUTOFMEMORY;
677 *r = jsval_string(ret);
679 return S_OK;
682 static HRESULT Date_valueOf(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
683 jsval_t *r)
685 DateInstance *date;
687 TRACE("\n");
689 if(!(date = date_this(jsthis)))
690 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
692 if(r)
693 *r = jsval_number(date->time);
694 return S_OK;
697 static inline HRESULT create_utc_string(script_ctx_t *ctx, vdisp_t *jsthis, jsval_t *r)
699 static const WCHAR formatADW[] = { '%','s',',',' ','%','d',' ','%','s',' ','%','d',' ',
700 '%','0','2','d',':','%','0','2','d',':','%','0','2','d',' ','U','T','C',0 };
701 static const WCHAR formatBCW[] = { '%','s',',',' ','%','d',' ','%','s',' ','%','d',' ','B','.','C','.',' ',
702 '%','0','2','d',':','%','0','2','d',':','%','0','2','d',' ','U','T','C',0 };
704 static const DWORD week_ids[] = { LOCALE_SABBREVDAYNAME7, LOCALE_SABBREVDAYNAME1,
705 LOCALE_SABBREVDAYNAME2, LOCALE_SABBREVDAYNAME3, LOCALE_SABBREVDAYNAME4,
706 LOCALE_SABBREVDAYNAME5, LOCALE_SABBREVDAYNAME6 };
707 static const DWORD month_ids[] = { LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2,
708 LOCALE_SABBREVMONTHNAME3, LOCALE_SABBREVMONTHNAME4,
709 LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6,
710 LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8,
711 LOCALE_SABBREVMONTHNAME9, LOCALE_SABBREVMONTHNAME10,
712 LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12 };
714 BOOL formatAD = TRUE;
715 WCHAR week[64], month[64];
716 WCHAR buf[192];
717 DateInstance *date;
718 jsstr_t *date_str;
719 int year, day;
720 DWORD lcid_en;
722 if(!(date = date_this(jsthis)))
723 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
725 if(isnan(date->time)) {
726 if(r)
727 *r = jsval_string(jsstr_nan());
728 return S_OK;
731 if(r) {
732 lcid_en = MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT);
734 week[0] = 0;
735 GetLocaleInfoW(lcid_en, week_ids[(int)week_day(date->time)], week, ARRAY_SIZE(week));
737 month[0] = 0;
738 GetLocaleInfoW(lcid_en, month_ids[(int)month_from_time(date->time)], month, ARRAY_SIZE(month));
740 year = year_from_time(date->time);
741 if(year<0) {
742 formatAD = FALSE;
743 year = -year+1;
746 day = date_from_time(date->time);
748 sprintfW(buf, formatAD ? formatADW : formatBCW, week, day, month, year,
749 (int)hour_from_time(date->time), (int)min_from_time(date->time),
750 (int)sec_from_time(date->time));
752 date_str = jsstr_alloc(buf);
753 if(!date_str)
754 return E_OUTOFMEMORY;
756 *r = jsval_string(date_str);
758 return S_OK;
761 /* ECMA-262 3rd Edition 15.9.5.42 */
762 static HRESULT Date_toUTCString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
763 jsval_t *r)
765 TRACE("\n");
766 return create_utc_string(ctx, jsthis, r);
769 static HRESULT Date_toGMTString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
770 jsval_t *r)
772 TRACE("\n");
773 return create_utc_string(ctx, jsthis, r);
776 /* ECMA-262 3rd Edition 15.9.5.3 */
777 static HRESULT dateobj_to_date_string(DateInstance *date, jsval_t *r)
779 static const WCHAR formatADW[] = { '%','s',' ','%','s',' ','%','d',' ','%','d',0 };
780 static const WCHAR formatBCW[] = { '%','s',' ','%','s',' ','%','d',' ','%','d',' ','B','.','C','.',0 };
782 static const DWORD week_ids[] = { LOCALE_SABBREVDAYNAME7, LOCALE_SABBREVDAYNAME1,
783 LOCALE_SABBREVDAYNAME2, LOCALE_SABBREVDAYNAME3, LOCALE_SABBREVDAYNAME4,
784 LOCALE_SABBREVDAYNAME5, LOCALE_SABBREVDAYNAME6 };
785 static const DWORD month_ids[] = { LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2,
786 LOCALE_SABBREVMONTHNAME3, LOCALE_SABBREVMONTHNAME4,
787 LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6,
788 LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8,
789 LOCALE_SABBREVMONTHNAME9, LOCALE_SABBREVMONTHNAME10,
790 LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12 };
792 BOOL formatAD = TRUE;
793 WCHAR week[64], month[64];
794 WCHAR buf[192];
795 jsstr_t *date_str;
796 DOUBLE time;
797 int year, day;
798 DWORD lcid_en;
800 if(isnan(date->time)) {
801 if(r)
802 *r = jsval_string(jsstr_nan());
803 return S_OK;
806 time = local_time(date->time, date);
808 if(r) {
809 lcid_en = MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT);
811 week[0] = 0;
812 GetLocaleInfoW(lcid_en, week_ids[(int)week_day(time)], week, ARRAY_SIZE(week));
814 month[0] = 0;
815 GetLocaleInfoW(lcid_en, month_ids[(int)month_from_time(time)], month, ARRAY_SIZE(month));
817 year = year_from_time(time);
818 if(year<0) {
819 formatAD = FALSE;
820 year = -year+1;
823 day = date_from_time(time);
825 sprintfW(buf, formatAD ? formatADW : formatBCW, week, month, day, year);
827 date_str = jsstr_alloc(buf);
828 if(!date_str)
829 return E_OUTOFMEMORY;
831 *r = jsval_string(date_str);
833 return S_OK;
836 static HRESULT Date_toDateString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
837 jsval_t *r)
839 DateInstance *date;
841 if(!(date = date_this(jsthis)))
842 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
844 return dateobj_to_date_string(date, r);
847 /* ECMA-262 3rd Edition 15.9.5.4 */
848 static HRESULT Date_toTimeString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
849 jsval_t *r)
851 static const WCHAR formatW[] = { '%','0','2','d',':','%','0','2','d',':','%','0','2','d',
852 ' ','U','T','C','%','c','%','0','2','d','%','0','2','d',0 };
853 static const WCHAR formatUTCW[] = { '%','0','2','d',':','%','0','2','d',
854 ':','%','0','2','d',' ','U','T','C',0 };
855 DateInstance *date;
856 jsstr_t *date_str;
857 WCHAR buf[32];
858 DOUBLE time;
859 WCHAR sign;
860 int offset;
862 TRACE("\n");
864 if(!(date = date_this(jsthis)))
865 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
867 if(isnan(date->time)) {
868 if(r)
869 *r = jsval_string(jsstr_nan());
870 return S_OK;
873 time = local_time(date->time, date);
875 if(r) {
876 offset = date->bias +
877 daylight_saving_ta(time, date);
879 if(offset < 0) {
880 sign = '+';
881 offset = -offset;
883 else sign = '-';
885 if(offset)
886 sprintfW(buf, formatW, (int)hour_from_time(time),
887 (int)min_from_time(time), (int)sec_from_time(time),
888 sign, offset/60, offset%60);
889 else
890 sprintfW(buf, formatUTCW, (int)hour_from_time(time),
891 (int)min_from_time(time), (int)sec_from_time(time));
893 date_str = jsstr_alloc(buf);
894 if(!date_str)
895 return E_OUTOFMEMORY;
897 *r = jsval_string(date_str);
899 return S_OK;
902 /* ECMA-262 3rd Edition 15.9.5.6 */
903 static HRESULT Date_toLocaleDateString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
904 jsval_t *r)
906 SYSTEMTIME st;
907 DateInstance *date;
908 jsstr_t *date_str;
909 int len;
911 TRACE("\n");
913 if(!(date = date_this(jsthis)))
914 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
916 if(isnan(date->time)) {
917 if(r)
918 *r = jsval_string(jsstr_nan());
919 return S_OK;
922 st = create_systemtime(local_time(date->time, date));
924 if(st.wYear<1601 || st.wYear>9999)
925 return dateobj_to_date_string(date, r);
927 if(r) {
928 WCHAR *ptr;
930 len = GetDateFormatW(ctx->lcid, DATE_LONGDATE, &st, NULL, NULL, 0);
931 date_str = jsstr_alloc_buf(len-1, &ptr);
932 if(!date_str)
933 return E_OUTOFMEMORY;
934 GetDateFormatW(ctx->lcid, DATE_LONGDATE, &st, NULL, ptr, len);
936 *r = jsval_string(date_str);
938 return S_OK;
941 /* ECMA-262 3rd Edition 15.9.5.7 */
942 static HRESULT Date_toLocaleTimeString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
943 jsval_t *r)
945 SYSTEMTIME st;
946 DateInstance *date;
947 jsstr_t *date_str;
948 int len;
950 TRACE("\n");
952 if(!(date = date_this(jsthis)))
953 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
955 if(isnan(date->time)) {
956 if(r)
957 *r = jsval_string(jsstr_nan());
958 return S_OK;
961 st = create_systemtime(local_time(date->time, date));
963 if(st.wYear<1601 || st.wYear>9999)
964 return Date_toTimeString(ctx, jsthis, flags, argc, argv, r);
966 if(r) {
967 WCHAR *ptr;
969 len = GetTimeFormatW(ctx->lcid, 0, &st, NULL, NULL, 0);
970 date_str = jsstr_alloc_buf(len-1, &ptr);
971 if(!date_str)
972 return E_OUTOFMEMORY;
973 GetTimeFormatW(ctx->lcid, 0, &st, NULL, ptr, len);
975 *r = jsval_string(date_str);
977 return S_OK;
980 /* ECMA-262 3rd Edition 15.9.5.9 */
981 static HRESULT Date_getTime(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
982 jsval_t *r)
984 DateInstance *date;
986 TRACE("\n");
988 if(!(date = date_this(jsthis)))
989 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
991 if(r)
992 *r = jsval_number(date->time);
993 return S_OK;
996 /* ECMA-262 3rd Edition 15.9.5.10 */
997 static HRESULT Date_getFullYear(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
998 jsval_t *r)
1000 DateInstance *date;
1002 TRACE("\n");
1004 if(!(date = date_this(jsthis)))
1005 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1007 if(r) {
1008 DOUBLE time = local_time(date->time, date);
1010 *r = jsval_number(year_from_time(time));
1012 return S_OK;
1015 /* ECMA-262 3rd Edition 15.9.5.11 */
1016 static HRESULT Date_getUTCFullYear(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1017 jsval_t *r)
1019 DateInstance *date;
1021 TRACE("\n");
1023 if(!(date = date_this(jsthis)))
1024 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1026 if(r)
1027 *r = jsval_number(year_from_time(date->time));
1028 return S_OK;
1031 /* ECMA-262 3rd Edition 15.9.5.12 */
1032 static HRESULT Date_getMonth(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
1034 DateInstance *date;
1036 TRACE("\n");
1038 if(!(date = date_this(jsthis)))
1039 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1041 if(r)
1042 *r = jsval_number(month_from_time(local_time(date->time, date)));
1043 return S_OK;
1046 /* ECMA-262 3rd Edition 15.9.5.13 */
1047 static HRESULT Date_getUTCMonth(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1048 jsval_t *r)
1050 DateInstance *date;
1052 TRACE("\n");
1054 if(!(date = date_this(jsthis)))
1055 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1057 if(r)
1058 *r = jsval_number(month_from_time(date->time));
1059 return S_OK;
1062 /* ECMA-262 3rd Edition 15.9.5.14 */
1063 static HRESULT Date_getDate(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
1065 DateInstance *date;
1067 TRACE("\n");
1069 if(!(date = date_this(jsthis)))
1070 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1072 if(r)
1073 *r = jsval_number(date_from_time(local_time(date->time, date)));
1074 return S_OK;
1077 /* ECMA-262 3rd Edition 15.9.5.15 */
1078 static HRESULT Date_getUTCDate(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1079 jsval_t *r)
1081 DateInstance *date;
1083 TRACE("\n");
1085 if(!(date = date_this(jsthis)))
1086 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1088 if(r)
1089 *r = jsval_number(date_from_time(date->time));
1090 return S_OK;
1093 /* ECMA-262 3rd Edition 15.9.5.16 */
1094 static HRESULT Date_getDay(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1095 jsval_t *r)
1097 DateInstance *date;
1099 TRACE("\n");
1101 if(!(date = date_this(jsthis)))
1102 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1104 if(r)
1105 *r = jsval_number(week_day(local_time(date->time, date)));
1106 return S_OK;
1109 /* ECMA-262 3rd Edition 15.9.5.17 */
1110 static HRESULT Date_getUTCDay(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1111 jsval_t *r)
1113 DateInstance *date;
1115 TRACE("\n");
1117 if(!(date = date_this(jsthis)))
1118 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1120 if(r)
1121 *r = jsval_number(week_day(date->time));
1122 return S_OK;
1125 /* ECMA-262 3rd Edition 15.9.5.18 */
1126 static HRESULT Date_getHours(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1127 jsval_t *r)
1129 DateInstance *date;
1131 TRACE("\n");
1133 if(!(date = date_this(jsthis)))
1134 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1136 if(r)
1137 *r = jsval_number(hour_from_time(local_time(date->time, date)));
1138 return S_OK;
1141 /* ECMA-262 3rd Edition 15.9.5.19 */
1142 static HRESULT Date_getUTCHours(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1143 jsval_t *r)
1145 DateInstance *date;
1147 TRACE("\n");
1149 if(!(date = date_this(jsthis)))
1150 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1152 if(r)
1153 *r = jsval_number(hour_from_time(date->time));
1154 return S_OK;
1157 /* ECMA-262 3rd Edition 15.9.5.20 */
1158 static HRESULT Date_getMinutes(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1159 jsval_t *r)
1161 DateInstance *date;
1163 TRACE("\n");
1165 if(!(date = date_this(jsthis)))
1166 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1168 if(r)
1169 *r = jsval_number(min_from_time(local_time(date->time, date)));
1170 return S_OK;
1173 /* ECMA-262 3rd Edition 15.9.5.21 */
1174 static HRESULT Date_getUTCMinutes(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1175 jsval_t *r)
1177 DateInstance *date;
1179 TRACE("\n");
1181 if(!(date = date_this(jsthis)))
1182 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1184 if(r)
1185 *r = jsval_number(min_from_time(date->time));
1186 return S_OK;
1189 /* ECMA-262 3rd Edition 15.9.5.22 */
1190 static HRESULT Date_getSeconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
1192 DateInstance *date;
1194 TRACE("\n");
1196 if(!(date = date_this(jsthis)))
1197 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1199 if(r)
1200 *r = jsval_number(sec_from_time(local_time(date->time, date)));
1201 return S_OK;
1204 /* ECMA-262 3rd Edition 15.9.5.23 */
1205 static HRESULT Date_getUTCSeconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1206 jsval_t *r)
1208 DateInstance *date;
1210 TRACE("\n");
1212 if(!(date = date_this(jsthis)))
1213 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1215 if(r)
1216 *r = jsval_number(sec_from_time(date->time));
1217 return S_OK;
1220 /* ECMA-262 3rd Edition 15.9.5.24 */
1221 static HRESULT Date_getMilliseconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1222 jsval_t *r)
1224 DateInstance *date;
1226 TRACE("\n");
1228 if(!(date = date_this(jsthis)))
1229 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1231 if(r)
1232 *r = jsval_number(ms_from_time(local_time(date->time, date)));
1233 return S_OK;
1236 /* ECMA-262 3rd Edition 15.9.5.25 */
1237 static HRESULT Date_getUTCMilliseconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1238 jsval_t *r)
1240 DateInstance *date;
1242 TRACE("\n");
1244 if(!(date = date_this(jsthis)))
1245 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1247 if(r)
1248 *r = jsval_number(ms_from_time(date->time));
1249 return S_OK;
1252 /* ECMA-262 3rd Edition 15.9.5.26 */
1253 static HRESULT Date_getTimezoneOffset(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1254 jsval_t *r)
1256 DateInstance *date;
1258 TRACE("\n");
1260 if(!(date = date_this(jsthis)))
1261 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1263 if(r)
1264 *r = jsval_number(floor((date->time-local_time(date->time, date))/MS_PER_MINUTE));
1265 return S_OK;
1268 /* ECMA-262 3rd Edition 15.9.5.27 */
1269 static HRESULT Date_setTime(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1270 jsval_t *r)
1272 double n;
1273 HRESULT hres;
1274 DateInstance *date;
1276 TRACE("\n");
1278 if(!(date = date_this(jsthis)))
1279 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1281 if(!argc)
1282 return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
1284 hres = to_number(ctx, argv[0], &n);
1285 if(FAILED(hres))
1286 return hres;
1288 date->time = time_clip(n);
1290 if(r)
1291 *r = jsval_number(date->time);
1292 return S_OK;
1295 /* ECMA-262 3rd Edition 15.9.5.28 */
1296 static HRESULT Date_setMilliseconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1297 jsval_t *r)
1299 DateInstance *date;
1300 double n, t;
1301 HRESULT hres;
1303 TRACE("\n");
1305 if(!(date = date_this(jsthis)))
1306 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1308 if(!argc)
1309 return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
1311 hres = to_number(ctx, argv[0], &n);
1312 if(FAILED(hres))
1313 return hres;
1315 t = local_time(date->time, date);
1316 t = make_date(day(t), make_time(hour_from_time(t), min_from_time(t),
1317 sec_from_time(t), n));
1318 date->time = time_clip(utc(t, date));
1320 if(r)
1321 *r = jsval_number(date->time);
1322 return S_OK;
1325 /* ECMA-262 3rd Edition 15.9.5.29 */
1326 static HRESULT Date_setUTCMilliseconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1327 jsval_t *r)
1329 DateInstance *date;
1330 double n, t;
1331 HRESULT hres;
1333 TRACE("\n");
1335 if(!(date = date_this(jsthis)))
1336 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1338 if(!argc)
1339 return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
1341 hres = to_number(ctx, argv[0], &n);
1342 if(FAILED(hres))
1343 return hres;
1345 t = date->time;
1346 t = make_date(day(t), make_time(hour_from_time(t), min_from_time(t),
1347 sec_from_time(t), n));
1348 date->time = time_clip(t);
1350 if(r)
1351 *r = jsval_number(date->time);
1352 return S_OK;
1355 /* ECMA-262 3rd Edition 15.9.5.30 */
1356 static HRESULT Date_setSeconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1357 jsval_t *r)
1359 DateInstance *date;
1360 double t, sec, ms;
1361 HRESULT hres;
1363 TRACE("\n");
1365 if(!(date = date_this(jsthis)))
1366 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1368 if(!argc)
1369 return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
1371 t = local_time(date->time, date);
1373 hres = to_number(ctx, argv[0], &sec);
1374 if(FAILED(hres))
1375 return hres;
1377 if(argc > 1) {
1378 hres = to_number(ctx, argv[1], &ms);
1379 if(FAILED(hres))
1380 return hres;
1381 }else {
1382 ms = ms_from_time(t);
1385 t = make_date(day(t), make_time(hour_from_time(t),
1386 min_from_time(t), sec, ms));
1387 date->time = time_clip(utc(t, date));
1389 if(r)
1390 *r = jsval_number(date->time);
1391 return S_OK;
1394 /* ECMA-262 3rd Edition 15.9.5.31 */
1395 static HRESULT Date_setUTCSeconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1396 jsval_t *r)
1398 DateInstance *date;
1399 double t, sec, ms;
1400 HRESULT hres;
1402 TRACE("\n");
1404 if(!(date = date_this(jsthis)))
1405 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1407 if(!argc)
1408 return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
1410 t = date->time;
1412 hres = to_number(ctx, argv[0], &sec);
1413 if(FAILED(hres))
1414 return hres;
1416 if(argc > 1) {
1417 hres = to_number(ctx, argv[1], &ms);
1418 if(FAILED(hres))
1419 return hres;
1420 }else {
1421 ms = ms_from_time(t);
1424 t = make_date(day(t), make_time(hour_from_time(t),
1425 min_from_time(t), sec, ms));
1426 date->time = time_clip(t);
1428 if(r)
1429 *r = jsval_number(date->time);
1430 return S_OK;
1433 /* ECMA-262 3rd Edition 15.9.5.33 */
1434 static HRESULT Date_setMinutes(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1435 jsval_t *r)
1437 DateInstance *date;
1438 double t, min, sec, ms;
1439 HRESULT hres;
1441 TRACE("\n");
1443 if(!(date = date_this(jsthis)))
1444 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1446 if(!argc)
1447 return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
1449 t = local_time(date->time, date);
1451 hres = to_number(ctx, argv[0], &min);
1452 if(FAILED(hres))
1453 return hres;
1455 if(argc > 1) {
1456 hres = to_number(ctx, argv[1], &sec);
1457 if(FAILED(hres))
1458 return hres;
1459 }else {
1460 sec = sec_from_time(t);
1463 if(argc > 2) {
1464 hres = to_number(ctx, argv[2], &ms);
1465 if(FAILED(hres))
1466 return hres;
1467 }else {
1468 ms = ms_from_time(t);
1471 t = make_date(day(t), make_time(hour_from_time(t),
1472 min, sec, ms));
1473 date->time = time_clip(utc(t, date));
1475 if(r)
1476 *r = jsval_number(date->time);
1477 return S_OK;
1480 /* ECMA-262 3rd Edition 15.9.5.34 */
1481 static HRESULT Date_setUTCMinutes(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1482 jsval_t *r)
1484 DateInstance *date;
1485 double t, min, sec, ms;
1486 HRESULT hres;
1488 TRACE("\n");
1490 if(!(date = date_this(jsthis)))
1491 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1493 if(!argc)
1494 return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
1496 t = date->time;
1498 hres = to_number(ctx, argv[0], &min);
1499 if(FAILED(hres))
1500 return hres;
1502 if(argc > 1) {
1503 hres = to_number(ctx, argv[1], &sec);
1504 if(FAILED(hres))
1505 return hres;
1506 }else {
1507 sec = sec_from_time(t);
1510 if(argc > 2) {
1511 hres = to_number(ctx, argv[2], &ms);
1512 if(FAILED(hres))
1513 return hres;
1514 }else {
1515 ms = ms_from_time(t);
1518 t = make_date(day(t), make_time(hour_from_time(t),
1519 min, sec, ms));
1520 date->time = time_clip(t);
1522 if(r)
1523 *r = jsval_number(date->time);
1524 return S_OK;
1527 /* ECMA-262 3rd Edition 15.9.5.35 */
1528 static HRESULT Date_setHours(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1529 jsval_t *r)
1531 DateInstance *date;
1532 double t, hour, min, sec, ms;
1533 HRESULT hres;
1535 TRACE("\n");
1537 if(!(date = date_this(jsthis)))
1538 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1540 if(!argc)
1541 return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
1543 t = local_time(date->time, date);
1545 hres = to_number(ctx, argv[0], &hour);
1546 if(FAILED(hres))
1547 return hres;
1549 if(argc > 1) {
1550 hres = to_number(ctx, argv[1], &min);
1551 if(FAILED(hres))
1552 return hres;
1553 }else {
1554 min = min_from_time(t);
1557 if(argc > 2) {
1558 hres = to_number(ctx, argv[2], &sec);
1559 if(FAILED(hres))
1560 return hres;
1561 }else {
1562 sec = sec_from_time(t);
1565 if(argc > 3) {
1566 hres = to_number(ctx, argv[3], &ms);
1567 if(FAILED(hres))
1568 return hres;
1569 }else {
1570 ms = ms_from_time(t);
1573 t = make_date(day(t), make_time(hour, min, sec, ms));
1574 date->time = time_clip(utc(t, date));
1576 if(r)
1577 *r = jsval_number(date->time);
1578 return S_OK;
1581 /* ECMA-262 3rd Edition 15.9.5.36 */
1582 static HRESULT Date_setUTCHours(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1583 jsval_t *r)
1585 DateInstance *date;
1586 double t, hour, min, sec, ms;
1587 HRESULT hres;
1589 TRACE("\n");
1591 if(!(date = date_this(jsthis)))
1592 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1594 if(!argc)
1595 return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
1597 t = date->time;
1599 hres = to_number(ctx, argv[0], &hour);
1600 if(FAILED(hres))
1601 return hres;
1603 if(argc > 1) {
1604 hres = to_number(ctx, argv[1], &min);
1605 if(FAILED(hres))
1606 return hres;
1607 }else {
1608 min = min_from_time(t);
1611 if(argc > 2) {
1612 hres = to_number(ctx, argv[2], &sec);
1613 if(FAILED(hres))
1614 return hres;
1615 }else {
1616 sec = sec_from_time(t);
1619 if(argc > 3) {
1620 hres = to_number(ctx, argv[3], &ms);
1621 if(FAILED(hres))
1622 return hres;
1623 }else {
1624 ms = ms_from_time(t);
1627 t = make_date(day(t), make_time(hour, min, sec, ms));
1628 date->time = time_clip(t);
1630 if(r)
1631 *r = jsval_number(date->time);
1632 return S_OK;
1635 /* ECMA-262 3rd Edition 15.9.5.36 */
1636 static HRESULT Date_setDate(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1637 jsval_t *r)
1639 DateInstance *date;
1640 double t, n;
1641 HRESULT hres;
1643 TRACE("\n");
1645 if(!(date = date_this(jsthis)))
1646 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1648 if(!argc)
1649 return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
1651 hres = to_number(ctx, argv[0], &n);
1652 if(FAILED(hres))
1653 return hres;
1655 t = local_time(date->time, date);
1656 t = make_date(make_day(year_from_time(t), month_from_time(t), n), time_within_day(t));
1657 date->time = time_clip(utc(t, date));
1659 if(r)
1660 *r = jsval_number(date->time);
1661 return S_OK;
1664 /* ECMA-262 3rd Edition 15.9.5.37 */
1665 static HRESULT Date_setUTCDate(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1666 jsval_t *r)
1668 DateInstance *date;
1669 double t, n;
1670 HRESULT hres;
1672 TRACE("\n");
1674 if(!(date = date_this(jsthis)))
1675 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1677 if(!argc)
1678 return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
1680 hres = to_number(ctx, argv[0], &n);
1681 if(FAILED(hres))
1682 return hres;
1684 t = date->time;
1685 t = make_date(make_day(year_from_time(t), month_from_time(t), n), time_within_day(t));
1686 date->time = time_clip(t);
1688 if(r)
1689 *r = jsval_number(date->time);
1690 return S_OK;
1693 /* ECMA-262 3rd Edition 15.9.5.38 */
1694 static HRESULT Date_setMonth(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1695 jsval_t *r)
1697 DateInstance *date;
1698 DOUBLE t, month, ddate;
1699 HRESULT hres;
1701 TRACE("\n");
1703 if(!(date = date_this(jsthis)))
1704 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1706 if(!argc)
1707 return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
1709 t = local_time(date->time, date);
1711 hres = to_number(ctx, argv[0], &month);
1712 if(FAILED(hres))
1713 return hres;
1715 if(argc > 1) {
1716 hres = to_number(ctx, argv[1], &ddate);
1717 if(FAILED(hres))
1718 return hres;
1719 }else {
1720 ddate = date_from_time(t);
1723 t = make_date(make_day(year_from_time(t), month, ddate),
1724 time_within_day(t));
1725 date->time = time_clip(utc(t, date));
1727 if(r)
1728 *r = jsval_number(date->time);
1729 return S_OK;
1732 /* ECMA-262 3rd Edition 15.9.5.39 */
1733 static HRESULT Date_setUTCMonth(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1734 jsval_t *r)
1736 DateInstance *date;
1737 double t, month, ddate;
1738 HRESULT hres;
1740 TRACE("\n");
1742 if(!(date = date_this(jsthis)))
1743 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1745 if(!argc)
1746 return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
1748 t = date->time;
1750 hres = to_number(ctx, argv[0], &month);
1751 if(FAILED(hres))
1752 return hres;
1754 if(argc > 1) {
1755 hres = to_number(ctx, argv[1], &ddate);
1756 if(FAILED(hres))
1757 return hres;
1758 }else {
1759 ddate = date_from_time(t);
1762 t = make_date(make_day(year_from_time(t), month, ddate),
1763 time_within_day(t));
1764 date->time = time_clip(t);
1766 if(r)
1767 *r = jsval_number(date->time);
1768 return S_OK;
1771 /* ECMA-262 3rd Edition 15.9.5.40 */
1772 static HRESULT Date_setFullYear(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1773 jsval_t *r)
1775 DateInstance *date;
1776 double t, year, month, ddate;
1777 HRESULT hres;
1779 TRACE("\n");
1781 if(!(date = date_this(jsthis)))
1782 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1784 if(!argc)
1785 return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
1787 t = local_time(date->time, date);
1789 hres = to_number(ctx, argv[0], &year);
1790 if(FAILED(hres))
1791 return hres;
1793 if(argc > 1) {
1794 hres = to_number(ctx, argv[1], &month);
1795 if(FAILED(hres))
1796 return hres;
1797 }else {
1798 month = month_from_time(t);
1801 if(argc > 2) {
1802 hres = to_number(ctx, argv[2], &ddate);
1803 if(FAILED(hres))
1804 return hres;
1805 }else {
1806 ddate = date_from_time(t);
1809 t = make_date(make_day(year, month, ddate), time_within_day(t));
1810 date->time = time_clip(utc(t, date));
1812 if(r)
1813 *r = jsval_number(date->time);
1814 return S_OK;
1817 /* ECMA-262 3rd Edition 15.9.5.41 */
1818 static HRESULT Date_setUTCFullYear(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1819 jsval_t *r)
1821 DateInstance *date;
1822 double t, year, month, ddate;
1823 HRESULT hres;
1825 TRACE("\n");
1827 if(!(date = date_this(jsthis)))
1828 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1830 if(!argc)
1831 return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
1833 t = date->time;
1835 hres = to_number(ctx, argv[0], &year);
1836 if(FAILED(hres))
1837 return hres;
1839 if(argc > 1) {
1840 hres = to_number(ctx, argv[1], &month);
1841 if(FAILED(hres))
1842 return hres;
1843 }else {
1844 month = month_from_time(t);
1847 if(argc > 2) {
1848 hres = to_number(ctx, argv[2], &ddate);
1849 if(FAILED(hres))
1850 return hres;
1851 }else {
1852 ddate = date_from_time(t);
1855 t = make_date(make_day(year, month, ddate), time_within_day(t));
1856 date->time = time_clip(t);
1858 if(r)
1859 *r = jsval_number(date->time);
1860 return S_OK;
1863 /* ECMA-262 3rd Edition B2.4 */
1864 static HRESULT Date_getYear(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1865 jsval_t *r)
1867 DateInstance *date;
1868 DOUBLE t, year;
1870 TRACE("\n");
1872 if(!(date = date_this(jsthis)))
1873 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1875 t = local_time(date->time, date);
1876 if(isnan(t)) {
1877 if(r)
1878 *r = jsval_number(NAN);
1879 return S_OK;
1882 year = year_from_time(t);
1883 if(r)
1884 *r = jsval_number((1900<=year && year<2000)?year-1900:year);
1885 return S_OK;
1888 /* ECMA-262 3rd Edition B2.5 */
1889 static HRESULT Date_setYear(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1890 jsval_t *r)
1892 DateInstance *date;
1893 DOUBLE t, year;
1894 HRESULT hres;
1896 TRACE("\n");
1898 if(!(date = date_this(jsthis)))
1899 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1901 if(!argc)
1902 return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
1904 t = local_time(date->time, date);
1906 hres = to_number(ctx, argv[0], &year);
1907 if(FAILED(hres))
1908 return hres;
1910 if(isnan(year)) {
1911 date->time = year;
1912 if(r)
1913 *r = jsval_number(NAN);
1914 return S_OK;
1917 year = year >= 0.0 ? floor(year) : -floor(-year);
1918 if(-1.0 < year && year < 100.0)
1919 year += 1900.0;
1921 date->time = time_clip(utc(make_date(make_day(year, month_from_time(t), date_from_time(t)), time_within_day(t)), date));
1923 if(r)
1924 *r = jsval_number(date->time);
1925 return S_OK;
1928 static HRESULT Date_get_value(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r)
1930 TRACE("\n");
1932 return dateobj_to_string(date_from_jsdisp(jsthis), r);
1935 static const builtin_prop_t Date_props[] = {
1936 {getDateW, Date_getDate, PROPF_METHOD},
1937 {getDayW, Date_getDay, PROPF_METHOD},
1938 {getFullYearW, Date_getFullYear, PROPF_METHOD},
1939 {getHoursW, Date_getHours, PROPF_METHOD},
1940 {getMillisecondsW, Date_getMilliseconds, PROPF_METHOD},
1941 {getMinutesW, Date_getMinutes, PROPF_METHOD},
1942 {getMonthW, Date_getMonth, PROPF_METHOD},
1943 {getSecondsW, Date_getSeconds, PROPF_METHOD},
1944 {getTimeW, Date_getTime, PROPF_METHOD},
1945 {getTimezoneOffsetW, Date_getTimezoneOffset, PROPF_METHOD},
1946 {getUTCDateW, Date_getUTCDate, PROPF_METHOD},
1947 {getUTCDayW, Date_getUTCDay, PROPF_METHOD},
1948 {getUTCFullYearW, Date_getUTCFullYear, PROPF_METHOD},
1949 {getUTCHoursW, Date_getUTCHours, PROPF_METHOD},
1950 {getUTCMillisecondsW, Date_getUTCMilliseconds, PROPF_METHOD},
1951 {getUTCMinutesW, Date_getUTCMinutes, PROPF_METHOD},
1952 {getUTCMonthW, Date_getUTCMonth, PROPF_METHOD},
1953 {getUTCSecondsW, Date_getUTCSeconds, PROPF_METHOD},
1954 {getYearW, Date_getYear, PROPF_METHOD},
1955 {setDateW, Date_setDate, PROPF_METHOD|1},
1956 {setFullYearW, Date_setFullYear, PROPF_METHOD|3},
1957 {setHoursW, Date_setHours, PROPF_METHOD|4},
1958 {setMillisecondsW, Date_setMilliseconds, PROPF_METHOD|1},
1959 {setMinutesW, Date_setMinutes, PROPF_METHOD|3},
1960 {setMonthW, Date_setMonth, PROPF_METHOD|2},
1961 {setSecondsW, Date_setSeconds, PROPF_METHOD|2},
1962 {setTimeW, Date_setTime, PROPF_METHOD|1},
1963 {setUTCDateW, Date_setUTCDate, PROPF_METHOD|1},
1964 {setUTCFullYearW, Date_setUTCFullYear, PROPF_METHOD|3},
1965 {setUTCHoursW, Date_setUTCHours, PROPF_METHOD|4},
1966 {setUTCMillisecondsW, Date_setUTCMilliseconds, PROPF_METHOD|1},
1967 {setUTCMinutesW, Date_setUTCMinutes, PROPF_METHOD|3},
1968 {setUTCMonthW, Date_setUTCMonth, PROPF_METHOD|2},
1969 {setUTCSecondsW, Date_setUTCSeconds, PROPF_METHOD|2},
1970 {setYearW, Date_setYear, PROPF_METHOD|1},
1971 {toDateStringW, Date_toDateString, PROPF_METHOD},
1972 {toGMTStringW, Date_toGMTString, PROPF_METHOD},
1973 {toISOStringW, Date_toISOString, PROPF_METHOD|PROPF_ES5},
1974 {toLocaleDateStringW, Date_toLocaleDateString, PROPF_METHOD},
1975 {toLocaleStringW, Date_toLocaleString, PROPF_METHOD},
1976 {toLocaleTimeStringW, Date_toLocaleTimeString, PROPF_METHOD},
1977 {toStringW, Date_toString, PROPF_METHOD},
1978 {toTimeStringW, Date_toTimeString, PROPF_METHOD},
1979 {toUTCStringW, Date_toUTCString, PROPF_METHOD},
1980 {valueOfW, Date_valueOf, PROPF_METHOD},
1983 static const builtin_info_t Date_info = {
1984 JSCLASS_DATE,
1985 {NULL, NULL,0, Date_get_value},
1986 ARRAY_SIZE(Date_props),
1987 Date_props,
1988 NULL,
1989 NULL
1992 static const builtin_info_t DateInst_info = {
1993 JSCLASS_DATE,
1994 {NULL, NULL,0, Date_get_value},
1995 0, NULL,
1996 NULL,
1997 NULL
2000 static HRESULT create_date(script_ctx_t *ctx, jsdisp_t *object_prototype, DOUBLE time, jsdisp_t **ret)
2002 DateInstance *date;
2003 HRESULT hres;
2004 TIME_ZONE_INFORMATION tzi;
2006 GetTimeZoneInformation(&tzi);
2008 date = heap_alloc_zero(sizeof(DateInstance));
2009 if(!date)
2010 return E_OUTOFMEMORY;
2012 if(object_prototype)
2013 hres = init_dispex(&date->dispex, ctx, &Date_info, object_prototype);
2014 else
2015 hres = init_dispex_from_constr(&date->dispex, ctx, &DateInst_info, ctx->date_constr);
2016 if(FAILED(hres)) {
2017 heap_free(date);
2018 return hres;
2021 date->time = time;
2022 date->bias = tzi.Bias;
2023 date->standardDate = tzi.StandardDate;
2024 date->standardBias = tzi.StandardBias;
2025 date->daylightDate = tzi.DaylightDate;
2026 date->daylightBias = tzi.DaylightBias;
2028 *ret = &date->dispex;
2029 return S_OK;
2032 static inline HRESULT date_parse(jsstr_t *input_str, double *ret) {
2033 static const DWORD string_ids[] = { LOCALE_SMONTHNAME12, LOCALE_SMONTHNAME11,
2034 LOCALE_SMONTHNAME10, LOCALE_SMONTHNAME9, LOCALE_SMONTHNAME8,
2035 LOCALE_SMONTHNAME7, LOCALE_SMONTHNAME6, LOCALE_SMONTHNAME5,
2036 LOCALE_SMONTHNAME4, LOCALE_SMONTHNAME3, LOCALE_SMONTHNAME2,
2037 LOCALE_SMONTHNAME1, LOCALE_SDAYNAME7, LOCALE_SDAYNAME1,
2038 LOCALE_SDAYNAME2, LOCALE_SDAYNAME3, LOCALE_SDAYNAME4,
2039 LOCALE_SDAYNAME5, LOCALE_SDAYNAME6 };
2040 WCHAR *strings[ARRAY_SIZE(string_ids)];
2041 WCHAR *parse;
2042 int input_len, parse_len = 0, nest_level = 0, i, size;
2043 int year = 0, month = 0, day = 0, hour = 0, min = 0, sec = 0;
2044 int ms = 0, offset = 0, hour_adjust = 0;
2045 BOOL set_year = FALSE, set_month = FALSE, set_day = FALSE, set_hour = FALSE;
2046 BOOL set_offset = FALSE, set_era = FALSE, ad = TRUE, set_am = FALSE, am = TRUE;
2047 BOOL set_hour_adjust = TRUE;
2048 TIME_ZONE_INFORMATION tzi;
2049 const WCHAR *input;
2050 DateInstance di;
2051 DWORD lcid_en;
2053 input_len = jsstr_length(input_str);
2054 input = jsstr_flatten(input_str);
2055 if(!input)
2056 return E_OUTOFMEMORY;
2058 for(i=0; i<input_len; i++) {
2059 if(input[i] == '(') nest_level++;
2060 else if(input[i] == ')') {
2061 nest_level--;
2062 if(nest_level<0) {
2063 *ret = NAN;
2064 return S_OK;
2067 else if(!nest_level) parse_len++;
2070 parse = heap_alloc((parse_len+1)*sizeof(WCHAR));
2071 if(!parse)
2072 return E_OUTOFMEMORY;
2073 nest_level = 0;
2074 parse_len = 0;
2075 for(i=0; i<input_len; i++) {
2076 if(input[i] == '(') nest_level++;
2077 else if(input[i] == ')') nest_level--;
2078 else if(!nest_level) parse[parse_len++] = toupperW(input[i]);
2080 parse[parse_len] = 0;
2082 GetTimeZoneInformation(&tzi);
2083 di.bias = tzi.Bias;
2084 di.standardDate = tzi.StandardDate;
2085 di.standardBias = tzi.StandardBias;
2086 di.daylightDate = tzi.DaylightDate;
2087 di.daylightBias = tzi.DaylightBias;
2089 /* FIXME: Cache strings */
2090 lcid_en = MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT);
2091 for(i=0; i<ARRAY_SIZE(string_ids); i++) {
2092 size = GetLocaleInfoW(lcid_en, string_ids[i], NULL, 0);
2093 strings[i] = heap_alloc((size+1)*sizeof(WCHAR));
2094 if(!strings[i]) {
2095 i--;
2096 while(i-- >= 0)
2097 heap_free(strings[i]);
2098 heap_free(parse);
2099 return E_OUTOFMEMORY;
2101 GetLocaleInfoW(lcid_en, string_ids[i], strings[i], size);
2104 for(i=0; i<parse_len;) {
2105 while(isspaceW(parse[i])) i++;
2106 if(parse[i] == ',') {
2107 while(parse[i] == ',') i++;
2108 continue;
2111 if(parse[i]>='0' && parse[i]<='9') {
2112 int tmp = atoiW(&parse[i]);
2113 while(parse[i]>='0' && parse[i]<='9') i++;
2114 while(isspaceW(parse[i])) i++;
2116 if(parse[i] == ':') {
2117 /* Time */
2118 if(set_hour) break;
2119 set_hour = TRUE;
2121 hour = tmp;
2123 while(parse[i] == ':') i++;
2124 while(isspaceW(parse[i])) i++;
2125 if(parse[i]>='0' && parse[i]<='9') {
2126 min = atoiW(&parse[i]);
2127 while(parse[i]>='0' && parse[i]<='9') i++;
2130 while(isspaceW(parse[i])) i++;
2131 while(parse[i] == ':') i++;
2132 while(isspaceW(parse[i])) i++;
2133 if(parse[i]>='0' && parse[i]<='9') {
2134 sec = atoiW(&parse[i]);
2135 while(parse[i]>='0' && parse[i]<='9') i++;
2138 else if(parse[i]=='-' || parse[i]=='/') {
2139 /* Short or long date */
2140 if(set_day || set_month || set_year) break;
2141 set_day = TRUE;
2142 set_month = TRUE;
2143 set_year = TRUE;
2145 month = tmp-1;
2147 while(isspaceW(parse[i])) i++;
2148 while(parse[i]=='-' || parse[i]=='/') i++;
2149 while(isspaceW(parse[i])) i++;
2150 if(parse[i]<'0' || parse[i]>'9') break;
2151 day = atoiW(&parse[i]);
2152 while(parse[i]>='0' && parse[i]<='9') i++;
2154 while(parse[i]=='-' || parse[i]=='/') i++;
2155 while(isspaceW(parse[i])) i++;
2156 if(parse[i]<'0' || parse[i]>'9') break;
2157 year = atoiW(&parse[i]);
2158 while(parse[i]>='0' && parse[i]<='9') i++;
2160 if(tmp >= 70){
2161 /* long date */
2162 month = day - 1;
2163 day = year;
2164 year = tmp;
2167 else if(tmp<0) break;
2168 else if(tmp<70) {
2169 /* Day */
2170 if(set_day) break;
2171 set_day = TRUE;
2172 day = tmp;
2174 else {
2175 /* Year */
2176 if(set_year) break;
2177 set_year = TRUE;
2178 year = tmp;
2181 else if(parse[i]=='+' || parse[i]=='-') {
2182 /* Timezone offset */
2183 BOOL positive = TRUE;
2185 if(set_offset && set_hour_adjust) break;
2186 set_offset = TRUE;
2187 set_hour_adjust = FALSE;
2189 if(parse[i] == '-') positive = FALSE;
2191 i++;
2192 while(isspaceW(parse[i])) i++;
2193 if(parse[i]<'0' || parse[i]>'9') break;
2194 offset = atoiW(&parse[i]);
2195 while(parse[i]>='0' && parse[i]<='9') i++;
2197 if(offset<24) offset *= 60;
2198 else offset = (offset/100)*60 + offset%100;
2200 if(positive) offset = -offset;
2203 else {
2204 if(parse[i]<'A' || parse[i]>'Z') break;
2205 else if(parse[i]=='B' && (parse[i+1]=='C' ||
2206 (parse[i+1]=='.' && parse[i+2]=='C'))) {
2207 /* AD/BC */
2208 if(set_era) break;
2209 set_era = TRUE;
2210 ad = FALSE;
2212 i++;
2213 if(parse[i] == '.') i++;
2214 i++;
2215 if(parse[i] == '.') i++;
2217 else if(parse[i]=='A' && (parse[i+1]=='D' ||
2218 (parse[i+1]=='.' && parse[i+2]=='D'))) {
2219 /* AD/BC */
2220 if(set_era) break;
2221 set_era = TRUE;
2223 i++;
2224 if(parse[i] == '.') i++;
2225 i++;
2226 if(parse[i] == '.') i++;
2228 else if(parse[i+1]<'A' || parse[i+1]>'Z') {
2229 /* Timezone */
2230 if(set_offset) break;
2231 set_offset = TRUE;
2233 if(parse[i] <= 'I') hour_adjust = parse[i]-'A'+2;
2234 else if(parse[i] == 'J') break;
2235 else if(parse[i] <= 'M') hour_adjust = parse[i]-'K'+11;
2236 else if(parse[i] <= 'Y') hour_adjust = parse[i]-'N';
2237 else hour_adjust = 1;
2239 i++;
2240 if(parse[i] == '.') i++;
2242 else if(parse[i]=='A' && parse[i+1]=='M') {
2243 /* AM/PM */
2244 if(set_am) break;
2245 set_am = TRUE;
2246 am = TRUE;
2247 i += 2;
2249 else if(parse[i]=='P' && parse[i+1]=='M') {
2250 /* AM/PM */
2251 if(set_am) break;
2252 set_am = TRUE;
2253 am = FALSE;
2254 i += 2;
2256 else if((parse[i]=='U' && parse[i+1]=='T' && parse[i+2]=='C')
2257 || (parse[i]=='G' && parse[i+1]=='M' && parse[i+2]=='T')) {
2258 /* Timezone */
2259 if(set_offset) break;
2260 set_offset = TRUE;
2261 set_hour_adjust = FALSE;
2263 i += 3;
2265 else {
2266 /* Month or garbage */
2267 unsigned int j;
2269 for(size=i; parse[size]>='A' && parse[size]<='Z'; size++);
2270 size -= i;
2272 for(j=0; j<ARRAY_SIZE(string_ids); j++)
2273 if(!strncmpiW(&parse[i], strings[j], size)) break;
2275 if(j < 12) {
2276 if(set_month) break;
2277 set_month = TRUE;
2278 month = 11-j;
2280 else if(j == ARRAY_SIZE(string_ids)) break;
2282 i += size;
2287 if(i == parse_len && set_year && set_month && set_day && (!set_am || hour<13)) {
2288 if(set_am) {
2289 if(hour == 12) hour = 0;
2290 if(!am) hour += 12;
2293 if(!ad) year = -year+1;
2294 else if(year<100) year += 1900;
2296 *ret = time_clip(make_date(make_day(year, month, day),
2297 make_time(hour+hour_adjust, min, sec, ms)) + offset*MS_PER_MINUTE);
2299 if(set_hour_adjust)
2300 *ret = utc(*ret, &di);
2301 }else {
2302 *ret = NAN;
2305 for(i=0; i<ARRAY_SIZE(string_ids); i++)
2306 heap_free(strings[i]);
2307 heap_free(parse);
2309 return S_OK;
2312 static HRESULT DateConstr_parse(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
2313 jsval_t *r)
2315 jsstr_t *parse_str;
2316 double n;
2317 HRESULT hres;
2319 TRACE("\n");
2321 if(!argc) {
2322 if(r)
2323 *r = jsval_number(NAN);
2324 return S_OK;
2327 hres = to_string(ctx, argv[0], &parse_str);
2328 if(FAILED(hres))
2329 return hres;
2331 hres = date_parse(parse_str, &n);
2332 jsstr_release(parse_str);
2333 if(FAILED(hres))
2334 return hres;
2336 *r = jsval_number(n);
2337 return S_OK;
2340 static HRESULT date_utc(script_ctx_t *ctx, unsigned argc, jsval_t *argv, double *ret)
2342 double year, month, vdate, hours, minutes, seconds, ms;
2343 HRESULT hres;
2345 TRACE("\n");
2347 if(argc) {
2348 hres = to_number(ctx, argv[0], &year);
2349 if(FAILED(hres))
2350 return hres;
2351 if(0 <= year && year <= 99)
2352 year += 1900;
2353 }else {
2354 year = 1900;
2357 if(argc>1) {
2358 hres = to_number(ctx, argv[1], &month);
2359 if(FAILED(hres))
2360 return hres;
2361 }else {
2362 month = 0;
2365 if(argc>2) {
2366 hres = to_number(ctx, argv[2], &vdate);
2367 if(FAILED(hres))
2368 return hres;
2369 }else {
2370 vdate = 1;
2373 if(argc>3) {
2374 hres = to_number(ctx, argv[3], &hours);
2375 if(FAILED(hres))
2376 return hres;
2377 }else {
2378 hours = 0;
2381 if(argc>4) {
2382 hres = to_number(ctx, argv[4], &minutes);
2383 if(FAILED(hres))
2384 return hres;
2385 }else {
2386 minutes = 0;
2389 if(argc>5) {
2390 hres = to_number(ctx, argv[5], &seconds);
2391 if(FAILED(hres))
2392 return hres;
2393 }else {
2394 seconds = 0;
2397 if(argc>6) {
2398 hres = to_number(ctx, argv[6], &ms);
2399 if(FAILED(hres))
2400 return hres;
2401 } else {
2402 ms = 0;
2405 *ret = time_clip(make_date(make_day(year, month, vdate),
2406 make_time(hours, minutes,seconds, ms)));
2407 return S_OK;
2410 static HRESULT DateConstr_UTC(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
2411 jsval_t *r)
2413 double n;
2414 HRESULT hres;
2416 TRACE("\n");
2418 hres = date_utc(ctx, argc, argv, &n);
2419 if(SUCCEEDED(hres) && r)
2420 *r = jsval_number(n);
2421 return hres;
2424 /* ECMA-262 5.1 Edition 15.9.4.4 */
2425 static HRESULT DateConstr_now(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
2427 TRACE("\n");
2429 if(r) *r = jsval_number(date_now());
2430 return S_OK;
2433 static HRESULT DateConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
2434 jsval_t *r)
2436 jsdisp_t *date;
2437 HRESULT hres;
2439 TRACE("\n");
2441 switch(flags) {
2442 case DISPATCH_CONSTRUCT:
2443 switch(argc) {
2444 /* ECMA-262 3rd Edition 15.9.3.3 */
2445 case 0:
2446 hres = create_date(ctx, NULL, date_now(), &date);
2447 if(FAILED(hres))
2448 return hres;
2449 break;
2451 /* ECMA-262 3rd Edition 15.9.3.2 */
2452 case 1: {
2453 jsval_t prim;
2454 double n;
2456 hres = to_primitive(ctx, argv[0], &prim, NO_HINT);
2457 if(FAILED(hres))
2458 return hres;
2460 if(is_string(prim))
2461 hres = date_parse(get_string(prim), &n);
2462 else
2463 hres = to_number(ctx, prim, &n);
2465 jsval_release(prim);
2466 if(FAILED(hres))
2467 return hres;
2469 hres = create_date(ctx, NULL, time_clip(n), &date);
2470 if(FAILED(hres))
2471 return hres;
2472 break;
2475 /* ECMA-262 3rd Edition 15.9.3.1 */
2476 default: {
2477 double ret_date;
2478 DateInstance *di;
2480 hres = date_utc(ctx, argc, argv, &ret_date);
2481 if(FAILED(hres))
2482 return hres;
2484 hres = create_date(ctx, NULL, ret_date, &date);
2485 if(FAILED(hres))
2486 return hres;
2488 di = date_from_jsdisp(date);
2489 di->time = utc(di->time, di);
2493 *r = jsval_obj(date);
2494 return S_OK;
2496 case INVOKE_FUNC: {
2497 FILETIME system_time, local_time;
2498 LONGLONG lltime;
2500 GetSystemTimeAsFileTime(&system_time);
2501 FileTimeToLocalFileTime(&system_time, &local_time);
2502 lltime = ((LONGLONG)local_time.dwHighDateTime<<32)
2503 + local_time.dwLowDateTime;
2505 return date_to_string(lltime/10000-TIME_EPOCH, FALSE, 0, r);
2508 default:
2509 FIXME("unimplemented flags %x\n", flags);
2510 return E_NOTIMPL;
2513 return S_OK;
2516 static const builtin_prop_t DateConstr_props[] = {
2517 {UTCW, DateConstr_UTC, PROPF_METHOD},
2518 {nowW, DateConstr_now, PROPF_HTML|PROPF_METHOD},
2519 {parseW, DateConstr_parse, PROPF_METHOD}
2522 static const builtin_info_t DateConstr_info = {
2523 JSCLASS_FUNCTION,
2524 DEFAULT_FUNCTION_VALUE,
2525 ARRAY_SIZE(DateConstr_props),
2526 DateConstr_props,
2527 NULL,
2528 NULL
2531 HRESULT create_date_constr(script_ctx_t *ctx, jsdisp_t *object_prototype, jsdisp_t **ret)
2533 jsdisp_t *date;
2534 HRESULT hres;
2536 static const WCHAR DateW[] = {'D','a','t','e',0};
2538 hres = create_date(ctx, object_prototype, 0.0, &date);
2539 if(FAILED(hres))
2540 return hres;
2542 hres = create_builtin_constructor(ctx, DateConstr_value, DateW, &DateConstr_info,
2543 PROPF_CONSTR|7, date, ret);
2545 jsdisp_release(date);
2546 return hres;