KDECore
kcalendarsystemhebrew.cpp
Go to the documentation of this file.
00001 /* 00002 Copyright (c) 2003 Hans Petter Bieker <bieker@kde.org> 00003 Copyright 2007, 2009, 2010 John Layt <john@layt.net> 00004 Calendar conversion routines based on Hdate v6, by Amos 00005 Shapir 1978 (rev. 1985, 1992) 00006 00007 This library is free software; you can redistribute it and/or 00008 modify it under the terms of the GNU Library General Public 00009 License as published by the Free Software Foundation; either 00010 version 2 of the License, or (at your option) any later version. 00011 00012 This library is distributed in the hope that it will be useful, 00013 but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 Library General Public License for more details. 00016 00017 You should have received a copy of the GNU Library General Public License 00018 along with this library; see the file COPYING.LIB. If not, write to 00019 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00020 Boston, MA 02110-1301, USA. 00021 */ 00022 00023 // Derived hebrew kde calendar class 00024 00025 #include "kcalendarsystemhebrew_p.h" 00026 #include "kcalendarsystemprivate_p.h" 00027 00028 #include "kdebug.h" 00029 #include "klocale.h" 00030 00031 #include <QtCore/QDate> 00032 #include <QtCore/QCharRef> 00033 00034 static int hebrewDaysElapsed( int y ); 00035 00036 class h_date 00037 { 00038 public: 00039 int hd_day; 00040 int hd_mon; 00041 int hd_year; 00042 int hd_dw; 00043 int hd_flg; 00044 }; 00045 00046 /* 00047 * compute general date structure from hebrew date 00048 */ 00049 static class h_date * hebrewToGregorian( int y, int m, int d ) 00050 { 00051 static class h_date h; 00052 int s; 00053 00054 y -= 3744; 00055 s = hebrewDaysElapsed( y ); 00056 d += s; 00057 s = hebrewDaysElapsed( y + 1 ) - s; /* length of year */ 00058 00059 if ( s > 365 && m > 6 ) { 00060 --m; 00061 d += 30; 00062 } 00063 d += ( 59 * ( m - 1 ) + 1 ) / 2; /* regular months */ 00064 /* special cases */ 00065 if ( s % 10 > 4 && m > 2 ) { /* long Heshvan */ 00066 d++; 00067 } 00068 if ( s % 10 < 4 && m > 3 ) { /* short Kislev */ 00069 d--; 00070 } 00071 // ### HPB: Broken in leap years 00072 //if (s > 365 && m > 6) /* leap year */ 00073 // d += 30; 00074 d -= 6002; 00075 00076 y = ( d + 36525 ) * 4 / 146097 - 1; 00077 d -= y / 4 * 146097 + ( y % 4 ) * 36524; 00078 y *= 100; 00079 00080 /* compute year */ 00081 s = ( d + 366 )*4 / 1461 - 1; 00082 d -= s / 4*1461 + ( s % 4 )*365; 00083 y += s; 00084 /* compute month */ 00085 m = ( d + 245 )*12 / 367 - 7; 00086 d -= m*367 / 12 - 30; 00087 if ( ++m >= 12 ) { 00088 m -= 12; 00089 y++; 00090 } 00091 h.hd_day = d; 00092 h.hd_mon = m; 00093 h.hd_year = y; 00094 return( &h ); 00095 } 00096 00097 /* 00098 * compute date structure from no. of days since 1 Tishrei 3744 00099 */ 00100 static class h_date * gregorianToHebrew( int y, int m, int d ) 00101 { 00102 static class h_date h; 00103 int s; 00104 00105 if ( ( m -= 2 ) <= 0 ) { 00106 m += 12; 00107 y--; 00108 } 00109 /* no. of days, Julian calendar */ 00110 d += 365*y + y / 4 + 367*m / 12 + 5968; 00111 /* Gregorian calendar */ 00112 d -= y / 100 - y / 400 - 2; 00113 h.hd_dw = ( d + 1 ) % 7; 00114 00115 /* compute the year */ 00116 y += 16; 00117 s = hebrewDaysElapsed( y ); 00118 m = hebrewDaysElapsed( y + 1 ); 00119 while( d >= m ) { /* computed year was underestimated */ 00120 s = m; 00121 y++; 00122 m = hebrewDaysElapsed( y + 1 ); 00123 } 00124 d -= s; 00125 s = m - s; /* size of current year */ 00126 y += 3744; 00127 00128 h.hd_flg = s % 10 - 4; 00129 00130 /* compute day and month */ 00131 if ( d >= s - 236 ) { /* last 8 months are regular */ 00132 d -= s - 236; 00133 m = d * 2 / 59; 00134 d -= ( m * 59 + 1 ) / 2; 00135 m += 4; 00136 if ( s > 365 && m <= 5 ) { /* Adar of Meuberet */ 00137 m += 8; 00138 } 00139 } else { 00140 /* first 4 months have 117-119 days */ 00141 s = 114 + s % 10; 00142 m = d * 4 / s; 00143 d -= ( m * s + 3 ) / 4; 00144 } 00145 00146 h.hd_day = d; 00147 h.hd_mon = m; 00148 h.hd_year = y; 00149 return( &h ); 00150 } 00151 00152 /* constants, in 1/18th of minute */ 00153 static const int HOUR = 1080; 00154 static const int DAY = 24*HOUR; 00155 static const int WEEK = 7*DAY; 00156 #define M(h,p) ((h)*HOUR+p) 00157 #define MONTH (DAY+M(12,793)) 00158 00163 static int hebrewDaysElapsed( int y ) 00164 { 00165 int m, nm, dw, s, l; 00166 00167 l = y * 7 + 1; // no. of leap months 00168 m = y * 12 + l / 19; // total no. of months 00169 l %= 19; 00170 nm = m * MONTH + M( 1 + 6, 779 ); // molad new year 3744 (16BC) + 6 hours 00171 s = m * 28 + nm / DAY - 2; 00172 00173 nm %= WEEK; 00174 dw = nm / DAY; 00175 nm %= DAY; 00176 00177 // special cases of Molad Zaken 00178 if ( (l < 12 && dw == 3 && nm >= M( 9 + 6, 204 )) || 00179 (l < 7 && dw == 2 && nm >= M( 15 + 6, 589 )) ) { 00180 s++, dw++; 00181 } 00182 00183 /* ADU */ 00184 if ( dw == 1 || dw == 4 || dw == 6 ) { 00185 s++; 00186 } 00187 return s; 00188 } 00189 00194 static int long_cheshvan( int year ) 00195 { 00196 QDate first, last; 00197 class h_date *gd; 00198 00199 gd = hebrewToGregorian( year, 1, 1 ); 00200 first.setYMD( gd->hd_year, gd->hd_mon + 1, gd->hd_day + 1 ); 00201 00202 gd = hebrewToGregorian( year + 1, 1, 1 ); 00203 last.setYMD( gd->hd_year, gd->hd_mon + 1, gd->hd_day + 1 ); 00204 00205 return ( first.daysTo( last ) % 10 == 5 ); 00206 } 00207 00212 static int short_kislev( int year ) 00213 { 00214 QDate first, last; 00215 class h_date * gd; 00216 00217 gd = hebrewToGregorian( year, 1, 1 ); 00218 first.setYMD( gd->hd_year, gd->hd_mon + 1, gd->hd_day + 1 ); 00219 00220 gd = hebrewToGregorian( year + 1, 1, 1 ); 00221 last.setYMD( gd->hd_year, gd->hd_mon + 1, gd->hd_day + 1 ); 00222 00223 return ( first.daysTo( last ) % 10 == 3 ); 00224 } 00225 00226 // Ok 00227 static class h_date *toHebrew( const QDate &date ) 00228 { 00229 class h_date *sd; 00230 00231 sd = gregorianToHebrew( date.year(), date.month(), date.day() ); 00232 ++sd->hd_mon; 00233 ++sd->hd_day; 00234 00235 return sd; 00236 } 00237 00238 class KCalendarSystemHebrewPrivate : public KCalendarSystemPrivate 00239 { 00240 public: 00241 explicit KCalendarSystemHebrewPrivate( KCalendarSystemHebrew *q ); 00242 00243 virtual ~KCalendarSystemHebrewPrivate(); 00244 00245 // Virtual methods each calendar system must re-implement 00246 virtual KLocale::CalendarSystem calendarSystem() const; 00247 virtual void loadDefaultEraList(); 00248 virtual int monthsInYear( int year ) const; 00249 virtual int daysInMonth( int year, int month ) const; 00250 virtual int daysInYear( int year ) const; 00251 virtual int daysInWeek() const; 00252 virtual bool isLeapYear( int year ) const; 00253 virtual bool hasLeapMonths() const; 00254 virtual bool hasYearZero() const; 00255 virtual int maxDaysInWeek() const; 00256 virtual int maxMonthsInYear() const; 00257 virtual int earliestValidYear() const; 00258 virtual int latestValidYear() const; 00259 00260 virtual int integerFromString( const QString &string, int maxLength, int &readLength ) const; 00261 virtual QString stringFromInteger( int number, int padWidth = 0, QChar padChar = QLatin1Char('0') ) const; 00262 virtual QString stringFromInteger( int number, int padWidth, QChar padChar, KLocale::DigitSet digitSet ) const; 00263 00264 virtual int monthNumberToMonthIndex( int year, int month ) const; 00265 }; 00266 00267 // Shared d pointer base class definitions 00268 00269 KCalendarSystemHebrewPrivate::KCalendarSystemHebrewPrivate( KCalendarSystemHebrew *q ) 00270 :KCalendarSystemPrivate( q ) 00271 { 00272 } 00273 00274 KCalendarSystemHebrewPrivate::~KCalendarSystemHebrewPrivate() 00275 { 00276 } 00277 00278 KLocale::CalendarSystem KCalendarSystemHebrewPrivate::calendarSystem() const 00279 { 00280 return KLocale::HebrewCalendar; 00281 } 00282 00283 void KCalendarSystemHebrewPrivate::loadDefaultEraList() 00284 { 00285 QString name, shortName, format; 00286 // Jewish Era, Anno Mundi, "Year of the World". 00287 name = i18nc( "Calendar Era: Hebrew Era, years > 0, LongFormat", "Anno Mundi" ); 00288 shortName = i18nc( "Calendar Era: Hebrew Era, years > 0, ShortFormat", "AM" ); 00289 format = i18nc( "(kdedt-format) Hebrew, AM, full era year format used for %EY, e.g. 2000 AM", "%Ey %EC" ); 00290 addEra( '+', 1, q->epoch(), 1, q->latestValidDate(), name, shortName, format ); 00291 } 00292 00293 int KCalendarSystemHebrewPrivate::monthsInYear( int year ) const 00294 { 00295 if ( isLeapYear( year ) ) { 00296 return 13; 00297 } else { 00298 return 12; 00299 } 00300 } 00301 00302 int KCalendarSystemHebrewPrivate::daysInMonth( int year, int month ) const 00303 { 00304 int mi = monthNumberToMonthIndex( year, month ); 00305 00306 if ( mi == 2 && long_cheshvan( year ) ) { 00307 return 30; 00308 } 00309 00310 if ( mi == 3 && short_kislev( year ) ) { 00311 return 29; 00312 } 00313 00314 if ( mi % 2 == 0 ) { // Even number months have 29 days 00315 return 29; 00316 } else { // Odd number months have 30 days 00317 return 30; 00318 } 00319 } 00320 00321 int KCalendarSystemHebrewPrivate::daysInYear( int year ) const 00322 { 00323 int days; 00324 00325 // Get Regular year length 00326 if ( isLeapYear( year ) ) { // Has 13 months 00327 days = 384; 00328 } else { // Has 12 months 00329 days = 354; 00330 } 00331 00332 // Check if is Deficient or Abundant year 00333 if ( short_kislev( year ) ) { // Deficient 00334 days = days - 1; 00335 } else if ( long_cheshvan( year ) ) { // Abundant 00336 days = days + 1; 00337 } 00338 00339 return days; 00340 } 00341 00342 int KCalendarSystemHebrewPrivate::daysInWeek() const 00343 { 00344 return 7; 00345 } 00346 00347 bool KCalendarSystemHebrewPrivate::isLeapYear( int year ) const 00348 { 00349 return ( ( ( ( 7 * year ) + 1 ) % 19 ) < 7 ); 00350 } 00351 00352 bool KCalendarSystemHebrewPrivate::hasLeapMonths() const 00353 { 00354 return true; 00355 } 00356 00357 bool KCalendarSystemHebrewPrivate::hasYearZero() const 00358 { 00359 return false; 00360 } 00361 00362 int KCalendarSystemHebrewPrivate::maxDaysInWeek() const 00363 { 00364 return 7; 00365 } 00366 00367 int KCalendarSystemHebrewPrivate::maxMonthsInYear() const 00368 { 00369 return 13; 00370 } 00371 00372 int KCalendarSystemHebrewPrivate::earliestValidYear() const 00373 { 00374 return 5344; 00375 } 00376 00377 int KCalendarSystemHebrewPrivate::latestValidYear() const 00378 { 00379 return 8119; 00380 } 00381 00382 int KCalendarSystemHebrewPrivate::integerFromString( const QString &inputString, int maxLength, int &readLength ) const 00383 { 00384 if ( locale()->language() == QLatin1String("he") ) { 00385 00386 // Hebrew numbers are composed of combinations of normal letters which have a numeric value. 00387 // This is a non-positional system, the numeric values are simply added together, however 00388 // convention is for a RTL highest to lowest value ordering. There is also a degree of 00389 // ambiguity due to the lack of a letter for 0, hence 5 and 5000 are written the same. 00390 // Hebrew numbers are only used in dates. 00391 // See http://www.i18nguy.com/unicode/hebrew-numbers.html for more explaination 00392 00393 /* 00394 Ref table for numbers to Hebrew chars 00395 00396 Value 1 2 3 4 5 6 7 8 9 00397 00398 x 1 Alef א Bet ב Gimel ג Dalet ד He ה Vav ו Zayen ז Het ח Tet ט 00399 0x05D0 0x05D1 0x05D2 0x05D3 0x05D4 0x05D5 0x05D6 0x05D7 0x05D8 00400 00401 x 10 Yod י Kaf כ Lamed ל Mem מ Nun נ Samekh ס Ayin ע Pe פ Tzadi צ 00402 0x05D9 0x05DB 0x05DC 0x05DE 0x05E0 0x05E1 0x05E2 0x05E4 0x05E6 00403 00404 x 100 Qof ק Resh ר Shin ש Tav ת 00405 0x05E7 0x05E8 0x05E9 0x05EA 00406 00407 Note special cases 15 = 9 + 6 = 96 טו and 16 = 9 + 7 = 97 טז 00408 */ 00409 00410 int decadeValues[14] = {10, 20, 20, 30, 40, 40, 50, 50, 60, 70, 80, 80, 90, 90}; 00411 00412 QChar thisChar, nextChar; 00413 QString string = inputString; 00414 00415 int stringLength = string.length(); 00416 readLength = 0; 00417 int position = 0; 00418 int result = 0; 00419 int value = 0; 00420 00421 for ( ; position < stringLength ; ++position ) { 00422 00423 thisChar = string[position]; 00424 00425 if ( position + 1 < stringLength ) { 00426 nextChar = string[position + 1]; 00427 // Ignore any geresh or gershayim chars, we don't bother checking they are in the right place 00428 if ( nextChar == QLatin1Char('\'') || nextChar == QChar( 0x05F3 ) || // geresh 00429 nextChar == QLatin1Char('\"') || nextChar == QChar( 0x05F4 ) ) { // gershayim 00430 string.remove( position + 1, 1 ); 00431 stringLength = string.length(); 00432 if ( position + 1 < stringLength ) { 00433 nextChar = string[position + 1]; 00434 } else { 00435 nextChar = QChar(); 00436 } 00437 readLength = readLength + 1; 00438 } 00439 } else { 00440 nextChar = QChar(); 00441 } 00442 00443 if ( thisChar >= QChar( 0x05D0 ) && thisChar <= QChar( 0x05D7 ) ) { 00444 00445 // If this char Alef to Het, 1 to 8, א to ח 00446 00447 // If next char is any valid digit char (Alef to Tav, 1 to 400, א to ת) 00448 // then this char is a thousands digit 00449 // else this char is a ones digit 00450 00451 if ( nextChar >= QChar( 0x05D0 ) && nextChar <= QChar( 0x05EA ) ) { 00452 value = ( thisChar.unicode() - 0x05D0 + 1 ) * 1000; 00453 } else { 00454 value = thisChar.unicode() - 0x05D0 + 1; 00455 } 00456 00457 } else if ( thisChar == QChar( 0x05D8 ) ) { 00458 00459 // If this char is Tet, 9, ט 00460 00461 // If next char is any valid digit char (Alef to Tav, 1 to 400, א to ת) 00462 // and next char not 6 (Special case for 96 = 15) 00463 // and next char not 7 (Special case for 97 = 16) 00464 // then is a thousands digit else is 9 00465 00466 if ( nextChar >= QChar( 0x05D0 ) && nextChar <= QChar( 0x05EA ) && 00467 nextChar != QChar( 0x05D5 ) && nextChar != QChar( 0x05D6 ) ) { 00468 value = 9000; 00469 } else { 00470 value = 9; 00471 } 00472 00473 } else if ( thisChar >= QChar( 0x05D9 ) && thisChar <= QChar( 0x05E6 ) ) { 00474 00475 // If this char Yod to Tsadi, 10 to 90, י to צ 00476 00477 // If next char is a tens or hundreds char then is an error 00478 // Else is a tens digit 00479 00480 if ( nextChar >= QChar( 0x05D9 ) ) { 00481 return -1; 00482 } else { 00483 value = decadeValues[thisChar.unicode() - 0x05D9]; 00484 } 00485 00486 } else if ( thisChar >= QChar( 0x05E7 ) && thisChar <= QChar( 0x05EA ) ) { 00487 00488 // If this char Qof to Tav, 100 to 400, ק to ת, then is hundreds digit 00489 00490 value = ( thisChar.unicode() - 0x05E7 + 1 ) * 100; 00491 00492 } else { 00493 00494 // If this char any non-digit char including whitespace or punctuation, we're done 00495 break; 00496 00497 } 00498 00499 result = result + value; 00500 00501 value = 0; 00502 } 00503 00504 readLength += position; 00505 00506 return result; 00507 00508 } else { 00509 return KCalendarSystemPrivate::integerFromString( inputString, maxLength, readLength ); 00510 } 00511 } 00512 00513 QString KCalendarSystemHebrewPrivate::stringFromInteger( int number, int padWidth, QChar padChar ) const 00514 { 00515 return KCalendarSystemPrivate::stringFromInteger( number, padWidth, padChar ); 00516 } 00517 00518 QString KCalendarSystemHebrewPrivate::stringFromInteger( int number, int padWidth, QChar padChar, KLocale::DigitSet digitSet ) const 00519 { 00520 if ( locale()->language() == QLatin1String("he") ) { 00521 00522 // Hebrew numbers are composed of combinations of normal letters which have a numeric value. 00523 // This is a non-positional system, the numeric values are simply added together, however 00524 // convention is for a RTL highest to lowest value ordering. There is also a degree of 00525 // ambiguity due to the lack of a letter for 0, hence 5 and 5000 are written the same. 00526 // Hebrew numbers are only used in dates. 00527 // See http://www.i18nguy.com/unicode/hebrew-numbers.html for more explaination 00528 00529 /* 00530 Ref table for numbers to Hebrew chars 00531 00532 Value 1 2 3 4 5 6 7 8 9 00533 00534 x 1 Alef א Bet ב Gimel ג Dalet ד He ה Vav ו Zayen ז Het ח Tet ט 00535 0x05D0 0x05D1 0x05D2 0x05D3 0x05D4 0x05D5 0x05D6 0x05D7 0x05D8 00536 00537 x 10 Yod י Kaf כ Lamed ל Mem מ Nun נ Samekh ס Ayin ע Pe פ Tzadi צ 00538 0x05D9 0x05DB 0x05DC 0x05DE 0x05E0 0x05E1 0x05E2 0x05E4 0x05E6 00539 00540 x 100 Qof ק Resh ר Shin ש Tav ת 00541 0x05E7 0x05E8 0x05E9 0x05EA 00542 00543 Note special cases 15 = 9 + 6 = 96 טו and 16 = 9 + 7 = 97 טז 00544 */ 00545 00546 const QChar decade[] = { 00547 // Tet = ט, Yod = י, Kaf = כ, Lamed = ל, Mem = מ 00548 // Nun = נ, Samekh = ס, Ayin = ע, Pe = פ, Tsadi = צ 00549 0x05D8, 0x05D9, 0x05DB, 0x05DC, 0x05DE, 00550 0x05E0, 0x05E1, 0x05E2, 0x05E4, 0x05E6 00551 }; 00552 00553 QString result; 00554 00555 // We have no rules for coping with numbers outside this range 00556 if ( number < 1 || number > 9999 ) { 00557 return KCalendarSystemPrivate::stringFromInteger( number, padWidth, padChar, digitSet ); 00558 } 00559 00560 // Translate the thousands digit, just uses letter for number 1..9 ( א to ט, Alef to Tet ) 00561 // Years 5001-5999 do not have the thousands by convention 00562 if ( number >= 1000 ) { 00563 if ( number <= 5000 || number >= 6000 ) { 00564 result += QChar( 0x05D0 - 1 + number / 1000 ); // Alef א to Tet ט 00565 } 00566 number %= 1000; 00567 } 00568 00569 // Translate the hundreds digit 00570 // Use traditional method where we only have letters assigned values for 100, 200, 300 and 400 00571 // so may need to repeat 400 twice to make up the required number 00572 if ( number >= 100 ) { 00573 while ( number >= 500 ) { 00574 result += QChar( 0x05EA ); // Tav = ת 00575 number -= 400; 00576 } 00577 result += QChar( 0x05E7 - 1 + number / 100 ); // Qof = ק to xxx 00578 number %= 100; 00579 } 00580 00581 // Translate the tens digit 00582 // The numbers 15 and 16 translate to letters that spell out the name of God which is 00583 // forbidden, so require special treatment where 15 = 9 + 6 and 1 = 9 + 7. 00584 if ( number >= 10 ) { 00585 if ( number == 15 || number == 16 ) 00586 number -= 9; 00587 result += decade[number / 10]; 00588 number %= 10; 00589 } 00590 00591 // Translate the ones digit, uses letter for number 1..9 ( א to ט, Alef to Tet ) 00592 if ( number > 0 ) { 00593 result += QChar( 0x05D0 - 1 + number ); // Alef = א to xxx 00594 } 00595 00596 // When used in a string with mixed names and numbers the numbers need special chars to 00597 // distinguish them from words composed of the same letters. 00598 // Single digit numbers are followed by a geresh symbol ? (Unicode = 0x05F3), but we use 00599 // single quote for convenience. 00600 // Multiple digit numbers have a gershayim symbol ? (Unicode = 0x05F4) as second-to-last 00601 // char, but we use double quote for convenience. 00602 if ( result.length() == 1 ) { 00603 result += QLatin1Char('\''); 00604 } else { 00605 result.insert( result.length() - 1, QLatin1Char('\"') ); 00606 } 00607 00608 return result; 00609 00610 } else { 00611 return KCalendarSystemPrivate::stringFromInteger( number, padWidth, padChar, digitSet ); 00612 } 00613 } 00614 00615 int KCalendarSystemHebrewPrivate::monthNumberToMonthIndex( int year, int month ) const 00616 { 00617 if ( isLeapYear( year ) ) { 00618 if ( month == 6 ) { 00619 return 13; // Adar I 00620 } else if ( month == 7 ) { 00621 return 14; // Adar II 00622 } else if ( month > 7 ) { 00623 return month - 1; // Because of Adar II 00624 } 00625 } 00626 00627 return month; 00628 } 00629 00630 00631 KCalendarSystemHebrew::KCalendarSystemHebrew( const KLocale *locale ) 00632 : KCalendarSystem( *new KCalendarSystemHebrewPrivate( this ), KSharedConfig::Ptr(), locale ), 00633 dont_use( 0 ) 00634 { 00635 d_ptr->loadConfig( calendarType() ); 00636 } 00637 00638 KCalendarSystemHebrew::KCalendarSystemHebrew( const KSharedConfig::Ptr config, const KLocale *locale ) 00639 : KCalendarSystem( *new KCalendarSystemHebrewPrivate( this ), config, locale ), 00640 dont_use( 0 ) 00641 { 00642 d_ptr->loadConfig( calendarType() ); 00643 } 00644 00645 KCalendarSystemHebrew::KCalendarSystemHebrew( KCalendarSystemHebrewPrivate &dd, 00646 const KSharedConfig::Ptr config, const KLocale *locale ) 00647 : KCalendarSystem( dd, config, locale ), 00648 dont_use( 0 ) 00649 { 00650 d_ptr->loadConfig( calendarType() ); 00651 } 00652 00653 KCalendarSystemHebrew::~KCalendarSystemHebrew() 00654 { 00655 delete dont_use; 00656 } 00657 00658 QString KCalendarSystemHebrew::calendarType() const 00659 { 00660 return QLatin1String( "hebrew" ); 00661 } 00662 00663 QDate KCalendarSystemHebrew::epoch() const 00664 { 00665 // Hebrew 0001-01-01 (Gregorian -3760-09-07, Julian -3761-10-07) 00666 return QDate::fromJulianDay( 347998 ); 00667 } 00668 00669 QDate KCalendarSystemHebrew::earliestValidDate() const 00670 { 00671 // Current formulas using direct Gregorian <-> Hebrew conversion using Qt 00672 // will return invalid results prior to the Gregorian switchover in 1582 00673 // Next valid Hebrew year starts 5344-01-01 (Gregorian 1583-09-17) 00674 return QDate::fromJulianDay( 2299498 ); 00675 } 00676 00677 QDate KCalendarSystemHebrew::latestValidDate() const 00678 { 00679 // Testing shows current formulas only work up to 8119-13-29 (Gregorian 4359-10-07) 00680 return QDate::fromJulianDay( 3313431 ); 00681 } 00682 00683 bool KCalendarSystemHebrew::isValid( int year, int month, int day ) const 00684 { 00685 return KCalendarSystem::isValid( year, month, day ); 00686 } 00687 00688 bool KCalendarSystemHebrew::isValid( const QDate &date ) const 00689 { 00690 return KCalendarSystem::isValid( date ); 00691 } 00692 00693 bool KCalendarSystemHebrew::setDate( QDate &date, int year, int month, int day ) const 00694 { 00695 return KCalendarSystem::setDate( date, year, month, day ); 00696 } 00697 00698 // Deprecated 00699 bool KCalendarSystemHebrew::setYMD( QDate &date, int year, int month, int day ) const 00700 { 00701 return KCalendarSystem::setYMD( date, year, month, day ); 00702 } 00703 00704 int KCalendarSystemHebrew::year( const QDate &date ) const 00705 { 00706 return KCalendarSystem::year( date ); 00707 } 00708 00709 int KCalendarSystemHebrew::month( const QDate &date ) const 00710 { 00711 return KCalendarSystem::month( date ); 00712 } 00713 00714 int KCalendarSystemHebrew::day( const QDate &date ) const 00715 { 00716 return KCalendarSystem::day( date ); 00717 } 00718 00719 QDate KCalendarSystemHebrew::addYears( const QDate &date, int nyears ) const 00720 { 00721 return KCalendarSystem::addYears( date, nyears ); 00722 } 00723 00724 QDate KCalendarSystemHebrew::addMonths( const QDate &date, int nmonths ) const 00725 { 00726 return KCalendarSystem::addMonths( date, nmonths ); 00727 } 00728 00729 QDate KCalendarSystemHebrew::addDays( const QDate &date, int ndays ) const 00730 { 00731 return KCalendarSystem::addDays( date, ndays ); 00732 } 00733 00734 int KCalendarSystemHebrew::monthsInYear( const QDate &date ) const 00735 { 00736 return KCalendarSystem::monthsInYear( date ); 00737 } 00738 00739 int KCalendarSystemHebrew::weeksInYear( const QDate &date ) const 00740 { 00741 return KCalendarSystem::weeksInYear( date ); 00742 } 00743 00744 int KCalendarSystemHebrew::weeksInYear( int year ) const 00745 { 00746 return KCalendarSystem::weeksInYear( year ); 00747 } 00748 00749 int KCalendarSystemHebrew::daysInYear( const QDate &date ) const 00750 { 00751 return KCalendarSystem::daysInYear( date ); 00752 } 00753 00754 int KCalendarSystemHebrew::daysInMonth( const QDate &date ) const 00755 { 00756 return KCalendarSystem::daysInMonth( date ); 00757 } 00758 00759 int KCalendarSystemHebrew::daysInWeek( const QDate &date ) const 00760 { 00761 return KCalendarSystem::daysInWeek( date ); 00762 } 00763 00764 int KCalendarSystemHebrew::dayOfYear( const QDate &date ) const 00765 { 00766 return KCalendarSystem::dayOfYear( date ); 00767 } 00768 00769 int KCalendarSystemHebrew::dayOfWeek( const QDate &date ) const 00770 { 00771 class h_date * sd = toHebrew( date ); 00772 if ( sd->hd_dw == 0 ) { 00773 return 7; 00774 } else { 00775 return ( sd->hd_dw ); 00776 } 00777 } 00778 00779 int KCalendarSystemHebrew::weekNumber( const QDate &date, int *yearNum ) const 00780 { 00781 return KCalendarSystem::weekNumber( date, yearNum ); 00782 } 00783 00784 bool KCalendarSystemHebrew::isLeapYear( int year ) const 00785 { 00786 return KCalendarSystem::isLeapYear( year ); 00787 } 00788 00789 bool KCalendarSystemHebrew::isLeapYear( const QDate &date ) const 00790 { 00791 return KCalendarSystem::isLeapYear( date ); 00792 } 00793 00794 // ### Fixme 00795 // JPL Fix what? 00796 // Ask translators for short fomats of month names! 00797 QString KCalendarSystemHebrew::monthName( int month, int year, MonthNameFormat format ) const 00798 { 00799 Q_D( const KCalendarSystemHebrew ); 00800 00801 if ( month < 1 || month > d->monthsInYear( year ) ) { 00802 return QString(); 00803 } 00804 00805 // We must map month number to month index 00806 int monthIndex = d->monthNumberToMonthIndex( year, month ); 00807 00808 if ( format == ShortNamePossessive || format == LongNamePossessive ) { 00809 switch( monthIndex ) { 00810 case 1: 00811 return ki18n( "of Tishrey" ).toString( locale() ); 00812 case 2: 00813 return ki18n( "of Heshvan" ).toString( locale() ); 00814 case 3: 00815 return ki18n( "of Kislev" ).toString( locale() ); 00816 case 4: 00817 return ki18n( "of Tevet" ).toString( locale() ); 00818 case 5: 00819 return ki18n( "of Shvat" ).toString( locale() ); 00820 case 6: 00821 return ki18n( "of Adar" ).toString( locale() ); 00822 case 7: 00823 return ki18n( "of Nisan" ).toString( locale() ); 00824 case 8: 00825 return ki18n( "of Iyar" ).toString( locale() ); 00826 case 9: 00827 return ki18n( "of Sivan" ).toString( locale() ); 00828 case 10: 00829 return ki18n( "of Tamuz" ).toString( locale() ); 00830 case 11: 00831 return ki18n( "of Av" ).toString( locale() ); 00832 case 12: 00833 return ki18n( "of Elul" ).toString( locale() ); 00834 case 13: 00835 return ki18n( "of Adar I" ).toString( locale() ); 00836 case 14: 00837 return ki18n( "of Adar II" ).toString( locale() ); 00838 default: 00839 return QString(); 00840 } 00841 } 00842 00843 switch( monthIndex ) { 00844 case 1: 00845 return ki18n( "Tishrey" ).toString( locale() ); 00846 case 2: 00847 return ki18n( "Heshvan" ).toString( locale() ); 00848 case 3: 00849 return ki18n( "Kislev" ).toString( locale() ); 00850 case 4: 00851 return ki18n( "Tevet" ).toString( locale() ); 00852 case 5: 00853 return ki18n( "Shvat" ).toString( locale() ); 00854 case 6: 00855 return ki18n( "Adar" ).toString( locale() ); 00856 case 7: 00857 return ki18n( "Nisan" ).toString( locale() ); 00858 case 8: 00859 return ki18n( "Iyar" ).toString( locale() ); 00860 case 9: 00861 return ki18n( "Sivan" ).toString( locale() ); 00862 case 10: 00863 return ki18n( "Tamuz" ).toString( locale() ); 00864 case 11: 00865 return ki18n( "Av" ).toString( locale() ); 00866 case 12: 00867 return ki18n( "Elul" ).toString( locale() ); 00868 case 13: 00869 return ki18n( "Adar I" ).toString( locale() ); 00870 case 14: 00871 return ki18n( "Adar II" ).toString( locale() ); 00872 default: 00873 return QString(); 00874 } 00875 } 00876 00877 QString KCalendarSystemHebrew::monthName( const QDate& date, MonthNameFormat format ) const 00878 { 00879 return monthName( month( date ), year( date ), format ); 00880 } 00881 00882 QString KCalendarSystemHebrew::weekDayName( int weekDay, WeekDayNameFormat format ) const 00883 { 00884 // Use Western day names for now as that's what the old version did, 00885 // but wouldn't it be better to use the right Hebrew names like Shabbat? 00886 // Could make it switchable by adding new enums to WeekDayFormat, e.g. ShortNameWestern? 00887 if ( format == ShortDayName ) { 00888 switch ( weekDay ) { 00889 case 1: return ki18nc( "Monday", "Mon" ).toString( locale() ); 00890 case 2: return ki18nc( "Tuesday", "Tue" ).toString( locale() ); 00891 case 3: return ki18nc( "Wednesday", "Wed" ).toString( locale() ); 00892 case 4: return ki18nc( "Thursday", "Thu" ).toString( locale() ); 00893 case 5: return ki18nc( "Friday", "Fri" ).toString( locale() ); 00894 case 6: return ki18nc( "Saturday", "Sat" ).toString( locale() ); 00895 case 7: return ki18nc( "Sunday", "Sun" ).toString( locale() ); 00896 default: return QString(); 00897 } 00898 } 00899 00900 switch ( weekDay ) { 00901 case 1: return ki18n( "Monday" ).toString( locale() ); 00902 case 2: return ki18n( "Tuesday" ).toString( locale() ); 00903 case 3: return ki18n( "Wednesday" ).toString( locale() ); 00904 case 4: return ki18n( "Thursday" ).toString( locale() ); 00905 case 5: return ki18n( "Friday" ).toString( locale() ); 00906 case 6: return ki18n( "Saturday" ).toString( locale() ); 00907 case 7: return ki18n( "Sunday" ).toString( locale() ); 00908 default: return QString(); 00909 } 00910 } 00911 00912 QString KCalendarSystemHebrew::weekDayName( const QDate &date, WeekDayNameFormat format ) const 00913 { 00914 return weekDayName( dayOfWeek( date ), format ); 00915 } 00916 00917 QString KCalendarSystemHebrew::yearString( const QDate &date, StringFormat format ) const 00918 { 00919 return KCalendarSystem::yearString( date, format ); 00920 } 00921 00922 QString KCalendarSystemHebrew::monthString( const QDate &date, StringFormat format ) const 00923 { 00924 return KCalendarSystem::monthString( date, format ); 00925 } 00926 00927 QString KCalendarSystemHebrew::dayString( const QDate &date, StringFormat format ) const 00928 { 00929 return KCalendarSystem::dayString( date, format ); 00930 } 00931 00932 int KCalendarSystemHebrew::yearStringToInteger( const QString &string, int &readLength ) const 00933 { 00934 int result = KCalendarSystem::yearStringToInteger( string, readLength ); 00935 00936 // Hebrew has no letter for 0, so 5 and 5000 are written the same 00937 // Assume if less than 10 then we are in an exact multiple of 1000 00938 if ( result < 10 ) { 00939 result = result * 1000; 00940 } 00941 00942 // Not good just assuming, make configurable 00943 if ( result < 1000 ) { 00944 result += 5000; // assume we're in the 6th millenium (y6k bug) 00945 } 00946 00947 return result; 00948 } 00949 00950 int KCalendarSystemHebrew::monthStringToInteger( const QString &string, int &readLength ) const 00951 { 00952 return KCalendarSystem::monthStringToInteger( string, readLength ); 00953 } 00954 00955 int KCalendarSystemHebrew::dayStringToInteger( const QString &string, int &readLength ) const 00956 { 00957 return KCalendarSystem::yearStringToInteger( string, readLength ); 00958 } 00959 00960 QString KCalendarSystemHebrew::formatDate( const QDate &date, KLocale::DateFormat format ) const 00961 { 00962 return KCalendarSystem::formatDate( date, format ); 00963 } 00964 00965 QDate KCalendarSystemHebrew::readDate( const QString &str, bool *ok ) const 00966 { 00967 return KCalendarSystem::readDate( str, ok ); 00968 } 00969 00970 QDate KCalendarSystemHebrew::readDate( const QString &intstr, const QString &fmt, bool *ok ) const 00971 { 00972 return KCalendarSystem::readDate( intstr, fmt, ok ); 00973 } 00974 00975 QDate KCalendarSystemHebrew::readDate( const QString &str, KLocale::ReadDateFlags flags, bool *ok ) const 00976 { 00977 return KCalendarSystem::readDate( str, flags, ok ); 00978 } 00979 00980 int KCalendarSystemHebrew::weekDayOfPray() const 00981 { 00982 return 6; // Saturday 00983 } 00984 00985 int KCalendarSystemHebrew::weekStartDay() const 00986 { 00987 return KCalendarSystem::weekStartDay(); 00988 } 00989 00990 bool KCalendarSystemHebrew::isLunar() const 00991 { 00992 return false; 00993 } 00994 00995 bool KCalendarSystemHebrew::isLunisolar() const 00996 { 00997 return true; 00998 } 00999 01000 bool KCalendarSystemHebrew::isSolar() const 01001 { 01002 return false; 01003 } 01004 01005 bool KCalendarSystemHebrew::isProleptic() const 01006 { 01007 return false; 01008 } 01009 01010 bool KCalendarSystemHebrew::julianDayToDate( int jd, int &year, int &month, int &day ) const 01011 { 01012 class h_date * sd = toHebrew( QDate::fromJulianDay( jd ) ); 01013 01014 year = sd->hd_year; 01015 01016 month = sd->hd_mon; 01017 if ( isLeapYear( sd->hd_year ) ) { 01018 if( month == 13 /*AdarI*/ ) { 01019 month = 6; 01020 } else if( month == 14 /*AdarII*/ ) { 01021 month = 7; 01022 } else if ( month > 6 && month < 13 ) { 01023 ++month; 01024 } 01025 } 01026 01027 day = sd->hd_day; 01028 01029 return true; 01030 } 01031 01032 bool KCalendarSystemHebrew::dateToJulianDay( int year, int month, int day, int &jd ) const 01033 { 01034 class h_date * gd = hebrewToGregorian( year, month, day ); 01035 01036 QDate tempDate( gd->hd_year, gd->hd_mon + 1, gd->hd_day + 1 ); 01037 01038 jd = tempDate.toJulianDay(); 01039 01040 return true; 01041 }
KDE 4.6 API Reference