Skip to content

Commit cbc441c

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

3 files changed

Lines changed: 997 additions & 904 deletions

File tree

pyzipcode/update_timezones.py

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
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+
BEFORE_DST_DATE = datetime.datetime(2021, 2, 1)
33+
DST_DATE = datetime.datetime(2021, 4, 1)
34+
35+
tf = TimezoneFinder()
36+
37+
38+
def coords_to_utcoffset_and_isdst(lng, lat):
39+
timezone_name = tf.timezone_at(lng=lng, lat=lat)
40+
timezone = pytz.timezone(timezone_name)
41+
offset = timezone.utcoffset(BEFORE_DST_DATE).total_seconds() / 60 / 60
42+
dst = timezone.dst(DST_DATE).total_seconds() / 60 / 60
43+
return offset, dst, timezone_name
44+
45+
46+
def run_update():
47+
"""Run the import code."""
48+
with open(csv_location, newline="", encoding="utf-8") as f:
49+
reader = csv.reader(f)
50+
header = next(reader)
51+
52+
new_rows = []
53+
for i, row in enumerate(reader, start=1):
54+
zip, city, state, lat, longt, timezone, dst = row
55+
longt, lat = float(longt), float(lat)
56+
timezone, dst = float(timezone), float(dst)
57+
58+
new_timezone, new_dst, tz_name = coords_to_utcoffset_and_isdst(longt, lat)
59+
if timezone != new_timezone or dst != new_dst:
60+
print(
61+
f"line {i: >5}: {zip}, {city: <26}, {state}, {lat}, {longt}\n"
62+
f"{timezone},{dst} -> {new_timezone},{new_dst} ({tz_name})\n",
63+
file=sys.stderr,
64+
)
65+
66+
if new_timezone != int(new_timezone):
67+
raise ValueError("USA has fractional-hour timezones now")
68+
if new_dst not in [1, 0]:
69+
raise ValueError("expected dst to be either +1 or 0")
70+
71+
new_timezone, new_dst = int(new_timezone), int(new_dst)
72+
new_rows.append([zip, city, state, lat, longt, new_timezone, new_dst])
73+
74+
with tempfile.TemporaryDirectory() as tempdir:
75+
out_filename = Path(tempdir) / "zipcode.csv"
76+
77+
with open(out_filename, "w", newline="", encoding="utf-8") as f:
78+
writer = csv.writer(f, lineterminator="\n")
79+
writer.writerow(header)
80+
writer.writerows(new_rows)
81+
82+
Path(csv_location).unlink()
83+
shutil.move(out_filename, csv_location)
84+
85+
86+
if __name__ == "__main__":
87+
run_update()

0 commit comments

Comments
 (0)