summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEdward Welbourne <edward.welbourne@qt.io>2017-10-26 19:18:09 +0200
committerEdward Welbourne <edward.welbourne@qt.io>2017-11-30 20:20:40 +0000
commit454bbbe787003be8ba41999ad5e3237b02deafd7 (patch)
tree594f4ebc2d40827befc280c02b8eca3d346d3bed
parent205df620a09d16bf0dffdf1f0d301b2f9e8c1384 (diff)
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>
-rw-r--r--src/corelib/tools/qtimezoneprivate_win.cpp47
1 files changed, 28 insertions, 19 deletions
diff --git a/src/corelib/tools/qtimezoneprivate_win.cpp b/src/corelib/tools/qtimezoneprivate_win.cpp
index 665e87daec..8bde07c710 100644
--- a/src/corelib/tools/qtimezoneprivate_win.cpp
+++ b/src/corelib/tools/qtimezoneprivate_win.cpp
@@ -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, 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);
}
-
- // If the year is set then is an absolute date
- return QDate(time.wYear, time.wMonth, time.wDay);
+ 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())