Commit Graph

173 Commits (410b5bc238549dce2b9ce904dcccd2ae573867e9)

Author SHA1 Message Date
Edward Welbourne 410b5bc238 Add MINS_PER_HOUR constant and avoid a Coverity overflow warning
Being able to distinguish which 60 is minutes-per-hour and which is
seconds-per-minute has some value in its own right, and doing it with
qint64 values (as usual for DateTimeConstants) takes care of two
Coverity warnings about multiplying before widening.

Use the new constant, and SECS_PER_MIN, in a few other places where
the result isn't an int (we don't want to provoke narrowing warnings).

Change-Id: Iadcb6956ac22a53029bf7b7518369520d2b1fd8b
Coverity-Id: CID 393112
Coverity-Id: CID 393113
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
2022-06-03 06:35:20 +02:00
Edward Welbourne 2dc82c2177 Move remaining time_t code from qdatetime.cpp to QLocalTime
What remains is all tangled together, but is now at least decoupled
from the rest of qdatetime.cpp, so moving it out makes that file
easier to read.

Task-number: QTBUG-95993
Change-Id: I3fba15aea59b3c8b4cbc6bf1cb03de96d68db0ce
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
2022-05-20 13:09:35 +02:00
Edward Welbourne 6d97cf0e57 Split qtLocalTime out into a new QLocalTime namespace
... in new qlocaltime* files, now that it's decoupled enough from the
internals of QDateTime for this to be possible. Part of the
consolidation of time_t code in one place.

Move assorted constants from qdatetime.cpp to a private namespace in
qdatetimeprivate_p.h to be shared between q*time.cpp hereafter (fixing
an out of date comment in the process - julianDayFromDate() is long
gone).

Task-number: QTBUG-95993
Change-Id: I03d97e959118041f9d86b8bb2e738599bc0b17e1
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
2022-05-20 13:09:23 +02:00
Edward Welbourne 1e295cff49 Replace qt_mktime(), avoiding out-parameters and conversions
Since qt_mktime() took QDate and QTime in/out parameters, its callers
had to convert the milliseconds they had to that form and back again
after. Since it combined optional look-up of zone abbreviation with
determination of offset and DST-ness (both ignore when the
abbreviation was asked for) it made sense to split it in two.

Each takes the millis and whatever knowledge we have of DST. One
returns tha abbreviation; the other returns a QDTP::ZoneState for the
caller that'll be returning that. Outside the system zone, when we
have to fall back to a kludge, their callers can now use the Julian
Day number change for its fake date to directly adjust the millis
there and back (effectively inlining former conversions to-and-from
date and time representation, but optimising out some of the work).

Change-Id: I7aa4583171f77fc0f4aa80c8f564e76995ca69d2
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
2022-05-20 13:08:54 +02:00
Edward Welbourne a534483518 Eliminate the msecsToTime() overload with out-parameters
Now that I've disposed of the callers that were or might be passing
null pointers for the out-parameters, getDateTime() can inline its
computation and the two other callers can use msecsTo{Date,Time} until
I eliminate the need for that.

Change-Id: Ia9169779cf03189fc7fd5271044d1ec90089fa03
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
2022-05-20 13:08:44 +02:00
Edward Welbourne ec1847fa38 Refactor QDateTimePrivate::*MSecsToEpochMSecs()
Aside from one client that wanted the zone abbreviation for a given
local time (and could supply a DST-ness hint), the callers actually
want to know the offset from UTC, DST-ness and any correction needed
to the local time to dig it out of a spring-forward. Mediating all of
that via a QDate, a QTime and a returned UTC seconds since the epoch
was not making our lives any easier.

Split the local-time function into one to get the abbreviation and
another to determine the data we actually need. The zone version only
needs the latter. Two functions with hairy signatures replete with
in/out parameters are replaced with three, with no in/out
parameters. Adapt all callers of the old functions to use the new,
simplifying them in the process. Inline some conversions between
date+time and msecs in the process.

Change-Id: Ice60b615121a99111ed882734785fa3c777e191c
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
2022-05-20 13:08:33 +02:00
Edward Welbourne b931688a1e Refactor qt_localtime()
Break out the part that calls the appropriate platform variant, so
that the logic of what we do with the result of that isn't tangled up
with the #if-ery. Rework the remainder to return a struct type that
packages the data we need, to get rid of the three out-parameter
pointers.

Change-Id: Ibba6f8de0954fab3fddf9e95adc18ef85e45ff72
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
2022-05-20 13:07:51 +02:00
Edward Welbourne 6f1eb8f127 QDateTime::setMSecsSinceEpoch(): push more work into a helper function
Formerly, setMSecsSinceEpoch() passed a QDate and a QTime to
epochMSecsToLocalTime() as in/out parameters, then obtained what it
actually wants, a count of milliseconds, from their modified values
and computed an offset from that. Pass the epoch milliseconds from
which the QDate and QTime were derived in place of them and return the
local milliseconds, offset and DST status back in a structure, rather
than via pointer parameters.

This prepares the way for pushing one step further, back into
qt_localtime(), so that we can simply get the count of milliseconds,
along with DST flag and offset from UTC, without going via QDate and
QTime (except in the kludge that copes with times outside the time_t
range; and even that can be short-cut somewhat).

Change-Id: I37ebb1efb355e81e1a116d03cbd52f9bb4a1f114
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
2022-05-20 13:07:40 +02:00
Edward Welbourne fc1a844111 Fix wrong QDateTime::isValid() to use the right QFlags method
It's documented to return true "if both the date and the time are
valid and they are valid in the current Qt::TimeSpec" but it was using
testAnyFlag() so would have returned true if any one of the three
conditions was met, rather than only if all three are met.

Change-Id: I91746224009d820abaffb541d8f6d6b13142849b
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
2022-05-20 13:07:30 +02:00
Edward Welbourne 0757c74b48 Simplify msecsToTime() and two callers by using QRoundingDown
The formerly cumbersome arithmetic, to adjust for division rounding
towards zero rather than down, is so much simpler this way. Break out
the conversion for only date and for only time, for the sake of (for
now) two callers that only need one; and inline QRoundingDown::qMod()
to save repeating the qDiv() call. Include the mapping from millis to
raw Julian Day as a separate function, as I'll be using it shortly.

Change-Id: I0ee74ea68421a347ed618fa34142bd034844351e
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
2022-05-20 13:07:17 +02:00
Lucie Gérard 05fc3aef53 Use SPDX license identifiers
Replace the current license disclaimer in files by
a SPDX-License-Identifier.
Files that have to be modified by hand are modified.
License files are organized under LICENSES directory.

Task-number: QTBUG-67283
Change-Id: Id880c92784c40f3bbde861c0d93f58151c18b9f1
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
Reviewed-by: Jörg Bornemann <joerg.bornemann@qt.io>
2022-05-16 16:37:38 +02:00
Edward Welbourne 0248838ee0 Correct leap year sequence in systemTimeYearMatching()
In the sequence for the early 32-bit time_t leap years, I somehow
managed to get two of the entries swapped. This amends
commit 1f4b237dad

Pick-to: 6.3
Change-Id: I5cb9080f8c6a24e2163508e640747c6fbbe93dbd
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
2022-04-25 19:18:49 +02:00
Giuseppe D'Angelo 41a7546789 QDate(Time): add a addDuration method
To complement the existing addSecs / MSecs / etc., add a function
that takes any compatible std::chrono::duration.

QTime also features similar functions, but it's also "unique" in that
it uses modular arithmetic (it wraps around in case of "overflow").
I'm not so sure that adding durations to a QTime object therefore
makes sense, and I'm not doing it in this patch.

[ChangeLog][QtCore][QDate] Added addDuration().
[ChangeLog][QtCore][QDateTime] Added addDuration().

Change-Id: I02aa37ff024d7f56fa976dc8f4f73523bdba8d94
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
2022-04-14 21:56:56 +02:00
Giuseppe D'Angelo 7de83f06c1 QDateTime: add conversions for time_point and zoned_time
In C++20, QDateTime is a direct equivalent of a sys_time<milliseconds>
time point. (Before, it might not have been, because system_clock before
C++20 was not guaranteed to be tracking Unix time, AKA UTC time without
leap seconds.) To be specific, sys_time<milliseconds> corresponds to
a QDateTime using the Qt::UTC timespec.

This patch:

1) adds named constructors taking time_points:

* a generic one taking any time_point convertible (via clock_cast) to
  a system_clock (this obviously includes system_clock, but also e.g.
  utc_clock)

* another couple taking local_time, interpreted as a duration from
  1/1/1970 in local time.

2) adds a named constructor from zoned_time (i.e. a sys_time + a
   timezone), that we can easily support via QTimeZone.

3) add conversion functions towards sys_time, matching the existing
   to(M)SecsSinceEpoch() functions.

[ChangeLog][QtCore][QDateTime] QDateTime can now be constructed
from std::chrono::time_point objects (including local_time), as
well as from std::chrono::zoned_time objects. Moreover, they
can be converted to std::chrono::time_point using system_clock
as their clock.

Change-Id: Ic6409bde43bc3e745d9df6257e0a77157472352d
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
2022-04-13 18:45:54 +02:00
Giuseppe D'Angelo 2e29f55f76 QDate: add conversions for std::chrono calendaring classes
std::chrono::year_month_day and related classes offer very
convenient to specify dates.

This patch adds implicit constructors to QDate to support this
convenience, e.g.:

  // YYYY-MM-DD, DD-MM-YYYY, MM-DD-YYYY formats:
  QDate d1 = 1985y / December / 8;
  QDate d2 = 8d / December / 1985;
  QDate d3 = December / 8d / 1985;

  // Indexed weekday:
  QDate d4 = 2000y / January / Monday[0];
  QDate d5 = 2000y / January / Monday[last];

and so on.

These are all implemented using the conversion from the std
calendaring classes to sys_days. Conversions between sys_days
and QDate are also added, since they're basically "for free".

I don't expect "ordinary" users to stumble upon it, but it's
worthy mentioning that std::chrono::year *does* have a year
zero (hence, year_month_day in year 0 or below are offset
by one with the corresponding QDate). I've left a note
in the documentation.

[ChangeLog][QtCore][QDate] QDate (and therefore QDateTime)
is now constructible using the year/month/day/week classes
available in the std::chrono library. Moreover, it now
features conversions from and to std::chrono::sys_days.

Change-Id: I2a4f56423ac7d1469541cbb6a278a65b48878b4a
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
2022-04-13 18:08:38 +02:00
Giuseppe D'Angelo 0a17a0da61 QDateTime: add support for std::chrono::duration arithmetic
QDateTime represents a specific point in time, so arithmetic
with durations makes perfect sense.

Moreover, we can finally equip QDateTime with a subtraction
operator, to calculate the duration between two QDateTime
objects.

[ChangeLog][QtCore][QDateTime] QDateTime now supports arithmetic
between QDateTime objects and std::chrono::duration objects.
A duration can be added to or subtracted from a QDateTime, yielding
another QDateTime; and two QDateTime objects can be subtracted
from each other, yielding the duration between them.

Change-Id: I656419f3bb9418c49f0e2fd0800c3dbaaf6aff32
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
2022-04-13 01:24:04 +02:00
Edward Welbourne 7db6aa4395 Fix overflow issue discovered by MSVC in C++20 mode
In setMSecsSinceEpoch(), when epochMSecsToLocalTime() fails (e.g. when
msecs is near one end of time and the offset being added causes
overflow), the call to setDateTime(d, ...) is bypassed so the d-ptr is
not updated and getStatus(d) returns the status prior to the function
call. The new status being prepared by the function should thus not be
updated to getStatus(d) unless setDateTime(d, ...) was called.

This amends commit 74eddd5bf0

Done-with: Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
Fixes: QTBUG-102157
Pick-to: 6.3
Change-Id: I25e358070907f22d9e4fb0030fa82ec290c7a730
Reviewed-by: Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
2022-04-05 19:40:17 +02:00
Edward Welbourne 1c359df621 QDateTimeParser: Correct a comment which was exactly wrong
Change-Id: I90c2b2bce4aeb5fe9edf70122c6546976583e1bf
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
2022-04-05 19:40:17 +02:00
Sona Kurazyan b625195893 QtCore: Replace remaining uses of QLatin1String with QLatin1StringView
Task-number: QTBUG-98434
Change-Id: Ib7c5fc0aaca6ef33b93c7486e99502c555bf20bc
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
Reviewed-by: Marc Mutz <marc.mutz@qt.io>
2022-03-26 01:44:05 +01:00
Sona Kurazyan 753a08ae0e QtCore: replace QLatin1String/QLatin1Char with _L1/u'' where applicable
As a drive-by, did also minor refactorings/improvements.

Task-number: QTBUG-98434
Change-Id: I81964176ae2f07ea63674c96f47f9c6aa046854f
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Reviewed-by: Anton Kudryavtsev <antkudr@mail.ru>
2022-03-25 19:16:29 +01:00
Edward Welbourne 460d7c8780 Avoid overflow in some more qdatetime.cpp functions
One multiplied TIME_T_MAX * MSECS_PER_SEC despite knowing this to be
too close for comfort to the bounds of qint64; but the comment
indicated it should have been using a 32-bit signed max in place of
TIME_T_MAX. Two others simply neglected to check for overflow.

Also use QRoundingDown::qMod() in one place to avoid needlessly
complicating arithmetic; and assert, in another, that we were never in
danger of overflowing anyway (thanks to an earlier isValid() check).
Restructured QDateTimePrivate::zoneMSecsToEpochMSecs() in the process
of catching its potential overflow.

Change-Id: I429321d90246ba922cccf09a4f028f03a514cb6b
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
2022-03-25 17:04:37 +01:00
Marc Mutz 4167a920ed QDateTime: enable larger ShortData for bootstrapped build
Ensures we get a modicum of testing of the Qt7 32-bit code in.

Change-Id: I0838e4340265e19ab2b17a1a91a11ef5f9948893
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
2022-03-23 13:46:33 +00:00
Marc Mutz 9f8da21239 QDateTime: future-proof swap()
In Qt 7 32-bit builds, the ShortData will be larger than the
d-pointer.

So don't swap() the d-pointer, but a) delegate to Data to swap itself
and b) swap the ShortData there, adding a static_assert in the .cpp
file that triggers when the assumption that ShortData is always at
least as large as a pointer is violated.

Found while porting away from overly-generic qSwap(), so done that,
too.

Task-number: QTBUG-97601
Pick-to: 6.3 6.2
Change-Id: I5139da58d99e9491a582ff2cb2f817cd96952044
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
2022-03-17 06:14:58 +00:00
Edward Welbourne 795c94658d Expand testing of QDateTime's isNull() and isValid()
Bring out the asymmetry between date and time more clearly; when date
is valid, an invalid time is ignored in favor of QTime(0, 0). At the
same time, eliminate an un-needed variable from the code that
implements this special handling. (Left over from when the QTime was
passed by const ref, rather than by value.)

Change-Id: I81d8a9026cbb7887a8c638a2761b3db54c088af7
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
2022-02-18 17:44:53 +01:00
Edward Welbourne 5d228beb52 Fix an assertion failure in massageAdjustedDateTime()
The QDateTimeData &d it's passed is a copy that's about to be
modified; before we do so, we haven't detached so its internals have a
ref-count of two, contradicting an assertion in the non-const
Data::operator->(); so just directly access d.d->m_timezone, since we
know that spec == TimeZone implies !isShort().
Added test that triggered the assertion and now doesn't.

Fixes: QTBUG-99668
Pick-to: 6.3 6.2 6.2.3 5.15
Change-Id: I07321ad91be5adce524be18e4ab82eee7110dc6a
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
2022-01-13 19:47:22 +01:00
Marc Mutz c47c98ea2b QDateTime: fix UB (signed overflow) in addDays()
The comment indicated that the author expected any overflow to be
caught by a bounds check in the subsequent function, however, signed
overflow is UB, so anything can happen.

Fix by using our API for safe additions instead.

Pick-to: 6.3 6.2 5.15
Change-Id: I41909defffa5305b02fdfcf6d5808e0d9fd5924f
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
2021-12-21 20:36:46 +01:00
Edward Welbourne 2bf5a60bfa Remove some spurious prefixes in declarations
The parameter-list of a method is already in its class's context, so
doesn't need it made explicit on the other class members involved.

Change-Id: I253b098ad1f2d2db80d49d8f484b7f95d14acec1
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Reviewed-by: Andrei Golubev <andrei.golubev@qt.io>
2021-11-18 18:13:20 +01:00
Venugopal Shivashankar b50ee930c7 Doc: Fix qdoc warnings
src/corelib/kernel/qmetatype.cpp:1605: (qdoc) warning: Command '\snippet (//! [[implicit]])' failed at end of file 'qmetatyp>
src/corelib/kernel/qmetatype.cpp:1615: (qdoc) warning: Command '\snippet (//! [[member]])' failed at end of file 'qmetatype/>
src/corelib/kernel/qmetatype.cpp:1626: (qdoc) warning: Command '\snippet (//! [[memberOk]])' failed at end of file 'qmetatyp>
src/corelib/kernel/qmetatype.cpp:1639: (qdoc) warning: Command '\snippet (//! [[unaryfunc]])' failed at end of file 'qmetaty>
src/corelib/text/qbytearraymatcher.cpp:233: (qdoc) warning: No such parameter 'view' in QByteArrayMatcher::indexIn()
src/corelib/time/qdatetime.cpp:1854: (qdoc) warning: Can't link to 'QLocaleie:pmText()'
src/corelib/thread/qsemaphore.cpp:494: (qdoc) warning: Undocumented return value (hint: use 'return' or 'returns' in the text
src/corelib/thread/qsemaphore.cpp:505: (qdoc) warning: Undocumented parameter 'timeout' in QSemaphore::try_acquire_for()
src/corelib/thread/qsemaphore.cpp:505: (qdoc) warning: Undocumented return value (hint: use 'return' or 'returns' in the text
src/corelib/thread/qsemaphore.cpp:516: (qdoc) warning: Undocumented parameter 'tp' in QSemaphore::try_acquire_until()
src/corelib/thread/qsemaphore.cpp:516: (qdoc) warning: Undocumented return value (hint: use 'return' or 'returns' in the text

Change-Id: Ib612c69525ec7542f2ad3dd9a07e89f266718fd8
Reviewed-by: Topi Reiniö <topi.reinio@qt.io>
2021-10-23 03:08:58 +02:00
Mårten Nordheim c58a3a4aae QDateTime: Limit string processing to known boundaries
We were treating the input as if it was always reasonably good.
Since we know the max boundaries anyway lets just stop processing
when those are reached

Fixes: QTBUG-97489
Change-Id: Ibb78d6d51ad58454b2007ab46d54116ca0be5448
Reviewed-by: Robert Löhning <robert.loehning@qt.io>
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
2021-10-20 15:16:53 +00:00
Jonas Kvinge 18e1711f7a corelib: Fix typos in documentation
Pick-to: 5.15 6.2
Change-Id: I64d63af708bc6ddaabd12450eb3089e5077f849e
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
2021-10-12 12:52:02 +02:00
Edward Welbourne 04419c2852 Set tm_isdst = -1 before calling mktime()
Leaving it set to 0 will cause mktime() to interpret other fields as
in standard time, potentially "correcting" them and tm_isdst to
represent the equivalent moment in daylight-saving time. Set it to -1
to tell mktime() to let the system work out whether the time is
standard or daylight-saving.

Change-Id: Id33d4cb0afdb14f236ca5ce04cf605610a30d712
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
2021-10-11 16:01:56 +02:00
Edward Welbourne 299f016b5d Broaden condition on use of MS's localtime_s()
It's available on MinGW, so not limited to MSVC; and the MinGW
localtime() and localtime_r() fail in some cases where it works.

Use the generic name rather than _localtime64_s(), since localtime_s()
now just calls it; and, in any case, we were assuming time_t is
__time64_t when calling it.

Change-Id: I316cc5b1a3e19cd6725555042dfaba3124a25a03
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
2021-10-11 16:01:56 +02:00
Edward Welbourne 3a8c8e7cf6 Remove an overly-complex assertion
It tried to sanity-check the correction being made to the time as a
result of converting zone to UTC, but handling also the case where the
correction avoided a gap. However, there are too many quirky cases to
permit a simple condition. The latest to trip it up is a case of a
zone leaving local solar mean time; a time in the gap that hits is
shunted by the width of the gap, which could be any old thing, and
won't show up on the data describing the zone before or after the
transition.

In any case, one branch of the check was doubling the zone's standard
time offset, which makes no sense. As that was checking for
double-DST, it would need to check standard offset plus twice the
usual DST offset; but the data it's looking at probably has its DST
offset set to the doubled one that needs to deal with. In general a
change in DST without going via standard time will have problems here,
and a change to standard time could also present problems.

Stop trying to shore up the assert and just trust the offset we got.

Change-Id: I4519f47e79dfb7595f4a12c259b80a338bc7033c
Reviewed-by: Andreas Buhr <andreas.buhr@qt.io>
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
2021-10-04 16:03:36 +02:00
Thiago Macieira 684c9b82b9 QDateTime: fix build with MinGW: need unistd.h very early
qobject.h has #include <chrono>, which #includes <ctime>, which includes
<time.h>.

datetime.cpp:2621:23: error: 'localtime_r' was not declared in this scope; did you mean 'localtime_s'?

Pick-to: 6.2
Change-Id: I2bbf422288924c198645fffd16a922719c4ce7d4
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
2021-09-29 13:18:21 -07:00
Edward Welbourne 4641ff0f6a Add new am/pm format-specifier that preserves locale's case
The existing a, ap, A and AP specifiers all force the case of the
formatted am/pm indicator. The indicators returned by QLocale's
amText() and pmText() methods are those given in CLDR, with no case
coercion. Application writers may reasonably want these strings used
verbatim, rather than having to chose a case and impose it on the
locale's indicators, in defiance of national custom. For example,
while en_US uses upper-case indicators by default, cs_CZ uses
lower-case ones. An application author writing a time format has been
forced to chose which of these locales to be wrong in.

Add support for aP and Ap specifiers, whose mixed case indicates that
the locale's case is to be respected. Amend an existing test-case of
tst_QLocale's formatDateTime() that used Ap (expecting, of course, an
upper-case indicator followed by a stray p) to now expect the
locale-appropriate-cased indicator. Extend formatTime() to test cases
using aP and Ap, to illustrate the difference between en_US and cs_CZ.

Rework QDateTimeParser to also support the new format specifier. This
required expanding its Case enum, used by the getAmPmText() method,
which was formerly shared with QDateTimeEditPrivate; however, as that
class no longer makes any reference to this method, it and the enum
can be made private, allowing a systematic clean-up of their use.
Added test-cases for both serialization and parsing; and amended some
existing parsing tests to verify am/pm indicators are matched
case-insensitively.

[ChangeLog][QtCore][Important Behavior Changes] Time formats used by
QLocale, QTime and QDateTime's parsing and serialization now recognize
'aP' and 'Ap' format specifiers to obtain an AM/PM indicator, using
the locale-appropriate case for the indicator, where previously the
author of a time format had to pick a case that might conflict with
the user's locale. For QTime and QDateTime the locale is always C,
whose indicators are uppercase. For QLocale, the case will now match
that of amText() or pmText(). Previously, 'aP' would have been read as
a lower-case indicator followed by a 'P' and 'Ap' as an upper-case
indicator followed by a 'p'. The 'P' or 'p' will now be treated as
part of the format specifier: if the prior behavior is desired, either
use 'APp' or 'apP' as format specifier or quote the 'p' or 'P' in the
format. The prior 'a', 'ap', 'A' and 'AP' specifiers are otherwise
unaffected.

Fixes: QTBUG-95790
Change-Id: I26603f70f068e132b5c6aa63214ac8c1774ec913
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Reviewed-by: Andrei Golubev <andrei.golubev@qt.io>
2021-09-08 20:28:40 +02:00
Lorn Potter a4a13949a8 wasm: fix assert in QDateTime
like windows, we dont have historical time data

Change-Id: Iab77c1e2949bc909324f18209e6c52324c80a548
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
2021-08-19 16:13:54 +00:00
Marc Mutz 96810e3863 QDateTime: port to QStringTokenizer and QVLA
The code isn't easily linearized to work directly with
QStringTokenizer, which is a forward-only range, but we can at least
remove the (non-error) memory allocations by supplying a
suitably-sized QVLA to tokenize into instead of the default QList.

Change-Id: I1aa11a5fbbe66ede4ec2e5b2090044a39052a241
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
2021-08-18 22:31:17 +02:00
Marc Mutz 0756b6a719 QDateTime: port away from takeFirst() use
Use the std-compatible API subset instead.

This is in preparation of using QVarLengthArray instead of QList here,
which (thankfully, because it's inefficient for arbitray T) doesn't
have pop_front().

As a drive-by, port at(0) to front() and introduce a temporary
variable. The front() call will briefly emit a detach attempt (but the
container isn't shared, so it won't actually detach), but only until
the next patch ports to QVLA.

Change-Id: I38ee123aa6730aee5ba1e14ec46fc71c5d74986e
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
2021-08-16 19:26:29 +02:00
Edward Welbourne 9159ce0373 Remove some now-redundant casts to qint64
One was long redundant. The other two, relatively recently added,
should be redundant thanks to the former enum member MSECS_PER_DAY
being changed to a constexpr qint64 by
commit 4059af81d3

Change-Id: I601ed8dae905fed6399ce29c25545ec651e9838a
Reviewed-by: Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Eirik Aavitsland <eirik.aavitsland@qt.io>
Reviewed-by: Andrei Golubev <andrei.golubev@qt.io>
2021-07-22 17:08:43 +02:00
Edward Welbourne 1f4b237dad Use year with same day-of-week pattern as fallback for out-of-range
The kludge previously implemented for handling dates outside the
supported time_t range, by asking for a corresponding date in a year
in the range, had a comment remarking that this is broken due to the
wrong day of the week and, consequently, the placement of DST
transitions, e.g. those scheduled by the last Sunday of a month,
happening on different dates in the year asked about and the in-range
year passed to the system time_t functions.

This can be handled by selecting a year in the time_t range which has
the same pattern days of the week (and length of the year, i.e
leap-ness). That may (particularly for leap years) need to select a
year far from the end of the range (and there may be a change to the
zone's rules between the selected year and the end).

Change-Id: Ia353b2cc7b7d266b7abf80e37cac61544ce95c2d
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
2021-06-16 15:53:23 +02:00
Edward Welbourne 76c8a988d2 Rework massageAdjusted and make the most of its DST knowledge
Since massageAdjustedDateTime() has to split LocalTime from TimeZone
and call {local,zone}MSecsToEpochMSecs() in any case, its call to
refreshZonedDateTime(), via checkValidDateTime(), was duplicating that
work uselessly. So handle UTC and offset-from-UTC separately with a
call to refreshSimple and handle local/zone time by inlining what
remains of refreshZonedDateTime() aside from the duplication.

At the same time, recent reworking of qt_mktime() make
localMSecsToEpochMSecs() handle its DST-hint the same way
zoneMSecsToEpochMSecs() has long done so, to take care of the intended
handling of DST gaps and repeats.

Change-Id: Id6bef7dd0f8983c3e923f4580a62a76aa6fcb810
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Reviewed-by: Andrei Golubev <andrei.golubev@qt.io>
2021-06-14 15:01:52 +02:00
Giuseppe D'Angelo 4059af81d3 Stop using mixed enum arithmetic
It's deprecated. Port some unnamed enumerations (used only to
declare constants) to constexpr integers instead. Apply qToUnderlying
as needed.

Task-number: QTBUG-94059
Change-Id: Ifaa64ece966ce08df40dc71ffcfa7ac038110e0b
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
2021-06-13 15:05:32 +02:00
Edward Welbourne 063b421251 Correct handling of last second of 1969 (again)
In my prior attempt to handle the last second of 1969, I forgot that
the QTime we're describing is a local time, so whether *it* thinks
we're at the last second of the day is beside the point. Fortunately,
preceding second should get -2 as return if mktime()'s initial -1
actually meant the last second of 1969, so we can test via that, after
a cheap pre-test to save doing this too often (albeit we only even
attempt the check if mktime() returned -1 in any case).

Restructured qt_mktime() in the process to deal with the error case's
early return promptly instead of doing it in an else clause. Also
repackage the calls to mktime to isolate various quirks and simplify
the logic in qt_mktime(). This also prepares for setting tm_isdst as a
hint when we know when we came from, in massageAdjustedDateTime().

Refined one test, added two more test cases. These didn't fail before
this fix, but a judiciously-placed qDebug() in testing revealed that
localMSecsToEpochMSecs() resorted to its fall-back handling - as if
the date-time were outside the time_t range - due to qt_mktime()
failing, for these test-cases (and several others). This fix evades
that fall-back behavior; a judiciously-placed qDebug() shows none of
our test-cases now fail callMkTime().

Change-Id: I11aa5015191dc4a565c28482307f7bc341c207e7
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
2021-06-11 17:12:12 +02:00
Edward Welbourne 74eddd5bf0 Rework setMSecsSinceEpoch() to avoid local->UTC conversions
The function takes a UTC time, which it converts to local time when
needed, but its (two) calls to refresh a local time instance were
doing the (more expensive) reverse conversion, which we don't need
(because we knew UTC to start with) and, in this case, it can't land
on an invalid time, so we don't need to cope with that.

Change-Id: I49b42bfa9f6a5fde12810f5a0da9ff4466ca86a4
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Reviewed-by: Andrei Golubev <andrei.golubev@qt.io>
2021-06-11 17:12:11 +02:00
Edward Welbourne ad554707dc Simplify QDate::weekNumber()
Eliminate two local variables and don't even compute the year if we
don't need it.

Change-Id: If968c619750cead317641885a0fb9b9974954782
Reviewed-by: Andrei Golubev <andrei.golubev@qt.io>
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
2021-06-07 18:43:17 +02:00
Edward Welbourne 451500f8f8 Check for overflow in QDateTime::setMSecsSinceEpoch()
When adding an offset from UTC, arithmetic may overflow.  Likewise
when combining a date and time (that have been offset for UTC).  Also
check the return from epochMSecsToLocalTime(), as it can fail; and pay
attention to the status stored by setDateTime(), to notice when it
hits an overflow. Fixed some tests that only passed because we
neglected these checks. Extended a test to check we detect overflow in
a couple of cases close to the extremes.

Change-Id: I127a670302f94a07bb9b087b1b9c608b7c08785c
Reviewed-by: Andrei Golubev <andrei.golubev@qt.io>
Reviewed-by: Øystein Heskestad <oystein.heskestad@qt.io>
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
2021-05-26 18:00:01 +02:00
Edward Welbourne fc6629b6bb Harmonize zoneMSecsToEpochMSecs() and localMSecsToEpochMSecs()
Now that the latter calls the former in its fall-back, this saves that
call the need to follow up with determining DST and abbreviation. This
also lets refreshZonedDateTime() update its DST guess for timezones as
well as for local time.

Change-Id: I820b65c1d6db78619defe2af5e947cb98ae336f0
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
2021-05-26 18:00:01 +02:00
Edward Welbourne 35412acd88 Use time-zone transition data before 1970 as well as after
QDateTime has long followed a convention of ignoring what it knows
about time-zone transitions before the epoch. This produces unhelpful
artefacts (such as an ahistorical spring-forward skipping the first
hour of 1970 in Europe/London, which was in permanent DST at the time)
and complicates the code. It documented that DST transitions were
ignored, but in fact ignored all transitions prior to 1970 and simply
assumed that the current time-zone properties (half a century later)
applied to all times before 1970.

This appears to be based on the fact that the MS APIs using time_t all
limit their range to after 1970. Given that we have to resort to
"other means" to deal with times after the end of time_t, when it's
only 32-bit (and after year 3000, on MS systems), we have the means in
place to handle times outside the range supported by the system APIs,
so have no need to mimic this restriction. (Those means are not as
robust as we might want, but they are less bad than assuming that the
present zone properites were always in effect prior to 1970.) On
macOS, the time_t functions only reach back to the start of 1900; it
reaches to the end of its time_t range and Linux covers the whole
range. Given this variety, the range is now auto-detected the first
time it is needed (based on some quick and dirty heuristics).

Various CET-specific tests now need adjustments in tests of times
before the introduction of time-zones (when they are in fact on LMT,
not CET). The systemZone() test of QTimeZone can now restore its
pre-zone test cases. Various comments on tests needed updates.

[ChangeLog][QtCore][QDateTime] Available time-zone information is now
used to its full extent, where previously QDateTime used LocalTime's
current standard time for all dates before 1970. Where we have
time-zone information, it is considered reliable, so we use it.  This
changes the "best efforts" used for times outside the range supported
by the system APIs, in most cases giving less misleading results.

Fixes: QTBUG-80421
Change-Id: I7b1df7622dd9be244b0238ed9c08845fb5b32215
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
2021-05-26 18:00:01 +02:00
Edward Welbourne 55765898fe Initialize SYSTEMTIME to {} instead of memset()ing
Change-Id: Ic17b90d10d6b5b7f4610e904e18979fc1d658a0a
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
2021-05-25 22:55:14 +02:00
Giuseppe D'Angelo 0c7e653ffd QDateTime(Parser): code tidies
Fixup a bunch of QFlags usage that ended up triggering implicit
conversions. These conversions happen because QDateTime tries to save
some space and shove a QFlags value in a bitfield, so there's
no way around them; use explicit conversions instead.

In other places: fix QFlags->bool conversions by using testAnyFlag.

Change-Id: I50e8d92ed829b64ac46097c09e547e1c89cc2e35
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
2021-05-25 13:38:44 +02:00