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.
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
#!/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 == "/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()
|
||||
Reference in New Issue
Block a user