Compare commits

2 Commits

Author SHA1 Message Date
0e49259a01 pyproject.toml corrected 2026-04-17 11:33:40 +02:00
4c3fdcfcbb Add conversion accuracy and epoch switching tests 2026-04-16 19:40:46 +02:00
4 changed files with 91 additions and 4 deletions

View File

@@ -83,7 +83,4 @@ Moon and dwarf planets (Pluto, Ceres, Eris) may be added later.
- TODO: Implement core `PlanetaryTime` class
- TODO: Implement conversion from Earth `datetime`
- TODO: Implement `__str__` / `__repr__`
- TODO: Write tests for conversion accuracy
- TODO: Write tests for epoch switching
- TODO: Populate README with usage examples
- TODO: Implement `scripts/refresh_data.py` — fetches rotation periods, orbital periods and discovery dates from Wikidata SPARQL endpoint and regenerates hardcoded data in `body.py`, `moon.py` and `epoch.py`; script is not part of the distributed package

View File

@@ -67,6 +67,8 @@ print(pt.sol) # 668
print(pt.hour) # 14
print(pt.minute) # 22
print(pt.second) # 7
print(pt.time) # "14:22:07"
print(pt.date) # "Year 415, Sol 668"
# Mars time since first contact (Viking 1, 1976)
pt = PlanetaryTime.from_earth(now, Body.MARS, EpochType.CONTACT)

View File

@@ -1,6 +1,6 @@
[project]
name = "planetarytime"
version = "1.2.0"
version = "1.2.1"
description = "Python library for representing and working with time on other bodies in the Solar System"
authors = [
{name = "Jan Doubravský", email = "jan.doubravsky@gmail.com"}

View File

@@ -80,3 +80,91 @@ def test_repr_contains_year_and_sol() -> None:
assert "PlanetaryTime(" in r
assert "year=" in r
assert "sol=" in r
# ------------------------------------------------------------------
# Conversion accuracy
# ------------------------------------------------------------------
def test_conversion_accuracy_sol_hour_minute() -> None:
"""26h 30m after epoch on Mars: sol 1, hour 1, minute 30."""
epoch_dt = get_epoch_date(Body.MARS, EpochType.DISCOVERY)
# Mars sol = 25 h; 26h 30m = 1 sol + 1h 30m
pt = PlanetaryTime.from_earth(epoch_dt + timedelta(hours=26, minutes=30), Body.MARS, EpochType.DISCOVERY)
assert pt.year == 0
assert pt.sol == 1
assert pt.hour == 1
assert pt.minute == 30
assert pt.second == 0
def test_conversion_accuracy_seconds() -> None:
"""45 seconds after epoch: only second counter advances."""
epoch_dt = get_epoch_date(Body.MARS, EpochType.DISCOVERY)
pt = PlanetaryTime.from_earth(epoch_dt + timedelta(seconds=45), Body.MARS, EpochType.DISCOVERY)
assert pt.year == 0
assert pt.sol == 0
assert pt.hour == 0
assert pt.minute == 0
assert pt.second == 45
def test_conversion_accuracy_year_boundary() -> None:
"""Exactly one Mars year after epoch lands on year 1, sol 0, 00:00:00."""
epoch_dt = get_epoch_date(Body.MARS, EpochType.DISCOVERY)
one_year_seconds = Body.MARS.sols_per_year * Body.MARS.hours_per_sol * 3600
pt = PlanetaryTime.from_earth(epoch_dt + timedelta(seconds=one_year_seconds), Body.MARS, EpochType.DISCOVERY)
assert pt.year == 1
assert pt.sol == 0
assert pt.hour == 0
assert pt.minute == 0
assert pt.second == 0
# ------------------------------------------------------------------
# Epoch switching
# ------------------------------------------------------------------
def test_epoch_switching_discovery_vs_contact_differ() -> None:
"""Discovery (1610) and contact (1976) epochs give significantly different years."""
dt = datetime(2024, 1, 1, tzinfo=timezone.utc)
pt_disc = PlanetaryTime.from_earth(dt, Body.MARS, EpochType.DISCOVERY)
pt_cont = PlanetaryTime.from_earth(dt, Body.MARS, EpochType.CONTACT)
assert pt_disc.year > pt_cont.year
def test_epoch_switching_preserves_body_and_epoch_type() -> None:
"""Switching epoch type is reflected in the epoch_type property; body stays the same."""
dt = datetime(2024, 1, 1, tzinfo=timezone.utc)
pt_disc = PlanetaryTime.from_earth(dt, Body.MARS, EpochType.DISCOVERY)
pt_cont = PlanetaryTime.from_earth(dt, Body.MARS, EpochType.CONTACT)
assert pt_disc.body is Body.MARS
assert pt_cont.body is Body.MARS
assert pt_disc.epoch_type is EpochType.DISCOVERY
assert pt_cont.epoch_type is EpochType.CONTACT
def test_epoch_switching_contact_sol_count_is_smaller() -> None:
"""Contact epoch is later, so sol count from contact is smaller than from discovery."""
dt = datetime(2024, 1, 1, tzinfo=timezone.utc)
pt_disc = PlanetaryTime.from_earth(dt, Body.MARS, EpochType.DISCOVERY)
pt_cont = PlanetaryTime.from_earth(dt, Body.MARS, EpochType.CONTACT)
total_sols_disc = pt_disc.year * Body.MARS.sols_per_year + pt_disc.sol
total_sols_cont = pt_cont.year * Body.MARS.sols_per_year + pt_cont.sol
assert total_sols_disc > total_sols_cont
# ------------------------------------------------------------------
# time and date properties
# ------------------------------------------------------------------
def test_time_property_format() -> None:
epoch_dt = get_epoch_date(Body.MARS, EpochType.DISCOVERY)
pt = PlanetaryTime.from_earth(epoch_dt + timedelta(hours=3, minutes=7, seconds=9), Body.MARS, EpochType.DISCOVERY)
assert pt.time == "03:07:09"
def test_date_property_format() -> None:
epoch_dt = get_epoch_date(Body.MARS, EpochType.DISCOVERY)
pt = PlanetaryTime.from_earth(epoch_dt + timedelta(hours=Body.MARS.hours_per_sol + 1), Body.MARS, EpochType.DISCOVERY)
assert pt.date == "Year 0, Sol 1"