The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Geo::Location::TimeZoneFinder - Map geographic coordinates to time zone names

VERSION

version 1.001

SYNOPSIS

  use Geo::Location::TimeZoneFinder;

  my $finder = Geo::Location::TimeZoneFinder->new(
    file_base => 'combined-shapefile');
  my @time_zones = $finder->time_zones_at(lat => $lat, lon => $lon);

DESCRIPTION

A Perl module that maps geographic coordinates to time zone names, such as "Asia/Shanghai". The module uses database files that are published by the Timezone Boundary Builder project.

SUBROUTINES/METHODS

new

  my $finder = Geo::Location::TimeZoneFinder->new(
    file_base => 'combined-shapefile');

The "file_base" parameter is the base path name for your database files. The extensions .dbf and .shp will be added to the base path name.

Returns a new object. Dies on invalid parameters and file read errors.

time_zones_at

  my @time_zones =
    $finder->time_zones_at(latitude => $lat, longitude => $lon);
  my $time_zone = $finder->time_zones_at(lat => $lat, lon => $lon);

Returns the names of the time zones at the coordinates given by the named parameters "latitude" und "longitude". In scalar context, only one name is returned.

The parameters "latitude" und "longitude" can be abbreviated to "lat" and "lon". The latitude and longitude must be in the ranges -90 to 90 and -180 to 180, respectively.

Dies on invalid parameters and file read errors.

The time zone names correspond to the names in the IANA time zone database, which is used by most Unix systems.

There is usually one time zone in a location, but there are disputed areas with multiple time zones as well as locations on boundaries, such as the North Pole at latitude 90° and the International Date Line at longitude 180°.

time_zone_at

  my $time_zone = $finder->time_zone_at(lat => $lat, lon => $lon);

An alias for time_zones_at that always returns a single value.

index

  for my $shape (@{$finder->index}) {
    my ($x_min, $y_min, $x_max, $y_max) = @{$shape->{bounding_box}};
    my $file_offset = $shape->{file_offset};
    my $time_zone   = $shape->{time_zone};
  }

Returns the internal index that is used to look up boundaries in the shape file.

DIAGNOSTICS

The "file_base" parameter is mandatory

The constructor was called without a filename base.

The "latitude" parameter is mandatory

No "latitude" parameter was given.

The "longitude" parameter is mandatory

No "longitude" parameter was given.

The "latitude" parameter N is not a number between -90 and 90

The latitude must be a number between -90 and 90.

The "longitude" parameter N is not a number between -180 and 180

The longitude must be a number between -180 and 180.

Error opening "FILE"

A file cannot be opened.

Error reading "FILE"

A file cannot be read.

Cannot set file position to N in "FILE"

The position in a file cannot be set.

Expected N records, got M in "FILE"

The number of records does not match the information in the file's header or the number of records in another file.

CONFIGURATION AND ENVIRONMENT

None.

DEPENDENCIES

Requires the file timezones.shapefile.zip from https://github.com/evansiroky/timezone-boundary-builder. The zip archive must be extracted to a directory.

INCOMPATIBILITIES

None.

EXAMPLES

Most Unix systems accept time zone names in the environment variable TZ.

  use Geo::Location::TimeZoneFinder;

  my $finder = Geo::Location::TimeZoneFinder->new(
    file_base => 'combined-shapefile');

  my $tz   = $finder->time_zone_at(lat => 39.916, lon => 116.383);
  my @time = do { local $ENV{TZ} = ":$tz"; localtime };

Speed up repeated lookups by using a cache.

  use Geo::Location::TimeZoneFinder;
  use Mojo::Cache;

  my $cache  = Mojo::Cache->new;
  my $finder = Geo::Location::TimeZoneFinder->new(
    file_base => 'combined-shapefile');

  sub time_zone_at {
    my %args = @_;

    my $lat = $args{lat};
    my $lon = $args{lon};
    my $key = "$lat,$lon";
    my $tz  = $cache->get($key);
    if (!defined $tz) {
      $tz = $finder->time_zone_at(lat => $lat, lon => $lon);
      $cache->set($key, $tz);
    }
    return $tz;
  }

BUGS AND LIMITATIONS

This module uses the point-in-polygon algorithm described in [1], which is very accurate but "cannot solve the problem of instability that can result from the comparison operations of floating-point numbers".

[1] Jianqiang Hao, Jianzhi Sun, Yi Chen, Qiang Cai, and Li Tan. "Optimal Reliable Point-in-Polygon Test and Differential Coding Boolean Operations on Polygons". Symmetry, 10, 2018.

AUTHOR

Andreas Vögele <voegelas@cpan.org>

LICENSE AND COPYRIGHT

Copyright (C) 2023 Andreas Vögele

This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself.