This repository contains the Swiss Ephemeris, packaged with a wrapper written in Swift. All Swiss Ephemeris C code has not been modified, is accessible and can be called directly after importing the package. If you program in C, or are familiar with the original library it is possible to ignore the Swift code.
I am working on a Swift wrapper for convenience and accessibility for developers who are not familiar with C, but would like to leverage the power of this ephemeris. This is still a work in progress, and the current state of the wrapper only utilizes a small percentage of what the ephemeris offers.
The package is available through Swift Package Manager
This project is under the licensing model
a) GNU public license version 2 or later outlined in the section on
How to license the Swiss Ephemeris on the description of the Astrodienst Swiss Ephemeris. Please familiarize yourself with the licensing requirements before getting started.
At the moment the JPL-Ephemeris files that are included are the following.
|Planet||sepl_18.se1||1800 AD – 2399 AD|
|Moon||semo_18.se1||1800 AD – 2399 AD|
|Asteroid||seas_18.se1||1800 AD – 2399 AD|
If you wish to support dates outside of the era 1800 AD – 2399 AD then please include the additional JPL files in
Setting the Ephemeris Files
It is crucial that the path to the JPL-Ephemeris files is set at runtime before getting any astrological data. Various documentation and examples that exist out there have this step as optional, but the functionality of this library will be greatly limited if not taken. Since Swift tools version 5.3 it is possible to bundle resources as a part of a Swift package. This allows adding the JPL file as a resource to the package, and setting the resource path as the path to the ephemeris files.
This method should be called once at the entry point of your app. By default, the
Bundle.module resource path of this package that holds the JPL files is set as the ephemeris path. However, It is also possible to pass in
path parameter to set a different ephemeris files that you have bundled in your app.
// Sets ephemeris path to the JPL resources. JPLFileManager.setEphemerisPath() // Set a path to JPL files added to your app bundle. let path = "URL to your ephemeris files" JPLFileManager.setEphemerisPath(path: )
Astronomical and Astrological Coordinates
To get coordinate data for a planet, moon or lunar node create a
T is the type of IPL body category. This type contains more than astrological data, including the latitudinal and longitudinal speed, and distance in AU for any planetary body.
let now = Date() // Astronomical and astrological information for the moon at this point in time. let moonCoordinate = Coordinate<Planet>(planet: .moon, date: now) // The moon's longitude. moonCoordinate.longitude // The moon's latitude. moonCoordinate.latitude // The distance in AU from the earth. moonCoordinate.distance // The speed in longitude (deg/day). moonCoordinate.speedLongitude // The speed in latitude (deg/day). moonCoordinate.speedLatitude // The speed in distance (AU/day). moonCoordinate.speedDistance
Astrological information about the tropical and sidereal zodiacal locations of a celestial body is also available from the same
Coordinate type through the
// Date for 12.14.2019 13:39 UT/GMT let date = Date(timeIntervalSince1970: 598023482.487818) // Astronomical and astrological information for the sun on December 14th 2019. let sunCoordinate = Coordinate<Planet>(planet: .sun, date: date) // This will return 21 Degrees Sagittarius ♐︎ 46' 49''. sunCoordinate.tropical.formatted // It is also possible to get the degree, minute and second as properties of the Coordinate. let degree = sunCoordinate.tropical.degree let minute = sunCoordinate.tropical.minute let second = sunCoordinate.tropical.second
To create an aspect between two
CelestialBody types use
Transit contains start and end date properties of the transit with an accuracy of one hour.
// Create a pair of celestial bodies. let moonTrueNode = Pair<Planet, LunarNorthNode>(a: .moon, b: .trueNode) // Transit contains start and end date properties. let transit = Transit(pair: moonTrueNode, date: Date(), orb: 8.0)
To get the house layout for a date, location, and house system create a
HouseSystem determines the type of astrological house system that is set. All house
Cusp properties can be used to create an
Aspect with a
CelestialBody. Zodiacal information for each cusp is available through the
// Create a date and location let now = Date() let latitude: Double = 37.5081153 let longitude: Double = -122.2854528 // All house cusps, Ascendent, and MC are properties on `houses`. let houses = HouseCusps(date: date, latitude: latitude, longitude: longitude, houseSystem: .placidus) // Get the formatted sidereal astrological position. let ascendentFormatted = houses.ascendent.sidereal.formatted // Or the precise degree for the sidereal zodiac. let degree = houses.ascendent.sidereal.degree
enum types for
LunarNorthNode correspond to IPL numbers in the ephemeris. Other celestial bodies such as stars as fictitious points still need to be added. The type numbering is not comprehensive, but can be easily extended to match the celestial body that is not available in the package. All of the types conform to the
CelestialBody protocol which makes it so different categories of celestial points can be mapped to the tropical zodiac both in aspect and position.
To get the most out of the ephemeris, you may need to make a lot of calculations at one time. Making calculations in mass is an expensive operation. and should never be done on the main thread. If you are making hundreds of calculations at one time it is recommended to use a
BatchRequest for increased performance and to avoid the undefined behavior that results from making a high number of calculations concurrently.
For example, to calculate the exact coordinates for the sun for a period of time:
let request = PlanetsRequest(body: .sun) let now = Date() let end = now.addingTimeInterval(60 * 60 * 24 * 30) // Asynchronously returns an array of `.sun` `Coordinate`s for every hour between now and 720 hours in the future. let batchCoordinates = await request.fetch(start: now, end: end, interval: 60.0 * 60.0)