return wd;
}
-// Get the DST offset for the time passed in.
+// Get the combined UTC + DST offset for the time passed in.
//
// NOTE: The implementation relies on the fact that no time zones have
// more than one daylight savings offset change per month.
// If this function is called with NaN it returns NaN.
-static double getDSTOffset(ExecState* exec, double ms, double utcOffset)
+static LocalTimeOffset getLocalTimeOffset(ExecState* exec, double ms)
{
- DSTOffsetCache& cache = exec->globalData().dstOffsetCache;
+ LocalTimeOffsetCache& cache = exec->globalData().localTimeOffsetCache;
double start = cache.start;
double end = cache.end;
double newEnd = end + cache.increment;
if (ms <= newEnd) {
- double endOffset = calculateDSTOffset(newEnd, utcOffset);
+ LocalTimeOffset endOffset = calculateLocalTimeOffset(newEnd);
if (cache.offset == endOffset) {
// If the offset at the end of the new interval still matches
// the offset in the cache, we grow the cached time interval
cache.end = newEnd;
cache.increment = msPerMonth;
return endOffset;
+ }
+ LocalTimeOffset offset = calculateLocalTimeOffset(ms);
+ if (offset == endOffset) {
+ // The offset at the given time is equal to the offset at the
+ // new end of the interval, so that means that we've just skipped
+ // the point in time where the DST offset change occurred. Updated
+ // the interval to reflect this and reset the increment.
+ cache.start = ms;
+ cache.end = newEnd;
+ cache.increment = msPerMonth;
} else {
- double offset = calculateDSTOffset(ms, utcOffset);
- if (offset == endOffset) {
- // The offset at the given time is equal to the offset at the
- // new end of the interval, so that means that we've just skipped
- // the point in time where the DST offset change occurred. Updated
- // the interval to reflect this and reset the increment.
- cache.start = ms;
- cache.end = newEnd;
- cache.increment = msPerMonth;
- } else {
- // The interval contains a DST offset change and the given time is
- // before it. Adjust the increment to avoid a linear search for
- // the offset change point and change the end of the interval.
- cache.increment /= 3;
- cache.end = ms;
- }
- // Update the offset in the cache and return it.
- cache.offset = offset;
- return offset;
+ // The interval contains a DST offset change and the given time is
+ // before it. Adjust the increment to avoid a linear search for
+ // the offset change point and change the end of the interval.
+ cache.increment /= 3;
+ cache.end = ms;
}
+ // Update the offset in the cache and return it.
+ cache.offset = offset;
+ return offset;
}
}
// Compute the DST offset for the time and shrink the cache interval
// to only contain the time. This allows fast repeated DST offset
// computations for the same time.
- double offset = calculateDSTOffset(ms, utcOffset);
+ LocalTimeOffset offset = calculateLocalTimeOffset(ms);
cache.offset = offset;
cache.start = ms;
cache.end = ms;
return offset;
}
-/*
- * Get the difference in milliseconds between this time zone and UTC (GMT)
- * NOT including DST.
- */
-double getUTCOffset(ExecState* exec)
-{
- double utcOffset = exec->globalData().cachedUTCOffset;
- if (!isnan(utcOffset))
- return utcOffset;
- exec->globalData().cachedUTCOffset = calculateUTCOffset();
- return exec->globalData().cachedUTCOffset;
-}
-
double gregorianDateTimeToMS(ExecState* exec, const GregorianDateTime& t, double milliSeconds, bool inputIsUTC)
{
double day = dateToDaysFrom1970(t.year(), t.month(), t.monthDay());
double ms = timeToMS(t.hour(), t.minute(), t.second(), milliSeconds);
double result = (day * WTF::msPerDay) + ms;
- if (!inputIsUTC) { // convert to UTC
- double utcOffset = getUTCOffset(exec);
- result -= utcOffset;
- result -= getDSTOffset(exec, result, utcOffset);
- }
+ // convert to UTC
+ if (!inputIsUTC)
+ result -= getLocalTimeOffset(exec, result).offset;
return result;
}
// input is UTC
void msToGregorianDateTime(ExecState* exec, double ms, bool outputIsUTC, GregorianDateTime& tm)
{
- double dstOff = 0.0;
- double utcOff = 0.0;
+ LocalTimeOffset localTimeOffset(false, 0);
if (!outputIsUTC) {
- utcOff = getUTCOffset(exec);
- dstOff = getDSTOffset(exec, ms, utcOff);
- ms += dstOff + utcOff;
+ localTimeOffset = getLocalTimeOffset(exec, ms);
+ ms += localTimeOffset.offset;
}
const int year = msToYear(ms);
tm.setMonthDay(dayInMonthFromDayInYear(tm.yearDay(), isLeapYear(year)));
tm.setMonth(monthFromDayInYear(tm.yearDay(), isLeapYear(year)));
tm.setYear(year);
- tm.setIsDST(dstOff != 0.0);
- tm.setUtcOffset(static_cast<long>((dstOff + utcOff) / WTF::msPerSecond));
+ tm.setIsDST(localTimeOffset.isDST);
+ tm.setUtcOffset(localTimeOffset.offset / WTF::msPerSecond);
}
double parseDateFromNullTerminatedCharacters(ExecState* exec, const char* dateString)
return std::numeric_limits<double>::quiet_NaN();
// fall back to local timezone
- if (!haveTZ) {
- double utcOffset = getUTCOffset(exec);
- double dstOffset = getDSTOffset(exec, ms, utcOffset);
- offset = static_cast<int>((utcOffset + dstOffset) / WTF::msPerMinute);
- }
+ if (!haveTZ)
+ offset = getLocalTimeOffset(exec, ms).offset / WTF::msPerMinute;
return ms - (offset * WTF::msPerMinute);
}
, sizeOfLastScratchBuffer(0)
#endif
, dynamicGlobalObject(0)
- , cachedUTCOffset(std::numeric_limits<double>::quiet_NaN())
, maxReentryDepth(threadStackType == ThreadStackTypeSmall ? MaxSmallThreadReentryDepth : MaxLargeThreadReentryDepth)
, m_enabledProfiler(0)
, m_regExpCache(new RegExpCache(this))
void JSGlobalData::resetDateCache()
{
- cachedUTCOffset = std::numeric_limits<double>::quiet_NaN();
- dstOffsetCache.reset();
+ localTimeOffsetCache.reset();
cachedDateString = UString();
cachedDateStringValue = std::numeric_limits<double>::quiet_NaN();
dateInstanceCache.reset();
#include "TimeoutChecker.h"
#include "WeakRandom.h"
#include <wtf/BumpPointerAllocator.h>
+#include <wtf/DateMath.h>
#include <wtf/Forward.h>
#include <wtf/HashMap.h>
#include <wtf/SimpleStats.h>
struct HashTable;
struct Instruction;
- struct DSTOffsetCache {
- DSTOffsetCache()
+ struct LocalTimeOffsetCache {
+ LocalTimeOffsetCache()
+ : offset(false, 0)
{
reset();
}
void reset()
{
- offset = 0.0;
+ offset = LocalTimeOffset(false, 0);
start = 0.0;
end = -1.0;
increment = 0.0;
}
- double offset;
+ LocalTimeOffset offset;
double start;
double end;
double increment;
HashSet<JSObject*> stringRecursionCheckVisitedObjects;
- double cachedUTCOffset;
- DSTOffsetCache dstOffsetCache;
+ LocalTimeOffsetCache localTimeOffsetCache;
UString cachedDateString;
double cachedDateStringValue;
return year;
}
-int32_t calculateUTCOffset()
+#if !HAVE(TM_GMTOFF)
+
+static int32_t calculateUTCOffset()
{
#if OS(WINDOWS)
TIME_ZONE_INFORMATION timeZoneInformation;
/*
* Get the DST offset for the time passed in.
*/
-static double calculateDSTOffsetSimple(double localTimeSeconds, double utcOffset)
+static double calculateDSTOffset(time_t localTime, double utcOffset)
{
- if (localTimeSeconds > maxUnixTime)
- localTimeSeconds = maxUnixTime;
- else if (localTimeSeconds < 0) // Go ahead a day to make localtime work (does not work with 0)
- localTimeSeconds += secondsPerDay;
-
//input is UTC so we have to shift back to local time to determine DST thus the + getUTCOffset()
- double offsetTime = (localTimeSeconds * msPerSecond) + utcOffset;
+ double offsetTime = (localTime * msPerSecond) + utcOffset;
// Offset from UTC but doesn't include DST obviously
int offsetHour = msToHours(offsetTime);
int offsetMinute = msToMinutes(offsetTime);
- // FIXME: time_t has a potential problem in 2038
- time_t localTime = static_cast<time_t>(localTimeSeconds);
-
tm localTM;
getLocalTime(&localTime, &localTM);
return (diff * msPerSecond);
}
-// Get the DST offset, given a time in UTC
-double calculateDSTOffset(double ms, double utcOffset)
+#endif
+
+// Returns combined offset in millisecond (UTC + DST).
+LocalTimeOffset calculateLocalTimeOffset(double ms)
{
- // On Mac OS X, the call to localtime (see calculateDSTOffsetSimple) will return historically accurate
+ // On Mac OS X, the call to localtime (see calculateDSTOffset) will return historically accurate
// DST information (e.g. New Zealand did not have DST from 1946 to 1974) however the JavaScript
// standard explicitly dictates that historical information should not be considered when
// determining DST. For this reason we shift away from years that localtime can handle but would
ms = (day * msPerDay) + msToMilliseconds(ms);
}
- return calculateDSTOffsetSimple(ms / msPerSecond, utcOffset);
+ double localTimeSeconds = ms / msPerSecond;
+ if (localTimeSeconds > maxUnixTime)
+ localTimeSeconds = maxUnixTime;
+ else if (localTimeSeconds < 0) // Go ahead a day to make localtime work (does not work with 0)
+ localTimeSeconds += secondsPerDay;
+ // FIXME: time_t has a potential problem in 2038
+ time_t localTime = static_cast<time_t>(localTimeSeconds);
+
+#if HAVE(TM_GMTOFF)
+ tm localTM;
+ getLocalTime(&localTime, &localTM);
+ return LocalTimeOffset(localTM.tm_isdst, localTM.tm_gmtoff * msPerSecond);
+#else
+ double utcOffset = calculateUTCOffset();
+ double dstOffset = calculateDSTOffset(localTime, utcOffset);
+ return LocalTimeOffset(dstOffset, utcOffset + dstOffset);
+#endif
}
void initializeDates()
return std::numeric_limits<double>::quiet_NaN();
// fall back to local timezone
- if (!haveTZ) {
- double utcOffset = calculateUTCOffset();
- double dstOffset = calculateDSTOffset(ms, utcOffset);
- offset = static_cast<int>((utcOffset + dstOffset) / msPerMinute);
- }
+ if (!haveTZ)
+ offset = calculateLocalTimeOffset(ms).offset / msPerMinute;
return ms - (offset * msPerMinute);
}
WTF_EXPORT_PRIVATE int dayInMonthFromDayInYear(int dayInYear, bool leapYear);
// Returns offset milliseconds for UTC and DST.
-WTF_EXPORT_PRIVATE int32_t calculateUTCOffset();
-WTF_EXPORT_PRIVATE double calculateDSTOffset(double ms, double utcOffset);
+struct LocalTimeOffset {
+ LocalTimeOffset(bool isDST, int offset)
+ : isDST(isDST)
+ , offset(offset)
+ {
+ }
+
+ bool operator==(const LocalTimeOffset& other)
+ {
+ return isDST == other.isDST && offset == other.offset;
+ }
+
+ bool isDST;
+ int offset;
+};
+// Returns combined offset in millisecond (UTC + DST).
+WTF_EXPORT_PRIVATE LocalTimeOffset calculateLocalTimeOffset(double);
} // namespace WTF
using WTF::secondsPerMinute;
using WTF::parseDateFromNullTerminatedCharacters;
using WTF::makeRFC2822DateString;
-using WTF::calculateUTCOffset;
-using WTF::calculateDSTOffset;
+using WTF::LocalTimeOffset;
+using WTF::calculateLocalTimeOffset;
#endif // DateMath_h
#if HAVE(TM_GMTOFF)
m_utcOffset = localTM.tm_gmtoff;
#else
- int utcOffset = calculateUTCOffset();
- utcOffset += calculateDSTOffset(localTime * msPerSecond, utcOffset);
- m_utcOffset = utcOffset / msPerSecond;
+ m_utcOffset = calculateLocalTimeOffset(localTime * msPerSecond).offset / msPerSecond;
#endif
#endif
}
#define ENABLE_TIZEN_JSC_CACHEFLUSH_PAGE_BY_PAGE 1 /* Hojong Han(hojong.han@samsung.com) : Fix YarrJIT crash */
#define ENABLE_TIZEN_SET_PROPERTY_ATTRIBUTE_CORRECTLY 1 /* Hojong Han(hojong.han@samsung.com) : Fix overwritting Read-only property, set from WRT */
#define ENABLE_TIZEN_JSC_SKIP_PROPERTY_TABLE_ERROR 1 /* Hojong Han(hojong.han@samsung.com) : Skip property table error */
+#define ENABLE_TIZEN_GENERATE_COMBINED_UTC_LOCAL 1 /* Hojong Han(hojong.han@samsung.com) : Simplify date handling code */
#define ENABLE_TIZEN_WRT_LAUNCHING_PERFORMANCE 1 /* Byungwoo Lee(bw80.lee@samsung.com) : Local patches to enhance web app launching performance */
Decimal BaseDateAndTimeInputType::defaultValueForStepUp() const
{
double ms = currentTimeMS();
+#if ENABLE(TIZEN_GENERATE_COMBINED_UTC_LOCAL)
+ int offset = calculateLocalTimeOffset(ms).offset / msPerMinute;
+#else
double utcOffset = calculateUTCOffset();
double dstOffset = calculateDSTOffset(ms, utcOffset);
int offset = static_cast<int>((utcOffset + dstOffset) / msPerMinute);
+#endif
return Decimal::fromDouble(ms + (offset * msPerMinute));
}
Decimal MonthInputType::defaultValueForStepUp() const
{
double current = currentTimeMS();
+#if ENABLE(TIZEN_GENERATE_COMBINED_UTC_LOCAL)
+ int offset = calculateLocalTimeOffset(current).offset / msPerMinute;
+#else
double utcOffset = calculateUTCOffset();
double dstOffset = calculateDSTOffset(current, utcOffset);
int offset = static_cast<int>((utcOffset + dstOffset) / msPerMinute);
+#endif
current += offset * msPerMinute;
DateComponents date;
Decimal TimeInputType::defaultValueForStepUp() const
{
double current = currentTimeMS();
+#if ENABLE(TIZEN_GENERATE_COMBINED_UTC_LOCAL)
+ int offset = calculateLocalTimeOffset(current).offset / msPerMinute;
+#else
double utcOffset = calculateUTCOffset();
double dstOffset = calculateDSTOffset(current, utcOffset);
int offset = static_cast<int>((utcOffset + dstOffset) / msPerMinute);
+#endif
current += offset * msPerMinute;
DateComponents date;