File indexing completed on 2024-04-21 14:55:29

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 "kcalendarsystemjulian_p.h"
0021 #include "kcalendarsystemprivate_p.h"
0022 
0023 #include "klocale.h"
0024 #include "klocalizedstring.h"
0025 #include "kconfiggroup.h"
0026 
0027 #include <QDate>
0028 #include <QCharRef>
0029 
0030 class KCalendarSystemJulianPrivate : public KCalendarSystemPrivate
0031 {
0032 public:
0033     KDELIBS4SUPPORT_DEPRECATED explicit KCalendarSystemJulianPrivate(KCalendarSystemJulian *q);
0034 
0035     ~KCalendarSystemJulianPrivate() override;
0036 
0037     // Virtual methods each calendar system must re-implement
0038     void loadDefaultEraList() override;
0039     int monthsInYear(int year) const override;
0040     int daysInMonth(int year, int month) const override;
0041     int daysInYear(int year) const override;
0042     bool isLeapYear(int year) const override;
0043     bool hasLeapMonths() const override;
0044     bool hasYearZero() const override;
0045     int maxMonthsInYear() const override;
0046     int earliestValidYear() const override;
0047     int latestValidYear() const override;
0048     QString monthName(int month, int year, KLocale::DateTimeComponentFormat format, bool possessive) const override;
0049     QString weekDayName(int weekDay, KLocale::DateTimeComponentFormat format) const override;
0050 
0051     bool m_useCommonEra;
0052 };
0053 
0054 // Shared d pointer base class definitions
0055 
0056 KCalendarSystemJulianPrivate::KCalendarSystemJulianPrivate(KCalendarSystemJulian *q)
0057     : KCalendarSystemPrivate(q)
0058 {
0059 }
0060 
0061 KCalendarSystemJulianPrivate::~KCalendarSystemJulianPrivate()
0062 {
0063 }
0064 
0065 void KCalendarSystemJulianPrivate::loadDefaultEraList()
0066 {
0067     QString name, shortName, format;
0068 
0069     KConfigGroup cg(config(), QString::fromLatin1("KCalendarSystem %1").arg(q->calendarType()));
0070     m_useCommonEra = cg.readEntry("UseCommonEra", false);
0071 
0072     if (m_useCommonEra) {
0073         name = i18nc("Calendar Era: Julian Common Era, years < 0, LongFormat", "Before Common Era");
0074         shortName = i18nc("Calendar Era: Julian Common Era, years < 0, ShortFormat", "BCE");
0075     } else {
0076         name = i18nc("Calendar Era: Julian Christian Era, years < 0, LongFormat", "Before Christ");
0077         shortName = i18nc("Calendar Era: Julian Christian Era, years < 0, ShortFormat", "BC");
0078     }
0079     format = i18nc("(kdedt-format) Julian, BC, full era year format used for %EY, e.g. 2000 BC", "%Ey %EC");
0080     addEra('-', 1, q->epoch().addDays(-1), -1, q->earliestValidDate(), name, shortName, format);
0081 
0082     if (m_useCommonEra) {
0083         name = i18nc("Calendar Era: Julian Common Era, years > 0, LongFormat", "Common Era");
0084         shortName = i18nc("Calendar Era: Julian Common Era, years > 0, ShortFormat", "CE");
0085     } else {
0086         name = i18nc("Calendar Era: Julian Christian Era, years > 0, LongFormat", "Anno Domini");
0087         shortName = i18nc("Calendar Era: Julian Christian Era, years > 0, ShortFormat", "AD");
0088     }
0089     format = i18nc("(kdedt-format) Julian, AD, full era year format used for %EY, e.g. 2000 AD", "%Ey %EC");
0090     addEra('+', 1, q->epoch(), 1, q->latestValidDate(), name, shortName, format);
0091 }
0092 
0093 int KCalendarSystemJulianPrivate::monthsInYear(int year) const
0094 {
0095     Q_UNUSED(year)
0096     return 12;
0097 }
0098 
0099 int KCalendarSystemJulianPrivate::daysInMonth(int year, int month) const
0100 {
0101     if (month == 2) {
0102         if (isLeapYear(year)) {
0103             return 29;
0104         } else {
0105             return 28;
0106         }
0107     }
0108 
0109     if (month == 4 || month == 6 || month == 9 || month == 11) {
0110         return 30;
0111     }
0112 
0113     return 31;
0114 }
0115 
0116 int KCalendarSystemJulianPrivate::daysInYear(int year) const
0117 {
0118     if (isLeapYear(year)) {
0119         return 366;
0120     } else {
0121         return 365;
0122     }
0123 }
0124 
0125 bool KCalendarSystemJulianPrivate::isLeapYear(int year) const
0126 {
0127     if (year < 1) {
0128         year = year + 1;
0129     }
0130 
0131     if (year % 4 == 0) {
0132         return true;
0133     }
0134 
0135     return false;
0136 }
0137 
0138 bool KCalendarSystemJulianPrivate::hasLeapMonths() const
0139 {
0140     return false;
0141 }
0142 
0143 bool KCalendarSystemJulianPrivate::hasYearZero() const
0144 {
0145     return false;
0146 }
0147 
0148 int KCalendarSystemJulianPrivate::maxMonthsInYear() const
0149 {
0150     return 12;
0151 }
0152 
0153 int KCalendarSystemJulianPrivate::earliestValidYear() const
0154 {
0155     return -4712;
0156 }
0157 
0158 int KCalendarSystemJulianPrivate::latestValidYear() const
0159 {
0160     return 9999;
0161 }
0162 
0163 QString KCalendarSystemJulianPrivate::monthName(int month, int year, KLocale::DateTimeComponentFormat format, bool possessive) const
0164 {
0165     Q_UNUSED(year);
0166 
0167     QStringList languages = locale()->languageList();
0168 
0169     if (format == KLocale::NarrowName) {
0170         switch (month) {
0171         case 1:
0172             return ki18nc("Julian month 1 - KLocale::NarrowName",  "J").toString(languages);
0173         case 2:
0174             return ki18nc("Julian month 2 - KLocale::NarrowName",  "F").toString(languages);
0175         case 3:
0176             return ki18nc("Julian month 3 - KLocale::NarrowName",  "M").toString(languages);
0177         case 4:
0178             return ki18nc("Julian month 4 - KLocale::NarrowName",  "A").toString(languages);
0179         case 5:
0180             return ki18nc("Julian month 5 - KLocale::NarrowName",  "M").toString(languages);
0181         case 6:
0182             return ki18nc("Julian month 6 - KLocale::NarrowName",  "J").toString(languages);
0183         case 7:
0184             return ki18nc("Julian month 7 - KLocale::NarrowName",  "J").toString(languages);
0185         case 8:
0186             return ki18nc("Julian month 8 - KLocale::NarrowName",  "A").toString(languages);
0187         case 9:
0188             return ki18nc("Julian month 9 - KLocale::NarrowName",  "S").toString(languages);
0189         case 10:
0190             return ki18nc("Julian month 10 - KLocale::NarrowName", "O").toString(languages);
0191         case 11:
0192             return ki18nc("Julian month 11 - KLocale::NarrowName", "N").toString(languages);
0193         case 12:
0194             return ki18nc("Julian month 12 - KLocale::NarrowName", "D").toString(languages);
0195         default:
0196             return QString();
0197         }
0198     }
0199 
0200     if (format == KLocale::ShortName && possessive) {
0201         switch (month) {
0202         case 1:
0203             return ki18nc("Julian month 1 - KLocale::ShortName Possessive",  "of Jan").toString(languages);
0204         case 2:
0205             return ki18nc("Julian month 2 - KLocale::ShortName Possessive",  "of Feb").toString(languages);
0206         case 3:
0207             return ki18nc("Julian month 3 - KLocale::ShortName Possessive",  "of Mar").toString(languages);
0208         case 4:
0209             return ki18nc("Julian month 4 - KLocale::ShortName Possessive",  "of Apr").toString(languages);
0210         case 5:
0211             return ki18nc("Julian month 5 - KLocale::ShortName Possessive",  "of May").toString(languages);
0212         case 6:
0213             return ki18nc("Julian month 6 - KLocale::ShortName Possessive",  "of Jun").toString(languages);
0214         case 7:
0215             return ki18nc("Julian month 7 - KLocale::ShortName Possessive",  "of Jul").toString(languages);
0216         case 8:
0217             return ki18nc("Julian month 8 - KLocale::ShortName Possessive",  "of Aug").toString(languages);
0218         case 9:
0219             return ki18nc("Julian month 9 - KLocale::ShortName Possessive",  "of Sep").toString(languages);
0220         case 10:
0221             return ki18nc("Julian month 10 - KLocale::ShortName Possessive", "of Oct").toString(languages);
0222         case 11:
0223             return ki18nc("Julian month 11 - KLocale::ShortName Possessive", "of Nov").toString(languages);
0224         case 12:
0225             return ki18nc("Julian month 12 - KLocale::ShortName Possessive", "of Dec").toString(languages);
0226         default:
0227             return QString();
0228         }
0229     }
0230 
0231     if (format == KLocale::ShortName && !possessive) {
0232         switch (month) {
0233         case 1:
0234             return ki18nc("Julian month 1 - KLocale::ShortName",  "Jan").toString(languages);
0235         case 2:
0236             return ki18nc("Julian month 2 - KLocale::ShortName",  "Feb").toString(languages);
0237         case 3:
0238             return ki18nc("Julian month 3 - KLocale::ShortName",  "Mar").toString(languages);
0239         case 4:
0240             return ki18nc("Julian month 4 - KLocale::ShortName",  "Apr").toString(languages);
0241         case 5:
0242             return ki18nc("Julian month 5 - KLocale::ShortName",  "May").toString(languages);
0243         case 6:
0244             return ki18nc("Julian month 6 - KLocale::ShortName",  "Jun").toString(languages);
0245         case 7:
0246             return ki18nc("Julian month 7 - KLocale::ShortName",  "Jul").toString(languages);
0247         case 8:
0248             return ki18nc("Julian month 8 - KLocale::ShortName",  "Aug").toString(languages);
0249         case 9:
0250             return ki18nc("Julian month 9 - KLocale::ShortName",  "Sep").toString(languages);
0251         case 10:
0252             return ki18nc("Julian month 10 - KLocale::ShortName", "Oct").toString(languages);
0253         case 11:
0254             return ki18nc("Julian month 11 - KLocale::ShortName", "Nov").toString(languages);
0255         case 12:
0256             return ki18nc("Julian month 12 - KLocale::ShortName", "Dec").toString(languages);
0257         default:
0258             return QString();
0259         }
0260     }
0261 
0262     if (format == KLocale::LongName && possessive) {
0263         switch (month) {
0264         case 1:
0265             return ki18nc("Julian month 1 - KLocale::LongName Possessive",  "of January").toString(languages);
0266         case 2:
0267             return ki18nc("Julian month 2 - KLocale::LongName Possessive",  "of February").toString(languages);
0268         case 3:
0269             return ki18nc("Julian month 3 - KLocale::LongName Possessive",  "of March").toString(languages);
0270         case 4:
0271             return ki18nc("Julian month 4 - KLocale::LongName Possessive",  "of April").toString(languages);
0272         case 5:
0273             return ki18nc("Julian month 5 - KLocale::LongName Possessive",  "of May").toString(languages);
0274         case 6:
0275             return ki18nc("Julian month 6 - KLocale::LongName Possessive",  "of June").toString(languages);
0276         case 7:
0277             return ki18nc("Julian month 7 - KLocale::LongName Possessive",  "of July").toString(languages);
0278         case 8:
0279             return ki18nc("Julian month 8 - KLocale::LongName Possessive",  "of August").toString(languages);
0280         case 9:
0281             return ki18nc("Julian month 9 - KLocale::LongName Possessive",  "of September").toString(languages);
0282         case 10:
0283             return ki18nc("Julian month 10 - KLocale::LongName Possessive", "of October").toString(languages);
0284         case 11:
0285             return ki18nc("Julian month 11 - KLocale::LongName Possessive", "of November").toString(languages);
0286         case 12:
0287             return ki18nc("Julian month 12 - KLocale::LongName Possessive", "of December").toString(languages);
0288         default:
0289             return QString();
0290         }
0291     }
0292 
0293     // Default to LongName
0294     switch (month) {
0295     case 1:
0296         return ki18nc("Julian month 1 - KLocale::LongName",  "January").toString(languages);
0297     case 2:
0298         return ki18nc("Julian month 2 - KLocale::LongName",  "February").toString(languages);
0299     case 3:
0300         return ki18nc("Julian month 3 - KLocale::LongName",  "March").toString(languages);
0301     case 4:
0302         return ki18nc("Julian month 4 - KLocale::LongName",  "April").toString(languages);
0303     case 5:
0304         return ki18nc("Julian month 5 - KLocale::LongName",  "May").toString(languages);
0305     case 6:
0306         return ki18nc("Julian month 6 - KLocale::LongName",  "June").toString(languages);
0307     case 7:
0308         return ki18nc("Julian month 7 - KLocale::LongName",  "July").toString(languages);
0309     case 8:
0310         return ki18nc("Julian month 8 - KLocale::LongName",  "August").toString(languages);
0311     case 9:
0312         return ki18nc("Julian month 9 - KLocale::LongName",  "September").toString(languages);
0313     case 10:
0314         return ki18nc("Julian month 10 - KLocale::LongName", "October").toString(languages);
0315     case 11:
0316         return ki18nc("Julian month 11 - KLocale::LongName", "November").toString(languages);
0317     case 12:
0318         return ki18nc("Julian month 12 - KLocale::LongName", "December").toString(languages);
0319     default:
0320         return QString();
0321     }
0322 }
0323 
0324 QString KCalendarSystemJulianPrivate::weekDayName(int weekDay, KLocale::DateTimeComponentFormat format) const
0325 {
0326     QStringList languages = locale()->languageList();
0327 
0328     if (format == KLocale::NarrowName) {
0329         switch (weekDay) {
0330         case 1:
0331             return ki18nc("Julian weekday 1 - KLocale::NarrowName ", "M").toString(languages);
0332         case 2:
0333             return ki18nc("Julian weekday 2 - KLocale::NarrowName ", "T").toString(languages);
0334         case 3:
0335             return ki18nc("Julian weekday 3 - KLocale::NarrowName ", "W").toString(languages);
0336         case 4:
0337             return ki18nc("Julian weekday 4 - KLocale::NarrowName ", "T").toString(languages);
0338         case 5:
0339             return ki18nc("Julian weekday 5 - KLocale::NarrowName ", "F").toString(languages);
0340         case 6:
0341             return ki18nc("Julian weekday 6 - KLocale::NarrowName ", "S").toString(languages);
0342         case 7:
0343             return ki18nc("Julian weekday 7 - KLocale::NarrowName ", "S").toString(languages);
0344         default:
0345             return QString();
0346         }
0347     }
0348 
0349     if (format == KLocale::ShortName  || format == KLocale:: ShortNumber) {
0350         switch (weekDay) {
0351         case 1:
0352             return ki18nc("Julian weekday 1 - KLocale::ShortName", "Mon").toString(languages);
0353         case 2:
0354             return ki18nc("Julian weekday 2 - KLocale::ShortName", "Tue").toString(languages);
0355         case 3:
0356             return ki18nc("Julian weekday 3 - KLocale::ShortName", "Wed").toString(languages);
0357         case 4:
0358             return ki18nc("Julian weekday 4 - KLocale::ShortName", "Thu").toString(languages);
0359         case 5:
0360             return ki18nc("Julian weekday 5 - KLocale::ShortName", "Fri").toString(languages);
0361         case 6:
0362             return ki18nc("Julian weekday 6 - KLocale::ShortName", "Sat").toString(languages);
0363         case 7:
0364             return ki18nc("Julian weekday 7 - KLocale::ShortName", "Sun").toString(languages);
0365         default: return QString();
0366         }
0367     }
0368 
0369     switch (weekDay) {
0370     case 1:
0371         return ki18nc("Julian weekday 1 - KLocale::LongName", "Monday").toString(languages);
0372     case 2:
0373         return ki18nc("Julian weekday 2 - KLocale::LongName", "Tuesday").toString(languages);
0374     case 3:
0375         return ki18nc("Julian weekday 3 - KLocale::LongName", "Wednesday").toString(languages);
0376     case 4:
0377         return ki18nc("Julian weekday 4 - KLocale::LongName", "Thursday").toString(languages);
0378     case 5:
0379         return ki18nc("Julian weekday 5 - KLocale::LongName", "Friday").toString(languages);
0380     case 6:
0381         return ki18nc("Julian weekday 6 - KLocale::LongName", "Saturday").toString(languages);
0382     case 7:
0383         return ki18nc("Julian weekday 7 - KLocale::LongName", "Sunday").toString(languages);
0384     default:
0385         return QString();
0386     }
0387 }
0388 
0389 KCalendarSystemJulian::KCalendarSystemJulian(const KSharedConfig::Ptr config, const KLocale *locale)
0390     : KCalendarSystem(*new KCalendarSystemJulianPrivate(this), config, locale)
0391 {
0392     d_ptr->loadConfig(calendarType());
0393 }
0394 
0395 KCalendarSystemJulian::KCalendarSystemJulian(KCalendarSystemJulianPrivate &dd,
0396         const KSharedConfig::Ptr config, const KLocale *locale)
0397     : KCalendarSystem(dd, config, locale)
0398 {
0399     d_ptr->loadConfig(calendarType());
0400 }
0401 
0402 KCalendarSystemJulian::~KCalendarSystemJulian()
0403 {
0404 }
0405 
0406 QString KCalendarSystemJulian::calendarType() const
0407 {
0408     return QLatin1String("julian");
0409 }
0410 
0411 KLocale::CalendarSystem KCalendarSystemJulian::calendarSystem() const
0412 {
0413     return KLocale::JulianCalendar;
0414 }
0415 
0416 QDate KCalendarSystemJulian::epoch() const
0417 {
0418     return QDate::fromJulianDay(1721426);
0419 }
0420 
0421 QDate KCalendarSystemJulian::earliestValidDate() const
0422 {
0423     // 1 Jan 4712 BC, no year zero, cant be 4713BC due to error in QDate that day 0 is not valid
0424     // and we really need the first in each year to be valid for the date maths
0425     return QDate::fromJulianDay(366);
0426 }
0427 
0428 QDate KCalendarSystemJulian::latestValidDate() const
0429 {
0430     // Set to last day of year 9999 until confirm date formats & widgets support > 9999
0431     // 31 Dec 9999 AD, no year zero
0432     return QDate::fromJulianDay(5373557);
0433 }
0434 
0435 QString KCalendarSystemJulian::monthName(int month, int year, MonthNameFormat format) const
0436 {
0437     return KCalendarSystem::monthName(month, year, format);
0438 }
0439 
0440 QString KCalendarSystemJulian::monthName(const QDate &date, MonthNameFormat format) const
0441 {
0442     return KCalendarSystem::monthName(date, format);
0443 }
0444 
0445 QString KCalendarSystemJulian::weekDayName(int weekDay, WeekDayNameFormat format) const
0446 {
0447     return KCalendarSystem::weekDayName(weekDay, format);
0448 }
0449 
0450 QString KCalendarSystemJulian::weekDayName(const QDate &date, WeekDayNameFormat format) const
0451 {
0452     return KCalendarSystem::weekDayName(date, format);
0453 }
0454 
0455 bool KCalendarSystemJulian::isLunar() const
0456 {
0457     return false;
0458 }
0459 
0460 bool KCalendarSystemJulian::isLunisolar() const
0461 {
0462     return false;
0463 }
0464 
0465 bool KCalendarSystemJulian::isSolar() const
0466 {
0467     return true;
0468 }
0469 
0470 bool KCalendarSystemJulian::isProleptic() const
0471 {
0472     return true;
0473 }
0474 
0475 bool KCalendarSystemJulian::julianDayToDate(qint64 jd, int &year, int &month, int &day) const
0476 {
0477     // Formula from The Calendar FAQ by Claus Tondering
0478     // http://www.tondering.dk/claus/cal/node3.html#SECTION003161000000000000000
0479     // NOTE: Coded from scratch from mathematical formulas, not copied from
0480     // the Boost licensed source code
0481 
0482     int b = 0;
0483     int c = jd + 32082;
0484     int d = ((4 * c) + 3) / 1461;
0485     int e = c - ((1461 * d) / 4);
0486     int m = ((5 * e) + 2) / 153;
0487     day = e - (((153 * m) + 2) / 5) + 1;
0488     month = m + 3 - (12 * (m / 10));
0489     year = (100 * b) + d - 4800 + (m / 10);
0490 
0491     // If year is -ve then is BC.  In Julian there is no year 0, but the maths
0492     // is easier if we pretend there is, so internally year of 0 = 1BC = -1 outside
0493     if (year < 1) {
0494         year = year - 1;
0495     }
0496 
0497     return true;
0498 }
0499 
0500 bool KCalendarSystemJulian::dateToJulianDay(int year, int month, int day, qint64 &jd) const
0501 {
0502     // Formula from The Calendar FAQ by Claus Tondering
0503     // http://www.tondering.dk/claus/cal/node3.html#SECTION003161000000000000000
0504     // NOTE: Coded from scratch from mathematical formulas, not copied from
0505     // the Boost licensed source code
0506 
0507     // If year is -ve then is BC.  In Julian there is no year 0, but the maths
0508     // is easier if we pretend there is, so internally year of -1 = 1BC = 0 internally
0509     int y;
0510     if (year < 1) {
0511         y = year + 1;
0512     } else {
0513         y = year;
0514     }
0515 
0516     int a = (14 - month) / 12;
0517     y = y + 4800 - a;
0518     int m = month + (12 * a) - 3;
0519 
0520     jd = day
0521          + (((153 * m) + 2) / 5)
0522          + (365 * y)
0523          + (y / 4)
0524          - 32083;
0525 
0526     return true;
0527 }