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 addYearNumber( int originalYear, int addYears ) const;
00105
00106 QDate invalidDate() const;
00107
00108 int stringToInteger( const QString &sNum, int &iLength );
00109
00110 const KLocale *locale;
00111 };
00112
00113
00114 bool KCalendarSystemPrivate::setAnyDate( QDate &date, int year, int month, int day ) const
00115 {
00116 int jd;
00117 q->dateToJulianDay( year, month, day, jd );
00118 date = QDate::fromJulianDay( jd );
00119 return true;
00120 }
00121
00122
00123
00124
00125
00126 int KCalendarSystemPrivate::addYearNumber( int originalYear, int addYears ) const
00127 {
00128 int newYear = originalYear + addYears;
00129
00130 if ( originalYear > 0 && newYear <= 0 ) {
00131 newYear = newYear - 1;
00132 } else if ( originalYear < 0 && newYear >= 0 ) {
00133 newYear = newYear + 1;
00134 }
00135
00136 return newYear;
00137 }
00138
00139 QDate KCalendarSystemPrivate::invalidDate() const
00140 {
00141
00142 return QDate::fromJulianDay( 0 );
00143 }
00144
00145 int KCalendarSystemPrivate::stringToInteger( const QString &sNum, int &iLength )
00146 {
00147 int iPos = 0;
00148 int result = 0;
00149
00150 for ( ; sNum.length() > iPos && sNum.at( iPos ).isDigit(); iPos++ ) {
00151 result *= 10;
00152 result += sNum.at( iPos ).digitValue();
00153 }
00154 iLength = iPos;
00155
00156 return result;
00157 }
00158
00159 KCalendarSystem::KCalendarSystem( const KLocale *locale ) : d( new KCalendarSystemPrivate( this ) )
00160 {
00161 d->locale = locale;
00162 }
00163
00164 KCalendarSystem::~KCalendarSystem()
00165 {
00166 delete d;
00167 }
00168
00169
00170 QDate KCalendarSystem::epoch() const
00171 {
00172
00173 return QDate::fromJulianDay( 1 );
00174 }
00175
00176 QDate KCalendarSystem::earliestValidDate() const
00177 {
00178 return epoch();
00179 }
00180
00181
00182 QDate KCalendarSystem::latestValidDate() const
00183 {
00184
00185 return QDate::fromJulianDay( 5373484 );
00186 }
00187
00188
00189 bool KCalendarSystem::isValid( int y, int month, int day ) const
00190 {
00191
00192
00193 if ( y == 0 || y < year( earliestValidDate() ) || y > year( latestValidDate() ) ) {
00194 return false;
00195 }
00196
00197 if ( month < 1 || month > 12 ) {
00198 return false;
00199 }
00200
00201 if ( month == 2 ) {
00202 if ( isLeapYear( y ) ) {
00203 return ( day >= 1 && day <= 29 );
00204 } else {
00205 return ( day >= 1 && day <= 28 );
00206 }
00207 }
00208
00209 if ( month == 4 || month == 6 || month == 9 || month == 11 ) {
00210 return ( day >= 1 && day <= 30 );
00211 }
00212
00213 return ( day >= 1 && day <= 31 );
00214 }
00215
00216 bool KCalendarSystem::isValid( const QDate &date ) const
00217 {
00218 if ( date.isNull() || date < earliestValidDate() || date > latestValidDate() ) {
00219 return false;
00220 }
00221 return true;
00222 }
00223
00224 bool KCalendarSystem::setDate( QDate &date, int year, int month, int day ) const
00225 {
00226 if ( isValid( year, month, day ) ) {
00227 int jd;
00228 dateToJulianDay( year, month, day, jd );
00229 date = QDate::fromJulianDay( jd );
00230 return true;
00231 }
00232
00233 return false;
00234 }
00235
00236
00237 bool KCalendarSystem::setYMD( QDate &date, int year, int month, int day ) const
00238 {
00239 return setDate( date, year, month, day );
00240 }
00241
00242 int KCalendarSystem::year( const QDate &date ) const
00243 {
00244 if ( isValid( date ) ) {
00245 int year, month, day;
00246
00247 julianDayToDate( date.toJulianDay(), year, month, day );
00248
00249 return year;
00250 }
00251
00252 return 0;
00253 }
00254
00255 int KCalendarSystem::month( const QDate &date ) const
00256 {
00257 if ( isValid( date ) ) {
00258 int year, month, day;
00259
00260 julianDayToDate( date.toJulianDay(), year, month, day );
00261
00262 return month;
00263 }
00264
00265 return 0;
00266 }
00267
00268 int KCalendarSystem::day( const QDate &date ) const
00269 {
00270 if ( isValid( date ) ) {
00271 int year, month, day;
00272
00273 julianDayToDate( date.toJulianDay(), year, month, day );
00274
00275 return day;
00276 }
00277
00278 return 0;
00279 }
00280
00281 QDate KCalendarSystem::addYears( const QDate &date, int numYears ) const
00282 {
00283 if ( isValid( date ) ) {
00284
00285 int originalYear, originalMonth, originalDay;
00286 int newYear, newMonth, newDay;
00287 QDate firstOfNewMonth, newDate;
00288
00289 julianDayToDate( date.toJulianDay(), originalYear, originalMonth, originalDay );
00290
00291 newYear = d->addYearNumber( originalYear, numYears );
00292
00293 newMonth = originalMonth;
00294
00295
00296 if ( setDate( firstOfNewMonth, newYear, newMonth, 1 ) ) {
00297 int daysInNewMonth = daysInMonth( firstOfNewMonth );
00298 newDay = ( daysInNewMonth < originalDay ) ? daysInNewMonth : originalDay;
00299
00300 if ( setDate( newDate, newYear, newMonth, newDay ) ) {
00301 return newDate;
00302 }
00303 }
00304
00305 }
00306
00307 return d->invalidDate();
00308 }
00309
00310 QDate KCalendarSystem::addMonths( const QDate &date, int numMonths ) const
00311 {
00312 if ( isValid( date ) ) {
00313
00314 int originalYear, originalMonth, originalDay;
00315 int newYear, newMonth, newDay;
00316 int monthsInOriginalYear, daysInNewMonth;
00317 QDate firstOfNewMonth, newDate;
00318
00319 julianDayToDate( date.toJulianDay(), originalYear, originalMonth, originalDay );
00320
00321 monthsInOriginalYear = monthsInYear( date );
00322
00323 newYear = d->addYearNumber( originalYear, ( originalMonth + numMonths ) / monthsInOriginalYear );
00324
00325 newMonth = ( originalMonth + numMonths ) % monthsInOriginalYear;
00326
00327 if ( newMonth == 0 ) {
00328 newYear = d->addYearNumber( newYear, - 1 );
00329 newMonth = monthsInOriginalYear;
00330 }
00331 if ( newMonth < 0 ) {
00332 newYear = d->addYearNumber( newYear, - 1 );
00333 newMonth = newMonth + monthsInOriginalYear;
00334 }
00335
00336
00337 if ( setDate( firstOfNewMonth, newYear, newMonth, 1 ) ) {
00338 daysInNewMonth = daysInMonth( firstOfNewMonth );
00339 newDay = ( daysInNewMonth < originalDay ) ? daysInNewMonth : originalDay;
00340
00341 if ( setDate( newDate, newYear, newMonth, newDay ) ) {
00342 return newDate;
00343 }
00344 }
00345
00346 }
00347
00348 return d->invalidDate();
00349 }
00350
00351 QDate KCalendarSystem::addDays( const QDate &date, int numDays ) const
00352 {
00353
00354 if ( isValid( date ) && (long) date.toJulianDay() + (long) numDays > 0 ) {
00355
00356 QDate temp = date.addDays( numDays );
00357 if ( isValid( temp ) ) {
00358 return temp;
00359 }
00360 }
00361
00362 return d->invalidDate();
00363 }
00364
00365 int KCalendarSystem::monthsInYear( const QDate &date ) const
00366 {
00367
00368
00369
00370 if ( isValid( date ) ) {
00371 QDate firstDayOfNextYear;
00372 d->setAnyDate( firstDayOfNextYear, d->addYearNumber( year( date ), 1 ), 1, 1 );
00373 QDate lastDayOfThisYear = addDays( firstDayOfNextYear, -1 );
00374 return month( lastDayOfThisYear );
00375 }
00376
00377 return -1;
00378 }
00379
00380 int KCalendarSystem::weeksInYear( const QDate &date ) const
00381 {
00382 if ( isValid( date ) ) {
00383 return weeksInYear( year( date ) );
00384 }
00385 return -1;
00386 }
00387
00388
00389 int KCalendarSystem::weeksInYear( int year ) const
00390 {
00391
00392
00393
00394 if ( isValid( year, 1, 1 ) ) {
00395 QDate firstDayOfNextYear;
00396 d->setAnyDate( firstDayOfNextYear, d->addYearNumber( year, 1 ), 1, 1 );
00397 QDate lastDayOfThisYear = addDays( firstDayOfNextYear, -1 );
00398
00399 int lastWeekInThisYear = weekNumber( lastDayOfThisYear );
00400
00401
00402 if ( lastWeekInThisYear == 1 ) {
00403 lastDayOfThisYear = lastDayOfThisYear.addDays( -7 );
00404 lastWeekInThisYear = weekNumber( lastDayOfThisYear );
00405 }
00406
00407 return lastWeekInThisYear;
00408 }
00409
00410 return -1;
00411 }
00412
00413 int KCalendarSystem::daysInYear( const QDate &date ) const
00414 {
00415
00416
00417
00418 if ( isValid( date ) ) {
00419 QDate firstDayOfThisYear, firstDayOfNextYear;
00420
00421 setDate( firstDayOfThisYear, year( date ), 1, 1 );
00422 d->setAnyDate( firstDayOfNextYear, d->addYearNumber( year( date ), 1 ), 1, 1 );
00423
00424 return ( firstDayOfNextYear.toJulianDay() - firstDayOfThisYear.toJulianDay() );
00425 }
00426
00427 return -1;
00428 }
00429
00430 int KCalendarSystem::daysInMonth( const QDate &date ) const
00431 {
00432
00433
00434
00435 if ( isValid( date ) ) {
00436 QDate firstDayOfThisMonth, firstDayOfNextMonth;
00437
00438 int thisYear = year( date );
00439 int thisMonth = month( date );
00440
00441 setDate( firstDayOfThisMonth, thisYear, thisMonth, 1 );
00442
00443
00444 if ( thisMonth < monthsInYear( date ) ) {
00445 setDate( firstDayOfNextMonth, thisYear, thisMonth + 1, 1 );
00446 } else {
00447 d->setAnyDate( firstDayOfNextMonth, d->addYearNumber( thisYear, 1 ), 1, 1 );
00448 }
00449
00450 return ( firstDayOfNextMonth.toJulianDay() - firstDayOfThisMonth.toJulianDay() );
00451 }
00452
00453 return -1;
00454 }
00455
00456 int KCalendarSystem::daysInWeek( const QDate &date ) const
00457 {
00458 Q_UNUSED( date );
00459 return 7;
00460 }
00461
00462 int KCalendarSystem::dayOfYear( const QDate &date ) const
00463 {
00464
00465
00466 if ( isValid( date ) ) {
00467 QDate firstDayOfYear;
00468
00469 if ( setDate( firstDayOfYear, year( date ), 1, 1 ) ) {
00470 return ( date.toJulianDay() - firstDayOfYear.toJulianDay() + 1 );
00471 }
00472 }
00473
00474 return -1;
00475 }
00476
00477 int KCalendarSystem::dayOfWeek( const QDate &date ) const
00478 {
00479
00480
00481
00482
00483 if ( isValid( date ) ) {
00484 return ( ( date.toJulianDay() % daysInWeek( date ) ) + 1 );
00485 }
00486
00487 return -1;
00488 }
00489
00490
00491
00492 int KCalendarSystem::weekNumber( const QDate &date, int *yearNum ) const
00493 {
00494 if ( isValid( date ) ) {
00495 QDate firstDayWeek1, lastDayOfYear;
00496 int y = year( date );
00497 int week;
00498 int weekDay1, dayOfWeek1InYear;
00499
00500
00501 setDate( firstDayWeek1, y, 1, 1 );
00502 weekDay1 = dayOfWeek( firstDayWeek1 );
00503
00504
00505 if ( weekDay1 > 4 ) {
00506 firstDayWeek1 = addDays( firstDayWeek1 , daysInWeek( date ) - weekDay1 + 1 );
00507 }
00508
00509 dayOfWeek1InYear = dayOfYear( firstDayWeek1 );
00510
00511
00512 if ( dayOfYear( date ) < dayOfWeek1InYear ) {
00513 if ( yearNum ) {
00514 *yearNum = d->addYearNumber( y, - 1 );
00515 }
00516 return weeksInYear( d->addYearNumber( y, - 1 ) );
00517 }
00518
00519
00520 d->setAnyDate( lastDayOfYear, d->addYearNumber( y, 1 ), 1, 1 );
00521 lastDayOfYear = addDays( lastDayOfYear, -1 );
00522
00523 if ( ( dayOfYear( date ) >= daysInYear( date ) - dayOfWeek( lastDayOfYear ) + 1 )
00524 && dayOfWeek( lastDayOfYear ) < 4 ) {
00525 if ( yearNum ) {
00526 * yearNum = d->addYearNumber( y, 1 );
00527 }
00528 week = 1;
00529 } else {
00530
00531 if( weekDay1 < 5 ) {
00532 firstDayWeek1 = addDays( firstDayWeek1, -( weekDay1 - 1 ) );
00533 }
00534
00535 week = firstDayWeek1.daysTo( date ) / daysInWeek( date ) + 1;
00536 }
00537
00538 return week;
00539 }
00540
00541 return -1;
00542 }
00543
00544
00545 bool KCalendarSystem::isLeapYear( int year ) const
00546 {
00547
00548
00549 int y;
00550
00551 if ( year < 1 ) {
00552 y = year + 1;
00553 } else {
00554 y = year;
00555 }
00556
00557 if ( y % 4 == 0 ) {
00558 if ( y % 100 != 0 ) {
00559 return true;
00560 } else if ( y % 400 == 0 ) {
00561 return true;
00562 }
00563 }
00564 return false;
00565 }
00566
00567 bool KCalendarSystem::isLeapYear( const QDate &date ) const
00568 {
00569 return isLeapYear( year( date ) );
00570 }
00571
00572 QString KCalendarSystem::monthName( const QDate &date, MonthNameFormat format ) const
00573 {
00574 if ( isValid( date ) ) {
00575 return monthName( month( date ), year( date ), format );
00576 }
00577
00578 return QString();
00579 }
00580
00581 QString KCalendarSystem::weekDayName( const QDate &date, WeekDayNameFormat format ) const
00582 {
00583 if ( isValid( date ) ) {
00584 return weekDayName( dayOfWeek( date ), format );
00585 }
00586
00587 return QString();
00588 }
00589
00590 QString KCalendarSystem::yearString( const QDate &date, StringFormat format ) const
00591 {
00592 if ( isValid( date ) ) {
00593 QString result;
00594
00595 result.setNum( year( date ) );
00596 if ( format == ShortFormat && result.length() == 4 ) {
00597 result = result.right( 2 );
00598 }
00599 result = locale()->convertDigits( result, locale()->dateTimeDigitSet() );
00600
00601 return result;
00602 }
00603
00604 return QString();
00605 }
00606
00607 QString KCalendarSystem::monthString( const QDate &date, StringFormat format ) const
00608 {
00609 if ( isValid( date ) ) {
00610 QString result;
00611
00612 result.setNum( month( date ) );
00613 if ( format == LongFormat && result.length() == 1 ) {
00614 result.prepend( QLatin1Char( '0' ) );
00615 }
00616 result = locale()->convertDigits( result, locale()->dateTimeDigitSet() );
00617
00618 return result;
00619 }
00620
00621 return QString();
00622 }
00623
00624 QString KCalendarSystem::dayString( const QDate &date, StringFormat format ) const
00625 {
00626 if ( isValid( date ) ) {
00627 QString result;
00628
00629 result.setNum( day( date ) );
00630 if ( format == LongFormat && result.length() == 1 ) {
00631 result.prepend( QLatin1Char( '0' ) );
00632 }
00633 result = locale()->convertDigits( result, locale()->dateTimeDigitSet() );
00634
00635 return result;
00636 }
00637
00638 return QString();
00639 }
00640
00641 int KCalendarSystem::yearStringToInteger( const QString &yearString, int &iLength ) const
00642 {
00643 return d->stringToInteger( yearString, iLength );
00644 }
00645
00646 int KCalendarSystem::monthStringToInteger( const QString &monthString, int &iLength ) const
00647 {
00648 return d->stringToInteger( monthString, iLength );
00649 }
00650
00651 int KCalendarSystem::dayStringToInteger( const QString &dayString, int &iLength ) const
00652 {
00653 return d->stringToInteger( dayString, iLength );
00654 }
00655
00656 QString KCalendarSystem::formatDate( const QDate &date, KLocale::DateFormat format ) const
00657 {
00658 return locale()->formatDate( date, format );
00659 }
00660
00661 QDate KCalendarSystem::readDate( const QString &str, bool *ok ) const
00662 {
00663 return locale()->readDate( str, ok );
00664 }
00665
00666 QDate KCalendarSystem::readDate( const QString &intstr, const QString &fmt, bool *ok ) const
00667 {
00668 return locale()->readDate( intstr, fmt, ok );
00669 }
00670
00671 QDate KCalendarSystem::readDate( const QString &str, KLocale::ReadDateFlags flags, bool *ok ) const
00672 {
00673 return locale()->readDate( str, flags, ok );
00674 }
00675
00676 int KCalendarSystem::weekStartDay() const
00677 {
00678 return locale()->weekStartDay();
00679 }
00680
00681
00682
00683
00684
00685
00686 bool KCalendarSystem::julianDayToDate( int jd, int &year, int &month, int &day ) const
00687 {
00688 QDate date = QDate::fromJulianDay( jd );
00689
00690 if ( date.isValid() ) {
00691 year = date.year();
00692 month = date.month();
00693 day = date.day();
00694 }
00695
00696 return date.isValid();
00697 }
00698
00699
00700
00701
00702
00703
00704 bool KCalendarSystem::dateToJulianDay( int year, int month, int day, int &jd ) const
00705 {
00706 QDate date;
00707
00708 if ( date.setDate( year, month, day ) ) {
00709 jd = date.toJulianDay();
00710 return true;
00711 }
00712
00713 return false;
00714 }
00715
00716 const KLocale * KCalendarSystem::locale() const
00717 {
00718 if ( d->locale ) {
00719 return d->locale;
00720 }
00721
00722 return KGlobal::locale();
00723 }