DatePrototype.cpp 43.1 KB
Newer Older
1 2 3
/*
 *  Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
 *  Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
4
 *  Copyright (C) 2008, 2009 Torch Mobile, Inc. All rights reserved.
5
 *  Copyright (C) 2010 Torch Mobile (Beijing) Co. Ltd. All rights reserved.
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
 *
 *  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 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 Street, Fifth Floor, Boston, MA  02110-1301
 *  USA
 *
 */

#include "config.h"
#include "DatePrototype.h"

dglazkov@chromium.org's avatar
dglazkov@chromium.org committed
27
#include "DateConversion.h"
28
#include "DateInstance.h"
29
#include "Error.h"
30
#include "JSDateMath.h"
31
#include "JSGlobalObject.h"
32
#include "JSString.h"
33
#include "JSStringBuilder.h"
34
#include "Lookup.h"
35
#include "ObjectPrototype.h"
36
#include "Operations.h"
37 38 39 40 41

#if !PLATFORM(MAC) && HAVE(LANGINFO_H)
#include <langinfo.h>
#endif

42 43 44
#include <limits.h>
#include <locale.h>
#include <math.h>
45
#include <stdlib.h>
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
#include <time.h>
#include <wtf/Assertions.h>
#include <wtf/MathExtras.h>
#include <wtf/StringExtras.h>

#if HAVE(SYS_PARAM_H)
#include <sys/param.h>
#endif

#if HAVE(SYS_TIME_H)
#include <sys/time.h>
#endif

#if HAVE(SYS_TIMEB_H)
#include <sys/timeb.h>
#endif

63
#if OS(DARWIN) && USE(CF)
64
#include <CoreFoundation/CoreFoundation.h>
65
#elif USE(ICU_UNICODE)
66 67 68
#include <unicode/udat.h>
#endif

69 70
using namespace WTF;

71
namespace JSC {
72

73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDate(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDay(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetFullYear(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetHours(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMilliSeconds(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMinutes(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMonth(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetSeconds(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetTime(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetTimezoneOffset(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCDate(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCDay(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCFullYear(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCHours(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMilliseconds(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMinutes(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMonth(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCSeconds(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetYear(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetDate(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetFullYear(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetHours(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMilliSeconds(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMinutes(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMonth(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetSeconds(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetTime(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCDate(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCFullYear(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCHours(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMilliseconds(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMinutes(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMonth(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCSeconds(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetYear(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncToDateString(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncToGMTString(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleDateString(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleString(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleTimeString(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncToString(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncToTimeString(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncToUTCString(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncToISOString(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncToJSON(ExecState*);
118

119 120 121 122
}

#include "DatePrototype.lut.h"

123
namespace JSC {
124

125 126
enum LocaleDateTimeFormat { LocaleDateAndTime, LocaleDate, LocaleTime };
 
127
#if OS(DARWIN) && USE(CF)
128

129
// FIXME: Since this is superior to the strftime-based version, why limit this to OS(DARWIN)?
130
// Instead we should consider using this whenever USE(CF) is true.
131

132
static CFDateFormatterStyle styleFromArgString(const String& string, CFDateFormatterStyle defaultStyle)
133 134 135 136 137 138 139 140 141 142 143 144
{
    if (string == "short")
        return kCFDateFormatterShortStyle;
    if (string == "medium")
        return kCFDateFormatterMediumStyle;
    if (string == "long")
        return kCFDateFormatterLongStyle;
    if (string == "full")
        return kCFDateFormatterFullStyle;
    return defaultStyle;
}

145
static JSCell* formatLocaleDate(ExecState* exec, DateInstance*, double timeInMilliseconds, LocaleDateTimeFormat format)
146
{
147 148
    CFDateFormatterStyle dateStyle = (format != LocaleTime ? kCFDateFormatterLongStyle : kCFDateFormatterNoStyle);
    CFDateFormatterStyle timeStyle = (format != LocaleDate ? kCFDateFormatterLongStyle : kCFDateFormatterNoStyle);
149 150

    bool useCustomFormat = false;
151
    String customFormatString;
152

153
    String arg0String = exec->argument(0).toString(exec)->value(exec);
154
    if (arg0String == "custom" && !exec->argument(1).isUndefined()) {
155
        useCustomFormat = true;
156
        customFormatString = exec->argument(1).toString(exec)->value(exec);
157
    } else if (format == LocaleDateAndTime && !exec->argument(1).isUndefined()) {
158
        dateStyle = styleFromArgString(arg0String, dateStyle);
159
        timeStyle = styleFromArgString(exec->argument(1).toString(exec)->value(exec), timeStyle);
160
    } else if (format != LocaleTime && !exec->argument(0).isUndefined())
161
        dateStyle = styleFromArgString(arg0String, dateStyle);
162
    else if (format != LocaleDate && !exec->argument(0).isUndefined())
163 164 165 166 167 168 169
        timeStyle = styleFromArgString(arg0String, timeStyle);

    CFLocaleRef locale = CFLocaleCopyCurrent();
    CFDateFormatterRef formatter = CFDateFormatterCreate(0, locale, dateStyle, timeStyle);
    CFRelease(locale);

    if (useCustomFormat) {
170
        CFStringRef customFormatCFString = CFStringCreateWithCharacters(0, customFormatString.characters(), customFormatString.length());
171 172 173 174
        CFDateFormatterSetFormat(formatter, customFormatCFString);
        CFRelease(customFormatCFString);
    }

175
    CFStringRef string = CFDateFormatterCreateStringWithAbsoluteTime(0, formatter, floor(timeInMilliseconds / msPerSecond) - kCFAbsoluteTimeIntervalSince1970);
176 177 178 179 180 181

    CFRelease(formatter);

    // We truncate the string returned from CFDateFormatter if it's absurdly long (> 200 characters).
    // That's not great error handling, but it just won't happen so it doesn't matter.
    UChar buffer[200];
182
    const size_t bufferLength = WTF_ARRAY_LENGTH(buffer);
183 184 185 186
    size_t length = CFStringGetLength(string);
    ASSERT(length <= bufferLength);
    if (length > bufferLength)
        length = bufferLength;
187
    CFStringGetCharacters(string, CFRangeMake(0, length), buffer);
188 189 190

    CFRelease(string);

191
    return jsNontrivialString(exec, String(buffer, length));
192 193
}

194 195
#elif USE(ICU_UNICODE) && !UCONFIG_NO_FORMATTING

196
static JSCell* formatLocaleDate(ExecState* exec, DateInstance*, double timeInMilliseconds, LocaleDateTimeFormat format)
197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212
{
    UDateFormatStyle timeStyle = (format != LocaleDate ? UDAT_LONG : UDAT_NONE);
    UDateFormatStyle dateStyle = (format != LocaleTime ? UDAT_LONG : UDAT_NONE);

    UErrorCode status = U_ZERO_ERROR;
    UDateFormat* df = udat_open(timeStyle, dateStyle, 0, 0, -1, 0, 0, &status);
    if (!df)
        return jsEmptyString(exec);

    UChar buffer[128];
    int32_t length;
    length = udat_format(df, timeInMilliseconds, buffer, 128, 0, &status);
    udat_close(df);
    if (status != U_ZERO_ERROR)
        return jsEmptyString(exec);

213
    return jsNontrivialString(exec, String(buffer, length));
214 215 216
}

#else
217

218
static JSCell* formatLocaleDate(ExecState* exec, const GregorianDateTime& gdt, LocaleDateTimeFormat format)
219
{
220 221 222
#if OS(WINDOWS)
    SYSTEMTIME systemTime;
    memset(&systemTime, 0, sizeof(systemTime));
223
    systemTime.wYear = gdt.year();
224 225 226 227 228 229
    systemTime.wMonth = gdt.month() + 1;
    systemTime.wDay = gdt.monthDay();
    systemTime.wDayOfWeek = gdt.weekDay();
    systemTime.wHour = gdt.hour();
    systemTime.wMinute = gdt.minute();
    systemTime.wSecond = gdt.second();
230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247

    Vector<UChar, 128> buffer;
    size_t length = 0;

    if (format == LocaleDate) {
        buffer.resize(GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &systemTime, 0, 0, 0));
        length = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &systemTime, 0, buffer.data(), buffer.size());
    } else if (format == LocaleTime) {
        buffer.resize(GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &systemTime, 0, 0, 0));
        length = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &systemTime, 0, buffer.data(), buffer.size());
    } else if (format == LocaleDateAndTime) {
        buffer.resize(GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &systemTime, 0, 0, 0) + GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &systemTime, 0, 0, 0));
        length = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &systemTime, 0, buffer.data(), buffer.size());
        if (length) {
            buffer[length - 1] = ' ';
            length += GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &systemTime, 0, buffer.data() + length, buffer.size() - length);
        }
    } else
248
        RELEASE_ASSERT_NOT_REACHED();
249 250 251 252 253

    //  Remove terminating null character.
    if (length)
        length--;

254
    return jsNontrivialString(exec, String(buffer.data(), length));
255 256 257

#else // OS(WINDOWS)

258 259 260
#if HAVE(LANGINFO_H)
    static const nl_item formats[] = { D_T_FMT, D_FMT, T_FMT };
#else
261
    static const char* const formatStrings[] = { "%#c", "%#x", "%X" };
262
#endif
263

264 265
    // Offset year if needed
    struct tm localTM = gdt;
266
    int year = gdt.year();
267
    bool yearNeedsOffset = year < 1900 || year > 2038;
268
    if (yearNeedsOffset)
269
        localTM.tm_year = equivalentYearForDST(year) - 1900;
270

271 272 273 274 275 276 277 278 279 280
#if HAVE(LANGINFO_H)
    // We do not allow strftime to generate dates with 2-digits years,
    // both to avoid ambiguity, and a crash in strncpy, for years that
    // need offset.
    char* formatString = strdup(nl_langinfo(formats[format]));
    char* yPos = strchr(formatString, 'y');
    if (yPos)
        *yPos = 'Y';
#endif

281
    // Do the formatting
282
    const int bufsize = 128;
283
    char timebuffer[bufsize];
284 285 286 287 288

#if HAVE(LANGINFO_H)
    size_t ret = strftime(timebuffer, bufsize, formatString, &localTM);
    free(formatString);
#else
289
    size_t ret = strftime(timebuffer, bufsize, formatStrings[format], &localTM);
290
#endif
291

292
    if (ret == 0)
darin@apple.com's avatar
darin@apple.com committed
293
        return jsEmptyString(exec);
294

295 296 297 298
    // Copy original into the buffer
    if (yearNeedsOffset && format != LocaleTime) {
        static const int yearLen = 5;   // FIXME will be a problem in the year 10,000
        char yearString[yearLen];
299

300 301 302
        snprintf(yearString, yearLen, "%d", localTM.tm_year + 1900);
        char* yearLocation = strstr(timebuffer, yearString);
        snprintf(yearString, yearLen, "%d", year);
303

304 305
        strncpy(yearLocation, yearString, yearLen - 1);
    }
306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322

    // Convert multi-byte result to UNICODE.
    // If __STDC_ISO_10646__ is defined, wide character represents
    // UTF-16 (or UTF-32) code point. In most modern Unix like system
    // (e.g. Linux with glibc 2.2 and above) the macro is defined,
    // and wide character represents UTF-32 code point.
    // Here we static_cast potential UTF-32 to UTF-16, it should be
    // safe because date and (or) time related characters in different languages
    // should be in UNICODE BMP. If mbstowcs fails, we just fall
    // back on using multi-byte result as-is.
#ifdef __STDC_ISO_10646__
    UChar buffer[bufsize];
    wchar_t tempbuffer[bufsize];
    size_t length = mbstowcs(tempbuffer, timebuffer, bufsize - 1);
    if (length != static_cast<size_t>(-1)) {
        for (size_t i = 0; i < length; ++i)
            buffer[i] = static_cast<UChar>(tempbuffer[i]);
323
        return jsNontrivialString(exec, String(buffer, length));
324 325 326
    }
#endif

darin@apple.com's avatar
darin@apple.com committed
327
    return jsNontrivialString(exec, timebuffer);
328
#endif // OS(WINDOWS)
329 330
}

331
static JSCell* formatLocaleDate(ExecState* exec, DateInstance* dateObject, double, LocaleDateTimeFormat format)
332
{
333
    const GregorianDateTime* gregorianDateTime = dateObject->gregorianDateTime(exec);
334
    if (!gregorianDateTime)
335
        return jsNontrivialString(exec, ASCIILiteral("Invalid Date"));
336
    return formatLocaleDate(exec, *gregorianDateTime, format);
337 338
}

339
#endif // OS(DARWIN) && USE(CF)
340

341 342 343
static EncodedJSValue formateDateInstance(ExecState* exec, DateTimeFormat format, bool asUTCVariant)
{
    JSValue thisValue = exec->hostThisValue();
344
    if (!thisValue.inherits(DateInstance::info()))
345 346 347 348 349 350 351 352
        return throwVMTypeError(exec);

    DateInstance* thisDateObj = asDateInstance(thisValue);

    const GregorianDateTime* gregorianDateTime = asUTCVariant
        ? thisDateObj->gregorianDateTimeUTC(exec)
        : thisDateObj->gregorianDateTime(exec);
    if (!gregorianDateTime)
353
        return JSValue::encode(jsNontrivialString(exec, String(ASCIILiteral("Invalid Date"))));
354 355 356 357

    return JSValue::encode(jsNontrivialString(exec, formatDateTime(*gregorianDateTime, format, asUTCVariant)));
}

358 359 360 361
// Converts a list of arguments sent to a Date member function into milliseconds, updating
// ms (representing milliseconds) and t (representing the rest of the date structure) appropriately.
//
// Format of member function: f([hour,] [min,] [sec,] [ms])
362
static bool fillStructuresUsingTimeArgs(ExecState* exec, int maxArgs, double* ms, GregorianDateTime* t)
363 364 365 366
{
    double milliseconds = 0;
    bool ok = true;
    int idx = 0;
367
    int numArgs = exec->argumentCount();
368 369 370 371 372 373 374
    
    // JS allows extra trailing arguments -- ignore them
    if (numArgs > maxArgs)
        numArgs = maxArgs;

    // hours
    if (maxArgs >= 4 && idx < numArgs) {
375
        t->setHour(0);
376
        double hours = exec->uncheckedArgument(idx++).toIntegerPreserveNaN(exec);
377
        ok = std::isfinite(hours);
378
        milliseconds += hours * msPerHour;
379 380 381 382
    }

    // minutes
    if (maxArgs >= 3 && idx < numArgs && ok) {
383
        t->setMinute(0);
384
        double minutes = exec->uncheckedArgument(idx++).toIntegerPreserveNaN(exec);
385
        ok = std::isfinite(minutes);
386
        milliseconds += minutes * msPerMinute;
387 388 389 390
    }
    
    // seconds
    if (maxArgs >= 2 && idx < numArgs && ok) {
391
        t->setSecond(0);
392
        double seconds = exec->uncheckedArgument(idx++).toIntegerPreserveNaN(exec);
393
        ok = std::isfinite(seconds);
394
        milliseconds += seconds * msPerSecond;
395 396 397 398 399 400 401
    }
    
    if (!ok)
        return false;
        
    // milliseconds
    if (idx < numArgs) {
402
        double millis = exec->uncheckedArgument(idx).toIntegerPreserveNaN(exec);
403
        ok = std::isfinite(millis);
404 405 406 407 408 409 410 411 412 413 414 415
        milliseconds += millis;
    } else
        milliseconds += *ms;
    
    *ms = milliseconds;
    return ok;
}

// Converts a list of arguments sent to a Date member function into years, months, and milliseconds, updating
// ms (representing milliseconds) and t (representing the rest of the date structure) appropriately.
//
// Format of member function: f([years,] [months,] [days])
416
static bool fillStructuresUsingDateArgs(ExecState *exec, int maxArgs, double *ms, GregorianDateTime *t)
417 418 419
{
    int idx = 0;
    bool ok = true;
420
    int numArgs = exec->argumentCount();
421 422 423 424 425 426
  
    // JS allows extra trailing arguments -- ignore them
    if (numArgs > maxArgs)
        numArgs = maxArgs;
  
    // years
427
    if (maxArgs >= 3 && idx < numArgs) {
428
        double years = exec->uncheckedArgument(idx++).toIntegerPreserveNaN(exec);
429
        ok = std::isfinite(years);
430
        t->setYear(toInt32(years));
431
    }
432
    // months
433
    if (maxArgs >= 2 && idx < numArgs && ok) {
434
        double months = exec->uncheckedArgument(idx++).toIntegerPreserveNaN(exec);
435
        ok = std::isfinite(months);
436
        t->setMonth(toInt32(months));
437
    }
438
    // days
439
    if (idx < numArgs && ok) {
440
        double days = exec->uncheckedArgument(idx++).toIntegerPreserveNaN(exec);
441
        ok = std::isfinite(days);
442
        t->setMonthDay(0);
443
        *ms += days * msPerDay;
444 445 446 447 448
    }
    
    return ok;
}

449
const ClassInfo DatePrototype::s_info = {"Date", &DateInstance::s_info, 0, ExecState::dateTable, CREATE_METHOD_TABLE(DatePrototype)};
450

451
/* Source for DatePrototype.lut.h
452 453
@begin dateTable
  toString              dateProtoFuncToString                DontEnum|Function       0
454
  toISOString           dateProtoFuncToISOString             DontEnum|Function       0
455 456 457 458 459 460
  toUTCString           dateProtoFuncToUTCString             DontEnum|Function       0
  toDateString          dateProtoFuncToDateString            DontEnum|Function       0
  toTimeString          dateProtoFuncToTimeString            DontEnum|Function       0
  toLocaleString        dateProtoFuncToLocaleString          DontEnum|Function       0
  toLocaleDateString    dateProtoFuncToLocaleDateString      DontEnum|Function       0
  toLocaleTimeString    dateProtoFuncToLocaleTimeString      DontEnum|Function       0
461
  valueOf               dateProtoFuncGetTime                 DontEnum|Function       0
462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497
  getTime               dateProtoFuncGetTime                 DontEnum|Function       0
  getFullYear           dateProtoFuncGetFullYear             DontEnum|Function       0
  getUTCFullYear        dateProtoFuncGetUTCFullYear          DontEnum|Function       0
  toGMTString           dateProtoFuncToGMTString             DontEnum|Function       0
  getMonth              dateProtoFuncGetMonth                DontEnum|Function       0
  getUTCMonth           dateProtoFuncGetUTCMonth             DontEnum|Function       0
  getDate               dateProtoFuncGetDate                 DontEnum|Function       0
  getUTCDate            dateProtoFuncGetUTCDate              DontEnum|Function       0
  getDay                dateProtoFuncGetDay                  DontEnum|Function       0
  getUTCDay             dateProtoFuncGetUTCDay               DontEnum|Function       0
  getHours              dateProtoFuncGetHours                DontEnum|Function       0
  getUTCHours           dateProtoFuncGetUTCHours             DontEnum|Function       0
  getMinutes            dateProtoFuncGetMinutes              DontEnum|Function       0
  getUTCMinutes         dateProtoFuncGetUTCMinutes           DontEnum|Function       0
  getSeconds            dateProtoFuncGetSeconds              DontEnum|Function       0
  getUTCSeconds         dateProtoFuncGetUTCSeconds           DontEnum|Function       0
  getMilliseconds       dateProtoFuncGetMilliSeconds         DontEnum|Function       0
  getUTCMilliseconds    dateProtoFuncGetUTCMilliseconds      DontEnum|Function       0
  getTimezoneOffset     dateProtoFuncGetTimezoneOffset       DontEnum|Function       0
  setTime               dateProtoFuncSetTime                 DontEnum|Function       1
  setMilliseconds       dateProtoFuncSetMilliSeconds         DontEnum|Function       1
  setUTCMilliseconds    dateProtoFuncSetUTCMilliseconds      DontEnum|Function       1
  setSeconds            dateProtoFuncSetSeconds              DontEnum|Function       2
  setUTCSeconds         dateProtoFuncSetUTCSeconds           DontEnum|Function       2
  setMinutes            dateProtoFuncSetMinutes              DontEnum|Function       3
  setUTCMinutes         dateProtoFuncSetUTCMinutes           DontEnum|Function       3
  setHours              dateProtoFuncSetHours                DontEnum|Function       4
  setUTCHours           dateProtoFuncSetUTCHours             DontEnum|Function       4
  setDate               dateProtoFuncSetDate                 DontEnum|Function       1
  setUTCDate            dateProtoFuncSetUTCDate              DontEnum|Function       1
  setMonth              dateProtoFuncSetMonth                DontEnum|Function       2
  setUTCMonth           dateProtoFuncSetUTCMonth             DontEnum|Function       2
  setFullYear           dateProtoFuncSetFullYear             DontEnum|Function       3
  setUTCFullYear        dateProtoFuncSetUTCFullYear          DontEnum|Function       3
  setYear               dateProtoFuncSetYear                 DontEnum|Function       1
  getYear               dateProtoFuncGetYear                 DontEnum|Function       0
498
  toJSON                dateProtoFuncToJSON                  DontEnum|Function       1
499 500
@end
*/
501

502 503
// ECMA 15.9.4

504
DatePrototype::DatePrototype(ExecState* exec, Structure* structure)
505
    : DateInstance(exec, structure)
506
{
507 508
}

509
void DatePrototype::finishCreation(VM& vm, JSGlobalObject*)
510
{
511
    Base::finishCreation(vm);
512
    ASSERT(inherits(info()));
513

514 515 516
    // The constructor will be added later, after DateConstructor has been built.
}

517
bool DatePrototype::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
518
{
519
    return getStaticFunctionSlot<JSObject>(exec, ExecState::dateTable(exec), jsCast<DatePrototype*>(object), propertyName, slot);
520
}
521

522 523
// Functions

524
EncodedJSValue JSC_HOST_CALL dateProtoFuncToString(ExecState* exec)
525
{
526 527
    const bool asUTCVariant = false;
    return formateDateInstance(exec, DateTimeFormatDateAndTime, asUTCVariant);
528 529
}

530
EncodedJSValue JSC_HOST_CALL dateProtoFuncToUTCString(ExecState* exec)
531
{
532 533
    const bool asUTCVariant = true;
    return formateDateInstance(exec, DateTimeFormatDateAndTime, asUTCVariant);
534 535
}

536
EncodedJSValue JSC_HOST_CALL dateProtoFuncToISOString(ExecState* exec)
537
{
538
    JSValue thisValue = exec->hostThisValue();
539
    if (!thisValue.inherits(DateInstance::info()))
540
        return throwVMTypeError(exec);
541 542
    
    DateInstance* thisDateObj = asDateInstance(thisValue); 
543
    if (!std::isfinite(thisDateObj->internalNumber()))
544
        return throwVMError(exec, createRangeError(exec, ASCIILiteral("Invalid Date")));
545

546
    const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
547
    if (!gregorianDateTime)
548
        return JSValue::encode(jsNontrivialString(exec, String(ASCIILiteral("Invalid Date"))));
549 550
    // Maximum amount of space we need in buffer: 7 (max. digits in year) + 2 * 5 (2 characters each for month, day, hour, minute, second) + 4 (. + 3 digits for milliseconds)
    // 6 for formatting and one for null termination = 28. We add one extra character to allow us to force null termination.
551
    char buffer[28];
552
    // If the year is outside the bounds of 0 and 9999 inclusive we want to use the extended year format (ES 15.9.1.15.1).
553 554 555
    int ms = static_cast<int>(fmod(thisDateObj->internalNumber(), msPerSecond));
    if (ms < 0)
        ms += msPerSecond;
556 557

    int charactersWritten;
558
    if (gregorianDateTime->year() > 9999 || gregorianDateTime->year() < 0)
559
        charactersWritten = snprintf(buffer, sizeof(buffer), "%+07d-%02d-%02dT%02d:%02d:%02d.%03dZ", gregorianDateTime->year(), gregorianDateTime->month() + 1, gregorianDateTime->monthDay(), gregorianDateTime->hour(), gregorianDateTime->minute(), gregorianDateTime->second(), ms);
560
    else
561 562 563 564 565 566 567
        charactersWritten = snprintf(buffer, sizeof(buffer), "%04d-%02d-%02dT%02d:%02d:%02d.%03dZ", gregorianDateTime->year(), gregorianDateTime->month() + 1, gregorianDateTime->monthDay(), gregorianDateTime->hour(), gregorianDateTime->minute(), gregorianDateTime->second(), ms);

    ASSERT(charactersWritten > 0 && static_cast<unsigned>(charactersWritten) < sizeof(buffer));
    if (static_cast<unsigned>(charactersWritten) >= sizeof(buffer))
        return JSValue::encode(jsEmptyString(exec));

    return JSValue::encode(jsNontrivialString(exec, String(buffer, charactersWritten)));
568 569
}

570
EncodedJSValue JSC_HOST_CALL dateProtoFuncToDateString(ExecState* exec)
571
{
572 573
    const bool asUTCVariant = false;
    return formateDateInstance(exec, DateTimeFormatDate, asUTCVariant);
574 575
}

576
EncodedJSValue JSC_HOST_CALL dateProtoFuncToTimeString(ExecState* exec)
577
{
578 579
    const bool asUTCVariant = false;
    return formateDateInstance(exec, DateTimeFormatTime, asUTCVariant);
580 581
}

582
EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleString(ExecState* exec)
583
{
584
    JSValue thisValue = exec->hostThisValue();
585
    if (!thisValue.inherits(DateInstance::info()))
586
        return throwVMTypeError(exec);
587

darin@apple.com's avatar
darin@apple.com committed
588
    DateInstance* thisDateObj = asDateInstance(thisValue); 
589
    return JSValue::encode(formatLocaleDate(exec, thisDateObj, thisDateObj->internalNumber(), LocaleDateAndTime));
590 591
}

592
EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleDateString(ExecState* exec)
593
{
594
    JSValue thisValue = exec->hostThisValue();
595
    if (!thisValue.inherits(DateInstance::info()))
596
        return throwVMTypeError(exec);
597

darin@apple.com's avatar
darin@apple.com committed
598
    DateInstance* thisDateObj = asDateInstance(thisValue); 
599
    return JSValue::encode(formatLocaleDate(exec, thisDateObj, thisDateObj->internalNumber(), LocaleDate));
600 601
}

602
EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleTimeString(ExecState* exec)
603
{
604
    JSValue thisValue = exec->hostThisValue();
605
    if (!thisValue.inherits(DateInstance::info()))
606
        return throwVMTypeError(exec);
607

darin@apple.com's avatar
darin@apple.com committed
608
    DateInstance* thisDateObj = asDateInstance(thisValue); 
609
    return JSValue::encode(formatLocaleDate(exec, thisDateObj, thisDateObj->internalNumber(), LocaleTime));
610 611
}

612
EncodedJSValue JSC_HOST_CALL dateProtoFuncGetTime(ExecState* exec)
613
{
614
    JSValue thisValue = exec->hostThisValue();
615
    if (!thisValue.inherits(DateInstance::info()))
616
        return throwVMTypeError(exec);
617

618
    return JSValue::encode(asDateInstance(thisValue)->internalValue());
619 620
}

621
EncodedJSValue JSC_HOST_CALL dateProtoFuncGetFullYear(ExecState* exec)
622
{
623
    JSValue thisValue = exec->hostThisValue();
624
    if (!thisValue.inherits(DateInstance::info()))
625
        return throwVMTypeError(exec);
626

darin@apple.com's avatar
darin@apple.com committed
627
    DateInstance* thisDateObj = asDateInstance(thisValue); 
628

629
    const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
630
    if (!gregorianDateTime)
631
        return JSValue::encode(jsNaN());
632
    return JSValue::encode(jsNumber(gregorianDateTime->year()));
633 634
}

635
EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCFullYear(ExecState* exec)
636
{
637
    JSValue thisValue = exec->hostThisValue();
638
    if (!thisValue.inherits(DateInstance::info()))
639
        return throwVMTypeError(exec);
640

darin@apple.com's avatar
darin@apple.com committed
641
    DateInstance* thisDateObj = asDateInstance(thisValue); 
642

643
    const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
644
    if (!gregorianDateTime)
645
        return JSValue::encode(jsNaN());
646
    return JSValue::encode(jsNumber(gregorianDateTime->year()));
647 648
}

649
EncodedJSValue JSC_HOST_CALL dateProtoFuncToGMTString(ExecState* exec)
650
{
651 652
    const bool asUTCVariant = true;
    return formateDateInstance(exec, DateTimeFormatDateAndTime, asUTCVariant);
653 654
}

655
EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMonth(ExecState* exec)
656
{
657
    JSValue thisValue = exec->hostThisValue();
658
    if (!thisValue.inherits(DateInstance::info()))
659
        return throwVMTypeError(exec);
660

darin@apple.com's avatar
darin@apple.com committed
661
    DateInstance* thisDateObj = asDateInstance(thisValue); 
662

663
    const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
664
    if (!gregorianDateTime)
665
        return JSValue::encode(jsNaN());
666
    return JSValue::encode(jsNumber(gregorianDateTime->month()));
667 668
}

669
EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMonth(ExecState* exec)
670
{
671
    JSValue thisValue = exec->hostThisValue();
672
    if (!thisValue.inherits(DateInstance::info()))
673
        return throwVMTypeError(exec);
674

darin@apple.com's avatar
darin@apple.com committed
675
    DateInstance* thisDateObj = asDateInstance(thisValue); 
676

677
    const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
678
    if (!gregorianDateTime)
679
        return JSValue::encode(jsNaN());
680
    return JSValue::encode(jsNumber(gregorianDateTime->month()));
681 682
}

683
EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDate(ExecState* exec)
684
{
685
    JSValue thisValue = exec->hostThisValue();
686
    if (!thisValue.inherits(DateInstance::info()))
687
        return throwVMTypeError(exec);
688

darin@apple.com's avatar
darin@apple.com committed
689
    DateInstance* thisDateObj = asDateInstance(thisValue); 
690

691
    const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
692
    if (!gregorianDateTime)
693
        return JSValue::encode(jsNaN());
694
    return JSValue::encode(jsNumber(gregorianDateTime->monthDay()));
695 696
}

697
EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCDate(ExecState* exec)
698
{
699
    JSValue thisValue = exec->hostThisValue();
700
    if (!thisValue.inherits(DateInstance::info()))
701
        return throwVMTypeError(exec);
702

darin@apple.com's avatar
darin@apple.com committed
703
    DateInstance* thisDateObj = asDateInstance(thisValue); 
704

705
    const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
706
    if (!gregorianDateTime)
707
        return JSValue::encode(jsNaN());
708
    return JSValue::encode(jsNumber(gregorianDateTime->monthDay()));
709 710
}

711
EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDay(ExecState* exec)
712
{
713
    JSValue thisValue = exec->hostThisValue();
714
    if (!thisValue.inherits(DateInstance::info()))
715
        return throwVMTypeError(exec);
716

darin@apple.com's avatar
darin@apple.com committed
717
    DateInstance* thisDateObj = asDateInstance(thisValue); 
718

719
    const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
720
    if (!gregorianDateTime)
721
        return JSValue::encode(jsNaN());
722
    return JSValue::encode(jsNumber(gregorianDateTime->weekDay()));
723 724
}

725
EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCDay(ExecState* exec)
726
{
727
    JSValue thisValue = exec->hostThisValue();
728
    if (!thisValue.inherits(DateInstance::info()))
729
        return throwVMTypeError(exec);
730

darin@apple.com's avatar
darin@apple.com committed
731
    DateInstance* thisDateObj = asDateInstance(thisValue); 
732

733
    const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
734
    if (!gregorianDateTime)
735
        return JSValue::encode(jsNaN());
736
    return JSValue::encode(jsNumber(gregorianDateTime->weekDay()));
737 738
}

739
EncodedJSValue JSC_HOST_CALL dateProtoFuncGetHours(ExecState* exec)
740
{
741
    JSValue thisValue = exec->hostThisValue();
742
    if (!thisValue.inherits(DateInstance::info()))
743
        return throwVMTypeError(exec);
744

darin@apple.com's avatar
darin@apple.com committed
745
    DateInstance* thisDateObj = asDateInstance(thisValue); 
746

747
    const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
748
    if (!gregorianDateTime)
749
        return JSValue::encode(jsNaN());
750
    return JSValue::encode(jsNumber(gregorianDateTime->hour()));
751 752
}

753
EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCHours(ExecState* exec)
754
{
755
    JSValue thisValue = exec->hostThisValue();
756
    if (!thisValue.inherits(DateInstance::info()))
757
        return throwVMTypeError(exec);
758

darin@apple.com's avatar
darin@apple.com committed
759
    DateInstance* thisDateObj = asDateInstance(thisValue); 
760

761
    const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
762
    if (!gregorianDateTime)
763
        return JSValue::encode(jsNaN());
764
    return JSValue::encode(jsNumber(gregorianDateTime->hour()));
765 766
}

767
EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMinutes(ExecState* exec)