QWinTimeZonePrivate: make transition searches more efficient
Iterate rules (now that there's fewer of them than years) with only a secondary iteration on years (when needed - in which case it should never need more than two iterations). In particular, avoid iterating years to the MIN_YEAR and MAX_YEAR extremes on failure; fail faster ! Change-Id: I354af8e0cb1e484c8abda279991e6e1824f9f7d4 Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
parent
a99c773972
commit
88d5ba5409
@ -401,9 +401,6 @@ struct TransitionTimePair
|
|||||||
{
|
{
|
||||||
// Transition times after the epoch, in ms:
|
// Transition times after the epoch, in ms:
|
||||||
qint64 std, dst;
|
qint64 std, dst;
|
||||||
TransitionTimePair()
|
|
||||||
: std(QTimeZonePrivate::invalidMSecs()), dst(QTimeZonePrivate::invalidMSecs())
|
|
||||||
{}
|
|
||||||
TransitionTimePair(const QWinTimeZonePrivate::QWinTransitionRule &rule, int year)
|
TransitionTimePair(const QWinTimeZonePrivate::QWinTransitionRule &rule, int year)
|
||||||
// The local time in Daylight Time of the switch to Standard Time
|
// The local time in Daylight Time of the switch to Standard Time
|
||||||
: std(calculateTransitionForYear(rule.standardTimeRule, year,
|
: std(calculateTransitionForYear(rule.standardTimeRule, year,
|
||||||
@ -660,39 +657,37 @@ bool QWinTimeZonePrivate::isDaylightTime(qint64 atMSecsSinceEpoch) const
|
|||||||
|
|
||||||
QTimeZonePrivate::Data QWinTimeZonePrivate::data(qint64 forMSecsSinceEpoch) const
|
QTimeZonePrivate::Data QWinTimeZonePrivate::data(qint64 forMSecsSinceEpoch) const
|
||||||
{
|
{
|
||||||
// Convert MSecs to year to get transitions for, assumes no transitions around 31 Dec/1 Jan
|
|
||||||
int year = msecsToDate(forMSecsSinceEpoch).year();
|
int year = msecsToDate(forMSecsSinceEpoch).year();
|
||||||
|
for (int ruleIndex = ruleIndexForYear(m_tranRules, year);
|
||||||
qint64 first;
|
ruleIndex >= 0; --ruleIndex) {
|
||||||
qint64 second;
|
const QWinTransitionRule &rule = m_tranRules.at(ruleIndex);
|
||||||
qint64 next = maxMSecs();
|
// Does this rule's period include any transition at all ?
|
||||||
TransitionTimePair pair;
|
if (rule.standardTimeRule.wMonth > 0 || rule.daylightTimeRule.wMonth > 0) {
|
||||||
Q_ASSERT(next != pair.dst); // so break on first iteration gets standard time
|
const int endYear = qMax(rule.startYear, year - 1);
|
||||||
QWinTransitionRule rule;
|
while (year >= endYear) {
|
||||||
do {
|
const TransitionTimePair pair(rule, year);
|
||||||
// Convert the transition rules into msecs for the year we want to try
|
bool isDst = false;
|
||||||
rule = m_tranRules.at(ruleIndexForYear(m_tranRules, year));
|
if (pair.std <= forMSecsSinceEpoch) {
|
||||||
// If no transition rules to calculate then no DST, so just use rule for std
|
isDst = pair.std < pair.dst && pair.dst <= forMSecsSinceEpoch;
|
||||||
if (rule.standardTimeRule.wMonth == 0 && rule.daylightTimeRule.wMonth == 0)
|
} else if (pair.dst <= forMSecsSinceEpoch) {
|
||||||
break;
|
isDst = true;
|
||||||
|
} else {
|
||||||
pair = TransitionTimePair(rule, year);
|
--year; // Try an earlier year for this rule (once).
|
||||||
if (pair.std < pair.dst) {
|
continue;
|
||||||
first = pair.std;
|
}
|
||||||
second = pair.dst;
|
return ruleToData(rule, forMSecsSinceEpoch,
|
||||||
|
isDst ? QTimeZone::DaylightTime : QTimeZone::StandardTime);
|
||||||
|
}
|
||||||
|
// Fell off start of rule, try previous rule.
|
||||||
} else {
|
} else {
|
||||||
first = pair.dst;
|
// No transition, no DST, use the year's standard time.
|
||||||
second = pair.std;
|
return ruleToData(rule, forMSecsSinceEpoch, QTimeZone::StandardTime);
|
||||||
}
|
}
|
||||||
if (forMSecsSinceEpoch >= second && second != invalidMSecs())
|
if (year >= rule.startYear)
|
||||||
next = second;
|
year = rule.startYear - 1; // Seek last transition in new rule.
|
||||||
else if (forMSecsSinceEpoch >= first && first != invalidMSecs())
|
}
|
||||||
next = first;
|
// We don't have relevant data :-(
|
||||||
// If didn't fall in this year, try the previous
|
return invalidData();
|
||||||
--year;
|
|
||||||
} while (next == maxMSecs() && year >= MIN_YEAR);
|
|
||||||
|
|
||||||
return ruleToData(rule, forMSecsSinceEpoch, (next == pair.dst) ? QTimeZone::DaylightTime : QTimeZone::StandardTime);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool QWinTimeZonePrivate::hasTransitions() const
|
bool QWinTimeZonePrivate::hasTransitions() const
|
||||||
@ -706,107 +701,70 @@ bool QWinTimeZonePrivate::hasTransitions() const
|
|||||||
|
|
||||||
QTimeZonePrivate::Data QWinTimeZonePrivate::nextTransition(qint64 afterMSecsSinceEpoch) const
|
QTimeZonePrivate::Data QWinTimeZonePrivate::nextTransition(qint64 afterMSecsSinceEpoch) const
|
||||||
{
|
{
|
||||||
// Convert MSecs to year to get transitions for, assumes no transitions around 31 Dec/1 Jan
|
|
||||||
int year = msecsToDate(afterMSecsSinceEpoch).year();
|
int year = msecsToDate(afterMSecsSinceEpoch).year();
|
||||||
|
for (int ruleIndex = ruleIndexForYear(m_tranRules, year);
|
||||||
|
ruleIndex < m_tranRules.count(); ++ruleIndex) {
|
||||||
|
const QWinTransitionRule &rule = m_tranRules.at(ruleIndex);
|
||||||
|
// Does this rule's period include any transition at all ?
|
||||||
|
if (rule.standardTimeRule.wMonth > 0 || rule.daylightTimeRule.wMonth > 0) {
|
||||||
|
if (year < rule.startYear)
|
||||||
|
year = rule.startYear; // Seek first transition in this rule.
|
||||||
|
const int endYear = ruleIndex + 1 < m_tranRules.count()
|
||||||
|
? qMin(m_tranRules.at(ruleIndex + 1).startYear, year + 2) : (year + 2);
|
||||||
|
while (year < endYear) {
|
||||||
|
const TransitionTimePair pair(rule, year);
|
||||||
|
bool isDst = false;
|
||||||
|
if (pair.std > afterMSecsSinceEpoch) {
|
||||||
|
isDst = pair.std > pair.dst && pair.dst > afterMSecsSinceEpoch;
|
||||||
|
} else if (pair.dst > afterMSecsSinceEpoch) {
|
||||||
|
isDst = true;
|
||||||
|
} else {
|
||||||
|
++year; // Try a later year for this rule (once).
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
QWinTransitionRule rule;
|
if (isDst)
|
||||||
// If the required year falls after the last rule start year and the last rule has no
|
return ruleToData(rule, pair.dst, QTimeZone::DaylightTime);
|
||||||
// valid future transition calculations then there is no next transition
|
return ruleToData(rule, pair.std, QTimeZone::StandardTime);
|
||||||
if (year > m_tranRules.last().startYear) {
|
}
|
||||||
rule = m_tranRules.at(ruleIndexForYear(m_tranRules, year));
|
// Fell off end of rule, try next rule.
|
||||||
// If the rules have either a fixed year, or no month, then no future trans
|
} // else: no transition during rule's period
|
||||||
if (rule.standardTimeRule.wYear != 0 || rule.daylightTimeRule.wYear != 0
|
|
||||||
|| rule.standardTimeRule.wMonth == 0 || rule.daylightTimeRule.wMonth == 0) {
|
|
||||||
return invalidData();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
// Apparently no transition after the given time:
|
||||||
// Otherwise we have a valid rule for the required year that can be used
|
return invalidData();
|
||||||
// to calculate this year or next
|
|
||||||
qint64 first;
|
|
||||||
qint64 second;
|
|
||||||
qint64 next = minMSecs();
|
|
||||||
TransitionTimePair pair;
|
|
||||||
do {
|
|
||||||
// Convert the transition rules into msecs for the year we want to try
|
|
||||||
rule = m_tranRules.at(ruleIndexForYear(m_tranRules, year));
|
|
||||||
// If there's no transition this year, check for a later year:
|
|
||||||
if (rule.standardTimeRule.wMonth == 0 && rule.daylightTimeRule.wMonth == 0) {
|
|
||||||
++year;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
pair = TransitionTimePair(rule, year);
|
|
||||||
// Find the first and second transition for the year
|
|
||||||
if (pair.std < pair.dst) {
|
|
||||||
first = pair.std;
|
|
||||||
second = pair.dst;
|
|
||||||
} else {
|
|
||||||
first = pair.dst;
|
|
||||||
second = pair.std;
|
|
||||||
}
|
|
||||||
if (afterMSecsSinceEpoch < first)
|
|
||||||
next = first;
|
|
||||||
else if (afterMSecsSinceEpoch < second)
|
|
||||||
next = second;
|
|
||||||
// If didn't fall in this year, try the next
|
|
||||||
++year;
|
|
||||||
} while (next == minMSecs() && year <= MAX_YEAR);
|
|
||||||
|
|
||||||
if (next == minMSecs() || next == invalidMSecs())
|
|
||||||
return invalidData();
|
|
||||||
|
|
||||||
return ruleToData(rule, next, (next == pair.dst) ? QTimeZone::DaylightTime : QTimeZone::StandardTime);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QTimeZonePrivate::Data QWinTimeZonePrivate::previousTransition(qint64 beforeMSecsSinceEpoch) const
|
QTimeZonePrivate::Data QWinTimeZonePrivate::previousTransition(qint64 beforeMSecsSinceEpoch) const
|
||||||
{
|
{
|
||||||
// Convert MSecs to year to get transitions for, assumes no transitions around 31 Dec/1 Jan
|
|
||||||
int year = msecsToDate(beforeMSecsSinceEpoch).year();
|
int year = msecsToDate(beforeMSecsSinceEpoch).year();
|
||||||
|
for (int ruleIndex = ruleIndexForYear(m_tranRules, year);
|
||||||
QWinTransitionRule rule;
|
ruleIndex >= 0; --ruleIndex) {
|
||||||
// If the required year falls before the first rule start year and the first rule has no
|
const QWinTransitionRule &rule = m_tranRules.at(ruleIndex);
|
||||||
// valid transition calculations then there is no previous transition
|
// Does this rule's period include any transition at all ?
|
||||||
if (year < m_tranRules.first().startYear) {
|
if (rule.standardTimeRule.wMonth > 0 || rule.daylightTimeRule.wMonth > 0) {
|
||||||
rule = m_tranRules.at(ruleIndexForYear(m_tranRules, year));
|
const int endYear = qMax(rule.startYear, year - 1);
|
||||||
// If the rules have either a fixed year, or no month, then no previous trans
|
while (year >= endYear) {
|
||||||
if (rule.standardTimeRule.wYear != 0 || rule.daylightTimeRule.wYear != 0
|
const TransitionTimePair pair(rule, year);
|
||||||
|| rule.standardTimeRule.wMonth == 0 || rule.daylightTimeRule.wMonth == 0) {
|
bool isDst = false;
|
||||||
return invalidData();
|
if (pair.std < beforeMSecsSinceEpoch) {
|
||||||
}
|
isDst = pair.std < pair.dst && pair.dst < beforeMSecsSinceEpoch;
|
||||||
|
} else if (pair.dst < beforeMSecsSinceEpoch) {
|
||||||
|
isDst = true;
|
||||||
|
} else {
|
||||||
|
--year; // Try an earlier year for this rule (once).
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (isDst)
|
||||||
|
return ruleToData(rule, pair.dst, QTimeZone::DaylightTime);
|
||||||
|
return ruleToData(rule, pair.std, QTimeZone::StandardTime);
|
||||||
|
}
|
||||||
|
// Fell off start of rule, try previous rule.
|
||||||
|
} // else: no transition during rule's period
|
||||||
|
if (year >= rule.startYear)
|
||||||
|
year = rule.startYear - 1; // Seek last transition in new rule
|
||||||
}
|
}
|
||||||
|
// Apparently no transition before the given time:
|
||||||
qint64 first;
|
return invalidData();
|
||||||
qint64 second;
|
|
||||||
qint64 next = maxMSecs();
|
|
||||||
TransitionTimePair pair;
|
|
||||||
do {
|
|
||||||
// Convert the transition rules into msecs for the year we want to try
|
|
||||||
rule = m_tranRules.at(ruleIndexForYear(m_tranRules, year));
|
|
||||||
// If there's no transition this year, check for an earlier year:
|
|
||||||
if (rule.standardTimeRule.wMonth == 0 && rule.daylightTimeRule.wMonth == 0) {
|
|
||||||
--year;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
pair = TransitionTimePair(rule, year);
|
|
||||||
if (pair.std < pair.dst) {
|
|
||||||
first = pair.std;
|
|
||||||
second = pair.dst;
|
|
||||||
} else {
|
|
||||||
first = pair.dst;
|
|
||||||
second = pair.std;
|
|
||||||
}
|
|
||||||
if (beforeMSecsSinceEpoch > second && second != invalidMSecs())
|
|
||||||
next = second;
|
|
||||||
else if (beforeMSecsSinceEpoch > first && first != invalidMSecs())
|
|
||||||
next = first;
|
|
||||||
// If didn't fall in this year, try the previous
|
|
||||||
--year;
|
|
||||||
} while (next == maxMSecs() && year >= MIN_YEAR);
|
|
||||||
|
|
||||||
if (next == maxMSecs())
|
|
||||||
return invalidData();
|
|
||||||
|
|
||||||
return ruleToData(rule, next, (next == pair.dst) ? QTimeZone::DaylightTime : QTimeZone::StandardTime);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray QWinTimeZonePrivate::systemTimeZoneId() const
|
QByteArray QWinTimeZonePrivate::systemTimeZoneId() const
|
||||||
|
Loading…
Reference in New Issue
Block a user