Skip to content

Commit db11ae5

Browse files
committed
set timezone/dst from lat/long using timezonefinder
1 parent bee469f commit db11ae5

2 files changed

Lines changed: 97 additions & 0 deletions

File tree

pyzipcode/update_timezones.py

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
"""
2+
A script to update the timezone data in the zipcode CSV file
3+
============================================================
4+
5+
Reads the zipcode CSV file and updates the timezone/dst fields using
6+
the lat/long coordinates.
7+
8+
Requires pytz and timezonefinder
9+
10+
Example usage::
11+
12+
# Assumes the file ./zipcode.csv exists and contains zipcode data
13+
python update_timezones.py
14+
15+
"""
16+
17+
import csv
18+
import datetime
19+
import shutil
20+
import tempfile
21+
import sys
22+
from pathlib import Path
23+
24+
import pytz
25+
from timezonefinder import TimezoneFinder
26+
27+
try:
28+
from settings import db_location, csv_location
29+
except ImportError:
30+
from pyzipcode.settings import db_location, csv_location
31+
32+
DST_DATE = datetime.datetime(2021, 4, 1)
33+
34+
tf = TimezoneFinder()
35+
36+
37+
def coords_to_utcoffset_and_isdst(lng, lat):
38+
timezone_name = tf.timezone_at(lng=lng, lat=lat)
39+
40+
timezone = pytz.timezone(timezone_name)
41+
# TODO: will this work year-round?
42+
timezone_now = datetime.datetime.now(timezone)
43+
offset = timezone_now.utcoffset().total_seconds() / 60 / 60
44+
45+
dst = timezone.dst(DST_DATE).total_seconds() / 60 / 60
46+
47+
return offset, dst, timezone_name
48+
49+
50+
def run_update():
51+
"""Run the import code."""
52+
with open(csv_location, newline="", encoding="utf-8") as f:
53+
reader = csv.reader(f)
54+
header = next(reader)
55+
56+
new_rows = []
57+
for i, row in enumerate(reader, start=1):
58+
zip, city, state, lat, longt, timezone, dst = row
59+
longt, lat = float(longt), float(lat)
60+
timezone, dst = float(timezone), float(dst)
61+
62+
new_timezone, new_dst, tz_name = coords_to_utcoffset_and_isdst(longt, lat)
63+
if timezone != new_timezone or dst != new_dst:
64+
print(
65+
f"line {i: >5}: {zip}, {city: <26}, {state}, {lat}, {longt}\n"
66+
f"{timezone},{dst} != {new_timezone},{new_dst} ({tz_name})\n",
67+
file=sys.stderr,
68+
)
69+
70+
if new_timezone != int(new_timezone):
71+
raise ValueError("USA has fractional-hour timezones now")
72+
if new_dst not in [1, 0]:
73+
raise ValueError("expected dst to be either +1 or 0")
74+
75+
new_timezone, new_dst = int(new_timezone), int(new_dst)
76+
new_rows.append([zip, city, state, lat, longt, new_timezone, new_dst])
77+
78+
with tempfile.TemporaryDirectory() as tempdir:
79+
out_filename = Path(tempdir) / "zipcode.csv"
80+
81+
with open(out_filename, "w", newline="", encoding="utf-8") as f:
82+
writer = csv.writer(f, lineterminator="\n")
83+
writer.writerow(header)
84+
writer.writerows(new_rows)
85+
86+
Path(csv_location).unlink()
87+
shutil.move(out_filename, csv_location)
88+
89+
90+
if __name__ == "__main__":
91+
run_update()

setup.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,12 @@
2020
include_package_data=True,
2121
zip_safe=False,
2222
install_requires=[],
23+
extras_require={
24+
'dev': [
25+
'pytz',
26+
'timezonefinder',
27+
]
28+
},
2329
python_requires='>=3.6',
2430
entry_points="""
2531
# -*- Entry points: -*-

0 commit comments

Comments
 (0)