You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdelibs/tdecore/kcalendarsystemhijri.cpp

597 lines
15 KiB

/*
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 <tdelocale.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 TDELocale * 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::fromLatin1("hijri");
}
bool KCalendarSystemHijri::isLunar() const
{
return true;
}
bool KCalendarSystemHijri::isLunisolar() const
{
return false;
}
bool KCalendarSystemHijri::isSolar() const
{
return false;
}