int64_t DSTOffsetCache::getDSTOffsetMilliseconds(int64_t localTimeMilliseconds, JSContext *cx) { sanityCheck(); int64_t localTimeSeconds = localTimeMilliseconds / MILLISECONDS_PER_SECOND; if (localTimeSeconds > MAX_UNIX_TIMET) { localTimeSeconds = MAX_UNIX_TIMET; } else if (localTimeSeconds < 0) { /* Go ahead a day to make localtime work (does not work with 0). */ localTimeSeconds = SECONDS_PER_DAY; } /* * NB: Be aware of the initial range values when making changes to this * code: the first call to this method, with those initial range * values, must result in a cache miss. */ if (rangeStartSeconds <= localTimeSeconds && localTimeSeconds <= rangeEndSeconds) { return offsetMilliseconds; } if (oldRangeStartSeconds <= localTimeSeconds && localTimeSeconds <= oldRangeEndSeconds) { return oldOffsetMilliseconds; } oldOffsetMilliseconds = offsetMilliseconds; oldRangeStartSeconds = rangeStartSeconds; oldRangeEndSeconds = rangeEndSeconds; if (rangeStartSeconds <= localTimeSeconds) { int64_t newEndSeconds = JS_MIN(rangeEndSeconds + RANGE_EXPANSION_AMOUNT, MAX_UNIX_TIMET); if (newEndSeconds >= localTimeSeconds) { int64_t endOffsetMilliseconds = computeDSTOffsetMilliseconds(newEndSeconds); if (endOffsetMilliseconds == offsetMilliseconds) { rangeEndSeconds = newEndSeconds; return offsetMilliseconds; } offsetMilliseconds = computeDSTOffsetMilliseconds(localTimeSeconds); if (offsetMilliseconds == endOffsetMilliseconds) { rangeStartSeconds = localTimeSeconds; rangeEndSeconds = newEndSeconds; } else { rangeEndSeconds = localTimeSeconds; } return offsetMilliseconds; } offsetMilliseconds = computeDSTOffsetMilliseconds(localTimeSeconds); rangeStartSeconds = rangeEndSeconds = localTimeSeconds; return offsetMilliseconds; } int64_t newStartSeconds = JS_MAX(rangeStartSeconds - RANGE_EXPANSION_AMOUNT, 0); if (newStartSeconds <= localTimeSeconds) { int64_t startOffsetMilliseconds = computeDSTOffsetMilliseconds(newStartSeconds); if (startOffsetMilliseconds == offsetMilliseconds) { rangeStartSeconds = newStartSeconds; return offsetMilliseconds; } offsetMilliseconds = computeDSTOffsetMilliseconds(localTimeSeconds); if (offsetMilliseconds == startOffsetMilliseconds) { rangeStartSeconds = newStartSeconds; rangeEndSeconds = localTimeSeconds; } else { rangeStartSeconds = localTimeSeconds; } return offsetMilliseconds; } rangeStartSeconds = rangeEndSeconds = localTimeSeconds; offsetMilliseconds = computeDSTOffsetMilliseconds(localTimeSeconds); return offsetMilliseconds; }
JSInt64 DSTOffsetCache::getDSTOffsetMilliseconds(JSInt64 localTimeMilliseconds, JSContext *cx) { sanityCheck(); noteOffsetCalculation(); JSInt64 localTimeSeconds = localTimeMilliseconds / MILLISECONDS_PER_SECOND; if (localTimeSeconds > MAX_UNIX_TIMET) { localTimeSeconds = MAX_UNIX_TIMET; } else if (localTimeSeconds < 0) { /* Go ahead a day to make localtime work (does not work with 0). */ localTimeSeconds = SECONDS_PER_DAY; } /* * NB: Be aware of the initial range values when making changes to this * code: the first call to this method, with those initial range * values, must result in a cache miss. */ if (rangeStartSeconds <= localTimeSeconds && localTimeSeconds <= rangeEndSeconds) { noteCacheHit(); return offsetMilliseconds; } if (oldRangeStartSeconds <= localTimeSeconds && localTimeSeconds <= oldRangeEndSeconds) { noteCacheHit(); return oldOffsetMilliseconds; } oldOffsetMilliseconds = offsetMilliseconds; oldRangeStartSeconds = rangeStartSeconds; oldRangeEndSeconds = rangeEndSeconds; if (rangeStartSeconds <= localTimeSeconds) { JSInt64 newEndSeconds = JS_MIN(rangeEndSeconds + RANGE_EXPANSION_AMOUNT, MAX_UNIX_TIMET); if (newEndSeconds >= localTimeSeconds) { JSInt64 endOffsetMilliseconds = computeDSTOffsetMilliseconds(newEndSeconds); if (endOffsetMilliseconds == offsetMilliseconds) { noteCacheMissIncrease(); rangeEndSeconds = newEndSeconds; return offsetMilliseconds; } offsetMilliseconds = computeDSTOffsetMilliseconds(localTimeSeconds); if (offsetMilliseconds == endOffsetMilliseconds) { noteCacheMissIncreasingOffsetChangeUpper(); rangeStartSeconds = localTimeSeconds; rangeEndSeconds = newEndSeconds; } else { noteCacheMissIncreasingOffsetChangeExpand(); rangeEndSeconds = localTimeSeconds; } return offsetMilliseconds; } noteCacheMissLargeIncrease(); offsetMilliseconds = computeDSTOffsetMilliseconds(localTimeSeconds); rangeStartSeconds = rangeEndSeconds = localTimeSeconds; return offsetMilliseconds; } JSInt64 newStartSeconds = JS_MAX(rangeStartSeconds - RANGE_EXPANSION_AMOUNT, 0); if (newStartSeconds <= localTimeSeconds) { JSInt64 startOffsetMilliseconds = computeDSTOffsetMilliseconds(newStartSeconds); if (startOffsetMilliseconds == offsetMilliseconds) { noteCacheMissDecrease(); rangeStartSeconds = newStartSeconds; return offsetMilliseconds; } offsetMilliseconds = computeDSTOffsetMilliseconds(localTimeSeconds); if (offsetMilliseconds == startOffsetMilliseconds) { noteCacheMissDecreasingOffsetChangeLower(); rangeStartSeconds = newStartSeconds; rangeEndSeconds = localTimeSeconds; } else { noteCacheMissDecreasingOffsetChangeExpand(); rangeStartSeconds = localTimeSeconds; } return offsetMilliseconds; } noteCacheMissLargeDecrease(); rangeStartSeconds = rangeEndSeconds = localTimeSeconds; offsetMilliseconds = computeDSTOffsetMilliseconds(localTimeSeconds); return offsetMilliseconds; }