Swiss Ephemeris GO wrapper.
A complete Swiss Ephemeris wrapper for Go.
Swiss Ephemeris is the de-facto astronomical engine for astrology and high-precision
ephemeris work — planetary positions, houses, eclipses, fixed stars, and more.
sweg exposes its full C API to Go through cgo, so you can call it with native Go types.
jd := sweg.Julday(2025, 1, 1, 12.0, sweg.SeGregCal) // Julian day, 2025-01-01 12:00 UT
xx := make([]float64, 6) // results: lon, lat, dist, + their speeds
serr := make([]byte, 256) // error message buffer
sweg.CalcUt(jd, sweg.SeSun, sweg.SeflgSwieph|sweg.SeflgSpeed, xx, serr)
fmt.Printf("Sun longitude: %.4f°\n", xx[0]) // → 281.3234° (Capricorn)- Go 1.25+
- cgo enabled (
CGO_ENABLED=1) and a working C compiler (clang/gcc) - The bundled
libswe.sois a macOS / Apple-Silicon (arm64) library. On other platforms, buildlibsweyourself from the official Swiss Ephemeris C sources and put it where your linker and loader can find it (see below).
go get github.com/danielradosa/swegThe build works out of the box — cgo links against the bundled libswe.so.
The one thing to know: the binary it produces still has to find libswe.so
at run time. The library's install name is @rpath/libswe.so and Go bakes no rpath
into your binary, so without help you'll see:
dyld: Library not loaded: @rpath/libswe.so — no LC_RPATH's found
Pick whichever fix suits you (all verified):
A. Point the loader at the library at run time
# macOS — directory that contains libswe.so
DYLD_LIBRARY_PATH=/path/to/sweg ./yourapp
# Linux
LD_LIBRARY_PATH=/path/to/libswe ./yourappB. Bake the path into the binary at build time
CGO_LDFLAGS="-Wl,-rpath,/path/to/sweg" go build .
# ...then ./yourapp runs with no extra environment.C. Install the library system-wide — copy libswe.so to a standard loader
path (e.g. /usr/local/lib, then sudo ldconfig on Linux).
Tip: when you depend on
swegas a module,libswe.solives in the Go module cache ($(go env GOMODCACHE)/github.com/danielradosa/sweg@<version>/). Use that directory as the path above, or copy the file next to your binary.
package main
import (
"fmt"
"github.com/danielradosa/sweg"
)
func main() {
defer sweg.Close() // releases Swiss Ephemeris resources
// Optional: point at high-precision ephemeris data files (.se1).
// Without them, the library uses its built-in fallback automatically.
// sweg.SetEphePath([]byte("/path/to/ephe"))
jd := sweg.Julday(2025, 1, 1, 12.0, sweg.SeGregCal)
xx := make([]float64, 6)
serr := make([]byte, 256)
ret := sweg.CalcUt(jd, sweg.SeSun, sweg.SeflgSwieph|sweg.SeflgSpeed, xx, serr)
if ret < 0 {
fmt.Println("error:", string(serr))
return
}
fmt.Printf("Sun: lon=%.6f° lat=%.6f° dist=%.6f AU speed=%.6f°/day\n",
xx[0], xx[1], xx[2], xx[3])
}sweg mirrors the original C API one-to-one, so two conventions carry over:
| C idiom | In sweg |
What you do |
|---|---|---|
Output array (double*) |
[]float64 |
Pass a pre-sized slice, e.g. make([]float64, 6); results are written into it |
Error message (char*) |
serr []byte |
Pass make([]byte, 256); read it with string(serr) on error |
String input (char*) |
[]byte |
Pass []byte("Sirius") |
Return code (int) |
int32 |
Most calc functions return < 0 on error (message is in serr) |
So the pattern is always: allocate your output slices, call the function, check the return code, read the slices.
The full Swiss Ephemeris surface — 100 functions. The most-used groups:
| Area | Functions |
|---|---|
| Planet & body positions | Calc, CalcUt, CalcPctr, NodAps, NodApsUt, GetOrbitalElements |
| Fixed stars | Fixstar, FixstarUt, FixstarMag, Fixstar2, Fixstar2Ut |
| Houses & angles | Houses, HousesEx, HousesEx2, HousePos, HouseName, GauquelinSector |
| Eclipses & occultations | SolEclipseWhen*, LunEclipseWhen*, LunOccultWhen*, …How, …Where |
| Rise / set / transit / horizon | RiseTrans, RiseTransTrueHor, Azalt, AzaltRev, Refrac |
| Heliacal phenomena | HeliacalUt, HeliacalPhenoUt, VisLimitMag, HeliacalAngle |
| Dates & time | Julday, Revjul, UtcToJd, DateConversion, Deltat, Sidtime, TimeEqu |
| Sidereal / ayanamsa | SetSidMode, GetAyanamsa, GetAyanamsaUt, GetAyanamsaName |
| Setup & config | SetEphePath, SetJplFile, SetTopo, SetTidAcc, Version, GetPlanetName, Close |
| Coordinate & math utilities | Degnorm, SplitDeg, Cotrans, CalcEpsilon, DegMidp |
Constants are exported in Go-idiomatic CamelCase, e.g. bodies SeSun, SeMoon,
SeTrueNode; flags SeflgSwieph, SeflgSpeed, SeflgSidereal; calendars
SeGregCal, SeJulCal. See constants.go for the full list.
Swiss Ephemeris keeps global state and isn't thread-safe. sweg guards every call
with an internal mutex, so it's safe to call from multiple goroutines — calls are
serialized rather than run in parallel.
For maximum precision and the widest date range, download the Swiss Ephemeris data
files (.se1) from Astrodienst and point
to them with SetEphePath. Without them, the library falls back to its built-in
(Moshier) ephemeris automatically — lower precision, but no setup required.
Swiss Ephemeris is created and copyrighted by
Astrodienst AG, Zürich. It is dual-licensed under
the AGPL-3.0 or a commercial license — those terms govern the bundled
libswe library and any software you distribute that links against it. Review them
before shipping a product. This repository is a thin Go binding around that library;
the cgo glue was generated with c-for-go.