summaryrefslogtreecommitdiffstats
path: root/src/corelib/time/qtimezoneprivate_tz.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/time/qtimezoneprivate_tz.cpp')
-rw-r--r--src/corelib/time/qtimezoneprivate_tz.cpp65
1 files changed, 44 insertions, 21 deletions
diff --git a/src/corelib/time/qtimezoneprivate_tz.cpp b/src/corelib/time/qtimezoneprivate_tz.cpp
index a21b7ab5c8..b98fe6327a 100644
--- a/src/corelib/time/qtimezoneprivate_tz.cpp
+++ b/src/corelib/time/qtimezoneprivate_tz.cpp
@@ -350,6 +350,11 @@ static QByteArray parseTzPosixRule(QDataStream &ds)
static QDate calculateDowDate(int year, int month, int dayOfWeek, int week)
{
+ if (dayOfWeek == 0) // Sunday; we represent it as 7, POSIX uses 0
+ dayOfWeek = 7;
+ else if (dayOfWeek & ~7 || month < 1 || month > 12 || week < 1 || week > 5)
+ return QDate();
+
QDate date(year, month, 1);
int startDow = date.dayOfWeek();
if (startDow <= dayOfWeek)
@@ -364,28 +369,34 @@ static QDate calculateDowDate(int year, int month, int dayOfWeek, int week)
static QDate calculatePosixDate(const QByteArray &dateRule, int year)
{
+ bool ok;
// Can start with M, J, or a digit
if (dateRule.at(0) == 'M') {
// nth week in month format "Mmonth.week.dow"
QList<QByteArray> dateParts = dateRule.split('.');
- int month = dateParts.at(0).mid(1).toInt();
- int week = dateParts.at(1).toInt();
- int dow = dateParts.at(2).toInt();
- if (dow == 0) // Sunday; we represent it as 7
- dow = 7;
- return calculateDowDate(year, month, dow, week);
+ if (dateParts.count() > 2) {
+ int month = dateParts.at(0).mid(1).toInt(&ok);
+ int week = ok ? dateParts.at(1).toInt(&ok) : 0;
+ int dow = ok ? dateParts.at(2).toInt(&ok) : 0;
+ if (ok)
+ return calculateDowDate(year, month, dow, week);
+ }
} else if (dateRule.at(0) == 'J') {
// Day of Year ignores Feb 29
- int doy = dateRule.mid(1).toInt();
- QDate date = QDate(year, 1, 1).addDays(doy - 1);
- if (QDate::isLeapYear(date.year()))
- date = date.addDays(-1);
- return date;
+ 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;
+ }
} else {
// Day of Year includes Feb 29
- int doy = dateRule.toInt();
- return QDate(year, 1, 1).addDays(doy - 1);
+ int doy = dateRule.toInt(&ok);
+ if (ok && doy > 0 && doy <= 366)
+ return QDate(year, 1, 1).addDays(doy - 1);
}
+ return QDate();
}
// returns the time in seconds, INT_MIN if we failed to parse
@@ -576,7 +587,8 @@ static QVector<QTimeZonePrivate::Data> calculatePosixTransitions(const QByteArra
result << data;
return result;
}
-
+ if (parts.count() < 3 || parts.at(1).isEmpty() || parts.at(2).isEmpty())
+ return result; // Malformed.
// Get the std to dst transtion details
QList<QByteArray> dstParts = parts.at(1).split('/');
@@ -596,6 +608,9 @@ static QVector<QTimeZonePrivate::Data> calculatePosixTransitions(const QByteArra
else
stdTime = QTime(2, 0, 0);
+ if (dstDateRule.isEmpty() || stdDateRule.isEmpty() || !dstTime.isValid() || !stdTime.isValid())
+ return result; // Malformed.
+
// Limit year to the range QDateTime can represent:
const int minYear = int(QDateTime::YearRange::First);
const int maxYear = int(QDateTime::YearRange::Last);
@@ -1169,8 +1184,11 @@ public:
*/
const StatIdent local = identify("/etc/localtime");
const StatIdent tz = identify("/etc/TZ");
- if (!m_name.isEmpty() && m_last.isValid() && (m_last == local || m_last == tz))
+ const StatIdent timezone = identify("/etc/timezone");
+ if (!m_name.isEmpty() && m_last.isValid()
+ && (m_last == local || m_last == tz || m_last == timezone)) {
return m_name;
+ }
m_name = etcLocalTime();
if (!m_name.isEmpty()) {
@@ -1178,12 +1196,19 @@ public:
return m_name;
}
- m_name = etcTZ();
- m_last = m_name.isEmpty() ? StatIdent() : tz;
+ // Some systems (e.g. uClibc) have a default value for $TZ in /etc/TZ:
+ m_name = etcContent(QStringLiteral("/etc/TZ"));
+ if (!m_name.isEmpty()) {
+ m_last = tz;
+ return m_name;
+ }
+
+ // Gentoo still (2020, QTBUG-87326) uses this:
+ m_name = etcContent(QStringLiteral("/etc/timezone"));
+ m_last = m_name.isEmpty() ? StatIdent() : timezone;
return m_name;
}
-
private:
QByteArray m_name;
struct StatIdent
@@ -1224,10 +1249,8 @@ private:
return QByteArray();
}
- static QByteArray etcTZ()
+ static QByteArray etcContent(const QString &path)
{
- // Some systems (e.g. uClibc) have a default value for $TZ in /etc/TZ:
- const QString path = QStringLiteral("/etc/TZ");
QFile zone(path);
if (zone.open(QIODevice::ReadOnly))
return zone.readAll().trimmed();