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 | |