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

0001 /*
0002     Copyright (C) 2002-2003 Arash Bijanzadeh  and FarsiKDE Project <www.farsikde.org>
0003     Contact: Arash Bijanzadeh <a.bijanzadeh@linuxiran.org>
0004     Copyright 2007, 2008, 2009, 2010 John Layt <john@layt.net>
0005 
0006     This library is free software; you can redistribute it and/or
0007     modify it under the terms of the GNU Library General Public
0008     License as published by the Free Software Foundation; either
0009     version 2 of the License, or (at your option) any later version.
0010 
0011     This library is distributed in the hope that it will be useful,
0012     but WITHOUT ANY WARRANTY; without even the implied warranty of
0013     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0014     Library General Public License for more details.
0015 
0016     You should have received a copy of the GNU Library General Public License
0017     along with this library; see the file COPYING.LIB.  If not, write to
0018     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0019     Boston, MA 02110-1301, USA.
0020 */
0021 
0022 /*
0023     This is an implementation of the artithmetic Persian calendar using the
0024     Birashk algorithm with adjustments to always be correct in the period 1244
0025     and 1530 (1865 to 2152 Gregorian).
0026 
0027     In future this will be replaced with the correct astronomical calendar.
0028 */
0029 
0030 #include "kcalendarsystemjalali_p.h"
0031 #include "kcalendarsystemprivate_p.h"
0032 
0033 #include <QDate>
0034 
0035 #include <klocalizedstring.h>
0036 
0037 class KCalendarSystemJalaliPrivate : public KCalendarSystemPrivate
0038 {
0039 public:
0040     KDELIBS4SUPPORT_DEPRECATED explicit KCalendarSystemJalaliPrivate(KCalendarSystemJalali *q);
0041 
0042     ~KCalendarSystemJalaliPrivate() override;
0043 
0044     // Virtual methods each calendar system must re-implement
0045     void loadDefaultEraList() override;
0046     int monthsInYear(int year) const override;
0047     int daysInMonth(int year, int month) const override;
0048     int daysInYear(int year) const override;
0049     bool isLeapYear(int year) const override;
0050     bool hasLeapMonths() const override;
0051     bool hasYearZero() const override;
0052     int maxMonthsInYear() const override;
0053     int earliestValidYear() const override;
0054     int latestValidYear() const override;
0055     QString monthName(int month, int year, KLocale::DateTimeComponentFormat format, bool possessive) const override;
0056     QString weekDayName(int weekDay, KLocale::DateTimeComponentFormat format) const override;
0057 };
0058 
0059 // Shared d pointer base class definitions
0060 
0061 KCalendarSystemJalaliPrivate::KCalendarSystemJalaliPrivate(KCalendarSystemJalali *q)
0062     : KCalendarSystemPrivate(q)
0063 {
0064 }
0065 
0066 KCalendarSystemJalaliPrivate::~KCalendarSystemJalaliPrivate()
0067 {
0068 }
0069 
0070 void KCalendarSystemJalaliPrivate::loadDefaultEraList()
0071 {
0072     QString name, shortName, format;
0073     // Islamic Era (Hijri), Anno Persico.
0074     name = i18nc("Calendar Era: Jalali Islamic Era, years > 0, LongFormat", "Anno Persico");
0075     shortName = i18nc("Calendar Era: Jalali Islamic Era, years > 0, ShortFormat", "AP");
0076     format = i18nc("(kdedt-format) Jalali, AP, full era year format used for %EY, e.g. 2000 AP", "%Ey %EC");
0077     addEra('+', 1, q->epoch(), 1, q->latestValidDate(), name, shortName, format);
0078 }
0079 
0080 int KCalendarSystemJalaliPrivate::monthsInYear(int year) const
0081 {
0082     Q_UNUSED(year)
0083     return 12;
0084 }
0085 
0086 int KCalendarSystemJalaliPrivate::daysInMonth(int year, int month) const
0087 {
0088     if (month == 12) {
0089         if (isLeapYear(year)) {
0090             return 30;
0091         } else {
0092             return 29;
0093         }
0094     }
0095 
0096     if (month <= 6) {
0097         return 31;
0098     }
0099 
0100     return 30;
0101 }
0102 
0103 int KCalendarSystemJalaliPrivate::daysInYear(int year) const
0104 {
0105     if (isLeapYear(year)) {
0106         return 366;
0107     } else {
0108         return 365;
0109     }
0110 }
0111 
0112 bool KCalendarSystemJalaliPrivate::isLeapYear(int year) const
0113 {
0114     // From formilab Public Domain code http://www.fourmilab.ch/documents/calendar/
0115     // Use Birashk algorithm as it matches the to/from jd code below
0116 
0117     // Birashk algorithm is incorrect in two years in period AP 1244 to 1531,
0118     // 1403/1404 and 1436/1437, and so catch them here first
0119     if (year == 1403 || year == 1436) {
0120         return true;
0121     } else if (year == 1404 || year == 1437) {
0122         return false;
0123     }
0124 
0125     if (year >= 0) {
0126         year = year - 474;
0127     } else {
0128         year = year - 473;
0129     }
0130 
0131     if ((((((year % 2820) + 474) + 38) * 682) % 2816) < 682) {
0132         return true;
0133     } else {
0134         return false;
0135     }
0136 }
0137 
0138 bool KCalendarSystemJalaliPrivate::hasLeapMonths() const
0139 {
0140     return false;
0141 }
0142 
0143 bool KCalendarSystemJalaliPrivate::hasYearZero() const
0144 {
0145     return false;
0146 }
0147 
0148 int KCalendarSystemJalaliPrivate::maxMonthsInYear() const
0149 {
0150     return 12;
0151 }
0152 
0153 int KCalendarSystemJalaliPrivate::earliestValidYear() const
0154 {
0155     return 1244;
0156 }
0157 
0158 int KCalendarSystemJalaliPrivate::latestValidYear() const
0159 {
0160     return 1530;
0161 }
0162 
0163 QString KCalendarSystemJalaliPrivate::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("Jalali month 1 - KLocale::NarrowName",  "F").toString(languages);
0173         case 2:
0174             return ki18nc("Jalali month 2 - KLocale::NarrowName",  "O").toString(languages);
0175         case 3:
0176             return ki18nc("Jalali month 3 - KLocale::NarrowName",  "K").toString(languages);
0177         case 4:
0178             return ki18nc("Jalali month 4 - KLocale::NarrowName",  "T").toString(languages);
0179         case 5:
0180             return ki18nc("Jalali month 5 - KLocale::NarrowName",  "M").toString(languages);
0181         case 6:
0182             return ki18nc("Jalali month 6 - KLocale::NarrowName",  "S").toString(languages);
0183         case 7:
0184             return ki18nc("Jalali month 7 - KLocale::NarrowName",  "M").toString(languages);
0185         case 8:
0186             return ki18nc("Jalali month 8 - KLocale::NarrowName",  "A").toString(languages);
0187         case 9:
0188             return ki18nc("Jalali month 9 - KLocale::NarrowName",  "A").toString(languages);
0189         case 10:
0190             return ki18nc("Jalali month 10 - KLocale::NarrowName", "D").toString(languages);
0191         case 11:
0192             return ki18nc("Jalali month 11 - KLocale::NarrowName", "B").toString(languages);
0193         case 12:
0194             return ki18nc("Jalali month 12 - KLocale::NarrowName", "E").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("Jalali month 1 - KLocale::ShortName Possessive",  "of Far").toString(languages);
0204         case 2:
0205             return ki18nc("Jalali month 2 - KLocale::ShortName Possessive",  "of Ord").toString(languages);
0206         case 3:
0207             return ki18nc("Jalali month 3 - KLocale::ShortName Possessive",  "of Kho").toString(languages);
0208         case 4:
0209             return ki18nc("Jalali month 4 - KLocale::ShortName Possessive",  "of Tir").toString(languages);
0210         case 5:
0211             return ki18nc("Jalali month 5 - KLocale::ShortName Possessive",  "of Mor").toString(languages);
0212         case 6:
0213             return ki18nc("Jalali month 6 - KLocale::ShortName Possessive",  "of Sha").toString(languages);
0214         case 7:
0215             return ki18nc("Jalali month 7 - KLocale::ShortName Possessive",  "of Meh").toString(languages);
0216         case 8:
0217             return ki18nc("Jalali month 8 - KLocale::ShortName Possessive",  "of Aba").toString(languages);
0218         case 9:
0219             return ki18nc("Jalali month 9 - KLocale::ShortName Possessive",  "of Aza").toString(languages);
0220         case 10:
0221             return ki18nc("Jalali month 10 - KLocale::ShortName Possessive", "of Dei").toString(languages);
0222         case 11:
0223             return ki18nc("Jalali month 11 - KLocale::ShortName Possessive", "of Bah").toString(languages);
0224         case 12:
0225             return ki18nc("Jalali month 12 - KLocale::ShortName Possessive", "of Esf").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("Jalali month 1 - KLocale::ShortName",  "Far").toString(languages);
0235         case 2:
0236             return ki18nc("Jalali month 2 - KLocale::ShortName",  "Ord").toString(languages);
0237         case 3:
0238             return ki18nc("Jalali month 3 - KLocale::ShortName",  "Kho").toString(languages);
0239         case 4:
0240             return ki18nc("Jalali month 4 - KLocale::ShortName",  "Tir").toString(languages);
0241         case 5:
0242             return ki18nc("Jalali month 5 - KLocale::ShortName",  "Mor").toString(languages);
0243         case 6:
0244             return ki18nc("Jalali month 6 - KLocale::ShortName",  "Sha").toString(languages);
0245         case 7:
0246             return ki18nc("Jalali month 7 - KLocale::ShortName",  "Meh").toString(languages);
0247         case 8:
0248             return ki18nc("Jalali month 8 - KLocale::ShortName",  "Aba").toString(languages);
0249         case 9:
0250             return ki18nc("Jalali month 9 - KLocale::ShortName",  "Aza").toString(languages);
0251         case 10:
0252             return ki18nc("Jalali month 10 - KLocale::ShortName", "Dei").toString(languages);
0253         case 11:
0254             return ki18nc("Jalali month 11 - KLocale::ShortName", "Bah").toString(languages);
0255         case 12:
0256             return ki18nc("Jalali month 12 - KLocale::ShortName", "Esf").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("Jalali month 1 - KLocale::LongName Possessive",  "of Farvardin").toString(languages);
0266         case 2:
0267             return ki18nc("Jalali month 2 - KLocale::LongName Possessive",  "of Ordibehesht").toString(languages);
0268         case 3:
0269             return ki18nc("Jalali month 3 - KLocale::LongName Possessive",  "of Khordad").toString(languages);
0270         case 4:
0271             return ki18nc("Jalali month 4 - KLocale::LongName Possessive",  "of Tir").toString(languages);
0272         case 5:
0273             return ki18nc("Jalali month 5 - KLocale::LongName Possessive",  "of Mordad").toString(languages);
0274         case 6:
0275             return ki18nc("Jalali month 6 - KLocale::LongName Possessive",  "of Shahrivar").toString(languages);
0276         case 7:
0277             return ki18nc("Jalali month 7 - KLocale::LongName Possessive",  "of Mehr").toString(languages);
0278         case 8:
0279             return ki18nc("Jalali month 8 - KLocale::LongName Possessive",  "of Aban").toString(languages);
0280         case 9:
0281             return ki18nc("Jalali month 9 - KLocale::LongName Possessive",  "of Azar").toString(languages);
0282         case 10:
0283             return ki18nc("Jalali month 10 - KLocale::LongName Possessive", "of Dei").toString(languages);
0284         case 11:
0285             return ki18nc("Jalali month 11 - KLocale::LongName Possessive", "of Bahman").toString(languages);
0286         case 12:
0287             return ki18nc("Jalali month 12 - KLocale::LongName Possessive", "of Esfand").toString(languages);
0288         default:
0289             return QString();
0290         }
0291     }
0292 
0293     // Default to LongName
0294     switch (month) {
0295     case 1:
0296         return ki18nc("Jalali month 1 - KLocale::LongName",  "Farvardin").toString(languages);
0297     case 2:
0298         return ki18nc("Jalali month 2 - KLocale::LongName",  "Ordibehesht").toString(languages);
0299     case 3:
0300         return ki18nc("Jalali month 3 - KLocale::LongName",  "Khordad").toString(languages);
0301     case 4:
0302         return ki18nc("Jalali month 4 - KLocale::LongName",  "Tir").toString(languages);
0303     case 5:
0304         return ki18nc("Jalali month 5 - KLocale::LongName",  "Mordad").toString(languages);
0305     case 6:
0306         return ki18nc("Jalali month 6 - KLocale::LongName",  "Shahrivar").toString(languages);
0307     case 7:
0308         return ki18nc("Jalali month 7 - KLocale::LongName",  "Mehr").toString(languages);
0309     case 8:
0310         return ki18nc("Jalali month 8 - KLocale::LongName",  "Aban").toString(languages);
0311     case 9:
0312         return ki18nc("Jalali month 9 - KLocale::LongName",  "Azar").toString(languages);
0313     case 10:
0314         return ki18nc("Jalali month 10 - KLocale::LongName", "Dei").toString(languages);
0315     case 11:
0316         return ki18nc("Jalali month 11 - KLocale::LongName", "Bahman").toString(languages);
0317     case 12:
0318         return ki18nc("Jalali month 12 - KLocale::LongName", "Esfand").toString(languages);
0319     default:
0320         return QString();
0321     }
0322 }
0323 
0324 QString KCalendarSystemJalaliPrivate::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("Jalali weekday 1 - KLocale::NarrowName ", "2").toString(languages);
0332         case 2:
0333             return ki18nc("Jalali weekday 2 - KLocale::NarrowName ", "3").toString(languages);
0334         case 3:
0335             return ki18nc("Jalali weekday 3 - KLocale::NarrowName ", "4").toString(languages);
0336         case 4:
0337             return ki18nc("Jalali weekday 4 - KLocale::NarrowName ", "5").toString(languages);
0338         case 5:
0339             return ki18nc("Jalali weekday 5 - KLocale::NarrowName ", "J").toString(languages);
0340         case 6:
0341             return ki18nc("Jalali weekday 6 - KLocale::NarrowName ", "S").toString(languages);
0342         case 7:
0343             return ki18nc("Jalali weekday 7 - KLocale::NarrowName ", "1").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("Jalali weekday 1 - KLocale::ShortName", "2sh").toString(languages);
0353         case 2:
0354             return ki18nc("Jalali weekday 2 - KLocale::ShortName", "3sh").toString(languages);
0355         case 3:
0356             return ki18nc("Jalali weekday 3 - KLocale::ShortName", "4sh").toString(languages);
0357         case 4:
0358             return ki18nc("Jalali weekday 4 - KLocale::ShortName", "5sh").toString(languages);
0359         case 5:
0360             return ki18nc("Jalali weekday 5 - KLocale::ShortName", "Jom").toString(languages);
0361         case 6:
0362             return ki18nc("Jalali weekday 6 - KLocale::ShortName", "Shn").toString(languages);
0363         case 7:
0364             return ki18nc("Jalali weekday 7 - KLocale::ShortName", "1sh").toString(languages);
0365         default: return QString();
0366         }
0367     }
0368 
0369     switch (weekDay) {
0370     case 1:
0371         return ki18nc("Jalali weekday 1 - KLocale::LongName", "Do shanbe").toString(languages);
0372     case 2:
0373         return ki18nc("Jalali weekday 2 - KLocale::LongName", "Se shanbe").toString(languages);
0374     case 3:
0375         return ki18nc("Jalali weekday 3 - KLocale::LongName", "Chahar shanbe").toString(languages);
0376     case 4:
0377         return ki18nc("Jalali weekday 4 - KLocale::LongName", "Panj shanbe").toString(languages);
0378     case 5:
0379         return ki18nc("Jalali weekday 5 - KLocale::LongName", "Jumee").toString(languages);
0380     case 6:
0381         return ki18nc("Jalali weekday 6 - KLocale::LongName", "Shanbe").toString(languages);
0382     case 7:
0383         return ki18nc("Jalali weekday 7 - KLocale::LongName", "Yek-shanbe").toString(languages);
0384     default:
0385         return QString();
0386     }
0387 }
0388 
0389 KCalendarSystemJalali::KCalendarSystemJalali(const KSharedConfig::Ptr config, const KLocale *locale)
0390     : KCalendarSystem(*new KCalendarSystemJalaliPrivate(this), config, locale)
0391 {
0392     d_ptr->loadConfig(calendarType());
0393 }
0394 
0395 KCalendarSystemJalali::KCalendarSystemJalali(KCalendarSystemJalaliPrivate &dd,
0396         const KSharedConfig::Ptr config, const KLocale *locale)
0397     : KCalendarSystem(dd, config, locale)
0398 {
0399     d_ptr->loadConfig(calendarType());
0400 }
0401 
0402 KCalendarSystemJalali::~KCalendarSystemJalali()
0403 {
0404 }
0405 
0406 QString KCalendarSystemJalali::calendarType() const
0407 {
0408     return QLatin1String("jalali");
0409 }
0410 
0411 KLocale::CalendarSystem KCalendarSystemJalali::calendarSystem() const
0412 {
0413     return KLocale::JalaliCalendar;
0414 }
0415 
0416 QDate KCalendarSystemJalali::epoch() const
0417 {
0418     // 19 March 622 in the Julian calendar
0419     return QDate::fromJulianDay(1948321);
0420 }
0421 
0422 QDate KCalendarSystemJalali::earliestValidDate() const
0423 {
0424     // Using the Birashk formula which is accurate in period AP 1244 to 1530 (AD 1865 to 2152)
0425     // 1244-01-01 Jalali 1865-03-21 Gregorian
0426     return QDate::fromJulianDay(2402317);
0427 }
0428 
0429 QDate KCalendarSystemJalali::latestValidDate() const
0430 {
0431     // Using the Birashk formula which is accurate in period AP 1244 to 1530 (AD 1865 to 2152)
0432     // 1530-12-29 Jalali 2152-03-19 Gregorian
0433     return QDate::fromJulianDay(2507140);
0434 }
0435 
0436 QString KCalendarSystemJalali::monthName(int month, int year, MonthNameFormat format) const
0437 {
0438     return KCalendarSystem::monthName(month, year, format);
0439 }
0440 
0441 QString KCalendarSystemJalali::monthName(const QDate &date, MonthNameFormat format) const
0442 {
0443     return KCalendarSystem::monthName(date, format);
0444 }
0445 
0446 QString KCalendarSystemJalali::weekDayName(int weekDay, WeekDayNameFormat format) const
0447 {
0448     return KCalendarSystem::weekDayName(weekDay, format);
0449 }
0450 
0451 QString KCalendarSystemJalali::weekDayName(const QDate &date, WeekDayNameFormat format) const
0452 {
0453     return KCalendarSystem::weekDayName(date, format);
0454 }
0455 
0456 bool KCalendarSystemJalali::isLunar() const
0457 {
0458     return false;
0459 }
0460 
0461 bool KCalendarSystemJalali::isLunisolar() const
0462 {
0463     return false;
0464 }
0465 
0466 bool KCalendarSystemJalali::isSolar() const
0467 {
0468     return true;
0469 }
0470 
0471 bool KCalendarSystemJalali::isProleptic() const
0472 {
0473     return false;
0474 }
0475 
0476 bool KCalendarSystemJalali::julianDayToDate(qint64 jd, int &year, int &month, int &day) const
0477 {
0478     // Birashk algorithm is incorrect in two years in period AP 1244 to 1531.
0479     // This results in a leap day being added to the end of 1404 instead of 1403
0480     // and to the end of 1437 instead of 1436.  Check for these dates first and
0481     // return accordingly.  Relies on later use of dateToJulianDay() to correctly
0482     // calculate firstDayOfYear in 1404 and 1437, so no other adjustments needed.
0483     if (jd == 2460755) {
0484         year = 1403;
0485         month = 12;
0486         day = 30;
0487         return true;
0488     }
0489     if (jd == 2472808) {
0490         year = 1436;
0491         month = 12;
0492         day = 30;
0493         return true;
0494     }
0495 
0496     // From original KDE3 code, source unknown?  Unable to contact author or committer to confirm
0497     // Matches Fermilab code, EMACS and D&R so check for PD source, likely Birashk's book
0498 
0499     qint64 jdCycleStart;
0500     int daysSinceCycleStart;
0501     int cycle;
0502     int dayInCycle;
0503     int yearInCycle;
0504     dateToJulianDay(475, 1, 1, jdCycleStart);
0505     daysSinceCycleStart = jd - jdCycleStart;
0506     cycle = daysSinceCycleStart / 1029983;
0507     dayInCycle = daysSinceCycleStart % 1029983;
0508     if (dayInCycle == 1029982) {
0509         yearInCycle = 2820;
0510     } else {
0511         int aux1 = dayInCycle / 366;
0512         int aux2 = dayInCycle % 366;
0513         yearInCycle = (((2134 * aux1) + (2816 * aux2) + 2815) / 1028522) + aux1 + 1;
0514     }
0515     year = yearInCycle + (2820 * cycle) + 474;
0516     if (year <= 0) {
0517         year = year - 1;
0518     }
0519 
0520     qint64 firstDayOfYear;
0521     dateToJulianDay(year, 1, 1, firstDayOfYear);
0522     int dayinYear = jd - firstDayOfYear + 1;
0523     if (dayinYear <= 186) {
0524         month = ((dayinYear - 1) / 31) + 1;
0525         day = dayinYear - ((month - 1) * 31);
0526     } else {
0527         month = ((dayinYear - 7) / 30) + 1;
0528         day = dayinYear - ((month - 1) * 30) - 6;
0529     }
0530 
0531     return true;
0532 }
0533 
0534 bool KCalendarSystemJalali::dateToJulianDay(int year, int month, int day, qint64 &jd) const
0535 {
0536     Q_D(const KCalendarSystemJalali);
0537 
0538     // Birashk algorithm is incorrect in two years in period AP 1244 to 1531.
0539     // This results in a leap day being added to the end of 1404 instead of 1403
0540     // and to the end of 1437 instead of 1436.  Thus all dates in 1404 and 1437
0541     // are off by 1 JD.  Check for these dates first and adjust accordingly.
0542     if (year == 1403 && month == 12 && day == 30) {
0543         jd = 2460755;
0544         return true;
0545     }
0546     if (year == 1436 && month == 12 && day == 30) {
0547         jd = 2472808;
0548         return true;
0549     }
0550     if (year == 1404 || year == 1437) {
0551         if (month < 12 && day + 1 > d->daysInMonth(year, month)) {
0552             day = 1;
0553             month = month + 1;
0554         } else {
0555             day = day + 1;
0556         }
0557     }
0558 
0559     // From original KDE3 code, source unknown?  Unable to contact author or committer to confirm
0560     // Matches Fermilab code, EMACS and D&R so check for PD source, likely Birashk's book
0561     int epbase;
0562     long epyear;
0563     long monthDays;
0564 
0565     if (year >= 0) {
0566         epbase = year - 474;
0567     } else {
0568         epbase = year - 473;
0569     }
0570 
0571     epyear = 474 + (epbase % 2820);
0572 
0573     if (month <= 7) {
0574         monthDays = (month - 1) * 31;
0575     } else {
0576         monthDays = ((month - 1) * 30) + 6;
0577     }
0578 
0579     jd = (epoch().toJulianDay() - 1) +            // days before epoch
0580          (epyear - 1) * 365 +                     // normal days in previous years
0581          (((epyear * 682) - 110) / 2816) +        // leap days in previous years
0582          (epbase / 2820) * 1029983 +
0583          monthDays +                              // days in previous months this year
0584          day;                                     // days in this month
0585 
0586     return true;
0587 }