summaryrefslogtreecommitdiffstats
path: root/src/corelib/time/qdatetime.cpp
diff options
context:
space:
mode:
authorEdward Welbourne <edward.welbourne@qt.io>2023-03-31 11:40:42 +0200
committerThiago Macieira <thiago.macieira@intel.com>2023-04-14 13:23:50 +0000
commit76075aa3a96c05afd2f6877af5b612adec325bb2 (patch)
treeeabd4b6dbe0d19bd71cb1e5ba0f8d57a1361c2e2 /src/corelib/time/qdatetime.cpp
parentb906796af62fb23e592625c7c86b31c98a08162b (diff)
QDate: enable {start,end}OfDay() to make second-adjustments
Previously it only got the answer correct to the minute. That's good enough for most transitions, but those involving local solar mean time (LMT) may have second deviations. So check the second before or after, that'll usually be the other side of the transition; if it isn't, do a further binary chop on seconds to hit the correct value. Most zones' canonical locations are only specified to the size of a city, so second precision is all anyone cares about; a few hundred metres difference in location would change that. The one exception is Europe/Amsterdam, which had its own Royal Observatory and time standard, hence had an offset known to greater precision; but the IANA DB duly approximates that, too, so we won't have data with millisecond precision even in that case, so don't try to refine beyond second. Change-Id: I20fb355f8113c32387ed8a84fbf5a41004273978 Reviewed-by: Thiago Macieira <thiago.macieira@intel.com> Reviewed-by: Konrad Kujawa <konrad.kujawa@qt.io>
Diffstat (limited to 'src/corelib/time/qdatetime.cpp')
-rw-r--r--src/corelib/time/qdatetime.cpp48
1 files changed, 42 insertions, 6 deletions
diff --git a/src/corelib/time/qdatetime.cpp b/src/corelib/time/qdatetime.cpp
index fdd2aa7793..d69101a0d1 100644
--- a/src/corelib/time/qdatetime.cpp
+++ b/src/corelib/time/qdatetime.cpp
@@ -864,8 +864,8 @@ static QDateTime toEarliest(QDate day, const QTimeZone &zone)
int low = 0;
// Binary chop to the right minute
while (high > low + 1) {
- int mid = (high + low) / 2;
- QDateTime probe = moment(QTime(mid / 60, mid % 60));
+ const int mid = (high + low) / 2;
+ const QDateTime probe = moment(QTime(mid / 60, mid % 60));
if (probe.isValid() && probe.date() == day) {
high = mid;
when = probe;
@@ -873,6 +873,24 @@ static QDateTime toEarliest(QDate day, const QTimeZone &zone)
low = mid;
}
}
+ // Transitions out of local solar mean time, and the few international
+ // date-line crossings before that (Alaska, Philippines), may have happened
+ // between minute boundaries. Don't try to fix milliseconds.
+ if (QDateTime p = moment(when.time().addSecs(-1)); Q_UNLIKELY(p.isValid() && p.date() == day)) {
+ high *= 60;
+ low *= 60;
+ while (high > low + 1) {
+ const int mid = (high + low) / 2;
+ const int min = mid / 60;
+ const QDateTime probe = moment(QTime(min / 60, min % 60, mid % 60));
+ if (probe.isValid() && probe.date() == day) {
+ high = mid;
+ when = probe;
+ } else {
+ low = mid;
+ }
+ }
+ }
return when.isValid() ? when : QDateTime();
}
@@ -910,7 +928,7 @@ QDateTime QDate::startOfDay(const QTimeZone &zone) const
return QDateTime();
QDateTime when(*this, QTime(0, 0), zone);
- if (when.isValid())
+ if (Q_LIKELY(when.isValid()))
return when;
#if QT_CONFIG(timezone)
@@ -995,8 +1013,8 @@ static QDateTime toLatest(QDate day, const QTimeZone &zone)
int low = when.time().msecsSinceStartOfDay() / 60000;
// Binary chop to the right minute
while (high > low + 1) {
- int mid = (high + low) / 2;
- QDateTime probe = moment(QTime(mid / 60, mid % 60, 59, 999));
+ const int mid = (high + low) / 2;
+ const QDateTime probe = moment(QTime(mid / 60, mid % 60, 59, 999));
if (probe.isValid() && probe.date() == day) {
low = mid;
when = probe;
@@ -1004,6 +1022,24 @@ static QDateTime toLatest(QDate day, const QTimeZone &zone)
high = mid;
}
}
+ // Transitions out of local solar mean time, and the few international
+ // date-line crossings before that (Alaska, Philippines), may have happened
+ // between minute boundaries. Don't try to fix milliseconds.
+ if (QDateTime p = moment(when.time().addSecs(1)); Q_UNLIKELY(p.isValid() && p.date() == day)) {
+ high *= 60;
+ low *= 60;
+ while (high > low + 1) {
+ const int mid = (high + low) / 2;
+ const int min = mid / 60;
+ const QDateTime probe = moment(QTime(min / 60, min % 60, mid % 60, 999));
+ if (probe.isValid() && probe.date() == day) {
+ low = mid;
+ when = probe;
+ } else {
+ high = mid;
+ }
+ }
+ }
return when.isValid() ? when : QDateTime();
}
@@ -1042,7 +1078,7 @@ QDateTime QDate::endOfDay(const QTimeZone &zone) const
return QDateTime();
QDateTime when(*this, QTime(23, 59, 59, 999), zone);
- if (when.isValid())
+ if (Q_LIKELY(when.isValid()))
return when;
#if QT_CONFIG(timezone)