/* Copyright (c) 2002-2003 Carlos Moro Copyright (c) 2002-2003 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 "kcalendarsystemislamiccivil_p.h" #include "kcalendarsystemprivate_p.h" #include class KCalendarSystemIslamicCivilPrivate : public KCalendarSystemPrivate { public: explicit KCalendarSystemIslamicCivilPrivate(KCalendarSystemIslamicCivil *q); virtual ~KCalendarSystemIslamicCivilPrivate(); // Virtual methods each calendar system must re-implement virtual KLocale::CalendarSystem calendarSystem() const; virtual void loadDefaultEraList(); virtual int monthsInYear(int year) const; virtual int daysInMonth(int year, int month) const; virtual int daysInYear(int year) const; virtual int daysInWeek() const; virtual bool isLeapYear(int year) const; virtual bool hasLeapMonths() const; virtual bool hasYearZero() const; virtual int maxDaysInWeek() const; virtual int maxMonthsInYear() const; virtual int earliestValidYear() const; virtual int latestValidYear() const; virtual QString monthName(int month, int year, KLocale::DateTimeComponentFormat format, bool possessive) const; virtual QString weekDayName(int weekDay, KLocale::DateTimeComponentFormat format) const; }; // Shared d pointer base class definitions KCalendarSystemIslamicCivilPrivate::KCalendarSystemIslamicCivilPrivate(KCalendarSystemIslamicCivil *q) : KCalendarSystemPrivate(q) { } KCalendarSystemIslamicCivilPrivate::~KCalendarSystemIslamicCivilPrivate() { } KLocale::CalendarSystem KCalendarSystemIslamicCivilPrivate::calendarSystem() const { return KLocale::IslamicCivilCalendar; } void KCalendarSystemIslamicCivilPrivate::loadDefaultEraList() { QString name, shortName, format; // Islamic Era, Anno Hegirae, "Year of the Hijra". name = i18nc("Calendar Era: Hijri Islamic Era, years > 0, LongFormat", "Anno Hegirae"); shortName = i18nc("Calendar Era: Hijri Islamic Era, years > 0, ShortFormat", "AH"); format = i18nc("(kdedt-format) Hijri, AH, full era year format used for %EY, e.g. 2000 AH", "%Ey %EC"); addEra('+', 1, q->epoch(), 1, q->latestValidDate(), name, shortName, format); } int KCalendarSystemIslamicCivilPrivate::monthsInYear(int year) const { Q_UNUSED(year) return 12; } int KCalendarSystemIslamicCivilPrivate::daysInMonth(int year, int month) const { if (month == 12 && isLeapYear(year)) { return 30; } if (month % 2 == 0) { // Even number months have 29 days return 29; } else { // Odd number months have 30 days return 30; } } int KCalendarSystemIslamicCivilPrivate::daysInYear(int year) const { if (isLeapYear(year)) { return 355; } else { return 354; } } int KCalendarSystemIslamicCivilPrivate::daysInWeek() const { return 7; } bool KCalendarSystemIslamicCivilPrivate::isLeapYear(int year) const { // Years 2, 5, 7, 10, 13, 16, 18, 21, 24, 26, 29 of the 30 year cycle /* The following C++ code is translated from the Lisp code in ``Calendrical Calculations'' by Nachum Dershowitz and Edward M. Reingold, Software---Practice & Experience, vol. 20, no. 9 (September, 1990), pp. 899--928. This code is in the public domain, but any use of it should publically acknowledge its source. */ if ((((11 * year) + 14) % 30) < 11) { return true; } else { return false; } // The following variations will be implemented in separate classes in 4.5 // May be cleaner to formally define using a case statement switch on (year % 30) // Variation used by Bar Habraeus / Graves / Birashk / Some Microsoft products // Years 2, 5, 7, 10, 13, 15, 18, 21, 24, 26, 29 of the 30 year cycle // if ( ( ( ( 11 * year ) + 15 ) % 30 ) < 11 ) { // Variation used by Bohras / Sahifa with epoch 15 July 622 jd = 1948440 // Years 2, 5, 8, 10, 13, 16, 19, 21, 24, 27, 29 of the 30 year cycle // if ( ( ( ( 11 * year ) + 1 ) % 30 ) < 11 ) { } bool KCalendarSystemIslamicCivilPrivate::hasLeapMonths() const { return false; } bool KCalendarSystemIslamicCivilPrivate::hasYearZero() const { return false; } int KCalendarSystemIslamicCivilPrivate::maxDaysInWeek() const { return 7; } int KCalendarSystemIslamicCivilPrivate::maxMonthsInYear() const { return 12; } int KCalendarSystemIslamicCivilPrivate::earliestValidYear() const { return 1; } int KCalendarSystemIslamicCivilPrivate::latestValidYear() const { return 9999; } QString KCalendarSystemIslamicCivilPrivate::monthName(int month, int year, KLocale::DateTimeComponentFormat format, bool possessive) const { Q_UNUSED(year); if (format == KLocale::NarrowName) { switch (month) { case 1: return ki18nc("Hijri month 1 - KLocale::NarrowName", "M").toString(locale()); case 2: return ki18nc("Hijri month 2 - KLocale::NarrowName", "S").toString(locale()); case 3: return ki18nc("Hijri month 3 - KLocale::NarrowName", "A").toString(locale()); case 4: return ki18nc("Hijri month 4 - KLocale::NarrowName", "T").toString(locale()); case 5: return ki18nc("Hijri month 5 - KLocale::NarrowName", "A").toString(locale()); case 6: return ki18nc("Hijri month 6 - KLocale::NarrowName", "T").toString(locale()); case 7: return ki18nc("Hijri month 7 - KLocale::NarrowName", "R").toString(locale()); case 8: return ki18nc("Hijri month 8 - KLocale::NarrowName", "S").toString(locale()); case 9: return ki18nc("Hijri month 9 - KLocale::NarrowName", "R").toString(locale()); case 10: return ki18nc("Hijri month 10 - KLocale::NarrowName", "S").toString(locale()); case 11: return ki18nc("Hijri month 11 - KLocale::NarrowName", "Q").toString(locale()); case 12: return ki18nc("Hijri month 12 - KLocale::NarrowName", "H").toString(locale()); default: return QString(); } } if (format == KLocale::ShortName && possessive) { switch (month) { case 1: return ki18nc("Hijri month 1 - KLocale::ShortName Possessive", "of Muh").toString(locale()); case 2: return ki18nc("Hijri month 2 - KLocale::ShortName Possessive", "of Saf").toString(locale()); case 3: return ki18nc("Hijri month 3 - KLocale::ShortName Possessive", "of R.A").toString(locale()); case 4: return ki18nc("Hijri month 4 - KLocale::ShortName Possessive", "of R.T").toString(locale()); case 5: return ki18nc("Hijri month 5 - KLocale::ShortName Possessive", "of J.A").toString(locale()); case 6: return ki18nc("Hijri month 6 - KLocale::ShortName Possessive", "of J.T").toString(locale()); case 7: return ki18nc("Hijri month 7 - KLocale::ShortName Possessive", "of Raj").toString(locale()); case 8: return ki18nc("Hijri month 8 - KLocale::ShortName Possessive", "of Sha").toString(locale()); case 9: return ki18nc("Hijri month 9 - KLocale::ShortName Possessive", "of Ram").toString(locale()); case 10: return ki18nc("Hijri month 10 - KLocale::ShortName Possessive", "of Shw").toString(locale()); case 11: return ki18nc("Hijri month 11 - KLocale::ShortName Possessive", "of Qid").toString(locale()); case 12: return ki18nc("Hijri month 12 - KLocale::ShortName Possessive", "of Hij").toString(locale()); default: return QString(); } } if (format == KLocale::ShortName && !possessive) { switch (month) { case 1: return ki18nc("Hijri month 1 - KLocale::ShortName", "Muh").toString(locale()); case 2: return ki18nc("Hijri month 2 - KLocale::ShortName", "Saf").toString(locale()); case 3: return ki18nc("Hijri month 3 - KLocale::ShortName", "R.A").toString(locale()); case 4: return ki18nc("Hijri month 4 - KLocale::ShortName", "R.T").toString(locale()); case 5: return ki18nc("Hijri month 5 - KLocale::ShortName", "J.A").toString(locale()); case 6: return ki18nc("Hijri month 6 - KLocale::ShortName", "J.T").toString(locale()); case 7: return ki18nc("Hijri month 7 - KLocale::ShortName", "Raj").toString(locale()); case 8: return ki18nc("Hijri month 8 - KLocale::ShortName", "Sha").toString(locale()); case 9: return ki18nc("Hijri month 9 - KLocale::ShortName", "Ram").toString(locale()); case 10: return ki18nc("Hijri month 10 - KLocale::ShortName", "Shw").toString(locale()); case 11: return ki18nc("Hijri month 11 - KLocale::ShortName", "Qid").toString(locale()); case 12: return ki18nc("Hijri month 12 - KLocale::ShortName", "Hij").toString(locale()); default: return QString(); } } if (format == KLocale::LongName && possessive) { switch (month) { case 1: return ki18nc("Hijri month 1 - KLocale::LongName Possessive", "of Muharram").toString(locale()); case 2: return ki18nc("Hijri month 2 - KLocale::LongName Possessive", "of Safar").toString(locale()); case 3: return ki18nc("Hijri month 3 - KLocale::LongName Possessive", "of Rabi` al-Awal").toString(locale()); case 4: return ki18nc("Hijri month 4 - KLocale::LongName Possessive", "of Rabi` al-Thaani").toString(locale()); case 5: return ki18nc("Hijri month 5 - KLocale::LongName Possessive", "of Jumaada al-Awal").toString(locale()); case 6: return ki18nc("Hijri month 6 - KLocale::LongName Possessive", "of Jumaada al-Thaani").toString(locale()); case 7: return ki18nc("Hijri month 7 - KLocale::LongName Possessive", "of Rajab").toString(locale()); case 8: return ki18nc("Hijri month 8 - KLocale::LongName Possessive", "of Sha`ban").toString(locale()); case 9: return ki18nc("Hijri month 9 - KLocale::LongName Possessive", "of Ramadan").toString(locale()); case 10: return ki18nc("Hijri month 10 - KLocale::LongName Possessive", "of Shawwal").toString(locale()); case 11: return ki18nc("Hijri month 11 - KLocale::LongName Possessive", "of Thu al-Qi`dah").toString(locale()); case 12: return ki18nc("Hijri month 12 - KLocale::LongName Possessive", "of Thu al-Hijjah").toString(locale()); default: return QString(); } } // Default to LongName switch (month) { case 1: return ki18nc("Hijri month 1 - KLocale::LongName", "Muharram").toString(locale()); case 2: return ki18nc("Hijri month 2 - KLocale::LongName", "Safar").toString(locale()); case 3: return ki18nc("Hijri month 3 - KLocale::LongName", "Rabi` al-Awal").toString(locale()); case 4: return ki18nc("Hijri month 4 - KLocale::LongName", "Rabi` al-Thaani").toString(locale()); case 5: return ki18nc("Hijri month 5 - KLocale::LongName", "Jumaada al-Awal").toString(locale()); case 6: return ki18nc("Hijri month 6 - KLocale::LongName", "Jumaada al-Thaani").toString(locale()); case 7: return ki18nc("Hijri month 7 - KLocale::LongName", "Rajab").toString(locale()); case 8: return ki18nc("Hijri month 8 - KLocale::LongName", "Sha`ban").toString(locale()); case 9: return ki18nc("Hijri month 9 - KLocale::LongName", "Ramadan").toString(locale()); case 10: return ki18nc("Hijri month 10 - KLocale::LongName", "Shawwal").toString(locale()); case 11: return ki18nc("Hijri month 11 - KLocale::LongName", "Thu al-Qi`dah").toString(locale()); case 12: return ki18nc("Hijri month 12 - KLocale::LongName", "Thu al-Hijjah").toString(locale()); default: return QString(); } } QString KCalendarSystemIslamicCivilPrivate::weekDayName(int weekDay, KLocale::DateTimeComponentFormat format) const { if (format == KLocale::NarrowName) { switch (weekDay) { case 1: return ki18nc("Hijri weekday 1 - KLocale::NarrowName ", "I").toString(locale()); case 2: return ki18nc("Hijri weekday 2 - KLocale::NarrowName ", "T").toString(locale()); case 3: return ki18nc("Hijri weekday 3 - KLocale::NarrowName ", "A").toString(locale()); case 4: return ki18nc("Hijri weekday 4 - KLocale::NarrowName ", "K").toString(locale()); case 5: return ki18nc("Hijri weekday 5 - KLocale::NarrowName ", "J").toString(locale()); case 6: return ki18nc("Hijri weekday 6 - KLocale::NarrowName ", "S").toString(locale()); case 7: return ki18nc("Hijri weekday 7 - KLocale::NarrowName ", "A").toString(locale()); default: return QString(); } } if (format == KLocale::ShortName || format == KLocale:: ShortNumber) { switch (weekDay) { case 1: return ki18nc("Hijri weekday 1 - KLocale::ShortName", "Ith").toString(locale()); case 2: return ki18nc("Hijri weekday 2 - KLocale::ShortName", "Thl").toString(locale()); case 3: return ki18nc("Hijri weekday 3 - KLocale::ShortName", "Arb").toString(locale()); case 4: return ki18nc("Hijri weekday 4 - KLocale::ShortName", "Kha").toString(locale()); case 5: return ki18nc("Hijri weekday 5 - KLocale::ShortName", "Jum").toString(locale()); case 6: return ki18nc("Hijri weekday 6 - KLocale::ShortName", "Sab").toString(locale()); case 7: return ki18nc("Hijri weekday 7 - KLocale::ShortName", "Ahd").toString(locale()); default: return QString(); } } switch (weekDay) { case 1: return ki18nc("Hijri weekday 1 - KLocale::LongName", "Yaum al-Ithnain").toString(locale()); case 2: return ki18nc("Hijri weekday 2 - KLocale::LongName", "Yau al-Thulatha").toString(locale()); case 3: return ki18nc("Hijri weekday 3 - KLocale::LongName", "Yaum al-Arbi'a").toString(locale()); case 4: return ki18nc("Hijri weekday 4 - KLocale::LongName", "Yaum al-Khamees").toString(locale()); case 5: return ki18nc("Hijri weekday 5 - KLocale::LongName", "Yaum al-Jumma").toString(locale()); case 6: return ki18nc("Hijri weekday 6 - KLocale::LongName", "Yaum al-Sabt").toString(locale()); case 7: return ki18nc("Hijri weekday 7 - KLocale::LongName", "Yaum al-Ahad").toString(locale()); default: return QString(); } } KCalendarSystemIslamicCivil::KCalendarSystemIslamicCivil(const KLocale *locale) : KCalendarSystem(*new KCalendarSystemIslamicCivilPrivate(this), KSharedConfig::Ptr(), locale) { d_ptr->loadConfig(calendarType()); } KCalendarSystemIslamicCivil::KCalendarSystemIslamicCivil(const KSharedConfig::Ptr config, const KLocale *locale) : KCalendarSystem(*new KCalendarSystemIslamicCivilPrivate(this), config, locale) { d_ptr->loadConfig(calendarType()); } KCalendarSystemIslamicCivil::KCalendarSystemIslamicCivil(KCalendarSystemIslamicCivilPrivate &dd, const KSharedConfig::Ptr config, const KLocale *locale) : KCalendarSystem(dd, config, locale) { d_ptr->loadConfig(calendarType()); } KCalendarSystemIslamicCivil::~KCalendarSystemIslamicCivil() { } QString KCalendarSystemIslamicCivil::calendarType() const { return QLatin1String("hijri"); } QDate KCalendarSystemIslamicCivil::epoch() const { // 16 July 622 in the Julian calendar return QDate::fromJulianDay(1948440); } QDate KCalendarSystemIslamicCivil::earliestValidDate() const { return epoch(); } QDate KCalendarSystemIslamicCivil::latestValidDate() const { // Set to last day of year 9999 // Last day of Islamic Civil year 9999 is 9999-12-29 return QDate::fromJulianDay(5491751); } bool KCalendarSystemIslamicCivil::isValid(int year, int month, int day) const { return KCalendarSystem::isValid(year, month, day); } bool KCalendarSystemIslamicCivil::isValid(const QDate &date) const { return KCalendarSystem::isValid(date); } bool KCalendarSystemIslamicCivil::isLeapYear(int year) const { return KCalendarSystem::isLeapYear(year); } bool KCalendarSystemIslamicCivil::isLeapYear(const QDate &date) const { return KCalendarSystem::isLeapYear(date); } QString KCalendarSystemIslamicCivil::monthName(int month, int year, MonthNameFormat format) const { return KCalendarSystem::monthName(month, year, format); } QString KCalendarSystemIslamicCivil::monthName(const QDate &date, MonthNameFormat format) const { return KCalendarSystem::monthName(date, format); } QString KCalendarSystemIslamicCivil::weekDayName(int weekDay, WeekDayNameFormat format) const { return KCalendarSystem::weekDayName(weekDay, format); } QString KCalendarSystemIslamicCivil::weekDayName(const QDate &date, WeekDayNameFormat format) const { return KCalendarSystem::weekDayName(date, format); } int KCalendarSystemIslamicCivil::weekDayOfPray() const { return 5; // Friday } bool KCalendarSystemIslamicCivil::isLunar() const { return true; } bool KCalendarSystemIslamicCivil::isLunisolar() const { return false; } bool KCalendarSystemIslamicCivil::isSolar() const { return false; } bool KCalendarSystemIslamicCivil::isProleptic() const { return false; } bool KCalendarSystemIslamicCivil::julianDayToDate(int jd, int &year, int &month, int &day) const { Q_D(const KCalendarSystemIslamicCivil); /* The following C++ code is translated from the Lisp code in ``Calendrical Calculations'' by Nachum Dershowitz and Edward M. Reingold, Software---Practice & Experience, vol. 20, no. 9 (September, 1990), pp. 899--928. This code is in the public domain, but any use of it should publically acknowledge its source. */ // Search forward year by year from approximate year year = (jd - epoch().toJulianDay()) / 355; int testJd; dateToJulianDay(year, 12, d->daysInMonth(year, 12), testJd); while (jd > testJd) { year++; dateToJulianDay(year, 12, d->daysInMonth(year, 12), testJd); } // Search forward month by month from Muharram month = 1; dateToJulianDay(year, month, d->daysInMonth(year, month), testJd); while (jd > testJd) { month++; dateToJulianDay(year, month, d->daysInMonth(year, month), testJd); } dateToJulianDay(year, month, 1, testJd); day = jd - testJd + 1; return true; // Alternative implementations // More recent editions of "Calendrical Calculations" by Dershowitz & Reingold have a more // efficient direct calculation without recusrion, but this cannot be used due to licensing /* Formula from "Explanatory Supplement to the Astronomical Almanac" 2006, derived from Fliegel & Van Flandern 1968 int L = jd - epoch().toJulianDay() + 10632; int N = ( L - 1 ) / 10631; L = L - 10631 * N + 354; int J = ( ( 10985 - L ) / 5316 ) x ( ( 50* L ) / 17719 ) + ( L / 5670 ) * ( ( 43 * L ) / 15238 ); L = L - ( ( 30 - J ) / 15 ) * ( ( 17719 * J ) / 50 ) - ( J / 16 ) * ( ( 15238 * J ) / 43 ) + 29; year = ( 30 * N ) + J - 30; month = ( 24 * L ) / 709; day = L - ( ( 709 * month ) / 24 ); */ /* Formula from Fourmilab website jd = Math.floor(jd) + 0.5; year = Math.floor(((30 * (jd - epoch().toJulianDay())) + 10646) / 10631); month = qMin(12, Math.ceil((jd - (29 + islamic_to_jd(year, 1, 1))) / 29.5) + 1); day = (jd - islamic_to_jd(year, month, 1)) + 1; */ } bool KCalendarSystemIslamicCivil::dateToJulianDay(int year, int month, int day, int &jd) const { /* The following C++ code is translated from the Lisp code in ``Calendrical Calculations'' by Nachum Dershowitz and Edward M. Reingold, Software---Practice & Experience, vol. 20, no. 9 (September, 1990), pp. 899--928. This code is in the public domain, but any use of it should publically acknowledge its source. */ jd = epoch().toJulianDay() - 1 + // days before start of calendar (year - 1) * 354 + // non-leap days in prior years (3 + (11 * year)) / 30 + // leap days in prior years 29 * (month - 1) + // days so far... month / 2 + // ...this year day; // days so far this month return true; // Alternative implementations /* Formula from "Explanatory Supplement to the Astronomical Almanac" 2006, derived from Fliegel & Van Flandern 1968 jd = ( 3 + ( 11 * year ) ) / 30 + 354 * year + 30 * month - ( month - 1 ) / 2 + day + epoch().toJulianDay() - 385; */ }