summaryrefslogtreecommitdiffstats
path: root/src/corelib/tools/qtimezoneprivate_tz.cpp
diff options
context:
space:
mode:
authorEdward Welbourne <edward.welbourne@qt.io>2016-10-06 18:29:19 +0200
committerEdward Welbourne <edward.welbourne@qt.io>2016-12-12 13:58:45 +0000
commit772b12c436e49fbaedea85e95ac645f40e4aa104 (patch)
tree55960fb403900b7266892e9f77d14559699056a7 /src/corelib/tools/qtimezoneprivate_tz.cpp
parent6e3f58cbbe313c3b843f69f3110e3c795fef6da8 (diff)
QTzTimeZonePrivate::init() fix for DST start as standard time changes
Europe/Samara reduced its standard offset at the same time as it started DST in March 2010, so the transition didn't change net offset. Our interpretation of the TZ database assumed the prior standard offset still applied; as this was equal to the new offset with DST, it marked the dst offset as zero, so we interpreted the next few months as being without DST, although the TZ database marks it as with. Generally, if a DST period has an odd DST offset, it's possible it's due to a change to standard offset at its start. Deem the offset odd if it's not what we last saw (or, on the first DST, not an hour); in that case, check the DST period's end, to see if it offers a less odd DST offset. Positive DST offsets are less odd than zero or negative; otherwise, expect what we saw last, one hour is not odd and closer to what we saw last is less odd than further from it. This suffices to fix Samara in 2010, at least. Task-number: QTBUG-56345 Change-Id: I9f0ee4e9cd6901c28a8ec1558aec5d26a21152f6 Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Diffstat (limited to 'src/corelib/tools/qtimezoneprivate_tz.cpp')
-rw-r--r--src/corelib/tools/qtimezoneprivate_tz.cpp50
1 files changed, 46 insertions, 4 deletions
diff --git a/src/corelib/tools/qtimezoneprivate_tz.cpp b/src/corelib/tools/qtimezoneprivate_tz.cpp
index 96d04df0e2..f5ab1a1deb 100644
--- a/src/corelib/tools/qtimezoneprivate_tz.cpp
+++ b/src/corelib/tools/qtimezoneprivate_tz.cpp
@@ -725,19 +725,61 @@ void QTzTimeZonePrivate::init(const QByteArray &ianaId)
}
}
- // Now for each transition time calculate our rule and save them
- m_tranTimes.reserve(tranList.count());
- for (const QTzTransition &tz_tran : qAsConst(tranList)) {
+ // Now for each transition time calculate and store our rule:
+ const int tranCount = tranList.count();;
+ m_tranTimes.reserve(tranCount);
+ // The DST offset when in effect: usually stable, usually an hour:
+ int lastDstOff = 3600;
+ for (int i = 0; i < tranCount; i++) {
+ const QTzTransition &tz_tran = tranList.at(i);
QTzTransitionTime tran;
QTzTransitionRule rule;
const QTzType tz_type = typeList.at(tz_tran.tz_typeind);
// Calculate the associated Rule
- if (!tz_type.tz_isdst)
+ if (!tz_type.tz_isdst) {
utcOffset = tz_type.tz_gmtoff;
+ } else if (Q_UNLIKELY(tz_type.tz_gmtoff != utcOffset + lastDstOff)) {
+ /*
+ This might be a genuine change in DST offset, but could also be
+ DST starting at the same time as the standard offset changed. See
+ if DST's end gives a more plausible utcOffset (i.e. one closer to
+ the last we saw, or a simple whole hour):
+ */
+ // Standard offset inferred from net offset and expected DST offset:
+ const int inferStd = tz_type.tz_gmtoff - lastDstOff; // != utcOffset
+ for (int j = i + 1; j < tranCount; j++) {
+ const QTzType new_type = typeList.at(tranList.at(j).tz_typeind);
+ if (!new_type.tz_isdst) {
+ const int newUtc = new_type.tz_gmtoff;
+ if (newUtc == utcOffset) {
+ // DST-end can't help us, avoid lots of messy checks.
+ // else: See if the end matches the familiar DST offset:
+ } else if (newUtc == inferStd) {
+ utcOffset = newUtc;
+ // else: let either end shift us to one hour as DST offset:
+ } else if (tz_type.tz_gmtoff - 3600 == utcOffset) {
+ // Start does it
+ } else if (tz_type.tz_gmtoff - 3600 == newUtc) {
+ utcOffset = newUtc; // End does it
+ // else: prefer whichever end gives DST offset closer to
+ // last, but consider any offset > 0 "closer" than any <= 0:
+ } else if (newUtc < tz_type.tz_gmtoff
+ ? (utcOffset >= tz_type.tz_gmtoff
+ || qAbs(newUtc - inferStd) < qAbs(utcOffset - inferStd))
+ : (utcOffset >= tz_type.tz_gmtoff
+ && qAbs(newUtc - inferStd) < qAbs(utcOffset - inferStd))) {
+ utcOffset = newUtc;
+ }
+ break;
+ }
+ }
+ lastDstOff = tz_type.tz_gmtoff - utcOffset;
+ }
rule.stdOffset = utcOffset;
rule.dstOffset = tz_type.tz_gmtoff - utcOffset;
rule.abbreviationIndex = tz_type.tz_abbrind;
+
// If the rule already exist then use that, otherwise add it
int ruleIndex = m_tranRules.indexOf(rule);
if (ruleIndex == -1) {