A Swift library for calculating positions of the Sun, Moon, planets, and fixed stars. Predicts moon phases, eclipses, transits, and rise/set times. Handles coordinate transformations across equatorial, ecliptic, horizontal, and galactic systems. Sub-arcminute accuracy, derived from NASA JPL ephemeris data. Runs entirely on-device.
AstronomyKit is a Swift wrapper around Don Cross’ Astronomy Engine C library.
- Positions for the Sun, Moon, planets, and Jupiter's moons
- Moon phase angles, quarters, illumination, and libration
- User-defined fixed stars from J2000 catalog coordinates
- Gravity-simulated position for 2060 Chiron
- Rise, set, and culmination times
- Lunar and solar eclipse predictions
- Equinoxes and solstices
- Coordinate transforms across equatorial, ecliptic, horizon, and galactic systems
- Apsides, elongation, and transits
- Full
Sendableconformance for Swift 6
Add to your Package.swift:
dependencies: [
.package(url: "https://github.com/heirloomlogic/AstronomyKit.git", from: "0.2.0")
]Or in Xcode: File → Add Package Dependencies and enter the repository URL.
import AstronomyKit
// Your location
let observer = Observer(latitude: 40.7128, longitude: -74.0060) // NYC
// Current moon phase
let angle = try Moon.phaseAngle(at: .now)
print("\(Moon.emoji(for: angle)) \(Moon.phaseName(for: angle))")
// Next sunrise
if let sunrise = try CelestialBody.sun.riseTime(after: .now, from: observer) {
print("Sunrise: \(sunrise.date)")
}
// Where is Mars?
let mars = try CelestialBody.mars.horizon(at: .now, from: observer)
print("Mars: \(mars.altitude)° \(mars.compassDirection)")// Current time
let now = AstroTime.now
// From components
let time = AstroTime(year: 2025, month: 6, day: 21, hour: 12)
// From Foundation Date
let time = AstroTime(Date())
// Time arithmetic
let tomorrow = now.addingDays(1)
let nextHour = now.addingHours(1)let seattle = Observer(latitude: 47.6062, longitude: -122.3321)
let denver = Observer(latitude: 39.7392, longitude: -104.9903, height: 1609)
// Built-in
let greenwich = Observer.greenwich// Available bodies
let planets = CelestialBody.planets // Mercury through Neptune
let galileanMoons = CelestialBody.galileanMoons // Io, Europa, Ganymede, Callisto
// Body properties
print(CelestialBody.mars.name) // "Mars"
print(CelestialBody.mars.orbitalPeriod) // ~686 days// Horizon coordinates (altitude/azimuth)
let horizon = try CelestialBody.jupiter.horizon(at: .now, from: observer)
print("Altitude: \(horizon.altitude)°")
print("Azimuth: \(horizon.azimuth)° (\(horizon.compassDirection))")
// Equatorial coordinates (RA/Dec)
let eq = try CelestialBody.saturn.equatorial(at: .now)
print("RA: \(eq.rightAscensionFormatted)") // "02h 15m 30.2s"
print("Dec: \(eq.declinationFormatted)") // "+12° 34' 56.7""
// Distance from Sun
let au = try CelestialBody.mars.distanceFromSun(at: .now)// Current phase
let angle = try Moon.phaseAngle(at: .now)
print(Moon.phaseName(for: angle)) // "Waxing Gibbous"
print(Moon.emoji(for: angle)) // "🌔"
print(Moon.illumination(for: angle)) // 0.0 to 1.0
// Find specific phases
let nextFull = try Moon.searchPhase(.full, after: .now)
let nextNew = try Moon.searchPhase(.new, after: .now)
// All quarters in January 2025
let quarters = try Moon.quarters(
from: AstroTime(year: 2025, month: 1, day: 1),
to: AstroTime(year: 2025, month: 2, day: 1)
)// Define a star from J2000 catalog coordinates
let algol = FixedStar(
name: "Algol",
ra: 3.136148, // Right ascension in hours
dec: 40.9556, // Declination in degrees
distance: 92.95 // Distance in light-years
)
// Ecliptic longitude
let longitude = try algol.eclipticLongitude(at: .now)
print("Algol is at \(longitude)°")
// Horizon coordinates
let horizon = try algol.horizon(at: .now, from: observer)
print("Algol: \(horizon.altitude)° altitude")// Chiron's ecliptic longitude (commonly used in astrology)
let longitude = try Chiron.eclipticLongitude(at: .now)
print("Chiron is at \(longitude)°")
// Full ecliptic coordinates
let ecliptic = try Chiron.ecliptic(at: .now)
print("Longitude: \(ecliptic.longitude)°, Latitude: \(ecliptic.latitude)°")
// Horizon position for an observer
let horizon = try Chiron.horizon(at: .now, from: observer)
print("Chiron altitude: \(horizon.altitude)°")let sunrise = try CelestialBody.sun.riseTime(after: .now, from: observer)
let sunset = try CelestialBody.sun.setTime(after: .now, from: observer)
let moonrise = try CelestialBody.moon.riseTime(after: .now, from: observer)
// Upper culmination (transit)
let transit = try CelestialBody.sun.culmination(after: .now, from: observer)
print("Max altitude: \(transit.horizon.altitude)°")let seasons = try Seasons.forYear(2025)
print("Spring: \(seasons.marchEquinox)")
print("Summer: \(seasons.juneSolstice)")
print("Autumn: \(seasons.septemberEquinox)")
print("Winter: \(seasons.decemberSolstice)")// Next lunar eclipse
let lunar = try Eclipse.searchLunar(after: .now)
print("\(lunar.kind) lunar eclipse at \(lunar.peak)")
// Next solar eclipse
let solar = try Eclipse.searchGlobalSolar(after: .now)
if solar.kind == .total, let lat = solar.latitude, let lon = solar.longitude {
print("Total solar eclipse visible at \(lat)°, \(lon)°")
}
// All eclipses in 2025
let eclipses = try Eclipse.lunarEclipses(
from: AstroTime(year: 2025, month: 1, day: 1),
to: AstroTime(year: 2026, month: 1, day: 1)
)| Type | Description |
|---|---|
Apsis |
Perihelion/aphelion or perigee/apogee events |
AstroTime |
Time representation with UT/TT and Date conversion |
CelestialBody |
Enum of Sun, Moon, planets, and moons |
Chiron |
Gravity-simulated position for 2060 Chiron |
Constellation |
Constellation identification |
Ecliptic |
Ecliptic longitude and latitude coordinates |
Elongation |
Angular separation from the Sun |
Equatorial |
Right ascension and declination coordinates |
FixedStar |
User-defined star from J2000 coordinates |
GlobalSolarEclipse |
Solar eclipse with peak location |
GravitySimulation |
N-body gravity simulation |
Horizon |
Altitude and azimuth for local sky position |
Illumination |
Visual magnitude and phase fraction |
LagrangePoint |
L1-L5 point calculations |
Libration |
Lunar libration angles and distance |
LocalSolarEclipse |
Solar eclipse visibility from observer |
LunarEclipse |
Lunar eclipse event with timing and duration |
LunarNode |
Ascending/descending node events |
MoonPhase |
Lunar phase enum (new, first quarter, full, third quarter) |
Observer |
Geographic location (latitude, longitude, height) |
RotationMatrix |
Coordinate system transformations |
Seasons |
Equinox and solstice times for a year |
Transit |
Mercury/Venus solar transit |
DocC documentation is available. Build it locally:
swift package generate-documentation --target AstronomyKitOr in Xcode: Product → Build Documentation
Runtime: Swift 6.0+, macOS 13+ / iOS 16+ / tvOS 16+ / watchOS 9+.
Development: Xcode 26.3 (Swift 6.3). The swift-format build tool plugin is pinned to a toolchain; see Toolchain Alignment.
- Fallow — Lunar fasting companion. Calculates Ekadashi and moon cycle timing.
- Edict — Electional astrology planner. Scans planetary positions to find timing windows for decisions.
Contributions are welcome. See CONTRIBUTING.md for guidelines.
- Astronomy Engine by Don Cross — the underlying C library (see THIRD_PARTY_NOTICES)
MIT License. See LICENSE for details.