Files
moxiaonian d9da4301cd 公众授权版:normal · 1000 次 · 有效期至 2026-12-31
副本编号 LY-20261007-AC63(水印指纹已嵌入)
含 README、.gitignore;排除 .DS_Store / __pycache__ / .pytest_cache
2026-10-07 17:29:52 +08:00

86 lines
3.3 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""真太阳时经度修正黄金样本(设计文档 §4.4 / §6.1)。
数据来源:
- golden/longitudes.yaml —— 不同经度城市逐条断言 lon_correction_min
- golden/time_boundary.yaml —— 其中带 expect.lon_correction_min 的 A 组样本
"""
import sys
import unittest
from datetime import datetime
from pathlib import Path
import yaml
SKILL_ROOT = Path(__file__).resolve().parents[1]
SCRIPTS_DIR = SKILL_ROOT / "scripts"
GOLDEN_DIR = Path(__file__).resolve().parent / "golden"
if str(SCRIPTS_DIR) not in sys.path:
sys.path.insert(0, str(SCRIPTS_DIR))
from astro.solar_time import to_true_solar_time # noqa: E402
from astro.timezone_resolve import to_utc # noqa: E402
from geo.cities import resolve_location # noqa: E402
def load_golden(name):
with open(GOLDEN_DIR / name, encoding="utf-8") as f:
return yaml.safe_load(f)
def true_solar_chain(place, birth):
"""数据流 L0-a ~ L0-d:地名 + 钟表时间 → (真太阳时, solar_audit, loc)。"""
loc = resolve_location(place)
clock = datetime.strptime(birth, "%Y-%m-%d %H:%M")
utc, _tz_audit = to_utc(clock, loc)
tst, st_audit = to_true_solar_time(utc, loc.lon)
return tst, st_audit, loc
class LongitudeCorrectionGoldenTest(unittest.TestCase):
def test_longitudes_yaml(self):
samples = load_golden("longitudes.yaml")
self.assertGreaterEqual(len(samples), 5, "longitudes.yaml 至少需要 5 组样本")
for s in samples:
with self.subTest(sample=s["name"], place=s["place"]):
_tst, audit, loc = true_solar_chain(s["place"], s["birth"])
# 城市表经度 sanity check(0.1° 级即够,见文档 §4.1)
self.assertAlmostEqual(loc.lon, s["lon"], delta=0.1)
self.assertAlmostEqual(
audit["lon_correction_min"],
s["expect_lon_correction_min"],
delta=s["tolerance"],
)
class TimeBoundaryGoldenTest(unittest.TestCase):
"""文档 §6.1 A 组:乌鲁木齐 / 成都 / 上海。"""
def test_time_boundary_yaml(self):
samples = [
s for s in load_golden("time_boundary.yaml")
if "lon_correction_min" in s.get("expect", {})
]
self.assertGreaterEqual(len(samples), 3, "time_boundary.yaml A 组应有 3 条样本")
for s in samples:
with self.subTest(sample=s["name"], place=s["place"]):
tst, audit, _loc = true_solar_chain(s["place"], s["birth"])
self.assertAlmostEqual(
audit["lon_correction_min"],
s["expect"]["lon_correction_min"],
delta=s["tolerance"],
)
if "true_solar_time" in s["expect"]:
want = datetime.strptime(
s["expect"]["true_solar_time"], "%Y-%m-%d %H:%M"
)
tol_min = s["expect"].get("true_solar_time_tolerance_min", 3)
self.assertLessEqual(
abs((tst - want).total_seconds()),
tol_min * 60,
f"真太阳时 {tst} 与期望 {want} 差距超过 {tol_min} 分钟",
)
if __name__ == "__main__":
unittest.main()