Astronomy¶
Shared, tradition-neutral astronomy used by the computed traditions: Julian-day and delta-T
conversion, nutation, solar terms, the time-model helpers, and the injectable Ephemeris protocol
with its pure-Python BuiltinEphemeris (and FixedEphemeris test stub).
astronomy ¶
Shared astronomy primitives used by multiple traditions.
The package contains deterministic Julian-day helpers, solar-term utilities, and an injectable ephemeris protocol. The default backend is pure Python and has no required runtime dependencies.
Example
JIE_LONGITUDES
module-attribute
¶
JIE_LONGITUDES: tuple[float, ...] = (
315.0,
345.0,
15.0,
45.0,
75.0,
105.0,
135.0,
165.0,
195.0,
225.0,
255.0,
285.0,
)
Body ¶
Bases: StrEnum
Astronomical body identifiers accepted by shared ephemeris backends.
Values are stable lowercase strings so they can be stored in reading modifiers and replay fixtures.
BuiltinEphemeris ¶
Pure-Python deterministic ephemeris shipped with the package.
The built-in backend keeps runtime dependencies empty and is suitable for deterministic tests and general symbolic work. It is not a replacement for a high-precision professional astronomy backend.
Example
supported_bodies ¶
position ¶
Return an apparent geocentric ecliptic position.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
body
|
Body
|
Body to compute. |
required |
jd_tt
|
float
|
Julian day on the Terrestrial Time scale. |
required |
Returns:
| Type | Description |
|---|---|
EclipticPosition
|
Ecliptic longitude, approximate longitude speed, and Moon latitude. |
Raises:
| Type | Description |
|---|---|
EphemerisError
|
If |
Source code in src/fortune_telling_core/astronomy/ephemeris/builtin.py
FixedEphemeris ¶
Deterministic ephemeris backed by a fixed position mapping.
This backend is intended for tests, examples, and replay fixtures where the caller wants exact symbolic placements without astronomical calculation.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
positions
|
Mapping[Body, EclipticPosition]
|
Mapping from body identifiers to ecliptic positions. If a north node is supplied without a south node, the south node is derived as the opposite longitude. |
required |
Example
Source code in src/fortune_telling_core/astronomy/ephemeris/fixed.py
supported_bodies ¶
position ¶
Return the fixed position for a body.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
body
|
Body
|
Body to look up. |
required |
jd_tt
|
float
|
Ignored Julian day, accepted for protocol compatibility. |
required |
Returns:
| Type | Description |
|---|---|
EclipticPosition
|
The configured ecliptic position. |
Raises:
| Type | Description |
|---|---|
EphemerisError
|
If no position exists for |
Source code in src/fortune_telling_core/astronomy/ephemeris/fixed.py
Ephemeris ¶
Bases: Protocol
Protocol for injectable astronomy backends.
Implementations provide apparent geocentric ecliptic positions in degrees.
Latitude may be None when a backend or body does not compute it. The
fortune-telling traditions depend only on this protocol, so applications
can bring their own precision and licensing choices.
Attributes:
| Name | Type | Description |
|---|---|---|
id |
str
|
Stable backend identifier recorded in reading provenance. |
version |
str
|
Backend version recorded in reading provenance. |
position ¶
Return an apparent geocentric ecliptic position.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
body
|
Body
|
Body to compute. |
required |
jd_tt
|
float
|
Julian day on the Terrestrial Time scale. |
required |
Returns:
| Type | Description |
|---|---|
EclipticPosition
|
Ecliptic position for the requested body. |
Raises:
| Type | Description |
|---|---|
EphemerisError
|
If the backend cannot compute the requested body. |
Source code in src/fortune_telling_core/astronomy/ephemeris/protocol.py
AstronomyError ¶
Bases: FortuneTellingError
Base error for shared astronomy helpers.
EphemerisError ¶
Bases: AstronomyError
Raised when an ephemeris cannot provide a requested position.
LunisolarDate
dataclass
¶
EclipticPosition
dataclass
¶
Geocentric ecliptic position returned by an ephemeris.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
longitude
|
float
|
Ecliptic longitude in degrees. The stored value is
normalized to |
required |
speed
|
float
|
Longitude speed in degrees per day. Negative speed is treated as retrograde motion. |
0.0
|
latitude
|
float | None
|
Ecliptic latitude in degrees, when the ephemeris computes
it. |
None
|
Example
TimeModel ¶
Bases: StrEnum
Civil-time adjustment models used by date-based traditions.
CLOCK keeps the supplied aware datetime unchanged. LOCAL_MEAN_TIME
shifts by longitude relative to the timezone offset. TRUE_SOLAR also
applies the equation of time.
delta_t_seconds ¶
Approximate Delta-T for a decimal year.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
year
|
float
|
Decimal Gregorian year. |
required |
Returns:
| Type | Description |
|---|---|
float
|
Approximate |
Source code in src/fortune_telling_core/astronomy/deltat.py
jd_tt_from_utc ¶
Convert a UTC Julian day to Terrestrial Time.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
jd_utc
|
float
|
Julian day on the UTC/UT scale. |
required |
Returns:
| Type | Description |
|---|---|
float
|
Julian day adjusted by the built-in Delta-T approximation. |
Source code in src/fortune_telling_core/astronomy/deltat.py
julian_centuries ¶
Convert a Julian day to Julian centuries since J2000.0.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
jd
|
float
|
Julian day in any compatible time scale. |
required |
Returns:
| Type | Description |
|---|---|
float
|
Centuries elapsed since Julian day 2451545.0. |
Source code in src/fortune_telling_core/astronomy/julian.py
julian_day_from_date ¶
Return the midnight Julian day number for a Gregorian date.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
year
|
int
|
Gregorian calendar year. |
required |
month
|
int
|
Gregorian calendar month, from 1 to 12. |
required |
day
|
int
|
Gregorian day of month. |
required |
Returns:
| Type | Description |
|---|---|
int
|
The integer Julian day number for midnight UTC on the date. |
Source code in src/fortune_telling_core/astronomy/julian.py
julian_day_utc ¶
Convert an aware civil datetime to a UTC Julian day.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
value
|
datetime
|
A timezone-aware datetime. Naive datetimes are rejected by the shared time coercion helper. |
required |
Returns:
| Type | Description |
|---|---|
float
|
The Julian day as a float, including the fractional day. |
Raises:
| Type | Description |
|---|---|
ValidationError
|
If |
Source code in src/fortune_telling_core/astronomy/julian.py
civil_day_number ¶
Return the integer civil day number of a TT Julian day in a timezone.
The result is comparable with
:func:fortune_telling_core.astronomy.julian.julian_day_from_date for the
same local date.
Source code in src/fortune_telling_core/astronomy/lunisolar.py
new_moon_on_or_before ¶
Return the Julian day (TT) of the last new moon at or before jd_tt.
Source code in src/fortune_telling_core/astronomy/lunisolar.py
to_lunisolar ¶
Convert a TT Julian day to a lunisolar (旧暦) date.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
jd_tt
|
float
|
Instant to convert, as a Terrestrial-Time Julian day. |
required |
tz_hours
|
float
|
Civil timezone offset (hours east of UTC) in which lunar
day boundaries are taken. Japanese 旧暦 uses |
required |
ephemeris
|
Ephemeris
|
Ephemeris backend for Sun and Moon positions. |
required |
Returns:
| Type | Description |
|---|---|
LunisolarDate
|
The lunisolar date. |
Source code in src/fortune_telling_core/astronomy/lunisolar.py
147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 | |
normalize_degrees ¶
Normalize an angle to the half-open range [0, 360).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
value
|
float
|
Angle in degrees. |
required |
Returns:
| Type | Description |
|---|---|
float
|
The equivalent angle in degrees, from 0 inclusive to 360 exclusive. |
Source code in src/fortune_telling_core/astronomy/position.py
equation_of_time ¶
Approximate the equation of time for a Julian day.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
jd_tt
|
float
|
Julian day on the Terrestrial Time scale. |
required |
ephemeris
|
Ephemeris
|
Ephemeris backend used for the Sun's longitude. |
required |
Returns:
| Type | Description |
|---|---|
float
|
Apparent solar time minus mean solar time, in minutes. |
Raises:
| Type | Description |
|---|---|
EphemerisError
|
If the backend cannot compute the Sun. |
Source code in src/fortune_telling_core/astronomy/solar.py
solar_longitude_crossing ¶
solar_longitude_crossing(
target_deg: float,
jd_start: float,
jd_end: float,
ephemeris: Ephemeris,
*,
tolerance_deg: float = 1e-06,
max_iterations: int = 100,
) -> float
Find when the Sun crosses a target longitude inside a bracket.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
target_deg
|
float
|
Target apparent solar longitude in degrees. |
required |
jd_start
|
float
|
Start of the Julian-day search bracket. |
required |
jd_end
|
float
|
End of the Julian-day search bracket. |
required |
ephemeris
|
Ephemeris
|
Ephemeris backend used for solar positions. |
required |
tolerance_deg
|
float
|
Maximum remaining longitude error before returning. |
1e-06
|
max_iterations
|
int
|
Maximum bisection iterations. |
100
|
Returns:
| Type | Description |
|---|---|
float
|
Julian day of the crossing. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the target is not bracketed by the supplied interval. |
EphemerisError
|
If the backend cannot compute the Sun. |
Source code in src/fortune_telling_core/astronomy/solar.py
sun_longitude ¶
Return the Sun's apparent ecliptic longitude.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
jd_tt
|
float
|
Julian day on the Terrestrial Time scale. |
required |
ephemeris
|
Ephemeris
|
Ephemeris backend used to compute the Sun's position. |
required |
Returns:
| Type | Description |
|---|---|
float
|
Apparent geocentric longitude in degrees. |
Raises:
| Type | Description |
|---|---|
EphemerisError
|
If the backend does not support the Sun. |
Source code in src/fortune_telling_core/astronomy/solar.py
adjacent_jie_crossing ¶
Find the previous or next sectional solar-term crossing.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
jd_tt
|
float
|
Julian day on the Terrestrial Time scale. |
required |
ephemeris
|
Ephemeris
|
Ephemeris backend used for solar positions. |
required |
forward
|
bool
|
If true, find the next jie. Otherwise find the previous jie. |
required |
Returns:
| Type | Description |
|---|---|
float
|
Julian day of the adjacent sectional solar-term crossing. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If no crossing is found in the fixed 40-day bracket. |
EphemerisError
|
If the backend cannot compute the Sun. |
Source code in src/fortune_telling_core/astronomy/solar_terms.py
lichun_crossing ¶
Find the Lichun crossing for a Gregorian year.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
year
|
int
|
Gregorian calendar year. |
required |
ephemeris
|
Ephemeris
|
Ephemeris backend used for solar positions. |
required |
Returns:
| Type | Description |
|---|---|
float
|
Julian day on the Terrestrial Time scale when the Sun crosses |
float
|
315 degrees. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the crossing is not found in the built-in bracket. |
EphemerisError
|
If the backend cannot compute the Sun. |
Source code in src/fortune_telling_core/astronomy/solar_terms.py
solar_month_index ¶
Return the sectional solar month index for a longitude.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
solar_longitude
|
float
|
Apparent solar longitude in degrees. |
required |
Returns:
| Type | Description |
|---|---|
int
|
Zero-based index where 0 begins at Lichun, 315 degrees. |
Source code in src/fortune_telling_core/astronomy/solar_terms.py
solar_term_crossing ¶
solar_term_crossing(
target: float,
jd_start: float,
jd_end: float,
ephemeris: Ephemeris,
) -> float
Find a solar-term crossing by scanning one-day brackets.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
target
|
float
|
Target apparent solar longitude in degrees. |
required |
jd_start
|
float
|
Start Julian day of the search interval. |
required |
jd_end
|
float
|
End Julian day of the search interval. |
required |
ephemeris
|
Ephemeris
|
Ephemeris backend used for solar positions. |
required |
Returns:
| Type | Description |
|---|---|
float
|
Julian day of the first crossing found in the interval. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the crossing is not found. |
EphemerisError
|
If the backend cannot compute the Sun. |
Source code in src/fortune_telling_core/astronomy/solar_terms.py
effective_datetime ¶
effective_datetime(
value: datetime,
longitude: float,
time_model: TimeModel,
ephemeris: Ephemeris,
) -> datetime
Apply a tradition time model to an aware datetime.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
value
|
datetime
|
Timezone-aware source datetime. |
required |
longitude
|
float
|
Geographic longitude in degrees east. |
required |
time_model
|
TimeModel
|
Time adjustment model to apply. |
required |
ephemeris
|
Ephemeris
|
Ephemeris backend used by true solar time. |
required |
Returns:
| Type | Description |
|---|---|
datetime
|
The adjusted datetime. The original timezone information is preserved. |
Raises:
| Type | Description |
|---|---|
EphemerisError
|
If true solar time is requested and the backend cannot compute the Sun. |