00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "kcalendarsystemhijri.h"
00025
00026 #include "kdebug.h"
00027 #include "klocale.h"
00028
00029 #include <QtCore/QDate>
00030 #include <QtCore/QCharRef>
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050 static int lastDayOfGregorianMonth( int month, int year )
00051 {
00052
00053
00054 switch ( month ) {
00055 case 2:
00056 if ( ( ( ( year % 4 ) == 0 ) && ( ( year % 100 ) != 0 ) )
00057 || ( ( year % 400 ) == 0 ) ) {
00058 return 29;
00059 } else {
00060 return 28;
00061 }
00062 case 4:
00063 case 6:
00064 case 9:
00065 case 11: return 30;
00066 default: return 31;
00067 }
00068 }
00069
00070 class GregorianDate
00071 {
00072 private:
00073 int year;
00074 int month;
00075 int day;
00076
00077 public:
00078 GregorianDate( int m, int d, int y )
00079 {
00080 month = m; day = d; year = y;
00081 }
00082
00083
00084 GregorianDate( int d )
00085 {
00086
00087 year = d / 366;
00088 while ( d >= GregorianDate( 1, 1, year + 1 ) ) {
00089 year++;
00090 }
00091
00092 month = 1;
00093 while ( d > GregorianDate( month, lastDayOfGregorianMonth( month, year ), year ) ) {
00094 month++;
00095 }
00096 day = d - GregorianDate( month, 1, year ) + 1;
00097 }
00098
00099
00100 operator int()
00101 {
00102 int N = day;
00103 for ( int m = month - 1; m > 0; m-- )
00104 N = N + lastDayOfGregorianMonth( m, year );
00105 return
00106 ( N
00107 + 365 * ( year - 1 )
00108 + ( year - 1 ) / 4
00109 - ( year - 1 ) / 100
00110 + ( year - 1 ) / 400 );
00111 }
00112
00113 int getMonth()
00114 {
00115 return month;
00116 }
00117
00118 int getDay()
00119 {
00120 return day;
00121 }
00122
00123 int getYear()
00124 {
00125 return year;
00126 }
00127
00128 };
00129
00130 static int IslamicLeapYear( int year )
00131 {
00132
00133
00134 if ( ( ( ( 11 * year ) + 14 ) % 30 ) < 11 ) {
00135 return 1;
00136 } else {
00137 return 0;
00138 }
00139 }
00140
00141 static const int IslamicEpoch = 227014;
00142
00143
00144 static int lastDayOfIslamicMonth( int month, int year )
00145 {
00146
00147
00148 if ( ( ( month % 2 ) == 1 ) || ( ( month == 12 ) && IslamicLeapYear( year ) ) ) {
00149 return 30;
00150 } else {
00151 return 29;
00152 }
00153 }
00154
00155 class IslamicDate
00156 {
00157 private:
00158 int year;
00159 int month;
00160 int day;
00161
00162 public:
00163 IslamicDate( int m, int d, int y )
00164 {
00165 month = m; day = d; year = y;
00166 }
00167
00168
00169 IslamicDate( int d )
00170 {
00171 if ( d <= IslamicEpoch ) {
00172 month = 0;
00173 day = 0;
00174 year = 0;
00175 } else {
00176
00177 year = ( d - IslamicEpoch ) / 355;
00178 while ( d >= IslamicDate( 1, 1, year + 1 ) ) {
00179 year++;
00180 }
00181
00182 month = 1;
00183 while ( d > IslamicDate( month, lastDayOfIslamicMonth( month, year ), year ) ) {
00184 month++;
00185 }
00186 day = d - IslamicDate( month, 1, year ) + 1;
00187 }
00188 }
00189
00190
00191 operator int()
00192 {
00193 return ( day
00194 + 29 * ( month - 1 )
00195 + month / 2
00196 + 354 * ( year - 1 )
00197 + ( 3 + ( 11 * year ) ) / 30
00198 + IslamicEpoch );
00199 }
00200
00201 int getMonth()
00202 {
00203 return month;
00204 }
00205
00206 int getDay()
00207 {
00208 return day;
00209 }
00210
00211 int getYear()
00212 {
00213 return year;
00214 }
00215
00216 };
00217
00218 static void gregorianToHijri( const QDate & date, int *pYear, int *pMonth, int * pDay )
00219 {
00220 GregorianDate gregorian( date.month(), date.day(), date.year() );
00221 int absolute = gregorian;
00222
00223 IslamicDate islamic( absolute );
00224
00225 if ( pYear ) {
00226 * pYear = islamic.getYear();
00227 }
00228
00229 if ( pMonth ) {
00230 * pMonth = islamic.getMonth();
00231 }
00232
00233 if ( pDay ) {
00234 * pDay = islamic.getDay();
00235 }
00236 }
00237
00238
00239
00240
00241
00242 KCalendarSystemHijri::KCalendarSystemHijri( const KLocale * locale )
00243 : KCalendarSystem( locale ), d( 0 )
00244 {
00245 }
00246
00247 KCalendarSystemHijri::~KCalendarSystemHijri()
00248 {
00249 }
00250
00251 QString KCalendarSystemHijri::calendarType() const
00252 {
00253 return QLatin1String( "hijri" );
00254 }
00255
00256 QDate KCalendarSystemHijri::epoch() const
00257 {
00258
00259 return QDate::fromJulianDay( 1948440 );
00260 }
00261
00262 QDate KCalendarSystemHijri::earliestValidDate() const
00263 {
00264 return KCalendarSystem::earliestValidDate();
00265 }
00266
00267 QDate KCalendarSystemHijri::latestValidDate() const
00268 {
00269
00270
00271
00272
00273
00274 return QDate( 10323, 10, 21 );
00275 }
00276
00277 bool KCalendarSystemHijri::isValid( int y, int month, int day ) const
00278 {
00279
00280 if ( y < year( earliestValidDate() ) || y > year( latestValidDate() ) ) {
00281 return false;
00282 }
00283
00284 if ( month < 1 || month > 12 ) {
00285 return false;
00286 }
00287
00288 if ( day < 1 || day > lastDayOfIslamicMonth( month, y ) ) {
00289 return false;
00290 }
00291
00292 return true;
00293 }
00294
00295 bool KCalendarSystemHijri::isValid( const QDate &date ) const
00296 {
00297 return KCalendarSystem::isValid( date );
00298 }
00299
00300 bool KCalendarSystemHijri::setDate( QDate &date, int year, int month, int day ) const
00301 {
00302 return KCalendarSystem::setDate( date, year, month, day );
00303 }
00304
00305
00306 bool KCalendarSystemHijri::setYMD( QDate &date, int y, int m, int d ) const
00307 {
00308
00309
00310
00311
00312
00313 if ( y < year( QDate( 1753, 1, 1 ) ) || y > 9999 ) {
00314 return false;
00315 }
00316
00317 if ( m < 1 || m > 12 ) {
00318 return false;
00319 }
00320
00321 if ( d < 1 || d > lastDayOfIslamicMonth( m, y ) ) {
00322 return false;
00323 }
00324
00325 IslamicDate islamic ( m, d, y );
00326 int absolute = islamic;
00327 GregorianDate gregorian( absolute );
00328
00329 return date.setYMD( gregorian.getYear(), gregorian.getMonth(), gregorian.getDay() );
00330 }
00331
00332 int KCalendarSystemHijri::year( const QDate &date ) const
00333 {
00334 int y;
00335
00336 gregorianToHijri( date, &y, 0, 0 );
00337
00338 return y;
00339 }
00340
00341 int KCalendarSystemHijri::month( const QDate &date ) const
00342 {
00343 int m;
00344 gregorianToHijri( date, 0, &m, 0 );
00345 return m;
00346 }
00347
00348 int KCalendarSystemHijri::day( const QDate &date ) const
00349 {
00350 int d;
00351
00352 gregorianToHijri( date, 0, 0, &d );
00353
00354 return d;
00355 }
00356
00357 QDate KCalendarSystemHijri::addYears( const QDate &date, int nyears ) const
00358 {
00359 QDate result = date;
00360
00361 int y = year( date ) + nyears;
00362 int m = month( date );
00363
00364
00365 if ( setYMD( result, y, m, 1 ) ) {
00366 setYMD( result, y, m, qMin( day( date ), daysInMonth( result ) ) );
00367 }
00368
00369 return result;
00370
00371
00372
00373
00374 }
00375
00376 QDate KCalendarSystemHijri::addMonths( const QDate &date, int nmonths ) const
00377 {
00378 QDate result = date;
00379 int m = month( date );
00380 int y = year( date );
00381
00382 if ( nmonths < 0 ) {
00383 m += 12;
00384 y -= 1;
00385 }
00386
00387 --m;
00388 m += nmonths;
00389 y += m / 12;
00390 m %= 12;
00391 ++m;
00392
00393
00394 if ( setYMD( result, y, m, 1 ) ) {
00395 setYMD( result, y, m, qMin( day( date ), daysInMonth( result ) ) );
00396 }
00397
00398 return result;
00399
00400
00401
00402
00403 }
00404
00405 QDate KCalendarSystemHijri::addDays( const QDate &date, int ndays ) const
00406 {
00407 return date.addDays( ndays );
00408 }
00409
00410 int KCalendarSystemHijri::monthsInYear( const QDate &date ) const
00411 {
00412 Q_UNUSED( date )
00413
00414 return 12;
00415 }
00416
00417 int KCalendarSystemHijri::weeksInYear( const QDate &date ) const
00418 {
00419 return KCalendarSystem::weeksInYear( date );
00420 }
00421
00422 int KCalendarSystemHijri::weeksInYear( int year ) const
00423 {
00424 QDate temp;
00425 setYMD( temp, year, 12, lastDayOfIslamicMonth( 12, year ) );
00426
00427
00428
00429 if ( weekNumber( temp ) == 1 ) {
00430 temp = addDays( temp, -7 );
00431 }
00432
00433 return weekNumber( temp );
00434 }
00435
00436 int KCalendarSystemHijri::daysInYear( const QDate &date ) const
00437 {
00438 QDate first, last;
00439
00440 setYMD( first, year( date ), 1, 1 );
00441 setYMD( last, year( date ) + 1, 1, 1 );
00442
00443 return first.daysTo( last );
00444 }
00445
00446 int KCalendarSystemHijri::daysInMonth( const QDate &date ) const
00447 {
00448 int y, m;
00449
00450 gregorianToHijri( date, &y, &m, 0 );
00451
00452 return lastDayOfIslamicMonth( m, y );
00453 }
00454
00455 int KCalendarSystemHijri::daysInWeek( const QDate &date ) const
00456 {
00457 return KCalendarSystem::daysInWeek( date );
00458 }
00459
00460 int KCalendarSystemHijri::dayOfYear( const QDate &date ) const
00461 {
00462 QDate first;
00463
00464 setYMD( first, year( date ), 1, 1 );
00465
00466 return first.daysTo( date ) + 1;
00467 }
00468
00469 int KCalendarSystemHijri::dayOfWeek( const QDate &date ) const
00470 {
00471 return date.dayOfWeek();
00472 }
00473
00474 int KCalendarSystemHijri::weekNumber( const QDate &date, int *yearNum ) const
00475 {
00476 QDate firstDayWeek1, lastDayOfYear;
00477 int y = year( date );
00478 int week;
00479 int weekDay1, dayOfWeek1InYear;
00480
00481
00482 setYMD( firstDayWeek1, y, 1, 1 );
00483 weekDay1 = dayOfWeek( firstDayWeek1 );
00484
00485
00486
00487 if ( weekDay1 > 4 ) {
00488 firstDayWeek1 = addDays( firstDayWeek1 , 7 - weekDay1 + 1 );
00489 }
00490
00491 dayOfWeek1InYear = dayOfYear( firstDayWeek1 );
00492
00493
00494 if ( dayOfYear( date ) < dayOfWeek1InYear ) {
00495 if ( yearNum ) {
00496 * yearNum = y - 1;
00497 }
00498 return weeksInYear( y - 1 );
00499 }
00500
00501
00502 setYMD( lastDayOfYear, y, 12, lastDayOfIslamicMonth( 12, y ) );
00503
00504 if ( ( dayOfYear( date ) >= daysInYear( date ) - dayOfWeek( lastDayOfYear ) + 1 )
00505 && dayOfWeek( lastDayOfYear ) < 4 ) {
00506 if ( yearNum ) {
00507 * yearNum = y + 1;
00508 }
00509 week = 1;
00510 } else {
00511 if ( weekDay1 < 5 ) {
00512 firstDayWeek1 = addDays( firstDayWeek1, - ( weekDay1 - 1 ) );
00513 }
00514
00515 week = firstDayWeek1.daysTo( date ) / 7 + 1;
00516 }
00517
00518 return week;
00519 }
00520
00521 bool KCalendarSystemHijri::isLeapYear( int year ) const
00522 {
00523
00524 if ( ( ( ( 11 * year ) + 14 ) % 30 ) < 11 ) {
00525 return true;
00526 } else {
00527 return false;
00528 }
00529 }
00530
00531 bool KCalendarSystemHijri::isLeapYear( const QDate &date ) const
00532 {
00533 return KCalendarSystem::isLeapYear( year( date ) );
00534 }
00535
00536 QString KCalendarSystemHijri::monthName( int month, int year, MonthNameFormat format ) const
00537 {
00538 Q_UNUSED( year );
00539
00540 if ( format == ShortNamePossessive ) {
00541 switch ( month ) {
00542 case 1:
00543 return ki18n( "of Muharram" ).toString( locale() );
00544 case 2:
00545 return ki18n( "of Safar" ).toString( locale() );
00546 case 3:
00547 return ki18n( "of R. Awal" ).toString( locale() );
00548 case 4:
00549 return ki18n( "of R. Thaani" ).toString( locale() );
00550 case 5:
00551 return ki18n( "of J. Awal" ).toString( locale() );
00552 case 6:
00553 return ki18n( "of J. Thaani" ).toString( locale() );
00554 case 7:
00555 return ki18n( "of Rajab" ).toString( locale() );
00556 case 8:
00557 return ki18n( "of Sha`ban" ).toString( locale() );
00558 case 9:
00559 return ki18n( "of Ramadan" ).toString( locale() );
00560 case 10:
00561 return ki18n( "of Shawwal" ).toString( locale() );
00562 case 11:
00563 return ki18n( "of Qi`dah" ).toString( locale() );
00564 case 12:
00565 return ki18n( "of Hijjah" ).toString( locale() );
00566 default:
00567 return QString();
00568 }
00569 }
00570
00571 if ( format == LongNamePossessive ) {
00572 switch ( month ) {
00573 case 1:
00574 return ki18n( "of Muharram" ).toString( locale() );
00575 case 2:
00576 return ki18n( "of Safar" ).toString( locale() );
00577 case 3:
00578 return ki18n( "of Rabi` al-Awal" ).toString( locale() );
00579 case 4:
00580 return ki18n( "of Rabi` al-Thaani" ).toString( locale() );
00581 case 5:
00582 return ki18n( "of Jumaada al-Awal" ).toString( locale() );
00583 case 6:
00584 return ki18n( "of Jumaada al-Thaani" ).toString( locale() );
00585 case 7:
00586 return ki18n( "of Rajab" ).toString( locale() );
00587 case 8:
00588 return ki18n( "of Sha`ban" ).toString( locale() );
00589 case 9:
00590 return ki18n( "of Ramadan" ).toString( locale() );
00591 case 10:
00592 return ki18n( "of Shawwal" ).toString( locale() );
00593 case 11:
00594 return ki18n( "of Thu al-Qi`dah" ).toString( locale() );
00595 case 12:
00596 return ki18n( "of Thu al-Hijjah" ).toString( locale() );
00597 default:
00598 return QString();
00599 }
00600 }
00601
00602 if ( format == ShortName ) {
00603 switch ( month ) {
00604 case 1:
00605 return ki18n( "Muharram" ).toString( locale() );
00606 case 2:
00607 return ki18n( "Safar" ).toString( locale() );
00608 case 3:
00609 return ki18n( "R. Awal" ).toString( locale() );
00610 case 4:
00611 return ki18n( "R. Thaani" ).toString( locale() );
00612 case 5:
00613 return ki18n( "J. Awal" ).toString( locale() );
00614 case 6:
00615 return ki18n( "J. Thaani" ).toString( locale() );
00616 case 7:
00617 return ki18n( "Rajab" ).toString( locale() );
00618 case 8:
00619 return ki18n( "Sha`ban" ).toString( locale() );
00620 case 9:
00621 return ki18n( "Ramadan" ).toString( locale() );
00622 case 10:
00623 return ki18n( "Shawwal" ).toString( locale() );
00624 case 11:
00625 return ki18n( "Qi`dah" ).toString( locale() );
00626 case 12:
00627 return ki18n( "Hijjah" ).toString( locale() );
00628 default:
00629 return QString();
00630 }
00631 }
00632
00633
00634 switch ( month ) {
00635 case 1:
00636 return ki18n( "Muharram" ).toString( locale() );
00637 case 2:
00638 return ki18n( "Safar" ).toString( locale() );
00639 case 3:
00640 return ki18n( "Rabi` al-Awal" ).toString( locale() );
00641 case 4:
00642 return ki18n( "Rabi` al-Thaani" ).toString( locale() );
00643 case 5:
00644 return ki18n( "Jumaada al-Awal" ).toString( locale() );
00645 case 6:
00646 return ki18n( "Jumaada al-Thaani" ).toString( locale() );
00647 case 7:
00648 return ki18n( "Rajab" ).toString( locale() );
00649 case 8:
00650 return ki18n( "Sha`ban" ).toString( locale() );
00651 case 9:
00652 return ki18n( "Ramadan" ).toString( locale() );
00653 case 10:
00654 return ki18n( "Shawwal" ).toString( locale() );
00655 case 11:
00656 return ki18n( "Thu al-Qi`dah" ).toString( locale() );
00657 case 12:
00658 return ki18n( "Thu al-Hijjah" ).toString( locale() );
00659 default:
00660 return QString();
00661 }
00662 }
00663
00664 QString KCalendarSystemHijri::monthName( const QDate &date, MonthNameFormat format ) const
00665 {
00666 return monthName( month( date ), year( date ), format );
00667 }
00668
00669 QString KCalendarSystemHijri::weekDayName( int weekDay, WeekDayNameFormat format ) const
00670 {
00671 if ( format == ShortDayName ) {
00672 switch ( weekDay ) {
00673 case 1:
00674 return ki18n( "Ith" ).toString( locale() );
00675 case 2:
00676 return ki18n( "Thl" ).toString( locale() );
00677 case 3:
00678 return ki18n( "Arb" ).toString( locale() );
00679 case 4:
00680 return ki18n( "Kha" ).toString( locale() );
00681 case 5:
00682 return ki18n( "Jum" ).toString( locale() );
00683 case 6:
00684 return ki18n( "Sab" ).toString( locale() );
00685 case 7:
00686 return ki18n( "Ahd" ).toString( locale() );
00687 default:
00688 return QString();
00689 }
00690 }
00691
00692
00693 switch ( weekDay ) {
00694 case 1:
00695 return ki18n( "Yaum al-Ithnain" ).toString( locale() );
00696 case 2:
00697 return ki18n( "Yau al-Thulatha" ).toString( locale() );
00698 case 3:
00699 return ki18n( "Yaum al-Arbi'a" ).toString( locale() );
00700 case 4:
00701 return ki18n( "Yaum al-Khamees" ).toString( locale() );
00702 case 5:
00703 return ki18n( "Yaum al-Jumma" ).toString( locale() );
00704 case 6:
00705 return ki18n( "Yaum al-Sabt" ).toString( locale() );
00706 case 7:
00707 return ki18n( "Yaum al-Ahad" ).toString( locale() );
00708 default:
00709 return QString();
00710 }
00711 }
00712
00713 QString KCalendarSystemHijri::weekDayName( const QDate &date, WeekDayNameFormat format ) const
00714 {
00715 return weekDayName( dayOfWeek( date ), format );
00716 }
00717
00718 QString KCalendarSystemHijri::yearString( const QDate &pDate, StringFormat format ) const
00719 {
00720 return KCalendarSystem::yearString( pDate, format );
00721 }
00722
00723 QString KCalendarSystemHijri::monthString( const QDate &pDate, StringFormat format ) const
00724 {
00725 return KCalendarSystem::monthString( pDate, format );
00726 }
00727
00728 QString KCalendarSystemHijri::dayString( const QDate &pDate, StringFormat format ) const
00729 {
00730 return KCalendarSystem::dayString( pDate, format );
00731 }
00732
00733 int KCalendarSystemHijri::yearStringToInteger( const QString &sNum, int &iLength ) const
00734 {
00735 return KCalendarSystem::yearStringToInteger( sNum, iLength );
00736 }
00737
00738 int KCalendarSystemHijri::monthStringToInteger( const QString &sNum, int &iLength ) const
00739 {
00740 return KCalendarSystem::monthStringToInteger( sNum, iLength );
00741 }
00742
00743 int KCalendarSystemHijri::dayStringToInteger( const QString &sNum, int &iLength ) const
00744 {
00745 return KCalendarSystem::dayStringToInteger( sNum, iLength );
00746 }
00747
00748 QString KCalendarSystemHijri::formatDate( const QDate &date, KLocale::DateFormat format ) const
00749 {
00750 return KCalendarSystem::formatDate( date, format );
00751 }
00752
00753 QDate KCalendarSystemHijri::readDate( const QString &str, bool *ok ) const
00754 {
00755 return KCalendarSystem::readDate( str, ok );
00756 }
00757
00758 QDate KCalendarSystemHijri::readDate( const QString &intstr, const QString &fmt, bool *ok ) const
00759 {
00760 return KCalendarSystem::readDate( intstr, fmt, ok );
00761 }
00762
00763 QDate KCalendarSystemHijri::readDate( const QString &str, KLocale::ReadDateFlags flags, bool *ok ) const
00764 {
00765 return KCalendarSystem::readDate( str, flags, ok );
00766 }
00767
00768 int KCalendarSystemHijri::weekStartDay() const
00769 {
00770 return KCalendarSystem::weekStartDay();
00771 }
00772
00773 int KCalendarSystemHijri::weekDayOfPray() const
00774 {
00775 return 5;
00776 }
00777
00778 bool KCalendarSystemHijri::isLunar() const
00779 {
00780 return true;
00781 }
00782
00783 bool KCalendarSystemHijri::isLunisolar() const
00784 {
00785 return false;
00786 }
00787
00788 bool KCalendarSystemHijri::isSolar() const
00789 {
00790 return false;
00791 }
00792
00793 bool KCalendarSystemHijri::isProleptic() const
00794 {
00795 return false;
00796 }
00797
00798 bool KCalendarSystemHijri::julianDayToDate( int jd, int &year, int &month, int &day ) const
00799 {
00800
00801 if ( jd >= earliestValidDate().toJulianDay() && jd <= latestValidDate().toJulianDay() ) {
00802
00803 year = ( jd - epoch().toJulianDay() ) / 355;
00804 while ( jd >= IslamicDate( 1, 1, year + 1 ) ) {
00805 year++;
00806 }
00807
00808 month = 1;
00809 while ( jd > IslamicDate( month, lastDayOfIslamicMonth( month, year ), year ) ) {
00810 month++;
00811 }
00812 day = jd - IslamicDate( month, 1, year ) + 1;
00813 return true;
00814 }
00815
00816 return false;
00817 }
00818
00819 bool KCalendarSystemHijri::dateToJulianDay( int year, int month, int day, int &jd ) const
00820 {
00821
00822 if ( isValid( year, month, day ) ) {
00823 jd = ( day
00824 + 29 * ( month - 1 )
00825 + month / 2
00826 + 354 * ( year - 1 )
00827 + ( 3 + ( 11 * year ) ) / 30
00828 + epoch().toJulianDay() );
00829 return true;
00830 }
00831
00832 return false;
00833 }
00834