KDELibs4Support

kcalendarsystemhebrew.cpp
1 /*
2  Copyright (c) 2003 Hans Petter Bieker <[email protected]>
3  Copyright 2007, 2009, 2010 John Layt <[email protected]>
4  Calendar conversion routines based on Hdate v6, by Amos
5  Shapir 1978 (rev. 1985, 1992)
6 
7  This library is free software; you can redistribute it and/or
8  modify it under the terms of the GNU Library General Public
9  License as published by the Free Software Foundation; either
10  version 2 of the License, or (at your option) any later version.
11 
12  This library is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  Library General Public License for more details.
16 
17  You should have received a copy of the GNU Library General Public License
18  along with this library; see the file COPYING.LIB. If not, write to
19  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20  Boston, MA 02110-1301, USA.
21 */
22 
23 // Derived hebrew kde calendar class
24 
25 #include "kcalendarsystemhebrew_p.h"
26 #include "kcalendarsystemprivate_p.h"
27 
28 #include "klocale.h"
29 #include "klocalizedstring.h"
30 
31 #include <QDate>
32 #include <QCharRef>
33 
34 static int hebrewDaysElapsed(int y);
35 
36 class h_date
37 {
38 public:
39  int hd_day;
40  int hd_mon;
41  int hd_year;
42  int hd_dw;
43  int hd_flg;
44 };
45 
46 /*
47  * compute general date structure from hebrew date
48  */
49 static class h_date *hebrewToGregorian(int y, int m, int d)
50 {
51  static class h_date h;
52  int s;
53 
54  y -= 3744;
55  s = hebrewDaysElapsed(y);
56  d += s;
57  s = hebrewDaysElapsed(y + 1) - s; /* length of year */
58 
59  if (s > 365 && m > 6) {
60  --m;
61  d += 30;
62  }
63  d += (59 * (m - 1) + 1) / 2; /* regular months */
64  /* special cases */
65  if (s % 10 > 4 && m > 2) { /* long Heshvan */
66  d++;
67  }
68  if (s % 10 < 4 && m > 3) { /* short Kislev */
69  d--;
70  }
71  // ### HPB: Broken in leap years
72  //if (s > 365 && m > 6) /* leap year */
73  // d += 30;
74  d -= 6002;
75 
76  y = (d + 36525) * 4 / 146097 - 1;
77  d -= y / 4 * 146097 + (y % 4) * 36524;
78  y *= 100;
79 
80  /* compute year */
81  s = (d + 366) * 4 / 1461 - 1;
82  d -= s / 4 * 1461 + (s % 4) * 365;
83  y += s;
84  /* compute month */
85  m = (d + 245) * 12 / 367 - 7;
86  d -= m * 367 / 12 - 30;
87  if (++m >= 12) {
88  m -= 12;
89  y++;
90  }
91  h.hd_day = d;
92  h.hd_mon = m;
93  h.hd_year = y;
94  return (&h);
95 }
96 
97 /*
98  * compute date structure from no. of days since 1 Tishrei 3744
99  */
100 static class h_date *gregorianToHebrew(int y, int m, int d)
101 {
102  static class h_date h;
103  int s;
104 
105  if ((m -= 2) <= 0) {
106  m += 12;
107  y--;
108  }
109  /* no. of days, Julian calendar */
110  d += 365 * y + y / 4 + 367 * m / 12 + 5968;
111  /* Gregorian calendar */
112  d -= y / 100 - y / 400 - 2;
113  h.hd_dw = (d + 1) % 7;
114 
115  /* compute the year */
116  y += 16;
117  s = hebrewDaysElapsed(y);
118  m = hebrewDaysElapsed(y + 1);
119  while (d >= m) { /* computed year was underestimated */
120  s = m;
121  y++;
122  m = hebrewDaysElapsed(y + 1);
123  }
124  d -= s;
125  s = m - s; /* size of current year */
126  y += 3744;
127 
128  h.hd_flg = s % 10 - 4;
129 
130  /* compute day and month */
131  if (d >= s - 236) { /* last 8 months are regular */
132  d -= s - 236;
133  m = d * 2 / 59;
134  d -= (m * 59 + 1) / 2;
135  m += 4;
136  if (s > 365 && m <= 5) { /* Adar of Meuberet */
137  m += 8;
138  }
139  } else {
140  /* first 4 months have 117-119 days */
141  s = 114 + s % 10;
142  m = d * 4 / s;
143  d -= (m * s + 3) / 4;
144  }
145 
146  h.hd_day = d;
147  h.hd_mon = m;
148  h.hd_year = y;
149  return (&h);
150 }
151 
152 /* constants, in 1/18th of minute */
153 static const int HOUR = 1080;
154 static const int DAY = 24 * HOUR;
155 static const int WEEK = 7 * DAY;
156 #define M(h,p) ((h)*HOUR+p)
157 #define MONTH (DAY+M(12,793))
158 
163 static int hebrewDaysElapsed(int y)
164 {
165  int m, nm, dw, s, l;
166 
167  l = y * 7 + 1; // no. of leap months
168  m = y * 12 + l / 19; // total no. of months
169  l %= 19;
170  nm = m * MONTH + M(1 + 6, 779); // molad new year 3744 (16BC) + 6 hours
171  s = m * 28 + nm / DAY - 2;
172 
173  nm %= WEEK;
174  dw = nm / DAY;
175  nm %= DAY;
176 
177  // special cases of Molad Zaken
178  if ((l < 12 && dw == 3 && nm >= M(9 + 6, 204)) ||
179  (l < 7 && dw == 2 && nm >= M(15 + 6, 589))) {
180  s++, dw++;
181  }
182 
183  /* ADU */
184  if (dw == 1 || dw == 4 || dw == 6) {
185  s++;
186  }
187  return s;
188 }
189 
194 static int long_cheshvan(int year)
195 {
196  QDate first, last;
197  class h_date *gd;
198 
199  gd = hebrewToGregorian(year, 1, 1);
200  first.setDate(gd->hd_year, gd->hd_mon + 1, gd->hd_day + 1);
201 
202  gd = hebrewToGregorian(year + 1, 1, 1);
203  last.setDate(gd->hd_year, gd->hd_mon + 1, gd->hd_day + 1);
204 
205  return (first.daysTo(last) % 10 == 5);
206 }
207 
212 static int short_kislev(int year)
213 {
214  QDate first, last;
215  class h_date *gd;
216 
217  gd = hebrewToGregorian(year, 1, 1);
218  first.setDate(gd->hd_year, gd->hd_mon + 1, gd->hd_day + 1);
219 
220  gd = hebrewToGregorian(year + 1, 1, 1);
221  last.setDate(gd->hd_year, gd->hd_mon + 1, gd->hd_day + 1);
222 
223  return (first.daysTo(last) % 10 == 3);
224 }
225 
226 // Ok
227 static class h_date *toHebrew(const QDate &date)
228 {
229  class h_date *sd;
230 
231  sd = gregorianToHebrew(date.year(), date.month(), date.day());
232  ++sd->hd_mon;
233  ++sd->hd_day;
234 
235  return sd;
236 }
237 
238 class KCalendarSystemHebrewPrivate : public KCalendarSystemPrivate
239 {
240 public:
241  KDELIBS4SUPPORT_DEPRECATED explicit KCalendarSystemHebrewPrivate(KCalendarSystemHebrew *q);
242 
243  virtual ~KCalendarSystemHebrewPrivate();
244 
245  // Virtual methods each calendar system must re-implement
246  void loadDefaultEraList() override;
247  int monthsInYear(int year) const override;
248  int daysInMonth(int year, int month) const override;
249  int daysInYear(int year) const override;
250  bool isLeapYear(int year) const override;
251  bool hasLeapMonths() const override;
252  bool hasYearZero() const override;
253  int maxMonthsInYear() const override;
254  int earliestValidYear() const override;
255  int latestValidYear() const override;
256  QString monthName(int month, int year, KLocale::DateTimeComponentFormat format, bool possessive) const override;
257  QString weekDayName(int weekDay, KLocale::DateTimeComponentFormat format) const override;
258 
259  int integerFromString(const QString &string, int maxLength, int &readLength) const override;
260  QString stringFromInteger(int number, int padWidth = 0, QChar padChar = QLatin1Char('0')) const override;
261  QString stringFromInteger(int number, int padWidth, QChar padChar, KLocale::DigitSet digitSet) const override;
262 
263  virtual int monthNumberToMonthIndex(int year, int month) const;
264 };
265 
266 // Shared d pointer base class definitions
267 
268 KCalendarSystemHebrewPrivate::KCalendarSystemHebrewPrivate(KCalendarSystemHebrew *q)
269  : KCalendarSystemPrivate(q)
270 {
271 }
272 
273 KCalendarSystemHebrewPrivate::~KCalendarSystemHebrewPrivate()
274 {
275 }
276 
277 void KCalendarSystemHebrewPrivate::loadDefaultEraList()
278 {
279  QString name, shortName, format;
280  // Jewish Era, Anno Mundi, "Year of the World".
281  name = i18nc("Calendar Era: Hebrew Era, years > 0, LongFormat", "Anno Mundi");
282  shortName = i18nc("Calendar Era: Hebrew Era, years > 0, ShortFormat", "AM");
283  format = i18nc("(kdedt-format) Hebrew, AM, full era year format used for %EY, e.g. 2000 AM", "%Ey %EC");
284  addEra('+', 1, q->epoch(), 1, q->latestValidDate(), name, shortName, format);
285 }
286 
287 int KCalendarSystemHebrewPrivate::monthsInYear(int year) const
288 {
289  if (isLeapYear(year)) {
290  return 13;
291  } else {
292  return 12;
293  }
294 }
295 
296 int KCalendarSystemHebrewPrivate::daysInMonth(int year, int month) const
297 {
298  int mi = monthNumberToMonthIndex(year, month);
299 
300  if (mi == 2 && long_cheshvan(year)) {
301  return 30;
302  }
303 
304  if (mi == 3 && short_kislev(year)) {
305  return 29;
306  }
307 
308  if (mi % 2 == 0) { // Even number months have 29 days
309  return 29;
310  } else { // Odd number months have 30 days
311  return 30;
312  }
313 }
314 
315 int KCalendarSystemHebrewPrivate::daysInYear(int year) const
316 {
317  int days;
318 
319  // Get Regular year length
320  if (isLeapYear(year)) { // Has 13 months
321  days = 384;
322  } else { // Has 12 months
323  days = 354;
324  }
325 
326  // Check if is Deficient or Abundant year
327  if (short_kislev(year)) { // Deficient
328  days = days - 1;
329  } else if (long_cheshvan(year)) { // Abundant
330  days = days + 1;
331  }
332 
333  return days;
334 }
335 
336 bool KCalendarSystemHebrewPrivate::isLeapYear(int year) const
337 {
338  return ((((7 * year) + 1) % 19) < 7);
339 }
340 
341 bool KCalendarSystemHebrewPrivate::hasLeapMonths() const
342 {
343  return true;
344 }
345 
346 bool KCalendarSystemHebrewPrivate::hasYearZero() const
347 {
348  return false;
349 }
350 
351 int KCalendarSystemHebrewPrivate::maxMonthsInYear() const
352 {
353  return 13;
354 }
355 
356 int KCalendarSystemHebrewPrivate::earliestValidYear() const
357 {
358  return 5344;
359 }
360 
361 int KCalendarSystemHebrewPrivate::latestValidYear() const
362 {
363  return 8119;
364 }
365 
366 int KCalendarSystemHebrewPrivate::integerFromString(const QString &inputString, int maxLength, int &readLength) const
367 {
368  if (locale()->language() == QLatin1String("he")) {
369 
370  // Hebrew numbers are composed of combinations of normal letters which have a numeric value.
371  // This is a non-positional system, the numeric values are simply added together, however
372  // convention is for a RTL highest to lowest value ordering. There is also a degree of
373  // ambiguity due to the lack of a letter for 0, hence 5 and 5000 are written the same.
374  // Hebrew numbers are only used in dates.
375  // See http://www.i18nguy.com/unicode/hebrew-numbers.html for more explaination
376 
377  /*
378  Ref table for numbers to Hebrew chars
379 
380  Value 1 2 3 4 5 6 7 8 9
381 
382  x 1 Alef א Bet ב Gimel ג Dalet ד He ה Vav ו Zayen ז Het ח Tet ט
383  0x05D0 0x05D1 0x05D2 0x05D3 0x05D4 0x05D5 0x05D6 0x05D7 0x05D8
384 
385  x 10 Yod י Kaf כ Lamed ל Mem מ Nun נ Samekh ס Ayin ע Pe פ Tzadi צ
386  0x05D9 0x05DB 0x05DC 0x05DE 0x05E0 0x05E1 0x05E2 0x05E4 0x05E6
387 
388  x 100 Qof ק Resh ר Shin ש Tav ת
389  0x05E7 0x05E8 0x05E9 0x05EA
390 
391  Note special cases 15 = 9 + 6 = 96 טו and 16 = 9 + 7 = 97 טז
392  */
393 
394  int decadeValues[14] = {10, 20, 20, 30, 40, 40, 50, 50, 60, 70, 80, 80, 90, 90};
395 
396  QChar thisChar, nextChar;
397  QString string = inputString;
398 
399  int stringLength = string.length();
400  readLength = 0;
401  int position = 0;
402  int result = 0;
403  int value = 0;
404 
405  for (; position < stringLength; ++position) {
406 
407  thisChar = string[position];
408 
409  if (position + 1 < stringLength) {
410  nextChar = string[position + 1];
411  // Ignore any geresh or gershayim chars, we don't bother checking they are in the right place
412  if (nextChar == QLatin1Char('\'') || nextChar == QChar(0x05F3) || // geresh
413  nextChar == QLatin1Char('\"') || nextChar == QChar(0x05F4)) { // gershayim
414  string.remove(position + 1, 1);
415  stringLength = string.length();
416  if (position + 1 < stringLength) {
417  nextChar = string[position + 1];
418  } else {
419  nextChar = QChar();
420  }
421  readLength = readLength + 1;
422  }
423  } else {
424  nextChar = QChar();
425  }
426 
427  if (thisChar >= QChar(0x05D0) && thisChar <= QChar(0x05D7)) {
428 
429  // If this char Alef to Het, 1 to 8, א to ח
430 
431  // If next char is any valid digit char (Alef to Tav, 1 to 400, א to ת)
432  // then this char is a thousands digit
433  // else this char is a ones digit
434 
435  if (nextChar >= QChar(0x05D0) && nextChar <= QChar(0x05EA)) {
436  value = (thisChar.unicode() - 0x05D0 + 1) * 1000;
437  } else {
438  value = thisChar.unicode() - 0x05D0 + 1;
439  }
440 
441  } else if (thisChar == QChar(0x05D8)) {
442 
443  // If this char is Tet, 9, ט
444 
445  // If next char is any valid digit char (Alef to Tav, 1 to 400, א to ת)
446  // and next char not 6 (Special case for 96 = 15)
447  // and next char not 7 (Special case for 97 = 16)
448  // then is a thousands digit else is 9
449 
450  if (nextChar >= QChar(0x05D0) && nextChar <= QChar(0x05EA) &&
451  nextChar != QChar(0x05D5) && nextChar != QChar(0x05D6)) {
452  value = 9000;
453  } else {
454  value = 9;
455  }
456 
457  } else if (thisChar >= QChar(0x05D9) && thisChar <= QChar(0x05E6)) {
458 
459  // If this char Yod to Tsadi, 10 to 90, י to צ
460 
461  // If next char is a tens or hundreds char then is an error
462  // Else is a tens digit
463 
464  if (nextChar >= QChar(0x05D9)) {
465  return -1;
466  } else {
467  value = decadeValues[thisChar.unicode() - 0x05D9];
468  }
469 
470  } else if (thisChar >= QChar(0x05E7) && thisChar <= QChar(0x05EA)) {
471 
472  // If this char Qof to Tav, 100 to 400, ק to ת, then is hundreds digit
473 
474  value = (thisChar.unicode() - 0x05E7 + 1) * 100;
475 
476  } else {
477 
478  // If this char any non-digit char including whitespace or punctuation, we're done
479  break;
480 
481  }
482 
483  result = result + value;
484 
485  value = 0;
486  }
487 
488  readLength += position;
489 
490  return result;
491 
492  } else {
493  return KCalendarSystemPrivate::integerFromString(inputString, maxLength, readLength);
494  }
495 }
496 
497 QString KCalendarSystemHebrewPrivate::stringFromInteger(int number, int padWidth, QChar padChar) const
498 {
499  return KCalendarSystemPrivate::stringFromInteger(number, padWidth, padChar);
500 }
501 
502 QString KCalendarSystemHebrewPrivate::stringFromInteger(int number, int padWidth, QChar padChar, KLocale::DigitSet digitSet) const
503 {
504  if (locale()->language() == QLatin1String("he")) {
505 
506  // Hebrew numbers are composed of combinations of normal letters which have a numeric value.
507  // This is a non-positional system, the numeric values are simply added together, however
508  // convention is for a RTL highest to lowest value ordering. There is also a degree of
509  // ambiguity due to the lack of a letter for 0, hence 5 and 5000 are written the same.
510  // Hebrew numbers are only used in dates.
511  // See http://www.i18nguy.com/unicode/hebrew-numbers.html for more explaination
512 
513  /*
514  Ref table for numbers to Hebrew chars
515 
516  Value 1 2 3 4 5 6 7 8 9
517 
518  x 1 Alef א Bet ב Gimel ג Dalet ד He ה Vav ו Zayen ז Het ח Tet ט
519  0x05D0 0x05D1 0x05D2 0x05D3 0x05D4 0x05D5 0x05D6 0x05D7 0x05D8
520 
521  x 10 Yod י Kaf כ Lamed ל Mem מ Nun נ Samekh ס Ayin ע Pe פ Tzadi צ
522  0x05D9 0x05DB 0x05DC 0x05DE 0x05E0 0x05E1 0x05E2 0x05E4 0x05E6
523 
524  x 100 Qof ק Resh ר Shin ש Tav ת
525  0x05E7 0x05E8 0x05E9 0x05EA
526 
527  Note special cases 15 = 9 + 6 = 96 טו and 16 = 9 + 7 = 97 טז
528  */
529 
530  const QChar decade[] = {
531  // Tet = ט, Yod = י, Kaf = כ, Lamed = ל, Mem = מ
532  // Nun = נ, Samekh = ס, Ayin = ע, Pe = פ, Tsadi = צ
533  0x05D8, 0x05D9, 0x05DB, 0x05DC, 0x05DE,
534  0x05E0, 0x05E1, 0x05E2, 0x05E4, 0x05E6
535  };
536 
537  QString result;
538 
539  // We have no rules for coping with numbers outside this range
540  if (number < 1 || number > 9999) {
541  return KCalendarSystemPrivate::stringFromInteger(number, padWidth, padChar, digitSet);
542  }
543 
544  // Translate the thousands digit, just uses letter for number 1..9 ( א to ט, Alef to Tet )
545  // Years 5001-5999 do not have the thousands by convention
546  if (number >= 1000) {
547  if (number <= 5000 || number >= 6000) {
548  result += QChar(0x05D0 - 1 + number / 1000); // Alef א to Tet ט
549  }
550  number %= 1000;
551  }
552 
553  // Translate the hundreds digit
554  // Use traditional method where we only have letters assigned values for 100, 200, 300 and 400
555  // so may need to repeat 400 twice to make up the required number
556  if (number >= 100) {
557  while (number >= 500) {
558  result += QChar(0x05EA); // Tav = ת
559  number -= 400;
560  }
561  result += QChar(0x05E7 - 1 + number / 100); // Qof = ק to xxx
562  number %= 100;
563  }
564 
565  // Translate the tens digit
566  // The numbers 15 and 16 translate to letters that spell out the name of God which is
567  // forbidden, so require special treatment where 15 = 9 + 6 and 1 = 9 + 7.
568  if (number >= 10) {
569  if (number == 15 || number == 16) {
570  number -= 9;
571  }
572  result += decade[number / 10];
573  number %= 10;
574  }
575 
576  // Translate the ones digit, uses letter for number 1..9 ( א to ט, Alef to Tet )
577  if (number > 0) {
578  result += QChar(0x05D0 - 1 + number); // Alef = א to xxx
579  }
580 
581  // When used in a string with mixed names and numbers the numbers need special chars to
582  // distinguish them from words composed of the same letters.
583  // Single digit numbers are followed by a geresh symbol ? (Unicode = 0x05F3), but we use
584  // single quote for convenience.
585  // Multiple digit numbers have a gershayim symbol ? (Unicode = 0x05F4) as second-to-last
586  // char, but we use double quote for convenience.
587  if (result.length() == 1) {
588  result += QLatin1Char('\'');
589  } else {
590  result.insert(result.length() - 1, QLatin1Char('\"'));
591  }
592 
593  return result;
594 
595  } else {
596  return KCalendarSystemPrivate::stringFromInteger(number, padWidth, padChar, digitSet);
597  }
598 }
599 
600 int KCalendarSystemHebrewPrivate::monthNumberToMonthIndex(int year, int month) const
601 {
602  if (isLeapYear(year)) {
603  if (month == 6) {
604  return 13; // Adar I
605  } else if (month == 7) {
606  return 14; // Adar II
607  } else if (month > 7) {
608  return month - 1; // Because of Adar II
609  }
610  }
611 
612  return month;
613 }
614 
615 QString KCalendarSystemHebrewPrivate::monthName(int month, int year, KLocale::DateTimeComponentFormat format, bool possessive) const
616 {
617  // We must map month number to month index
618  int monthIndex = monthNumberToMonthIndex(year, month);
619 
620  QStringList languages = locale()->languageList();
621 
622  if (format == KLocale::NarrowName) {
623  switch (monthIndex) {
624  case 1:
625  return ki18nc("Hebrew month 1 - KLocale::NarrowName", "T").toString(languages);
626  case 2:
627  return ki18nc("Hebrew month 2 - KLocale::NarrowName", "H").toString(languages);
628  case 3:
629  return ki18nc("Hebrew month 3 - KLocale::NarrowName", "K").toString(languages);
630  case 4:
631  return ki18nc("Hebrew month 4 - KLocale::NarrowName", "T").toString(languages);
632  case 5:
633  return ki18nc("Hebrew month 5 - KLocale::NarrowName", "S").toString(languages);
634  case 6:
635  return ki18nc("Hebrew month 6 - KLocale::NarrowName", "A").toString(languages);
636  case 7:
637  return ki18nc("Hebrew month 7 - KLocale::NarrowName", "N").toString(languages);
638  case 8:
639  return ki18nc("Hebrew month 8 - KLocale::NarrowName", "I").toString(languages);
640  case 9:
641  return ki18nc("Hebrew month 9 - KLocale::NarrowName", "S").toString(languages);
642  case 10:
643  return ki18nc("Hebrew month 10 - KLocale::NarrowName", "T").toString(languages);
644  case 11:
645  return ki18nc("Hebrew month 11 - KLocale::NarrowName", "A").toString(languages);
646  case 12:
647  return ki18nc("Hebrew month 12 - KLocale::NarrowName", "E").toString(languages);
648  case 13:
649  return ki18nc("Hebrew month 13 - KLocale::NarrowName", "A").toString(languages);
650  case 14:
651  return ki18nc("Hebrew month 14 - KLocale::NarrowName", "A").toString(languages);
652  default:
653  return QString();
654  }
655  }
656 
657  if (format == KLocale::ShortName && possessive) {
658  switch (monthIndex) {
659  case 1:
660  return ki18nc("Hebrew month 1 - KLocale::ShortName Possessive", "of Tis").toString(languages);
661  case 2:
662  return ki18nc("Hebrew month 2 - KLocale::ShortName Possessive", "of Hes").toString(languages);
663  case 3:
664  return ki18nc("Hebrew month 3 - KLocale::ShortName Possessive", "of Kis").toString(languages);
665  case 4:
666  return ki18nc("Hebrew month 4 - KLocale::ShortName Possessive", "of Tev").toString(languages);
667  case 5:
668  return ki18nc("Hebrew month 5 - KLocale::ShortName Possessive", "of Shv").toString(languages);
669  case 6:
670  return ki18nc("Hebrew month 6 - KLocale::ShortName Possessive", "of Ada").toString(languages);
671  case 7:
672  return ki18nc("Hebrew month 7 - KLocale::ShortName Possessive", "of Nis").toString(languages);
673  case 8:
674  return ki18nc("Hebrew month 8 - KLocale::ShortName Possessive", "of Iya").toString(languages);
675  case 9:
676  return ki18nc("Hebrew month 9 - KLocale::ShortName Possessive", "of Siv").toString(languages);
677  case 10:
678  return ki18nc("Hebrew month 10 - KLocale::ShortName Possessive", "of Tam").toString(languages);
679  case 11:
680  return ki18nc("Hebrew month 11 - KLocale::ShortName Possessive", "of Av").toString(languages);
681  case 12:
682  return ki18nc("Hebrew month 12 - KLocale::ShortName Possessive", "of Elu").toString(languages);
683  case 13:
684  return ki18nc("Hebrew month 13 - KLocale::ShortName Possessive", "of Ad1").toString(languages);
685  case 14:
686  return ki18nc("Hebrew month 14 - KLocale::ShortName Possessive", "of Ad2").toString(languages);
687  default:
688  return QString();
689  }
690  }
691 
692  if (format == KLocale::ShortName && !possessive) {
693  switch (monthIndex) {
694  case 1:
695  return ki18nc("Hebrew month 1 - KLocale::ShortName", "Tis").toString(languages);
696  case 2:
697  return ki18nc("Hebrew month 2 - KLocale::ShortName", "Hes").toString(languages);
698  case 3:
699  return ki18nc("Hebrew month 3 - KLocale::ShortName", "Kis").toString(languages);
700  case 4:
701  return ki18nc("Hebrew month 4 - KLocale::ShortName", "Tev").toString(languages);
702  case 5:
703  return ki18nc("Hebrew month 5 - KLocale::ShortName", "Shv").toString(languages);
704  case 6:
705  return ki18nc("Hebrew month 6 - KLocale::ShortName", "Ada").toString(languages);
706  case 7:
707  return ki18nc("Hebrew month 7 - KLocale::ShortName", "Nis").toString(languages);
708  case 8:
709  return ki18nc("Hebrew month 8 - KLocale::ShortName", "Iya").toString(languages);
710  case 9:
711  return ki18nc("Hebrew month 9 - KLocale::ShortName", "Siv").toString(languages);
712  case 10:
713  return ki18nc("Hebrew month 10 - KLocale::ShortName", "Tam").toString(languages);
714  case 11:
715  return ki18nc("Hebrew month 11 - KLocale::ShortName", "Av").toString(languages);
716  case 12:
717  return ki18nc("Hebrew month 12 - KLocale::ShortName", "Elu").toString(languages);
718  case 13:
719  return ki18nc("Hebrew month 13 - KLocale::ShortName", "Ad1").toString(languages);
720  case 14:
721  return ki18nc("Hebrew month 14 - KLocale::ShortName", "Ad2").toString(languages);
722  default:
723  return QString();
724  }
725  }
726 
727  if (format == KLocale::LongName && possessive) {
728  switch (monthIndex) {
729  case 1:
730  return ki18nc("Hebrew month 1 - KLocale::LongName Possessive", "of Tishrey").toString(languages);
731  case 2:
732  return ki18nc("Hebrew month 2 - KLocale::LongName Possessive", "of Heshvan").toString(languages);
733  case 3:
734  return ki18nc("Hebrew month 3 - KLocale::LongName Possessive", "of Kislev").toString(languages);
735  case 4:
736  return ki18nc("Hebrew month 4 - KLocale::LongName Possessive", "of Tevet").toString(languages);
737  case 5:
738  return ki18nc("Hebrew month 5 - KLocale::LongName Possessive", "of Shvat").toString(languages);
739  case 6:
740  return ki18nc("Hebrew month 6 - KLocale::LongName Possessive", "of Adar").toString(languages);
741  case 7:
742  return ki18nc("Hebrew month 7 - KLocale::LongName Possessive", "of Nisan").toString(languages);
743  case 8:
744  return ki18nc("Hebrew month 8 - KLocale::LongName Possessive", "of Iyar").toString(languages);
745  case 9:
746  return ki18nc("Hebrew month 9 - KLocale::LongName Possessive", "of Sivan").toString(languages);
747  case 10:
748  return ki18nc("Hebrew month 10 - KLocale::LongName Possessive", "of Tamuz").toString(languages);
749  case 11:
750  return ki18nc("Hebrew month 11 - KLocale::LongName Possessive", "of Av").toString(languages);
751  case 12:
752  return ki18nc("Hebrew month 12 - KLocale::LongName Possessive", "of Elul").toString(languages);
753  case 13:
754  return ki18nc("Hebrew month 13 - KLocale::LongName Possessive", "of Adar I").toString(languages);
755  case 14:
756  return ki18nc("Hebrew month 14 - KLocale::LongName Possessive", "of Adar II").toString(languages);
757  default:
758  return QString();
759  }
760  }
761 
762  // Default to LongName
763  switch (monthIndex) {
764  case 1:
765  return ki18nc("Hebrew month 1 - KLocale::LongName", "Tishrey").toString(languages);
766  case 2:
767  return ki18nc("Hebrew month 2 - KLocale::LongName", "Heshvan").toString(languages);
768  case 3:
769  return ki18nc("Hebrew month 3 - KLocale::LongName", "Kislev").toString(languages);
770  case 4:
771  return ki18nc("Hebrew month 4 - KLocale::LongName", "Tevet").toString(languages);
772  case 5:
773  return ki18nc("Hebrew month 5 - KLocale::LongName", "Shvat").toString(languages);
774  case 6:
775  return ki18nc("Hebrew month 6 - KLocale::LongName", "Adar").toString(languages);
776  case 7:
777  return ki18nc("Hebrew month 7 - KLocale::LongName", "Nisan").toString(languages);
778  case 8:
779  return ki18nc("Hebrew month 8 - KLocale::LongName", "Iyar").toString(languages);
780  case 9:
781  return ki18nc("Hebrew month 9 - KLocale::LongName", "Sivan").toString(languages);
782  case 10:
783  return ki18nc("Hebrew month 10 - KLocale::LongName", "Tamuz").toString(languages);
784  case 11:
785  return ki18nc("Hebrew month 11 - KLocale::LongName", "Av").toString(languages);
786  case 12:
787  return ki18nc("Hebrew month 12 - KLocale::LongName", "Elul").toString(languages);
788  case 13:
789  return ki18nc("Hebrew month 13 - KLocale::LongName", "Adar I").toString(languages);
790  case 14:
791  return ki18nc("Hebrew month 14 - KLocale::LongName", "Adar II").toString(languages);
792  default:
793  return QString();
794  }
795 }
796 
797 // Use Western day names for now as that's what the old version did,
798 // but wouldn't it be better to use the right Hebrew names like Shabbat?
799 // Could make it switchable by adding new enums to WeekDayFormat, e.g. ShortNameWestern?
800 QString KCalendarSystemHebrewPrivate::weekDayName(int weekDay, KLocale::DateTimeComponentFormat format) const
801 {
802  QStringList languages = locale()->languageList();
803 
804  if (format == KLocale::NarrowName) {
805  switch (weekDay) {
806  case 1:
807  return ki18nc("Gregorian weekday 1 - KLocale::NarrowName ", "M").toString(languages);
808  case 2:
809  return ki18nc("Gregorian weekday 2 - KLocale::NarrowName ", "T").toString(languages);
810  case 3:
811  return ki18nc("Gregorian weekday 3 - KLocale::NarrowName ", "W").toString(languages);
812  case 4:
813  return ki18nc("Gregorian weekday 4 - KLocale::NarrowName ", "T").toString(languages);
814  case 5:
815  return ki18nc("Gregorian weekday 5 - KLocale::NarrowName ", "F").toString(languages);
816  case 6:
817  return ki18nc("Gregorian weekday 6 - KLocale::NarrowName ", "S").toString(languages);
818  case 7:
819  return ki18nc("Gregorian weekday 7 - KLocale::NarrowName ", "S").toString(languages);
820  default:
821  return QString();
822  }
823  }
824 
825  if (format == KLocale::ShortName || format == KLocale:: ShortNumber) {
826  switch (weekDay) {
827  case 1:
828  return ki18nc("Gregorian weekday 1 - KLocale::ShortName", "Mon").toString(languages);
829  case 2:
830  return ki18nc("Gregorian weekday 2 - KLocale::ShortName", "Tue").toString(languages);
831  case 3:
832  return ki18nc("Gregorian weekday 3 - KLocale::ShortName", "Wed").toString(languages);
833  case 4:
834  return ki18nc("Gregorian weekday 4 - KLocale::ShortName", "Thu").toString(languages);
835  case 5:
836  return ki18nc("Gregorian weekday 5 - KLocale::ShortName", "Fri").toString(languages);
837  case 6:
838  return ki18nc("Gregorian weekday 6 - KLocale::ShortName", "Sat").toString(languages);
839  case 7:
840  return ki18nc("Gregorian weekday 7 - KLocale::ShortName", "Sun").toString(languages);
841  default: return QString();
842  }
843  }
844 
845  switch (weekDay) {
846  case 1:
847  return ki18nc("Gregorian weekday 1 - KLocale::LongName", "Monday").toString(languages);
848  case 2:
849  return ki18nc("Gregorian weekday 2 - KLocale::LongName", "Tuesday").toString(languages);
850  case 3:
851  return ki18nc("Gregorian weekday 3 - KLocale::LongName", "Wednesday").toString(languages);
852  case 4:
853  return ki18nc("Gregorian weekday 4 - KLocale::LongName", "Thursday").toString(languages);
854  case 5:
855  return ki18nc("Gregorian weekday 5 - KLocale::LongName", "Friday").toString(languages);
856  case 6:
857  return ki18nc("Gregorian weekday 6 - KLocale::LongName", "Saturday").toString(languages);
858  case 7:
859  return ki18nc("Gregorian weekday 7 - KLocale::LongName", "Sunday").toString(languages);
860  default:
861  return QString();
862  }
863 }
864 
865 KCalendarSystemHebrew::KCalendarSystemHebrew(const KSharedConfig::Ptr config, const KLocale *locale)
866  : KCalendarSystem(*new KCalendarSystemHebrewPrivate(this), config, locale)
867 {
868  d_ptr->loadConfig(calendarType());
869 }
870 
871 KCalendarSystemHebrew::KCalendarSystemHebrew(KCalendarSystemHebrewPrivate &dd,
872  const KSharedConfig::Ptr config, const KLocale *locale)
873  : KCalendarSystem(dd, config, locale)
874 {
875  d_ptr->loadConfig(calendarType());
876 }
877 
878 KCalendarSystemHebrew::~KCalendarSystemHebrew()
879 {
880 }
881 
882 QString KCalendarSystemHebrew::calendarType() const
883 {
884  return QLatin1String("hebrew");
885 }
886 
887 KLocale::CalendarSystem KCalendarSystemHebrew::calendarSystem() const
888 {
890 }
891 
892 QDate KCalendarSystemHebrew::epoch() const
893 {
894  // Hebrew 0001-01-01 (Gregorian -3760-09-07, Julian -3761-10-07)
895  return QDate::fromJulianDay(347998);
896 }
897 
898 QDate KCalendarSystemHebrew::earliestValidDate() const
899 {
900  // Current formulas using direct Gregorian <-> Hebrew conversion using Qt
901  // will return invalid results prior to the Gregorian switchover in 1582
902  // Next valid Hebrew year starts 5344-01-01 (Gregorian 1583-09-17)
903  return QDate::fromJulianDay(2299498);
904 }
905 
906 QDate KCalendarSystemHebrew::latestValidDate() const
907 {
908  // Testing shows current formulas only work up to 8119-13-29 (Gregorian 4359-10-07)
909  return QDate::fromJulianDay(3313431);
910 }
911 
912 QString KCalendarSystemHebrew::monthName(int month, int year, MonthNameFormat format) const
913 {
914  return KCalendarSystem::monthName(month, year, format);
915 }
916 
917 QString KCalendarSystemHebrew::monthName(const QDate &date, MonthNameFormat format) const
918 {
919  return KCalendarSystem::monthName(date, format);
920 }
921 
922 QString KCalendarSystemHebrew::weekDayName(int weekDay, WeekDayNameFormat format) const
923 {
924  return KCalendarSystem::weekDayName(weekDay, format);
925 }
926 
927 QString KCalendarSystemHebrew::weekDayName(const QDate &date, WeekDayNameFormat format) const
928 {
929  return KCalendarSystem::weekDayName(date, format);
930 }
931 
932 int KCalendarSystemHebrew::yearStringToInteger(const QString &string, int &readLength) const
933 {
934  int result = KCalendarSystem::yearStringToInteger(string, readLength);
935 
936  // Hebrew has no letter for 0, so 5 and 5000 are written the same
937  // Assume if less than 10 then we are in an exact multiple of 1000
938  if (result < 10) {
939  result = result * 1000;
940  }
941 
942  // Not good just assuming, make configurable
943  if (result < 1000) {
944  result += 5000; // assume we're in the 6th millenium (y6k bug)
945  }
946 
947  return result;
948 }
949 
950 bool KCalendarSystemHebrew::isLunar() const
951 {
952  return false;
953 }
954 
955 bool KCalendarSystemHebrew::isLunisolar() const
956 {
957  return true;
958 }
959 
960 bool KCalendarSystemHebrew::isSolar() const
961 {
962  return false;
963 }
964 
965 bool KCalendarSystemHebrew::isProleptic() const
966 {
967  return false;
968 }
969 
970 bool KCalendarSystemHebrew::julianDayToDate(qint64 jd, int &year, int &month, int &day) const
971 {
972  class h_date *sd = toHebrew(QDate::fromJulianDay(jd));
973 
974  year = sd->hd_year;
975 
976  month = sd->hd_mon;
977  if (isLeapYear(sd->hd_year)) {
978  if (month == 13 /*AdarI*/) {
979  month = 6;
980  } else if (month == 14 /*AdarII*/) {
981  month = 7;
982  } else if (month > 6 && month < 13) {
983  ++month;
984  }
985  }
986 
987  day = sd->hd_day;
988 
989  return true;
990 }
991 
992 bool KCalendarSystemHebrew::dateToJulianDay(int year, int month, int day, qint64 &jd) const
993 {
994  class h_date *gd = hebrewToGregorian(year, month, day);
995 
996  QDate tempDate(gd->hd_year, gd->hd_mon + 1, gd->hd_day + 1);
997 
998  jd = tempDate.toJulianDay();
999 
1000  return true;
1001 }
qint64 daysTo(const QDate &d) const const
Narrow text format, may not be unique, e.g.
Definition: klocale.h:775
QString toString() const
QString name(const QVariant &location)
virtual int day(const QDate &date) const
Returns the day portion of a given date in the current calendar system.
virtual QString weekDayName(int weekDay, WeekDayNameFormat format=LongDayName) const =0
Gets specific calendar type week day name.
int day() const const
MonthNameFormat
Format for returned month / day name.
Hebrew Calendar, aka Jewish Calendar.
Definition: klocale.h:654
Number at its natural width, e.g.
Definition: klocale.h:772
KCalendarSystem abstract base class, provides support for local Calendar Systems in KDE...
DateTimeComponentFormat
Definition: klocale.h:770
QString & insert(int position, QChar ch)
CalendarSystem
Definition: klocale.h:646
bool isLeapYear(int year) const
Returns whether a given year is a leap year.
QString i18nc(const char *context, const char *text, const TYPE &arg...)
Long text format, e.g.
Definition: klocale.h:777
virtual int month(const QDate &date) const
Returns the month portion of a given date in the current calendar system.
const KLocale * locale() const
Returns the locale used for translations and formats for this calendar system instance.
WeekDayNameFormat
Format for returned month / day name.
ushort unicode() const const
virtual int yearStringToInteger(const QString &sNum, int &iLength) const
Short text format, e.g.
Definition: klocale.h:776
bool setDate(int year, int month, int day)
KLocalizedString KI18N_EXPORT ki18nc(const char *context, const char *text)
QStringList languageList() const
Returns the language codes selected by user, ordered by decreasing priority.
Definition: klocale.cpp:376
virtual QString monthName(int month, int year, MonthNameFormat format=LongName) const =0
Gets specific calendar type month name for a given month number If an invalid month is specified...
KLocale provides support for language and country specific stuff.
Definition: klocale.h:75
int length() const const
DigitSet
Definition: klocale.h:176
QDate fromJulianDay(qint64 jd)
virtual QString calendarType() const =0
int year() const const
int month() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Sat Oct 24 2020 23:03:50 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.