70 lines
2.2 KiB
Go
70 lines
2.2 KiB
Go
|
|
package astro
|
|||
|
|
|
|||
|
|
import (
|
|||
|
|
"math"
|
|||
|
|
"testing"
|
|||
|
|
"time"
|
|||
|
|
|
|||
|
|
"b612.me/astro/basic"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
// time.Time 往返经 JD 舍入,容差为 0.2 ms。
|
|||
|
|
func TestBarycentricTimeFacade(t *testing.T) {
|
|||
|
|
tt := time.Date(2026, 1, 1, 0, 0, 0, 0, time.UTC)
|
|||
|
|
if got := TCGMinusTT(tt); math.Abs(got-1.0777) > 5e-3 {
|
|||
|
|
t.Errorf("TCG−TT=%v 秒, want ≈1.078", got)
|
|||
|
|
}
|
|||
|
|
if got := TCBMinusTT(tt); math.Abs(got-23.9757) > 5e-3 {
|
|||
|
|
t.Errorf("TCB−TT=%v 秒, want ≈23.976", got)
|
|||
|
|
}
|
|||
|
|
if got := TDBMinusTT(tt); math.Abs(got) > 2e-3 {
|
|||
|
|
t.Errorf("TDB−TT=%v 秒, want |·| ≤ 1.7 ms", got)
|
|||
|
|
}
|
|||
|
|
for _, tc := range []struct {
|
|||
|
|
name string
|
|||
|
|
fwd func(time.Time) time.Time
|
|||
|
|
back func(time.Time) time.Time
|
|||
|
|
}{
|
|||
|
|
{"TCG", TCGFromTT, TTFromTCG},
|
|||
|
|
{"TCB", TCBFromTT, TTFromTCB},
|
|||
|
|
{"TDB", TDBFromTT, TTFromTDB},
|
|||
|
|
} {
|
|||
|
|
round := tc.back(tc.fwd(tt))
|
|||
|
|
if delta := math.Abs(round.Sub(tt).Seconds()); delta > 2e-4 {
|
|||
|
|
t.Errorf("%s 往返差 %.6f 秒", tc.name, delta)
|
|||
|
|
}
|
|||
|
|
if forward := tc.fwd(tt); !forward.After(tt.Add(-time.Second)) || !forward.Before(tt.Add(time.Minute)) {
|
|||
|
|
t.Errorf("%s 结果 %v 离开合理区间", tc.name, forward)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
tcb := TCBFromTT(tt)
|
|||
|
|
if diff := tcb.Sub(TDBFromTCB(tcb)).Seconds(); math.Abs(diff-23.9757) > 0.1 {
|
|||
|
|
t.Errorf("TCB−TDB=%v 秒, want ≈23.976", diff)
|
|||
|
|
}
|
|||
|
|
if delta := math.Abs(TTFromTCB(tcb).Sub(tt).Seconds()); delta > 2e-4 {
|
|||
|
|
t.Errorf("TT→TCB 往返差 %.6f 秒", delta)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func TestBarycentricTimeFacadePreservesScaleAndInstant(t *testing.T) {
|
|||
|
|
tt := time.Date(2026, 1, 1, 0, 0, 0, 0, time.UTC)
|
|||
|
|
for _, date := range []time.Time{tt, tt.In(time.FixedZone("UTC+08", 8*3600))} {
|
|||
|
|
jd := basic.Date2JD(date.UTC())
|
|||
|
|
for name, pair := range map[string][2]float64{
|
|||
|
|
"TCG": {TCGMinusTT(date), basic.TCGMinusTTSeconds(jd)},
|
|||
|
|
"TCB": {TCBMinusTT(date), basic.TCBMinusTTSeconds(jd)},
|
|||
|
|
"TDB": {TDBMinusTT(date), basic.TDBMinusTTSeconds(jd)},
|
|||
|
|
} {
|
|||
|
|
if pair[0] != pair[1] {
|
|||
|
|
t.Errorf("%s facade=%v, basic=%v", name, pair[0], pair[1])
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
if direct, composed := TDBFromTT(date), TDBFromTCB(TCBFromTT(date)); math.Abs(direct.Sub(composed).Seconds()) > 1e-4 {
|
|||
|
|
t.Errorf("direct TDB=%v, composed=%v", direct, composed)
|
|||
|
|
}
|
|||
|
|
if got := TCGFromTT(date); got.Location() != time.UTC || !got.Equal(TCGFromTT(tt)) {
|
|||
|
|
t.Errorf("TCG depends on input Location: %v", got)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|