Files
clock-site/server.py
T
Seth a6b3f039d8 Initial commit — Seth Calendar & Decimal Time clock site
Pages: /, /simple, /decimal, /seth, /calendar, /astro, /convert, /timegov
Features: Seth Calendar (10×36 + holidays), decimal time, moon phases,
astronomy (sun/moon), bidirectional time converter, Seth date display,
leap day split cell in calendar grid.
2026-03-08 22:32:38 +00:00

108 lines
3.6 KiB
Python
Executable File

#!/usr/bin/env python3
import json
import time
from datetime import date, datetime, timezone
from http.server import ThreadingHTTPServer, SimpleHTTPRequestHandler
from pathlib import Path
from urllib.parse import urlparse
ROOT = Path(__file__).resolve().parent
CLOCK_CGI_PATH = "/zzz__2fbc6c3300df7e4483acd44c5044098a9fcc61d6.cgi"
def us_dst_dates_for_year(year: int) -> tuple[int, int]:
march1 = date(year, 3, 1)
first_sunday_march = 1 + ((6 - march1.weekday()) % 7)
second_sunday_march = first_sunday_march + 7
nov1 = date(year, 11, 1)
first_sunday_november = 1 + ((6 - nov1.weekday()) % 7)
return second_sunday_march, first_sunday_november
class Handler(SimpleHTTPRequestHandler):
def __init__(self, *args, **kwargs):
super().__init__(*args, directory=str(ROOT), **kwargs)
def do_GET(self):
parsed = urlparse(self.path)
if parsed.path == "/":
self.send_response(302)
self.send_header("Location", "/timegov/")
self.end_headers()
return
if parsed.path in {"/simple", "/simple/"}:
self.path = "/index.html"
return super().do_GET()
if parsed.path in {"/decimal", "/decimal/"}:
self.path = "/decimal.html"
return super().do_GET()
if parsed.path in {"/seth", "/seth/"}:
self.path = "/seth.html"
return super().do_GET()
if parsed.path in {"/calendar", "/calendar/"}:
self.path = "/calendar.html"
return super().do_GET()
if parsed.path in {"/astro", "/astro/"}:
self.path = "/astro.html"
return super().do_GET()
if parsed.path in {"/convert", "/convert/"}:
self.path = "/convert.html"
return super().do_GET()
if parsed.path == "/api/time":
self.send_response(200)
self.send_header("Content-Type", "application/json")
self.send_header("Cache-Control", "no-store")
self.end_headers()
payload = {
"epoch_ms": time.time_ns() // 1_000_000,
"iso_utc": datetime.now(timezone.utc).isoformat(),
}
self.wfile.write(json.dumps(payload).encode("utf-8"))
return
if parsed.path == "/api/timegov/auxdata.xml":
now = datetime.now(timezone.utc)
dst_start_day, dst_end_day = us_dst_dates_for_year(now.year)
xml = (
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
"<timeData>"
f"<currYear>{now.year}</currYear>"
f"<DstDates>3 {dst_start_day} 11 {dst_end_day}</DstDates>"
"<LeapDate>2099 12 31</LeapDate>"
"</timeData>"
)
self.send_response(200)
self.send_header("Content-Type", "application/xml")
self.send_header("Cache-Control", "no-store")
self.end_headers()
self.wfile.write(xml.encode("utf-8"))
return
if parsed.path == CLOCK_CGI_PATH:
t2 = time.time_ns() // 1_000
t3 = time.time_ns() // 1_000
xml = f"<timestamp time2=\"{t2}\" time3=\"{t3}\"/>"
self.send_response(200)
self.send_header("Content-Type", "application/xml")
self.send_header("Cache-Control", "no-store")
self.end_headers()
self.wfile.write(xml.encode("utf-8"))
return
return super().do_GET()
if __name__ == "__main__":
server = ThreadingHTTPServer(("0.0.0.0", 8092), Handler)
server.serve_forever()