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 virtual QString monthName(int month, int year, KLocale::DateTimeComponentFormat format, bool possessive) const; 00260 virtual QString weekDayName(int weekDay, KLocale::DateTimeComponentFormat format) const; 00261 00262 virtual int integerFromString(const QString &string, int maxLength, int &readLength) const; 00263 virtual QString stringFromInteger(int number, int padWidth = 0, QChar padChar = QLatin1Char('0')) const; 00264 virtual QString stringFromInteger(int number, int padWidth, QChar padChar, KLocale::DigitSet digitSet) const; 00265 00266 virtual int monthNumberToMonthIndex(int year, int month) const; 00267 }; 00268 00269 // Shared d pointer base class definitions 00270 00271 KCalendarSystemHebrewPrivate::KCalendarSystemHebrewPrivate(KCalendarSystemHebrew *q) 00272 : KCalendarSystemPrivate(q) 00273 { 00274 } 00275 00276 KCalendarSystemHebrewPrivate::~KCalendarSystemHebrewPrivate() 00277 { 00278 } 00279 00280 KLocale::CalendarSystem KCalendarSystemHebrewPrivate::calendarSystem() const 00281 { 00282 return KLocale::HebrewCalendar; 00283 } 00284 00285 void KCalendarSystemHebrewPrivate::loadDefaultEraList() 00286 { 00287 QString name, shortName, format; 00288 // Jewish Era, Anno Mundi, "Year of the World". 00289 name = i18nc("Calendar Era: Hebrew Era, years > 0, LongFormat", "Anno Mundi"); 00290 shortName = i18nc("Calendar Era: Hebrew Era, years > 0, ShortFormat", "AM"); 00291 format = i18nc("(kdedt-format) Hebrew, AM, full era year format used for %EY, e.g. 2000 AM", "%Ey %EC"); 00292 addEra('+', 1, q->epoch(), 1, q->latestValidDate(), name, shortName, format); 00293 } 00294 00295 int KCalendarSystemHebrewPrivate::monthsInYear(int year) const 00296 { 00297 if (isLeapYear(year)) { 00298 return 13; 00299 } else { 00300 return 12; 00301 } 00302 } 00303 00304 int KCalendarSystemHebrewPrivate::daysInMonth(int year, int month) const 00305 { 00306 int mi = monthNumberToMonthIndex(year, month); 00307 00308 if (mi == 2 && long_cheshvan(year)) { 00309 return 30; 00310 } 00311 00312 if (mi == 3 && short_kislev(year)) { 00313 return 29; 00314 } 00315 00316 if (mi % 2 == 0) { // Even number months have 29 days 00317 return 29; 00318 } else { // Odd number months have 30 days 00319 return 30; 00320 } 00321 } 00322 00323 int KCalendarSystemHebrewPrivate::daysInYear(int year) const 00324 { 00325 int days; 00326 00327 // Get Regular year length 00328 if (isLeapYear(year)) { // Has 13 months 00329 days = 384; 00330 } else { // Has 12 months 00331 days = 354; 00332 } 00333 00334 // Check if is Deficient or Abundant year 00335 if (short_kislev(year)) { // Deficient 00336 days = days - 1; 00337 } else if (long_cheshvan(year)) { // Abundant 00338 days = days + 1; 00339 } 00340 00341 return days; 00342 } 00343 00344 int KCalendarSystemHebrewPrivate::daysInWeek() const 00345 { 00346 return 7; 00347 } 00348 00349 bool KCalendarSystemHebrewPrivate::isLeapYear(int year) const 00350 { 00351 return ((((7 * year) + 1) % 19) < 7); 00352 } 00353 00354 bool KCalendarSystemHebrewPrivate::hasLeapMonths() const 00355 { 00356 return true; 00357 } 00358 00359 bool KCalendarSystemHebrewPrivate::hasYearZero() const 00360 { 00361 return false; 00362 } 00363 00364 int KCalendarSystemHebrewPrivate::maxDaysInWeek() const 00365 { 00366 return 7; 00367 } 00368 00369 int KCalendarSystemHebrewPrivate::maxMonthsInYear() const 00370 { 00371 return 13; 00372 } 00373 00374 int KCalendarSystemHebrewPrivate::earliestValidYear() const 00375 { 00376 return 5344; 00377 } 00378 00379 int KCalendarSystemHebrewPrivate::latestValidYear() const 00380 { 00381 return 8119; 00382 } 00383 00384 int KCalendarSystemHebrewPrivate::integerFromString(const QString &inputString, int maxLength, int &readLength) const 00385 { 00386 if (locale()->language() == QLatin1String("he")) { 00387 00388 // Hebrew numbers are composed of combinations of normal letters which have a numeric value. 00389 // This is a non-positional system, the numeric values are simply added together, however 00390 // convention is for a RTL highest to lowest value ordering. There is also a degree of 00391 // ambiguity due to the lack of a letter for 0, hence 5 and 5000 are written the same. 00392 // Hebrew numbers are only used in dates. 00393 // See http://www.i18nguy.com/unicode/hebrew-numbers.html for more explaination 00394 00395 /* 00396 Ref table for numbers to Hebrew chars 00397 00398 Value 1 2 3 4 5 6 7 8 9 00399 00400 x 1 Alef א Bet ב Gimel ג Dalet ד He ה Vav ו Zayen ז Het ח Tet ט 00401 0x05D0 0x05D1 0x05D2 0x05D3 0x05D4 0x05D5 0x05D6 0x05D7 0x05D8 00402 00403 x 10 Yod י Kaf כ Lamed ל Mem מ Nun נ Samekh ס Ayin ע Pe פ Tzadi צ 00404 0x05D9 0x05DB 0x05DC 0x05DE 0x05E0 0x05E1 0x05E2 0x05E4 0x05E6 00405 00406 x 100 Qof ק Resh ר Shin ש Tav ת 00407 0x05E7 0x05E8 0x05E9 0x05EA 00408 00409 Note special cases 15 = 9 + 6 = 96 טו and 16 = 9 + 7 = 97 טז 00410 */ 00411 00412 int decadeValues[14] = {10, 20, 20, 30, 40, 40, 50, 50, 60, 70, 80, 80, 90, 90}; 00413 00414 QChar thisChar, nextChar; 00415 QString string = inputString; 00416 00417 int stringLength = string.length(); 00418 readLength = 0; 00419 int position = 0; 00420 int result = 0; 00421 int value = 0; 00422 00423 for (; position < stringLength ; ++position) { 00424 00425 thisChar = string[position]; 00426 00427 if (position + 1 < stringLength) { 00428 nextChar = string[position + 1]; 00429 // Ignore any geresh or gershayim chars, we don't bother checking they are in the right place 00430 if (nextChar == QLatin1Char('\'') || nextChar == QChar(0x05F3) || // geresh 00431 nextChar == QLatin1Char('\"') || nextChar == QChar(0x05F4)) { // gershayim 00432 string.remove(position + 1, 1); 00433 stringLength = string.length(); 00434 if (position + 1 < stringLength) { 00435 nextChar = string[position + 1]; 00436 } else { 00437 nextChar = QChar(); 00438 } 00439 readLength = readLength + 1; 00440 } 00441 } else { 00442 nextChar = QChar(); 00443 } 00444 00445 if (thisChar >= QChar(0x05D0) && thisChar <= QChar(0x05D7)) { 00446 00447 // If this char Alef to Het, 1 to 8, א to ח 00448 00449 // If next char is any valid digit char (Alef to Tav, 1 to 400, א to ת) 00450 // then this char is a thousands digit 00451 // else this char is a ones digit 00452 00453 if (nextChar >= QChar(0x05D0) && nextChar <= QChar(0x05EA)) { 00454 value = (thisChar.unicode() - 0x05D0 + 1) * 1000; 00455 } else { 00456 value = thisChar.unicode() - 0x05D0 + 1; 00457 } 00458 00459 } else if (thisChar == QChar(0x05D8)) { 00460 00461 // If this char is Tet, 9, ט 00462 00463 // If next char is any valid digit char (Alef to Tav, 1 to 400, א to ת) 00464 // and next char not 6 (Special case for 96 = 15) 00465 // and next char not 7 (Special case for 97 = 16) 00466 // then is a thousands digit else is 9 00467 00468 if (nextChar >= QChar(0x05D0) && nextChar <= QChar(0x05EA) && 00469 nextChar != QChar(0x05D5) && nextChar != QChar(0x05D6)) { 00470 value = 9000; 00471 } else { 00472 value = 9; 00473 } 00474 00475 } else if (thisChar >= QChar(0x05D9) && thisChar <= QChar(0x05E6)) { 00476 00477 // If this char Yod to Tsadi, 10 to 90, י to צ 00478 00479 // If next char is a tens or hundreds char then is an error 00480 // Else is a tens digit 00481 00482 if (nextChar >= QChar(0x05D9)) { 00483 return -1; 00484 } else { 00485 value = decadeValues[thisChar.unicode() - 0x05D9]; 00486 } 00487 00488 } else if (thisChar >= QChar(0x05E7) && thisChar <= QChar(0x05EA)) { 00489 00490 // If this char Qof to Tav, 100 to 400, ק to ת, then is hundreds digit 00491 00492 value = (thisChar.unicode() - 0x05E7 + 1) * 100; 00493 00494 } else { 00495 00496 // If this char any non-digit char including whitespace or punctuation, we're done 00497 break; 00498 00499 } 00500 00501 result = result + value; 00502 00503 value = 0; 00504 } 00505 00506 readLength += position; 00507 00508 return result; 00509 00510 } else { 00511 return KCalendarSystemPrivate::integerFromString(inputString, maxLength, readLength); 00512 } 00513 } 00514 00515 QString KCalendarSystemHebrewPrivate::stringFromInteger(int number, int padWidth, QChar padChar) const 00516 { 00517 return KCalendarSystemPrivate::stringFromInteger(number, padWidth, padChar); 00518 } 00519 00520 QString KCalendarSystemHebrewPrivate::stringFromInteger(int number, int padWidth, QChar padChar, KLocale::DigitSet digitSet) const 00521 { 00522 if (locale()->language() == QLatin1String("he")) { 00523 00524 // Hebrew numbers are composed of combinations of normal letters which have a numeric value. 00525 // This is a non-positional system, the numeric values are simply added together, however 00526 // convention is for a RTL highest to lowest value ordering. There is also a degree of 00527 // ambiguity due to the lack of a letter for 0, hence 5 and 5000 are written the same. 00528 // Hebrew numbers are only used in dates. 00529 // See http://www.i18nguy.com/unicode/hebrew-numbers.html for more explaination 00530 00531 /* 00532 Ref table for numbers to Hebrew chars 00533 00534 Value 1 2 3 4 5 6 7 8 9 00535 00536 x 1 Alef א Bet ב Gimel ג Dalet ד He ה Vav ו Zayen ז Het ח Tet ט 00537 0x05D0 0x05D1 0x05D2 0x05D3 0x05D4 0x05D5 0x05D6 0x05D7 0x05D8 00538 00539 x 10 Yod י Kaf כ Lamed ל Mem מ Nun נ Samekh ס Ayin ע Pe פ Tzadi צ 00540 0x05D9 0x05DB 0x05DC 0x05DE 0x05E0 0x05E1 0x05E2 0x05E4 0x05E6 00541 00542 x 100 Qof ק Resh ר Shin ש Tav ת 00543 0x05E7 0x05E8 0x05E9 0x05EA 00544 00545 Note special cases 15 = 9 + 6 = 96 טו and 16 = 9 + 7 = 97 טז 00546 */ 00547 00548 const QChar decade[] = { 00549 // Tet = ט, Yod = י, Kaf = כ, Lamed = ל, Mem = מ 00550 // Nun = נ, Samekh = ס, Ayin = ע, Pe = פ, Tsadi = צ 00551 0x05D8, 0x05D9, 0x05DB, 0x05DC, 0x05DE, 00552 0x05E0, 0x05E1, 0x05E2, 0x05E4, 0x05E6 00553 }; 00554 00555 QString result; 00556 00557 // We have no rules for coping with numbers outside this range 00558 if (number < 1 || number > 9999) { 00559 return KCalendarSystemPrivate::stringFromInteger(number, padWidth, padChar, digitSet); 00560 } 00561 00562 // Translate the thousands digit, just uses letter for number 1..9 ( א to ט, Alef to Tet ) 00563 // Years 5001-5999 do not have the thousands by convention 00564 if (number >= 1000) { 00565 if (number <= 5000 || number >= 6000) { 00566 result += QChar(0x05D0 - 1 + number / 1000); // Alef א to Tet ט 00567 } 00568 number %= 1000; 00569 } 00570 00571 // Translate the hundreds digit 00572 // Use traditional method where we only have letters assigned values for 100, 200, 300 and 400 00573 // so may need to repeat 400 twice to make up the required number 00574 if (number >= 100) { 00575 while (number >= 500) { 00576 result += QChar(0x05EA); // Tav = ת 00577 number -= 400; 00578 } 00579 result += QChar(0x05E7 - 1 + number / 100); // Qof = ק to xxx 00580 number %= 100; 00581 } 00582 00583 // Translate the tens digit 00584 // The numbers 15 and 16 translate to letters that spell out the name of God which is 00585 // forbidden, so require special treatment where 15 = 9 + 6 and 1 = 9 + 7. 00586 if (number >= 10) { 00587 if (number == 15 || number == 16) 00588 number -= 9; 00589 result += decade[number / 10]; 00590 number %= 10; 00591 } 00592 00593 // Translate the ones digit, uses letter for number 1..9 ( א to ט, Alef to Tet ) 00594 if (number > 0) { 00595 result += QChar(0x05D0 - 1 + number); // Alef = א to xxx 00596 } 00597 00598 // When used in a string with mixed names and numbers the numbers need special chars to 00599 // distinguish them from words composed of the same letters. 00600 // Single digit numbers are followed by a geresh symbol ? (Unicode = 0x05F3), but we use 00601 // single quote for convenience. 00602 // Multiple digit numbers have a gershayim symbol ? (Unicode = 0x05F4) as second-to-last 00603 // char, but we use double quote for convenience. 00604 if (result.length() == 1) { 00605 result += QLatin1Char('\''); 00606 } else { 00607 result.insert(result.length() - 1, QLatin1Char('\"')); 00608 } 00609 00610 return result; 00611 00612 } else { 00613 return KCalendarSystemPrivate::stringFromInteger(number, padWidth, padChar, digitSet); 00614 } 00615 } 00616 00617 int KCalendarSystemHebrewPrivate::monthNumberToMonthIndex(int year, int month) const 00618 { 00619 if (isLeapYear(year)) { 00620 if (month == 6) { 00621 return 13; // Adar I 00622 } else if (month == 7) { 00623 return 14; // Adar II 00624 } else if (month > 7) { 00625 return month - 1; // Because of Adar II 00626 } 00627 } 00628 00629 return month; 00630 } 00631 00632 QString KCalendarSystemHebrewPrivate::monthName(int month, int year, KLocale::DateTimeComponentFormat format, bool possessive) const 00633 { 00634 // We must map month number to month index 00635 int monthIndex = monthNumberToMonthIndex(year, month); 00636 00637 if (format == KLocale::NarrowName) { 00638 switch (monthIndex) { 00639 case 1: 00640 return ki18nc("Hebrew month 1 - KLocale::NarrowName", "T").toString(locale()); 00641 case 2: 00642 return ki18nc("Hebrew month 2 - KLocale::NarrowName", "H").toString(locale()); 00643 case 3: 00644 return ki18nc("Hebrew month 3 - KLocale::NarrowName", "K").toString(locale()); 00645 case 4: 00646 return ki18nc("Hebrew month 4 - KLocale::NarrowName", "T").toString(locale()); 00647 case 5: 00648 return ki18nc("Hebrew month 5 - KLocale::NarrowName", "S").toString(locale()); 00649 case 6: 00650 return ki18nc("Hebrew month 6 - KLocale::NarrowName", "A").toString(locale()); 00651 case 7: 00652 return ki18nc("Hebrew month 7 - KLocale::NarrowName", "N").toString(locale()); 00653 case 8: 00654 return ki18nc("Hebrew month 8 - KLocale::NarrowName", "I").toString(locale()); 00655 case 9: 00656 return ki18nc("Hebrew month 9 - KLocale::NarrowName", "S").toString(locale()); 00657 case 10: 00658 return ki18nc("Hebrew month 10 - KLocale::NarrowName", "T").toString(locale()); 00659 case 11: 00660 return ki18nc("Hebrew month 11 - KLocale::NarrowName", "A").toString(locale()); 00661 case 12: 00662 return ki18nc("Hebrew month 12 - KLocale::NarrowName", "E").toString(locale()); 00663 case 13: 00664 return ki18nc("Hebrew month 13 - KLocale::NarrowName", "A").toString(locale()); 00665 case 14: 00666 return ki18nc("Hebrew month 14 - KLocale::NarrowName", "A").toString(locale()); 00667 default: 00668 return QString(); 00669 } 00670 } 00671 00672 if (format == KLocale::ShortName && possessive) { 00673 switch (monthIndex) { 00674 case 1: 00675 return ki18nc("Hebrew month 1 - KLocale::ShortName Possessive", "of Tis").toString(locale()); 00676 case 2: 00677 return ki18nc("Hebrew month 2 - KLocale::ShortName Possessive", "of Hes").toString(locale()); 00678 case 3: 00679 return ki18nc("Hebrew month 3 - KLocale::ShortName Possessive", "of Kis").toString(locale()); 00680 case 4: 00681 return ki18nc("Hebrew month 4 - KLocale::ShortName Possessive", "of Tev").toString(locale()); 00682 case 5: 00683 return ki18nc("Hebrew month 5 - KLocale::ShortName Possessive", "of Shv").toString(locale()); 00684 case 6: 00685 return ki18nc("Hebrew month 6 - KLocale::ShortName Possessive", "of Ada").toString(locale()); 00686 case 7: 00687 return ki18nc("Hebrew month 7 - KLocale::ShortName Possessive", "of Nis").toString(locale()); 00688 case 8: 00689 return ki18nc("Hebrew month 8 - KLocale::ShortName Possessive", "of Iya").toString(locale()); 00690 case 9: 00691 return ki18nc("Hebrew month 9 - KLocale::ShortName Possessive", "of Siv").toString(locale()); 00692 case 10: 00693 return ki18nc("Hebrew month 10 - KLocale::ShortName Possessive", "of Tam").toString(locale()); 00694 case 11: 00695 return ki18nc("Hebrew month 11 - KLocale::ShortName Possessive", "of Av").toString(locale()); 00696 case 12: 00697 return ki18nc("Hebrew month 12 - KLocale::ShortName Possessive", "of Elu").toString(locale()); 00698 case 13: 00699 return ki18nc("Hebrew month 13 - KLocale::ShortName Possessive", "of Ad1").toString(locale()); 00700 case 14: 00701 return ki18nc("Hebrew month 14 - KLocale::ShortName Possessive", "of Ad2").toString(locale()); 00702 default: 00703 return QString(); 00704 } 00705 } 00706 00707 if (format == KLocale::ShortName && !possessive) { 00708 switch (monthIndex) { 00709 case 1: 00710 return ki18nc("Hebrew month 1 - KLocale::ShortName", "Tis").toString(locale()); 00711 case 2: 00712 return ki18nc("Hebrew month 2 - KLocale::ShortName", "Hes").toString(locale()); 00713 case 3: 00714 return ki18nc("Hebrew month 3 - KLocale::ShortName", "Kis").toString(locale()); 00715 case 4: 00716 return ki18nc("Hebrew month 4 - KLocale::ShortName", "Tev").toString(locale()); 00717 case 5: 00718 return ki18nc("Hebrew month 5 - KLocale::ShortName", "Shv").toString(locale()); 00719 case 6: 00720 return ki18nc("Hebrew month 6 - KLocale::ShortName", "Ada").toString(locale()); 00721 case 7: 00722 return ki18nc("Hebrew month 7 - KLocale::ShortName", "Nis").toString(locale()); 00723 case 8: 00724 return ki18nc("Hebrew month 8 - KLocale::ShortName", "Iya").toString(locale()); 00725 case 9: 00726 return ki18nc("Hebrew month 9 - KLocale::ShortName", "Siv").toString(locale()); 00727 case 10: 00728 return ki18nc("Hebrew month 10 - KLocale::ShortName", "Tam").toString(locale()); 00729 case 11: 00730 return ki18nc("Hebrew month 11 - KLocale::ShortName", "Av").toString(locale()); 00731 case 12: 00732 return ki18nc("Hebrew month 12 - KLocale::ShortName", "Elu").toString(locale()); 00733 case 13: 00734 return ki18nc("Hebrew month 13 - KLocale::ShortName", "Ad1").toString(locale()); 00735 case 14: 00736 return ki18nc("Hebrew month 14 - KLocale::ShortName", "Ad2").toString(locale()); 00737 default: 00738 return QString(); 00739 } 00740 } 00741 00742 if (format == KLocale::LongName && possessive) { 00743 switch (monthIndex) { 00744 case 1: 00745 return ki18nc("Hebrew month 1 - KLocale::LongName Possessive", "of Tishrey").toString(locale()); 00746 case 2: 00747 return ki18nc("Hebrew month 2 - KLocale::LongName Possessive", "of Heshvan").toString(locale()); 00748 case 3: 00749 return ki18nc("Hebrew month 3 - KLocale::LongName Possessive", "of Kislev").toString(locale()); 00750 case 4: 00751 return ki18nc("Hebrew month 4 - KLocale::LongName Possessive", "of Tevet").toString(locale()); 00752 case 5: 00753 return ki18nc("Hebrew month 5 - KLocale::LongName Possessive", "of Shvat").toString(locale()); 00754 case 6: 00755 return ki18nc("Hebrew month 6 - KLocale::LongName Possessive", "of Adar").toString(locale()); 00756 case 7: 00757 return ki18nc("Hebrew month 7 - KLocale::LongName Possessive", "of Nisan").toString(locale()); 00758 case 8: 00759 return ki18nc("Hebrew month 8 - KLocale::LongName Possessive", "of Iyar").toString(locale()); 00760 case 9: 00761 return ki18nc("Hebrew month 9 - KLocale::LongName Possessive", "of Sivan").toString(locale()); 00762 case 10: 00763 return ki18nc("Hebrew month 10 - KLocale::LongName Possessive", "of Tamuz").toString(locale()); 00764 case 11: 00765 return ki18nc("Hebrew month 11 - KLocale::LongName Possessive", "of Av").toString(locale()); 00766 case 12: 00767 return ki18nc("Hebrew month 12 - KLocale::LongName Possessive", "of Elul").toString(locale()); 00768 case 13: 00769 return ki18nc("Hebrew month 13 - KLocale::LongName Possessive", "of Adar I").toString(locale()); 00770 case 14: 00771 return ki18nc("Hebrew month 14 - KLocale::LongName Possessive", "of Adar II").toString(locale()); 00772 default: 00773 return QString(); 00774 } 00775 } 00776 00777 // Default to LongName 00778 switch (monthIndex) { 00779 case 1: 00780 return ki18nc("Hebrew month 1 - KLocale::LongName", "Tishrey").toString(locale()); 00781 case 2: 00782 return ki18nc("Hebrew month 2 - KLocale::LongName", "Heshvan").toString(locale()); 00783 case 3: 00784 return ki18nc("Hebrew month 3 - KLocale::LongName", "Kislev").toString(locale()); 00785 case 4: 00786 return ki18nc("Hebrew month 4 - KLocale::LongName", "Tevet").toString(locale()); 00787 case 5: 00788 return ki18nc("Hebrew month 5 - KLocale::LongName", "Shvat").toString(locale()); 00789 case 6: 00790 return ki18nc("Hebrew month 6 - KLocale::LongName", "Adar").toString(locale()); 00791 case 7: 00792 return ki18nc("Hebrew month 7 - KLocale::LongName", "Nisan").toString(locale()); 00793 case 8: 00794 return ki18nc("Hebrew month 8 - KLocale::LongName", "Iyar").toString(locale()); 00795 case 9: 00796 return ki18nc("Hebrew month 9 - KLocale::LongName", "Sivan").toString(locale()); 00797 case 10: 00798 return ki18nc("Hebrew month 10 - KLocale::LongName", "Tamuz").toString(locale()); 00799 case 11: 00800 return ki18nc("Hebrew month 11 - KLocale::LongName", "Av").toString(locale()); 00801 case 12: 00802 return ki18nc("Hebrew month 12 - KLocale::LongName", "Elul").toString(locale()); 00803 case 13: 00804 return ki18nc("Hebrew month 13 - KLocale::LongName", "Adar I").toString(locale()); 00805 case 14: 00806 return ki18nc("Hebrew month 14 - KLocale::LongName", "Adar II").toString(locale()); 00807 default: 00808 return QString(); 00809 } 00810 } 00811 00812 // Use Western day names for now as that's what the old version did, 00813 // but wouldn't it be better to use the right Hebrew names like Shabbat? 00814 // Could make it switchable by adding new enums to WeekDayFormat, e.g. ShortNameWestern? 00815 QString KCalendarSystemHebrewPrivate::weekDayName(int weekDay, KLocale::DateTimeComponentFormat format) const 00816 { 00817 if (format == KLocale::NarrowName) { 00818 switch (weekDay) { 00819 case 1: 00820 return ki18nc("Gregorian weekday 1 - KLocale::NarrowName ", "M").toString(locale()); 00821 case 2: 00822 return ki18nc("Gregorian weekday 2 - KLocale::NarrowName ", "T").toString(locale()); 00823 case 3: 00824 return ki18nc("Gregorian weekday 3 - KLocale::NarrowName ", "W").toString(locale()); 00825 case 4: 00826 return ki18nc("Gregorian weekday 4 - KLocale::NarrowName ", "T").toString(locale()); 00827 case 5: 00828 return ki18nc("Gregorian weekday 5 - KLocale::NarrowName ", "F").toString(locale()); 00829 case 6: 00830 return ki18nc("Gregorian weekday 6 - KLocale::NarrowName ", "S").toString(locale()); 00831 case 7: 00832 return ki18nc("Gregorian weekday 7 - KLocale::NarrowName ", "S").toString(locale()); 00833 default: 00834 return QString(); 00835 } 00836 } 00837 00838 if (format == KLocale::ShortName || format == KLocale:: ShortNumber) { 00839 switch (weekDay) { 00840 case 1: 00841 return ki18nc("Gregorian weekday 1 - KLocale::ShortName", "Mon").toString(locale()); 00842 case 2: 00843 return ki18nc("Gregorian weekday 2 - KLocale::ShortName", "Tue").toString(locale()); 00844 case 3: 00845 return ki18nc("Gregorian weekday 3 - KLocale::ShortName", "Wed").toString(locale()); 00846 case 4: 00847 return ki18nc("Gregorian weekday 4 - KLocale::ShortName", "Thu").toString(locale()); 00848 case 5: 00849 return ki18nc("Gregorian weekday 5 - KLocale::ShortName", "Fri").toString(locale()); 00850 case 6: 00851 return ki18nc("Gregorian weekday 6 - KLocale::ShortName", "Sat").toString(locale()); 00852 case 7: 00853 return ki18nc("Gregorian weekday 7 - KLocale::ShortName", "Sun").toString(locale()); 00854 default: return QString(); 00855 } 00856 } 00857 00858 switch (weekDay) { 00859 case 1: 00860 return ki18nc("Gregorian weekday 1 - KLocale::LongName", "Monday").toString(locale()); 00861 case 2: 00862 return ki18nc("Gregorian weekday 2 - KLocale::LongName", "Tuesday").toString(locale()); 00863 case 3: 00864 return ki18nc("Gregorian weekday 3 - KLocale::LongName", "Wednesday").toString(locale()); 00865 case 4: 00866 return ki18nc("Gregorian weekday 4 - KLocale::LongName", "Thursday").toString(locale()); 00867 case 5: 00868 return ki18nc("Gregorian weekday 5 - KLocale::LongName", "Friday").toString(locale()); 00869 case 6: 00870 return ki18nc("Gregorian weekday 6 - KLocale::LongName", "Saturday").toString(locale()); 00871 case 7: 00872 return ki18nc("Gregorian weekday 7 - KLocale::LongName", "Sunday").toString(locale()); 00873 default: 00874 return QString(); 00875 } 00876 } 00877 00878 00879 KCalendarSystemHebrew::KCalendarSystemHebrew(const KLocale *locale) 00880 : KCalendarSystem(*new KCalendarSystemHebrewPrivate(this), KSharedConfig::Ptr(), locale) 00881 { 00882 d_ptr->loadConfig(calendarType()); 00883 } 00884 00885 KCalendarSystemHebrew::KCalendarSystemHebrew(const KSharedConfig::Ptr config, const KLocale *locale) 00886 : KCalendarSystem(*new KCalendarSystemHebrewPrivate(this), config, locale) 00887 { 00888 d_ptr->loadConfig(calendarType()); 00889 } 00890 00891 KCalendarSystemHebrew::KCalendarSystemHebrew(KCalendarSystemHebrewPrivate &dd, 00892 const KSharedConfig::Ptr config, const KLocale *locale) 00893 : KCalendarSystem(dd, config, locale) 00894 { 00895 d_ptr->loadConfig(calendarType()); 00896 } 00897 00898 KCalendarSystemHebrew::~KCalendarSystemHebrew() 00899 { 00900 } 00901 00902 QString KCalendarSystemHebrew::calendarType() const 00903 { 00904 return QLatin1String("hebrew"); 00905 } 00906 00907 QDate KCalendarSystemHebrew::epoch() const 00908 { 00909 // Hebrew 0001-01-01 (Gregorian -3760-09-07, Julian -3761-10-07) 00910 return QDate::fromJulianDay(347998); 00911 } 00912 00913 QDate KCalendarSystemHebrew::earliestValidDate() const 00914 { 00915 // Current formulas using direct Gregorian <-> Hebrew conversion using Qt 00916 // will return invalid results prior to the Gregorian switchover in 1582 00917 // Next valid Hebrew year starts 5344-01-01 (Gregorian 1583-09-17) 00918 return QDate::fromJulianDay(2299498); 00919 } 00920 00921 QDate KCalendarSystemHebrew::latestValidDate() const 00922 { 00923 // Testing shows current formulas only work up to 8119-13-29 (Gregorian 4359-10-07) 00924 return QDate::fromJulianDay(3313431); 00925 } 00926 00927 bool KCalendarSystemHebrew::isValid(int year, int month, int day) const 00928 { 00929 return KCalendarSystem::isValid(year, month, day); 00930 } 00931 00932 bool KCalendarSystemHebrew::isValid(const QDate &date) const 00933 { 00934 return KCalendarSystem::isValid(date); 00935 } 00936 00937 int KCalendarSystemHebrew::dayOfWeek(const QDate &date) const 00938 { 00939 class h_date * sd = toHebrew(date); 00940 if (sd->hd_dw == 0) { 00941 return 7; 00942 } else { 00943 return (sd->hd_dw); 00944 } 00945 } 00946 00947 bool KCalendarSystemHebrew::isLeapYear(int year) const 00948 { 00949 return KCalendarSystem::isLeapYear(year); 00950 } 00951 00952 bool KCalendarSystemHebrew::isLeapYear(const QDate &date) const 00953 { 00954 return KCalendarSystem::isLeapYear(date); 00955 } 00956 00957 QString KCalendarSystemHebrew::monthName(int month, int year, MonthNameFormat format) const 00958 { 00959 return KCalendarSystem::monthName(month, year, format); 00960 } 00961 00962 QString KCalendarSystemHebrew::monthName(const QDate &date, MonthNameFormat format) const 00963 { 00964 return KCalendarSystem::monthName(date, format); 00965 } 00966 00967 QString KCalendarSystemHebrew::weekDayName(int weekDay, WeekDayNameFormat format) const 00968 { 00969 return KCalendarSystem::weekDayName(weekDay, format); 00970 } 00971 00972 QString KCalendarSystemHebrew::weekDayName(const QDate &date, WeekDayNameFormat format) const 00973 { 00974 return KCalendarSystem::weekDayName(date, format); 00975 } 00976 00977 int KCalendarSystemHebrew::yearStringToInteger(const QString &string, int &readLength) const 00978 { 00979 int result = KCalendarSystem::yearStringToInteger(string, readLength); 00980 00981 // Hebrew has no letter for 0, so 5 and 5000 are written the same 00982 // Assume if less than 10 then we are in an exact multiple of 1000 00983 if (result < 10) { 00984 result = result * 1000; 00985 } 00986 00987 // Not good just assuming, make configurable 00988 if (result < 1000) { 00989 result += 5000; // assume we're in the 6th millenium (y6k bug) 00990 } 00991 00992 return result; 00993 } 00994 00995 int KCalendarSystemHebrew::weekDayOfPray() const 00996 { 00997 return 6; // Saturday 00998 } 00999 01000 bool KCalendarSystemHebrew::isLunar() const 01001 { 01002 return false; 01003 } 01004 01005 bool KCalendarSystemHebrew::isLunisolar() const 01006 { 01007 return true; 01008 } 01009 01010 bool KCalendarSystemHebrew::isSolar() const 01011 { 01012 return false; 01013 } 01014 01015 bool KCalendarSystemHebrew::isProleptic() const 01016 { 01017 return false; 01018 } 01019 01020 bool KCalendarSystemHebrew::julianDayToDate(int jd, int &year, int &month, int &day) const 01021 { 01022 class h_date * sd = toHebrew(QDate::fromJulianDay(jd)); 01023 01024 year = sd->hd_year; 01025 01026 month = sd->hd_mon; 01027 if (isLeapYear(sd->hd_year)) { 01028 if (month == 13 /*AdarI*/) { 01029 month = 6; 01030 } else if (month == 14 /*AdarII*/) { 01031 month = 7; 01032 } else if (month > 6 && month < 13) { 01033 ++month; 01034 } 01035 } 01036 01037 day = sd->hd_day; 01038 01039 return true; 01040 } 01041 01042 bool KCalendarSystemHebrew::dateToJulianDay(int year, int month, int day, int &jd) const 01043 { 01044 class h_date * gd = hebrewToGregorian(year, month, day); 01045 01046 QDate tempDate(gd->hd_year, gd->hd_mon + 1, gd->hd_day + 1); 01047 01048 jd = tempDate.toJulianDay(); 01049 01050 return true; 01051 }
KDE 4.7 API Reference