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 return qMod<2820>((year + 2346) * 683) < 683;
103}
104
105bool QJalaliCalendar::isLunar() const
106{
107 return false;
108}
109
110bool QJalaliCalendar::isLuniSolar() const
111{
112 return false;
113}
114
115bool QJalaliCalendar::isSolar() const
116{
117 return true;
118}
119
120bool QJalaliCalendar::dateToJulianDay(int year, int month, int day, qint64 *jd) const
121{
122 Q_ASSERT(jd);
123 if (!isDateValid(year, month, day))
124 return false;
125
126 const int y = year - (year < 0 ? 474 : 475);
127 const int c = qDiv<cycleYears>(y);
128 const int yearInCycle = y - c * cycleYears;
129 int dayInYear = day;
130 for (int i = 1; i < month; ++i)
131 dayInYear += daysInMonth(i, year);
132 *jd = firstDayOfYear(yearInCycle, c) + dayInYear - 1;
133 return true;
134}
135
136QCalendar::YearMonthDay QJalaliCalendar::julianDayToDate(qint64 jd) const
137{
138 const int c = cycle(jd);
139 int yearInCycle = qFloor((jd - cycleStart(c)) / yearLength);
140 int year = yearInCycle + 475 + c * cycleYears;
141 int day = jd - firstDayOfYear(yearInCycle, c) + 1;
142 if (day > daysInYear(year <= 0 ? year - 1 : year)) {
143 ++year;
144 day = 1;
145 }
146 if (year <= 0)
147 year--;
148 int month;
149 for (month = 1; month < 12; ++month) {
150 const int last = daysInMonth(month, year);
151 if (day <= last)
152 break;
153 day -= last;
154 }
155 return QCalendar::YearMonthDay(year, month, day);
156}
157
158int QJalaliCalendar::daysInMonth(int month, int year) const
159{
160 if (!year || month < 1 || month > 12)
161 return 0;
162
163 if (month < 7)
164 return 31;
165
166 if (month < 12 || year == QCalendar::Unspecified || isLeapYear(year))
167 return 30;
168
169 return 29;
170}
171
172const QCalendarLocale *QJalaliCalendar::localeMonthIndexData() const
173{
174 return QtPrivate::Jalali::locale_data;
175}
176
177const char16_t *QJalaliCalendar::localeMonthData() const
178{
179 return QtPrivate::Jalali::months_data;
180}
181
182QT_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