Correct the parsing of POSIX rule day-of-year fields
There are two formats for such fields: one with a J prefix on a number in the range 1 to 365, the other with no prefix and a range from 0 to 365. The code mistakenly treated the latter as if its range were from 1 to 366. The J-form doesn't count Feb 29th, so March always starts on day 60; the code tried to take that into account, but adjusted in the wrong direction (and this mislead me, in a recent partial fix, into a fence-post error). Add a test-case based on the Africa/Casablanca POSIX rule seen on RHEL 8.2, which tripped over the off-by-one error without a J prefix. This incidentally also tests the J case. Change-Id: I692ca511e5c960f91a6c21073d3b2f037f5e445f Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
parent
678cbaebcf
commit
2383e82bcf
@ -393,19 +393,22 @@ static QDate calculatePosixDate(const QByteArray &dateRule, int year)
|
||||
return calculateDowDate(year, month, dow, week);
|
||||
}
|
||||
} else if (dateRule.at(0) == 'J') {
|
||||
// Day of Year ignores Feb 29
|
||||
// Day of Year 1...365, ignores Feb 29.
|
||||
// So March always starts on day 60.
|
||||
int doy = dateRule.mid(1).toInt(&ok);
|
||||
if (ok && doy > 0 && doy < 366) {
|
||||
QDate date = QDate(year, 1, 1).addDays(doy - 1);
|
||||
if (QDate::isLeapYear(date.year()) && date.month() > 2)
|
||||
date = date.addDays(-1);
|
||||
return date;
|
||||
// Subtract 1 because we're adding days *after* the first of
|
||||
// January, unless it's after February in a leap year, when the leap
|
||||
// day cancels that out:
|
||||
if (!QDate::isLeapYear(year) || doy < 60)
|
||||
--doy;
|
||||
return QDate(year, 1, 1).addDays(doy);
|
||||
}
|
||||
} else {
|
||||
// Day of Year includes Feb 29
|
||||
// Day of Year 0...365, includes Feb 29
|
||||
int doy = dateRule.toInt(&ok);
|
||||
if (ok && doy > 0 && doy <= 366)
|
||||
return QDate(year, 1, 1).addDays(doy - 1);
|
||||
if (ok && doy >= 0 && doy < 366)
|
||||
return QDate(year, 1, 1).addDays(doy);
|
||||
}
|
||||
return QDate();
|
||||
}
|
||||
|
@ -1141,6 +1141,18 @@ void tst_QTimeZone::tzTest()
|
||||
QTzTimeZonePrivate tzposix("MET-1METDST-2,M3.5.0/02:00:00,M10.5.0/03:00:00");
|
||||
QVERIFY(tzposix.isValid());
|
||||
|
||||
// RHEL has been seen with this as Africa/Casablanca's POSIX rule:
|
||||
QTzTimeZonePrivate permaDst("<+00>0<+01>,0/0,J365/25");
|
||||
const QTimeZone utcP1("UTC+01:00"); // Should always have same offset as permaDst
|
||||
QVERIFY(permaDst.isValid());
|
||||
QVERIFY(permaDst.hasDaylightTime());
|
||||
QVERIFY(permaDst.isDaylightTime(QDate(2020, 1, 1).startOfDay(utcP1).toMSecsSinceEpoch()));
|
||||
QVERIFY(permaDst.isDaylightTime(QDate(2020, 12, 31).endOfDay(utcP1).toMSecsSinceEpoch()));
|
||||
// Note that the final /25 could be misunderstood as putting a fall-back at
|
||||
// 1am on the next year's Jan 1st; check we don't do that:
|
||||
QVERIFY(permaDst.isDaylightTime(
|
||||
QDateTime(QDate(2020, 1, 1), QTime(1, 30), utcP1).toMSecsSinceEpoch()));
|
||||
|
||||
QTimeZone tzBrazil("BRT+3"); // parts of Northern Brazil, as a POSIX rule
|
||||
QVERIFY(tzBrazil.isValid());
|
||||
QCOMPARE(tzBrazil.offsetFromUtc(QDateTime(QDate(1111, 11, 11).startOfDay())), -10800);
|
||||
|
Loading…
Reference in New Issue
Block a user