Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qjalalicalendar.cpp
Go to the documentation of this file.
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// Qt-Security score:significant reason:default
4
5#include "qglobal.h"
9#include <QtCore/qmath.h>
10
12
13using namespace QRoundingDown;
14
15// Constants
16
17constexpr qint64 cycleDays = 1029983;
18constexpr int cycleYears = 2820;
19constexpr double yearLength = 365.24219858156028368; // 365 + 683 / 2820.
20constexpr qint64 jalaliEpoch = 2121446; // 475/01/01 AP, start of 2820 cycle
21// This appears to be based on Ahmad Birashk's algorithm.
22
23// Calendar implementation
24
25static inline int cycle(qint64 jdn)
26{
27 return qDiv<cycleDays>(jdn - jalaliEpoch);
28}
29
30qint64 cycleStart(int cycleNo)
31{
32 return jalaliEpoch + cycleNo * cycleDays;
33}
34
35qint64 firstDayOfYear(int year, int cycleNo)
36{
37 qint64 firstDOYinEra = static_cast<qint64>(qFloor(year * yearLength));
38 return jalaliEpoch + cycleNo * cycleDays + firstDOYinEra;
39}
40
41/*!
42 \since 5.14
43 \internal
44
45 \class QJalaliCalendar
46 \inmodule QtCore
47 \brief The QJalaliCalendar class provides Jalali (Hijri Shamsi) calendar
48 system implementation.
49
50 \section1 Solar Hijri Calendar System
51
52 The Solar Hijri calendar, also called the Solar Hejri calendar, Shamsi
53 Hijri calendar or Jalali calendar, is the official calendar of Iran and
54 Afghanistan. It begins on the vernal equinox (Nowruz) as determined by
55 astronomical calculation for the Iran Standard Time meridian
56 (52.5°E or GMT+3.5h). This determination of starting moment is more accurate
57 than the Gregorian calendar for predicting the date of the vernal equinox,
58 because it uses astronomical observations rather than mathematical rules.
59
60 \section2 Calendar Organization
61
62 Each of the twelve months corresponds with a zodiac sign. The first six
63 months have 31 days, the next five have 30 days, and the last month has 29
64 days in usual years but 30 days in leap years. The New Year's Day always
65 falls on the March equinox.
66
67 \section2 Leap Year Rules
68
69 The Solar Hijri calendar produces a five-year leap year interval after about
70 every seven four-year leap year intervals. It usually follows a 33-year
71 cycle with occasional interruptions by single 29-year or 37-year subcycles.
72 The reason for this behavior is that it tracks the observed vernal equinox.
73 By contrast, some less accurate predictive algorithms are in use based
74 on confusion between the average tropical year (365.2422 days, approximated
75 with near 128-year cycles or 2820-year great cycles) and the mean interval
76 between spring equinoxes (365.2424 days, approximated with a near 33-year
77 cycle).
78
79 Source: \l {https://en.wikipedia.org/wiki/Solar_Hijri_calendar}{Wikipedia
80 page on Solar Hijri Calendar}
81*/
82
83QString QJalaliCalendar::name() const
84{
85 return QStringLiteral("Jalali");
86}
87
88QStringList QJalaliCalendar::nameList()
89{
90 return {
91 QStringLiteral("Jalali"),
92 QStringLiteral("Persian"),
93 };
94}
95
96bool QJalaliCalendar::isLeapYear(int year) const
97{
98 if (year == QCalendar::Unspecified)
99 return false;
100 if (year < 0)
101 ++year;
102
103 year = qMod<2820>(year); // Avoids overflow in:
104 return qMod<2820>((year + 2346) * 683) < 683;
105}
106
107bool QJalaliCalendar::isLunar() const
108{
109 return false;
110}
111
112bool QJalaliCalendar::isLuniSolar() const
113{
114 return false;
115}
116
117bool QJalaliCalendar::isSolar() const
118{
119 return true;
120}
121
122bool QJalaliCalendar::dateToJulianDay(int year, int month, int day, qint64 *jd) const
123{
124 Q_ASSERT(jd);
125 if (!isDateValid(year, month, day))
126 return false;
127
128 const int y = year - (year < 0 ? 474 : 475);
129 const int c = qDiv<cycleYears>(y);
130 const int yearInCycle = y - c * cycleYears;
131 int dayInYear = day;
132 for (int i = 1; i < month; ++i)
133 dayInYear += daysInMonth(i, year);
134 *jd = firstDayOfYear(yearInCycle, c) + dayInYear - 1;
135 return true;
136}
137
138QCalendar::YearMonthDay QJalaliCalendar::julianDayToDate(qint64 jd) const
139{
140 const int c = cycle(jd);
141 int yearInCycle = qFloor((jd - cycleStart(c)) / yearLength);
142 int year = yearInCycle + 475 + c * cycleYears;
143 int day = jd - firstDayOfYear(yearInCycle, c) + 1;
144 if (day > daysInYear(year <= 0 ? year - 1 : year)) {
145 ++year;
146 day = 1;
147 }
148 if (year <= 0)
149 year--;
150 int month;
151 for (month = 1; month < 12; ++month) {
152 const int last = daysInMonth(month, year);
153 if (day <= last)
154 break;
155 day -= last;
156 }
157 return QCalendar::YearMonthDay(year, month, day);
158}
159
160int QJalaliCalendar::daysInMonth(int month, int year) const
161{
162 if (!year || month < 1 || month > 12)
163 return 0;
164
165 if (month < 7)
166 return 31;
167
168 if (month < 12 || year == QCalendar::Unspecified || isLeapYear(year))
169 return 30;
170
171 return 29;
172}
173
174const QCalendarLocale *QJalaliCalendar::localeMonthIndexData() const
175{
176 return QtPrivate::Jalali::locale_data;
177}
178
179const char16_t *QJalaliCalendar::localeMonthData() const
180{
181 return QtPrivate::Jalali::months_data;
182}
183
184QT_END_NAMESPACE
Combined button and popup list for selecting options.
constexpr int cycleYears
constexpr qint64 jalaliEpoch
qint64 cycleStart(int cycleNo)
static int cycle(qint64 jdn)
qint64 firstDayOfYear(int year, int cycleNo)
constexpr double yearLength
constexpr qint64 cycleDays