File indexing completed on 2024-04-21 14:55:27

0001 /*
0002     Copyright (c) 2002 Carlos Moro <cfmoro@correo.uniovi.es>
0003     Copyright (c) 2002 Hans Petter Bieker <bieker@kde.org>
0004     Copyright 2007, 2008, 2009, 2010 John Layt <john@layt.net>
0005 
0006     This library is free software; you can redistribute it and/or
0007     modify it under the terms of the GNU Library General Public
0008     License as published by the Free Software Foundation; either
0009     version 2 of the License, or (at your option) any later version.
0010 
0011     This library is distributed in the hope that it will be useful,
0012     but WITHOUT ANY WARRANTY; without even the implied warranty of
0013     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0014     Library General Public License for more details.
0015 
0016     You should have received a copy of the GNU Library General Public License
0017     along with this library; see the file COPYING.LIB.  If not, write to
0018     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0019     Boston, MA 02110-1301, USA.
0020 */
0021 
0022 #include "kcalendarsystem.h"
0023 #include "kcalendarsystemprivate_p.h"
0024 
0025 #include "kconfiggroup.h"
0026 
0027 #include <QDateTime>
0028 
0029 #include "klocalizedstring.h"
0030 #include "kdatetime.h"
0031 #include "kdatetimeformatter_p.h"
0032 #include "kdatetimeparser_p.h"
0033 #include "kcalendarera_p.h"
0034 #include "kcalendarsystemcoptic_p.h"
0035 #include "kcalendarsystemethiopian_p.h"
0036 #include "kcalendarsystemgregorian_p.h"
0037 #include "kcalendarsystemhebrew_p.h"
0038 #include "kcalendarsystemindiannational_p.h"
0039 #include "kcalendarsystemislamiccivil_p.h"
0040 #include "kcalendarsystemjalali_p.h"
0041 #include "kcalendarsystemjapanese_p.h"
0042 #include "kcalendarsystemjulian_p.h"
0043 #include "kcalendarsystemminguo_p.h"
0044 #include "kcalendarsystemthai_p.h"
0045 
0046 KCalendarSystem *KCalendarSystem::create(KLocale::CalendarSystem calendarSystem, const KLocale *locale)
0047 {
0048     return create(calendarSystem, KSharedConfig::Ptr(), locale);
0049 }
0050 
0051 KCalendarSystem *KCalendarSystem::create(KLocale::CalendarSystem calendarSystem,
0052         KSharedConfig::Ptr config,
0053         const KLocale *locale)
0054 {
0055     switch (calendarSystem) {
0056     case KLocale::GregorianCalendar:
0057         return new KCalendarSystemGregorian(config, locale);
0058     case KLocale::CopticCalendar:
0059         return new KCalendarSystemCoptic(config, locale);
0060     case KLocale::EthiopianCalendar:
0061         return new KCalendarSystemEthiopian(config, locale);
0062     case KLocale::HebrewCalendar:
0063         return new KCalendarSystemHebrew(config, locale);
0064     case KLocale::IndianNationalCalendar:
0065         return new KCalendarSystemIndianNational(config, locale);
0066     case KLocale::IslamicCivilCalendar:
0067         return new KCalendarSystemIslamicCivil(config, locale);
0068     case KLocale::JalaliCalendar:
0069         return new KCalendarSystemJalali(config, locale);
0070     case KLocale::JapaneseCalendar:
0071         return new KCalendarSystemJapanese(config, locale);
0072     case KLocale::JulianCalendar:
0073         return new KCalendarSystemJulian(config, locale);
0074     case KLocale::MinguoCalendar:
0075         return new KCalendarSystemMinguo(config, locale);
0076     case KLocale::ThaiCalendar:
0077         return new KCalendarSystemThai(config, locale);
0078     default:
0079         return new KCalendarSystemGregorian(config, locale);
0080     }
0081 }
0082 
0083 QList<KLocale::CalendarSystem> KCalendarSystem::calendarSystemsList()
0084 {
0085     QList<KLocale::CalendarSystem> list;
0086 
0087     list.append(KLocale::GregorianCalendar);
0088     list.append(KLocale::CopticCalendar);
0089     list.append(KLocale::EthiopianCalendar);
0090     list.append(KLocale::HebrewCalendar);
0091     list.append(KLocale::IslamicCivilCalendar);
0092     list.append(KLocale::IndianNationalCalendar);
0093     list.append(KLocale::JalaliCalendar);
0094     list.append(KLocale::JapaneseCalendar);
0095     list.append(KLocale::JulianCalendar);
0096     list.append(KLocale::MinguoCalendar);
0097     list.append(KLocale::ThaiCalendar);
0098 
0099     return list;
0100 }
0101 
0102 QString KCalendarSystem::calendarLabel(KLocale::CalendarSystem calendarSystem, const KLocale *locale)
0103 {
0104     QStringList languages = locale->languageList();
0105 
0106     switch (calendarSystem) {
0107     case KLocale::GregorianCalendar:
0108         return ki18nc("@item Calendar system", "Gregorian").toString(languages);
0109     case KLocale::CopticCalendar:
0110         return ki18nc("@item Calendar system", "Coptic").toString(languages);
0111     case KLocale::EthiopianCalendar:
0112         return ki18nc("@item Calendar system", "Ethiopian").toString(languages);
0113     case KLocale::HebrewCalendar:
0114         return ki18nc("@item Calendar system", "Hebrew").toString(languages);
0115     case KLocale::IslamicCivilCalendar:
0116         return ki18nc("@item Calendar system", "Islamic / Hijri (Civil)").toString(languages);
0117     case KLocale::IndianNationalCalendar:
0118         return ki18nc("@item Calendar system", "Indian National").toString(languages);
0119     case KLocale::JalaliCalendar:
0120         return ki18nc("@item Calendar system", "Jalali").toString(languages);
0121     case KLocale::JapaneseCalendar:
0122         return ki18nc("@item Calendar system", "Japanese").toString(languages);
0123     case KLocale::JulianCalendar:
0124         return ki18nc("@item Calendar system", "Julian").toString(languages);
0125     case KLocale::MinguoCalendar:
0126         return ki18nc("@item Calendar system", "Taiwanese").toString(languages);
0127     case KLocale::ThaiCalendar:
0128         return ki18nc("@item Calendar system", "Thai").toString(languages);
0129     }
0130 
0131     return ki18nc("@item Calendar system", "Invalid Calendar Type").toString(languages);
0132 }
0133 
0134 // Shared d pointer base class definitions
0135 
0136 KCalendarSystemPrivate::KCalendarSystemPrivate(KCalendarSystem *q_ptr)
0137     : q(q_ptr),
0138       m_eraList(nullptr),
0139       m_shortYearWindowStartYear(2000)
0140 {
0141 }
0142 
0143 KCalendarSystemPrivate::~KCalendarSystemPrivate()
0144 {
0145     delete m_eraList;
0146 }
0147 
0148 int KCalendarSystemPrivate::isoWeekNumber(const QDate &date, int *yearNum) const
0149 {
0150     int y, m, d;
0151     q->julianDayToDate(date.toJulianDay(), y, m, d);
0152 
0153     QDate firstDayWeek1, lastDay;
0154     int week;
0155     int weekDay1, dayOfWeek1InYear;
0156 
0157     // let's guess 1st day of 1st week
0158     firstDayWeek1 = firstDayOfYear(y);
0159     weekDay1 = dayOfWeek(firstDayWeek1);
0160 
0161     // iso 8601: week 1  is the first containing thursday and week starts on monday
0162     if (weekDay1 > 4 /*Thursday*/) {
0163         firstDayWeek1 = q->addDays(firstDayWeek1, daysInWeek() - weekDay1 + 1);   // next monday
0164     }
0165 
0166     dayOfWeek1InYear = dayOfYear(firstDayWeek1);
0167 
0168     // our date in prev year's week
0169     if (dayOfYear(date) < dayOfWeek1InYear) {
0170         if (yearNum) {
0171             *yearNum = addYears(y, - 1);
0172         }
0173         return isoWeeksInYear(addYears(y, - 1));
0174     }
0175 
0176     // let's check if its last week belongs to next year
0177     lastDay = lastDayOfYear(y);
0178 
0179     // if our date is in last week && 1st week in next year has thursday
0180     if ((dayOfYear(date) >= daysInYear(y) - dayOfWeek(lastDay) + 1)
0181             && dayOfWeek(lastDay) < 4) {
0182         if (yearNum) {
0183             * yearNum = addYears(y, 1);
0184         }
0185         week = 1;
0186     } else {
0187         // To calculate properly the number of weeks from day a to x let's make a day 1 of week
0188         if (weekDay1 < 5) {
0189             firstDayWeek1 = q->addDays(firstDayWeek1, -(weekDay1 - 1));
0190         }
0191 
0192         if (yearNum) {
0193             * yearNum = y;
0194         }
0195 
0196         week = firstDayWeek1.daysTo(date) / daysInWeek() + 1;
0197     }
0198 
0199     return week;
0200 }
0201 
0202 int KCalendarSystemPrivate::regularWeekNumber(const QDate &date, int weekStartDay, int firstWeekNumber, int *weekYear) const
0203 {
0204     int y, m, d;
0205     q->julianDayToDate(date.toJulianDay(), y, m, d);
0206 
0207     int firstWeekDayOffset = (dayOfWeek(date) - weekStartDay + daysInWeek()) % daysInWeek();
0208     int dayInYear = date.toJulianDay() - firstDayOfYear(y).toJulianDay();   // 0 indexed
0209     int week = ((dayInYear - firstWeekDayOffset + daysInWeek()) / daysInWeek());
0210 
0211     if (dayOfWeek(firstDayOfYear(y)) != weekStartDay) {
0212         week = week + firstWeekNumber;
0213     }
0214 
0215     if (week < 1) {
0216         y = y - 1;
0217         week = regularWeeksInYear(y, weekStartDay, firstWeekNumber);
0218     }
0219 
0220     if (weekYear) {
0221         *weekYear = y;
0222     }
0223 
0224     return week;
0225 }
0226 
0227 int KCalendarSystemPrivate::simpleWeekNumber(const QDate &date, int *yearNum) const
0228 {
0229     int y, m, d;
0230     q->julianDayToDate(date.toJulianDay(), y, m, d);
0231     if (yearNum) {
0232         *yearNum = y;
0233     }
0234     return ((date.toJulianDay() - firstDayOfYear(y).toJulianDay()) / daysInWeek()) + 1;
0235 }
0236 
0237 int KCalendarSystemPrivate::isoWeeksInYear(int year) const
0238 {
0239     QDate lastDayOfThisYear = lastDayOfYear(year);
0240 
0241     int weekYear = year;
0242     int lastWeekInThisYear = isoWeekNumber(lastDayOfThisYear, &weekYear);
0243 
0244     // If error, or the last day of the year is in the first week of next year use the week before
0245     if (lastWeekInThisYear < 1 || weekYear != year) {
0246         lastWeekInThisYear = isoWeekNumber(q->addDays(lastDayOfThisYear, -7), &weekYear);
0247     }
0248 
0249     return lastWeekInThisYear;
0250 }
0251 
0252 int KCalendarSystemPrivate::regularWeeksInYear(int year, int weekStartDay, int firstWeekNumber) const
0253 {
0254     return regularWeekNumber(lastDayOfYear(year), weekStartDay, firstWeekNumber, nullptr);
0255 }
0256 
0257 int KCalendarSystemPrivate::simpleWeeksInYear(int year) const
0258 {
0259     return simpleWeekNumber(lastDayOfYear(year), nullptr);
0260 }
0261 
0262 // Reimplement if special maths handling required, e.g. Hebrew.
0263 // Works for calendars with constant number of months, or where leap month is last month of year
0264 // Will not work for Hebrew or others where leap month is inserted in middle of year
0265 void KCalendarSystemPrivate::dateDifference(const QDate &fromDate, const QDate &toDate,
0266         int *yearsDiff, int *monthsDiff, int *daysDiff, int *direction) const
0267 {
0268     // This could be optimised a little but is left in full as it's easier to understand
0269     int dy = 0;
0270     int dm = 0;
0271     int dd = 0;
0272     int dir = 1;
0273 
0274     if (toDate < fromDate) {
0275         dateDifference(toDate, fromDate, &dy, &dm, &dd, nullptr);
0276         dir = -1;
0277     } else if (toDate > fromDate) {
0278 
0279         int fromYear = q->year(fromDate);
0280         int toYear = q->year(toDate);
0281         int fromMonth = q->month(fromDate);
0282         int toMonth = q->month(toDate);
0283         int fromDay = q->day(fromDate);
0284         int toDay = q->day(toDate);
0285 
0286         int monthsInPrevYear = monthsInYear(addYears(toYear, -1));
0287         int daysInPrevMonth = q->daysInMonth(q->addMonths(toDate, -1));
0288         int daysInFromMonth = daysInMonth(fromYear, fromMonth);
0289         int daysInToMonth = daysInMonth(toYear, toMonth);
0290 
0291         // Calculate years difference
0292         if (toYear == fromYear) {
0293             dy = 0;
0294         } else if (toMonth > fromMonth) {
0295             dy = differenceYearNumbers(fromYear, toYear);
0296         } else if (toMonth < fromMonth) {
0297             dy = differenceYearNumbers(fromYear, toYear) - 1;
0298         } else { // toMonth == fromMonth
0299             // Allow for last day of month to last day of month and leap days
0300             // e.g. 2000-02-29 to 2001-02-28 is 1 year not 0 years
0301             if ((toDay >= fromDay) || (fromDay == daysInFromMonth && toDay == daysInToMonth)) {
0302                 dy = differenceYearNumbers(fromYear, toYear);
0303             } else {
0304                 dy = differenceYearNumbers(fromYear, toYear) - 1;
0305             }
0306         }
0307 
0308         // Calculate months and days difference
0309         if (toDay >= fromDay) {
0310             dm = (monthsInPrevYear + toMonth - fromMonth) % monthsInPrevYear;
0311             dd = toDay - fromDay;
0312         } else { // toDay < fromDay
0313             // Allow for last day of month to last day of month and leap days
0314             // e.g. 2010-03-31 to 2010-04-30 is 1 month
0315             //      2000-02-29 to 2001-02-28 is 1 year
0316             //      2000-02-29 to 2001-03-01 is 1 year 1 day
0317             int prevMonth = q->month(q->addMonths(toDate, -1));
0318             if (fromDay == daysInFromMonth && toDay == daysInToMonth) {
0319                 dm = (monthsInPrevYear + toMonth - fromMonth) % monthsInPrevYear;
0320                 dd = 0;
0321             } else if (prevMonth == fromMonth && daysInPrevMonth < daysInFromMonth) {
0322                 // Special case where fromDate = leap day and toDate in month following but non-leap year
0323                 // e.g. 2000-02-29 to 2001-03-01 needs to use 29 to calculate day number not 28
0324                 dm = (monthsInPrevYear + toMonth - fromMonth - 1) % monthsInPrevYear;
0325                 dd = (daysInFromMonth + toDay - fromDay) % daysInFromMonth;
0326             } else {
0327                 dm = (monthsInPrevYear + toMonth - fromMonth - 1) % monthsInPrevYear;
0328                 dd = (daysInPrevMonth + toDay - fromDay) % daysInPrevMonth;
0329             }
0330         }
0331 
0332     }
0333 
0334     // Only return values if we have a valid pointer
0335     if (yearsDiff) {
0336         *yearsDiff = dy;
0337     }
0338     if (monthsDiff) {
0339         *monthsDiff = dm;
0340     }
0341     if (daysDiff) {
0342         *daysDiff = dd;
0343     }
0344     if (direction) {
0345         *direction = dir;
0346     }
0347 }
0348 
0349 // Reimplement if special maths handling required, e.g. Hebrew
0350 // Allows for calendars with leap months at end of year but not during year
0351 int KCalendarSystemPrivate::yearsDifference(const QDate &fromDate, const QDate &toDate) const
0352 {
0353     // This could be optimised a little but is left in full as it's easier to understand
0354     // Alternatively could just call dateDifference(), but this is slightly more efficient
0355 
0356     if (toDate < fromDate) {
0357         return 0 - yearsDifference(toDate, fromDate);
0358     }
0359 
0360     if (toDate == fromDate) {
0361         return 0;
0362     }
0363 
0364     int fromYear = q->year(fromDate);
0365     int toYear = q->year(toDate);
0366 
0367     if (toYear == fromYear) {
0368         return 0;
0369     }
0370 
0371     int fromMonth = q->month(fromDate);
0372     int toMonth = q->month(toDate);
0373 
0374     if (toMonth > fromMonth) {
0375         return differenceYearNumbers(fromYear, toYear);
0376     }
0377 
0378     if (toMonth < fromMonth) {
0379         return differenceYearNumbers(fromYear, toYear) - 1;
0380     }
0381 
0382     // toMonth == fromMonth
0383     int fromDay = q->day(fromDate);
0384     int toDay = q->day(toDate);
0385 
0386     // Adjust for month numbers in from and to year
0387     // Allow for last day of month to last day of month and leap days
0388     // e.g. 2000-02-29 to 2001-02-28 is 1 year not 0 years
0389     if ((toDay >= fromDay) ||
0390             (fromDay == daysInMonth(fromYear, fromMonth) &&
0391              toDay == daysInMonth(toYear, toMonth))) {
0392         return differenceYearNumbers(fromYear, toYear);
0393     } else {
0394         return differenceYearNumbers(fromYear, toYear) - 1;
0395     }
0396 
0397 }
0398 
0399 // Reimplement if special maths handling required, e.g. maybe Hebrew?
0400 // Allows for calendars with leap months
0401 int KCalendarSystemPrivate::monthsDifference(const QDate &fromDate, const QDate &toDate) const
0402 {
0403     if (toDate < fromDate) {
0404         return 0 - monthsDifference(toDate, fromDate);
0405     }
0406 
0407     if (toDate == fromDate) {
0408         return 0;
0409     }
0410 
0411     int fromYear = q->year(fromDate);
0412     int toYear = q->year(toDate);
0413     int fromMonth = q->month(fromDate);
0414     int toMonth = q->month(toDate);
0415     int fromDay = q->day(fromDate);
0416     int toDay = q->day(toDate);
0417 
0418     int monthsInPreceedingYears;
0419 
0420     // Calculate number of months in full years preceding toYear
0421     if (toYear == fromYear) {
0422         monthsInPreceedingYears = 0;
0423     } else if (hasLeapMonths()) {
0424         monthsInPreceedingYears = 0;
0425         for (int y = fromYear; y < toYear; y = addYears(y, 1)) {
0426             monthsInPreceedingYears = monthsInPreceedingYears + monthsInYear(y);
0427         }
0428     } else {
0429         monthsInPreceedingYears = differenceYearNumbers(fromYear, toYear) * monthsInYear(toYear);
0430     }
0431 
0432     // Adjust for months in from and to year
0433     // Allow for last day of month to last day of month and leap days
0434     // e.g. 2010-03-31 to 2010-04-30 is 1 month not 0 months
0435     // also 2000-02-29 to 2001-02-28 is 12 months not 11 months
0436     if ((toDay >= fromDay) ||
0437             (fromDay == daysInMonth(fromYear, fromMonth) &&
0438              toDay == daysInMonth(toYear, toMonth))) {
0439         return monthsInPreceedingYears + toMonth - fromMonth;
0440     } else {
0441         return monthsInPreceedingYears + toMonth - fromMonth - 1;
0442     }
0443 }
0444 
0445 // Reimplement if special string to integer handling required, e.g. Hebrew.
0446 // Peel a number off the front of a string which may have other trailing chars after the number
0447 // Stop either at either maxLength, eos, or first non-digit char
0448 int KCalendarSystemPrivate::integerFromString(const QString &string, int maxLength, int &readLength) const
0449 {
0450     int value = -1;
0451     int position = 0;
0452     readLength = 0;
0453     bool ok = false;
0454 
0455     if (maxLength < 0) {
0456         maxLength = string.length();
0457     }
0458 
0459     while (position < string.length() &&
0460             position < maxLength &&
0461             string.at(position).isDigit()) {
0462         position++;
0463     }
0464 
0465     if (position > 0) {
0466         value = string.left(position).toInt(&ok);
0467         if (ok) {
0468             readLength = position;
0469         } else {
0470             value = -1;
0471         }
0472     }
0473 
0474     return value;
0475 }
0476 
0477 // Reimplement if special integer to string handling required, e.g. Hebrew.
0478 // Utility to convert an integer into the correct display string form
0479 QString KCalendarSystemPrivate::stringFromInteger(int number, int padWidth, QChar padChar) const
0480 {
0481     return stringFromInteger(number, padWidth, padChar, q->locale()->dateTimeDigitSet());
0482 }
0483 
0484 // Reimplement if special integer to string handling required, e.g. Hebrew.
0485 // Utility to convert an integer into the correct display string form
0486 QString KCalendarSystemPrivate::stringFromInteger(int number, int padWidth, QChar padChar, KLocale::DigitSet digitSet) const
0487 {
0488     if (padChar == QLatin1Char('\0') || padWidth == 0) {
0489         return q->locale()->convertDigits(QString::number(number), digitSet);
0490     } else {
0491         return q->locale()->convertDigits(QString::number(number).rightJustified(padWidth, padChar), digitSet);
0492     }
0493 }
0494 
0495 // Utility to correctly add years to a year number because some systems such as
0496 // Julian and Gregorian calendars don't have a year 0
0497 int KCalendarSystemPrivate::addYears(int originalYear, int addYears) const
0498 {
0499     int newYear = originalYear + addYears;
0500 
0501     if (!hasYearZero()) {
0502         if (originalYear > 0 && newYear <= 0) {
0503             newYear = newYear - 1;
0504         } else if (originalYear < 0 && newYear >= 0) {
0505             newYear = newYear + 1;
0506         }
0507     }
0508 
0509     return newYear;
0510 }
0511 
0512 // Utility to correctly return number of years between two year numbers because some systems such as
0513 // Julian and Gregorian calendars don't have a year 0
0514 int KCalendarSystemPrivate::differenceYearNumbers(int fromYear, int toYear) const
0515 {
0516     int dy = toYear - fromYear;
0517 
0518     if (!hasYearZero()) {
0519         if (toYear > 0 && fromYear < 0) {
0520             dy = dy - 1;
0521         } else if (toYear < 0 && fromYear > 0) {
0522             dy = dy + 1;
0523         }
0524     }
0525 
0526     return dy;
0527 }
0528 
0529 QString KCalendarSystemPrivate::simpleDateString(const QString &str) const
0530 {
0531     QString newStr;
0532     newStr.reserve(str.length());
0533     for (int i = 0; i < str.length(); i++) {
0534         if (str.at(i).isLetterOrNumber()) {
0535             newStr.append(str.at(i));
0536         } else {
0537             newStr.append(QLatin1Char(' '));
0538         }
0539     }
0540 
0541     return newStr.simplified();
0542 }
0543 
0544 // If we ever want to support a calendar system with another week length,this
0545 // method can be changed to virtual. Doing so will, however, likely break some
0546 // code, so don't do that without testing and fixing at least all of KDE SC.
0547 int KCalendarSystemPrivate::daysInWeek() const
0548 {
0549     return 7;
0550 }
0551 
0552 int KCalendarSystemPrivate::dayOfYear(const QDate &date) const
0553 {
0554     qint64 jdFirstDayOfYear;
0555     int y, m, d;
0556     q->julianDayToDate(date.toJulianDay(), y, m, d);
0557     q->dateToJulianDay(y, 1, 1, jdFirstDayOfYear);
0558     //Take the jd of the given date, and subtract the jd of the first day of that year
0559     return (date.toJulianDay() - jdFirstDayOfYear + 1);
0560 }
0561 
0562 // This assumes all calendar systems agree on the day of week for a given
0563 // julian day number. That is true of all current calendar systems. If we
0564 // ever want to support one for which it isn't this implementation can be
0565 // changed. Doing so will, however, likely break some code, so don't do that
0566 // without testing and fixing at least all of KDE SC.
0567 int KCalendarSystemPrivate::dayOfWeek(const QDate &date) const
0568 {
0569     return date.dayOfWeek();
0570 }
0571 
0572 QDate KCalendarSystemPrivate::firstDayOfYear(int year) const
0573 {
0574     qint64 jd;
0575     q->dateToJulianDay(year, 1, 1, jd);
0576     return QDate::fromJulianDay(jd);
0577 }
0578 
0579 QDate KCalendarSystemPrivate::lastDayOfYear(int year) const
0580 {
0581     qint64 jd;
0582     q->dateToJulianDay(year, 1, 1, jd);
0583     jd = jd + daysInYear(year) - 1;
0584     return QDate::fromJulianDay(jd);
0585 }
0586 
0587 QDate KCalendarSystemPrivate::firstDayOfMonth(int year, int month) const
0588 {
0589     qint64 jd;
0590     q->dateToJulianDay(year, month, 1, jd);
0591     return QDate::fromJulianDay(jd);
0592 }
0593 
0594 QDate KCalendarSystemPrivate::lastDayOfMonth(int year, int month) const
0595 {
0596     qint64 jd;
0597     q->dateToJulianDay(year, month, 1, jd);
0598     jd = jd + daysInMonth(year, month) - 1;
0599     return QDate::fromJulianDay(jd);
0600 }
0601 
0602 const KLocale *KCalendarSystemPrivate::locale() const
0603 {
0604     if (m_locale) {
0605         return m_locale;
0606     } else {
0607         return KLocale::global();
0608     }
0609 }
0610 
0611 QList<KCalendarEra> *KCalendarSystemPrivate::eraList() const
0612 {
0613     return m_eraList;
0614 }
0615 
0616 KCalendarEra KCalendarSystemPrivate::era(const QDate &eraDate) const
0617 {
0618     for (int i = m_eraList->count() - 1; i >= 0; --i) {
0619         if (m_eraList->at(i).isInEra(eraDate)) {
0620             return m_eraList->at(i);
0621         }
0622     }
0623     return KCalendarEra();
0624 }
0625 
0626 KCalendarEra KCalendarSystemPrivate::era(const QString &eraName, int yearInEra) const
0627 {
0628     Q_UNUSED(yearInEra)
0629 
0630     for (int i = m_eraList->count() - 1; i >= 0; --i) {
0631         KCalendarEra era = m_eraList->at(i);
0632         if (era.name(KLocale::LongName).toLower() == eraName.toLower() ||
0633                 era.name(KLocale::ShortName).toLower() == eraName.toLower()) {
0634             return era;
0635         }
0636     }
0637     return KCalendarEra();
0638 }
0639 
0640 void KCalendarSystemPrivate::loadEraList(const KConfigGroup &cg)
0641 {
0642     delete m_eraList;
0643     m_eraList = new QList<KCalendarEra>;
0644     QString eraKey = QString::fromLatin1("Era1");
0645     int i = 1;
0646     while (cg.hasKey(eraKey)) {
0647         QString eraEntry = cg.readEntry(eraKey, QString());
0648         if (!eraEntry.isEmpty()) {
0649             // Based on LC_TIME, but different!
0650             // Includes long and short names, uses ISO fomat dates
0651             // e.g. +:1:0001-01-01:9999-12-31:Anno Domini:AD:%EC %Ey
0652             QChar direction = eraEntry.section(QLatin1Char(':'), 0, 0).at(0);
0653             QDate startDate, endDate;
0654             int startYear;
0655             QString buffer = eraEntry.section(QLatin1Char(':'), 2, 2);
0656             if (buffer.isEmpty()) {
0657                 if (direction == QLatin1Char('-')) {
0658                     startDate = q->latestValidDate();
0659                 } else {
0660                     startDate = q->earliestValidDate();
0661                 }
0662             } else {
0663                 startDate = q->readDate(buffer, KLocale::IsoFormat);
0664             }
0665             if (q->isValid(startDate)) {
0666                 startYear = q->year(startDate);
0667             } else {
0668                 startYear = eraEntry.section(QLatin1Char(':'), 1, 1).toInt();   //Use offset
0669             }
0670 
0671             buffer = eraEntry.section(QLatin1Char(':'), 3, 3);
0672             if (buffer.isEmpty()) {
0673                 if (direction == QLatin1Char('-')) {
0674                     endDate = q->earliestValidDate();
0675                 } else {
0676                     endDate = q->latestValidDate();
0677                 }
0678             } else {
0679                 endDate = q->readDate(buffer, KLocale::IsoFormat);
0680             }
0681             addEra(direction.toLatin1(), eraEntry.section(QLatin1Char(':'), 1, 1).toInt(),
0682                    startDate, startYear, endDate, eraEntry.section(QLatin1Char(':'), 4, 4),
0683                    eraEntry.section(QLatin1Char(':'), 5, 5), eraEntry.section(QLatin1Char(':'), 6));
0684         }
0685         ++i;
0686         eraKey = QString::fromLatin1("Era%1").arg(i);
0687     }
0688 
0689     if (m_eraList->isEmpty()) {
0690         loadDefaultEraList();
0691     }
0692 }
0693 
0694 void KCalendarSystemPrivate::addEra(char direction, int offset,
0695                                     const QDate &startDate, int startYear, const QDate &endDate,
0696                                     const QString &name, const QString &shortName,
0697                                     const QString &format)
0698 {
0699     KCalendarEra newEra;
0700 
0701     newEra.m_sequence = m_eraList->count() + 1;
0702     if (direction == '-') {
0703         newEra.m_direction = -1;
0704     } else {
0705         newEra.m_direction = 1;
0706     }
0707     newEra.m_offset = offset;
0708     newEra.m_startDate = startDate;
0709     newEra.m_startYear = startYear;
0710     newEra.m_endDate = endDate;
0711     newEra.m_longName = name;
0712     newEra.m_shortName = shortName;
0713     newEra.m_format = format;
0714 
0715     m_eraList->append(newEra);
0716 }
0717 
0718 int KCalendarSystemPrivate::shortYearWindowStartYear() const
0719 {
0720     return m_shortYearWindowStartYear;
0721 }
0722 
0723 int KCalendarSystemPrivate::applyShortYearWindow(int inputYear) const
0724 {
0725     if (inputYear >= 0 && inputYear <= 99) {
0726         int shortStartYear = m_shortYearWindowStartYear % 100;
0727         int yearOffset = m_shortYearWindowStartYear - shortStartYear;
0728         if (inputYear >= shortStartYear) {
0729             return inputYear + yearOffset;
0730         } else {
0731             return inputYear + yearOffset + 100;
0732         }
0733     } else {
0734         return inputYear;
0735     }
0736 }
0737 
0738 void KCalendarSystemPrivate::loadShortYearWindowStartYear(const KConfigGroup &cg)
0739 {
0740     // Default to 2000 for backwards compatibility
0741     // as that's the old readDate() default value
0742     int startYear = 2000;
0743     if (cg.exists()) {
0744         startYear = cg.readEntry("ShortYearWindowStartYear", 2000);
0745     }
0746     m_shortYearWindowStartYear = startYear;
0747 }
0748 
0749 KSharedConfig::Ptr KCalendarSystemPrivate::config()
0750 {
0751     if (m_config == KSharedConfig::Ptr()) {
0752         return KSharedConfig::openConfig();
0753     } else {
0754         return m_config;
0755     }
0756 }
0757 
0758 void KCalendarSystemPrivate::loadConfig(const QString &calendarType)
0759 {
0760     KConfigGroup localeGroup(config(), QString::fromLatin1("Locale"));
0761     KConfigGroup calendarGroup = localeGroup.group(QString::fromLatin1("KCalendarSystem %1").arg(calendarType));
0762     loadEraList(calendarGroup);
0763     loadShortYearWindowStartYear(calendarGroup);
0764 }
0765 
0766 KCalendarSystem::KCalendarSystem(KCalendarSystemPrivate &dd, const KSharedConfig::Ptr config, const KLocale *locale)
0767     : d_ptr(&dd)
0768 {
0769     d_ptr->m_config = config;
0770     d_ptr->m_locale = locale;
0771 }
0772 
0773 KCalendarSystem::~KCalendarSystem()
0774 {
0775     delete d_ptr;
0776 }
0777 
0778 // NOT VIRTUAL - If override needed use shared-d
0779 QString KCalendarSystem::calendarLabel() const
0780 {
0781     return KCalendarSystem::calendarLabel(calendarSystem());
0782 }
0783 
0784 bool KCalendarSystem::isValid(int year, int month, int day) const
0785 {
0786     Q_D(const KCalendarSystem);
0787 
0788     return year >= d->earliestValidYear() && year <= d->latestValidYear() && (d->hasYearZero() || year != 0) &&
0789            month >= 1 && month <= d->monthsInYear(year) &&
0790            day >= 1 && day <= d->daysInMonth(year, month);
0791 }
0792 
0793 bool KCalendarSystem::isValid(int year, int dayOfYear) const
0794 {
0795     Q_D(const KCalendarSystem);
0796 
0797     return (isValid(year, 1, 1) && dayOfYear > 0 && dayOfYear <= d->daysInYear(year));
0798 }
0799 
0800 bool KCalendarSystem::isValid(const QString &eraName, int yearInEra, int month, int day) const
0801 {
0802     Q_D(const KCalendarSystem);
0803 
0804     KCalendarEra era = d->era(eraName, yearInEra);
0805     return (era.isValid() && isValid(era.year(yearInEra), month, day));
0806 }
0807 
0808 // NOT VIRTUAL - If override needed use shared-d
0809 bool KCalendarSystem::isValidIsoWeekDate(int year, int isoWeekNumber, int dayOfIsoWeek) const
0810 {
0811     Q_D(const KCalendarSystem);
0812 
0813     //Tests Year value in standard YMD isValid()
0814     if (!isValid(year, 1, 1)) {
0815         return false;
0816     }
0817 
0818     //Test Week Number falls in valid range for this year
0819     int weeksInThisYear = weeksInYear(year);
0820     if (isoWeekNumber < 1 || isoWeekNumber  > weeksInThisYear) {
0821         return false;
0822     }
0823 
0824     //Test Day of Week Number falls in valid range
0825     if (dayOfIsoWeek < 1 || dayOfIsoWeek > d->daysInWeek()) {
0826         return false;
0827     }
0828 
0829     //If not in earliest or latest years then all OK
0830     //Otherwise need to check don't fall into previous or next year that would be invalid
0831     if (year == d->earliestValidYear() && isoWeekNumber == 1) {
0832         //If firstDayOfYear falls on or before Thursday then firstDayOfYear falls in week 1 this
0833         //year and if wanted dayOfIsoWeek falls before firstDayOfYear then falls in previous year
0834         //and so in invalid year
0835         int dowFirstDay = dayOfWeek(d->firstDayOfYear(year));
0836         if (dowFirstDay <= 4 && dayOfIsoWeek < dowFirstDay) {
0837             return false;
0838         }
0839     } else if (year == d->latestValidYear() && isoWeekNumber == weeksInThisYear) {
0840         //If lastDayOfYear falls on or after Thursday then lastDayOfYear falls in last week this
0841         //year and if wanted dayOfIsoWeek falls after lastDayOfYear then falls in next year
0842         //and so in invalid year
0843         int dowLastDay = dayOfWeek(d->lastDayOfYear(year));
0844         if (dowLastDay >= 4 && dayOfIsoWeek > dowLastDay) {
0845             return false;
0846         }
0847     }
0848 
0849     return true;
0850 }
0851 
0852 bool KCalendarSystem::setDate(QDate &date, int year, int month, int day) const
0853 {
0854     date = QDate();
0855 
0856     if (isValid(year, month, day)) {
0857         qint64 jd;
0858         dateToJulianDay(year, month, day, jd);
0859         QDate calcDate = QDate::fromJulianDay(jd);
0860 
0861         if (isValid(calcDate)) {
0862             date = calcDate;
0863             return true;
0864         }
0865     }
0866 
0867     return false;
0868 }
0869 
0870 // NOT VIRTUAL - If override needed use shared-d
0871 bool KCalendarSystem::setDate(QDate &date, int year, int dayOfYear) const
0872 {
0873     date = QDate();
0874 
0875     if (isValid(year, dayOfYear)) {
0876         qint64 jd;
0877         dateToJulianDay(year, 1, 1, jd);
0878         QDate calcDate = QDate::fromJulianDay(jd + dayOfYear - 1);
0879         if (isValid(calcDate)) {
0880             date = calcDate;
0881             return true;
0882         }
0883     }
0884 
0885     return false;
0886 }
0887 
0888 // NOT VIRTUAL - If override needed use shared-d
0889 bool KCalendarSystem::setDate(QDate &date, QString eraName, int yearInEra, int month, int day) const
0890 {
0891     Q_D(const KCalendarSystem);
0892 
0893     KCalendarEra era = d->era(eraName, yearInEra);
0894     return (era.isValid() && setDate(date, era.year(yearInEra), month, day));
0895 }
0896 
0897 // NOT VIRTUAL - If override needed use shared-d
0898 bool KCalendarSystem::setDateIsoWeek(QDate &date, int year, int isoWeekNumber, int dayOfIsoWeek) const
0899 {
0900     Q_D(const KCalendarSystem);
0901 
0902     date = QDate();
0903 
0904     if (isValidIsoWeekDate(year, isoWeekNumber, dayOfIsoWeek)) {
0905 
0906         QDate calcDate = d->firstDayOfYear(year);
0907         int dowFirstDayOfYear = dayOfWeek(calcDate);
0908 
0909         int daysToAdd = (d->daysInWeek() * (isoWeekNumber - 1)) + dayOfIsoWeek;
0910 
0911         if (dowFirstDayOfYear <= 4) {
0912             calcDate = calcDate.addDays(daysToAdd - dowFirstDayOfYear);
0913         } else {
0914             calcDate = calcDate.addDays(daysInWeek(calcDate) + daysToAdd - dowFirstDayOfYear);
0915         }
0916 
0917         if (isValid(calcDate)) {
0918             date = calcDate;
0919             return true;
0920         }
0921     }
0922 
0923     return false;
0924 }
0925 
0926 // NOT VIRTUAL - If override needed use shared-d
0927 void KCalendarSystem::getDate(const QDate date, int *year, int *month, int *day) const
0928 {
0929     int y, m, d;
0930 
0931     if (isValid(date)) {
0932         julianDayToDate(date.toJulianDay(), y, m, d);
0933     } else {
0934         y = 0;  // How do you denote invalid year when we support -ve years?
0935         m = 0;
0936         d = 0;
0937     }
0938 
0939     if (year) {
0940         *year = y;
0941     }
0942     if (month) {
0943         *month = m;
0944     }
0945     if (day) {
0946         *day = d;
0947     }
0948 
0949 }
0950 
0951 int KCalendarSystem::year(const QDate &date) const
0952 {
0953     if (isValid(date)) {
0954         int year, month, day;
0955 
0956         julianDayToDate(date.toJulianDay(), year, month, day);
0957 
0958         return year;
0959     }
0960 
0961     return 0;  // How do you denote invalid year when we support -ve years?
0962 }
0963 
0964 int KCalendarSystem::month(const QDate &date) const
0965 {
0966     if (isValid(date)) {
0967         int year, month, day;
0968 
0969         julianDayToDate(date.toJulianDay(), year, month, day);
0970 
0971         return month;
0972     }
0973 
0974     return 0;
0975 }
0976 
0977 int KCalendarSystem::day(const QDate &date) const
0978 {
0979     if (isValid(date)) {
0980         int year, month, day;
0981 
0982         julianDayToDate(date.toJulianDay(), year, month, day);
0983 
0984         return day;
0985     }
0986 
0987     return 0;
0988 }
0989 
0990 // NOT VIRTUAL - If override needed use shared-d
0991 QString KCalendarSystem::eraName(const QDate &date, StringFormat format) const
0992 {
0993     Q_D(const KCalendarSystem);
0994 
0995     if (isValid(date)) {
0996         if (format == LongFormat) {
0997             return d->era(date).name(KLocale::LongName);
0998         } else {
0999             return d->era(date).name(KLocale::ShortName);
1000         }
1001     }
1002 
1003     return QString();
1004 }
1005 
1006 // NOT VIRTUAL - If override needed use shared-d
1007 QString KCalendarSystem::eraYear(const QDate &date, StringFormat format) const
1008 {
1009     Q_UNUSED(format)
1010     Q_D(const KCalendarSystem);
1011 
1012     if (isValid(date)) {
1013         return formatDate(date, d->era(date).format());
1014     }
1015 
1016     return QString();
1017 }
1018 
1019 // NOT VIRTUAL - If override needed use shared-d
1020 int KCalendarSystem::yearInEra(const QDate &date) const
1021 {
1022     Q_D(const KCalendarSystem);
1023 
1024     if (isValid(date)) {
1025         return d->era(date).yearInEra(year(date));
1026     }
1027 
1028     return -1;
1029 }
1030 
1031 // NOT VIRTUAL - If override needed use shared-d
1032 QList<KCalendarEra> *KCalendarSystem::eraList() const
1033 {
1034     Q_D(const KCalendarSystem);
1035 
1036     return d->eraList();
1037 }
1038 
1039 // NOT VIRTUAL - If override needed use shared-d
1040 KCalendarEra KCalendarSystem::era(const QDate &eraDate) const
1041 {
1042     Q_D(const KCalendarSystem);
1043 
1044     return d->era(eraDate);
1045 }
1046 
1047 // NOT VIRTUAL - If override needed use shared-d
1048 KCalendarEra KCalendarSystem::era(const QString &eraName, int yearInEra) const
1049 {
1050     Q_D(const KCalendarSystem);
1051 
1052     return d->era(eraName, yearInEra);
1053 }
1054 
1055 QDate KCalendarSystem::addYears(const QDate &date, int numYears) const
1056 {
1057     Q_D(const KCalendarSystem);
1058 
1059     if (isValid(date)) {
1060 
1061         int originalYear, originalMonth, originalDay;
1062         julianDayToDate(date.toJulianDay(), originalYear, originalMonth, originalDay);
1063 
1064         int newYear = d->addYears(originalYear, numYears);
1065         int newMonth = originalMonth;
1066         int newDay = originalDay;
1067 
1068         //Adjust day number if new month has fewer days than old month
1069         int daysInNewMonth = d->daysInMonth(newYear, newMonth);
1070         if (daysInNewMonth < originalDay) {
1071             newDay = daysInNewMonth;
1072         }
1073 
1074         QDate newDate;
1075         setDate(newDate, newYear, newMonth, newDay);
1076         return newDate;
1077 
1078     }
1079 
1080     return QDate();
1081 }
1082 
1083 QDate KCalendarSystem::addMonths(const QDate &date, int numMonths) const
1084 {
1085     Q_D(const KCalendarSystem);
1086 
1087     if (isValid(date)) {
1088 
1089         int originalYear, originalMonth, originalDay;
1090         julianDayToDate(date.toJulianDay(), originalYear, originalMonth, originalDay);
1091 
1092         int monthsInOriginalYear = d->monthsInYear(originalYear);
1093 
1094         int newYear = d->addYears(originalYear, (originalMonth + numMonths) / monthsInOriginalYear);
1095         int newMonth = (originalMonth + numMonths) % monthsInOriginalYear;
1096         int newDay = originalDay;
1097 
1098         if (newMonth == 0) {
1099             newYear = d->addYears(newYear, - 1);
1100             newMonth = monthsInOriginalYear;
1101         }
1102         if (newMonth < 0) {
1103             newYear = d->addYears(newYear, - 1);
1104             newMonth = newMonth + monthsInOriginalYear;
1105         }
1106 
1107         //Adjust day number if new month has fewer days than old month
1108         int daysInNewMonth = d->daysInMonth(newYear, newMonth);
1109         if (daysInNewMonth < originalDay) {
1110             newDay = daysInNewMonth;
1111         }
1112 
1113         QDate newDate;
1114         setDate(newDate, newYear, newMonth, newDay);
1115         return newDate;
1116 
1117     }
1118 
1119     return QDate();
1120 }
1121 
1122 // NOT VIRTUAL - Uses shared-d instead
1123 void KCalendarSystem::dateDifference(const QDate &fromDate, const QDate &toDate,
1124                                      int *yearsDiff, int *monthsDiff, int *daysDiff, int *direction) const
1125 {
1126     Q_D(const KCalendarSystem);
1127 
1128     if (isValid(fromDate) && isValid(toDate)) {
1129         d->dateDifference(fromDate, toDate, yearsDiff, monthsDiff, daysDiff, direction);
1130     }
1131 }
1132 
1133 // NOT VIRTUAL - Uses shared-d instead
1134 int KCalendarSystem::yearsDifference(const QDate &fromDate, const QDate &toDate) const
1135 {
1136     Q_D(const KCalendarSystem);
1137 
1138     if (isValid(fromDate) && isValid(toDate)) {
1139         return d->yearsDifference(fromDate, toDate);
1140     }
1141 
1142     return 0;
1143 }
1144 
1145 // NOT VIRTUAL - Uses shared-d instead
1146 int KCalendarSystem::monthsDifference(const QDate &fromDate, const QDate &toDate) const
1147 {
1148     Q_D(const KCalendarSystem);
1149 
1150     if (isValid(fromDate) && isValid(toDate)) {
1151         return d->monthsDifference(fromDate, toDate);
1152     }
1153 
1154     return 0;
1155 }
1156 
1157 int KCalendarSystem::monthsInYear(const QDate &date) const
1158 {
1159     Q_D(const KCalendarSystem);
1160 
1161     if (isValid(date)) {
1162         return d->monthsInYear(year(date));
1163     }
1164 
1165     return -1;
1166 }
1167 
1168 int KCalendarSystem::monthsInYear(int year) const
1169 {
1170     Q_D(const KCalendarSystem);
1171 
1172     if (isValid(year, 1, 1)) {
1173         return d->monthsInYear(year);
1174     }
1175 
1176     return -1;
1177 }
1178 
1179 int KCalendarSystem::weeksInYear(int year, KLocale::WeekNumberSystem weekNumberSystem) const
1180 {
1181     Q_D(const KCalendarSystem);
1182 
1183     if (!isValid(year, 1, 1)) {
1184         return -1;
1185     }
1186 
1187     switch (weekNumberSystem) {
1188     case KLocale::IsoWeekNumber:
1189         return d->isoWeeksInYear(year);
1190     case KLocale::FirstFullWeek:
1191         return d->regularWeeksInYear(year, locale()->weekStartDay(), 0);
1192     case KLocale::FirstPartialWeek:
1193         return d->regularWeeksInYear(year, locale()->weekStartDay(), 1);
1194     case KLocale::SimpleWeek:
1195         return d->simpleWeeksInYear(year);
1196     case KLocale::DefaultWeekNumber:
1197     default:
1198         return weeksInYear(year, locale()->weekNumberSystem());
1199     }
1200 }
1201 
1202 int KCalendarSystem::daysInYear(const QDate &date) const
1203 {
1204     Q_D(const KCalendarSystem);
1205 
1206     if (isValid(date)) {
1207         return d->daysInYear(year(date));
1208     }
1209 
1210     return -1;
1211 }
1212 
1213 int KCalendarSystem::daysInYear(int year) const
1214 {
1215     Q_D(const KCalendarSystem);
1216 
1217     if (isValid(year, 1, 1)) {
1218         return d->daysInYear(year);
1219     }
1220 
1221     return -1;
1222 }
1223 
1224 int KCalendarSystem::daysInMonth(const QDate &date) const
1225 {
1226     Q_D(const KCalendarSystem);
1227 
1228     if (isValid(date)) {
1229         int year, month, day;
1230         julianDayToDate(date.toJulianDay(), year, month, day);
1231         return d->daysInMonth(year, month);
1232     }
1233 
1234     return -1;
1235 }
1236 
1237 int KCalendarSystem::daysInMonth(int year, int month) const
1238 {
1239     Q_D(const KCalendarSystem);
1240 
1241     if (isValid(year, month, 1)) {
1242         return d->daysInMonth(year, month);
1243     }
1244 
1245     return -1;
1246 }
1247 
1248 // If ever changed to depend on the date, a lot of code will break.
1249 // Don't do that without testing and fixing at least all of KDE SC.
1250 int KCalendarSystem::daysInWeek(const QDate &date) const
1251 {
1252     Q_UNUSED(date)
1253     Q_D(const KCalendarSystem);
1254     return d->daysInWeek();
1255 }
1256 
1257 int KCalendarSystem::dayOfYear(const QDate &date) const
1258 {
1259     Q_D(const KCalendarSystem);
1260 
1261     if (isValid(date)) {
1262         return d->dayOfYear(date);
1263     }
1264 
1265     return -1;
1266 }
1267 
1268 int KCalendarSystem::dayOfWeek(const QDate &date) const
1269 {
1270     Q_D(const KCalendarSystem);
1271 
1272     if (isValid(date)) {
1273         return d->dayOfWeek(date);
1274     }
1275 
1276     return -1;
1277 }
1278 
1279 int KCalendarSystem::week(const QDate &date, KLocale::WeekNumberSystem weekNumberSystem, int *yearNum) const
1280 {
1281     Q_D(const KCalendarSystem);
1282 
1283     if (!isValid(date)) {
1284         return -1;
1285     }
1286 
1287     switch (weekNumberSystem) {
1288     case KLocale::IsoWeekNumber:
1289         return d->isoWeekNumber(date, yearNum);
1290     case KLocale::FirstFullWeek:
1291         return d->regularWeekNumber(date, locale()->weekStartDay(), 0, yearNum);
1292     case KLocale::FirstPartialWeek:
1293         return d->regularWeekNumber(date, locale()->weekStartDay(), 1, yearNum);
1294     case KLocale::SimpleWeek:
1295         return d->simpleWeekNumber(date, yearNum);
1296     case KLocale::DefaultWeekNumber:
1297     default:
1298         return week(date, locale()->weekNumberSystem(), yearNum);
1299     }
1300 }
1301 
1302 bool KCalendarSystem::isLeapYear(int year) const
1303 {
1304     Q_D(const KCalendarSystem);
1305 
1306     if (isValid(year, 1, 1)) {
1307         return d->isLeapYear(year);
1308     }
1309 
1310     return false;
1311 }
1312 
1313 bool KCalendarSystem::isLeapYear(const QDate &date) const
1314 {
1315     Q_D(const KCalendarSystem);
1316 
1317     if (isValid(date)) {
1318         return d->isLeapYear(year(date));
1319     }
1320 
1321     return false;
1322 }
1323 
1324 // NOT VIRTUAL - If override needed use shared-d
1325 QDate KCalendarSystem::firstDayOfYear(int year) const
1326 {
1327     Q_D(const KCalendarSystem);
1328 
1329     if (isValid(year, 1, 1)) {
1330         return d->firstDayOfYear(year);
1331     }
1332 
1333     return QDate();
1334 }
1335 
1336 // NOT VIRTUAL - If override needed use shared-d
1337 QDate KCalendarSystem::lastDayOfYear(int year) const
1338 {
1339     Q_D(const KCalendarSystem);
1340 
1341     if (isValid(year, 1, 1)) {
1342         return d->lastDayOfYear(year);
1343     }
1344 
1345     return QDate();
1346 }
1347 
1348 // NOT VIRTUAL - If override needed use shared-d
1349 QDate KCalendarSystem::firstDayOfYear(const QDate &date) const
1350 {
1351     Q_D(const KCalendarSystem);
1352 
1353     if (isValid(date)) {
1354         return d->firstDayOfYear(year(date));
1355     }
1356 
1357     return QDate();
1358 }
1359 
1360 // NOT VIRTUAL - If override needed use shared-d
1361 QDate KCalendarSystem::lastDayOfYear(const QDate &date) const
1362 {
1363     Q_D(const KCalendarSystem);
1364 
1365     if (isValid(date)) {
1366         return d->lastDayOfYear(year(date));
1367     }
1368 
1369     return QDate();
1370 }
1371 
1372 // NOT VIRTUAL - If override needed use shared-d
1373 QDate KCalendarSystem::firstDayOfMonth(int year, int month) const
1374 {
1375     Q_D(const KCalendarSystem);
1376 
1377     if (isValid(year, month, 1)) {
1378         return d->firstDayOfMonth(year, month);
1379     }
1380 
1381     return QDate();
1382 }
1383 
1384 // NOT VIRTUAL - If override needed use shared-d
1385 QDate KCalendarSystem::lastDayOfMonth(int year, int month) const
1386 {
1387     Q_D(const KCalendarSystem);
1388 
1389     if (isValid(year, month, 1)) {
1390         return d->lastDayOfMonth(year, month);
1391     }
1392 
1393     return QDate();
1394 }
1395 
1396 // NOT VIRTUAL - If override needed use shared-d
1397 QDate KCalendarSystem::firstDayOfMonth(const QDate &date) const
1398 {
1399     Q_D(const KCalendarSystem);
1400 
1401     if (isValid(date)) {
1402         int year, month;
1403         getDate(date, &year, &month, nullptr);
1404         return d->firstDayOfMonth(year, month);
1405     }
1406 
1407     return QDate();
1408 }
1409 
1410 // NOT VIRTUAL - If override needed use shared-d
1411 QDate KCalendarSystem::lastDayOfMonth(const QDate &date) const
1412 {
1413     Q_D(const KCalendarSystem);
1414 
1415     if (isValid(date)) {
1416         int year, month;
1417         getDate(date, &year, &month, nullptr);
1418         return d->lastDayOfMonth(year, month);
1419     }
1420 
1421     return QDate();
1422 }
1423 
1424 QString KCalendarSystem::monthName(int month, int year, KCalendarSystem::MonthNameFormat format) const
1425 {
1426     Q_D(const KCalendarSystem);
1427 
1428     if (!isValid(year, month, 1)) {
1429         return QString();
1430     }
1431 
1432     if (format == KCalendarSystem::NarrowName) {
1433         return d->monthName(month, year, KLocale::NarrowName, false);
1434     }
1435 
1436     if (format == KCalendarSystem::ShortNamePossessive) {
1437         return d->monthName(month, year, KLocale::ShortName, true);
1438     }
1439 
1440     if (format == KCalendarSystem::ShortName) {
1441         return d->monthName(month, year, KLocale::ShortName, false);
1442     }
1443 
1444     if (format == KCalendarSystem::LongNamePossessive) {
1445         return d->monthName(month, year, KLocale::LongName, true);
1446     }
1447 
1448     // KCalendarSystem::LongName or any other
1449     return d->monthName(month, year, KLocale::LongName, false);
1450 }
1451 
1452 QString KCalendarSystem::monthName(const QDate &date, MonthNameFormat format) const
1453 {
1454     if (isValid(date)) {
1455         int year, month;
1456         getDate(date, &year, &month, nullptr);
1457         return monthName(month, year, format);
1458     }
1459 
1460     return QString();
1461 }
1462 
1463 QString KCalendarSystem::weekDayName(int weekDay, KCalendarSystem::WeekDayNameFormat format) const
1464 {
1465     Q_D(const KCalendarSystem);
1466 
1467     if (weekDay < 1 || weekDay > d->daysInWeek()) {
1468         return QString();
1469     }
1470 
1471     if (format == KCalendarSystem::NarrowDayName) {
1472         return d->weekDayName(weekDay, KLocale::NarrowName);
1473     }
1474 
1475     if (format == KCalendarSystem::ShortDayName) {
1476         return d->weekDayName(weekDay, KLocale::ShortName);
1477     }
1478 
1479     return d->weekDayName(weekDay, KLocale::LongName);
1480 }
1481 
1482 QString KCalendarSystem::weekDayName(const QDate &date, WeekDayNameFormat format) const
1483 {
1484     if (isValid(date)) {
1485         return weekDayName(dayOfWeek(date), format);
1486     }
1487 
1488     return QString();
1489 }
1490 
1491 int KCalendarSystem::yearStringToInteger(const QString &yearString, int &readLength) const
1492 {
1493     Q_D(const KCalendarSystem);
1494 
1495     QString minus = i18nc("Negative symbol as used for year numbers, e.g. -5 = 5 BC", "-");
1496     if (yearString.startsWith(minus)) {
1497         int value = d->integerFromString(yearString.mid(minus.length()), 4, readLength);
1498         if (readLength > 0 && value >= 0) {
1499             readLength = readLength + minus.length();
1500             return value * -1;
1501         } else {
1502             return value;
1503         }
1504     }
1505 
1506     return d->integerFromString(yearString, 4, readLength);
1507 }
1508 
1509 int KCalendarSystem::monthStringToInteger(const QString &monthString, int &readLength) const
1510 {
1511     Q_D(const KCalendarSystem);
1512     return d->integerFromString(monthString, 2, readLength);
1513 }
1514 
1515 int KCalendarSystem::dayStringToInteger(const QString &dayString, int &readLength) const
1516 {
1517     Q_D(const KCalendarSystem);
1518     return d->integerFromString(dayString, 2, readLength);
1519 }
1520 
1521 QString KCalendarSystem::formatDate(const QDate &fromDate, KLocale::DateFormat toFormat) const
1522 {
1523     if (!fromDate.isValid()) {
1524         return QString();
1525     }
1526 
1527     if (toFormat == KLocale::FancyShortDate || toFormat == KLocale::FancyLongDate) {
1528         QDate now = KDateTime::currentLocalDate();
1529         int daysToNow = fromDate.daysTo(now);
1530         switch (daysToNow) {
1531         case 0:
1532             return i18n("Today");
1533         case 1:
1534             return i18n("Yesterday");
1535         case 2:
1536         case 3:
1537         case 4:
1538         case 5:
1539         case 6:
1540             return weekDayName(fromDate);
1541         default:
1542             break;
1543         }
1544     }
1545 
1546     switch (toFormat) {
1547     case KLocale::LongDate:
1548     case KLocale::FancyLongDate:
1549         return formatDate(fromDate, locale()->dateFormat());
1550     case KLocale::IsoDate:
1551         return formatDate(fromDate, QLatin1String("%Y-%m-%d"));
1552     case KLocale::IsoWeekDate:
1553         return formatDate(fromDate, QLatin1String("%Y-W%V-%u"));
1554     case KLocale::IsoOrdinalDate:
1555         return formatDate(fromDate, QLatin1String("%Y-%j"));
1556     case KLocale::ShortDate:
1557     case KLocale::FancyShortDate:
1558     default:
1559         return formatDate(fromDate, locale()->dateFormatShort());
1560     }
1561 
1562 }
1563 
1564 // NOT VIRTUAL - If override needed use shared-d
1565 QString KCalendarSystem::formatDate(const QDate &fromDate, const QString &toFormat,
1566                                     KLocale::DateTimeFormatStandard standard) const
1567 {
1568     return formatDate(fromDate, toFormat, locale()->dateTimeDigitSet(), standard);
1569 }
1570 
1571 // NOT VIRTUAL - If override needed use shared-d
1572 QString KCalendarSystem::formatDate(const QDate &fromDate, const QString &toFormat, KLocale::DigitSet digitSet,
1573                                     KLocale::DateTimeFormatStandard formatStandard) const
1574 {
1575     if (!isValid(fromDate) || toFormat.isEmpty()) {
1576         return QString();
1577     }
1578 
1579     KDateTimeFormatter formatter;
1580     return formatter.formatDate(fromDate, toFormat, this, locale(), digitSet, formatStandard);
1581 }
1582 
1583 // NOT VIRTUAL - If override needed use shared-d
1584 QString KCalendarSystem::formatDate(const QDate &date, KLocale::DateTimeComponent component,
1585                                     KLocale::DateTimeComponentFormat format,
1586                                     KLocale::WeekNumberSystem weekNumberSystem) const
1587 {
1588     Q_D(const KCalendarSystem);
1589 
1590     switch (component) {
1591     case KLocale::Year:
1592     case KLocale::YearName:
1593         switch (format) {
1594         case KLocale::ShortName:
1595         case KLocale::NarrowName:
1596         case KLocale::ShortNumber:
1597             return formatDate(date, QLatin1String("%y"));
1598         case KLocale::LongNumber:
1599         case KLocale::LongName:
1600         case KLocale::DefaultComponentFormat:
1601         default:
1602             return formatDate(date, QLatin1String("%Y"));
1603         }
1604     case KLocale::Month:
1605         switch (format) {
1606         case KLocale::LongName:
1607             return monthName(date, KCalendarSystem::LongName);
1608         case KLocale::ShortName:
1609             return monthName(date, KCalendarSystem::ShortName);
1610         case KLocale::NarrowName:
1611             return monthName(date, KCalendarSystem::NarrowName);
1612         case KLocale::LongNumber:
1613             return formatDate(date, QLatin1String("%m"));
1614         case KLocale::ShortNumber:
1615         case KLocale::DefaultComponentFormat:
1616         default:
1617             return formatDate(date, QLatin1String("%n"));
1618         }
1619     case KLocale::MonthName:
1620         switch (format) {
1621         case KLocale::NarrowName:
1622             return monthName(date, KCalendarSystem::NarrowName);
1623         case KLocale::ShortName:
1624         case KLocale::ShortNumber:
1625             return monthName(date, KCalendarSystem::ShortName);
1626         case KLocale::LongName:
1627         case KLocale::LongNumber:
1628         case KLocale::DefaultComponentFormat:
1629         default:
1630             return monthName(date, KCalendarSystem::LongName);
1631         }
1632     case KLocale::Day:
1633     case KLocale::DayName:
1634         switch (format) {
1635         case KLocale::LongNumber:
1636         case KLocale::LongName:
1637             return formatDate(date, QLatin1String("%d"));
1638         case KLocale::ShortName:
1639         case KLocale::NarrowName:
1640         case KLocale::ShortNumber:
1641         case KLocale::DefaultComponentFormat:
1642         default:
1643             return formatDate(date, QLatin1String("%e"));
1644         }
1645     case KLocale::JulianDay:
1646         return d->stringFromInteger(date.toJulianDay(), 0);
1647     case KLocale::EraName:
1648         switch (format) {
1649         case KLocale::LongNumber:
1650         case KLocale::LongName:
1651             return eraName(date, KCalendarSystem::LongFormat);
1652         case KLocale::ShortName:
1653         case KLocale::NarrowName:
1654         case KLocale::ShortNumber:
1655         case KLocale::DefaultComponentFormat:
1656         default:
1657             return eraName(date, KCalendarSystem::ShortFormat);
1658         }
1659     case KLocale::EraYear:
1660         switch (format) {
1661         case KLocale::LongNumber:
1662         case KLocale::LongName:
1663             return eraYear(date, KCalendarSystem::LongFormat);
1664         case KLocale::ShortName:
1665         case KLocale::NarrowName:
1666         case KLocale::ShortNumber:
1667         case KLocale::DefaultComponentFormat:
1668         default:
1669             return eraYear(date, KCalendarSystem::ShortFormat);
1670         }
1671     case KLocale::YearInEra:
1672         switch (format) {
1673         case KLocale::LongNumber:
1674         case KLocale::LongName:
1675             return formatDate(date, QLatin1String("%4Ey"));
1676         case KLocale::ShortName:
1677         case KLocale::NarrowName:
1678         case KLocale::ShortNumber:
1679         case KLocale::DefaultComponentFormat:
1680         default:
1681             return formatDate(date, QLatin1String("%Ey"));
1682         }
1683     case KLocale::DayOfYear:
1684     case KLocale::DayOfYearName:
1685         switch (format) {
1686         case KLocale::LongNumber:
1687         case KLocale::LongName:
1688             return formatDate(date, QLatin1String("%j"));
1689         case KLocale::ShortName:
1690         case KLocale::NarrowName:
1691         case KLocale::ShortNumber:
1692         case KLocale::DefaultComponentFormat:
1693         default:
1694             return formatDate(date, QLatin1String("%-j"));
1695         }
1696     case KLocale::DayOfWeek:
1697         switch (format) {
1698         case KLocale::LongName:
1699             return weekDayName(date, KCalendarSystem::LongDayName);
1700         case KLocale::ShortName:
1701             return weekDayName(date, KCalendarSystem::ShortDayName);
1702         case KLocale::NarrowName:
1703             return weekDayName(date, KCalendarSystem::NarrowDayName);
1704         case KLocale::LongNumber:
1705         case KLocale::ShortNumber:
1706         case KLocale::DefaultComponentFormat:
1707         default:
1708             return formatDate(date, QLatin1String("%-u"));
1709         }
1710     case KLocale::DayOfWeekName:
1711         switch (format) {
1712         case KLocale::NarrowName:
1713             return weekDayName(date, KCalendarSystem::NarrowDayName);
1714         case KLocale::ShortName:
1715         case KLocale::ShortNumber:
1716             return weekDayName(date, KCalendarSystem::ShortDayName);
1717         case KLocale::LongName:
1718         case KLocale::LongNumber:
1719         case KLocale::DefaultComponentFormat:
1720         default:
1721             return weekDayName(date, KCalendarSystem::LongDayName);
1722         }
1723     case KLocale::Week:
1724         switch (format) {
1725         case KLocale::LongNumber:
1726         case KLocale::LongName:
1727             return d->stringFromInteger(week(date, weekNumberSystem, nullptr), 2, QLatin1Char('0'));
1728         case KLocale::ShortName:
1729         case KLocale::NarrowName:
1730         case KLocale::ShortNumber:
1731         case KLocale::DefaultComponentFormat:
1732         default:
1733             return d->stringFromInteger(week(date, weekNumberSystem, nullptr), 0, QLatin1Char('0'));
1734         }
1735     case KLocale::WeekYear: {
1736         int weekYear;
1737         QDate yearDate;
1738         week(date, weekNumberSystem, &weekYear);
1739         setDate(yearDate, weekYear, 1, 1);
1740         return formatDate(yearDate, KLocale::Year, format);
1741     }
1742     case KLocale::MonthsInYear:
1743         switch (format) {
1744         case KLocale::LongNumber:
1745         case KLocale::LongName:
1746             return d->stringFromInteger(monthsInYear(date), 2, QLatin1Char('0'));
1747         case KLocale::ShortName:
1748         case KLocale::NarrowName:
1749         case KLocale::ShortNumber:
1750         case KLocale::DefaultComponentFormat:
1751         default:
1752             return d->stringFromInteger(monthsInYear(date), 0, QLatin1Char('0'));
1753         }
1754     case KLocale::WeeksInYear:
1755         switch (format) {
1756         case KLocale::LongNumber:
1757         case KLocale::LongName:
1758             return d->stringFromInteger(weeksInYear(date), 2, QLatin1Char('0'));
1759         case KLocale::ShortName:
1760         case KLocale::NarrowName:
1761         case KLocale::ShortNumber:
1762         case KLocale::DefaultComponentFormat:
1763         default:
1764             return d->stringFromInteger(weeksInYear(date), 0, QLatin1Char('0'));
1765         }
1766     case KLocale::DaysInYear:
1767         switch (format) {
1768         case KLocale::LongNumber:
1769         case KLocale::LongName:
1770             return d->stringFromInteger(daysInYear(date), 3, QLatin1Char('0'));
1771         case KLocale::ShortName:
1772         case KLocale::NarrowName:
1773         case KLocale::ShortNumber:
1774         case KLocale::DefaultComponentFormat:
1775         default:
1776             return d->stringFromInteger(daysInYear(date), 0, QLatin1Char('0'));
1777         }
1778     case KLocale::DaysInMonth:
1779         switch (format) {
1780         case KLocale::LongNumber:
1781         case KLocale::LongName:
1782             return d->stringFromInteger(daysInMonth(date), 2, QLatin1Char('0'));
1783         case KLocale::ShortName:
1784         case KLocale::NarrowName:
1785         case KLocale::ShortNumber:
1786         case KLocale::DefaultComponentFormat:
1787         default:
1788             return d->stringFromInteger(daysInMonth(date), 0, QLatin1Char('0'));
1789         }
1790     case KLocale::DaysInWeek:
1791         switch (format) {
1792         case KLocale::LongNumber:
1793         case KLocale::LongName:
1794         case KLocale::ShortName:
1795         case KLocale::NarrowName:
1796         case KLocale::ShortNumber:
1797         case KLocale::DefaultComponentFormat:
1798         default:
1799             return d->stringFromInteger(d->daysInWeek(), 0);
1800         }
1801     default:
1802         return QString();
1803     }
1804 }
1805 
1806 QDate KCalendarSystem::readDate(const QString &str, bool *ok) const
1807 {
1808     //Try each standard format in turn, start with the locale ones,
1809     //then the well defined standards
1810     QDate date = readDate(str, KLocale::ShortFormat, ok);
1811     if (!isValid(date)) {
1812         date = readDate(str, KLocale::NormalFormat, ok);
1813         if (!isValid(date)) {
1814             date = readDate(str, KLocale::IsoFormat, ok);
1815             if (!isValid(date)) {
1816                 date = readDate(str, KLocale::IsoWeekFormat, ok);
1817                 if (!isValid(date)) {
1818                     date = readDate(str, KLocale::IsoOrdinalFormat, ok);
1819                 }
1820             }
1821         }
1822     }
1823 
1824     return date;
1825 }
1826 
1827 QDate KCalendarSystem::readDate(const QString &str, KLocale::ReadDateFlags flags, bool *ok) const
1828 {
1829     if (flags & KLocale::ShortFormat) {
1830         return readDate(str, locale()->dateFormatShort(), ok);
1831     } else if (flags & KLocale::NormalFormat) {
1832         return readDate(str, locale()->dateFormat(), ok);
1833     } else if (flags & KLocale::IsoFormat) {
1834         return readDate(str, QLatin1String("%Y-%m-%d"), ok);
1835     } else if (flags & KLocale::IsoWeekFormat) {
1836         return readDate(str, QLatin1String("%Y-W%V-%u"), ok);
1837     } else if (flags & KLocale::IsoOrdinalFormat) {
1838         return readDate(str, QLatin1String("%Y-%j"), ok);
1839     }
1840     return QDate();
1841 }
1842 
1843 QDate KCalendarSystem::readDate(const QString &inputString, const QString &formatString, bool *ok) const
1844 {
1845     return readDate(inputString, formatString, ok, KLocale::KdeFormat);
1846 }
1847 
1848 // NOT VIRTUAL - If override needed use shared-d
1849 QDate KCalendarSystem::readDate(const QString &inputString, const QString &formatString, bool *ok,
1850                                 KLocale::DateTimeFormatStandard formatStandard) const
1851 {
1852     KDateTimeParser parser;
1853     QDate resultDate = parser.parseDate(inputString, formatString, this, locale(), locale()->dateTimeDigitSet(), formatStandard);
1854     if (ok) {
1855         *ok = resultDate.isValid();
1856     }
1857     return resultDate;
1858 }
1859 
1860 // NOT VIRTUAL - If override needed use shared-d
1861 int KCalendarSystem::shortYearWindowStartYear() const
1862 {
1863     Q_D(const KCalendarSystem);
1864 
1865     return d->shortYearWindowStartYear();
1866 }
1867 
1868 // NOT VIRTUAL - If override needed use shared-d
1869 int KCalendarSystem::applyShortYearWindow(int inputYear) const
1870 {
1871     Q_D(const KCalendarSystem);
1872 
1873     return d->applyShortYearWindow(inputYear);
1874 }
1875 
1876 const KLocale *KCalendarSystem::locale() const
1877 {
1878     Q_D(const KCalendarSystem);
1879 
1880     return d->locale();
1881 }