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