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