npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

nrel-spa

v2.0.1

Published

Pure JavaScript implementation of the NREL Solar Position Algorithm (SPA). Calculates solar zenith, azimuth, sunrise, sunset, and solar noon for any location and date.

Readme

nrel-spa

npm version CI license

Pure JavaScript implementation of the NREL Solar Position Algorithm (SPA). Computes solar zenith angle, azimuth, sunrise, sunset, and solar noon for any location and date. Validated to produce identical results to the original NREL C reference implementation.

Installation

npm install nrel-spa

Quick Start

import { getSpa, calcSpa } from 'nrel-spa';

const date = new Date('2025-06-21T00:00:00Z'); // UTC date/time

// Minimum required parameters
const raw = getSpa(date, 40.7128, -74.006, -4); // New York, EDT (UTC-4)
console.log(raw.sunrise);   // 5.417 (fractional hours)
console.log(raw.solarNoon); // 12.965
console.log(raw.sunset);    // 20.509

// Formatted output — same parameters, HH:MM:SS strings
const fmt = calcSpa(date, 40.7128, -74.006, -4);
console.log(fmt.sunrise);   // "05:25:03"
console.log(fmt.solarNoon); // "12:57:56"
console.log(fmt.sunset);    // "20:30:35"

// With atmospheric parameters and custom zenith angles (twilight)
const result = calcSpa(
  date,
  40.7128,          // latitude (degrees, negative = south)
  -74.006,          // longitude (degrees, negative = west)
  -4,               // timezone offset in hours from UTC
  {
    elevation: 10,  // meters above sea level
    pressure: 1013, // millibars
    temperature: 20 // degrees Celsius
  },
  [96, 102, 108],   // civil, nautical, astronomical twilight zenith angles
);
console.log(result.sunrise);        // "05:25:03"
console.log(result.angles[0]);      // { sunrise: "04:53:...", sunset: "20:02:..." }

API

getSpa(date, latitude, longitude, timezone?, options?, angles?)

Returns raw numerical values. Sunrise, solarNoon, and sunset are fractional hours (e.g., 5.417 for 05:25).

| Parameter | Type | Required | Description | | --- | --- | --- | --- | | date | Date | Yes | UTC date and time for the calculation | | latitude | number | Yes | Observer latitude in degrees (-90 to 90) | | longitude | number | Yes | Observer longitude in degrees (-180 to 180) | | timezone | number \| null | No | Hours from UTC. Default: 0 | | options | SpaOptions \| null | No | Atmospheric and calculation parameters | | angles | number[] | No | Custom zenith angles in degrees for twilight |

Returns: SpaResult (or SpaResultWithAngles when angles is provided)

interface SpaResult {
  zenith:    number; // topocentric zenith angle (degrees)
  azimuth:   number; // topocentric azimuth, eastward from north (degrees)
  sunrise:   number; // local sunrise time (fractional hours)
  solarNoon: number; // local solar noon (fractional hours)
  sunset:    number; // local sunset time (fractional hours)
}

calcSpa(date, latitude, longitude, timezone?, options?, angles?)

Same as getSpa(), but formats sunrise, solarNoon, and sunset as HH:MM:SS strings. Returns "N/A" for those fields during polar day or polar night.

formatTime(hours)

Converts fractional hours to HH:MM:SS format. Returns "N/A" for negative or non-finite values.

import { formatTime } from 'nrel-spa';
formatTime(5.417489); // "05:25:03"
formatTime(-1);       // "N/A"

SpaOptions

| Option | Type | Default | Description | | --- | --- | --- | --- | | elevation | number | 0 | Observer elevation in meters | | pressure | number | 1013 | Atmospheric pressure in millibars | | temperature | number | 15 | Temperature in degrees Celsius | | delta_ut1 | number | 0 | UT1-UTC correction in seconds | | delta_t | number | 67 | TT-UTC difference in seconds | | slope | number | 0 | Surface slope from horizontal (degrees) | | azm_rotation | number | 0 | Surface azimuth rotation from south (degrees) | | atmos_refract | number | 0.5667 | Atmospheric refraction at sunrise/sunset (degrees) | | function | SpaFunctionCode | SPA_ZA_RTS | Which outputs to compute |

Function Codes

import { SPA_ZA, SPA_ZA_INC, SPA_ZA_RTS, SPA_ALL } from 'nrel-spa';

| Code | Value | Computes | | --- | --- | --- | | SPA_ZA | 0 | Zenith and azimuth only | | SPA_ZA_INC | 1 | Zenith, azimuth, and incidence angle | | SPA_ZA_RTS | 2 | Zenith, azimuth, sunrise, noon, sunset (default) | | SPA_ALL | 3 | All outputs |

Architecture

The core algorithm in lib/spa.js is a direct port of the NREL SPA C source to JavaScript, preserving the same mathematical structure: 63 periodic nutation terms, full heliocentric coordinate calculation, topocentric correction, and atmospheric refraction. It has been validated to produce output identical to the C reference within rounding.

The TypeScript wrapper in src/ provides the public API, input validation, and the formatTime utility. The package ships dual CJS and ESM builds via tsup, with full TypeScript definitions.

See the wiki for a detailed breakdown of the algorithm and architecture.

Compatibility

  • Node.js: 20, 22, 24 (CI tested)
  • ESM: import { getSpa } from 'nrel-spa'
  • CommonJS: const { getSpa } = require('nrel-spa')
  • TypeScript: Full type definitions included

Bundlers (Vite, Webpack, esbuild, Rollup) work via the exports map in package.json.

TypeScript

import {
  getSpa,
  calcSpa,
  formatTime,
  SPA_ZA,
  SPA_ZA_INC,
  SPA_ZA_RTS,
  SPA_ALL,
  type SpaOptions,
  type SpaResult,
  type SpaFormattedResult,
  type SpaAnglesResult,
  type SpaFormattedAnglesResult,
  type SpaResultWithAngles,
  type SpaFormattedResultWithAngles,
  type SpaFunctionCode,
} from 'nrel-spa';

Documentation

Full documentation is available on the GitHub Wiki:

Related

Other packages in this collection:

  • solar-spa: WASM build of the same algorithm, async, for high-throughput batch calculations
  • pray-calc: Islamic prayer times built on nrel-spa

Acknowledgments

The core algorithm is a JavaScript port of the Solar Position Algorithm (SPA) developed by Ibrahim Reda and Afshin Andreas at the National Renewable Energy Laboratory (NREL):

Reda, I., Andreas, A. (2004). "Solar Position Algorithm for Solar Radiation Applications." Solar Energy, 76(5), 577-589. https://doi.org/10.1016/j.solener.2003.12.003

Original source: https://midcdmz.nrel.gov/spa/

License

MIT (TypeScript wrapper and build tooling). The core algorithm in lib/spa.js is a port of NREL's SPA C source, which is subject to its own terms. See the LICENSE file for the full notice.