#
# Copyright (c) 2014-2021 National Technology and Engineering
# Solutions of Sandia, LLC. Under the terms of Contract DE-NA0003525
# with National Technology and Engineering Solutions of Sandia, LLC,
# the U.S. Government retains certain rights in this software.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from __future__ import print_function, division, absolute_import
import logging
import os.path
import pytz
import shapefile
from shapely.geometry.polygon import Polygon
from shapely.geometry import Point, MultiPolygon
from six.moves import range
TIMEZONE_BOUNDARIES = None
TIMEZONE_STRUCTS = dict()
[docs]def load_timezone_shapefile():
"""Load in the timezone shapefile and extract the timezone boundaries.
Returns:
No return value.
"""
raise NotImplementedError("load_timezone_shapefile needs a shapefile reader!")
global TIMEZONE_BOUNDARIES
logger = logging.getLogger(__name__)
full_path = os.path.join(os.path.dirname(__file__), 'data', 'tz_world')
logger.debug('Loading timezone shapefile from {}'.format(full_path))
reader = shapefile.Reader(full_path)
timezone_names = [ record[0] for record in reader.records() ]
shapes = reader.shapes()
split_names = [ tz.split('/') for tz in timezone_names ]
names_and_zones = zip(shapes, split_names)
america_timezones = [thing for thing in names_and_zones if thing[1][0] == 'America']
canada_timezones = [ thing for thing in names_and_zones if thing[1][0] == 'Canada' ]
all_other_timezones = [ thing for thing in names_and_zones if (thing[1][0] != 'Canada' and thing[1][0] != 'America') ]
sorted_timezones = america_timezones + canada_timezones + all_other_timezones
boundaries = []
logger.debug("Converting shapefile to polygons")
TIMEZONE_BOUNDARIES = []
for named_shape in sorted_timezones:
shape = named_shape[0]
name_list = named_shape[1]
joined_name = '/'.join(name_list)
polygons = []
num_polys = len(shape.parts)
for i in range(num_polys):
poly_start = shape.parts[i]
poly_end = shape.parts[i+1] if (i+1) < num_polys else -1
poly_points = shape.points[poly_start:poly_end]
next_polygon = Polygon(poly_points)
polygons.append(next_polygon)
TIMEZONE_BOUNDARIES.append((MultiPolygon(polygons), joined_name))
# ----------------------------------------------------------------------
[docs]def find_containing_timezone(longitude, latitude):
"""Returns a timezone that contains the given long-lat.
Arguments:
longitude (float): Longitude of location to find timezone
latitude (float): Latitude of location to find timezone
Returns:
Timezone or None if no timezone is found.
"""
global TIMEZONE_BOUNDARIES, TIMEZONE_STRUCTS
if not TIMEZONE_BOUNDARIES:
load_timezone_shapefile()
assert TIMEZONE_BOUNDARIES
lonlat_point = Point(longitude, latitude)
for (boundary, name) in TIMEZONE_BOUNDARIES:
if boundary.contains(lonlat_point):
if name in TIMEZONE_STRUCTS:
return TIMEZONE_STRUCTS[name]
else:
TIMEZONE_STRUCTS[name] = pytz.timezone(name)
return TIMEZONE_STRUCTS[name]
return None
# ----------------------------------------------------------------------
[docs]def print_file():
"""Print the filename name.
Returns:
No return value.
"""
print("__file__: %s" % __file__)
[docs]def retrieve_file():
"""Return the given input file.
Returns:
``__file__``.
"""
return __file__
[docs]def local_time_for_position(position):
"""For a given .
Arguments:
position (Point): Point containing longitude and latitude values
Returns:
Positions timezone or timestamp if no timezone is found.
"""
timezone = find_containing_timezone(position.longitude, position.latitude)
if timezone:
return position.timestamp.astimezone(timezone)
else:
return position.timestamp