"""BeatTime API client — Python (standard library only, no dependencies). BeatTime is one universal time: 1000 .beats/day, anchored to UTC, no timezones. Public, free, read-only API + proof-of-existence. https://beattime.live from beattime import BeatTime bt = BeatTime() print(bt.beat_now()) # '@523' print(bt.time_to_beat('2026-06-15T14:30:00+02:00')) # {'beat': '@520', ...} print(bt.beat_to_time(523.45)) # {'utc': '...', ...} # Proof of existence (only the SHA-256 hash is sent — your file stays local): digest = BeatTime.sha256_file('contract.pdf') bt.stamp(digest) # record it print(bt.cert_url(digest)) # downloadable PDF certificate No API key, no limits beyond fair-use rate limiting. MIT-style: use freely. """ from __future__ import annotations import hashlib import json import urllib.parse import urllib.request BASE_URL = "https://beattime.live" class BeatTime: def __init__(self, base_url: str = BASE_URL, timeout: float = 10.0): self.base = base_url.rstrip("/") self.timeout = timeout # --- low-level ------------------------------------------------------- def _get(self, path: str, params: dict | None = None) -> dict: url = self.base + path if params: clean = {k: v for k, v in params.items() if v is not None} if clean: url += "?" + urllib.parse.urlencode(clean) with urllib.request.urlopen(url, timeout=self.timeout) as r: return json.load(r) def _post(self, path: str, data: dict) -> dict: body = json.dumps(data).encode("utf-8") req = urllib.request.Request( self.base + path, body, {"Content-Type": "application/json"} ) with urllib.request.urlopen(req, timeout=self.timeout) as r: return json.load(r) # --- time ------------------------------------------------------------ def now(self) -> dict: """Current time: {'beat': '@523', 'beat_centi': '@523.45', 'beats': .., 'utc': ..}.""" return self._get("/api/now/") def beat_now(self) -> str: """Just the current '@NNN'.""" return self.now()["beat"] def time_to_beat(self, iso8601: str) -> dict: """Convert an instant (ISO 8601; no timezone = UTC) to its @beat.""" return self._get("/api/convert/", {"at": iso8601}) def beat_to_time(self, beat: float, date: str | None = None, tz_offset: int | None = None) -> dict: """Convert a beat [0,1000) to UTC time. Optional date (YYYY-MM-DD) and tz_offset (minutes, e.g. 120 for UTC+2) to also get the local time.""" return self._get("/api/convert/", {"beat": beat, "date": date, "tz_offset": tz_offset}) def sync(self) -> dict: """Server time for clock sync (SNTP-style): {'server_unix_ms': .., ...}.""" return self._get("/api/sync/") def health(self) -> dict: return self._get("/api/health/") # --- proof of existence --------------------------------------------- def stamp(self, digest: str) -> dict: """Record a 64-char lowercase hex SHA-256 in the public proof log. Idempotent: the first stamp wins. The file never leaves your machine.""" return self._post("/api/proof/stamp", {"digest": digest}) def verify(self, digest: str) -> dict: """Look up a digest: timestamp, inclusion proof, signature, anchors.""" return self._get("/api/proof/verify", {"digest": digest}) def cert_url(self, digest: str) -> str: """URL of the downloadable PDF certificate for a stamped digest.""" return f"{self.base}/api/proof/cert/{digest}" def verify_url(self, digest: str) -> str: """URL of the public verification page for a digest.""" return f"{self.base}/proof/?h={digest}" @staticmethod def sha256_file(path: str) -> str: """SHA-256 of a file (streamed) — feed it to stamp()/verify().""" h = hashlib.sha256() with open(path, "rb") as f: for chunk in iter(lambda: f.read(65536), b""): h.update(chunk) return h.hexdigest() if __name__ == "__main__": print(BeatTime().beat_now())