File indexing completed on 2023-09-24 04:04:44
0001 /* 0002 Copyright (c) 2003 Hans Petter Bieker <bieker@kde.org> 0003 Copyright 2007, 2009, 2010 John Layt <john@layt.net> 0004 Calendar conversion routines based on Hdate v6, by Amos 0005 Shapir 1978 (rev. 1985, 1992) 0006 0007 This library is free software; you can redistribute it and/or 0008 modify it under the terms of the GNU Library General Public 0009 License as published by the Free Software Foundation; either 0010 version 2 of the License, or (at your option) any later version. 0011 0012 This library is distributed in the hope that it will be useful, 0013 but WITHOUT ANY WARRANTY; without even the implied warranty of 0014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0015 Library General Public License for more details. 0016 0017 You should have received a copy of the GNU Library General Public License 0018 along with this library; see the file COPYING.LIB. If not, write to 0019 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0020 Boston, MA 02110-1301, USA. 0021 */ 0022 0023 // Derived hebrew kde calendar class 0024 0025 #include "kcalendarsystemhebrew_p.h" 0026 #include "kcalendarsystemprivate_p.h" 0027 0028 #include "klocale.h" 0029 #include "klocalizedstring.h" 0030 0031 #include <QDate> 0032 #include <QCharRef> 0033 0034 static int hebrewDaysElapsed(int y); 0035 0036 class h_date 0037 { 0038 public: 0039 int hd_day; 0040 int hd_mon; 0041 int hd_year; 0042 int hd_dw; 0043 int hd_flg; 0044 }; 0045 0046 /* 0047 * compute general date structure from hebrew date 0048 */ 0049 static class h_date *hebrewToGregorian(int y, int m, int d) 0050 { 0051 static class h_date h; 0052 int s; 0053 0054 y -= 3744; 0055 s = hebrewDaysElapsed(y); 0056 d += s; 0057 s = hebrewDaysElapsed(y + 1) - s; /* length of year */ 0058 0059 if (s > 365 && m > 6) { 0060 --m; 0061 d += 30; 0062 } 0063 d += (59 * (m - 1) + 1) / 2; /* regular months */ 0064 /* special cases */ 0065 if (s % 10 > 4 && m > 2) { /* long Heshvan */ 0066 d++; 0067 } 0068 if (s % 10 < 4 && m > 3) { /* short Kislev */ 0069 d--; 0070 } 0071 // ### HPB: Broken in leap years 0072 //if (s > 365 && m > 6) /* leap year */ 0073 // d += 30; 0074 d -= 6002; 0075 0076 y = (d + 36525) * 4 / 146097 - 1; 0077 d -= y / 4 * 146097 + (y % 4) * 36524; 0078 y *= 100; 0079 0080 /* compute year */ 0081 s = (d + 366) * 4 / 1461 - 1; 0082 d -= s / 4 * 1461 + (s % 4) * 365; 0083 y += s; 0084 /* compute month */ 0085 m = (d + 245) * 12 / 367 - 7; 0086 d -= m * 367 / 12 - 30; 0087 if (++m >= 12) { 0088 m -= 12; 0089 y++; 0090 } 0091 h.hd_day = d; 0092 h.hd_mon = m; 0093 h.hd_year = y; 0094 return (&h); 0095 } 0096 0097 /* 0098 * compute date structure from no. of days since 1 Tishrei 3744 0099 */ 0100 static class h_date *gregorianToHebrew(int y, int m, int d) 0101 { 0102 static class h_date h; 0103 int s; 0104 0105 if ((m -= 2) <= 0) { 0106 m += 12; 0107 y--; 0108 } 0109 /* no. of days, Julian calendar */ 0110 d += 365 * y + y / 4 + 367 * m / 12 + 5968; 0111 /* Gregorian calendar */ 0112 d -= y / 100 - y / 400 - 2; 0113 h.hd_dw = (d + 1) % 7; 0114 0115 /* compute the year */ 0116 y += 16; 0117 s = hebrewDaysElapsed(y); 0118 m = hebrewDaysElapsed(y + 1); 0119 while (d >= m) { /* computed year was underestimated */ 0120 s = m; 0121 y++; 0122 m = hebrewDaysElapsed(y + 1); 0123 } 0124 d -= s; 0125 s = m - s; /* size of current year */ 0126 y += 3744; 0127 0128 h.hd_flg = s % 10 - 4; 0129 0130 /* compute day and month */ 0131 if (d >= s - 236) { /* last 8 months are regular */ 0132 d -= s - 236; 0133 m = d * 2 / 59; 0134 d -= (m * 59 + 1) / 2; 0135 m += 4; 0136 if (s > 365 && m <= 5) { /* Adar of Meuberet */ 0137 m += 8; 0138 } 0139 } else { 0140 /* first 4 months have 117-119 days */ 0141 s = 114 + s % 10; 0142 m = d * 4 / s; 0143 d -= (m * s + 3) / 4; 0144 } 0145 0146 h.hd_day = d; 0147 h.hd_mon = m; 0148 h.hd_year = y; 0149 return (&h); 0150 } 0151 0152 /* constants, in 1/18th of minute */ 0153 static const int HOUR = 1080; 0154 static const int DAY = 24 * HOUR; 0155 static const int WEEK = 7 * DAY; 0156 #define M(h,p) ((h)*HOUR+p) 0157 #define MONTH (DAY+M(12,793)) 0158 0159 /** 0160 * @internal 0161 * no. of days in y years 0162 */ 0163 static int hebrewDaysElapsed(int y) 0164 { 0165 int m, nm, dw, s, l; 0166 0167 l = y * 7 + 1; // no. of leap months 0168 m = y * 12 + l / 19; // total no. of months 0169 l %= 19; 0170 nm = m * MONTH + M(1 + 6, 779); // molad new year 3744 (16BC) + 6 hours 0171 s = m * 28 + nm / DAY - 2; 0172 0173 nm %= WEEK; 0174 dw = nm / DAY; 0175 nm %= DAY; 0176 0177 // special cases of Molad Zaken 0178 if ((l < 12 && dw == 3 && nm >= M(9 + 6, 204)) || 0179 (l < 7 && dw == 2 && nm >= M(15 + 6, 589))) { 0180 s++, dw++; 0181 } 0182 0183 /* ADU */ 0184 if (dw == 1 || dw == 4 || dw == 6) { 0185 s++; 0186 } 0187 return s; 0188 } 0189 0190 /** 0191 * @internal 0192 * true if long Cheshvan 0193 */ 0194 static int long_cheshvan(int year) 0195 { 0196 QDate first, last; 0197 class h_date *gd; 0198 0199 gd = hebrewToGregorian(year, 1, 1); 0200 first.setDate(gd->hd_year, gd->hd_mon + 1, gd->hd_day + 1); 0201 0202 gd = hebrewToGregorian(year + 1, 1, 1); 0203 last.setDate(gd->hd_year, gd->hd_mon + 1, gd->hd_day + 1); 0204 0205 return (first.daysTo(last) % 10 == 5); 0206 } 0207 0208 /** 0209 * @internal 0210 * true if short Kislev 0211 */ 0212 static int short_kislev(int year) 0213 { 0214 QDate first, last; 0215 class h_date *gd; 0216 0217 gd = hebrewToGregorian(year, 1, 1); 0218 first.setDate(gd->hd_year, gd->hd_mon + 1, gd->hd_day + 1); 0219 0220 gd = hebrewToGregorian(year + 1, 1, 1); 0221 last.setDate(gd->hd_year, gd->hd_mon + 1, gd->hd_day + 1); 0222 0223 return (first.daysTo(last) % 10 == 3); 0224 } 0225 0226 // Ok 0227 static class h_date *toHebrew(const QDate &date) 0228 { 0229 class h_date *sd; 0230 0231 sd = gregorianToHebrew(date.year(), date.month(), date.day()); 0232 ++sd->hd_mon; 0233 ++sd->hd_day; 0234 0235 return sd; 0236 } 0237 0238 class KCalendarSystemHebrewPrivate : public KCalendarSystemPrivate 0239 { 0240 public: 0241 KDELIBS4SUPPORT_DEPRECATED explicit KCalendarSystemHebrewPrivate(KCalendarSystemHebrew *q); 0242 0243 ~KCalendarSystemHebrewPrivate() override; 0244 0245 // Virtual methods each calendar system must re-implement 0246 void loadDefaultEraList() override; 0247 int monthsInYear(int year) const override; 0248 int daysInMonth(int year, int month) const override; 0249 int daysInYear(int year) const override; 0250 bool isLeapYear(int year) const override; 0251 bool hasLeapMonths() const override; 0252 bool hasYearZero() const override; 0253 int maxMonthsInYear() const override; 0254 int earliestValidYear() const override; 0255 int latestValidYear() const override; 0256 QString monthName(int month, int year, KLocale::DateTimeComponentFormat format, bool possessive) const override; 0257 QString weekDayName(int weekDay, KLocale::DateTimeComponentFormat format) const override; 0258 0259 int integerFromString(const QString &string, int maxLength, int &readLength) const override; 0260 QString stringFromInteger(int number, int padWidth = 0, QChar padChar = QLatin1Char('0')) const override; 0261 QString stringFromInteger(int number, int padWidth, QChar padChar, KLocale::DigitSet digitSet) const override; 0262 0263 virtual int monthNumberToMonthIndex(int year, int month) const; 0264 }; 0265 0266 // Shared d pointer base class definitions 0267 0268 KCalendarSystemHebrewPrivate::KCalendarSystemHebrewPrivate(KCalendarSystemHebrew *q) 0269 : KCalendarSystemPrivate(q) 0270 { 0271 } 0272 0273 KCalendarSystemHebrewPrivate::~KCalendarSystemHebrewPrivate() 0274 { 0275 } 0276 0277 void KCalendarSystemHebrewPrivate::loadDefaultEraList() 0278 { 0279 QString name, shortName, format; 0280 // Jewish Era, Anno Mundi, "Year of the World". 0281 name = i18nc("Calendar Era: Hebrew Era, years > 0, LongFormat", "Anno Mundi"); 0282 shortName = i18nc("Calendar Era: Hebrew Era, years > 0, ShortFormat", "AM"); 0283 format = i18nc("(kdedt-format) Hebrew, AM, full era year format used for %EY, e.g. 2000 AM", "%Ey %EC"); 0284 addEra('+', 1, q->epoch(), 1, q->latestValidDate(), name, shortName, format); 0285 } 0286 0287 int KCalendarSystemHebrewPrivate::monthsInYear(int year) const 0288 { 0289 if (isLeapYear(year)) { 0290 return 13; 0291 } else { 0292 return 12; 0293 } 0294 } 0295 0296 int KCalendarSystemHebrewPrivate::daysInMonth(int year, int month) const 0297 { 0298 int mi = monthNumberToMonthIndex(year, month); 0299 0300 if (mi == 2 && long_cheshvan(year)) { 0301 return 30; 0302 } 0303 0304 if (mi == 3 && short_kislev(year)) { 0305 return 29; 0306 } 0307 0308 if (mi % 2 == 0) { // Even number months have 29 days 0309 return 29; 0310 } else { // Odd number months have 30 days 0311 return 30; 0312 } 0313 } 0314 0315 int KCalendarSystemHebrewPrivate::daysInYear(int year) const 0316 { 0317 int days; 0318 0319 // Get Regular year length 0320 if (isLeapYear(year)) { // Has 13 months 0321 days = 384; 0322 } else { // Has 12 months 0323 days = 354; 0324 } 0325 0326 // Check if is Deficient or Abundant year 0327 if (short_kislev(year)) { // Deficient 0328 days = days - 1; 0329 } else if (long_cheshvan(year)) { // Abundant 0330 days = days + 1; 0331 } 0332 0333 return days; 0334 } 0335 0336 bool KCalendarSystemHebrewPrivate::isLeapYear(int year) const 0337 { 0338 return ((((7 * year) + 1) % 19) < 7); 0339 } 0340 0341 bool KCalendarSystemHebrewPrivate::hasLeapMonths() const 0342 { 0343 return true; 0344 } 0345 0346 bool KCalendarSystemHebrewPrivate::hasYearZero() const 0347 { 0348 return false; 0349 } 0350 0351 int KCalendarSystemHebrewPrivate::maxMonthsInYear() const 0352 { 0353 return 13; 0354 } 0355 0356 int KCalendarSystemHebrewPrivate::earliestValidYear() const 0357 { 0358 return 5344; 0359 } 0360 0361 int KCalendarSystemHebrewPrivate::latestValidYear() const 0362 { 0363 return 8119; 0364 } 0365 0366 int KCalendarSystemHebrewPrivate::integerFromString(const QString &inputString, int maxLength, int &readLength) const 0367 { 0368 if (locale()->language() == QLatin1String("he")) { 0369 0370 // Hebrew numbers are composed of combinations of normal letters which have a numeric value. 0371 // This is a non-positional system, the numeric values are simply added together, however 0372 // convention is for a RTL highest to lowest value ordering. There is also a degree of 0373 // ambiguity due to the lack of a letter for 0, hence 5 and 5000 are written the same. 0374 // Hebrew numbers are only used in dates. 0375 // See http://www.i18nguy.com/unicode/hebrew-numbers.html for more explaination 0376 0377 /* 0378 Ref table for numbers to Hebrew chars 0379 0380 Value 1 2 3 4 5 6 7 8 9 0381 0382 x 1 Alef א Bet ב Gimel ג Dalet ד He ה Vav ו Zayen ז Het ח Tet ט 0383 0x05D0 0x05D1 0x05D2 0x05D3 0x05D4 0x05D5 0x05D6 0x05D7 0x05D8 0384 0385 x 10 Yod י Kaf כ Lamed ל Mem מ Nun נ Samekh ס Ayin ע Pe פ Tzadi צ 0386 0x05D9 0x05DB 0x05DC 0x05DE 0x05E0 0x05E1 0x05E2 0x05E4 0x05E6 0387 0388 x 100 Qof ק Resh ר Shin ש Tav ת 0389 0x05E7 0x05E8 0x05E9 0x05EA 0390 0391 Note special cases 15 = 9 + 6 = 96 טו and 16 = 9 + 7 = 97 טז 0392 */ 0393 0394 int decadeValues[14] = {10, 20, 20, 30, 40, 40, 50, 50, 60, 70, 80, 80, 90, 90}; 0395 0396 QChar thisChar, nextChar; 0397 QString string = inputString; 0398 0399 int stringLength = string.length(); 0400 readLength = 0; 0401 int position = 0; 0402 int result = 0; 0403 int value = 0; 0404 0405 for (; position < stringLength; ++position) { 0406 0407 thisChar = string[position]; 0408 0409 if (position + 1 < stringLength) { 0410 nextChar = string[position + 1]; 0411 // Ignore any geresh or gershayim chars, we don't bother checking they are in the right place 0412 if (nextChar == QLatin1Char('\'') || nextChar == QChar(0x05F3) || // geresh 0413 nextChar == QLatin1Char('\"') || nextChar == QChar(0x05F4)) { // gershayim 0414 string.remove(position + 1, 1); 0415 stringLength = string.length(); 0416 if (position + 1 < stringLength) { 0417 nextChar = string[position + 1]; 0418 } else { 0419 nextChar = QChar(); 0420 } 0421 readLength = readLength + 1; 0422 } 0423 } else { 0424 nextChar = QChar(); 0425 } 0426 0427 if (thisChar >= QChar(0x05D0) && thisChar <= QChar(0x05D7)) { 0428 0429 // If this char Alef to Het, 1 to 8, א to ח 0430 0431 // If next char is any valid digit char (Alef to Tav, 1 to 400, א to ת) 0432 // then this char is a thousands digit 0433 // else this char is a ones digit 0434 0435 if (nextChar >= QChar(0x05D0) && nextChar <= QChar(0x05EA)) { 0436 value = (thisChar.unicode() - 0x05D0 + 1) * 1000; 0437 } else { 0438 value = thisChar.unicode() - 0x05D0 + 1; 0439 } 0440 0441 } else if (thisChar == QChar(0x05D8)) { 0442 0443 // If this char is Tet, 9, ט 0444 0445 // If next char is any valid digit char (Alef to Tav, 1 to 400, א to ת) 0446 // and next char not 6 (Special case for 96 = 15) 0447 // and next char not 7 (Special case for 97 = 16) 0448 // then is a thousands digit else is 9 0449 0450 if (nextChar >= QChar(0x05D0) && nextChar <= QChar(0x05EA) && 0451 nextChar != QChar(0x05D5) && nextChar != QChar(0x05D6)) { 0452 value = 9000; 0453 } else { 0454 value = 9; 0455 } 0456 0457 } else if (thisChar >= QChar(0x05D9) && thisChar <= QChar(0x05E6)) { 0458 0459 // If this char Yod to Tsadi, 10 to 90, י to צ 0460 0461 // If next char is a tens or hundreds char then is an error 0462 // Else is a tens digit 0463 0464 if (nextChar >= QChar(0x05D9)) { 0465 return -1; 0466 } else { 0467 value = decadeValues[thisChar.unicode() - 0x05D9]; 0468 } 0469 0470 } else if (thisChar >= QChar(0x05E7) && thisChar <= QChar(0x05EA)) { 0471 0472 // If this char Qof to Tav, 100 to 400, ק to ת, then is hundreds digit 0473 0474 value = (thisChar.unicode() - 0x05E7 + 1) * 100; 0475 0476 } else { 0477 0478 // If this char any non-digit char including whitespace or punctuation, we're done 0479 break; 0480 0481 } 0482 0483 result = result + value; 0484 0485 value = 0; 0486 } 0487 0488 readLength += position; 0489 0490 return result; 0491 0492 } else { 0493 return KCalendarSystemPrivate::integerFromString(inputString, maxLength, readLength); 0494 } 0495 } 0496 0497 QString KCalendarSystemHebrewPrivate::stringFromInteger(int number, int padWidth, QChar padChar) const 0498 { 0499 return KCalendarSystemPrivate::stringFromInteger(number, padWidth, padChar); 0500 } 0501 0502 QString KCalendarSystemHebrewPrivate::stringFromInteger(int number, int padWidth, QChar padChar, KLocale::DigitSet digitSet) const 0503 { 0504 if (locale()->language() == QLatin1String("he")) { 0505 0506 // Hebrew numbers are composed of combinations of normal letters which have a numeric value. 0507 // This is a non-positional system, the numeric values are simply added together, however 0508 // convention is for a RTL highest to lowest value ordering. There is also a degree of 0509 // ambiguity due to the lack of a letter for 0, hence 5 and 5000 are written the same. 0510 // Hebrew numbers are only used in dates. 0511 // See http://www.i18nguy.com/unicode/hebrew-numbers.html for more explaination 0512 0513 /* 0514 Ref table for numbers to Hebrew chars 0515 0516 Value 1 2 3 4 5 6 7 8 9 0517 0518 x 1 Alef א Bet ב Gimel ג Dalet ד He ה Vav ו Zayen ז Het ח Tet ט 0519 0x05D0 0x05D1 0x05D2 0x05D3 0x05D4 0x05D5 0x05D6 0x05D7 0x05D8 0520 0521 x 10 Yod י Kaf כ Lamed ל Mem מ Nun נ Samekh ס Ayin ע Pe פ Tzadi צ 0522 0x05D9 0x05DB 0x05DC 0x05DE 0x05E0 0x05E1 0x05E2 0x05E4 0x05E6 0523 0524 x 100 Qof ק Resh ר Shin ש Tav ת 0525 0x05E7 0x05E8 0x05E9 0x05EA 0526 0527 Note special cases 15 = 9 + 6 = 96 טו and 16 = 9 + 7 = 97 טז 0528 */ 0529 0530 const QChar decade[] = { 0531 // Tet = ט, Yod = י, Kaf = כ, Lamed = ל, Mem = מ 0532 // Nun = נ, Samekh = ס, Ayin = ע, Pe = פ, Tsadi = צ 0533 0x05D8, 0x05D9, 0x05DB, 0x05DC, 0x05DE, 0534 0x05E0, 0x05E1, 0x05E2, 0x05E4, 0x05E6 0535 }; 0536 0537 QString result; 0538 0539 // We have no rules for coping with numbers outside this range 0540 if (number < 1 || number > 9999) { 0541 return KCalendarSystemPrivate::stringFromInteger(number, padWidth, padChar, digitSet); 0542 } 0543 0544 // Translate the thousands digit, just uses letter for number 1..9 ( א to ט, Alef to Tet ) 0545 // Years 5001-5999 do not have the thousands by convention 0546 if (number >= 1000) { 0547 if (number <= 5000 || number >= 6000) { 0548 result += QChar(0x05D0 - 1 + number / 1000); // Alef א to Tet ט 0549 } 0550 number %= 1000; 0551 } 0552 0553 // Translate the hundreds digit 0554 // Use traditional method where we only have letters assigned values for 100, 200, 300 and 400 0555 // so may need to repeat 400 twice to make up the required number 0556 if (number >= 100) { 0557 while (number >= 500) { 0558 result += QChar(0x05EA); // Tav = ת 0559 number -= 400; 0560 } 0561 result += QChar(0x05E7 - 1 + number / 100); // Qof = ק to xxx 0562 number %= 100; 0563 } 0564 0565 // Translate the tens digit 0566 // The numbers 15 and 16 translate to letters that spell out the name of God which is 0567 // forbidden, so require special treatment where 15 = 9 + 6 and 1 = 9 + 7. 0568 if (number >= 10) { 0569 if (number == 15 || number == 16) { 0570 number -= 9; 0571 } 0572 result += decade[number / 10]; 0573 number %= 10; 0574 } 0575 0576 // Translate the ones digit, uses letter for number 1..9 ( א to ט, Alef to Tet ) 0577 if (number > 0) { 0578 result += QChar(0x05D0 - 1 + number); // Alef = א to xxx 0579 } 0580 0581 // When used in a string with mixed names and numbers the numbers need special chars to 0582 // distinguish them from words composed of the same letters. 0583 // Single digit numbers are followed by a geresh symbol ? (Unicode = 0x05F3), but we use 0584 // single quote for convenience. 0585 // Multiple digit numbers have a gershayim symbol ? (Unicode = 0x05F4) as second-to-last 0586 // char, but we use double quote for convenience. 0587 if (result.length() == 1) { 0588 result += QLatin1Char('\''); 0589 } else { 0590 result.insert(result.length() - 1, QLatin1Char('\"')); 0591 } 0592 0593 return result; 0594 0595 } else { 0596 return KCalendarSystemPrivate::stringFromInteger(number, padWidth, padChar, digitSet); 0597 } 0598 } 0599 0600 int KCalendarSystemHebrewPrivate::monthNumberToMonthIndex(int year, int month) const 0601 { 0602 if (isLeapYear(year)) { 0603 if (month == 6) { 0604 return 13; // Adar I 0605 } else if (month == 7) { 0606 return 14; // Adar II 0607 } else if (month > 7) { 0608 return month - 1; // Because of Adar II 0609 } 0610 } 0611 0612 return month; 0613 } 0614 0615 QString KCalendarSystemHebrewPrivate::monthName(int month, int year, KLocale::DateTimeComponentFormat format, bool possessive) const 0616 { 0617 // We must map month number to month index 0618 int monthIndex = monthNumberToMonthIndex(year, month); 0619 0620 QStringList languages = locale()->languageList(); 0621 0622 if (format == KLocale::NarrowName) { 0623 switch (monthIndex) { 0624 case 1: 0625 return ki18nc("Hebrew month 1 - KLocale::NarrowName", "T").toString(languages); 0626 case 2: 0627 return ki18nc("Hebrew month 2 - KLocale::NarrowName", "H").toString(languages); 0628 case 3: 0629 return ki18nc("Hebrew month 3 - KLocale::NarrowName", "K").toString(languages); 0630 case 4: 0631 return ki18nc("Hebrew month 4 - KLocale::NarrowName", "T").toString(languages); 0632 case 5: 0633 return ki18nc("Hebrew month 5 - KLocale::NarrowName", "S").toString(languages); 0634 case 6: 0635 return ki18nc("Hebrew month 6 - KLocale::NarrowName", "A").toString(languages); 0636 case 7: 0637 return ki18nc("Hebrew month 7 - KLocale::NarrowName", "N").toString(languages); 0638 case 8: 0639 return ki18nc("Hebrew month 8 - KLocale::NarrowName", "I").toString(languages); 0640 case 9: 0641 return ki18nc("Hebrew month 9 - KLocale::NarrowName", "S").toString(languages); 0642 case 10: 0643 return ki18nc("Hebrew month 10 - KLocale::NarrowName", "T").toString(languages); 0644 case 11: 0645 return ki18nc("Hebrew month 11 - KLocale::NarrowName", "A").toString(languages); 0646 case 12: 0647 return ki18nc("Hebrew month 12 - KLocale::NarrowName", "E").toString(languages); 0648 case 13: 0649 return ki18nc("Hebrew month 13 - KLocale::NarrowName", "A").toString(languages); 0650 case 14: 0651 return ki18nc("Hebrew month 14 - KLocale::NarrowName", "A").toString(languages); 0652 default: 0653 return QString(); 0654 } 0655 } 0656 0657 if (format == KLocale::ShortName && possessive) { 0658 switch (monthIndex) { 0659 case 1: 0660 return ki18nc("Hebrew month 1 - KLocale::ShortName Possessive", "of Tis").toString(languages); 0661 case 2: 0662 return ki18nc("Hebrew month 2 - KLocale::ShortName Possessive", "of Hes").toString(languages); 0663 case 3: 0664 return ki18nc("Hebrew month 3 - KLocale::ShortName Possessive", "of Kis").toString(languages); 0665 case 4: 0666 return ki18nc("Hebrew month 4 - KLocale::ShortName Possessive", "of Tev").toString(languages); 0667 case 5: 0668 return ki18nc("Hebrew month 5 - KLocale::ShortName Possessive", "of Shv").toString(languages); 0669 case 6: 0670 return ki18nc("Hebrew month 6 - KLocale::ShortName Possessive", "of Ada").toString(languages); 0671 case 7: 0672 return ki18nc("Hebrew month 7 - KLocale::ShortName Possessive", "of Nis").toString(languages); 0673 case 8: 0674 return ki18nc("Hebrew month 8 - KLocale::ShortName Possessive", "of Iya").toString(languages); 0675 case 9: 0676 return ki18nc("Hebrew month 9 - KLocale::ShortName Possessive", "of Siv").toString(languages); 0677 case 10: 0678 return ki18nc("Hebrew month 10 - KLocale::ShortName Possessive", "of Tam").toString(languages); 0679 case 11: 0680 return ki18nc("Hebrew month 11 - KLocale::ShortName Possessive", "of Av").toString(languages); 0681 case 12: 0682 return ki18nc("Hebrew month 12 - KLocale::ShortName Possessive", "of Elu").toString(languages); 0683 case 13: 0684 return ki18nc("Hebrew month 13 - KLocale::ShortName Possessive", "of Ad1").toString(languages); 0685 case 14: 0686 return ki18nc("Hebrew month 14 - KLocale::ShortName Possessive", "of Ad2").toString(languages); 0687 default: 0688 return QString(); 0689 } 0690 } 0691 0692 if (format == KLocale::ShortName && !possessive) { 0693 switch (monthIndex) { 0694 case 1: 0695 return ki18nc("Hebrew month 1 - KLocale::ShortName", "Tis").toString(languages); 0696 case 2: 0697 return ki18nc("Hebrew month 2 - KLocale::ShortName", "Hes").toString(languages); 0698 case 3: 0699 return ki18nc("Hebrew month 3 - KLocale::ShortName", "Kis").toString(languages); 0700 case 4: 0701 return ki18nc("Hebrew month 4 - KLocale::ShortName", "Tev").toString(languages); 0702 case 5: 0703 return ki18nc("Hebrew month 5 - KLocale::ShortName", "Shv").toString(languages); 0704 case 6: 0705 return ki18nc("Hebrew month 6 - KLocale::ShortName", "Ada").toString(languages); 0706 case 7: 0707 return ki18nc("Hebrew month 7 - KLocale::ShortName", "Nis").toString(languages); 0708 case 8: 0709 return ki18nc("Hebrew month 8 - KLocale::ShortName", "Iya").toString(languages); 0710 case 9: 0711 return ki18nc("Hebrew month 9 - KLocale::ShortName", "Siv").toString(languages); 0712 case 10: 0713 return ki18nc("Hebrew month 10 - KLocale::ShortName", "Tam").toString(languages); 0714 case 11: 0715 return ki18nc("Hebrew month 11 - KLocale::ShortName", "Av").toString(languages); 0716 case 12: 0717 return ki18nc("Hebrew month 12 - KLocale::ShortName", "Elu").toString(languages); 0718 case 13: 0719 return ki18nc("Hebrew month 13 - KLocale::ShortName", "Ad1").toString(languages); 0720 case 14: 0721 return ki18nc("Hebrew month 14 - KLocale::ShortName", "Ad2").toString(languages); 0722 default: 0723 return QString(); 0724 } 0725 } 0726 0727 if (format == KLocale::LongName && possessive) { 0728 switch (monthIndex) { 0729 case 1: 0730 return ki18nc("Hebrew month 1 - KLocale::LongName Possessive", "of Tishrey").toString(languages); 0731 case 2: 0732 return ki18nc("Hebrew month 2 - KLocale::LongName Possessive", "of Heshvan").toString(languages); 0733 case 3: 0734 return ki18nc("Hebrew month 3 - KLocale::LongName Possessive", "of Kislev").toString(languages); 0735 case 4: 0736 return ki18nc("Hebrew month 4 - KLocale::LongName Possessive", "of Tevet").toString(languages); 0737 case 5: 0738 return ki18nc("Hebrew month 5 - KLocale::LongName Possessive", "of Shvat").toString(languages); 0739 case 6: 0740 return ki18nc("Hebrew month 6 - KLocale::LongName Possessive", "of Adar").toString(languages); 0741 case 7: 0742 return ki18nc("Hebrew month 7 - KLocale::LongName Possessive", "of Nisan").toString(languages); 0743 case 8: 0744 return ki18nc("Hebrew month 8 - KLocale::LongName Possessive", "of Iyar").toString(languages); 0745 case 9: 0746 return ki18nc("Hebrew month 9 - KLocale::LongName Possessive", "of Sivan").toString(languages); 0747 case 10: 0748 return ki18nc("Hebrew month 10 - KLocale::LongName Possessive", "of Tamuz").toString(languages); 0749 case 11: 0750 return ki18nc("Hebrew month 11 - KLocale::LongName Possessive", "of Av").toString(languages); 0751 case 12: 0752 return ki18nc("Hebrew month 12 - KLocale::LongName Possessive", "of Elul").toString(languages); 0753 case 13: 0754 return ki18nc("Hebrew month 13 - KLocale::LongName Possessive", "of Adar I").toString(languages); 0755 case 14: 0756 return ki18nc("Hebrew month 14 - KLocale::LongName Possessive", "of Adar II").toString(languages); 0757 default: 0758 return QString(); 0759 } 0760 } 0761 0762 // Default to LongName 0763 switch (monthIndex) { 0764 case 1: 0765 return ki18nc("Hebrew month 1 - KLocale::LongName", "Tishrey").toString(languages); 0766 case 2: 0767 return ki18nc("Hebrew month 2 - KLocale::LongName", "Heshvan").toString(languages); 0768 case 3: 0769 return ki18nc("Hebrew month 3 - KLocale::LongName", "Kislev").toString(languages); 0770 case 4: 0771 return ki18nc("Hebrew month 4 - KLocale::LongName", "Tevet").toString(languages); 0772 case 5: 0773 return ki18nc("Hebrew month 5 - KLocale::LongName", "Shvat").toString(languages); 0774 case 6: 0775 return ki18nc("Hebrew month 6 - KLocale::LongName", "Adar").toString(languages); 0776 case 7: 0777 return ki18nc("Hebrew month 7 - KLocale::LongName", "Nisan").toString(languages); 0778 case 8: 0779 return ki18nc("Hebrew month 8 - KLocale::LongName", "Iyar").toString(languages); 0780 case 9: 0781 return ki18nc("Hebrew month 9 - KLocale::LongName", "Sivan").toString(languages); 0782 case 10: 0783 return ki18nc("Hebrew month 10 - KLocale::LongName", "Tamuz").toString(languages); 0784 case 11: 0785 return ki18nc("Hebrew month 11 - KLocale::LongName", "Av").toString(languages); 0786 case 12: 0787 return ki18nc("Hebrew month 12 - KLocale::LongName", "Elul").toString(languages); 0788 case 13: 0789 return ki18nc("Hebrew month 13 - KLocale::LongName", "Adar I").toString(languages); 0790 case 14: 0791 return ki18nc("Hebrew month 14 - KLocale::LongName", "Adar II").toString(languages); 0792 default: 0793 return QString(); 0794 } 0795 } 0796 0797 // Use Western day names for now as that's what the old version did, 0798 // but wouldn't it be better to use the right Hebrew names like Shabbat? 0799 // Could make it switchable by adding new enums to WeekDayFormat, e.g. ShortNameWestern? 0800 QString KCalendarSystemHebrewPrivate::weekDayName(int weekDay, KLocale::DateTimeComponentFormat format) const 0801 { 0802 QStringList languages = locale()->languageList(); 0803 0804 if (format == KLocale::NarrowName) { 0805 switch (weekDay) { 0806 case 1: 0807 return ki18nc("Gregorian weekday 1 - KLocale::NarrowName ", "M").toString(languages); 0808 case 2: 0809 return ki18nc("Gregorian weekday 2 - KLocale::NarrowName ", "T").toString(languages); 0810 case 3: 0811 return ki18nc("Gregorian weekday 3 - KLocale::NarrowName ", "W").toString(languages); 0812 case 4: 0813 return ki18nc("Gregorian weekday 4 - KLocale::NarrowName ", "T").toString(languages); 0814 case 5: 0815 return ki18nc("Gregorian weekday 5 - KLocale::NarrowName ", "F").toString(languages); 0816 case 6: 0817 return ki18nc("Gregorian weekday 6 - KLocale::NarrowName ", "S").toString(languages); 0818 case 7: 0819 return ki18nc("Gregorian weekday 7 - KLocale::NarrowName ", "S").toString(languages); 0820 default: 0821 return QString(); 0822 } 0823 } 0824 0825 if (format == KLocale::ShortName || format == KLocale:: ShortNumber) { 0826 switch (weekDay) { 0827 case 1: 0828 return ki18nc("Gregorian weekday 1 - KLocale::ShortName", "Mon").toString(languages); 0829 case 2: 0830 return ki18nc("Gregorian weekday 2 - KLocale::ShortName", "Tue").toString(languages); 0831 case 3: 0832 return ki18nc("Gregorian weekday 3 - KLocale::ShortName", "Wed").toString(languages); 0833 case 4: 0834 return ki18nc("Gregorian weekday 4 - KLocale::ShortName", "Thu").toString(languages); 0835 case 5: 0836 return ki18nc("Gregorian weekday 5 - KLocale::ShortName", "Fri").toString(languages); 0837 case 6: 0838 return ki18nc("Gregorian weekday 6 - KLocale::ShortName", "Sat").toString(languages); 0839 case 7: 0840 return ki18nc("Gregorian weekday 7 - KLocale::ShortName", "Sun").toString(languages); 0841 default: return QString(); 0842 } 0843 } 0844 0845 switch (weekDay) { 0846 case 1: 0847 return ki18nc("Gregorian weekday 1 - KLocale::LongName", "Monday").toString(languages); 0848 case 2: 0849 return ki18nc("Gregorian weekday 2 - KLocale::LongName", "Tuesday").toString(languages); 0850 case 3: 0851 return ki18nc("Gregorian weekday 3 - KLocale::LongName", "Wednesday").toString(languages); 0852 case 4: 0853 return ki18nc("Gregorian weekday 4 - KLocale::LongName", "Thursday").toString(languages); 0854 case 5: 0855 return ki18nc("Gregorian weekday 5 - KLocale::LongName", "Friday").toString(languages); 0856 case 6: 0857 return ki18nc("Gregorian weekday 6 - KLocale::LongName", "Saturday").toString(languages); 0858 case 7: 0859 return ki18nc("Gregorian weekday 7 - KLocale::LongName", "Sunday").toString(languages); 0860 default: 0861 return QString(); 0862 } 0863 } 0864 0865 KCalendarSystemHebrew::KCalendarSystemHebrew(const KSharedConfig::Ptr config, const KLocale *locale) 0866 : KCalendarSystem(*new KCalendarSystemHebrewPrivate(this), config, locale) 0867 { 0868 d_ptr->loadConfig(calendarType()); 0869 } 0870 0871 KCalendarSystemHebrew::KCalendarSystemHebrew(KCalendarSystemHebrewPrivate &dd, 0872 const KSharedConfig::Ptr config, const KLocale *locale) 0873 : KCalendarSystem(dd, config, locale) 0874 { 0875 d_ptr->loadConfig(calendarType()); 0876 } 0877 0878 KCalendarSystemHebrew::~KCalendarSystemHebrew() 0879 { 0880 } 0881 0882 QString KCalendarSystemHebrew::calendarType() const 0883 { 0884 return QLatin1String("hebrew"); 0885 } 0886 0887 KLocale::CalendarSystem KCalendarSystemHebrew::calendarSystem() const 0888 { 0889 return KLocale::HebrewCalendar; 0890 } 0891 0892 QDate KCalendarSystemHebrew::epoch() const 0893 { 0894 // Hebrew 0001-01-01 (Gregorian -3760-09-07, Julian -3761-10-07) 0895 return QDate::fromJulianDay(347998); 0896 } 0897 0898 QDate KCalendarSystemHebrew::earliestValidDate() const 0899 { 0900 // Current formulas using direct Gregorian <-> Hebrew conversion using Qt 0901 // will return invalid results prior to the Gregorian switchover in 1582 0902 // Next valid Hebrew year starts 5344-01-01 (Gregorian 1583-09-17) 0903 return QDate::fromJulianDay(2299498); 0904 } 0905 0906 QDate KCalendarSystemHebrew::latestValidDate() const 0907 { 0908 // Testing shows current formulas only work up to 8119-13-29 (Gregorian 4359-10-07) 0909 return QDate::fromJulianDay(3313431); 0910 } 0911 0912 QString KCalendarSystemHebrew::monthName(int month, int year, MonthNameFormat format) const 0913 { 0914 return KCalendarSystem::monthName(month, year, format); 0915 } 0916 0917 QString KCalendarSystemHebrew::monthName(const QDate &date, MonthNameFormat format) const 0918 { 0919 return KCalendarSystem::monthName(date, format); 0920 } 0921 0922 QString KCalendarSystemHebrew::weekDayName(int weekDay, WeekDayNameFormat format) const 0923 { 0924 return KCalendarSystem::weekDayName(weekDay, format); 0925 } 0926 0927 QString KCalendarSystemHebrew::weekDayName(const QDate &date, WeekDayNameFormat format) const 0928 { 0929 return KCalendarSystem::weekDayName(date, format); 0930 } 0931 0932 int KCalendarSystemHebrew::yearStringToInteger(const QString &string, int &readLength) const 0933 { 0934 int result = KCalendarSystem::yearStringToInteger(string, readLength); 0935 0936 // Hebrew has no letter for 0, so 5 and 5000 are written the same 0937 // Assume if less than 10 then we are in an exact multiple of 1000 0938 if (result < 10) { 0939 result = result * 1000; 0940 } 0941 0942 // Not good just assuming, make configurable 0943 if (result < 1000) { 0944 result += 5000; // assume we're in the 6th millenium (y6k bug) 0945 } 0946 0947 return result; 0948 } 0949 0950 bool KCalendarSystemHebrew::isLunar() const 0951 { 0952 return false; 0953 } 0954 0955 bool KCalendarSystemHebrew::isLunisolar() const 0956 { 0957 return true; 0958 } 0959 0960 bool KCalendarSystemHebrew::isSolar() const 0961 { 0962 return false; 0963 } 0964 0965 bool KCalendarSystemHebrew::isProleptic() const 0966 { 0967 return false; 0968 } 0969 0970 bool KCalendarSystemHebrew::julianDayToDate(qint64 jd, int &year, int &month, int &day) const 0971 { 0972 class h_date *sd = toHebrew(QDate::fromJulianDay(jd)); 0973 0974 year = sd->hd_year; 0975 0976 month = sd->hd_mon; 0977 if (isLeapYear(sd->hd_year)) { 0978 if (month == 13 /*AdarI*/) { 0979 month = 6; 0980 } else if (month == 14 /*AdarII*/) { 0981 month = 7; 0982 } else if (month > 6 && month < 13) { 0983 ++month; 0984 } 0985 } 0986 0987 day = sd->hd_day; 0988 0989 return true; 0990 } 0991 0992 bool KCalendarSystemHebrew::dateToJulianDay(int year, int month, int day, qint64 &jd) const 0993 { 0994 class h_date *gd = hebrewToGregorian(year, month, day); 0995 0996 QDate tempDate(gd->hd_year, gd->hd_mon + 1, gd->hd_day + 1); 0997 0998 jd = tempDate.toJulianDay(); 0999 1000 return true; 1001 }