Skip to content

Repository files navigation

@yogur/solpos

High-accuracy topocentric solar position, solar transit, and arbitrary-horizon crossing calculations for TypeScript.

@yogur/solpos is an ESM package for Node.js 20 or later and browser-oriented runtimes. It provides:

  • geometric and optional atmosphere-corrected topocentric solar position;
  • daily solar transit;
  • sunrise/sunset and civil, nautical, and astronomical twilight;
  • custom geometric solar-center horizons;
  • explicit polar and civil-day-boundary outcomes; and
  • a convenience Delta-T estimator with caller overrides for precision-sensitive work.

The package is deterministic and offline. Named time-zone calculations use the IANA data.

Installation

npm install @yogur/solpos

Solar position

import { calculateSolarPosition } from "@yogur/solpos";

const position = calculateSolarPosition({
  instant: {
    epochMilliseconds: Date.UTC(2026, 6, 17, 9, 0, 0),
  },
  observer: {
    latitudeDegrees: 33.8938,
    longitudeDegrees: 35.5018,
    elevationMeters: 50,
  },
  atmosphere: {
    pressureMillibars: 1013.25,
    temperatureCelsius: 25,
  },
});

console.log(position.azimuthDegrees);
console.log(position.elevationDegrees);
console.log(position.apparent?.elevationDegrees);

Azimuth is measured eastward from true north in [0, 360) degrees. Elevation is geometric unless read from the optional apparent result. Atmospheric refraction is evaluated only when both pressure and temperature are supplied, and its correction is zero below the geometric horizon.

Daily events

import { calculateDailySolarEvents } from "@yogur/solpos";

const events = calculateDailySolarEvents({
  date: { year: 2026, month: 7, day: 17 },
  timeZone: "Asia/Beirut",
  location: {
    latitudeDegrees: 33.8938,
    longitudeDegrees: 35.5018,
  },
  horizons: ["sunrise-sunset", "civil-twilight", { elevationDegrees: -16 }],
});

console.log(new Date(events.transit.epochMilliseconds));

for (const event of events.horizons) {
  switch (event.outcome.kind) {
    case "crossings":
      console.log(
        new Date(event.outcome.ascending.epochMilliseconds),
        new Date(event.outcome.descending.epochMilliseconds),
      );
      break;
    case "ascending-only":
      console.log(new Date(event.outcome.ascending.epochMilliseconds));
      break;
    case "descending-only":
      console.log(new Date(event.outcome.descending.epochMilliseconds));
      break;
    case "never-above":
    case "never-below":
      console.log(event.outcome.kind);
      break;
  }
}

The date is proleptic Gregorian with astronomical year numbering. timeZone accepts an IANA identifier or a textual fixed offset such as "+03:00" or "UTC". Returned instants are integer Unix epoch milliseconds and always belong to the requested local civil day.

Standard horizons are geometric solar-center elevations:

Name Elevation
sunrise-sunset -0.8333
civil-twilight -6
nautical-twilight -12
astronomical-twilight -18

Custom horizons do not receive hidden corrections for terrain, observer elevation, horizon dip, solar radius, or atmosphere. Incorporate any desired adjustment into elevationDegrees.

Time scales

Calculations require Delta-T (TT - UT1) and UT1 - UTC. By default, the package estimates Delta-T and uses UT1 - UTC = 0. Every result reports the values and their sources.

const position = calculateSolarPosition({
  instant: { epochMilliseconds },
  observer,
  timeScales: {
    deltaTSeconds: 69.2,
    ut1MinusUtcSeconds: 0.04,
  },
});

The built-in estimator covers years -1999 through 3000. Supply deltaTSeconds explicitly outside that interval or when an observed or more suitable modeled value is available. See the Delta-T model for provenance and limitations.

Errors

  • TypeError reports wrong runtime shapes, primitive types, and non-finite numbers.
  • RangeError reports values outside the documented ranges, invalid dates or zones, and exceptional civil days that cannot fit the singular result shape.
  • SolarCalculationError with code "NUMERICAL_FAILURE" reports an unexpected finite-input numerical failure.

never-above and never-below are ordinary horizon outcomes, not errors.

The API reference defines all units, ranges, calendar behavior, outcomes, and error conditions.

Accuracy and physical limits

Published worked values and stage calculations guard conformance to the selected mathematical procedure. A separately sourced regression corpus covers both hemispheres, equatorial and high latitudes, atmospheric inputs, civil-day transitions, custom horizons, single-direction crossings, polar day, and polar night.

Computational agreement is not the same as physical prediction accuracy. The revised report states approximately +/-0.0003 deg uncertainty for solar zenith and azimuth over years -2000 through 6000. Event observations also depend on atmosphere, terrain, the visible horizon, solar-radius convention, Earth-orientation inputs, and time-zone data. See the conformance record for measured ceilings and maxima.

Scope

The package intentionally does not expose astronomical intermediate stages, coefficient arrays, surface incidence, irradiance, formatted local times, terrain models, or application-specific scheduling policy.

Method and credit

The implementation follows the selected procedures in:

Ibrahim Reda and Afshin Andreas, Solar Position Algorithm for Solar Radiation Applications (Revised), NREL/TP-560-34302, revised January 2008 (report, DOI).

The repository preserves the reviewed mathematical procedure and conformance decisions used to implement the focused package surface.

License

MIT

About

TypeScript library based on NREL’s Solar Position Algorithm (SPA), for observer-relative solar position, transit, and arbitrary-horizon crossings.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages