File indexing completed on 2023-09-24 04:04:42
0001 /* 0002 Copyright 2009, 2010 John Layt <john@layt.net> 0003 0004 This library is free software; you can redistribute it and/or 0005 modify it under the terms of the GNU Library General Public 0006 License as published by the Free Software Foundation; either 0007 version 2 of the License, or (at your option) any later version. 0008 0009 This library is distributed in the hope that it will be useful, 0010 but WITHOUT ANY WARRANTY; without even the implied warranty of 0011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0012 Library General Public License for more details. 0013 0014 You should have received a copy of the GNU Library General Public License 0015 along with this library; see the file COPYING.LIB. If not, write to 0016 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0017 Boston, MA 02110-1301, USA. 0018 */ 0019 0020 #include "kcalendarsystemcoptic_p.h" 0021 #include "kcalendarsystemprivate_p.h" 0022 #include "kcalendarsystemcopticprivate_p.h" 0023 0024 #include "klocale.h" 0025 #include "klocalizedstring.h" 0026 0027 #include <QDate> 0028 #include <QCharRef> 0029 0030 // Shared d pointer implementations 0031 0032 KCalendarSystemCopticPrivate::KCalendarSystemCopticPrivate(KCalendarSystemCoptic *q) 0033 : KCalendarSystemPrivate(q) 0034 { 0035 } 0036 0037 KCalendarSystemCopticPrivate::~KCalendarSystemCopticPrivate() 0038 { 0039 } 0040 0041 void KCalendarSystemCopticPrivate::loadDefaultEraList() 0042 { 0043 QString name, shortName, format; 0044 // AM for Anno Martyrum or "Year of the Martyrs" 0045 name = i18nc("Calendar Era: Coptic Era of Martyrs, years > 0, LongFormat", "Anno Martyrum"); 0046 shortName = i18nc("Calendar Era: Coptic Era of Martyrs, years > 0, ShortFormat", "AM"); 0047 format = i18nc("(kdedt-format) Coptic, AM, full era year format used for %EY, e.g. 2000 AM", "%Ey %EC"); 0048 addEra('+', 1, q->epoch(), 1, q->latestValidDate(), name, shortName, format); 0049 } 0050 0051 int KCalendarSystemCopticPrivate::monthsInYear(int year) const 0052 { 0053 Q_UNUSED(year) 0054 return 13; 0055 } 0056 0057 int KCalendarSystemCopticPrivate::daysInMonth(int year, int month) const 0058 { 0059 if (month == 13) { 0060 if (isLeapYear(year)) { 0061 return 6; 0062 } else { 0063 return 5; 0064 } 0065 } 0066 0067 return 30; 0068 } 0069 0070 int KCalendarSystemCopticPrivate::daysInYear(int year) const 0071 { 0072 if (isLeapYear(year)) { 0073 return 366; 0074 } else { 0075 return 365; 0076 } 0077 } 0078 0079 bool KCalendarSystemCopticPrivate::isLeapYear(int year) const 0080 { 0081 //Uses same rule as Julian but offset by 1 year with year 3 being first leap year 0082 if (year < 1) { 0083 year = year + 2; 0084 } else { 0085 year = year + 1; 0086 } 0087 0088 if (year % 4 == 0) { 0089 return true; 0090 } 0091 return false; 0092 } 0093 0094 bool KCalendarSystemCopticPrivate::hasLeapMonths() const 0095 { 0096 return false; 0097 } 0098 0099 bool KCalendarSystemCopticPrivate::hasYearZero() const 0100 { 0101 return false; 0102 } 0103 0104 int KCalendarSystemCopticPrivate::maxMonthsInYear() const 0105 { 0106 return 13; 0107 } 0108 0109 int KCalendarSystemCopticPrivate::earliestValidYear() const 0110 { 0111 return 1; 0112 } 0113 0114 int KCalendarSystemCopticPrivate::latestValidYear() const 0115 { 0116 return 9999; 0117 } 0118 0119 // Names taken from Bohairic dialect transliterations in http://www.copticheritage.org/parameters/copticheritage/calendar/The_Coptic_Calendar.pdf 0120 // These differ from the transliterations found on Wikipedia http://en.wikipedia.org/wiki/Coptic_calendar 0121 // These differ from the Sahidic dialect transliterations used in Dershowitz & Reingold which went out of use in the 11th centuary 0122 // These differ from the Arabic transliterations found on Wikipedia 0123 // These differ from the transliterations used in Mac OSX 10.6 Snow Leopard 0124 // The Boharic was initially chosen as this is the dialect apparantly in 'common' use in the Coptic Church. 0125 // But it could be argued the Arabic forms should be used as they are in 'common' usage in Eqypt 0126 // And where did the rest come from? 0127 // 0128 // Boharic Wikipedia Copt D&R Sahidic Wikipedia Arab Mac OSX 0129 // -------------- --------------- -------------- -------------- -------------- 0130 // * Thoout Thout Thoout Tout Tout 0131 // * Paope Paopi Paope Baba Baba 0132 // * Hathor Hathor Athōr Hatour Hatour 0133 // * Kiahk Koiak Koiak Kiahk Kiahk 0134 // * Tobe Tobi Tōbe Touba Toba 0135 // * Meshir Meshir Meshir Amshir Amshir 0136 // * Paremhotep Paremhat Paremotep Baramhat Baramhat 0137 // * Parmoute Paremoude Paremoute Baramouda Baramouda 0138 // * Pashons Pashons Pashons Bashans Bashans 0139 // * Paone Paoni Paōne Ba'ouna Paona 0140 // * Epep Epip Epēp Abib Epep 0141 // * Mesore Mesori Mesorē Mesra Mesra 0142 // * Kouji nabot Pi Kogi Enavot Epagomenē Nasie 0143 // * 0144 QString KCalendarSystemCopticPrivate::monthName(int month, int year, KLocale::DateTimeComponentFormat format, bool possessive) const 0145 { 0146 Q_UNUSED(year); 0147 0148 QStringList languages = locale()->languageList(); 0149 0150 if (format == KLocale::NarrowName) { 0151 switch (month) { 0152 case 1: 0153 return ki18nc("Coptic month 1 - KLocale::NarrowName", "T").toString(languages); 0154 case 2: 0155 return ki18nc("Coptic month 2 - KLocale::NarrowName", "P").toString(languages); 0156 case 3: 0157 return ki18nc("Coptic month 3 - KLocale::NarrowName", "H").toString(languages); 0158 case 4: 0159 return ki18nc("Coptic month 4 - KLocale::NarrowName", "K").toString(languages); 0160 case 5: 0161 return ki18nc("Coptic month 5 - KLocale::NarrowName", "T").toString(languages); 0162 case 6: 0163 return ki18nc("Coptic month 6 - KLocale::NarrowName", "M").toString(languages); 0164 case 7: 0165 return ki18nc("Coptic month 7 - KLocale::NarrowName", "P").toString(languages); 0166 case 8: 0167 return ki18nc("Coptic month 8 - KLocale::NarrowName", "P").toString(languages); 0168 case 9: 0169 return ki18nc("Coptic month 9 - KLocale::NarrowName", "P").toString(languages); 0170 case 10: 0171 return ki18nc("Coptic month 10 - KLocale::NarrowName", "P").toString(languages); 0172 case 11: 0173 return ki18nc("Coptic month 11 - KLocale::NarrowName", "E").toString(languages); 0174 case 12: 0175 return ki18nc("Coptic month 12 - KLocale::NarrowName", "M").toString(languages); 0176 case 13: 0177 return ki18nc("Coptic month 13 - KLocale::NarrowName", "K").toString(languages); 0178 default: 0179 return QString(); 0180 } 0181 } 0182 0183 if (format == KLocale::ShortName && possessive) { 0184 switch (month) { 0185 case 1: 0186 return ki18nc("Coptic month 1 - KLocale::ShortName Possessive", "of Tho").toString(languages); 0187 case 2: 0188 return ki18nc("Coptic month 2 - KLocale::ShortName Possessive", "of Pao").toString(languages); 0189 case 3: 0190 return ki18nc("Coptic month 3 - KLocale::ShortName Possessive", "of Hat").toString(languages); 0191 case 4: 0192 return ki18nc("Coptic month 4 - KLocale::ShortName Possessive", "of Kia").toString(languages); 0193 case 5: 0194 return ki18nc("Coptic month 5 - KLocale::ShortName Possessive", "of Tob").toString(languages); 0195 case 6: 0196 return ki18nc("Coptic month 6 - KLocale::ShortName Possessive", "of Mes").toString(languages); 0197 case 7: 0198 return ki18nc("Coptic month 7 - KLocale::ShortName Possessive", "of Par").toString(languages); 0199 case 8: 0200 return ki18nc("Coptic month 8 - KLocale::ShortName Possessive", "of Pam").toString(languages); 0201 case 9: 0202 return ki18nc("Coptic month 9 - KLocale::ShortName Possessive", "of Pas").toString(languages); 0203 case 10: 0204 return ki18nc("Coptic month 10 - KLocale::ShortName Possessive", "of Pan").toString(languages); 0205 case 11: 0206 return ki18nc("Coptic month 11 - KLocale::ShortName Possessive", "of Epe").toString(languages); 0207 case 12: 0208 return ki18nc("Coptic month 12 - KLocale::ShortName Possessive", "of Meo").toString(languages); 0209 case 13: 0210 return ki18nc("Coptic month 13 - KLocale::ShortName Possessive", "of Kou").toString(languages); 0211 default: 0212 return QString(); 0213 } 0214 } 0215 0216 if (format == KLocale::ShortName && !possessive) { 0217 switch (month) { 0218 case 1: 0219 return ki18nc("Coptic month 1 - KLocale::ShortName", "Tho").toString(languages); 0220 case 2: 0221 return ki18nc("Coptic month 2 - KLocale::ShortName", "Pao").toString(languages); 0222 case 3: 0223 return ki18nc("Coptic month 3 - KLocale::ShortName", "Hat").toString(languages); 0224 case 4: 0225 return ki18nc("Coptic month 4 - KLocale::ShortName", "Kia").toString(languages); 0226 case 5: 0227 return ki18nc("Coptic month 5 - KLocale::ShortName", "Tob").toString(languages); 0228 case 6: 0229 return ki18nc("Coptic month 6 - KLocale::ShortName", "Mes").toString(languages); 0230 case 7: 0231 return ki18nc("Coptic month 7 - KLocale::ShortName", "Par").toString(languages); 0232 case 8: 0233 return ki18nc("Coptic month 8 - KLocale::ShortName", "Pam").toString(languages); 0234 case 9: 0235 return ki18nc("Coptic month 9 - KLocale::ShortName", "Pas").toString(languages); 0236 case 10: 0237 return ki18nc("Coptic month 10 - KLocale::ShortName", "Pan").toString(languages); 0238 case 11: 0239 return ki18nc("Coptic month 11 - KLocale::ShortName", "Epe").toString(languages); 0240 case 12: 0241 return ki18nc("Coptic month 12 - KLocale::ShortName", "Meo").toString(languages); 0242 case 13: 0243 return ki18nc("Coptic month 12 - KLocale::ShortName", "Kou").toString(languages); 0244 default: 0245 return QString(); 0246 } 0247 } 0248 0249 if (format == KLocale::LongName && possessive) { 0250 switch (month) { 0251 case 1: 0252 return ki18nc("Coptic month 1 - KLocale::LongName Possessive", "of Thoout").toString(languages); 0253 case 2: 0254 return ki18nc("Coptic month 2 - KLocale::LongName Possessive", "of Paope").toString(languages); 0255 case 3: 0256 return ki18nc("Coptic month 3 - KLocale::LongName Possessive", "of Hathor").toString(languages); 0257 case 4: 0258 return ki18nc("Coptic month 4 - KLocale::LongName Possessive", "of Kiahk").toString(languages); 0259 case 5: 0260 return ki18nc("Coptic month 5 - KLocale::LongName Possessive", "of Tobe").toString(languages); 0261 case 6: 0262 return ki18nc("Coptic month 6 - KLocale::LongName Possessive", "of Meshir").toString(languages); 0263 case 7: 0264 return ki18nc("Coptic month 7 - KLocale::LongName Possessive", "of Paremhotep").toString(languages); 0265 case 8: 0266 return ki18nc("Coptic month 8 - KLocale::LongName Possessive", "of Parmoute").toString(languages); 0267 case 9: 0268 return ki18nc("Coptic month 9 - KLocale::LongName Possessive", "of Pashons").toString(languages); 0269 case 10: 0270 return ki18nc("Coptic month 10 - KLocale::LongName Possessive", "of Paone").toString(languages); 0271 case 11: 0272 return ki18nc("Coptic month 11 - KLocale::LongName Possessive", "of Epep").toString(languages); 0273 case 12: 0274 return ki18nc("Coptic month 12 - KLocale::LongName Possessive", "of Mesore").toString(languages); 0275 case 13: 0276 return ki18nc("Coptic month 12 - KLocale::LongName Possessive", "of Kouji nabot").toString(languages); 0277 default: 0278 return QString(); 0279 } 0280 } 0281 0282 // Default to LongName 0283 switch (month) { 0284 case 1: 0285 return ki18nc("Coptic month 1 - KLocale::LongName", "Thoout").toString(languages); 0286 case 2: 0287 return ki18nc("Coptic month 2 - KLocale::LongName", "Paope").toString(languages); 0288 case 3: 0289 return ki18nc("Coptic month 3 - KLocale::LongName", "Hathor").toString(languages); 0290 case 4: 0291 return ki18nc("Coptic month 4 - KLocale::LongName", "Kiahk").toString(languages); 0292 case 5: 0293 return ki18nc("Coptic month 5 - KLocale::LongName", "Tobe").toString(languages); 0294 case 6: 0295 return ki18nc("Coptic month 6 - KLocale::LongName", "Meshir").toString(languages); 0296 case 7: 0297 return ki18nc("Coptic month 7 - KLocale::LongName", "Paremhotep").toString(languages); 0298 case 8: 0299 return ki18nc("Coptic month 8 - KLocale::LongName", "Parmoute").toString(languages); 0300 case 9: 0301 return ki18nc("Coptic month 9 - KLocale::LongName", "Pashons").toString(languages); 0302 case 10: 0303 return ki18nc("Coptic month 10 - KLocale::LongName", "Paone").toString(languages); 0304 case 11: 0305 return ki18nc("Coptic month 11 - KLocale::LongName", "Epep").toString(languages); 0306 case 12: 0307 return ki18nc("Coptic month 12 - KLocale::LongName", "Mesore").toString(languages); 0308 case 13: 0309 return ki18nc("Coptic month 12 - KLocale::LongName", "Kouji nabot").toString(languages); 0310 default: 0311 return QString(); 0312 } 0313 } 0314 0315 // Names taken from from the Sahidic dialect transliterations used in Dershowitz & Reingold which went out of use in the 11th centuary 0316 // Boharic or Arabic transliterations would be preferred but none could be found 0317 QString KCalendarSystemCopticPrivate::weekDayName(int weekDay, KLocale::DateTimeComponentFormat format) const 0318 { 0319 QStringList languages = locale()->languageList(); 0320 0321 if (format == KLocale::NarrowName) { 0322 switch (weekDay) { 0323 case 1: 0324 return ki18nc("Coptic weekday 1 - KLocale::NarrowName", "P").toString(languages); 0325 case 2: 0326 return ki18nc("Coptic weekday 2 - KLocale::NarrowName", "P").toString(languages); 0327 case 3: 0328 return ki18nc("Coptic weekday 3 - KLocale::NarrowName", "P").toString(languages); 0329 case 4: 0330 return ki18nc("Coptic weekday 4 - KLocale::NarrowName", "P").toString(languages); 0331 case 5: 0332 return ki18nc("Coptic weekday 5 - KLocale::NarrowName", "P").toString(languages); 0333 case 6: 0334 return ki18nc("Coptic weekday 6 - KLocale::NarrowName", "P").toString(languages); 0335 case 7: 0336 return ki18nc("Coptic weekday 7 - KLocale::NarrowName", "T").toString(languages); 0337 default: 0338 return QString(); 0339 } 0340 } 0341 0342 if (format == KLocale::ShortName || format == KLocale:: ShortNumber) { 0343 switch (weekDay) { 0344 case 1: 0345 return ki18nc("Coptic weekday 1 - KLocale::ShortName", "Pes").toString(languages); 0346 case 2: 0347 return ki18nc("Coptic weekday 2 - KLocale::ShortName", "Psh").toString(languages); 0348 case 3: 0349 return ki18nc("Coptic weekday 3 - KLocale::ShortName", "Pef").toString(languages); 0350 case 4: 0351 return ki18nc("Coptic weekday 4 - KLocale::ShortName", "Pti").toString(languages); 0352 case 5: 0353 return ki18nc("Coptic weekday 5 - KLocale::ShortName", "Pso").toString(languages); 0354 case 6: 0355 return ki18nc("Coptic weekday 6 - KLocale::ShortName", "Psa").toString(languages); 0356 case 7: 0357 return ki18nc("Coptic weekday 7 - KLocale::ShortName", "Tky").toString(languages); 0358 default: 0359 return QString(); 0360 } 0361 } 0362 0363 switch (weekDay) { 0364 case 1: 0365 return ki18nc("Coptic weekday 1 - KLocale::LongName", "Pesnau").toString(languages); 0366 case 2: 0367 return ki18nc("Coptic weekday 2 - KLocale::LongName", "Pshoment").toString(languages); 0368 case 3: 0369 return ki18nc("Coptic weekday 3 - KLocale::LongName", "Peftoou").toString(languages); 0370 case 4: 0371 return ki18nc("Coptic weekday 4 - KLocale::LongName", "Ptiou").toString(languages); 0372 case 5: 0373 return ki18nc("Coptic weekday 5 - KLocale::LongName", "Psoou").toString(languages); 0374 case 6: 0375 return ki18nc("Coptic weekday 6 - KLocale::LongName", "Psabbaton").toString(languages); 0376 case 7: 0377 return ki18nc("Coptic weekday 7 - KLocale::LongName", "Tkyriakē").toString(languages); 0378 default: 0379 return QString(); 0380 } 0381 } 0382 0383 KCalendarSystemCoptic::KCalendarSystemCoptic(const KSharedConfig::Ptr config, const KLocale *locale) 0384 : KCalendarSystem(*new KCalendarSystemCopticPrivate(this), config, locale) 0385 { 0386 d_ptr->loadConfig(calendarType()); 0387 } 0388 0389 KCalendarSystemCoptic::KCalendarSystemCoptic(KCalendarSystemCopticPrivate &dd, 0390 const KSharedConfig::Ptr config, const KLocale *locale) 0391 : KCalendarSystem(dd, config, locale) 0392 { 0393 d_ptr->loadConfig(calendarType()); 0394 } 0395 0396 KCalendarSystemCoptic::~KCalendarSystemCoptic() 0397 { 0398 } 0399 0400 QString KCalendarSystemCoptic::calendarType() const 0401 { 0402 return QLatin1String("coptic"); 0403 } 0404 0405 KLocale::CalendarSystem KCalendarSystemCoptic::calendarSystem() const 0406 { 0407 return KLocale::CopticCalendar; 0408 } 0409 0410 QDate KCalendarSystemCoptic::epoch() const 0411 { 0412 //0001-01-01, no Year 0. 0413 //0284-08-29 AD Julian 0414 return QDate::fromJulianDay(1825030); 0415 } 0416 0417 QDate KCalendarSystemCoptic::earliestValidDate() const 0418 { 0419 //0001-01-01, no Year 0. 0420 //0284-08-29 AD Julian 0421 return QDate::fromJulianDay(1825030); 0422 } 0423 0424 QDate KCalendarSystemCoptic::latestValidDate() const 0425 { 0426 // Set to last day of year 9999 until confirm date formats & widgets support > 9999 0427 //9999-12-30 0428 //10283-08-29 AD Julian 0429 return QDate::fromJulianDay(5477164); 0430 } 0431 0432 QString KCalendarSystemCoptic::monthName(int month, int year, MonthNameFormat format) const 0433 { 0434 return KCalendarSystem::monthName(month, year, format); 0435 } 0436 0437 QString KCalendarSystemCoptic::monthName(const QDate &date, MonthNameFormat format) const 0438 { 0439 return KCalendarSystem::monthName(date, format); 0440 } 0441 0442 QString KCalendarSystemCoptic::weekDayName(int weekDay, WeekDayNameFormat format) const 0443 { 0444 return KCalendarSystem::weekDayName(weekDay, format); 0445 } 0446 0447 QString KCalendarSystemCoptic::weekDayName(const QDate &date, WeekDayNameFormat format) const 0448 { 0449 return KCalendarSystem::weekDayName(date, format); 0450 } 0451 0452 bool KCalendarSystemCoptic::isLunar() const 0453 { 0454 return false; 0455 } 0456 0457 bool KCalendarSystemCoptic::isLunisolar() const 0458 { 0459 return false; 0460 } 0461 0462 bool KCalendarSystemCoptic::isSolar() const 0463 { 0464 return true; 0465 } 0466 0467 bool KCalendarSystemCoptic::isProleptic() const 0468 { 0469 return false; 0470 } 0471 0472 bool KCalendarSystemCoptic::julianDayToDate(qint64 jd, int &year, int &month, int &day) const 0473 { 0474 //The Coptic calendar has 12 months of 30 days, a 13th month of 5 or 6 days, 0475 //and a leap year every 4th year without fail that falls on the last day of 0476 //the year, starting from year 3. 0477 0478 //Use a fake year 0 for our epoch instead of the real epoch in year 1. This is because year 3 0479 //is the first leap year and a pattern of 365/365/366/365 is hard to calculate, instead a 0480 //pattern of 365/365/365/366 with the leap day the very last day makes the maths easier. 0481 0482 //Day number in the fake epoch, 0 indexed 0483 int dayInEpoch = jd - (epoch().toJulianDay() - 365); 0484 //How many full 4 year leap cycles have been completed, 1461 = (365*3)+366 0485 int leapCyclesCompleted = dayInEpoch / 1461; 0486 //Which year are we in the current 4 year leap cycle, 0 indexed 0487 //Need the qMin as day 366 of 4th year of cycle returns following year (max 3 as 0 index) 0488 int yearInCurrentLeapCycle = qMin(3, (dayInEpoch % 1461) / 365); 0489 //Calculate the year 0490 year = (leapCyclesCompleted * 4) + yearInCurrentLeapCycle; 0491 //Days since the fake epoch up to 1st day of this year 0492 int daysBeforeThisYear = (year * 365) + (year / 4); 0493 //Gives the day number in this year, 0 indexed 0494 int dayOfThisYear = dayInEpoch - daysBeforeThisYear; 0495 //Then just calculate month and day from that based on regular 30 day months 0496 month = ((dayOfThisYear) / 30) + 1; 0497 day = dayOfThisYear - ((month - 1) * 30) + 1; 0498 0499 // If year is -ve then is BC. In Coptic there is no year 0, but the maths 0500 // is easier if we pretend there is, so internally year of 0 = 1BC = -1 outside 0501 if (year < 1) { 0502 year = year - 1; 0503 } 0504 0505 return true; 0506 } 0507 0508 bool KCalendarSystemCoptic::dateToJulianDay(int year, int month, int day, qint64 &jd) const 0509 { 0510 //The Coptic calendar has 12 months of 30 days, a 13th month of 5 or 6 days, 0511 //and a leap year every 4th year without fail that falls on the last day of 0512 //the year, starting from year 3. This simple repeating pattern makes calculating 0513 // a jd the simple process taking the epoch jd and adding on the years months and 0514 //days required. 0515 0516 // If year is -ve then is 'BC'. In Coptic there is no year 0, but the maths 0517 // is easier if we pretend there is, so internally year of -1 = 1BC = 0 internally 0518 int y; 0519 if (year < 1) { 0520 y = year + 1; 0521 } else { 0522 y = year; 0523 } 0524 0525 jd = epoch().toJulianDay() - 1 // jd of day before Epoch 0526 + ((y - 1) * 365) // Add all normal days in years preceding 0527 + (y / 4) // Add all leap days in years preceding 0528 + ((month - 1) * 30) // Add days this year in months preceding 0529 + day; // Add days in this month 0530 0531 return true; 0532 }