diff --git a/declarativeimports/locale/calendarsystem.cpp b/declarativeimports/locale/calendarsystem.cpp new file mode 100644 index 000000000..77ef0e948 --- /dev/null +++ b/declarativeimports/locale/calendarsystem.cpp @@ -0,0 +1,2506 @@ +/* + Copyright (c) 2002 Carlos Moro + Copyright (c) 2002 Hans Petter Bieker + Copyright 2007, 2008, 2009, 2010 John Layt + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "kcalendarsystem.h" +#include "kcalendarsystemprivate_p.h" + +#include "kdebug.h" +#include "kconfiggroup.h" + +#include + +#include "kdatetime.h" +#include "kdatetimeformatter_p.h" +#include "kdatetimeparser_p.h" +#include "kcalendarera_p.h" +#include "kcalendarsystemcoptic_p.h" +#include "kcalendarsystemethiopian_p.h" +#include "kcalendarsystemgregorian_p.h" +#include "kcalendarsystemhebrew_p.h" +#include "kcalendarsystemindiannational_p.h" +#include "kcalendarsystemislamiccivil_p.h" +#include "kcalendarsystemjalali_p.h" +#include "kcalendarsystemjapanese_p.h" +#include "kcalendarsystemjulian_p.h" +#include "kcalendarsystemminguo_p.h" +#include "kcalendarsystemqdate_p.h" +#include "kcalendarsystemthai_p.h" + +KCalendarSystem *KCalendarSystem::create(const QString &calendarType, const KLocale *locale) +{ + return create(calendarSystem(calendarType), locale); +} + +KCalendarSystem *KCalendarSystem::create(const QString &calendarType, KSharedConfig::Ptr config, + const KLocale *locale) +{ + return create(calendarSystem(calendarType), config, locale); +} + +QStringList KCalendarSystem::calendarSystems() +{ + QStringList lst; + + lst.append(QLatin1String("coptic")); + lst.append(QLatin1String("ethiopian")); + lst.append(QLatin1String("gregorian")); + lst.append(QLatin1String("gregorian-proleptic")); + lst.append(QLatin1String("hebrew")); + lst.append(QLatin1String("hijri")); + lst.append(QLatin1String("indian-national")); + lst.append(QLatin1String("jalali")); + lst.append(QLatin1String("japanese")); + lst.append(QLatin1String("julian")); + lst.append(QLatin1String("minguo")); + lst.append(QLatin1String("thai")); + + return lst; +} + +QString KCalendarSystem::calendarLabel(const QString &calendarType) +{ + if (calendarSystemsList().contains(calendarSystem(calendarType))) { + return KCalendarSystem::calendarLabel(KCalendarSystem::calendarSystem(calendarType)); + } else { + return ki18nc("@item Calendar system", "Invalid Calendar Type").toString(KGlobal::locale()); + } +} + +KCalendarSystem *KCalendarSystem::create(KLocale::CalendarSystem calendarSystem, const KLocale *locale) +{ + return create(calendarSystem, KSharedConfig::Ptr(), locale); +} + +KCalendarSystem *KCalendarSystem::create(KLocale::CalendarSystem calendarSystem, + KSharedConfig::Ptr config, + const KLocale *locale) +{ + switch (calendarSystem) { + case KLocale::QDateCalendar: + return new KCalendarSystemQDate(config, locale); + case KLocale::CopticCalendar: + return new KCalendarSystemCoptic(config, locale); + case KLocale::EthiopianCalendar: + return new KCalendarSystemEthiopian(config, locale); + case KLocale::GregorianCalendar: + return new KCalendarSystemGregorian(config, locale); + case KLocale::HebrewCalendar: + return new KCalendarSystemHebrew(config, locale); + case KLocale::IndianNationalCalendar: + return new KCalendarSystemIndianNational(config, locale); + case KLocale::IslamicCivilCalendar: + return new KCalendarSystemIslamicCivil(config, locale); + case KLocale::JalaliCalendar: + return new KCalendarSystemJalali(config, locale); + case KLocale::JapaneseCalendar: + return new KCalendarSystemJapanese(config, locale); + case KLocale::JulianCalendar: + return new KCalendarSystemJulian(config, locale); + case KLocale::MinguoCalendar: + return new KCalendarSystemMinguo(config, locale); + case KLocale::ThaiCalendar: + return new KCalendarSystemThai(config, locale); + default: + return new KCalendarSystemQDate(config, locale); + } +} + +QList KCalendarSystem::calendarSystemsList() +{ + QList list; + + list.append(KLocale::QDateCalendar); + list.append(KLocale::CopticCalendar); + list.append(KLocale::EthiopianCalendar); + list.append(KLocale::GregorianCalendar); + list.append(KLocale::HebrewCalendar); + list.append(KLocale::IslamicCivilCalendar); + list.append(KLocale::IndianNationalCalendar); + list.append(KLocale::JalaliCalendar); + list.append(KLocale::JapaneseCalendar); + list.append(KLocale::JulianCalendar); + list.append(KLocale::MinguoCalendar); + list.append(KLocale::ThaiCalendar); + + return list; +} + +QString KCalendarSystem::calendarLabel(KLocale::CalendarSystem calendarSystem, const KLocale *locale) +{ + switch (calendarSystem) { + case KLocale::QDateCalendar: + return ki18nc("@item Calendar system", "Gregorian").toString(locale); + case KLocale::CopticCalendar: + return ki18nc("@item Calendar system", "Coptic").toString(locale); + case KLocale::EthiopianCalendar: + return ki18nc("@item Calendar system", "Ethiopian").toString(locale); + case KLocale::GregorianCalendar: + return ki18nc("@item Calendar system", "Gregorian (Proleptic)").toString(locale); + case KLocale::HebrewCalendar: + return ki18nc("@item Calendar system", "Hebrew").toString(locale); + case KLocale::IslamicCivilCalendar: + return ki18nc("@item Calendar system", "Islamic / Hijri (Civil)").toString(locale); + case KLocale::IndianNationalCalendar: + return ki18nc("@item Calendar system", "Indian National").toString(locale); + case KLocale::JalaliCalendar: + return ki18nc("@item Calendar system", "Jalali").toString(locale); + case KLocale::JapaneseCalendar: + return ki18nc("@item Calendar system", "Japanese").toString(locale); + case KLocale::JulianCalendar: + return ki18nc("@item Calendar system", "Julian").toString(locale); + case KLocale::MinguoCalendar: + return ki18nc("@item Calendar system", "Taiwanese").toString(locale); + case KLocale::ThaiCalendar: + return ki18nc("@item Calendar system", "Thai").toString(locale); + } + + return ki18nc("@item Calendar system", "Invalid Calendar Type").toString(locale); +} + +KLocale::CalendarSystem KCalendarSystem::calendarSystemForCalendarType(const QString &calendarType ) +{ + return calendarSystem( calendarType ); +} + +KLocale::CalendarSystem KCalendarSystem::calendarSystem(const QString &calendarType ) +{ + if (calendarType == QLatin1String("coptic")) { + return KLocale::CopticCalendar; + } else if (calendarType == QLatin1String("ethiopian")) { + return KLocale::EthiopianCalendar; + } else if (calendarType == QLatin1String("gregorian")) { + return KLocale::QDateCalendar; + } else if (calendarType == QLatin1String("gregorian-proleptic")) { + return KLocale::GregorianCalendar; + } else if (calendarType == QLatin1String("hebrew")) { + return KLocale::HebrewCalendar; + } else if (calendarType == QLatin1String("hijri")) { + return KLocale::IslamicCivilCalendar; + } else if (calendarType == QLatin1String("indian-national")) { + return KLocale::IndianNationalCalendar; + } else if (calendarType == QLatin1String("jalali")) { + return KLocale::JalaliCalendar; + } else if (calendarType == QLatin1String("japanese")) { + return KLocale::JapaneseCalendar; + } else if (calendarType == QLatin1String("julian")) { + return KLocale::JulianCalendar; + } else if (calendarType == QLatin1String("minguo")) { + return KLocale::MinguoCalendar; + } else if (calendarType == QLatin1String("thai")) { + return KLocale::ThaiCalendar; + } else { + return KLocale::QDateCalendar; + } +} + +QString KCalendarSystem::calendarType(KLocale::CalendarSystem calendarSystem) +{ + if (calendarSystem == KLocale::QDateCalendar) { + return QLatin1String("gregorian"); + } else if (calendarSystem == KLocale::CopticCalendar) { + return QLatin1String("coptic"); + } else if (calendarSystem == KLocale::EthiopianCalendar) { + return QLatin1String("ethiopian"); + } else if (calendarSystem == KLocale::GregorianCalendar) { + return QLatin1String("gregorian-proleptic"); + } else if (calendarSystem == KLocale::HebrewCalendar) { + return QLatin1String("hebrew"); + } else if (calendarSystem == KLocale::IndianNationalCalendar) { + return QLatin1String("indian-national"); + } else if (calendarSystem == KLocale::IslamicCivilCalendar) { + return QLatin1String("hijri"); + } else if (calendarSystem == KLocale::JalaliCalendar) { + return QLatin1String("jalali"); + } else if (calendarSystem == KLocale::JapaneseCalendar) { + return QLatin1String("japanese"); + } else if (calendarSystem == KLocale::JulianCalendar) { + return QLatin1String("julian"); + } else if (calendarSystem == KLocale::MinguoCalendar) { + return QLatin1String("minguo"); + } else if (calendarSystem == KLocale::ThaiCalendar) { + return QLatin1String("thai"); + } else { + return QLatin1String("gregorian"); + } +} + +// Shared d pointer base class definitions + +KCalendarSystemPrivate::KCalendarSystemPrivate(KCalendarSystem *q_ptr) + : q(q_ptr), + m_eraList(0), + m_shortYearWindowStartYear(2000) +{ +} + +KCalendarSystemPrivate::~KCalendarSystemPrivate() +{ + delete m_eraList; +} + +// Dummy version using Gregorian as an example +// This method MUST be re-implemented in any new Calendar System +KLocale::CalendarSystem KCalendarSystemPrivate::calendarSystem() const +{ + return KLocale::QDateCalendar; +} + +// Dummy version as an example, remember to translate (see Gregorian for example) +// Add the Era's in chronological order, from earliest to latest +// This method MUST be re-implemented in any new Calendar System +void KCalendarSystemPrivate::loadDefaultEraList() +{ + addEra('-', 1, q->epoch().addDays(-1), -1, q->earliestValidDate(), QLatin1String("Before KDE"), QLatin1String("BK"), QLatin1String("%Ey %EC")); + addEra('+', 1, q->epoch(), 1, q->latestValidDate(), QLatin1String("Anno KDE"), QLatin1String("AK"), QLatin1String("%Ey %EC")); +} + +// Dummy version using Gregorian as an example +// This method MUST be re-implemented in any new Calendar System +int KCalendarSystemPrivate::monthsInYear(int year) const +{ + Q_UNUSED(year) + return 12; +} + +// Dummy version using Gregorian as an example +// This method MUST be re-implemented in any new Calendar System +int KCalendarSystemPrivate::daysInMonth(int year, int month) const +{ + if (month == 2) { + if (isLeapYear(year)) { + return 29; + } else { + return 28; + } + } + + if (month == 4 || month == 6 || month == 9 || month == 11) { + return 30; + } + + return 31; +} + +// Dummy version using Gregorian as an example +// This method MUST be re-implemented in any new Calendar System +int KCalendarSystemPrivate::daysInYear(int year) const +{ + if (isLeapYear(year)) { + return 366; + } else { + return 365; + } +} + +// Dummy version using Gregorian as an example +// This method MUST be re-implemented in any new Calendar System +int KCalendarSystemPrivate::daysInWeek() const +{ + return 7; +} + +// Dummy version using Gregorian as an example +// This method MUST be re-implemented in any new Calendar System +bool KCalendarSystemPrivate::isLeapYear(int year) const +{ + if (year < 1) { + year = year + 1; + } + + if (year % 4 == 0) { + if (year % 100 != 0) { + return true; + } else if (year % 400 == 0) { + return true; + } + } + + return false; +} + +// Dummy version using Gregorian as an example +// This method MUST be re-implemented in any new Calendar System +bool KCalendarSystemPrivate::hasLeapMonths() const +{ + return false; +} + +// Dummy version using Gregorian as an example +// This method MUST be re-implemented in any new Calendar System +bool KCalendarSystemPrivate::hasYearZero() const +{ + return false; +} + +// Dummy version using Gregorian as an example +// This method MUST be re-implemented in any new Calendar System +int KCalendarSystemPrivate::maxDaysInWeek() const +{ + return 7; +} + +// Dummy version using Gregorian as an example +// This method MUST be re-implemented in any new Calendar System +int KCalendarSystemPrivate::maxMonthsInYear() const +{ + return 12; +} + +// Convenince, faster than calling year( ealiestValidDate() ), +// needed in fake-virtual functions so don't remove +// Dummy version using Gregorian as an example +// This method MUST be re-implemented in any new Calendar System +int KCalendarSystemPrivate::earliestValidYear() const +{ + return -4712; +} + +// Convenince, faster than calling year( latestValidDate() ), +// needed in fake-virtual functions so don't remove +// Dummy version using Gregorian as an example +// This method MUST be re-implemented in any new Calendar System +int KCalendarSystemPrivate::latestValidYear() const +{ + return 9999; +} + +// Dummy version +// This method MUST be re-implemented in any new Calendar System +QString KCalendarSystemPrivate::monthName(int month, int year, KLocale::DateTimeComponentFormat format, bool possessive) const +{ + Q_UNUSED(month); + Q_UNUSED(year); + Q_UNUSED(format); + Q_UNUSED(possessive); + return QString(); +} + +// Dummy version +// This method MUST be re-implemented in any new Calendar System +QString KCalendarSystemPrivate::weekDayName(int weekDay, KLocale::DateTimeComponentFormat format) const +{ + Q_UNUSED(weekDay); + Q_UNUSED(format); + return QString(); +} + +// Reimplement if special maths handling required, e.g. Hebrew. +int KCalendarSystemPrivate::week(const QDate &date, KLocale::WeekNumberSystem weekNumberSystem, int *yearNum) const +{ + int y, m, d; + q->julianDayToDate(date.toJulianDay(), y, m, d); + + switch (weekNumberSystem) { + case KLocale::IsoWeekNumber: + return isoWeekNumber(date, yearNum); + case KLocale::FirstFullWeek: + return regularWeekNumber(date, locale()->weekStartDay(), 0, yearNum); + case KLocale::FirstPartialWeek: + return regularWeekNumber(date, locale()->weekStartDay(), 1, yearNum); + case KLocale::SimpleWeek: + return simpleWeekNumber(date, yearNum); + case KLocale::DefaultWeekNumber: + default: + return week(date, locale()->weekNumberSystem(), yearNum); + } +} + +// Reimplement if special maths handling required, e.g. Hebrew. +int KCalendarSystemPrivate::isoWeekNumber(const QDate &date, int *yearNum) const +{ + int y, m, d; + q->julianDayToDate(date.toJulianDay(), y, m, d); + + QDate firstDayWeek1, lastDay; + int week; + int weekDay1, dayOfWeek1InYear; + + // let's guess 1st day of 1st week + firstDayWeek1 = firstDayOfYear(y); + weekDay1 = dayOfWeek(firstDayWeek1); + + // iso 8601: week 1 is the first containing thursday and week starts on monday + if (weekDay1 > 4 /*Thursday*/) { + firstDayWeek1 = q->addDays(firstDayWeek1 , daysInWeek() - weekDay1 + 1); // next monday + } + + dayOfWeek1InYear = dayOfYear(firstDayWeek1); + + // our date in prev year's week + if (dayOfYear(date) < dayOfWeek1InYear) { + if (yearNum) { + *yearNum = addYears(y, - 1); + } + return isoWeeksInYear(addYears(y, - 1)); + } + + // let's check if its last week belongs to next year + lastDay = lastDayOfYear(y); + + // if our date is in last week && 1st week in next year has thursday + if ((dayOfYear(date) >= daysInYear(y) - dayOfWeek(lastDay) + 1) + && dayOfWeek(lastDay) < 4) { + if (yearNum) { + * yearNum = addYears(y, 1); + } + week = 1; + } else { + // To calculate properly the number of weeks from day a to x let's make a day 1 of week + if (weekDay1 < 5) { + firstDayWeek1 = q->addDays(firstDayWeek1, -(weekDay1 - 1)); + } + + if (yearNum) { + * yearNum = y; + } + + week = firstDayWeek1.daysTo(date) / daysInWeek() + 1; + } + + return week; +} + +// Reimplement if special maths handling required, e.g. Hebrew. +int KCalendarSystemPrivate::regularWeekNumber(const QDate &date, int weekStartDay, int firstWeekNumber, int *weekYear) const +{ + int y, m, d; + q->julianDayToDate(date.toJulianDay(), y, m, d); + + int firstWeekDayOffset = (dayOfWeek(date) - weekStartDay + daysInWeek()) % daysInWeek(); + int dayInYear = date.toJulianDay() - firstDayOfYear(y).toJulianDay(); // 0 indexed + int week = ((dayInYear - firstWeekDayOffset + daysInWeek()) / daysInWeek()); + + if (dayOfWeek(firstDayOfYear(y)) != weekStartDay) { + week = week + firstWeekNumber; + } + + if (week < 1) { + y = y - 1; + week = regularWeeksInYear(y, weekStartDay, firstWeekNumber); + } + + if (weekYear) { + *weekYear = y; + } + + return week; +} + +// Reimplement if special maths handling required, e.g. Hebrew. +int KCalendarSystemPrivate::simpleWeekNumber(const QDate &date, int *yearNum) const +{ + int y, m, d; + q->julianDayToDate(date.toJulianDay(), y, m, d); + if (yearNum) { + *yearNum = y; + } + return ((date.toJulianDay() - firstDayOfYear(y).toJulianDay()) / daysInWeek()) + 1; +} + +// Reimplement if special maths handling required, e.g. Hebrew. +int KCalendarSystemPrivate::weeksInYear(int year, KLocale::WeekNumberSystem weekNumberSystem) const +{ + switch (weekNumberSystem) { + case KLocale::IsoWeekNumber: + return isoWeeksInYear(year); + case KLocale::FirstFullWeek: + return regularWeeksInYear(year, locale()->weekStartDay(), 0); + case KLocale::FirstPartialWeek: + return regularWeeksInYear(year, locale()->weekStartDay(), 1); + case KLocale::SimpleWeek: + return simpleWeeksInYear(year); + case KLocale::DefaultWeekNumber: + default: + return weeksInYear(year, locale()->weekNumberSystem()); + } +} + +// Reimplement if special maths handling required, e.g. Hebrew. +int KCalendarSystemPrivate::isoWeeksInYear(int year) const +{ + QDate lastDayOfThisYear = lastDayOfYear(year); + + int weekYear = year; + int lastWeekInThisYear = isoWeekNumber(lastDayOfThisYear, &weekYear); + + // If error, or the last day of the year is in the first week of next year use the week before + if (lastWeekInThisYear < 1 || weekYear != year) { + lastWeekInThisYear = isoWeekNumber(q->addDays(lastDayOfThisYear, -7), &weekYear); + } + + return lastWeekInThisYear; +} + +// Reimplement if special maths handling required, e.g. Hebrew. +int KCalendarSystemPrivate::regularWeeksInYear(int year, int weekStartDay, int firstWeekNumber) const +{ + return regularWeekNumber(lastDayOfYear(year), weekStartDay, firstWeekNumber, 0); +} + +// Reimplement if special maths handling required, e.g. Hebrew. +int KCalendarSystemPrivate::simpleWeeksInYear(int year) const +{ + return simpleWeekNumber(lastDayOfYear(year), 0); +} + +// Reimplement if special maths handling required, e.g. Hebrew. +// Works for calendars with constant number of months, or where leap month is last month of year +// Will not work for Hebrew or others where leap month is inserted in middle of year +void KCalendarSystemPrivate::dateDifference(const QDate &fromDate, const QDate &toDate, + int *yearsDiff, int *monthsDiff, int *daysDiff, int *direction) const +{ + // This could be optimised a little but is left in full as it's easier to understand + int dy = 0; + int dm = 0; + int dd = 0; + int dir = 1; + + if (toDate < fromDate) { + dateDifference(toDate, fromDate, &dy, &dm, &dd, 0); + dir = -1; + } else if (toDate > fromDate) { + + int fromYear = q->year(fromDate); + int toYear = q->year(toDate); + int fromMonth = q->month(fromDate); + int toMonth = q->month(toDate); + int fromDay = q->day(fromDate); + int toDay = q->day(toDate); + + int monthsInPrevYear = monthsInYear(addYears(toYear, -1)); + int daysInPrevMonth = q->daysInMonth(q->addMonths(toDate, -1)); + int daysInFromMonth = daysInMonth(fromYear, fromMonth); + int daysInToMonth = daysInMonth(toYear, toMonth); + + // Calculate years difference + if (toYear == fromYear) { + dy = 0; + } else if (toMonth > fromMonth) { + dy = differenceYearNumbers(fromYear, toYear); + } else if (toMonth < fromMonth) { + dy = differenceYearNumbers(fromYear, toYear) - 1; + } else { // toMonth == fromMonth + // Allow for last day of month to last day of month and leap days + // e.g. 2000-02-29 to 2001-02-28 is 1 year not 0 years + if ((toDay >= fromDay) || (fromDay == daysInFromMonth && toDay == daysInToMonth)) { + dy = differenceYearNumbers(fromYear, toYear); + } else { + dy = differenceYearNumbers(fromYear, toYear) - 1; + } + } + + // Calculate months and days difference + if (toDay >= fromDay) { + dm = (monthsInPrevYear + toMonth - fromMonth) % monthsInPrevYear; + dd = toDay - fromDay; + } else { // toDay < fromDay + // Allow for last day of month to last day of month and leap days + // e.g. 2010-03-31 to 2010-04-30 is 1 month + // 2000-02-29 to 2001-02-28 is 1 year + // 2000-02-29 to 2001-03-01 is 1 year 1 day + int prevMonth = q->month(q->addMonths(toDate, -1)); + if (fromDay == daysInFromMonth && toDay == daysInToMonth) { + dm = (monthsInPrevYear + toMonth - fromMonth) % monthsInPrevYear; + dd = 0; + } else if (prevMonth == fromMonth && daysInPrevMonth < daysInFromMonth) { + // Special case where fromDate = leap day and toDate in month following but non-leap year + // e.g. 2000-02-29 to 2001-03-01 needs to use 29 to calculate day number not 28 + dm = (monthsInPrevYear + toMonth - fromMonth - 1) % monthsInPrevYear; + dd = (daysInFromMonth + toDay - fromDay) % daysInFromMonth; + } else { + dm = (monthsInPrevYear + toMonth - fromMonth - 1) % monthsInPrevYear; + dd = (daysInPrevMonth + toDay - fromDay) % daysInPrevMonth; + } + } + + } + + // Only return values if we have a valid pointer + if (yearsDiff) { + *yearsDiff = dy; + } + if (monthsDiff) { + *monthsDiff = dm; + } + if (daysDiff) { + *daysDiff = dd; + } + if (direction) { + *direction = dir; + } +} + +// Reimplement if special maths handling required, e.g. Hebrew +// Allows for calendars with leap months at end of year but not during year +int KCalendarSystemPrivate::yearsDifference(const QDate &fromDate, const QDate &toDate) const +{ + // This could be optimised a little but is left in full as it's easier to understand + // Alternatively could just call dateDifference(), but this is slightly more efficient + + if (toDate < fromDate) { + return 0 - yearsDifference(toDate, fromDate); + } + + if (toDate == fromDate) { + return 0; + } + + int fromYear = q->year(fromDate); + int toYear = q->year(toDate); + + if (toYear == fromYear) { + return 0; + } + + int fromMonth = q->month(fromDate); + int toMonth = q->month(toDate); + + if (toMonth > fromMonth) { + return differenceYearNumbers(fromYear, toYear); + } + + if (toMonth < fromMonth) { + return differenceYearNumbers(fromYear, toYear) - 1; + } + + // toMonth == fromMonth + int fromDay = q->day(fromDate); + int toDay = q->day(toDate); + + // Adjust for month numbers in from and to year + // Allow for last day of month to last day of month and leap days + // e.g. 2000-02-29 to 2001-02-28 is 1 year not 0 years + if ((toDay >= fromDay) || + (fromDay == daysInMonth(fromYear, fromMonth) && + toDay == daysInMonth(toYear, toMonth))) { + return differenceYearNumbers(fromYear, toYear); + } else { + return differenceYearNumbers(fromYear, toYear) - 1; + } + +} + +// Reimplement if special maths handling required, e.g. maybe Hebrew? +// Allows for calendars with leap months +int KCalendarSystemPrivate::monthsDifference(const QDate &fromDate, const QDate &toDate) const +{ + if (toDate < fromDate) { + return 0 - monthsDifference(toDate, fromDate); + } + + if (toDate == fromDate) { + return 0; + } + + int fromYear = q->year(fromDate); + int toYear = q->year(toDate); + int fromMonth = q->month(fromDate); + int toMonth = q->month(toDate); + int fromDay = q->day(fromDate); + int toDay = q->day(toDate); + + int monthsInPreceedingYears; + + // Calculate number of months in full years preceding toYear + if (toYear == fromYear) { + monthsInPreceedingYears = 0; + } else if (hasLeapMonths()) { + monthsInPreceedingYears = 0; + for (int y = fromYear; y < toYear; y = addYears(y, 1)) { + monthsInPreceedingYears = monthsInPreceedingYears + monthsInYear(y); + } + } else { + monthsInPreceedingYears = differenceYearNumbers(fromYear, toYear) * monthsInYear(toYear); + } + + // Adjust for months in from and to year + // Allow for last day of month to last day of month and leap days + // e.g. 2010-03-31 to 2010-04-30 is 1 month not 0 months + // also 2000-02-29 to 2001-02-28 is 12 months not 11 months + if ((toDay >= fromDay) || + (fromDay == daysInMonth(fromYear, fromMonth) && + toDay == daysInMonth(toYear, toMonth))) { + return monthsInPreceedingYears + toMonth - fromMonth; + } else { + return monthsInPreceedingYears + toMonth - fromMonth - 1; + } +} + +// Reimplement if special string to integer handling required, e.g. Hebrew. +// Peel a number off the front of a string which may have other trailing chars after the number +// Stop either at either maxLength, eos, or first non-digit char +int KCalendarSystemPrivate::integerFromString(const QString &string, int maxLength, int &readLength) const +{ + int value = -1; + int position = 0; + readLength = 0; + bool ok = false; + + if (maxLength < 0) { + maxLength = string.length(); + } + + while (position < string.length() && + position < maxLength && + string.at(position).isDigit()) { + position++; + } + + if (position > 0) { + value = string.left(position).toInt(&ok); + if (ok) { + readLength = position; + } else { + value = -1; + } + } + + return value; +} + +// Reimplement if special integer to string handling required, e.g. Hebrew. +// Utility to convert an integer into the correct display string form +QString KCalendarSystemPrivate::stringFromInteger(int number, int padWidth, QChar padChar) const +{ + return stringFromInteger(number, padWidth, padChar, q->locale()->dateTimeDigitSet()); +} + +// Reimplement if special integer to string handling required, e.g. Hebrew. +// Utility to convert an integer into the correct display string form +QString KCalendarSystemPrivate::stringFromInteger(int number, int padWidth, QChar padChar, KLocale::DigitSet digitSet) const +{ + if (padChar == QLatin1Char('\0') || padWidth == 0) { + return q->locale()->convertDigits(QString::number(number), digitSet); + } else { + return q->locale()->convertDigits(QString::number(number).rightJustified(padWidth, padChar), digitSet); + } +} + +// Allows us to set dates outside publically valid range, USE WITH CARE!!!! +bool KCalendarSystemPrivate::setAnyDate(QDate &date, int year, int month, int day) const +{ + int jd; + q->dateToJulianDay(year, month, day, jd); + date = QDate::fromJulianDay(jd); + return true; +} + +// Utility to correctly add years to a year number because some systems such as +// Julian and Gregorian calendars don't have a year 0 +int KCalendarSystemPrivate::addYears(int originalYear, int addYears) const +{ + int newYear = originalYear + addYears; + + if (!hasYearZero()) { + if (originalYear > 0 && newYear <= 0) { + newYear = newYear - 1; + } else if (originalYear < 0 && newYear >= 0) { + newYear = newYear + 1; + } + } + + return newYear; +} + +// Utility to correctly return number of years between two year numbers because some systems such as +// Julian and Gregorian calendars don't have a year 0 +int KCalendarSystemPrivate::differenceYearNumbers(int fromYear, int toYear) const +{ + int dy = toYear - fromYear; + + if (!hasYearZero()) { + if (toYear > 0 && fromYear < 0) { + dy = dy - 1; + } else if (toYear < 0 && fromYear > 0) { + dy = dy + 1; + } + } + + return dy; +} + +QDate KCalendarSystemPrivate::invalidDate() const +{ + //Is QDate's way of saying is invalid + return QDate(); +} + +QString KCalendarSystemPrivate::simpleDateString(const QString &str) const +{ + QString newStr; + for (int i = 0; i < str.length(); i++) { + if (str.at(i).isLetterOrNumber()) { + newStr.append(str.at(i)); + } else { + newStr.append(QLatin1Char(' ')); + } + } + newStr.simplified(); + return newStr; +} + +int KCalendarSystemPrivate::dayOfYear(const QDate &date) const +{ + int y, m, d, jdFirstDayOfYear; + q->julianDayToDate(date.toJulianDay(), y, m, d); + q->dateToJulianDay(y, 1, 1, jdFirstDayOfYear); + //Take the jd of the given date, and subtract the jd of the first day of that year + return (date.toJulianDay() - jdFirstDayOfYear + 1); +} + +int KCalendarSystemPrivate::dayOfWeek(const QDate &date) const +{ + // Makes assumption that Julian Day 0 was day 1 of week + // This is true for Julian/Gregorian calendar with jd 0 being Monday + // We add 1 for ISO compliant numbering for 7 day week + // Assumes we've never skipped weekdays + return ((date.toJulianDay() % daysInWeek()) + 1); +} + +QDate KCalendarSystemPrivate::firstDayOfYear(int year) const +{ + int jd; + q->dateToJulianDay(year, 1, 1, jd); + return QDate::fromJulianDay(jd); +} + +QDate KCalendarSystemPrivate::lastDayOfYear(int year) const +{ + int jd; + q->dateToJulianDay(year, 1, 1, jd); + jd = jd + daysInYear(year) - 1; + return QDate::fromJulianDay(jd); +} + +QDate KCalendarSystemPrivate::firstDayOfMonth(int year, int month) const +{ + int jd; + q->dateToJulianDay(year, month, 1, jd); + return QDate::fromJulianDay(jd); +} + +QDate KCalendarSystemPrivate::lastDayOfMonth(int year, int month) const +{ + int jd; + q->dateToJulianDay(year, month, 1, jd); + jd = jd + daysInMonth(year, month) - 1; + return QDate::fromJulianDay(jd); +} + +const KLocale * KCalendarSystemPrivate::locale() const +{ + if (m_locale) { + return m_locale; + } else { + return KGlobal::locale(); + } +} + +QList *KCalendarSystemPrivate::eraList() const +{ + return m_eraList; +} + +KCalendarEra KCalendarSystemPrivate::era(const QDate &eraDate) const +{ + for (int i = m_eraList->count() - 1; i >= 0; --i) { + if (m_eraList->at(i).isInEra(eraDate)) { + return m_eraList->at(i); + } + } + return KCalendarEra(); +} + +KCalendarEra KCalendarSystemPrivate::era(const QString &eraName, int yearInEra) const +{ + Q_UNUSED(yearInEra) + + for (int i = m_eraList->count() - 1; i >= 0; --i) { + KCalendarEra era = m_eraList->at(i); + if (era.name(KLocale::LongName).toLower() == eraName.toLower() || + era.name(KLocale::ShortName).toLower() == eraName.toLower()) { + return era; + } + } + return KCalendarEra(); +} + +void KCalendarSystemPrivate::loadEraList(const KConfigGroup & cg) +{ + delete m_eraList; + m_eraList = new QList; + QString eraKey = QString::fromLatin1("Era1"); + int i = 1; + while (cg.hasKey(eraKey)) { + QString eraEntry = cg.readEntry(eraKey, QString()); + if (!eraEntry.isEmpty()) { + // Based on LC_TIME, but different! + // Includes long and short names, uses ISO fomat dates + // e.g. +:1:0001-01-01:9999-12-31:Anno Domini:AD:%EC %Ey + QChar direction = eraEntry.section(QLatin1Char(':'), 0, 0).at(0); + QDate startDate, endDate; + int startYear; + QString buffer = eraEntry.section(QLatin1Char(':'), 2, 2); + if (buffer.isEmpty()) { + if (direction == QLatin1Char('-')) { + startDate = q->latestValidDate(); + } else { + startDate = q->earliestValidDate(); + } + } else { + startDate = q->readDate(buffer, KLocale::IsoFormat); + } + if (q->isValid(startDate)) { + startYear = q->year(startDate); + } else { + startYear = eraEntry.section(QLatin1Char(':'), 1, 1).toInt(); //Use offset + } + + buffer = eraEntry.section(QLatin1Char(':'), 3, 3); + if (buffer.isEmpty()) { + if (direction == QLatin1Char('-')) { + endDate = q->earliestValidDate(); + } else { + endDate = q->latestValidDate(); + } + } else { + endDate = q->readDate(buffer, KLocale::IsoFormat); + } + addEra(direction.toLatin1(), eraEntry.section(QLatin1Char(':'), 1, 1).toInt(), + startDate, startYear, endDate, eraEntry.section(QLatin1Char(':'), 4, 4), + eraEntry.section(QLatin1Char(':'), 5, 5), eraEntry.section(QLatin1Char(':'), 6)); + } + ++i; + eraKey = QString::fromLatin1("Era%1").arg(i); + } + + if (m_eraList->isEmpty()) { + loadDefaultEraList(); + } +} + +void KCalendarSystemPrivate::addEra(char direction, int offset, + const QDate &startDate, int startYear, const QDate &endDate, + const QString &name, const QString &shortName, + const QString &format) +{ + KCalendarEra newEra; + + newEra.m_sequence = m_eraList->count() + 1; + if (direction == '-') { + newEra.m_direction = -1; + } else { + newEra.m_direction = 1; + } + newEra.m_offset = offset; + newEra.m_startDate = startDate; + newEra.m_startYear = startYear; + newEra.m_endDate = endDate; + newEra.m_longName = name; + newEra.m_shortName = shortName; + newEra.m_format = format; + + m_eraList->append(newEra); +} + +int KCalendarSystemPrivate::shortYearWindowStartYear() const +{ + return m_shortYearWindowStartYear; +} + +int KCalendarSystemPrivate::applyShortYearWindow(int inputYear) const +{ + if (inputYear >= 0 && inputYear <= 99) { + int shortStartYear = m_shortYearWindowStartYear % 100; + int yearOffset = m_shortYearWindowStartYear - shortStartYear; + if (inputYear >= shortStartYear) { + return inputYear + yearOffset; + } else { + return inputYear + yearOffset + 100; + } + } else { + return inputYear; + } +} + +void KCalendarSystemPrivate::loadShortYearWindowStartYear(const KConfigGroup & cg) +{ + // Default to 2000 for backwards compatibility + // as that's the old readDate() default value + int startYear = 2000; + if (cg.exists()) { + startYear = cg.readEntry("ShortYearWindowStartYear", 2000); + } + m_shortYearWindowStartYear = startYear; +} + +KSharedConfig::Ptr KCalendarSystemPrivate::config() +{ + if (m_config == KSharedConfig::Ptr()) { + return KGlobal::config(); + } else { + return m_config; + } +} + +void KCalendarSystemPrivate::loadConfig(const QString & calendarType) +{ + KConfigGroup localeGroup(config(), QString::fromLatin1("Locale")); + KConfigGroup calendarGroup = localeGroup.group(QString::fromLatin1("KCalendarSystem %1").arg(calendarType)); + loadEraList(calendarGroup); + loadShortYearWindowStartYear(calendarGroup); +} + + +KCalendarSystem::KCalendarSystem(const KLocale *locale) + : d_ptr(new KCalendarSystemPrivate(this)) +{ + d_ptr->m_config = KSharedConfig::Ptr(); + d_ptr->m_locale = locale; +} + +KCalendarSystem::KCalendarSystem(const KSharedConfig::Ptr config, const KLocale *locale) + : d_ptr(new KCalendarSystemPrivate(this)) +{ + d_ptr->m_config = config; + d_ptr->m_locale = locale; +} + +KCalendarSystem::KCalendarSystem(KCalendarSystemPrivate &dd, const KSharedConfig::Ptr config, const KLocale *locale) + : d_ptr(&dd) +{ + d_ptr->m_config = config; + d_ptr->m_locale = locale; +} + +KCalendarSystem::~KCalendarSystem() +{ + delete d_ptr; +} + +// NOT VIRTUAL - If override needed use shared-d +KLocale::CalendarSystem KCalendarSystem::calendarSystem() const +{ + Q_D(const KCalendarSystem); + + return d->calendarSystem(); +} + +// NOT VIRTUAL - If override needed use shared-d +QString KCalendarSystem::calendarLabel() const +{ + return KCalendarSystem::calendarLabel(calendarSystem()); +} + +// Dummy version using Gregorian as an example +// This method MUST be re-implemented in any new Calendar System +QDate KCalendarSystem::epoch() const +{ + return QDate::fromJulianDay(38); +} + +QDate KCalendarSystem::earliestValidDate() const +{ + return epoch(); +} + +// Dummy version using Gregorian as an example +// This method MUST be re-implemented in any new Calendar System +QDate KCalendarSystem::latestValidDate() const +{ + // Default to Gregorian 9999-12-31 + return QDate::fromJulianDay(5373484); +} + +bool KCalendarSystem::isValid(int year, int month, int day) const +{ + Q_D(const KCalendarSystem); + + if (year < d->earliestValidYear() || year > d->latestValidYear() || + (!d->hasYearZero() && year == 0)) { + return false; + } + + if (month < 1 || month > d->monthsInYear(year)) { + return false; + } + + if (day < 1 || day > d->daysInMonth(year, month)) { + return false; + } + + return true; +} + +// NOT VIRTUAL - If override needed use shared-d +bool KCalendarSystem::isValid(int year, int dayOfYear) const +{ + Q_D(const KCalendarSystem); + + return (isValid(year, 1, 1) && dayOfYear > 0 && dayOfYear <= d->daysInYear(year)); +} + +// NOT VIRTUAL - If override needed use shared-d +bool KCalendarSystem::isValid(const QString &eraName, int yearInEra, int month, int day) const +{ + Q_D(const KCalendarSystem); + + KCalendarEra era = d->era(eraName, yearInEra); + return (era.isValid() && isValid(era.year(yearInEra), month, day)); +} + +// NOT VIRTUAL - If override needed use shared-d +bool KCalendarSystem::isValidIsoWeekDate(int year, int isoWeekNumber, int dayOfIsoWeek) const +{ + Q_D(const KCalendarSystem); + + //Tests Year value in standard YMD isValid() + if (!isValid(year, 1, 1)) { + return false; + } + + //Test Week Number falls in valid range for this year + int weeksInThisYear = weeksInYear(year); + if (isoWeekNumber < 1 || isoWeekNumber > weeksInThisYear) { + return false; + } + + //Test Day of Week Number falls in valid range + if (dayOfIsoWeek < 1 || dayOfIsoWeek > d->daysInWeek()) { + return false; + } + + //If not in earliest or latest years then all OK + //Otherwise need to check don't fall into previous or next year that would be invalid + if (year == d->earliestValidYear() && isoWeekNumber == 1) { + //If firstDayOfYear falls on or before Thursday then firstDayOfYear falls in week 1 this + //year and if wanted dayOfIsoWeek falls before firstDayOfYear then falls in previous year + //and so in invalid year + int dowFirstDay = dayOfWeek(d->firstDayOfYear(year)); + if (dowFirstDay <= 4 && dayOfIsoWeek < dowFirstDay) { + return false; + } + } else if (year == d->latestValidYear() && isoWeekNumber == weeksInThisYear) { + //If lastDayOfYear falls on or after Thursday then lastDayOfYear falls in last week this + //year and if wanted dayOfIsoWeek falls after lastDayOfYear then falls in next year + //and so in invalid year + int dowLastDay = dayOfWeek(d->lastDayOfYear(year)); + if (dowLastDay >= 4 && dayOfIsoWeek > dowLastDay) { + return false; + } + } + + return true; +} + +bool KCalendarSystem::isValid(const QDate &date) const +{ + if (date.isNull() || date < earliestValidDate() || date > latestValidDate()) { + return false; + } + return true; +} + +bool KCalendarSystem::setDate(QDate &date, int year, int month, int day) const +{ + Q_D(const KCalendarSystem); + + date = d->invalidDate(); + + if (isValid(year, month, day)) { + int jd; + dateToJulianDay(year, month, day, jd); + QDate calcDate = QDate::fromJulianDay(jd); + + if (isValid(calcDate)) { + date = calcDate; + return true; + } + } + + return false; +} + +// NOT VIRTUAL - If override needed use shared-d +bool KCalendarSystem::setDate(QDate &date, int year, int dayOfYear) const +{ + Q_D(const KCalendarSystem); + + date = d->invalidDate(); + + if (isValid(year, dayOfYear)) { + int jd; + dateToJulianDay(year, 1, 1, jd); + QDate calcDate = QDate::fromJulianDay(jd + dayOfYear - 1); + if (isValid(calcDate)) { + date = calcDate; + return true; + } + } + + return false; +} + +// NOT VIRTUAL - If override needed use shared-d +bool KCalendarSystem::setDate(QDate &date, QString eraName, int yearInEra, int month, int day) const +{ + Q_D(const KCalendarSystem); + + KCalendarEra era = d->era(eraName, yearInEra); + return (era.isValid() && setDate(date, era.year(yearInEra), month, day)); +} + +// NOT VIRTUAL - If override needed use shared-d +bool KCalendarSystem::setDateIsoWeek(QDate &date, int year, int isoWeekNumber, int dayOfIsoWeek) const +{ + Q_D(const KCalendarSystem); + + date = d->invalidDate(); + + if (isValidIsoWeekDate(year, isoWeekNumber, dayOfIsoWeek)) { + + QDate calcDate = d->firstDayOfYear(year); + int dowFirstDayOfYear = dayOfWeek(calcDate); + + int daysToAdd = (d->daysInWeek() * (isoWeekNumber - 1)) + dayOfIsoWeek; + + if (dowFirstDayOfYear <= 4) { + calcDate = calcDate.addDays(daysToAdd - dowFirstDayOfYear); + } else { + calcDate = calcDate.addDays(daysInWeek(calcDate) + daysToAdd - dowFirstDayOfYear); + } + + if (isValid(calcDate)) { + date = calcDate; + return true; + } + } + + return false; +} + +// Deprecated +bool KCalendarSystem::setYMD(QDate &date, int year, int month, int day) const +{ + return setDate(date, year, month, day); +} + +// NOT VIRTUAL - If override needed use shared-d +void KCalendarSystem::getDate(const QDate date, int *year, int *month, int *day) const +{ + int y, m, d; + + if (isValid(date)) { + julianDayToDate(date.toJulianDay(), y, m, d); + } else { + y = 0; // How do you denote invalid year when we support -ve years? + m = 0; + d = 0; + } + + if (year) { + *year = y; + } + if (month) { + *month = m; + } + if (day) { + *day = d; + } + +} + +int KCalendarSystem::year(const QDate &date) const +{ + if (isValid(date)) { + int year, month, day; + + julianDayToDate(date.toJulianDay(), year, month, day); + + return year; + } + + return 0; // How do you denote invalid year when we support -ve years? +} + +int KCalendarSystem::month(const QDate &date) const +{ + if (isValid(date)) { + int year, month, day; + + julianDayToDate(date.toJulianDay(), year, month, day); + + return month; + } + + return 0; +} + +int KCalendarSystem::day(const QDate &date) const +{ + if (isValid(date)) { + int year, month, day; + + julianDayToDate(date.toJulianDay(), year, month, day); + + return day; + } + + return 0; +} + +// NOT VIRTUAL - If override needed use shared-d +QString KCalendarSystem::eraName(const QDate &date, StringFormat format) const +{ + Q_D(const KCalendarSystem); + + if (isValid(date)) { + if (format == LongFormat) { + return d->era(date).name(KLocale::LongName); + } else { + return d->era(date).name(KLocale::ShortName); + } + } + + return QString(); +} + +// NOT VIRTUAL - If override needed use shared-d +QString KCalendarSystem::eraYear(const QDate &date, StringFormat format) const +{ + Q_UNUSED(format) + Q_D(const KCalendarSystem); + + if (isValid(date)) { + return formatDate(date, d->era(date).format()); + } + + return QString(); +} + +// NOT VIRTUAL - If override needed use shared-d +int KCalendarSystem::yearInEra(const QDate &date) const +{ + Q_D(const KCalendarSystem); + + if (isValid(date)) { + return d->era(date).yearInEra(year(date)); + } + + return -1; +} + +// NOT VIRTUAL - If override needed use shared-d +QList *KCalendarSystem::eraList() const +{ + Q_D(const KCalendarSystem); + + return d->eraList(); +} + +// NOT VIRTUAL - If override needed use shared-d +KCalendarEra KCalendarSystem::era(const QDate &eraDate) const +{ + Q_D(const KCalendarSystem); + + return d->era(eraDate); +} + +// NOT VIRTUAL - If override needed use shared-d +KCalendarEra KCalendarSystem::era(const QString &eraName, int yearInEra) const +{ + Q_D(const KCalendarSystem); + + return d->era(eraName, yearInEra); +} + +QDate KCalendarSystem::addYears(const QDate &date, int numYears) const +{ + Q_D(const KCalendarSystem); + + if (isValid(date)) { + + int originalYear, originalMonth, originalDay; + julianDayToDate(date.toJulianDay(), originalYear, originalMonth, originalDay); + + int newYear = d->addYears(originalYear, numYears); + int newMonth = originalMonth; + int newDay = originalDay; + + //Adjust day number if new month has fewer days than old month + int daysInNewMonth = d->daysInMonth(newYear, newMonth); + if (daysInNewMonth < originalDay) { + newDay = daysInNewMonth; + } + + QDate newDate; + setDate(newDate, newYear, newMonth, newDay); + return newDate; + + } + + return d->invalidDate(); +} + +QDate KCalendarSystem::addMonths(const QDate &date, int numMonths) const +{ + Q_D(const KCalendarSystem); + + if (isValid(date)) { + + int originalYear, originalMonth, originalDay; + julianDayToDate(date.toJulianDay(), originalYear, originalMonth, originalDay); + + int monthsInOriginalYear = d->monthsInYear(originalYear); + + int newYear = d->addYears(originalYear, (originalMonth + numMonths) / monthsInOriginalYear); + int newMonth = (originalMonth + numMonths) % monthsInOriginalYear; + int newDay = originalDay; + + if (newMonth == 0) { + newYear = d->addYears(newYear, - 1); + newMonth = monthsInOriginalYear; + } + if (newMonth < 0) { + newYear = d->addYears(newYear, - 1); + newMonth = newMonth + monthsInOriginalYear; + } + + //Adjust day number if new month has fewer days than old month + int daysInNewMonth = d->daysInMonth(newYear, newMonth); + if (daysInNewMonth < originalDay) { + newDay = daysInNewMonth; + } + + QDate newDate; + setDate(newDate, newYear, newMonth, newDay); + return newDate; + + } + + return d->invalidDate(); +} + +QDate KCalendarSystem::addDays(const QDate &date, int numDays) const +{ + Q_D(const KCalendarSystem); + + // QDate only holds a uint and has no boundary checking in addDays(), so we need to check + if (isValid(date) && (long) date.toJulianDay() + (long) numDays > 0) { + // QDate adds straight to jd + QDate temp = date.addDays(numDays); + if (isValid(temp)) { + return temp; + } + } + + return d->invalidDate(); +} + +// NOT VIRTUAL - Uses shared-d instead +void KCalendarSystem::dateDifference(const QDate &fromDate, const QDate &toDate, + int *yearsDiff, int *monthsDiff, int *daysDiff, int *direction) const +{ + Q_D(const KCalendarSystem); + + if (isValid(fromDate) && isValid(toDate)) { + d->dateDifference(fromDate, toDate, yearsDiff, monthsDiff, daysDiff, direction); + } +} + +// NOT VIRTUAL - Uses shared-d instead +int KCalendarSystem::yearsDifference(const QDate &fromDate, const QDate &toDate) const +{ + Q_D(const KCalendarSystem); + + if (isValid(fromDate) && isValid(toDate)) { + return d->yearsDifference(fromDate, toDate); + } + + return 0; +} + +// NOT VIRTUAL - Uses shared-d instead +int KCalendarSystem::monthsDifference(const QDate &fromDate, const QDate &toDate) const +{ + Q_D(const KCalendarSystem); + + if (isValid(fromDate) && isValid(toDate)) { + return d->monthsDifference(fromDate, toDate); + } + + return 0; +} + +// NOT VIRTUAL - Uses shared-d instead +int KCalendarSystem::daysDifference(const QDate &fromDate, const QDate &toDate) const +{ + if (isValid(fromDate) && isValid(toDate)) { + return toDate.toJulianDay() - fromDate.toJulianDay(); + } + + return 0; +} + +int KCalendarSystem::monthsInYear(const QDate &date) const +{ + Q_D(const KCalendarSystem); + + if (isValid(date)) { + return d->monthsInYear(year(date)); + } + + return -1; +} + +// NOT VIRTUAL - Uses shared-d instead +int KCalendarSystem::monthsInYear(int year) const +{ + Q_D(const KCalendarSystem); + + if (isValid(year, 1, 1)) { + return d->monthsInYear(year); + } + + return -1; +} + +int KCalendarSystem::weeksInYear(const QDate &date) const +{ + return weeksInYear(date, KLocale::DefaultWeekNumber); +} + +int KCalendarSystem::weeksInYear(int year) const +{ + return weeksInYear(year, KLocale::DefaultWeekNumber); +} + +// NOT VIRTUAL - Uses shared-d instead +int KCalendarSystem::weeksInYear(const QDate &date, KLocale::WeekNumberSystem weekNumberSystem) const +{ + Q_D(const KCalendarSystem); + + if (isValid(date)) { + return d->weeksInYear(year(date), weekNumberSystem); + } + + return -1; +} + +// NOT VIRTUAL - Uses shared-d instead +int KCalendarSystem::weeksInYear(int year, KLocale::WeekNumberSystem weekNumberSystem) const +{ + Q_D(const KCalendarSystem); + + if (isValid(year, 1, 1)) { + return d->weeksInYear(year, weekNumberSystem); + } + + return -1; +} + +int KCalendarSystem::daysInYear(const QDate &date) const +{ + Q_D(const KCalendarSystem); + + if (isValid(date)) { + return d->daysInYear(year(date)); + } + + return -1; +} + +// NOT VIRTUAL - Uses shared-d instead +int KCalendarSystem::daysInYear(int year) const +{ + Q_D(const KCalendarSystem); + + if (isValid(year, 1, 1)) { + return d->daysInYear(year); + } + + return -1; +} + +int KCalendarSystem::daysInMonth(const QDate &date) const +{ + Q_D(const KCalendarSystem); + + if (isValid(date)) { + int year, month; + getDate(date, &year, &month, 0); + return d->daysInMonth(year, month); + } + + return -1; +} + +// NOT VIRTUAL - Uses shared-d instead +int KCalendarSystem::daysInMonth(int year, int month) const +{ + Q_D(const KCalendarSystem); + + if (isValid(year, 1, 1)) { + return d->daysInMonth(year, month); + } + + return -1; +} + +int KCalendarSystem::daysInWeek(const QDate &date) const +{ + Q_UNUSED(date) + Q_D(const KCalendarSystem); + return d->daysInWeek(); +} + +int KCalendarSystem::dayOfYear(const QDate &date) const +{ + Q_D(const KCalendarSystem); + + if (isValid(date)) { + return d->dayOfYear(date); + } + + return -1; +} + +int KCalendarSystem::dayOfWeek(const QDate &date) const +{ + Q_D(const KCalendarSystem); + + if (isValid(date)) { + return d->dayOfWeek(date); + } + + return -1; +} + +int KCalendarSystem::weekNumber(const QDate &date, int *yearNum) const +{ + return week(date, KLocale::IsoWeekNumber, yearNum); +} + +// NOT VIRTUAL - Uses shared-d instead +int KCalendarSystem::week(const QDate &date, int *yearNum) const +{ + return week(date, KLocale::DefaultWeekNumber, yearNum); +} + +// NOT VIRTUAL - Uses shared-d instead +int KCalendarSystem::week(const QDate &date, KLocale::WeekNumberSystem weekNumberSystem, int *yearNum) const +{ + Q_D(const KCalendarSystem); + + if (isValid(date)) { + return d->week(date, weekNumberSystem, yearNum); + } + + return -1; +} + +bool KCalendarSystem::isLeapYear(int year) const +{ + Q_D(const KCalendarSystem); + + if (isValid(year, 1, 1)) { + return d->isLeapYear(year); + } + + return false; +} + +bool KCalendarSystem::isLeapYear(const QDate &date) const +{ + Q_D(const KCalendarSystem); + + if (isValid(date)) { + return d->isLeapYear(year(date)); + } + + return false; +} + +// NOT VIRTUAL - If override needed use shared-d +QDate KCalendarSystem::firstDayOfYear(int year) const +{ + Q_D(const KCalendarSystem); + + if (isValid(year, 1, 1)) { + return d->firstDayOfYear(year); + } + + return QDate(); +} + +// NOT VIRTUAL - If override needed use shared-d +QDate KCalendarSystem::lastDayOfYear(int year) const +{ + Q_D(const KCalendarSystem); + + if (isValid(year, 1, 1)) { + return d->lastDayOfYear(year); + } + + return QDate(); +} + +// NOT VIRTUAL - If override needed use shared-d +QDate KCalendarSystem::firstDayOfYear(const QDate &date) const +{ + Q_D(const KCalendarSystem); + + if (isValid(date)) { + return d->firstDayOfYear(year(date)); + } + + return QDate(); +} + +// NOT VIRTUAL - If override needed use shared-d +QDate KCalendarSystem::lastDayOfYear(const QDate &date) const +{ + Q_D(const KCalendarSystem); + + if (isValid(date)) { + return d->lastDayOfYear(year(date)); + } + + return QDate(); +} + +// NOT VIRTUAL - If override needed use shared-d +QDate KCalendarSystem::firstDayOfMonth(int year, int month) const +{ + Q_D(const KCalendarSystem); + + if (isValid(year, month, 1)) { + return d->firstDayOfMonth(year, month); + } + + return QDate(); +} + +// NOT VIRTUAL - If override needed use shared-d +QDate KCalendarSystem::lastDayOfMonth(int year, int month) const +{ + Q_D(const KCalendarSystem); + + if (isValid(year, month, 1)) { + return d->lastDayOfMonth(year, month); + } + + return QDate(); +} + +// NOT VIRTUAL - If override needed use shared-d +QDate KCalendarSystem::firstDayOfMonth(const QDate &date) const +{ + Q_D(const KCalendarSystem); + + if (isValid(date)) { + int year, month; + getDate(date, &year, &month, 0); + return d->firstDayOfMonth(year, month); + } + + return QDate(); +} + +// NOT VIRTUAL - If override needed use shared-d +QDate KCalendarSystem::lastDayOfMonth(const QDate &date) const +{ + Q_D(const KCalendarSystem); + + if (isValid(date)) { + int year, month; + getDate(date, &year, &month, 0); + return d->lastDayOfMonth(year, month); + } + + return QDate(); +} + +QString KCalendarSystem::monthName(int month, int year, KCalendarSystem::MonthNameFormat format) const +{ + Q_D(const KCalendarSystem); + + if (!isValid(year, month, 1)) { + return QString(); + } + + if (format == KCalendarSystem::NarrowName) { + return d->monthName(month, year, KLocale::NarrowName, false); + } + + if (format == KCalendarSystem::ShortNamePossessive) { + return d->monthName(month, year, KLocale::ShortName, true); + } + + if (format == KCalendarSystem::ShortName) { + return d->monthName(month, year, KLocale::ShortName, false); + } + + if (format == KCalendarSystem::LongNamePossessive) { + return d->monthName(month, year, KLocale::LongName, true); + } + + // KCalendarSystem::LongName or any other + return d->monthName(month, year, KLocale::LongName, false); +} + +QString KCalendarSystem::monthName(const QDate &date, MonthNameFormat format) const +{ + if (isValid(date)) { + int year, month; + getDate(date, &year, &month, 0); + return monthName(month, year, format); + } + + return QString(); +} + +QString KCalendarSystem::weekDayName(int weekDay, KCalendarSystem::WeekDayNameFormat format) const +{ + Q_D(const KCalendarSystem); + + if (weekDay < 1 || weekDay > d->daysInWeek()) { + return QString(); + } + + if (format == KCalendarSystem::NarrowDayName) { + return d->weekDayName(weekDay, KLocale::NarrowName); + } + + if (format == KCalendarSystem::ShortDayName) { + return d->weekDayName(weekDay, KLocale::ShortName); + } + + if (format == KCalendarSystem::ShortDayName) { + return d->weekDayName(weekDay, KLocale::ShortName); + } + + return d->weekDayName(weekDay, KLocale::LongName); +} + +QString KCalendarSystem::weekDayName(const QDate &date, WeekDayNameFormat format) const +{ + if (isValid(date)) { + return weekDayName(dayOfWeek(date), format); + } + + return QString(); +} + +QString KCalendarSystem::yearString(const QDate &date, StringFormat format) const +{ + if (format == ShortFormat) { + return formatDate(date, KLocale::Year, KLocale::ShortNumber); + } else { + return formatDate(date, KLocale::Year, KLocale::LongNumber); + } +} + +QString KCalendarSystem::monthString(const QDate &date, StringFormat format) const +{ + if (format == ShortFormat) { + return formatDate(date, KLocale::Month, KLocale::ShortNumber); + } else { + return formatDate(date, KLocale::Month, KLocale::LongNumber); + } +} + +QString KCalendarSystem::dayString(const QDate &date, StringFormat format) const +{ + if (format == ShortFormat) { + return formatDate(date, KLocale::Day, KLocale::ShortNumber); + } else { + return formatDate(date, KLocale::Day, KLocale::LongNumber); + } +} + +// NOT VIRTUAL - If override needed use shared-d +QString KCalendarSystem::yearInEraString(const QDate &date, StringFormat format) const +{ + if (format == ShortFormat) { + return formatDate(date, KLocale::YearInEra, KLocale::ShortNumber); + } else { + return formatDate(date, KLocale::YearInEra, KLocale::LongNumber); + } +} + +// NOT VIRTUAL - If override needed use shared-d +QString KCalendarSystem::dayOfYearString(const QDate &date, StringFormat format) const +{ + if (format == ShortFormat) { + return formatDate(date, KLocale::DayOfYear, KLocale::ShortNumber); + } else { + return formatDate(date, KLocale::DayOfYear, KLocale::LongNumber); + } +} + +// NOT VIRTUAL - If override needed use shared-d +QString KCalendarSystem::dayOfWeekString(const QDate &date) const +{ + return formatDate(date, KLocale::DayOfWeek, KLocale::ShortNumber); +} + +// NOT VIRTUAL - If override needed use shared-d +QString KCalendarSystem::weekNumberString(const QDate &date, StringFormat format) const +{ + if (format == ShortFormat) { + return formatDate(date, KLocale::Week, KLocale::ShortNumber); + } else { + return formatDate(date, KLocale::Week, KLocale::LongNumber); + } +} + +// NOT VIRTUAL - If override needed use shared-d +QString KCalendarSystem::monthsInYearString(const QDate &date, StringFormat format) const +{ + if (format == ShortFormat) { + return formatDate(date, KLocale::MonthsInYear, KLocale::ShortNumber); + } else { + return formatDate(date, KLocale::MonthsInYear, KLocale::LongNumber); + } +} + +// NOT VIRTUAL - If override needed use shared-d +QString KCalendarSystem::weeksInYearString(const QDate &date, StringFormat format) const +{ + if (format == ShortFormat) { + return formatDate(date, KLocale::WeeksInYear, KLocale::ShortNumber); + } else { + return formatDate(date, KLocale::WeeksInYear, KLocale::LongNumber); + } +} + +// NOT VIRTUAL - If override needed use shared-d +QString KCalendarSystem::daysInYearString(const QDate &date, StringFormat format) const +{ + if (format == ShortFormat) { + return formatDate(date, KLocale::DaysInYear, KLocale::ShortNumber); + } else { + return formatDate(date, KLocale::DaysInYear, KLocale::LongNumber); + } +} + +// NOT VIRTUAL - If override needed use shared-d +QString KCalendarSystem::daysInMonthString(const QDate &date, StringFormat format) const +{ + if (format == ShortFormat) { + return formatDate(date, KLocale::DaysInMonth, KLocale::ShortNumber); + } else { + return formatDate(date, KLocale::DaysInMonth, KLocale::LongNumber); + } +} + +// NOT VIRTUAL - If override needed use shared-d +QString KCalendarSystem::daysInWeekString(const QDate &date) const +{ + return formatDate(date, KLocale::DaysInWeek, KLocale::ShortNumber); +} + +int KCalendarSystem::yearStringToInteger(const QString &yearString, int &readLength) const +{ + Q_D(const KCalendarSystem); + + QString minus = i18nc("Negative symbol as used for year numbers, e.g. -5 = 5 BC", "-"); + if (yearString.startsWith(minus)) { + int value = d->integerFromString(yearString.mid(minus.length()), 4, readLength); + if (readLength > 0 && value >= 0) { + readLength = readLength + minus.length(); + return value * -1; + } else { + return value; + } + } + + return d->integerFromString(yearString, 4, readLength); +} + +int KCalendarSystem::monthStringToInteger(const QString &monthString, int &readLength) const +{ + Q_D(const KCalendarSystem); + return d->integerFromString(monthString, 2, readLength); +} + +int KCalendarSystem::dayStringToInteger(const QString &dayString, int &readLength) const +{ + Q_D(const KCalendarSystem); + return d->integerFromString(dayString, 2, readLength); +} + +QString KCalendarSystem::formatDate(const QDate &fromDate, KLocale::DateFormat toFormat) const +{ + if (!fromDate.isValid()) { + return QString(); + } + + if (toFormat == KLocale::FancyShortDate || toFormat == KLocale::FancyLongDate) { + QDate now = KDateTime::currentLocalDate(); + int daysToNow = fromDate.daysTo(now); + switch (daysToNow) { + case 0: + return i18n("Today"); + case 1: + return i18n("Yesterday"); + case 2: + case 3: + case 4: + case 5: + case 6: + return weekDayName(fromDate); + default: + break; + } + } + + switch (toFormat) { + case KLocale::LongDate: + case KLocale::FancyLongDate: + return formatDate(fromDate, locale()->dateFormat()); + case KLocale::IsoDate: + return formatDate(fromDate, QLatin1String("%Y-%m-%d")); + case KLocale::IsoWeekDate: + return formatDate(fromDate, QLatin1String("%Y-W%V-%u")); + case KLocale::IsoOrdinalDate: + return formatDate(fromDate, QLatin1String("%Y-%j")); + case KLocale::ShortDate: + case KLocale::FancyShortDate: + default: + return formatDate(fromDate, locale()->dateFormatShort()); + } + +} + +// NOT VIRTUAL - If override needed use shared-d +QString KCalendarSystem::formatDate(const QDate &fromDate, const QString &toFormat, + KLocale::DateTimeFormatStandard standard) const +{ + return formatDate(fromDate, toFormat, locale()->dateTimeDigitSet(), standard); +} + +// NOT VIRTUAL - If override needed use shared-d +QString KCalendarSystem::formatDate(const QDate &fromDate, const QString &toFormat, KLocale::DigitSet digitSet, + KLocale::DateTimeFormatStandard formatStandard) const +{ + if (!isValid(fromDate) || toFormat.isEmpty()) { + return QString(); + } + + KDateTimeFormatter formatter; + return formatter.formatDate(fromDate, toFormat, this, locale(), digitSet, formatStandard); +} + +// NOT VIRTUAL - If override needed use shared-d +QString KCalendarSystem::formatDate(const QDate &date, KLocale::DateTimeComponent component, + KLocale::DateTimeComponentFormat format, + KLocale::WeekNumberSystem weekNumberSystem) const +{ + Q_D(const KCalendarSystem); + + switch (component) { + case KLocale::Year: + case KLocale::YearName: + switch (format) { + case KLocale::ShortName: + case KLocale::NarrowName: + case KLocale::ShortNumber: + return formatDate(date, QLatin1String("%y")); + case KLocale::LongNumber: + case KLocale::LongName: + case KLocale::DefaultComponentFormat: + default: + return formatDate(date, QLatin1String("%Y")); + } + case KLocale::Month: + switch (format) { + case KLocale::LongName: + return monthName(date, KCalendarSystem::LongName); + case KLocale::ShortName: + return monthName(date, KCalendarSystem::ShortName); + case KLocale::NarrowName: + return monthName(date, KCalendarSystem::NarrowName); + case KLocale::LongNumber: + return formatDate(date, QLatin1String("%m")); + case KLocale::ShortNumber: + case KLocale::DefaultComponentFormat: + default: + return formatDate(date, QLatin1String("%n")); + } + case KLocale::MonthName: + switch (format) { + case KLocale::NarrowName: + return monthName(date, KCalendarSystem::NarrowName); + case KLocale::ShortName: + case KLocale::ShortNumber: + return monthName(date, KCalendarSystem::ShortName); + case KLocale::LongName: + case KLocale::LongNumber: + case KLocale::DefaultComponentFormat: + default: + return monthName(date, KCalendarSystem::LongName); + } + case KLocale::Day: + case KLocale::DayName: + switch (format) { + case KLocale::LongNumber: + case KLocale::LongName: + return formatDate(date, QLatin1String("%d")); + case KLocale::ShortName: + case KLocale::NarrowName: + case KLocale::ShortNumber: + case KLocale::DefaultComponentFormat: + default: + return formatDate(date, QLatin1String("%e")); + } + case KLocale::JulianDay: + return d->stringFromInteger(date.toJulianDay(), 0); + case KLocale::EraName: + switch (format) { + case KLocale::LongNumber: + case KLocale::LongName: + return eraName(date, KCalendarSystem::LongFormat); + case KLocale::ShortName: + case KLocale::NarrowName: + case KLocale::ShortNumber: + case KLocale::DefaultComponentFormat: + default: + return eraName(date, KCalendarSystem::ShortFormat); + } + case KLocale::EraYear: + switch (format) { + case KLocale::LongNumber: + case KLocale::LongName: + return eraYear(date, KCalendarSystem::LongFormat); + case KLocale::ShortName: + case KLocale::NarrowName: + case KLocale::ShortNumber: + case KLocale::DefaultComponentFormat: + default: + return eraYear(date, KCalendarSystem::ShortFormat); + } + case KLocale::YearInEra: + switch (format) { + case KLocale::LongNumber: + case KLocale::LongName: + return formatDate(date, QLatin1String("%4Ey")); + case KLocale::ShortName: + case KLocale::NarrowName: + case KLocale::ShortNumber: + case KLocale::DefaultComponentFormat: + default: + return formatDate(date, QLatin1String("%Ey")); + } + case KLocale::DayOfYear: + case KLocale::DayOfYearName: + switch (format) { + case KLocale::LongNumber: + case KLocale::LongName: + return formatDate(date, QLatin1String("%j")); + case KLocale::ShortName: + case KLocale::NarrowName: + case KLocale::ShortNumber: + case KLocale::DefaultComponentFormat: + default: + return formatDate(date, QLatin1String("%-j")); + } + case KLocale::DayOfWeek: + switch (format) { + case KLocale::LongName: + return weekDayName(date, KCalendarSystem::LongDayName); + case KLocale::ShortName: + return weekDayName(date, KCalendarSystem::ShortDayName); + case KLocale::NarrowName: + return weekDayName(date, KCalendarSystem::NarrowDayName); + case KLocale::LongNumber: + case KLocale::ShortNumber: + case KLocale::DefaultComponentFormat: + default: + return formatDate(date, QLatin1String("%-u")); + } + case KLocale::DayOfWeekName: + switch (format) { + case KLocale::NarrowName: + return weekDayName(date, KCalendarSystem::NarrowDayName); + case KLocale::ShortName: + case KLocale::ShortNumber: + return weekDayName(date, KCalendarSystem::ShortDayName); + case KLocale::LongName: + case KLocale::LongNumber: + case KLocale::DefaultComponentFormat: + default: + return weekDayName(date, KCalendarSystem::LongDayName); + } + case KLocale::Week: + switch (format) { + case KLocale::LongNumber: + case KLocale::LongName: + return d->stringFromInteger(week(date, weekNumberSystem, 0), 2, QLatin1Char('0')); + case KLocale::ShortName: + case KLocale::NarrowName: + case KLocale::ShortNumber: + case KLocale::DefaultComponentFormat: + default: + return d->stringFromInteger(week(date, weekNumberSystem, 0), 0, QLatin1Char('0')); + } + case KLocale::WeekYear: { + int weekYear; + QDate yearDate; + week(date, weekNumberSystem, &weekYear); + setDate(yearDate, weekYear, 1, 1); + return formatDate(yearDate, KLocale::Year, format); + } + case KLocale::MonthsInYear: + switch (format) { + case KLocale::LongNumber: + case KLocale::LongName: + return d->stringFromInteger(monthsInYear(date), 2, QLatin1Char('0')); + case KLocale::ShortName: + case KLocale::NarrowName: + case KLocale::ShortNumber: + case KLocale::DefaultComponentFormat: + default: + return d->stringFromInteger(monthsInYear(date), 0, QLatin1Char('0')); + } + case KLocale::WeeksInYear: + switch (format) { + case KLocale::LongNumber: + case KLocale::LongName: + return d->stringFromInteger(weeksInYear(date), 2, QLatin1Char('0')); + case KLocale::ShortName: + case KLocale::NarrowName: + case KLocale::ShortNumber: + case KLocale::DefaultComponentFormat: + default: + return d->stringFromInteger(weeksInYear(date), 0, QLatin1Char('0')); + } + case KLocale::DaysInYear: + switch (format) { + case KLocale::LongNumber: + case KLocale::LongName: + return d->stringFromInteger(daysInYear(date), 3, QLatin1Char('0')); + case KLocale::ShortName: + case KLocale::NarrowName: + case KLocale::ShortNumber: + case KLocale::DefaultComponentFormat: + default: + return d->stringFromInteger(daysInYear(date), 0, QLatin1Char('0')); + } + case KLocale::DaysInMonth: + switch (format) { + case KLocale::LongNumber: + case KLocale::LongName: + return d->stringFromInteger(daysInMonth(date), 2, QLatin1Char('0')); + case KLocale::ShortName: + case KLocale::NarrowName: + case KLocale::ShortNumber: + case KLocale::DefaultComponentFormat: + default: + return d->stringFromInteger(daysInMonth(date), 0, QLatin1Char('0')); + } + case KLocale::DaysInWeek: + switch (format) { + case KLocale::LongNumber: + case KLocale::LongName: + case KLocale::ShortName: + case KLocale::NarrowName: + case KLocale::ShortNumber: + case KLocale::DefaultComponentFormat: + default: + return d->stringFromInteger(d->daysInWeek(), 0); + } + default: + return QString(); + } +} + +QDate KCalendarSystem::readDate(const QString &str, bool *ok) const +{ + //Try each standard format in turn, start with the locale ones, + //then the well defined standards + QDate date = readDate(str, KLocale::ShortFormat, ok); + if (!isValid(date)) { + date = readDate(str, KLocale::NormalFormat, ok); + if (!isValid(date)) { + date = readDate(str, KLocale::IsoFormat, ok); + if (!isValid(date)) { + date = readDate(str, KLocale::IsoWeekFormat, ok); + if (!isValid(date)) { + date = readDate(str, KLocale::IsoOrdinalFormat, ok); + } + } + } + } + + return date; +} + +QDate KCalendarSystem::readDate(const QString &str, KLocale::ReadDateFlags flags, bool *ok) const +{ + Q_D(const KCalendarSystem); + + if (flags & KLocale::ShortFormat) { + return readDate(str, locale()->dateFormatShort(), ok); + } else if (flags & KLocale::NormalFormat) { + return readDate(str, locale()->dateFormat(), ok); + } else if (flags & KLocale::IsoFormat) { + return readDate(str, QLatin1String("%Y-%m-%d"), ok); + } else if (flags & KLocale::IsoWeekFormat) { + return readDate(str, QLatin1String("%Y-W%V-%u"), ok); + } else if (flags & KLocale::IsoOrdinalFormat) { + return readDate(str, QLatin1String("%Y-%j"), ok); + } + return d->invalidDate(); +} + +QDate KCalendarSystem::readDate(const QString &inputString, const QString &formatString, bool *ok) const +{ + return readDate(inputString, formatString, ok, KLocale::KdeFormat); +} + +// NOT VIRTUAL - If override needed use shared-d +QDate KCalendarSystem::readDate(const QString &inputString, const QString &formatString, bool *ok, + KLocale::DateTimeFormatStandard formatStandard) const +{ + KDateTimeParser parser; + QDate resultDate = parser.parseDate(inputString, formatString, this, locale(), locale()->dateTimeDigitSet(), formatStandard); + if (ok) { + *ok = resultDate.isValid(); + } + return resultDate; +} + +// NOT VIRTUAL - If override needed use shared-d +int KCalendarSystem::shortYearWindowStartYear() const +{ + Q_D(const KCalendarSystem); + + return d->shortYearWindowStartYear(); +} + +// NOT VIRTUAL - If override needed use shared-d +int KCalendarSystem::applyShortYearWindow(int inputYear) const +{ + Q_D(const KCalendarSystem); + + return d->applyShortYearWindow(inputYear); +} + +int KCalendarSystem::weekStartDay() const +{ + return locale()->weekStartDay(); +} + +// Dummy version using Gregorian as an example +// This method MUST be re-implemented in any new Calendar System +// The implementation MUST NOT do validity checking on date ranges, all calls to this function MUST +// instead be wrapped in validity checks, as sometimes we want this to work outside the public valid +// range, i.e. to allow us to internally set dates of 1/1/10000 which are not publically valid but +// are required for internal maths +bool KCalendarSystem::julianDayToDate(int jd, int &year, int &month, int &day) const +{ + // Formula from The Calendar FAQ by Claus Tondering + // http://www.tondering.dk/claus/cal/node3.html#SECTION003161000000000000000 + // NOTE: Coded from scratch from mathematical formulas, not copied from + // the Boost licensed source code + + int a = jd + 32044; + int b = ((4 * a) + 3) / 146097; + int c = a - ((146097 * b) / 4); + int d = ((4 * c) + 3) / 1461; + int e = c - ((1461 * d) / 4); + int m = ((5 * e) + 2) / 153; + day = e - (((153 * m) + 2) / 5) + 1; + month = m + 3 - (12 * (m / 10)); + year = (100 * b) + d - 4800 + (m / 10); + + // If year is -ve then is BC. In Gregorian there is no year 0, but the maths + // is easier if we pretend there is, so internally year of 0 = 1BC = -1 outside + if (year < 1) { + year = year - 1; + } + + return true; +} + +// Dummy version using Gregorian as an example +// This method MUST be re-implemented in any new Calendar System +// The implementation MUST NOT do validity checking on date ranges, all calls to this function MUST +// instead be wrapped in validity checks, as sometimes we want this to work outside the public valid +// range, i.e. to allow us to internally set dates of 1/1/10000 which are not publically valid but +// are required for internal maths +bool KCalendarSystem::dateToJulianDay(int year, int month, int day, int &jd) const +{ + // Formula from The Calendar FAQ by Claus Tondering + // http://www.tondering.dk/claus/cal/node3.html#SECTION003161000000000000000 + // NOTE: Coded from scratch from mathematical formulas, not copied from + // the Boost licensed source code + + // If year is -ve then is BC. In Gregorian there is no year 0, but the maths + // is easier if we pretend there is, so internally year of -1 = 1BC = 0 internally + int y; + if (year < 1) { + y = year + 1; + } else { + y = year; + } + + int a = (14 - month) / 12; + y = y + 4800 - a; + int m = month + (12 * a) - 3; + + jd = day + + (((153 * m) + 2) / 5) + + (365 * y) + + (y / 4) + - (y / 100) + + (y / 400) + - 32045; + + return true; +} + +const KLocale * KCalendarSystem::locale() const +{ + Q_D(const KCalendarSystem); + + return d->locale(); +} + +// Deprecated +void KCalendarSystem::setMaxMonthsInYear(int maxMonths) +{ + Q_UNUSED(maxMonths) +} + +// Deprecated +void KCalendarSystem::setMaxDaysInWeek(int maxDays) +{ + Q_UNUSED(maxDays) +} + +// Deprecated +void KCalendarSystem::setHasYear0(bool hasYear0) +{ + Q_UNUSED(hasYear0) +} diff --git a/declarativeimports/locale/calendarsystem.h b/declarativeimports/locale/calendarsystem.h new file mode 100644 index 000000000..2f96a1cbb --- /dev/null +++ b/declarativeimports/locale/calendarsystem.h @@ -0,0 +1,1324 @@ +/* + Copyright (c) 2002 Carlos Moro + Copyright (c) 2002-2003 Hans Petter Bieker + Copyright 2007, 2009, 2010 John Layt + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef KCALENDARSYSTEM_H +#define KCALENDARSYSTEM_H + +#include +#include "klocale.h" // needed for enums +#include "kglobal.h" + +#include +#include + +class KCalendarSystemPrivate; +class KCalendarEra; + +/** + * KCalendarSystem abstract base class, provides support for local Calendar Systems in KDE + * + * Derived classes must be created through the create() static method + */ +class KDECORE_EXPORT KCalendarSystem +{ +public: + + /** + * Format for returned year number / month number / day number as string. + */ + enum StringFormat { + ShortFormat, /**< Short string format, e.g. 2000 = "00" or 6 = "6" */ + LongFormat /**< Long string format, e.g. 2000 = "2000" or 6 = "06" */ + }; + + /** + * Format for returned month / day name. + */ + enum MonthNameFormat { + ShortName, /**< Short name format, e.g. "Dec" */ + LongName, /**< Long name format, e.g. "December" */ + ShortNamePossessive, /**< Short name possessive format, e.g. "of Dec" */ + LongNamePossessive, /**< Long name possessive format, e.g. "of December" */ + NarrowName /**< Narrow name format, e.g. "D". @since 4.7 */ + }; + + /** + * Format for returned month / day name. + */ + enum WeekDayNameFormat { + ShortDayName, /**< Short name format, e.g. "Fri" */ + LongDayName, /**< Long name format, e.g. "Friday" */ + NarrowDayName /**< Narrow name format, e.g. "F". @since 4.7 */ + }; + + //KDE5 add default value to calendarSystem + /** + * @since 4.6 + * + * Creates a KCalendarSystem object for the required Calendar System + * + * @param calendarSystem the Calendar System to create, defaults to QDate compatible + * @param locale locale to use for translations. The global locale is used if null. + * @return a KCalendarSystem object + */ + static KCalendarSystem *create(KLocale::CalendarSystem calendarSystem, + const KLocale *locale = 0); + + /** + * @since 4.6 + * + * Creates a KCalendarSystem object for the required Calendar System + * + * @param calendarSystem the Calendar System to create + * @param config a configuration file with a 'KCalendarSystem %calendarType' group detailing + * locale-related preferences (such as era options). The global config is used + if null. + * @param locale locale to use for translations. The global locale is used if null. + * @return a KCalendarSystem object + */ + static KCalendarSystem *create(KLocale::CalendarSystem calendarSystem, KSharedConfig::Ptr config, + const KLocale *locale = 0); + + /** + * @since 4.6 + * + * Returns a localized label to display for the required Calendar System type. + * + * Use with calendarSystemsList() to populate selection lists of available + * calendar systems. + * + * @param calendarSystem the specific calendar type to return the label for + * @param locale the locale to use for the label, defaults to global + * @return label for calendar + */ + static QString calendarLabel(KLocale::CalendarSystem calendarSystem, const KLocale *locale = KGlobal::locale()); + + /** + * @since 4.7 + * + * Returns the Calendar System enum value for a given Calendar Type, + * e.g. KLocale::QDateCalendar for "gregorian" + * + * @param calendarType the calendar type to convert + * @return calendar system for calendar type + */ + static KLocale::CalendarSystem calendarSystem(const QString &calendarType); + + //KDE5 remove + /** + * @since 4.7 + * + * Returns the deprecated Calendar Type for a given Calendar System enum value, + * e.g. "gregorian" for KLocale::QDateCalendar + * + * @param calendarSystem the calendar system to convert + * @return calendar type for calendar system + */ + static QString calendarType(KLocale::CalendarSystem calendarSystem); + + /** + * Constructor of abstract calendar class. This will be called by derived classes. + * + * @param locale locale to use for translations. The global locale is used if null. + */ + explicit KCalendarSystem(const KLocale *locale = 0); + + /** + * Constructor of abstract calendar class. This will be called by derived classes. + * + * @param config a configuration file with a 'KCalendarSystem %calendarName' group detailing + * locale-related preferences (such as era options). The global config is used + if null. + * @param locale locale to use for translations. The global locale is used if null. + */ + explicit KCalendarSystem(const KSharedConfig::Ptr config, const KLocale *locale = 0); + + /** + * Destructor. + */ + virtual ~KCalendarSystem(); + + /** + * @since 4.6 + * + * Returns the Calendar System type of the KCalendarSystem object + * + * @return type of calendar system + */ + KLocale::CalendarSystem calendarSystem() const; + + //KDE5 make virtual? + /** + * @since 4.6 + * + * Returns a localized label to display for the current Calendar System type. + * + * @return localized label for this Calendar System + */ + QString calendarLabel() const; + + /** + * Returns a QDate holding the epoch of the calendar system. Usually YMD + * of 1/1/1, access the returned QDates method toJulianDay() if you + * require the actual Julian day number. Note: a particular calendar + * system implementation may not include the epoch in its supported range, + * or the calendar system may be proleptic in which case it supports dates + * before the epoch. + * + * @see KCalendarSystem::earliestValidDate + * @see KCalendarSystem::latestValidDate + * @see KCalendarSystem::isProleptic + * @see KCalendarSystem::isValid + * + * @return epoch of calendar system + */ + virtual QDate epoch() const; + + /** + * Returns the earliest date valid in this calendar system implementation. + * + * If the calendar system is proleptic then this may be before epoch. + * + * @see KCalendarSystem::epoch + * @see KCalendarSystem::latestValidDate + * + * @return date the earliest valid date + */ + virtual QDate earliestValidDate() const; + + /** + * Returns the latest date valid in this calendar system implementation. + * + * @see KCalendarSystem::epoch + * @see KCalendarSystem::earliestValidDate + * + * @return date the latest valid date + */ + virtual QDate latestValidDate() const; + + /** + * Returns whether a given date is valid in this calendar system. + * + * @param year the year portion of the date to check + * @param month the month portion of the date to check + * @param day the day portion of the date to check + * @return @c true if the date is valid, @c false otherwise + */ + virtual bool isValid(int year, int month, int day) const = 0; + + //KDE5 make virtual? + /** + * @since 4.4 + * + * Returns whether a given date is valid in this calendar system. + * + * @param year the year portion of the date to check + * @param dayOfYear the day of year portion of the date to check + * @return @c true if the date is valid, @c false otherwise + */ + bool isValid(int year, int dayOfYear) const; + + //KDE5 make virtual? + /** + * @since 4.5 + * + * Returns whether a given date is valid in this calendar system. + * + * @param eraName the Era Name portion of the date to check + * @param yearInEra the Year In Era portion of the date to check + * @param month the Month portion of the date to check + * @param day the Day portion of the date to check + * @return @c true if the date is valid, @c false otherwise + */ + bool isValid(const QString &eraName, int yearInEra, int month, int day) const; + + //KDE5 make virtual? + /** + * @since 4.4 + * + * Returns whether a given date is valid in this calendar system. + * + * @param year the year portion of the date to check + * @param isoWeekNumber the ISO week portion of the date to check + * @param dayOfIsoWeek the day of week portion of the date to check + * @return @c true if the date is valid, @c false otherwise + */ + bool isValidIsoWeekDate(int year, int isoWeekNumber, int dayOfIsoWeek) const; + + /** + * Returns whether a given date is valid in this calendar system. + * + * @param date the date to check + * @return @c true if the date is valid, @c false otherwise + */ + virtual bool isValid(const QDate &date) const; + + /** + * Changes the date's year, month and day. The range of the year, month + * and day depends on which calendar is being used. All years entered + * are treated literally, i.e. no Y2K translation is applied to years + * entered in the range 00 to 99. Replaces setYMD. + * + * @param date date to change + * @param year year + * @param month month number + * @param day day of month + * @return @c true if the date is valid, @c false otherwise + */ + virtual bool setDate(QDate &date, int year, int month, int day) const; + + //KDE5 make virtual? + /** + * @since 4.4 + * + * Set a date using the year number and day of year number only. + * + * @param date date to change + * @param year year + * @param dayOfYear day of year + * @return @c true if the date is valid, @c false otherwise + */ + bool setDate(QDate &date, int year, int dayOfYear) const; + + //KDE5 make virtual? + /** + * @since 4.5 + * + * Set a date using the era, year in era number, month and day + * + * @param date date to change + * @param eraName Era string + * @param yearInEra Year In Era number + * @param month Month number + * @param day Day Of Month number + * @return @c true if the date is valid, @c false otherwise + */ + bool setDate(QDate &date, QString eraName, int yearInEra, int month, int day) const; + + //KDE5 make virtual? + /** + * @since 4.4 + * + * Set a date using the year number, ISO week number and day of week number. + * + * @param date date to change + * @param year year + * @param isoWeekNumber ISO week of year + * @param dayOfIsoWeek day of week Mon..Sun (1..7) + * @return @c true if the date is valid, @c false otherwise + */ + bool setDateIsoWeek(QDate &date, int year, int isoWeekNumber, int dayOfIsoWeek) const; + + + //KDE5 make virtual? + /** + * @since 4.5 + * + * Returns the year, month and day portion of a given date in the current calendar system + * + * @param date date to get year, month and day for + * @param year year number returned in this variable + * @param month month number returned in this variable + * @param day day of month returned in this variable + */ + void getDate(const QDate date, int *year, int *month, int *day) const; + + /** + * Returns the year portion of a given date in the current calendar system + * + * @param date date to return year for + * @return year, 0 if input date is invalid + */ + virtual int year(const QDate &date) const; + + /** + * Returns the month portion of a given date in the current calendar system + * + * @param date date to return month for + * @return month of year, 0 if input date is invalid + */ + virtual int month(const QDate &date) const; + + /** + * Returns the day portion of a given date in the current calendar system + * + * @param date date to return day for + * @return day of the month, 0 if input date is invalid + */ + virtual int day(const QDate &date) const; + + //KDE5 make virtual? + /** + * @since 4.5 + * + * Returns the Era Name portion of a given date in the current calendar system, + * for example "AD" or "Anno Domini" for the Gregorian calendar and Christian Era. + * + * @param date date to return Era Name for + * @param format format to return, either short or long + * @return era name, empty string if input date is invalid + */ + QString eraName(const QDate &date, StringFormat format = ShortFormat) const; + + //KDE5 make virtual? + /** + * @since 4.5 + * + * Returns the Era Year portion of a given date in the current + * calendar system, for example "2000 AD" or "Heisei 22". + * + * @param date date to return Era Year for + * @param format format to return, either short or long + * @return era name, empty string if input date is invalid + */ + QString eraYear(const QDate &date, StringFormat format = ShortFormat) const; + + //KDE5 make virtual? + /** + * @since 4.5 + * + * Returns the Year In Era portion of a given date in the current calendar + * system, for example 1 for "1 BC". + * + * @param date date to return Year In Era for + * @return Year In Era, -1 if input date is invalid + */ + int yearInEra(const QDate &date) const; + + /** + * Returns a QDate containing a date @p nyears years later. + * + * @param date The old date + * @param nyears The number of years to add + * @return The new date, null date if any errors + */ + virtual QDate addYears(const QDate &date, int nyears) const; + + /** + * Returns a QDate containing a date @p nmonths months later. + * + * @param date The old date + * @param nmonths number of months to add + * @return The new date, null date if any errors + */ + virtual QDate addMonths(const QDate &date, int nmonths) const; + + /** + * Returns a QDate containing a date @p ndays days later. + * + * @param date The old date + * @param ndays number of days to add + * @return The new date, null date if any errors + */ + virtual QDate addDays(const QDate &date, int ndays) const; + + //KDE5 make virtual? + /** + * Returns the difference between two dates in years, months and days. + * The difference is always caculated from the earlier date to the later + * date in year, month and day order, with the @p direction parameter + * indicating which direction the difference is applied from the @p toDate. + * + * For example, the difference between 2010-06-10 and 2012-09-5 is 2 years, + * 2 months and 26 days. Note that the difference between two last days of + * the month is always 1 month, e.g. 2010-01-31 to 2010-02-28 is 1 month + * not 28 days. + * + * @param fromDate The date to start from + * @param toDate The date to end at + * @param yearsDiff Returns number of years difference + * @param monthsDiff Returns number of months difference + * @param daysDiff Returns number of days difference + * @param direction Returns direction of difference, 1 if fromDate <= toDate, -1 otherwise + */ + void dateDifference(const QDate &fromDate, const QDate &toDate, + int *yearsDiff, int *monthsDiff, int *daysDiff, int *direction) const; + + //KDE5 make virtual? + /** + * Returns the difference between two dates in completed calendar years. + * The returned value will be negative if @p fromDate > @p toDate. + * + * For example, the difference between 2010-06-10 and 2012-09-5 is 2 years. + * + * @param fromDate The date to start from + * @param toDate The date to end at + * @return The number of years difference + */ + int yearsDifference(const QDate &fromDate, const QDate &toDate) const; + + //KDE5 make virtual? + /** + * Returns the difference between two dates in completed calendar months + * The returned value will be negative if @p fromDate > @p toDate. + * + * For example, the difference between 2010-06-10 and 2012-09-5 is 26 months. + * Note that the difference between two last days of the month is always 1 + * month, e.g. 2010-01-31 to 2010-02-28 is 1 month not 28 days. + * + * @param fromDate The date to start from + * @param toDate The date to end at + * @return The number of months difference + */ + int monthsDifference(const QDate &fromDate, const QDate &toDate) const; + + //KDE5 make virtual? + /** + * Returns the difference between two dates in days + * The returned value will be negative if @p fromDate > @p toDate. + * + * @param fromDate The date to start from + * @param toDate The date to end at + * @return The number of days difference + */ + int daysDifference(const QDate &fromDate, const QDate &toDate) const; + + /** + * Returns number of months in the given year + * + * @param date the date to obtain year from + * @return number of months in the year, -1 if input date invalid + */ + virtual int monthsInYear(const QDate &date) const; + + //KDE5 make virtual? + /** + * @since 4.5 + * + * Returns number of months in the given year + * + * @param year the required year + * @return number of months in the year, -1 if input date invalid + */ + int monthsInYear(int year) const; + + /** + * Returns the number of localized weeks in the given year. + * + * @param date the date to obtain year from + * @return number of weeks in the year, -1 if input date invalid + */ + virtual int weeksInYear(const QDate &date) const; + + //KDE5 Merge with virtual weeksInYear with default + /** + * @since 4.7 + * + * Returns the number of Weeks in a year using the required Week Number System. + * + * Unless you specifically want a particular Week Number System (e.g. ISO Weeks) + * you should use the localized number of weeks provided by weeksInYear(). + * + * @see week() + * @see formatDate() + * @param date the date to obtain year from + * @param weekNumberSystem the week number system to use + * @return number of weeks in the year, -1 if date invalid + */ + int weeksInYear(const QDate &date, KLocale::WeekNumberSystem weekNumberSystem) const; + + /** + * Returns the number of localized weeks in the given year. + * + * @param year the year + * @return number of weeks in the year, -1 if input date invalid + */ + virtual int weeksInYear(int year) const; + + //KDE5 Merge with virtual weeksInYear with default + /** + * @since 4.7 + * + * Returns the number of Weeks in a year using the required Week Number System. + * + * Unless you specifically want a particular Week Number System (e.g. ISO Weeks) + * you should use the localized number of weeks provided by weeksInYear(). + * + * @see week() + * @see formatDate() + * @param year the year + * @param weekNumberSystem the week number system to use + * @return number of weeks in the year, -1 if date invalid + */ + int weeksInYear(int year, KLocale::WeekNumberSystem weekNumberSystem) const; + + /** + * Returns the number of days in the given year. + * + * @param date the date to obtain year from + * @return number of days in year, -1 if input date invalid + */ + virtual int daysInYear(const QDate &date) const; + + //KDE5 make virtual? + /** + * @since 4.5 + * + * Returns the number of days in the given year. + * + * @param year the year + * @return number of days in year, -1 if input date invalid + */ + int daysInYear(int year) const; + + /** + * Returns the number of days in the given month. + * + * @param date the date to obtain month from + * @return number of days in month, -1 if input date invalid + */ + virtual int daysInMonth(const QDate &date) const; + + //KDE5 make virtual? + /** + * @since 4.5 + * + * Returns the number of days in the given month. + * + * @param year the year the month is in + * @param month the month + * @return number of days in month, -1 if input date invalid + */ + int daysInMonth(int year, int month) const; + + /** + * Returns the number of days in the given week. + * + * @param date the date to obtain week from + * @return number of days in week, -1 if input date invalid + */ + virtual int daysInWeek(const QDate &date) const; + + /** + * Returns the day number of year for the given date + * + * The days are numbered 1..daysInYear() + * + * @param date the date to obtain day from + * @return day of year number, -1 if input date not valid + */ + virtual int dayOfYear(const QDate &date) const; + + /** + * Returns the weekday number for the given date + * + * The weekdays are numbered 1..7 for Monday..Sunday. + * + * This value is @em not affected by the value of weekStartDay() + * + * @param date the date to obtain day from + * @return day of week number, -1 if input date not valid + */ + virtual int dayOfWeek(const QDate &date) const; + + //KDE5 Make virtual? + /** + * Returns the localized Week Number for the date. + * + * This may be ISO, US, or any other supported week numbering scheme. If + * you specifically require the ISO Week or any other scheme, you should use + * the week(KLocale::WeekNumberSystem) form. + * + * If the date falls in the last week of the previous year or the first + * week of the following year, then the yearNum returned will be set to the + * appropriate year. + * + * @see weeksInYear() + * @see formatDate() + * @param date the date to obtain week from + * @param yearNum returns the year the date belongs to + * @return localized week number, -1 if input date invalid + */ + int week(const QDate &date, int *yearNum = 0) const; + + //KDE5 Make virtual? + /** + * Returns the Week Number for the date in the required Week Number System. + * + * Unless you want a specific Week Number System (e.g. ISO Week), you should + * use the localized Week Number form of week(). + * + * If the date falls in the last week of the previous year or the first + * week of the following year, then the yearNum returned will be set to the + * appropriate year. + * + * Technically, the ISO Week Number only applies to the ISO/Gregorian Calendar + * System, but the same rules will be applied to the current Calendar System. + * + * @see weeksInYear() + * @see formatDate() + * @param date the date to obtain week from + * @param weekNumberSystem the Week Number System to use + * @param yearNum returns the year the date belongs to + * @return week number, -1 if input date invalid + */ + int week(const QDate &date, KLocale::WeekNumberSystem weekNumberSystem, int *yearNum = 0) const; + + /** + * Returns whether a given year is a leap year. + * + * Input year must be checked for validity in current Calendar System prior to calling, no + * validity checking performed in this routine, behaviour is undefined in invalid case. + * + * @param year the year to check + * @return @c true if the year is a leap year, @c false otherwise + */ + virtual bool isLeapYear(int year) const = 0; + + /** + * Returns whether a given date falls in a leap year. + * + * Input date must be checked for validity in current Calendar System prior to calling, no + * validity checking performed in this routine, behaviour is undefined in invalid case. + * + * @param date the date to check + * @return @c true if the date falls in a leap year, @c false otherwise + */ + virtual bool isLeapYear(const QDate &date) const; + + //KDE5 Make virtual? + /** + * @since 4.6 + * + * Returns a QDate containing the first day of the year + * + * @param year The year to return the date for + * @return The first day of the year + */ + QDate firstDayOfYear(int year) const; + + //KDE5 Make virtual? + /** + * @since 4.6 + * + * Returns a QDate containing the last day of the year + * + * @param year The year to return the date for + * @return The last day of the year + */ + QDate lastDayOfYear(int year) const; + + //KDE5 Make virtual? + /** + * @since 4.6 + * + * Returns a QDate containing the first day of the year + * + * @param date The year to return the date for, defaults to today + * @return The first day of the year + */ + QDate firstDayOfYear(const QDate &date = QDate::currentDate()) const; + + //KDE5 Make virtual? + /** + * @since 4.6 + * + * Returns a QDate containing the last day of the year + * + * @param date The year to return the date for, defaults to today + * @return The last day of the year + */ + QDate lastDayOfYear(const QDate &date = QDate::currentDate()) const; + + //KDE5 Make virtual? + /** + * @since 4.6 + * + * Returns a QDate containing the first day of the month + * + * @param year The year to return the date for + * @param month The month to return the date for + * @return The first day of the month + */ + QDate firstDayOfMonth(int year, int month) const; + + //KDE5 Make virtual? + /** + * @since 4.6 + * + * Returns a QDate containing the last day of the month + * + * @param year The year to return the date for + * @param month The month to return the date for + * @return The last day of the month + */ + QDate lastDayOfMonth(int year, int month) const; + + //KDE5 Make virtual? + /** + * @since 4.6 + * + * Returns a QDate containing the first day of the month + * + * @param date The month to return the date for, defaults to today + * @return The first day of the month + */ + QDate firstDayOfMonth(const QDate &date = QDate::currentDate()) const; + + //KDE5 Make virtual? + /** + * @since 4.6 + * + * Returns a QDate containing the last day of the month + * + * @param date The month to return the date for, defaults to today + * @return The last day of the month + */ + QDate lastDayOfMonth(const QDate &date = QDate::currentDate()) const; + + /** + * Gets specific calendar type month name for a given month number + * If an invalid month is specified, QString() is returned. + * + * @param month the month number + * @param year the year the month belongs to + * @param format specifies whether the short month name or long month name should be used + * @return name of the month, empty string if any error + */ + virtual QString monthName(int month, int year, MonthNameFormat format = LongName) const = 0; + + /** + * Gets specific calendar type month name for a given date + * + * @param date date to obtain month from + * @param format specifies whether the short month name or long month name should be used + * @return name of the month, empty string if any error + */ + virtual QString monthName(const QDate &date, MonthNameFormat format = LongName) const; + + /** + * Gets specific calendar type week day name. + * If an invalid week day is specified, QString() is returned. + * + * @param weekDay number of day in week (Monday = 1, ..., Sunday = 7) + * @param format specifies whether the short month name or long month name should be used + * @return day name, empty string if any error + */ + virtual QString weekDayName(int weekDay, WeekDayNameFormat format = LongDayName) const = 0; + + /** + * Gets specific calendar type week day name. + * + * @param date the date + * @param format specifies whether the short month name or long month name should be used + * @return day name, empty string if any error + */ + virtual QString weekDayName(const QDate &date, WeekDayNameFormat format = LongDayName) const; + + /** + * Returns a string formatted to the current locale's conventions + * regarding dates. + * + * Uses the calendar system's internal locale set when the instance was + * created, which ensures that the correct calendar system and locale + * settings are respected, which would not occur in some cases if using + * the global locale. Defaults to global locale. + * + * @see KLocale::formatDate + * + * @param fromDate the date to be formatted + * @param toFormat category of date format to use + * + * @return The date as a string + */ + virtual QString formatDate(const QDate &fromDate, KLocale::DateFormat toFormat = KLocale::LongDate) const; + + //KDE5 Make virtual + /** + * @since 4.4 + * + * Returns a string formatted to the given format and localised to the + * correct language and digit set using the requested format standard. + * + * *** WITH GREAT POWER COMES GREAT RESPONSIBILITY *** + * Please use with care and only in situations where the DateFormat enum + * or locale formats or individual string methods do not provide what you + * need. You should almost always translate your format string as + * documented. Using the standard DateFormat options instead would take + * care of the translation for you. + * + * Warning: The %n element differs from the GNU/POSIX standard where it is + * defined as a newline. KDE currently uses this for short day number. It + * is recommended for compatibility purposes to use %-m instead. + * + * The toFormat parameter is a good candidate to be made translatable, + * so that translators can adapt it to their language's convention. + * There should also be a context using the "kdedt-format" keyword (for + * automatic validation of translations) and stating the format's purpose: + * \code + * QDate reportDate; + * KGlobal::locale()->calendar()->setDate(reportDate, reportYear, reportMonth, 1); + * dateFormat = i18nc("(kdedt-format) Report month and year in report header", "%B %Y")); + * dateString = KGlobal::locale()->calendar()->formatDate(reportDate, dateFormat); + * \endcode + * + * The date format string can be defined using either the KDE or POSIX standards. + * The KDE standard closely follows the POSIX standard but with some exceptions. + * Always use the KDE standard within KDE, but where interaction is required with + * external POSIX compliant systems (e.g. Gnome, glibc, etc) the POSIX standard + * should be used. + * + * Date format strings are made up of date componants and string literals. + * Date componants are prefixed by a % escape character and are made up of + * optional padding and case modifier flags, an optional width value, and a + * compulsary code for the actual date componant: + * %[Flags][Width][Componant] + * e.g. %_^5Y + * No spaces are allowed. + * + * The Flags can modify the padding character and/or case of the Date Componant. + * The Flags are optional and may be combined and/or repeated in any order, + * in which case the last Padding Flag and last Case Flag will be the + * ones used. The Flags must be immediately after the % and before any Width. + * + * The Width can modify how wide the date Componant is padded to. The Width + * is an optional interger value and must be after any Flags but before the + * Componant. If the Width is less than the minimum defined for a Componant + * then the default minimum will be used instead. + * + * By default most numeric Date Componants are right-aligned with leading 0's. + * + * By default all string name fields are capital case and unpadded. + * + * The following Flags may be specified: + * @li - (hyphen) no padding (e.g. 1 Jan and "%-j" = "1") + * @li _ (underscore) pad with spaces (e.g. 1 Jan and "%-j" = " 1") + * @li 0 (zero) pad with 0's (e.g. 1 Jan and "%0j" = "001") + * @li ^ (caret) make uppercase (e.g. 1 Jan and "%^B" = "JANUARY") + * @li # (hash) invert case (e.g. 1 Jan and "%#B" = "???") + * + * The following Date Componants can be specified: + * @li %Y the year to 4 digits (e.g. "1984" for 1984, "0584" for 584, "0084" for 84) + * @li %C the 'century' portion of the year to 2 digits (e.g. "19" for 1984, "05" for 584, "00" for 84) + * @li %y the lower 2 digits of the year to 2 digits (e.g. "84" for 1984, "05" for 2005) + * @li %EY the full local era year (e.g. "2000 AD") + * @li %EC the era name short form (e.g. "AD") + * @li %Ey the year in era to 1 digit (e.g. 1 or 2000) + * @li %m the month number to 2 digits (January="01", December="12") + * @li %n the month number to 1 digit (January="1", December="12"), see notes! + * @li %d the day number of the month to 2 digits (e.g. "01" on the first of March) + * @li %e the day number of the month to 1 digit (e.g. "1" on the first of March) + * @li %B the month name long form (e.g. "January") + * @li %b the month name short form (e.g. "Jan" for January) + * @li %h the month name short form (e.g. "Jan" for January) + * @li %A the weekday name long form (e.g. "Wednesday" for Wednesday) + * @li %a the weekday name short form (e.g. "Wed" for Wednesday) + * @li %j the day of the year number to 3 digits (e.g. "001" for 1 Jan) + * @li %V the ISO week of the year number to 2 digits (e.g. "01" for ISO Week 1) + * @li %G the year number in long form of the ISO week of the year to 4 digits (e.g. "2004" for 1 Jan 2005) + * @li %g the year number in short form of the ISO week of the year to 2 digits (e.g. "04" for 1 Jan 2005) + * @li %u the day of the week number to 1 digit (e.g. "1" for Monday) + * @li %D the US short date format (e.g. "%m/%d/%y") + * @li %F the ISO short date format (e.g. "%Y-%m-%d") + * @li %x the KDE locale short date format + * @li %% the literal "%" + * @li %t a tab character + * + * Everything else in the format string will be taken as literal text. + * + * Examples: + * "%Y-%m-%d" = "2009-01-01" + * "%Y-%-m-%_4d" = "2009-1- 1" + * + * The following format codes behave differently in the KDE and POSIX standards + * @li %e in GNU/POSIX is space padded to 2 digits, in KDE is not padded + * @li %n in GNU/POSIX is newline, in KDE is short month number + * + * The following POSIX format codes are currently not supported: + * @li %U US week number + * @li %w US day of week + * @li %W US week number + * @li %O locale's alternative numeric symbols, in KDE is not supported + * + * %0 is not supported as the returned result is always in the locale's chosen numeric symbol digit set. + * + * @see KLocale::formatDate + * + * @param fromDate the date to be formatted + * @param toFormat the date format to use + * @param formatStandard the standard the date format uses, defaults to KDE Standard + * + * @return The date as a string + */ + QString formatDate(const QDate &fromDate, const QString &toFormat, + KLocale::DateTimeFormatStandard formatStandard = KLocale::KdeFormat) const; + + //KDE5 Make virtual + /** + * @since 4.4 + * + * Returns a string formatted to the given format string and Digit Set. + * Only use this version if you need control over the Digit Set and do + * not want to use the locale Digit Set. + * + * @see formatDate + * + * @param fromDate the date to be formatted + * @param toFormat the date format to use + * @param digitSet the Digit Set to format the date in + * @param formatStandard the standard the date format uses, defaults to KDE Standard + * + * @return The date as a string + */ + QString formatDate(const QDate &fromDate, const QString &toFormat, KLocale::DigitSet digitSet, + KLocale::DateTimeFormatStandard formatStandard = KLocale::KdeFormat) const; + + //KDE5 Make virtual + /** + * @since 4.6 + * + * Returns a Date Component as a localized string in the requested format. + * + * For example for 2010-01-01 the KLocale::Month with en_US Locale and Gregorian calendar may return: + * KLocale::ShortNumber = "1" + * KLocale::LongNumber = "01" + * KLocale::NarrowName = "J" + * KLocale::ShortName = "Jan" + * KLocale::LongName = "January" + * + * @param date The date to format + * @param component The date component to return + * @param format The format to return the @p component in + * @param weekNumberSystem To override the default Week Number System to use + * @return The localized string form of the date component + */ + QString formatDate(const QDate &date, KLocale::DateTimeComponent component, + KLocale::DateTimeComponentFormat format = KLocale::DefaultComponentFormat, + KLocale::WeekNumberSystem weekNumberSystem = KLocale::DefaultWeekNumber) const; + + /** + * Converts a localized date string to a QDate. + * The bool pointed by @p ok will be @c false if the date entered was invalid. + * + * Uses the calendar system's internal locale set when the instance was + * created, which ensures that the correct calendar system and locale + * settings are respected, which would not occur in some cases if using + * the global locale. Defaults to global locale. + * + * @see KLocale::readDate + * + * @param str the string to convert + * @param ok if non-null, will be set to @c true if the date is valid, @c false if invalid + * + * @return the string converted to a QDate + */ + virtual QDate readDate(const QString &str, bool *ok = 0) const; + + /** + * Converts a localized date string to a QDate. + * This method is stricter than readDate(str,&ok): it will either accept + * a date in full format or a date in short format, depending on @p flags. + * + * Uses the calendar system's internal locale set when the instance was + * created, which ensures that the correct calendar system and locale + * settings are respected, which would not occur in some cases if using + * the global locale. Defaults to global locale. + * + * @see KLocale::readDate + * + * @param str the string to convert + * @param flags whether the date string is to be in full format or in short format + * @param ok if non-null, will be set to @c true if the date is valid, @c false if invalid + * + * @return the string converted to a QDate + */ + virtual QDate readDate(const QString &str, KLocale::ReadDateFlags flags, bool *ok = 0) const; + + /** + * Converts a localized date string to a QDate, using the specified @p format. + * You will usually not want to use this method. Uses teh KDE format standard. + * + * @param dateString the string to convert + * @param dateFormat the date format to use, in KDE format standard + * @param ok if non-null, will be set to @c true if the date is valid, @c false if invalid + * + * @return the string converted to a QDate + * + * @see formatDate + * @see KLocale::readDate + */ + virtual QDate readDate(const QString &dateString, const QString &dateFormat, bool *ok = 0) const; + + //KDE5 Make virtual + /** + * Converts a localized date string to a QDate, using the specified @p format. + * You will usually not want to use this method. + * + * You must supply a format and string containing at least one of the following combinations to + * create a valid date: + * @li a month and day of month + * @li a day of year + * @li a ISO week number and day of week + * + * If a year number is not supplied then the current year will be assumed. + * + * All date componants must be separated by a non-numeric character. + * + * The format is not applied strictly to the input string: + * @li extra whitespace is ignored + * @li leading 0's on numbers are ignored + * @li capitalisation of literals is ignored + * + * The allowed format componants are almost the same as the formatDate() function. + * The following date componants will be read: + * @li %Y the whole year (e.g. "1984" for 1984) + * @li %y the lower 2 digits of the year (e.g. "84" for 1984) + * @li %EY the full local era year (e.g. "2000 AD") + * @li %EC the era name short form (e.g. "AD") + * @li %Ey the year in era to 1 digit (e.g. 1 or 2000) + * @li %m the month number to two digits (January="01", December="12") + * @li %n the month number (January="1", December="12") + * @li %d the day number of the month to two digits (e.g. "01" on the first of March) + * @li %e the day number of the month (e.g. "1" on the first of March) + * @li %B the month name long form (e.g. "January") + * @li %b the month name short form (e.g. "Jan" for January) + * @li %h the month name short form (e.g. "Jan" for January) + * @li %A the weekday name long form (e.g. "Wednesday" for Wednesday) + * @li %a the weekday name short form (e.g. "Wed" for Wednesday) + * @li %j the day of the year number to three digits (e.g. "001" for 1 Jan) + * @li %V the ISO week of the year number to two digits (e.g. "01" for ISO Week 1) + * @li %u the day of the week number (e.g. "1" for Monday) + * + * The following date componants are NOT supported: + * @li %C the 'century' portion of the year (e.g. "19" for 1984, "5" for 584, "" for 84) + * @li %G the year number in long form of the ISO week of the year (e.g. "2004" for 1 Jan 2005) + * @li %g the year number in short form of the ISO week of the year (e.g. "04" for 1 Jan 2005) + * @li %D the US short date format (e.g. "%m/%d/%y") + * @li %F the ISO short date format (e.g. "%Y-%m-%d") + * @li %x the KDE locale short date format + * @li %% the literal "%" + * @li %t a tab character + * + * @param dateString the string to convert + * @param dateFormat the date format to use + * @param ok if non-null, will be set to @c true if the date is valid, @c false if invalid + * @param formatStandard the standard the date format uses + * + * @return the string converted to a QDate + * + * @see formatDate + * @see KLocale::readDate + */ + QDate readDate(const QString &dateString, const QString &dateFormat, bool *ok, + KLocale::DateTimeFormatStandard formatStandard) const; + + //KDE5 Make virtual + /** + * @since 4.6 + * + * Returns the Short Year Window Start Year for the current Calendar System. + * + * Use this function to get the Start Year for the Short Year Window to be + * applied when 2 digit years are entered for a Short Year input format, + * e.g. if the Short Year Window Start Year is 1930, then the input Short + * Year value of 40 is interpreted as 1940 and the input Short Year value + * of 10 is interpreted as 2010. + * + * The Short Year Window is only ever applied when reading the Short Year + * format and not the Long Year format, i.e. KLocale::ShortFormat or '%y' + * only and not KLocale::LongFormat or '%Y'. + * + * The Start Year 0 effectively means not to use a Short Year Window + * + * Each Calendar System requires a different Short Year Window as they have + * different epochs. The Gregorian Short Year Window usually pivots around + * the year 2000, whereas the Hebrew Short Year Window usually pivots around + * the year 5000. + * + * This value must always be used when evaluating user input Short Year + * strings. + * + * @see KLocale::shortYearWindowStartYear + * @see KLocale::applyShortYearWindow + * @return the short year window start year + */ + int shortYearWindowStartYear() const; + + //KDE5 Make virtual + /** + * @since 4.6 + * + * Returns the Year Number after applying the Year Window. + * + * If the @p inputYear is between 0 and 99, then apply the Year Window and + * return the calculated Year Number. + * + * If the @p inputYear is not between 0 and 99, then the original Year Number + * is returned. + * + * @see KLocale::setYearWindowOffset + * @see KLocale::yearWindowOffset + * @param inputYear the year number to apply the year window to + * @return the year number after applying the year window + */ + int applyShortYearWindow(int inputYear) const; + + /** + * Use this to determine which day is the first day of the week. + * + * Uses the calendar system's internal locale set when the instance was + * created, which ensures that the correct calendar system and locale + * settings are respected, which would not occur in some cases if using + * the global locale. Defaults to global locale. + * + * @see KLocale::weekStartDay + * + * @return an integer (Monday = 1, ..., Sunday = 7) + */ + virtual int weekStartDay() const; + + /** + * Returns whether the calendar is lunar based. + * + * @return @c true if the calendar is lunar based, @c false if not + */ + virtual bool isLunar() const = 0; + + /** + * Returns whether the calendar is lunisolar based. + * + * @return @c true if the calendar is lunisolar based, @c false if not + */ + virtual bool isLunisolar() const = 0; + + /** + * Returns whether the calendar is solar based. + * + * @return @c true if the calendar is solar based, @c false if not + */ + virtual bool isSolar() const = 0; + + /** + * Returns whether the calendar system is proleptic, i.e. whether dates + * before the epoch are supported. + * + * @see KCalendarSystem::epoch + * + * @return @c true if the calendar system is proleptic, @c false if not + */ + virtual bool isProleptic() const = 0; + +protected: + + /** + * Internal method to convert a Julian Day number into the YMD values for + * this calendar system. + * + * All calendar system implementations MUST implement julianDayToDate and + * dateToJulianDay methods as all other methods can be expressed as + * functions of these. Does no internal validity checking. + * + * @see KCalendarSystem::dateToJulianDay + * + * @param jd Julian day number to convert to date + * @param year year number returned in this variable + * @param month month number returned in this variable + * @param day day of month returned in this variable + * @return @c true if the date is valid, @c false otherwise + */ + virtual bool julianDayToDate(int jd, int &year, int &month, int &day) const = 0; + + /** + * Internal method to convert YMD values for this calendar system into a + * Julian Day number. + * + * All calendar system implementations MUST implement julianDayToDate and + * dateToJulianDay methods as all other methods can be expressed as + * functions of these. Does no internal validity checking. + * + * @see KCalendarSystem::julianDayToDate + * + * @param year year number + * @param month month number + * @param day day of month + * @param jd Julian day number returned in this variable + * @return @c true if the date is valid, @c false otherwise + */ + virtual bool dateToJulianDay(int year, int month, int day, int &jd) const = 0; + + /** + * Returns the locale used for translations and formats for this + * calendar system instance. This allows a calendar system instance to be + * independent of the global translations and formats if required. All + * implementations must refer to this locale. + * + * Only for internal calendar system use; if public access is required then + * provide public methods only for those methods actually required. Any + * app that creates an instance with its own locale overriding global will + * have the original handle to the locale and can manipulate it that way if + * required, e.g. to change default date format. Only expose those methods + * that library widgets require access to internally. + * + * @see KCalendarSystem::formatDate + * @see KLocale::formatDate + * @see KCalendarSystem::weekStartDay + * @see KLocale::weekStartDay + * @see KCalendarSystem::readDate + * @see KLocale::readDate + * + * @return locale to use + */ + const KLocale *locale() const; + + /** + * Constructor of abstract calendar class. This will be called by derived classes. + * + * @param dd derived private d-pointer. + * @param config a configuration file with a 'KCalendarSystem %calendarName' group detailing + * locale-related preferences (such as era options). The global config is used + if null. + * @param locale locale to use for translations. The global locale is used if null. + */ + KCalendarSystem(KCalendarSystemPrivate &dd, + const KSharedConfig::Ptr config = KSharedConfig::Ptr(), + const KLocale *locale = 0); + +private: + //Required for shared d-pointer as already private, remove in KDE5 + friend class KCalendarSystemCoptic; + friend class KCalendarSystemEthiopian; + friend class KCalendarSystemGregorian; + friend class KCalendarSystemHebrew; + friend class KCalendarSystemIndianNational; + friend class KCalendarSystemIslamicCivil; + friend class KCalendarSystemJalali; + friend class KCalendarSystemJapanese; + friend class KCalendarSystemJulian; + friend class KCalendarSystemMinguo; + friend class KCalendarSystemQDate; + friend class KCalendarSystemThai; + //Other friends that need access to protected/private functions + friend class KLocalizedDate; + friend class KLocalizedDatePrivate; + friend class KDateTimeParser; + friend class KDateTable; + + // Era functions needed by friends, may be made public later if needed in KCM + QList *eraList() const; + KCalendarEra era(const QDate &eraDate) const; + KCalendarEra era(const QString &eraName, int yearInEra) const; + + Q_DISABLE_COPY(KCalendarSystem) + KCalendarSystemPrivate * const d_ptr; // KDE5 make protected + Q_DECLARE_PRIVATE(KCalendarSystem) +}; + +#endif