From 659fc03c429f57656cecad399e97f115448de04b Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Mon, 21 Jan 2013 11:57:17 +0100 Subject: [PATCH] Move the Date Object into it's own file Change-Id: I3f94fa1dcfc8e23414ee2b3f96cffffa1f753bc1 Reviewed-by: Simon Hausmann --- qmljs_engine.cpp | 1 + qmljs_objects.h | 7 - qv4dateobject.cpp | 1285 ++++++++++++++++++++++++++++++++++++++++++++++++++++ qv4dateobject.h | 125 +++++ qv4ecmaobjects.cpp | 1213 ------------------------------------------------- qv4ecmaobjects_p.h | 64 --- v4.pro | 2 + 7 files changed, 1413 insertions(+), 1284 deletions(-) create mode 100644 qv4dateobject.cpp create mode 100644 qv4dateobject.h diff --git a/qmljs_engine.cpp b/qmljs_engine.cpp index 0145238..a6ee9ab 100644 --- a/qmljs_engine.cpp +++ b/qmljs_engine.cpp @@ -44,6 +44,7 @@ #include #include "qv4mm.h" #include +#include #include namespace QQmlJS { diff --git a/qmljs_objects.h b/qmljs_objects.h index f1cbf4b..91b1241 100644 --- a/qmljs_objects.h +++ b/qmljs_objects.h @@ -205,13 +205,6 @@ struct StringObject: Object { PropertyDescriptor *getIndex(ExecutionContext *ctx, uint index); }; -struct DateObject: Object { - Value value; - DateObject(const Value &value): value(value) {} - virtual QString className() { return QStringLiteral("Date"); } - virtual DateObject *asDateObject() { return this; } -}; - struct ArrayObject: Object { ArrayObject(ExecutionContext *ctx) { init(ctx); } ArrayObject(ExecutionContext *ctx, const Array &value): Object(value) { init(ctx); array.setLengthUnchecked(array.length()); } diff --git a/qv4dateobject.cpp b/qv4dateobject.cpp new file mode 100644 index 0000000..d9c6f5e --- /dev/null +++ b/qv4dateobject.cpp @@ -0,0 +1,1285 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the V4VM module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include "qv4dateobject.h" +#include "qv4mm.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#ifndef Q_WS_WIN +# include +# ifndef Q_OS_VXWORKS +# include +# else +# include "qplatformdefs.h" +# endif +#else +# include +#endif + +using namespace QQmlJS::VM; + +static const double HoursPerDay = 24.0; +static const double MinutesPerHour = 60.0; +static const double SecondsPerMinute = 60.0; +static const double msPerSecond = 1000.0; +static const double msPerMinute = 60000.0; +static const double msPerHour = 3600000.0; +static const double msPerDay = 86400000.0; + +static double LocalTZA = 0.0; // initialized at startup + +static inline double TimeWithinDay(double t) +{ + double r = ::fmod(t, msPerDay); + return (r >= 0) ? r : r + msPerDay; +} + +static inline int HourFromTime(double t) +{ + int r = int(::fmod(::floor(t / msPerHour), HoursPerDay)); + return (r >= 0) ? r : r + int(HoursPerDay); +} + +static inline int MinFromTime(double t) +{ + int r = int(::fmod(::floor(t / msPerMinute), MinutesPerHour)); + return (r >= 0) ? r : r + int(MinutesPerHour); +} + +static inline int SecFromTime(double t) +{ + int r = int(::fmod(::floor(t / msPerSecond), SecondsPerMinute)); + return (r >= 0) ? r : r + int(SecondsPerMinute); +} + +static inline int msFromTime(double t) +{ + int r = int(::fmod(t, msPerSecond)); + return (r >= 0) ? r : r + int(msPerSecond); +} + +static inline double Day(double t) +{ + return ::floor(t / msPerDay); +} + +static inline double DaysInYear(double y) +{ + if (::fmod(y, 4)) + return 365; + + else if (::fmod(y, 100)) + return 366; + + else if (::fmod(y, 400)) + return 365; + + return 366; +} + +static inline double DayFromYear(double y) +{ + return 365 * (y - 1970) + + ::floor((y - 1969) / 4) + - ::floor((y - 1901) / 100) + + ::floor((y - 1601) / 400); +} + +static inline double TimeFromYear(double y) +{ + return msPerDay * DayFromYear(y); +} + +static inline double YearFromTime(double t) +{ + int y = 1970; + y += (int) ::floor(t / (msPerDay * 365.2425)); + + double t2 = TimeFromYear(y); + return (t2 > t) ? y - 1 : ((t2 + msPerDay * DaysInYear(y)) <= t) ? y + 1 : y; +} + +static inline bool InLeapYear(double t) +{ + double x = DaysInYear(YearFromTime(t)); + if (x == 365) + return 0; + + assert(x == 366); + return 1; +} + +static inline double DayWithinYear(double t) +{ + return Day(t) - DayFromYear(YearFromTime(t)); +} + +static inline double MonthFromTime(double t) +{ + double d = DayWithinYear(t); + double l = InLeapYear(t); + + if (d < 31.0) + return 0; + + else if (d < 59.0 + l) + return 1; + + else if (d < 90.0 + l) + return 2; + + else if (d < 120.0 + l) + return 3; + + else if (d < 151.0 + l) + return 4; + + else if (d < 181.0 + l) + return 5; + + else if (d < 212.0 + l) + return 6; + + else if (d < 243.0 + l) + return 7; + + else if (d < 273.0 + l) + return 8; + + else if (d < 304.0 + l) + return 9; + + else if (d < 334.0 + l) + return 10; + + else if (d < 365.0 + l) + return 11; + + return qSNaN(); // ### assert? +} + +static inline double DateFromTime(double t) +{ + int m = (int) Value::toInteger(MonthFromTime(t)); + double d = DayWithinYear(t); + double l = InLeapYear(t); + + switch (m) { + case 0: return d + 1.0; + case 1: return d - 30.0; + case 2: return d - 58.0 - l; + case 3: return d - 89.0 - l; + case 4: return d - 119.0 - l; + case 5: return d - 150.0 - l; + case 6: return d - 180.0 - l; + case 7: return d - 211.0 - l; + case 8: return d - 242.0 - l; + case 9: return d - 272.0 - l; + case 10: return d - 303.0 - l; + case 11: return d - 333.0 - l; + } + + return qSNaN(); // ### assert +} + +static inline double WeekDay(double t) +{ + double r = ::fmod (Day(t) + 4.0, 7.0); + return (r >= 0) ? r : r + 7.0; +} + + +static inline double MakeTime(double hour, double min, double sec, double ms) +{ + return ((hour * MinutesPerHour + min) * SecondsPerMinute + sec) * msPerSecond + ms; +} + +static inline double DayFromMonth(double month, double leap) +{ + switch ((int) month) { + case 0: return 0; + case 1: return 31.0; + case 2: return 59.0 + leap; + case 3: return 90.0 + leap; + case 4: return 120.0 + leap; + case 5: return 151.0 + leap; + case 6: return 181.0 + leap; + case 7: return 212.0 + leap; + case 8: return 243.0 + leap; + case 9: return 273.0 + leap; + case 10: return 304.0 + leap; + case 11: return 334.0 + leap; + } + + return qSNaN(); // ### assert? +} + +static double MakeDay(double year, double month, double day) +{ + year += ::floor(month / 12.0); + + month = ::fmod(month, 12.0); + if (month < 0) + month += 12.0; + + double t = TimeFromYear(year); + double leap = InLeapYear(t); + + day += ::floor(t / msPerDay); + day += DayFromMonth(month, leap); + + return day - 1; +} + +static inline double MakeDate(double day, double time) +{ + return day * msPerDay + time; +} + +static inline double DaylightSavingTA(double t) +{ +#ifndef Q_WS_WIN + long int tt = (long int)(t / msPerSecond); + struct tm tmtm; + if (!localtime_r((const time_t*)&tt, &tmtm)) + return 0; + return (tmtm.tm_isdst > 0) ? msPerHour : 0; +#else + Q_UNUSED(t); + /// ### implement me + return 0; +#endif +} + +static inline double LocalTime(double t) +{ + return t + LocalTZA + DaylightSavingTA(t); +} + +static inline double UTC(double t) +{ + return t - LocalTZA - DaylightSavingTA(t - LocalTZA); +} + +static inline double currentTime() +{ +#ifndef Q_WS_WIN + struct timeval tv; + + gettimeofday(&tv, 0); + return ::floor(tv.tv_sec * msPerSecond + (tv.tv_usec / 1000.0)); +#else + SYSTEMTIME st; + GetSystemTime(&st); + FILETIME ft; + SystemTimeToFileTime(&st, &ft); + LARGE_INTEGER li; + li.LowPart = ft.dwLowDateTime; + li.HighPart = ft.dwHighDateTime; + return double(li.QuadPart - Q_INT64_C(116444736000000000)) / 10000.0; +#endif +} + +static inline double TimeClip(double t) +{ + if (! qIsFinite(t) || fabs(t) > 8.64e15) + return qSNaN(); + return Value::toInteger(t); +} + +static inline double FromDateTime(const QDateTime &dt) +{ + if (!dt.isValid()) + return qSNaN(); + QDate date = dt.date(); + QTime taim = dt.time(); + int year = date.year(); + int month = date.month() - 1; + int day = date.day(); + int hours = taim.hour(); + int mins = taim.minute(); + int secs = taim.second(); + int ms = taim.msec(); + double t = MakeDate(MakeDay(year, month, day), + MakeTime(hours, mins, secs, ms)); + if (dt.timeSpec() == Qt::LocalTime) + t = UTC(t); + return TimeClip(t); +} + +static inline double ParseString(const QString &s) +{ + // first try the format defined in 15.9.1.15, only if that fails fall back to + // QDateTime for parsing + + // the define string format is YYYY-MM-DDTHH:mm:ss.sssZ + // It can be date or time only, and the second and later components + // of both fields are optional + // and extended syntax for negative and large positive years exists: +/-YYYYYY + + enum Format { + Year, + Month, + Day, + Hour, + Minute, + Second, + MilliSecond, + TimezoneHour, + TimezoneMinute, + Done + }; + + const QChar *ch = s.constData(); + const QChar *end = ch + s.length(); + + uint format = Year; + int current = 0; + int currentSize = 0; + bool extendedYear = false; + + int yearSign = 1; + int year = 0; + int month = 0; + int day = 1; + int hour = 0; + int minute = 0; + int second = 0; + int msec = 0; + int offsetSign = 1; + int offset = 0; + + bool error = false; + if (*ch == '+' || *ch == '-') { + extendedYear = true; + if (*ch == '-') + yearSign = -1; + ++ch; + } + while (ch <= end) { + if (*ch >= '0' && *ch <= '9') { + current *= 10; + current += ch->unicode() - '0'; + ++currentSize; + } else { // other char, delimits field + switch (format) { + case Year: + year = current; + if (extendedYear) + error = (currentSize != 6); + else + error = (currentSize != 4); + break; + case Month: + month = current - 1; + error = (currentSize != 2) || month > 11; + break; + case Day: + day = current; + error = (currentSize != 2) || day > 31; + break; + case Hour: + hour = current; + error = (currentSize != 2) || hour > 24; + break; + case Minute: + minute = current; + error = (currentSize != 2) || minute > 60; + break; + case Second: + second = current; + error = (currentSize != 2) || second > 60; + break; + case MilliSecond: + msec = current; + error = (currentSize != 3); + break; + case TimezoneHour: + offset = current*60; + error = (currentSize != 2) || offset > 23*60; + break; + case TimezoneMinute: + offset += current; + error = (currentSize != 2) || current >= 60; + break; + } + if (*ch == 'T') { + if (format >= Hour) + error = true; + format = Hour; + } else if (*ch == '-') { + if (format < Day) + ++format; + else if (format < Minute) + error = true; + else if (format >= TimezoneHour) + error = true; + else { + offsetSign = -1; + format = TimezoneHour; + } + } else if (*ch == ':') { + if (format != Hour && format != Minute && format != TimezoneHour) + error = true; + ++format; + } else if (*ch == '.') { + if (format != Second) + error = true; + ++format; + } else if (*ch == '+') { + if (format < Minute || format >= TimezoneHour) + error = true; + format = TimezoneHour; + } else if (*ch == 'Z' || *ch == 0) { + format = Done; + } + current = 0; + currentSize = 0; + } + if (error || format == Done) + break; + ++ch; + } + + if (!error) { + double t = MakeDate(MakeDay(year * yearSign, month, day), MakeTime(hour, minute, second, msec)); + t += offset * offsetSign * 60 * 1000; + return t; + } + + QDateTime dt = QDateTime::fromString(s, Qt::TextDate); + if (!dt.isValid()) + dt = QDateTime::fromString(s, Qt::ISODate); + if (!dt.isValid()) { + QStringList formats; + formats << QStringLiteral("M/d/yyyy") + << QStringLiteral("M/d/yyyy hh:mm") + << QStringLiteral("M/d/yyyy hh:mm A") + + << QStringLiteral("M/d/yyyy, hh:mm") + << QStringLiteral("M/d/yyyy, hh:mm A") + + << QStringLiteral("MMM d yyyy") + << QStringLiteral("MMM d yyyy hh:mm") + << QStringLiteral("MMM d yyyy hh:mm:ss") + << QStringLiteral("MMM d yyyy, hh:mm") + << QStringLiteral("MMM d yyyy, hh:mm:ss") + + << QStringLiteral("MMMM d yyyy") + << QStringLiteral("MMMM d yyyy hh:mm") + << QStringLiteral("MMMM d yyyy hh:mm:ss") + << QStringLiteral("MMMM d yyyy, hh:mm") + << QStringLiteral("MMMM d yyyy, hh:mm:ss") + + << QStringLiteral("MMM d, yyyy") + << QStringLiteral("MMM d, yyyy hh:mm") + << QStringLiteral("MMM d, yyyy hh:mm:ss") + + << QStringLiteral("MMMM d, yyyy") + << QStringLiteral("MMMM d, yyyy hh:mm") + << QStringLiteral("MMMM d, yyyy hh:mm:ss") + + << QStringLiteral("d MMM yyyy") + << QStringLiteral("d MMM yyyy hh:mm") + << QStringLiteral("d MMM yyyy hh:mm:ss") + << QStringLiteral("d MMM yyyy, hh:mm") + << QStringLiteral("d MMM yyyy, hh:mm:ss") + + << QStringLiteral("d MMMM yyyy") + << QStringLiteral("d MMMM yyyy hh:mm") + << QStringLiteral("d MMMM yyyy hh:mm:ss") + << QStringLiteral("d MMMM yyyy, hh:mm") + << QStringLiteral("d MMMM yyyy, hh:mm:ss") + + << QStringLiteral("d MMM, yyyy") + << QStringLiteral("d MMM, yyyy hh:mm") + << QStringLiteral("d MMM, yyyy hh:mm:ss") + + << QStringLiteral("d MMMM, yyyy") + << QStringLiteral("d MMMM, yyyy hh:mm") + << QStringLiteral("d MMMM, yyyy hh:mm:ss"); + + for (int i = 0; i < formats.size(); ++i) { + dt = QDateTime::fromString(s, formats.at(i)); + if (dt.isValid()) + break; + } + } + return FromDateTime(dt); +} + +/*! + \internal + + Converts the ECMA Date value \tt (in UTC form) to QDateTime + according to \a spec. +*/ +static inline QDateTime ToDateTime(double t, Qt::TimeSpec spec) +{ + if (std::isnan(t)) + return QDateTime(); + if (spec == Qt::LocalTime) + t = LocalTime(t); + int year = int(YearFromTime(t)); + int month = int(MonthFromTime(t) + 1); + int day = int(DateFromTime(t)); + int hours = HourFromTime(t); + int mins = MinFromTime(t); + int secs = SecFromTime(t); + int ms = msFromTime(t); + return QDateTime(QDate(year, month, day), QTime(hours, mins, secs, ms), spec); +} + +static inline QString ToString(double t) +{ + if (std::isnan(t)) + return QStringLiteral("Invalid Date"); + QString str = ToDateTime(t, Qt::LocalTime).toString() + QStringLiteral(" GMT"); + double tzoffset = LocalTZA + DaylightSavingTA(t); + if (tzoffset) { + int hours = static_cast(::fabs(tzoffset) / 1000 / 60 / 60); + int mins = int(::fabs(tzoffset) / 1000 / 60) % 60; + str.append(QLatin1Char((tzoffset > 0) ? '+' : '-')); + if (hours < 10) + str.append(QLatin1Char('0')); + str.append(QString::number(hours)); + if (mins < 10) + str.append(QLatin1Char('0')); + str.append(QString::number(mins)); + } + return str; +} + +static inline QString ToUTCString(double t) +{ + if (std::isnan(t)) + return QStringLiteral("Invalid Date"); + return ToDateTime(t, Qt::UTC).toString() + QStringLiteral(" GMT"); +} + +static inline QString ToDateString(double t) +{ + return ToDateTime(t, Qt::LocalTime).date().toString(); +} + +static inline QString ToTimeString(double t) +{ + return ToDateTime(t, Qt::LocalTime).time().toString(); +} + +static inline QString ToLocaleString(double t) +{ + return ToDateTime(t, Qt::LocalTime).toString(Qt::LocaleDate); +} + +static inline QString ToLocaleDateString(double t) +{ + return ToDateTime(t, Qt::LocalTime).date().toString(Qt::LocaleDate); +} + +static inline QString ToLocaleTimeString(double t) +{ + return ToDateTime(t, Qt::LocalTime).time().toString(Qt::LocaleDate); +} + +static double getLocalTZA() +{ +#ifndef Q_WS_WIN + struct tm t; + time_t curr; + time(&curr); + localtime_r(&curr, &t); + time_t locl = mktime(&t); + gmtime_r(&curr, &t); + time_t globl = mktime(&t); + return double(locl - globl) * 1000.0; +#else + TIME_ZONE_INFORMATION tzInfo; + GetTimeZoneInformation(&tzInfo); + return -tzInfo.Bias * 60.0 * 1000.0; +#endif +} + + +DateCtor::DateCtor(ExecutionContext *scope) + : FunctionObject(scope) +{ +} + +Value DateCtor::construct(ExecutionContext *ctx) +{ + double t = 0; + + if (ctx->argumentCount == 0) + t = currentTime(); + + else if (ctx->argumentCount == 1) { + Value arg = ctx->argument(0); + if (DateObject *d = arg.asDateObject()) + arg = d->value; + else + arg = __qmljs_to_primitive(arg, ctx, PREFERREDTYPE_HINT); + + if (arg.isString()) + t = ParseString(arg.stringValue()->toQString()); + else + t = TimeClip(arg.toNumber(ctx)); + } + + else { // ctx->argumentCount > 1 + double year = ctx->argument(0).toNumber(ctx); + double month = ctx->argument(1).toNumber(ctx); + double day = ctx->argumentCount >= 3 ? ctx->argument(2).toNumber(ctx) : 1; + double hours = ctx->argumentCount >= 4 ? ctx->argument(3).toNumber(ctx) : 0; + double mins = ctx->argumentCount >= 5 ? ctx->argument(4).toNumber(ctx) : 0; + double secs = ctx->argumentCount >= 6 ? ctx->argument(5).toNumber(ctx) : 0; + double ms = ctx->argumentCount >= 7 ? ctx->argument(6).toNumber(ctx) : 0; + if (year >= 0 && year <= 99) + year += 1900; + t = MakeDate(MakeDay(year, month, day), MakeTime(hours, mins, secs, ms)); + t = TimeClip(UTC(t)); + } + + Object *d = ctx->engine->newDateObject(Value::fromDouble(t)); + return Value::fromObject(d); +} + +Value DateCtor::call(ExecutionContext *ctx) +{ + double t = currentTime(); + return Value::fromString(ctx, ToString(t)); +} + +void DatePrototype::init(ExecutionContext *ctx, const Value &ctor) +{ + ctor.objectValue()->defineReadonlyProperty(ctx->engine->id_prototype, Value::fromObject(this)); + ctor.objectValue()->defineReadonlyProperty(ctx->engine->id_length, Value::fromInt32(1)); + LocalTZA = getLocalTZA(); + + ctor.objectValue()->defineDefaultProperty(ctx, QStringLiteral("parse"), method_parse, 1); + ctor.objectValue()->defineDefaultProperty(ctx, QStringLiteral("UTC"), method_UTC, 7); + + defineDefaultProperty(ctx, QStringLiteral("constructor"), ctor); + defineDefaultProperty(ctx, QStringLiteral("toString"), method_toString, 0); + defineDefaultProperty(ctx, QStringLiteral("toDateString"), method_toDateString, 0); + defineDefaultProperty(ctx, QStringLiteral("toTimeString"), method_toTimeString, 0); + defineDefaultProperty(ctx, QStringLiteral("toLocaleString"), method_toLocaleString, 0); + defineDefaultProperty(ctx, QStringLiteral("toLocaleDateString"), method_toLocaleDateString, 0); + defineDefaultProperty(ctx, QStringLiteral("toLocaleTimeString"), method_toLocaleTimeString, 0); + defineDefaultProperty(ctx, QStringLiteral("valueOf"), method_valueOf, 0); + defineDefaultProperty(ctx, QStringLiteral("getTime"), method_getTime, 0); + defineDefaultProperty(ctx, QStringLiteral("getYear"), method_getYear, 0); + defineDefaultProperty(ctx, QStringLiteral("getFullYear"), method_getFullYear, 0); + defineDefaultProperty(ctx, QStringLiteral("getUTCFullYear"), method_getUTCFullYear, 0); + defineDefaultProperty(ctx, QStringLiteral("getMonth"), method_getMonth, 0); + defineDefaultProperty(ctx, QStringLiteral("getUTCMonth"), method_getUTCMonth, 0); + defineDefaultProperty(ctx, QStringLiteral("getDate"), method_getDate, 0); + defineDefaultProperty(ctx, QStringLiteral("getUTCDate"), method_getUTCDate, 0); + defineDefaultProperty(ctx, QStringLiteral("getDay"), method_getDay, 0); + defineDefaultProperty(ctx, QStringLiteral("getUTCDay"), method_getUTCDay, 0); + defineDefaultProperty(ctx, QStringLiteral("getHours"), method_getHours, 0); + defineDefaultProperty(ctx, QStringLiteral("getUTCHours"), method_getUTCHours, 0); + defineDefaultProperty(ctx, QStringLiteral("getMinutes"), method_getMinutes, 0); + defineDefaultProperty(ctx, QStringLiteral("getUTCMinutes"), method_getUTCMinutes, 0); + defineDefaultProperty(ctx, QStringLiteral("getSeconds"), method_getSeconds, 0); + defineDefaultProperty(ctx, QStringLiteral("getUTCSeconds"), method_getUTCSeconds, 0); + defineDefaultProperty(ctx, QStringLiteral("getMilliseconds"), method_getMilliseconds, 0); + defineDefaultProperty(ctx, QStringLiteral("getUTCMilliseconds"), method_getUTCMilliseconds, 0); + defineDefaultProperty(ctx, QStringLiteral("getTimezoneOffset"), method_getTimezoneOffset, 0); + defineDefaultProperty(ctx, QStringLiteral("setTime"), method_setTime, 1); + defineDefaultProperty(ctx, QStringLiteral("setMilliseconds"), method_setMilliseconds, 1); + defineDefaultProperty(ctx, QStringLiteral("setUTCMilliseconds"), method_setUTCMilliseconds, 1); + defineDefaultProperty(ctx, QStringLiteral("setSeconds"), method_setSeconds, 2); + defineDefaultProperty(ctx, QStringLiteral("setUTCSeconds"), method_setUTCSeconds, 2); + defineDefaultProperty(ctx, QStringLiteral("setMinutes"), method_setMinutes, 3); + defineDefaultProperty(ctx, QStringLiteral("setUTCMinutes"), method_setUTCMinutes, 3); + defineDefaultProperty(ctx, QStringLiteral("setHours"), method_setHours, 4); + defineDefaultProperty(ctx, QStringLiteral("setUTCHours"), method_setUTCHours, 4); + defineDefaultProperty(ctx, QStringLiteral("setDate"), method_setDate, 1); + defineDefaultProperty(ctx, QStringLiteral("setUTCDate"), method_setUTCDate, 1); + defineDefaultProperty(ctx, QStringLiteral("setMonth"), method_setMonth, 2); + defineDefaultProperty(ctx, QStringLiteral("setUTCMonth"), method_setUTCMonth, 2); + defineDefaultProperty(ctx, QStringLiteral("setYear"), method_setYear, 1); + defineDefaultProperty(ctx, QStringLiteral("setFullYear"), method_setFullYear, 3); + defineDefaultProperty(ctx, QStringLiteral("setUTCFullYear"), method_setUTCFullYear, 3); + defineDefaultProperty(ctx, QStringLiteral("toUTCString"), method_toUTCString, 0); + defineDefaultProperty(ctx, QStringLiteral("toGMTString"), method_toUTCString, 0); + defineDefaultProperty(ctx, QStringLiteral("toISOString"), method_toISOString, 0); +} + +double DatePrototype::getThisDate(ExecutionContext *ctx) +{ + if (DateObject *thisObject = ctx->thisObject.asDateObject()) + return thisObject->value.asDouble(); + else { + ctx->throwTypeError(); + return 0; + } +} + +Value DatePrototype::method_parse(ExecutionContext *ctx) +{ + return Value::fromDouble(ParseString(ctx->argument(0).toString(ctx)->toQString())); +} + +Value DatePrototype::method_UTC(ExecutionContext *ctx) +{ + const int numArgs = ctx->argumentCount; + if (numArgs >= 2) { + double year = ctx->argument(0).toNumber(ctx); + double month = ctx->argument(1).toNumber(ctx); + double day = numArgs >= 3 ? ctx->argument(2).toNumber(ctx) : 1; + double hours = numArgs >= 4 ? ctx->argument(3).toNumber(ctx) : 0; + double mins = numArgs >= 5 ? ctx->argument(4).toNumber(ctx) : 0; + double secs = numArgs >= 6 ? ctx->argument(5).toNumber(ctx) : 0; + double ms = numArgs >= 7 ? ctx->argument(6).toNumber(ctx) : 0; + if (year >= 0 && year <= 99) + year += 1900; + double t = MakeDate(MakeDay(year, month, day), + MakeTime(hours, mins, secs, ms)); + return Value::fromDouble(TimeClip(t)); + } + return Value::undefinedValue(); +} + +Value DatePrototype::method_toString(ExecutionContext *ctx) +{ + double t = getThisDate(ctx); + return Value::fromString(ctx, ToString(t)); +} + +Value DatePrototype::method_toDateString(ExecutionContext *ctx) +{ + double t = getThisDate(ctx); + return Value::fromString(ctx, ToDateString(t)); +} + +Value DatePrototype::method_toTimeString(ExecutionContext *ctx) +{ + double t = getThisDate(ctx); + return Value::fromString(ctx, ToTimeString(t)); +} + +Value DatePrototype::method_toLocaleString(ExecutionContext *ctx) +{ + double t = getThisDate(ctx); + return Value::fromString(ctx, ToLocaleString(t)); +} + +Value DatePrototype::method_toLocaleDateString(ExecutionContext *ctx) +{ + double t = getThisDate(ctx); + return Value::fromString(ctx, ToLocaleDateString(t)); +} + +Value DatePrototype::method_toLocaleTimeString(ExecutionContext *ctx) +{ + double t = getThisDate(ctx); + return Value::fromString(ctx, ToLocaleTimeString(t)); +} + +Value DatePrototype::method_valueOf(ExecutionContext *ctx) +{ + double t = getThisDate(ctx); + return Value::fromDouble(t); +} + +Value DatePrototype::method_getTime(ExecutionContext *ctx) +{ + double t = getThisDate(ctx); + return Value::fromDouble(t); +} + +Value DatePrototype::method_getYear(ExecutionContext *ctx) +{ + double t = getThisDate(ctx); + if (! std::isnan(t)) + t = YearFromTime(LocalTime(t)) - 1900; + return Value::fromDouble(t); +} + +Value DatePrototype::method_getFullYear(ExecutionContext *ctx) +{ + double t = getThisDate(ctx); + if (! std::isnan(t)) + t = YearFromTime(LocalTime(t)); + return Value::fromDouble(t); +} + +Value DatePrototype::method_getUTCFullYear(ExecutionContext *ctx) +{ + double t = getThisDate(ctx); + if (! std::isnan(t)) + t = YearFromTime(t); + return Value::fromDouble(t); +} + +Value DatePrototype::method_getMonth(ExecutionContext *ctx) +{ + double t = getThisDate(ctx); + if (! std::isnan(t)) + t = MonthFromTime(LocalTime(t)); + return Value::fromDouble(t); +} + +Value DatePrototype::method_getUTCMonth(ExecutionContext *ctx) +{ + double t = getThisDate(ctx); + if (! std::isnan(t)) + t = MonthFromTime(t); + return Value::fromDouble(t); +} + +Value DatePrototype::method_getDate(ExecutionContext *ctx) +{ + double t = getThisDate(ctx); + if (! std::isnan(t)) + t = DateFromTime(LocalTime(t)); + return Value::fromDouble(t); +} + +Value DatePrototype::method_getUTCDate(ExecutionContext *ctx) +{ + double t = getThisDate(ctx); + if (! std::isnan(t)) + t = DateFromTime(t); + return Value::fromDouble(t); +} + +Value DatePrototype::method_getDay(ExecutionContext *ctx) +{ + double t = getThisDate(ctx); + if (! std::isnan(t)) + t = WeekDay(LocalTime(t)); + return Value::fromDouble(t); +} + +Value DatePrototype::method_getUTCDay(ExecutionContext *ctx) +{ + double t = getThisDate(ctx); + if (! std::isnan(t)) + t = WeekDay(t); + return Value::fromDouble(t); +} + +Value DatePrototype::method_getHours(ExecutionContext *ctx) +{ + double t = getThisDate(ctx); + if (! std::isnan(t)) + t = HourFromTime(LocalTime(t)); + return Value::fromDouble(t); +} + +Value DatePrototype::method_getUTCHours(ExecutionContext *ctx) +{ + double t = getThisDate(ctx); + if (! std::isnan(t)) + t = HourFromTime(t); + return Value::fromDouble(t); +} + +Value DatePrototype::method_getMinutes(ExecutionContext *ctx) +{ + double t = getThisDate(ctx); + if (! std::isnan(t)) + t = MinFromTime(LocalTime(t)); + return Value::fromDouble(t); +} + +Value DatePrototype::method_getUTCMinutes(ExecutionContext *ctx) +{ + double t = getThisDate(ctx); + if (! std::isnan(t)) + t = MinFromTime(t); + return Value::fromDouble(t); +} + +Value DatePrototype::method_getSeconds(ExecutionContext *ctx) +{ + double t = getThisDate(ctx); + if (! std::isnan(t)) + t = SecFromTime(LocalTime(t)); + return Value::fromDouble(t); +} + +Value DatePrototype::method_getUTCSeconds(ExecutionContext *ctx) +{ + double t = getThisDate(ctx); + if (! std::isnan(t)) + t = SecFromTime(t); + return Value::fromDouble(t); +} + +Value DatePrototype::method_getMilliseconds(ExecutionContext *ctx) +{ + double t = getThisDate(ctx); + if (! std::isnan(t)) + t = msFromTime(LocalTime(t)); + return Value::fromDouble(t); +} + +Value DatePrototype::method_getUTCMilliseconds(ExecutionContext *ctx) +{ + double t = getThisDate(ctx); + if (! std::isnan(t)) + t = msFromTime(t); + return Value::fromDouble(t); +} + +Value DatePrototype::method_getTimezoneOffset(ExecutionContext *ctx) +{ + double t = getThisDate(ctx); + if (! std::isnan(t)) + t = (t - LocalTime(t)) / msPerMinute; + return Value::fromDouble(t); +} + +Value DatePrototype::method_setTime(ExecutionContext *ctx) +{ + DateObject *self = ctx->thisObject.asDateObject(); + if (!self) + ctx->throwTypeError(); + + self->value.setDouble(TimeClip(ctx->argument(0).toNumber(ctx))); + return self->value; +} + +Value DatePrototype::method_setMilliseconds(ExecutionContext *ctx) +{ + DateObject *self = ctx->thisObject.asDateObject(); + if (!self) + ctx->throwTypeError(); + + double t = LocalTime(self->value.asDouble()); + double ms = ctx->argument(0).toNumber(ctx); + self->value.setDouble(TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), SecFromTime(t), ms))))); + return self->value; +} + +Value DatePrototype::method_setUTCMilliseconds(ExecutionContext *ctx) +{ + DateObject *self = ctx->thisObject.asDateObject(); + if (!self) + ctx->throwTypeError(); + + double t = self->value.asDouble(); + double ms = ctx->argument(0).toNumber(ctx); + self->value.setDouble(TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), SecFromTime(t), ms))))); + return self->value; +} + +Value DatePrototype::method_setSeconds(ExecutionContext *ctx) +{ + DateObject *self = ctx->thisObject.asDateObject(); + if (!self) + ctx->throwTypeError(); + + double t = LocalTime(self->value.asDouble()); + double sec = ctx->argument(0).toNumber(ctx); + double ms = (ctx->argumentCount < 2) ? msFromTime(t) : ctx->argument(1).toNumber(ctx); + t = TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), sec, ms)))); + self->value.setDouble(t); + return self->value; +} + +Value DatePrototype::method_setUTCSeconds(ExecutionContext *ctx) +{ + DateObject *self = ctx->thisObject.asDateObject(); + if (!self) + ctx->throwTypeError(); + + double t = self->value.asDouble(); + double sec = ctx->argument(0).toNumber(ctx); + double ms = (ctx->argumentCount < 2) ? msFromTime(t) : ctx->argument(1).toNumber(ctx); + t = TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), sec, ms)))); + self->value.setDouble(t); + return self->value; +} + +Value DatePrototype::method_setMinutes(ExecutionContext *ctx) +{ + DateObject *self = ctx->thisObject.asDateObject(); + if (!self) + ctx->throwTypeError(); + + double t = LocalTime(self->value.asDouble()); + double min = ctx->argument(0).toNumber(ctx); + double sec = (ctx->argumentCount < 2) ? SecFromTime(t) : ctx->argument(1).toNumber(ctx); + double ms = (ctx->argumentCount < 3) ? msFromTime(t) : ctx->argument(2).toNumber(ctx); + t = TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), min, sec, ms)))); + self->value.setDouble(t); + return self->value; +} + +Value DatePrototype::method_setUTCMinutes(ExecutionContext *ctx) +{ + DateObject *self = ctx->thisObject.asDateObject(); + if (!self) + ctx->throwTypeError(); + + double t = self->value.asDouble(); + double min = ctx->argument(0).toNumber(ctx); + double sec = (ctx->argumentCount < 2) ? SecFromTime(t) : ctx->argument(1).toNumber(ctx); + double ms = (ctx->argumentCount < 3) ? msFromTime(t) : ctx->argument(2).toNumber(ctx); + t = TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), min, sec, ms)))); + self->value.setDouble(t); + return self->value; +} + +Value DatePrototype::method_setHours(ExecutionContext *ctx) +{ + DateObject *self = ctx->thisObject.asDateObject(); + if (!self) + ctx->throwTypeError(); + + double t = LocalTime(self->value.asDouble()); + double hour = ctx->argument(0).toNumber(ctx); + double min = (ctx->argumentCount < 2) ? MinFromTime(t) : ctx->argument(1).toNumber(ctx); + double sec = (ctx->argumentCount < 3) ? SecFromTime(t) : ctx->argument(2).toNumber(ctx); + double ms = (ctx->argumentCount < 4) ? msFromTime(t) : ctx->argument(3).toNumber(ctx); + t = TimeClip(UTC(MakeDate(Day(t), MakeTime(hour, min, sec, ms)))); + self->value.setDouble(t); + return self->value; +} + +Value DatePrototype::method_setUTCHours(ExecutionContext *ctx) +{ + DateObject *self = ctx->thisObject.asDateObject(); + if (!self) + ctx->throwTypeError(); + + double t = self->value.asDouble(); + double hour = ctx->argument(0).toNumber(ctx); + double min = (ctx->argumentCount < 2) ? MinFromTime(t) : ctx->argument(1).toNumber(ctx); + double sec = (ctx->argumentCount < 3) ? SecFromTime(t) : ctx->argument(2).toNumber(ctx); + double ms = (ctx->argumentCount < 4) ? msFromTime(t) : ctx->argument(3).toNumber(ctx); + t = TimeClip(UTC(MakeDate(Day(t), MakeTime(hour, min, sec, ms)))); + self->value.setDouble(t); + return self->value; +} + +Value DatePrototype::method_setDate(ExecutionContext *ctx) +{ + DateObject *self = ctx->thisObject.asDateObject(); + if (!self) + ctx->throwTypeError(); + + double t = LocalTime(self->value.asDouble()); + double date = ctx->argument(0).toNumber(ctx); + t = TimeClip(UTC(MakeDate(MakeDay(YearFromTime(t), MonthFromTime(t), date), TimeWithinDay(t)))); + self->value.setDouble(t); + return self->value; +} + +Value DatePrototype::method_setUTCDate(ExecutionContext *ctx) +{ + DateObject *self = ctx->thisObject.asDateObject(); + if (!self) + ctx->throwTypeError(); + + double t = self->value.asDouble(); + double date = ctx->argument(0).toNumber(ctx); + t = TimeClip(UTC(MakeDate(MakeDay(YearFromTime(t), MonthFromTime(t), date), TimeWithinDay(t)))); + self->value.setDouble(t); + return self->value; +} + +Value DatePrototype::method_setMonth(ExecutionContext *ctx) +{ + DateObject *self = ctx->thisObject.asDateObject(); + if (!self) + ctx->throwTypeError(); + + double t = LocalTime(self->value.asDouble()); + double month = ctx->argument(0).toNumber(ctx); + double date = (ctx->argumentCount < 2) ? DateFromTime(t) : ctx->argument(1).toNumber(ctx); + t = TimeClip(UTC(MakeDate(MakeDay(YearFromTime(t), month, date), TimeWithinDay(t)))); + self->value.setDouble(t); + return self->value; +} + +Value DatePrototype::method_setUTCMonth(ExecutionContext *ctx) +{ + DateObject *self = ctx->thisObject.asDateObject(); + if (!self) + ctx->throwTypeError(); + + double t = self->value.asDouble(); + double month = ctx->argument(0).toNumber(ctx); + double date = (ctx->argumentCount < 2) ? DateFromTime(t) : ctx->argument(1).toNumber(ctx); + t = TimeClip(UTC(MakeDate(MakeDay(YearFromTime(t), month, date), TimeWithinDay(t)))); + self->value.setDouble(t); + return self->value; +} + +Value DatePrototype::method_setYear(ExecutionContext *ctx) +{ + DateObject *self = ctx->thisObject.asDateObject(); + if (!self) + ctx->throwTypeError(); + + double t = self->value.asDouble(); + if (std::isnan(t)) + t = 0; + else + t = LocalTime(t); + double year = ctx->argument(0).toNumber(ctx); + double r; + if (std::isnan(year)) { + r = qSNaN(); + } else { + if ((Value::toInteger(year) >= 0) && (Value::toInteger(year) <= 99)) + year += 1900; + r = MakeDay(year, MonthFromTime(t), DateFromTime(t)); + r = UTC(MakeDate(r, TimeWithinDay(t))); + r = TimeClip(r); + } + self->value.setDouble(r); + return self->value; +} + +Value DatePrototype::method_setUTCFullYear(ExecutionContext *ctx) +{ + DateObject *self = ctx->thisObject.asDateObject(); + if (!self) + ctx->throwTypeError(); + + double t = self->value.asDouble(); + double year = ctx->argument(0).toNumber(ctx); + double month = (ctx->argumentCount < 2) ? MonthFromTime(t) : ctx->argument(1).toNumber(ctx); + double date = (ctx->argumentCount < 3) ? DateFromTime(t) : ctx->argument(2).toNumber(ctx); + t = TimeClip(UTC(MakeDate(MakeDay(year, month, date), TimeWithinDay(t)))); + self->value.setDouble(t); + return self->value; +} + +Value DatePrototype::method_setFullYear(ExecutionContext *ctx) +{ + DateObject *self = ctx->thisObject.asDateObject(); + if (!self) + ctx->throwTypeError(); + + double t = LocalTime(self->value.asDouble()); + double year = ctx->argument(0).toNumber(ctx); + double month = (ctx->argumentCount < 2) ? MonthFromTime(t) : ctx->argument(1).toNumber(ctx); + double date = (ctx->argumentCount < 3) ? DateFromTime(t) : ctx->argument(2).toNumber(ctx); + t = TimeClip(UTC(MakeDate(MakeDay(year, month, date), TimeWithinDay(t)))); + self->value.setDouble(t); + return self->value; +} + +Value DatePrototype::method_toUTCString(ExecutionContext *ctx) +{ + DateObject *self = ctx->thisObject.asDateObject(); + if (!self) + ctx->throwTypeError(); + + double t = self->value.asDouble(); + return Value::fromString(ctx, ToUTCString(t)); +} + +static void addZeroPrefixedInt(QString &str, int num, int nDigits) +{ + str.resize(str.size() + nDigits); + + QChar *c = str.data() + str.size() - 1; + while (nDigits) { + *c = QChar(num % 10 + '0'); + num /= 10; + --c; + --nDigits; + } +} + +Value DatePrototype::method_toISOString(ExecutionContext *ctx) +{ + DateObject *self = ctx->thisObject.asDateObject(); + if (!self) + ctx->throwTypeError(); + + double t = self->value.asDouble(); + if (!std::isfinite(t)) + ctx->throwRangeError(ctx->thisObject); + + QString result; + int year = (int)YearFromTime(t); + if (year < 0 || year > 9999) { + if (qAbs(year) >= 1000000) + return Value::fromString(ctx, QStringLiteral("Invalid Date")); + result += year < 0 ? '-' : '+'; + year = qAbs(year); + addZeroPrefixedInt(result, year, 6); + } else { + addZeroPrefixedInt(result, year, 4); + } + result += '-'; + addZeroPrefixedInt(result, (int)MonthFromTime(t) + 1, 2); + result += '-'; + addZeroPrefixedInt(result, (int)DateFromTime(t), 2); + result += 'T'; + addZeroPrefixedInt(result, HourFromTime(t), 2); + result += ':'; + addZeroPrefixedInt(result, MinFromTime(t), 2); + result += ':'; + addZeroPrefixedInt(result, SecFromTime(t), 2); + result += '.'; + addZeroPrefixedInt(result, msFromTime(t), 3); + result += 'Z'; + + return Value::fromString(ctx, result); +} diff --git a/qv4dateobject.h b/qv4dateobject.h new file mode 100644 index 0000000..3a67c47 --- /dev/null +++ b/qv4dateobject.h @@ -0,0 +1,125 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the V4VM module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef QV4DATEOBJECT_P_H +#define QV4DATEOBJECT_P_H + +#include "qmljs_objects.h" +#include "qv4ecmaobjects_p.h" +#include + +namespace QQmlJS { +namespace VM { + +struct DateObject: Object { + Value value; + DateObject(const Value &value): value(value) {} + virtual QString className() { return QStringLiteral("Date"); } + virtual DateObject *asDateObject() { return this; } +}; + +struct DateCtor: FunctionObject +{ + DateCtor(ExecutionContext *scope); + + virtual Value construct(ExecutionContext *ctx); + virtual Value call(ExecutionContext *ctx); +}; + +struct DatePrototype: DateObject +{ + DatePrototype(): DateObject(Value::fromDouble(qSNaN())) {} + void init(ExecutionContext *ctx, const Value &ctor); + + static double getThisDate(ExecutionContext *ctx); + + static Value method_parse(ExecutionContext *ctx); + static Value method_UTC(ExecutionContext *ctx); + + static Value method_toString(ExecutionContext *ctx); + static Value method_toDateString(ExecutionContext *ctx); + static Value method_toTimeString(ExecutionContext *ctx); + static Value method_toLocaleString(ExecutionContext *ctx); + static Value method_toLocaleDateString(ExecutionContext *ctx); + static Value method_toLocaleTimeString(ExecutionContext *ctx); + static Value method_valueOf(ExecutionContext *ctx); + static Value method_getTime(ExecutionContext *ctx); + static Value method_getYear(ExecutionContext *ctx); + static Value method_getFullYear(ExecutionContext *ctx); + static Value method_getUTCFullYear(ExecutionContext *ctx); + static Value method_getMonth(ExecutionContext *ctx); + static Value method_getUTCMonth(ExecutionContext *ctx); + static Value method_getDate(ExecutionContext *ctx); + static Value method_getUTCDate(ExecutionContext *ctx); + static Value method_getDay(ExecutionContext *ctx); + static Value method_getUTCDay(ExecutionContext *ctx); + static Value method_getHours(ExecutionContext *ctx); + static Value method_getUTCHours(ExecutionContext *ctx); + static Value method_getMinutes(ExecutionContext *ctx); + static Value method_getUTCMinutes(ExecutionContext *ctx); + static Value method_getSeconds(ExecutionContext *ctx); + static Value method_getUTCSeconds(ExecutionContext *ctx); + static Value method_getMilliseconds(ExecutionContext *ctx); + static Value method_getUTCMilliseconds(ExecutionContext *ctx); + static Value method_getTimezoneOffset(ExecutionContext *ctx); + static Value method_setTime(ExecutionContext *ctx); + static Value method_setMilliseconds(ExecutionContext *ctx); + static Value method_setUTCMilliseconds(ExecutionContext *ctx); + static Value method_setSeconds(ExecutionContext *ctx); + static Value method_setUTCSeconds(ExecutionContext *ctx); + static Value method_setMinutes(ExecutionContext *ctx); + static Value method_setUTCMinutes(ExecutionContext *ctx); + static Value method_setHours(ExecutionContext *ctx); + static Value method_setUTCHours(ExecutionContext *ctx); + static Value method_setDate(ExecutionContext *ctx); + static Value method_setUTCDate(ExecutionContext *ctx); + static Value method_setMonth(ExecutionContext *ctx); + static Value method_setUTCMonth(ExecutionContext *ctx); + static Value method_setYear(ExecutionContext *ctx); + static Value method_setFullYear(ExecutionContext *ctx); + static Value method_setUTCFullYear(ExecutionContext *ctx); + static Value method_toUTCString(ExecutionContext *ctx); + static Value method_toISOString(ExecutionContext *ctx); +}; + +} // end of namespace VM +} // end of namespace QQmlJS + +#endif // QV4ECMAOBJECTS_P_H diff --git a/qv4ecmaobjects.cpp b/qv4ecmaobjects.cpp index df3ff9b..933cb18 100644 --- a/qv4ecmaobjects.cpp +++ b/qv4ecmaobjects.cpp @@ -75,588 +75,6 @@ using namespace QQmlJS::VM; static const double qt_PI = 2.0 * ::asin(1.0); -static const double HoursPerDay = 24.0; -static const double MinutesPerHour = 60.0; -static const double SecondsPerMinute = 60.0; -static const double msPerSecond = 1000.0; -static const double msPerMinute = 60000.0; -static const double msPerHour = 3600000.0; -static const double msPerDay = 86400000.0; - -static double LocalTZA = 0.0; // initialized at startup - -static inline double TimeWithinDay(double t) -{ - double r = ::fmod(t, msPerDay); - return (r >= 0) ? r : r + msPerDay; -} - -static inline int HourFromTime(double t) -{ - int r = int(::fmod(::floor(t / msPerHour), HoursPerDay)); - return (r >= 0) ? r : r + int(HoursPerDay); -} - -static inline int MinFromTime(double t) -{ - int r = int(::fmod(::floor(t / msPerMinute), MinutesPerHour)); - return (r >= 0) ? r : r + int(MinutesPerHour); -} - -static inline int SecFromTime(double t) -{ - int r = int(::fmod(::floor(t / msPerSecond), SecondsPerMinute)); - return (r >= 0) ? r : r + int(SecondsPerMinute); -} - -static inline int msFromTime(double t) -{ - int r = int(::fmod(t, msPerSecond)); - return (r >= 0) ? r : r + int(msPerSecond); -} - -static inline double Day(double t) -{ - return ::floor(t / msPerDay); -} - -static inline double DaysInYear(double y) -{ - if (::fmod(y, 4)) - return 365; - - else if (::fmod(y, 100)) - return 366; - - else if (::fmod(y, 400)) - return 365; - - return 366; -} - -static inline double DayFromYear(double y) -{ - return 365 * (y - 1970) - + ::floor((y - 1969) / 4) - - ::floor((y - 1901) / 100) - + ::floor((y - 1601) / 400); -} - -static inline double TimeFromYear(double y) -{ - return msPerDay * DayFromYear(y); -} - -static inline double YearFromTime(double t) -{ - int y = 1970; - y += (int) ::floor(t / (msPerDay * 365.2425)); - - double t2 = TimeFromYear(y); - return (t2 > t) ? y - 1 : ((t2 + msPerDay * DaysInYear(y)) <= t) ? y + 1 : y; -} - -static inline bool InLeapYear(double t) -{ - double x = DaysInYear(YearFromTime(t)); - if (x == 365) - return 0; - - assert(x == 366); - return 1; -} - -static inline double DayWithinYear(double t) -{ - return Day(t) - DayFromYear(YearFromTime(t)); -} - -static inline double MonthFromTime(double t) -{ - double d = DayWithinYear(t); - double l = InLeapYear(t); - - if (d < 31.0) - return 0; - - else if (d < 59.0 + l) - return 1; - - else if (d < 90.0 + l) - return 2; - - else if (d < 120.0 + l) - return 3; - - else if (d < 151.0 + l) - return 4; - - else if (d < 181.0 + l) - return 5; - - else if (d < 212.0 + l) - return 6; - - else if (d < 243.0 + l) - return 7; - - else if (d < 273.0 + l) - return 8; - - else if (d < 304.0 + l) - return 9; - - else if (d < 334.0 + l) - return 10; - - else if (d < 365.0 + l) - return 11; - - return qSNaN(); // ### assert? -} - -static inline double DateFromTime(double t) -{ - int m = (int) Value::toInteger(MonthFromTime(t)); - double d = DayWithinYear(t); - double l = InLeapYear(t); - - switch (m) { - case 0: return d + 1.0; - case 1: return d - 30.0; - case 2: return d - 58.0 - l; - case 3: return d - 89.0 - l; - case 4: return d - 119.0 - l; - case 5: return d - 150.0 - l; - case 6: return d - 180.0 - l; - case 7: return d - 211.0 - l; - case 8: return d - 242.0 - l; - case 9: return d - 272.0 - l; - case 10: return d - 303.0 - l; - case 11: return d - 333.0 - l; - } - - return qSNaN(); // ### assert -} - -static inline double WeekDay(double t) -{ - double r = ::fmod (Day(t) + 4.0, 7.0); - return (r >= 0) ? r : r + 7.0; -} - - -static inline double MakeTime(double hour, double min, double sec, double ms) -{ - return ((hour * MinutesPerHour + min) * SecondsPerMinute + sec) * msPerSecond + ms; -} - -static inline double DayFromMonth(double month, double leap) -{ - switch ((int) month) { - case 0: return 0; - case 1: return 31.0; - case 2: return 59.0 + leap; - case 3: return 90.0 + leap; - case 4: return 120.0 + leap; - case 5: return 151.0 + leap; - case 6: return 181.0 + leap; - case 7: return 212.0 + leap; - case 8: return 243.0 + leap; - case 9: return 273.0 + leap; - case 10: return 304.0 + leap; - case 11: return 334.0 + leap; - } - - return qSNaN(); // ### assert? -} - -static double MakeDay(double year, double month, double day) -{ - year += ::floor(month / 12.0); - - month = ::fmod(month, 12.0); - if (month < 0) - month += 12.0; - - double t = TimeFromYear(year); - double leap = InLeapYear(t); - - day += ::floor(t / msPerDay); - day += DayFromMonth(month, leap); - - return day - 1; -} - -static inline double MakeDate(double day, double time) -{ - return day * msPerDay + time; -} - -static inline double DaylightSavingTA(double t) -{ -#ifndef Q_WS_WIN - long int tt = (long int)(t / msPerSecond); - struct tm tmtm; - if (!localtime_r((const time_t*)&tt, &tmtm)) - return 0; - return (tmtm.tm_isdst > 0) ? msPerHour : 0; -#else - Q_UNUSED(t); - /// ### implement me - return 0; -#endif -} - -static inline double LocalTime(double t) -{ - return t + LocalTZA + DaylightSavingTA(t); -} - -static inline double UTC(double t) -{ - return t - LocalTZA - DaylightSavingTA(t - LocalTZA); -} - -static inline double currentTime() -{ -#ifndef Q_WS_WIN - struct timeval tv; - - gettimeofday(&tv, 0); - return ::floor(tv.tv_sec * msPerSecond + (tv.tv_usec / 1000.0)); -#else - SYSTEMTIME st; - GetSystemTime(&st); - FILETIME ft; - SystemTimeToFileTime(&st, &ft); - LARGE_INTEGER li; - li.LowPart = ft.dwLowDateTime; - li.HighPart = ft.dwHighDateTime; - return double(li.QuadPart - Q_INT64_C(116444736000000000)) / 10000.0; -#endif -} - -static inline double TimeClip(double t) -{ - if (! qIsFinite(t) || fabs(t) > 8.64e15) - return qSNaN(); - return Value::toInteger(t); -} - -static inline double FromDateTime(const QDateTime &dt) -{ - if (!dt.isValid()) - return qSNaN(); - QDate date = dt.date(); - QTime taim = dt.time(); - int year = date.year(); - int month = date.month() - 1; - int day = date.day(); - int hours = taim.hour(); - int mins = taim.minute(); - int secs = taim.second(); - int ms = taim.msec(); - double t = MakeDate(MakeDay(year, month, day), - MakeTime(hours, mins, secs, ms)); - if (dt.timeSpec() == Qt::LocalTime) - t = UTC(t); - return TimeClip(t); -} - -static inline double ParseString(const QString &s) -{ - // first try the format defined in 15.9.1.15, only if that fails fall back to - // QDateTime for parsing - - // the define string format is YYYY-MM-DDTHH:mm:ss.sssZ - // It can be date or time only, and the second and later components - // of both fields are optional - // and extended syntax for negative and large positive years exists: +/-YYYYYY - - enum Format { - Year, - Month, - Day, - Hour, - Minute, - Second, - MilliSecond, - TimezoneHour, - TimezoneMinute, - Done - }; - - const QChar *ch = s.constData(); - const QChar *end = ch + s.length(); - - uint format = Year; - int current = 0; - int currentSize = 0; - bool extendedYear = false; - - int yearSign = 1; - int year = 0; - int month = 0; - int day = 1; - int hour = 0; - int minute = 0; - int second = 0; - int msec = 0; - int offsetSign = 1; - int offset = 0; - - bool error = false; - if (*ch == '+' || *ch == '-') { - extendedYear = true; - if (*ch == '-') - yearSign = -1; - ++ch; - } - while (ch <= end) { - if (*ch >= '0' && *ch <= '9') { - current *= 10; - current += ch->unicode() - '0'; - ++currentSize; - } else { // other char, delimits field - switch (format) { - case Year: - year = current; - if (extendedYear) - error = (currentSize != 6); - else - error = (currentSize != 4); - break; - case Month: - month = current - 1; - error = (currentSize != 2) || month > 11; - break; - case Day: - day = current; - error = (currentSize != 2) || day > 31; - break; - case Hour: - hour = current; - error = (currentSize != 2) || hour > 24; - break; - case Minute: - minute = current; - error = (currentSize != 2) || minute > 60; - break; - case Second: - second = current; - error = (currentSize != 2) || second > 60; - break; - case MilliSecond: - msec = current; - error = (currentSize != 3); - break; - case TimezoneHour: - offset = current*60; - error = (currentSize != 2) || offset > 23*60; - break; - case TimezoneMinute: - offset += current; - error = (currentSize != 2) || current >= 60; - break; - } - if (*ch == 'T') { - if (format >= Hour) - error = true; - format = Hour; - } else if (*ch == '-') { - if (format < Day) - ++format; - else if (format < Minute) - error = true; - else if (format >= TimezoneHour) - error = true; - else { - offsetSign = -1; - format = TimezoneHour; - } - } else if (*ch == ':') { - if (format != Hour && format != Minute && format != TimezoneHour) - error = true; - ++format; - } else if (*ch == '.') { - if (format != Second) - error = true; - ++format; - } else if (*ch == '+') { - if (format < Minute || format >= TimezoneHour) - error = true; - format = TimezoneHour; - } else if (*ch == 'Z' || *ch == 0) { - format = Done; - } - current = 0; - currentSize = 0; - } - if (error || format == Done) - break; - ++ch; - } - - if (!error) { - double t = MakeDate(MakeDay(year * yearSign, month, day), MakeTime(hour, minute, second, msec)); - t += offset * offsetSign * 60 * 1000; - return t; - } - - QDateTime dt = QDateTime::fromString(s, Qt::TextDate); - if (!dt.isValid()) - dt = QDateTime::fromString(s, Qt::ISODate); - if (!dt.isValid()) { - QStringList formats; - formats << QStringLiteral("M/d/yyyy") - << QStringLiteral("M/d/yyyy hh:mm") - << QStringLiteral("M/d/yyyy hh:mm A") - - << QStringLiteral("M/d/yyyy, hh:mm") - << QStringLiteral("M/d/yyyy, hh:mm A") - - << QStringLiteral("MMM d yyyy") - << QStringLiteral("MMM d yyyy hh:mm") - << QStringLiteral("MMM d yyyy hh:mm:ss") - << QStringLiteral("MMM d yyyy, hh:mm") - << QStringLiteral("MMM d yyyy, hh:mm:ss") - - << QStringLiteral("MMMM d yyyy") - << QStringLiteral("MMMM d yyyy hh:mm") - << QStringLiteral("MMMM d yyyy hh:mm:ss") - << QStringLiteral("MMMM d yyyy, hh:mm") - << QStringLiteral("MMMM d yyyy, hh:mm:ss") - - << QStringLiteral("MMM d, yyyy") - << QStringLiteral("MMM d, yyyy hh:mm") - << QStringLiteral("MMM d, yyyy hh:mm:ss") - - << QStringLiteral("MMMM d, yyyy") - << QStringLiteral("MMMM d, yyyy hh:mm") - << QStringLiteral("MMMM d, yyyy hh:mm:ss") - - << QStringLiteral("d MMM yyyy") - << QStringLiteral("d MMM yyyy hh:mm") - << QStringLiteral("d MMM yyyy hh:mm:ss") - << QStringLiteral("d MMM yyyy, hh:mm") - << QStringLiteral("d MMM yyyy, hh:mm:ss") - - << QStringLiteral("d MMMM yyyy") - << QStringLiteral("d MMMM yyyy hh:mm") - << QStringLiteral("d MMMM yyyy hh:mm:ss") - << QStringLiteral("d MMMM yyyy, hh:mm") - << QStringLiteral("d MMMM yyyy, hh:mm:ss") - - << QStringLiteral("d MMM, yyyy") - << QStringLiteral("d MMM, yyyy hh:mm") - << QStringLiteral("d MMM, yyyy hh:mm:ss") - - << QStringLiteral("d MMMM, yyyy") - << QStringLiteral("d MMMM, yyyy hh:mm") - << QStringLiteral("d MMMM, yyyy hh:mm:ss"); - - for (int i = 0; i < formats.size(); ++i) { - dt = QDateTime::fromString(s, formats.at(i)); - if (dt.isValid()) - break; - } - } - return FromDateTime(dt); -} - -/*! - \internal - - Converts the ECMA Date value \tt (in UTC form) to QDateTime - according to \a spec. -*/ -static inline QDateTime ToDateTime(double t, Qt::TimeSpec spec) -{ - if (std::isnan(t)) - return QDateTime(); - if (spec == Qt::LocalTime) - t = LocalTime(t); - int year = int(YearFromTime(t)); - int month = int(MonthFromTime(t) + 1); - int day = int(DateFromTime(t)); - int hours = HourFromTime(t); - int mins = MinFromTime(t); - int secs = SecFromTime(t); - int ms = msFromTime(t); - return QDateTime(QDate(year, month, day), QTime(hours, mins, secs, ms), spec); -} - -static inline QString ToString(double t) -{ - if (std::isnan(t)) - return QStringLiteral("Invalid Date"); - QString str = ToDateTime(t, Qt::LocalTime).toString() + QStringLiteral(" GMT"); - double tzoffset = LocalTZA + DaylightSavingTA(t); - if (tzoffset) { - int hours = static_cast(::fabs(tzoffset) / 1000 / 60 / 60); - int mins = int(::fabs(tzoffset) / 1000 / 60) % 60; - str.append(QLatin1Char((tzoffset > 0) ? '+' : '-')); - if (hours < 10) - str.append(QLatin1Char('0')); - str.append(QString::number(hours)); - if (mins < 10) - str.append(QLatin1Char('0')); - str.append(QString::number(mins)); - } - return str; -} - -static inline QString ToUTCString(double t) -{ - if (std::isnan(t)) - return QStringLiteral("Invalid Date"); - return ToDateTime(t, Qt::UTC).toString() + QStringLiteral(" GMT"); -} - -static inline QString ToDateString(double t) -{ - return ToDateTime(t, Qt::LocalTime).date().toString(); -} - -static inline QString ToTimeString(double t) -{ - return ToDateTime(t, Qt::LocalTime).time().toString(); -} - -static inline QString ToLocaleString(double t) -{ - return ToDateTime(t, Qt::LocalTime).toString(Qt::LocaleDate); -} - -static inline QString ToLocaleDateString(double t) -{ - return ToDateTime(t, Qt::LocalTime).date().toString(Qt::LocaleDate); -} - -static inline QString ToLocaleTimeString(double t) -{ - return ToDateTime(t, Qt::LocalTime).time().toString(Qt::LocaleDate); -} - -static double getLocalTZA() -{ -#ifndef Q_WS_WIN - struct tm t; - time_t curr; - time(&curr); - localtime_r(&curr, &t); - time_t locl = mktime(&t); - gmtime_r(&curr, &t); - time_t globl = mktime(&t); - return double(locl - globl) * 1000.0; -#else - TIME_ZONE_INFORMATION tzInfo; - GetTimeZoneInformation(&tzInfo); - return -tzInfo.Bias * 60.0 * 1000.0; -#endif -} - // // Object // @@ -2549,637 +1967,6 @@ Value FunctionPrototype::method_bind(ExecutionContext *ctx) } // -// Date object -// -DateCtor::DateCtor(ExecutionContext *scope) - : FunctionObject(scope) -{ -} - -Value DateCtor::construct(ExecutionContext *ctx) -{ - double t = 0; - - if (ctx->argumentCount == 0) - t = currentTime(); - - else if (ctx->argumentCount == 1) { - Value arg = ctx->argument(0); - if (DateObject *d = arg.asDateObject()) - arg = d->value; - else - arg = __qmljs_to_primitive(arg, ctx, PREFERREDTYPE_HINT); - - if (arg.isString()) - t = ParseString(arg.stringValue()->toQString()); - else - t = TimeClip(arg.toNumber(ctx)); - } - - else { // ctx->argumentCount > 1 - double year = ctx->argument(0).toNumber(ctx); - double month = ctx->argument(1).toNumber(ctx); - double day = ctx->argumentCount >= 3 ? ctx->argument(2).toNumber(ctx) : 1; - double hours = ctx->argumentCount >= 4 ? ctx->argument(3).toNumber(ctx) : 0; - double mins = ctx->argumentCount >= 5 ? ctx->argument(4).toNumber(ctx) : 0; - double secs = ctx->argumentCount >= 6 ? ctx->argument(5).toNumber(ctx) : 0; - double ms = ctx->argumentCount >= 7 ? ctx->argument(6).toNumber(ctx) : 0; - if (year >= 0 && year <= 99) - year += 1900; - t = MakeDate(MakeDay(year, month, day), MakeTime(hours, mins, secs, ms)); - t = TimeClip(UTC(t)); - } - - Object *d = ctx->engine->newDateObject(Value::fromDouble(t)); - return Value::fromObject(d); -} - -Value DateCtor::call(ExecutionContext *ctx) -{ - double t = currentTime(); - return Value::fromString(ctx, ToString(t)); -} - -void DatePrototype::init(ExecutionContext *ctx, const Value &ctor) -{ - ctor.objectValue()->defineReadonlyProperty(ctx->engine->id_prototype, Value::fromObject(this)); - ctor.objectValue()->defineReadonlyProperty(ctx->engine->id_length, Value::fromInt32(1)); - LocalTZA = getLocalTZA(); - - ctor.objectValue()->defineDefaultProperty(ctx, QStringLiteral("parse"), method_parse, 1); - ctor.objectValue()->defineDefaultProperty(ctx, QStringLiteral("UTC"), method_UTC, 7); - - defineDefaultProperty(ctx, QStringLiteral("constructor"), ctor); - defineDefaultProperty(ctx, QStringLiteral("toString"), method_toString, 0); - defineDefaultProperty(ctx, QStringLiteral("toDateString"), method_toDateString, 0); - defineDefaultProperty(ctx, QStringLiteral("toTimeString"), method_toTimeString, 0); - defineDefaultProperty(ctx, QStringLiteral("toLocaleString"), method_toLocaleString, 0); - defineDefaultProperty(ctx, QStringLiteral("toLocaleDateString"), method_toLocaleDateString, 0); - defineDefaultProperty(ctx, QStringLiteral("toLocaleTimeString"), method_toLocaleTimeString, 0); - defineDefaultProperty(ctx, QStringLiteral("valueOf"), method_valueOf, 0); - defineDefaultProperty(ctx, QStringLiteral("getTime"), method_getTime, 0); - defineDefaultProperty(ctx, QStringLiteral("getYear"), method_getYear, 0); - defineDefaultProperty(ctx, QStringLiteral("getFullYear"), method_getFullYear, 0); - defineDefaultProperty(ctx, QStringLiteral("getUTCFullYear"), method_getUTCFullYear, 0); - defineDefaultProperty(ctx, QStringLiteral("getMonth"), method_getMonth, 0); - defineDefaultProperty(ctx, QStringLiteral("getUTCMonth"), method_getUTCMonth, 0); - defineDefaultProperty(ctx, QStringLiteral("getDate"), method_getDate, 0); - defineDefaultProperty(ctx, QStringLiteral("getUTCDate"), method_getUTCDate, 0); - defineDefaultProperty(ctx, QStringLiteral("getDay"), method_getDay, 0); - defineDefaultProperty(ctx, QStringLiteral("getUTCDay"), method_getUTCDay, 0); - defineDefaultProperty(ctx, QStringLiteral("getHours"), method_getHours, 0); - defineDefaultProperty(ctx, QStringLiteral("getUTCHours"), method_getUTCHours, 0); - defineDefaultProperty(ctx, QStringLiteral("getMinutes"), method_getMinutes, 0); - defineDefaultProperty(ctx, QStringLiteral("getUTCMinutes"), method_getUTCMinutes, 0); - defineDefaultProperty(ctx, QStringLiteral("getSeconds"), method_getSeconds, 0); - defineDefaultProperty(ctx, QStringLiteral("getUTCSeconds"), method_getUTCSeconds, 0); - defineDefaultProperty(ctx, QStringLiteral("getMilliseconds"), method_getMilliseconds, 0); - defineDefaultProperty(ctx, QStringLiteral("getUTCMilliseconds"), method_getUTCMilliseconds, 0); - defineDefaultProperty(ctx, QStringLiteral("getTimezoneOffset"), method_getTimezoneOffset, 0); - defineDefaultProperty(ctx, QStringLiteral("setTime"), method_setTime, 1); - defineDefaultProperty(ctx, QStringLiteral("setMilliseconds"), method_setMilliseconds, 1); - defineDefaultProperty(ctx, QStringLiteral("setUTCMilliseconds"), method_setUTCMilliseconds, 1); - defineDefaultProperty(ctx, QStringLiteral("setSeconds"), method_setSeconds, 2); - defineDefaultProperty(ctx, QStringLiteral("setUTCSeconds"), method_setUTCSeconds, 2); - defineDefaultProperty(ctx, QStringLiteral("setMinutes"), method_setMinutes, 3); - defineDefaultProperty(ctx, QStringLiteral("setUTCMinutes"), method_setUTCMinutes, 3); - defineDefaultProperty(ctx, QStringLiteral("setHours"), method_setHours, 4); - defineDefaultProperty(ctx, QStringLiteral("setUTCHours"), method_setUTCHours, 4); - defineDefaultProperty(ctx, QStringLiteral("setDate"), method_setDate, 1); - defineDefaultProperty(ctx, QStringLiteral("setUTCDate"), method_setUTCDate, 1); - defineDefaultProperty(ctx, QStringLiteral("setMonth"), method_setMonth, 2); - defineDefaultProperty(ctx, QStringLiteral("setUTCMonth"), method_setUTCMonth, 2); - defineDefaultProperty(ctx, QStringLiteral("setYear"), method_setYear, 1); - defineDefaultProperty(ctx, QStringLiteral("setFullYear"), method_setFullYear, 3); - defineDefaultProperty(ctx, QStringLiteral("setUTCFullYear"), method_setUTCFullYear, 3); - defineDefaultProperty(ctx, QStringLiteral("toUTCString"), method_toUTCString, 0); - defineDefaultProperty(ctx, QStringLiteral("toGMTString"), method_toUTCString, 0); - defineDefaultProperty(ctx, QStringLiteral("toISOString"), method_toISOString, 0); -} - -double DatePrototype::getThisDate(ExecutionContext *ctx) -{ - if (DateObject *thisObject = ctx->thisObject.asDateObject()) - return thisObject->value.asDouble(); - else { - ctx->throwTypeError(); - return 0; - } -} - -Value DatePrototype::method_parse(ExecutionContext *ctx) -{ - return Value::fromDouble(ParseString(ctx->argument(0).toString(ctx)->toQString())); -} - -Value DatePrototype::method_UTC(ExecutionContext *ctx) -{ - const int numArgs = ctx->argumentCount; - if (numArgs >= 2) { - double year = ctx->argument(0).toNumber(ctx); - double month = ctx->argument(1).toNumber(ctx); - double day = numArgs >= 3 ? ctx->argument(2).toNumber(ctx) : 1; - double hours = numArgs >= 4 ? ctx->argument(3).toNumber(ctx) : 0; - double mins = numArgs >= 5 ? ctx->argument(4).toNumber(ctx) : 0; - double secs = numArgs >= 6 ? ctx->argument(5).toNumber(ctx) : 0; - double ms = numArgs >= 7 ? ctx->argument(6).toNumber(ctx) : 0; - if (year >= 0 && year <= 99) - year += 1900; - double t = MakeDate(MakeDay(year, month, day), - MakeTime(hours, mins, secs, ms)); - return Value::fromDouble(TimeClip(t)); - } - return Value::undefinedValue(); -} - -Value DatePrototype::method_toString(ExecutionContext *ctx) -{ - double t = getThisDate(ctx); - return Value::fromString(ctx, ToString(t)); -} - -Value DatePrototype::method_toDateString(ExecutionContext *ctx) -{ - double t = getThisDate(ctx); - return Value::fromString(ctx, ToDateString(t)); -} - -Value DatePrototype::method_toTimeString(ExecutionContext *ctx) -{ - double t = getThisDate(ctx); - return Value::fromString(ctx, ToTimeString(t)); -} - -Value DatePrototype::method_toLocaleString(ExecutionContext *ctx) -{ - double t = getThisDate(ctx); - return Value::fromString(ctx, ToLocaleString(t)); -} - -Value DatePrototype::method_toLocaleDateString(ExecutionContext *ctx) -{ - double t = getThisDate(ctx); - return Value::fromString(ctx, ToLocaleDateString(t)); -} - -Value DatePrototype::method_toLocaleTimeString(ExecutionContext *ctx) -{ - double t = getThisDate(ctx); - return Value::fromString(ctx, ToLocaleTimeString(t)); -} - -Value DatePrototype::method_valueOf(ExecutionContext *ctx) -{ - double t = getThisDate(ctx); - return Value::fromDouble(t); -} - -Value DatePrototype::method_getTime(ExecutionContext *ctx) -{ - double t = getThisDate(ctx); - return Value::fromDouble(t); -} - -Value DatePrototype::method_getYear(ExecutionContext *ctx) -{ - double t = getThisDate(ctx); - if (! std::isnan(t)) - t = YearFromTime(LocalTime(t)) - 1900; - return Value::fromDouble(t); -} - -Value DatePrototype::method_getFullYear(ExecutionContext *ctx) -{ - double t = getThisDate(ctx); - if (! std::isnan(t)) - t = YearFromTime(LocalTime(t)); - return Value::fromDouble(t); -} - -Value DatePrototype::method_getUTCFullYear(ExecutionContext *ctx) -{ - double t = getThisDate(ctx); - if (! std::isnan(t)) - t = YearFromTime(t); - return Value::fromDouble(t); -} - -Value DatePrototype::method_getMonth(ExecutionContext *ctx) -{ - double t = getThisDate(ctx); - if (! std::isnan(t)) - t = MonthFromTime(LocalTime(t)); - return Value::fromDouble(t); -} - -Value DatePrototype::method_getUTCMonth(ExecutionContext *ctx) -{ - double t = getThisDate(ctx); - if (! std::isnan(t)) - t = MonthFromTime(t); - return Value::fromDouble(t); -} - -Value DatePrototype::method_getDate(ExecutionContext *ctx) -{ - double t = getThisDate(ctx); - if (! std::isnan(t)) - t = DateFromTime(LocalTime(t)); - return Value::fromDouble(t); -} - -Value DatePrototype::method_getUTCDate(ExecutionContext *ctx) -{ - double t = getThisDate(ctx); - if (! std::isnan(t)) - t = DateFromTime(t); - return Value::fromDouble(t); -} - -Value DatePrototype::method_getDay(ExecutionContext *ctx) -{ - double t = getThisDate(ctx); - if (! std::isnan(t)) - t = WeekDay(LocalTime(t)); - return Value::fromDouble(t); -} - -Value DatePrototype::method_getUTCDay(ExecutionContext *ctx) -{ - double t = getThisDate(ctx); - if (! std::isnan(t)) - t = WeekDay(t); - return Value::fromDouble(t); -} - -Value DatePrototype::method_getHours(ExecutionContext *ctx) -{ - double t = getThisDate(ctx); - if (! std::isnan(t)) - t = HourFromTime(LocalTime(t)); - return Value::fromDouble(t); -} - -Value DatePrototype::method_getUTCHours(ExecutionContext *ctx) -{ - double t = getThisDate(ctx); - if (! std::isnan(t)) - t = HourFromTime(t); - return Value::fromDouble(t); -} - -Value DatePrototype::method_getMinutes(ExecutionContext *ctx) -{ - double t = getThisDate(ctx); - if (! std::isnan(t)) - t = MinFromTime(LocalTime(t)); - return Value::fromDouble(t); -} - -Value DatePrototype::method_getUTCMinutes(ExecutionContext *ctx) -{ - double t = getThisDate(ctx); - if (! std::isnan(t)) - t = MinFromTime(t); - return Value::fromDouble(t); -} - -Value DatePrototype::method_getSeconds(ExecutionContext *ctx) -{ - double t = getThisDate(ctx); - if (! std::isnan(t)) - t = SecFromTime(LocalTime(t)); - return Value::fromDouble(t); -} - -Value DatePrototype::method_getUTCSeconds(ExecutionContext *ctx) -{ - double t = getThisDate(ctx); - if (! std::isnan(t)) - t = SecFromTime(t); - return Value::fromDouble(t); -} - -Value DatePrototype::method_getMilliseconds(ExecutionContext *ctx) -{ - double t = getThisDate(ctx); - if (! std::isnan(t)) - t = msFromTime(LocalTime(t)); - return Value::fromDouble(t); -} - -Value DatePrototype::method_getUTCMilliseconds(ExecutionContext *ctx) -{ - double t = getThisDate(ctx); - if (! std::isnan(t)) - t = msFromTime(t); - return Value::fromDouble(t); -} - -Value DatePrototype::method_getTimezoneOffset(ExecutionContext *ctx) -{ - double t = getThisDate(ctx); - if (! std::isnan(t)) - t = (t - LocalTime(t)) / msPerMinute; - return Value::fromDouble(t); -} - -Value DatePrototype::method_setTime(ExecutionContext *ctx) -{ - DateObject *self = ctx->thisObject.asDateObject(); - if (!self) - ctx->throwTypeError(); - - self->value.setDouble(TimeClip(ctx->argument(0).toNumber(ctx))); - return self->value; -} - -Value DatePrototype::method_setMilliseconds(ExecutionContext *ctx) -{ - DateObject *self = ctx->thisObject.asDateObject(); - if (!self) - ctx->throwTypeError(); - - double t = LocalTime(self->value.asDouble()); - double ms = ctx->argument(0).toNumber(ctx); - self->value.setDouble(TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), SecFromTime(t), ms))))); - return self->value; -} - -Value DatePrototype::method_setUTCMilliseconds(ExecutionContext *ctx) -{ - DateObject *self = ctx->thisObject.asDateObject(); - if (!self) - ctx->throwTypeError(); - - double t = self->value.asDouble(); - double ms = ctx->argument(0).toNumber(ctx); - self->value.setDouble(TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), SecFromTime(t), ms))))); - return self->value; -} - -Value DatePrototype::method_setSeconds(ExecutionContext *ctx) -{ - DateObject *self = ctx->thisObject.asDateObject(); - if (!self) - ctx->throwTypeError(); - - double t = LocalTime(self->value.asDouble()); - double sec = ctx->argument(0).toNumber(ctx); - double ms = (ctx->argumentCount < 2) ? msFromTime(t) : ctx->argument(1).toNumber(ctx); - t = TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), sec, ms)))); - self->value.setDouble(t); - return self->value; -} - -Value DatePrototype::method_setUTCSeconds(ExecutionContext *ctx) -{ - DateObject *self = ctx->thisObject.asDateObject(); - if (!self) - ctx->throwTypeError(); - - double t = self->value.asDouble(); - double sec = ctx->argument(0).toNumber(ctx); - double ms = (ctx->argumentCount < 2) ? msFromTime(t) : ctx->argument(1).toNumber(ctx); - t = TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), sec, ms)))); - self->value.setDouble(t); - return self->value; -} - -Value DatePrototype::method_setMinutes(ExecutionContext *ctx) -{ - DateObject *self = ctx->thisObject.asDateObject(); - if (!self) - ctx->throwTypeError(); - - double t = LocalTime(self->value.asDouble()); - double min = ctx->argument(0).toNumber(ctx); - double sec = (ctx->argumentCount < 2) ? SecFromTime(t) : ctx->argument(1).toNumber(ctx); - double ms = (ctx->argumentCount < 3) ? msFromTime(t) : ctx->argument(2).toNumber(ctx); - t = TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), min, sec, ms)))); - self->value.setDouble(t); - return self->value; -} - -Value DatePrototype::method_setUTCMinutes(ExecutionContext *ctx) -{ - DateObject *self = ctx->thisObject.asDateObject(); - if (!self) - ctx->throwTypeError(); - - double t = self->value.asDouble(); - double min = ctx->argument(0).toNumber(ctx); - double sec = (ctx->argumentCount < 2) ? SecFromTime(t) : ctx->argument(1).toNumber(ctx); - double ms = (ctx->argumentCount < 3) ? msFromTime(t) : ctx->argument(2).toNumber(ctx); - t = TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), min, sec, ms)))); - self->value.setDouble(t); - return self->value; -} - -Value DatePrototype::method_setHours(ExecutionContext *ctx) -{ - DateObject *self = ctx->thisObject.asDateObject(); - if (!self) - ctx->throwTypeError(); - - double t = LocalTime(self->value.asDouble()); - double hour = ctx->argument(0).toNumber(ctx); - double min = (ctx->argumentCount < 2) ? MinFromTime(t) : ctx->argument(1).toNumber(ctx); - double sec = (ctx->argumentCount < 3) ? SecFromTime(t) : ctx->argument(2).toNumber(ctx); - double ms = (ctx->argumentCount < 4) ? msFromTime(t) : ctx->argument(3).toNumber(ctx); - t = TimeClip(UTC(MakeDate(Day(t), MakeTime(hour, min, sec, ms)))); - self->value.setDouble(t); - return self->value; -} - -Value DatePrototype::method_setUTCHours(ExecutionContext *ctx) -{ - DateObject *self = ctx->thisObject.asDateObject(); - if (!self) - ctx->throwTypeError(); - - double t = self->value.asDouble(); - double hour = ctx->argument(0).toNumber(ctx); - double min = (ctx->argumentCount < 2) ? MinFromTime(t) : ctx->argument(1).toNumber(ctx); - double sec = (ctx->argumentCount < 3) ? SecFromTime(t) : ctx->argument(2).toNumber(ctx); - double ms = (ctx->argumentCount < 4) ? msFromTime(t) : ctx->argument(3).toNumber(ctx); - t = TimeClip(UTC(MakeDate(Day(t), MakeTime(hour, min, sec, ms)))); - self->value.setDouble(t); - return self->value; -} - -Value DatePrototype::method_setDate(ExecutionContext *ctx) -{ - DateObject *self = ctx->thisObject.asDateObject(); - if (!self) - ctx->throwTypeError(); - - double t = LocalTime(self->value.asDouble()); - double date = ctx->argument(0).toNumber(ctx); - t = TimeClip(UTC(MakeDate(MakeDay(YearFromTime(t), MonthFromTime(t), date), TimeWithinDay(t)))); - self->value.setDouble(t); - return self->value; -} - -Value DatePrototype::method_setUTCDate(ExecutionContext *ctx) -{ - DateObject *self = ctx->thisObject.asDateObject(); - if (!self) - ctx->throwTypeError(); - - double t = self->value.asDouble(); - double date = ctx->argument(0).toNumber(ctx); - t = TimeClip(UTC(MakeDate(MakeDay(YearFromTime(t), MonthFromTime(t), date), TimeWithinDay(t)))); - self->value.setDouble(t); - return self->value; -} - -Value DatePrototype::method_setMonth(ExecutionContext *ctx) -{ - DateObject *self = ctx->thisObject.asDateObject(); - if (!self) - ctx->throwTypeError(); - - double t = LocalTime(self->value.asDouble()); - double month = ctx->argument(0).toNumber(ctx); - double date = (ctx->argumentCount < 2) ? DateFromTime(t) : ctx->argument(1).toNumber(ctx); - t = TimeClip(UTC(MakeDate(MakeDay(YearFromTime(t), month, date), TimeWithinDay(t)))); - self->value.setDouble(t); - return self->value; -} - -Value DatePrototype::method_setUTCMonth(ExecutionContext *ctx) -{ - DateObject *self = ctx->thisObject.asDateObject(); - if (!self) - ctx->throwTypeError(); - - double t = self->value.asDouble(); - double month = ctx->argument(0).toNumber(ctx); - double date = (ctx->argumentCount < 2) ? DateFromTime(t) : ctx->argument(1).toNumber(ctx); - t = TimeClip(UTC(MakeDate(MakeDay(YearFromTime(t), month, date), TimeWithinDay(t)))); - self->value.setDouble(t); - return self->value; -} - -Value DatePrototype::method_setYear(ExecutionContext *ctx) -{ - DateObject *self = ctx->thisObject.asDateObject(); - if (!self) - ctx->throwTypeError(); - - double t = self->value.asDouble(); - if (std::isnan(t)) - t = 0; - else - t = LocalTime(t); - double year = ctx->argument(0).toNumber(ctx); - double r; - if (std::isnan(year)) { - r = qSNaN(); - } else { - if ((Value::toInteger(year) >= 0) && (Value::toInteger(year) <= 99)) - year += 1900; - r = MakeDay(year, MonthFromTime(t), DateFromTime(t)); - r = UTC(MakeDate(r, TimeWithinDay(t))); - r = TimeClip(r); - } - self->value.setDouble(r); - return self->value; -} - -Value DatePrototype::method_setUTCFullYear(ExecutionContext *ctx) -{ - DateObject *self = ctx->thisObject.asDateObject(); - if (!self) - ctx->throwTypeError(); - - double t = self->value.asDouble(); - double year = ctx->argument(0).toNumber(ctx); - double month = (ctx->argumentCount < 2) ? MonthFromTime(t) : ctx->argument(1).toNumber(ctx); - double date = (ctx->argumentCount < 3) ? DateFromTime(t) : ctx->argument(2).toNumber(ctx); - t = TimeClip(UTC(MakeDate(MakeDay(year, month, date), TimeWithinDay(t)))); - self->value.setDouble(t); - return self->value; -} - -Value DatePrototype::method_setFullYear(ExecutionContext *ctx) -{ - DateObject *self = ctx->thisObject.asDateObject(); - if (!self) - ctx->throwTypeError(); - - double t = LocalTime(self->value.asDouble()); - double year = ctx->argument(0).toNumber(ctx); - double month = (ctx->argumentCount < 2) ? MonthFromTime(t) : ctx->argument(1).toNumber(ctx); - double date = (ctx->argumentCount < 3) ? DateFromTime(t) : ctx->argument(2).toNumber(ctx); - t = TimeClip(UTC(MakeDate(MakeDay(year, month, date), TimeWithinDay(t)))); - self->value.setDouble(t); - return self->value; -} - -Value DatePrototype::method_toUTCString(ExecutionContext *ctx) -{ - DateObject *self = ctx->thisObject.asDateObject(); - if (!self) - ctx->throwTypeError(); - - double t = self->value.asDouble(); - return Value::fromString(ctx, ToUTCString(t)); -} - -static void addZeroPrefixedInt(QString &str, int num, int nDigits) -{ - str.resize(str.size() + nDigits); - - QChar *c = str.data() + str.size() - 1; - while (nDigits) { - *c = QChar(num % 10 + '0'); - num /= 10; - --c; - --nDigits; - } -} - -Value DatePrototype::method_toISOString(ExecutionContext *ctx) -{ - DateObject *self = ctx->thisObject.asDateObject(); - if (!self) - ctx->throwTypeError(); - - double t = self->value.asDouble(); - if (!std::isfinite(t)) - ctx->throwRangeError(ctx->thisObject); - - QString result; - int year = (int)YearFromTime(t); - if (year < 0 || year > 9999) { - if (qAbs(year) >= 1000000) - return Value::fromString(ctx, QStringLiteral("Invalid Date")); - result += year < 0 ? '-' : '+'; - year = qAbs(year); - addZeroPrefixedInt(result, year, 6); - } else { - addZeroPrefixedInt(result, year, 4); - } - result += '-'; - addZeroPrefixedInt(result, (int)MonthFromTime(t) + 1, 2); - result += '-'; - addZeroPrefixedInt(result, (int)DateFromTime(t), 2); - result += 'T'; - addZeroPrefixedInt(result, HourFromTime(t), 2); - result += ':'; - addZeroPrefixedInt(result, MinFromTime(t), 2); - result += ':'; - addZeroPrefixedInt(result, SecFromTime(t), 2); - result += '.'; - addZeroPrefixedInt(result, msFromTime(t), 3); - result += 'Z'; - - return Value::fromString(ctx, result); -} - -// // RegExp object // RegExpCtor::RegExpCtor(ExecutionContext *scope) diff --git a/qv4ecmaobjects_p.h b/qv4ecmaobjects_p.h index 571dc17..a2726c7 100644 --- a/qv4ecmaobjects_p.h +++ b/qv4ecmaobjects_p.h @@ -220,70 +220,6 @@ struct FunctionPrototype: FunctionObject static Value method_bind(ExecutionContext *ctx); }; -struct DateCtor: FunctionObject -{ - DateCtor(ExecutionContext *scope); - - virtual Value construct(ExecutionContext *ctx); - virtual Value call(ExecutionContext *ctx); -}; - -struct DatePrototype: DateObject -{ - DatePrototype(): DateObject(Value::fromDouble(qSNaN())) {} - void init(ExecutionContext *ctx, const Value &ctor); - - static double getThisDate(ExecutionContext *ctx); - - static Value method_parse(ExecutionContext *ctx); - static Value method_UTC(ExecutionContext *ctx); - - static Value method_toString(ExecutionContext *ctx); - static Value method_toDateString(ExecutionContext *ctx); - static Value method_toTimeString(ExecutionContext *ctx); - static Value method_toLocaleString(ExecutionContext *ctx); - static Value method_toLocaleDateString(ExecutionContext *ctx); - static Value method_toLocaleTimeString(ExecutionContext *ctx); - static Value method_valueOf(ExecutionContext *ctx); - static Value method_getTime(ExecutionContext *ctx); - static Value method_getYear(ExecutionContext *ctx); - static Value method_getFullYear(ExecutionContext *ctx); - static Value method_getUTCFullYear(ExecutionContext *ctx); - static Value method_getMonth(ExecutionContext *ctx); - static Value method_getUTCMonth(ExecutionContext *ctx); - static Value method_getDate(ExecutionContext *ctx); - static Value method_getUTCDate(ExecutionContext *ctx); - static Value method_getDay(ExecutionContext *ctx); - static Value method_getUTCDay(ExecutionContext *ctx); - static Value method_getHours(ExecutionContext *ctx); - static Value method_getUTCHours(ExecutionContext *ctx); - static Value method_getMinutes(ExecutionContext *ctx); - static Value method_getUTCMinutes(ExecutionContext *ctx); - static Value method_getSeconds(ExecutionContext *ctx); - static Value method_getUTCSeconds(ExecutionContext *ctx); - static Value method_getMilliseconds(ExecutionContext *ctx); - static Value method_getUTCMilliseconds(ExecutionContext *ctx); - static Value method_getTimezoneOffset(ExecutionContext *ctx); - static Value method_setTime(ExecutionContext *ctx); - static Value method_setMilliseconds(ExecutionContext *ctx); - static Value method_setUTCMilliseconds(ExecutionContext *ctx); - static Value method_setSeconds(ExecutionContext *ctx); - static Value method_setUTCSeconds(ExecutionContext *ctx); - static Value method_setMinutes(ExecutionContext *ctx); - static Value method_setUTCMinutes(ExecutionContext *ctx); - static Value method_setHours(ExecutionContext *ctx); - static Value method_setUTCHours(ExecutionContext *ctx); - static Value method_setDate(ExecutionContext *ctx); - static Value method_setUTCDate(ExecutionContext *ctx); - static Value method_setMonth(ExecutionContext *ctx); - static Value method_setUTCMonth(ExecutionContext *ctx); - static Value method_setYear(ExecutionContext *ctx); - static Value method_setFullYear(ExecutionContext *ctx); - static Value method_setUTCFullYear(ExecutionContext *ctx); - static Value method_toUTCString(ExecutionContext *ctx); - static Value method_toISOString(ExecutionContext *ctx); -}; - struct RegExpCtor: FunctionObject { RegExpCtor(ExecutionContext *scope); diff --git a/v4.pro b/v4.pro index b195d50..723f331 100644 --- a/v4.pro +++ b/v4.pro @@ -28,6 +28,7 @@ SOURCES += main.cpp \ qv4managed.cpp \ qv4array.cpp \ qv4argumentsobject.cpp \ + qv4dateobject.cpp \ qv4jsonobject.cpp \ qv4string.cpp \ qv4objectiterator.cpp \ @@ -52,6 +53,7 @@ HEADERS += \ qv4managed.h \ qv4array.h \ qv4argumentsobject.h \ + qv4dateobject.h \ qv4jsonobject.h \ qv4string.h \ qv4propertydescriptor.h \ -- 2.7.4