summaryrefslogtreecommitdiffstats
path: root/src/corelib/time
diff options
context:
space:
mode:
authorEdward Welbourne <edward.welbourne@qt.io>2023-11-07 18:34:50 +0100
committerEdward Welbourne <edward.welbourne@qt.io>2023-12-08 11:40:37 +0100
commitd2f15d65c7f3c4cff1ae547789e15fc3a5da6212 (patch)
tree171b19882089f1d7ae954cb4ac5b8e0ec940f24b /src/corelib/time
parent4799516de902de21e63639717cd27070f107dc57 (diff)
Improve week-day-based resolution of two-digit year numbers
Where a date format only gives the last two digits of the year, along with month and day of month, the day of the week can help settle the question of which century to use. The date-time parser has used this for some time, rather crudely, but only considered centuries adjacent to the default (1900 through 1999). Refine that by using QCalendar's new matchCenturyToWeekday(). Simplify the account of parsing now that client code doesn't have to do this for itself. Task-number: QTBUG-46843 Change-Id: Id054cc87ec867a2498145932d721c3368210cba0 Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Diffstat (limited to 'src/corelib/time')
-rw-r--r--src/corelib/time/qdatetime.cpp27
-rw-r--r--src/corelib/time/qdatetimeparser.cpp17
2 files changed, 14 insertions, 30 deletions
diff --git a/src/corelib/time/qdatetime.cpp b/src/corelib/time/qdatetime.cpp
index 7790e9669a..51b19b1957 100644
--- a/src/corelib/time/qdatetime.cpp
+++ b/src/corelib/time/qdatetime.cpp
@@ -1731,14 +1731,10 @@ QDate QDate::fromString(QStringView string, Qt::DateFormat format)
default for \a baseYear, selecting a year from then to 1999. Passing 1976 as
\a baseYear will select a year from 1976 through 2075, for example. When the
format also includes month, day (of month) and day-of-week, these suffice to
- imply the century. Parsing all but the day of week and then using
- QCalendar::matchCenturyToWeekday() to combine that with the day of the week
- could disambiguate such a date, but runs the risk of turning a user error -
- that would otherwise be recognized by the invalid result of parsing - into a
- valid result in another century, that wasn't the user's intent. At present,
- the date parser only considers the century indicated by \a baseYear and the
- centuries immediately after and before it, to limit the scope for such
- mistakes. See \l {Date ambiguities} for further details,
+ imply the century. In such a case, a matching date is selected in the
+ nearest century to the one indicated by \a baseYear, prefering later over
+ earlier. See \l QCalendar::matchCenturyToWeekday() and \l {Date ambiguities}
+ for further details,
The following examples demonstrate the default values:
@@ -1774,15 +1770,12 @@ QDate QDate::fromString(QStringView string, Qt::DateFormat format)
Including a day of the week in the format can also resolve the century of a
date specified using only the last two digits of its year. Unfortunately,
when combined with a date in which the user (or other source of data) has
- mixed up two of the fields, this resolution could lead to finding a date
- which does match the format's reading but isn't the one intended by its
- author. This would be in a different century, which would in many cases at
- least make it possible to recognize there is a problem with the data. At
- present, date parsing considers the centuries after and before the one
- indicated by \a baseYear, which may fall foul of this problem. See the
- discussion above about using QCalendar::matchCenturyToWeekday() to extend
- that to a wider range of centuries, if that can safely be applied in your
- use-case.
+ mixed up two of the fields, this resolution can lead to finding a date which
+ does match the format's reading but isn't the one intended by its author.
+ Likewise, if the user simply gets the day of the week wrong, in an otherwise
+ correct date, this can lead a date in a different century. In each case,
+ finding a date in a different century can turn a wrongly-input date into a
+ wildly different one.
The best way to avoid date ambiguities is to use four-digit years and months
specified by name (whether full or abbreviated), ideally collected via user
diff --git a/src/corelib/time/qdatetimeparser.cpp b/src/corelib/time/qdatetimeparser.cpp
index 6837caaa8a..f50b3b0d3f 100644
--- a/src/corelib/time/qdatetimeparser.cpp
+++ b/src/corelib/time/qdatetimeparser.cpp
@@ -1120,20 +1120,11 @@ static QDate actualDate(QDateTimeParser::Sections known, const QCalendar &calend
if ((known & QDateTimeParser::YearSection) == 0) {
if (known & QDateTimeParser::YearSection2Digits) {
- /*
- Two-digit year and month are specified; choice of century can only
- fix this if diff is in one of {1, 2, 5} or {2, 4, 6}; but not if
- diff is in the other. It's also only reasonable to consider
- adjacent century, e.g. if year thinks it's 2012 and two-digit year
- is '97, it makes sense to consider 1997. If either adjacent
- century does work, the other won't.
- */
- actual = QDate(year + 100, month, day, calendar);
- if (calendar.dayOfWeek(actual) == dayofweek)
- return actual;
- actual = QDate(year - 100, month, day, calendar);
- if (calendar.dayOfWeek(actual) == dayofweek)
+ actual = calendar.matchCenturyToWeekday({year, month, day}, dayofweek);
+ if (actual.isValid()) {
+ Q_ASSERT(calendar.dayOfWeek(actual) == dayofweek);
return actual;
+ }
} else {
// Offset by 7 is usually enough, but rare cases may need more:
for (int y = 1; y < 12; y++) {