summaryrefslogtreecommitdiffstats
path: root/tests/auto/corelib/time
Commit message (Collapse)AuthorAgeFilesLines
* Use SPDX license identifiersLucie Gérard2022-05-168-219/+19
| | | | | | | | | | | | | 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>
* Replace remaining uses of deprecated _qs with _sSona Kurazyan2022-05-021-2/+4
| | | | | | Task-number: QTBUG-101408 Change-Id: I1fda67c07e948af5017f0b99b67f8c20d7052033 Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
* QDate(Time): add a addDuration methodGiuseppe D'Angelo2022-04-142-14/+27
| | | | | | | | | | | | | | | | 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>
* QDateTime: add conversions for time_point and zoned_timeGiuseppe D'Angelo2022-04-131-0/+227
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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>
* QDate: add conversions for std::chrono calendaring classesGiuseppe D'Angelo2022-04-131-0/+39
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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>
* QDateTime: add support for std::chrono::duration arithmeticGiuseppe D'Angelo2022-04-131-1/+20
| | | | | | | | | | | | | | | | | | | 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>
* QTimeZone: add construction from std::chrono::time_zone*Giuseppe D'Angelo2022-04-121-0/+48
| | | | | | | | | | | A time_zone represents a timezone identified by its IANA ID. This allows for a straightforward conversion to QTimeZone. [ChangeLog][QtCore][QTimeZone] QTimeZone can now be constructed from a std::chrono::time_zone pointer. Change-Id: I093d9fc2e989475d30730a9dcdef491903a2aeb2 Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
* Android: use BCP 47 tag to create a correct Locale for QTimeZone::displayName()Ivan Solovev2022-04-081-0/+52
| | | | | | | | | | | | | | | | | | Before the patch we tried to create a java Locale object by passing the human-readable language, territory and variant strings. However, the Locale constructor accepts ISO-defined codes. Fix it by using a factory method Locale.forLanguageTag() [0] that constructs a Java Locale object based on BCP 47 tag. [0]: https://developer.android.com/reference/java/util/Locale#forLanguageTag(java.lang.String) Fixes: QTBUG-101460 Pick-to: 6.3 6.2 5.15 Change-Id: If414c66cf0e5b7e8299ffc3a6038b6f9eb79d5ec Reviewed-by: Edward Welbourne <edward.welbourne@qt.io> Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Assam Boudjelthia <assam.boudjelthia@qt.io>
* Add a test and remove a work-around for a fixed bugEdward Welbourne2022-03-291-4/+5
| | | | | | | | | | | | The ASN.1 parser for a date-time had to check the date-time string was all digits to catch the case of a sign in the month field, which used to be accepted when it should not be. That bug has now been fixed, so remove the work-around and add a second date-time test-case, renaming (and modernising) the existing one for consistency. Task-number: QTBUG-84349 Change-Id: I649c5129312b6865af08b22ba6893cb4e29243f8 Reviewed-by: Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
* Include zone name on tst_QTimeZone::isTimeZoneIdAvailable() failureEdward Welbourne2022-03-251-1/+1
| | | | | | | | | The zone name was reported if isValid() failed, but not if isTimeZoneIdAvailable(), where it also proved useful in uncovering ICU's use of over-long zone name components. Change-Id: I4b3b65b1a4a338b638c01fc7ad47294118ee0efc Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
* Apply the East-Saskatchewan exception to zone-fragment lengths to ICUEdward Welbourne2022-03-251-2/+2
| | | | | | | | | | | | The exception was previously limited to Android, but I now find that ICU has the same over-long names; it seems likely that's where Android gets them. Also update the link to the theory page from the TZ DB, as it now has an official home on www.iana.org. Task-number: QTBUG-99747 Pick-to: 6.3 6.2 Change-Id: I9af67426d15609dfaf5f335405ceb1218fcf40ff Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
* Tests: Do not depend on transitive includesFabian Kosmale2022-03-171-0/+1
| | | | | Change-Id: Ibc6a948480a904913a5427e6408d4d296784fb4f Reviewed-by: Sona Kurazyan <sona.kurazyan@qt.io>
* QDateTime: future-proof swap()Marc Mutz2022-03-171-0/+13
| | | | | | | | | | | | | | | | | | 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>
* Add tests for an assertion seen on WindowsEdward Welbourne2022-03-041-1/+12
| | | | | | | | | | | QDateTimeEdit's default constructor instantiates the start of 1752-09-14 as its default earliest time; however Friedeman has seen this triggering an assertion. The QDTE tests should be picking that up anyway, but let's overtly test it in QDate's startOfDay testing, too. Change-Id: Ifae87f2695ac3a7993c173a7c21809c87d5daa71 Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io> Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
* Expand testing of QDateTime's isNull() and isValid()Edward Welbourne2022-02-181-4/+25
| | | | | | | | | | | | 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>
* Tidy up tst_QTimeZone::specificTransition()Edward Welbourne2022-02-181-7/+8
| | | | | | | | | It can now use startOfDay()/endOfDay() for the end-points of its search range; and it should check transit is not empty before dereferencing transits.at(0). Change-Id: Ib1568f4d8d6ce301d601071bb58185be906c631a Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
* Exclude autotest for INTEGRITYTatiana Borisova2022-02-181-1/+1
| | | | | | | | | | - ICU is not supported by backend. System supports only a simple named UTC time zone implementation(see QUtcTimeZonePrivate) Task-number: QTBUG-99123 Pick-to: 6.2 6.3 Change-Id: I4a87fc3d5484d75d55890bf88d012955e5048a0b Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
* Convert a table iteration to use ranged-forEdward Welbourne2022-02-151-10/+6
| | | | | | | | | | | The loop used an int counter that was initialized from a size_t, provoking a warning from MSVC. Since the indexing is irrelevant in any case, use a ranged-for loop. Since the loop was formerly in decreasing index order, reverse the table being iterated so that entries remain in their prior order. Change-Id: I79b93c5a3f39a502b0cae83215b8e3665d0e17f5 Reviewed-by: Marc Mutz <marc.mutz@qt.io>
* Fix an inaccurate comment and update a test caseEdward Welbourne2022-02-091-2/+2
| | | | | | | | | | | | | The offset fields for tst_QTimeZone::specificTransition() had a comment claiming they are in minutes; they are in fact in seconds, so fix that. At the same time, Moscow hasn't had a time-zone change since 2017, so the end-date for one of the test intervals can be nudged a little closer to the present without harm. Change-Id: I66822cb758f7e00d6added801466a6745be3e31a Reviewed-by: Marc Mutz <marc.mutz@qt.io> Reviewed-by: Thiago Macieira <thiago.macieira@intel.com> Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
* Add some more QDate::{start,end}OfDay() testsEdward Welbourne2022-02-021-0/+12
| | | | | | | | | | | | | | | | | | | | | While investigating an assertion failure I noticed that the existing tests didn't even exercise these methods for local time or zone time. Of course, we can't robustly test these time-specs, due to vagueries of offset details and zone availability, but we can at least verify that they return date-times on the specified date. Add a test-case for the start of 1900, on which the assertions were first seen; it is the earliest moment representable with tm_year >= 0, after all. One of these tests fails on 6.2 but the fix for that (as opposed to the the assertion) requires 6.3's improvements to the handling of time_t's fuller range - too risky a change to pick back to 6.2. Pick-to: 6.3 Task-number: QTBUG-99747 Change-Id: I98f5d7850a701972b2d8ea2ce203a2b3e7071354 Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Marc Mutz <marc.mutz@qt.io> Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
* Use Q_INT64_C() to express qint64 constantsEdward Welbourne2022-01-211-3/+3
| | | | | | | | | | | When int is 32-bit, 0x80000000L is int-min, and (consequently) negating it makes no difference, so MSVC warns about this. Instead of using an L suffix, wrap the constant in Q_INT64_C(). Do the same for similar large constants in the same block. Pick-to: 6.2 6.3 Change-Id: Ib371b932792f170ab7db2e472a4283df3a205af3 Reviewed-by: Marc Mutz <marc.mutz@qt.io>
* Fix an assertion failure in massageAdjustedDateTime()Edward Welbourne2022-01-131-0/+12
| | | | | | | | | | | | | | 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>
* Skip QTimeZone::checkOffset() if there are no valid zones to testEdward Welbourne2021-11-261-0/+4
| | | | | Change-Id: I62df34fe40b8e89b99912e8ad0d1d2f2f11fd71e Reviewed-by: Andrei Golubev <andrei.golubev@qt.io>
* Check for relevant zones existing when adding data rowsEdward Welbourne2021-11-261-12/+22
| | | | | | | | | tst_QDate::startOfDay_endOfDay_data() naively assumed some zones would exist. They don't on QNX, apparently. Change-Id: I3a364964d03f59f5869b4b7639f089dd303180b1 Reviewed-by: Andreas Buhr <andreas.buhr@qt.io> Reviewed-by: Andrei Golubev <andrei.golubev@qt.io>
* Add a note to save the next reader some confusionEdward Welbourne2021-11-261-0/+4
| | | | | | | | I was briefly confused about why an Etc/GMT+3 test was using GMT as localtime. Fortunately I worked it out before mis-"correcting" it. Change-Id: I7b0473c7d3974ef186e1170cf4999aca52aaaf45 Reviewed-by: Andreas Buhr <andreas.buhr@qt.io>
* Skip test if it has no data-rowsEdward Welbourne2021-11-261-0/+7
| | | | | | | | | | On QNX, tst_QDateTime::fromStringStringFormat_localTimeZone_data() failed to set up any rows for the data-driven tests to fetch, leading to an assertion failure on trying to fetch a row. Change-Id: I7c405b1142a8cb6d445b501ea44fe3d440570cf3 Reviewed-by: Andreas Buhr <andreas.buhr@qt.io> Reviewed-by: Andrei Golubev <andrei.golubev@qt.io>
* Revise (recently-added) yearSharingWeekDays() to take a QDateEdward Welbourne2021-11-152-0/+50
| | | | | | | | | | This lets it avoid a two-digit year that would clash with month or day. That shall make fixing up system locale date formatting run cleaner. Add a test for QGregorianCalendar's two extensions. Change-Id: I77083ff9d5e4035763250904a59fcf416286545b Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
* Use a local check-macro to save lots of repetition in time-zone testsEdward Welbourne2021-11-101-90/+53
| | | | | | | | | | Tests of QTimeZone::dispayName() were burying most of what was interesting in the variations among them by repetition of a large amount of boilerplate. Package the repetition in a macro so that the differences between checks are more evident. Change-Id: I23bcafab641b7d3bed50248ba5313250c150d30c Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
* Correct and clarify some commentsEdward Welbourne2021-11-081-3/+3
| | | | | Change-Id: I011b04cf0dccea51c00c597c8dff74d574fe36ad Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
* Express 64-bit integral constants consistentlyEdward Welbourne2021-11-081-6/+7
| | | | | | | | Use the Q_INT64_C() macro and qint64()-as-function instead of C-style casts. Change-Id: I9d169715da96a49898e9c9e2a6d3ee5182e1d91c Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
* Give symbolic names to some constants used in time-zone testsEdward Welbourne2021-11-081-12/+15
| | | | | | | | | | Where std::numeric_limits<...>::min() is used used as invalid value for an API return, save it as a named constant so that the comparisons are against an informative name, rather than leaving the reader to guess the significance of the min-value. Change-Id: Ia99c75e21856f65cb4494120d05eed36f5fc2d50 Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
* Fix handling of time-zone gap in QTimeZonePrivate::dataForLocalTime()Edward Welbourne2021-10-121-0/+12
| | | | | | | | | | | | | | | | | | | | | | | | | | This was handled correctly when the backend supplies transitions bracketing the time in question, but the fallback code tried to use the DST offset at the time with larger offset from UTC; this did not work when the gap was due to a change in standard time. Discovered by ANS1 parsing of a date-time with two-digit year, for which the date-time parser tried to use 1921-05-01T00:00 local time when filling in the fields it had parsed; but, when run in Europe/Helsinki, there is no such time due to the 20m 11s skipped when joining EET from the prior local solar mean time. Correct the calculation to use the actual change in offset from UTC, as used in the (far better tested) between-transitions branch of the code, rather than the DST offset after the transition. Add a test-case based on the ASN.1 certificate date whose parsing revealed the issue. Although it seems nothing in Coin can reproduce the issue, the reporter has verified that the test does indeed fail on the system where the bug was found and the fix does fix it. Fixes: QTBUG-96861 Pick-to: 6.2 Change-Id: I12b02bad01daca2073d1a356452cd573684aa688 Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
* Fix QDateTimeParser's handling of 't' format to match serializationEdward Welbourne2021-09-201-1/+6
| | | | | | | | | | | | | | | | | | This amends commit 68f19fb630dc02463c2d61fc511de7407687795e to only consume one 't' from the format string, to match qlocale.cpp's serialization of time-zone specifiers, which only consumes one, so will repeat the time-zone specifier as many times as unquoted t appears in the format. It's hard to imagine why anyone would want this behavior, but it's what our serialization has always done and parsing should match serialization. Add test-cases for double time-zone specifier. Delete a lie in the process. Task-number: QTBUG-95966 Change-Id: I574896040a74085dee89a4fefd8384be44ad827b Reviewed-by: Andrei Golubev <andrei.golubev@qt.io> Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
* Remove conditioning on Android embeddedEdward Welbourne2021-09-171-2/+2
| | | | | | | | It is no longer handled separately from Android. This effectively reverts commit 6d50f746fe05a7008b63818e77784dd0c99270a1 Change-Id: Ic2d75b8c5a09895810913311ab2fe3355d4d2983 Reviewed-by: Assam Boudjelthia <assam.boudjelthia@qt.io>
* Add new am/pm format-specifier that preserves locale's caseEdward Welbourne2021-09-081-5/+12
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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>
* Fix and clean up utterly confused (and confusing) transition testsEdward Welbourne2021-06-151-201/+241
| | | | | | | | | | | | | | | | | | | | | | | Various QDateTime tests relating to transitions * used a nomenclature that made them confusing to thing about; and * expected identically-initiallized variables to behave differently. The latter, naturally, lead to "expected fail" tests. Rewrote the tests to get the date-times they want to test at by means that avoid the ambiguities inherent in QDateTime's lack of a way to distinguish the two passes through the repeated hour in a fall-back (QTBUG-79923) and added commented-out tests indicating what should be true once that ambiguity is resolved. Verified the DST status is as expected in the cases where that's the correct distinction between date-times with the same date and time. Renamed various things to (hopefully) make them more intelligible. In the process, purged some leading 0s from numbers in code. Fixes: QTBUG-68936 Change-Id: Id7a348995238b70dcb81a96edb8a3fa5315f86fa Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
* Correct handling of last second of 1969 (again)Edward Welbourne2021-06-111-3/+12
| | | | | | | | | | | | | | | | | | | | | | | | | | | | 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>
* Clean up tst_QDateTime's conditions on zoneIsCETEdward Welbourne2021-06-111-419/+414
| | | | | | | | | | | | | In setMSecsSinceEpoch(), the CET end-of-time is invalid anyway, so a whole block (rather than just one sub-test of it) was irrelevant for the max-qint64 test case (aside from verifying cet *is* invalid). Split out to a separate test the part of a data-driven test that was the same for all data rows. Reworked several ill-advised ways to use QSKIP(). Change-Id: If757d3e722c81fc42a87256125ceef605b6bfb64 Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
* Check for overflow in QDateTime::setMSecsSinceEpoch()Edward Welbourne2021-05-261-11/+30
| | | | | | | | | | | | | | | 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>
* Use time-zone transition data before 1970 as well as afterEdward Welbourne2021-05-262-47/+55
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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>
* Ensure setDateTime clears status also when shortEdward Welbourne2021-05-041-0/+7
| | | | | | | | | | | Previously, if multiplication overflowed when trying to set the date and time of a formerly short-form QDateTime, its status didn't get set to reflect the failed validity check. Added a test that now correctly detects that it's produced an invalid date-time on overflow, where previously it produced a wrong valid date-time. Change-Id: Id46ca34d1e32e9b9b0630f3723cefd1c13b5761e Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
* Revert early return from QTimeZone on invalid IDEdward Welbourne2021-04-291-1/+1
| | | | | | | | | | | | | | This reverts commit ec8808c3020abbc436f1a2d90fecf3245fd6417b but retains its test, as the problem it fixed is now solved by having the TZ backend validate the ID it's passed, so that it now only accepts valid POSIX zone-descriptions and valid IANA IDs. The former were being excluded by this check. Amended a POSIX test to fail with the check in place; it passes now. Change-Id: I0d5e8c6e0a315ac2509f3d23bebb52aede8f79d0 Reviewed-by: Thiago Macieira <thiago.macieira@intel.com> Reviewed-by: Robert Löhning <robert.loehning@qt.io>
* Check POSIX rules during QTzTimeZone creationEdward Welbourne2021-04-271-0/+1
| | | | | | | | | | | | | | | | | | | | | Previously, an apparent POSIX rule would be saved and any defects in it would only be discovered when trying to use it to generate transitions. Instead, check that it has the right form during the initial parsing of its data. In the process, since checking for DST in the process is trivial, implement a long-standing TODO to cache hasDaylightTime()'s answer. The array it scanned was in any case being scanned during construction, so detecting DST in init()'s scan is trivial; and its failure to check the POSIX rule mean it failed to notice when zones entirely specified by a POSIX rule have DST. Adapt a test using a POSIX-only rule to verify it does know the zone has DST; it did not, before this change. Change-Id: I690c013d3331600f7348dae61c35d41e5599da70 Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
* Fix handling of a POSIX zone rule describing permanent DSTEdward Welbourne2021-04-271-0/+6
| | | | | | | | | | | | | | | | | | | | | | | | | The description necessarily has fake transitions at start and end of the year, potentially outside the year. These transitions should not be reported by QTzTimeZonePrivate as transitions, although its data() must find a "transition" whose data it can use (as in the permanent standard time case, which could potentially be represented the same way, although there's a saner way to do so, that the code already handles) to report the zone's properties. In the process, fix (and make more straightforward) the convoluted decision-making code that was deciding which transitions to include in the returned list. It was assuming invalidMSecs() would be set as the atMSecsSinceEpoch of a transition, although this is computed in a way that makes that value most unlikely, even when the result is invalid. It also rather confusingly mixed < 0 tests as tests for overflow with the one < 0 test that's about ignoring DST before 1970. Also added comments to clarify some of what's going on there. Expanded a recently-added test of a permanent DST zone to verify this now works correctly. Change-Id: Ia8d98f433fb1e479dba5479220a62196c30f0244 Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
* Correct the parsing of POSIX rule day-of-year fieldsEdward Welbourne2021-04-271-0/+12
| | | | | | | | | | | | | | | | | There are two formats for such fields: one with a J prefix on a number in the range 1 to 365, the other with no prefix and a range from 0 to 365. The code mistakenly treated the latter as if its range were from 1 to 366. The J-form doesn't count Feb 29th, so March always starts on day 60; the code tried to take that into account, but adjusted in the wrong direction (and this mislead me, in a recent partial fix, into a fence-post error). Add a test-case based on the Africa/Casablanca POSIX rule seen on RHEL 8.2, which tripped over the off-by-one error without a J prefix. This incidentally also tests the J case. Change-Id: I692ca511e5c960f91a6c21073d3b2f037f5e445f Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
* Correct the range of allowed hours for a POSIX rule's transitionEdward Welbourne2021-04-201-1/+1
| | | | | | | | | | | | | | | | | | | | A POSIX rule's transition time is allowed an hour in the range from -137 to 137; in particular, a negative hour is allowed, and used by some Greenland zones using Europe's time-of-transition which, as they are more than two hours west of Greenwich, happens before midnight. This means the time of transition can't be represented by a QTime(), so propagate the int that represents it to the code that consumes it; and treat parsing failure as an error rather than "correcting" it - if the transition time is given, it must be valid. Changed tst_QTimeZone::isTimeZoneIdAvailable()'s verification of validity to report the name of the zone it thought was invalid. (A later change, validating POSIX rules, caued this to fail for America/Nuuk without the present fix.) Change-Id: I5c9127ac34d878554dd0aca1c1c7338c7e0e1c28 Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
* Return early from QTimeZone constructor if alleged IANA ID is invalidEdward Welbourne2021-04-201-0/+3
| | | | | | | | | | | | If the ID isn't even valid, don't waste cycles trying to make sense of it as identifying a time-zone. Add test of an invalid ID that provoked an integer overflow on trying to parse it as a POSIX zone specification. Fixes: QTBUG-92842 Change-Id: Ib80bbb88c11c0484ce0358acabbdc25c5bd8e0b3 Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
* Merge integration refs/builds/qtci/dev/1618564901Qt CI Bot2021-04-161-9/+5
|\
| * Extend time_t-based handling all the way to the end of time_tEdward Welbourne2021-04-161-9/+5
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | At least some modern 64-bit systems have widened time_t to 64 bits fixing the "Unix time" problem. (This is even the default on MS-Win, although the system functions artificially limit the accepted range to 1970 through 3000.) Even the 32-bit range extends into January 2038 but the code was artificially cutting this off at the end of 2037. This is a preparation for using the same also all the way back to the start of time_t. In the process, simplify and tidy up the logic of the existing code, update the docs (this includes correcting some misinformation) and revise some tests. Fixes: QTBUG-73225 Change-Id: Ib8001b5a982386c747eda3dea2b5a26eedd499ad Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
* | Catch invalid offset returns from QTimeZone backendsEdward Welbourne2021-04-161-2/+2
|/ | | | | | | | | | If the backends run into an error in computing the offset, they return INT_MIN; but they are valled via the front-end, which returns zero when the zone is invalid. So treat INT_MIN returns from the backend the same as the case of being invalid. Change-Id: Ic3c4dfe964dbfba4030c770213eca8a63e84736d Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>