Commit 9b93d2ec authored by Volker Krause's avatar Volker Krause
Browse files

Use both the geo coordinate and the country to determine the timezone

When running this for all train stations in our database this gets very
close to the expected timezones now, achieving 29789 matching results with
only 9 deviations (some of those are mistakes, some are in disputed areas
where the "correct" result isn't entirely obvious). Performance for
airports is slightly worse, as those are more spread out over the world,
and thus don't benefit as much from the fine-granular country structure
in Europe that helps a lot here.

There are some more ideas on how to further improve this, either way it
looks very promising as a generic replacement for the timezone information
in our static databases.
parent 9650bb4c
......@@ -66,4 +66,47 @@ KnowledgeDb::Tz KnowledgeDb::timezoneForCoordinate(float lat, float lon)
}
return (*std::prev(it)).tz;
}
static bool compareOffsetData(const QTimeZone::OffsetData &lhs, const QTimeZone::OffsetData &rhs)
{
return lhs.offsetFromUtc == rhs.offsetFromUtc
&& lhs.standardTimeOffset == rhs.standardTimeOffset
&& lhs.daylightTimeOffset == rhs.daylightTimeOffset
&& lhs.atUtc == rhs.atUtc
&& lhs.abbreviation == rhs.abbreviation;
}
static bool isEquivalentTimezone(const QTimeZone &lhs, const QTimeZone &rhs)
{
auto dt = QDateTime::currentDateTimeUtc();
if (lhs.offsetFromUtc(dt) != rhs.offsetFromUtc(dt) || lhs.hasTransitions() != rhs.hasTransitions()) {
return false;
}
for (int i = 0; i < 2 && dt.isValid(); ++i) {
const auto lhsOff = lhs.nextTransition(dt);
const auto rhsOff = rhs.nextTransition(dt);
if (!compareOffsetData(lhsOff, rhsOff)) {
return false;
}
dt = lhsOff.atUtc;
}
return true;
}
KnowledgeDb::Tz KnowledgeDb::timezoneForLocation(float lat, float lon, CountryId country)
{
const auto coordTz = timezoneForCoordinate(lat, lon);
const auto countryTz = timezoneForCountry(country);
if (coordTz == Tz::Undefined || coordTz == countryTz) {
return countryTz;
}
if (countryTz == Tz::Undefined) {
return coordTz;
}
// if both timezones are equivalent, the country-based one wins, otherwise we use the coordinate one
return isEquivalentTimezone(toQTimeZone(coordTz), toQTimeZone(countryTz)) ? countryTz : coordTz;
}
#endif
......@@ -45,6 +45,12 @@ namespace KnowledgeDb {
* The result can be @c Tz::Undefined if this cannot be clearly determined.
*/
KITINERARY_EXPORT Tz timezoneForCoordinate(float lat, float lon);
/** Returns the timezone for the given location consisting of coordinates and country.
* This combines the results of the two above individual queries
* to obtain better results close to borders.
*/
KITINERARY_EXPORT Tz timezoneForLocation(float lat, float lon, CountryId country);
#endif
}
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment