# PlanetaryTime Python library for representing and working with time on other bodies in the Solar System — similar in spirit to the standard `datetime` module. Time on a given body is expressed using a human-readable clock where **one hour is as close to one Earth hour as possible**. The number of hours per sol (day) is derived from the body's sidereal rotation period rounded to the nearest integer. ## Installation ```bash pip install planetarytime ``` ## Supported bodies ### Planets | Body | Hours per sol | Sols per year | |---------|--------------|---------------| | Mercury | 1408 | 2 | | Venus | 5833 | 1 | | Mars | 25 | 670 | | Jupiter | 10 | 10476 | | Saturn | 11 | 24491 | | Uranus | 17 | 42718 | | Neptune | 16 | 89667 | ### Moons Accessible via `Body.[index]`, ordered by distance from the planet. | Planet | Index | Moon | Hours per sol | Tidally locked | |---------|-------|-----------|--------------|----------------| | Mars | 0 | Phobos | 8 | yes | | Mars | 1 | Deimos | 30 | yes | | Jupiter | 0 | Io | 42 | yes | | Jupiter | 1 | Europa | 85 | yes | | Jupiter | 2 | Ganymede | 172 | yes | | Jupiter | 3 | Callisto | 401 | yes | | Saturn | 0 | Titan | 383 | yes | | Saturn | 1 | Enceladus | 33 | yes | | Uranus | 0 | Miranda | 34 | yes | | Uranus | 1 | Ariel | 60 | yes | | Uranus | 2 | Umbriel | 99 | yes | | Uranus | 3 | Titania | 209 | yes | | Uranus | 4 | Oberon | 323 | yes | | Neptune | 0 | Triton | 141 | yes | For tidally locked moons, one sol equals one year (one orbit around the parent planet). ## Usage ### Planets ```python from datetime import datetime, timezone from planetarytime import Body, EpochType, PlanetaryTime now = datetime.now(timezone.utc) # Mars time since discovery (Galileo, 1610) pt = PlanetaryTime.from_earth(now, Body.MARS, EpochType.DISCOVERY) print(pt) # Year 415, Sol 668, 14:22:07 (Mars / discovery epoch) print(pt.year) # 415 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) print(pt) # Year 25, Sol 23, 14:22:07 (Mars / contact epoch) ``` ### Moons ```python # Titan time since discovery (Huygens, 1655) titan = Body.SATURN[0] pt = PlanetaryTime.from_earth(now, titan, EpochType.DISCOVERY) print(pt) # Year 1, Sol 0, 08:11:45 (Titan / discovery epoch) # Titan time since Huygens probe landing (2005) pt = PlanetaryTime.from_earth(now, titan, EpochType.CONTACT) print(pt) # Check if a moon is tidally locked print(titan.is_tidally_locked) # True ``` ### Epochs | EpochType | Meaning | |--------------------|----------------------------------------------| | `EpochType.DISCOVERY` | First recorded observation of the body | | `EpochType.CONTACT` | First probe landing or crewed landing | `EpochUnavailableError` is raised when `CONTACT` is requested for a body that has not been visited yet. ## Logging This library uses [loguru](https://github.com/Delgan/loguru) for internal logging. By default, loguru has a sink to `stderr` enabled. If your application also uses loguru, library logs appear in your configured sinks automatically. ### Suppress library logs ```python from loguru import logger logger.disable("planetarytime") ``` ### Filter by level ```python from loguru import logger import sys logger.add(sys.stderr, filter={"planetarytime": "WARNING"}) ``` ## License MIT