1 | // Copyright (C) 2021 The Qt Company Ltd. |
2 | // Copyright (C) 2021 Intel Corporation. |
3 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
4 | |
5 | #ifndef QDATETIME_H |
6 | #define QDATETIME_H |
7 | |
8 | #include <QtCore/qcalendar.h> |
9 | #include <QtCore/qcompare.h> |
10 | #include <QtCore/qlocale.h> |
11 | #include <QtCore/qnamespace.h> |
12 | #include <QtCore/qshareddata.h> |
13 | #include <QtCore/qstring.h> |
14 | |
15 | #include <limits> |
16 | #include <chrono> |
17 | |
18 | #if defined(Q_OS_DARWIN) || defined(Q_QDOC) |
19 | Q_FORWARD_DECLARE_CF_TYPE(CFDate); |
20 | Q_FORWARD_DECLARE_OBJC_CLASS(NSDate); |
21 | #endif |
22 | |
23 | QT_BEGIN_NAMESPACE |
24 | |
25 | class QTimeZone; |
26 | class QDateTime; |
27 | |
28 | class Q_CORE_EXPORT QDate |
29 | { |
30 | explicit constexpr QDate(qint64 julianDay) : jd(julianDay) {} |
31 | public: |
32 | constexpr QDate() : jd(nullJd()) {} |
33 | QDate(int y, int m, int d); |
34 | QDate(int y, int m, int d, QCalendar cal); |
35 | #if __cpp_lib_chrono >= 201907L || defined(Q_QDOC) |
36 | QT_POST_CXX17_API_IN_EXPORTED_CLASS |
37 | Q_IMPLICIT constexpr QDate(std::chrono::year_month_day date) noexcept |
38 | : jd(date.ok() ? stdSysDaysToJulianDay(days: date QT6_CALL_NEW_OVERLOAD_TAIL) : nullJd()) |
39 | {} |
40 | |
41 | QT_POST_CXX17_API_IN_EXPORTED_CLASS |
42 | Q_IMPLICIT constexpr QDate(std::chrono::year_month_day_last date) noexcept |
43 | : jd(date.ok() ? stdSysDaysToJulianDay(days: date QT6_CALL_NEW_OVERLOAD_TAIL) : nullJd()) |
44 | {} |
45 | |
46 | QT_POST_CXX17_API_IN_EXPORTED_CLASS |
47 | Q_IMPLICIT constexpr QDate(std::chrono::year_month_weekday date) noexcept |
48 | : jd(date.ok() ? stdSysDaysToJulianDay(days: date QT6_CALL_NEW_OVERLOAD_TAIL) : nullJd()) |
49 | {} |
50 | |
51 | QT_POST_CXX17_API_IN_EXPORTED_CLASS |
52 | Q_IMPLICIT constexpr QDate(std::chrono::year_month_weekday_last date) noexcept |
53 | : jd(date.ok() ? stdSysDaysToJulianDay(days: date QT6_CALL_NEW_OVERLOAD_TAIL) : nullJd()) |
54 | {} |
55 | |
56 | QT_POST_CXX17_API_IN_EXPORTED_CLASS |
57 | static constexpr QDate fromStdSysDays(const std::chrono::sys_days &days) noexcept |
58 | { |
59 | return QDate(stdSysDaysToJulianDay(days QT6_CALL_NEW_OVERLOAD_TAIL)); |
60 | } |
61 | |
62 | QT_POST_CXX17_API_IN_EXPORTED_CLASS |
63 | constexpr std::chrono::sys_days toStdSysDays() const noexcept |
64 | { |
65 | const qint64 days = isValid() ? jd - unixEpochJd() : 0; |
66 | return std::chrono::sys_days(std::chrono::days(days)); |
67 | } |
68 | #endif |
69 | |
70 | constexpr bool isNull() const { return !isValid(); } |
71 | constexpr bool isValid() const { return jd >= minJd() && jd <= maxJd(); } |
72 | |
73 | // Gregorian-optimized: |
74 | int year() const; |
75 | int month() const; |
76 | int day() const; |
77 | int dayOfWeek() const; |
78 | int dayOfYear() const; |
79 | int daysInMonth() const; |
80 | int daysInYear() const; |
81 | int weekNumber(int *yearNum = nullptr) const; // ISO 8601, always Gregorian |
82 | |
83 | int year(QCalendar cal) const; |
84 | int month(QCalendar cal) const; |
85 | int day(QCalendar cal) const; |
86 | int dayOfWeek(QCalendar cal) const; |
87 | int dayOfYear(QCalendar cal) const; |
88 | int daysInMonth(QCalendar cal) const; |
89 | int daysInYear(QCalendar cal) const; |
90 | |
91 | #if QT_DEPRECATED_SINCE(6, 9) |
92 | QT_DEPRECATED_VERSION_X_6_9("Pass QTimeZone instead" ) |
93 | QDateTime startOfDay(Qt::TimeSpec spec, int offsetSeconds = 0) const; |
94 | QT_DEPRECATED_VERSION_X_6_9("Pass QTimeZone instead" ) |
95 | QDateTime endOfDay(Qt::TimeSpec spec, int offsetSeconds = 0) const; |
96 | #endif |
97 | |
98 | QDateTime startOfDay(const QTimeZone &zone) const; |
99 | QDateTime endOfDay(const QTimeZone &zone) const; |
100 | QDateTime startOfDay() const; |
101 | QDateTime endOfDay() const; |
102 | |
103 | #if QT_CONFIG(datestring) |
104 | QString toString(Qt::DateFormat format = Qt::TextDate) const; |
105 | QString toString(const QString &format) const; |
106 | QString toString(const QString &format, QCalendar cal) const |
107 | { return toString(format: qToStringViewIgnoringNull(s: format), cal); } |
108 | QString toString(QStringView format) const; |
109 | QString toString(QStringView format, QCalendar cal) const; |
110 | #endif |
111 | bool setDate(int year, int month, int day); // Gregorian-optimized |
112 | bool setDate(int year, int month, int day, QCalendar cal); |
113 | |
114 | void getDate(int *year, int *month, int *day) const; |
115 | |
116 | [[nodiscard]] QDate addDays(qint64 days) const; |
117 | #if __cpp_lib_chrono >= 201907L || defined(Q_QDOC) |
118 | QT_POST_CXX17_API_IN_EXPORTED_CLASS |
119 | [[nodiscard]] QDate addDuration(std::chrono::days days) const |
120 | { |
121 | return addDays(days: days.count()); |
122 | } |
123 | #endif |
124 | // Gregorian-optimized: |
125 | [[nodiscard]] QDate addMonths(int months) const; |
126 | [[nodiscard]] QDate addYears(int years) const; |
127 | [[nodiscard]] QDate addMonths(int months, QCalendar cal) const; |
128 | [[nodiscard]] QDate addYears(int years, QCalendar cal) const; |
129 | qint64 daysTo(QDate d) const; |
130 | |
131 | static QDate currentDate(); |
132 | #if QT_CONFIG(datestring) |
133 | // No DateFormat accepts a two-digit year, so no need for baseYear: |
134 | static QDate fromString(QStringView string, Qt::DateFormat format = Qt::TextDate); |
135 | static QDate fromString(const QString &string, Qt::DateFormat format = Qt::TextDate) |
136 | { return fromString(string: qToStringViewIgnoringNull(s: string), format); } |
137 | |
138 | // Accept calendar without over-ride of base year: |
139 | static QDate fromString(QStringView string, QStringView format, QCalendar cal) |
140 | { return fromString(string: string.toString(), format, baseYear: QLocale::DefaultTwoDigitBaseYear, cal); } |
141 | QT_CORE_INLINE_SINCE(6, 7) |
142 | static QDate fromString(const QString &string, QStringView format, QCalendar cal); |
143 | static QDate fromString(const QString &string, const QString &format, QCalendar cal) |
144 | { return fromString(string, format: qToStringViewIgnoringNull(s: format), baseYear: QLocale::DefaultTwoDigitBaseYear, cal); } |
145 | |
146 | // Overriding base year is likely more common than overriding calendar (and |
147 | // likely to get more so, as the legacy base drops ever further behind us). |
148 | static QDate fromString(QStringView string, QStringView format, |
149 | int baseYear = QLocale::DefaultTwoDigitBaseYear) |
150 | { return fromString(string: string.toString(), format, baseYear); } |
151 | static QDate fromString(QStringView string, QStringView format, |
152 | int baseYear, QCalendar cal) |
153 | { return fromString(string: string.toString(), format, baseYear, cal); } |
154 | static QDate fromString(const QString &string, QStringView format, |
155 | int baseYear = QLocale::DefaultTwoDigitBaseYear); |
156 | static QDate fromString(const QString &string, QStringView format, |
157 | int baseYear, QCalendar cal); |
158 | static QDate fromString(const QString &string, const QString &format, |
159 | int baseYear = QLocale::DefaultTwoDigitBaseYear) |
160 | { return fromString(string, format: qToStringViewIgnoringNull(s: format), baseYear); } |
161 | static QDate fromString(const QString &string, const QString &format, |
162 | int baseYear, QCalendar cal) |
163 | { return fromString(string, format: qToStringViewIgnoringNull(s: format), baseYear, cal); } |
164 | #endif |
165 | static bool isValid(int y, int m, int d); |
166 | static bool isLeapYear(int year); |
167 | |
168 | static constexpr inline QDate fromJulianDay(qint64 jd_) |
169 | { return jd_ >= minJd() && jd_ <= maxJd() ? QDate(jd_) : QDate() ; } |
170 | constexpr inline qint64 toJulianDay() const { return jd; } |
171 | |
172 | private: |
173 | // using extra parentheses around min to avoid expanding it if it is a macro |
174 | static constexpr inline qint64 nullJd() { return (std::numeric_limits<qint64>::min)(); } |
175 | static constexpr inline qint64 minJd() { return Q_INT64_C(-784350574879); } |
176 | static constexpr inline qint64 maxJd() { return Q_INT64_C( 784354017364); } |
177 | static constexpr inline qint64 unixEpochJd() { return Q_INT64_C(2440588); } |
178 | |
179 | #if __cpp_lib_chrono >= 201907L |
180 | QT_POST_CXX17_API_IN_EXPORTED_CLASS |
181 | static constexpr qint64 |
182 | stdSysDaysToJulianDay(const std::chrono::sys_days &days QT6_DECL_NEW_OVERLOAD_TAIL) noexcept |
183 | { |
184 | const auto epochDays = days.time_since_epoch().count(); |
185 | // minJd() and maxJd() fit into 40 bits. |
186 | if constexpr (sizeof(epochDays) * CHAR_BIT >= 41) { |
187 | constexpr auto top = maxJd() - unixEpochJd(); |
188 | constexpr auto bottom = minJd() - unixEpochJd(); |
189 | if (epochDays > top || epochDays < bottom) |
190 | return nullJd(); |
191 | } |
192 | return unixEpochJd() + epochDays; |
193 | } |
194 | |
195 | #if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) |
196 | static constexpr qint64 stdSysDaysToJulianDay(const std::chrono::sys_days &days) noexcept |
197 | { |
198 | return stdSysDaysToJulianDay(days QT6_CALL_NEW_OVERLOAD_TAIL); |
199 | } |
200 | #endif // QT_VERSION < QT_VERSION_CHECK(7, 0, 0) |
201 | #endif // __cpp_lib_chrono >= 201907L |
202 | |
203 | qint64 jd; |
204 | |
205 | friend class QDateTime; |
206 | friend class QDateTimeParser; |
207 | friend class QDateTimePrivate; |
208 | |
209 | friend constexpr bool comparesEqual(const QDate &lhs, const QDate &rhs) noexcept |
210 | { return lhs.jd == rhs.jd; } |
211 | friend constexpr Qt::strong_ordering |
212 | compareThreeWay(const QDate &lhs, const QDate &rhs) noexcept |
213 | { return Qt::compareThreeWay(lhs: lhs.jd, rhs: rhs.jd); } |
214 | Q_DECLARE_STRONGLY_ORDERED_LITERAL_TYPE(QDate) |
215 | |
216 | #ifndef QT_NO_DATASTREAM |
217 | friend Q_CORE_EXPORT QDataStream &operator<<(QDataStream &, QDate); |
218 | friend Q_CORE_EXPORT QDataStream &operator>>(QDataStream &, QDate &); |
219 | #endif |
220 | }; |
221 | Q_DECLARE_TYPEINFO(QDate, Q_RELOCATABLE_TYPE); |
222 | |
223 | class Q_CORE_EXPORT QTime |
224 | { |
225 | explicit constexpr QTime(int ms) : mds(ms) |
226 | {} |
227 | public: |
228 | constexpr QTime(): mds(NullTime) |
229 | {} |
230 | QTime(int h, int m, int s = 0, int ms = 0); |
231 | |
232 | constexpr bool isNull() const { return mds == NullTime; } |
233 | bool isValid() const; |
234 | |
235 | int hour() const; |
236 | int minute() const; |
237 | int second() const; |
238 | int msec() const; |
239 | #if QT_CONFIG(datestring) |
240 | QString toString(Qt::DateFormat f = Qt::TextDate) const; |
241 | QString toString(const QString &format) const |
242 | { return toString(format: qToStringViewIgnoringNull(s: format)); } |
243 | QString toString(QStringView format) const; |
244 | #endif |
245 | bool setHMS(int h, int m, int s, int ms = 0); |
246 | |
247 | [[nodiscard]] QTime addSecs(int secs) const; |
248 | int secsTo(QTime t) const; |
249 | [[nodiscard]] QTime addMSecs(int ms) const; |
250 | int msecsTo(QTime t) const; |
251 | |
252 | static constexpr inline QTime fromMSecsSinceStartOfDay(int msecs) { return QTime(msecs); } |
253 | constexpr inline int msecsSinceStartOfDay() const { return mds == NullTime ? 0 : mds; } |
254 | |
255 | static QTime currentTime(); |
256 | #if QT_CONFIG(datestring) |
257 | static QTime fromString(QStringView string, Qt::DateFormat format = Qt::TextDate); |
258 | static QTime fromString(QStringView string, QStringView format) |
259 | { return fromString(string: string.toString(), format); } |
260 | static QTime fromString(const QString &string, QStringView format); |
261 | static QTime fromString(const QString &string, Qt::DateFormat format = Qt::TextDate) |
262 | { return fromString(string: qToStringViewIgnoringNull(s: string), format); } |
263 | static QTime fromString(const QString &string, const QString &format) |
264 | { return fromString(string, format: qToStringViewIgnoringNull(s: format)); } |
265 | #endif |
266 | static bool isValid(int h, int m, int s, int ms = 0); |
267 | |
268 | private: |
269 | enum TimeFlag { NullTime = -1 }; |
270 | constexpr inline int ds() const { return mds == -1 ? 0 : mds; } |
271 | int mds; |
272 | |
273 | friend constexpr bool comparesEqual(const QTime &lhs, const QTime &rhs) noexcept |
274 | { return lhs.mds == rhs.mds; } |
275 | friend constexpr Qt::strong_ordering |
276 | compareThreeWay(const QTime &lhs, const QTime &rhs) noexcept |
277 | { return Qt::compareThreeWay(lhs: lhs.mds, rhs: rhs.mds); } |
278 | Q_DECLARE_STRONGLY_ORDERED_LITERAL_TYPE(QTime) |
279 | |
280 | friend class QDateTime; |
281 | friend class QDateTimePrivate; |
282 | #ifndef QT_NO_DATASTREAM |
283 | friend Q_CORE_EXPORT QDataStream &operator<<(QDataStream &, QTime); |
284 | friend Q_CORE_EXPORT QDataStream &operator>>(QDataStream &, QTime &); |
285 | #endif |
286 | }; |
287 | Q_DECLARE_TYPEINFO(QTime, Q_RELOCATABLE_TYPE); |
288 | |
289 | class QDateTimePrivate; |
290 | |
291 | class Q_CORE_EXPORT QDateTime |
292 | { |
293 | struct ShortData { |
294 | #if QT_VERSION >= QT_VERSION_CHECK(7,0,0) || defined(QT_BOOTSTRAPPED) |
295 | # if Q_BYTE_ORDER == Q_LITTLE_ENDIAN |
296 | qint64 status : 8; |
297 | # endif |
298 | qint64 msecs : 56; |
299 | |
300 | # if Q_BYTE_ORDER == Q_BIG_ENDIAN |
301 | qint64 status : 8; |
302 | # endif |
303 | #else |
304 | # if Q_BYTE_ORDER == Q_LITTLE_ENDIAN |
305 | quintptr status : 8; |
306 | # endif |
307 | // note: this is only 24 bits on 32-bit systems... |
308 | qintptr msecs : sizeof(void *) * 8 - 8; |
309 | |
310 | # if Q_BYTE_ORDER == Q_BIG_ENDIAN |
311 | quintptr status : 8; |
312 | # endif |
313 | #endif |
314 | friend constexpr bool operator==(const ShortData &lhs, const ShortData &rhs) |
315 | { return lhs.status == rhs.status && lhs.msecs == rhs.msecs; } |
316 | }; |
317 | |
318 | union Data { |
319 | // To be of any use, we need at least 60 years around 1970, which |
320 | // is 1,893,456,000,000 ms. That requires 41 bits to store, plus |
321 | // the sign bit. With the status byte, the minimum size is 50 bits. |
322 | static constexpr bool CanBeSmall = sizeof(ShortData) * 8 > 50; |
323 | |
324 | Data() noexcept; |
325 | Data(const QTimeZone &); |
326 | Data(const Data &other) noexcept; |
327 | Data(Data &&other) noexcept; |
328 | Data &operator=(const Data &other) noexcept; |
329 | Data &operator=(Data &&other) noexcept { swap(other); return *this; } |
330 | ~Data(); |
331 | |
332 | void swap(Data &other) noexcept |
333 | { std::swap(a&: data, b&: other.data); } |
334 | |
335 | bool isShort() const; |
336 | inline void invalidate(); |
337 | void detach(); |
338 | QTimeZone timeZone() const; |
339 | |
340 | const QDateTimePrivate *operator->() const; |
341 | QDateTimePrivate *operator->(); |
342 | |
343 | QDateTimePrivate *d; |
344 | ShortData data; |
345 | }; |
346 | |
347 | public: |
348 | QDateTime() noexcept; |
349 | |
350 | enum class TransitionResolution { |
351 | Reject = 0, |
352 | RelativeToBefore, |
353 | RelativeToAfter, |
354 | PreferBefore, |
355 | PreferAfter, |
356 | PreferStandard, |
357 | PreferDaylightSaving, |
358 | // Closest match to behavior prior to introducing TransitionResolution: |
359 | LegacyBehavior = RelativeToBefore |
360 | }; |
361 | |
362 | #if QT_DEPRECATED_SINCE(6, 9) |
363 | QT_DEPRECATED_VERSION_X_6_9("Pass QTimeZone instead" ) |
364 | QDateTime(QDate date, QTime time, Qt::TimeSpec spec, int offsetSeconds = 0); |
365 | #endif |
366 | #if QT_CORE_REMOVED_SINCE(6, 7) |
367 | QDateTime(QDate date, QTime time, const QTimeZone &timeZone); |
368 | QDateTime(QDate date, QTime time); |
369 | #endif |
370 | QDateTime(QDate date, QTime time, const QTimeZone &timeZone, |
371 | TransitionResolution resolve = TransitionResolution::LegacyBehavior); |
372 | QDateTime(QDate date, QTime time, |
373 | TransitionResolution resolve = TransitionResolution::LegacyBehavior); |
374 | QDateTime(const QDateTime &other) noexcept; |
375 | QDateTime(QDateTime &&other) noexcept; |
376 | ~QDateTime(); |
377 | |
378 | QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QDateTime) |
379 | QDateTime &operator=(const QDateTime &other) noexcept; |
380 | |
381 | void swap(QDateTime &other) noexcept { d.swap(other&: other.d); } |
382 | |
383 | bool isNull() const; |
384 | bool isValid() const; |
385 | |
386 | QDate date() const; |
387 | QTime time() const; |
388 | Qt::TimeSpec timeSpec() const; |
389 | int offsetFromUtc() const; |
390 | QTimeZone timeRepresentation() const; |
391 | #if QT_CONFIG(timezone) |
392 | QTimeZone timeZone() const; |
393 | #endif // timezone |
394 | QString timeZoneAbbreviation() const; |
395 | bool isDaylightTime() const; |
396 | |
397 | qint64 toMSecsSinceEpoch() const; |
398 | qint64 toSecsSinceEpoch() const; |
399 | |
400 | #if QT_CORE_REMOVED_SINCE(6, 7) |
401 | void setDate(QDate date); |
402 | void setTime(QTime time); |
403 | #endif |
404 | void setDate(QDate date, TransitionResolution resolve = TransitionResolution::LegacyBehavior); |
405 | void setTime(QTime time, TransitionResolution resolve = TransitionResolution::LegacyBehavior); |
406 | |
407 | #if QT_DEPRECATED_SINCE(6, 9) |
408 | QT_DEPRECATED_VERSION_X_6_9("Use setTimeZone() instead" ) |
409 | void setTimeSpec(Qt::TimeSpec spec); |
410 | QT_DEPRECATED_VERSION_X_6_9("Use setTimeZone() instead" ) |
411 | void setOffsetFromUtc(int offsetSeconds); |
412 | #endif |
413 | #if QT_CORE_REMOVED_SINCE(6, 7) |
414 | void setTimeZone(const QTimeZone &toZone); |
415 | #endif |
416 | void setTimeZone(const QTimeZone &toZone, |
417 | TransitionResolution resolve = TransitionResolution::LegacyBehavior); |
418 | void setMSecsSinceEpoch(qint64 msecs); |
419 | void setSecsSinceEpoch(qint64 secs); |
420 | |
421 | #if QT_CONFIG(datestring) |
422 | QString toString(Qt::DateFormat format = Qt::TextDate) const; |
423 | QString toString(const QString &format) const; |
424 | QString toString(const QString &format, QCalendar cal) const |
425 | { return toString(format: qToStringViewIgnoringNull(s: format), cal); } |
426 | QString toString(QStringView format) const; |
427 | QString toString(QStringView format, QCalendar cal) const; |
428 | #endif |
429 | [[nodiscard]] QDateTime addDays(qint64 days) const; |
430 | [[nodiscard]] QDateTime addMonths(int months) const; |
431 | [[nodiscard]] QDateTime addYears(int years) const; |
432 | [[nodiscard]] QDateTime addSecs(qint64 secs) const; |
433 | [[nodiscard]] QDateTime addMSecs(qint64 msecs) const; |
434 | [[nodiscard]] QDateTime addDuration(std::chrono::milliseconds msecs) const |
435 | { |
436 | return addMSecs(msecs: msecs.count()); |
437 | } |
438 | |
439 | #if QT_DEPRECATED_SINCE(6, 9) |
440 | QT_DEPRECATED_VERSION_X_6_9("Use toTimeZone instead" ) |
441 | QDateTime toTimeSpec(Qt::TimeSpec spec) const; |
442 | #endif |
443 | QDateTime toLocalTime() const; |
444 | QDateTime toUTC() const; |
445 | QDateTime toOffsetFromUtc(int offsetSeconds) const; |
446 | QDateTime toTimeZone(const QTimeZone &toZone) const; |
447 | |
448 | qint64 daysTo(const QDateTime &) const; |
449 | qint64 secsTo(const QDateTime &) const; |
450 | qint64 msecsTo(const QDateTime &) const; |
451 | |
452 | static QDateTime currentDateTime(const QTimeZone &zone); |
453 | static QDateTime currentDateTime(); |
454 | static QDateTime currentDateTimeUtc(); |
455 | #if QT_CONFIG(datestring) |
456 | // No DateFormat accepts a two-digit year, so no need for baseYear: |
457 | static QDateTime fromString(QStringView string, Qt::DateFormat format = Qt::TextDate); |
458 | static QDateTime fromString(const QString &string, Qt::DateFormat format = Qt::TextDate) |
459 | { return fromString(string: qToStringViewIgnoringNull(s: string), format); } |
460 | |
461 | // Accept calendar without over-ride of base year: |
462 | static QDateTime fromString(QStringView string, QStringView format, QCalendar cal) |
463 | { return fromString(string: string.toString(), format, baseYear: QLocale::DefaultTwoDigitBaseYear, cal); } |
464 | QT_CORE_INLINE_SINCE(6, 7) |
465 | static QDateTime fromString(const QString &string, QStringView format, QCalendar cal); |
466 | static QDateTime fromString(const QString &string, const QString &format, QCalendar cal) |
467 | { return fromString(string, format: qToStringViewIgnoringNull(s: format), baseYear: QLocale::DefaultTwoDigitBaseYear, cal); } |
468 | |
469 | // Overriding base year is likely more common than overriding calendar (and |
470 | // likely to get more so, as the legacy base drops ever further behind us). |
471 | static QDateTime fromString(QStringView string, QStringView format, |
472 | int baseYear = QLocale::DefaultTwoDigitBaseYear) |
473 | { return fromString(string: string.toString(), format, baseYear); } |
474 | static QDateTime fromString(QStringView string, QStringView format, |
475 | int baseYear, QCalendar cal) |
476 | { return fromString(string: string.toString(), format, baseYear, cal); } |
477 | static QDateTime fromString(const QString &string, QStringView format, |
478 | int baseYear = QLocale::DefaultTwoDigitBaseYear); |
479 | static QDateTime fromString(const QString &string, QStringView format, |
480 | int baseYear, QCalendar cal); |
481 | static QDateTime fromString(const QString &string, const QString &format, |
482 | int baseYear = QLocale::DefaultTwoDigitBaseYear) |
483 | { return fromString(string, format: qToStringViewIgnoringNull(s: format), baseYear); } |
484 | static QDateTime fromString(const QString &string, const QString &format, |
485 | int baseYear, QCalendar cal) |
486 | { return fromString(string, format: qToStringViewIgnoringNull(s: format), baseYear, cal); } |
487 | #endif |
488 | |
489 | #if QT_DEPRECATED_SINCE(6, 9) |
490 | QT_DEPRECATED_VERSION_X_6_9("Pass QTimeZone instead of time-spec, offset" ) |
491 | static QDateTime fromMSecsSinceEpoch(qint64 msecs, Qt::TimeSpec spec, int offsetFromUtc = 0); |
492 | QT_DEPRECATED_VERSION_X_6_9("Pass QTimeZone instead of time-spec, offset" ) |
493 | static QDateTime fromSecsSinceEpoch(qint64 secs, Qt::TimeSpec spec, int offsetFromUtc = 0); |
494 | #endif |
495 | |
496 | static QDateTime fromMSecsSinceEpoch(qint64 msecs, const QTimeZone &timeZone); |
497 | static QDateTime fromSecsSinceEpoch(qint64 secs, const QTimeZone &timeZone); |
498 | static QDateTime fromMSecsSinceEpoch(qint64 msecs); |
499 | static QDateTime fromSecsSinceEpoch(qint64 secs); |
500 | |
501 | static qint64 currentMSecsSinceEpoch() noexcept; |
502 | static qint64 currentSecsSinceEpoch() noexcept; |
503 | |
504 | #if defined(Q_OS_DARWIN) || defined(Q_QDOC) |
505 | static QDateTime fromCFDate(CFDateRef date); |
506 | CFDateRef toCFDate() const Q_DECL_CF_RETURNS_RETAINED; |
507 | static QDateTime fromNSDate(const NSDate *date); |
508 | NSDate *toNSDate() const Q_DECL_NS_RETURNS_AUTORELEASED; |
509 | #endif |
510 | |
511 | static QDateTime fromStdTimePoint( |
512 | std::chrono::time_point< |
513 | std::chrono::system_clock, |
514 | std::chrono::milliseconds |
515 | > time |
516 | ); |
517 | |
518 | #if __cpp_lib_chrono >= 201907L || defined(Q_QDOC) |
519 | #if __cpp_concepts >= 201907L || defined(Q_QDOC) |
520 | private: |
521 | // The duration type of the result of a clock_cast<system_clock>. |
522 | // This duration may differ from the duration of the input. |
523 | template <typename Clock, typename Duration> |
524 | using system_clock_cast_duration = decltype( |
525 | std::chrono::clock_cast<std::chrono::system_clock>( |
526 | std::declval<const std::chrono::time_point<Clock, Duration> &>() |
527 | ).time_since_epoch() |
528 | ); |
529 | |
530 | public: |
531 | // Generic clock, as long as it's compatible with us (= system_clock) |
532 | template <typename Clock, typename Duration> |
533 | static QDateTime fromStdTimePoint(const std::chrono::time_point<Clock, Duration> &time) |
534 | requires |
535 | requires(const std::chrono::time_point<Clock, Duration> &t) { |
536 | // the clock can be converted to system_clock |
537 | std::chrono::clock_cast<std::chrono::system_clock>(t); |
538 | // after the conversion to system_clock, the duration type |
539 | // we get is convertible to milliseconds |
540 | requires std::is_convertible_v< |
541 | system_clock_cast_duration<Clock, Duration>, |
542 | std::chrono::milliseconds |
543 | >; |
544 | } |
545 | { |
546 | const auto sysTime = std::chrono::clock_cast<std::chrono::system_clock>(time); |
547 | // clock_cast can change the duration, so convert it again to milliseconds |
548 | const auto timeInMSec = std::chrono::time_point_cast<std::chrono::milliseconds>(sysTime); |
549 | return fromStdTimePoint(timeInMSec); |
550 | } |
551 | #endif // __cpp_concepts |
552 | |
553 | // local_time |
554 | QT_POST_CXX17_API_IN_EXPORTED_CLASS |
555 | static QDateTime fromStdTimePoint(const std::chrono::local_time<std::chrono::milliseconds> &time) |
556 | { |
557 | return fromStdLocalTime(time); |
558 | } |
559 | |
560 | QT_POST_CXX17_API_IN_EXPORTED_CLASS |
561 | static QDateTime fromStdLocalTime(const std::chrono::local_time<std::chrono::milliseconds> &time) |
562 | { |
563 | QDateTime result(QDate(1970, 1, 1), QTime(0, 0, 0), TransitionResolution::LegacyBehavior); |
564 | return result.addMSecs(msecs: time.time_since_epoch().count()); |
565 | } |
566 | |
567 | #if QT_CONFIG(timezone) && (__cpp_lib_chrono >= 201907L || defined(Q_QDOC)) |
568 | // zoned_time. defined in qtimezone.h |
569 | QT_POST_CXX17_API_IN_EXPORTED_CLASS |
570 | static QDateTime fromStdZonedTime(const std::chrono::zoned_time< |
571 | std::chrono::milliseconds, |
572 | const std::chrono::time_zone * |
573 | > &time); |
574 | #endif // QT_CONFIG(timezone) |
575 | |
576 | QT_POST_CXX17_API_IN_EXPORTED_CLASS |
577 | std::chrono::sys_time<std::chrono::milliseconds> toStdSysMilliseconds() const |
578 | { |
579 | const std::chrono::milliseconds duration(toMSecsSinceEpoch()); |
580 | return std::chrono::sys_time<std::chrono::milliseconds>(duration); |
581 | } |
582 | |
583 | QT_POST_CXX17_API_IN_EXPORTED_CLASS |
584 | std::chrono::sys_seconds toStdSysSeconds() const |
585 | { |
586 | const std::chrono::seconds duration(toSecsSinceEpoch()); |
587 | return std::chrono::sys_seconds(duration); |
588 | } |
589 | #endif // __cpp_lib_chrono >= 201907L |
590 | |
591 | friend std::chrono::milliseconds operator-(const QDateTime &lhs, const QDateTime &rhs) |
592 | { |
593 | return std::chrono::milliseconds(rhs.msecsTo(lhs)); |
594 | } |
595 | |
596 | friend QDateTime operator+(const QDateTime &dateTime, std::chrono::milliseconds duration) |
597 | { |
598 | return dateTime.addMSecs(msecs: duration.count()); |
599 | } |
600 | |
601 | friend QDateTime operator+(std::chrono::milliseconds duration, const QDateTime &dateTime) |
602 | { |
603 | return dateTime + duration; |
604 | } |
605 | |
606 | QDateTime &operator+=(std::chrono::milliseconds duration) |
607 | { |
608 | *this = addMSecs(msecs: duration.count()); |
609 | return *this; |
610 | } |
611 | |
612 | friend QDateTime operator-(const QDateTime &dateTime, std::chrono::milliseconds duration) |
613 | { |
614 | return dateTime.addMSecs(msecs: -duration.count()); |
615 | } |
616 | |
617 | QDateTime &operator-=(std::chrono::milliseconds duration) |
618 | { |
619 | *this = addMSecs(msecs: -duration.count()); |
620 | return *this; |
621 | } |
622 | |
623 | // (1<<63) ms is 292277024.6 (average Gregorian) years, counted from the start of 1970, so |
624 | // Last is floor(1970 + 292277024.6); no year 0, so First is floor(1970 - 1 - 292277024.6) |
625 | enum class YearRange : qint32 { First = -292275056, Last = +292278994 }; |
626 | |
627 | private: |
628 | bool equals(const QDateTime &other) const; |
629 | #if QT_CORE_REMOVED_SINCE(6, 7) |
630 | bool precedes(const QDateTime &other) const; |
631 | #endif |
632 | friend class QDateTimePrivate; |
633 | |
634 | Data d; |
635 | |
636 | friend bool comparesEqual(const QDateTime &lhs, const QDateTime &rhs) |
637 | { return lhs.equals(other: rhs); } |
638 | friend Q_CORE_EXPORT Qt::weak_ordering |
639 | compareThreeWay(const QDateTime &lhs, const QDateTime &rhs); |
640 | Q_DECLARE_WEAKLY_ORDERED(QDateTime) |
641 | |
642 | #ifndef QT_NO_DATASTREAM |
643 | friend Q_CORE_EXPORT QDataStream &operator<<(QDataStream &, const QDateTime &); |
644 | friend Q_CORE_EXPORT QDataStream &operator>>(QDataStream &, QDateTime &); |
645 | #endif |
646 | |
647 | #if !defined(QT_NO_DEBUG_STREAM) && QT_CONFIG(datestring) |
648 | friend Q_CORE_EXPORT QDebug operator<<(QDebug, const QDateTime &); |
649 | #endif |
650 | }; |
651 | Q_DECLARE_SHARED(QDateTime) |
652 | |
653 | #ifndef QT_NO_DATASTREAM |
654 | Q_CORE_EXPORT QDataStream &operator<<(QDataStream &, QDate); |
655 | Q_CORE_EXPORT QDataStream &operator>>(QDataStream &, QDate &); |
656 | Q_CORE_EXPORT QDataStream &operator<<(QDataStream &, QTime); |
657 | Q_CORE_EXPORT QDataStream &operator>>(QDataStream &, QTime &); |
658 | Q_CORE_EXPORT QDataStream &operator<<(QDataStream &, const QDateTime &); |
659 | Q_CORE_EXPORT QDataStream &operator>>(QDataStream &, QDateTime &); |
660 | #endif // QT_NO_DATASTREAM |
661 | |
662 | #if !defined(QT_NO_DEBUG_STREAM) && QT_CONFIG(datestring) |
663 | Q_CORE_EXPORT QDebug operator<<(QDebug, QDate); |
664 | Q_CORE_EXPORT QDebug operator<<(QDebug, QTime); |
665 | Q_CORE_EXPORT QDebug operator<<(QDebug, const QDateTime &); |
666 | #endif |
667 | |
668 | // QDateTime is not noexcept for now -- to be revised once |
669 | // timezone and calendaring support is added |
670 | Q_CORE_EXPORT size_t qHash(const QDateTime &key, size_t seed = 0); |
671 | Q_CORE_EXPORT size_t qHash(QDate key, size_t seed = 0) noexcept; |
672 | Q_CORE_EXPORT size_t qHash(QTime key, size_t seed = 0) noexcept; |
673 | |
674 | #if QT_CONFIG(datestring) && QT_CORE_INLINE_IMPL_SINCE(6, 7) |
675 | QDate QDate::fromString(const QString &string, QStringView format, QCalendar cal) |
676 | { |
677 | return fromString(string, format, baseYear: QLocale::DefaultTwoDigitBaseYear, cal); |
678 | } |
679 | |
680 | QDateTime QDateTime::fromString(const QString &string, QStringView format, QCalendar cal) |
681 | { |
682 | return fromString(string, format, baseYear: QLocale::DefaultTwoDigitBaseYear, cal); |
683 | } |
684 | #endif |
685 | |
686 | QT_END_NAMESPACE |
687 | |
688 | #endif // QDATETIME_H |
689 | |