| 1 | // Copyright (C) 2021 The Qt Company Ltd. |
| 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
| 3 | |
| 4 | #include "qglobal.h" |
| 5 | #include "qislamiccivilcalendar_p.h" |
| 6 | #include "qcalendarmath_p.h" |
| 7 | |
| 8 | QT_BEGIN_NAMESPACE |
| 9 | |
| 10 | using namespace QRoundingDown; |
| 11 | |
| 12 | /*! |
| 13 | \since 5.14 |
| 14 | \internal |
| 15 | |
| 16 | \class QIslamicCivilCalendar |
| 17 | \inmodule QtCore |
| 18 | \brief Implements a commonly-used computed version of the Islamic calendar. |
| 19 | |
| 20 | \section1 Civil Islamic Calendar |
| 21 | |
| 22 | QIslamicCivilCalendar implements a tabular version of the Hijri calendar |
| 23 | which is known as the Islamic Civil Calendar. It has the same numbering of |
| 24 | years and months, but the months are determined by arithmetical rules rather |
| 25 | than by observation or astronomical calculations. |
| 26 | |
| 27 | \section2 Calendar Organization |
| 28 | |
| 29 | The civil calendar follows the usual tabular scheme of odd-numbered months |
| 30 | and the last month of each leap year being 30 days long, the rest being 29 |
| 31 | days long. Its determination of leap years follows a 30-year cycle, in each |
| 32 | of which the years 2, 5, 7, 10, 13, 16, 18, 21, 24, 26 and 29 are leap |
| 33 | years. |
| 34 | |
| 35 | \sa QHijriCalendar, QCalendar |
| 36 | */ |
| 37 | |
| 38 | QString QIslamicCivilCalendar::name() const |
| 39 | { |
| 40 | return QStringLiteral("Islamic Civil" ); |
| 41 | } |
| 42 | |
| 43 | QStringList QIslamicCivilCalendar::nameList() |
| 44 | { |
| 45 | return { |
| 46 | QStringLiteral("Islamic Civil" ), |
| 47 | QStringLiteral("islamic-civil" ), // CLDR name |
| 48 | QStringLiteral("islamicc" ), // old CLDR name, still (2018) used by Mozilla |
| 49 | // Until we have a concrete implementation that knows all the needed ephemerides: |
| 50 | QStringLiteral("Islamic" ), |
| 51 | }; |
| 52 | } |
| 53 | |
| 54 | bool QIslamicCivilCalendar::isLeapYear(int year) const |
| 55 | { |
| 56 | if (year == QCalendar::Unspecified) |
| 57 | return false; |
| 58 | if (year < 0) |
| 59 | ++year; |
| 60 | return qMod<30>(a: year * 11 + 14) < 11; |
| 61 | } |
| 62 | |
| 63 | // First day of first year (Gregorian 622 CE July 19th) is the base date here: |
| 64 | constexpr qint64 EpochJd = 1948440; |
| 65 | // Each 30 years has 11 leap years of 355 days and 19 ordinary years of 354: |
| 66 | constexpr unsigned ThirtyYears = 11 * 355 + 19 * 354; |
| 67 | // The first eleven months of the year alternate 30, 29, ..., 29, 30 days in length. |
| 68 | constexpr unsigned ElevenMonths = 6 * 30 + 5 * 29; |
| 69 | |
| 70 | bool QIslamicCivilCalendar::dateToJulianDay(int year, int month, int day, qint64 *jd) const |
| 71 | { |
| 72 | Q_ASSERT(jd); |
| 73 | if (!isDateValid(year, month, day)) |
| 74 | return false; |
| 75 | |
| 76 | *jd = qDiv<30>(a: qint64(ThirtyYears) * (year > 0 ? year - 1 : year) + 14) |
| 77 | + qDiv<11>(a: ElevenMonths * (month - 1) + 5) |
| 78 | + day + EpochJd - 1; |
| 79 | return true; |
| 80 | } |
| 81 | |
| 82 | QCalendar::YearMonthDay QIslamicCivilCalendar::julianDayToDate(qint64 jd) const |
| 83 | { |
| 84 | const auto year30Day = qDivMod<ThirtyYears>(a: 30 * (jd - EpochJd) + 15); |
| 85 | // Its remainder changes by 30 per day, except roughly yearly. |
| 86 | const auto month11Day = qDivMod<ElevenMonths>(a: 11 * qDiv<30>(a: year30Day.remainder) + 5); |
| 87 | // Its remainder changes by 11 per day except roughly monthly. |
| 88 | const int month = month11Day.quotient + 1; |
| 89 | const int day = qDiv<11>(a: month11Day.remainder) + 1; |
| 90 | const int y = year30Day.quotient + 1; |
| 91 | return QCalendar::YearMonthDay(y > 0 ? y : y - 1, month, day); |
| 92 | } |
| 93 | |
| 94 | QT_END_NAMESPACE |
| 95 | |