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