1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2022 The Qt Company Ltd. |
4 | ** Copyright (C) 2016 Intel Corporation. |
5 | ** Contact: https://www.qt.io/licensing/ |
6 | ** |
7 | ** This file is part of the QtCore module of the Qt Toolkit. |
8 | ** |
9 | ** $QT_BEGIN_LICENSE:LGPL$ |
10 | ** Commercial License Usage |
11 | ** Licensees holding valid commercial Qt licenses may use this file in |
12 | ** accordance with the commercial license agreement provided with the |
13 | ** Software or, alternatively, in accordance with the terms contained in |
14 | ** a written agreement between you and The Qt Company. For licensing terms |
15 | ** and conditions see https://www.qt.io/terms-conditions. For further |
16 | ** information use the contact form at https://www.qt.io/contact-us. |
17 | ** |
18 | ** GNU Lesser General Public License Usage |
19 | ** Alternatively, this file may be used under the terms of the GNU Lesser |
20 | ** General Public License version 3 as published by the Free Software |
21 | ** Foundation and appearing in the file LICENSE.LGPL3 included in the |
22 | ** packaging of this file. Please review the following information to |
23 | ** ensure the GNU Lesser General Public License version 3 requirements |
24 | ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. |
25 | ** |
26 | ** GNU General Public License Usage |
27 | ** Alternatively, this file may be used under the terms of the GNU |
28 | ** General Public License version 2.0 or (at your option) the GNU General |
29 | ** Public license version 3 or any later version approved by the KDE Free |
30 | ** Qt Foundation. The licenses are as published by the Free Software |
31 | ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 |
32 | ** included in the packaging of this file. Please review the following |
33 | ** information to ensure the GNU General Public License requirements will |
34 | ** be met: https://www.gnu.org/licenses/gpl-2.0.html and |
35 | ** https://www.gnu.org/licenses/gpl-3.0.html. |
36 | ** |
37 | ** $QT_END_LICENSE$ |
38 | ** |
39 | ****************************************************************************/ |
40 | |
41 | #include "qplatformdefs.h" |
42 | #include "private/qdatetime_p.h" |
43 | #if QT_CONFIG(datetimeparser) |
44 | #include "private/qdatetimeparser_p.h" |
45 | #endif |
46 | |
47 | #include "qdatastream.h" |
48 | #include "qset.h" |
49 | #include "qlocale.h" |
50 | #include "qdatetime.h" |
51 | #if QT_CONFIG(timezone) |
52 | #include "qtimezoneprivate_p.h" |
53 | #endif |
54 | #include "qregexp.h" |
55 | #include "qdebug.h" |
56 | #ifndef Q_OS_WIN |
57 | #include <locale.h> |
58 | #endif |
59 | |
60 | #include <cmath> |
61 | #ifdef Q_CC_MINGW |
62 | # include <unistd.h> // Define _POSIX_THREAD_SAFE_FUNCTIONS to obtain localtime_r() |
63 | #endif |
64 | #include <time.h> |
65 | #ifdef Q_OS_WIN |
66 | # include <qt_windows.h> |
67 | # ifdef Q_OS_WINRT |
68 | # include "qfunctions_winrt.h" |
69 | # endif |
70 | #endif |
71 | |
72 | #if defined(Q_OS_MAC) |
73 | #include <private/qcore_mac_p.h> |
74 | #endif |
75 | |
76 | #include "qcalendar.h" |
77 | #include "qgregoriancalendar_p.h" |
78 | #include "private/qnumeric_p.h" |
79 | |
80 | QT_BEGIN_NAMESPACE |
81 | |
82 | /***************************************************************************** |
83 | Date/Time Constants |
84 | *****************************************************************************/ |
85 | |
86 | enum { |
87 | SECS_PER_DAY = 86400, |
88 | MSECS_PER_DAY = 86400000, |
89 | SECS_PER_HOUR = 3600, |
90 | MSECS_PER_HOUR = 3600000, |
91 | SECS_PER_MIN = 60, |
92 | MSECS_PER_MIN = 60000, |
93 | TIME_T_MAX = 2145916799, // int maximum 2037-12-31T23:59:59 UTC |
94 | JULIAN_DAY_FOR_EPOCH = 2440588 // result of julianDayFromDate(1970, 1, 1) |
95 | }; |
96 | |
97 | /***************************************************************************** |
98 | QDate static helper functions |
99 | *****************************************************************************/ |
100 | |
101 | static inline QDate fixedDate(QCalendar::YearMonthDay &&parts, QCalendar cal) |
102 | { |
103 | if ((parts.year < 0 && !cal.isProleptic()) || (parts.year == 0 && !cal.hasYearZero())) |
104 | return QDate(); |
105 | |
106 | parts.day = qMin(a: parts.day, b: cal.daysInMonth(month: parts.month, year: parts.year)); |
107 | return cal.dateFromParts(parts); |
108 | } |
109 | |
110 | static inline QDate fixedDate(QCalendar::YearMonthDay &&parts) |
111 | { |
112 | if (parts.year) { |
113 | parts.day = qMin(a: parts.day, b: QGregorianCalendar::monthLength(month: parts.month, year: parts.year)); |
114 | qint64 jd; |
115 | if (QGregorianCalendar::julianFromParts(year: parts.year, month: parts.month, day: parts.day, jd: &jd)) |
116 | return QDate::fromJulianDay(jd_: jd); |
117 | } |
118 | return QDate(); |
119 | } |
120 | |
121 | /***************************************************************************** |
122 | Date/Time formatting helper functions |
123 | *****************************************************************************/ |
124 | |
125 | #if QT_CONFIG(textdate) |
126 | static const char qt_shortMonthNames[][4] = { |
127 | "Jan" , "Feb" , "Mar" , "Apr" , "May" , "Jun" , |
128 | "Jul" , "Aug" , "Sep" , "Oct" , "Nov" , "Dec" |
129 | }; |
130 | |
131 | static int qt_monthNumberFromShortName(QStringView shortName) |
132 | { |
133 | for (unsigned int i = 0; i < sizeof(qt_shortMonthNames) / sizeof(qt_shortMonthNames[0]); ++i) { |
134 | if (shortName == QLatin1String(qt_shortMonthNames[i], 3)) |
135 | return i + 1; |
136 | } |
137 | return -1; |
138 | } |
139 | static int qt_monthNumberFromShortName(const QString &shortName) |
140 | { return qt_monthNumberFromShortName(shortName: QStringView(shortName)); } |
141 | |
142 | static int fromShortMonthName(QStringView monthName, int year) |
143 | { |
144 | // Assume that English monthnames are the default |
145 | int month = qt_monthNumberFromShortName(shortName: monthName); |
146 | if (month != -1) |
147 | return month; |
148 | // If English names can't be found, search the localized ones |
149 | for (int i = 1; i <= 12; ++i) { |
150 | if (monthName == QCalendar().monthName(locale: QLocale::system(), month: i, year, format: QLocale::ShortFormat)) |
151 | return i; |
152 | } |
153 | return -1; |
154 | } |
155 | #endif // textdate |
156 | |
157 | #if QT_CONFIG(datestring) |
158 | struct ParsedRfcDateTime { |
159 | QDate date; |
160 | QTime time; |
161 | int utcOffset; |
162 | }; |
163 | |
164 | static ParsedRfcDateTime rfcDateImpl(const QString &s) |
165 | { |
166 | ParsedRfcDateTime result; |
167 | |
168 | // Matches "[ddd,] dd MMM yyyy[ hh:mm[:ss]] [±hhmm]" - correct RFC 822, 2822, 5322 format |
169 | QRegExp rex(QStringLiteral("^[ \\t]*(?:[A-Z][a-z]+,)?[ \\t]*(\\d{1,2})[ \\t]+([A-Z][a-z]+)[ \\t]+(\\d\\d\\d\\d)(?:[ \\t]+(\\d\\d):(\\d\\d)(?::(\\d\\d))?)?[ \\t]*(?:([+-])(\\d\\d)(\\d\\d))?" )); |
170 | if (s.indexOf(rex) == 0) { |
171 | const QStringList cap = rex.capturedTexts(); |
172 | result.date = QDate(cap[3].toInt(), qt_monthNumberFromShortName(shortName: cap[2]), cap[1].toInt()); |
173 | if (!cap[4].isEmpty()) |
174 | result.time = QTime(cap[4].toInt(), cap[5].toInt(), cap[6].toInt()); |
175 | const bool positiveOffset = (cap[7] == QLatin1String("+" )); |
176 | const int hourOffset = cap[8].toInt(); |
177 | const int minOffset = cap[9].toInt(); |
178 | result.utcOffset = ((hourOffset * 60 + minOffset) * (positiveOffset ? 60 : -60)); |
179 | } else { |
180 | // Matches "ddd MMM dd[ hh:mm:ss] yyyy [±hhmm]" - permissive RFC 850, 1036 (read only) |
181 | QRegExp rex(QStringLiteral("^[ \\t]*[A-Z][a-z]+[ \\t]+([A-Z][a-z]+)[ \\t]+(\\d\\d)(?:[ \\t]+(\\d\\d):(\\d\\d):(\\d\\d))?[ \\t]+(\\d\\d\\d\\d)[ \\t]*(?:([+-])(\\d\\d)(\\d\\d))?" )); |
182 | if (s.indexOf(rex) == 0) { |
183 | const QStringList cap = rex.capturedTexts(); |
184 | result.date = QDate(cap[6].toInt(), qt_monthNumberFromShortName(shortName: cap[1]), cap[2].toInt()); |
185 | if (!cap[3].isEmpty()) |
186 | result.time = QTime(cap[3].toInt(), cap[4].toInt(), cap[5].toInt()); |
187 | const bool positiveOffset = (cap[7] == QLatin1String("+" )); |
188 | const int hourOffset = cap[8].toInt(); |
189 | const int minOffset = cap[9].toInt(); |
190 | result.utcOffset = ((hourOffset * 60 + minOffset) * (positiveOffset ? 60 : -60)); |
191 | } |
192 | } |
193 | |
194 | return result; |
195 | } |
196 | #endif // datestring |
197 | |
198 | // Return offset in [+-]HH:mm format |
199 | static QString toOffsetString(Qt::DateFormat format, int offset) |
200 | { |
201 | return QString::asprintf(format: "%c%02d%s%02d" , |
202 | offset >= 0 ? '+' : '-', |
203 | qAbs(t: offset) / SECS_PER_HOUR, |
204 | // Qt::ISODate puts : between the hours and minutes, but Qt:TextDate does not: |
205 | format == Qt::TextDate ? "" : ":" , |
206 | (qAbs(t: offset) / 60) % 60); |
207 | } |
208 | |
209 | #if QT_CONFIG(datestring) |
210 | // Parse offset in [+-]HH[[:]mm] format |
211 | static int fromOffsetString(QStringView offsetString, bool *valid) noexcept |
212 | { |
213 | *valid = false; |
214 | |
215 | const int size = offsetString.size(); |
216 | if (size < 2 || size > 6) |
217 | return 0; |
218 | |
219 | // sign will be +1 for a positive and -1 for a negative offset |
220 | int sign; |
221 | |
222 | // First char must be + or - |
223 | const QChar signChar = offsetString.at(n: 0); |
224 | if (signChar == QLatin1Char('+')) |
225 | sign = 1; |
226 | else if (signChar == QLatin1Char('-')) |
227 | sign = -1; |
228 | else |
229 | return 0; |
230 | |
231 | // Split the hour and minute parts |
232 | const QStringView time = offsetString.mid(pos: 1); |
233 | qsizetype hhLen = time.indexOf(c: QLatin1Char(':')); |
234 | qsizetype mmIndex; |
235 | if (hhLen == -1) |
236 | mmIndex = hhLen = 2; // [+-]HHmm or [+-]HH format |
237 | else |
238 | mmIndex = hhLen + 1; |
239 | |
240 | const QLocale C = QLocale::c(); |
241 | const QStringView hhRef = time.left(n: qMin(a: hhLen, b: time.size())); |
242 | bool ok = false; |
243 | const int hour = C.toInt(s: hhRef, ok: &ok); |
244 | if (!ok || hour > 23) // More generous than QTimeZone::MaxUtcOffsetSecs |
245 | return 0; |
246 | |
247 | const QStringView mmRef = time.mid(pos: qMin(a: mmIndex, b: time.size())); |
248 | const int minute = mmRef.isEmpty() ? 0 : C.toInt(s: mmRef, ok: &ok); |
249 | if (!ok || minute < 0 || minute > 59) |
250 | return 0; |
251 | |
252 | *valid = true; |
253 | return sign * ((hour * 60) + minute) * 60; |
254 | } |
255 | #endif // datestring |
256 | |
257 | /***************************************************************************** |
258 | QDate member functions |
259 | *****************************************************************************/ |
260 | |
261 | /*! |
262 | \since 4.5 |
263 | |
264 | \enum QDate::MonthNameType |
265 | |
266 | This enum describes the types of the string representation used |
267 | for the month name. |
268 | |
269 | \value DateFormat This type of name can be used for date-to-string formatting. |
270 | \value StandaloneFormat This type is used when you need to enumerate months or weekdays. |
271 | Usually standalone names are represented in singular forms with |
272 | capitalized first letter. |
273 | */ |
274 | |
275 | /*! |
276 | \class QDate |
277 | \inmodule QtCore |
278 | \reentrant |
279 | \brief The QDate class provides date functions. |
280 | |
281 | A QDate object represents a particular day, regardless of calendar, |
282 | locale or other settings used when creating it or supplied by the system. |
283 | It can report the year, month and day of the month that represent the |
284 | day with respect to the proleptic Gregorian calendar or any calendar supplied |
285 | as a QCalendar object. |
286 | |
287 | A QDate object is typically created by giving the year, month, and day |
288 | numbers explicitly. Note that QDate interprets year numbers less than 100 as |
289 | presented, i.e., as years 1 through 99, without adding any offset. The |
290 | static function currentDate() creates a QDate object containing the date |
291 | read from the system clock. An explicit date can also be set using |
292 | setDate(). The fromString() function returns a QDate given a string and a |
293 | date format which is used to interpret the date within the string. |
294 | |
295 | The year(), month(), and day() functions provide access to the year, month, |
296 | and day numbers. When more than one of these values is needed, it is more |
297 | efficient to call QCalendar::partsFromDate(), to save repeating (potentially |
298 | expensive) calendrical calculations. |
299 | |
300 | Also, dayOfWeek() and dayOfYear() functions are provided. The same |
301 | information is provided in textual format by toString(). QLocale can map the |
302 | day numbers to names, QCalendar can map month numbers to names. |
303 | |
304 | QDate provides a full set of operators to compare two QDate |
305 | objects where smaller means earlier, and larger means later. |
306 | |
307 | You can increment (or decrement) a date by a given number of days |
308 | using addDays(). Similarly you can use addMonths() and addYears(). |
309 | The daysTo() function returns the number of days between two |
310 | dates. |
311 | |
312 | The daysInMonth() and daysInYear() functions return how many days there are |
313 | in this date's month and year, respectively. The isLeapYear() function |
314 | indicates whether a date is in a leap year. QCalendar can also supply this |
315 | information, in some cases more conveniently. |
316 | |
317 | \section1 Remarks |
318 | |
319 | \section2 No Year 0 |
320 | |
321 | In the Gregorian calendar, there is no year 0. Dates in that year are |
322 | considered invalid. The year -1 is the year "1 before Christ" or "1 before |
323 | common era." The day before 1 January 1 CE, QDate(1, 1, 1), is 31 December |
324 | 1 BCE, QDate(-1, 12, 31). Various other calendars behave similarly; see |
325 | QCalendar::hasYearZero(). |
326 | |
327 | \section2 Range of Valid Dates |
328 | |
329 | Dates are stored internally as a Julian Day number, an integer count of |
330 | every day in a contiguous range, with 24 November 4714 BCE in the Gregorian |
331 | calendar being Julian Day 0 (1 January 4713 BCE in the Julian calendar). |
332 | As well as being an efficient and accurate way of storing an absolute date, |
333 | it is suitable for converting a date into other calendar systems such as |
334 | Hebrew, Islamic or Chinese. The Julian Day number can be obtained using |
335 | QDate::toJulianDay() and can be set using QDate::fromJulianDay(). |
336 | |
337 | The range of Julian Day numbers that QDate can represent is, for technical |
338 | reasons, limited to between -784350574879 and 784354017364, which means from |
339 | before 2 billion BCE to after 2 billion CE. This is more than seven times as |
340 | wide as the range of dates a QDateTime can represent. |
341 | |
342 | \sa QTime, QDateTime, QCalendar, QDateTime::YearRange, QDateEdit, QDateTimeEdit, QCalendarWidget |
343 | */ |
344 | |
345 | /*! |
346 | \fn QDate::QDate() |
347 | |
348 | Constructs a null date. Null dates are invalid. |
349 | |
350 | \sa isNull(), isValid() |
351 | */ |
352 | |
353 | /*! |
354 | Constructs a date with year \a y, month \a m and day \a d. |
355 | |
356 | The date is understood in terms of the Gregorian calendar. If the specified |
357 | date is invalid, the date is not set and isValid() returns \c false. |
358 | |
359 | \warning Years 1 to 99 are interpreted as is. Year 0 is invalid. |
360 | |
361 | \sa isValid(), QCalendar::dateFromParts() |
362 | */ |
363 | |
364 | QDate::QDate(int y, int m, int d) |
365 | { |
366 | if (!QGregorianCalendar::julianFromParts(year: y, month: m, day: d, jd: &jd)) |
367 | jd = nullJd(); |
368 | } |
369 | |
370 | QDate::QDate(int y, int m, int d, QCalendar cal) |
371 | { |
372 | *this = cal.dateFromParts(year: y, month: m, day: d); |
373 | } |
374 | |
375 | /*! |
376 | \fn bool QDate::isNull() const |
377 | |
378 | Returns \c true if the date is null; otherwise returns \c false. A null |
379 | date is invalid. |
380 | |
381 | \note The behavior of this function is equivalent to isValid(). |
382 | |
383 | \sa isValid() |
384 | */ |
385 | |
386 | /*! |
387 | \fn bool QDate::isValid() const |
388 | |
389 | Returns \c true if this date is valid; otherwise returns \c false. |
390 | |
391 | \sa isNull(), QCalendar::isDateValid() |
392 | */ |
393 | |
394 | /*! |
395 | Returns the year of this date. |
396 | |
397 | Uses \a cal as calendar, if supplied, else the Gregorian calendar. |
398 | |
399 | Returns 0 if the date is invalid. For some calendars, dates before their |
400 | first year may all be invalid. |
401 | |
402 | If using a calendar which has a year 0, check using isValid() if the return |
403 | is 0. Such calendars use negative year numbers in the obvious way, with |
404 | year 1 preceded by year 0, in turn preceded by year -1 and so on. |
405 | |
406 | Some calendars, despite having no year 0, have a conventional numbering of |
407 | the years before their first year, counting backwards from 1. For example, |
408 | in the proleptic Gregorian calendar, successive years before 1 CE (the first |
409 | year) are identified as 1 BCE, 2 BCE, 3 BCE and so on. For such calendars, |
410 | negative year numbers are used to indicate these years before year 1, with |
411 | -1 indicating the year before 1. |
412 | |
413 | \sa month(), day(), QCalendar::hasYearZero(), QCalendar::isProleptic(), QCalendar::partsFromDate() |
414 | */ |
415 | |
416 | int QDate::year(QCalendar cal) const |
417 | { |
418 | if (isValid()) { |
419 | const auto parts = cal.partsFromDate(date: *this); |
420 | if (parts.isValid()) |
421 | return parts.year; |
422 | } |
423 | return 0; |
424 | } |
425 | |
426 | /*! |
427 | \overload |
428 | */ |
429 | |
430 | int QDate::year() const |
431 | { |
432 | if (isValid()) { |
433 | const auto parts = QGregorianCalendar::partsFromJulian(jd); |
434 | if (parts.isValid()) |
435 | return parts.year; |
436 | } |
437 | return 0; |
438 | } |
439 | |
440 | /*! |
441 | Returns the month-number for the date. |
442 | |
443 | Numbers the months of the year starting with 1 for the first. Uses \a cal |
444 | as calendar if supplied, else the Gregorian calendar, for which the month |
445 | numbering is as follows: |
446 | |
447 | \list |
448 | \li 1 = "January" |
449 | \li 2 = "February" |
450 | \li 3 = "March" |
451 | \li 4 = "April" |
452 | \li 5 = "May" |
453 | \li 6 = "June" |
454 | \li 7 = "July" |
455 | \li 8 = "August" |
456 | \li 9 = "September" |
457 | \li 10 = "October" |
458 | \li 11 = "November" |
459 | \li 12 = "December" |
460 | \endlist |
461 | |
462 | Returns 0 if the date is invalid. Note that some calendars may have more |
463 | than 12 months in some years. |
464 | |
465 | \sa year(), day(), QCalendar::partsFromDate() |
466 | */ |
467 | |
468 | int QDate::month(QCalendar cal) const |
469 | { |
470 | if (isValid()) { |
471 | const auto parts = cal.partsFromDate(date: *this); |
472 | if (parts.isValid()) |
473 | return parts.month; |
474 | } |
475 | return 0; |
476 | } |
477 | |
478 | /*! |
479 | \overload |
480 | */ |
481 | |
482 | int QDate::month() const |
483 | { |
484 | if (isValid()) { |
485 | const auto parts = QGregorianCalendar::partsFromJulian(jd); |
486 | if (parts.isValid()) |
487 | return parts.month; |
488 | } |
489 | return 0; |
490 | } |
491 | |
492 | /*! |
493 | Returns the day of the month for this date. |
494 | |
495 | Uses \a cal as calendar if supplied, else the Gregorian calendar (for which |
496 | the return ranges from 1 to 31). Returns 0 if the date is invalid. |
497 | |
498 | \sa year(), month(), dayOfWeek(), QCalendar::partsFromDate() |
499 | */ |
500 | |
501 | int QDate::day(QCalendar cal) const |
502 | { |
503 | if (isValid()) { |
504 | const auto parts = cal.partsFromDate(date: *this); |
505 | if (parts.isValid()) |
506 | return parts.day; |
507 | } |
508 | return 0; |
509 | } |
510 | |
511 | /*! |
512 | \overload |
513 | */ |
514 | |
515 | int QDate::day() const |
516 | { |
517 | if (isValid()) { |
518 | const auto parts = QGregorianCalendar::partsFromJulian(jd); |
519 | if (parts.isValid()) |
520 | return parts.day; |
521 | } |
522 | return 0; |
523 | } |
524 | |
525 | /*! |
526 | Returns the weekday (1 = Monday to 7 = Sunday) for this date. |
527 | |
528 | Uses \a cal as calendar if supplied, else the Gregorian calendar. Returns 0 |
529 | if the date is invalid. Some calendars may give special meaning |
530 | (e.g. intercallary days) to values greater than 7. |
531 | |
532 | \sa day(), dayOfYear(), QCalendar::dayOfWeek(), Qt::DayOfWeek |
533 | */ |
534 | |
535 | int QDate::dayOfWeek(QCalendar cal) const |
536 | { |
537 | if (isNull()) |
538 | return 0; |
539 | |
540 | return cal.dayOfWeek(date: *this); |
541 | } |
542 | |
543 | /*! |
544 | \overload |
545 | */ |
546 | |
547 | int QDate::dayOfWeek() const |
548 | { |
549 | return isValid() ? QGregorianCalendar::weekDayOfJulian(jd) : 0; |
550 | } |
551 | |
552 | /*! |
553 | Returns the day of the year (1 for the first day) for this date. |
554 | |
555 | Uses \a cal as calendar if supplied, else the Gregorian calendar. |
556 | Returns 0 if either the date or the first day of its year is invalid. |
557 | |
558 | \sa day(), dayOfWeek(), QCalendar::daysInYear() |
559 | */ |
560 | |
561 | int QDate::dayOfYear(QCalendar cal) const |
562 | { |
563 | if (isValid()) { |
564 | QDate firstDay = cal.dateFromParts(year: year(cal), month: 1, day: 1); |
565 | if (firstDay.isValid()) |
566 | return firstDay.daysTo(*this) + 1; |
567 | } |
568 | return 0; |
569 | } |
570 | |
571 | /*! |
572 | \overload |
573 | */ |
574 | |
575 | int QDate::dayOfYear() const |
576 | { |
577 | if (isValid()) { |
578 | qint64 first; |
579 | if (QGregorianCalendar::julianFromParts(year: year(), month: 1, day: 1, jd: &first)) |
580 | return jd - first + 1; |
581 | } |
582 | return 0; |
583 | } |
584 | |
585 | /*! |
586 | Returns the number of days in the month for this date. |
587 | |
588 | Uses \a cal as calendar if supplied, else the Gregorian calendar (for which |
589 | the result ranges from 28 to 31). Returns 0 if the date is invalid. |
590 | |
591 | \sa day(), daysInYear(), QCalendar::daysInMonth(), |
592 | QCalendar::maximumDaysInMonth(), QCalendar::minimumDaysInMonth() |
593 | */ |
594 | |
595 | int QDate::daysInMonth(QCalendar cal) const |
596 | { |
597 | if (isValid()) { |
598 | const auto parts = cal.partsFromDate(date: *this); |
599 | if (parts.isValid()) |
600 | return cal.daysInMonth(month: parts.month, year: parts.year); |
601 | } |
602 | return 0; |
603 | } |
604 | |
605 | /*! |
606 | \overload |
607 | */ |
608 | |
609 | int QDate::daysInMonth() const |
610 | { |
611 | if (isValid()) { |
612 | const auto parts = QGregorianCalendar::partsFromJulian(jd); |
613 | if (parts.isValid()) |
614 | return QGregorianCalendar::monthLength(month: parts.month, year: parts.year); |
615 | } |
616 | return 0; |
617 | } |
618 | |
619 | /*! |
620 | Returns the number of days in the year for this date. |
621 | |
622 | Uses \a cal as calendar if supplied, else the Gregorian calendar (for which |
623 | the result is 365 or 366). Returns 0 if the date is invalid. |
624 | |
625 | \sa day(), daysInMonth(), QCalendar::daysInYear(), QCalendar::maximumMonthsInYear() |
626 | */ |
627 | |
628 | int QDate::daysInYear(QCalendar cal) const |
629 | { |
630 | if (isNull()) |
631 | return 0; |
632 | |
633 | return cal.daysInYear(year: year(cal)); |
634 | } |
635 | |
636 | /*! |
637 | \overload |
638 | */ |
639 | |
640 | int QDate::daysInYear() const |
641 | { |
642 | return isValid() ? QGregorianCalendar::leapTest(year: year()) ? 366 : 365 : 0; |
643 | } |
644 | |
645 | /*! |
646 | Returns the ISO 8601 week number (1 to 53). |
647 | |
648 | Returns 0 if the date is invalid. Otherwise, returns the week number for the |
649 | date. If \a yearNumber is not \nullptr (its default), stores the year as |
650 | *\a{yearNumber}. |
651 | |
652 | In accordance with ISO 8601, each week falls in the year to which most of |
653 | its days belong, in the Gregorian calendar. As ISO 8601's week starts on |
654 | Monday, this is the year in which the week's Thursday falls. Most years have |
655 | 52 weeks, but some have 53. |
656 | |
657 | \note *\a{yearNumber} is not always the same as year(). For example, 1 |
658 | January 2000 has week number 52 in the year 1999, and 31 December |
659 | 2002 has week number 1 in the year 2003. |
660 | |
661 | \sa isValid() |
662 | */ |
663 | |
664 | int QDate::weekNumber(int *yearNumber) const |
665 | { |
666 | if (!isValid()) |
667 | return 0; |
668 | |
669 | // This could be replaced by use of QIso8601Calendar, once we implement it. |
670 | // The Thursday of the same week determines our answer: |
671 | QDate thursday(addDays(days: 4 - dayOfWeek())); |
672 | int year = thursday.year(); |
673 | // Week n's Thurs's DOY has 1 <= DOY - 7*(n-1) < 8, so 0 <= DOY + 6 - 7*n < 7: |
674 | int week = (thursday.dayOfYear() + 6) / 7; |
675 | |
676 | if (yearNumber) |
677 | *yearNumber = year; |
678 | return week; |
679 | } |
680 | |
681 | static bool inDateTimeRange(qint64 jd, bool start) |
682 | { |
683 | using Bounds = std::numeric_limits<qint64>; |
684 | if (jd < Bounds::min() + JULIAN_DAY_FOR_EPOCH) |
685 | return false; |
686 | jd -= JULIAN_DAY_FOR_EPOCH; |
687 | const qint64 maxDay = Bounds::max() / MSECS_PER_DAY; |
688 | const qint64 minDay = Bounds::min() / MSECS_PER_DAY - 1; |
689 | // (Divisions rounded towards zero, as MSECS_PER_DAY has factors other than two.) |
690 | // Range includes start of last day and end of first: |
691 | if (start) |
692 | return jd > minDay && jd <= maxDay; |
693 | return jd >= minDay && jd < maxDay; |
694 | } |
695 | |
696 | static QDateTime toEarliest(QDate day, const QDateTime &form) |
697 | { |
698 | const Qt::TimeSpec spec = form.timeSpec(); |
699 | const int offset = (spec == Qt::OffsetFromUTC) ? form.offsetFromUtc() : 0; |
700 | #if QT_CONFIG(timezone) |
701 | QTimeZone zone; |
702 | if (spec == Qt::TimeZone) |
703 | zone = form.timeZone(); |
704 | #endif |
705 | auto moment = [=](QTime time) { |
706 | switch (spec) { |
707 | case Qt::OffsetFromUTC: return QDateTime(day, time, spec, offset); |
708 | #if QT_CONFIG(timezone) |
709 | case Qt::TimeZone: return QDateTime(day, time, zone); |
710 | #endif |
711 | default: return QDateTime(day, time, spec); |
712 | } |
713 | }; |
714 | // Longest routine time-zone transition is 2 hours: |
715 | QDateTime when = moment(QTime(2, 0)); |
716 | if (!when.isValid()) { |
717 | // Noon should be safe ... |
718 | when = moment(QTime(12, 0)); |
719 | if (!when.isValid()) { |
720 | // ... unless it's a 24-hour jump (moving the date-line) |
721 | when = moment(QTime(23, 59, 59, 999)); |
722 | if (!when.isValid()) |
723 | return QDateTime(); |
724 | } |
725 | } |
726 | int high = when.time().msecsSinceStartOfDay() / 60000; |
727 | int low = 0; |
728 | // Binary chop to the right minute |
729 | while (high > low + 1) { |
730 | int mid = (high + low) / 2; |
731 | QDateTime probe = moment(QTime(mid / 60, mid % 60)); |
732 | if (probe.isValid() && probe.date() == day) { |
733 | high = mid; |
734 | when = probe; |
735 | } else { |
736 | low = mid; |
737 | } |
738 | } |
739 | return when; |
740 | } |
741 | |
742 | /*! |
743 | \since 5.14 |
744 | \fn QDateTime QDate::startOfDay(Qt::TimeSpec spec, int offsetSeconds) const |
745 | \fn QDateTime QDate::startOfDay(const QTimeZone &zone) const |
746 | |
747 | Returns the start-moment of the day. Usually, this shall be midnight at the |
748 | start of the day: however, if a time-zone transition causes the given date |
749 | to skip over that midnight (e.g. a DST spring-forward skipping from the end |
750 | of the previous day to 01:00 of the new day), the actual earliest time in |
751 | the day is returned. This can only arise when the start-moment is specified |
752 | in terms of a time-zone (by passing its QTimeZone as \a zone) or in terms of |
753 | local time (by passing Qt::LocalTime as \a spec; this is its default). |
754 | |
755 | The \a offsetSeconds is ignored unless \a spec is Qt::OffsetFromUTC, when it |
756 | gives the implied zone's offset from UTC. As UTC and such zones have no |
757 | transitions, the start of the day is QTime(0, 0) in these cases. |
758 | |
759 | In the rare case of a date that was entirely skipped (this happens when a |
760 | zone east of the international date-line switches to being west of it), the |
761 | return shall be invalid. Passing Qt::TimeZone as \a spec (instead of |
762 | passing a QTimeZone) or passing an invalid time-zone as \a zone will also |
763 | produce an invalid result, as shall dates that start outside the range |
764 | representable by QDateTime. |
765 | |
766 | \sa endOfDay() |
767 | */ |
768 | QDateTime QDate::startOfDay(Qt::TimeSpec spec, int offsetSeconds) const |
769 | { |
770 | if (!inDateTimeRange(jd, start: true)) |
771 | return QDateTime(); |
772 | |
773 | switch (spec) { |
774 | case Qt::TimeZone: // should pass a QTimeZone instead of Qt::TimeZone |
775 | qWarning() << "Called QDate::startOfDay(Qt::TimeZone) on" << *this; |
776 | return QDateTime(); |
777 | case Qt::OffsetFromUTC: |
778 | case Qt::UTC: |
779 | return QDateTime(*this, QTime(0, 0), spec, offsetSeconds); |
780 | |
781 | case Qt::LocalTime: |
782 | if (offsetSeconds) |
783 | qWarning(msg: "Ignoring offset (%d seconds) passed with Qt::LocalTime" , offsetSeconds); |
784 | break; |
785 | } |
786 | QDateTime when(*this, QTime(0, 0), spec); |
787 | if (!when.isValid()) |
788 | when = toEarliest(day: *this, form: when); |
789 | |
790 | return when.isValid() ? when : QDateTime(); |
791 | } |
792 | |
793 | #if QT_CONFIG(timezone) |
794 | /*! |
795 | \overload |
796 | \since 5.14 |
797 | */ |
798 | QDateTime QDate::startOfDay(const QTimeZone &zone) const |
799 | { |
800 | if (!inDateTimeRange(jd, start: true) || !zone.isValid()) |
801 | return QDateTime(); |
802 | |
803 | QDateTime when(*this, QTime(0, 0), zone); |
804 | if (when.isValid()) |
805 | return when; |
806 | |
807 | // The start of the day must have fallen in a spring-forward's gap; find the spring-forward: |
808 | if (zone.hasTransitions()) { |
809 | QTimeZone::OffsetData tran = zone.previousTransition(beforeDateTime: QDateTime(*this, QTime(23, 59, 59, 999), zone)); |
810 | const QDateTime &at = tran.atUtc.toTimeZone(toZone: zone); |
811 | if (at.isValid() && at.date() == *this) |
812 | return at; |
813 | } |
814 | |
815 | when = toEarliest(day: *this, form: when); |
816 | return when.isValid() ? when : QDateTime(); |
817 | } |
818 | #endif // timezone |
819 | |
820 | static QDateTime toLatest(QDate day, const QDateTime &form) |
821 | { |
822 | const Qt::TimeSpec spec = form.timeSpec(); |
823 | const int offset = (spec == Qt::OffsetFromUTC) ? form.offsetFromUtc() : 0; |
824 | #if QT_CONFIG(timezone) |
825 | QTimeZone zone; |
826 | if (spec == Qt::TimeZone) |
827 | zone = form.timeZone(); |
828 | #endif |
829 | auto moment = [=](QTime time) { |
830 | switch (spec) { |
831 | case Qt::OffsetFromUTC: return QDateTime(day, time, spec, offset); |
832 | #if QT_CONFIG(timezone) |
833 | case Qt::TimeZone: return QDateTime(day, time, zone); |
834 | #endif |
835 | default: return QDateTime(day, time, spec); |
836 | } |
837 | }; |
838 | // Longest routine time-zone transition is 2 hours: |
839 | QDateTime when = moment(QTime(21, 59, 59, 999)); |
840 | if (!when.isValid()) { |
841 | // Noon should be safe ... |
842 | when = moment(QTime(12, 0)); |
843 | if (!when.isValid()) { |
844 | // ... unless it's a 24-hour jump (moving the date-line) |
845 | when = moment(QTime(0, 0)); |
846 | if (!when.isValid()) |
847 | return QDateTime(); |
848 | } |
849 | } |
850 | int high = 24 * 60; |
851 | int low = when.time().msecsSinceStartOfDay() / 60000; |
852 | // Binary chop to the right minute |
853 | while (high > low + 1) { |
854 | int mid = (high + low) / 2; |
855 | QDateTime probe = moment(QTime(mid / 60, mid % 60, 59, 999)); |
856 | if (probe.isValid() && probe.date() == day) { |
857 | low = mid; |
858 | when = probe; |
859 | } else { |
860 | high = mid; |
861 | } |
862 | } |
863 | return when; |
864 | } |
865 | |
866 | /*! |
867 | \since 5.14 |
868 | \fn QDateTime QDate::endOfDay(Qt::TimeSpec spec, int offsetSeconds) const |
869 | \fn QDateTime QDate::endOfDay(const QTimeZone &zone) const |
870 | |
871 | Returns the end-moment of the day. Usually, this is one millisecond before |
872 | the midnight at the end of the day: however, if a time-zone transition |
873 | causes the given date to skip over that midnight (e.g. a DST spring-forward |
874 | skipping from just before 23:00 to the start of the next day), the actual |
875 | latest time in the day is returned. This can only arise when the |
876 | start-moment is specified in terms of a time-zone (by passing its QTimeZone |
877 | as \a zone) or in terms of local time (by passing Qt::LocalTime as \a spec; |
878 | this is its default). |
879 | |
880 | The \a offsetSeconds is ignored unless \a spec is Qt::OffsetFromUTC, when it |
881 | gives the implied zone's offset from UTC. As UTC and such zones have no |
882 | transitions, the end of the day is QTime(23, 59, 59, 999) in these cases. |
883 | |
884 | In the rare case of a date that was entirely skipped (this happens when a |
885 | zone east of the international date-line switches to being west of it), the |
886 | return shall be invalid. Passing Qt::TimeZone as \a spec (instead of |
887 | passing a QTimeZone) will also produce an invalid result, as shall dates |
888 | that end outside the range representable by QDateTime. |
889 | |
890 | \sa startOfDay() |
891 | */ |
892 | QDateTime QDate::endOfDay(Qt::TimeSpec spec, int offsetSeconds) const |
893 | { |
894 | if (!inDateTimeRange(jd, start: false)) |
895 | return QDateTime(); |
896 | |
897 | switch (spec) { |
898 | case Qt::TimeZone: // should pass a QTimeZone instead of Qt::TimeZone |
899 | qWarning() << "Called QDate::endOfDay(Qt::TimeZone) on" << *this; |
900 | return QDateTime(); |
901 | case Qt::UTC: |
902 | case Qt::OffsetFromUTC: |
903 | return QDateTime(*this, QTime(23, 59, 59, 999), spec, offsetSeconds); |
904 | |
905 | case Qt::LocalTime: |
906 | if (offsetSeconds) |
907 | qWarning(msg: "Ignoring offset (%d seconds) passed with Qt::LocalTime" , offsetSeconds); |
908 | break; |
909 | } |
910 | QDateTime when(*this, QTime(23, 59, 59, 999), spec); |
911 | if (!when.isValid()) |
912 | when = toLatest(day: *this, form: when); |
913 | return when.isValid() ? when : QDateTime(); |
914 | } |
915 | |
916 | #if QT_CONFIG(timezone) |
917 | /*! |
918 | \overload |
919 | \since 5.14 |
920 | */ |
921 | QDateTime QDate::endOfDay(const QTimeZone &zone) const |
922 | { |
923 | if (!inDateTimeRange(jd, start: false) || !zone.isValid()) |
924 | return QDateTime(); |
925 | |
926 | QDateTime when(*this, QTime(23, 59, 59, 999), zone); |
927 | if (when.isValid()) |
928 | return when; |
929 | |
930 | // The end of the day must have fallen in a spring-forward's gap; find the spring-forward: |
931 | if (zone.hasTransitions()) { |
932 | QTimeZone::OffsetData tran = zone.nextTransition(afterDateTime: QDateTime(*this, QTime(0, 0), zone)); |
933 | const QDateTime &at = tran.atUtc.toTimeZone(toZone: zone); |
934 | if (at.isValid() && at.date() == *this) |
935 | return at; |
936 | } |
937 | |
938 | when = toLatest(day: *this, form: when); |
939 | return when.isValid() ? when : QDateTime(); |
940 | } |
941 | #endif // timezone |
942 | |
943 | #if QT_DEPRECATED_SINCE(5, 11) && QT_CONFIG(textdate) |
944 | |
945 | /*! |
946 | \since 4.5 |
947 | \deprecated |
948 | |
949 | Returns the short name of the \a month for the representation specified |
950 | by \a type. |
951 | |
952 | The months are enumerated using the following convention: |
953 | |
954 | \list |
955 | \li 1 = "Jan" |
956 | \li 2 = "Feb" |
957 | \li 3 = "Mar" |
958 | \li 4 = "Apr" |
959 | \li 5 = "May" |
960 | \li 6 = "Jun" |
961 | \li 7 = "Jul" |
962 | \li 8 = "Aug" |
963 | \li 9 = "Sep" |
964 | \li 10 = "Oct" |
965 | \li 11 = "Nov" |
966 | \li 12 = "Dec" |
967 | \endlist |
968 | |
969 | The month names will be localized according to the system's |
970 | locale settings, i.e. using QLocale::system(). |
971 | |
972 | Returns an empty string if the date is invalid. |
973 | |
974 | \sa toString(), longMonthName(), shortDayName(), longDayName() |
975 | */ |
976 | |
977 | QString QDate::shortMonthName(int month, QDate::MonthNameType type) |
978 | { |
979 | switch (type) { |
980 | case QDate::DateFormat: |
981 | return QCalendar().monthName(locale: QLocale::system(), month, |
982 | year: QCalendar::Unspecified, format: QLocale::ShortFormat); |
983 | case QDate::StandaloneFormat: |
984 | return QCalendar().standaloneMonthName(locale: QLocale::system(), month, |
985 | year: QCalendar::Unspecified, format: QLocale::ShortFormat); |
986 | } |
987 | return QString(); |
988 | } |
989 | |
990 | /*! |
991 | \since 4.5 |
992 | \deprecated |
993 | |
994 | Returns the long name of the \a month for the representation specified |
995 | by \a type. |
996 | |
997 | The months are enumerated using the following convention: |
998 | |
999 | \list |
1000 | \li 1 = "January" |
1001 | \li 2 = "February" |
1002 | \li 3 = "March" |
1003 | \li 4 = "April" |
1004 | \li 5 = "May" |
1005 | \li 6 = "June" |
1006 | \li 7 = "July" |
1007 | \li 8 = "August" |
1008 | \li 9 = "September" |
1009 | \li 10 = "October" |
1010 | \li 11 = "November" |
1011 | \li 12 = "December" |
1012 | \endlist |
1013 | |
1014 | The month names will be localized according to the system's |
1015 | locale settings, i.e. using QLocale::system(). |
1016 | |
1017 | Returns an empty string if the date is invalid. |
1018 | |
1019 | \sa toString(), shortMonthName(), shortDayName(), longDayName() |
1020 | */ |
1021 | |
1022 | QString QDate::longMonthName(int month, MonthNameType type) |
1023 | { |
1024 | switch (type) { |
1025 | case QDate::DateFormat: |
1026 | return QCalendar().monthName(locale: QLocale::system(), month, |
1027 | year: QCalendar::Unspecified, format: QLocale::LongFormat); |
1028 | case QDate::StandaloneFormat: |
1029 | return QCalendar().standaloneMonthName(locale: QLocale::system(), month, |
1030 | year: QCalendar::Unspecified, format: QLocale::LongFormat); |
1031 | } |
1032 | return QString(); |
1033 | } |
1034 | |
1035 | /*! |
1036 | \since 4.5 |
1037 | \deprecated |
1038 | |
1039 | Returns the short name of the \a weekday for the representation specified |
1040 | by \a type. |
1041 | |
1042 | The days are enumerated using the following convention: |
1043 | |
1044 | \list |
1045 | \li 1 = "Mon" |
1046 | \li 2 = "Tue" |
1047 | \li 3 = "Wed" |
1048 | \li 4 = "Thu" |
1049 | \li 5 = "Fri" |
1050 | \li 6 = "Sat" |
1051 | \li 7 = "Sun" |
1052 | \endlist |
1053 | |
1054 | The day names will be localized according to the system's |
1055 | locale settings, i.e. using QLocale::system(). |
1056 | |
1057 | Returns an empty string if the date is invalid. |
1058 | |
1059 | \sa toString(), shortMonthName(), longMonthName(), longDayName() |
1060 | */ |
1061 | |
1062 | QString QDate::shortDayName(int weekday, MonthNameType type) |
1063 | { |
1064 | switch (type) { |
1065 | case QDate::DateFormat: |
1066 | return QLocale::system().dayName(weekday, format: QLocale::ShortFormat); |
1067 | case QDate::StandaloneFormat: |
1068 | return QLocale::system().standaloneDayName(weekday, format: QLocale::ShortFormat); |
1069 | } |
1070 | return QString(); |
1071 | } |
1072 | |
1073 | /*! |
1074 | \since 4.5 |
1075 | \deprecated |
1076 | |
1077 | Returns the long name of the \a weekday for the representation specified |
1078 | by \a type. |
1079 | |
1080 | The days are enumerated using the following convention: |
1081 | |
1082 | \list |
1083 | \li 1 = "Monday" |
1084 | \li 2 = "Tuesday" |
1085 | \li 3 = "Wednesday" |
1086 | \li 4 = "Thursday" |
1087 | \li 5 = "Friday" |
1088 | \li 6 = "Saturday" |
1089 | \li 7 = "Sunday" |
1090 | \endlist |
1091 | |
1092 | The day names will be localized according to the system's |
1093 | locale settings, i.e. using QLocale::system(). |
1094 | |
1095 | Returns an empty string if the date is invalid. |
1096 | |
1097 | \sa toString(), shortDayName(), shortMonthName(), longMonthName() |
1098 | */ |
1099 | |
1100 | QString QDate::longDayName(int weekday, MonthNameType type) |
1101 | { |
1102 | switch (type) { |
1103 | case QDate::DateFormat: |
1104 | return QLocale::system().dayName(weekday, format: QLocale::LongFormat); |
1105 | case QDate::StandaloneFormat: |
1106 | return QLocale::system().standaloneDayName(weekday, format: QLocale::LongFormat); |
1107 | } |
1108 | return QString(); |
1109 | } |
1110 | #endif // textdate && deprecated |
1111 | |
1112 | #if QT_CONFIG(datestring) // depends on, so implies, textdate |
1113 | |
1114 | static QString toStringTextDate(QDate date) |
1115 | { |
1116 | if (date.isValid()) { |
1117 | QCalendar cal; // Always Gregorian |
1118 | const auto parts = cal.partsFromDate(date); |
1119 | if (parts.isValid()) { |
1120 | const QLatin1Char sp(' '); |
1121 | return QLocale::system().dayName(cal.dayOfWeek(date), format: QLocale::ShortFormat) + sp |
1122 | + cal.monthName(locale: QLocale::system(), month: parts.month, year: parts.year, format: QLocale::ShortFormat) |
1123 | + sp + QString::number(parts.day) + sp + QString::number(parts.year); |
1124 | } |
1125 | } |
1126 | return QString(); |
1127 | } |
1128 | |
1129 | static QString toStringIsoDate(QDate date) |
1130 | { |
1131 | const auto parts = QCalendar().partsFromDate(date); |
1132 | if (parts.isValid() && parts.year >= 0 && parts.year <= 9999) |
1133 | return QString::asprintf(format: "%04d-%02d-%02d" , parts.year, parts.month, parts.day); |
1134 | return QString(); |
1135 | } |
1136 | |
1137 | /*! |
1138 | \overload |
1139 | |
1140 | Returns the date as a string. The \a format parameter determines the format |
1141 | of the string. |
1142 | |
1143 | If the \a format is Qt::TextDate, the string is formatted in the default |
1144 | way. The day and month names will be localized names using the system |
1145 | locale, i.e. QLocale::system(). An example of this formatting |
1146 | is "Sat May 20 1995". |
1147 | |
1148 | If the \a format is Qt::ISODate, the string format corresponds |
1149 | to the ISO 8601 extended specification for representations of |
1150 | dates and times, taking the form yyyy-MM-dd, where yyyy is the |
1151 | year, MM is the month of the year (between 01 and 12), and dd is |
1152 | the day of the month between 01 and 31. |
1153 | |
1154 | The \a format options Qt::SystemLocaleDate, Qt::SystemLocaleShortDate and |
1155 | Qt::SystemLocaleLongDate shall be removed in Qt 6. Their use should be |
1156 | replaced with |
1157 | \l {QLocale::toString()}{QLocale::system().toString(date, QLocale::ShortFormat)} or |
1158 | \l {QLocale::toString()}{QLocale::system().toString(date, QLocale::LongFormat)}. |
1159 | |
1160 | The \a format options Qt::LocaleDate, Qt::DefaultLocaleShortDate and |
1161 | Qt::DefaultLocaleLongDate shall be removed in Qt 6. Their use should be |
1162 | replaced with |
1163 | \l {QLocale::toString()}{QLocale().toString(date, QLocale::ShortFormat)} or |
1164 | \l {QLocale::toString()}{QLocale().toString(date, QLocale::LongFormat)}. |
1165 | |
1166 | If the \a format is Qt::RFC2822Date, the string is formatted in |
1167 | an \l{RFC 2822} compatible way. An example of this formatting is |
1168 | "20 May 1995". |
1169 | |
1170 | If the date is invalid, an empty string will be returned. |
1171 | |
1172 | \warning The Qt::ISODate format is only valid for years in the |
1173 | range 0 to 9999. |
1174 | |
1175 | \sa fromString(), QLocale::toString() |
1176 | */ |
1177 | QString QDate::toString(Qt::DateFormat format) const |
1178 | { |
1179 | if (!isValid()) |
1180 | return QString(); |
1181 | |
1182 | switch (format) { |
1183 | #if QT_DEPRECATED_SINCE(5, 15) |
1184 | QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED |
1185 | case Qt::SystemLocaleDate: |
1186 | case Qt::SystemLocaleShortDate: |
1187 | return QLocale::system().toString(date: *this, format: QLocale::ShortFormat); |
1188 | case Qt::SystemLocaleLongDate: |
1189 | return QLocale::system().toString(date: *this, format: QLocale::LongFormat); |
1190 | case Qt::LocaleDate: |
1191 | case Qt::DefaultLocaleShortDate: |
1192 | return QLocale().toString(date: *this, format: QLocale::ShortFormat); |
1193 | case Qt::DefaultLocaleLongDate: |
1194 | return QLocale().toString(date: *this, format: QLocale::LongFormat); |
1195 | QT_WARNING_POP |
1196 | #endif // 5.15 |
1197 | case Qt::RFC2822Date: |
1198 | return QLocale::c().toString(date: *this, formatStr: QStringView(u"dd MMM yyyy" )); |
1199 | default: |
1200 | case Qt::TextDate: |
1201 | return toStringTextDate(date: *this); |
1202 | case Qt::ISODate: |
1203 | case Qt::ISODateWithMs: |
1204 | // No calendar dependence |
1205 | return toStringIsoDate(date: *this); |
1206 | } |
1207 | } |
1208 | |
1209 | #if QT_DEPRECATED_SINCE(5, 15) |
1210 | QString QDate::toString(Qt::DateFormat format, QCalendar cal) const |
1211 | { |
1212 | if (!isValid()) |
1213 | return QString(); |
1214 | |
1215 | switch (format) { |
1216 | QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED |
1217 | case Qt::SystemLocaleDate: |
1218 | case Qt::SystemLocaleShortDate: |
1219 | return QLocale::system().toString(date: *this, format: QLocale::ShortFormat, cal); |
1220 | case Qt::SystemLocaleLongDate: |
1221 | return QLocale::system().toString(date: *this, format: QLocale::LongFormat, cal); |
1222 | case Qt::LocaleDate: |
1223 | case Qt::DefaultLocaleShortDate: |
1224 | return QLocale().toString(date: *this, format: QLocale::ShortFormat, cal); |
1225 | case Qt::DefaultLocaleLongDate: |
1226 | return QLocale().toString(date: *this, format: QLocale::LongFormat, cal); |
1227 | QT_WARNING_POP |
1228 | case Qt::RFC2822Date: |
1229 | return QLocale::c().toString(date: *this, formatStr: QStringView(u"dd MMM yyyy" ), cal); |
1230 | default: |
1231 | case Qt::TextDate: |
1232 | return toStringTextDate(date: *this); |
1233 | case Qt::ISODate: |
1234 | case Qt::ISODateWithMs: |
1235 | // No calendar dependence |
1236 | return toStringIsoDate(date: *this); |
1237 | } |
1238 | } |
1239 | #endif // 5.15 |
1240 | |
1241 | /*! |
1242 | \fn QString QDate::toString(const QString &format) const |
1243 | \fn QString QDate::toString(const QString &format, QCalendar cal) const |
1244 | \fn QString QDate::toString(QStringView format) const |
1245 | \fn QString QDate::toString(QStringView format, QCalendar cal) const |
1246 | |
1247 | Returns the date as a string. The \a format parameter determines the format |
1248 | of the result string. If \a cal is supplied, it determines the calendar used |
1249 | to represent the date; it defaults to Gregorian. |
1250 | |
1251 | These expressions may be used: |
1252 | |
1253 | \table |
1254 | \header \li Expression \li Output |
1255 | \row \li d \li The day as a number without a leading zero (1 to 31) |
1256 | \row \li dd \li The day as a number with a leading zero (01 to 31) |
1257 | \row \li ddd |
1258 | \li The abbreviated localized day name (e.g. 'Mon' to 'Sun'). |
1259 | Uses the system locale to localize the name, i.e. QLocale::system(). |
1260 | \row \li dddd |
1261 | \li The long localized day name (e.g. 'Monday' to 'Sunday'). |
1262 | Uses the system locale to localize the name, i.e. QLocale::system(). |
1263 | \row \li M \li The month as a number without a leading zero (1 to 12) |
1264 | \row \li MM \li The month as a number with a leading zero (01 to 12) |
1265 | \row \li MMM |
1266 | \li The abbreviated localized month name (e.g. 'Jan' to 'Dec'). |
1267 | Uses the system locale to localize the name, i.e. QLocale::system(). |
1268 | \row \li MMMM |
1269 | \li The long localized month name (e.g. 'January' to 'December'). |
1270 | Uses the system locale to localize the name, i.e. QLocale::system(). |
1271 | \row \li yy \li The year as a two digit number (00 to 99) |
1272 | \row \li yyyy \li The year as a four digit number. If the year is negative, |
1273 | a minus sign is prepended, making five characters. |
1274 | \endtable |
1275 | |
1276 | Any sequence of characters enclosed in single quotes will be included |
1277 | verbatim in the output string (stripped of the quotes), even if it contains |
1278 | formatting characters. Two consecutive single quotes ("''") are replaced by |
1279 | a single quote in the output. All other characters in the format string are |
1280 | included verbatim in the output string. |
1281 | |
1282 | Formats without separators (e.g. "ddMM") are supported but must be used with |
1283 | care, as the resulting strings aren't always reliably readable (e.g. if "dM" |
1284 | produces "212" it could mean either the 2nd of December or the 21st of |
1285 | February). |
1286 | |
1287 | Example format strings (assuming that the QDate is the 20 July |
1288 | 1969): |
1289 | |
1290 | \table |
1291 | \header \li Format \li Result |
1292 | \row \li dd.MM.yyyy \li 20.07.1969 |
1293 | \row \li ddd MMMM d yy \li Sun July 20 69 |
1294 | \row \li 'The day is' dddd \li The day is Sunday |
1295 | \endtable |
1296 | |
1297 | If the datetime is invalid, an empty string will be returned. |
1298 | |
1299 | \note If localized month and day names are desired, please switch to using |
1300 | QLocale::system().toString() as QDate methods shall change to use English (C |
1301 | locale) names at Qt 6. |
1302 | |
1303 | \sa fromString(), QDateTime::toString(), QTime::toString(), QLocale::toString() |
1304 | |
1305 | */ |
1306 | QString QDate::toString(QStringView format) const |
1307 | { |
1308 | return toString(format, cal: QCalendar()); |
1309 | } |
1310 | |
1311 | QString QDate::toString(QStringView format, QCalendar cal) const |
1312 | { |
1313 | return QLocale::system().toString(date: *this, formatStr: format, cal); // QLocale::c() ### Qt6 |
1314 | } |
1315 | |
1316 | #if QT_STRINGVIEW_LEVEL < 2 |
1317 | QString QDate::toString(const QString &format) const |
1318 | { |
1319 | return toString(format: qToStringViewIgnoringNull(s: format), cal: QCalendar()); |
1320 | } |
1321 | |
1322 | QString QDate::toString(const QString &format, QCalendar cal) const |
1323 | { |
1324 | return toString(format: qToStringViewIgnoringNull(s: format), cal); |
1325 | } |
1326 | #endif |
1327 | |
1328 | #endif // datestring |
1329 | |
1330 | /*! |
1331 | \fn bool QDate::setYMD(int y, int m, int d) |
1332 | |
1333 | \deprecated in 5.0, use setDate() instead. |
1334 | |
1335 | Sets the date's year \a y, month \a m, and day \a d. |
1336 | |
1337 | If \a y is in the range 0 to 99, it is interpreted as 1900 to |
1338 | 1999. |
1339 | Returns \c false if the date is invalid. |
1340 | |
1341 | Use setDate() instead. |
1342 | */ |
1343 | |
1344 | /*! |
1345 | \since 4.2 |
1346 | |
1347 | Sets this to represent the date, in the Gregorian calendar, with the given |
1348 | \a year, \a month and \a day numbers. Returns true if the resulting date is |
1349 | valid, otherwise it sets this to represent an invalid date and returns |
1350 | false. |
1351 | |
1352 | \sa isValid(), QCalendar::dateFromParts() |
1353 | */ |
1354 | bool QDate::setDate(int year, int month, int day) |
1355 | { |
1356 | if (QGregorianCalendar::julianFromParts(year, month, day, jd: &jd)) |
1357 | return true; |
1358 | |
1359 | jd = nullJd(); |
1360 | return false; |
1361 | } |
1362 | |
1363 | /*! |
1364 | \since 5.14 |
1365 | |
1366 | Sets this to represent the date, in the given calendar \a cal, with the |
1367 | given \a year, \a month and \a day numbers. Returns true if the resulting |
1368 | date is valid, otherwise it sets this to represent an invalid date and |
1369 | returns false. |
1370 | |
1371 | \sa isValid(), QCalendar::dateFromParts() |
1372 | */ |
1373 | |
1374 | bool QDate::setDate(int year, int month, int day, QCalendar cal) |
1375 | { |
1376 | *this = QDate(year, month, day, cal); |
1377 | return isValid(); |
1378 | } |
1379 | |
1380 | /*! |
1381 | \since 4.5 |
1382 | |
1383 | Extracts the date's year, month, and day, and assigns them to |
1384 | *\a year, *\a month, and *\a day. The pointers may be null. |
1385 | |
1386 | Returns 0 if the date is invalid. |
1387 | |
1388 | \note In Qt versions prior to 5.7, this function is marked as non-\c{const}. |
1389 | |
1390 | \sa year(), month(), day(), isValid(), QCalendar::partsFromDate() |
1391 | */ |
1392 | void QDate::getDate(int *year, int *month, int *day) const |
1393 | { |
1394 | QCalendar::YearMonthDay parts; // invalid by default |
1395 | if (isValid()) |
1396 | parts = QGregorianCalendar::partsFromJulian(jd); |
1397 | |
1398 | const bool ok = parts.isValid(); |
1399 | if (year) |
1400 | *year = ok ? parts.year : 0; |
1401 | if (month) |
1402 | *month = ok ? parts.month : 0; |
1403 | if (day) |
1404 | *day = ok ? parts.day : 0; |
1405 | } |
1406 | |
1407 | #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) |
1408 | /*! |
1409 | \overload |
1410 | \internal |
1411 | */ |
1412 | void QDate::getDate(int *year, int *month, int *day) |
1413 | { |
1414 | qAsConst(t&: *this).getDate(year, month, day); |
1415 | } |
1416 | #endif // < Qt 6 |
1417 | |
1418 | /*! |
1419 | Returns a QDate object containing a date \a ndays later than the |
1420 | date of this object (or earlier if \a ndays is negative). |
1421 | |
1422 | Returns a null date if the current date is invalid or the new date is |
1423 | out of range. |
1424 | |
1425 | \sa addMonths(), addYears(), daysTo() |
1426 | */ |
1427 | |
1428 | QDate QDate::addDays(qint64 ndays) const |
1429 | { |
1430 | if (isNull()) |
1431 | return QDate(); |
1432 | |
1433 | qint64 r; |
1434 | if (Q_UNLIKELY(add_overflow(jd, ndays, &r))) |
1435 | return QDate(); |
1436 | else |
1437 | return fromJulianDay(jd_: r); |
1438 | } |
1439 | |
1440 | /*! |
1441 | Returns a QDate object containing a date \a nmonths later than the |
1442 | date of this object (or earlier if \a nmonths is negative). |
1443 | |
1444 | Uses \a cal as calendar, if supplied, else the Gregorian calendar. |
1445 | |
1446 | \note If the ending day/month combination does not exist in the resulting |
1447 | month/year, this function will return a date that is the latest valid date |
1448 | in the selected month. |
1449 | |
1450 | \sa addDays(), addYears() |
1451 | */ |
1452 | |
1453 | QDate QDate::addMonths(int nmonths, QCalendar cal) const |
1454 | { |
1455 | if (!isValid()) |
1456 | return QDate(); |
1457 | |
1458 | if (nmonths == 0) |
1459 | return *this; |
1460 | |
1461 | auto parts = cal.partsFromDate(date: *this); |
1462 | |
1463 | if (!parts.isValid()) |
1464 | return QDate(); |
1465 | Q_ASSERT(parts.year || cal.hasYearZero()); |
1466 | |
1467 | parts.month += nmonths; |
1468 | while (parts.month <= 0) { |
1469 | if (--parts.year || cal.hasYearZero()) |
1470 | parts.month += cal.monthsInYear(year: parts.year); |
1471 | } |
1472 | int count = cal.monthsInYear(year: parts.year); |
1473 | while (parts.month > count) { |
1474 | parts.month -= count; |
1475 | count = (++parts.year || cal.hasYearZero()) ? cal.monthsInYear(year: parts.year) : 0; |
1476 | } |
1477 | |
1478 | return fixedDate(parts: std::move(parts), cal); |
1479 | } |
1480 | |
1481 | /*! |
1482 | \overload |
1483 | */ |
1484 | |
1485 | QDate QDate::addMonths(int nmonths) const |
1486 | { |
1487 | if (isNull()) |
1488 | return QDate(); |
1489 | |
1490 | if (nmonths == 0) |
1491 | return *this; |
1492 | |
1493 | auto parts = QGregorianCalendar::partsFromJulian(jd); |
1494 | |
1495 | if (!parts.isValid()) |
1496 | return QDate(); |
1497 | Q_ASSERT(parts.year); |
1498 | |
1499 | parts.month += nmonths; |
1500 | while (parts.month <= 0) { |
1501 | if (--parts.year) // skip over year 0 |
1502 | parts.month += 12; |
1503 | } |
1504 | while (parts.month > 12) { |
1505 | parts.month -= 12; |
1506 | if (!++parts.year) // skip over year 0 |
1507 | ++parts.year; |
1508 | } |
1509 | |
1510 | return fixedDate(parts: std::move(parts)); |
1511 | } |
1512 | |
1513 | /*! |
1514 | Returns a QDate object containing a date \a nyears later than the |
1515 | date of this object (or earlier if \a nyears is negative). |
1516 | |
1517 | Uses \a cal as calendar, if supplied, else the Gregorian calendar. |
1518 | |
1519 | \note If the ending day/month combination does not exist in the resulting |
1520 | year (e.g., for the Gregorian calendar, if the date was Feb 29 and the final |
1521 | year is not a leap year), this function will return a date that is the |
1522 | latest valid date in the given month (in the example, Feb 28). |
1523 | |
1524 | \sa addDays(), addMonths() |
1525 | */ |
1526 | |
1527 | QDate QDate::addYears(int nyears, QCalendar cal) const |
1528 | { |
1529 | if (!isValid()) |
1530 | return QDate(); |
1531 | |
1532 | auto parts = cal.partsFromDate(date: *this); |
1533 | if (!parts.isValid()) |
1534 | return QDate(); |
1535 | |
1536 | int old_y = parts.year; |
1537 | parts.year += nyears; |
1538 | |
1539 | // If we just crossed (or hit) a missing year zero, adjust year by +/- 1: |
1540 | if (!cal.hasYearZero() && ((old_y > 0) != (parts.year > 0) || !parts.year)) |
1541 | parts.year += nyears > 0 ? +1 : -1; |
1542 | |
1543 | return fixedDate(parts: std::move(parts), cal); |
1544 | } |
1545 | |
1546 | /*! |
1547 | \overload |
1548 | */ |
1549 | |
1550 | QDate QDate::addYears(int nyears) const |
1551 | { |
1552 | if (isNull()) |
1553 | return QDate(); |
1554 | |
1555 | auto parts = QGregorianCalendar::partsFromJulian(jd); |
1556 | if (!parts.isValid()) |
1557 | return QDate(); |
1558 | |
1559 | int old_y = parts.year; |
1560 | parts.year += nyears; |
1561 | |
1562 | // If we just crossed (or hit) a missing year zero, adjust year by +/- 1: |
1563 | if ((old_y > 0) != (parts.year > 0) || !parts.year) |
1564 | parts.year += nyears > 0 ? +1 : -1; |
1565 | |
1566 | return fixedDate(parts: std::move(parts)); |
1567 | } |
1568 | |
1569 | /*! |
1570 | Returns the number of days from this date to \a d (which is |
1571 | negative if \a d is earlier than this date). |
1572 | |
1573 | Returns 0 if either date is invalid. |
1574 | |
1575 | Example: |
1576 | \snippet code/src_corelib_tools_qdatetime.cpp 0 |
1577 | |
1578 | \sa addDays() |
1579 | */ |
1580 | |
1581 | qint64 QDate::daysTo(const QDate &d) const |
1582 | { |
1583 | if (isNull() || d.isNull()) |
1584 | return 0; |
1585 | |
1586 | // Due to limits on minJd() and maxJd() we know this will never overflow |
1587 | return d.jd - jd; |
1588 | } |
1589 | |
1590 | |
1591 | /*! |
1592 | \fn bool QDate::operator==(const QDate &d) const |
1593 | |
1594 | Returns \c true if this date and \a d represent the same day, otherwise |
1595 | \c false. |
1596 | */ |
1597 | |
1598 | /*! |
1599 | \fn bool QDate::operator!=(const QDate &d) const |
1600 | |
1601 | Returns \c true if this date is different from \a d; otherwise |
1602 | returns \c false. |
1603 | |
1604 | \sa operator==() |
1605 | */ |
1606 | |
1607 | /*! |
1608 | \fn bool QDate::operator<(const QDate &d) const |
1609 | |
1610 | Returns \c true if this date is earlier than \a d; otherwise returns |
1611 | false. |
1612 | */ |
1613 | |
1614 | /*! |
1615 | \fn bool QDate::operator<=(const QDate &d) const |
1616 | |
1617 | Returns \c true if this date is earlier than or equal to \a d; |
1618 | otherwise returns \c false. |
1619 | */ |
1620 | |
1621 | /*! |
1622 | \fn bool QDate::operator>(const QDate &d) const |
1623 | |
1624 | Returns \c true if this date is later than \a d; otherwise returns |
1625 | false. |
1626 | */ |
1627 | |
1628 | /*! |
1629 | \fn bool QDate::operator>=(const QDate &d) const |
1630 | |
1631 | Returns \c true if this date is later than or equal to \a d; |
1632 | otherwise returns \c false. |
1633 | */ |
1634 | |
1635 | /*! |
1636 | \fn QDate::currentDate() |
1637 | Returns the current date, as reported by the system clock. |
1638 | |
1639 | \sa QTime::currentTime(), QDateTime::currentDateTime() |
1640 | */ |
1641 | |
1642 | #if QT_CONFIG(datestring) // depends on, so implies, textdate |
1643 | namespace { |
1644 | |
1645 | struct ParsedInt { int value = 0; bool ok = false; }; |
1646 | |
1647 | /* |
1648 | /internal |
1649 | |
1650 | Read an int that must be the whole text. QStringRef::toInt() will ignore |
1651 | spaces happily; but ISO date format should not. |
1652 | */ |
1653 | ParsedInt readInt(QStringView text) |
1654 | { |
1655 | ParsedInt result; |
1656 | for (const auto &ch : text) { |
1657 | if (ch.isSpace()) |
1658 | return result; |
1659 | } |
1660 | result.value = QLocale::c().toInt(s: text, ok: &result.ok); |
1661 | return result; |
1662 | } |
1663 | |
1664 | } |
1665 | |
1666 | /*! |
1667 | Returns the QDate represented by the \a string, using the |
1668 | \a format given, or an invalid date if the string cannot be |
1669 | parsed. |
1670 | |
1671 | Note for Qt::TextDate: It is recommended that you use the English short |
1672 | month names (e.g. "Jan"). Although localized month names can also be used in |
1673 | Qt 5, they depend on the user's locale settings. |
1674 | |
1675 | \note Support for localized dates, including the format options |
1676 | Qt::SystemLocaleDate, Qt::SystemLocaleShortDate, Qt::SystemLocaleLongDate, |
1677 | Qt::LocaleDate, Qt::DefaultLocaleShortDate, and Qt::DefaultLocaleLongDate, |
1678 | shall be removed in Qt 6. Use QLocale::toDate() instead. |
1679 | |
1680 | \sa toString(), QLocale::toDate() |
1681 | */ |
1682 | |
1683 | QDate QDate::fromString(const QString &string, Qt::DateFormat format) |
1684 | { |
1685 | if (string.isEmpty()) |
1686 | return QDate(); |
1687 | |
1688 | switch (format) { |
1689 | #if QT_DEPRECATED_SINCE(5, 15) |
1690 | QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED |
1691 | case Qt::SystemLocaleDate: |
1692 | case Qt::SystemLocaleShortDate: |
1693 | return QLocale::system().toDate(string, QLocale::ShortFormat); |
1694 | case Qt::SystemLocaleLongDate: |
1695 | return QLocale::system().toDate(string, QLocale::LongFormat); |
1696 | case Qt::LocaleDate: |
1697 | case Qt::DefaultLocaleShortDate: |
1698 | return QLocale().toDate(string, QLocale::ShortFormat); |
1699 | case Qt::DefaultLocaleLongDate: |
1700 | return QLocale().toDate(string, QLocale::LongFormat); |
1701 | QT_WARNING_POP |
1702 | #endif // 5.15 |
1703 | case Qt::RFC2822Date: |
1704 | return rfcDateImpl(s: string).date; |
1705 | default: |
1706 | case Qt::TextDate: { |
1707 | // Accept only "ddd MMM d yyyy" form (in contrast with QDateTime), e.g. "Sun Dec 1 1974" |
1708 | QVector<QStringRef> parts = string.splitRef(sep: QLatin1Char(' '), behavior: Qt::SkipEmptyParts); |
1709 | const int count = parts.count(); |
1710 | bool ok = count > 3; |
1711 | int year = ok ? parts.at(i: count - 1).toInt(ok: &ok) : 0; |
1712 | int day = ok ? parts.at(i: count - 2).toInt(ok: &ok) : 0; |
1713 | if (!ok || !day || !year) |
1714 | return QDate(); |
1715 | |
1716 | // Some locales have multi-word month names: |
1717 | int i = count - 3; |
1718 | QString monthName = parts.at(i).toString(); |
1719 | while (i > 0) { |
1720 | const int month = fromShortMonthName(monthName, year); |
1721 | if (month > 0) // Month name matches an English or localised name. |
1722 | return QDate(year, month, day); |
1723 | monthName = parts.at(i: --i) + QLatin1Char(' ') + monthName; |
1724 | } |
1725 | return QDate(); |
1726 | } |
1727 | case Qt::ISODate: |
1728 | // Semi-strict parsing, must be long enough and have punctuators as separators |
1729 | if (string.size() >= 10 && string.at(i: 4).isPunct() && string.at(i: 7).isPunct() |
1730 | && (string.size() == 10 || !string.at(i: 10).isDigit())) { |
1731 | QStringView view(string); |
1732 | const ParsedInt year = readInt(text: view.mid(pos: 0, n: 4)); |
1733 | const ParsedInt month = readInt(text: view.mid(pos: 5, n: 2)); |
1734 | const ParsedInt day = readInt(text: view.mid(pos: 8, n: 2)); |
1735 | if (year.ok && year.value > 0 && year.value <= 9999 && month.ok && day.ok) |
1736 | return QDate(year.value, month.value, day.value); |
1737 | } |
1738 | break; |
1739 | } |
1740 | return QDate(); |
1741 | } |
1742 | |
1743 | /*! |
1744 | Returns the QDate represented by the \a string, using the \a |
1745 | format given, or an invalid date if the string cannot be parsed. |
1746 | |
1747 | Uses \a cal as calendar if supplied, else the Gregorian calendar. Ranges of |
1748 | values in the format descriptions below are for the latter; they may be |
1749 | different for other calendars. |
1750 | |
1751 | These expressions may be used for the format: |
1752 | |
1753 | \table |
1754 | \header \li Expression \li Output |
1755 | \row \li d \li The day as a number without a leading zero (1 to 31) |
1756 | \row \li dd \li The day as a number with a leading zero (01 to 31) |
1757 | \row \li ddd |
1758 | \li The abbreviated localized day name (e.g. 'Mon' to 'Sun'). |
1759 | Uses the system locale to localize the name, i.e. QLocale::system(). |
1760 | \row \li dddd |
1761 | \li The long localized day name (e.g. 'Monday' to 'Sunday'). |
1762 | Uses the system locale to localize the name, i.e. QLocale::system(). |
1763 | \row \li M \li The month as a number without a leading zero (1 to 12) |
1764 | \row \li MM \li The month as a number with a leading zero (01 to 12) |
1765 | \row \li MMM |
1766 | \li The abbreviated localized month name (e.g. 'Jan' to 'Dec'). |
1767 | Uses the system locale to localize the name, i.e. QLocale::system(). |
1768 | \row \li MMMM |
1769 | \li The long localized month name (e.g. 'January' to 'December'). |
1770 | Uses the system locale to localize the name, i.e. QLocale::system(). |
1771 | \row \li yy \li The year as a two digit number (00 to 99) |
1772 | \row \li yyyy \li The year as a four digit number, possibly plus a leading |
1773 | minus sign for negative years. |
1774 | \endtable |
1775 | |
1776 | \note Unlike the other version of this function, day and month names must |
1777 | be given in the user's local language. It is only possible to use the English |
1778 | names if the user's language is English. |
1779 | |
1780 | All other input characters will be treated as text. Any non-empty sequence |
1781 | of characters enclosed in single quotes will also be treated (stripped of |
1782 | the quotes) as text and not be interpreted as expressions. For example: |
1783 | |
1784 | \snippet code/src_corelib_tools_qdatetime.cpp 1 |
1785 | |
1786 | If the format is not satisfied, an invalid QDate is returned. The |
1787 | expressions that don't expect leading zeroes (d, M) will be |
1788 | greedy. This means that they will use two digits even if this |
1789 | will put them outside the accepted range of values and leaves too |
1790 | few digits for other sections. For example, the following format |
1791 | string could have meant January 30 but the M will grab two |
1792 | digits, resulting in an invalid date: |
1793 | |
1794 | \snippet code/src_corelib_tools_qdatetime.cpp 2 |
1795 | |
1796 | For any field that is not represented in the format the following |
1797 | defaults are used: |
1798 | |
1799 | \table |
1800 | \header \li Field \li Default value |
1801 | \row \li Year \li 1900 |
1802 | \row \li Month \li 1 |
1803 | \row \li Day \li 1 |
1804 | \endtable |
1805 | |
1806 | The following examples demonstrate the default values: |
1807 | |
1808 | \snippet code/src_corelib_tools_qdatetime.cpp 3 |
1809 | |
1810 | \note If localized month and day names are used, please switch to using |
1811 | QLocale::system().toDate() as QDate methods shall change to only recognize |
1812 | English (C locale) names at Qt 6. |
1813 | |
1814 | \sa toString(), QDateTime::fromString(), QTime::fromString(), |
1815 | QLocale::toDate() |
1816 | */ |
1817 | |
1818 | QDate QDate::fromString(const QString &string, const QString &format, QCalendar cal) |
1819 | { |
1820 | QDate date; |
1821 | #if QT_CONFIG(datetimeparser) |
1822 | QDateTimeParser dt(QMetaType::QDate, QDateTimeParser::FromString, cal); |
1823 | // dt.setDefaultLocale(QLocale::c()); ### Qt 6 |
1824 | if (dt.parseFormat(format)) |
1825 | dt.fromString(text: string, date: &date, time: nullptr); |
1826 | #else |
1827 | Q_UNUSED(string); |
1828 | Q_UNUSED(format); |
1829 | Q_UNUSED(cal); |
1830 | #endif |
1831 | return date; |
1832 | } |
1833 | |
1834 | /*! |
1835 | \overload |
1836 | */ |
1837 | |
1838 | QDate QDate::fromString(const QString &string, const QString &format) |
1839 | { |
1840 | return fromString(string, format, cal: QCalendar()); |
1841 | } |
1842 | #endif // datestring |
1843 | |
1844 | /*! |
1845 | \overload |
1846 | |
1847 | Returns \c true if the specified date (\a year, \a month, and \a day) is |
1848 | valid in the Gregorian calendar; otherwise returns \c false. |
1849 | |
1850 | Example: |
1851 | \snippet code/src_corelib_tools_qdatetime.cpp 4 |
1852 | |
1853 | \sa isNull(), setDate(), QCalendar::isDateValid() |
1854 | */ |
1855 | |
1856 | bool QDate::isValid(int year, int month, int day) |
1857 | { |
1858 | return QGregorianCalendar::validParts(year, month, day); |
1859 | } |
1860 | |
1861 | /*! |
1862 | \fn bool QDate::isLeapYear(int year) |
1863 | |
1864 | Returns \c true if the specified \a year is a leap year in the Gregorian |
1865 | calendar; otherwise returns \c false. |
1866 | |
1867 | \sa QCalendar::isLeapYear() |
1868 | */ |
1869 | |
1870 | bool QDate::isLeapYear(int y) |
1871 | { |
1872 | return QGregorianCalendar::leapTest(year: y); |
1873 | } |
1874 | |
1875 | /*! \fn static QDate QDate::fromJulianDay(qint64 jd) |
1876 | |
1877 | Converts the Julian day \a jd to a QDate. |
1878 | |
1879 | \sa toJulianDay() |
1880 | */ |
1881 | |
1882 | /*! \fn int QDate::toJulianDay() const |
1883 | |
1884 | Converts the date to a Julian day. |
1885 | |
1886 | \sa fromJulianDay() |
1887 | */ |
1888 | |
1889 | /***************************************************************************** |
1890 | QTime member functions |
1891 | *****************************************************************************/ |
1892 | |
1893 | /*! |
1894 | \class QTime |
1895 | \inmodule QtCore |
1896 | \reentrant |
1897 | |
1898 | \brief The QTime class provides clock time functions. |
1899 | |
1900 | |
1901 | A QTime object contains a clock time, which it can express as the numbers of |
1902 | hours, minutes, seconds, and milliseconds since midnight. It provides |
1903 | functions for comparing times and for manipulating a time by adding a number |
1904 | of milliseconds. |
1905 | |
1906 | QTime uses the 24-hour clock format; it has no concept of AM/PM. |
1907 | Unlike QDateTime, QTime knows nothing about time zones or |
1908 | daylight-saving time (DST). |
1909 | |
1910 | A QTime object is typically created either by giving the number of hours, |
1911 | minutes, seconds, and milliseconds explicitly, or by using the static |
1912 | function currentTime(), which creates a QTime object that represents the |
1913 | system's local time. |
1914 | |
1915 | The hour(), minute(), second(), and msec() functions provide |
1916 | access to the number of hours, minutes, seconds, and milliseconds |
1917 | of the time. The same information is provided in textual format by |
1918 | the toString() function. |
1919 | |
1920 | The addSecs() and addMSecs() functions provide the time a given |
1921 | number of seconds or milliseconds later than a given time. |
1922 | Correspondingly, the number of seconds or milliseconds |
1923 | between two times can be found using secsTo() or msecsTo(). |
1924 | |
1925 | QTime provides a full set of operators to compare two QTime |
1926 | objects; an earlier time is considered smaller than a later one; |
1927 | if A.msecsTo(B) is positive, then A < B. |
1928 | |
1929 | \sa QDate, QDateTime |
1930 | */ |
1931 | |
1932 | /*! |
1933 | \fn QTime::QTime() |
1934 | |
1935 | Constructs a null time object. For a null time, isNull() returns \c true and |
1936 | isValid() returns \c false. If you need a zero time, use QTime(0, 0). For |
1937 | the start of a day, see QDate::startOfDay(). |
1938 | |
1939 | \sa isNull(), isValid() |
1940 | */ |
1941 | |
1942 | /*! |
1943 | Constructs a time with hour \a h, minute \a m, seconds \a s and |
1944 | milliseconds \a ms. |
1945 | |
1946 | \a h must be in the range 0 to 23, \a m and \a s must be in the |
1947 | range 0 to 59, and \a ms must be in the range 0 to 999. |
1948 | |
1949 | \sa isValid() |
1950 | */ |
1951 | |
1952 | QTime::QTime(int h, int m, int s, int ms) |
1953 | { |
1954 | setHMS(h, m, s, ms); |
1955 | } |
1956 | |
1957 | |
1958 | /*! |
1959 | \fn bool QTime::isNull() const |
1960 | |
1961 | Returns \c true if the time is null (i.e., the QTime object was |
1962 | constructed using the default constructor); otherwise returns |
1963 | false. A null time is also an invalid time. |
1964 | |
1965 | \sa isValid() |
1966 | */ |
1967 | |
1968 | /*! |
1969 | Returns \c true if the time is valid; otherwise returns \c false. For example, |
1970 | the time 23:30:55.746 is valid, but 24:12:30 is invalid. |
1971 | |
1972 | \sa isNull() |
1973 | */ |
1974 | |
1975 | bool QTime::isValid() const |
1976 | { |
1977 | return mds > NullTime && mds < MSECS_PER_DAY; |
1978 | } |
1979 | |
1980 | |
1981 | /*! |
1982 | Returns the hour part (0 to 23) of the time. |
1983 | |
1984 | Returns -1 if the time is invalid. |
1985 | |
1986 | \sa minute(), second(), msec() |
1987 | */ |
1988 | |
1989 | int QTime::hour() const |
1990 | { |
1991 | if (!isValid()) |
1992 | return -1; |
1993 | |
1994 | return ds() / MSECS_PER_HOUR; |
1995 | } |
1996 | |
1997 | /*! |
1998 | Returns the minute part (0 to 59) of the time. |
1999 | |
2000 | Returns -1 if the time is invalid. |
2001 | |
2002 | \sa hour(), second(), msec() |
2003 | */ |
2004 | |
2005 | int QTime::minute() const |
2006 | { |
2007 | if (!isValid()) |
2008 | return -1; |
2009 | |
2010 | return (ds() % MSECS_PER_HOUR) / MSECS_PER_MIN; |
2011 | } |
2012 | |
2013 | /*! |
2014 | Returns the second part (0 to 59) of the time. |
2015 | |
2016 | Returns -1 if the time is invalid. |
2017 | |
2018 | \sa hour(), minute(), msec() |
2019 | */ |
2020 | |
2021 | int QTime::second() const |
2022 | { |
2023 | if (!isValid()) |
2024 | return -1; |
2025 | |
2026 | return (ds() / 1000)%SECS_PER_MIN; |
2027 | } |
2028 | |
2029 | /*! |
2030 | Returns the millisecond part (0 to 999) of the time. |
2031 | |
2032 | Returns -1 if the time is invalid. |
2033 | |
2034 | \sa hour(), minute(), second() |
2035 | */ |
2036 | |
2037 | int QTime::msec() const |
2038 | { |
2039 | if (!isValid()) |
2040 | return -1; |
2041 | |
2042 | return ds() % 1000; |
2043 | } |
2044 | |
2045 | #if QT_CONFIG(datestring) // depends on, so implies, textdate |
2046 | /*! |
2047 | \overload |
2048 | |
2049 | Returns the time as a string. The \a format parameter determines |
2050 | the format of the string. |
2051 | |
2052 | If \a format is Qt::TextDate, the string format is HH:mm:ss; |
2053 | e.g. 1 second before midnight would be "23:59:59". |
2054 | |
2055 | If \a format is Qt::ISODate, the string format corresponds to the |
2056 | ISO 8601 extended specification for representations of dates, |
2057 | represented by HH:mm:ss. To include milliseconds in the ISO 8601 |
2058 | date, use the \a format Qt::ISODateWithMs, which corresponds to |
2059 | HH:mm:ss.zzz. |
2060 | |
2061 | The \a format options Qt::SystemLocaleDate:, Qt::SystemLocaleShortDate and |
2062 | Qt::SystemLocaleLongDate shall be removed in Qt 6. Their use should be |
2063 | replaced with: |
2064 | \l {QLocale::toString()}{QLocale::system().toString(time, QLocale::ShortFormat)} or |
2065 | \l {QLocale::toString()}{QLocale::system().toString(time, QLocale::LongFormat)}. |
2066 | |
2067 | The \a format options Qt::LocaleDate, Qt::DefaultLocaleShortDate and |
2068 | Qt::DefaultLocaleLongDate shall be removed in Qt 6. Their use should be |
2069 | replaced with: |
2070 | \l {QLocale::toString()}{QLocale().toString(time, QLocale::ShortFormat)} or |
2071 | \l {QLocale::toString()}{QLocale().toString(time, QLocale::LongFormat)}. |
2072 | |
2073 | If the \a format is Qt::RFC2822Date, the string is formatted in |
2074 | an \l{RFC 2822} compatible way. An example of this formatting is |
2075 | "23:59:20". |
2076 | |
2077 | If the time is invalid, an empty string will be returned. |
2078 | |
2079 | \sa fromString(), QDate::toString(), QDateTime::toString(), QLocale::toString() |
2080 | */ |
2081 | |
2082 | QString QTime::toString(Qt::DateFormat format) const |
2083 | { |
2084 | if (!isValid()) |
2085 | return QString(); |
2086 | |
2087 | switch (format) { |
2088 | #if QT_DEPRECATED_SINCE(5, 15) |
2089 | QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED |
2090 | case Qt::SystemLocaleDate: |
2091 | case Qt::SystemLocaleShortDate: |
2092 | return QLocale::system().toString(time: *this, format: QLocale::ShortFormat); |
2093 | case Qt::SystemLocaleLongDate: |
2094 | return QLocale::system().toString(time: *this, format: QLocale::LongFormat); |
2095 | case Qt::LocaleDate: |
2096 | case Qt::DefaultLocaleShortDate: |
2097 | return QLocale().toString(time: *this, format: QLocale::ShortFormat); |
2098 | case Qt::DefaultLocaleLongDate: |
2099 | return QLocale().toString(time: *this, format: QLocale::LongFormat); |
2100 | QT_WARNING_POP |
2101 | #endif // 5.15 |
2102 | case Qt::ISODateWithMs: |
2103 | return QString::asprintf(format: "%02d:%02d:%02d.%03d" , hour(), minute(), second(), msec()); |
2104 | case Qt::RFC2822Date: |
2105 | case Qt::ISODate: |
2106 | case Qt::TextDate: |
2107 | default: |
2108 | return QString::asprintf(format: "%02d:%02d:%02d" , hour(), minute(), second()); |
2109 | } |
2110 | } |
2111 | |
2112 | /*! |
2113 | \fn QString QTime::toString(const QString &format) const |
2114 | \fn QString QTime::toString(QStringView format) const |
2115 | |
2116 | Returns the time as a string. The \a format parameter determines |
2117 | the format of the result string. |
2118 | |
2119 | These expressions may be used: |
2120 | |
2121 | \table |
2122 | \header \li Expression \li Output |
2123 | \row \li h |
2124 | \li The hour without a leading zero (0 to 23 or 1 to 12 if AM/PM display) |
2125 | \row \li hh |
2126 | \li The hour with a leading zero (00 to 23 or 01 to 12 if AM/PM display) |
2127 | \row \li H |
2128 | \li The hour without a leading zero (0 to 23, even with AM/PM display) |
2129 | \row \li HH |
2130 | \li The hour with a leading zero (00 to 23, even with AM/PM display) |
2131 | \row \li m \li The minute without a leading zero (0 to 59) |
2132 | \row \li mm \li The minute with a leading zero (00 to 59) |
2133 | \row \li s \li The whole second, without any leading zero (0 to 59) |
2134 | \row \li ss \li The whole second, with a leading zero where applicable (00 to 59) |
2135 | \row \li z \li The fractional part of the second, to go after a decimal |
2136 | point, without trailing zeroes (0 to 999). Thus "\c{s.z}" |
2137 | reports the seconds to full available (millisecond) precision |
2138 | without trailing zeroes. |
2139 | \row \li zzz \li The fractional part of the second, to millisecond |
2140 | precision, including trailing zeroes where applicable (000 to 999). |
2141 | \row \li AP or A |
2142 | \li Use AM/PM display. \e A/AP will be replaced by an upper-case |
2143 | version of either QLocale::amText() or QLocale::pmText(). |
2144 | \row \li ap or a |
2145 | \li Use am/pm display. \e a/ap will be replaced by a lower-case version |
2146 | of either QLocale::amText() or QLocale::pmText(). |
2147 | \row \li t \li The timezone (for example "CEST") |
2148 | \endtable |
2149 | |
2150 | Any non-empty sequence of characters enclosed in single quotes will be |
2151 | included verbatim in the output string (stripped of the quotes), even if it |
2152 | contains formatting characters. Two consecutive single quotes ("''") are |
2153 | replaced by a single quote in the output. All other characters in the format |
2154 | string are included verbatim in the output string. |
2155 | |
2156 | Formats without separators (e.g. "ddMM") are supported but must be used with |
2157 | care, as the resulting strings aren't always reliably readable (e.g. if "dM" |
2158 | produces "212" it could mean either the 2nd of December or the 21st of |
2159 | February). |
2160 | |
2161 | Example format strings (assuming that the QTime is 14:13:09.042 and the system |
2162 | locale is \c{en_US}) |
2163 | |
2164 | \table |
2165 | \header \li Format \li Result |
2166 | \row \li hh:mm:ss.zzz \li 14:13:09.042 |
2167 | \row \li h:m:s ap \li 2:13:9 pm |
2168 | \row \li H:m:s a \li 14:13:9 pm |
2169 | \endtable |
2170 | |
2171 | If the time is invalid, an empty string will be returned. |
2172 | If \a format is empty, the default format "hh:mm:ss" is used. |
2173 | |
2174 | \note If localized forms of am or pm (the AP, ap, A or a formats) are |
2175 | desired, please switch to using QLocale::system().toString() as QTime |
2176 | methods shall change to use English (C locale) at Qt 6. |
2177 | |
2178 | \sa fromString(), QDate::toString(), QDateTime::toString(), QLocale::toString() |
2179 | */ |
2180 | QString QTime::toString(QStringView format) const |
2181 | { |
2182 | return QLocale::system().toString(time: *this, formatStr: format); // QLocale::c() ### Qt6 |
2183 | } |
2184 | |
2185 | #if QT_STRINGVIEW_VERSION < 2 |
2186 | QString QTime::toString(const QString &format) const |
2187 | { |
2188 | return toString(format: qToStringViewIgnoringNull(s: format)); |
2189 | } |
2190 | #endif |
2191 | |
2192 | #endif // datestring |
2193 | |
2194 | /*! |
2195 | Sets the time to hour \a h, minute \a m, seconds \a s and |
2196 | milliseconds \a ms. |
2197 | |
2198 | \a h must be in the range 0 to 23, \a m and \a s must be in the |
2199 | range 0 to 59, and \a ms must be in the range 0 to 999. |
2200 | Returns \c true if the set time is valid; otherwise returns \c false. |
2201 | |
2202 | \sa isValid() |
2203 | */ |
2204 | |
2205 | bool QTime::setHMS(int h, int m, int s, int ms) |
2206 | { |
2207 | if (!isValid(h,m,s,ms)) { |
2208 | mds = NullTime; // make this invalid |
2209 | return false; |
2210 | } |
2211 | mds = (h*SECS_PER_HOUR + m*SECS_PER_MIN + s)*1000 + ms; |
2212 | return true; |
2213 | } |
2214 | |
2215 | /*! |
2216 | Returns a QTime object containing a time \a s seconds later |
2217 | than the time of this object (or earlier if \a s is negative). |
2218 | |
2219 | Note that the time will wrap if it passes midnight. |
2220 | |
2221 | Returns a null time if this time is invalid. |
2222 | |
2223 | Example: |
2224 | |
2225 | \snippet code/src_corelib_tools_qdatetime.cpp 5 |
2226 | |
2227 | \sa addMSecs(), secsTo(), QDateTime::addSecs() |
2228 | */ |
2229 | |
2230 | QTime QTime::addSecs(int s) const |
2231 | { |
2232 | s %= SECS_PER_DAY; |
2233 | return addMSecs(ms: s * 1000); |
2234 | } |
2235 | |
2236 | /*! |
2237 | Returns the number of seconds from this time to \a t. |
2238 | If \a t is earlier than this time, the number of seconds returned |
2239 | is negative. |
2240 | |
2241 | Because QTime measures time within a day and there are 86400 |
2242 | seconds in a day, the result is always between -86400 and 86400. |
2243 | |
2244 | secsTo() does not take into account any milliseconds. |
2245 | |
2246 | Returns 0 if either time is invalid. |
2247 | |
2248 | \sa addSecs(), QDateTime::secsTo() |
2249 | */ |
2250 | |
2251 | int QTime::secsTo(const QTime &t) const |
2252 | { |
2253 | if (!isValid() || !t.isValid()) |
2254 | return 0; |
2255 | |
2256 | // Truncate milliseconds as we do not want to consider them. |
2257 | int ourSeconds = ds() / 1000; |
2258 | int theirSeconds = t.ds() / 1000; |
2259 | return theirSeconds - ourSeconds; |
2260 | } |
2261 | |
2262 | /*! |
2263 | Returns a QTime object containing a time \a ms milliseconds later |
2264 | than the time of this object (or earlier if \a ms is negative). |
2265 | |
2266 | Note that the time will wrap if it passes midnight. See addSecs() |
2267 | for an example. |
2268 | |
2269 | Returns a null time if this time is invalid. |
2270 | |
2271 | \sa addSecs(), msecsTo(), QDateTime::addMSecs() |
2272 | */ |
2273 | |
2274 | QTime QTime::addMSecs(int ms) const |
2275 | { |
2276 | QTime t; |
2277 | if (isValid()) { |
2278 | if (ms < 0) { |
2279 | // %,/ not well-defined for -ve, so always work with +ve. |
2280 | int negdays = (MSECS_PER_DAY - ms) / MSECS_PER_DAY; |
2281 | t.mds = (ds() + ms + negdays * MSECS_PER_DAY) % MSECS_PER_DAY; |
2282 | } else { |
2283 | t.mds = (ds() + ms) % MSECS_PER_DAY; |
2284 | } |
2285 | } |
2286 | return t; |
2287 | } |
2288 | |
2289 | /*! |
2290 | Returns the number of milliseconds from this time to \a t. |
2291 | If \a t is earlier than this time, the number of milliseconds returned |
2292 | is negative. |
2293 | |
2294 | Because QTime measures time within a day and there are 86400 |
2295 | seconds in a day, the result is always between -86400000 and |
2296 | 86400000 ms. |
2297 | |
2298 | Returns 0 if either time is invalid. |
2299 | |
2300 | \sa secsTo(), addMSecs(), QDateTime::msecsTo() |
2301 | */ |
2302 | |
2303 | int QTime::msecsTo(const QTime &t) const |
2304 | { |
2305 | if (!isValid() || !t.isValid()) |
2306 | return 0; |
2307 | return t.ds() - ds(); |
2308 | } |
2309 | |
2310 | |
2311 | /*! |
2312 | \fn bool QTime::operator==(const QTime &t) const |
2313 | |
2314 | Returns \c true if this time is equal to \a t; otherwise returns \c false. |
2315 | */ |
2316 | |
2317 | /*! |
2318 | \fn bool QTime::operator!=(const QTime &t) const |
2319 | |
2320 | Returns \c true if this time is different from \a t; otherwise returns \c false. |
2321 | */ |
2322 | |
2323 | /*! |
2324 | \fn bool QTime::operator<(const QTime &t) const |
2325 | |
2326 | Returns \c true if this time is earlier than \a t; otherwise returns \c false. |
2327 | */ |
2328 | |
2329 | /*! |
2330 | \fn bool QTime::operator<=(const QTime &t) const |
2331 | |
2332 | Returns \c true if this time is earlier than or equal to \a t; |
2333 | otherwise returns \c false. |
2334 | */ |
2335 | |
2336 | /*! |
2337 | \fn bool QTime::operator>(const QTime &t) const |
2338 | |
2339 | Returns \c true if this time is later than \a t; otherwise returns \c false. |
2340 | */ |
2341 | |
2342 | /*! |
2343 | \fn bool QTime::operator>=(const QTime &t) const |
2344 | |
2345 | Returns \c true if this time is later than or equal to \a t; |
2346 | otherwise returns \c false. |
2347 | */ |
2348 | |
2349 | /*! |
2350 | \fn QTime QTime::fromMSecsSinceStartOfDay(int msecs) |
2351 | |
2352 | Returns a new QTime instance with the time set to the number of \a msecs |
2353 | since the start of the day, i.e. since 00:00:00. |
2354 | |
2355 | If \a msecs falls outside the valid range an invalid QTime will be returned. |
2356 | |
2357 | \sa msecsSinceStartOfDay() |
2358 | */ |
2359 | |
2360 | /*! |
2361 | \fn int QTime::msecsSinceStartOfDay() const |
2362 | |
2363 | Returns the number of msecs since the start of the day, i.e. since 00:00:00. |
2364 | |
2365 | \sa fromMSecsSinceStartOfDay() |
2366 | */ |
2367 | |
2368 | /*! |
2369 | \fn QTime::currentTime() |
2370 | |
2371 | Returns the current time as reported by the system clock. |
2372 | |
2373 | Note that the accuracy depends on the accuracy of the underlying |
2374 | operating system; not all systems provide 1-millisecond accuracy. |
2375 | |
2376 | Furthermore, currentTime() only increases within each day; it shall drop by |
2377 | 24 hours each time midnight passes; and, beside this, changes in it may not |
2378 | correspond to elapsed time, if a daylight-saving transition intervenes. |
2379 | |
2380 | \sa QDateTime::currentDateTime(), QDateTime::currentDateTimeUtc() |
2381 | */ |
2382 | |
2383 | #if QT_CONFIG(datestring) // depends on, so implies, textdate |
2384 | |
2385 | static QTime fromIsoTimeString(QStringView string, Qt::DateFormat format, bool *isMidnight24) |
2386 | { |
2387 | if (isMidnight24) |
2388 | *isMidnight24 = false; |
2389 | |
2390 | const int size = string.size(); |
2391 | if (size < 5 || string.at(n: 2) != QLatin1Char(':')) |
2392 | return QTime(); |
2393 | |
2394 | ParsedInt hour = readInt(text: string.mid(pos: 0, n: 2)); |
2395 | ParsedInt minute = readInt(text: string.mid(pos: 3, n: 2)); |
2396 | if (!hour.ok || !minute.ok) |
2397 | return QTime(); |
2398 | // FIXME: ISO 8601 allows [,.]\d+ after hour, just as it does after minute |
2399 | |
2400 | int second = 0; |
2401 | int msec = 0; |
2402 | |
2403 | if (size == 5) { |
2404 | // HH:mm format |
2405 | second = 0; |
2406 | msec = 0; |
2407 | } else if (string.at(n: 5) == QLatin1Char(',') || string.at(n: 5) == QLatin1Char('.')) { |
2408 | if (format == Qt::TextDate) |
2409 | return QTime(); |
2410 | // ISODate HH:mm.ssssss format |
2411 | // We only want 5 digits worth of fraction of minute. This follows the existing |
2412 | // behavior that determines how milliseconds are read; 4 millisecond digits are |
2413 | // read and then rounded to 3. If we read at most 5 digits for fraction of minute, |
2414 | // the maximum amount of millisecond digits it will expand to once converted to |
2415 | // seconds is 4. E.g. 12:34,99999 will expand to 12:34:59.9994. The milliseconds |
2416 | // will then be rounded up AND clamped to 999. |
2417 | |
2418 | const QStringView minuteFractionStr = string.mid(pos: 6, n: qMin(a: qsizetype(5), b: string.size() - 6)); |
2419 | const ParsedInt parsed = readInt(text: minuteFractionStr); |
2420 | if (!parsed.ok) |
2421 | return QTime(); |
2422 | const float secondWithMs |
2423 | = double(parsed.value) * 60 / (std::pow(x: double(10), y: minuteFractionStr.size())); |
2424 | |
2425 | second = std::floor(x: secondWithMs); |
2426 | const float secondFraction = secondWithMs - second; |
2427 | msec = qMin(a: qRound(d: secondFraction * 1000.0), b: 999); |
2428 | } else if (string.at(n: 5) == QLatin1Char(':')) { |
2429 | // HH:mm:ss or HH:mm:ss.zzz |
2430 | const ParsedInt parsed = readInt(text: string.mid(pos: 6, n: qMin(a: qsizetype(2), b: string.size() - 6))); |
2431 | if (!parsed.ok) |
2432 | return QTime(); |
2433 | second = parsed.value; |
2434 | if (size <= 8) { |
2435 | // No fractional part to read |
2436 | } else if (string.at(n: 8) == QLatin1Char(',') || string.at(n: 8) == QLatin1Char('.')) { |
2437 | QStringView msecStr(string.mid(pos: 9, n: qMin(a: qsizetype(4), b: string.size() - 9))); |
2438 | bool ok = true; |
2439 | // Can't use readInt() here, as we *do* allow trailing space - but not leading: |
2440 | if (!msecStr.isEmpty() && !msecStr.at(n: 0).isDigit()) |
2441 | return QTime(); |
2442 | msecStr = msecStr.trimmed(); |
2443 | int msecInt = msecStr.isEmpty() ? 0 : QLocale::c().toInt(s: msecStr, ok: &ok); |
2444 | if (!ok) |
2445 | return QTime(); |
2446 | const double secondFraction(msecInt / (std::pow(x: double(10), y: msecStr.size()))); |
2447 | msec = qMin(a: qRound(d: secondFraction * 1000.0), b: 999); |
2448 | } else { |
2449 | #if QT_VERSION >= QT_VERSION_CHECK(6,0,0) // behavior change |
2450 | // Stray cruft after date-time: tolerate trailing space, but nothing else. |
2451 | for (const auto &ch : string.mid(8)) { |
2452 | if (!ch.isSpace()) |
2453 | return QTime(); |
2454 | } |
2455 | #endif |
2456 | } |
2457 | } else { |
2458 | return QTime(); |
2459 | } |
2460 | |
2461 | const bool isISODate = format == Qt::ISODate || format == Qt::ISODateWithMs; |
2462 | if (isISODate && hour.value == 24 && minute.value == 0 && second == 0 && msec == 0) { |
2463 | if (isMidnight24) |
2464 | *isMidnight24 = true; |
2465 | hour.value = 0; |
2466 | } |
2467 | |
2468 | return QTime(hour.value, minute.value, second, msec); |
2469 | } |
2470 | |
2471 | /*! |
2472 | Returns the time represented in the \a string as a QTime using the |
2473 | \a format given, or an invalid time if this is not possible. |
2474 | |
2475 | Note that fromString() uses a "C" locale encoded string to convert |
2476 | milliseconds to a float value. If the default locale is not "C", |
2477 | this may result in two conversion attempts (if the conversion |
2478 | fails for the default locale). This should be considered an |
2479 | implementation detail. |
2480 | |
2481 | |
2482 | \note Support for localized dates, including the format options |
2483 | Qt::SystemLocaleDate, Qt::SystemLocaleShortDate, Qt::SystemLocaleLongDate, |
2484 | Qt::LocaleDate, Qt::DefaultLocaleShortDate, and Qt::DefaultLocaleLongDate, |
2485 | shall be removed in Qt 6. Use QLocale::toTime() instead. |
2486 | |
2487 | \sa toString(), QLocale::toTime() |
2488 | */ |
2489 | QTime QTime::fromString(const QString &string, Qt::DateFormat format) |
2490 | { |
2491 | if (string.isEmpty()) |
2492 | return QTime(); |
2493 | |
2494 | switch (format) { |
2495 | #if QT_DEPRECATED_SINCE(5, 15) |
2496 | QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED |
2497 | case Qt::SystemLocaleDate: |
2498 | case Qt::SystemLocaleShortDate: |
2499 | return QLocale::system().toTime(string, QLocale::ShortFormat); |
2500 | case Qt::SystemLocaleLongDate: |
2501 | return QLocale::system().toTime(string, QLocale::LongFormat); |
2502 | case Qt::LocaleDate: |
2503 | case Qt::DefaultLocaleShortDate: |
2504 | return QLocale().toTime(string, QLocale::ShortFormat); |
2505 | case Qt::DefaultLocaleLongDate: |
2506 | return QLocale().toTime(string, QLocale::LongFormat); |
2507 | QT_WARNING_POP |
2508 | #endif // 5.15 |
2509 | case Qt::RFC2822Date: |
2510 | return rfcDateImpl(s: string).time; |
2511 | case Qt::ISODate: |
2512 | case Qt::ISODateWithMs: |
2513 | case Qt::TextDate: |
2514 | default: |
2515 | return fromIsoTimeString(string: QStringView(string), format, isMidnight24: nullptr); |
2516 | } |
2517 | } |
2518 | |
2519 | /*! |
2520 | Returns the QTime represented by the \a string, using the \a |
2521 | format given, or an invalid time if the string cannot be parsed. |
2522 | |
2523 | These expressions may be used for the format: |
2524 | |
2525 | \table |
2526 | \header \li Expression \li Output |
2527 | \row \li h |
2528 | \li The hour without a leading zero (0 to 23 or 1 to 12 if AM/PM display) |
2529 | \row \li hh |
2530 | \li The hour with a leading zero (00 to 23 or 01 to 12 if AM/PM display) |
2531 | \row \li H |
2532 | \li The hour without a leading zero (0 to 23, even with AM/PM display) |
2533 | \row \li HH |
2534 | \li The hour with a leading zero (00 to 23, even with AM/PM display) |
2535 | \row \li m \li The minute without a leading zero (0 to 59) |
2536 | \row \li mm \li The minute with a leading zero (00 to 59) |
2537 | \row \li s \li The whole second, without any leading zero (0 to 59) |
2538 | \row \li ss \li The whole second, with a leading zero where applicable (00 to 59) |
2539 | \row \li z \li The fractional part of the second, to go after a decimal |
2540 | point, without trailing zeroes (0 to 999). Thus "\c{s.z}" |
2541 | reports the seconds to full available (millisecond) precision |
2542 | without trailing zeroes. |
2543 | \row \li zzz \li The fractional part of the second, to millisecond |
2544 | precision, including trailing zeroes where applicable (000 to 999). |
2545 | \row \li AP or A |
2546 | \li Interpret as an AM/PM time. \e A/AP will match an upper-case |
2547 | version of either QLocale::amText() or QLocale::pmText(). |
2548 | \row \li ap or a |
2549 | \li Interpret as an am/pm time. \e a/ap will match a lower-case version |
2550 | of either QLocale::amText() or QLocale::pmText(). |
2551 | \endtable |
2552 | |
2553 | All other input characters will be treated as text. Any non-empty sequence |
2554 | of characters enclosed in single quotes will also be treated (stripped of |
2555 | the quotes) as text and not be interpreted as expressions. |
2556 | |
2557 | \snippet code/src_corelib_tools_qdatetime.cpp 6 |
2558 | |
2559 | If the format is not satisfied, an invalid QTime is returned. |
2560 | Expressions that do not expect leading zeroes to be given (h, m, s |
2561 | and z) are greedy. This means that they will use two digits even if |
2562 | this puts them outside the range of accepted values and leaves too |
2563 | few digits for other sections. For example, the following string |
2564 | could have meant 00:07:10, but the m will grab two digits, resulting |
2565 | in an invalid time: |
2566 | |
2567 | \snippet code/src_corelib_tools_qdatetime.cpp 7 |
2568 | |
2569 | Any field that is not represented in the format will be set to zero. |
2570 | For example: |
2571 | |
2572 | \snippet code/src_corelib_tools_qdatetime.cpp 8 |
2573 | |
2574 | \note If localized forms of am or pm (the AP, ap, A or a formats) are used, |
2575 | please switch to using QLocale::system().toTime() as QTime methods shall |
2576 | change to only recognize English (C locale) at Qt 6. |
2577 | |
2578 | \sa toString(), QDateTime::fromString(), QDate::fromString(), |
2579 | QLocale::toTime() |
2580 | */ |
2581 | |
2582 | QTime QTime::fromString(const QString &string, const QString &format) |
2583 | { |
2584 | QTime time; |
2585 | #if QT_CONFIG(datetimeparser) |
2586 | QDateTimeParser dt(QMetaType::QTime, QDateTimeParser::FromString, QCalendar()); |
2587 | // dt.setDefaultLocale(QLocale::c()); ### Qt 6 |
2588 | if (dt.parseFormat(format)) |
2589 | dt.fromString(text: string, date: nullptr, time: &time); |
2590 | #else |
2591 | Q_UNUSED(string); |
2592 | Q_UNUSED(format); |
2593 | #endif |
2594 | return time; |
2595 | } |
2596 | |
2597 | #endif // datestring |
2598 | |
2599 | |
2600 | /*! |
2601 | \overload |
2602 | |
2603 | Returns \c true if the specified time is valid; otherwise returns |
2604 | false. |
2605 | |
2606 | The time is valid if \a h is in the range 0 to 23, \a m and |
2607 | \a s are in the range 0 to 59, and \a ms is in the range 0 to 999. |
2608 | |
2609 | Example: |
2610 | |
2611 | \snippet code/src_corelib_tools_qdatetime.cpp 9 |
2612 | */ |
2613 | |
2614 | bool QTime::isValid(int h, int m, int s, int ms) |
2615 | { |
2616 | return (uint)h < 24 && (uint)m < 60 && (uint)s < 60 && (uint)ms < 1000; |
2617 | } |
2618 | |
2619 | #if QT_DEPRECATED_SINCE(5, 14) // ### Qt 6: remove |
2620 | /*! |
2621 | \deprecated |
2622 | |
2623 | Sets this time to the current time. This is practical for timing: |
2624 | |
2625 | \snippet code/src_corelib_tools_qdatetime.cpp 10 |
2626 | |
2627 | \sa restart(), elapsed(), currentTime() |
2628 | */ |
2629 | |
2630 | void QTime::start() |
2631 | { |
2632 | *this = currentTime(); |
2633 | } |
2634 | |
2635 | /*! |
2636 | Sets this time to the current time and returns the number of |
2637 | milliseconds that have elapsed since the last time start() or |
2638 | restart() was called. |
2639 | |
2640 | This function is guaranteed to be atomic and is thus very handy |
2641 | for repeated measurements. Call start() to start the first |
2642 | measurement, and restart() for each later measurement. |
2643 | |
2644 | Note that the counter wraps to zero 24 hours after the last call |
2645 | to start() or restart(). |
2646 | |
2647 | \warning If the system's clock setting has been changed since the |
2648 | last time start() or restart() was called, the result is |
2649 | undefined. This can happen when daylight-saving time is turned on |
2650 | or off. |
2651 | |
2652 | \sa start(), elapsed(), currentTime() |
2653 | */ |
2654 | |
2655 | int QTime::restart() |
2656 | { |
2657 | QTime t = currentTime(); |
2658 | int n = msecsTo(t); |
2659 | if (n < 0) // passed midnight |
2660 | n += 86400*1000; |
2661 | *this = t; |
2662 | return n; |
2663 | } |
2664 | |
2665 | /*! |
2666 | \deprecated |
2667 | |
2668 | Returns the number of milliseconds that have elapsed since the |
2669 | last time start() or restart() was called. |
2670 | |
2671 | Note that the counter wraps to zero 24 hours after the last call |
2672 | to start() or restart. |
2673 | |
2674 | Note that the accuracy depends on the accuracy of the underlying |
2675 | operating system; not all systems provide 1-millisecond accuracy. |
2676 | |
2677 | \warning If the system's clock setting has been changed since the |
2678 | last time start() or restart() was called, the result is |
2679 | undefined. This can happen when daylight-saving time is turned on |
2680 | or off. |
2681 | |
2682 | \sa start(), restart() |
2683 | */ |
2684 | |
2685 | int QTime::elapsed() const |
2686 | { |
2687 | int n = msecsTo(t: currentTime()); |
2688 | if (n < 0) // passed midnight |
2689 | n += 86400 * 1000; |
2690 | return n; |
2691 | } |
2692 | #endif // Use QElapsedTimer instead ! |
2693 | |
2694 | /***************************************************************************** |
2695 | QDateTime static helper functions |
2696 | *****************************************************************************/ |
2697 | |
2698 | // get the types from QDateTime (through QDateTimePrivate) |
2699 | typedef QDateTimePrivate::QDateTimeShortData ShortData; |
2700 | typedef QDateTimePrivate::QDateTimeData QDateTimeData; |
2701 | |
2702 | // Returns the platform variant of timezone, i.e. the standard time offset |
2703 | // The timezone external variable is documented as always holding the |
2704 | // Standard Time offset as seconds west of Greenwich, i.e. UTC+01:00 is -3600 |
2705 | // Note this may not be historicaly accurate. |
2706 | // Relies on tzset, mktime, or localtime having been called to populate timezone |
2707 | static int qt_timezone() |
2708 | { |
2709 | #if defined(_MSC_VER) |
2710 | long offset; |
2711 | _get_timezone(&offset); |
2712 | return offset; |
2713 | #elif defined(Q_OS_BSD4) && !defined(Q_OS_DARWIN) |
2714 | time_t clock = time(NULL); |
2715 | struct tm t; |
2716 | localtime_r(&clock, &t); |
2717 | // QTBUG-36080 Workaround for systems without the POSIX timezone |
2718 | // variable. This solution is not very efficient but fixing it is up to |
2719 | // the libc implementations. |
2720 | // |
2721 | // tm_gmtoff has some important differences compared to the timezone |
2722 | // variable: |
2723 | // - It returns the number of seconds east of UTC, and we want the |
2724 | // number of seconds west of UTC. |
2725 | // - It also takes DST into account, so we need to adjust it to always |
2726 | // get the Standard Time offset. |
2727 | return -t.tm_gmtoff + (t.tm_isdst ? (long)SECS_PER_HOUR : 0L); |
2728 | #elif defined(Q_OS_INTEGRITY) || defined(Q_OS_RTEMS) |
2729 | return 0; |
2730 | #else |
2731 | return timezone; |
2732 | #endif // Q_OS_WIN |
2733 | } |
2734 | |
2735 | // Returns the tzname, assume tzset has been called already |
2736 | static QString qt_tzname(QDateTimePrivate::DaylightStatus daylightStatus) |
2737 | { |
2738 | int isDst = (daylightStatus == QDateTimePrivate::DaylightTime) ? 1 : 0; |
2739 | #if defined(Q_CC_MSVC) |
2740 | size_t s = 0; |
2741 | char name[512]; |
2742 | if (_get_tzname(&s, name, 512, isDst)) |
2743 | return QString(); |
2744 | return QString::fromLocal8Bit(name); |
2745 | #else |
2746 | return QString::fromLocal8Bit(str: tzname[isDst]); |
2747 | #endif // Q_OS_WIN |
2748 | } |
2749 | |
2750 | #if QT_CONFIG(datetimeparser) |
2751 | /* |
2752 | \internal |
2753 | Implemented here to share qt_tzname() |
2754 | */ |
2755 | int QDateTimeParser::startsWithLocalTimeZone(const QStringRef name) |
2756 | { |
2757 | QDateTimePrivate::DaylightStatus zones[2] = { |
2758 | QDateTimePrivate::StandardTime, |
2759 | QDateTimePrivate::DaylightTime |
2760 | }; |
2761 | for (const auto z : zones) { |
2762 | QString zone(qt_tzname(daylightStatus: z)); |
2763 | if (name.startsWith(s: zone)) |
2764 | return zone.size(); |
2765 | } |
2766 | return 0; |
2767 | } |
2768 | #endif // datetimeparser |
2769 | |
2770 | // Calls the platform variant of mktime for the given date, time and daylightStatus, |
2771 | // and updates the date, time, daylightStatus and abbreviation with the returned values |
2772 | // If the date falls outside the 1970 to 2037 range supported by mktime / time_t |
2773 | // then null date/time will be returned, you should adjust the date first if |
2774 | // you need a guaranteed result. |
2775 | static qint64 qt_mktime(QDate *date, QTime *time, QDateTimePrivate::DaylightStatus *daylightStatus, |
2776 | QString *abbreviation, bool *ok = nullptr) |
2777 | { |
2778 | const qint64 msec = time->msec(); |
2779 | int yy, mm, dd; |
2780 | date->getDate(year: &yy, month: &mm, day: &dd); |
2781 | |
2782 | // All other platforms provide standard C library time functions |
2783 | tm local; |
2784 | memset(s: &local, c: 0, n: sizeof(local)); // tm_[wy]day plus any non-standard fields |
2785 | local.tm_sec = time->second(); |
2786 | local.tm_min = time->minute(); |
2787 | local.tm_hour = time->hour(); |
2788 | local.tm_mday = dd; |
2789 | local.tm_mon = mm - 1; |
2790 | local.tm_year = yy - 1900; |
2791 | if (daylightStatus) |
2792 | local.tm_isdst = int(*daylightStatus); |
2793 | else |
2794 | local.tm_isdst = -1; |
2795 | |
2796 | #if defined(Q_OS_WIN) |
2797 | int hh = local.tm_hour; |
2798 | #endif // Q_OS_WIN |
2799 | time_t secsSinceEpoch = qMkTime(when: &local); |
2800 | if (secsSinceEpoch != time_t(-1)) { |
2801 | *date = QDate(local.tm_year + 1900, local.tm_mon + 1, local.tm_mday); |
2802 | *time = QTime(local.tm_hour, local.tm_min, local.tm_sec, msec); |
2803 | #if defined(Q_OS_WIN) |
2804 | // Windows mktime for the missing hour subtracts 1 hour from the time |
2805 | // instead of adding 1 hour. If time differs and is standard time then |
2806 | // this has happened, so add 2 hours to the time and 1 hour to the msecs |
2807 | if (local.tm_isdst == 0 && local.tm_hour != hh) { |
2808 | if (time->hour() >= 22) |
2809 | *date = date->addDays(1); |
2810 | *time = time->addSecs(2 * SECS_PER_HOUR); |
2811 | secsSinceEpoch += SECS_PER_HOUR; |
2812 | local.tm_isdst = 1; |
2813 | } |
2814 | #endif // Q_OS_WIN |
2815 | if (local.tm_isdst >= 1) { |
2816 | if (daylightStatus) |
2817 | *daylightStatus = QDateTimePrivate::DaylightTime; |
2818 | if (abbreviation) |
2819 | *abbreviation = qt_tzname(daylightStatus: QDateTimePrivate::DaylightTime); |
2820 | } else if (local.tm_isdst == 0) { |
2821 | if (daylightStatus) |
2822 | *daylightStatus = QDateTimePrivate::StandardTime; |
2823 | if (abbreviation) |
2824 | *abbreviation = qt_tzname(daylightStatus: QDateTimePrivate::StandardTime); |
2825 | } else { |
2826 | if (daylightStatus) |
2827 | *daylightStatus = QDateTimePrivate::UnknownDaylightTime; |
2828 | if (abbreviation) |
2829 | *abbreviation = qt_tzname(daylightStatus: QDateTimePrivate::StandardTime); |
2830 | } |
2831 | if (ok) |
2832 | *ok = true; |
2833 | } else { |
2834 | *date = QDate(); |
2835 | *time = QTime(); |
2836 | if (daylightStatus) |
2837 | *daylightStatus = QDateTimePrivate::UnknownDaylightTime; |
2838 | if (abbreviation) |
2839 | *abbreviation = QString(); |
2840 | if (ok) |
2841 | *ok = false; |
2842 | } |
2843 | |
2844 | return ((qint64)secsSinceEpoch * 1000) + msec; |
2845 | } |
2846 | |
2847 | // Calls the platform variant of localtime for the given msecs, and updates |
2848 | // the date, time, and DST status with the returned values. |
2849 | static bool qt_localtime(qint64 msecsSinceEpoch, QDate *localDate, QTime *localTime, |
2850 | QDateTimePrivate::DaylightStatus *daylightStatus) |
2851 | { |
2852 | const time_t secsSinceEpoch = msecsSinceEpoch / 1000; |
2853 | const int msec = msecsSinceEpoch % 1000; |
2854 | |
2855 | tm local; |
2856 | bool valid = false; |
2857 | |
2858 | // localtime() is specified to work as if it called tzset(). |
2859 | // localtime_r() does not have this constraint, so make an explicit call. |
2860 | // The explicit call should also request the timezone info be re-parsed. |
2861 | qTzSet(); |
2862 | #if QT_CONFIG(thread) && defined(_POSIX_THREAD_SAFE_FUNCTIONS) |
2863 | // Use the reentrant version of localtime() where available |
2864 | // as is thread-safe and doesn't use a shared static data area |
2865 | tm *res = nullptr; |
2866 | res = localtime_r(timer: &secsSinceEpoch, tp: &local); |
2867 | if (res) |
2868 | valid = true; |
2869 | #elif defined(Q_CC_MSVC) |
2870 | if (!_localtime64_s(&local, &secsSinceEpoch)) |
2871 | valid = true; |
2872 | #else |
2873 | // Returns shared static data which may be overwritten at any time |
2874 | // So copy the result asap |
2875 | tm *res = nullptr; |
2876 | res = localtime(&secsSinceEpoch); |
2877 | if (res) { |
2878 | local = *res; |
2879 | valid = true; |
2880 | } |
2881 | #endif |
2882 | if (valid) { |
2883 | *localDate = QDate(local.tm_year + 1900, local.tm_mon + 1, local.tm_mday); |
2884 | *localTime = QTime(local.tm_hour, local.tm_min, local.tm_sec, msec); |
2885 | if (daylightStatus) { |
2886 | if (local.tm_isdst > 0) |
2887 | *daylightStatus = QDateTimePrivate::DaylightTime; |
2888 | else if (local.tm_isdst < 0) |
2889 | *daylightStatus = QDateTimePrivate::UnknownDaylightTime; |
2890 | else |
2891 | *daylightStatus = QDateTimePrivate::StandardTime; |
2892 | } |
2893 | return true; |
2894 | } else { |
2895 | *localDate = QDate(); |
2896 | *localTime = QTime(); |
2897 | if (daylightStatus) |
2898 | *daylightStatus = QDateTimePrivate::UnknownDaylightTime; |
2899 | return false; |
2900 | } |
2901 | } |
2902 | |
2903 | // Converts an msecs value into a date and time |
2904 | static void msecsToTime(qint64 msecs, QDate *date, QTime *time) |
2905 | { |
2906 | qint64 jd = JULIAN_DAY_FOR_EPOCH; |
2907 | qint64 ds = 0; |
2908 | |
2909 | if (msecs >= MSECS_PER_DAY || msecs <= -MSECS_PER_DAY) { |
2910 | jd += msecs / MSECS_PER_DAY; |
2911 | msecs %= MSECS_PER_DAY; |
2912 | } |
2913 | |
2914 | if (msecs < 0) { |
2915 | ds = MSECS_PER_DAY - msecs - 1; |
2916 | jd -= ds / MSECS_PER_DAY; |
2917 | ds = ds % MSECS_PER_DAY; |
2918 | ds = MSECS_PER_DAY - ds - 1; |
2919 | } else { |
2920 | ds = msecs; |
2921 | } |
2922 | |
2923 | if (date) |
2924 | *date = QDate::fromJulianDay(jd_: jd); |
2925 | if (time) |
2926 | *time = QTime::fromMSecsSinceStartOfDay(msecs: ds); |
2927 | } |
2928 | |
2929 | // Converts a date/time value into msecs |
2930 | static qint64 timeToMSecs(QDate date, QTime time) |
2931 | { |
2932 | return ((date.toJulianDay() - JULIAN_DAY_FOR_EPOCH) * MSECS_PER_DAY) |
2933 | + time.msecsSinceStartOfDay(); |
2934 | } |
2935 | |
2936 | // Convert an MSecs Since Epoch into Local Time |
2937 | static bool epochMSecsToLocalTime(qint64 msecs, QDate *localDate, QTime *localTime, |
2938 | QDateTimePrivate::DaylightStatus *daylightStatus = nullptr) |
2939 | { |
2940 | if (msecs < 0) { |
2941 | // Docs state any LocalTime before 1970-01-01 will *not* have any Daylight Time applied |
2942 | // Instead just use the standard offset from UTC to convert to UTC time |
2943 | qTzSet(); |
2944 | msecsToTime(msecs: msecs - qt_timezone() * 1000, date: localDate, time: localTime); |
2945 | if (daylightStatus) |
2946 | *daylightStatus = QDateTimePrivate::StandardTime; |
2947 | return true; |
2948 | } else if (msecs > (qint64(TIME_T_MAX) * 1000)) { |
2949 | // Docs state any LocalTime after 2037-12-31 *will* have any DST applied |
2950 | // but this may fall outside the supported time_t range, so need to fake it. |
2951 | // Use existing method to fake the conversion, but this is deeply flawed as it may |
2952 | // apply the conversion from the wrong day number, e.g. if rule is last Sunday of month |
2953 | // TODO Use QTimeZone when available to apply the future rule correctly |
2954 | QDate utcDate; |
2955 | QTime utcTime; |
2956 | msecsToTime(msecs, date: &utcDate, time: &utcTime); |
2957 | int year, month, day; |
2958 | utcDate.getDate(year: &year, month: &month, day: &day); |
2959 | // 2037 is not a leap year, so make sure date isn't Feb 29 |
2960 | if (month == 2 && day == 29) |
2961 | --day; |
2962 | QDate fakeDate(2037, month, day); |
2963 | qint64 fakeMsecs = QDateTime(fakeDate, utcTime, Qt::UTC).toMSecsSinceEpoch(); |
2964 | bool res = qt_localtime(msecsSinceEpoch: fakeMsecs, localDate, localTime, daylightStatus); |
2965 | *localDate = localDate->addDays(ndays: fakeDate.daysTo(d: utcDate)); |
2966 | return res; |
2967 | } else { |
2968 | // Falls inside time_t suported range so can use localtime |
2969 | return qt_localtime(msecsSinceEpoch: msecs, localDate, localTime, daylightStatus); |
2970 | } |
2971 | } |
2972 | |
2973 | // Convert a LocalTime expressed in local msecs encoding and the corresponding |
2974 | // DST status into a UTC epoch msecs. Optionally populate the returned |
2975 | // values from mktime for the adjusted local date and time. |
2976 | static qint64 localMSecsToEpochMSecs(qint64 localMsecs, |
2977 | QDateTimePrivate::DaylightStatus *daylightStatus, |
2978 | QDate *localDate = nullptr, QTime *localTime = nullptr, |
2979 | QString *abbreviation = nullptr) |
2980 | { |
2981 | QDate dt; |
2982 | QTime tm; |
2983 | msecsToTime(msecs: localMsecs, date: &dt, time: &tm); |
2984 | |
2985 | const qint64 msecsMax = qint64(TIME_T_MAX) * 1000; |
2986 | |
2987 | if (localMsecs <= qint64(MSECS_PER_DAY)) { |
2988 | |
2989 | // Docs state any LocalTime before 1970-01-01 will *not* have any DST applied |
2990 | |
2991 | // First, if localMsecs is within +/- 1 day of minimum time_t try mktime in case it does |
2992 | // fall after minimum and needs proper DST conversion |
2993 | if (localMsecs >= -qint64(MSECS_PER_DAY)) { |
2994 | bool valid; |
2995 | qint64 utcMsecs = qt_mktime(date: &dt, time: &tm, daylightStatus, abbreviation, ok: &valid); |
2996 | if (valid && utcMsecs >= 0) { |
2997 | // mktime worked and falls in valid range, so use it |
2998 | if (localDate) |
2999 | *localDate = dt; |
3000 | if (localTime) |
3001 | *localTime = tm; |
3002 | return utcMsecs; |
3003 | } |
3004 | } else { |
3005 | // If we don't call mktime then need to call tzset to get offset |
3006 | qTzSet(); |
3007 | } |
3008 | // Time is clearly before 1970-01-01 so just use standard offset to convert |
3009 | qint64 utcMsecs = localMsecs + qt_timezone() * 1000; |
3010 | if (localDate || localTime) |
3011 | msecsToTime(msecs: localMsecs, date: localDate, time: localTime); |
3012 | if (daylightStatus) |
3013 | *daylightStatus = QDateTimePrivate::StandardTime; |
3014 | if (abbreviation) |
3015 | *abbreviation = qt_tzname(daylightStatus: QDateTimePrivate::StandardTime); |
3016 | return utcMsecs; |
3017 | |
3018 | } else if (localMsecs >= msecsMax - MSECS_PER_DAY) { |
3019 | |
3020 | // Docs state any LocalTime after 2037-12-31 *will* have any DST applied |
3021 | // but this may fall outside the supported time_t range, so need to fake it. |
3022 | |
3023 | // First, if localMsecs is within +/- 1 day of maximum time_t try mktime in case it does |
3024 | // fall before maximum and can use proper DST conversion |
3025 | if (localMsecs <= msecsMax + MSECS_PER_DAY) { |
3026 | bool valid; |
3027 | qint64 utcMsecs = qt_mktime(date: &dt, time: &tm, daylightStatus, abbreviation, ok: &valid); |
3028 | if (valid && utcMsecs <= msecsMax) { |
3029 | // mktime worked and falls in valid range, so use it |
3030 | if (localDate) |
3031 | *localDate = dt; |
3032 | if (localTime) |
3033 | *localTime = tm; |
3034 | return utcMsecs; |
3035 | } |
3036 | } |
3037 | // Use existing method to fake the conversion, but this is deeply flawed as it may |
3038 | // apply the conversion from the wrong day number, e.g. if rule is last Sunday of month |
3039 | // TODO Use QTimeZone when available to apply the future rule correctly |
3040 | int year, month, day; |
3041 | dt.getDate(year: &year, month: &month, day: &day); |
3042 | // 2037 is not a leap year, so make sure date isn't Feb 29 |
3043 | if (month == 2 && day == 29) |
3044 | --day; |
3045 | QDate fakeDate(2037, month, day); |
3046 | qint64 fakeDiff = fakeDate.daysTo(d: dt); |
3047 | qint64 utcMsecs = qt_mktime(date: &fakeDate, time: &tm, daylightStatus, abbreviation); |
3048 | if (localDate) |
3049 | *localDate = fakeDate.addDays(ndays: fakeDiff); |
3050 | if (localTime) |
3051 | *localTime = tm; |
3052 | QDate utcDate; |
3053 | QTime utcTime; |
3054 | msecsToTime(msecs: utcMsecs, date: &utcDate, time: &utcTime); |
3055 | utcDate = utcDate.addDays(ndays: fakeDiff); |
3056 | utcMsecs = timeToMSecs(date: utcDate, time: utcTime); |
3057 | return utcMsecs; |
3058 | |
3059 | } else { |
3060 | |
3061 | // Clearly falls inside 1970-2037 suported range so can use mktime |
3062 | qint64 utcMsecs = qt_mktime(date: &dt, time: &tm, daylightStatus, abbreviation); |
3063 | if (localDate) |
3064 | *localDate = dt; |
3065 | if (localTime) |
3066 | *localTime = tm; |
3067 | return utcMsecs; |
3068 | |
3069 | } |
3070 | } |
3071 | |
3072 | static inline bool specCanBeSmall(Qt::TimeSpec spec) |
3073 | { |
3074 | return spec == Qt::LocalTime || spec == Qt::UTC; |
3075 | } |
3076 | |
3077 | static inline bool msecsCanBeSmall(qint64 msecs) |
3078 | { |
3079 | if (!QDateTimeData::CanBeSmall) |
3080 | return false; |
3081 | |
3082 | ShortData sd; |
3083 | sd.msecs = qintptr(msecs); |
3084 | return sd.msecs == msecs; |
3085 | } |
3086 | |
3087 | static Q_DECL_CONSTEXPR inline |
3088 | QDateTimePrivate::StatusFlags mergeSpec(QDateTimePrivate::StatusFlags status, Qt::TimeSpec spec) |
3089 | { |
3090 | return QDateTimePrivate::StatusFlags((status & ~QDateTimePrivate::TimeSpecMask) | |
3091 | (int(spec) << QDateTimePrivate::TimeSpecShift)); |
3092 | } |
3093 | |
3094 | static Q_DECL_CONSTEXPR inline Qt::TimeSpec (QDateTimePrivate::StatusFlags status) |
3095 | { |
3096 | return Qt::TimeSpec((status & QDateTimePrivate::TimeSpecMask) >> QDateTimePrivate::TimeSpecShift); |
3097 | } |
3098 | |
3099 | // Set the Daylight Status if LocalTime set via msecs |
3100 | static Q_DECL_RELAXED_CONSTEXPR inline QDateTimePrivate::StatusFlags |
3101 | mergeDaylightStatus(QDateTimePrivate::StatusFlags sf, QDateTimePrivate::DaylightStatus status) |
3102 | { |
3103 | sf &= ~QDateTimePrivate::DaylightMask; |
3104 | if (status == QDateTimePrivate::DaylightTime) { |
3105 | sf |= QDateTimePrivate::SetToDaylightTime; |
3106 | } else if (status == QDateTimePrivate::StandardTime) { |
3107 | sf |= QDateTimePrivate::SetToStandardTime; |
3108 | } |
3109 | return sf; |
3110 | } |
3111 | |
3112 | // Get the DST Status if LocalTime set via msecs |
3113 | static Q_DECL_RELAXED_CONSTEXPR inline |
3114 | QDateTimePrivate::DaylightStatus (QDateTimePrivate::StatusFlags status) |
3115 | { |
3116 | if (status & QDateTimePrivate::SetToDaylightTime) |
3117 | return QDateTimePrivate::DaylightTime; |
3118 | if (status & QDateTimePrivate::SetToStandardTime) |
3119 | return QDateTimePrivate::StandardTime; |
3120 | return QDateTimePrivate::UnknownDaylightTime; |
3121 | } |
3122 | |
3123 | static inline qint64 getMSecs(const QDateTimeData &d) |
3124 | { |
3125 | if (d.isShort()) { |
3126 | // same as, but producing better code |
3127 | //return d.data.msecs; |
3128 | return qintptr(d.d) >> 8; |
3129 | } |
3130 | return d->m_msecs; |
3131 | } |
3132 | |
3133 | static inline QDateTimePrivate::StatusFlags getStatus(const QDateTimeData &d) |
3134 | { |
3135 | if (d.isShort()) { |
3136 | // same as, but producing better code |
3137 | //return StatusFlag(d.data.status); |
3138 | return QDateTimePrivate::StatusFlag(qintptr(d.d) & 0xFF); |
3139 | } |
3140 | return d->m_status; |
3141 | } |
3142 | |
3143 | static inline Qt::TimeSpec getSpec(const QDateTimeData &d) |
3144 | { |
3145 | return extractSpec(status: getStatus(d)); |
3146 | } |
3147 | |
3148 | #if QT_CONFIG(timezone) |
3149 | void QDateTimePrivate::setUtcOffsetByTZ(qint64 atMSecsSinceEpoch) |
3150 | { |
3151 | m_offsetFromUtc = m_timeZone.d->offsetFromUtc(atMSecsSinceEpoch); |
3152 | } |
3153 | #endif |
3154 | |
3155 | // Refresh the LocalTime validity and offset |
3156 | static void refreshDateTime(QDateTimeData &d) |
3157 | { |
3158 | auto status = getStatus(d); |
3159 | const auto spec = extractSpec(status); |
3160 | const qint64 msecs = getMSecs(d); |
3161 | qint64 epochMSecs = 0; |
3162 | int offsetFromUtc = 0; |
3163 | QDate testDate; |
3164 | QTime testTime; |
3165 | Q_ASSERT(spec == Qt::TimeZone || spec == Qt::LocalTime); |
3166 | |
3167 | #if QT_CONFIG(timezone) |
3168 | // If not valid time zone then is invalid |
3169 | if (spec == Qt::TimeZone) { |
3170 | if (!d->m_timeZone.isValid()) { |
3171 | status &= ~QDateTimePrivate::ValidDateTime; |
3172 | } else { |
3173 | epochMSecs = QDateTimePrivate::zoneMSecsToEpochMSecs(msecs, zone: d->m_timeZone, hint: extractDaylightStatus(status), localDate: &testDate, localTime: &testTime); |
3174 | d->setUtcOffsetByTZ(epochMSecs); |
3175 | } |
3176 | } |
3177 | #endif // timezone |
3178 | |
3179 | // If not valid date and time then is invalid |
3180 | if (!(status & QDateTimePrivate::ValidDate) || !(status & QDateTimePrivate::ValidTime)) { |
3181 | status &= ~QDateTimePrivate::ValidDateTime; |
3182 | if (status & QDateTimePrivate::ShortData) { |
3183 | d.data.status = status; |
3184 | } else { |
3185 | d->m_status = status; |
3186 | d->m_offsetFromUtc = 0; |
3187 | } |
3188 | return; |
3189 | } |
3190 | |
3191 | // We have a valid date and time and a Qt::LocalTime or Qt::TimeZone that needs calculating |
3192 | // LocalTime and TimeZone might fall into a "missing" DST transition hour |
3193 | // Calling toEpochMSecs will adjust the returned date/time if it does |
3194 | if (spec == Qt::LocalTime) { |
3195 | auto dstStatus = extractDaylightStatus(status); |
3196 | epochMSecs = localMSecsToEpochMSecs(localMsecs: msecs, daylightStatus: &dstStatus, localDate: &testDate, localTime: &testTime); |
3197 | status = mergeDaylightStatus(sf: status, status: dstStatus); |
3198 | } |
3199 | if (timeToMSecs(date: testDate, time: testTime) == msecs) { |
3200 | status |= QDateTimePrivate::ValidDateTime; |
3201 | // Cache the offset to use in offsetFromUtc() |
3202 | offsetFromUtc = (msecs - epochMSecs) / 1000; |
3203 | } else { |
3204 | status &= ~QDateTimePrivate::ValidDateTime; |
3205 | } |
3206 | |
3207 | if (status & QDateTimePrivate::ShortData) { |
3208 | d.data.status = status; |
3209 | } else { |
3210 | d->m_status = status; |
3211 | d->m_offsetFromUtc = offsetFromUtc; |
3212 | } |
3213 | } |
3214 | |
3215 | // Check the UTC / offsetFromUTC validity |
3216 | static void checkValidDateTime(QDateTimeData &d) |
3217 | { |
3218 | auto status = getStatus(d); |
3219 | auto spec = extractSpec(status); |
3220 | switch (spec) { |
3221 | case Qt::OffsetFromUTC: |
3222 | case Qt::UTC: |
3223 | // for these, a valid date and a valid time imply a valid QDateTime |
3224 | if ((status & QDateTimePrivate::ValidDate) && (status & QDateTimePrivate::ValidTime)) |
3225 | status |= QDateTimePrivate::ValidDateTime; |
3226 | else |
3227 | status &= ~QDateTimePrivate::ValidDateTime; |
3228 | if (status & QDateTimePrivate::ShortData) |
3229 | d.data.status = status; |
3230 | else |
3231 | d->m_status = status; |
3232 | break; |
3233 | case Qt::TimeZone: |
3234 | case Qt::LocalTime: |
3235 | // for these, we need to check whether the timezone is valid and whether |
3236 | // the time is valid in that timezone. Expensive, but no other option. |
3237 | refreshDateTime(d); |
3238 | break; |
3239 | } |
3240 | } |
3241 | |
3242 | static void setTimeSpec(QDateTimeData &d, Qt::TimeSpec spec, int offsetSeconds) |
3243 | { |
3244 | auto status = getStatus(d); |
3245 | status &= ~(QDateTimePrivate::ValidDateTime | QDateTimePrivate::DaylightMask | |
3246 | QDateTimePrivate::TimeSpecMask); |
3247 | |
3248 | switch (spec) { |
3249 | case Qt::OffsetFromUTC: |
3250 | if (offsetSeconds == 0) |
3251 | spec = Qt::UTC; |
3252 | break; |
3253 | case Qt::TimeZone: |
3254 | // Use system time zone instead |
3255 | spec = Qt::LocalTime; |
3256 | Q_FALLTHROUGH(); |
3257 | case Qt::UTC: |
3258 | case Qt::LocalTime: |
3259 | offsetSeconds = 0; |
3260 | break; |
3261 | } |
3262 | |
3263 | status = mergeSpec(status, spec); |
3264 | if (d.isShort() && offsetSeconds == 0) { |
3265 | d.data.status = status; |
3266 | } else { |
3267 | d.detach(); |
3268 | d->m_status = status & ~QDateTimePrivate::ShortData; |
3269 | d->m_offsetFromUtc = offsetSeconds; |
3270 | #if QT_CONFIG(timezone) |
3271 | d->m_timeZone = QTimeZone(); |
3272 | #endif // timezone |
3273 | } |
3274 | } |
3275 | |
3276 | static void setDateTime(QDateTimeData &d, QDate date, QTime time) |
3277 | { |
3278 | // If the date is valid and the time is not we set time to 00:00:00 |
3279 | QTime useTime = time; |
3280 | if (!useTime.isValid() && date.isValid()) |
3281 | useTime = QTime::fromMSecsSinceStartOfDay(msecs: 0); |
3282 | |
3283 | QDateTimePrivate::StatusFlags newStatus = { }; |
3284 | |
3285 | // Set date value and status |
3286 | qint64 days = 0; |
3287 | if (date.isValid()) { |
3288 | days = date.toJulianDay() - JULIAN_DAY_FOR_EPOCH; |
3289 | newStatus = QDateTimePrivate::ValidDate; |
3290 | } |
3291 | |
3292 | // Set time value and status |
3293 | int ds = 0; |
3294 | if (useTime.isValid()) { |
3295 | ds = useTime.msecsSinceStartOfDay(); |
3296 | newStatus |= QDateTimePrivate::ValidTime; |
3297 | } |
3298 | |
3299 | // Set msecs serial value |
3300 | qint64 msecs = (days * MSECS_PER_DAY) + ds; |
3301 | if (d.isShort()) { |
3302 | // let's see if we can keep this short |
3303 | if (msecsCanBeSmall(msecs)) { |
3304 | // yes, we can |
3305 | d.data.msecs = qintptr(msecs); |
3306 | d.data.status &= ~(QDateTimePrivate::ValidityMask | QDateTimePrivate::DaylightMask); |
3307 | d.data.status |= newStatus; |
3308 | } else { |
3309 | // nope... |
3310 | d.detach(); |
3311 | } |
3312 | } |
3313 | if (!d.isShort()) { |
3314 | d.detach(); |
3315 | d->m_msecs = msecs; |
3316 | d->m_status &= ~(QDateTimePrivate::ValidityMask | QDateTimePrivate::DaylightMask); |
3317 | d->m_status |= newStatus; |
3318 | } |
3319 | |
3320 | // Set if date and time are valid |
3321 | checkValidDateTime(d); |
3322 | } |
3323 | |
3324 | static QPair<QDate, QTime> getDateTime(const QDateTimeData &d) |
3325 | { |
3326 | QPair<QDate, QTime> result; |
3327 | qint64 msecs = getMSecs(d); |
3328 | auto status = getStatus(d); |
3329 | msecsToTime(msecs, date: &result.first, time: &result.second); |
3330 | |
3331 | if (!status.testFlag(flag: QDateTimePrivate::ValidDate)) |
3332 | result.first = QDate(); |
3333 | |
3334 | if (!status.testFlag(flag: QDateTimePrivate::ValidTime)) |
3335 | result.second = QTime(); |
3336 | |
3337 | return result; |
3338 | } |
3339 | |
3340 | /***************************************************************************** |
3341 | QDateTime::Data member functions |
3342 | *****************************************************************************/ |
3343 | |
3344 | inline QDateTime::Data::Data() |
3345 | { |
3346 | // default-constructed data has a special exception: |
3347 | // it can be small even if CanBeSmall == false |
3348 | // (optimization so we don't allocate memory in the default constructor) |
3349 | quintptr value = quintptr(mergeSpec(status: QDateTimePrivate::ShortData, spec: Qt::LocalTime)); |
3350 | d = reinterpret_cast<QDateTimePrivate *>(value); |
3351 | } |
3352 | |
3353 | inline QDateTime::Data::Data(Qt::TimeSpec spec) |
3354 | { |
3355 | if (CanBeSmall && Q_LIKELY(specCanBeSmall(spec))) { |
3356 | d = reinterpret_cast<QDateTimePrivate *>(quintptr(mergeSpec(status: QDateTimePrivate::ShortData, spec))); |
3357 | } else { |
3358 | // the structure is too small, we need to detach |
3359 | d = new QDateTimePrivate; |
3360 | d->ref.ref(); |
3361 | d->m_status = mergeSpec(status: {}, spec); |
3362 | } |
3363 | } |
3364 | |
3365 | inline QDateTime::Data::Data(const Data &other) |
3366 | : d(other.d) |
3367 | { |
3368 | if (!isShort()) { |
3369 | // check if we could shrink |
3370 | if (specCanBeSmall(spec: extractSpec(status: d->m_status)) && msecsCanBeSmall(msecs: d->m_msecs)) { |
3371 | ShortData sd; |
3372 | sd.msecs = qintptr(d->m_msecs); |
3373 | sd.status = d->m_status | QDateTimePrivate::ShortData; |
3374 | data = sd; |
3375 | } else { |
3376 | // no, have to keep it big |
3377 | d->ref.ref(); |
3378 | } |
3379 | } |
3380 | } |
3381 | |
3382 | inline QDateTime::Data::Data(Data &&other) |
3383 | : d(other.d) |
3384 | { |
3385 | // reset the other to a short state |
3386 | Data dummy; |
3387 | Q_ASSERT(dummy.isShort()); |
3388 | other.d = dummy.d; |
3389 | } |
3390 | |
3391 | inline QDateTime::Data &QDateTime::Data::operator=(const Data &other) |
3392 | { |
3393 | if (d == other.d) |
3394 | return *this; |
3395 | |
3396 | auto x = d; |
3397 | d = other.d; |
3398 | if (!other.isShort()) { |
3399 | // check if we could shrink |
3400 | if (specCanBeSmall(spec: extractSpec(status: other.d->m_status)) && msecsCanBeSmall(msecs: other.d->m_msecs)) { |
3401 | ShortData sd; |
3402 | sd.msecs = qintptr(other.d->m_msecs); |
3403 | sd.status = other.d->m_status | QDateTimePrivate::ShortData; |
3404 | data = sd; |
3405 | } else { |
3406 | // no, have to keep it big |
3407 | other.d->ref.ref(); |
3408 | } |
3409 | } |
3410 | |
3411 | if (!(quintptr(x) & QDateTimePrivate::ShortData) && !x->ref.deref()) |
3412 | delete x; |
3413 | return *this; |
3414 | } |
3415 | |
3416 | inline QDateTime::Data::~Data() |
3417 | { |
3418 | if (!isShort() && !d->ref.deref()) |
3419 | delete d; |
3420 | } |
3421 | |
3422 | inline bool QDateTime::Data::isShort() const |
3423 | { |
3424 | bool b = quintptr(d) & QDateTimePrivate::ShortData; |
3425 | |
3426 | // sanity check: |
3427 | Q_ASSERT(b || (d->m_status & QDateTimePrivate::ShortData) == 0); |
3428 | |
3429 | // even if CanBeSmall = false, we have short data for a default-constructed |
3430 | // QDateTime object. But it's unlikely. |
3431 | if (CanBeSmall) |
3432 | return Q_LIKELY(b); |
3433 | return Q_UNLIKELY(b); |
3434 | } |
3435 | |
3436 | inline void QDateTime::Data::detach() |
3437 | { |
3438 | QDateTimePrivate *x; |
3439 | bool wasShort = isShort(); |
3440 | if (wasShort) { |
3441 | // force enlarging |
3442 | x = new QDateTimePrivate; |
3443 | x->m_status = QDateTimePrivate::StatusFlag(data.status & ~QDateTimePrivate::ShortData); |
3444 | x->m_msecs = data.msecs; |
3445 | } else { |
3446 | if (d->ref.loadRelaxed() == 1) |
3447 | return; |
3448 | |
3449 | x = new QDateTimePrivate(*d); |
3450 | } |
3451 | |
3452 | x->ref.storeRelaxed(newValue: 1); |
3453 | if (!wasShort && !d->ref.deref()) |
3454 | delete d; |
3455 | d = x; |
3456 | } |
3457 | |
3458 | inline const QDateTimePrivate *QDateTime::Data::operator->() const |
3459 | { |
3460 | Q_ASSERT(!isShort()); |
3461 | return d; |
3462 | } |
3463 | |
3464 | inline QDateTimePrivate *QDateTime::Data::operator->() |
3465 | { |
3466 | // should we attempt to detach here? |
3467 | Q_ASSERT(!isShort()); |
3468 | Q_ASSERT(d->ref.loadRelaxed() == 1); |
3469 | return d; |
3470 | } |
3471 | |
3472 | /***************************************************************************** |
3473 | QDateTimePrivate member functions |
3474 | *****************************************************************************/ |
3475 | |
3476 | Q_NEVER_INLINE |
3477 | QDateTime::Data QDateTimePrivate::create(const QDate &toDate, const QTime &toTime, Qt::TimeSpec toSpec, |
3478 | int offsetSeconds) |
3479 | { |
3480 | QDateTime::Data result(toSpec); |
3481 | setTimeSpec(d&: result, spec: toSpec, offsetSeconds); |
3482 | setDateTime(d&: result, date: toDate, time: toTime); |
3483 | return result; |
3484 | } |
3485 | |
3486 | #if QT_CONFIG(timezone) |
3487 | inline QDateTime::Data QDateTimePrivate::create(const QDate &toDate, const QTime &toTime, |
3488 | const QTimeZone &toTimeZone) |
3489 | { |
3490 | QDateTime::Data result(Qt::TimeZone); |
3491 | Q_ASSERT(!result.isShort()); |
3492 | |
3493 | result.d->m_status = mergeSpec(status: result.d->m_status, spec: Qt::TimeZone); |
3494 | result.d->m_timeZone = toTimeZone; |
3495 | setDateTime(d&: result, date: toDate, time: toTime); |
3496 | return result; |
3497 | } |
3498 | |
3499 | // Convert a TimeZone time expressed in zone msecs encoding into a UTC epoch msecs |
3500 | // DST transitions are disambiguated by hint. |
3501 | inline qint64 QDateTimePrivate::zoneMSecsToEpochMSecs(qint64 zoneMSecs, const QTimeZone &zone, |
3502 | DaylightStatus hint, |
3503 | QDate *zoneDate, QTime *zoneTime) |
3504 | { |
3505 | Q_ASSERT(zone.isValid()); |
3506 | // Get the effective data from QTimeZone |
3507 | QTimeZonePrivate::Data data = zone.d->dataForLocalTime(forLocalMSecs: zoneMSecs, hint: int(hint)); |
3508 | // Docs state any time before 1970-01-01 will *not* have any DST applied |
3509 | // but all affected times afterwards will have DST applied. |
3510 | if (data.atMSecsSinceEpoch < 0) { |
3511 | msecsToTime(msecs: zoneMSecs, date: zoneDate, time: zoneTime); |
3512 | return zoneMSecs - data.standardTimeOffset * 1000; |
3513 | } else { |
3514 | msecsToTime(msecs: data.atMSecsSinceEpoch + data.offsetFromUtc * 1000, date: zoneDate, time: zoneTime); |
3515 | return data.atMSecsSinceEpoch; |
3516 | } |
3517 | } |
3518 | #endif // timezone |
3519 | |
3520 | /***************************************************************************** |
3521 | QDateTime member functions |
3522 | *****************************************************************************/ |
3523 | |
3524 | /*! |
3525 | \class QDateTime |
3526 | \inmodule QtCore |
3527 | \ingroup shared |
3528 | \reentrant |
3529 | \brief The QDateTime class provides date and time functions. |
3530 | |
3531 | |
3532 | A QDateTime object encodes a calendar date and a clock time (a |
3533 | "datetime"). It combines features of the QDate and QTime classes. |
3534 | It can read the current datetime from the system clock. It |
3535 | provides functions for comparing datetimes and for manipulating a |
3536 | datetime by adding a number of seconds, days, months, or years. |
3537 | |
3538 | QDateTime can describe datetimes with respect to \l{Qt::LocalTime}{local |
3539 | time}, to \l{Qt::UTC}{UTC}, to a specified \l{Qt::OffsetFromUTC}{offset from |
3540 | UTC} or to a specified \l{Qt::TimeZone}{time zone}, in conjunction with the |
3541 | QTimeZone class. For example, a time zone of "Europe/Berlin" will apply the |
3542 | daylight-saving rules as used in Germany since 1970. In contrast, an offset |
3543 | from UTC of +3600 seconds is one hour ahead of UTC (usually written in ISO |
3544 | standard notation as "UTC+01:00"), with no daylight-saving offset or |
3545 | changes. When using either local time or a specified time zone, time-zone |
3546 | transitions such as the starts and ends of daylight-saving time (DST; but |
3547 | see below) are taken into account. The choice of system used to represent a |
3548 | datetime is described as its "timespec". |
3549 | |
3550 | A QDateTime object is typically created either by giving a date and time |
3551 | explicitly in the constructor, or by using a static function such as |
3552 | currentDateTime() or fromMSecsSinceEpoch(). The date and time can be changed |
3553 | with setDate() and setTime(). A datetime can also be set using the |
3554 | setMSecsSinceEpoch() function that takes the time, in milliseconds, since |
3555 | 00:00:00 on January 1, 1970. The fromString() function returns a QDateTime, |
3556 | given a string and a date format used to interpret the date within the |
3557 | string. |
3558 | |
3559 | QDateTime::currentDateTime() returns a QDateTime that expresses the current |
3560 | time with respect to local time. QDateTime::currentDateTimeUtc() returns a |
3561 | QDateTime that expresses the current time with respect to UTC. |
3562 | |
3563 | The date() and time() functions provide access to the date and |
3564 | time parts of the datetime. The same information is provided in |
3565 | textual format by the toString() function. |
3566 | |
3567 | QDateTime provides a full set of operators to compare two |
3568 | QDateTime objects, where smaller means earlier and larger means |
3569 | later. |
3570 | |
3571 | You can increment (or decrement) a datetime by a given number of |
3572 | milliseconds using addMSecs(), seconds using addSecs(), or days using |
3573 | addDays(). Similarly, you can use addMonths() and addYears(). The daysTo() |
3574 | function returns the number of days between two datetimes, secsTo() returns |
3575 | the number of seconds between two datetimes, and msecsTo() returns the |
3576 | number of milliseconds between two datetimes. These operations are aware of |
3577 | daylight-saving time (DST) and other time-zone transitions, where |
3578 | applicable. |
3579 | |
3580 | Use toTimeSpec() to express a datetime in local time or UTC, |
3581 | toOffsetFromUtc() to express in terms of an offset from UTC, or toTimeZone() |
3582 | to express it with respect to a general time zone. You can use timeSpec() to |
3583 | find out what time-spec a QDateTime object stores its time relative to. When |
3584 | that is Qt::TimeZone, you can use timeZone() to find out which zone it is |
3585 | using. |
3586 | |
3587 | \note QDateTime does not account for leap seconds. |
3588 | |
3589 | \section1 Remarks |
3590 | |
3591 | \section2 No Year 0 |
3592 | |
3593 | There is no year 0. Dates in that year are considered invalid. The |
3594 | year -1 is the year "1 before Christ" or "1 before current era." |
3595 | The day before 1 January 1 CE is 31 December 1 BCE. |
3596 | |
3597 | \section2 Range of Valid Dates |
3598 | |
3599 | The range of values that QDateTime can represent is dependent on the |
3600 | internal storage implementation. QDateTime is currently stored in a qint64 |
3601 | as a serial msecs value encoding the date and time. This restricts the date |
3602 | range to about +/- 292 million years, compared to the QDate range of +/- 2 |
3603 | billion years. Care must be taken when creating a QDateTime with extreme |
3604 | values that you do not overflow the storage. The exact range of supported |
3605 | values varies depending on the Qt::TimeSpec and time zone. |
3606 | |
3607 | \section2 Use of Timezones |
3608 | |
3609 | QDateTime uses the system's time zone information to determine the current |
3610 | local time zone and its offset from UTC. If the system is not configured |
3611 | correctly or not up-to-date, QDateTime will give wrong results. |
3612 | |
3613 | QDateTime likewise uses system-provided information to determine the offsets |
3614 | of other timezones from UTC. If this information is incomplete or out of |
3615 | date, QDateTime will give wrong results. See the QTimeZone documentation for |
3616 | more details. |
3617 | |
3618 | On modern Unix systems, this means QDateTime usually has accurate |
3619 | information about historical transitions (including DST, see below) whenever |
3620 | possible. On Windows, where the system doesn't support historical timezone |
3621 | data, historical accuracy is not maintained with respect to timezone |
3622 | transitions, notably including DST. |
3623 | |
3624 | \section2 Daylight-Saving Time (DST) |
3625 | |
3626 | QDateTime takes into account transitions between Standard Time and |
3627 | Daylight-Saving Time. For example, if the transition is at 2am and the clock |
3628 | goes forward to 3am, then there is a "missing" hour from 02:00:00 to |
3629 | 02:59:59.999 which QDateTime considers to be invalid. Any date arithmetic |
3630 | performed will take this missing hour into account and return a valid |
3631 | result. For example, adding one minute to 01:59:59 will get 03:00:00. |
3632 | |
3633 | The range of valid dates taking DST into account is 1970-01-01 to the |
3634 | present, and rules are in place for handling DST correctly until 2037-12-31, |
3635 | but these could change. For dates after 2037, QDateTime makes a \e{best |
3636 | guess} using the rules for year 2037, but we can't guarantee accuracy; |
3637 | indeed, for \e{any} future date, the time-zone may change its rules before |
3638 | that date comes around. For dates before 1970, QDateTime doesn't take DST |
3639 | changes into account, even if the system's time zone database provides that |
3640 | information, although it does take into account changes to the time-zone's |
3641 | standard offset, where this information is available. |
3642 | |
3643 | \section2 Offsets From UTC |
3644 | |
3645 | There is no explicit size restriction on an offset from UTC, but there is an |
3646 | implicit limit imposed when using the toString() and fromString() methods |
3647 | which use a [+|-]hh:mm format, effectively limiting the range to +/- 99 |
3648 | hours and 59 minutes and whole minutes only. Note that currently no time |
3649 | zone lies outside the range of +/- 14 hours. |
3650 | |
3651 | \sa QDate, QTime, QDateTimeEdit, QTimeZone |
3652 | */ |
3653 | |
3654 | /*! |
3655 | \since 5.14 |
3656 | \enum QDateTime::YearRange |
3657 | |
3658 | This enumerated type describes the range of years (in the Gregorian |
3659 | calendar) representable by QDateTime: |
3660 | |
3661 | \value First The later parts of this year are representable |
3662 | \value Last The earlier parts of this year are representable |
3663 | |
3664 | All dates strictly between these two years are also representable. |
3665 | Note, however, that the Gregorian Calendar has no year zero. |
3666 | |
3667 | \note QDate can describe dates in a wider range of years. For most |
3668 | purposes, this makes little difference, as the range of years that QDateTime |
3669 | can support reaches 292 million years either side of 1970. |
3670 | |
3671 | \sa isValid(), QDate |
3672 | */ |
3673 | |
3674 | /*! |
3675 | Constructs a null datetime (i.e. null date and null time). A null |
3676 | datetime is invalid, since the date is invalid. |
3677 | |
3678 | \sa isValid() |
3679 | */ |
3680 | QDateTime::QDateTime() noexcept(Data::CanBeSmall) |
3681 | { |
3682 | } |
3683 | |
3684 | |
3685 | #if QT_DEPRECATED_SINCE(5, 17) // ### Qt 6: remove |
3686 | /*! |
3687 | Constructs a datetime with the given \a date, using Qt::LocalTime as the |
3688 | timeSpec() and the time at the start of that date. |
3689 | |
3690 | \sa QDate::startOfDay() |
3691 | */ |
3692 | QDateTime::QDateTime(const QDate &date) |
3693 | : QDateTime(date.startOfDay(spec: Qt::LocalTime, offsetSeconds: 0)) |
3694 | { |
3695 | } |
3696 | #endif |
3697 | |
3698 | /*! |
3699 | Constructs a datetime with the given \a date and \a time, using |
3700 | the time specification defined by \a spec. |
3701 | |
3702 | If \a date is valid and \a time is not, the time will be set to midnight. |
3703 | |
3704 | If \a spec is Qt::OffsetFromUTC then it will be set to Qt::UTC, i.e. an |
3705 | offset of 0 seconds. To create a Qt::OffsetFromUTC datetime use the |
3706 | correct constructor. |
3707 | |
3708 | If \a spec is Qt::TimeZone then the spec will be set to Qt::LocalTime, |
3709 | i.e. the current system time zone. To create a Qt::TimeZone datetime |
3710 | use the correct constructor. |
3711 | */ |
3712 | |
3713 | QDateTime::QDateTime(const QDate &date, const QTime &time, Qt::TimeSpec spec) |
3714 | : d(QDateTimePrivate::create(toDate: date, toTime: time, toSpec: spec, offsetSeconds: 0)) |
3715 | { |
3716 | } |
3717 | |
3718 | /*! |
3719 | \since 5.2 |
3720 | |
3721 | Constructs a datetime with the given \a date and \a time, using |
3722 | the time specification defined by \a spec and \a offsetSeconds seconds. |
3723 | |
3724 | If \a date is valid and \a time is not, the time will be set to midnight. |
3725 | |
3726 | If the \a spec is not Qt::OffsetFromUTC then \a offsetSeconds will be ignored. |
3727 | |
3728 | If the \a spec is Qt::OffsetFromUTC and \a offsetSeconds is 0 then the |
3729 | timeSpec() will be set to Qt::UTC, i.e. an offset of 0 seconds. |
3730 | |
3731 | If \a spec is Qt::TimeZone then the spec will be set to Qt::LocalTime, |
3732 | i.e. the current system time zone. To create a Qt::TimeZone datetime |
3733 | use the correct constructor. |
3734 | */ |
3735 | |
3736 | QDateTime::QDateTime(const QDate &date, const QTime &time, Qt::TimeSpec spec, int offsetSeconds) |
3737 | : d(QDateTimePrivate::create(toDate: date, toTime: time, toSpec: spec, offsetSeconds)) |
3738 | { |
3739 | } |
3740 | |
3741 | #if QT_CONFIG(timezone) |
3742 | /*! |
3743 | \since 5.2 |
3744 | |
3745 | Constructs a datetime with the given \a date and \a time, using |
3746 | the Time Zone specified by \a timeZone. |
3747 | |
3748 | If \a date is valid and \a time is not, the time will be set to 00:00:00. |
3749 | |
3750 | If \a timeZone is invalid then the datetime will be invalid. |
3751 | */ |
3752 | |
3753 | QDateTime::QDateTime(const QDate &date, const QTime &time, const QTimeZone &timeZone) |
3754 | : d(QDateTimePrivate::create(toDate: date, toTime: time, toTimeZone: timeZone)) |
3755 | { |
3756 | } |
3757 | #endif // timezone |
3758 | |
3759 | /*! |
3760 | Constructs a copy of the \a other datetime. |
3761 | */ |
3762 | QDateTime::QDateTime(const QDateTime &other) noexcept |
3763 | : d(other.d) |
3764 | { |
3765 | } |
3766 | |
3767 | /*! |
3768 | \since 5.8 |
3769 | Moves the content of the temporary \a other datetime to this object and |
3770 | leaves \a other in an unspecified (but proper) state. |
3771 | */ |
3772 | QDateTime::QDateTime(QDateTime &&other) noexcept |
3773 | : d(std::move(other.d)) |
3774 | { |
3775 | } |
3776 | |
3777 | /*! |
3778 | Destroys the datetime. |
3779 | */ |
3780 | QDateTime::~QDateTime() |
3781 | { |
3782 | } |
3783 | |
3784 | /*! |
3785 | Makes a copy of the \a other datetime and returns a reference to the |
3786 | copy. |
3787 | */ |
3788 | |
3789 | QDateTime &QDateTime::operator=(const QDateTime &other) noexcept |
3790 | { |
3791 | d = other.d; |
3792 | return *this; |
3793 | } |
3794 | /*! |
3795 | \fn void QDateTime::swap(QDateTime &other) |
3796 | \since 5.0 |
3797 | |
3798 | Swaps this datetime with \a other. This operation is very fast |
3799 | and never fails. |
3800 | */ |
3801 | |
3802 | /*! |
3803 | Returns \c true if both the date and the time are null; otherwise |
3804 | returns \c false. A null datetime is invalid. |
3805 | |
3806 | \sa QDate::isNull(), QTime::isNull(), isValid() |
3807 | */ |
3808 | |
3809 | bool QDateTime::isNull() const |
3810 | { |
3811 | auto status = getStatus(d); |
3812 | return !status.testFlag(flag: QDateTimePrivate::ValidDate) && |
3813 | !status.testFlag(flag: QDateTimePrivate::ValidTime); |
3814 | } |
3815 | |
3816 | /*! |
3817 | Returns \c true if both the date and the time are valid and they are valid in |
3818 | the current Qt::TimeSpec, otherwise returns \c false. |
3819 | |
3820 | If the timeSpec() is Qt::LocalTime or Qt::TimeZone then the date and time are |
3821 | checked to see if they fall in the Standard Time to Daylight-Saving Time transition |
3822 | hour, i.e. if the transition is at 2am and the clock goes forward to 3am |
3823 | then the time from 02:00:00 to 02:59:59.999 is considered to be invalid. |
3824 | |
3825 | \sa QDateTime::YearRange, QDate::isValid(), QTime::isValid() |
3826 | */ |
3827 | |
3828 | bool QDateTime::isValid() const |
3829 | { |
3830 | auto status = getStatus(d); |
3831 | return status & QDateTimePrivate::ValidDateTime; |
3832 | } |
3833 | |
3834 | /*! |
3835 | Returns the date part of the datetime. |
3836 | |
3837 | \sa setDate(), time(), timeSpec() |
3838 | */ |
3839 | |
3840 | QDate QDateTime::date() const |
3841 | { |
3842 | auto status = getStatus(d); |
3843 | if (!status.testFlag(flag: QDateTimePrivate::ValidDate)) |
3844 | return QDate(); |
3845 | QDate dt; |
3846 | msecsToTime(msecs: getMSecs(d), date: &dt, time: nullptr); |
3847 | return dt; |
3848 | } |
3849 | |
3850 | /*! |
3851 | Returns the time part of the datetime. |
3852 | |
3853 | \sa setTime(), date(), timeSpec() |
3854 | */ |
3855 | |
3856 | QTime QDateTime::time() const |
3857 | { |
3858 | auto status = getStatus(d); |
3859 | if (!status.testFlag(flag: QDateTimePrivate::ValidTime)) |
3860 | return QTime(); |
3861 | QTime tm; |
3862 | msecsToTime(msecs: getMSecs(d), date: nullptr, time: &tm); |
3863 | return tm; |
3864 | } |
3865 | |
3866 | /*! |
3867 | Returns the time specification of the datetime. |
3868 | |
3869 | \sa setTimeSpec(), date(), time(), Qt::TimeSpec |
3870 | */ |
3871 | |
3872 | Qt::TimeSpec QDateTime::timeSpec() const |
3873 | { |
3874 | return getSpec(d); |
3875 | } |
3876 | |
3877 | #if QT_CONFIG(timezone) |
3878 | /*! |
3879 | \since 5.2 |
3880 | |
3881 | Returns the time zone of the datetime. |
3882 | |
3883 | If the timeSpec() is Qt::LocalTime then an instance of the current system |
3884 | time zone will be returned. Note however that if you copy this time zone |
3885 | the instance will not remain in sync if the system time zone changes. |
3886 | |
3887 | \sa setTimeZone(), Qt::TimeSpec |
3888 | */ |
3889 | |
3890 | QTimeZone QDateTime::timeZone() const |
3891 | { |
3892 | switch (getSpec(d)) { |
3893 | case Qt::UTC: |
3894 | return QTimeZone::utc(); |
3895 | case Qt::OffsetFromUTC: |
3896 | return QTimeZone(d->m_offsetFromUtc); |
3897 | case Qt::TimeZone: |
3898 | if (d->m_timeZone.isValid()) |
3899 | return d->m_timeZone; |
3900 | break; |
3901 | case Qt::LocalTime: |
3902 | return QTimeZone::systemTimeZone(); |
3903 | } |
3904 | return QTimeZone(); |
3905 | } |
3906 | #endif // timezone |
3907 | |
3908 | /*! |
3909 | \since 5.2 |
3910 | |
3911 | Returns this date-time's Offset From UTC in seconds. |
3912 | |
3913 | The result depends on timeSpec(): |
3914 | \list |
3915 | \li \c Qt::UTC The offset is 0. |
3916 | \li \c Qt::OffsetFromUTC The offset is the value originally set. |
3917 | \li \c Qt::LocalTime The local time's offset from UTC is returned. |
3918 | \li \c Qt::TimeZone The offset used by the time-zone is returned. |
3919 | \endlist |
3920 | |
3921 | For the last two, the offset at this date and time will be returned, taking |
3922 | account of Daylight-Saving Offset unless the date precedes the start of |
3923 | 1970. The offset is the difference between the local time or time in the |
3924 | given time-zone and UTC time; it is positive in time-zones ahead of UTC |
3925 | (East of The Prime Meridian), negative for those behind UTC (West of The |
3926 | Prime Meridian). |
3927 | |
3928 | \sa setOffsetFromUtc() |
3929 | */ |
3930 | |
3931 | int QDateTime::offsetFromUtc() const |
3932 | { |
3933 | if (!d.isShort()) |
3934 | return d->m_offsetFromUtc; |
3935 | if (!isValid()) |
3936 | return 0; |
3937 | |
3938 | auto spec = getSpec(d); |
3939 | if (spec == Qt::LocalTime) { |
3940 | // we didn't cache the value, so we need to calculate it now... |
3941 | qint64 msecs = getMSecs(d); |
3942 | return (msecs - toMSecsSinceEpoch()) / 1000; |
3943 | } |
3944 | |
3945 | Q_ASSERT(spec == Qt::UTC); |
3946 | return 0; |
3947 | } |
3948 | |
3949 | /*! |
3950 | \since 5.2 |
3951 | |
3952 | Returns the Time Zone Abbreviation for the datetime. |
3953 | |
3954 | If the timeSpec() is Qt::UTC this will be "UTC". |
3955 | |
3956 | If the timeSpec() is Qt::OffsetFromUTC this will be in the format |
3957 | "UTC[+-]00:00". |
3958 | |
3959 | If the timeSpec() is Qt::LocalTime then the host system is queried for the |
3960 | correct abbreviation. |
3961 | |
3962 | Note that abbreviations may or may not be localized. |
3963 | |
3964 | Note too that the abbreviation is not guaranteed to be a unique value, |
3965 | i.e. different time zones may have the same abbreviation. |
3966 | |
3967 | \sa timeSpec() |
3968 | */ |
3969 | |
3970 | QString QDateTime::timeZoneAbbreviation() const |
3971 | { |
3972 | if (!isValid()) |
3973 | return QString(); |
3974 | |
3975 | switch (getSpec(d)) { |
3976 | case Qt::UTC: |
3977 | return QLatin1String("UTC" ); |
3978 | case Qt::OffsetFromUTC: |
3979 | return QLatin1String("UTC" ) + toOffsetString(format: Qt::ISODate, offset: d->m_offsetFromUtc); |
3980 | case Qt::TimeZone: |
3981 | #if !QT_CONFIG(timezone) |
3982 | break; |
3983 | #else |
3984 | Q_ASSERT(d->m_timeZone.isValid()); |
3985 | return d->m_timeZone.d->abbreviation(atMSecsSinceEpoch: toMSecsSinceEpoch()); |
3986 | #endif // timezone |
3987 | case Qt::LocalTime: { |
3988 | QString abbrev; |
3989 | auto status = extractDaylightStatus(status: getStatus(d)); |
3990 | localMSecsToEpochMSecs(localMsecs: getMSecs(d), daylightStatus: &status, localDate: nullptr, localTime: nullptr, abbreviation: &abbrev); |
3991 | return abbrev; |
3992 | } |
3993 | } |
3994 | return QString(); |
3995 | } |
3996 | |
3997 | /*! |
3998 | \since 5.2 |
3999 | |
4000 | Returns if this datetime falls in Daylight-Saving Time. |
4001 | |
4002 | If the Qt::TimeSpec is not Qt::LocalTime or Qt::TimeZone then will always |
4003 | return false. |
4004 | |
4005 | \sa timeSpec() |
4006 | */ |
4007 | |
4008 | bool QDateTime::isDaylightTime() const |
4009 | { |
4010 | if (!isValid()) |
4011 | return false; |
4012 | |
4013 | switch (getSpec(d)) { |
4014 | case Qt::UTC: |
4015 | case Qt::OffsetFromUTC: |
4016 | return false; |
4017 | case Qt::TimeZone: |
4018 | #if !QT_CONFIG(timezone) |
4019 | break; |
4020 | #else |
4021 | Q_ASSERT(d->m_timeZone.isValid()); |
4022 | return d->m_timeZone.d->isDaylightTime(atMSecsSinceEpoch: toMSecsSinceEpoch()); |
4023 | #endif // timezone |
4024 | case Qt::LocalTime: { |
4025 | auto status = extractDaylightStatus(status: getStatus(d)); |
4026 | if (status == QDateTimePrivate::UnknownDaylightTime) |
4027 | localMSecsToEpochMSecs(localMsecs: getMSecs(d), daylightStatus: &status); |
4028 | return (status == QDateTimePrivate::DaylightTime); |
4029 | } |
4030 | } |
4031 | return false; |
4032 | } |
4033 | |
4034 | /*! |
4035 | Sets the date part of this datetime to \a date. If no time is set yet, it |
4036 | is set to midnight. If \a date is invalid, this QDateTime becomes invalid. |
4037 | |
4038 | \sa date(), setTime(), setTimeSpec() |
4039 | */ |
4040 | |
4041 | void QDateTime::setDate(const QDate &date) |
4042 | { |
4043 | setDateTime(d, date, time: time()); |
4044 | } |
4045 | |
4046 | /*! |
4047 | Sets the time part of this datetime to \a time. If \a time is not valid, |
4048 | this function sets it to midnight. Therefore, it's possible to clear any |
4049 | set time in a QDateTime by setting it to a default QTime: |
4050 | |
4051 | \code |
4052 | QDateTime dt = QDateTime::currentDateTime(); |
4053 | dt.setTime(QTime()); |
4054 | \endcode |
4055 | |
4056 | \sa time(), setDate(), setTimeSpec() |
4057 | */ |
4058 | |
4059 | void QDateTime::setTime(const QTime &time) |
4060 | { |
4061 | setDateTime(d, date: date(), time); |
4062 | } |
4063 | |
4064 | /*! |
4065 | Sets the time specification used in this datetime to \a spec. |
4066 | The datetime will refer to a different point in time. |
4067 | |
4068 | If \a spec is Qt::OffsetFromUTC then the timeSpec() will be set |
4069 | to Qt::UTC, i.e. an effective offset of 0. |
4070 | |
4071 | If \a spec is Qt::TimeZone then the spec will be set to Qt::LocalTime, |
4072 | i.e. the current system time zone. |
4073 | |
4074 | Example: |
4075 | \snippet code/src_corelib_tools_qdatetime.cpp 19 |
4076 | |
4077 | \sa timeSpec(), setDate(), setTime(), setTimeZone(), Qt::TimeSpec |
4078 | */ |
4079 | |
4080 | void QDateTime::setTimeSpec(Qt::TimeSpec spec) |
4081 | { |
4082 | QT_PREPEND_NAMESPACE(setTimeSpec(d, spec, 0)); |
4083 | checkValidDateTime(d); |
4084 | } |
4085 | |
4086 | /*! |
4087 | \since 5.2 |
4088 | |
4089 | Sets the timeSpec() to Qt::OffsetFromUTC and the offset to \a offsetSeconds. |
4090 | The datetime will refer to a different point in time. |
4091 | |
4092 | The maximum and minimum offset is 14 positive or negative hours. If |
4093 | \a offsetSeconds is larger or smaller than that, then the result is |
4094 | undefined. |
4095 | |
4096 | If \a offsetSeconds is 0 then the timeSpec() will be set to Qt::UTC. |
4097 | |
4098 | \sa isValid(), offsetFromUtc() |
4099 | */ |
4100 | |
4101 | void QDateTime::setOffsetFromUtc(int offsetSeconds) |
4102 | { |
4103 | QT_PREPEND_NAMESPACE(setTimeSpec(d, Qt::OffsetFromUTC, offsetSeconds)); |
4104 | checkValidDateTime(d); |
4105 | } |
4106 | |
4107 | #if QT_CONFIG(timezone) |
4108 | /*! |
4109 | \since 5.2 |
4110 | |
4111 | Sets the time zone used in this datetime to \a toZone. |
4112 | The datetime will refer to a different point in time. |
4113 | |
4114 | If \a toZone is invalid then the datetime will be invalid. |
4115 | |
4116 | \sa timeZone(), Qt::TimeSpec |
4117 | */ |
4118 | |
4119 | void QDateTime::setTimeZone(const QTimeZone &toZone) |
4120 | { |
4121 | d.detach(); // always detach |
4122 | d->m_status = mergeSpec(status: d->m_status, spec: Qt::TimeZone); |
4123 | d->m_offsetFromUtc = 0; |
4124 | d->m_timeZone = toZone; |
4125 | refreshDateTime(d); |
4126 | } |
4127 | #endif // timezone |
4128 | |
4129 | /*! |
4130 | \since 4.7 |
4131 | |
4132 | Returns the datetime as the number of milliseconds that have passed |
4133 | since 1970-01-01T00:00:00.000, Coordinated Universal Time (Qt::UTC). |
4134 | |
4135 | On systems that do not support time zones, this function will |
4136 | behave as if local time were Qt::UTC. |
4137 | |
4138 | The behavior for this function is undefined if the datetime stored in |
4139 | this object is not valid. However, for all valid dates, this function |
4140 | returns a unique value. |
4141 | |
4142 | \sa toSecsSinceEpoch(), setMSecsSinceEpoch() |
4143 | */ |
4144 | qint64 QDateTime::toMSecsSinceEpoch() const |
4145 | { |
4146 | // Note: QDateTimeParser relies on this producing a useful result, even when |
4147 | // !isValid(), at least when the invalidity is a time in a fall-back (that |
4148 | // we'll have adjusted to lie outside it, but marked invalid because it's |
4149 | // not what was asked for). Other things may be doing similar. |
4150 | switch (getSpec(d)) { |
4151 | case Qt::UTC: |
4152 | return getMSecs(d); |
4153 | |
4154 | case Qt::OffsetFromUTC: |
4155 | return d->m_msecs - (d->m_offsetFromUtc * 1000); |
4156 | |
4157 | case Qt::LocalTime: { |
4158 | // recalculate the local timezone |
4159 | auto status = extractDaylightStatus(status: getStatus(d)); |
4160 | return localMSecsToEpochMSecs(localMsecs: getMSecs(d), daylightStatus: &status); |
4161 | } |
4162 | |
4163 | case Qt::TimeZone: |
4164 | #if QT_CONFIG(timezone) |
4165 | if (d->m_timeZone.isValid()) { |
4166 | return QDateTimePrivate::zoneMSecsToEpochMSecs(zoneMSecs: d->m_msecs, zone: d->m_timeZone, |
4167 | hint: extractDaylightStatus(status: getStatus(d))); |
4168 | } |
4169 | #endif |
4170 | return 0; |
4171 | } |
4172 | Q_UNREACHABLE(); |
4173 | return 0; |
4174 | } |
4175 | |
4176 | /*! |
4177 | \since 5.8 |
4178 | |
4179 | Returns the datetime as the number of seconds that have passed since |
4180 | 1970-01-01T00:00:00.000, Coordinated Universal Time (Qt::UTC). |
4181 | |
4182 | On systems that do not support time zones, this function will |
4183 | behave as if local time were Qt::UTC. |
4184 | |
4185 | The behavior for this function is undefined if the datetime stored in |
4186 | this object is not valid. However, for all valid dates, this function |
4187 | returns a unique value. |
4188 | |
4189 | \sa toMSecsSinceEpoch(), setSecsSinceEpoch() |
4190 | */ |
4191 | qint64 QDateTime::toSecsSinceEpoch() const |
4192 | { |
4193 | return toMSecsSinceEpoch() / 1000; |
4194 | } |
4195 | |
4196 | #if QT_DEPRECATED_SINCE(5, 8) |
4197 | /*! |
4198 | \deprecated |
4199 | |
4200 | Returns the datetime as the number of seconds that have passed |
4201 | since 1970-01-01T00:00:00, Coordinated Universal Time (Qt::UTC). |
4202 | |
4203 | On systems that do not support time zones, this function will |
4204 | behave as if local time were Qt::UTC. |
4205 | |
4206 | \note This function returns a 32-bit unsigned integer and is deprecated. |
4207 | |
4208 | If the date is outside the range 1970-01-01T00:00:00 to |
4209 | 2106-02-07T06:28:14, this function returns -1 cast to an unsigned integer |
4210 | (i.e., 0xFFFFFFFF). |
4211 | |
4212 | To get an extended range, use toMSecsSinceEpoch() or toSecsSinceEpoch(). |
4213 | |
4214 | \sa toSecsSinceEpoch(), toMSecsSinceEpoch(), setTime_t() |
4215 | */ |
4216 | |
4217 | uint QDateTime::toTime_t() const |
4218 | { |
4219 | if (!isValid()) |
4220 | return uint(-1); |
4221 | qint64 retval = toMSecsSinceEpoch() / 1000; |
4222 | if (quint64(retval) >= Q_UINT64_C(0xFFFFFFFF)) |
4223 | return uint(-1); |
4224 | return uint(retval); |
4225 | } |
4226 | #endif |
4227 | |
4228 | /*! |
4229 | \since 4.7 |
4230 | |
4231 | Sets the date and time given the number of milliseconds \a msecs that have |
4232 | passed since 1970-01-01T00:00:00.000, Coordinated Universal Time |
4233 | (Qt::UTC). On systems that do not support time zones this function |
4234 | will behave as if local time were Qt::UTC. |
4235 | |
4236 | Note that passing the minimum of \c qint64 |
4237 | (\c{std::numeric_limits<qint64>::min()}) to \a msecs will result in |
4238 | undefined behavior. |
4239 | |
4240 | \sa toMSecsSinceEpoch(), setSecsSinceEpoch() |
4241 | */ |
4242 | void QDateTime::setMSecsSinceEpoch(qint64 msecs) |
4243 | { |
4244 | const auto spec = getSpec(d); |
4245 | auto status = getStatus(d); |
4246 | |
4247 | status &= ~QDateTimePrivate::ValidityMask; |
4248 | switch (spec) { |
4249 | case Qt::UTC: |
4250 | status = status |
4251 | | QDateTimePrivate::ValidDate |
4252 | | QDateTimePrivate::ValidTime |
4253 | | QDateTimePrivate::ValidDateTime; |
4254 | break; |
4255 | case Qt::OffsetFromUTC: |
4256 | msecs = msecs + (d->m_offsetFromUtc * 1000); |
4257 | status = status |
4258 | | QDateTimePrivate::ValidDate |
4259 | | QDateTimePrivate::ValidTime |
4260 | | QDateTimePrivate::ValidDateTime; |
4261 | break; |
4262 | case Qt::TimeZone: |
4263 | Q_ASSERT(!d.isShort()); |
4264 | #if QT_CONFIG(timezone) |
4265 | d.detach(); |
4266 | if (!d->m_timeZone.isValid()) |
4267 | break; |
4268 | // Docs state any LocalTime before 1970-01-01 will *not* have any DST applied |
4269 | // but all affected times afterwards will have DST applied. |
4270 | if (msecs >= 0) { |
4271 | status = mergeDaylightStatus(sf: status, |
4272 | status: d->m_timeZone.d->isDaylightTime(atMSecsSinceEpoch: msecs) |
4273 | ? QDateTimePrivate::DaylightTime |
4274 | : QDateTimePrivate::StandardTime); |
4275 | d->m_offsetFromUtc = d->m_timeZone.d->offsetFromUtc(atMSecsSinceEpoch: msecs); |
4276 | } else { |
4277 | status = mergeDaylightStatus(sf: status, status: QDateTimePrivate::StandardTime); |
4278 | d->m_offsetFromUtc = d->m_timeZone.d->standardTimeOffset(atMSecsSinceEpoch: msecs); |
4279 | } |
4280 | msecs = msecs + (d->m_offsetFromUtc * 1000); |
4281 | status = status |
4282 | | QDateTimePrivate::ValidDate |
4283 | | QDateTimePrivate::ValidTime |
4284 | | QDateTimePrivate::ValidDateTime; |
4285 | #endif // timezone |
4286 | break; |
4287 | case Qt::LocalTime: { |
4288 | QDate dt; |
4289 | QTime tm; |
4290 | QDateTimePrivate::DaylightStatus dstStatus; |
4291 | epochMSecsToLocalTime(msecs, localDate: &dt, localTime: &tm, daylightStatus: &dstStatus); |
4292 | setDateTime(d, date: dt, time: tm); |
4293 | msecs = getMSecs(d); |
4294 | status = mergeDaylightStatus(sf: getStatus(d), status: dstStatus); |
4295 | break; |
4296 | } |
4297 | } |
4298 | |
4299 | if (msecsCanBeSmall(msecs) && d.isShort()) { |
4300 | // we can keep short |
4301 | d.data.msecs = qintptr(msecs); |
4302 | d.data.status = status; |
4303 | } else { |
4304 | d.detach(); |
4305 | d->m_status = status & ~QDateTimePrivate::ShortData; |
4306 | d->m_msecs = msecs; |
4307 | } |
4308 | |
4309 | if (spec == Qt::LocalTime || spec == Qt::TimeZone) |
4310 | refreshDateTime(d); |
4311 | } |
4312 | |
4313 | /*! |
4314 | \since 5.8 |
4315 | |
4316 | Sets the date and time given the number of seconds \a secs that have |
4317 | passed since 1970-01-01T00:00:00.000, Coordinated Universal Time |
4318 | (Qt::UTC). On systems that do not support time zones this function |
4319 | will behave as if local time were Qt::UTC. |
4320 | |
4321 | \sa toSecsSinceEpoch(), setMSecsSinceEpoch() |
4322 | */ |
4323 | void QDateTime::setSecsSinceEpoch(qint64 secs) |
4324 | { |
4325 | setMSecsSinceEpoch(secs * 1000); |
4326 | } |
4327 | |
4328 | #if QT_DEPRECATED_SINCE(5, 8) |
4329 | /*! |
4330 | \fn void QDateTime::setTime_t(uint seconds) |
4331 | \deprecated |
4332 | |
4333 | Sets the date and time given the number of \a seconds that have |
4334 | passed since 1970-01-01T00:00:00, Coordinated Universal Time |
4335 | (Qt::UTC). On systems that do not support time zones this function |
4336 | will behave as if local time were Qt::UTC. |
4337 | |
4338 | \note This function is deprecated. For new code, use setSecsSinceEpoch(). |
4339 | |
4340 | \sa toTime_t() |
4341 | */ |
4342 | |
4343 | void QDateTime::setTime_t(uint secsSince1Jan1970UTC) |
4344 | { |
4345 | setMSecsSinceEpoch((qint64)secsSince1Jan1970UTC * 1000); |
4346 | } |
4347 | #endif |
4348 | |
4349 | #if QT_CONFIG(datestring) // depends on, so implies, textdate |
4350 | /*! |
4351 | \overload |
4352 | |
4353 | Returns the datetime as a string in the \a format given. |
4354 | |
4355 | If the \a format is Qt::TextDate, the string is formatted in the default |
4356 | way. The day and month names will be localized names using the system |
4357 | locale, i.e. QLocale::system(). An example of this formatting is "Wed May 20 |
4358 | 03:40:13 1998". |
4359 | |
4360 | If the \a format is Qt::ISODate, the string format corresponds |
4361 | to the ISO 8601 extended specification for representations of |
4362 | dates and times, taking the form yyyy-MM-ddTHH:mm:ss[Z|[+|-]HH:mm], |
4363 | depending on the timeSpec() of the QDateTime. If the timeSpec() |
4364 | is Qt::UTC, Z will be appended to the string; if the timeSpec() is |
4365 | Qt::OffsetFromUTC, the offset in hours and minutes from UTC will |
4366 | be appended to the string. To include milliseconds in the ISO 8601 |
4367 | date, use the \a format Qt::ISODateWithMs, which corresponds to |
4368 | yyyy-MM-ddTHH:mm:ss.zzz[Z|[+|-]HH:mm]. |
4369 | |
4370 | The \a format options Qt::SystemLocaleDate, Qt::SystemLocaleShortDate and |
4371 | Qt::SystemLocaleLongDate shall be removed in Qt 6. Their use should be |
4372 | replaced with |
4373 | \l {QLocale::toString()}{QLocale::system().toString(datetime, QLocale::ShortFormat)} or |
4374 | \l {QLocale::toString()}{QLocale::system().toString(datetime, QLocale::LongFormat)}. |
4375 | |
4376 | The \a format options Qt::LocaleDate, Qt::DefaultLocaleShortDate and |
4377 | Qt::DefaultLocaleLongDate shall be removed in Qt 6. Their use should be |
4378 | replaced with |
4379 | \l {QLocale::toString()}{QLocale().toString(datetime, QLocale::ShortFormat)} or |
4380 | \l {QLocale::toString()}{QLocale().toString(datetime, QLocale::LongFormat)}. |
4381 | |
4382 | If the \a format is Qt::RFC2822Date, the string is formatted |
4383 | following \l{RFC 2822}. |
4384 | |
4385 | If the datetime is invalid, an empty string will be returned. |
4386 | |
4387 | \warning The Qt::ISODate format is only valid for years in the |
4388 | range 0 to 9999. |
4389 | |
4390 | \sa fromString(), QDate::toString(), QTime::toString(), |
4391 | QLocale::toString() |
4392 | */ |
4393 | |
4394 | QString QDateTime::toString(Qt::DateFormat format) const |
4395 | { |
4396 | QString buf; |
4397 | if (!isValid()) |
4398 | return buf; |
4399 | |
4400 | switch (format) { |
4401 | #if QT_DEPRECATED_SINCE(5, 15) |
4402 | QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED |
4403 | case Qt::SystemLocaleDate: |
4404 | case Qt::SystemLocaleShortDate: |
4405 | return QLocale::system().toString(dateTime: *this, format: QLocale::ShortFormat); |
4406 | case Qt::SystemLocaleLongDate: |
4407 | return QLocale::system().toString(dateTime: *this, format: QLocale::LongFormat); |
4408 | case Qt::LocaleDate: |
4409 | case Qt::DefaultLocaleShortDate: |
4410 | return QLocale().toString(dateTime: *this, format: QLocale::ShortFormat); |
4411 | case Qt::DefaultLocaleLongDate: |
4412 | return QLocale().toString(dateTime: *this, format: QLocale::LongFormat); |
4413 | QT_WARNING_POP |
4414 | #endif // 5.15 |
4415 | case Qt::RFC2822Date: { |
4416 | buf = QLocale::c().toString(dateTime: *this, format: u"dd MMM yyyy hh:mm:ss " ); |
4417 | buf += toOffsetString(format: Qt::TextDate, offset: offsetFromUtc()); |
4418 | return buf; |
4419 | } |
4420 | default: |
4421 | case Qt::TextDate: { |
4422 | const QPair<QDate, QTime> p = getDateTime(d); |
4423 | buf = toStringTextDate(date: p.first); |
4424 | // Insert time between date's day and year: |
4425 | buf.insert(i: buf.lastIndexOf(c: QLatin1Char(' ')), |
4426 | s: QLatin1Char(' ') + p.second.toString(format: Qt::TextDate)); |
4427 | // Append zone/offset indicator, as appropriate: |
4428 | switch (timeSpec()) { |
4429 | case Qt::LocalTime: |
4430 | break; |
4431 | #if QT_CONFIG(timezone) |
4432 | case Qt::TimeZone: |
4433 | buf += QLatin1Char(' ') + d->m_timeZone.abbreviation(atDateTime: *this); |
4434 | break; |
4435 | #endif |
4436 | default: |
4437 | buf += QLatin1String(" GMT" ); |
4438 | if (getSpec(d) == Qt::OffsetFromUTC) |
4439 | buf += toOffsetString(format: Qt::TextDate, offset: offsetFromUtc()); |
4440 | } |
4441 | return buf; |
4442 | } |
4443 | case Qt::ISODate: |
4444 | case Qt::ISODateWithMs: { |
4445 | const QPair<QDate, QTime> p = getDateTime(d); |
4446 | buf = toStringIsoDate(date: p.first); |
4447 | if (buf.isEmpty()) |
4448 | return QString(); // failed to convert |
4449 | buf += QLatin1Char('T') + p.second.toString(format); |
4450 | switch (getSpec(d)) { |
4451 | case Qt::UTC: |
4452 | buf += QLatin1Char('Z'); |
4453 | break; |
4454 | case Qt::OffsetFromUTC: |
4455 | #if QT_CONFIG(timezone) |
4456 | case Qt::TimeZone: |
4457 | #endif |
4458 | buf += toOffsetString(format: Qt::ISODate, offset: offsetFromUtc()); |
4459 | break; |
4460 | default: |
4461 | break; |
4462 | } |
4463 | return buf; |
4464 | } |
4465 | } |
4466 | } |
4467 | |
4468 | /*! |
4469 | \fn QString QDateTime::toString(const QString &format) const |
4470 | \fn QString QDateTime::toString(const QString &format, QCalendar cal) const |
4471 | \fn QString QDateTime::toString(QStringView format) const |
4472 | \fn QString QDateTime::toString(QStringView format, QCalendar cal) const |
4473 | |
4474 | Returns the datetime as a string. The \a format parameter determines the |
4475 | format of the result string. If \a cal is supplied, it determines the calendar |
4476 | used to represent the date; it defaults to Gregorian. See QTime::toString() |
4477 | and QDate::toString() for the supported specifiers for time and date, |
4478 | respectively. |
4479 | |
4480 | Any sequence of characters enclosed in single quotes will be included |
4481 | verbatim in the output string (stripped of the quotes), even if it contains |
4482 | formatting characters. Two consecutive single quotes ("''") are replaced by |
4483 | a single quote in the output. All other characters in the format string are |
4484 | included verbatim in the output string. |
4485 | |
4486 | Formats without separators (e.g. "ddMM") are supported but must be used with |
4487 | care, as the resulting strings aren't always reliably readable (e.g. if "dM" |
4488 | produces "212" it could mean either the 2nd of December or the 21st of |
4489 | February). |
4490 | |
4491 | Example format strings (assumed that the QDateTime is 21 May 2001 |
4492 | 14:13:09.120): |
4493 | |
4494 | \table |
4495 | \header \li Format \li Result |
4496 | \row \li dd.MM.yyyy \li 21.05.2001 |
4497 | \row \li ddd MMMM d yy \li Tue May 21 01 |
4498 | \row \li hh:mm:ss.zzz \li 14:13:09.120 |
4499 | \row \li hh:mm:ss.z \li 14:13:09.12 |
4500 | \row \li h:m:s ap \li 2:13:9 pm |
4501 | \endtable |
4502 | |
4503 | If the datetime is invalid, an empty string will be returned. |
4504 | |
4505 | \note If localized month and day names are desired, please switch to using |
4506 | QLocale::system().toString() as QDateTime methods shall change to use |
4507 | English (C locale) names at Qt 6. |
4508 | |
4509 | \sa fromString(), QDate::toString(), QTime::toString(), QLocale::toString() |
4510 | */ |
4511 | QString QDateTime::toString(QStringView format) const |
4512 | { |
4513 | return toString(format, cal: QCalendar()); |
4514 | } |
4515 | |
4516 | QString QDateTime::toString(QStringView format, QCalendar cal) const |
4517 | { |
4518 | return QLocale::system().toString(dateTime: *this, formatStr: format, cal); // QLocale::c() ### Qt6 |
4519 | } |
4520 | |
4521 | #if QT_STRINGVIEW_LEVEL < 2 |
4522 | QString QDateTime::toString(const QString &format) const |
4523 | { |
4524 | return toString(format: qToStringViewIgnoringNull(s: format), cal: QCalendar()); |
4525 | } |
4526 | |
4527 | QString QDateTime::toString(const QString &format, QCalendar cal) const |
4528 | { |
4529 | return toString(format: qToStringViewIgnoringNull(s: format), cal); |
4530 | } |
4531 | #endif |
4532 | |
4533 | #endif // datestring |
4534 | |
4535 | static inline void massageAdjustedDateTime(const QDateTimeData &d, QDate *date, QTime *time) |
4536 | { |
4537 | /* |
4538 | If we have just adjusted to a day with a DST transition, our given time |
4539 | may lie in the transition hour (either missing or duplicated). For any |
4540 | other time, telling mktime (deep in the bowels of localMSecsToEpochMSecs) |
4541 | we don't know its DST-ness will produce no adjustment (just a decision as |
4542 | to its DST-ness); but for a time in spring's missing hour it'll adjust the |
4543 | time while picking a DST-ness. (Handling of autumn is trickier, as either |
4544 | DST-ness is valid, without adjusting the time. We might want to propagate |
4545 | the daylight status in that case, but it's hard to do so without breaking |
4546 | (far more common) other cases; and it makes little difference, as the two |
4547 | answers do then differ only in DST-ness.) |
4548 | */ |
4549 | auto spec = getSpec(d); |
4550 | if (spec == Qt::LocalTime) { |
4551 | QDateTimePrivate::DaylightStatus status = QDateTimePrivate::UnknownDaylightTime; |
4552 | localMSecsToEpochMSecs(localMsecs: timeToMSecs(date: *date, time: *time), daylightStatus: &status, localDate: date, localTime: time); |
4553 | #if QT_CONFIG(timezone) |
4554 | } else if (spec == Qt::TimeZone && d.d->m_timeZone.isValid()) { |
4555 | QDateTimePrivate::zoneMSecsToEpochMSecs(zoneMSecs: timeToMSecs(date: *date, time: *time), |
4556 | zone: d.d->m_timeZone, |
4557 | hint: QDateTimePrivate::UnknownDaylightTime, |
4558 | zoneDate: date, zoneTime: time); |
4559 | #endif // timezone |
4560 | } |
4561 | } |
4562 | |
4563 | /*! |
4564 | Returns a QDateTime object containing a datetime \a ndays days |
4565 | later than the datetime of this object (or earlier if \a ndays is |
4566 | negative). |
4567 | |
4568 | If the timeSpec() is Qt::LocalTime and the resulting |
4569 | date and time fall in the Standard Time to Daylight-Saving Time transition |
4570 | hour then the result will be adjusted accordingly, i.e. if the transition |
4571 | is at 2am and the clock goes forward to 3am and the result falls between |
4572 | 2am and 3am then the result will be adjusted to fall after 3am. |
4573 | |
4574 | \sa daysTo(), addMonths(), addYears(), addSecs() |
4575 | */ |
4576 | |
4577 | QDateTime QDateTime::addDays(qint64 ndays) const |
4578 | { |
4579 | QDateTime dt(*this); |
4580 | QPair<QDate, QTime> p = getDateTime(d); |
4581 | QDate &date = p.first; |
4582 | QTime &time = p.second; |
4583 | date = date.addDays(ndays); |
4584 | massageAdjustedDateTime(d: dt.d, date: &date, time: &time); |
4585 | setDateTime(d&: dt.d, date, time); |
4586 | return dt; |
4587 | } |
4588 | |
4589 | /*! |
4590 | Returns a QDateTime object containing a datetime \a nmonths months |
4591 | later than the datetime of this object (or earlier if \a nmonths |
4592 | is negative). |
4593 | |
4594 | If the timeSpec() is Qt::LocalTime and the resulting |
4595 | date and time fall in the Standard Time to Daylight-Saving Time transition |
4596 | hour then the result will be adjusted accordingly, i.e. if the transition |
4597 | is at 2am and the clock goes forward to 3am and the result falls between |
4598 | 2am and 3am then the result will be adjusted to fall after 3am. |
4599 | |
4600 | \sa daysTo(), addDays(), addYears(), addSecs() |
4601 | */ |
4602 | |
4603 | QDateTime QDateTime::addMonths(int nmonths) const |
4604 | { |
4605 | QDateTime dt(*this); |
4606 | QPair<QDate, QTime> p = getDateTime(d); |
4607 | QDate &date = p.first; |
4608 | QTime &time = p.second; |
4609 | date = date.addMonths(nmonths); |
4610 | massageAdjustedDateTime(d: dt.d, date: &date, time: &time); |
4611 | setDateTime(d&: dt.d, date, time); |
4612 | return dt; |
4613 | } |
4614 | |
4615 | /*! |
4616 | Returns a QDateTime object containing a datetime \a nyears years |
4617 | later than the datetime of this object (or earlier if \a nyears is |
4618 | negative). |
4619 | |
4620 | If the timeSpec() is Qt::LocalTime and the resulting |
4621 | date and time fall in the Standard Time to Daylight-Saving Time transition |
4622 | hour then the result will be adjusted accordingly, i.e. if the transition |
4623 | is at 2am and the clock goes forward to 3am and the result falls between |
4624 | 2am and 3am then the result will be adjusted to fall after 3am. |
4625 | |
4626 | \sa daysTo(), addDays(), addMonths(), addSecs() |
4627 | */ |
4628 | |
4629 | QDateTime QDateTime::addYears(int nyears) const |
4630 | { |
4631 | QDateTime dt(*this); |
4632 | QPair<QDate, QTime> p = getDateTime(d); |
4633 | QDate &date = p.first; |
4634 | QTime &time = p.second; |
4635 | date = date.addYears(nyears); |
4636 | massageAdjustedDateTime(d: dt.d, date: &date, time: &time); |
4637 | setDateTime(d&: dt.d, date, time); |
4638 | return dt; |
4639 | } |
4640 | |
4641 | /*! |
4642 | Returns a QDateTime object containing a datetime \a s seconds |
4643 | later than the datetime of this object (or earlier if \a s is |
4644 | negative). |
4645 | |
4646 | If this datetime is invalid, an invalid datetime will be returned. |
4647 | |
4648 | \sa addMSecs(), secsTo(), addDays(), addMonths(), addYears() |
4649 | */ |
4650 | |
4651 | QDateTime QDateTime::addSecs(qint64 s) const |
4652 | { |
4653 | return addMSecs(msecs: s * 1000); |
4654 | } |
4655 | |
4656 | /*! |
4657 | Returns a QDateTime object containing a datetime \a msecs miliseconds |
4658 | later than the datetime of this object (or earlier if \a msecs is |
4659 | negative). |
4660 | |
4661 | If this datetime is invalid, an invalid datetime will be returned. |
4662 | |
4663 | \sa addSecs(), msecsTo(), addDays(), addMonths(), addYears() |
4664 | */ |
4665 | QDateTime QDateTime::addMSecs(qint64 msecs) const |
4666 | { |
4667 | if (!isValid()) |
4668 | return QDateTime(); |
4669 | |
4670 | QDateTime dt(*this); |
4671 | auto spec = getSpec(d); |
4672 | if (spec == Qt::LocalTime || spec == Qt::TimeZone) { |
4673 | // Convert to real UTC first in case crosses DST transition |
4674 | dt.setMSecsSinceEpoch(toMSecsSinceEpoch() + msecs); |
4675 | } else { |
4676 | // No need to convert, just add on |
4677 | if (d.isShort()) { |
4678 | // need to check if we need to enlarge first |
4679 | msecs += dt.d.data.msecs; |
4680 | if (msecsCanBeSmall(msecs)) { |
4681 | dt.d.data.msecs = qintptr(msecs); |
4682 | } else { |
4683 | dt.d.detach(); |
4684 | dt.d->m_msecs = msecs; |
4685 | } |
4686 | } else { |
4687 | dt.d.detach(); |
4688 | dt.d->m_msecs += msecs; |
4689 | } |
4690 | } |
4691 | return dt; |
4692 | } |
4693 | |
4694 | /*! |
4695 | Returns the number of days from this datetime to the \a other |
4696 | datetime. The number of days is counted as the number of times |
4697 | midnight is reached between this datetime to the \a other |
4698 | datetime. This means that a 10 minute difference from 23:55 to |
4699 | 0:05 the next day counts as one day. |
4700 | |
4701 | If the \a other datetime is earlier than this datetime, |
4702 | the value returned is negative. |
4703 | |
4704 | Example: |
4705 | \snippet code/src_corelib_tools_qdatetime.cpp 15 |
4706 | |
4707 | \sa addDays(), secsTo(), msecsTo() |
4708 | */ |
4709 | |
4710 | qint64 QDateTime::daysTo(const QDateTime &other) const |
4711 | { |
4712 | return date().daysTo(d: other.date()); |
4713 | } |
4714 | |
4715 | /*! |
4716 | Returns the number of seconds from this datetime to the \a other |
4717 | datetime. If the \a other datetime is earlier than this datetime, |
4718 | the value returned is negative. |
4719 | |
4720 | Before performing the comparison, the two datetimes are converted |
4721 | to Qt::UTC to ensure that the result is correct if daylight-saving |
4722 | (DST) applies to one of the two datetimes but not the other. |
4723 | |
4724 | Returns 0 if either datetime is invalid. |
4725 | |
4726 | Example: |
4727 | \snippet code/src_corelib_tools_qdatetime.cpp 11 |
4728 | |
4729 | \sa addSecs(), daysTo(), QTime::secsTo() |
4730 | */ |
4731 | |
4732 | qint64 QDateTime::secsTo(const QDateTime &other) const |
4733 | { |
4734 | return (msecsTo(other) / 1000); |
4735 | } |
4736 | |
4737 | /*! |
4738 | Returns the number of milliseconds from this datetime to the \a other |
4739 | datetime. If the \a other datetime is earlier than this datetime, |
4740 | the value returned is negative. |
4741 | |
4742 | Before performing the comparison, the two datetimes are converted |
4743 | to Qt::UTC to ensure that the result is correct if daylight-saving |
4744 | (DST) applies to one of the two datetimes and but not the other. |
4745 | |
4746 | Returns 0 if either datetime is invalid. |
4747 | |
4748 | \sa addMSecs(), daysTo(), QTime::msecsTo() |
4749 | */ |
4750 | |
4751 | qint64 QDateTime::msecsTo(const QDateTime &other) const |
4752 | { |
4753 | if (!isValid() || !other.isValid()) |
4754 | return 0; |
4755 | |
4756 | return other.toMSecsSinceEpoch() - toMSecsSinceEpoch(); |
4757 | } |
4758 | |
4759 | /*! |
4760 | \fn QDateTime QDateTime::toTimeSpec(Qt::TimeSpec spec) const |
4761 | |
4762 | Returns a copy of this datetime converted to the given time |
4763 | \a spec. |
4764 | |
4765 | If \a spec is Qt::OffsetFromUTC then it is set to Qt::UTC. To set to a |
4766 | spec of Qt::OffsetFromUTC use toOffsetFromUtc(). |
4767 | |
4768 | If \a spec is Qt::TimeZone then it is set to Qt::LocalTime, |
4769 | i.e. the local Time Zone. |
4770 | |
4771 | Example: |
4772 | \snippet code/src_corelib_tools_qdatetime.cpp 16 |
4773 | |
4774 | \sa timeSpec(), toTimeZone(), toOffsetFromUtc() |
4775 | */ |
4776 | |
4777 | QDateTime QDateTime::toTimeSpec(Qt::TimeSpec spec) const |
4778 | { |
4779 | if (getSpec(d) == spec && (spec == Qt::UTC || spec == Qt::LocalTime)) |
4780 | return *this; |
4781 | |
4782 | if (!isValid()) { |
4783 | QDateTime ret = *this; |
4784 | ret.setTimeSpec(spec); |
4785 | return ret; |
4786 | } |
4787 | |
4788 | return fromMSecsSinceEpoch(msecs: toMSecsSinceEpoch(), spec, offsetFromUtc: 0); |
4789 | } |
4790 | |
4791 | /*! |
4792 | \since 5.2 |
4793 | |
4794 | \fn QDateTime QDateTime::toOffsetFromUtc(int offsetSeconds) const |
4795 | |
4796 | Returns a copy of this datetime converted to a spec of Qt::OffsetFromUTC |
4797 | with the given \a offsetSeconds. |
4798 | |
4799 | If the \a offsetSeconds equals 0 then a UTC datetime will be returned |
4800 | |
4801 | \sa setOffsetFromUtc(), offsetFromUtc(), toTimeSpec() |
4802 | */ |
4803 | |
4804 | QDateTime QDateTime::toOffsetFromUtc(int offsetSeconds) const |
4805 | { |
4806 | if (getSpec(d) == Qt::OffsetFromUTC |
4807 | && d->m_offsetFromUtc == offsetSeconds) |
4808 | return *this; |
4809 | |
4810 | if (!isValid()) { |
4811 | QDateTime ret = *this; |
4812 | ret.setOffsetFromUtc(offsetSeconds); |
4813 | return ret; |
4814 | } |
4815 | |
4816 | return fromMSecsSinceEpoch(msecs: toMSecsSinceEpoch(), spec: Qt::OffsetFromUTC, offsetFromUtc: offsetSeconds); |
4817 | } |
4818 | |
4819 | #if QT_CONFIG(timezone) |
4820 | /*! |
4821 | \since 5.2 |
4822 | |
4823 | Returns a copy of this datetime converted to the given \a timeZone |
4824 | |
4825 | \sa timeZone(), toTimeSpec() |
4826 | */ |
4827 | |
4828 | QDateTime QDateTime::toTimeZone(const QTimeZone &timeZone) const |
4829 | { |
4830 | if (getSpec(d) == Qt::TimeZone && d->m_timeZone == timeZone) |
4831 | return *this; |
4832 | |
4833 | if (!isValid()) { |
4834 | QDateTime ret = *this; |
4835 | ret.setTimeZone(timeZone); |
4836 | return ret; |
4837 | } |
4838 | |
4839 | return fromMSecsSinceEpoch(msecs: toMSecsSinceEpoch(), timeZone); |
4840 | } |
4841 | #endif // timezone |
4842 | |
4843 | /*! |
4844 | Returns \c true if this datetime is equal to the \a other datetime; |
4845 | otherwise returns \c false. |
4846 | |
4847 | Since 5.14, all invalid datetimes are equal to one another and differ from |
4848 | all other datetimes. |
4849 | |
4850 | \sa operator!=() |
4851 | */ |
4852 | |
4853 | bool QDateTime::operator==(const QDateTime &other) const |
4854 | { |
4855 | if (!isValid()) |
4856 | return !other.isValid(); |
4857 | if (!other.isValid()) |
4858 | return false; |
4859 | |
4860 | if (getSpec(d) == Qt::LocalTime && getStatus(d) == getStatus(d: other.d)) |
4861 | return getMSecs(d) == getMSecs(d: other.d); |
4862 | |
4863 | // Convert to UTC and compare |
4864 | return toMSecsSinceEpoch() == other.toMSecsSinceEpoch(); |
4865 | } |
4866 | |
4867 | /*! |
4868 | \fn bool QDateTime::operator!=(const QDateTime &other) const |
4869 | |
4870 | Returns \c true if this datetime is different from the \a other |
4871 | datetime; otherwise returns \c false. |
4872 | |
4873 | Two datetimes are different if either the date, the time, or the time zone |
4874 | components are different. Since 5.14, any invalid datetime is less than all |
4875 | valid datetimes. |
4876 | |
4877 | \sa operator==() |
4878 | */ |
4879 | |
4880 | /*! |
4881 | Returns \c true if this datetime is earlier than the \a other |
4882 | datetime; otherwise returns \c false. |
4883 | */ |
4884 | |
4885 | bool QDateTime::operator<(const QDateTime &other) const |
4886 | { |
4887 | if (!isValid()) |
4888 | return other.isValid(); |
4889 | if (!other.isValid()) |
4890 | return false; |
4891 | |
4892 | if (getSpec(d) == Qt::LocalTime && getStatus(d) == getStatus(d: other.d)) |
4893 | return getMSecs(d) < getMSecs(d: other.d); |
4894 | |
4895 | // Convert to UTC and compare |
4896 | return toMSecsSinceEpoch() < other.toMSecsSinceEpoch(); |
4897 | } |
4898 | |
4899 | /*! |
4900 | \fn bool QDateTime::operator<=(const QDateTime &other) const |
4901 | |
4902 | Returns \c true if this datetime is earlier than or equal to the |
4903 | \a other datetime; otherwise returns \c false. |
4904 | */ |
4905 | |
4906 | /*! |
4907 | \fn bool QDateTime::operator>(const QDateTime &other) const |
4908 | |
4909 | Returns \c true if this datetime is later than the \a other datetime; |
4910 | otherwise returns \c false. |
4911 | */ |
4912 | |
4913 | /*! |
4914 | \fn bool QDateTime::operator>=(const QDateTime &other) const |
4915 | |
4916 | Returns \c true if this datetime is later than or equal to the |
4917 | \a other datetime; otherwise returns \c false. |
4918 | */ |
4919 | |
4920 | /*! |
4921 | \fn QDateTime QDateTime::currentDateTime() |
4922 | Returns the current datetime, as reported by the system clock, in |
4923 | the local time zone. |
4924 | |
4925 | \sa currentDateTimeUtc(), QDate::currentDate(), QTime::currentTime(), toTimeSpec() |
4926 | */ |
4927 | |
4928 | /*! |
4929 | \fn QDateTime QDateTime::currentDateTimeUtc() |
4930 | \since 4.7 |
4931 | Returns the current datetime, as reported by the system clock, in |
4932 | UTC. |
4933 | |
4934 | \sa currentDateTime(), QDate::currentDate(), QTime::currentTime(), toTimeSpec() |
4935 | */ |
4936 | |
4937 | /*! |
4938 | \fn qint64 QDateTime::currentMSecsSinceEpoch() |
4939 | \since 4.7 |
4940 | |
4941 | Returns the number of milliseconds since 1970-01-01T00:00:00 Universal |
4942 | Coordinated Time. This number is like the POSIX time_t variable, but |
4943 | expressed in milliseconds instead. |
4944 | |
4945 | \sa currentDateTime(), currentDateTimeUtc(), toTime_t(), toTimeSpec() |
4946 | */ |
4947 | |
4948 | /*! |
4949 | \fn qint64 QDateTime::currentSecsSinceEpoch() |
4950 | \since 5.8 |
4951 | |
4952 | Returns the number of seconds since 1970-01-01T00:00:00 Universal |
4953 | Coordinated Time. |
4954 | |
4955 | \sa currentMSecsSinceEpoch() |
4956 | */ |
4957 | |
4958 | #if defined(Q_OS_WIN) |
4959 | static inline uint msecsFromDecomposed(int hour, int minute, int sec, int msec = 0) |
4960 | { |
4961 | return MSECS_PER_HOUR * hour + MSECS_PER_MIN * minute + 1000 * sec + msec; |
4962 | } |
4963 | |
4964 | QDate QDate::currentDate() |
4965 | { |
4966 | SYSTEMTIME st; |
4967 | memset(&st, 0, sizeof(SYSTEMTIME)); |
4968 | GetLocalTime(&st); |
4969 | return QDate(st.wYear, st.wMonth, st.wDay); |
4970 | } |
4971 | |
4972 | QTime QTime::currentTime() |
4973 | { |
4974 | QTime ct; |
4975 | SYSTEMTIME st; |
4976 | memset(&st, 0, sizeof(SYSTEMTIME)); |
4977 | GetLocalTime(&st); |
4978 | ct.setHMS(st.wHour, st.wMinute, st.wSecond, st.wMilliseconds); |
4979 | return ct; |
4980 | } |
4981 | |
4982 | QDateTime QDateTime::currentDateTime() |
4983 | { |
4984 | QTime t; |
4985 | SYSTEMTIME st; |
4986 | memset(&st, 0, sizeof(SYSTEMTIME)); |
4987 | GetLocalTime(&st); |
4988 | QDate d(st.wYear, st.wMonth, st.wDay); |
4989 | t.mds = msecsFromDecomposed(st.wHour, st.wMinute, st.wSecond, st.wMilliseconds); |
4990 | return QDateTime(d, t); |
4991 | } |
4992 | |
4993 | QDateTime QDateTime::currentDateTimeUtc() |
4994 | { |
4995 | QTime t; |
4996 | SYSTEMTIME st; |
4997 | memset(&st, 0, sizeof(SYSTEMTIME)); |
4998 | GetSystemTime(&st); |
4999 | QDate d(st.wYear, st.wMonth, st.wDay); |
5000 | t.mds = msecsFromDecomposed(st.wHour, st.wMinute, st.wSecond, st.wMilliseconds); |
5001 | return QDateTime(d, t, Qt::UTC); |
5002 | } |
5003 | |
5004 | qint64 QDateTime::currentMSecsSinceEpoch() noexcept |
5005 | { |
5006 | SYSTEMTIME st; |
5007 | memset(&st, 0, sizeof(SYSTEMTIME)); |
5008 | GetSystemTime(&st); |
5009 | const qint64 daysAfterEpoch = QDate(1970, 1, 1).daysTo(QDate(st.wYear, st.wMonth, st.wDay)); |
5010 | |
5011 | return msecsFromDecomposed(st.wHour, st.wMinute, st.wSecond, st.wMilliseconds) + |
5012 | daysAfterEpoch * Q_INT64_C(86400000); |
5013 | } |
5014 | |
5015 | qint64 QDateTime::currentSecsSinceEpoch() noexcept |
5016 | { |
5017 | SYSTEMTIME st; |
5018 | memset(&st, 0, sizeof(SYSTEMTIME)); |
5019 | GetSystemTime(&st); |
5020 | const qint64 daysAfterEpoch = QDate(1970, 1, 1).daysTo(QDate(st.wYear, st.wMonth, st.wDay)); |
5021 | |
5022 | return st.wHour * SECS_PER_HOUR + st.wMinute * SECS_PER_MIN + st.wSecond + |
5023 | daysAfterEpoch * Q_INT64_C(86400); |
5024 | } |
5025 | |
5026 | #elif defined(Q_OS_UNIX) |
5027 | QDate QDate::currentDate() |
5028 | { |
5029 | return QDateTime::currentDateTime().date(); |
5030 | } |
5031 | |
5032 | QTime QTime::currentTime() |
5033 | { |
5034 | return QDateTime::currentDateTime().time(); |
5035 | } |
5036 | |
5037 | QDateTime QDateTime::currentDateTime() |
5038 | { |
5039 | return fromMSecsSinceEpoch(msecs: currentMSecsSinceEpoch(), spec: Qt::LocalTime); |
5040 | } |
5041 | |
5042 | QDateTime QDateTime::currentDateTimeUtc() |
5043 | { |
5044 | return fromMSecsSinceEpoch(msecs: currentMSecsSinceEpoch(), spec: Qt::UTC); |
5045 | } |
5046 | |
5047 | qint64 QDateTime::currentMSecsSinceEpoch() noexcept |
5048 | { |
5049 | // posix compliant system |
5050 | // we have milliseconds |
5051 | struct timeval tv; |
5052 | gettimeofday(tv: &tv, tz: nullptr); |
5053 | return qint64(tv.tv_sec) * Q_INT64_C(1000) + tv.tv_usec / 1000; |
5054 | } |
5055 | |
5056 | qint64 QDateTime::currentSecsSinceEpoch() noexcept |
5057 | { |
5058 | struct timeval tv; |
5059 | gettimeofday(tv: &tv, tz: nullptr); |
5060 | return qint64(tv.tv_sec); |
5061 | } |
5062 | #else |
5063 | #error "What system is this?" |
5064 | #endif |
5065 | |
5066 | #if QT_DEPRECATED_SINCE(5, 8) |
5067 | /*! |
5068 | \since 4.2 |
5069 | \deprecated |
5070 | |
5071 | Returns a datetime whose date and time are the number of \a seconds |
5072 | that have passed since 1970-01-01T00:00:00, Coordinated Universal |
5073 | Time (Qt::UTC) and converted to Qt::LocalTime. On systems that do not |
5074 | support time zones, the time will be set as if local time were Qt::UTC. |
5075 | |
5076 | \note This function is deprecated. Please use fromSecsSinceEpoch() in new |
5077 | code. |
5078 | |
5079 | \sa toTime_t(), setTime_t() |
5080 | */ |
5081 | QDateTime QDateTime::fromTime_t(uint seconds) |
5082 | { |
5083 | return fromMSecsSinceEpoch(msecs: (qint64)seconds * 1000, spec: Qt::LocalTime); |
5084 | } |
5085 | |
5086 | /*! |
5087 | \since 5.2 |
5088 | \deprecated |
5089 | |
5090 | Returns a datetime whose date and time are the number of \a seconds |
5091 | that have passed since 1970-01-01T00:00:00, Coordinated Universal |
5092 | Time (Qt::UTC) and converted to the given \a spec. |
5093 | |
5094 | If the \a spec is not Qt::OffsetFromUTC then the \a offsetSeconds will be |
5095 | ignored. If the \a spec is Qt::OffsetFromUTC and the \a offsetSeconds is 0 |
5096 | then the spec will be set to Qt::UTC, i.e. an offset of 0 seconds. |
5097 | |
5098 | \note This function is deprecated. Please use fromSecsSinceEpoch() in new |
5099 | code. |
5100 | |
5101 | \sa toTime_t(), setTime_t() |
5102 | */ |
5103 | QDateTime QDateTime::fromTime_t(uint seconds, Qt::TimeSpec spec, int offsetSeconds) |
5104 | { |
5105 | return fromMSecsSinceEpoch(msecs: (qint64)seconds * 1000, spec, offsetFromUtc: offsetSeconds); |
5106 | } |
5107 | |
5108 | #if QT_CONFIG(timezone) |
5109 | /*! |
5110 | \since 5.2 |
5111 | \deprecated |
5112 | |
5113 | Returns a datetime whose date and time are the number of \a seconds |
5114 | that have passed since 1970-01-01T00:00:00, Coordinated Universal |
5115 | Time (Qt::UTC) and with the given \a timeZone. |
5116 | |
5117 | \note This function is deprecated. Please use fromSecsSinceEpoch() in new |
5118 | code. |
5119 | |
5120 | \sa toTime_t(), setTime_t() |
5121 | */ |
5122 | QDateTime QDateTime::fromTime_t(uint seconds, const QTimeZone &timeZone) |
5123 | { |
5124 | return fromMSecsSinceEpoch(msecs: (qint64)seconds * 1000, timeZone); |
5125 | } |
5126 | #endif |
5127 | #endif // QT_DEPRECATED_SINCE(5, 8) |
5128 | |
5129 | /*! |
5130 | \since 4.7 |
5131 | |
5132 | Returns a datetime whose date and time are the number of milliseconds, \a msecs, |
5133 | that have passed since 1970-01-01T00:00:00.000, Coordinated Universal |
5134 | Time (Qt::UTC), and converted to Qt::LocalTime. On systems that do not |
5135 | support time zones, the time will be set as if local time were Qt::UTC. |
5136 | |
5137 | Note that there are possible values for \a msecs that lie outside the valid |
5138 | range of QDateTime, both negative and positive. The behavior of this |
5139 | function is undefined for those values. |
5140 | |
5141 | \sa toMSecsSinceEpoch(), setMSecsSinceEpoch() |
5142 | */ |
5143 | QDateTime QDateTime::fromMSecsSinceEpoch(qint64 msecs) |
5144 | { |
5145 | return fromMSecsSinceEpoch(msecs, spec: Qt::LocalTime); |
5146 | } |
5147 | |
5148 | /*! |
5149 | \since 5.2 |
5150 | |
5151 | Returns a datetime whose date and time are the number of milliseconds \a msecs |
5152 | that have passed since 1970-01-01T00:00:00.000, Coordinated Universal |
5153 | Time (Qt::UTC) and converted to the given \a spec. |
5154 | |
5155 | Note that there are possible values for \a msecs that lie outside the valid |
5156 | range of QDateTime, both negative and positive. The behavior of this |
5157 | function is undefined for those values. |
5158 | |
5159 | If the \a spec is not Qt::OffsetFromUTC then the \a offsetSeconds will be |
5160 | ignored. If the \a spec is Qt::OffsetFromUTC and the \a offsetSeconds is 0 |
5161 | then the spec will be set to Qt::UTC, i.e. an offset of 0 seconds. |
5162 | |
5163 | If \a spec is Qt::TimeZone then the spec will be set to Qt::LocalTime, |
5164 | i.e. the current system time zone. |
5165 | |
5166 | \sa toMSecsSinceEpoch(), setMSecsSinceEpoch() |
5167 | */ |
5168 | QDateTime QDateTime::fromMSecsSinceEpoch(qint64 msecs, Qt::TimeSpec spec, int offsetSeconds) |
5169 | { |
5170 | QDateTime dt; |
5171 | QT_PREPEND_NAMESPACE(setTimeSpec(dt.d, spec, offsetSeconds)); |
5172 | dt.setMSecsSinceEpoch(msecs); |
5173 | return dt; |
5174 | } |
5175 | |
5176 | /*! |
5177 | \since 5.8 |
5178 | |
5179 | Returns a datetime whose date and time are the number of seconds \a secs |
5180 | that have passed since 1970-01-01T00:00:00.000, Coordinated Universal |
5181 | Time (Qt::UTC) and converted to the given \a spec. |
5182 | |
5183 | Note that there are possible values for \a secs that lie outside the valid |
5184 | range of QDateTime, both negative and positive. The behavior of this |
5185 | function is undefined for those values. |
5186 | |
5187 | If the \a spec is not Qt::OffsetFromUTC then the \a offsetSeconds will be |
5188 | ignored. If the \a spec is Qt::OffsetFromUTC and the \a offsetSeconds is 0 |
5189 | then the spec will be set to Qt::UTC, i.e. an offset of 0 seconds. |
5190 | |
5191 | If \a spec is Qt::TimeZone then the spec will be set to Qt::LocalTime, |
5192 | i.e. the current system time zone. |
5193 | |
5194 | \sa toSecsSinceEpoch(), setSecsSinceEpoch() |
5195 | */ |
5196 | QDateTime QDateTime::fromSecsSinceEpoch(qint64 secs, Qt::TimeSpec spec, int offsetSeconds) |
5197 | { |
5198 | return fromMSecsSinceEpoch(msecs: secs * 1000, spec, offsetSeconds); |
5199 | } |
5200 | |
5201 | #if QT_CONFIG(timezone) |
5202 | /*! |
5203 | \since 5.2 |
5204 | |
5205 | Returns a datetime whose date and time are the number of milliseconds \a msecs |
5206 | that have passed since 1970-01-01T00:00:00.000, Coordinated Universal |
5207 | Time (Qt::UTC) and with the given \a timeZone. |
5208 | |
5209 | \sa fromSecsSinceEpoch() |
5210 | */ |
5211 | QDateTime QDateTime::fromMSecsSinceEpoch(qint64 msecs, const QTimeZone &timeZone) |
5212 | { |
5213 | QDateTime dt; |
5214 | dt.setTimeZone(timeZone); |
5215 | if (timeZone.isValid()) |
5216 | dt.setMSecsSinceEpoch(msecs); |
5217 | return dt; |
5218 | } |
5219 | |
5220 | /*! |
5221 | \since 5.8 |
5222 | |
5223 | Returns a datetime whose date and time are the number of seconds \a secs |
5224 | that have passed since 1970-01-01T00:00:00.000, Coordinated Universal |
5225 | Time (Qt::UTC) and with the given \a timeZone. |
5226 | |
5227 | \sa fromMSecsSinceEpoch() |
5228 | */ |
5229 | QDateTime QDateTime::fromSecsSinceEpoch(qint64 secs, const QTimeZone &timeZone) |
5230 | { |
5231 | return fromMSecsSinceEpoch(msecs: secs * 1000, timeZone); |
5232 | } |
5233 | #endif |
5234 | |
5235 | #if QT_DEPRECATED_SINCE(5, 2) |
5236 | /*! |
5237 | \since 4.4 |
5238 | \internal |
5239 | \obsolete |
5240 | |
5241 | This method was added in 4.4 but never documented as public. It was replaced |
5242 | in 5.2 with public method setOffsetFromUtc() for consistency with QTimeZone. |
5243 | |
5244 | This method should never be made public. |
5245 | |
5246 | \sa setOffsetFromUtc() |
5247 | */ |
5248 | void QDateTime::setUtcOffset(int seconds) |
5249 | { |
5250 | setOffsetFromUtc(seconds); |
5251 | } |
5252 | |
5253 | /*! |
5254 | \since 4.4 |
5255 | \internal |
5256 | \obsolete |
5257 | |
5258 | This method was added in 4.4 but never documented as public. It was replaced |
5259 | in 5.1 with public method offsetFromUTC() for consistency with QTimeZone. |
5260 | |
5261 | This method should never be made public. |
5262 | |
5263 | \sa offsetFromUTC() |
5264 | */ |
5265 | int QDateTime::utcOffset() const |
5266 | { |
5267 | return offsetFromUtc(); |
5268 | } |
5269 | #endif // QT_DEPRECATED_SINCE |
5270 | |
5271 | #if QT_CONFIG(datestring) // depends on, so implies, textdate |
5272 | |
5273 | /*! |
5274 | Returns the QDateTime represented by the \a string, using the |
5275 | \a format given, or an invalid datetime if this is not possible. |
5276 | |
5277 | Note for Qt::TextDate: It is recommended that you use the English short |
5278 | month names (e.g. "Jan"). Although localized month names can also be used in |
5279 | Qt 5, they depend on the user's locale settings. |
5280 | |
5281 | \note Support for localized dates, including the format options |
5282 | Qt::SystemLocaleDate, Qt::SystemLocaleShortDate, Qt::SystemLocaleLongDate, |
5283 | Qt::LocaleDate, Qt::DefaultLocaleShortDate, and Qt::DefaultLocaleLongDate, |
5284 | shall be removed in Qt 6. Use QLocale::toDateTime() instead. |
5285 | |
5286 | \sa toString(), QLocale::toDateTime() |
5287 | */ |
5288 | QDateTime QDateTime::fromString(const QString &string, Qt::DateFormat format) |
5289 | { |
5290 | if (string.isEmpty()) |
5291 | return QDateTime(); |
5292 | |
5293 | switch (format) { |
5294 | #if QT_DEPRECATED_SINCE(5, 15) |
5295 | QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED |
5296 | case Qt::SystemLocaleDate: |
5297 | case Qt::SystemLocaleShortDate: |
5298 | return QLocale::system().toDateTime(string, format: QLocale::ShortFormat); |
5299 | case Qt::SystemLocaleLongDate: |
5300 | return QLocale::system().toDateTime(string, format: QLocale::LongFormat); |
5301 | case Qt::LocaleDate: |
5302 | case Qt::DefaultLocaleShortDate: |
5303 | return QLocale().toDateTime(string, format: QLocale::ShortFormat); |
5304 | case Qt::DefaultLocaleLongDate: |
5305 | return QLocale().toDateTime(string, format: QLocale::LongFormat); |
5306 | QT_WARNING_POP |
5307 | #endif // 5.15 |
5308 | case Qt::RFC2822Date: { |
5309 | const ParsedRfcDateTime rfc = rfcDateImpl(s: string); |
5310 | |
5311 | if (!rfc.date.isValid() || !rfc.time.isValid()) |
5312 | return QDateTime(); |
5313 | |
5314 | QDateTime dateTime(rfc.date, rfc.time, Qt::UTC); |
5315 | dateTime.setOffsetFromUtc(rfc.utcOffset); |
5316 | return dateTime; |
5317 | } |
5318 | case Qt::ISODate: |
5319 | case Qt::ISODateWithMs: { |
5320 | const int size = string.size(); |
5321 | if (size < 10) |
5322 | return QDateTime(); |
5323 | |
5324 | QDate date = QDate::fromString(string: string.left(n: 10), format: Qt::ISODate); |
5325 | if (!date.isValid()) |
5326 | return QDateTime(); |
5327 | if (size == 10) |
5328 | return date.startOfDay(); |
5329 | |
5330 | Qt::TimeSpec spec = Qt::LocalTime; |
5331 | QStringView isoString = QStringView(string).mid(pos: 10); // trim "yyyy-MM-dd" |
5332 | |
5333 | // Must be left with T (or space) and at least one digit for the hour: |
5334 | if (isoString.size() < 2 |
5335 | || !(isoString.startsWith(c: QLatin1Char('T'), cs: Qt::CaseInsensitive) |
5336 | // RFC 3339 (section 5.6) allows a space here. (It actually |
5337 | // allows any separator one considers more readable, merely |
5338 | // giving space as an example - but let's not go wild !) |
5339 | || isoString.startsWith(c: QLatin1Char(' ')))) { |
5340 | return QDateTime(); |
5341 | } |
5342 | isoString = isoString.mid(pos: 1); // trim 'T' (or space) |
5343 | |
5344 | int offset = 0; |
5345 | // Check end of string for Time Zone definition, either Z for UTC or [+-]HH:mm for Offset |
5346 | if (isoString.endsWith(c: QLatin1Char('Z'), cs: Qt::CaseInsensitive)) { |
5347 | spec = Qt::UTC; |
5348 | isoString.chop(n: 1); // trim 'Z' |
5349 | } else { |
5350 | // the loop below is faster but functionally equal to: |
5351 | // const int signIndex = isoString.indexOf(QRegExp(QStringLiteral("[+-]"))); |
5352 | int signIndex = isoString.size() - 1; |
5353 | Q_ASSERT(signIndex >= 0); |
5354 | bool found = false; |
5355 | { |
5356 | const QChar plus = QLatin1Char('+'); |
5357 | const QChar minus = QLatin1Char('-'); |
5358 | do { |
5359 | QChar character(isoString.at(n: signIndex)); |
5360 | found = character == plus || character == minus; |
5361 | } while (!found && --signIndex >= 0); |
5362 | } |
5363 | |
5364 | if (found) { |
5365 | bool ok; |
5366 | offset = fromOffsetString(offsetString: isoString.mid(pos: signIndex), valid: &ok); |
5367 | if (!ok) |
5368 | return QDateTime(); |
5369 | isoString = isoString.left(n: signIndex); |
5370 | spec = Qt::OffsetFromUTC; |
5371 | } |
5372 | } |
5373 | |
5374 | // Might be end of day (24:00, including variants), which QTime considers invalid. |
5375 | // ISO 8601 (section 4.2.3) says that 24:00 is equivalent to 00:00 the next day. |
5376 | bool isMidnight24 = false; |
5377 | QTime time = fromIsoTimeString(string: isoString, format, isMidnight24: &isMidnight24); |
5378 | if (!time.isValid()) |
5379 | return QDateTime(); |
5380 | if (isMidnight24) |
5381 | date = date.addDays(ndays: 1); |
5382 | return QDateTime(date, time, spec, offset); |
5383 | } |
5384 | case Qt::TextDate: { |
5385 | QVector<QStringRef> parts = string.splitRef(sep: QLatin1Char(' '), behavior: Qt::SkipEmptyParts); |
5386 | |
5387 | const int count = parts.count(); |
5388 | if (count < 5) |
5389 | return QDateTime(); |
5390 | |
5391 | // Accept "Sun Dec 1 13:02:00 1974" and "Sun 1. Dec 13:02:00 1974" with |
5392 | // optional GMT-based zone-suffix, with time and year in either order; |
5393 | // and some locales have spaces even in short names of months and days. |
5394 | int tail = count - 1, zonePart = 0; |
5395 | if (parts.at(i: tail).startsWith(s: QLatin1String("GMT" ), cs: Qt::CaseInsensitive)) |
5396 | zonePart = tail--; |
5397 | |
5398 | // Year and time can be in either order. |
5399 | // Guess which by looking for ':' in the time |
5400 | int yearPart = tail; |
5401 | int timePart = tail; |
5402 | if (parts.at(i: timePart).contains(c: QLatin1Char(':'))) |
5403 | yearPart--; |
5404 | else if (parts.at(i: timePart - 1).contains(c: QLatin1Char(':'))) |
5405 | timePart--; |
5406 | else |
5407 | return QDateTime(); |
5408 | |
5409 | int dayPart = tail - 2; // but may be earlier, with a comma after: |
5410 | for (int i = 1; i < dayPart; i++) { |
5411 | if (parts.at(i).endsWith(c: QLatin1Char('.'))) |
5412 | dayPart = i; // exits the loop |
5413 | } |
5414 | |
5415 | bool ok = false; |
5416 | int year = parts.at(i: yearPart).toInt(ok: &ok); |
5417 | int day = 0; |
5418 | |
5419 | if (ok && year) { |
5420 | QStringRef dayStr = parts.at(i: dayPart); |
5421 | if (dayStr.endsWith(c: QLatin1Char('.'))) |
5422 | dayStr.chop(n: 1); |
5423 | day = dayStr.toInt(ok: &ok); |
5424 | } |
5425 | if (!ok || !year || !day) |
5426 | return QDateTime(); |
5427 | |
5428 | int month = 0; |
5429 | if (dayPart < tail - 2) { |
5430 | // Easy case, month is the parts from dayPart + 1 to count - 3 |
5431 | int i = dayPart + 1; |
5432 | QString monthName = parts.at(i).toString(); |
5433 | while (++i < tail - 1) |
5434 | monthName += QLatin1Char(' ') + parts.at(i); |
5435 | month = fromShortMonthName(monthName, year); |
5436 | } else { |
5437 | int i = dayPart - 1; |
5438 | QString monthName = parts.at(i).toString(); |
5439 | while (i > 0) { |
5440 | month = fromShortMonthName(monthName, year); |
5441 | if (month > 0) |
5442 | break; |
5443 | monthName = parts.at(i: --i) + QLatin1Char(' ') + monthName; |
5444 | } |
5445 | } |
5446 | if (month <= 0) |
5447 | return QDateTime(); |
5448 | |
5449 | QDate date(year, month, day); |
5450 | if (!date.isValid()) |
5451 | return QDateTime(); |
5452 | |
5453 | QVector<QStringRef> timeParts = parts.at(i: timePart).split(sep: QLatin1Char(':')); |
5454 | if (timeParts.count() < 2 || timeParts.count() > 3) |
5455 | return QDateTime(); |
5456 | |
5457 | int hour = timeParts.at(i: 0).toInt(ok: &ok); |
5458 | if (!ok) |
5459 | return QDateTime(); |
5460 | |
5461 | int minute = timeParts.at(i: 1).toInt(ok: &ok); |
5462 | if (!ok) |
5463 | return QDateTime(); |
5464 | |
5465 | int second = 0; |
5466 | int millisecond = 0; |
5467 | if (timeParts.count() > 2) { |
5468 | const QVector<QStringRef> secondParts = timeParts.at(i: 2).split(sep: QLatin1Char('.')); |
5469 | if (secondParts.size() > 2) { |
5470 | return QDateTime(); |
5471 | } |
5472 | |
5473 | second = secondParts.first().toInt(ok: &ok); |
5474 | if (!ok) { |
5475 | return QDateTime(); |
5476 | } |
5477 | |
5478 | if (secondParts.size() > 1) { |
5479 | millisecond = secondParts.last().toInt(ok: &ok); |
5480 | if (!ok) { |
5481 | return QDateTime(); |
5482 | } |
5483 | } |
5484 | } |
5485 | |
5486 | QTime time(hour, minute, second, millisecond); |
5487 | if (!time.isValid()) |
5488 | return QDateTime(); |
5489 | |
5490 | if (!zonePart) |
5491 | return QDateTime(date, time, Qt::LocalTime); |
5492 | |
5493 | const QStringView tz = parts.at(i: zonePart).mid(pos: 3); |
5494 | if (tz.isEmpty()) |
5495 | return QDateTime(date, time, Qt::UTC); |
5496 | |
5497 | int offset = fromOffsetString(offsetString: tz, valid: &ok); |
5498 | return ok ? QDateTime(date, time, Qt::OffsetFromUTC, offset) : QDateTime(); |
5499 | } |
5500 | } |
5501 | |
5502 | return QDateTime(); |
5503 | } |
5504 | |
5505 | /*! |
5506 | Returns the QDateTime represented by the \a string, using the \a |
5507 | format given, or an invalid datetime if the string cannot be parsed. |
5508 | |
5509 | Uses the calendar \a cal if supplied, else Gregorian. |
5510 | |
5511 | In addition to the expressions, recognized in the format string to represent |
5512 | parts of the date and time, by QDate::fromString() and QTime::fromString(), |
5513 | this method supports: |
5514 | |
5515 | \table |
5516 | \header \li Expression \li Output |
5517 | \row \li t \li the timezone (for example "CEST") |
5518 | \endtable |
5519 | |
5520 | All other input characters will be treated as text. Any non-empty sequence |
5521 | of characters enclosed in single quotes will also be treated (stripped of |
5522 | the quotes) as text and not be interpreted as expressions. |
5523 | |
5524 | \snippet code/src_corelib_tools_qdatetime.cpp 12 |
5525 | |
5526 | If the format is not satisfied, an invalid QDateTime is returned. If the |
5527 | format is satisfied but \a string represents an invalid date-time (e.g. in a |
5528 | gap skipped by a time-zone transition), an invalid QDateTime is returned, |
5529 | whose toMSecsSinceEpoch() represents a near-by date-time that is |
5530 | valid. Passing that to fromMSecsSinceEpoch() will produce a valid date-time |
5531 | that isn't faithfully represented by the string parsed. |
5532 | |
5533 | The expressions that don't have leading zeroes (d, M, h, m, s, z) will be |
5534 | greedy. This means that they will use two digits even if this will |
5535 | put them outside the range and/or leave too few digits for other |
5536 | sections. |
5537 | |
5538 | \snippet code/src_corelib_tools_qdatetime.cpp 13 |
5539 | |
5540 | This could have meant 1 January 00:30.00 but the M will grab |
5541 | two digits. |
5542 | |
5543 | Incorrectly specified fields of the \a string will cause an invalid |
5544 | QDateTime to be returned. For example, consider the following code, |
5545 | where the two digit year 12 is read as 1912 (see the table below for all |
5546 | field defaults); the resulting datetime is invalid because 23 April 1912 |
5547 | was a Tuesday, not a Monday: |
5548 | |
5549 | \snippet code/src_corelib_tools_qdatetime.cpp 20 |
5550 | |
5551 | The correct code is: |
5552 | |
5553 | \snippet code/src_corelib_tools_qdatetime.cpp 21 |
5554 | |
5555 | For any field that is not represented in the format, the following |
5556 | defaults are used: |
5557 | |
5558 | \table |
5559 | \header \li Field \li Default value |
5560 | \row \li Year \li 1900 |
5561 | \row \li Month \li 1 (January) |
5562 | \row \li Day \li 1 |
5563 | \row \li Hour \li 0 |
5564 | \row \li Minute \li 0 |
5565 | \row \li Second \li 0 |
5566 | \endtable |
5567 | |
5568 | For example: |
5569 | |
5570 | \snippet code/src_corelib_tools_qdatetime.cpp 14 |
5571 | |
5572 | \note If localized month and day names are used, please switch to using |
5573 | QLocale::system().toDateTime() as QDateTime methods shall change to only |
5574 | recognize English (C locale) names at Qt 6. |
5575 | |
5576 | \sa toString(), QDate::fromString(), QTime::fromString(), |
5577 | QLocale::toDateTime() |
5578 | */ |
5579 | |
5580 | QDateTime QDateTime::fromString(const QString &string, const QString &format, QCalendar cal) |
5581 | { |
5582 | #if QT_CONFIG(datetimeparser) |
5583 | QDateTime datetime; |
5584 | |
5585 | QDateTimeParser dt(QMetaType::QDateTime, QDateTimeParser::FromString, cal); |
5586 | // dt.setDefaultLocale(QLocale::c()); ### Qt 6 |
5587 | if (dt.parseFormat(format) && (dt.fromString(text: string, datetime: &datetime) || !datetime.isValid())) |
5588 | return datetime; |
5589 | #else |
5590 | Q_UNUSED(string); |
5591 | Q_UNUSED(format); |
5592 | Q_UNUSED(cal); |
5593 | #endif |
5594 | return QDateTime(); |
5595 | } |
5596 | |
5597 | /*! |
5598 | \overload |
5599 | */ |
5600 | |
5601 | QDateTime QDateTime::fromString(const QString &string, const QString &format) |
5602 | { |
5603 | return fromString(string, format, cal: QCalendar()); |
5604 | } |
5605 | |
5606 | #endif // datestring |
5607 | /*! |
5608 | \fn QDateTime QDateTime::toLocalTime() const |
5609 | |
5610 | Returns a datetime containing the date and time information in |
5611 | this datetime, but specified using the Qt::LocalTime definition. |
5612 | |
5613 | Example: |
5614 | |
5615 | \snippet code/src_corelib_tools_qdatetime.cpp 17 |
5616 | |
5617 | \sa toTimeSpec() |
5618 | */ |
5619 | |
5620 | /*! |
5621 | \fn QDateTime QDateTime::toUTC() const |
5622 | |
5623 | Returns a datetime containing the date and time information in |
5624 | this datetime, but specified using the Qt::UTC definition. |
5625 | |
5626 | Example: |
5627 | |
5628 | \snippet code/src_corelib_tools_qdatetime.cpp 18 |
5629 | |
5630 | \sa toTimeSpec() |
5631 | */ |
5632 | |
5633 | /***************************************************************************** |
5634 | Date/time stream functions |
5635 | *****************************************************************************/ |
5636 | |
5637 | #ifndef QT_NO_DATASTREAM |
5638 | /*! |
5639 | \relates QDate |
5640 | |
5641 | Writes the \a date to stream \a out. |
5642 | |
5643 | \sa {Serializing Qt Data Types} |
5644 | */ |
5645 | |
5646 | QDataStream &operator<<(QDataStream &out, const QDate &date) |
5647 | { |
5648 | if (out.version() < QDataStream::Qt_5_0) |
5649 | return out << quint32(date.jd); |
5650 | else |
5651 | return out << qint64(date.jd); |
5652 | } |
5653 | |
5654 | /*! |
5655 | \relates QDate |
5656 | |
5657 | Reads a date from stream \a in into the \a date. |
5658 | |
5659 | \sa {Serializing Qt Data Types} |
5660 | */ |
5661 | |
5662 | QDataStream &operator>>(QDataStream &in, QDate &date) |
5663 | { |
5664 | if (in.version() < QDataStream::Qt_5_0) { |
5665 | quint32 jd; |
5666 | in >> jd; |
5667 | // Older versions consider 0 an invalid jd. |
5668 | date.jd = (jd != 0 ? jd : QDate::nullJd()); |
5669 | } else { |
5670 | qint64 jd; |
5671 | in >> jd; |
5672 | date.jd = jd; |
5673 | } |
5674 | |
5675 | return in; |
5676 | } |
5677 | |
5678 | /*! |
5679 | \relates QTime |
5680 | |
5681 | Writes \a time to stream \a out. |
5682 | |
5683 | \sa {Serializing Qt Data Types} |
5684 | */ |
5685 | |
5686 | QDataStream &operator<<(QDataStream &out, const QTime &time) |
5687 | { |
5688 | if (out.version() >= QDataStream::Qt_4_0) { |
5689 | return out << quint32(time.mds); |
5690 | } else { |
5691 | // Qt3 had no support for reading -1, QTime() was valid and serialized as 0 |
5692 | return out << quint32(time.isNull() ? 0 : time.mds); |
5693 | } |
5694 | } |
5695 | |
5696 | /*! |
5697 | \relates QTime |
5698 | |
5699 | Reads a time from stream \a in into the given \a time. |
5700 | |
5701 | \sa {Serializing Qt Data Types} |
5702 | */ |
5703 | |
5704 | QDataStream &operator>>(QDataStream &in, QTime &time) |
5705 | { |
5706 | quint32 ds; |
5707 | in >> ds; |
5708 | if (in.version() >= QDataStream::Qt_4_0) { |
5709 | time.mds = int(ds); |
5710 | } else { |
5711 | // Qt3 would write 0 for a null time |
5712 | time.mds = (ds == 0) ? QTime::NullTime : int(ds); |
5713 | } |
5714 | return in; |
5715 | } |
5716 | |
5717 | /*! |
5718 | \relates QDateTime |
5719 | |
5720 | Writes \a dateTime to the \a out stream. |
5721 | |
5722 | \sa {Serializing Qt Data Types} |
5723 | */ |
5724 | QDataStream &operator<<(QDataStream &out, const QDateTime &dateTime) |
5725 | { |
5726 | QPair<QDate, QTime> dateAndTime; |
5727 | |
5728 | if (out.version() >= QDataStream::Qt_5_2) { |
5729 | |
5730 | // In 5.2 we switched to using Qt::TimeSpec and added offset support |
5731 | dateAndTime = getDateTime(d: dateTime.d); |
5732 | out << dateAndTime << qint8(dateTime.timeSpec()); |
5733 | if (dateTime.timeSpec() == Qt::OffsetFromUTC) |
5734 | out << qint32(dateTime.offsetFromUtc()); |
5735 | #if QT_CONFIG(timezone) |
5736 | else if (dateTime.timeSpec() == Qt::TimeZone) |
5737 | out << dateTime.timeZone(); |
5738 | #endif // timezone |
5739 | |
5740 | } else if (out.version() == QDataStream::Qt_5_0) { |
5741 | |
5742 | // In Qt 5.0 we incorrectly serialised all datetimes as UTC. |
5743 | // This approach is wrong and should not be used again; it breaks |
5744 | // the guarantee that a deserialised local datetime is the same time |
5745 | // of day, regardless of which timezone it was serialised in. |
5746 | dateAndTime = getDateTime(d: (dateTime.isValid() ? dateTime.toUTC() : dateTime).d); |
5747 | out << dateAndTime << qint8(dateTime.timeSpec()); |
5748 | |
5749 | } else if (out.version() >= QDataStream::Qt_4_0) { |
5750 | |
5751 | // From 4.0 to 5.1 (except 5.0) we used QDateTimePrivate::Spec |
5752 | dateAndTime = getDateTime(d: dateTime.d); |
5753 | out << dateAndTime; |
5754 | switch (dateTime.timeSpec()) { |
5755 | case Qt::UTC: |
5756 | out << (qint8)QDateTimePrivate::UTC; |
5757 | break; |
5758 | case Qt::OffsetFromUTC: |
5759 | out << (qint8)QDateTimePrivate::OffsetFromUTC; |
5760 | break; |
5761 | case Qt::TimeZone: |
5762 | out << (qint8)QDateTimePrivate::TimeZone; |
5763 | break; |
5764 | case Qt::LocalTime: |
5765 | out << (qint8)QDateTimePrivate::LocalUnknown; |
5766 | break; |
5767 | } |
5768 | |
5769 | } else { // version < QDataStream::Qt_4_0 |
5770 | |
5771 | // Before 4.0 there was no TimeSpec, only Qt::LocalTime was supported |
5772 | dateAndTime = getDateTime(d: dateTime.d); |
5773 | out << dateAndTime; |
5774 | |
5775 | } |
5776 | |
5777 | return out; |
5778 | } |
5779 | |
5780 | /*! |
5781 | \relates QDateTime |
5782 | |
5783 | Reads a datetime from the stream \a in into \a dateTime. |
5784 | |
5785 | \sa {Serializing Qt Data Types} |
5786 | */ |
5787 | |
5788 | QDataStream &operator>>(QDataStream &in, QDateTime &dateTime) |
5789 | { |
5790 | QDate dt; |
5791 | QTime tm; |
5792 | qint8 ts = 0; |
5793 | Qt::TimeSpec spec = Qt::LocalTime; |
5794 | qint32 offset = 0; |
5795 | #if QT_CONFIG(timezone) |
5796 | QTimeZone tz; |
5797 | #endif // timezone |
5798 | |
5799 | if (in.version() >= QDataStream::Qt_5_2) { |
5800 | |
5801 | // In 5.2 we switched to using Qt::TimeSpec and added offset support |
5802 | in >> dt >> tm >> ts; |
5803 | spec = static_cast<Qt::TimeSpec>(ts); |
5804 | if (spec == Qt::OffsetFromUTC) { |
5805 | in >> offset; |
5806 | dateTime = QDateTime(dt, tm, spec, offset); |
5807 | #if QT_CONFIG(timezone) |
5808 | } else if (spec == Qt::TimeZone) { |
5809 | in >> tz; |
5810 | dateTime = QDateTime(dt, tm, tz); |
5811 | #endif // timezone |
5812 | } else { |
5813 | dateTime = QDateTime(dt, tm, spec); |
5814 | } |
5815 | |
5816 | } else if (in.version() == QDataStream::Qt_5_0) { |
5817 | |
5818 | // In Qt 5.0 we incorrectly serialised all datetimes as UTC |
5819 | in >> dt >> tm >> ts; |
5820 | spec = static_cast<Qt::TimeSpec>(ts); |
5821 | dateTime = QDateTime(dt, tm, Qt::UTC); |
5822 | dateTime = dateTime.toTimeSpec(spec); |
5823 | |
5824 | } else if (in.version() >= QDataStream::Qt_4_0) { |
5825 | |
5826 | // From 4.0 to 5.1 (except 5.0) we used QDateTimePrivate::Spec |
5827 | in >> dt >> tm >> ts; |
5828 | switch ((QDateTimePrivate::Spec)ts) { |
5829 | case QDateTimePrivate::UTC: |
5830 | spec = Qt::UTC; |
5831 | break; |
5832 | case QDateTimePrivate::OffsetFromUTC: |
5833 | spec = Qt::OffsetFromUTC; |
5834 | break; |
5835 | case QDateTimePrivate::TimeZone: |
5836 | spec = Qt::TimeZone; |
5837 | #if QT_CONFIG(timezone) |
5838 | // FIXME: need to use a different constructor ! |
5839 | #endif |
5840 | break; |
5841 | case QDateTimePrivate::LocalUnknown: |
5842 | case QDateTimePrivate::LocalStandard: |
5843 | case QDateTimePrivate::LocalDST: |
5844 | spec = Qt::LocalTime; |
5845 | break; |
5846 | } |
5847 | dateTime = QDateTime(dt, tm, spec, offset); |
5848 | |
5849 | } else { // version < QDataStream::Qt_4_0 |
5850 | |
5851 | // Before 4.0 there was no TimeSpec, only Qt::LocalTime was supported |
5852 | in >> dt >> tm; |
5853 | dateTime = QDateTime(dt, tm, spec, offset); |
5854 | |
5855 | } |
5856 | |
5857 | return in; |
5858 | } |
5859 | #endif // QT_NO_DATASTREAM |
5860 | |
5861 | /***************************************************************************** |
5862 | Date / Time Debug Streams |
5863 | *****************************************************************************/ |
5864 | |
5865 | #if !defined(QT_NO_DEBUG_STREAM) && QT_CONFIG(datestring) |
5866 | QDebug operator<<(QDebug dbg, const QDate &date) |
5867 | { |
5868 | QDebugStateSaver saver(dbg); |
5869 | dbg.nospace() << "QDate(" ; |
5870 | if (date.isValid()) |
5871 | dbg.nospace() << date.toString(format: Qt::ISODate); |
5872 | else |
5873 | dbg.nospace() << "Invalid" ; |
5874 | dbg.nospace() << ')'; |
5875 | return dbg; |
5876 | } |
5877 | |
5878 | QDebug operator<<(QDebug dbg, const QTime &time) |
5879 | { |
5880 | QDebugStateSaver saver(dbg); |
5881 | dbg.nospace() << "QTime(" ; |
5882 | if (time.isValid()) |
5883 | dbg.nospace() << time.toString(format: u"HH:mm:ss.zzz" ); |
5884 | else |
5885 | dbg.nospace() << "Invalid" ; |
5886 | dbg.nospace() << ')'; |
5887 | return dbg; |
5888 | } |
5889 | |
5890 | QDebug operator<<(QDebug dbg, const QDateTime &date) |
5891 | { |
5892 | QDebugStateSaver saver(dbg); |
5893 | dbg.nospace() << "QDateTime(" ; |
5894 | if (date.isValid()) { |
5895 | const Qt::TimeSpec ts = date.timeSpec(); |
5896 | dbg.noquote() << date.toString(format: u"yyyy-MM-dd HH:mm:ss.zzz t" ) |
5897 | << ' ' << ts; |
5898 | switch (ts) { |
5899 | case Qt::UTC: |
5900 | break; |
5901 | case Qt::OffsetFromUTC: |
5902 | dbg.space() << date.offsetFromUtc() << 's'; |
5903 | break; |
5904 | case Qt::TimeZone: |
5905 | #if QT_CONFIG(timezone) |
5906 | dbg.space() << date.timeZone().id(); |
5907 | #endif // timezone |
5908 | break; |
5909 | case Qt::LocalTime: |
5910 | break; |
5911 | } |
5912 | } else { |
5913 | dbg.nospace() << "Invalid" ; |
5914 | } |
5915 | return dbg.nospace() << ')'; |
5916 | } |
5917 | #endif // debug_stream && datestring |
5918 | |
5919 | /*! \fn uint qHash(const QDateTime &key, uint seed = 0) |
5920 | \relates QHash |
5921 | \since 5.0 |
5922 | |
5923 | Returns the hash value for the \a key, using \a seed to seed the calculation. |
5924 | */ |
5925 | uint qHash(const QDateTime &key, uint seed) |
5926 | { |
5927 | // Use to toMSecsSinceEpoch instead of individual qHash functions for |
5928 | // QDate/QTime/spec/offset because QDateTime::operator== converts both arguments |
5929 | // to the same timezone. If we don't, qHash would return different hashes for |
5930 | // two QDateTimes that are equivalent once converted to the same timezone. |
5931 | return key.isValid() ? qHash(key: key.toMSecsSinceEpoch(), seed) : seed; |
5932 | } |
5933 | |
5934 | /*! \fn uint qHash(const QDate &key, uint seed = 0) |
5935 | \relates QHash |
5936 | \since 5.0 |
5937 | |
5938 | Returns the hash value for the \a key, using \a seed to seed the calculation. |
5939 | */ |
5940 | uint qHash(const QDate &key, uint seed) noexcept |
5941 | { |
5942 | return qHash(key: key.toJulianDay(), seed); |
5943 | } |
5944 | |
5945 | /*! \fn uint qHash(const QTime &key, uint seed = 0) |
5946 | \relates QHash |
5947 | \since 5.0 |
5948 | |
5949 | Returns the hash value for the \a key, using \a seed to seed the calculation. |
5950 | */ |
5951 | uint qHash(const QTime &key, uint seed) noexcept |
5952 | { |
5953 | return qHash(key: key.msecsSinceStartOfDay(), seed); |
5954 | } |
5955 | |
5956 | QT_END_NAMESPACE |
5957 | |