diff options
Diffstat (limited to 'tdecore/kcalendarsystemhijri.cpp')
-rw-r--r-- | tdecore/kcalendarsystemhijri.cpp | 596 |
1 files changed, 596 insertions, 0 deletions
diff --git a/tdecore/kcalendarsystemhijri.cpp b/tdecore/kcalendarsystemhijri.cpp new file mode 100644 index 000000000..90faec48e --- /dev/null +++ b/tdecore/kcalendarsystemhijri.cpp @@ -0,0 +1,596 @@ +/* + Copyright (c) 2002-2003 Carlos Moro <cfmoro@correo.uniovi.es> + Copyright (c) 2002-2003 Hans Petter Bieker <bieker@kde.org> + + 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. +*/ + +// Derived hijri kde calendar class + +#include <tqdatetime.h> +#include <tqstring.h> + +#include <klocale.h> +#include <kdebug.h> + +#include "kcalendarsystemhijri.h" + +/* + 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. + + Classes GregorianDate, IslamicDate + */ + +static int lastDayOfGregorianMonth(int month, int year) { +// Compute the last date of the month for the Gregorian calendar. + + switch (month) { + case 2: + if ((((year % 4) == 0) && ((year % 100) != 0)) + || ((year % 400) == 0)) + return 29; + else + return 28; + case 4: + case 6: + case 9: + case 11: return 30; + default: return 31; + } +} + +class GregorianDate { +private: + int year; // 1... + int month; // 1 == January, ..., 12 == December + int day; // 1..lastDayOfGregorianMonth(month, year) + +public: + GregorianDate(int m, int d, int y) { month = m; day = d; year = y; } + + GregorianDate(int d) { // Computes the Gregorian date from the absolute date. + + // Search forward year by year from approximate year + year = d/366; + while (d >= GregorianDate(1,1,year+1)) + year++; + // Search forward month by month from January + month = 1; + while (d > GregorianDate(month, lastDayOfGregorianMonth(month,year), year)) + month++; + day = d - GregorianDate(month,1,year) + 1; + } + + operator int() { // Computes the absolute date from the Gregorian date. + int N = day; // days this month + for (int m = month - 1; m > 0; m--) // days in prior months this year + N = N + lastDayOfGregorianMonth(m, year); + return + (N // days this year + + 365 * (year - 1) // days in previous years ignoring leap days + + (year - 1)/4 // Julian leap days before this year... + - (year - 1)/100 // ...minus prior century years... + + (year - 1)/400); // ...plus prior years divisible by 400 + } + + int getMonth() { return month; } + int getDay() { return day; } + int getYear() { return year; } + +}; + +static int IslamicLeapYear(int year) { +// True if year is an Islamic leap year + + if ((((11 * year) + 14) % 30) < 11) + return 1; + else + return 0; +} + +static const int IslamicEpoch = 227014; // Absolute date of start of + // Islamic calendar + +static int lastDayOfIslamicMonth(int month, int year) { +// Last day in month during year on the Islamic calendar. + + if (((month % 2) == 1) || ((month == 12) && IslamicLeapYear(year))) + return 30; + else + return 29; +} + +class IslamicDate { +private: + int year; // 1... + int month; // 1..13 (12 in a common year) + int day; // 1..lastDayOfIslamicMonth(month,year) + +public: + IslamicDate(int m, int d, int y) { month = m; day = d; year = y; } + + IslamicDate(int d) { // Computes the Islamic date from the absolute date. + if (d <= IslamicEpoch) { // Date is pre-Islamic + month = 0; + day = 0; + year = 0; + } + else { + // Search forward year by year from approximate year + year = (d - IslamicEpoch) / 355; + while (d >= IslamicDate(1,1,year+1)) + year++; + // Search forward month by month from Muharram + month = 1; + while (d > IslamicDate(month, lastDayOfIslamicMonth(month,year), year)) + month++; + day = d - IslamicDate(month,1,year) + 1; + } + } + + operator int() { // Computes the absolute date from the Islamic date. + return (day // days so far this month + + 29 * (month - 1) // days so far... + + month/2 // ...this year + + 354 * (year - 1) // non-leap days in prior years + + (3 + (11 * year)) / 30 // leap days in prior years + + IslamicEpoch); // days before start of calendar + } + + int getMonth() { return month; } + int getDay() { return day; } + int getYear() { return year; } + +}; + +static void gregorianToHijri(const TQDate & date, int * pYear, int * pMonth, + int * pDay) +{ + GregorianDate gregorian(date.month(),date.day(),date.year()); + int absolute = gregorian; + + IslamicDate islamic(absolute); + + if (pYear) + *pYear = islamic.getYear(); + if (pMonth) + *pMonth = islamic.getMonth(); + if (pDay) + *pDay = islamic.getDay(); +} + +KCalendarSystemHijri::KCalendarSystemHijri(const KLocale * locale) + : KCalendarSystem(locale) +{ +} + +KCalendarSystemHijri::~KCalendarSystemHijri() +{ +} + +int KCalendarSystemHijri::year(const TQDate& date) const +{ + int y; + gregorianToHijri(date, &y, 0, 0); + return y; +} + +int KCalendarSystemHijri::month(const TQDate& date) const +{ + int m; + gregorianToHijri(date, 0, &m, 0); + return m; +} + +int KCalendarSystemHijri::day(const TQDate& date) const +{ + int d; + gregorianToHijri(date, 0, 0, &d); + return d; +} + +int KCalendarSystemHijri::monthsInYear( const TQDate & date ) const +{ + Q_UNUSED( date ) + + return 12; +} + +int KCalendarSystemHijri::weeksInYear(int year) const +{ + TQDate temp; + setYMD(temp, year, 12, lastDayOfIslamicMonth(12, year)); + + // If the last day of the year is in the first week, we have to check the + // week before + if ( weekNumber(temp) == 1 ) + temp = addDays(temp, -7); + + return weekNumber(temp); +} + +int KCalendarSystemHijri::weekNumber(const TQDate& date, int * yearNum) const +{ + TQDate firstDayWeek1, lastDayOfYear; + int y = year(date); + int week; + int weekDay1, dayOfWeek1InYear; + + // let's guess 1st day of 1st week + setYMD(firstDayWeek1, y, 1, 1); + weekDay1 = dayOfWeek(firstDayWeek1); + + // iso 8601: week 1 is the first containing thursday and week starts on + // monday + if (weekDay1 > 4 ) + firstDayWeek1 = addDays(firstDayWeek1 , 7 - weekDay1 + 1); // next monday + + dayOfWeek1InYear = dayOfYear(firstDayWeek1); + + if ( dayOfYear(date) < dayOfWeek1InYear ) // our date in prev year's week + { + if ( yearNum ) + *yearNum = y - 1; + return weeksInYear(y - 1); + } + + // let' check if its last week belongs to next year + setYMD(lastDayOfYear, y, 12, lastDayOfIslamicMonth(12, y)); + if ( (dayOfYear(date) >= daysInYear(date) - dayOfWeek(lastDayOfYear) + 1) + // our date is in last week + && dayOfWeek(lastDayOfYear) < 4) // 1st week in next year has thursday + { + if ( yearNum ) + *yearNum = y + 1; + week = 1; + } + else + { + if ( weekDay1 < 5 ) + firstDayWeek1 = addDays(firstDayWeek1, - (weekDay1 - 1)); + + week = firstDayWeek1.daysTo(date) / 7 + 1; + } + + return week; +} + +TQString KCalendarSystemHijri::monthName(const TQDate& date, + bool shortName) const +{ + return monthName(month(date), year(date), shortName); +} + +TQString KCalendarSystemHijri::monthNamePossessive(const TQDate& date, + bool shortName) const +{ + return monthNamePossessive(month(date), year(date), shortName); +} + +TQString KCalendarSystemHijri::monthName(int month, int year, bool shortName) + const { + + Q_UNUSED(year); + + if (shortName) + switch ( month ) + { + case 1: + return locale()->translate("Muharram"); + case 2: + return locale()->translate("Safar"); + case 3: + return locale()->translate("R. Awal"); + case 4: + return locale()->translate("R. Thaani"); + case 5: + return locale()->translate("J. Awal"); + case 6: + return locale()->translate("J. Thaani"); + case 7: + return locale()->translate("Rajab"); + case 8: + return locale()->translate("Sha`ban"); + case 9: + return locale()->translate("Ramadan"); + case 10: + return locale()->translate("Shawwal"); + case 11: + return locale()->translate("Qi`dah"); + case 12: + return locale()->translate("Hijjah"); + } + else + switch ( month ) + { + case 1: + return locale()->translate("Muharram"); + case 2: + return locale()->translate("Safar"); + case 3: + return locale()->translate("Rabi` al-Awal"); + case 4: + return locale()->translate("Rabi` al-Thaani"); + case 5: + return locale()->translate("Jumaada al-Awal"); + case 6: + return locale()->translate("Jumaada al-Thaani"); + case 7: + return locale()->translate("Rajab"); + case 8: + return locale()->translate("Sha`ban"); + case 9: + return locale()->translate("Ramadan"); + case 10: + return locale()->translate("Shawwal"); + case 11: + return locale()->translate("Thu al-Qi`dah"); + case 12: + return locale()->translate("Thu al-Hijjah"); + } + + return TQString::null; +} + +TQString KCalendarSystemHijri::monthNamePossessive(int month, int year, + bool shortName) const +{ + Q_UNUSED(year); + + if (shortName) + switch ( month ) + { + case 1: + return locale()->translate("of Muharram"); + case 2: + return locale()->translate("of Safar"); + case 3: + return locale()->translate("of R. Awal"); + case 4: + return locale()->translate("of R. Thaani"); + case 5: + return locale()->translate("of J. Awal"); + case 6: + return locale()->translate("of J. Thaani"); + case 7: + return locale()->translate("of Rajab"); + case 8: + return locale()->translate("of Sha`ban"); + case 9: + return locale()->translate("of Ramadan"); + case 10: + return locale()->translate("of Shawwal"); + case 11: + return locale()->translate("of Qi`dah"); + case 12: + return locale()->translate("of Hijjah"); + } + else + switch ( month ) + { + case 1: + return locale()->translate("of Muharram"); + case 2: + return locale()->translate("of Safar"); + case 3: + return locale()->translate("of Rabi` al-Awal"); + case 4: + return locale()->translate("of Rabi` al-Thaani"); + case 5: + return locale()->translate("of Jumaada al-Awal"); + case 6: + return locale()->translate("of Jumaada al-Thaani"); + case 7: + return locale()->translate("of Rajab"); + case 8: + return locale()->translate("of Sha`ban"); + case 9: + return locale()->translate("of Ramadan"); + case 10: + return locale()->translate("of Shawwal"); + case 11: + return locale()->translate("of Thu al-Qi`dah"); + case 12: + return locale()->translate("of Thu al-Hijjah"); + } + + return TQString::null; +} + +bool KCalendarSystemHijri::setYMD(TQDate & date, int y, int m, int d) const +{ + // range checks + if ( y < minValidYear() || y > maxValidYear() ) + return false; + + if ( m < 1 || m > 12 ) + return false; + + if ( d < 1 || d > lastDayOfIslamicMonth(m, y) ) + return false; + + IslamicDate islamic (m, d, y); + int absolute = islamic; + GregorianDate gregorian(absolute); + + return date.setYMD(gregorian.getYear(), gregorian.getMonth(), + gregorian.getDay()); +} + +TQString KCalendarSystemHijri::weekDayName(int day, bool shortName) const +{ + if ( shortName ) + switch (day) + { + case 1: + return locale()->translate("Ith"); + case 2: + return locale()->translate("Thl"); + case 3: + return locale()->translate("Arb"); + case 4: + return locale()->translate("Kha"); + case 5: + return locale()->translate("Jum"); + case 6: + return locale()->translate("Sab"); + case 7: + return locale()->translate("Ahd"); + } + else + switch ( day ) + { + case 1: + return locale()->translate("Yaum al-Ithnain"); + case 2: + return locale()->translate("Yau al-Thulatha"); + case 3: + return locale()->translate("Yaum al-Arbi'a"); + case 4: + return locale()->translate("Yaum al-Khamees"); + case 5: + return locale()->translate("Yaum al-Jumma"); + case 6: + return locale()->translate("Yaum al-Sabt"); + case 7: + return locale()->translate("Yaum al-Ahad"); + } + + return TQString::null; +} + +TQString KCalendarSystemHijri::weekDayName(const TQDate& date, + bool shortName) const +{ + return weekDayName(dayOfWeek(date), shortName); +} + +int KCalendarSystemHijri::dayOfWeek(const TQDate& date) const +{ + return date.dayOfWeek(); // same as gregorian +} + +int KCalendarSystemHijri::dayOfYear(const TQDate & date) const +{ + TQDate first; + setYMD(first, year(date), 1, 1); + + return first.daysTo(date) + 1; + + return 100; +} + +int KCalendarSystemHijri::daysInMonth(const TQDate& date) const +{ + int y, m; + gregorianToHijri(date, &y, &m, 0); + + return lastDayOfIslamicMonth(m, y); +} + +// Min valid year that may be converted to QDate +int KCalendarSystemHijri::minValidYear() const +{ + TQDate date(1753, 1, 1); + + return year(date); +} + +// Max valid year that may be converted to QDate +int KCalendarSystemHijri::maxValidYear() const +{ + TQDate date(8000, 1, 1); + + return year(date); +} + +int KCalendarSystemHijri::daysInYear(const TQDate & date) const +{ + TQDate first, last; + setYMD(first, year(date), 1, 1); + setYMD(last, year(date) + 1, 1, 1); + + return first.daysTo(last); +} + +int KCalendarSystemHijri::weekDayOfPray() const +{ + return 5; // friday +} + +TQDate KCalendarSystemHijri::addDays( const TQDate & date, int ndays ) const +{ + return TQT_TQDATE_OBJECT(date.addDays( ndays )); +} + +TQDate KCalendarSystemHijri::addMonths( const TQDate & date, int nmonths ) const +{ + TQDate result = date; + int m = month(date); + int y = year(date); + + if ( nmonths < 0 ) + { + m += 12; + y -= 1; + } + + --m; // this only works if we start counting at zero + m += nmonths; + y += m / 12; + m %= 12; + ++m; + + setYMD( result, y, m, day(date) ); + + return result; +} + +TQDate KCalendarSystemHijri::addYears( const TQDate & date, int nyears ) const +{ + TQDate result = date; + int y = year(date) + nyears; + + setYMD( result, y, month(date), day(date) ); + + return result; +} + +TQString KCalendarSystemHijri::calendarName() const +{ + return TQString::tqfromLatin1("hijri"); +} + +bool KCalendarSystemHijri::isLunar() const +{ + return true; +} + +bool KCalendarSystemHijri::isLunisolar() const +{ + return false; +} + +bool KCalendarSystemHijri::isSolar() const +{ + return false; +} |