1 /*
2 Copyright 2009, 2010 John Layt <john@layt.net>
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to
16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 Boston, MA 02110-1301, USA.
18 */
19
20 #include "kcalendarsystemcoptic_p.h"
21 #include "kcalendarsystemprivate_p.h"
22 #include "kcalendarsystemcopticprivate_p.h"
23
24 #include "klocale.h"
25 #include "klocalizedstring.h"
26
27 #include <QDate>
28 #include <QCharRef>
29
30 // Shared d pointer implementations
31
KCalendarSystemCopticPrivate(KCalendarSystemCoptic * q)32 KCalendarSystemCopticPrivate::KCalendarSystemCopticPrivate(KCalendarSystemCoptic *q)
33 : KCalendarSystemPrivate(q)
34 {
35 }
36
~KCalendarSystemCopticPrivate()37 KCalendarSystemCopticPrivate::~KCalendarSystemCopticPrivate()
38 {
39 }
40
loadDefaultEraList()41 void KCalendarSystemCopticPrivate::loadDefaultEraList()
42 {
43 QString name, shortName, format;
44 // AM for Anno Martyrum or "Year of the Martyrs"
45 name = i18nc("Calendar Era: Coptic Era of Martyrs, years > 0, LongFormat", "Anno Martyrum");
46 shortName = i18nc("Calendar Era: Coptic Era of Martyrs, years > 0, ShortFormat", "AM");
47 format = i18nc("(kdedt-format) Coptic, AM, full era year format used for %EY, e.g. 2000 AM", "%Ey %EC");
48 addEra('+', 1, q->epoch(), 1, q->latestValidDate(), name, shortName, format);
49 }
50
monthsInYear(int year) const51 int KCalendarSystemCopticPrivate::monthsInYear(int year) const
52 {
53 Q_UNUSED(year)
54 return 13;
55 }
56
daysInMonth(int year,int month) const57 int KCalendarSystemCopticPrivate::daysInMonth(int year, int month) const
58 {
59 if (month == 13) {
60 if (isLeapYear(year)) {
61 return 6;
62 } else {
63 return 5;
64 }
65 }
66
67 return 30;
68 }
69
daysInYear(int year) const70 int KCalendarSystemCopticPrivate::daysInYear(int year) const
71 {
72 if (isLeapYear(year)) {
73 return 366;
74 } else {
75 return 365;
76 }
77 }
78
isLeapYear(int year) const79 bool KCalendarSystemCopticPrivate::isLeapYear(int year) const
80 {
81 //Uses same rule as Julian but offset by 1 year with year 3 being first leap year
82 if (year < 1) {
83 year = year + 2;
84 } else {
85 year = year + 1;
86 }
87
88 if (year % 4 == 0) {
89 return true;
90 }
91 return false;
92 }
93
hasLeapMonths() const94 bool KCalendarSystemCopticPrivate::hasLeapMonths() const
95 {
96 return false;
97 }
98
hasYearZero() const99 bool KCalendarSystemCopticPrivate::hasYearZero() const
100 {
101 return false;
102 }
103
maxMonthsInYear() const104 int KCalendarSystemCopticPrivate::maxMonthsInYear() const
105 {
106 return 13;
107 }
108
earliestValidYear() const109 int KCalendarSystemCopticPrivate::earliestValidYear() const
110 {
111 return 1;
112 }
113
latestValidYear() const114 int KCalendarSystemCopticPrivate::latestValidYear() const
115 {
116 return 9999;
117 }
118
119 // Names taken from Bohairic dialect transliterations in http://www.copticheritage.org/parameters/copticheritage/calendar/The_Coptic_Calendar.pdf
120 // These differ from the transliterations found on Wikipedia http://en.wikipedia.org/wiki/Coptic_calendar
121 // These differ from the Sahidic dialect transliterations used in Dershowitz & Reingold which went out of use in the 11th centuary
122 // These differ from the Arabic transliterations found on Wikipedia
123 // These differ from the transliterations used in Mac OSX 10.6 Snow Leopard
124 // The Boharic was initially chosen as this is the dialect apparantly in 'common' use in the Coptic Church.
125 // But it could be argued the Arabic forms should be used as they are in 'common' usage in Eqypt
126 // And where did the rest come from?
127 //
128 // Boharic Wikipedia Copt D&R Sahidic Wikipedia Arab Mac OSX
129 // -------------- --------------- -------------- -------------- --------------
130 // * Thoout Thout Thoout Tout Tout
131 // * Paope Paopi Paope Baba Baba
132 // * Hathor Hathor Athōr Hatour Hatour
133 // * Kiahk Koiak Koiak Kiahk Kiahk
134 // * Tobe Tobi Tōbe Touba Toba
135 // * Meshir Meshir Meshir Amshir Amshir
136 // * Paremhotep Paremhat Paremotep Baramhat Baramhat
137 // * Parmoute Paremoude Paremoute Baramouda Baramouda
138 // * Pashons Pashons Pashons Bashans Bashans
139 // * Paone Paoni Paōne Ba'ouna Paona
140 // * Epep Epip Epēp Abib Epep
141 // * Mesore Mesori Mesorē Mesra Mesra
142 // * Kouji nabot Pi Kogi Enavot Epagomenē Nasie
143 // *
monthName(int month,int year,KLocale::DateTimeComponentFormat format,bool possessive) const144 QString KCalendarSystemCopticPrivate::monthName(int month, int year, KLocale::DateTimeComponentFormat format, bool possessive) const
145 {
146 Q_UNUSED(year);
147
148 QStringList languages = locale()->languageList();
149
150 if (format == KLocale::NarrowName) {
151 switch (month) {
152 case 1:
153 return ki18nc("Coptic month 1 - KLocale::NarrowName", "T").toString(languages);
154 case 2:
155 return ki18nc("Coptic month 2 - KLocale::NarrowName", "P").toString(languages);
156 case 3:
157 return ki18nc("Coptic month 3 - KLocale::NarrowName", "H").toString(languages);
158 case 4:
159 return ki18nc("Coptic month 4 - KLocale::NarrowName", "K").toString(languages);
160 case 5:
161 return ki18nc("Coptic month 5 - KLocale::NarrowName", "T").toString(languages);
162 case 6:
163 return ki18nc("Coptic month 6 - KLocale::NarrowName", "M").toString(languages);
164 case 7:
165 return ki18nc("Coptic month 7 - KLocale::NarrowName", "P").toString(languages);
166 case 8:
167 return ki18nc("Coptic month 8 - KLocale::NarrowName", "P").toString(languages);
168 case 9:
169 return ki18nc("Coptic month 9 - KLocale::NarrowName", "P").toString(languages);
170 case 10:
171 return ki18nc("Coptic month 10 - KLocale::NarrowName", "P").toString(languages);
172 case 11:
173 return ki18nc("Coptic month 11 - KLocale::NarrowName", "E").toString(languages);
174 case 12:
175 return ki18nc("Coptic month 12 - KLocale::NarrowName", "M").toString(languages);
176 case 13:
177 return ki18nc("Coptic month 13 - KLocale::NarrowName", "K").toString(languages);
178 default:
179 return QString();
180 }
181 }
182
183 if (format == KLocale::ShortName && possessive) {
184 switch (month) {
185 case 1:
186 return ki18nc("Coptic month 1 - KLocale::ShortName Possessive", "of Tho").toString(languages);
187 case 2:
188 return ki18nc("Coptic month 2 - KLocale::ShortName Possessive", "of Pao").toString(languages);
189 case 3:
190 return ki18nc("Coptic month 3 - KLocale::ShortName Possessive", "of Hat").toString(languages);
191 case 4:
192 return ki18nc("Coptic month 4 - KLocale::ShortName Possessive", "of Kia").toString(languages);
193 case 5:
194 return ki18nc("Coptic month 5 - KLocale::ShortName Possessive", "of Tob").toString(languages);
195 case 6:
196 return ki18nc("Coptic month 6 - KLocale::ShortName Possessive", "of Mes").toString(languages);
197 case 7:
198 return ki18nc("Coptic month 7 - KLocale::ShortName Possessive", "of Par").toString(languages);
199 case 8:
200 return ki18nc("Coptic month 8 - KLocale::ShortName Possessive", "of Pam").toString(languages);
201 case 9:
202 return ki18nc("Coptic month 9 - KLocale::ShortName Possessive", "of Pas").toString(languages);
203 case 10:
204 return ki18nc("Coptic month 10 - KLocale::ShortName Possessive", "of Pan").toString(languages);
205 case 11:
206 return ki18nc("Coptic month 11 - KLocale::ShortName Possessive", "of Epe").toString(languages);
207 case 12:
208 return ki18nc("Coptic month 12 - KLocale::ShortName Possessive", "of Meo").toString(languages);
209 case 13:
210 return ki18nc("Coptic month 13 - KLocale::ShortName Possessive", "of Kou").toString(languages);
211 default:
212 return QString();
213 }
214 }
215
216 if (format == KLocale::ShortName && !possessive) {
217 switch (month) {
218 case 1:
219 return ki18nc("Coptic month 1 - KLocale::ShortName", "Tho").toString(languages);
220 case 2:
221 return ki18nc("Coptic month 2 - KLocale::ShortName", "Pao").toString(languages);
222 case 3:
223 return ki18nc("Coptic month 3 - KLocale::ShortName", "Hat").toString(languages);
224 case 4:
225 return ki18nc("Coptic month 4 - KLocale::ShortName", "Kia").toString(languages);
226 case 5:
227 return ki18nc("Coptic month 5 - KLocale::ShortName", "Tob").toString(languages);
228 case 6:
229 return ki18nc("Coptic month 6 - KLocale::ShortName", "Mes").toString(languages);
230 case 7:
231 return ki18nc("Coptic month 7 - KLocale::ShortName", "Par").toString(languages);
232 case 8:
233 return ki18nc("Coptic month 8 - KLocale::ShortName", "Pam").toString(languages);
234 case 9:
235 return ki18nc("Coptic month 9 - KLocale::ShortName", "Pas").toString(languages);
236 case 10:
237 return ki18nc("Coptic month 10 - KLocale::ShortName", "Pan").toString(languages);
238 case 11:
239 return ki18nc("Coptic month 11 - KLocale::ShortName", "Epe").toString(languages);
240 case 12:
241 return ki18nc("Coptic month 12 - KLocale::ShortName", "Meo").toString(languages);
242 case 13:
243 return ki18nc("Coptic month 12 - KLocale::ShortName", "Kou").toString(languages);
244 default:
245 return QString();
246 }
247 }
248
249 if (format == KLocale::LongName && possessive) {
250 switch (month) {
251 case 1:
252 return ki18nc("Coptic month 1 - KLocale::LongName Possessive", "of Thoout").toString(languages);
253 case 2:
254 return ki18nc("Coptic month 2 - KLocale::LongName Possessive", "of Paope").toString(languages);
255 case 3:
256 return ki18nc("Coptic month 3 - KLocale::LongName Possessive", "of Hathor").toString(languages);
257 case 4:
258 return ki18nc("Coptic month 4 - KLocale::LongName Possessive", "of Kiahk").toString(languages);
259 case 5:
260 return ki18nc("Coptic month 5 - KLocale::LongName Possessive", "of Tobe").toString(languages);
261 case 6:
262 return ki18nc("Coptic month 6 - KLocale::LongName Possessive", "of Meshir").toString(languages);
263 case 7:
264 return ki18nc("Coptic month 7 - KLocale::LongName Possessive", "of Paremhotep").toString(languages);
265 case 8:
266 return ki18nc("Coptic month 8 - KLocale::LongName Possessive", "of Parmoute").toString(languages);
267 case 9:
268 return ki18nc("Coptic month 9 - KLocale::LongName Possessive", "of Pashons").toString(languages);
269 case 10:
270 return ki18nc("Coptic month 10 - KLocale::LongName Possessive", "of Paone").toString(languages);
271 case 11:
272 return ki18nc("Coptic month 11 - KLocale::LongName Possessive", "of Epep").toString(languages);
273 case 12:
274 return ki18nc("Coptic month 12 - KLocale::LongName Possessive", "of Mesore").toString(languages);
275 case 13:
276 return ki18nc("Coptic month 12 - KLocale::LongName Possessive", "of Kouji nabot").toString(languages);
277 default:
278 return QString();
279 }
280 }
281
282 // Default to LongName
283 switch (month) {
284 case 1:
285 return ki18nc("Coptic month 1 - KLocale::LongName", "Thoout").toString(languages);
286 case 2:
287 return ki18nc("Coptic month 2 - KLocale::LongName", "Paope").toString(languages);
288 case 3:
289 return ki18nc("Coptic month 3 - KLocale::LongName", "Hathor").toString(languages);
290 case 4:
291 return ki18nc("Coptic month 4 - KLocale::LongName", "Kiahk").toString(languages);
292 case 5:
293 return ki18nc("Coptic month 5 - KLocale::LongName", "Tobe").toString(languages);
294 case 6:
295 return ki18nc("Coptic month 6 - KLocale::LongName", "Meshir").toString(languages);
296 case 7:
297 return ki18nc("Coptic month 7 - KLocale::LongName", "Paremhotep").toString(languages);
298 case 8:
299 return ki18nc("Coptic month 8 - KLocale::LongName", "Parmoute").toString(languages);
300 case 9:
301 return ki18nc("Coptic month 9 - KLocale::LongName", "Pashons").toString(languages);
302 case 10:
303 return ki18nc("Coptic month 10 - KLocale::LongName", "Paone").toString(languages);
304 case 11:
305 return ki18nc("Coptic month 11 - KLocale::LongName", "Epep").toString(languages);
306 case 12:
307 return ki18nc("Coptic month 12 - KLocale::LongName", "Mesore").toString(languages);
308 case 13:
309 return ki18nc("Coptic month 12 - KLocale::LongName", "Kouji nabot").toString(languages);
310 default:
311 return QString();
312 }
313 }
314
315 // Names taken from from the Sahidic dialect transliterations used in Dershowitz & Reingold which went out of use in the 11th centuary
316 // Boharic or Arabic transliterations would be preferred but none could be found
weekDayName(int weekDay,KLocale::DateTimeComponentFormat format) const317 QString KCalendarSystemCopticPrivate::weekDayName(int weekDay, KLocale::DateTimeComponentFormat format) const
318 {
319 QStringList languages = locale()->languageList();
320
321 if (format == KLocale::NarrowName) {
322 switch (weekDay) {
323 case 1:
324 return ki18nc("Coptic weekday 1 - KLocale::NarrowName", "P").toString(languages);
325 case 2:
326 return ki18nc("Coptic weekday 2 - KLocale::NarrowName", "P").toString(languages);
327 case 3:
328 return ki18nc("Coptic weekday 3 - KLocale::NarrowName", "P").toString(languages);
329 case 4:
330 return ki18nc("Coptic weekday 4 - KLocale::NarrowName", "P").toString(languages);
331 case 5:
332 return ki18nc("Coptic weekday 5 - KLocale::NarrowName", "P").toString(languages);
333 case 6:
334 return ki18nc("Coptic weekday 6 - KLocale::NarrowName", "P").toString(languages);
335 case 7:
336 return ki18nc("Coptic weekday 7 - KLocale::NarrowName", "T").toString(languages);
337 default:
338 return QString();
339 }
340 }
341
342 if (format == KLocale::ShortName || format == KLocale:: ShortNumber) {
343 switch (weekDay) {
344 case 1:
345 return ki18nc("Coptic weekday 1 - KLocale::ShortName", "Pes").toString(languages);
346 case 2:
347 return ki18nc("Coptic weekday 2 - KLocale::ShortName", "Psh").toString(languages);
348 case 3:
349 return ki18nc("Coptic weekday 3 - KLocale::ShortName", "Pef").toString(languages);
350 case 4:
351 return ki18nc("Coptic weekday 4 - KLocale::ShortName", "Pti").toString(languages);
352 case 5:
353 return ki18nc("Coptic weekday 5 - KLocale::ShortName", "Pso").toString(languages);
354 case 6:
355 return ki18nc("Coptic weekday 6 - KLocale::ShortName", "Psa").toString(languages);
356 case 7:
357 return ki18nc("Coptic weekday 7 - KLocale::ShortName", "Tky").toString(languages);
358 default:
359 return QString();
360 }
361 }
362
363 switch (weekDay) {
364 case 1:
365 return ki18nc("Coptic weekday 1 - KLocale::LongName", "Pesnau").toString(languages);
366 case 2:
367 return ki18nc("Coptic weekday 2 - KLocale::LongName", "Pshoment").toString(languages);
368 case 3:
369 return ki18nc("Coptic weekday 3 - KLocale::LongName", "Peftoou").toString(languages);
370 case 4:
371 return ki18nc("Coptic weekday 4 - KLocale::LongName", "Ptiou").toString(languages);
372 case 5:
373 return ki18nc("Coptic weekday 5 - KLocale::LongName", "Psoou").toString(languages);
374 case 6:
375 return ki18nc("Coptic weekday 6 - KLocale::LongName", "Psabbaton").toString(languages);
376 case 7:
377 return ki18nc("Coptic weekday 7 - KLocale::LongName", "Tkyriakē").toString(languages);
378 default:
379 return QString();
380 }
381 }
382
KCalendarSystemCoptic(const KSharedConfig::Ptr config,const KLocale * locale)383 KCalendarSystemCoptic::KCalendarSystemCoptic(const KSharedConfig::Ptr config, const KLocale *locale)
384 : KCalendarSystem(*new KCalendarSystemCopticPrivate(this), config, locale)
385 {
386 d_ptr->loadConfig(calendarType());
387 }
388
KCalendarSystemCoptic(KCalendarSystemCopticPrivate & dd,const KSharedConfig::Ptr config,const KLocale * locale)389 KCalendarSystemCoptic::KCalendarSystemCoptic(KCalendarSystemCopticPrivate &dd,
390 const KSharedConfig::Ptr config, const KLocale *locale)
391 : KCalendarSystem(dd, config, locale)
392 {
393 d_ptr->loadConfig(calendarType());
394 }
395
~KCalendarSystemCoptic()396 KCalendarSystemCoptic::~KCalendarSystemCoptic()
397 {
398 }
399
calendarType() const400 QString KCalendarSystemCoptic::calendarType() const
401 {
402 return QLatin1String("coptic");
403 }
404
calendarSystem() const405 KLocale::CalendarSystem KCalendarSystemCoptic::calendarSystem() const
406 {
407 return KLocale::CopticCalendar;
408 }
409
epoch() const410 QDate KCalendarSystemCoptic::epoch() const
411 {
412 //0001-01-01, no Year 0.
413 //0284-08-29 AD Julian
414 return QDate::fromJulianDay(1825030);
415 }
416
earliestValidDate() const417 QDate KCalendarSystemCoptic::earliestValidDate() const
418 {
419 //0001-01-01, no Year 0.
420 //0284-08-29 AD Julian
421 return QDate::fromJulianDay(1825030);
422 }
423
latestValidDate() const424 QDate KCalendarSystemCoptic::latestValidDate() const
425 {
426 // Set to last day of year 9999 until confirm date formats & widgets support > 9999
427 //9999-12-30
428 //10283-08-29 AD Julian
429 return QDate::fromJulianDay(5477164);
430 }
431
monthName(int month,int year,MonthNameFormat format) const432 QString KCalendarSystemCoptic::monthName(int month, int year, MonthNameFormat format) const
433 {
434 return KCalendarSystem::monthName(month, year, format);
435 }
436
monthName(const QDate & date,MonthNameFormat format) const437 QString KCalendarSystemCoptic::monthName(const QDate &date, MonthNameFormat format) const
438 {
439 return KCalendarSystem::monthName(date, format);
440 }
441
weekDayName(int weekDay,WeekDayNameFormat format) const442 QString KCalendarSystemCoptic::weekDayName(int weekDay, WeekDayNameFormat format) const
443 {
444 return KCalendarSystem::weekDayName(weekDay, format);
445 }
446
weekDayName(const QDate & date,WeekDayNameFormat format) const447 QString KCalendarSystemCoptic::weekDayName(const QDate &date, WeekDayNameFormat format) const
448 {
449 return KCalendarSystem::weekDayName(date, format);
450 }
451
isLunar() const452 bool KCalendarSystemCoptic::isLunar() const
453 {
454 return false;
455 }
456
isLunisolar() const457 bool KCalendarSystemCoptic::isLunisolar() const
458 {
459 return false;
460 }
461
isSolar() const462 bool KCalendarSystemCoptic::isSolar() const
463 {
464 return true;
465 }
466
isProleptic() const467 bool KCalendarSystemCoptic::isProleptic() const
468 {
469 return false;
470 }
471
julianDayToDate(qint64 jd,int & year,int & month,int & day) const472 bool KCalendarSystemCoptic::julianDayToDate(qint64 jd, int &year, int &month, int &day) const
473 {
474 //The Coptic calendar has 12 months of 30 days, a 13th month of 5 or 6 days,
475 //and a leap year every 4th year without fail that falls on the last day of
476 //the year, starting from year 3.
477
478 //Use a fake year 0 for our epoch instead of the real epoch in year 1. This is because year 3
479 //is the first leap year and a pattern of 365/365/366/365 is hard to calculate, instead a
480 //pattern of 365/365/365/366 with the leap day the very last day makes the maths easier.
481
482 //Day number in the fake epoch, 0 indexed
483 int dayInEpoch = jd - (epoch().toJulianDay() - 365);
484 //How many full 4 year leap cycles have been completed, 1461 = (365*3)+366
485 int leapCyclesCompleted = dayInEpoch / 1461;
486 //Which year are we in the current 4 year leap cycle, 0 indexed
487 //Need the qMin as day 366 of 4th year of cycle returns following year (max 3 as 0 index)
488 int yearInCurrentLeapCycle = qMin(3, (dayInEpoch % 1461) / 365);
489 //Calculate the year
490 year = (leapCyclesCompleted * 4) + yearInCurrentLeapCycle;
491 //Days since the fake epoch up to 1st day of this year
492 int daysBeforeThisYear = (year * 365) + (year / 4);
493 //Gives the day number in this year, 0 indexed
494 int dayOfThisYear = dayInEpoch - daysBeforeThisYear;
495 //Then just calculate month and day from that based on regular 30 day months
496 month = ((dayOfThisYear) / 30) + 1;
497 day = dayOfThisYear - ((month - 1) * 30) + 1;
498
499 // If year is -ve then is BC. In Coptic there is no year 0, but the maths
500 // is easier if we pretend there is, so internally year of 0 = 1BC = -1 outside
501 if (year < 1) {
502 year = year - 1;
503 }
504
505 return true;
506 }
507
dateToJulianDay(int year,int month,int day,qint64 & jd) const508 bool KCalendarSystemCoptic::dateToJulianDay(int year, int month, int day, qint64 &jd) const
509 {
510 //The Coptic calendar has 12 months of 30 days, a 13th month of 5 or 6 days,
511 //and a leap year every 4th year without fail that falls on the last day of
512 //the year, starting from year 3. This simple repeating pattern makes calculating
513 // a jd the simple process taking the epoch jd and adding on the years months and
514 //days required.
515
516 // If year is -ve then is 'BC'. In Coptic there is no year 0, but the maths
517 // is easier if we pretend there is, so internally year of -1 = 1BC = 0 internally
518 int y;
519 if (year < 1) {
520 y = year + 1;
521 } else {
522 y = year;
523 }
524
525 jd = epoch().toJulianDay() - 1 // jd of day before Epoch
526 + ((y - 1) * 365) // Add all normal days in years preceding
527 + (y / 4) // Add all leap days in years preceding
528 + ((month - 1) * 30) // Add days this year in months preceding
529 + day; // Add days in this month
530
531 return true;
532 }
533