import lox_space as lox
import pytest
def test_time(provider):
tai_exp = lox.Time("TAI", 2000, 1, 1)
tai_act = lox.Time.from_iso("2000-01-01T00:00:00.000 TAI")
assert tai_exp == tai_act
tai_act = tai_exp.to_scale("TAI")
assert tai_exp == tai_act
tai_act = tai_exp.to_scale("TCB").to_scale("TAI")
assert tai_exp.isclose(tai_act)
tai_act = tai_exp.to_scale("TCG").to_scale("TAI")
assert tai_exp.isclose(tai_act)
tai_act = tai_exp.to_scale("TDB").to_scale("TAI")
assert tai_exp.isclose(tai_act)
tai_act = tai_exp.to_scale("TT").to_scale("TAI")
assert tai_exp.isclose(tai_act)
tai_act = tai_exp.to_scale("UT1", provider).to_scale("TAI", provider)
assert tai_exp.isclose(tai_act)
tai1 = lox.Time("TAI", 2000, 1, 1, 0, 0, 0.5)
assert tai1 > tai_exp
assert tai1 >= tai_exp
assert tai_exp < tai1
assert tai_exp <= tai1
assert tai_exp != tai1
dt = lox.TimeDelta(0.5)
assert (tai_exp + dt).isclose(tai1)
assert (tai1 - dt).isclose(tai_exp)
assert float(tai1 - tai_exp) == pytest.approx(float(dt))
def test_utc(provider):
utc_exp = lox.UTC(2000, 1, 1)
utc_act = lox.UTC.from_iso("2000-01-01T00:00:00.000")
assert utc_exp == utc_act
utc_act = lox.UTC.from_iso("2000-01-01T00:00:00.000Z")
assert utc_exp == utc_act
utc_act = lox.UTC.from_iso("2000-01-01T00:00:00.000 UTC")
assert utc_exp == utc_act
utc_act = utc_exp.to_scale("TAI").to_utc()
assert utc_exp == utc_act
utc_act = utc_exp.to_scale("TCB").to_utc()
assert utc_exp.isclose(utc_act)
utc_act = utc_exp.to_scale("TCG").to_utc()
assert utc_exp.isclose(utc_act)
utc_act = utc_exp.to_scale("TDB").to_utc()
assert utc_exp.isclose(utc_act)
utc_act = utc_exp.to_scale("TT").to_utc()
assert utc_exp == utc_act
utc_act = utc_exp.to_scale("UT1", provider).to_utc(provider)
assert utc_exp.isclose(utc_act)
def test_time_delta():
delta = lox.TimeDelta(1.5)
assert str(delta) == "1.5 seconds"
assert repr(delta) == "TimeDelta(1.5)"
assert delta.seconds() == 1
assert delta.subsecond() == 0.5
assert str(delta + delta) == "3 seconds"
assert str(delta - delta) == "0 seconds"
assert str(-delta) == "-1.5 seconds"
with pytest.raises(lox.NonFiniteTimeDeltaError):
lox.TimeDelta(float("nan")).seconds()
def test_time_delta_constructors():
td = lox.TimeDelta.from_seconds(123)
assert td.to_decimal_seconds() == 123.0
td = lox.TimeDelta.from_minutes(2.0)
assert td.to_decimal_seconds() == 120.0
td = lox.TimeDelta.from_hours(2.0)
assert td.to_decimal_seconds() == 7200.0
td = lox.TimeDelta.from_days(2.0)
assert td.to_decimal_seconds() == 172800.0
td = lox.TimeDelta.from_julian_years(2.0)
assert td.to_decimal_seconds() == 63115200.0
td = lox.TimeDelta.from_julian_centuries(2.0)
assert td.to_decimal_seconds() == 6311520000.0
def test_time_repr():
time = lox.Time("TAI", 2000, 1, 1, 0, 0, 12.123456789123)
assert repr(time) == 'Time("TAI", 2000, 1, 1, 0, 0, 12.123456789123)'
assert str(time) == "2000-01-01T00:00:12.123 TAI"
def test_time_accessors():
time = lox.Time("TAI", 2000, 1, 1, 0, 0, 12.123456789123)
assert time.scale().abbreviation() == "TAI"
assert time.year() == 2000
assert time.month() == 1
assert time.day() == 1
assert time.hour() == 0
assert time.minute() == 0
assert time.second() == 12
assert time.millisecond() == 123
assert time.microsecond() == 456
assert time.nanosecond() == 789
assert time.picosecond() == 123
assert time.femtosecond() == 0
assert time.decimal_seconds() == pytest.approx(12.123456789123, rel=1e-15)
def test_time_invalid_date():
with pytest.raises(ValueError, match="invalid date"):
lox.Time("TAI", 2000, 13, 1)
def test_time_invalid_hour():
with pytest.raises(ValueError, match="hour must be in the range"):
lox.Time("TAI", 2000, 12, 1, 24, 0, 0.0)
def test_time_sub_different_scales():
t1 = lox.Time("TAI", 2000, 1, 1, 0, 0, 1.0)
t0 = lox.Time("TT", 2000, 1, 1, 0, 0, 1.0)
with pytest.raises(ValueError, match="cannot subtract.*different time scales"):
t1 - t0
def test_time_isclose_different_scales():
t0 = lox.Time("TAI", 2000, 1, 1)
t1 = lox.Time("TT", 2000, 1, 1)
with pytest.raises(ValueError, match="cannot compare.*different time scales"):
t0.isclose(t1)
def test_time_from_iso_invalid():
with pytest.raises(ValueError, match="invalid ISO"):
lox.Time.from_iso("2000-01-01X00:00:00 TAI")
def test_time_from_iso_invalid_scale():
with pytest.raises(ValueError, match="invalid ISO"):
lox.Time.from_iso("2000-01-01T00:00:00 UTC")
def test_time_from_iso_invalid_scale_arg():
with pytest.raises(ValueError, match="unknown time scale: UTC"):
lox.Time.from_iso("2000-01-01T00:00:00 TAI", scale="UTC")
def test_time_julian_date():
time = lox.Time.from_julian_date("TAI", 0.0, "j2000")
assert time.julian_date("j2000", "seconds") == 0.0
assert time.julian_date("j2000", "days") == 0.0
assert time.julian_date("j2000", "centuries") == 0.0
assert time.julian_date("jd", "days") == 2451545.0
assert time.julian_date("mjd", "days") == 51544.5
assert time.julian_date("j1950", "days") == 18262.5
time = lox.Time.from_julian_date("TAI", 0.0, "j1950")
assert time.julian_date("j1950", "days") == 0.0
time = lox.Time.from_julian_date("TAI", 0.0, "mjd")
assert time.julian_date("mjd", "days") == 0.0
time = lox.Time.from_julian_date("TAI", 0.0, "jd")
assert time.julian_date("jd", "days") == 0.0
def test_time_invalid_epoch():
time = lox.Time("TAI", 2000, 1, 1)
with pytest.raises(ValueError, match="unknown epoch: unknown"):
time.julian_date("unknown", "days")
def test_time_invalid_unit():
time = lox.Time("TAI", 2000, 1, 1)
with pytest.raises(ValueError, match="unknown unit: unknown"):
time.julian_date("jd", "unknown")
def test_time_from_two_part_julian_date():
expected = lox.Time("TAI", 2024, 7, 11, 8, 2, 14.0)
jd1, jd2 = expected.two_part_julian_date()
actual = lox.Time.from_two_part_julian_date("TAI", jd1, jd2)
assert expected.isclose(actual)
def test_time_from_day_of_year():
expected = lox.Time("TAI", 2024, 12, 31)
actual = lox.Time.from_day_of_year("TAI", 2024, 366)
assert actual == expected
def test_utc_accessors():
utc = lox.UTC(2000, 1, 1, 12, 13, 14.123456789123)
assert utc.year() == 2000
assert utc.month() == 1
assert utc.day() == 1
assert utc.hour() == 12
assert utc.minute() == 13
assert utc.second() == 14
assert utc.millisecond() == 123
assert utc.microsecond() == 456
assert utc.nanosecond() == 789
assert utc.picosecond() == 123
assert utc.decimal_seconds() == 14.123456789123
assert str(utc) == "2000-01-01T12:13:14.123 UTC"
assert repr(utc) == "UTC(2000, 1, 1, 12, 13, 14.123456789123)"
def test_utc_invalid_date():
with pytest.raises(ValueError, match="invalid date"):
lox.UTC(2000, 0, 1)
def test_utc_from_iso_invalid():
with pytest.raises(ValueError, match="invalid ISO"):
lox.UTC.from_iso("2000-01-01X00:00:00 UTC")
def test_time_delta_units():
assert (60 * lox.seconds).to_decimal_seconds() == 60.0
assert (2 * lox.minutes).to_decimal_seconds() == 120.0
assert (0.5 * lox.hours).to_decimal_seconds() == 1800.0
assert (1 * lox.days).to_decimal_seconds() == 86400.0
def test_time_delta_subsecond_constructors():
td = lox.TimeDelta.from_milliseconds(1500)
assert td.seconds() == 1
assert td.subsecond() == 0.5
td = lox.TimeDelta.from_microseconds(1_000_000)
assert td.to_decimal_seconds() == 1.0
td = lox.TimeDelta.from_nanoseconds(500_000_000)
assert td.to_decimal_seconds() == 0.5
def test_eop_provider_invalid_path():
with pytest.raises(lox.EopParserError):
lox.EOPProvider("invalid_path")
def test_eop_provider_extrapolated(provider):
tai = lox.Time("TAI", 2100, 1, 1)
with pytest.raises(lox.EopProviderError, match="extrapolated"):
tai.to_scale("UT1", provider)
def test_time_comparison_same_scale():
t1 = lox.Time("TAI", 2000, 1, 1)
t2 = lox.Time("TAI", 2000, 1, 2)
assert t1 < t2
assert t2 > t1
assert t1 == t1
def test_time_comparison_different_scale_raises():
t_tai = lox.Time("TAI", 2000, 1, 1)
t_tt = lox.Time("TT", 2000, 1, 1)
with pytest.raises(ValueError, match="different time scales"):
_ = t_tai < t_tt
with pytest.raises(ValueError, match="different time scales"):
_ = t_tt > t_tai