Calculating the difference between two QDates
I wanted to calculate the difference between two QDates. Not only the days, but also the years, months, and weeks (for use in KPhotoAlbum).
I ended up using the following algorithm:
[Update 2024-02-07]: In some cases, the days weren't calculated correctly, becase a day surpassing the days in that specific month has been used, resulting in an invalid QDate
. This is now fixed.
[Update 2024-03-05]: Now, we also calculate timespans correctly if the date we refer to is a February 29.
struct DateDifference { int years; int months; int days; bool operator==(const DateDifference &other) const { return this->years == other.years && this->months == other.months && this->days == other.days; } bool operator!=(const DateDifference &other) const { return this->years != other.years || this->months != other.months || this->days != other.days; } }; DateDifference dateDifference(const QDate &date, const QDate &reference) { if (date > reference) { return dateDifference(reference, date); } int dateDay = date.day(); if (date.month() == 2 && dateDay == 29 && ! QDate::isLeapYear(reference.year())) { // If we calculate the timespan to a February 29 for a non-leap year, we use February 28 // instead (the last day in February). This will also make birthdays for people born on // February 29 being calculated correctly (February 28, the last day in February, for // non-leap years) dateDay = 28; } int years = reference.year() - date.year(); int months = reference.month() - date.month(); if (reference.month() < date.month() || ((reference.month() == date.month()) && (reference.day() < dateDay))) { years--; months += 12; } if (reference.day() < dateDay) { months--; } int remainderMonth = reference.month() - (reference.day() < dateDay); int remainderYear = reference.year(); if (remainderMonth == 0) { remainderMonth = 12; remainderYear--; } const auto daysOfRemainderMonth = QDate(remainderYear, remainderMonth, 1).daysInMonth(); const auto remainderDay = dateDay > daysOfRemainderMonth ? daysOfRemainderMonth : dateDay; int days = QDate(remainderYear, remainderMonth, remainderDay).daysTo(reference); return { years, months, days }; }
Perhaps, this will help somebody.
I also filed a Feature request about adding such a function to Qt directly. Hopefully, it will be added in Qt 5.14 (to the new QCalendar class) :-)