00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include <klocale.h>
00025 #include <kdebug.h>
00026
00027 #include "kcalendarsystemhebrew.h"
00028
00029 static int hebrewDaysElapsed(int y);
00030 static QString num2heb(int num, bool includeMillenium);
00031
00032 class h_date
00033 {
00034 public:
00035 int hd_day;
00036 int hd_mon;
00037 int hd_year;
00038 int hd_dw;
00039 int hd_flg;
00040 };
00041
00042
00043
00044
00045 static class h_date * hebrewToGregorian(int y, int m, int d)
00046 {
00047 static class h_date h;
00048 int s;
00049
00050 y -= 3744;
00051 s = hebrewDaysElapsed(y);
00052 d += s;
00053 s = hebrewDaysElapsed(y + 1) - s;
00054
00055 if (s > 365 && m > 6 )
00056 {
00057 --m;
00058 d += 30;
00059 }
00060 d += (59 * (m - 1) + 1) / 2;
00061
00062 if (s % 10 > 4 && m > 2)
00063 d++;
00064 if (s % 10 < 4 && m > 3)
00065 d--;
00066
00067
00068
00069 d -= 6002;
00070
00071 y = (d + 36525) * 4 / 146097 - 1;
00072 d -= y / 4 * 146097 + (y % 4) * 36524;
00073 y *= 100;
00074
00075
00076 s = (d + 366)*4/1461-1;
00077 d -= s/4*1461 + (s % 4)*365;
00078 y += s;
00079
00080 m = (d + 245)*12/367-7;
00081 d -= m*367/12-30;
00082 if (++m >= 12) {
00083 m -= 12;
00084 y++;
00085 }
00086 h.hd_day = d;
00087 h.hd_mon = m;
00088 h.hd_year = y;
00089 return(&h);
00090 }
00091
00092
00093
00094
00095 static class h_date * gregorianToHebrew(int y, int m, int d)
00096 {
00097 static class h_date h;
00098 int s;
00099
00100 if ((m -= 2) <= 0) {
00101 m += 12;
00102 y--;
00103 }
00104
00105 d += 365*y + y/4 + 367*m/12 + 5968;
00106
00107 d -= y/100-y/400-2;
00108 h.hd_dw = (d + 1) % 7;
00109
00110
00111 y += 16;
00112 s = hebrewDaysElapsed(y);
00113 m = hebrewDaysElapsed(y + 1);
00114 while(d >= m) {
00115 s = m;
00116 y++;
00117 m = hebrewDaysElapsed(y + 1);
00118 }
00119 d -= s;
00120 s = m-s;
00121 y += 3744;
00122
00123 h.hd_flg = s % 10-4;
00124
00125
00126 if (d >= s-236) {
00127 d -= s-236;
00128 m = d*2/59;
00129 d -= (m*59 + 1)/2;
00130 m += 4;
00131 if (s > 365 && m <= 5)
00132 m += 8;
00133 } else {
00134
00135 s = 114 + s % 10;
00136 m = d * 4 / s;
00137 d -= (m * s + 3) / 4;
00138 }
00139
00140 h.hd_day = d;
00141 h.hd_mon = m;
00142 h.hd_year = y;
00143 return(&h);
00144 }
00145
00146 static QString num2heb(int num, bool includeMillenium)
00147 {
00148 const QChar decade[] = {0x05D8, 0x05D9, 0x05DB, 0x05DC, 0x05DE,
00149 0x05E0, 0x05E1, 0x05E2, 0x05E4, 0x05E6};
00150 QString result;
00151
00152 if (num < 1 || num > 9999)
00153 return QString::number(num);
00154
00155 if (num >= 1000) {
00156 if (includeMillenium || num % 1000 == 0)
00157 result += QChar(0x05D0 - 1 + num / 1000);
00158 num %= 1000;
00159 }
00160 if (num >= 100) {
00161 while (num >= 500) {
00162 result += QChar(0x05EA);
00163 num -= 400;
00164 }
00165 result += QChar(0x05E7 - 1 + num / 100);
00166 num %= 100;
00167 }
00168 if (num >= 10) {
00169 if (num == 15 || num == 16)
00170 num -= 9;
00171 result += decade[num / 10];
00172 num %= 10;
00173 }
00174 if (num > 0)
00175 result += QChar(0x05D0 - 1 + num);
00176
00177 if (result.length() == 1)
00178 result += "'";
00179 else
00180 result.insert(result.length() - 1, '\"');
00181
00182 return result;
00183 }
00184
00185
00186 static const int HOUR = 1080;
00187 static const int DAY = 24*HOUR;
00188 static const int WEEK = 7*DAY;
00189 #define M(h,p) ((h)*HOUR+p)
00190 #define MONTH (DAY+M(12,793))
00191
00196 static int hebrewDaysElapsed(int y)
00197 {
00198 int m, nm, dw, s, l;
00199
00200 l = y * 7 + 1;
00201 m = y*12+l/19;
00202 l %= 19;
00203 nm = m*MONTH+M(1+6,779);
00204 s = m*28+nm/DAY-2;
00205
00206 nm %= WEEK;
00207 dw = nm/DAY;
00208 nm %= DAY;
00209
00210
00211 if (l < 12 && dw == 3 && nm >= M(9 + 6,204) ||
00212 l < 7 && dw == 2 && nm>=M(15+6,589))
00213 s++,dw++;
00214
00215 if (dw == 1 || dw == 4 || dw == 6)
00216 s++;
00217 return s;
00218 }
00219
00224 static int long_cheshvan(int year)
00225 {
00226 QDate first, last;
00227 class h_date *gd;
00228
00229 gd = hebrewToGregorian(year, 1, 1);
00230 first.setYMD(gd->hd_year, gd->hd_mon + 1, gd->hd_day + 1);
00231
00232 gd = hebrewToGregorian(year + 1, 1, 1);
00233 last.setYMD(gd->hd_year, gd->hd_mon + 1, gd->hd_day + 1);
00234
00235 return (first.daysTo(last) % 10 == 5);
00236 }
00237
00242 static int short_kislev(int year)
00243 {
00244 QDate first, last;
00245 class h_date * gd;
00246
00247 gd = hebrewToGregorian(year, 1, 1);
00248 first.setYMD(gd->hd_year, gd->hd_mon + 1, gd->hd_day + 1);
00249
00250 gd = hebrewToGregorian(year + 1, 1, 1);
00251 last.setYMD(gd->hd_year, gd->hd_mon + 1, gd->hd_day + 1);
00252
00253 return (first.daysTo(last) % 10 == 3);
00254 }
00255
00256 static bool is_leap_year(int year)
00257 {
00258 return ((((7 * year) + 1) % 19) < 7);
00259 }
00260
00261
00262 KCalendarSystemHebrew::KCalendarSystemHebrew(const KLocale * locale)
00263 : KCalendarSystem(locale)
00264 {
00265 }
00266
00267
00268 KCalendarSystemHebrew::~KCalendarSystemHebrew()
00269 {
00270 }
00271
00272
00273 static class h_date * toHebrew(const QDate & date)
00274 {
00275 class h_date *sd;
00276 sd = gregorianToHebrew(date.year(), date.month(), date.day());
00277 ++sd->hd_mon;
00278 ++sd->hd_day;
00279 return sd;
00280 }
00281
00282
00283 int KCalendarSystemHebrew::year(const QDate& date) const
00284 {
00285 class h_date *sd = toHebrew(date);
00286 return sd->hd_year;
00287 }
00288
00289
00290 int KCalendarSystemHebrew::monthsInYear( const QDate & date ) const
00291 {
00292 if ( is_leap_year( year(date) ) )
00293 return 13;
00294 else
00295 return 12;
00296 }
00297
00298
00299 int KCalendarSystemHebrew::weeksInYear(int year) const
00300 {
00301 QDate temp;
00302 setYMD(temp, year, 1, 1);
00303
00304 setYMD(temp, year, monthsInYear(temp), hndays(monthsInYear(temp), year) );
00305
00306 int nWeekNumber = weekNumber(temp);
00307 if(nWeekNumber == 1)
00308 {
00309 temp = temp.addDays(-7);
00310 nWeekNumber = weekNumber(temp);
00311 }
00312
00313 return nWeekNumber;
00314 }
00315
00316 int KCalendarSystemHebrew::weekNumber(const QDate& date, int * yearNum) const
00317 {
00318 QDate firstDayWeek1, lastDayOfYear;
00319 int y = year(date);
00320 int week;
00321 int weekDay1, dayOfWeek1InYear;
00322
00323
00324 setYMD(firstDayWeek1, y, 1, 1);
00325 weekDay1 = dayOfWeek(firstDayWeek1);
00326
00327
00328
00329 if (weekDay1 > 4 )
00330 firstDayWeek1 = addDays(firstDayWeek1 , 7 - weekDay1 + 1);
00331
00332 dayOfWeek1InYear = dayOfYear(firstDayWeek1);
00333
00334 if ( dayOfYear(date) < dayOfWeek1InYear )
00335 {
00336 if ( yearNum )
00337 *yearNum = y - 1;
00338 return weeksInYear(y - 1);
00339 }
00340
00341
00342 setYMD(lastDayOfYear, y + 1, 1, 1);
00343 lastDayOfYear = addDays(lastDayOfYear, -1);
00344 if ( (dayOfYear(date) >= daysInYear(date) - dayOfWeek(lastDayOfYear) + 1)
00345
00346 && dayOfWeek(lastDayOfYear) < 4)
00347 {
00348 if ( yearNum )
00349 *yearNum = y + 1;
00350 week = 1;
00351 }
00352 else
00353 {
00354 if( weekDay1 < 5 )
00355
00356 firstDayWeek1 = addDays( firstDayWeek1, -( weekDay1 - 1));
00357
00358 week = firstDayWeek1.daysTo(date) / 7 + 1;
00359 }
00360
00361 return week;
00362 }
00363
00364
00365 QString KCalendarSystemHebrew::monthName(const QDate& date,
00366 bool shortName) const
00367 {
00368 return monthName(month(date), year(date), shortName);
00369 }
00370
00371
00372 QString KCalendarSystemHebrew::monthNamePossessive(const QDate& date,
00373 bool shortName) const
00374 {
00375 return monthNamePossessive(month(date), year(date), shortName);
00376 }
00377
00378
00379 QString KCalendarSystemHebrew::monthName(int month, int year, bool ) const
00380 {
00381 if ( month < 1 )
00382 return QString::null;
00383 if ( is_leap_year(year) )
00384 {
00385 if ( month > 13 )
00386 return QString::null;
00387 }
00388 else if ( month > 12 )
00389 return QString::null;
00390
00391
00392 if( month == 6 && is_leap_year(year) )
00393 month = 13;
00394 else if ( month == 7 && is_leap_year(year) )
00395 month = 14;
00396 else if ( month > 7 && is_leap_year(year) )
00397 month--;
00398
00399 switch(month)
00400 {
00401 case 1:
00402 return locale()->translate("Tishrey");
00403 case 2:
00404 return locale()->translate("Heshvan");
00405 case 3:
00406 return locale()->translate("Kislev");
00407 case 4:
00408 return locale()->translate("Tevet");
00409 case 5:
00410 return locale()->translate("Shvat");
00411 case 6:
00412 return locale()->translate("Adar");
00413 case 7:
00414 return locale()->translate("Nisan");
00415 case 8:
00416 return locale()->translate("Iyar");
00417 case 9:
00418 return locale()->translate("Sivan");
00419 case 10:
00420 return locale()->translate("Tamuz");
00421 case 11:
00422 return locale()->translate("Av");
00423 case 12:
00424 return locale()->translate("Elul");
00425 case 13:
00426 return locale()->translate("Adar I");
00427 case 14:
00428 return locale()->translate("Adar II");
00429 default:
00430 break;
00431 }
00432
00433 return QString::null;
00434 }
00435
00436
00437 QString KCalendarSystemHebrew::monthNamePossessive(int month, int year,
00438 bool shortName) const
00439 {
00440 return "of " + monthName(month, year, shortName);
00441 }
00442
00443 bool KCalendarSystemHebrew::setYMD(QDate & date, int y, int m, int d) const
00444 {
00445 if( y < minValidYear() || y > maxValidYear() )
00446 return false;
00447 if( m < 1 || m > (is_leap_year(y) ? 13 : 12) )
00448 return false;
00449 if( d < 1 || d > hndays(m,y) )
00450 return false;
00451
00452 class h_date * gd = hebrewToGregorian( y, m, d );
00453
00454 return date.setYMD(gd->hd_year, gd->hd_mon + 1, gd->hd_day + 1);
00455 }
00456
00457 QString KCalendarSystemHebrew::weekDayName(int day, bool shortName) const
00458 {
00459 return KCalendarSystem::weekDayName(day, shortName);
00460 }
00461
00462
00463 QString KCalendarSystemHebrew::weekDayName(const QDate& date,
00464 bool shortName) const
00465 {
00466 return weekDayName(dayOfWeek(date), shortName);
00467 }
00468
00469
00470 int KCalendarSystemHebrew::dayOfWeek(const QDate& date) const
00471 {
00472 class h_date *sd = toHebrew(date);
00473 if ( sd->hd_dw == 0 )
00474 return 7;
00475 else
00476 return (sd->hd_dw);
00477 }
00478
00479
00480 int KCalendarSystemHebrew::dayOfYear(const QDate & date) const
00481 {
00482 QDate first;
00483 setYMD(first, year(date), 1, 1);
00484
00485 return first.daysTo(date) + 1;
00486 }
00487
00488 int KCalendarSystemHebrew::daysInMonth(const QDate& date) const
00489 {
00490 return hndays(month(date), year(date));
00491 }
00492
00493 int KCalendarSystemHebrew::hndays(int mon, int year) const
00494 {
00495 if ( mon == 6 && is_leap_year(year) )
00496 mon = 13;
00497 else if ( mon == 7 && is_leap_year(year) )
00498 mon = 14;
00499 else if ( mon > 7 && is_leap_year(year) )
00500 mon--;
00501
00502 if( mon == 8 || mon == 10 ||
00503 mon == 12 || mon == 4 ||
00504 mon == 14 ||
00505 ( mon == 6 && !is_leap_year(year)) ||
00506 (mon == 2 && !long_cheshvan(year)) ||
00507 (mon == 3 && short_kislev(year)))
00508 return 29;
00509 else
00510 return 30;
00511 }
00512
00513
00514
00515 int KCalendarSystemHebrew::minValidYear() const
00516 {
00517 QDate date(1753, 1, 1);
00518
00519 return year(date);
00520 }
00521
00522
00523
00524 int KCalendarSystemHebrew::maxValidYear() const
00525 {
00526 QDate date(8000, 1, 1);
00527
00528 return year(date);
00529 }
00530
00531
00532 int KCalendarSystemHebrew::day(const QDate& date) const
00533 {
00534 class h_date *sd = toHebrew(date);
00535
00536 return sd->hd_day;
00537 }
00538
00539
00540 int KCalendarSystemHebrew::month(const QDate& date) const
00541 {
00542 class h_date *sd = toHebrew(date);
00543
00544 int month = sd->hd_mon;
00545 if ( is_leap_year( sd->hd_year ) )
00546 {
00547 if( month == 13 )
00548 month = 6;
00549 else if( month == 14 )
00550 month = 7;
00551 else if ( month > 6 && month < 13 )
00552 ++month;
00553 }
00554
00555 return month;
00556 }
00557
00558
00559 int KCalendarSystemHebrew::daysInYear(const QDate & date) const
00560 {
00561 QDate first, last;
00562 setYMD(first, year(date), 1, 1);
00563 setYMD(last, year(date) + 1, 1, 1);
00564
00565 return first.daysTo(last);
00566 }
00567
00568
00569 int KCalendarSystemHebrew::weekDayOfPray() const
00570 {
00571 return 6;
00572 }
00573
00574
00575 QDate KCalendarSystemHebrew::addDays( const QDate & date, int ndays ) const
00576 {
00577 return date.addDays( ndays );
00578 }
00579
00580
00581 QDate KCalendarSystemHebrew::addMonths( const QDate & date, int nmonths ) const
00582 {
00583 QDate result = date;
00584
00585 while ( nmonths > 0 )
00586 {
00587 result = addDays(result, daysInMonth(result));
00588 --nmonths;
00589 }
00590
00591 while ( nmonths < 0 )
00592 {
00593
00594
00595 int nDaysInMonth = daysInMonth(addDays(result, -day(result)));
00596 result = addDays(result, -nDaysInMonth);
00597 ++nmonths;
00598 }
00599
00600 return result;
00601 }
00602
00603
00604 QDate KCalendarSystemHebrew::addYears( const QDate & date, int nyears ) const
00605 {
00606 QDate result = date;
00607 int y = year(date) + nyears;
00608
00609 setYMD( result, y, month(date), day(date) );
00610
00611 return result;
00612 }
00613
00614
00615 QString KCalendarSystemHebrew::calendarName() const
00616 {
00617 return QString::fromLatin1("hebrew");
00618 }
00619
00620
00621 bool KCalendarSystemHebrew::isLunar() const
00622 {
00623 return false;
00624 }
00625
00626
00627 bool KCalendarSystemHebrew::isLunisolar() const
00628 {
00629 return true;
00630 }
00631
00632
00633 bool KCalendarSystemHebrew::isSolar() const
00634 {
00635 return false;
00636 }
00637
00638 QString KCalendarSystemHebrew::dayString(const QDate & pDate, bool bShort) const
00639 {
00640 QString sResult;
00641
00642
00643 if (locale()->language() == QString::fromLatin1("he"))
00644 sResult = num2heb(day(pDate), false);
00645 else
00646 sResult = KCalendarSystem::dayString(pDate, bShort);
00647
00648 return sResult;
00649 }
00650
00651 QString KCalendarSystemHebrew::yearString(const QDate & pDate, bool bShort) const
00652 {
00653 QString sResult;
00654
00655
00656 if (locale()->language() == QString::fromLatin1("he"))
00657 sResult = num2heb(year(pDate), !bShort);
00658 else
00659 sResult = KCalendarSystem::yearString(pDate, bShort);
00660
00661 return sResult;
00662 }
00663
00664 static int heb2num(const QString& str, int & iLength) {
00665 QChar c;
00666 QString s = str;
00667 int result = 0;
00668 iLength = 0;
00669 int decadeValues[14] = {10, 20, 20, 30, 40, 40, 50,
00670 50, 60, 70, 80, 80, 90, 90};
00671
00672 uint pos;
00673 for (pos = 0 ; pos < s.length() ; pos++)
00674 {
00675 c = s[pos];
00676 if (s.length() > pos && (s[pos + 1] == QChar('\'') ||
00677 s[pos + 1] == QChar('\"')))
00678 {
00679 iLength++;
00680 s.remove(pos + 1, 1);
00681 }
00682
00683 if (c >= QChar(0x05D0) && c <= QChar(0x05D7))
00684 {
00685 if (s.length() > pos && s[pos + 1] >= QChar(0x05D0) &&
00686 s[pos + 1] <= QChar(0x05EA))
00687 result += (c.unicode() - 0x05D0 + 1) * 1000;
00688 else
00689 result += c.unicode() - 0x05D0 + 1;
00690 }
00691 else if (c == QChar(0x05D8))
00692 {
00693 if (s.length() > pos && s[pos + 1] >= QChar(0x05D0) &&
00694 s[pos + 1] <= QChar(0x05EA) && s[pos + 1] != QChar(0x05D5) &&
00695 s[pos + 1] != QChar(0x05D6))
00696 result += 9000;
00697 else
00698 result += 9;
00699 }
00700 else if (c >= QChar(0x05D9) && c <= QChar(0x05E6))
00701 {
00702 if (s.length() > pos && s[pos + 1] >= QChar(0x05D9))
00703 return -1;
00704 else
00705 result += decadeValues[c.unicode() - 0x05D9];
00706 }
00707 else if (c >= QChar(0x05E7) && c <= QChar(0x05EA))
00708 {
00709 result += (c.unicode() - 0x05E7 + 1) * 100;
00710 }
00711 else
00712 {
00713 break;
00714 }
00715 }
00716
00717 iLength += pos;
00718
00719 return result;
00720 }
00721
00722 int KCalendarSystemHebrew::dayStringToInteger(const QString & sNum, int & iLength) const
00723 {
00724 int iResult;
00725 if (locale()->language() == "he")
00726 iResult= heb2num(sNum, iLength);
00727 else
00728 iResult = KCalendarSystem::yearStringToInteger(sNum, iLength);
00729
00730 return iResult;
00731 }
00732
00733 int KCalendarSystemHebrew::yearStringToInteger(const QString & sNum, int & iLength) const
00734 {
00735 int iResult;
00736 if (locale()->language() == "he")
00737 iResult = heb2num(sNum, iLength);
00738 else
00739 iResult = KCalendarSystem::yearStringToInteger(sNum, iLength);
00740
00741 if (iResult < 1000)
00742 iResult += 5000;
00743
00744 return iResult;
00745 }
00746