diff --git a/src/libcalamares/locale/Tests.cpp b/src/libcalamares/locale/Tests.cpp index 081d0ced5..e498ac039 100644 --- a/src/libcalamares/locale/Tests.cpp +++ b/src/libcalamares/locale/Tests.cpp @@ -395,8 +395,19 @@ LocaleTests::testLocationLookup() { const CalamaresUtils::Locale::ZonesModel zones; - QVERIFY( zones.find( 50.0, 0.0 ) ); - QCOMPARE( zones.find( 50.0, 0.0 )->zone(), QStringLiteral( "London" ) ); + const auto* zone = zones.find( 50.0, 0.0 ); + QVERIFY( zone ); + QCOMPARE( zone->zone(), QStringLiteral( "London" ) ); + + + // Tarawa is close to "the other side of the world" from London + zone = zones.find( 0.0, 179.0 ); + QVERIFY( zone ); + QCOMPARE( zone->zone(), QStringLiteral( "Tarawa" ) ); + + zone = zones.find( 0.0, -179.0 ); + QVERIFY( zone ); + QCOMPARE( zone->zone(), QStringLiteral( "Tarawa" ) ); } diff --git a/src/libcalamares/locale/TimeZone.cpp b/src/libcalamares/locale/TimeZone.cpp index 7143d7d33..364564232 100644 --- a/src/libcalamares/locale/TimeZone.cpp +++ b/src/libcalamares/locale/TimeZone.cpp @@ -327,7 +327,42 @@ ZonesModel::find( const QString& region, const QString& zone ) const const TimeZoneData* ZonesModel::find( double latitude, double longitude ) const { - return nullptr; + /* This is a somewhat derpy way of finding "closest", + * in that it considers one degree of separation + * either N/S or E/W equal to any other; this obviously + * falls apart at the poles. + */ + + double largestDifference = 720.0; + const TimeZoneData* closest = nullptr; + + for ( const auto* zone : m_private->m_zones ) + { + // Latitude doesn't wrap around: there is nothing north of 90 + double latitudeDifference = abs( zone->latitude() - latitude ); + + // Longitude **does** wrap around, so consider the case of -178 and 178 + // which differ by 4 degrees. + double westerly = qMin( zone->longitude(), longitude ); + double easterly = qMax( zone->longitude(), longitude ); + double longitudeDifference = 0.0; + if ( westerly < 0.0 && !( easterly < 0.0 ) ) + { + // Only if they're different signs can we have wrap-around. + longitudeDifference = qMin( abs( westerly - easterly ), abs( 360.0 + westerly - easterly ) ); + } + else + { + longitudeDifference = abs( westerly - easterly ); + } + + if ( latitudeDifference + longitudeDifference < largestDifference ) + { + largestDifference = latitudeDifference + longitudeDifference; + closest = zone; + } + } + return closest; } QObject*