115QGregorianCalendar::matchCenturyToWeekday(
const QCalendar::YearMonthDay &parts,
int dow)
const
118
119
120
121
122
123 auto maybe = julianFromParts(parts.year, parts.month, parts.day);
125 int diff = weekDayOfJulian(*maybe) - dow;
128 int year = parts.year < 0 ? parts.year + 1 : parts.year;
131 const auto yearSplit = qDivMod<100>(year - (parts.month < 3 ? 1 : 0));
132 const int centuryMod4 = qMod<4>(yearSplit.quotient);
134 static_assert(qMod<7>(36524) == 5);
137 if (qMod<7>(diff * 4 + centuryMod4) < 4) {
139 year += (((qMod<7>(diff) + 3) / 2) % 4 - 1) * 100;
140 maybe = julianFromParts(year > 0 ? year : year - 1, parts.month, parts.day);
141 if (maybe && weekDayOfJulian(*maybe) == dow)
143 Q_ASSERT(parts.month == 2 && parts.day == 29
144 && dow !=
int(Qt::Tuesday) && !(year % 100));
147 }
else if (parts.month == 2 && parts.day == 29) {
148 int year = parts.year < 0 ? parts.year + 1 : parts.year;
150 const auto yearSplit = qDivMod<100>(year);
151 if (!yearSplit.remainder) {
152 const auto centuryMod4 = qMod<4>(yearSplit.quotient);
153 Q_ASSERT(centuryMod4);
154 if (centuryMod4 == 1)
157 year += (4 - centuryMod4) * 100;
158 maybe = julianFromParts(year > 0 ? year : year - 1, parts.month, parts.day);
159 if (maybe && weekDayOfJulian(*maybe) == dow)
161 Q_ASSERT(dow !=
int(Qt::Tuesday));
164 return (std::numeric_limits<qint64>::min)();
174int QGregorianCalendar::yearSharingWeekDays(QDate date)
191 static_assert((400 * 365 + 97) % 7 == 0);
197 const int year = date.year();
198 int res = (year < 1970
199 ? 2400 - (2000 - (year < 0 ? year + 1 : year)) % 400
200 : year > 2399 ? 2000 + (year - 2000) % 400 : year);
203 const int lastTwo = res % 100;
204 if (lastTwo == date.month() || lastTwo == date.day()) {
205 Q_ASSERT(lastTwo && !(lastTwo & ~31));
207 static constexpr int usual[] = { 2198, 2199, 2098, 2099, 2399, 2298, 2299 };
208 static constexpr int leaps[] = { 2396, 2284, 2296, 2184, 2196, 2084, 2096 };
211 res = (leapTest(year) ? leaps : usual)[yearStartWeekDay(year) - 1];
213 Q_ASSERT(QDate(res, 1, 1).dayOfWeek() == QDate(year, 1, 1).dayOfWeek());
214 Q_ASSERT(QDate(res, 12, 31).dayOfWeek() == QDate(year, 12, 31).dayOfWeek());
216 Q_ASSERT(res >= 1970 && res <= 2400);
236std::optional<qint64> QGregorianCalendar::julianFromParts(
int year,
int month,
int day)
238 if (!validParts(year, month, day))
241 const auto yearDays = yearMonthToYearDays(year, month);
242 const qint64 y = yearDays.year;
243 const qint64 fromYear = 365 * y + qDiv<4>(y) - qDiv<100>(y) + qDiv<400>(y);
244 return fromYear + yearDays.days + day + BaseJd;
247QCalendar::YearMonthDay QGregorianCalendar::partsFromJulian(qint64 jd)
249 const qint64 dayNumber = jd - BaseJd;
250 const qint64 century = qDiv<FourCenturies>(4 * dayNumber - 1);
251 const int dayInCentury = dayNumber - qDiv<4>(FourCenturies * century);
253 const int yearInCentury = qDiv<FourYears>(4 * dayInCentury - 1);
254 const int dayInYear = dayInCentury - qDiv<4>(FourYears * yearInCentury);
255 const int m = qDiv<FiveMonths>(5 * dayInYear - 3);
256 Q_ASSERT(m < 12 && m >= 0);
258 const int yearOffset = m < 10 ? 0 : 1;
260 const int y = 100 * century + yearInCentury + yearOffset;
261 const int month = m + 3 - 12 * yearOffset;
262 const int day = dayInYear - qDiv<5>(FiveMonths * m + 2);
265 return QCalendar::YearMonthDay(y > 0 ? y : y - 1, month, day);