• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • tdecore
 

tdecore

  • tdecore
kcalendarsystemhebrew.cpp
1/*
2 Copyright (c) 2003 Hans Petter Bieker <bieker@kde.org>
3 Calendar conversion routines based on Hdate v6, by Amos
4 Shapir 1978 (rev. 1985, 1992)
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public
8 License as published by the Free Software Foundation; either
9 version 2 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Library General Public License for more details.
15
16 You should have received a copy of the GNU Library General Public License
17 along with this library; see the file COPYING.LIB. If not, write to
18 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 Boston, MA 02110-1301, USA.
20*/
21
22// Derived hebrew kde calendar class
23
24#include <tdelocale.h>
25#include <kdebug.h>
26
27#include "kcalendarsystemhebrew.h"
28
29static int hebrewDaysElapsed(int y);
30static TQString num2heb(int num, bool includeMillenium);
31
32class h_date
33{
34public:
35 int hd_day;
36 int hd_mon;
37 int hd_year;
38 int hd_dw;
39 int hd_flg;
40};
41
42/*
43 * compute general date structure from hebrew date
44 */
45static class h_date * hebrewToGregorian(int y, int m, int d)
46{
47 static class h_date h;
48 int s;
49
50 y -= 3744;
51 s = hebrewDaysElapsed(y);
52 d += s;
53 s = hebrewDaysElapsed(y + 1) - s; /* length of year */
54
55 if (s > 365 && m > 6 )
56 {
57 --m;
58 d += 30;
59 }
60 d += (59 * (m - 1) + 1) / 2; /* regular months */
61 /* special cases */
62 if (s % 10 > 4 && m > 2) /* long Heshvan */
63 d++;
64 if (s % 10 < 4 && m > 3) /* short Kislev */
65 d--;
66 // ### HPB: Broken in leap years
67 //if (s > 365 && m > 6) /* leap year */
68 // d += 30;
69 d -= 6002;
70
71 y = (d + 36525) * 4 / 146097 - 1;
72 d -= y / 4 * 146097 + (y % 4) * 36524;
73 y *= 100;
74
75 /* compute year */
76 s = (d + 366)*4/1461-1;
77 d -= s/4*1461 + (s % 4)*365;
78 y += s;
79 /* compute month */
80 m = (d + 245)*12/367-7;
81 d -= m*367/12-30;
82 if (++m >= 12) {
83 m -= 12;
84 y++;
85 }
86 h.hd_day = d;
87 h.hd_mon = m;
88 h.hd_year = y;
89 return(&h);
90}
91
92/*
93 * compute date structure from no. of days since 1 Tishrei 3744
94 */
95static class h_date * gregorianToHebrew(int y, int m, int d)
96{
97 static class h_date h;
98 int s;
99
100 if ((m -= 2) <= 0) {
101 m += 12;
102 y--;
103 }
104 /* no. of days, Julian calendar */
105 d += 365*y + y/4 + 367*m/12 + 5968;
106 /* Gregorian calendar */
107 d -= y/100-y/400-2;
108 h.hd_dw = (d + 1) % 7;
109
110 /* compute the year */
111 y += 16;
112 s = hebrewDaysElapsed(y);
113 m = hebrewDaysElapsed(y + 1);
114 while(d >= m) { /* computed year was underestimated */
115 s = m;
116 y++;
117 m = hebrewDaysElapsed(y + 1);
118 }
119 d -= s;
120 s = m-s; /* size of current year */
121 y += 3744;
122
123 h.hd_flg = s % 10-4;
124
125 /* compute day and month */
126 if (d >= s-236) { /* last 8 months are regular */
127 d -= s-236;
128 m = d*2/59;
129 d -= (m*59 + 1)/2;
130 m += 4;
131 if (s > 365 && m <= 5) /* Adar of Meuberet */
132 m += 8;
133 } else {
134 /* first 4 months have 117-119 days */
135 s = 114 + s % 10;
136 m = d * 4 / s;
137 d -= (m * s + 3) / 4;
138 }
139
140 h.hd_day = d;
141 h.hd_mon = m;
142 h.hd_year = y;
143 return(&h);
144}
145
146static TQString num2heb(int num, bool includeMillenium)
147{
148 const TQChar decade[] = {0x05D8, 0x05D9, 0x05DB, 0x05DC, 0x05DE,
149 0x05E0, 0x05E1, 0x05E2, 0x05E4, 0x05E6};
150 TQString result;
151
152 if (num < 1 || num > 9999)
153 return TQString::number(num);
154
155 if (num >= 1000) {
156 if (includeMillenium || num % 1000 == 0)
157 result += TQChar(0x05D0 - 1 + num / 1000);
158 num %= 1000;
159 }
160 if (num >= 100) {
161 while (num >= 500) {
162 result += TQChar(0x05EA);
163 num -= 400;
164 }
165 result += TQChar(0x05E7 - 1 + num / 100);
166 num %= 100;
167 }
168 if (num >= 10) {
169 if (num == 15 || num == 16)
170 num -= 9;
171 result += decade[num / 10];
172 num %= 10;
173 }
174 if (num > 0)
175 result += TQChar(0x05D0 - 1 + num);
176
177 if (result.length() == 1)
178 result += "'";
179 else
180 result.insert(result.length() - 1, '\"');
181
182 return result;
183}
184
185/* constants, in 1/18th of minute */
186static const int HOUR = 1080;
187static const int DAY = 24*HOUR;
188static const int WEEK = 7*DAY;
189#define M(h,p) ((h)*HOUR+p)
190#define MONTH (DAY+M(12,793))
191
196static int hebrewDaysElapsed(int y)
197{
198 int m, nm, dw, s, l;
199
200 l = y * 7 + 1; // no. of leap months
201 m = y*12+l/19; // total no. of months
202 l %= 19;
203 nm = m*MONTH+M(1+6,779); // molad new year 3744 (16BC) + 6 hours
204 s = m*28+nm/DAY-2;
205
206 nm %= WEEK;
207 dw = nm/DAY;
208 nm %= DAY;
209
210 // special cases of Molad Zaken
211 if (l < 12 && dw == 3 && nm >= M(9 + 6,204) ||
212 l < 7 && dw == 2 && nm>=M(15+6,589))
213 s++,dw++;
214 /* ADU */
215 if (dw == 1 || dw == 4 || dw == 6)
216 s++;
217 return s;
218}
219
224static int long_cheshvan(int year)
225{
226 TQDate first, last;
227 class h_date *gd;
228
229 gd = hebrewToGregorian(year, 1, 1);
230 first.setYMD(gd->hd_year, gd->hd_mon + 1, gd->hd_day + 1);
231
232 gd = hebrewToGregorian(year + 1, 1, 1);
233 last.setYMD(gd->hd_year, gd->hd_mon + 1, gd->hd_day + 1);
234
235 return (first.daysTo(last) % 10 == 5);
236}
237
242static int short_kislev(int year)
243{
244 TQDate first, last;
245 class h_date * gd;
246
247 gd = hebrewToGregorian(year, 1, 1);
248 first.setYMD(gd->hd_year, gd->hd_mon + 1, gd->hd_day + 1);
249
250 gd = hebrewToGregorian(year + 1, 1, 1);
251 last.setYMD(gd->hd_year, gd->hd_mon + 1, gd->hd_day + 1);
252
253 return (first.daysTo(last) % 10 == 3);
254}
255
256static bool is_leap_year(int year)
257{
258 return ((((7 * year) + 1) % 19) < 7);
259}
260
261// Ok
262KCalendarSystemHebrew::KCalendarSystemHebrew(const TDELocale * locale)
263 : KCalendarSystem(locale)
264{
265}
266
267// Ok
268KCalendarSystemHebrew::~KCalendarSystemHebrew()
269{
270}
271
272// Ok
273static class h_date * toHebrew(const TQDate & date)
274{
275 class h_date *sd;
276 sd = gregorianToHebrew(date.year(), date.month(), date.day());
277 ++sd->hd_mon;
278 ++sd->hd_day;
279 return sd;
280}
281
282// Ok
283int KCalendarSystemHebrew::year(const TQDate& date) const
284{
285 class h_date *sd = toHebrew(date);
286 return sd->hd_year;
287}
288
289// Ok
290int KCalendarSystemHebrew::monthsInYear( const TQDate & date ) const
291{
292 if ( is_leap_year( year(date) ) )
293 return 13;
294 else
295 return 12;
296}
297
298// Ok
299int KCalendarSystemHebrew::weeksInYear(int year) const
300{
301 TQDate temp;
302 setYMD(temp, year, 1, 1); // don't pass an uninitialized TQDate to
303 // monthsInYear in the next call
304 setYMD(temp, year, monthsInYear(temp), hndays(monthsInYear(temp), year) );
305
306 int nWeekNumber = weekNumber(temp);
307 if(nWeekNumber == 1) // last week belongs to next year
308 {
309 temp = temp.addDays(-7);
310 nWeekNumber = weekNumber(temp);
311 }
312
313 return nWeekNumber;
314}
315
316int KCalendarSystemHebrew::weekNumber(const TQDate& date, int * yearNum) const
317{
318 TQDate firstDayWeek1, lastDayOfYear;
319 int y = year(date);
320 int week;
321 int weekDay1, dayOfWeek1InYear;
322
323 // let's guess 1st day of 1st week
324 setYMD(firstDayWeek1, y, 1, 1);
325 weekDay1 = dayOfWeek(firstDayWeek1);
326
327 // iso 8601: week 1 is the first containing thursday and week starts on
328 // monday
329 if (weekDay1 > 4 /*Thursday*/)
330 firstDayWeek1 = addDays(firstDayWeek1 , 7 - weekDay1 + 1); // next monday
331
332 dayOfWeek1InYear = dayOfYear(firstDayWeek1);
333
334 if ( dayOfYear(date) < dayOfWeek1InYear ) // our date in prev year's week
335 {
336 if ( yearNum )
337 *yearNum = y - 1;
338 return weeksInYear(y - 1);
339 }
340
341 // let's check if its last week belongs to next year
342 setYMD(lastDayOfYear, y + 1, 1, 1);
343 lastDayOfYear = addDays(lastDayOfYear, -1);
344 if ( (dayOfYear(date) >= daysInYear(date) - dayOfWeek(lastDayOfYear) + 1)
345 // our date is in last week
346 && dayOfWeek(lastDayOfYear) < 4) // 1st week in next year has thursday
347 {
348 if ( yearNum )
349 *yearNum = y + 1;
350 week = 1;
351 }
352 else
353 {
354 if( weekDay1 < 5 ) // To calculate properly the number of weeks
355 // from day a to x let's make a day 1 of week
356 firstDayWeek1 = addDays( firstDayWeek1, -( weekDay1 - 1));
357
358 week = firstDayWeek1.daysTo(date) / 7 + 1;
359 }
360
361 return week;
362}
363
364// Ok
365TQString KCalendarSystemHebrew::monthName(const TQDate& date,
366 bool shortName) const
367{
368 return monthName(month(date), year(date), shortName);
369}
370
371// Ok
372TQString KCalendarSystemHebrew::monthNamePossessive(const TQDate& date,
373 bool shortName) const
374{
375 return monthNamePossessive(month(date), year(date), shortName);
376}
377
378// ### Fixme
379TQString KCalendarSystemHebrew::monthName(int month, int year, bool /*shortName*/) const
380{
381 if ( month < 1 )
382 return TQString::null;
383 if ( is_leap_year(year) )
384 {
385 if ( month > 13 )
386 return TQString::null;
387 }
388 else if ( month > 12 )
389 return TQString::null;
390
391 // We must map conversion algorithm month index to real index
392 if( month == 6 && is_leap_year(year) )
393 month = 13; /*Adar I*/
394 else if ( month == 7 && is_leap_year(year) )
395 month = 14; /*Adar II*/
396 else if ( month > 7 && is_leap_year(year) )
397 month--; //Because of Adar II
398
399 switch(month)
400 {
401 case 1:
402 return locale()->translate("Tishrey");
403 case 2:
404 return locale()->translate("Heshvan");
405 case 3:
406 return locale()->translate("Kislev");
407 case 4:
408 return locale()->translate("Tevet");
409 case 5:
410 return locale()->translate("Shvat");
411 case 6:
412 return locale()->translate("Adar");
413 case 7:
414 return locale()->translate("Nisan");
415 case 8:
416 return locale()->translate("Iyar");
417 case 9:
418 return locale()->translate("Sivan");
419 case 10:
420 return locale()->translate("Tamuz");
421 case 11:
422 return locale()->translate("Av");
423 case 12:
424 return locale()->translate("Elul");
425 case 13:
426 return locale()->translate("Adar I");
427 case 14:
428 return locale()->translate("Adar II");
429 default:
430 break;
431 }
432
433 return TQString::null;
434}
435
436// ### Fixme
437TQString KCalendarSystemHebrew::monthNamePossessive(int month, int year,
438 bool shortName) const
439{
440 return "of " + monthName(month, year, shortName);
441}
442
443bool KCalendarSystemHebrew::setYMD(TQDate & date, int y, int m, int d) const
444{
445 if( y < minValidYear() || y > maxValidYear() )
446 return false;
447 if( m < 1 || m > (is_leap_year(y) ? 13 : 12) )
448 return false;
449 if( d < 1 || d > hndays(m,y) )
450 return false;
451
452 class h_date * gd = hebrewToGregorian( y, m, d );
453
454 return date.setYMD(gd->hd_year, gd->hd_mon + 1, gd->hd_day + 1);
455}
456
457TQString KCalendarSystemHebrew::weekDayName(int day, bool shortName) const
458{
459 return KCalendarSystem::weekDayName(day, shortName);
460}
461
462// Ok
463TQString KCalendarSystemHebrew::weekDayName(const TQDate& date,
464 bool shortName) const
465{
466 return weekDayName(dayOfWeek(date), shortName);
467}
468
469// Ok
470int KCalendarSystemHebrew::dayOfWeek(const TQDate& date) const
471{
472 class h_date *sd = toHebrew(date);
473 if ( sd->hd_dw == 0 )
474 return 7;
475 else
476 return (sd->hd_dw);
477}
478
479// Ok
480int KCalendarSystemHebrew::dayOfYear(const TQDate & date) const
481{
482 TQDate first;
483 setYMD(first, year(date), 1, 1);
484
485 return first.daysTo(date) + 1;
486}
487
488int KCalendarSystemHebrew::daysInMonth(const TQDate& date) const
489{
490 return hndays(month(date), year(date));
491}
492
493int KCalendarSystemHebrew::hndays(int mon, int year) const
494{
495 if ( mon == 6 && is_leap_year(year) )
496 mon = 13; /*Adar I*/
497 else if ( mon == 7 && is_leap_year(year) )
498 mon = 14; /*Adar II*/
499 else if ( mon > 7 && is_leap_year(year) )
500 mon--; //Because of Adar II
501
502 if( mon == 8 /*IYYAR*/ || mon == 10 /*TAMUZ*/ ||
503 mon == 12 /*ELUL*/ || mon == 4 /*TEVET*/ ||
504 mon == 14 /*ADAR 2*/||
505 ( mon == 6 /*ADAR*/ && !is_leap_year(year)) ||
506 (mon == 2 /*CHESHVAN*/ && !long_cheshvan(year)) ||
507 (mon == 3 /*KISLEV*/ && short_kislev(year)))
508 return 29;
509 else
510 return 30;
511}
512
513// Ok
514// Min valid year that may be converted to QDate
515int KCalendarSystemHebrew::minValidYear() const
516{
517 TQDate date(1753, 1, 1);
518
519 return year(date);
520}
521
522// Ok
523// Max valid year that may be converted to QDate
524int KCalendarSystemHebrew::maxValidYear() const
525{
526 TQDate date(8000, 1, 1);
527
528 return year(date);
529}
530
531// Ok
532int KCalendarSystemHebrew::day(const TQDate& date) const
533{
534 class h_date *sd = toHebrew(date);
535
536 return sd->hd_day;
537}
538
539// Ok
540int KCalendarSystemHebrew::month(const TQDate& date) const
541{
542 class h_date *sd = toHebrew(date);
543
544 int month = sd->hd_mon;
545 if ( is_leap_year( sd->hd_year ) )
546 {
547 if( month == 13 /*AdarI*/ )
548 month = 6;
549 else if( month == 14 /*AdarII*/ )
550 month = 7;
551 else if ( month > 6 && month < 13 )
552 ++month;
553 }
554
555 return month;
556}
557
558// Ok
559int KCalendarSystemHebrew::daysInYear(const TQDate & date) const
560{
561 TQDate first, last;
562 setYMD(first, year(date), 1, 1); // 1 Tishrey
563 setYMD(last, year(date) + 1, 1, 1); // 1 Tishrey the year later
564
565 return first.daysTo(last);
566}
567
568// Ok
569int KCalendarSystemHebrew::weekDayOfPray() const
570{
571 return 6; // saturday
572}
573
574// Ok
575TQDate KCalendarSystemHebrew::addDays( const TQDate & date, int ndays ) const
576{
577 return date.addDays( ndays );
578}
579
580// Ok
581TQDate KCalendarSystemHebrew::addMonths( const TQDate & date, int nmonths ) const
582{
583 TQDate result = date;
584
585 while ( nmonths > 0 )
586 {
587 result = addDays(result, daysInMonth(result));
588 --nmonths;
589 }
590
591 while ( nmonths < 0 )
592 {
593 // get the number of days in the previous month to be consistent with
594 // addMonths where nmonths > 0
595 int nDaysInMonth = daysInMonth(addDays(result, -day(result)));
596 result = addDays(result, -nDaysInMonth);
597 ++nmonths;
598 }
599
600 return result;
601}
602
603// Ok
604TQDate KCalendarSystemHebrew::addYears( const TQDate & date, int nyears ) const
605{
606 TQDate result = date;
607 int y = year(date) + nyears;
608
609 setYMD( result, y, month(date), day(date) );
610
611 return result;
612}
613
614// Ok
615TQString KCalendarSystemHebrew::calendarName() const
616{
617 return TQString::fromLatin1("hebrew");
618}
619
620// Ok
621bool KCalendarSystemHebrew::isLunar() const
622{
623 return false;
624}
625
626// Ok
627bool KCalendarSystemHebrew::isLunisolar() const
628{
629 return true;
630}
631
632// Ok
633bool KCalendarSystemHebrew::isSolar() const
634{
635 return false;
636}
637
638TQString KCalendarSystemHebrew::dayString(const TQDate & pDate, bool bShort) const
639{
640 TQString sResult;
641
642 // Only use hebrew numbers if the hebrew setting is selected
643 if (locale()->language() == TQString::fromLatin1("he"))
644 sResult = num2heb(day(pDate), false);
645 else
646 sResult = KCalendarSystem::dayString(pDate, bShort);
647
648 return sResult;
649}
650
651TQString KCalendarSystemHebrew::yearString(const TQDate & pDate, bool bShort) const
652{
653 TQString sResult;
654
655 // Only use hebrew numbers if the hebrew setting is selected
656 if (locale()->language() == TQString::fromLatin1("he"))
657 sResult = num2heb(year(pDate), !bShort);
658 else
659 sResult = KCalendarSystem::yearString(pDate, bShort);
660
661 return sResult;
662}
663
664static int heb2num(const TQString& str, int & iLength) {
665 TQChar c;
666 TQString s = str;
667 int result = 0;
668 iLength = 0;
669 int decadeValues[14] = {10, 20, 20, 30, 40, 40, 50,
670 50, 60, 70, 80, 80, 90, 90};
671
672 uint pos;
673 for (pos = 0 ; pos < s.length() ; pos++)
674 {
675 c = s[pos];
676 if (s.length() > pos && (s[pos + 1] == TQChar('\'') ||
677 s[pos + 1] == TQChar('\"')))
678 {
679 iLength++;
680 s.remove(pos + 1, 1);
681 }
682
683 if (c >= TQChar(0x05D0) && c <= TQChar(0x05D7))
684 {
685 if (s.length() > pos && s[pos + 1] >= TQChar(0x05D0) &&
686 s[pos + 1] <= TQChar(0x05EA))
687 result += (c.unicode() - 0x05D0 + 1) * 1000;
688 else
689 result += c.unicode() - 0x05D0 + 1;
690 }
691 else if (c == TQChar(0x05D8))
692 {
693 if (s.length() > pos && s[pos + 1] >= TQChar(0x05D0) &&
694 s[pos + 1] <= TQChar(0x05EA) && s[pos + 1] != TQChar(0x05D5) &&
695 s[pos + 1] != TQChar(0x05D6))
696 result += 9000;
697 else
698 result += 9;
699 }
700 else if (c >= TQChar(0x05D9) && c <= TQChar(0x05E6))
701 {
702 if (s.length() > pos && s[pos + 1] >= TQChar(0x05D9))
703 return -1;
704 else
705 result += decadeValues[c.unicode() - 0x05D9];
706 }
707 else if (c >= TQChar(0x05E7) && c <= TQChar(0x05EA))
708 {
709 result += (c.unicode() - 0x05E7 + 1) * 100;
710 }
711 else
712 {
713 break;
714 }
715 }
716
717 iLength += pos;
718
719 return result;
720}
721
722int KCalendarSystemHebrew::dayStringToInteger(const TQString & sNum, int & iLength) const
723{
724 int iResult;
725 if (locale()->language() == "he")
726 iResult= heb2num(sNum, iLength);
727 else
728 iResult = KCalendarSystem::yearStringToInteger(sNum, iLength);
729
730 return iResult;
731}
732
733int KCalendarSystemHebrew::yearStringToInteger(const TQString & sNum, int & iLength) const
734{
735 int iResult;
736 if (locale()->language() == "he")
737 iResult = heb2num(sNum, iLength);
738 else
739 iResult = KCalendarSystem::yearStringToInteger(sNum, iLength);
740
741 if (iResult < 1000)
742 iResult += 5000; // assume we're in the 6th millenium (y6k bug)
743
744 return iResult;
745}
746
KCalendarSystem
CalendarSystem abstract class, default derived kde gregorian class and factory class.
Definition: kcalendarsystem.h:43
KCalendarSystem::weekDayName
virtual TQString weekDayName(int weekDay, bool shortName=false) const =0
Gets specific calendar type week day name If an invalid week day is specified, TQString::null is retu...
Definition: kcalendarsystem.cpp:119
KCalendarSystem::yearStringToInteger
virtual int yearStringToInteger(const TQString &sNum, int &iLength) const
Converts a year literal of a part of a string into a integer starting at the beginning of the string.
Definition: kcalendarsystem.cpp:114
KCalendarSystem::dayString
virtual TQString dayString(const TQDate &pDate, bool bShort) const
Converts a date into a day literal.
Definition: kcalendarsystem.cpp:55
KCalendarSystem::yearString
virtual TQString yearString(const TQDate &pDate, bool bShort) const
Converts a date into a year literal.
Definition: kcalendarsystem.cpp:77
TDELocale
TDELocale provides support for country specific stuff like the national language.
Definition: tdelocale.h:124
tdelocale.h

tdecore

Skip menu "tdecore"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

tdecore

Skip menu "tdecore"
  • arts
  • dcop
  • dnssd
  • interfaces
  •   kspeech
  •     interface
  •     library
  •   tdetexteditor
  • kate
  • kded
  • kdoctools
  • kimgio
  • kjs
  • libtdemid
  • libtdescreensaver
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdeioslave
  •   http
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for tdecore by doxygen 1.9.4
This website is maintained by Timothy Pearson.