PHP: Convert a Geolocation (Latitude / Longitude Coordinates) to a Timezone identifier

Part of a PHP project I’m working contains a list of sites/buildings. For each site/building we monitor some data, for example its energy usage.

We decided that we wanted to generate a daily/weekly/monthly reports of the data, by aggregating the datapoints. As our sites/buildings are spread across the globe – and thus timezones – we can’t simply select data between 00:00:00 UTC and 23:59:59 UTC but have to use its geographical location’s “day window” to do our calculations.

Unfortunately we don’t didn’t store the timezone for a site/building, but since we do keep track of its geographical location – using a WGS84 latitude-longitude pair – it should be possible to derive its timezone, right?

Right! On StackOverflow I found this little snippet that does the job:

function get_nearest_timezone($cur_lat, $cur_long, $country_code = '') {
    $timezone_ids = ($country_code) ? DateTimeZone::listIdentifiers(DateTimeZone::PER_COUNTRY, $country_code)
                                    : DateTimeZone::listIdentifiers();

    if($timezone_ids && is_array($timezone_ids) && isset($timezone_ids[0])) {

        $time_zone = '';
        $tz_distance = 0;

        //only one identifier?
        if (count($timezone_ids) == 1) {
            $time_zone = $timezone_ids[0];
        } else {

            foreach($timezone_ids as $timezone_id) {
                $timezone = new DateTimeZone($timezone_id);
                $location = $timezone->getLocation();
                $tz_lat   = $location['latitude'];
                $tz_long  = $location['longitude'];

                $theta    = $cur_long - $tz_long;
                $distance = (sin(deg2rad($cur_lat)) * sin(deg2rad($tz_lat))) 
                + (cos(deg2rad($cur_lat)) * cos(deg2rad($tz_lat)) * cos(deg2rad($theta)));
                $distance = acos($distance);
                $distance = abs(rad2deg($distance));
                // echo '<br />'.$timezone_id.' '.$distance; 

                if (!$time_zone || $tz_distance > $distance) {
                    $time_zone   = $timezone_id;
                    $tz_distance = $distance;
                } 

            }
        }
        return  $time_zone;
    }
    return 'unknown';
}

Usage is as follows:

// Timezone for one NY coordinate
echo get_nearest_timezone(40.772222,-74.164581);
// ~> America/New_York

// Timezone for one Belgian coordinate
echo get_nearest_timezone(51.0162167, 3.7338451);
// ~> Europe/Brussels

// More faster and accurate if you can pass the country code 
echo get_nearest_timezone(40.772222, -74.164581, 'US');
// ~> America/New_York

With this timezone identifier now being available, we can include it in our queries and generate our daily/weekly/monthly reports 🙂

🍻 Here’s to copying-and-pasting from StackOverflow!

On a related note: Falsehoods programmers believe about time and time zones is worth a read, especially if you’ve already dealt with time and timezones.

what3words – The addressing system to uniquely identify locations using just three words

what3words is a really simple way to talk about location. We have divided the world into a grid of 3m x 3m squares and assigned each one a unique 3 word address. It means anyone can accurately find any location and share it more quickly, easily and with less ambiguity than any other system.

The service can be used via the free mobile app or online map. It can also be built into any other app, platform or website, with just a few lines of code.

For example, the torch of the Statue of Liberty is located at toned.melt.ship. This combination is unique, no other location across the globe has it. Easier to remember than WGS84 coordinates, and still very precise.

what3words Online Map →
what3words Website →
what3words: toned.melt.ship