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#include "qcalendar.h"
4#include "qcalendarbackend_p.h"
5#include "qgregoriancalendar_p.h"
6#ifndef QT_BOOTSTRAPPED
7#include "qjuliancalendar_p.h"
8#include "qmilankoviccalendar_p.h"
9#endif
10#if QT_CONFIG(jalalicalendar)
11#include "qjalalicalendar_p.h"
12#endif
13#if QT_CONFIG(islamiccivilcalendar)
14#include "qislamiccivilcalendar_p.h"
15#endif
16
17#include <private/qflatmap_p.h>
18#include "qatomic.h"
19#include "qdatetime.h"
20#include "qcalendarmath_p.h"
21#include <qhash.h>
22#include <qreadwritelock.h>
23
24#include <vector>
25
26QT_BEGIN_NAMESPACE
27
28struct QCalendarRegistryCaseInsensitiveAnyStringViewLessThan
29{
30 struct is_transparent {};
31 bool operator()(QAnyStringView lhs, QAnyStringView rhs) const
32 {
33 return QAnyStringView::compare(lhs, rhs, cs: Qt::CaseInsensitive) < 0;
34 }
35};
36
37namespace QtPrivate {
38
39/*
40 \internal
41 Handles calendar backend registration.
42*/
43class QCalendarRegistry
44{
45 Q_DISABLE_COPY_MOVE(QCalendarRegistry); // This is a singleton.
46
47 static constexpr qsizetype ExpectedNumberOfBackends = qsizetype(QCalendar::System::Last) + 1;
48
49 /*
50 Lock protecting the registry from concurrent modification.
51 */
52 QReadWriteLock lock;
53
54 /*
55 Vector containing all registered backends.
56
57 The indices 0 to \c QCalendar::System::Last inclusive are allocated
58 for system backends and always present (but may be null).
59 */
60 std::vector<QCalendarBackend *> byId;
61
62 /*
63 Backends registered by name.
64
65 Each backend may be registered with several names associated with it.
66 The names are case-insensitive.
67 */
68 QFlatMap<
69 QString, QCalendarBackend *,
70 QCalendarRegistryCaseInsensitiveAnyStringViewLessThan,
71 QStringList,
72 std::vector<QCalendarBackend *>
73 > byName;
74
75 /*
76 Pointer to the Gregorian backend for faster lockless access to it.
77
78 This pointer may be null if the Gregorian backend is not yet registered.
79 This pointer may only be set once and only when write lock is held on
80 the registry.
81 */
82 QAtomicPointer<const QCalendarBackend> gregorianCalendar = nullptr;
83
84 enum : int {
85 Unpopulated, // The standard backends may not yet be created
86 Populated, // All standard backends were created
87 IsBeingDestroyed, // The registry and the backends are being destroyed
88 };
89
90 /*
91 Fast way to check whether the standard calendars were populated.
92
93 The status should only be changed while the write lock is held.
94 */
95 QAtomicInt status = Unpopulated;
96
97 void ensurePopulated();
98 QCalendarBackend *registerSystemBackendLockHeld(QCalendar::System system);
99 void registerBackendLockHeld(QCalendarBackend *backend, const QStringList &names,
100 QCalendar::System system);
101
102public:
103 QCalendarRegistry()
104 {
105 byId.resize(new_size: ExpectedNumberOfBackends);
106 byName.reserve(s: ExpectedNumberOfBackends * 2); // assume one alias on average
107 }
108
109 ~QCalendarRegistry();
110
111 bool isBeingDestroyed() const { return status.loadRelaxed() == IsBeingDestroyed; }
112
113 void registerCustomBackend(QCalendarBackend *backend, const QStringList &names);
114
115 QStringList availableCalendars();
116
117 /*
118 Returns backend for Gregorian calendar.
119
120 The backend is returned without locking the registry if possible.
121 */
122 const QCalendarBackend *gregorian()
123 {
124 const QCalendarBackend *backend = gregorianCalendar.loadAcquire();
125 if (Q_LIKELY(backend != nullptr))
126 return backend;
127 return fromEnum(system: QCalendar::System::Gregorian);
128 }
129
130 /*
131 Returns \a true if the argument matches the registered Gregorian backend.
132
133 \a backend should not be \nullptr.
134 */
135 bool isGregorian(const QCalendarBackend *backend) const
136 {
137 return backend == gregorianCalendar.loadRelaxed();
138 }
139
140 const QCalendarBackend *fromName(QAnyStringView name);
141 const QCalendarBackend *fromIndex(size_t index);
142 const QCalendarBackend *fromEnum(QCalendar::System system);
143
144 QStringList backendNames(const QCalendarBackend *backend);
145};
146
147/*
148 Destroy the registry.
149
150 This destroys all registered backends. This destructor should only be called
151 in a single-threaded context at program exit.
152*/
153QCalendarRegistry::~QCalendarRegistry()
154{
155 QWriteLocker locker(&lock);
156
157 status.storeRelaxed(newValue: IsBeingDestroyed);
158
159 qDeleteAll(c: byId);
160}
161
162/*
163 Registers a custom backend.
164
165 A new unique ID is allocated for the \a backend. The registry takes
166 ownership of the \a backend.
167
168 The \a names of the backend are also registered. Already registered
169 names are not updated.
170
171 The \a backend should not be already registered.
172
173 The \a backend should be fully initialized. It becomes available
174 to other threads before this function returns.
175*/
176void QCalendarRegistry::registerCustomBackend(QCalendarBackend *backend, const QStringList &names)
177{
178 Q_ASSERT(!backend->calendarId().isValid());
179
180 ensurePopulated();
181
182 QWriteLocker locker(&lock);
183 registerBackendLockHeld(backend, names, system: QCalendar::System::User);
184}
185
186/*
187 Ensures all system calendars have been instantiated.
188
189 This arranges for each system backend to be registered. The method only
190 does anything on its first call, which ensures that name-based lookups can
191 always find all the calendars available via the \c QCalendar::System other
192 than \c QCalendar::System::User.
193*/
194void QCalendarRegistry::ensurePopulated()
195{
196 if (Q_LIKELY(status.loadAcquire() != Unpopulated))
197 return;
198
199 QWriteLocker locker(&lock);
200 if (status.loadAcquire() != Unpopulated)
201 return;
202
203 for (int i = 0; i <= int(QCalendar::System::Last); ++i) {
204 if (byId[i] == nullptr)
205 registerSystemBackendLockHeld(system: QCalendar::System(i));
206 }
207
208#if defined(QT_FORCE_ASSERTS) || !defined(QT_NO_DEBUG)
209 auto oldValue = status.fetchAndStoreRelease(newValue: Populated);
210 Q_ASSERT(oldValue == Unpopulated);
211#else
212 status.storeRelease(Populated);
213#endif
214}
215
216/*
217 Helper functions for system backend registration.
218
219 This function must be called with write lock held on the registry.
220
221 \sa registerSystemBackend
222*/
223QCalendarBackend *QCalendarRegistry::registerSystemBackendLockHeld(QCalendar::System system)
224{
225 Q_ASSERT(system != QCalendar::System::User);
226
227 QCalendarBackend *backend = nullptr;
228 QStringList names;
229
230 switch (system) {
231 case QCalendar::System::Gregorian:
232 backend = new QGregorianCalendar;
233 names = QGregorianCalendar::nameList();
234 break;
235#ifndef QT_BOOTSTRAPPED
236 case QCalendar::System::Julian:
237 backend = new QJulianCalendar;
238 names = QJulianCalendar::nameList();
239 break;
240 case QCalendar::System::Milankovic:
241 backend = new QMilankovicCalendar;
242 names = QMilankovicCalendar::nameList();
243 break;
244#endif
245#if QT_CONFIG(jalalicalendar)
246 case QCalendar::System::Jalali:
247 backend = new QJalaliCalendar;
248 names = QJalaliCalendar::nameList();
249 break;
250#endif
251#if QT_CONFIG(islamiccivilcalendar)
252 case QCalendar::System::IslamicCivil:
253 backend = new QIslamicCivilCalendar;
254 names = QIslamicCivilCalendar::nameList();
255 break;
256#else // When highest-numbered system isn't enabled, ensure we have a case for Last:
257 case QCalendar::System::Last:
258#endif
259 case QCalendar::System::User:
260 Q_UNREACHABLE();
261 }
262 if (!backend)
263 return nullptr;
264
265 registerBackendLockHeld(backend, names, system);
266 Q_ASSERT(backend == byId[size_t(system)]);
267
268 return backend;
269}
270
271/*
272 Helper function for backend registration.
273
274 This function must be called with write lock held on the registry.
275
276 \sa registerBackend
277*/
278void QCalendarRegistry::registerBackendLockHeld(QCalendarBackend *backend, const QStringList &names,
279 QCalendar::System system)
280{
281 Q_ASSERT(!backend->calendarId().isValid());
282
283 auto index = size_t(system);
284
285 // Note: it is important to update the calendar ID before making
286 // the calendar available for queries.
287 if (system == QCalendar::System::User) {
288 backend->setIndex(byId.size());
289 byId.push_back(x: backend);
290 } else if (byId[index] == nullptr) {
291 backend->setIndex(index);
292 if (system == QCalendar::System::Gregorian) {
293#if defined(QT_FORCE_ASSERTS) || !defined(QT_NO_DEBUG)
294 auto oldValue = gregorianCalendar.fetchAndStoreRelease(newValue: backend);
295 Q_ASSERT(oldValue == nullptr);
296#else
297 gregorianCalendar.storeRelease(backend);
298#endif
299 }
300
301 Q_ASSERT(byId.size() > index);
302 Q_ASSERT(byId[index] == nullptr);
303 byId[index] = backend;
304 }
305
306 // Register any names.
307 for (const auto &name : names) {
308 auto [it, inserted] = byName.try_emplace(key: name, args&: backend);
309 if (!inserted) {
310 Q_ASSERT(system == QCalendar::System::User);
311 qWarning(msg: "Cannot register name %ls (already in use) for %ls",
312 qUtf16Printable(name), qUtf16Printable(backend->name()));
313 }
314 }
315}
316
317/*
318 Returns a list of names of the available calendar systems.
319
320 Any QCalendarBackend sub-class must be registered before being exposed to Date
321 and Time APIs.
322
323 \sa fromName()
324*/
325QStringList QCalendarRegistry::availableCalendars()
326{
327 ensurePopulated();
328
329 QReadLocker locker(&lock);
330 return byName.keys();
331}
332
333/*
334 Returns a pointer to a named calendar backend.
335
336 If the given \a name is present in availableCalendars(), the backend
337 matching it is returned. Otherwise, \nullptr is returned. Matching of
338 names ignores case.
339
340 \sa availableCalendars(), fromEnum(), fromIndex()
341*/
342const QCalendarBackend *QCalendarRegistry::fromName(QAnyStringView name)
343{
344 ensurePopulated();
345
346 QReadLocker locker(&lock);
347 return byName.value(key: name, defaultValue: nullptr);
348}
349
350/*
351 Returns a pointer to a calendar backend, specified by index.
352
353 If a calendar with ID \a index is known to the calendar registry, the backend
354 with this ID is returned. Otherwise, \nullptr is returned.
355
356 \sa fromEnum(), calendarId()
357*/
358const QCalendarBackend *QCalendarRegistry::fromIndex(size_t index)
359{
360 {
361 QReadLocker locker(&lock);
362
363 if (index >= byId.size())
364 return nullptr;
365
366 if (auto backend = byId[index])
367 return backend;
368 }
369
370 if (index <= size_t(QCalendar::System::Last))
371 return fromEnum(system: QCalendar::System(index));
372
373 return nullptr;
374}
375
376/*
377 Returns a pointer to a calendar backend, specified by \a system.
378
379 This will instantiate the indicated calendar (which will enable fromName()
380 to return it subsequently), but only for the Qt-supported calendars for
381 which (where relevant) the appropriate feature has been enabled.
382
383 \a system should be a member of \a QCalendar::System other than
384 \a QCalendar::System::User.
385
386 \sa fromName(), fromId()
387*/
388const QCalendarBackend *QCalendarRegistry::fromEnum(QCalendar::System system)
389{
390 Q_ASSERT(system <= QCalendar::System::Last);
391 auto index = size_t(system);
392
393 {
394 QReadLocker locker(&lock);
395 Q_ASSERT(byId.size() > index);
396 if (auto backend = byId[index])
397 return backend;
398 }
399
400 QWriteLocker locker(&lock);
401
402 // Check if the backend was registered after releasing the read lock above.
403 if (auto backend = byId[index])
404 return backend;
405
406 return registerSystemBackendLockHeld(system);
407}
408
409/*
410 Returns a list of names \a backend was registered with.
411*/
412QStringList QCalendarRegistry::backendNames(const QCalendarBackend *backend)
413{
414 QStringList l;
415 l.reserve(asize: byName.size()); // too large, but never really large, so ok
416
417 QT_WARNING_PUSH
418 // Clang complains about the reference still causing a copy. The reference is idiomatic, but
419 // runs afoul of QFlatMap's iterators which return a pair of references instead of a reference
420 // to pair. Suppress the warning, because `const auto [key, value]` would look wrong.
421 QT_WARNING_DISABLE_CLANG("-Wrange-loop-analysis")
422 for (const auto &[key, value] : byName) {
423 if (value == backend)
424 l.push_back(t: key);
425 }
426 QT_WARNING_POP
427
428 return l;
429}
430
431} // namespace QtPrivate
432
433Q_GLOBAL_STATIC(QtPrivate::QCalendarRegistry, calendarRegistry);
434
435/*!
436 \since 5.14
437
438 \class QCalendarBackend
439 \inmodule QtCore
440 \internal
441 \reentrant
442 \brief The QCalendarBackend class provides basic calendaring functions.
443
444 QCalendarBackend provides the base class on which all calendar types are
445 implemented. The backend must be registered before it is available via
446 QCalendar API. The registration for system backends is arranged by
447 the calendar registry. Custom backends may be registered using the
448 \c registerCustomBackend() method.
449
450 A backend may also be registered by one or more names. Registering with the
451 name used by CLDR (the Unicode consortium's Common Locale Data Repository)
452 is recommended, particularly when interacting with third-party software.
453 Once a backend is registered for a name, QCalendar can be constructed using
454 that name to select the backend.
455
456 Each built-in backend has a distinct primary name and all built-in backends
457 are instantiated before any custom backend is registered, to prevent custom
458 backends with conflicting names from replacing built-in backends.
459
460 Each calendar backend must inherit from QCalendarBackend and implement its
461 pure virtual methods. It may also override some other virtual methods, as
462 needed.
463
464 Most backends are pure code, with only one data element (this base-classe's
465 \c m_id). Such backends should normally be implemented as singletons.
466
467 The backends may be used by multiple threads simultaneously. The virtual
468 methods must be implemented in a \l {thread-safe} way.
469
470 \section1 Instantiating backends
471
472 Backends may be defined by third-party, plugin or user code. When such
473 custom backends are registered they shall be allocated a unique ID, by
474 which client code may access it. A custom backend instance can have no names
475 if access by name is not needed, or impractical (e.g. because the backend
476 is not a singleton and constructing names for each instance would not make
477 sense). If a custom backend has names that are already registered for
478 another backend, those names are ignored.
479
480 A backend class that has instance variables as well as code may be
481 instantiated many times, each with a distinct set of names, to implement
482 distinct backends - presumably variants on some parameterized calendar.
483 Each instance is then a distinct backend. A pure code backend class shall
484 typically only be instantiated once, as it is only capable of representing
485 one backend.
486
487 Each backend should be instantiated exactly once, on the heap (using the C++
488 \c new operator), so that the registry can take ownership of it after
489 registration.
490
491 Built-in backends, identified by \c QCalendar::System values other than
492 \c{User}, should only be registered by \c{QCalendarRegistry::fromEnum()};
493 no other code should ever register one, this guarantees that such a backend
494 will be a singleton.
495
496 The shareable base-classes for backends, QRomanCalendar and QHijriCalendar,
497 are not themselves identified by QCalendar::System and may be used as
498 base-classes for custom calendar backends, but cannot be instantiated
499 themselves.
500
501 \sa calendarId(), QDate, QDateTime, QDateEdit, QDateTimeEdit,
502 QCalendarWidget, {The Low-Level API: Extending Qt Applications}
503*/
504
505/*!
506 Destroys the calendar backend.
507
508 Each calendar backend, once instantiated and successfully registered by ID,
509 shall exist until it is destroyed by the registry. Destroying a
510 successfully-registered backend otherwise may leave existing QCalendar
511 instances referencing the destroyed calendar, with undefined results.
512
513 If a backend has not been registered it may safely be deleted.
514
515 \sa calendarId()
516*/
517QCalendarBackend::~QCalendarBackend()
518{
519 Q_ASSERT(!m_id.isValid() || calendarRegistry.isDestroyed()
520 || calendarRegistry->isBeingDestroyed());
521}
522
523/*!
524 \fn QString QCalendarBackend::name() const
525 Returns the primary name of the calendar.
526 */
527
528/*!
529 Returns list of names this backend was registered with.
530
531 The list is a subset of the names passed to \c registerCustomBackend().
532 Some names passed during the registration may not be associated
533 with a backend if they were claimed by another backend first.
534
535 \sa registerCustomBackend()
536*/
537QStringList QCalendarBackend::names() const
538{
539 if (Q_UNLIKELY(calendarRegistry.isDestroyed()))
540 return {};
541
542 return calendarRegistry->backendNames(backend: this);
543}
544
545/*!
546 Set the internal index of the backed to the specified value.
547
548 This method exists to allow QCalendarRegistry to update the backend ID
549 after registration without exposing it in public API for QCalendar.
550 */
551void QCalendarBackend::setIndex(size_t index)
552{
553 Q_ASSERT(!m_id.isValid());
554 m_id.id = index;
555}
556
557/*!
558 Register this backend as a custom backend.
559
560 The backend should not already be registered. This method should only be
561 called on objects that are completely initialized because they become
562 available to other threads immediately. In particular, this function should
563 not be called from backend constructors.
564
565 The backend is also registered by names passed in \a names. Only the names
566 that are not already registered are associated with the backend. The name
567 matching is case-insensitive. The list of names associated with the backend
568 can be queried using \c names() method after successful registration.
569
570 Returns the new ID assigned to this backend. If its isValid() is \c true,
571 the calendar registry has taken ownership of the object; this ID can then
572 be used to create \c QCalendar instances. Otherwise, registration failed
573 and the caller is responsible for destruction of the backend, which shall
574 not be available for use by \c QCalendar. Failure should normally only
575 happen if registration is attempted during program termination.
576
577 \sa names()
578*/
579QCalendar::SystemId QCalendarBackend::registerCustomBackend(const QStringList &names)
580{
581 Q_ASSERT(!m_id.isValid());
582
583 if (Q_LIKELY(!calendarRegistry.isDestroyed()))
584 calendarRegistry->registerCustomBackend(backend: this, names);
585
586 return m_id;
587}
588
589bool QCalendarBackend::isGregorian() const
590{
591 if (Q_UNLIKELY(calendarRegistry.isDestroyed()))
592 return false;
593
594 return calendarRegistry->isGregorian(backend: this);
595}
596
597/*!
598 \since 6.2
599 \fn QCalendar::SystemId QCalendarBackend::calendarId() const
600
601 Each backend is allocated an ID when successfully registered. A backend whose
602 calendarId() has isValid() \c{false} has not been registered; it also cannot
603 be used, as it is not known to any of the available ways to create a QCalendar.
604
605 \sa calendarSystem(), fromId()
606*/
607
608/*!
609 The calendar system of this calendar.
610
611 \sa fromEnum(), calendarId()
612*/
613QCalendar::System QCalendarBackend::calendarSystem() const
614{
615 return m_id.isInEnum() ? QCalendar::System(m_id.index()) : QCalendar::System::User;
616}
617
618/*
619 Create local variable d containing the backend associated with a QCalendar
620 instance unless the calendar registry is destroyed together with all backends,
621 then return nullptr.
622
623 This assumes that the registry is only destroyed in single threaded context.
624*/
625#define SAFE_D() const auto d = Q_UNLIKELY(calendarRegistry.isDestroyed()) ? nullptr : d_ptr
626
627/*!
628 The primary name of this calendar.
629
630 The calendar may also be known by some aliases. A calendar instantiated by
631 name may use such an alias, in which case its name() need not match the
632 alias by which it was instantiated.
633*/
634QString QCalendar::name() const
635{
636 SAFE_D();
637 return d ? d->name() : QString();
638}
639
640// date queries
641/*!
642 \fn int QCalendarBackend::daysInMonth(int month, int year) const
643
644 Returns number of days in the month number \a month, in year \a year.
645
646 An implementation should return 0 if the given year had no such month. If
647 year is QCalendar::Unspecified, return the usual number of days for the
648 month, in those years that include it.
649
650 Calendars with intercallary days may represent these as extra days of the
651 preceding month, or as short months separate from the usual ones. In the
652 former case, daysInMonth(month, year) should be the number of ordinary days
653 in the month, although \c{isDateValid(year, month, day)} might return \c true
654 for some larger values of \c day.
655
656 \sa daysInYear(), monthsInYear(), minimumDaysInMonth(), maximumDaysInMonth()
657*/
658
659// properties of the calendar
660
661/*!
662 \fn bool QCalendarBackend::isLeapYear(int year) const
663
664 Returns \c true if the specified \a year is a leap year for this calendar.
665
666 \sa daysInYear(), isDateValid()
667*/
668
669/*!
670 \fn bool QCalendarBackend::isLunar() const
671
672 Returns \c true if this calendar is a lunar calendar. Otherwise returns \c
673 false.
674
675 A lunar calendar is a calendar based upon the monthly cycles of the Moon's
676 phases (synodic months). This contrasts with solar calendars, whose annual
677 cycles are based only upon the solar year.
678
679 \sa isLuniSolar(), isSolar(), isProleptic()
680*/
681
682/*!
683 \fn bool QCalendarBackend::isLuniSolar() const
684
685 Returns \c true if this calendar is a lunisolar calendar. Otherwise returns
686 \c false.
687
688 A lunisolar calendar is a calendar whose date indicates both the moon phase
689 and the time of the solar year.
690
691 \sa isLunar(), isSolar(), isProleptic()
692*/
693
694/*!
695 \fn bool QCalendarBackend::isSolar() const
696
697 Returns \c true if this calendar is a solar calendar. Otherwise returns
698 \c false.
699
700 A solar calendar is a calendar whose dates indicate the season or almost
701 equivalently the apparent position of the sun relative to the fixed stars.
702 The Gregorian calendar, widely accepted as standard in the world,
703 is an example of solar calendar.
704
705 \sa isLuniSolar(), isLunar(), isProleptic()
706*/
707
708/*!
709 Returns the total number of days in the year number \a year.
710 Returns zero if there is no such year in this calendar.
711
712 This base implementation returns 366 for leap years and 365 for ordinary
713 years.
714
715 \sa monthsInYear(), daysInMonth(), isLeapYear()
716*/
717int QCalendarBackend::daysInYear(int year) const
718{
719 return monthsInYear(year) ? isLeapYear(year) ? 366 : 365 : 0;
720}
721
722/*!
723 Returns the total number of months in the year number \a year.
724 Returns zero if there is no such year in this calendar.
725
726 This base implementation returns 12 for any valid year.
727
728 \sa daysInYear(), maximumMonthsInYear(), isDateValid()
729*/
730int QCalendarBackend::monthsInYear(int year) const
731{
732 return year > 0 || (year < 0 ? isProleptic() : hasYearZero()) ? 12 : 0;
733}
734
735/*!
736 Returns \c true if the date specified by \a year, \a month, and \a day is
737 valid for this calendar; otherwise returns \c false. For example,
738 the date 2018-04-19 is valid for the Gregorian calendar, but 2018-16-19 and
739 2018-04-38 are invalid.
740
741 Calendars with intercallary days may represent these as extra days of the
742 preceding month or as short months separate from the usual ones. In the
743 former case, a \a day value greater than \c{daysInMonth(\a{month},
744 \a{year})} may be valid.
745
746 \sa daysInMonth(), monthsInYear()
747*/
748bool QCalendarBackend::isDateValid(int year, int month, int day) const
749{
750 return day > 0 && day <= daysInMonth(month, year);
751}
752
753/*!
754 Returns \c true if this calendar is a proleptic calendar. Otherwise returns
755 \c false.
756
757 A proleptic calendar results from allowing negative year numbers to indicate
758 years before the nominal start of the calendar system.
759
760 \sa isLuniSolar(), isSolar(), isLunar(), hasYearZero()
761*/
762
763bool QCalendarBackend::isProleptic() const
764{
765 return true;
766}
767
768/*!
769 Returns \c true if year number \c 0 is considered a valid year in this
770 calendar. Otherwise returns \c false.
771
772 \sa isDateValid(), isProleptic()
773*/
774
775bool QCalendarBackend::hasYearZero() const
776{
777 return false;
778}
779
780/*!
781 Returns the maximum number of days in a month for any year.
782
783 This base implementation returns 31, as this is a common case.
784
785 For calendars with intercallary days, although daysInMonth() doesn't include
786 the intercallary days in its count for an individual month,
787 maximumDaysInMonth() should include intercallary days, so that it is the
788 maximum value of \c day for which \c{isDateValid(year, month, day)} can be
789 true.
790
791 \sa maximumMonthsInYear(), daysInMonth()
792*/
793int QCalendarBackend::maximumDaysInMonth() const
794{
795 return 31;
796}
797
798/*!
799 Returns the minimum number of days in any valid month of any valid year.
800
801 This base implementation returns 29, as this is a common case.
802
803 \sa maximumMonthsInYear(), daysInMonth()
804*/
805int QCalendarBackend::minimumDaysInMonth() const
806{
807 return 29;
808}
809
810/*!
811 Returns the maximum number of months possible in any year.
812
813 This base implementation returns 12, as this is a common case.
814
815 \sa maximumDaysInMonth(), monthsInYear()
816*/
817int QCalendarBackend::maximumMonthsInYear() const
818{
819 return 12;
820}
821
822// Julian day number calculations
823
824/*!
825 \fn bool QCalendarBackend::dateToJulianDay(int year, int month, int day, qint64 *jd) const
826
827 Computes the Julian day number corresponding to the specified \a year, \a
828 month, and \a day. Returns true and sets \a jd if there is such a date in
829 this calendar; otherwise, returns false.
830
831 \sa QCalendar::partsFromDate(), julianDayToDate()
832*/
833
834/*!
835 \fn QCalendar::YearMonthDay QCalendarBackend::julianDayToDate(qint64 jd) const
836
837 Computes the year, month, and day in this calendar for the given Julian day
838 number \a jd. If the given day falls outside this calendar's scope
839 (e.g. before the start-date of a non-proleptic calendar), the returned
840 structure's isValid() is false; otherwise, its year, month, and day fields
841 provide this calendar's description of the date.
842
843 \sa QCalendar::dateFromParts(), dateToJulianDay()
844*/
845
846/*!
847 Returns the day of the week for the given Julian Day Number \a jd.
848
849 This is 1 for Monday through 7 for Sunday.
850
851 Calendars with intercallary days may return larger values for these
852 intercallary days. They should avoid using 0 for any special purpose (it is
853 already used in QDate::dayOfWeek() to mean an invalid date). The calendar
854 should treat the numbers used as an \c enum, whose values need not be
855 contiguous, nor need they follow closely from the 1 through 7 of the usual
856 returns. It suffices that;
857 \list
858 \li weekDayName() can recognize each such number as identifying a distinct
859 name, that it returns to identify the particular intercallary day; and
860 \li matchCenturyToWeekday() can determine what century adjustment aligns a
861 given date within a century to a given day of the week, where this is
862 relevant and possible.
863 \endlist
864
865 This base implementation uses the day-numbering that various calendars have
866 borrowed off the Hebrew calendar.
867
868 \sa weekDayName(), standaloneWeekDayName(), QDate::dayOfWeek(), Qt::DayOfWeek
869*/
870int QCalendarBackend::dayOfWeek(qint64 jd) const
871{
872 return QRoundingDown::qMod<7>(a: jd) + 1;
873}
874
875/*!
876 \since 6.7
877 Adjusts century of \a parts to match \a dow.
878
879 Preserves parts.month and parts.day while adjusting parts.year by a multiple
880 of 100 (taking the absence of year zero into account, when relevant) to
881 obtain a date for which dayOfWeek() is \a dow. Prefers smaller changes over
882 larger and increases to the century over decreases of the same
883 magnitude. Returns the Julian Day number for the selected date or
884 std::numeric_limits<qint64>::min(), a.k.a. QDate::nullJd(), if there is no
885 date matching these requirements.
886
887 The base-class provides a brute-force implementation that steps outwards
888 from the given date by centures, above and below by up to 14 centuries, in
889 search of a matching date. This is neither computationally efficient nor
890 elegant but should work as advertised for calendars in which every month-day
891 combination does appear on all days of the week, across sufficiently many
892 centuries.
893*/
894qint64 QCalendarBackend::matchCenturyToWeekday(const QCalendar::YearMonthDay &parts, int dow) const
895{
896 Q_ASSERT(parts.isValid());
897 // Brute-force solution as fall-back.
898 const auto checkOffset = [parts, dow, this](int centuries) -> std::optional<qint64> {
899 // Offset parts.year by the given number of centuries:
900 int year = parts.year + centuries * 100;
901 // but take into account the effect of crossing zero, if we did:
902 if (!hasYearZero() && (parts.year > 0) != (year > 0))
903 year += parts.year > 0 ? -1 : +1;
904 qint64 jd;
905 if (isDateValid(year, month: parts.month, day: parts.day)
906 && dateToJulianDay(year, month: parts.month, day: parts.day, jd: &jd)
907 && dayOfWeek(jd) == dow) {
908 return jd;
909 }
910 return std::nullopt;
911 };
912 // Empirically, aside from Gregorian, each calendar finds every dow within
913 // any 29-century run, so 14 centuries is the biggest offset we ever need.
914 for (int offset = 0; offset < 15; ++offset) {
915 if (auto jd = checkOffset(offset))
916 return *jd;
917 if (offset) {
918 if (auto jd = checkOffset(-offset))
919 return *jd;
920 }
921 }
922 return (std::numeric_limits<qint64>::min)();
923}
924
925// Month and week-day name look-ups (implemented in qlocale.cpp):
926/*!
927 \fn QString QCalendarBackend::monthName(const QLocale &locale, int month, int year,
928 QLocale::FormatType format) const
929
930 Returns the name of the specified \a month in the given \a year for the
931 chosen \a locale, using the given \a format to determine how complete the
932 name is.
933
934 If \a year is Unspecified, return the name for the month that usually has
935 this number within a typical year. Calendars with a leap month that isn't
936 always the last may need to take account of the year to map the month number
937 to the particular year's month with that number.
938
939 \note Backends for which CLDR provides data can configure the default
940 implementation of the two month name look-up methods by arranging for
941 localeMonthIndexData() and localeMonthData() to provide access to the CLDR
942 data (see cldr2qlocalexml.py, qlocalexml2cpp.py and existing backends).
943 Conversely, backends that override both month name look-up methods need not
944 return anything meaningful from localeMonthIndexData() or localeMonthData().
945
946 \sa standaloneMonthName(), QLocale::monthName()
947*/
948
949/*!
950 \fn QString QCalendarBackend::standaloneMonthName(const QLocale &locale, int month, int year
951 QLocale::FormatType format) const
952
953 Returns the standalone name of the specified \a month in the chosen \a
954 locale, using the specified \a format to determine how complete the name is.
955
956 If \a year is Unspecified, return the standalone name for the month that
957 usually has this number within a typical year. Calendars with a leap month
958 that isn't always the last may need to take account of the year to map the
959 month number to the particular year's month with that number.
960
961 \sa monthName(), QLocale::standaloneMonthName()
962*/
963
964/*!
965 \fn QString QCalendarBackend::weekDayName(const QLocale &locale, int day,
966 QLocale::FormatType format) const
967
968 Returns the name of the specified \a day of the week in the chosen \a
969 locale, using the specified \a format to determine how complete the name is.
970
971 The base implementation handles \a day values from 1 to 7 using the day
972 names CLDR provides, which are suitable for calendards that use the same
973 (Hebrew-derived) week as the Gregorian calendar.
974
975 Calendars whose dayOfWeek() returns a value outside the range from 1 to 7
976 need to reimplement this method to handle such extra week-day values. They
977 can assume that \a day is a value returned by the same calendar's
978 dayOfWeek().
979
980 \sa dayOfWeek(), standaloneWeekDayName(), QLocale::dayName()
981*/
982
983/*!
984 \fn QString QCalendarBackend::standaloneWeekDayName(const QLocale &locale, int day,
985 QLocale::FormatType format) const
986
987 Returns the standalone name of the specified \a day of the week in the
988 chosen \a locale, using the specified \a format to determine how complete
989 the name is.
990
991 The base implementation handles \a day values from 1 to 7 using the
992 standalone day names CLDR provides, which are suitable for calendards that
993 use the same (Hebrew-derived) week as the Gregorian calendar.
994
995 Calendars whose dayOfWeek() returns a value outside the range from 1 to 7
996 need to reimplement this method to handle such extra week-day values. They
997 can assume that \a day is a value returned by the same calendar's
998 dayOfWeek().
999
1000 \sa dayOfWeek(), weekDayName(), QLocale::standaloneDayName()
1001*/
1002
1003/*!
1004 \fn QString QCalendarBackend::dateTimeToString(QStringView format, const QDateTime &datetime,
1005 QDate dateOnly, QTime timeOnly,
1006 const QLocale &locale) const
1007
1008 Returns a string representing a given date, time or date-time.
1009
1010 If \a datetime is specified and valid, it is used and both date and time
1011 format tokens are converted to appropriate representations of the parts of
1012 the datetime. Otherwise, if \a dateOnly is valid, only date format tokens
1013 are converted; else, if \a timeOnly is valid, only time format tokens are
1014 converted. If none are valid, an empty string is returned.
1015
1016 The specified \a locale influences how some format tokens are converted; for
1017 example, when substituting day and month names and their short-forms. For
1018 the supported formatting tokens, see QDate::toString() and
1019 QTime::toString(). As described above, the provided date, time and date-time
1020 determine which of these tokens are recognized: where these appear in \a
1021 format they are replaced by data. Any text in \a format not recognized as a
1022 format token is copied verbatim into the result string.
1023
1024 \sa QDate::toString(), QTime::toString(), QDateTime::toString()
1025*/
1026// End of methods implemented in qlocale.cpp
1027
1028/*!
1029 Returns a list of names of the available calendar systems. Any
1030 QCalendarBackend sub-class must be registered before being exposed to Date
1031 and Time APIs.
1032
1033 \sa fromName()
1034*/
1035QStringList QCalendarBackend::availableCalendars()
1036{
1037 if (Q_UNLIKELY(calendarRegistry.isDestroyed()))
1038 return {};
1039
1040 return calendarRegistry->availableCalendars();
1041}
1042
1043/*!
1044 \internal
1045 Returns a pointer to a named calendar backend.
1046
1047 If the given \a name is present in availableCalendars(), the backend
1048 matching it is returned; otherwise, \nullptr is returned. Matching of
1049 names ignores case.
1050
1051 \sa availableCalendars(), fromEnum(), fromId()
1052*/
1053const QCalendarBackend *QCalendarBackend::fromName(QAnyStringView name)
1054{
1055 if (Q_UNLIKELY(calendarRegistry.isDestroyed()))
1056 return nullptr;
1057
1058 return calendarRegistry->fromName(name);
1059}
1060
1061/*!
1062 \internal
1063 Returns a pointer to a calendar backend, specified by ID.
1064
1065 If a calendar with ID \a id is known to the calendar registry, the backend
1066 with this ID is returned; otherwise, \nullptr is returned.
1067
1068 \sa fromEnum(), calendarId()
1069*/
1070const QCalendarBackend *QCalendarBackend::fromId(QCalendar::SystemId id)
1071{
1072 if (Q_UNLIKELY(calendarRegistry.isDestroyed() || !id.isValid()))
1073 return nullptr;
1074
1075 return calendarRegistry->fromIndex(index: id.index());
1076}
1077
1078/*!
1079 \internal
1080 Returns a pointer to a calendar backend, specified by \c enum.
1081
1082 This will instantiate the indicated calendar (which will enable fromName()
1083 to return it subsequently), but only for the Qt-supported calendars for
1084 which (where relevant) the appropriate feature has been enabled.
1085
1086 \sa fromName(), fromId()
1087*/
1088const QCalendarBackend *QCalendarBackend::fromEnum(QCalendar::System system)
1089{
1090 if (Q_UNLIKELY(calendarRegistry.isDestroyed() || system == QCalendar::System::User))
1091 return nullptr;
1092
1093 return calendarRegistry->fromEnum(system);
1094}
1095
1096/*!
1097 \internal
1098 Returns backend for Gregorian calendar.
1099
1100 The backend is returned without locking the registry if possible.
1101*/
1102const QCalendarBackend *QCalendarBackend::gregorian()
1103{
1104 if (Q_UNLIKELY(calendarRegistry.isDestroyed()))
1105 return nullptr;
1106
1107 return calendarRegistry->gregorian();
1108}
1109
1110/*!
1111 \since 5.14
1112
1113 \class QCalendar
1114 \inmodule QtCore
1115 \reentrant
1116 \brief The QCalendar class describes calendar systems.
1117
1118 A QCalendar object maps a year, month, and day-number to a specific day
1119 (ultimately identified by its Julian day number), using the rules of a
1120 particular system.
1121
1122 The default QCalendar() is a proleptic Gregorian calendar, which has no year
1123 zero. Other calendars may be supported by enabling suitable features or
1124 loading plugins. Calendars supported as features can be constructed by
1125 passing the QCalendar::System enumeration to the constructor. All supported
1126 calendars may be constructed by name, once they have been constructed. (Thus
1127 plugins instantiate their calendar backend to register it.) Built-in
1128 backends, accessible via QCalendar::System, are also always available by
1129 name. Calendars using custom backends may also be constructed using a unique
1130 ID allocated to the backend on construction.
1131
1132 A QCalendar value is immutable.
1133
1134 \sa QDate, QDateTime
1135*/
1136
1137/*!
1138 \enum QCalendar::System
1139
1140 This enumerated type is used to specify a choice of calendar system.
1141
1142 \value Gregorian The default calendar, used internationally.
1143 \value Julian An ancient Roman calendar.
1144 \value Milankovic A revised Julian calendar used by some Orthodox churches.
1145 \value Jalali The Solar Hijri calendar (also called Persian).
1146 \value IslamicCivil The (tabular) Islamic Civil calendar.
1147 \omitvalue Last
1148 \omitvalue User
1149
1150 \sa QCalendar, QCalendar::SystemId
1151*/
1152
1153/*!
1154 \class QCalendar::SystemId
1155 \inmodule QtCore
1156 \since 6.2
1157
1158 This is an opaque type used to identify custom calendar implementations. The
1159 only supported source for values of this type is the backend's \c
1160 calendarId() method. A value of this type whose isValid() is false does not
1161 identify a successfully-registered backend. The only valid consumer of
1162 values of this type is a QCalendar constructor, which will only produce a
1163 valid QCalendar instance if the ID passed to it is valid.
1164
1165 \sa QCalendar, QCalendar::System
1166*/
1167
1168/*!
1169 \fn QCalendar::SystemId::isValid() const
1170
1171 Returns \c true if this is a valid calendar implementation identifier,
1172 \c false otherwise.
1173
1174 \sa QCalendar
1175*/
1176
1177/*!
1178 \internal
1179 \fn QCalendar::SystemId::SystemId()
1180
1181 Constructs an invalid calendar system identifier.
1182*/
1183
1184/*!
1185 \internal
1186 \fn QCalendar::SystemId::index()
1187
1188 Returns the internal representation of the identifier.
1189*/
1190
1191/*!
1192 \fn QCalendar::QCalendar()
1193 \fn QCalendar::QCalendar(QCalendar::System system)
1194 \fn QCalendar::QCalendar(QAnyStringView name)
1195
1196 Constructs a calendar object.
1197
1198 The choice of calendar to use may be indicated by \a system, using the
1199 enumeration QCalendar::System, or by \a name, using a string (either Unicode
1200 or Latin 1). Construction by name may depend on an instance of the given
1201 calendar being constructed by other means first. With no argument, the
1202 default constructor returns the Gregorian calendar.
1203
1204 \note In Qt versions before 6.4, the constructor by \a name accepted only
1205 QStringView and QLatin1String, not QAnyStringView.
1206
1207 \sa QCalendar, System, isValid()
1208*/
1209
1210QCalendar::QCalendar()
1211 : d_ptr(QCalendarBackend::gregorian())
1212{
1213 Q_ASSERT(!d_ptr || d_ptr->calendarId().isValid());
1214}
1215
1216QCalendar::QCalendar(QCalendar::System system) : d_ptr(QCalendarBackend::fromEnum(system))
1217{
1218 // If system is valid, we should get a valid d for that system.
1219 Q_ASSERT(!d_ptr || (uint(system) > uint(QCalendar::System::Last))
1220 || (d_ptr->calendarId().index() == size_t(system)));
1221}
1222
1223/*!
1224 \overload
1225 \since 6.2
1226
1227 Constructs a calendar object.
1228
1229 When using a custom calendar implementation, its backend is allocated a unique
1230 ID when created; passing that as \a id to this constructor will get a
1231 QCalendar using that backend. This can be useful when the backend is not
1232 registered by name.
1233*/
1234QCalendar::QCalendar(QCalendar::SystemId id)
1235 : d_ptr(QCalendarBackend::fromId(id))
1236{
1237 Q_ASSERT(!d_ptr || d_ptr->calendarId().index() == id.index());
1238}
1239
1240QCalendar::QCalendar(QAnyStringView name)
1241 : d_ptr(QCalendarBackend::fromName(name))
1242{
1243 Q_ASSERT(!d_ptr || d_ptr->calendarId().isValid());
1244}
1245
1246/*!
1247 \fn bool QCalendar::isValid() const
1248
1249 Returns true if this is a valid calendar object.
1250
1251 Constructing a calendar with an unrecognised calendar name may result in an
1252 invalid object. Use this method to check after creating a calendar by name.
1253*/
1254
1255// Date queries:
1256
1257/*!
1258 Returns the number of days in the given \a month of the given \a year.
1259
1260 Months are numbered consecutively, starting with 1 for the first month of
1261 each year. If \a year is \c Unspecified (its default, if not passed), the
1262 month's length in a normal year is returned.
1263
1264 \sa maximumDaysInMonth(), minimumDaysInMonth()
1265*/
1266int QCalendar::daysInMonth(int month, int year) const
1267{
1268 SAFE_D();
1269 return d ? d->daysInMonth(month, year) : 0;
1270}
1271
1272/*!
1273 Returns the number of days in the given \a year.
1274
1275 Handling of \c Unspecified as \a year is undefined.
1276*/
1277int QCalendar::daysInYear(int year) const
1278{
1279 SAFE_D();
1280 return d ? d->daysInYear(year) : 0;
1281}
1282
1283/*!
1284 Returns the number of months in the given \a year.
1285
1286 If \a year is \c Unspecified, returns the maximum number of months in a
1287 year.
1288
1289 \sa maximumMonthsInYear()
1290*/
1291int QCalendar::monthsInYear(int year) const
1292{
1293 SAFE_D();
1294 return d ? year == Unspecified ? d->maximumMonthsInYear() : d->monthsInYear(year) : 0;
1295}
1296
1297/*!
1298 Returns \c true precisely if the given \a year, \a month, and \a day specify
1299 a valid date in this calendar.
1300
1301 Usually this means 1 <= month <= monthsInYear(year) and 1 <= day <=
1302 daysInMonth(month, year). However, calendars with intercallary days or
1303 months may complicate that.
1304*/
1305bool QCalendar::isDateValid(int year, int month, int day) const
1306{
1307 SAFE_D();
1308 return d && d->isDateValid(year, month, day);
1309}
1310
1311// properties of the calendar
1312
1313/*!
1314 Returns \c true if this calendar object is the Gregorian calendar object
1315 used as default calendar by other Qt APIs, e.g. in QDate.
1316*/
1317bool QCalendar::isGregorian() const
1318{
1319 SAFE_D();
1320 return d && d->isGregorian();
1321}
1322
1323/*!
1324 Returns \c true if the given \a year is a leap year.
1325
1326 Since the year is not a whole number of days long, some years are longer
1327 than others. The difference may be a whole month or just a single day; the
1328 details vary between calendars.
1329
1330 \sa isDateValid()
1331*/
1332bool QCalendar::isLeapYear(int year) const
1333{
1334 SAFE_D();
1335 return d && d->isLeapYear(year);
1336}
1337
1338/*!
1339 Returns \c true if this calendar is a lunar calendar.
1340
1341 A lunar calendar is one based primarily on the phases of the moon.
1342*/
1343bool QCalendar::isLunar() const
1344{
1345 SAFE_D();
1346 return d && d->isLunar();
1347}
1348
1349/*!
1350 Returns \c true if this calendar is luni-solar.
1351
1352 A luni-solar calendar expresses the phases of the moon but adapts itself to
1353 also keep track of the Sun's varying position in the sky, relative to the
1354 fixed stars.
1355*/
1356bool QCalendar::isLuniSolar() const
1357{
1358 SAFE_D();
1359 return d && d->isLuniSolar();
1360}
1361
1362/*!
1363 Returns \c true if this calendar is solar.
1364
1365 A solar calendar is based primarily on the Sun's varying position in the
1366 sky, relative to the fixed stars.
1367*/
1368bool QCalendar::isSolar() const
1369{
1370 SAFE_D();
1371 return d && d->isSolar();
1372}
1373
1374/*!
1375 Returns \c true if this calendar is proleptic.
1376
1377 A proleptic calendar is able to describe years arbitrarily long before its
1378 first. These are represented by negative year numbers and possibly by a year
1379 zero.
1380
1381 \sa hasYearZero()
1382*/
1383bool QCalendar::isProleptic() const
1384{
1385 SAFE_D();
1386 return d && d->isProleptic();
1387}
1388
1389/*!
1390 Returns \c true if this calendar has a year zero.
1391
1392 A calendar may represent years from its first year onwards but provide no
1393 way to describe years before its first; such a calendar has no year zero and
1394 is not proleptic.
1395
1396 A calendar which represents years before its first may number these years
1397 simply by following the usual integer counting, so that the year before the
1398 first is year zero, with negative-numbered years preceding this; such a
1399 calendar is proleptic and has a year zero. A calendar might also have a year
1400 zero (for example, the year of some great event, with subsequent years being
1401 the first year after that event, the second year after, and so on) without
1402 describing years before its year zero. Such a calendar would have a year
1403 zero without being proleptic.
1404
1405 Some calendars, however, represent years before their first by an alternate
1406 numbering; for example, the proleptic Gregorian calendar's first year is 1
1407 CE and the year before it is 1 BCE, preceded by 2 BCE and so on. In this
1408 case, we use negative year numbers for this alternate numbering, with year
1409 -1 as the year before year 1, year -2 as the year before year -1 and so
1410 on. Such a calendar is proleptic but has no year zero.
1411
1412 \sa isProleptic()
1413*/
1414bool QCalendar::hasYearZero() const
1415{
1416 SAFE_D();
1417 return d && d->hasYearZero();
1418}
1419
1420/*!
1421 Returns the number of days in the longest month in the calendar, in any year.
1422
1423 \sa daysInMonth(), minimumDaysInMonth()
1424*/
1425int QCalendar::maximumDaysInMonth() const
1426{
1427 SAFE_D();
1428 return d ? d->maximumDaysInMonth() : 0;
1429}
1430
1431/*!
1432 Returns the number of days in the shortest month in the calendar, in any year.
1433
1434 \sa daysInMonth(), maximumDaysInMonth()
1435*/
1436int QCalendar::minimumDaysInMonth() const
1437{
1438 SAFE_D();
1439 return d ? d->minimumDaysInMonth() : 0;
1440}
1441
1442/*!
1443 Returns the largest number of months that any year may contain.
1444
1445 \sa monthName(), standaloneMonthName(), monthsInYear()
1446*/
1447int QCalendar::maximumMonthsInYear() const
1448{
1449 SAFE_D();
1450 return d ? d->maximumMonthsInYear() : 0;
1451}
1452
1453// Julian Day conversions:
1454
1455/*!
1456 \fn QDate QCalendar::dateFromParts(int year, int month, int day) const
1457 \fn QDate QCalendar::dateFromParts(const QCalendar::YearMonthDay &parts) const
1458
1459 Converts a year, month, and day to a QDate.
1460
1461 The \a year, \a month, and \a day may be passed as separate numbers or
1462 packaged together as the members of \a parts. Returns a QDate with the given
1463 year, month, and day of the month in this calendar, if there is one.
1464 Otherwise, including the case where any of the values is
1465 QCalendar::Unspecified, returns a QDate whose isNull() is true.
1466
1467 \sa isDateValid(), partsFromDate()
1468*/
1469QDate QCalendar::dateFromParts(int year, int month, int day) const
1470{
1471 SAFE_D();
1472 qint64 jd;
1473 return d && d->dateToJulianDay(year, month, day, jd: &jd)
1474 ? QDate::fromJulianDay(jd_: jd) : QDate();
1475}
1476
1477QDate QCalendar::dateFromParts(const QCalendar::YearMonthDay &parts) const
1478{
1479 return parts.isValid() ? dateFromParts(year: parts.year, month: parts.month, day: parts.day) : QDate();
1480}
1481
1482/*!
1483 \since 6.7
1484 Adjusts the century of a date to match a given day of the week.
1485
1486 For use when given a date's day of week, day of month, month and last two
1487 digits of the year. Returns a QDate instance with the given \a dow as its \l
1488 {QDate::}{dayOfWeek()}, matching the given \a parts in month and day of the
1489 month. The returned QDate's \l {QDate::}{year()} shall differ from
1490 \c{parts.year} by a multiple of 100, preferring small multiples over larger
1491 and positive multiples over their negations.
1492
1493 If no date matches these conditions, an invalid QDate is returned: the day
1494 of week is incompatible with the other data given. This arises, for example,
1495 with the Gregorian calendar, whose 400-year cycle is a whole number of weeks
1496 long, so any given month and day of that month only ever falls, in years
1497 with a given last two digits, on four days of the week. (In the special case
1498 of February 29th at the turn of a century, when that is a leap year, only
1499 one day of the week is possible: Tuesday.)
1500*/
1501QDate QCalendar::matchCenturyToWeekday(const QCalendar::YearMonthDay &parts, int dow) const
1502{
1503 SAFE_D();
1504 return d && parts.isValid()
1505 ? QDate::fromJulianDay(jd_: d->matchCenturyToWeekday(parts, dow)) : QDate();
1506}
1507
1508/*!
1509 Converts a QDate to a year, month, and day of the month.
1510
1511 The returned structure's isValid() shall be false if the calendar is unable
1512 to represent the given \a date. Otherwise its year, month, and day
1513 members record the so-named parts of its representation.
1514
1515 \sa dateFromParts(), isProleptic(), hasYearZero()
1516*/
1517QCalendar::YearMonthDay QCalendar::partsFromDate(QDate date) const
1518{
1519 SAFE_D();
1520 return d && date.isValid() ? d->julianDayToDate(jd: date.toJulianDay()) : YearMonthDay();
1521}
1522
1523/*!
1524 Returns the day of the week number for the given \a date.
1525
1526 Returns zero if the calendar is unable to represent the indicated date.
1527 Returns 1 for Monday through 7 for Sunday. Calendars with intercallary days
1528 may use other numbers to represent these.
1529
1530 \sa partsFromDate(), Qt::DayOfWeek
1531*/
1532int QCalendar::dayOfWeek(QDate date) const
1533{
1534 SAFE_D();
1535 return d && date.isValid() ? d->dayOfWeek(jd: date.toJulianDay()) : 0;
1536}
1537
1538// Locale data access
1539
1540/*!
1541 Returns a suitably localised name for a month.
1542
1543 The month is indicated by a number, with \a month = 1 meaning the first
1544 month of the year and subsequent months numbered accordingly. Returns an
1545 empty string if the \a month number is unrecognized.
1546
1547 The \a year may be Unspecified, in which case the mapping from numbers to
1548 names for a typical year's months should be used. Some calendars have leap
1549 months that aren't always at the end of the year; their mapping of month
1550 numbers to names may then depend on the placement of a leap month. Thus the
1551 year should normally be specified, if known.
1552
1553 The name is returned in the form that would normally be used in a full date,
1554 in the specified \a locale; the \a format determines how fully it shall be
1555 expressed (i.e. to what extent it is abbreviated).
1556
1557 \sa standaloneMonthName(), maximumMonthsInYear(), dateTimeToString()
1558*/
1559QString QCalendar::monthName(const QLocale &locale, int month, int year,
1560 QLocale::FormatType format) const
1561{
1562 SAFE_D();
1563 const int maxMonth = year == Unspecified ? maximumMonthsInYear() : monthsInYear(year);
1564 if (!d || month < 1 || month > maxMonth)
1565 return QString();
1566
1567 return d->monthName(locale, month, year, format);
1568}
1569
1570/*!
1571 Returns a suitably localised standalone name for a month.
1572
1573 The month is indicated by a number, with \a month = 1 meaning the first
1574 month of the year and subsequent months numbered accordingly. Returns an
1575 empty string if the \a month number is unrecognized.
1576
1577 The \a year may be Unspecified, in which case the mapping from numbers to
1578 names for a typical year's months should be used. Some calendars have leap
1579 months that aren't always at the end of the year; their mapping of month
1580 numbers to names may then depend on the placement of a leap month. Thus the
1581 year should normally be specified, if known.
1582
1583 The name is returned in the form that would be used in isolation in the
1584 specified \a locale; the \a format determines how fully it shall be
1585 expressed (i.e. to what extent it is abbreviated).
1586
1587 \sa monthName(), maximumMonthsInYear(), dateTimeToString()
1588*/
1589QString QCalendar::standaloneMonthName(const QLocale &locale, int month, int year,
1590 QLocale::FormatType format) const
1591{
1592 SAFE_D();
1593 const int maxMonth = year == Unspecified ? maximumMonthsInYear() : monthsInYear(year);
1594 if (!d || month < 1 || month > maxMonth)
1595 return QString();
1596
1597 return d->standaloneMonthName(locale, month, year, format);
1598}
1599
1600/*!
1601 Returns a suitably localised name for a day of the week.
1602
1603 The days of the week are numbered from 1 for Monday through 7 for
1604 Sunday. Some calendars may support higher numbers for other days
1605 (e.g. intercallary days, that are not part of any week). Returns an empty
1606 string if the \a day number is unrecognized.
1607
1608 The name is returned in the form that would normally be used in a full date,
1609 in the specified \a locale; the \a format determines how fully it shall be
1610 expressed (i.e. to what extent it is abbreviated).
1611
1612 \sa standaloneWeekDayName(), dayOfWeek()
1613*/
1614QString QCalendar::weekDayName(const QLocale &locale, int day,
1615 QLocale::FormatType format) const
1616{
1617 SAFE_D();
1618 return d ? d->weekDayName(locale, day, format) : QString();
1619}
1620
1621/*!
1622 Returns a suitably localised standalone name for a day of the week.
1623
1624 The days of the week are numbered from 1 for Monday through 7 for
1625 Sunday. Some calendars may support higher numbers for other days
1626 (e.g. intercallary days, that are not part of any week). Returns an empty
1627 string if the \a day number is unrecognized.
1628
1629 The name is returned in the form that would be used in isolation (for
1630 example as a column heading in a calendar's tabular display of a month with
1631 successive weeks as rows) in the specified \a locale; the \a format
1632 determines how fully it shall be expressed (i.e. to what extent it is
1633 abbreviated).
1634
1635 \sa weekDayName(), dayOfWeek()
1636*/
1637QString QCalendar::standaloneWeekDayName(const QLocale &locale, int day,
1638 QLocale::FormatType format) const
1639{
1640 SAFE_D();
1641 return d ? d->standaloneWeekDayName(locale, day, format) : QString();
1642}
1643
1644/*!
1645 Returns a string representing a given date, time or date-time.
1646
1647 If \a datetime is valid, it is represented and format specifiers for both
1648 date and time fields are recognized; otherwise, if \a dateOnly is valid, it
1649 is represented and only format specifiers for date fields are recognized;
1650 finally, if \a timeOnly is valid, it is represented and only format
1651 specifiers for time fields are recognized. If none of these is valid, an
1652 empty string is returned.
1653
1654 See QDate::toString and QTime::toString() for the supported field
1655 specifiers. Characters in \a format that are recognized as field specifiers
1656 are replaced by text representing appropriate data from the date and/or time
1657 being represented. The texts to represent them may depend on the \a locale
1658 specified. Other charagers in \a format are copied verbatim into the
1659 returned string.
1660
1661 \sa monthName(), weekDayName(), QDate::toString(), QTime::toString()
1662*/
1663QString QCalendar::dateTimeToString(QStringView format, const QDateTime &datetime,
1664 QDate dateOnly, QTime timeOnly,
1665 const QLocale &locale) const
1666{
1667 SAFE_D();
1668 return d ? d->dateTimeToString(format, datetime, dateOnly, timeOnly, locale) : QString();
1669}
1670
1671/*!
1672 Returns a list of names of the available calendar systems.
1673
1674 These may be supplied by plugins or other code linked into an application,
1675 in addition to the ones provided by Qt, some of which are controlled by
1676 features.
1677*/
1678QStringList QCalendar::availableCalendars()
1679{
1680 return QCalendarBackend::availableCalendars();
1681}
1682
1683QT_END_NAMESPACE
1684
1685#ifndef QT_BOOTSTRAPPED
1686#include "moc_qcalendar.cpp"
1687#endif
1688

source code of qtbase/src/corelib/time/qcalendar.cpp