Clean up in TZP-Win's calculateTransitionLocalDate()

It's decoding a SYSTEMTIME in the slightly quirky manner of MS's
timezone APIs (year 0 means annual, with wDay as 1 through 4 for the
first through fourth, or 5 for the last, of a specified week-day
within a month) and the calculations to go with it were a little
opaque.  So clean it up, document what it's doing (and why) and assert
some things that should be true.  Also, only copy one int, instead of
a whole structure, to change from their day-numbering to ours.
Expand on a related TODO comment in its caller, at the same time.

Change-Id: Iffd95c094c37fc1081b73b2a267cfdcd29aeb4ae
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
Edward Welbourne 2017-10-26 19:18:09 +02:00
parent 205df620a0
commit 454bbbe787

View File

@ -360,25 +360,33 @@ QDate calculateTransitionLocalDate(const SYSTEMTIME &rule, int year)
if (rule.wMonth == 0)
return QDate();
SYSTEMTIME time = rule;
// If the year isn't set, then the rule date is relative
if (time.wYear == 0) {
if (time.wDayOfWeek == 0)
time.wDayOfWeek = 7;
QDate date(year, time.wMonth, 1);
int startDow = date.dayOfWeek();
if (startDow <= time.wDayOfWeek)
date = date.addDays(time.wDayOfWeek - startDow - 7);
else
date = date.addDays(time.wDayOfWeek - startDow);
date = date.addDays(time.wDay * 7);
while (date.month() != time.wMonth)
date = date.addDays(-7);
return date;
}
// Interpret SYSTEMTIME according to the slightly quirky rules in:
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms725481(v=vs.85).aspx
// If the year is set then is an absolute date
return QDate(time.wYear, time.wMonth, time.wDay);
// If the year is set, the rule gives an absolute date:
if (rule.wYear)
return QDate(rule.wYear, rule.wMonth, rule.wDay);
// Otherwise, the rule date is annual and relative:
const int dayOfWeek = rule.wDayOfWeek == 0 ? 7 : rule.wDayOfWeek;
QDate date(year, rule.wMonth, 1);
// How many days before was last dayOfWeek before target month ?
int adjust = dayOfWeek - date.dayOfWeek(); // -6 <= adjust < 7
if (adjust >= 0) // Ensure -7 <= adjust < 0:
adjust -= 7;
// Normally, wDay is day-within-month; but here it is 1 for the first
// of the given dayOfWeek in the month, through 4 for the fourth or ...
adjust += (rule.wDay < 1 ? 1 : rule.wDay > 4 ? 5 : rule.wDay) * 7;
date = date.addDays(adjust);
// ... 5 for the last; so back up by weeks to get within the month:
if (date.month() != rule.wMonth) {
Q_ASSERT(rule.wDay > 4);
// (Note that, with adjust < 0, date <= 28th of our target month
// is guaranteed when wDay <= 4, or after our first -7 here.)
date = date.addDays(-7);
Q_ASSERT(date.month() == rule.wMonth);
}
return date;
}
// Converts a date/time value into msecs
@ -390,7 +398,8 @@ inline qint64 timeToMSecs(const QDate &date, const QTime &time)
qint64 calculateTransitionForYear(const SYSTEMTIME &rule, int year, int bias)
{
// TODO Consider caching the calculated values
// TODO Consider caching the calculated values - i.e. replace SYSTEMTIME in
// WinTransitionRule; do this in init() once and store the results.
const QDate date = calculateTransitionLocalDate(rule, year);
const QTime time = QTime(rule.wHour, rule.wMinute, rule.wSecond);
if (date.isValid() && time.isValid())