date.c 68.4 KB
Newer Older
1 2
/*
 * Copyright 2008 Jacek Caban for CodeWeavers
3
 * Copyright 2009 Piotr Caban
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 */

20

21 22
#include <limits.h>
#include <math.h>
23
#include <assert.h>
24

25 26 27 28 29 30
#include "jscript.h"

#include "wine/debug.h"

WINE_DEFAULT_DEBUG_CHANNEL(jscript);

31 32 33
/* 1601 to 1970 is 369 years plus 89 leap days */
#define TIME_EPOCH  ((ULONGLONG)(369 * 365 + 89) * 86400 * 1000)

34
typedef struct {
35
    jsdisp_t dispex;
36 37 38

    /* ECMA-262 3rd Edition    15.9.1.1 */
    DOUBLE time;
39 40

    LONG bias;
41 42 43 44
    SYSTEMTIME standardDate;
    LONG standardBias;
    SYSTEMTIME daylightDate;
    LONG daylightBias;
45 46 47 48 49
} DateInstance;

static const WCHAR toStringW[] = {'t','o','S','t','r','i','n','g',0};
static const WCHAR toLocaleStringW[] = {'t','o','L','o','c','a','l','e','S','t','r','i','n','g',0};
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 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
static const WCHAR toDateStringW[] = {'t','o','D','a','t','e','S','t','r','i','n','g',0};
static const WCHAR toTimeStringW[] = {'t','o','T','i','m','e','S','t','r','i','n','g',0};
static const WCHAR toLocaleDateStringW[] = {'t','o','L','o','c','a','l','e','D','a','t','e','S','t','r','i','n','g',0};
static const WCHAR toLocaleTimeStringW[] = {'t','o','L','o','c','a','l','e','T','i','m','e','S','t','r','i','n','g',0};
static const WCHAR getTimeW[] = {'g','e','t','T','i','m','e',0};
static const WCHAR getFullYearW[] = {'g','e','t','F','u','l','l','Y','e','a','r',0};
static const WCHAR getUTCFullYearW[] = {'g','e','t','U','T','C','F','u','l','l','Y','e','a','r',0};
static const WCHAR getMonthW[] = {'g','e','t','M','o','n','t','h',0};
static const WCHAR getUTCMonthW[] = {'g','e','t','U','T','C','M','o','n','t','h',0};
static const WCHAR getDateW[] = {'g','e','t','D','a','t','e',0};
static const WCHAR getUTCDateW[] = {'g','e','t','U','T','C','D','a','t','e',0};
static const WCHAR getDayW[] = {'g','e','t','D','a','y',0};
static const WCHAR getUTCDayW[] = {'g','e','t','U','T','C','D','a','y',0};
static const WCHAR getHoursW[] = {'g','e','t','H','o','u','r','s',0};
static const WCHAR getUTCHoursW[] = {'g','e','t','U','T','C','H','o','u','r','s',0};
static const WCHAR getMinutesW[] = {'g','e','t','M','i','n','u','t','e','s',0};
static const WCHAR getUTCMinutesW[] = {'g','e','t','U','T','C','M','i','n','u','t','e','s',0};
static const WCHAR getSecondsW[] = {'g','e','t','S','e','c','o','n','d','s',0};
static const WCHAR getUTCSecondsW[] = {'g','e','t','U','T','C','S','e','c','o','n','d','s',0};
72 73
static const WCHAR getMillisecondsW[] = {'g','e','t','M','i','l','l','i','s','e','c','o','n','d','s',0};
static const WCHAR getUTCMillisecondsW[] = {'g','e','t','U','T','C','M','i','l','l','i','s','e','c','o','n','d','s',0};
74 75
static const WCHAR getTimezoneOffsetW[] = {'g','e','t','T','i','m','e','z','o','n','e','O','f','f','s','e','t',0};
static const WCHAR setTimeW[] = {'s','e','t','T','i','m','e',0};
76 77
static const WCHAR setMillisecondsW[] = {'s','e','t','M','i','l','l','i','s','e','c','o','n','d','s',0};
static const WCHAR setUTCMillisecondsW[] = {'s','e','t','U','T','C','M','i','l','l','i','s','e','c','o','n','d','s',0};
78 79 80 81 82
static const WCHAR setSecondsW[] = {'s','e','t','S','e','c','o','n','d','s',0};
static const WCHAR setUTCSecondsW[] = {'s','e','t','U','T','C','S','e','c','o','n','d','s',0};
static const WCHAR setMinutesW[] = {'s','e','t','M','i','n','u','t','e','s',0};
static const WCHAR setUTCMinutesW[] = {'s','e','t','U','T','C','M','i','n','u','t','e','s',0};
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 85 86 87 88 89
static const WCHAR setDateW[] = {'s','e','t','D','a','t','e',0};
static const WCHAR setUTCDateW[] = {'s','e','t','U','T','C','D','a','t','e',0};
static const WCHAR setMonthW[] = {'s','e','t','M','o','n','t','h',0};
static const WCHAR setUTCMonthW[] = {'s','e','t','U','T','C','M','o','n','t','h',0};
static const WCHAR setFullYearW[] = {'s','e','t','F','u','l','l','Y','e','a','r',0};
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};
92

93
static const WCHAR UTCW[] = {'U','T','C',0};
94
static const WCHAR nowW[] = {'n','o','w',0};
95 96
static const WCHAR parseW[] = {'p','a','r','s','e',0};

97 98 99 100 101
static inline DateInstance *date_from_jsdisp(jsdisp_t *jsdisp)
{
    return CONTAINING_RECORD(jsdisp, DateInstance, dispex);
}

102 103
static inline DateInstance *date_this(vdisp_t *jsthis)
{
104
    return is_vclass(jsthis, JSCLASS_DATE) ? date_from_jsdisp(jsthis->u.jsdisp) : NULL;
105 106
}

107
/*ECMA-262 3rd Edition    15.9.1.2 */
108
#define MS_PER_DAY 86400000
109
#define MS_PER_HOUR 3600000
110 111
#define MS_PER_MINUTE 60000

112
/* ECMA-262 3rd Edition    15.9.1.2 */
113 114 115 116 117
static inline DOUBLE day(DOUBLE time)
{
    return floor(time / MS_PER_DAY);
}

118 119 120 121 122 123 124 125 126 127 128 129
/* ECMA-262 3rd Edition    15.9.1.2 */
static inline DOUBLE time_within_day(DOUBLE time)
{
    DOUBLE ret;

    ret = fmod(time, MS_PER_DAY);
    if(ret < 0)
        ret += MS_PER_DAY;

    return ret;
}

130
/* ECMA-262 3rd Edition    15.9.1.3 */
131 132 133 134 135
static inline DOUBLE days_in_year(DOUBLE year)
{
    int y;

    if(year != (int)year)
136
        return NAN;
137 138 139 140 141 142 143 144

    y = year;
    if(y%4 != 0) return 365;
    if(y%100 != 0) return 366;
    if(y%400 != 0) return 365;
    return 366;
}

145
/* ECMA-262 3rd Edition    15.9.1.3 */
146 147 148
static inline DOUBLE day_from_year(DOUBLE year)
{
    if(year != (int)year)
149
        return NAN;
150

151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183
    return floor(365.0*(year-1970) + floor((year-1969)/4)
        - floor((year-1901)/100) + floor((year-1601)/400));
}

static inline int day_from_month(int month, int in_leap_year)
{
    switch(month)
    {
        case 0:
            return 0;
        case 1:
            return 31;
        case 2:
            return 59+in_leap_year;
        case 3:
            return 90+in_leap_year;
        case 4:
            return 120+in_leap_year;
        case 5:
            return 151+in_leap_year;
        case 6:
            return 181+in_leap_year;
        case 7:
            return 212+in_leap_year;
        case 8:
            return 243+in_leap_year;
        case 9:
            return 273+in_leap_year;
        case 10:
            return 304+in_leap_year;
        default:
            return 334+in_leap_year;
    }
184 185
}

186
/* ECMA-262 3rd Edition    15.9.1.3 */
187 188 189 190 191
static inline DOUBLE time_from_year(DOUBLE year)
{
    return MS_PER_DAY*day_from_year(year);
}

192
/* ECMA-262 3rd Edition    15.9.1.3 */
193 194 195 196 197
static inline DOUBLE year_from_time(DOUBLE time)
{
    int y;

    if(isnan(time))
198
        return NAN;
199 200 201 202 203 204 205 206 207 208 209

    y = 1970 + time/365.25/MS_PER_DAY;

    if(time_from_year(y) > time)
        while(time_from_year(y) > time) y--;
    else
        while(time_from_year(y+1)<=time) y++;

    return y;
}

210
/* ECMA-262 3rd Edition    15.9.1.3 */
211 212 213 214 215 216 217
static inline int in_leap_year(DOUBLE time)
{
    if(days_in_year(year_from_time(time))==366)
        return 1;
    return 0;
}

218
/* ECMA-262 3rd Edition    15.9.1.4 */
219 220 221 222 223
static inline int day_within_year(DOUBLE time)
{
    return day(time) - day_from_year(year_from_time(time));
}

224
/* ECMA-262 3rd Edition    15.9.1.4 */
225 226 227 228 229 230
static inline DOUBLE month_from_time(DOUBLE time)
{
    int ily = in_leap_year(time);
    int dwy = day_within_year(time);

    if(isnan(time))
231
        return NAN;
232 233 234 235 236 237 238 239 240 241 242 243 244 245 246

    if(0<=dwy && dwy<31) return 0;
    if(dwy < 59+ily) return 1;
    if(dwy < 90+ily) return 2;
    if(dwy < 120+ily) return 3;
    if(dwy < 151+ily) return 4;
    if(dwy < 181+ily) return 5;
    if(dwy < 212+ily) return 6;
    if(dwy < 243+ily) return 7;
    if(dwy < 273+ily) return 8;
    if(dwy < 304+ily) return  9;
    if(dwy < 334+ily) return  10;
    return  11;
}

247
/* ECMA-262 3rd Edition    15.9.1.5 */
248 249 250 251 252 253 254
static inline DOUBLE date_from_time(DOUBLE time)
{
    int dwy = day_within_year(time);
    int ily = in_leap_year(time);
    int mft = month_from_time(time);

    if(isnan(time))
255
        return NAN;
256 257 258 259 260 261 262 263 264 265 266 267 268 269 270

    if(mft==0) return dwy+1;
    if(mft==1) return dwy-30;
    if(mft==2) return dwy-58-ily;
    if(mft==3) return dwy-89-ily;
    if(mft==4) return dwy-119-ily;
    if(mft==5) return dwy-150-ily;
    if(mft==6) return dwy-180-ily;
    if(mft==7) return dwy-211-ily;
    if(mft==8) return dwy-242-ily;
    if(mft==9) return dwy-272-ily;
    if(mft==10) return dwy-303-ily;
    return dwy-333-ily;
}

271
/* ECMA-262 3rd Edition    15.9.1.6 */
272 273
static inline DOUBLE week_day(DOUBLE time)
{
274 275
    DOUBLE ret;

276
    if(isnan(time))
277
        return NAN;
278

279 280 281 282
    ret = fmod(day(time)+4, 7);
    if(ret<0) ret += 7;

    return ret;
283 284
}

285 286 287 288 289 290
static inline DOUBLE convert_time(int year, SYSTEMTIME st)
{
    DOUBLE time;
    int set_week_day;

    if(st.wMonth == 0)
291
        return NAN;
292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345

    if(st.wYear != 0)
        year = st.wYear;

    time = time_from_year(year);
    time += (DOUBLE)day_from_month(st.wMonth-1, in_leap_year(time)) * MS_PER_DAY;

    if(st.wYear == 0) {
        set_week_day = st.wDayOfWeek-week_day(time);
        if(set_week_day < 0)
            set_week_day += 7;
        time += set_week_day * MS_PER_DAY;

        time += (DOUBLE)(st.wDay-1) * 7 * MS_PER_DAY;
        if(month_from_time(time) != st.wMonth-1)
            time -= 7 * MS_PER_DAY;
    }
    else
        time += st.wDay * MS_PER_DAY;

    time += st.wHour * MS_PER_HOUR;
    time += st.wMinute * MS_PER_MINUTE;

    return time;
}

/* ECMA-262 3rd Edition    15.9.1.9 */
static inline DOUBLE daylight_saving_ta(DOUBLE time, DateInstance *date)
{
    int year = year_from_time(time);
    DOUBLE standardTime, daylightTime;

    if(isnan(time))
        return 0;

    standardTime = convert_time(year, date->standardDate);
    daylightTime = convert_time(year, date->daylightDate);

    if(isnan(standardTime) || isnan(daylightTime))
        return 0;
    else if(standardTime > daylightTime) {
        if(daylightTime <= time && time < standardTime)
            return date->daylightBias;

        return date->standardBias;
    }
    else {
        if(standardTime <= time && time < daylightTime)
            return date->standardBias;

        return date->daylightBias;
    }
}

346 347 348 349 350 351
/* ECMA-262 3rd Edition    15.9.1.9 */
static inline DOUBLE local_time(DOUBLE time, DateInstance *date)
{
    return time - (daylight_saving_ta(time, date)+date->bias)*MS_PER_MINUTE;
}

352 353 354 355 356 357 358
/* ECMA-262 3rd Edition    15.9.1.9 */
static inline DOUBLE utc(DOUBLE time, DateInstance *date)
{
    time += date->bias * MS_PER_MINUTE;
    return time + daylight_saving_ta(time, date)*MS_PER_MINUTE;
}

359
/* ECMA-262 3rd Edition    15.9.1.10 */
360 361
static inline DOUBLE hour_from_time(DOUBLE time)
{
362 363
    DOUBLE ret;

364
    if(isnan(time))
365
        return NAN;
366

367 368 369 370
    ret = fmod(floor(time/MS_PER_HOUR), 24);
    if(ret<0) ret += 24;

    return ret;
371 372
}

373
/* ECMA-262 3rd Edition    15.9.1.10 */
374 375 376 377 378
static inline DOUBLE min_from_time(DOUBLE time)
{
    DOUBLE ret;

    if(isnan(time))
379
        return NAN;
380 381 382 383 384 385 386

    ret = fmod(floor(time/MS_PER_MINUTE), 60);
    if(ret<0) ret += 60;

    return ret;
}

387
/* ECMA-262 3rd Edition    15.9.1.10 */
388 389 390 391 392
static inline DOUBLE sec_from_time(DOUBLE time)
{
    DOUBLE ret;

    if(isnan(time))
393
        return NAN;
394 395 396 397 398 399 400

    ret = fmod(floor(time/1000), 60);
    if(ret<0) ret += 60;

    return ret;
}

401
/* ECMA-262 3rd Edition    15.9.1.10 */
402 403 404 405 406
static inline DOUBLE ms_from_time(DOUBLE time)
{
    DOUBLE ret;

    if(isnan(time))
407
        return NAN;
408 409 410 411 412 413 414

    ret = fmod(time, 1000);
    if(ret<0) ret += 1000;

    return ret;
}

415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444
/* ECMA-262 3rd Edition    15.9.1.11 */
static inline DOUBLE make_time(DOUBLE hour, DOUBLE min, DOUBLE sec, DOUBLE ms)
{
    return hour*MS_PER_HOUR + min*MS_PER_MINUTE + sec*1000 + ms;
}

/* ECMA-262 3rd Edition    15.9.1.12 */
static inline DOUBLE make_day(DOUBLE year, DOUBLE month, DOUBLE day)
{
    DOUBLE time;

    year += floor(month/12);

    month = fmod(month, 12);
    if(month<0) month += 12;

    time = time_from_year(year);

    day += floor(time / MS_PER_DAY);
    day += day_from_month(month, in_leap_year(time));

    return day-1;
}

/* ECMA-262 3rd Edition    15.9.1.13 */
static inline DOUBLE make_date(DOUBLE day, DOUBLE time)
{
    return day*MS_PER_DAY + time;
}

445 446
/* ECMA-262 3rd Edition    15.9.1.14 */
static inline DOUBLE time_clip(DOUBLE time)
447
{
448
    if(8.64e15 < time || time < -8.64e15) {
449
        return NAN;
450 451 452
    }

    return floor(time);
453 454
}

455 456 457 458 459 460 461 462 463 464 465
static double date_now(void)
{
    FILETIME ftime;
    LONGLONG time;

    GetSystemTimeAsFileTime(&ftime);
    time = ((LONGLONG)ftime.dwHighDateTime << 32) + ftime.dwLowDateTime;

    return time/10000 - TIME_EPOCH;
}

466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481
static SYSTEMTIME create_systemtime(DOUBLE time)
{
    SYSTEMTIME st;

    st.wYear = year_from_time(time);
    st.wMonth = month_from_time(time) + 1;
    st.wDayOfWeek = week_day(time);
    st.wDay = date_from_time(time);
    st.wHour = hour_from_time(time);
    st.wMinute = min_from_time(time);
    st.wSecond = sec_from_time(time);
    st.wMilliseconds = ms_from_time(time);

    return st;
}

482
static inline HRESULT date_to_string(DOUBLE time, BOOL show_offset, int offset, jsval_t *r)
483
{
484 485 486 487 488 489
    static const WCHAR formatW[] = { '%','s',' ','%','s',' ','%','d',' ',
        '%','0','2','d',':','%','0','2','d',':','%','0','2','d',' ',
        'U','T','C','%','c','%','0','2','d','%','0','2','d',' ','%','d','%','s',0 };
    static const WCHAR formatUTCW[] = { '%','s',' ','%','s',' ','%','d',' ',
        '%','0','2','d',':','%','0','2','d',':','%','0','2','d',' ',
        'U','T','C',' ','%','d','%','s',0 };
490 491 492
    static const WCHAR formatNoOffsetW[] = { '%','s',' ','%','s',' ',
        '%','d',' ','%','0','2','d',':','%','0','2','d',':',
        '%','0','2','d',' ','%','d','%','s',0 };
493 494 495 496 497 498 499 500 501 502 503 504 505 506
    static const WCHAR ADW[] = { 0 };
    static const WCHAR BCW[] = { ' ','B','.','C','.',0 };

    static const DWORD week_ids[] = { LOCALE_SABBREVDAYNAME7, LOCALE_SABBREVDAYNAME1,
        LOCALE_SABBREVDAYNAME2, LOCALE_SABBREVDAYNAME3, LOCALE_SABBREVDAYNAME4,
        LOCALE_SABBREVDAYNAME5, LOCALE_SABBREVDAYNAME6 };
    static const DWORD month_ids[] = { LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2,
        LOCALE_SABBREVMONTHNAME3, LOCALE_SABBREVMONTHNAME4,
        LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6,
        LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8,
        LOCALE_SABBREVMONTHNAME9, LOCALE_SABBREVMONTHNAME10,
        LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12 };

    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 513
    WCHAR sign = '-';

514
    if(isnan(time)) {
515 516
        if(r)
            *r = jsval_string(jsstr_nan());
517 518 519
        return S_OK;
    }

520
    if(r) {
521 522
        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));
525

526
        month[0] = 0;
527
        GetLocaleInfoW(lcid_en, month_ids[(int)month_from_time(time)], month, ARRAY_SIZE(month));
528 529 530 531 532 533 534 535 536

        year = year_from_time(time);
        if(year<0) {
            formatAD = FALSE;
            year = -year+1;
        }

        day = date_from_time(time);

537
        if(offset < 0) {
538 539 540 541
            sign = '+';
            offset = -offset;
        }

542
        if(!show_offset)
543
            swprintf(buf, ARRAY_SIZE(buf), formatNoOffsetW, week, month, day,
544 545 546
                    (int)hour_from_time(time), (int)min_from_time(time),
                    (int)sec_from_time(time), year, formatAD?ADW:BCW);
        else if(offset)
547
            swprintf(buf, ARRAY_SIZE(buf), formatW, week, month, day,
548 549 550 551
                    (int)hour_from_time(time), (int)min_from_time(time),
                    (int)sec_from_time(time), sign, offset/60, offset%60,
                    year, formatAD?ADW:BCW);
        else
552
            swprintf(buf, ARRAY_SIZE(buf), formatUTCW, week, month, day,
553 554
                    (int)hour_from_time(time), (int)min_from_time(time),
                    (int)sec_from_time(time), year, formatAD?ADW:BCW);
555

556 557 558 559
        date_jsstr = jsstr_alloc(buf);
        if(!date_jsstr)
            return E_OUTOFMEMORY;

560
        *r = jsval_string(date_jsstr);
561 562
    }
    return S_OK;
563 564
}

565
/* ECMA-262 3rd Edition    15.9.1.2 */
566
static HRESULT dateobj_to_string(DateInstance *date, jsval_t *r)
567 568 569 570 571 572 573 574
{
    DOUBLE time;
    int offset;

    time = local_time(date->time, date);
    offset = date->bias +
        daylight_saving_ta(time, date);

575
    return date_to_string(time, TRUE, offset, r);
576 577
}

578
static HRESULT Date_toString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
579
{
580 581
    DateInstance *date;

582 583
    TRACE("\n");

584
    if(!(date = date_this(jsthis)))
585
        return JS_E_DATE_EXPECTED;
586

587
    return dateobj_to_string(date, r);
588 589
}

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)
593
{
594 595
    SYSTEMTIME st;
    DateInstance *date;
596
    jsstr_t *date_str;
597 598 599 600
    int date_len, time_len;

    TRACE("\n");

601
    if(!(date = date_this(jsthis)))
602
        return JS_E_DATE_EXPECTED;
603 604

    if(isnan(date->time)) {
605 606
        if(r)
            *r = jsval_string(jsstr_nan());
607 608 609 610 611 612
        return S_OK;
    }

    st = create_systemtime(local_time(date->time, date));

    if(st.wYear<1601 || st.wYear>9999)
613
        return dateobj_to_string(date, r);
614

615
    if(r) {
616 617
        WCHAR *ptr;

618 619
        date_len = GetDateFormatW(ctx->lcid, DATE_LONGDATE, &st, NULL, NULL, 0);
        time_len = GetTimeFormatW(ctx->lcid, 0, &st, NULL, NULL, 0);
620

621
        date_str = jsstr_alloc_buf(date_len+time_len-1, &ptr);
622 623
        if(!date_str)
            return E_OUTOFMEMORY;
624 625 626 627

        GetDateFormatW(ctx->lcid, DATE_LONGDATE, &st, NULL, ptr, date_len);
        GetTimeFormatW(ctx->lcid, 0, &st, NULL, ptr+date_len, time_len);
        ptr[date_len-1] = ' ';
628

629
        *r = jsval_string(date_str);
630 631
    }
    return S_OK;
632 633
}

634 635 636 637 638 639 640 641 642 643 644 645 646 647 648
static HRESULT Date_toISOString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
        jsval_t *r)
{
    DateInstance *date;
    WCHAR buf[64], *p = buf;
    double year;

    static const WCHAR short_year_formatW[] = {'%','0','4','d',0};
    static const WCHAR long_year_formatW[] = {'%','0','6','d',0};
    static const WCHAR formatW[] = {'-','%','0','2','d','-','%','0','2','d',
        'T','%','0','2','d',':','%','0','2','d',':','%','0','2','d','.','%','0','3','d','Z',0};

    TRACE("\n");

    if(!(date = date_this(jsthis)))
649
        return JS_E_DATE_EXPECTED;
650 651 652 653 654 655 656 657 658

    year = year_from_time(date->time);
    if(isnan(year) || year > 999999 || year < -999999) {
        FIXME("year %lf should throw an exception\n", year);
        return E_FAIL;
    }

    if(year < 0) {
        *p++ = '-';
659
        p += swprintf(p, ARRAY_SIZE(buf) - 1, long_year_formatW, -(int)year);
660 661
    }else if(year > 9999) {
        *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);
665 666
    }

667 668
    swprintf(p, ARRAY_SIZE(buf) - (p - buf), formatW,
             (int)month_from_time(date->time) + 1, (int)date_from_time(date->time),
669 670 671 672 673 674 675 676 677 678 679 680
             (int)hour_from_time(date->time), (int)min_from_time(date->time),
             (int)sec_from_time(date->time), (int)ms_from_time(date->time));

    if(r) {
        jsstr_t *ret;
        if(!(ret = jsstr_alloc(buf)))
            return E_OUTOFMEMORY;
        *r = jsval_string(ret);
    }
    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)
683
{
684 685
    DateInstance *date;

686 687
    TRACE("\n");

688
    if(!(date = date_this(jsthis)))
689
        return JS_E_DATE_EXPECTED;
690

691 692
    if(r)
        *r = jsval_number(date->time);
693
    return S_OK;
694 695
}

696
static inline HRESULT create_utc_string(script_ctx_t *ctx, vdisp_t *jsthis, jsval_t *r)
697
{
698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713
    static const WCHAR formatADW[] = { '%','s',',',' ','%','d',' ','%','s',' ','%','d',' ',
        '%','0','2','d',':','%','0','2','d',':','%','0','2','d',' ','U','T','C',0 };
    static const WCHAR formatBCW[] = { '%','s',',',' ','%','d',' ','%','s',' ','%','d',' ','B','.','C','.',' ',
        '%','0','2','d',':','%','0','2','d',':','%','0','2','d',' ','U','T','C',0 };

    static const DWORD week_ids[] = { LOCALE_SABBREVDAYNAME7, LOCALE_SABBREVDAYNAME1,
        LOCALE_SABBREVDAYNAME2, LOCALE_SABBREVDAYNAME3, LOCALE_SABBREVDAYNAME4,
        LOCALE_SABBREVDAYNAME5, LOCALE_SABBREVDAYNAME6 };
    static const DWORD month_ids[] = { LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2,
        LOCALE_SABBREVMONTHNAME3, LOCALE_SABBREVMONTHNAME4,
        LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6,
        LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8,
        LOCALE_SABBREVMONTHNAME9, LOCALE_SABBREVMONTHNAME10,
        LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12 };

    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;
720

721
    if(!(date = date_this(jsthis)))
722
        return JS_E_DATE_EXPECTED;
723 724

    if(isnan(date->time)) {
725 726
        if(r)
            *r = jsval_string(jsstr_nan());
727 728 729
        return S_OK;
    }

730
    if(r) {
731 732
        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));
735

736
        month[0] = 0;
737
        GetLocaleInfoW(lcid_en, month_ids[(int)month_from_time(date->time)], month, ARRAY_SIZE(month));
738 739 740 741 742 743 744

        year = year_from_time(date->time);
        if(year<0) {
            formatAD = FALSE;
            year = -year+1;
        }

745
        day = date_from_time(date->time);
746

747
        swprintf(buf, ARRAY_SIZE(buf), formatAD ? formatADW : formatBCW, week, day, month, year,
748 749 750
                (int)hour_from_time(date->time), (int)min_from_time(date->time),
                (int)sec_from_time(date->time));

751 752 753 754
        date_str = jsstr_alloc(buf);
        if(!date_str)
            return E_OUTOFMEMORY;

755
        *r = jsval_string(date_str);
756 757
    }
    return S_OK;
758 759
}

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)
763 764
{
    TRACE("\n");
765
    return create_utc_string(ctx, jsthis, r);
766 767
}

768
static HRESULT Date_toGMTString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
769
        jsval_t *r)
770
{
771
    TRACE("\n");
772
    return create_utc_string(ctx, jsthis, r);
773 774
}

775
/* ECMA-262 3rd Edition    15.9.5.3 */
776
static HRESULT dateobj_to_date_string(DateInstance *date, jsval_t *r)
777
{
778 779 780 781 782 783 784 785 786 787 788 789 790 791
    static const WCHAR formatADW[] = { '%','s',' ','%','s',' ','%','d',' ','%','d',0 };
    static const WCHAR formatBCW[] = { '%','s',' ','%','s',' ','%','d',' ','%','d',' ','B','.','C','.',0 };

    static const DWORD week_ids[] = { LOCALE_SABBREVDAYNAME7, LOCALE_SABBREVDAYNAME1,
        LOCALE_SABBREVDAYNAME2, LOCALE_SABBREVDAYNAME3, LOCALE_SABBREVDAYNAME4,
        LOCALE_SABBREVDAYNAME5, LOCALE_SABBREVDAYNAME6 };
    static const DWORD month_ids[] = { LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2,
        LOCALE_SABBREVMONTHNAME3, LOCALE_SABBREVMONTHNAME4,
        LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6,
        LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8,
        LOCALE_SABBREVMONTHNAME9, LOCALE_SABBREVMONTHNAME10,
        LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12 };

    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;
798 799

    if(isnan(date->time)) {
800 801
        if(r)
            *r = jsval_string(jsstr_nan());
802 803 804 805 806
        return S_OK;
    }

    time = local_time(date->time, date);

807
    if(r) {
808 809
        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));
812

813
        month[0] = 0;
814
        GetLocaleInfoW(lcid_en, month_ids[(int)month_from_time(time)], month, ARRAY_SIZE(month));
815 816 817 818 819 820 821 822 823

        year = year_from_time(time);
        if(year<0) {
            formatAD = FALSE;
            year = -year+1;
        }

        day = date_from_time(time);

824
        swprintf(buf, ARRAY_SIZE(buf), formatAD ? formatADW : formatBCW, week, month, day, year);
825 826

        date_str = jsstr_alloc(buf);
827
        if(!date_str)
828 829
            return E_OUTOFMEMORY;

830
        *r = jsval_string(date_str);
831 832
    }
    return S_OK;
833 834
}

835
static HRESULT Date_toDateString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
836
        jsval_t *r)
837
{
838 839 840
    DateInstance *date;

    if(!(date = date_this(jsthis)))
841
        return JS_E_DATE_EXPECTED;
842

843
    return dateobj_to_date_string(date, r);
844 845
}

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)
849
{
850 851 852 853 854
    static const WCHAR formatW[] = { '%','0','2','d',':','%','0','2','d',':','%','0','2','d',
        ' ','U','T','C','%','c','%','0','2','d','%','0','2','d',0 };
    static const WCHAR formatUTCW[] = { '%','0','2','d',':','%','0','2','d',
        ':','%','0','2','d',' ','U','T','C',0 };
    DateInstance *date;
855
    jsstr_t *date_str;
856
    WCHAR buf[32];
857 858 859 860 861 862
    DOUBLE time;
    WCHAR sign;
    int offset;

    TRACE("\n");

863
    if(!(date = date_this(jsthis)))
864
        return JS_E_DATE_EXPECTED;
865 866

    if(isnan(date->time)) {
867 868 869
        if(r)
            *r = jsval_string(jsstr_nan());
        return S_OK;
870 871 872 873
    }

    time = local_time(date->time, date);

874
    if(r) {
875 876 877 878 879 880 881 882 883 884
        offset = date->bias +
            daylight_saving_ta(time, date);

        if(offset < 0) {
            sign = '+';
            offset = -offset;
        }
        else sign = '-';

        if(offset)
885
            swprintf(buf, ARRAY_SIZE(buf), formatW, (int)hour_from_time(time),
886 887 888
                    (int)min_from_time(time), (int)sec_from_time(time),
                    sign, offset/60, offset%60);
        else
889
            swprintf(buf, ARRAY_SIZE(buf), formatUTCW, (int)hour_from_time(time),
890 891
                    (int)min_from_time(time), (int)sec_from_time(time));

892 893 894 895
        date_str = jsstr_alloc(buf);
        if(!date_str)
            return E_OUTOFMEMORY;

896
        *r = jsval_string(date_str);
897 898
    }
    return S_OK;
899 900
}

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)
904
{
905 906
    SYSTEMTIME st;
    DateInstance *date;
907
    jsstr_t *date_str;
908 909 910 911
    int len;

    TRACE("\n");

912
    if(!(date = date_this(jsthis)))
913
        return JS_E_DATE_EXPECTED;
914 915

    if(isnan(date->time)) {
916 917
        if(r)
            *r = jsval_string(jsstr_nan());
918 919 920 921 922 923
        return S_OK;
    }

    st = create_systemtime(local_time(date->time, date));

    if(st.wYear<1601 || st.wYear>9999)
924
        return dateobj_to_date_string(date, r);
925

926
    if(r) {
927 928
        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);
934

935
        *r = jsval_string(date_str);
936 937
    }
    return S_OK;
938 939
}

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)
943
{
944 945
    SYSTEMTIME st;
    DateInstance *date;
946
    jsstr_t *date_str;
947 948 949 950
    int len;

    TRACE("\n");

951
    if(!(date = date_this(jsthis)))
952
        return JS_E_DATE_EXPECTED;
953 954

    if(isnan(date->time)) {
955 956
        if(r)
            *r = jsval_string(jsstr_nan());
957 958 959 960 961 962
        return S_OK;
    }

    st = create_systemtime(local_time(date->time, date));

    if(st.wYear<1601 || st.wYear>9999)
963
        return Date_toTimeString(ctx, jsthis, flags, argc, argv, r);
964

965
    if(r) {
966 967
        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);
973

974
        *r = jsval_string(date_str);
975 976
    }
    return S_OK;
977 978
}

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)
982
{
983 984
    DateInstance *date;

985 986
    TRACE("\n");

987
    if(!(date = date_this(jsthis)))
988
        return JS_E_DATE_EXPECTED;
989

990 991
    if(r)
        *r = jsval_number(date->time);
992
    return S_OK;
993 994
}

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)
998
{
999 1000
    DateInstance *date;

1001 1002
    TRACE("\n");

1003
    if(!(date = date_this(jsthis)))
1004
        return JS_E_DATE_EXPECTED;
1005

1006
    if(r) {
1007
        DOUBLE time = local_time(date->time, date);
1008

1009
        *r = jsval_number(year_from_time(time));
1010 1011
    }
    return S_OK;
1012 1013
}

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)
1017
{
1018 1019
    DateInstance *date;

1020 1021
    TRACE("\n");

1022
    if(!(date = date_this(jsthis)))
1023
        return JS_E_DATE_EXPECTED;
1024

1025 1026
    if(r)
        *r = jsval_number(year_from_time(date->time));
1027
    return S_OK;
1028 1029
}

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)
1032
{
1033 1034
    DateInstance *date;

1035 1036
    TRACE("\n");

1037
    if(!(date = date_this(jsthis)))
1038
        return JS_E_DATE_EXPECTED;
1039

1040 1041
    if(r)
        *r = jsval_number(month_from_time(local_time(date->time, date)));
1042
    return S_OK;
1043 1044
}

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)
1048
{
1049 1050
    DateInstance *date;

1051 1052
    TRACE("\n");

1053
    if(!(date = date_this(jsthis)))
1054
        return JS_E_DATE_EXPECTED;
1055

1056 1057
    if(r)
        *r = jsval_number(month_from_time(date->time));
1058
    return S_OK;
1059 1060
}

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)
1063
{
1064 1065
    DateInstance *date;

1066 1067
    TRACE("\n");

1068
    if(!(date = date_this(jsthis)))
1069
        return JS_E_DATE_EXPECTED;
1070

1071 1072
    if(r)
        *r = jsval_number(date_from_time(local_time(date->time, date)));
1073
    return S_OK;
1074 1075
}

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)
1079
{
1080 1081
    DateInstance *date;

1082 1083
    TRACE("\n");

1084
    if(!(date = date_this(jsthis)))
1085
        return JS_E_DATE_EXPECTED;
1086

1087 1088
    if(r)
        *r = jsval_number(date_from_time(date->time));
1089
    return S_OK;
1090 1091
}

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)
1095
{
1096 1097
    DateInstance *date;

1098 1099
    TRACE("\n");

1100
    if(!(date = date_this(jsthis)))
1101
        return JS_E_DATE_EXPECTED;
1102

1103 1104
    if(r)
        *r = jsval_number(week_day(local_time(date->time, date)));
1105
    return S_OK;
1106 1107
}

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)
1111
{
1112 1113
    DateInstance *date;

1114 1115
    TRACE("\n");

1116
    if(!(date = date_this(jsthis)))
1117
        return JS_E_DATE_EXPECTED;
1118

1119 1120
    if(r)
        *r = jsval_number(week_day(date->time));
1121
    return S_OK;
1122 1123
}

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)
1127
{
1128 1129
    DateInstance *date;

1130 1131
    TRACE("\n");

1132
    if(!(date = date_this(jsthis)))
1133
        return JS_E_DATE_EXPECTED;
1134

1135 1136
    if(r)
        *r = jsval_number(hour_from_time(local_time(date->time, date)));
1137
    return S_OK;
1138 1139
}

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)
1143
{
1144 1145
    DateInstance *date;

1146 1147
    TRACE("\n");

1148
    if(!(date = date_this(jsthis)))
1149
        return JS_E_DATE_EXPECTED;
1150

1151 1152
    if(r)
        *r = jsval_number(hour_from_time(date->time));
1153
    return S_OK;
1154 1155
}

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)
1159
{
1160 1161
    DateInstance *date;

1162 1163
    TRACE("\n");

1164
    if(!(date = date_this(jsthis)))
1165
        return JS_E_DATE_EXPECTED;
1166

1167 1168
    if(r)
        *r = jsval_number(min_from_time(local_time(date->time, date)));
1169
    return S_OK;
1170 1171
}

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)
1175
{
1176 1177
    DateInstance *date;

1178 1179
    TRACE("\n");

1180
    if(!(date = date_this(jsthis)))
1181
        return JS_E_DATE_EXPECTED;
1182

1183 1184
    if(r)
        *r = jsval_number(min_from_time(date->time));
1185
    return S_OK;
1186 1187
}

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)
1190
{
1191 1192
    DateInstance *date;

1193 1194
    TRACE("\n");

1195
    if(!(date = date_this(jsthis)))
1196
        return JS_E_DATE_EXPECTED;
1197

1198 1199
    if(r)
        *r = jsval_number(sec_from_time(local_time(date->time, date)));
1200
    return S_OK;
1201 1202
}

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)
1206
{
1207 1208
    DateInstance *date;

1209 1210
    TRACE("\n");

1211
    if(!(date = date_this(jsthis)))
1212
        return JS_E_DATE_EXPECTED;
1213

1214 1215
    if(r)
        *r = jsval_number(sec_from_time(date->time));
1216
    return S_OK;
1217 1218
}

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)
1222
{
1223 1224
    DateInstance *date;

1225 1226
    TRACE("\n");

1227
    if(!(date = date_this(jsthis)))
1228
        return JS_E_DATE_EXPECTED;
1229

1230 1231
    if(r)
        *r = jsval_number(ms_from_time(local_time(date->time, date)));
1232
    return S_OK;
1233 1234
}

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)
1238
{
1239 1240
    DateInstance *date;

1241 1242
    TRACE("\n");

1243
    if(!(date = date_this(jsthis)))
1244
        return JS_E_DATE_EXPECTED;
1245

1246 1247
    if(r)
        *r = jsval_number(ms_from_time(date->time));
1248
    return S_OK;
1249 1250
}

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)
1254
{
1255 1256
    DateInstance *date;

1257 1258
    TRACE("\n");

1259
    if(!(date = date_this(jsthis)))
1260
        return JS_E_DATE_EXPECTED;
1261

1262 1263
    if(r)
        *r = jsval_number(floor((date->time-local_time(date->time, date))/MS_PER_MINUTE));
1264
    return S_OK;
1265 1266
}

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)
1270
{
1271
    double n;
1272 1273 1274 1275 1276
    HRESULT hres;
    DateInstance *date;

    TRACE("\n");

1277
    if(!(date = date_this(jsthis)))
1278
        return JS_E_DATE_EXPECTED;
1279

1280
    if(!argc)
1281
        return JS_E_MISSING_ARG;
1282

1283
    hres = to_number(ctx, argv[0], &n);
1284 1285 1286
    if(FAILED(hres))
        return hres;

1287
    date->time = time_clip(n);
1288

1289 1290
    if(r)
        *r = jsval_number(date->time);
1291
    return S_OK;
1292 1293
}

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)
1297
{
1298
    DateInstance *date;
1299 1300
    double n, t;
    HRESULT hres;
1301 1302 1303

    TRACE("\n");

1304
    if(!(date = date_this(jsthis)))
1305
        return JS_E_DATE_EXPECTED;
1306

1307
    if(!argc)
1308
        return JS_E_MISSING_ARG;
1309

1310
    hres = to_number(ctx, argv[0], &n);
1311 1312 1313
    if(FAILED(hres))
        return hres;

1314 1315
    t = local_time(date->time, date);
    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));
1318

1319 1320
    if(r)
        *r = jsval_number(date->time);
1321
    return S_OK;
1322 1323
}

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)
1327
{
1328
    DateInstance *date;
1329 1330
    double n, t;
    HRESULT hres;
1331 1332 1333

    TRACE("\n");

1334
    if(!(date = date_this(jsthis)))
1335
        return JS_E_DATE_EXPECTED;
1336

1337
    if(!argc)
1338
        return JS_E_MISSING_ARG;
1339

1340
    hres = to_number(ctx, argv[0], &n);
1341 1342 1343 1344 1345
    if(FAILED(hres))
        return hres;

    t = date->time;
    t = make_date(day(t), make_time(hour_from_time(t), min_from_time(t),
1346
                sec_from_time(t), n));
1347 1348
    date->time = time_clip(t);

1349 1350
    if(r)
        *r = jsval_number(date->time);
1351
    return S_OK;
1352 1353
}

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)
1357
{
1358
    DateInstance *date;
1359 1360
    double t, sec, ms;
    HRESULT hres;
1361 1362 1363

    TRACE("\n");

1364
    if(!(date = date_this(jsthis)))
1365
        return JS_E_DATE_EXPECTED;
1366

1367
    if(!argc)
1368
        return JS_E_MISSING_ARG;
1369

1370 1371
    t = local_time(date->time, date);

1372
    hres = to_number(ctx, argv[0], &sec);
1373 1374 1375
    if(FAILED(hres))
        return hres;

1376
    if(argc > 1) {
1377
        hres = to_number(ctx, argv[1], &ms);
1378 1379
        if(FAILED(hres))
            return hres;
1380 1381
    }else {
        ms = ms_from_time(t);
1382 1383 1384 1385 1386
    }

    t = make_date(day(t), make_time(hour_from_time(t),
                min_from_time(t), sec, ms));
    date->time = time_clip(utc(t, date));
1387

1388 1389
    if(r)
        *r = jsval_number(date->time);
1390
    return S_OK;
1391 1392
}

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)
1396
{
1397
    DateInstance *date;
1398 1399
    double t, sec, ms;
    HRESULT hres;
1400 1401 1402

    TRACE("\n");

1403
    if(!(date = date_this(jsthis)))
1404
        return JS_E_DATE_EXPECTED;
1405

1406
    if(!argc)
1407
        return JS_E_MISSING_ARG;
1408 1409 1410

    t = date->time;

1411
    hres = to_number(ctx, argv[0], &sec);
1412 1413 1414
    if(FAILED(hres))
        return hres;

1415
    if(argc > 1) {
1416
        hres = to_number(ctx, argv[1], &ms);
1417 1418
        if(FAILED(hres))
            return hres;
1419 1420
    }else {
        ms = ms_from_time(t);
1421 1422 1423 1424 1425 1426
    }

    t = make_date(day(t), make_time(hour_from_time(t),
                min_from_time(t), sec, ms));
    date->time = time_clip(t);

1427 1428
    if(r)
        *r = jsval_number(date->time);
1429
    return S_OK;
1430 1431
}

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)
1435
{
1436
    DateInstance *date;
1437 1438
    double t, min, sec, ms;
    HRESULT hres;
1439 1440 1441

    TRACE("\n");

1442
    if(!(date = date_this(jsthis)))
1443
        return JS_E_DATE_EXPECTED;
1444

1445
    if(!argc)
1446
        return JS_E_MISSING_ARG;
1447

1448 1449
    t = local_time(date->time, date);

1450
    hres = to_number(ctx, argv[0], &min);
1451 1452 1453
    if(FAILED(hres))
        return hres;

1454
    if(argc > 1) {
1455
        hres = to_number(ctx, argv[1], &sec);
1456 1457
        if(FAILED(hres))
            return hres;
1458 1459
    }else {
        sec = sec_from_time(t);
1460 1461
    }

1462
    if(argc > 2) {
1463
        hres = to_number(ctx, argv[2], &ms);
1464 1465
        if(FAILED(hres))
            return hres;
1466 1467
    }else {
        ms = ms_from_time(t);
1468 1469 1470 1471 1472
    }

    t = make_date(day(t), make_time(hour_from_time(t),
                min, sec, ms));
    date->time = time_clip(utc(t, date));
1473

1474 1475
    if(r)
        *r = jsval_number(date->time);
1476
    return S_OK;
1477 1478
}

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)
1482
{
1483
    DateInstance *date;
1484 1485
    double t, min, sec, ms;
    HRESULT hres;
1486 1487 1488

    TRACE("\n");

1489
    if(!(date = date_this(jsthis)))
1490
        return JS_E_DATE_EXPECTED;
1491

1492
    if(!argc)
1493
        return JS_E_MISSING_ARG;
1494 1495 1496

    t = date->time;

1497
    hres = to_number(ctx, argv[0], &min);
1498 1499 1500
    if(FAILED(hres))
        return hres;

1501
    if(argc > 1) {
1502
        hres = to_number(ctx, argv[1], &sec);
1503 1504
        if(FAILED(hres))
            return hres;
1505 1506
    }else {
        sec = sec_from_time(t);
1507 1508
    }

1509
    if(argc > 2) {
1510
        hres = to_number(ctx, argv[2], &ms);
1511 1512
        if(FAILED(hres))
            return hres;
1513 1514
    }else {
        ms = ms_from_time(t);
1515 1516 1517 1518 1519 1520
    }

    t = make_date(day(t), make_time(hour_from_time(t),
                min, sec, ms));
    date->time = time_clip(t);

1521 1522
    if(r)
        *r = jsval_number(date->time);
1523
    return S_OK;
1524 1525
}

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)
1529
{
1530
    DateInstance *date;
1531 1532
    double t, hour, min, sec, ms;
    HRESULT hres;
1533 1534 1535

    TRACE("\n");

1536
    if(!(date = date_this(jsthis)))
1537
        return JS_E_DATE_EXPECTED;
1538

1539
    if(!argc)
1540
        return JS_E_MISSING_ARG;
1541

1542 1543
    t = local_time(date->time, date);

1544
    hres = to_number(ctx, argv[0], &hour);
1545 1546 1547
    if(FAILED(hres))
        return hres;

1548
    if(argc > 1) {
1549
        hres = to_number(ctx, argv[1], &min);
1550 1551
        if(FAILED(hres))
            return hres;
1552 1553
    }else {
        min = min_from_time(t);
1554 1555
    }

1556
    if(argc > 2) {
1557
        hres = to_number(ctx, argv[2], &sec);
1558 1559
        if(FAILED(hres))
            return hres;
1560 1561
    }else {
        sec = sec_from_time(t);
1562 1563
    }

1564
    if(argc > 3) {
1565
        hres = to_number(ctx, argv[3], &ms);
1566 1567
        if(FAILED(hres))
            return hres;
1568 1569
    }else {
        ms = ms_from_time(t);
1570 1571 1572 1573
    }

    t = make_date(day(t), make_time(hour, min, sec, ms));
    date->time = time_clip(utc(t, date));
1574

1575 1576
    if(r)
        *r = jsval_number(date->time);
1577
    return S_OK;
1578 1579
}

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)
1583
{
1584
    DateInstance *date;
1585
    double t, hour, min, sec, ms;
1586 1587 1588 1589
    HRESULT hres;

    TRACE("\n");

1590
    if(!(date = date_this(jsthis)))
1591
        return JS_E_DATE_EXPECTED;
1592

1593
    if(!argc)
1594
        return JS_E_MISSING_ARG;
1595

1596 1597
    t = date->time;

1598
    hres = to_number(ctx, argv[0], &hour);
1599 1600 1601
    if(FAILED(hres))
        return hres;

1602
    if(argc > 1) {
1603
        hres = to_number(ctx, argv[1], &min);
1604 1605
        if(FAILED(hres))
            return hres;
1606 1607
    }else {
        min = min_from_time(t);
1608 1609
    }

1610
    if(argc > 2) {
1611
        hres = to_number(ctx, argv[2], &sec);
1612 1613
        if(FAILED(hres))
            return hres;
1614 1615
    }else {
        sec = sec_from_time(t);
1616 1617
    }

1618
    if(argc > 3) {
1619
        hres = to_number(ctx, argv[3], &ms);
1620 1621
        if(FAILED(hres))
            return hres;
1622 1623
    }else {
        ms = ms_from_time(t);
1624 1625 1626 1627
    }

    t = make_date(day(t), make_time(hour, min, sec, ms));
    date->time = time_clip(t);
1628

1629 1630
    if(r)
        *r = jsval_number(date->time);
1631
    return S_OK;
1632 1633
}

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)
1637
{
1638
    DateInstance *date;
1639 1640
    double t, n;
    HRESULT hres;
1641 1642 1643

    TRACE("\n");

1644
    if(!(date = date_this(jsthis)))
1645
        return JS_E_DATE_EXPECTED;
1646

1647
    if(!argc)
1648
        return JS_E_MISSING_ARG;
1649

1650
    hres = to_number(ctx, argv[0], &n);
1651 1652 1653 1654
    if(FAILED(hres))
        return hres;

    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 1657
    date->time = time_clip(utc(t, date));

1658 1659
    if(r)
        *r = jsval_number(date->time);
1660
    return S_OK;
1661 1662
}

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)
1666
{
1667
    DateInstance *date;
1668 1669
    double t, n;
    HRESULT hres;
1670 1671 1672

    TRACE("\n");

1673
    if(!(date = date_this(jsthis)))
1674
        return JS_E_DATE_EXPECTED;
1675

1676
    if(!argc)
1677
        return JS_E_MISSING_ARG;
1678

1679
    hres = to_number(ctx, argv[0], &n);
1680 1681 1682 1683
    if(FAILED(hres))
        return hres;

    t = date->time;
1684
    t = make_date(make_day(year_from_time(t), month_from_time(t), n), time_within_day(t));
1685 1686
    date->time = time_clip(t);

1687 1688
    if(r)
        *r = jsval_number(date->time);
1689
    return S_OK;
1690 1691
}

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)
1695
{
1696 1697
    DateInstance *date;
    DOUBLE t, month, ddate;
1698
    HRESULT hres;
1699 1700 1701

    TRACE("\n");

1702
    if(!(date = date_this(jsthis)))
1703
        return JS_E_DATE_EXPECTED;
1704

1705
    if(!argc)
1706
        return JS_E_MISSING_ARG;
1707 1708 1709

    t = local_time(date->time, date);

1710
    hres = to_number(ctx, argv[0], &month);
1711 1712 1713
    if(FAILED(hres))
        return hres;

1714
    if(argc > 1) {
1715
        hres = to_number(ctx, argv[1], &ddate);
1716 1717
        if(FAILED(hres))
            return hres;
1718 1719
    }else {
        ddate = date_from_time(t);
1720 1721 1722 1723 1724 1725
    }

    t = make_date(make_day(year_from_time(t), month, ddate),
            time_within_day(t));
    date->time = time_clip(utc(t, date));

1726 1727
    if(r)
        *r = jsval_number(date->time);
1728
    return S_OK;
1729 1730
}

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)
1734
{
1735
    DateInstance *date;
1736 1737
    double t, month, ddate;
    HRESULT hres;
1738 1739 1740

    TRACE("\n");

1741
    if(!(date = date_this(jsthis)))
1742
        return JS_E_DATE_EXPECTED;
1743

1744
    if(!argc)
1745
        return JS_E_MISSING_ARG;
1746 1747 1748

    t = date->time;

1749
    hres = to_number(ctx, argv[0], &month);
1750 1751 1752
    if(FAILED(hres))
        return hres;

1753
    if(argc > 1) {
1754
        hres = to_number(ctx, argv[1], &ddate);
1755 1756
        if(FAILED(hres))
            return hres;
1757 1758
    }else {
        ddate = date_from_time(t);
1759 1760 1761 1762 1763 1764
    }

    t = make_date(make_day(year_from_time(t), month, ddate),
            time_within_day(t));
    date->time = time_clip(t);

1765 1766
    if(r)
        *r = jsval_number(date->time);
1767
    return S_OK;
1768 1769
}

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)
1773
{
1774
    DateInstance *date;
1775 1776
    double t, year, month, ddate;
    HRESULT hres;
1777 1778 1779

    TRACE("\n");

1780
    if(!(date = date_this(jsthis)))
1781
        return JS_E_DATE_EXPECTED;
1782

1783
    if(!argc)
1784
        return JS_E_MISSING_ARG;
1785 1786 1787

    t = local_time(date->time, date);

1788
    hres = to_number(ctx, argv[0], &year);
1789 1790 1791
    if(FAILED(hres))
        return hres;

1792
    if(argc > 1) {
1793
        hres = to_number(ctx, argv[1], &month);
1794 1795
        if(FAILED(hres))
            return hres;
1796 1797
    }else {
        month = month_from_time(t);
1798 1799
    }

1800
    if(argc > 2) {
1801
        hres = to_number(ctx, argv[2], &ddate);
1802 1803
        if(FAILED(hres))
            return hres;
1804 1805
    }else {
        ddate = date_from_time(t);
1806 1807 1808 1809 1810
    }

    t = make_date(make_day(year, month, ddate), time_within_day(t));
    date->time = time_clip(utc(t, date));

1811 1812
    if(r)
        *r = jsval_number(date->time);
1813
    return S_OK;
1814 1815
}

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)
1819
{
1820
    DateInstance *date;
1821 1822
    double t, year, month, ddate;
    HRESULT hres;
1823 1824 1825

    TRACE("\n");

1826
    if(!(date = date_this(jsthis)))
1827
        return JS_E_DATE_EXPECTED;
1828

1829
    if(!argc)
1830
        return JS_E_MISSING_ARG;
1831 1832 1833

    t = date->time;

1834
    hres = to_number(ctx, argv[0], &year);
1835 1836 1837
    if(FAILED(hres))
        return hres;

1838
    if(argc > 1) {
1839
        hres = to_number(ctx, argv[1], &month);
1840 1841
        if(FAILED(hres))
            return hres;
1842 1843
    }else {
        month = month_from_time(t);
1844 1845
    }

1846
    if(argc > 2) {
1847
        hres = to_number(ctx, argv[2], &ddate);
1848 1849
        if(FAILED(hres))
            return hres;
1850 1851
    }else {
        ddate = date_from_time(t);
1852 1853 1854 1855 1856
    }

    t = make_date(make_day(year, month, ddate), time_within_day(t));
    date->time = time_clip(t);

1857 1858
    if(r)
        *r = jsval_number(date->time);
1859
    return S_OK;
1860 1861
}

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)
1865 1866 1867 1868 1869 1870
{
    DateInstance *date;
    DOUBLE t, year;

    TRACE("\n");

1871
    if(!(date = date_this(jsthis)))
1872
        return JS_E_DATE_EXPECTED;
1873 1874 1875

    t = local_time(date->time, date);
    if(isnan(t)) {
1876 1877
        if(r)
            *r = jsval_number(NAN);
1878 1879 1880 1881
        return S_OK;
    }

    year = year_from_time(t);
1882 1883
    if(r)
        *r = jsval_number((1900<=year && year<2000)?year-1900:year);
1884 1885 1886
    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)
1890
{
1891 1892 1893 1894 1895 1896 1897
    DateInstance *date;
    DOUBLE t, year;
    HRESULT hres;

    TRACE("\n");

    if(!(date = date_this(jsthis)))
1898
        return JS_E_DATE_EXPECTED;
1899

1900
    if(!argc)
1901
        return JS_E_MISSING_ARG;
1902 1903 1904

    t = local_time(date->time, date);

1905
    hres = to_number(ctx, argv[0], &year);
1906 1907 1908 1909 1910
    if(FAILED(hres))
        return hres;

    if(isnan(year)) {
        date->time = year;
1911 1912
        if(r)
            *r = jsval_number(NAN);
1913 1914 1915 1916 1917 1918 1919 1920 1921
        return S_OK;
    }

    year = year >= 0.0 ? floor(year) : -floor(-year);
    if(-1.0 < year && year < 100.0)
        year += 1900.0;

    date->time = time_clip(utc(make_date(make_day(year, month_from_time(t), date_from_time(t)), time_within_day(t)), date));

1922 1923
    if(r)
        *r = jsval_number(date->time);
1924
    return S_OK;
1925 1926
}

1927
static HRESULT Date_get_value(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r)
1928
{
1929 1930
    TRACE("\n");

1931
    return dateobj_to_string(date_from_jsdisp(jsthis), r);
1932 1933 1934 1935 1936 1937 1938
}

static const builtin_prop_t Date_props[] = {
    {getDateW,               Date_getDate,               PROPF_METHOD},
    {getDayW,                Date_getDay,                PROPF_METHOD},
    {getFullYearW,           Date_getFullYear,           PROPF_METHOD},
    {getHoursW,              Date_getHours,              PROPF_METHOD},
1939
    {getMillisecondsW,       Date_getMilliseconds,       PROPF_METHOD},
1940 1941 1942 1943 1944 1945 1946 1947 1948
    {getMinutesW,            Date_getMinutes,            PROPF_METHOD},
    {getMonthW,              Date_getMonth,              PROPF_METHOD},
    {getSecondsW,            Date_getSeconds,            PROPF_METHOD},
    {getTimeW,               Date_getTime,               PROPF_METHOD},
    {getTimezoneOffsetW,     Date_getTimezoneOffset,     PROPF_METHOD},
    {getUTCDateW,            Date_getUTCDate,            PROPF_METHOD},
    {getUTCDayW,             Date_getUTCDay,             PROPF_METHOD},
    {getUTCFullYearW,        Date_getUTCFullYear,        PROPF_METHOD},
    {getUTCHoursW,           Date_getUTCHours,           PROPF_METHOD},
1949
    {getUTCMillisecondsW,    Date_getUTCMilliseconds,    PROPF_METHOD},
1950 1951 1952
    {getUTCMinutesW,         Date_getUTCMinutes,         PROPF_METHOD},
    {getUTCMonthW,           Date_getUTCMonth,           PROPF_METHOD},
    {getUTCSecondsW,         Date_getUTCSeconds,         PROPF_METHOD},
1953
    {getYearW,               Date_getYear,               PROPF_METHOD},
1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968
    {setDateW,               Date_setDate,               PROPF_METHOD|1},
    {setFullYearW,           Date_setFullYear,           PROPF_METHOD|3},
    {setHoursW,              Date_setHours,              PROPF_METHOD|4},
    {setMillisecondsW,       Date_setMilliseconds,       PROPF_METHOD|1},
    {setMinutesW,            Date_setMinutes,            PROPF_METHOD|3},
    {setMonthW,              Date_setMonth,              PROPF_METHOD|2},
    {setSecondsW,            Date_setSeconds,            PROPF_METHOD|2},
    {setTimeW,               Date_setTime,               PROPF_METHOD|1},
    {setUTCDateW,            Date_setUTCDate,            PROPF_METHOD|1},
    {setUTCFullYearW,        Date_setUTCFullYear,        PROPF_METHOD|3},
    {setUTCHoursW,           Date_setUTCHours,           PROPF_METHOD|4},
    {setUTCMillisecondsW,    Date_setUTCMilliseconds,    PROPF_METHOD|1},
    {setUTCMinutesW,         Date_setUTCMinutes,         PROPF_METHOD|3},
    {setUTCMonthW,           Date_setUTCMonth,           PROPF_METHOD|2},
    {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 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983
    {toLocaleDateStringW,    Date_toLocaleDateString,    PROPF_METHOD},
    {toLocaleStringW,        Date_toLocaleString,        PROPF_METHOD},
    {toLocaleTimeStringW,    Date_toLocaleTimeString,    PROPF_METHOD},
    {toStringW,              Date_toString,              PROPF_METHOD},
    {toTimeStringW,          Date_toTimeString,          PROPF_METHOD},
    {toUTCStringW,           Date_toUTCString,           PROPF_METHOD},
    {valueOfW,               Date_valueOf,               PROPF_METHOD},
};

static const builtin_info_t Date_info = {
    JSCLASS_DATE,
1984
    {NULL, NULL,0, Date_get_value},
1985
    ARRAY_SIZE(Date_props),
1986 1987 1988 1989 1990
    Date_props,
    NULL,
    NULL
};

1991 1992
static const builtin_info_t DateInst_info = {
    JSCLASS_DATE,
1993
    {NULL, NULL,0, Date_get_value},
1994 1995 1996 1997 1998
    0, NULL,
    NULL,
    NULL
};

1999
static HRESULT create_date(script_ctx_t *ctx, jsdisp_t *object_prototype, DOUBLE time, jsdisp_t **ret)
2000 2001 2002
{
    DateInstance *date;
    HRESULT hres;
2003 2004
    TIME_ZONE_INFORMATION tzi;

2005
    GetTimeZoneInformation(&tzi);
2006 2007 2008 2009 2010

    date = heap_alloc_zero(sizeof(DateInstance));
    if(!date)
        return E_OUTOFMEMORY;

2011 2012
    if(object_prototype)
        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 2016 2017 2018 2019
    if(FAILED(hres)) {
        heap_free(date);
        return hres;
    }

2020
    date->time = time;
2021
    date->bias = tzi.Bias;
2022 2023 2024 2025
    date->standardDate = tzi.StandardDate;
    date->standardBias = tzi.StandardBias;
    date->daylightDate = tzi.DaylightDate;
    date->daylightBias = tzi.DaylightBias;
2026

2027 2028 2029 2030
    *ret = &date->dispex;
    return S_OK;
}

2031
static inline HRESULT date_parse(jsstr_t *input_str, double *ret) {
2032 2033 2034 2035 2036 2037 2038
    static const DWORD string_ids[] = { LOCALE_SMONTHNAME12, LOCALE_SMONTHNAME11,
        LOCALE_SMONTHNAME10, LOCALE_SMONTHNAME9, LOCALE_SMONTHNAME8,
        LOCALE_SMONTHNAME7, LOCALE_SMONTHNAME6, LOCALE_SMONTHNAME5,
        LOCALE_SMONTHNAME4, LOCALE_SMONTHNAME3, LOCALE_SMONTHNAME2,
        LOCALE_SMONTHNAME1, LOCALE_SDAYNAME7, LOCALE_SDAYNAME1,
        LOCALE_SDAYNAME2, LOCALE_SDAYNAME3, LOCALE_SDAYNAME4,
        LOCALE_SDAYNAME5, LOCALE_SDAYNAME6 };
2039
    WCHAR *strings[ARRAY_SIZE(string_ids)];
2040
    WCHAR *parse;
2041 2042 2043 2044 2045 2046 2047
    int input_len, parse_len = 0, nest_level = 0, i, size;
    int year = 0, month = 0, day = 0, hour = 0, min = 0, sec = 0;
    int ms = 0, offset = 0, hour_adjust = 0;
    BOOL set_year = FALSE, set_month = FALSE, set_day = FALSE, set_hour = FALSE;
    BOOL set_offset = FALSE, set_era = FALSE, ad = TRUE, set_am = FALSE, am = TRUE;
    BOOL set_hour_adjust = TRUE;
    TIME_ZONE_INFORMATION tzi;
2048
    const WCHAR *input;
2049 2050 2051
    DateInstance di;
    DWORD lcid_en;

2052
    input_len = jsstr_length(input_str);
2053 2054 2055
    input = jsstr_flatten(input_str);
    if(!input)
        return E_OUTOFMEMORY;
2056

2057 2058 2059 2060
    for(i=0; i<input_len; i++) {
        if(input[i] == '(') nest_level++;
        else if(input[i] == ')') {
            nest_level--;
2061
            if(nest_level<0) {
2062
                *ret = NAN;
2063
                return S_OK;
2064
            }
2065 2066 2067 2068
        }
        else if(!nest_level) parse_len++;
    }

2069
    parse = heap_alloc((parse_len+1)*sizeof(WCHAR));
2070 2071 2072 2073 2074 2075 2076
    if(!parse)
        return E_OUTOFMEMORY;
    nest_level = 0;
    parse_len = 0;
    for(i=0; i<input_len; i++) {
        if(input[i] == '(') nest_level++;
        else if(input[i] == ')') nest_level--;
2077
        else if(!nest_level) parse[parse_len++] = towupper(input[i]);
2078
    }
2079
    parse[parse_len] = 0;
2080 2081 2082 2083 2084 2085 2086 2087

    GetTimeZoneInformation(&tzi);
    di.bias = tzi.Bias;
    di.standardDate = tzi.StandardDate;
    di.standardBias = tzi.StandardBias;
    di.daylightDate = tzi.DaylightDate;
    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 2094 2095
        if(!strings[i]) {
            i--;
            while(i-- >= 0)
2096 2097
                heap_free(strings[i]);
            heap_free(parse);
2098 2099 2100 2101 2102 2103
            return E_OUTOFMEMORY;
        }
        GetLocaleInfoW(lcid_en, string_ids[i], strings[i], size);
    }

    for(i=0; i<parse_len;) {
2104
        while(iswspace(parse[i])) i++;
2105 2106 2107 2108 2109 2110
        if(parse[i] == ',') {
            while(parse[i] == ',') i++;
            continue;
        }

        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++;
2114 2115 2116 2117 2118 2119 2120 2121 2122

            if(parse[i] == ':') {
                /* Time */
                if(set_hour) break;
                set_hour = TRUE;

                hour = tmp;

                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 2127 2128
                    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 2135 2136 2137
                    while(parse[i]>='0' && parse[i]<='9') i++;
                }
            }
            else if(parse[i]=='-' || parse[i]=='/') {
2138
                /* Short or long date */
2139 2140 2141 2142 2143 2144 2145
                if(set_day || set_month || set_year) break;
                set_day = TRUE;
                set_month = TRUE;
                set_year = TRUE;

                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 2152 2153
                while(parse[i]>='0' && parse[i]<='9') i++;

                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++;
2158 2159 2160 2161 2162 2163 2164

                if(tmp >= 70){
                        /* long date */
                        month = day - 1;
                        day = year;
                        year = tmp;
		}
2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179
            }
            else if(tmp<0) break;
            else if(tmp<70) {
                /* Day */
                if(set_day) break;
                set_day = TRUE;
                day = tmp;
            }
            else {
                /* Year */
                if(set_year) break;
                set_year = TRUE;
                year = tmp;
            }
        }
2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190
        else if(parse[i]=='+' || parse[i]=='-') {
            /* Timezone offset */
            BOOL positive = TRUE;

            if(set_offset && set_hour_adjust) break;
            set_offset = TRUE;
            set_hour_adjust = FALSE;

            if(parse[i] == '-')  positive = FALSE;

            i++;
2191
            while(iswspace(parse[i])) i++;
2192
            if(parse[i]<'0' || parse[i]>'9') break;
2193
            offset = wcstol(&parse[i], NULL, 10);
2194 2195 2196 2197 2198 2199 2200 2201
            while(parse[i]>='0' && parse[i]<='9') i++;

            if(offset<24) offset *= 60;
            else offset = (offset/100)*60 + offset%100;

            if(positive) offset = -offset;

        }
2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265
        else {
            if(parse[i]<'A' || parse[i]>'Z') break;
            else if(parse[i]=='B' && (parse[i+1]=='C' ||
                        (parse[i+1]=='.' && parse[i+2]=='C'))) {
                /* AD/BC */
                if(set_era) break;
                set_era = TRUE;
                ad = FALSE;

                i++;
                if(parse[i] == '.') i++;
                i++;
                if(parse[i] == '.') i++;
            }
            else if(parse[i]=='A' && (parse[i+1]=='D' ||
                        (parse[i+1]=='.' && parse[i+2]=='D'))) {
                /* AD/BC */
                if(set_era) break;
                set_era = TRUE;

                i++;
                if(parse[i] == '.') i++;
                i++;
                if(parse[i] == '.') i++;
            }
            else if(parse[i+1]<'A' || parse[i+1]>'Z') {
                /* Timezone */
                if(set_offset) break;
                set_offset = TRUE;

                if(parse[i] <= 'I') hour_adjust = parse[i]-'A'+2;
                else if(parse[i] == 'J') break;
                else if(parse[i] <= 'M') hour_adjust = parse[i]-'K'+11;
                else if(parse[i] <= 'Y') hour_adjust = parse[i]-'N';
                else hour_adjust = 1;

                i++;
                if(parse[i] == '.') i++;
            }
            else if(parse[i]=='A' && parse[i+1]=='M') {
                /* AM/PM */
                if(set_am) break;
                set_am = TRUE;
                am = TRUE;
                i += 2;
            }
            else if(parse[i]=='P' && parse[i+1]=='M') {
                /* AM/PM */
                if(set_am) break;
                set_am = TRUE;
                am = FALSE;
                i += 2;
            }
            else if((parse[i]=='U' && parse[i+1]=='T' && parse[i+2]=='C')
                    || (parse[i]=='G' && parse[i+1]=='M' && parse[i+2]=='T')) {
                /* Timezone */
                if(set_offset) break;
                set_offset = TRUE;
                set_hour_adjust = FALSE;

                i += 3;
            }
            else {
                /* Month or garbage */
2266
                unsigned int j;
2267 2268 2269 2270

                for(size=i; parse[size]>='A' && parse[size]<='Z'; size++);
                size -= i;

2271
                for(j=0; j<ARRAY_SIZE(string_ids); j++)
2272
                    if(!wcsnicmp(&parse[i], strings[j], size)) break;
2273 2274 2275 2276 2277 2278

                if(j < 12) {
                    if(set_month) break;
                    set_month = TRUE;
                    month = 11-j;
                }
2279
                else if(j == ARRAY_SIZE(string_ids)) break;
2280 2281 2282 2283 2284 2285

                i += size;
            }
        }
    }

2286
    if(i == parse_len && set_year && set_month && set_day && (!set_am || hour<13)) {
2287 2288 2289 2290 2291 2292 2293 2294
        if(set_am) {
            if(hour == 12) hour = 0;
            if(!am) hour += 12;
        }

        if(!ad) year = -year+1;
        else if(year<100) year += 1900;

2295
        *ret = time_clip(make_date(make_day(year, month, day),
2296 2297
                    make_time(hour+hour_adjust, min, sec, ms)) + offset*MS_PER_MINUTE);

2298 2299 2300
        if(set_hour_adjust)
            *ret = utc(*ret, &di);
    }else {
2301
        *ret = NAN;
2302 2303
    }

2304
    for(i=0; i<ARRAY_SIZE(string_ids); i++)
2305 2306
        heap_free(strings[i]);
    heap_free(parse);
2307 2308 2309 2310

    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)
2313
{
2314
    jsstr_t *parse_str;
2315
    double n;
2316 2317 2318 2319
    HRESULT hres;

    TRACE("\n");

2320
    if(!argc) {
2321 2322
        if(r)
            *r = jsval_number(NAN);
2323 2324 2325
        return S_OK;
    }

2326
    hres = to_string(ctx, argv[0], &parse_str);
2327 2328 2329
    if(FAILED(hres))
        return hres;

2330
    hres = date_parse(parse_str, &n);
2331
    jsstr_release(parse_str);
2332 2333 2334
    if(FAILED(hres))
        return hres;

2335
    *r = jsval_number(n);
2336
    return S_OK;
2337 2338
}

2339
static HRESULT date_utc(script_ctx_t *ctx, unsigned argc, jsval_t *argv, double *ret)
2340
{
2341
    double year, month, vdate, hours, minutes, seconds, ms;
2342 2343 2344 2345
    HRESULT hres;

    TRACE("\n");

2346
    if(argc) {
2347
        hres = to_number(ctx, argv[0], &year);
2348 2349
        if(FAILED(hres))
            return hres;
2350 2351 2352 2353
        if(0 <= year && year <= 99)
            year += 1900;
    }else {
        year = 1900;
2354 2355
    }

2356
    if(argc>1) {
2357
        hres = to_number(ctx, argv[1], &month);
2358 2359
        if(FAILED(hres))
            return hres;
2360 2361
    }else {
        month = 0;
2362 2363
    }

2364
    if(argc>2) {
2365
        hres = to_number(ctx, argv[2], &vdate);
2366 2367
        if(FAILED(hres))
            return hres;
2368 2369
    }else {
        vdate = 1;
2370 2371
    }

2372
    if(argc>3) {
2373
        hres = to_number(ctx, argv[3], &hours);
2374 2375
        if(FAILED(hres))
            return hres;
2376 2377
    }else {
        hours = 0;
2378 2379
    }

2380
    if(argc>4) {
2381
        hres = to_number(ctx, argv[4], &minutes);
2382 2383
        if(FAILED(hres))
            return hres;
2384 2385
    }else {
        minutes = 0;
2386 2387
    }

2388
    if(argc>5) {
2389
        hres = to_number(ctx, argv[5], &seconds);
2390 2391
        if(FAILED(hres))
            return hres;
2392 2393
    }else {
        seconds = 0;
2394 2395
    }

2396
    if(argc>6) {
2397
        hres = to_number(ctx, argv[6], &ms);
2398 2399
        if(FAILED(hres))
            return hres;
2400 2401
    } else {
        ms = 0;
2402 2403
    }

2404 2405
    *ret = time_clip(make_date(make_day(year, month, vdate),
            make_time(hours, minutes,seconds, ms)));
2406
    return S_OK;
2407 2408
}

2409
static HRESULT DateConstr_UTC(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
2410
        jsval_t *r)
2411
{
2412 2413 2414
    double n;
    HRESULT hres;

2415 2416
    TRACE("\n");

2417
    hres = date_utc(ctx, argc, argv, &n);
2418 2419
    if(SUCCEEDED(hres) && r)
        *r = jsval_number(n);
2420
    return hres;
2421 2422
}

2423 2424 2425 2426 2427 2428 2429 2430 2431
/* ECMA-262 5.1 Edition    15.9.4.4 */
static HRESULT DateConstr_now(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
{
    TRACE("\n");

    if(r) *r = jsval_number(date_now());
    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)
2434
{
2435
    jsdisp_t *date;
2436 2437 2438 2439 2440 2441
    HRESULT hres;

    TRACE("\n");

    switch(flags) {
    case DISPATCH_CONSTRUCT:
2442
        switch(argc) {
2443
        /* ECMA-262 3rd Edition    15.9.3.3 */
2444 2445
        case 0:
            hres = create_date(ctx, NULL, date_now(), &date);
2446 2447 2448 2449 2450 2451
            if(FAILED(hres))
                return hres;
            break;

        /* ECMA-262 3rd Edition    15.9.3.2 */
        case 1: {
2452
            jsval_t prim;
2453
            double n;
2454

2455
            hres = to_primitive(ctx, argv[0], &prim, NO_HINT);
2456 2457 2458
            if(FAILED(hres))
                return hres;

2459 2460
            if(is_string(prim))
                hres = date_parse(get_string(prim), &n);
2461
            else
2462
                hres = to_number(ctx, prim, &n);
2463

2464
            jsval_release(prim);
2465 2466 2467
            if(FAILED(hres))
                return hres;

2468
            hres = create_date(ctx, NULL, time_clip(n), &date);
2469 2470 2471 2472 2473
            if(FAILED(hres))
                return hres;
            break;
        }

2474 2475
        /* ECMA-262 3rd Edition    15.9.3.1 */
        default: {
2476
            double ret_date;
2477 2478
            DateInstance *di;

2479
            hres = date_utc(ctx, argc, argv, &ret_date);
2480 2481
            if(FAILED(hres))
                return hres;
2482

2483
            hres = create_date(ctx, NULL, ret_date, &date);
2484 2485 2486
            if(FAILED(hres))
                return hres;

2487
            di = date_from_jsdisp(date);
2488 2489
            di->time = utc(di->time, di);
        }
2490 2491
        }

2492
        *r = jsval_obj(date);
2493 2494
        return S_OK;

2495 2496 2497 2498 2499 2500 2501 2502 2503
    case INVOKE_FUNC: {
        FILETIME system_time, local_time;
        LONGLONG lltime;

        GetSystemTimeAsFileTime(&system_time);
        FileTimeToLocalFileTime(&system_time, &local_time);
        lltime = ((LONGLONG)local_time.dwHighDateTime<<32)
            + local_time.dwLowDateTime;

2504
        return date_to_string(lltime/10000-TIME_EPOCH, FALSE, 0, r);
2505 2506
    }

2507 2508 2509 2510 2511 2512
    default:
        FIXME("unimplemented flags %x\n", flags);
        return E_NOTIMPL;
    }

    return S_OK;
2513 2514
}

2515 2516
static const builtin_prop_t DateConstr_props[] = {
    {UTCW,    DateConstr_UTC,    PROPF_METHOD},
2517
    {nowW,    DateConstr_now,    PROPF_HTML|PROPF_METHOD},
2518 2519 2520 2521 2522
    {parseW,  DateConstr_parse,  PROPF_METHOD}
};

static const builtin_info_t DateConstr_info = {
    JSCLASS_FUNCTION,
2523
    DEFAULT_FUNCTION_VALUE,
2524
    ARRAY_SIZE(DateConstr_props),
2525 2526 2527 2528 2529
    DateConstr_props,
    NULL,
    NULL
};

2530
HRESULT create_date_constr(script_ctx_t *ctx, jsdisp_t *object_prototype, jsdisp_t **ret)
2531
{
2532
    jsdisp_t *date;
2533 2534
    HRESULT hres;

2535 2536
    static const WCHAR DateW[] = {'D','a','t','e',0};

2537
    hres = create_date(ctx, object_prototype, 0.0, &date);
2538 2539 2540
    if(FAILED(hres))
        return hres;

2541
    hres = create_builtin_constructor(ctx, DateConstr_value, DateW, &DateConstr_info,
2542
            PROPF_CONSTR|7, date, ret);
2543 2544 2545 2546

    jsdisp_release(date);
    return hres;
}