QTzTimeZonePrivate: introduce PosixZone class

... as a replacement for QPair<QString, int>, and move some
repsonsibilities into it.

This avoids the repeated use of the magic number INT_MIN to indicate
absence of an offset and does away with the confusing .first and
.second, replacing them instead with proper names, .name and .offset.

Change-Id: I0f6906467b8efa16bed2bf5677f2bbbd534da1ae
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
Marc Mutz 2017-02-21 13:25:43 +01:00
parent c585802e94
commit adca47cbc1

View File

@ -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<QString, int> parsePosixZoneNameAndOffset(const char *&pos, const char *end)
PosixZone PosixZone::parse(const char *&pos, const char *end)
{
static const char offsetChars[] = "0123456789:";
QPair<QString, int> result = qMakePair(QString(), INT_MIN);
const char *nameBegin = pos;
const char *nameEnd;
@ -480,7 +498,7 @@ static QPair<QString, int> 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<QString, int> 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<QTimeZonePrivate::Data> calculatePosixTransitions(const QByteArray &posixRule,
@ -517,19 +534,19 @@ static QVector<QTimeZonePrivate::Data> calculatePosixTransitions(const QByteArra
// See the section about TZ at http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html
QList<QByteArray> parts = posixRule.split(',');
QPair<QString, int> 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<QTimeZonePrivate::Data> 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<QTimeZonePrivate::Data> 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) {