Skip to content

Instantly share code, notes, and snippets.

Created January 8, 2023 07:35
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
What would you like to do?
#!/usr/bin/env python3
"""Parse sunrise/sunset tables as provided by the USNO website at"""
import re
import argparse
def parse_table(filename: str):
def to_decimal_deg(latlon_tup) -> float:
assert len(latlon_tup) == 3 and re.match("[NESW]", latlon_tup[0])
deg = int(latlon_tup[1]) + int(latlon_tup[2]) / 60.0
if latlon_tup[0] in ("S", "W"):
return -deg
return deg
def time_colon(timestr: str) -> str:
if timestr.isdigit():
return timestr[:2] + ":" + timestr[2:]
return timestr
months = [{} for i in range(12)]
year, location = None, None
with open(filename, encoding="utf8") as f:
for line in f:
if line.startswith("Location: "):
m ="\s+([EW])(\d+)\s+(\d+)[\s,]+([NS])(\d+)\s+(\d+)", line)
assert m, "can't parse location as expected"
lon, lat = m.groups()[:3], m.groups()[3:]
location = (to_decimal_deg(lat), to_decimal_deg(lon))
m ="Rise and Set for the Sun for (\d+)", line)
assert m, "can't parse year as expected"
year = int(
elif re.match(r"^\d\d ", line):
# this is a fixed tabular format with occasional empty "cells", so we'll just use indexes
day = int(line[:2])
for month, slot in enumerate(range(4, 135, 11)):
sunrise, sunset = (
line[slot : slot + 4].strip(),
line[slot + 5 : slot + 5 + 4].strip(),
if (sunrise and sunset): # ignore nonexistent or weird days with only one value
assert len(sunrise) == len(sunset) == 4, "unexpected format"
months[month][day]=(time_colon(sunrise), time_colon(sunset))
assert year and location
return location, year, months
if __name__ == "__main__":
location, year, months = parse_table("xyz.txt")
for month, days in enumerate(months, start=1):
for day, values in days.items():
print(year, month, day, values)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment