Installation
All PrayCalc packages are published to npm, written in TypeScript, and ship both ESM and CommonJS builds. Install only what you need.
Requirements
- Node.js 20 or later
- TypeScript 5.0 or later (optional but recommended)
- pnpm, npm, or yarn
pray-calc
The main prayer times engine. Supports all 14 standard calculation methods plus dynamic angle mode.
<span><span style="color: var(--shiki-token-function)">pnpm</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">add</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">pray-calc</span></span>
<span></span>
<span><span style="color: var(--shiki-token-keyword)">import</span><span style="color: var(--shiki-color-text)"> { getPrayerTimes } </span><span style="color: var(--shiki-token-keyword)">from</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string-expression)">'pray-calc'</span></span>
<span></span>
<span><span style="color: var(--shiki-token-keyword)">const</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-constant)">times</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-function)">getPrayerTimes</span><span style="color: var(--shiki-color-text)">({</span></span>
<span><span style="color: var(--shiki-color-text)"> date</span><span style="color: var(--shiki-token-keyword)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">new</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-function)">Date</span><span style="color: var(--shiki-color-text)">()</span><span style="color: var(--shiki-token-punctuation)">,</span></span>
<span><span style="color: var(--shiki-color-text)"> latitude</span><span style="color: var(--shiki-token-keyword)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-constant)">41.4993</span><span style="color: var(--shiki-token-punctuation)">,</span></span>
<span><span style="color: var(--shiki-color-text)"> longitude</span><span style="color: var(--shiki-token-keyword)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">-</span><span style="color: var(--shiki-token-constant)">81.6944</span><span style="color: var(--shiki-token-punctuation)">,</span></span>
<span><span style="color: var(--shiki-color-text)"> timezone</span><span style="color: var(--shiki-token-keyword)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string-expression)">'America/New_York'</span><span style="color: var(--shiki-token-punctuation)">,</span></span>
<span><span style="color: var(--shiki-color-text)"> method</span><span style="color: var(--shiki-token-keyword)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string-expression)">'ISNA'</span><span style="color: var(--shiki-token-punctuation)">,</span></span>
<span><span style="color: var(--shiki-color-text)">})</span></span>
<span></span>
<span><span style="color: var(--shiki-token-constant)">console</span><span style="color: var(--shiki-token-function)">.log</span><span style="color: var(--shiki-color-text)">(</span><span style="color: var(--shiki-token-constant)">times</span><span style="color: var(--shiki-color-text)">.fajr) </span><span style="color: var(--shiki-token-comment)">// e.g. "05:34"</span></span>
<span><span style="color: var(--shiki-token-constant)">console</span><span style="color: var(--shiki-token-function)">.log</span><span style="color: var(--shiki-color-text)">(</span><span style="color: var(--shiki-token-constant)">times</span><span style="color: var(--shiki-color-text)">.dhuhr) </span><span style="color: var(--shiki-token-comment)">// e.g. "13:02"</span></span>
<span><span style="color: var(--shiki-token-constant)">console</span><span style="color: var(--shiki-token-function)">.log</span><span style="color: var(--shiki-color-text)">(</span><span style="color: var(--shiki-token-constant)">times</span><span style="color: var(--shiki-color-text)">.asr) </span><span style="color: var(--shiki-token-comment)">// e.g. "16:28"</span></span>
<span><span style="color: var(--shiki-token-constant)">console</span><span style="color: var(--shiki-token-function)">.log</span><span style="color: var(--shiki-color-text)">(</span><span style="color: var(--shiki-token-constant)">times</span><span style="color: var(--shiki-color-text)">.maghrib) </span><span style="color: var(--shiki-token-comment)">// e.g. "19:47"</span></span>
<span><span style="color: var(--shiki-token-constant)">console</span><span style="color: var(--shiki-token-function)">.log</span><span style="color: var(--shiki-color-text)">(</span><span style="color: var(--shiki-token-constant)">times</span><span style="color: var(--shiki-color-text)">.isha) </span><span style="color: var(--shiki-token-comment)">// e.g. "21:12"</span></span>
<span></span>
nrel-spa
TypeScript port of the NREL Solar Position Algorithm. Used internally by pray-calc.
<span><span style="color: var(--shiki-token-function)">pnpm</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">add</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">nrel-spa</span></span>
<span></span>
<span><span style="color: var(--shiki-token-keyword)">import</span><span style="color: var(--shiki-color-text)"> { computeSolarPosition } </span><span style="color: var(--shiki-token-keyword)">from</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string-expression)">'nrel-spa'</span></span>
<span></span>
<span><span style="color: var(--shiki-token-keyword)">const</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-constant)">pos</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-function)">computeSolarPosition</span><span style="color: var(--shiki-color-text)">({</span></span>
<span><span style="color: var(--shiki-color-text)"> date</span><span style="color: var(--shiki-token-keyword)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">new</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-function)">Date</span><span style="color: var(--shiki-color-text)">()</span><span style="color: var(--shiki-token-punctuation)">,</span></span>
<span><span style="color: var(--shiki-color-text)"> latitude</span><span style="color: var(--shiki-token-keyword)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-constant)">41.4993</span><span style="color: var(--shiki-token-punctuation)">,</span></span>
<span><span style="color: var(--shiki-color-text)"> longitude</span><span style="color: var(--shiki-token-keyword)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">-</span><span style="color: var(--shiki-token-constant)">81.6944</span><span style="color: var(--shiki-token-punctuation)">,</span></span>
<span><span style="color: var(--shiki-color-text)"> elevation</span><span style="color: var(--shiki-token-keyword)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-constant)">200</span><span style="color: var(--shiki-token-punctuation)">,</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-comment)">// metres above sea level</span></span>
<span><span style="color: var(--shiki-color-text)"> pressure</span><span style="color: var(--shiki-token-keyword)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-constant)">1013.25</span><span style="color: var(--shiki-token-punctuation)">,</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-comment)">// millibars</span></span>
<span><span style="color: var(--shiki-color-text)"> temperature</span><span style="color: var(--shiki-token-keyword)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-constant)">15</span><span style="color: var(--shiki-token-punctuation)">,</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-comment)">// °C</span></span>
<span><span style="color: var(--shiki-color-text)"> deltaT</span><span style="color: var(--shiki-token-keyword)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-constant)">69.18</span><span style="color: var(--shiki-token-punctuation)">,</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-comment)">// seconds (ΔT for 2025)</span></span>
<span><span style="color: var(--shiki-color-text)">})</span></span>
<span></span>
<span><span style="color: var(--shiki-token-constant)">console</span><span style="color: var(--shiki-token-function)">.log</span><span style="color: var(--shiki-color-text)">(</span><span style="color: var(--shiki-token-constant)">pos</span><span style="color: var(--shiki-color-text)">.topocentricAltitude) </span><span style="color: var(--shiki-token-comment)">// degrees above horizon</span></span>
<span><span style="color: var(--shiki-token-constant)">console</span><span style="color: var(--shiki-token-function)">.log</span><span style="color: var(--shiki-color-text)">(</span><span style="color: var(--shiki-token-constant)">pos</span><span style="color: var(--shiki-color-text)">.topocentricAzimuth) </span><span style="color: var(--shiki-token-comment)">// degrees clockwise from north</span></span>
<span></span>
moon-sighting
JPL DE442S-based lunar crescent visibility. Requires downloading the kernel file separately (see package README).
<span><span style="color: var(--shiki-token-function)">pnpm</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">add</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">moon-sighting</span></span>
<span></span>
<span><span style="color: var(--shiki-token-keyword)">import</span><span style="color: var(--shiki-color-text)"> { getMoonSightingReport } </span><span style="color: var(--shiki-token-keyword)">from</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string-expression)">'moon-sighting'</span></span>
<span></span>
<span><span style="color: var(--shiki-token-keyword)">const</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-constant)">report</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">await</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-function)">getMoonSightingReport</span><span style="color: var(--shiki-color-text)">({</span></span>
<span><span style="color: var(--shiki-color-text)"> date</span><span style="color: var(--shiki-token-keyword)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">new</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-function)">Date</span><span style="color: var(--shiki-color-text)">(</span><span style="color: var(--shiki-token-string-expression)">'2025-03-01'</span><span style="color: var(--shiki-color-text)">)</span><span style="color: var(--shiki-token-punctuation)">,</span></span>
<span><span style="color: var(--shiki-color-text)"> latitude</span><span style="color: var(--shiki-token-keyword)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-constant)">21.3891</span><span style="color: var(--shiki-token-punctuation)">,</span></span>
<span><span style="color: var(--shiki-color-text)"> longitude</span><span style="color: var(--shiki-token-keyword)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-constant)">39.8579</span><span style="color: var(--shiki-token-punctuation)">,</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-comment)">// Mecca</span></span>
<span><span style="color: var(--shiki-color-text)">})</span></span>
<span></span>
<span><span style="color: var(--shiki-token-constant)">console</span><span style="color: var(--shiki-token-function)">.log</span><span style="color: var(--shiki-color-text)">(</span><span style="color: var(--shiki-token-constant)">report</span><span style="color: var(--shiki-color-text)">.yallopCriteria) </span><span style="color: var(--shiki-token-comment)">// 'A' | 'B' | 'C' | 'D' | 'F'</span></span>
<span><span style="color: var(--shiki-token-constant)">console</span><span style="color: var(--shiki-token-function)">.log</span><span style="color: var(--shiki-color-text)">(</span><span style="color: var(--shiki-token-constant)">report</span><span style="color: var(--shiki-color-text)">.odehCriteria) </span><span style="color: var(--shiki-token-comment)">// 'visible' | 'not-visible' | 'marginal'</span></span>
<span></span>
moon-cycle
Maps any date/time to a NASA SVS moon phase image frame.
<span><span style="color: var(--shiki-token-function)">pnpm</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">add</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">moon-cycle</span></span>
<span></span>
<span><span style="color: var(--shiki-token-keyword)">import</span><span style="color: var(--shiki-color-text)"> { cycleMonth</span><span style="color: var(--shiki-token-punctuation)">,</span><span style="color: var(--shiki-color-text)"> cdnUrl } </span><span style="color: var(--shiki-token-keyword)">from</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string-expression)">'moon-cycle'</span></span>
<span></span>
<span><span style="color: var(--shiki-token-keyword)">const</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-constant)">frames</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-function)">cycleMonth</span><span style="color: var(--shiki-color-text)">({ year</span><span style="color: var(--shiki-token-keyword)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-constant)">2025</span><span style="color: var(--shiki-token-punctuation)">,</span><span style="color: var(--shiki-color-text)"> month</span><span style="color: var(--shiki-token-keyword)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-constant)">3</span><span style="color: var(--shiki-color-text)"> })</span></span>
<span><span style="color: var(--shiki-token-keyword)">const</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-constant)">imageUrl</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-function)">cdnUrl</span><span style="color: var(--shiki-color-text)">(frames[</span><span style="color: var(--shiki-token-constant)">0</span><span style="color: var(--shiki-color-text)">])</span></span>
<span><span style="color: var(--shiki-token-constant)">console</span><span style="color: var(--shiki-token-function)">.log</span><span style="color: var(--shiki-color-text)">(imageUrl) </span><span style="color: var(--shiki-token-comment)">// jsDelivr CDN URL for the frame image</span></span>
<span></span>
hijri-core
Zero-dependency Hijri calendar engine.
<span><span style="color: var(--shiki-token-function)">pnpm</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">add</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">hijri-core</span></span>
<span></span>
<span><span style="color: var(--shiki-token-keyword)">import</span><span style="color: var(--shiki-color-text)"> { toHijri</span><span style="color: var(--shiki-token-punctuation)">,</span><span style="color: var(--shiki-color-text)"> toGregorian } </span><span style="color: var(--shiki-token-keyword)">from</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string-expression)">'hijri-core'</span></span>
<span></span>
<span><span style="color: var(--shiki-token-keyword)">const</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-constant)">hijri</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-function)">toHijri</span><span style="color: var(--shiki-color-text)">(</span><span style="color: var(--shiki-token-keyword)">new</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-function)">Date</span><span style="color: var(--shiki-color-text)">(</span><span style="color: var(--shiki-token-string-expression)">'2025-03-29'</span><span style="color: var(--shiki-color-text)">))</span></span>
<span><span style="color: var(--shiki-token-constant)">console</span><span style="color: var(--shiki-token-function)">.log</span><span style="color: var(--shiki-color-text)">(hijri) </span><span style="color: var(--shiki-token-comment)">// { year: 1446, month: 9, day: 29 }</span></span>
<span></span>
<span><span style="color: var(--shiki-token-keyword)">const</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-constant)">greg</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-function)">toGregorian</span><span style="color: var(--shiki-color-text)">({ year</span><span style="color: var(--shiki-token-keyword)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-constant)">1446</span><span style="color: var(--shiki-token-punctuation)">,</span><span style="color: var(--shiki-color-text)"> month</span><span style="color: var(--shiki-token-keyword)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-constant)">10</span><span style="color: var(--shiki-token-punctuation)">,</span><span style="color: var(--shiki-color-text)"> day</span><span style="color: var(--shiki-token-keyword)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-constant)">1</span><span style="color: var(--shiki-color-text)"> })</span></span>
<span><span style="color: var(--shiki-token-constant)">console</span><span style="color: var(--shiki-token-function)">.log</span><span style="color: var(--shiki-color-text)">(greg) </span><span style="color: var(--shiki-token-comment)">// Date object: 2025-03-30</span></span>
<span></span>
luxon-hijri
Hijri/Gregorian conversion with Luxon. Requires luxon as a peer dependency.
<span><span style="color: var(--shiki-token-function)">pnpm</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">add</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">luxon-hijri</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">luxon</span></span>
<span></span>
<span><span style="color: var(--shiki-token-keyword)">import</span><span style="color: var(--shiki-color-text)"> { toHijri</span><span style="color: var(--shiki-token-punctuation)">,</span><span style="color: var(--shiki-color-text)"> formatHijriDate } </span><span style="color: var(--shiki-token-keyword)">from</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string-expression)">'luxon-hijri'</span></span>
<span><span style="color: var(--shiki-token-keyword)">import</span><span style="color: var(--shiki-color-text)"> { DateTime } </span><span style="color: var(--shiki-token-keyword)">from</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string-expression)">'luxon'</span></span>
<span></span>
<span><span style="color: var(--shiki-token-keyword)">const</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-constant)">dt</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-constant)">DateTime</span><span style="color: var(--shiki-token-function)">.fromISO</span><span style="color: var(--shiki-color-text)">(</span><span style="color: var(--shiki-token-string-expression)">'2025-03-29'</span><span style="color: var(--shiki-color-text)">)</span></span>
<span><span style="color: var(--shiki-token-keyword)">const</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-constant)">hijri</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-function)">toHijri</span><span style="color: var(--shiki-color-text)">(dt)</span></span>
<span><span style="color: var(--shiki-token-constant)">console</span><span style="color: var(--shiki-token-function)">.log</span><span style="color: var(--shiki-color-text)">(hijri) </span><span style="color: var(--shiki-token-comment)">// { year: 1446, month: 9, day: 29 }</span></span>
<span></span>
<span><span style="color: var(--shiki-token-keyword)">const</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-constant)">formatted</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-function)">formatHijriDate</span><span style="color: var(--shiki-color-text)">(dt</span><span style="color: var(--shiki-token-punctuation)">,</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string-expression)">'iD iMMMM iYYYY'</span><span style="color: var(--shiki-color-text)">)</span></span>
<span><span style="color: var(--shiki-token-constant)">console</span><span style="color: var(--shiki-token-function)">.log</span><span style="color: var(--shiki-color-text)">(formatted) </span><span style="color: var(--shiki-token-comment)">// e.g. "29 Ramadan 1446"</span></span>
<span></span>