diff --git a/src/corelib/tools/qtimezoneprivate_tz.cpp b/src/corelib/tools/qtimezoneprivate_tz.cpp index 38dff88919..9cbe339225 100644 --- a/src/corelib/tools/qtimezoneprivate_tz.cpp +++ b/src/corelib/tools/qtimezoneprivate_tz.cpp @@ -452,13 +452,31 @@ static inline bool asciiIsLetter(char ch) return ch >= 'a' && ch <= 'z'; } +namespace { + +struct PosixZone +{ + enum { + InvalidOffset = INT_MIN, + }; + + QString name; + int offset; + + static PosixZone invalid() { return {QString(), InvalidOffset}; } + static PosixZone parse(const char *&pos, const char *end); + + bool hasValidOffset() const Q_DECL_NOTHROW { return offset != InvalidOffset; } +}; + +} // unnamed namespace + // Returns the zone name, the offset (in seconds) and advances \a begin to // where the parsing ended. Returns a zone of INT_MIN in case an offset // couldn't be read. -static QPair parsePosixZoneNameAndOffset(const char *&pos, const char *end) +PosixZone PosixZone::parse(const char *&pos, const char *end) { static const char offsetChars[] = "0123456789:"; - QPair result = qMakePair(QString(), INT_MIN); const char *nameBegin = pos; const char *nameEnd; @@ -480,7 +498,7 @@ static QPair parsePosixZoneNameAndOffset(const char *&pos, const c pos = nameEnd; } if (nameEnd - nameBegin < 3) - return result; // name must be at least 3 characters long + return invalid(); // name must be at least 3 characters long // zone offset, form [+-]hh:mm:ss const char *zoneBegin = pos; @@ -493,11 +511,10 @@ static QPair parsePosixZoneNameAndOffset(const char *&pos, const c ++zoneEnd; } - result.first = QString::fromUtf8(nameBegin, nameEnd - nameBegin); - if (zoneEnd > zoneBegin) - result.second = parsePosixOffset(zoneBegin, zoneEnd); + QString name = QString::fromUtf8(nameBegin, nameEnd - nameBegin); + const int offset = zoneEnd > zoneBegin ? parsePosixOffset(zoneBegin, zoneEnd) : InvalidOffset; pos = zoneEnd; - return result; + return {std::move(name), offset}; } static QVector calculatePosixTransitions(const QByteArray &posixRule, @@ -517,19 +534,19 @@ static QVector calculatePosixTransitions(const QByteArra // See the section about TZ at http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html QList parts = posixRule.split(','); - QPair stdZone, dstZone; + PosixZone stdZone, dstZone; { const QByteArray &zoneinfo = parts.at(0); const char *begin = zoneinfo.constBegin(); - stdZone = parsePosixZoneNameAndOffset(begin, zoneinfo.constEnd()); - if (stdZone.second == INT_MIN) { - stdZone.second = 0; // reset to UTC if we failed to parse + stdZone = PosixZone::parse(begin, zoneinfo.constEnd()); + if (!stdZone.hasValidOffset()) { + stdZone.offset = 0; // reset to UTC if we failed to parse } else if (begin < zoneinfo.constEnd()) { - dstZone = parsePosixZoneNameAndOffset(begin, zoneinfo.constEnd()); - if (dstZone.second == INT_MIN) { + dstZone = PosixZone::parse(begin, zoneinfo.constEnd()); + if (!dstZone.hasValidOffset()) { // if the dst offset isn't provided, it is 1 hour ahead of the standard offset - dstZone.second = stdZone.second + (60 * 60); + dstZone.offset = stdZone.offset + (60 * 60); } } } @@ -538,10 +555,10 @@ static QVector calculatePosixTransitions(const QByteArra if (parts.count() == 1) { QTimeZonePrivate::Data data; data.atMSecsSinceEpoch = lastTranMSecs; - data.offsetFromUtc = stdZone.second; - data.standardTimeOffset = stdZone.second; + data.offsetFromUtc = stdZone.offset; + data.standardTimeOffset = stdZone.offset; data.daylightTimeOffset = 0; - data.abbreviation = stdZone.first; + data.abbreviation = stdZone.name; result << data; return result; } @@ -568,18 +585,18 @@ static QVector calculatePosixTransitions(const QByteArra for (int year = startYear; year <= endYear; ++year) { QTimeZonePrivate::Data dstData; QDateTime dst(calculatePosixDate(dstDateRule, year), dstTime, Qt::UTC); - dstData.atMSecsSinceEpoch = dst.toMSecsSinceEpoch() - (stdZone.second * 1000); - dstData.offsetFromUtc = dstZone.second; - dstData.standardTimeOffset = stdZone.second; - dstData.daylightTimeOffset = dstZone.second - stdZone.second; - dstData.abbreviation = dstZone.first; + dstData.atMSecsSinceEpoch = dst.toMSecsSinceEpoch() - (stdZone.offset * 1000); + dstData.offsetFromUtc = dstZone.offset; + dstData.standardTimeOffset = stdZone.offset; + dstData.daylightTimeOffset = dstZone.offset - stdZone.offset; + dstData.abbreviation = dstZone.name; QTimeZonePrivate::Data stdData; QDateTime std(calculatePosixDate(stdDateRule, year), stdTime, Qt::UTC); - stdData.atMSecsSinceEpoch = std.toMSecsSinceEpoch() - (dstZone.second * 1000); - stdData.offsetFromUtc = stdZone.second; - stdData.standardTimeOffset = stdZone.second; + stdData.atMSecsSinceEpoch = std.toMSecsSinceEpoch() - (dstZone.offset * 1000); + stdData.offsetFromUtc = stdZone.offset; + stdData.standardTimeOffset = stdZone.offset; stdData.daylightTimeOffset = 0; - stdData.abbreviation = stdZone.first; + stdData.abbreviation = stdZone.name; // Part of the high year will overflow if (year == 292278994 && (dstData.atMSecsSinceEpoch < 0 || stdData.atMSecsSinceEpoch < 0)) { if (dstData.atMSecsSinceEpoch > 0) {