Fix counting of number of months from one date to another

QQuickCalendarModelPrivate::getCount() was kludgey and wrong.
Rewrite it to use QCalendar::partsFromDate(), thereby bypassing repeat
calls to calendrical calculations, document what it's meant to be
doing and do that.

Fixes: QTBUG-111634
Pick-to: 6.5 6.4
Change-Id: I3bdf0233fc1b170eaeb1948ba74e93f636a29bd7
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Mitch Curtis <mitch.curtis@qt.io>
This commit is contained in:
Edward Welbourne 2023-03-02 11:06:53 +01:00
parent e61d555a6d
commit 17d0bf258b
2 changed files with 27 additions and 16 deletions

View File

@ -52,21 +52,23 @@ public:
int count;
};
// Returns the number of months we need to display for both from and to to be shown,
// or zero if from is in a later month than to, or either is invalid.
int QQuickCalendarModelPrivate::getCount(QDate from, QDate to)
{
if (!from.isValid() || !to.isValid())
return 0;
QDate f(from.year(), from.month(), 1);
QDate t(to.year(), to.month(), to.daysInMonth());
int days = f.daysTo(t);
if (days < 0)
const QCalendar gregorian;
Q_ASSERT(gregorian.isGregorian());
const QCalendar::YearMonthDay &f = gregorian.partsFromDate(from);
const QCalendar::YearMonthDay &t = gregorian.partsFromDate(to);
Q_ASSERT(f.isValid() && t.isValid()); // ... because from and to are valid.
if (f.year > t.year || (f.year == t.year && f.month > t.month))
return 0;
QDate r = QDate(1, 1, 1).addDays(days);
int years = r.year() - 1;
int months = r.month() - 1;
return 12 * years + months + (r.day() / t.day());
// Count from's month and every subsequent month until to's:
return 1 + t.month + 12 * (t.year - f.year) - f.month;
}
void QQuickCalendarModelPrivate::populate(QDate f, QDate t, bool force)

View File

@ -31,23 +31,32 @@ TestCase {
function test_indices_data() {
return [
// "from" and "to" must currently be in the same year.
{ tag: "2013", from: "2013-01-01", to: "2013-12-31", count: 12 },
{ tag: "2016", from: "2016-01-01", to: "2016-03-31", count: 3 }
{ tag: "2016", from: "2016-01-01", to: "2016-03-31", count: 3 },
{ tag: "2016-02-01 to 2016-12-31", from: "2016-02-01", to: "2016-12-31", count: 11 },
{ tag: "2014-11-30 to 2016-01-01", from: "2014-11-30", to: "2016-01-01", count: 15 }
]
}
function test_indices(data) {
var model = calendarModel.createObject(testCase, {from: data.from, to: data.to})
let model = calendarModel.createObject(testCase, {from: data.from, to: data.to})
verify(model)
compare(model.count, data.count)
var y = parseInt(data.tag)
for (var m = 0; m < 12; ++m) {
compare(model.yearAt(m), y)
compare(model.indexOf(y, m), m)
compare(model.indexOf(new Date(y, m, 1)), m)
compare(model.monthAt(m), m)
const from = new Date(data.from)
const to = new Date(data.to)
let index = 0
for (let date = from; date <= to; date.setMonth(date.getMonth() + 1, 28), ++index) {
compare(model.yearAt(index), date.getFullYear(),
`yearAt(${index}) returned incorrect value`)
compare(model.indexOf(date.getFullYear(), date.getMonth()), index,
`indexOf(${date.getFullYear()}, ${date.getMonth()}) returned incorrect value`)
compare(model.indexOf(date), index,
`indexOf(${date}) returned incorrect value`)
compare(model.monthAt(index), date.getMonth(),
`monthAt(${index}) returned incorrect value`)
}
model.destroy()