00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "kcalendarsystem.h"
00023
00024 #include "kglobal.h"
00025
00026 #include <QtCore/QDateTime>
00027
00028 #include "kcalendarsystemgregorian.h"
00029 #include "kcalendarsystemhebrew.h"
00030 #include "kcalendarsystemhijri.h"
00031 #include "kcalendarsystemjalali.h"
00032
00033 KCalendarSystem *KCalendarSystem::create( const QString &calendarType, const KLocale *locale )
00034 {
00035 if ( calendarType == "hebrew" ) {
00036 return new KCalendarSystemHebrew( locale );
00037 }
00038
00039 if ( calendarType == "hijri" ) {
00040 return new KCalendarSystemHijri( locale );
00041 }
00042
00043 if ( calendarType == "gregorian" ) {
00044 return new KCalendarSystemGregorian( locale );
00045 }
00046
00047 if ( calendarType == "jalali" ) {
00048 return new KCalendarSystemJalali( locale );
00049 }
00050
00051
00052 return new KCalendarSystemGregorian( locale );
00053 }
00054
00055 QStringList KCalendarSystem::calendarSystems()
00056 {
00057 QStringList lst;
00058
00059 lst.append( "hebrew" );
00060 lst.append( "hijri" );
00061 lst.append( "gregorian" );
00062 lst.append( "jalali" );
00063
00064 return lst;
00065 }
00066
00067 QString KCalendarSystem::calendarLabel( const QString &calendarType )
00068 {
00069 if ( calendarType == "gregorian" ) {
00070 return ki18nc( "@item Calendar system", "Gregorian" ).toString( KGlobal::locale() );
00071 }
00072
00073 if ( calendarType == "hebrew" ) {
00074 return ki18nc( "@item Calendar system", "Hebrew" ).toString( KGlobal::locale() );
00075 }
00076
00077 if ( calendarType == "hijri" ) {
00078 return ki18nc("@item Calendar system", "Hijri").toString( KGlobal::locale());
00079 }
00080
00081 if ( calendarType == "jalali" ) {
00082 return ki18nc( "@item Calendar system", "Jalali" ).toString( KGlobal::locale() );
00083 }
00084
00085 return ki18nc( "@item Calendar system", "Invalid Calendar Type" ).toString( KGlobal::locale() );
00086 }
00087
00088
00089 class KCalendarSystemPrivate
00090 {
00091 public:
00092 KCalendarSystemPrivate( KCalendarSystem *q ): q( q )
00093 {
00094 }
00095
00096 ~KCalendarSystemPrivate()
00097 {
00098 }
00099
00100 KCalendarSystem *q;
00101
00102 bool setAnyDate( QDate &date, int year, int month, int day ) const;
00103
00104 int stringToInteger( const QString &sNum, int &iLength );
00105
00106 const KLocale *locale;
00107 };
00108
00109
00110 bool KCalendarSystemPrivate::setAnyDate( QDate &date, int year, int month, int day ) const
00111 {
00112 int jd;
00113 q->dateToJulianDay( year, month, day, jd );
00114 date = QDate::fromJulianDay( jd );
00115 return true;
00116 }
00117
00118 int KCalendarSystemPrivate::stringToInteger( const QString &sNum, int &iLength )
00119 {
00120 int iPos = 0;
00121 int result = 0;
00122
00123 for ( ; sNum.length() > iPos && sNum.at( iPos ).isDigit(); iPos++ ) {
00124 result *= 10;
00125 result += sNum.at( iPos ).digitValue();
00126 }
00127 iLength = iPos;
00128
00129 return result;
00130 }
00131
00132 KCalendarSystem::KCalendarSystem( const KLocale *locale ) : d( new KCalendarSystemPrivate( this ) )
00133 {
00134 d->locale = locale;
00135 }
00136
00137 KCalendarSystem::~KCalendarSystem()
00138 {
00139 delete d;
00140 }
00141
00142
00143 QDate KCalendarSystem::epoch() const
00144 {
00145
00146 return QDate::fromJulianDay( 1 );
00147 }
00148
00149 QDate KCalendarSystem::earliestValidDate() const
00150 {
00151 return epoch();
00152 }
00153
00154
00155 QDate KCalendarSystem::latestValidDate() const
00156 {
00157
00158 return QDate::fromJulianDay( 5373484 );
00159 }
00160
00161
00162 bool KCalendarSystem::isValid( int y, int month, int day ) const
00163 {
00164
00165
00166 if ( y < year( earliestValidDate() ) || y > year( latestValidDate() ) ) {
00167 return false;
00168 }
00169
00170 if ( month < 1 || month > 12 ) {
00171 return false;
00172 }
00173
00174 if ( month == 2 ) {
00175 if ( isLeapYear( y ) ) {
00176 return ( day >= 1 && day <= 29 );
00177 } else {
00178 return ( day >= 1 && day <= 28 );
00179 }
00180 }
00181
00182 if ( month == 4 || month == 6 || month == 9 || month == 11 ) {
00183 return ( day >= 1 && day <= 30 );
00184 }
00185
00186 return ( day >= 1 && day <= 31 );
00187 }
00188
00189 bool KCalendarSystem::isValid( const QDate &date ) const
00190 {
00191 if ( date.isNull() || date < earliestValidDate() || date > latestValidDate() ) {
00192 return false;
00193 }
00194 return true;
00195 }
00196
00197 bool KCalendarSystem::setDate( QDate &date, int year, int month, int day ) const
00198 {
00199 if ( isValid( year, month, day ) ) {
00200 int jd;
00201 dateToJulianDay( year, month, day, jd );
00202 date = QDate::fromJulianDay( jd );
00203 return true;
00204 }
00205
00206 return false;
00207 }
00208
00209
00210 bool KCalendarSystem::setYMD( QDate &date, int year, int month, int day ) const
00211 {
00212 return setDate( date, year, month, day );
00213 }
00214
00215 int KCalendarSystem::year( const QDate &date ) const
00216 {
00217 if ( isValid( date ) ) {
00218 int year, month, day;
00219
00220 julianDayToDate( date.toJulianDay(), year, month, day );
00221
00222 return year;
00223 }
00224
00225 return 0;
00226 }
00227
00228 int KCalendarSystem::month( const QDate &date ) const
00229 {
00230 if ( isValid( date ) ) {
00231 int year, month, day;
00232
00233 julianDayToDate( date.toJulianDay(), year, month, day );
00234
00235 return month;
00236 }
00237
00238 return 0;
00239 }
00240
00241 int KCalendarSystem::day( const QDate &date ) const
00242 {
00243 if ( isValid( date ) ) {
00244 int year, month, day;
00245
00246 julianDayToDate( date.toJulianDay(), year, month, day );
00247
00248 return day;
00249 }
00250
00251 return 0;
00252 }
00253
00254 QDate KCalendarSystem::addYears( const QDate &date, int numYears ) const
00255 {
00256 if ( isValid( date ) ) {
00257
00258 int originalYear, originalMonth, originalDay;
00259 int newYear, newMonth, newDay;
00260 QDate firstOfNewMonth, newDate;
00261
00262 julianDayToDate( date.toJulianDay(), originalYear, originalMonth, originalDay );
00263
00264 newYear = originalYear + numYears;
00265 newMonth = originalMonth;
00266
00267
00268 if ( setDate( firstOfNewMonth, newYear, newMonth, 1 ) ) {
00269 int daysInNewMonth = daysInMonth( firstOfNewMonth );
00270 newDay = ( daysInNewMonth < originalDay ) ? daysInNewMonth : originalDay;
00271
00272 if ( setDate( newDate, newYear, newMonth, newDay ) ) {
00273 return newDate;
00274 }
00275 }
00276
00277 }
00278
00279
00280 return QDate::fromJulianDay( 0 );
00281 }
00282
00283 QDate KCalendarSystem::addMonths( const QDate &date, int numMonths ) const
00284 {
00285 if ( isValid( date ) ) {
00286
00287 int originalYear, originalMonth, originalDay;
00288 int newYear, newMonth, newDay;
00289 int monthsInOriginalYear, daysInNewMonth;
00290 QDate firstOfNewMonth, newDate;
00291
00292 julianDayToDate( date.toJulianDay(), originalYear, originalMonth, originalDay );
00293
00294 monthsInOriginalYear = monthsInYear( date );
00295
00296 newYear = originalYear + ( ( originalMonth + numMonths ) / monthsInOriginalYear );
00297 newMonth = ( originalMonth + numMonths ) % monthsInOriginalYear;
00298
00299 if ( newMonth == 0 ) {
00300 newYear = newYear - 1;
00301 newMonth = monthsInOriginalYear;
00302 }
00303 if ( newMonth < 0 ) {
00304 newYear = newYear - 1;
00305 newMonth = newMonth + monthsInOriginalYear;
00306 }
00307
00308
00309 if ( setDate( firstOfNewMonth, newYear, newMonth, 1 ) ) {
00310 daysInNewMonth = daysInMonth( firstOfNewMonth );
00311 newDay = ( daysInNewMonth < originalDay ) ? daysInNewMonth : originalDay;
00312
00313 if ( setDate( newDate, newYear, newMonth, newDay ) ) {
00314 return newDate;
00315 }
00316 }
00317
00318 }
00319
00320
00321 return QDate::fromJulianDay( 0 );
00322 }
00323
00324 QDate KCalendarSystem::addDays( const QDate &date, int numDays ) const
00325 {
00326
00327 if ( isValid( date ) && (long) date.toJulianDay() + (long) numDays > 0 ) {
00328
00329 QDate temp = date.addDays( numDays );
00330 if ( isValid( temp ) ) {
00331 return temp;
00332 }
00333 }
00334
00335
00336 return QDate::fromJulianDay( 0 );
00337 }
00338
00339 int KCalendarSystem::monthsInYear( const QDate &date ) const
00340 {
00341
00342
00343
00344 if ( isValid( date ) ) {
00345 QDate firstDayOfNextYear;
00346 d->setAnyDate( firstDayOfNextYear, year( date ) + 1, 1, 1 );
00347 QDate lastDayOfThisYear = addDays( firstDayOfNextYear, -1 );
00348 return month( lastDayOfThisYear );
00349 }
00350
00351 return -1;
00352 }
00353
00354 int KCalendarSystem::weeksInYear( const QDate &date ) const
00355 {
00356 if ( isValid( date ) ) {
00357 return weeksInYear( year( date ) );
00358 }
00359 return -1;
00360 }
00361
00362
00363 int KCalendarSystem::weeksInYear( int year ) const
00364 {
00365
00366
00367
00368 if ( isValid( year, 1, 1 ) ) {
00369 QDate firstDayOfNextYear;
00370 d->setAnyDate( firstDayOfNextYear, year + 1, 1, 1 );
00371 QDate lastDayOfThisYear = addDays( firstDayOfNextYear, -1 );
00372
00373 int lastWeekInThisYear = weekNumber( lastDayOfThisYear );
00374
00375
00376 if ( lastWeekInThisYear == 1 ) {
00377 lastDayOfThisYear = lastDayOfThisYear.addDays( -7 );
00378 lastWeekInThisYear = weekNumber( lastDayOfThisYear );
00379 }
00380
00381 return lastWeekInThisYear;
00382 }
00383
00384 return -1;
00385 }
00386
00387 int KCalendarSystem::daysInYear( const QDate &date ) const
00388 {
00389
00390
00391
00392 if ( isValid( date ) ) {
00393 QDate firstDayOfThisYear, firstDayOfNextYear;
00394
00395 setDate( firstDayOfThisYear, year( date ), 1, 1 );
00396 d->setAnyDate( firstDayOfNextYear, year( date ) + 1, 1, 1 );
00397
00398 return ( firstDayOfNextYear.toJulianDay() - firstDayOfThisYear.toJulianDay() );
00399 }
00400
00401 return -1;
00402 }
00403
00404 int KCalendarSystem::daysInMonth( const QDate &date ) const
00405 {
00406
00407
00408
00409 if ( isValid( date ) ) {
00410 QDate firstDayOfThisMonth, firstDayOfNextMonth;
00411
00412 int thisYear = year( date );
00413 int thisMonth = month( date );
00414
00415 setDate( firstDayOfThisMonth, thisYear, thisMonth, 1 );
00416
00417
00418 if ( thisMonth < monthsInYear( date ) ) {
00419 setDate( firstDayOfNextMonth, thisYear, thisMonth + 1, 1 );
00420 } else {
00421 d->setAnyDate( firstDayOfNextMonth, thisYear + 1, 1, 1 );
00422 }
00423
00424 return ( firstDayOfNextMonth.toJulianDay() - firstDayOfThisMonth.toJulianDay() );
00425 }
00426
00427 return -1;
00428 }
00429
00430 int KCalendarSystem::daysInWeek( const QDate &date ) const
00431 {
00432 Q_UNUSED( date );
00433 return 7;
00434 }
00435
00436 int KCalendarSystem::dayOfYear( const QDate &date ) const
00437 {
00438
00439
00440 if ( isValid( date ) ) {
00441 QDate firstDayOfYear;
00442
00443 if ( setDate( firstDayOfYear, year( date ), 1, 1 ) ) {
00444 return ( date.toJulianDay() - firstDayOfYear.toJulianDay() + 1 );
00445 }
00446 }
00447
00448 return -1;
00449 }
00450
00451 int KCalendarSystem::dayOfWeek( const QDate &date ) const
00452 {
00453
00454
00455
00456
00457 if ( isValid( date ) ) {
00458 return ( ( date.toJulianDay() % daysInWeek( date ) ) + 1 );
00459 }
00460
00461 return -1;
00462 }
00463
00464
00465
00466 int KCalendarSystem::weekNumber( const QDate &date, int *yearNum ) const
00467 {
00468 if ( isValid( date ) ) {
00469 QDate firstDayWeek1, lastDayOfYear;
00470 int y = year( date );
00471 int week;
00472 int weekDay1, dayOfWeek1InYear;
00473
00474
00475 setDate( firstDayWeek1, y, 1, 1 );
00476 weekDay1 = dayOfWeek( firstDayWeek1 );
00477
00478
00479 if ( weekDay1 > 4 ) {
00480 firstDayWeek1 = addDays( firstDayWeek1 , daysInWeek( date ) - weekDay1 + 1 );
00481 }
00482
00483 dayOfWeek1InYear = dayOfYear( firstDayWeek1 );
00484
00485
00486 if ( dayOfYear( date ) < dayOfWeek1InYear ) {
00487 if ( yearNum ) {
00488 *yearNum = y - 1;
00489 }
00490 return weeksInYear( y - 1 );
00491 }
00492
00493
00494 d->setAnyDate( lastDayOfYear, y + 1, 1, 1 );
00495 lastDayOfYear = addDays( lastDayOfYear, -1 );
00496
00497 if ( ( dayOfYear( date ) >= daysInYear( date ) - dayOfWeek( lastDayOfYear ) + 1 )
00498 && dayOfWeek( lastDayOfYear ) < 4 ) {
00499 if ( yearNum ) {
00500 * yearNum = y + 1;
00501 }
00502 week = 1;
00503 } else {
00504
00505 if( weekDay1 < 5 ) {
00506 firstDayWeek1 = addDays( firstDayWeek1, -( weekDay1 - 1 ) );
00507 }
00508
00509 week = firstDayWeek1.daysTo( date ) / daysInWeek( date ) + 1;
00510 }
00511
00512 return week;
00513 }
00514
00515 return -1;
00516 }
00517
00518
00519 bool KCalendarSystem::isLeapYear( int year ) const
00520 {
00521
00522
00523 if ( year % 4 == 0 ) {
00524 if ( year % 100 != 0 ) {
00525 return true;
00526 } else if ( year % 400 == 0 ) {
00527 return true;
00528 }
00529 }
00530 return false;
00531 }
00532
00533 bool KCalendarSystem::isLeapYear( const QDate &date ) const
00534 {
00535 return isLeapYear( year( date ) );
00536 }
00537
00538 QString KCalendarSystem::monthName( const QDate &date, MonthNameFormat format ) const
00539 {
00540 if ( isValid( date ) ) {
00541 return monthName( month( date ), year( date ), format );
00542 }
00543
00544 return QString();
00545 }
00546
00547 QString KCalendarSystem::weekDayName( const QDate &date, WeekDayNameFormat format ) const
00548 {
00549 if ( isValid( date ) ) {
00550 return weekDayName( dayOfWeek( date ), format );
00551 }
00552
00553 return QString();
00554 }
00555
00556 QString KCalendarSystem::yearString( const QDate &date, StringFormat format ) const
00557 {
00558 if ( isValid( date ) ) {
00559 QString result;
00560
00561 result.setNum( year( date ) );
00562 if ( format == ShortFormat && result.length() == 4 ) {
00563 result = result.right( 2 );
00564 }
00565
00566 return result;
00567 }
00568
00569 return QString();
00570 }
00571
00572 QString KCalendarSystem::monthString( const QDate &date, StringFormat format ) const
00573 {
00574 if ( isValid( date ) ) {
00575 QString result;
00576
00577 result.setNum( month( date ) );
00578 if ( format == LongFormat && result.length() == 1 ) {
00579 result.prepend( QLatin1Char( '0' ) );
00580 }
00581
00582 return result;
00583 }
00584
00585 return QString();
00586 }
00587
00588 QString KCalendarSystem::dayString( const QDate &date, StringFormat format ) const
00589 {
00590 if ( isValid( date ) ) {
00591 QString result;
00592
00593 result.setNum( day( date ) );
00594 if ( format == LongFormat && result.length() == 1 ) {
00595 result.prepend( QLatin1Char( '0' ) );
00596 }
00597
00598 return result;
00599 }
00600
00601 return QString();
00602 }
00603
00604 int KCalendarSystem::yearStringToInteger( const QString &yearString, int &iLength ) const
00605 {
00606 return d->stringToInteger( yearString, iLength );
00607 }
00608
00609 int KCalendarSystem::monthStringToInteger( const QString &monthString, int &iLength ) const
00610 {
00611 return d->stringToInteger( monthString, iLength );
00612 }
00613
00614 int KCalendarSystem::dayStringToInteger( const QString &dayString, int &iLength ) const
00615 {
00616 return d->stringToInteger( dayString, iLength );
00617 }
00618
00619 QString KCalendarSystem::formatDate( const QDate &date, KLocale::DateFormat format ) const
00620 {
00621 return locale()->formatDate( date, format );
00622 }
00623
00624 QDate KCalendarSystem::readDate( const QString &str, bool *ok ) const
00625 {
00626 return locale()->readDate( str, ok );
00627 }
00628
00629 QDate KCalendarSystem::readDate( const QString &intstr, const QString &fmt, bool *ok ) const
00630 {
00631 return locale()->readDate( intstr, fmt, ok );
00632 }
00633
00634 QDate KCalendarSystem::readDate( const QString &str, KLocale::ReadDateFlags flags, bool *ok ) const
00635 {
00636 return locale()->readDate( str, flags, ok );
00637 }
00638
00639 int KCalendarSystem::weekStartDay() const
00640 {
00641 return locale()->weekStartDay();
00642 }
00643
00644
00645
00646
00647
00648
00649 bool KCalendarSystem::julianDayToDate( int jd, int &year, int &month, int &day ) const
00650 {
00651 QDate date = QDate::fromJulianDay( jd );
00652
00653 if ( date.isValid() ) {
00654 year = date.year();
00655 month = date.month();
00656 day = date.day();
00657 }
00658
00659 return date.isValid();
00660 }
00661
00662
00663
00664
00665
00666
00667 bool KCalendarSystem::dateToJulianDay( int year, int month, int day, int &jd ) const
00668 {
00669 QDate date;
00670
00671 if ( date.setDate( year, month, day ) ) {
00672 jd = date.toJulianDay();
00673 return true;
00674 }
00675
00676 return false;
00677 }
00678
00679 const KLocale * KCalendarSystem::locale() const
00680 {
00681 if ( d->locale ) {
00682 return d->locale;
00683 }
00684
00685 return KGlobal::locale();
00686 }