// Get the 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) { DSTOffsetCache& cache = exec->globalData().dstOffsetCache; double start = cache.start; double end = cache.end; if (start <= ms) { // If the time fits in the cached interval, return the cached offset. if (ms <= end) return cache.offset; // Compute a possible new interval end. double newEnd = end + cache.increment; if (ms <= newEnd) { double endOffset = calculateDSTOffset(newEnd, utcOffset); 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 // and return the offset. cache.end = newEnd; cache.increment = msPerMonth; return endOffset; } 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; } } } // 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); cache.offset = offset; cache.start = ms; cache.end = ms; cache.increment = msPerMonth; return offset; }
static int currentFullYear() { double current = currentTimeMS(); double utcOffset = calculateUTCOffset(); double dstOffset = calculateDSTOffset(current, utcOffset); int offset = static_cast<int>((utcOffset + dstOffset) / msPerMinute); current += offset * msPerMinute; DateComponents date; date.setMillisecondsSinceEpochForMonth(current); return date.fullYear(); }
int DateTimeYearFieldElement::defaultValueForStepDown() const { double current = currentTimeMS(); double utcOffset = calculateUTCOffset(); double dstOffset = calculateDSTOffset(current, utcOffset); int offset = static_cast<int>((utcOffset + dstOffset) / msPerMinute); current += offset * msPerMinute; DateComponents date; date.setMillisecondsSinceEpochForMonth(current); return date.fullYear(); }
Decimal MonthInputType::defaultValueForStepUp() const { double current = currentTimeMS(); double utcOffset = calculateUTCOffset(); double dstOffset = calculateDSTOffset(current, utcOffset); int offset = static_cast<int>((utcOffset + dstOffset) / msPerMinute); current += offset * msPerMinute; DateComponents date; date.setMillisecondsSinceEpochForMonth(current); double months = date.monthsSinceEpoch(); ASSERT(std::isfinite(months)); return Decimal::fromDouble(months); }
double parseDateFromNullTerminatedCharacters(const char* dateString) { bool haveTZ; int offset; double ms = parseDateFromNullTerminatedCharacters(dateString, haveTZ, offset); if (isnan(ms)) return NaN; // fall back to local timezone if (!haveTZ) { double utcOffset = calculateUTCOffset(); double dstOffset = calculateDSTOffset(ms, utcOffset); offset = static_cast<int>((utcOffset + dstOffset) / msPerMinute); } return ms - (offset * msPerMinute); }
double parseDateFromNullTerminatedCharacters(const char* dateString) { bool haveTZ; int offset; double ms = parseDateFromNullTerminatedCharacters(dateString, haveTZ, offset); if (std::isnan(ms)) return std::numeric_limits<double>::quiet_NaN(); // fall back to local timezone if (!haveTZ) { double utcOffset = calculateUTCOffset(); double dstOffset = calculateDSTOffset(ms, utcOffset); offset = (utcOffset + dstOffset) / msPerMinute; } return ms - (offset * msPerMinute); }
// Returns combined offset in millisecond (UTC + DST). LocalTimeOffset calculateLocalTimeOffset(double ms, TimeType inputTimeType) { #if HAVE(TM_GMTOFF) double localToUTCTimeOffset = inputTimeType == LocalTime ? calculateUTCOffset() : 0; #else double localToUTCTimeOffset = calculateUTCOffset(); #endif if (inputTimeType == LocalTime) ms -= localToUTCTimeOffset; // 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 // return historically accurate information. int year = msToYear(ms); int equivalentYear = equivalentYearForDST(year); if (year != equivalentYear) { bool leapYear = isLeapYear(year); int dayInYearLocal = dayInYear(ms, year); int dayInMonth = dayInMonthFromDayInYear(dayInYearLocal, leapYear); int month = monthFromDayInYear(dayInYearLocal, leapYear); double day = dateToDaysFrom1970(equivalentYear, month, dayInMonth); ms = (day * msPerDay) + msToMilliseconds(ms); } 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 dstOffset = calculateDSTOffset(localTime, localToUTCTimeOffset); return LocalTimeOffset(dstOffset, localToUTCTimeOffset + dstOffset); #endif }