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

panchang-ts

v0.2.1

Published

Pure TypeScript Hindu Panchang calculations. Tithi, Nakshatra, Yoga, Karana, Vara, and more. Offline-first, React Native compatible.

Readme

panchang-ts

Pure TypeScript Hindu Panchang (almanac) calculations. Zero native dependencies. Works offline in React Native (Hermes), Node.js, and browsers.

Features

  • Pancha Anga (5 limbs): Tithi, Nakshatra, Yoga, Karana, Vara — with mid-day transition times
  • Lunar calendar: Chandra Masa (lunar month + Adhika/leap detection), Vikram Samvat, Shaka Samvat
  • Zodiac & asterism: Chandra Rashi (Moon sign), Surya Nakshatra (Sun's asterism)
  • Muhurta: Brahma Muhurta, Abhijit Muhurta
  • Inauspicious periods: Rahu Kalam, Gulika Kalam, Yamaganda
  • Choghadiya: 16 time slots (8 day + 8 night), each named and rated auspicious/neutral/inauspicious
  • Hora: 24 planetary hours per day (12 day + 12 night) in Chaldean order
  • Astronomical events: Sunrise, Sunset, Moonrise, Moonset
  • Panchaka detection: Flag when Moon is in the last 5 nakshatras (Dhanishta 3rd pada → Revati)
  • Daily mode: Full sunrise-to-sunrise day with all element transitions
  • Instant mode: Elements active at an exact moment (birth charts, muhurta selection)
  • 3 ayanamsa systems: Lahiri (default), B.V. Raman, KP (Krishnamurti)
  • 3 languages: English, Sanskrit (Devanagari), Hindi
  • React Native compatible: Pure JS math, no native modules, tested on Hermes
  • Fast: ~0.1 ms names-only on Node.js; <100 ms on budget Android (Hermes)
  • Typed: Full TypeScript types for every result and option

Install

npm install panchang-ts
# or
pnpm add panchang-ts
# or
yarn add panchang-ts

Quick Start

import { getDailyPanchang } from 'panchang-ts';

const result = getDailyPanchang(
  new Date(2025, 0, 14),                      // January 14, 2025
  { latitude: 18.5204, longitude: 73.8567 },  // Pune, India
  { timezone: 330 },                          // IST = UTC+5:30 = 330 minutes
);

// Pancha Anga
console.log(result.tithis[0].name);           // "Krishna Chaturdashi"
console.log(result.nakshatras[0].name);       // "Mrigashira"
console.log(result.vara.name);                // "Mangalavara"

// Lunar calendar
console.log(result.chandramasa.name);         // "Pausha"
console.log(result.samvat.vikramSamvat);      // 2081
console.log(result.samvat.shakaSamvat);       // 1946

// Zodiac
console.log(result.chandraRashi.name);        // "Mithuna" (Moon in Gemini)
console.log(result.suryaNakshatra.name);      // "Uttara Ashadha"

// Astronomical events
console.log(result.sunrise);                  // Date (read via getUTC*)
console.log(result.moonrise);                 // Date | null

// Muhurta
console.log(result.brahmaMuhurta);            // { start: Date, end: Date }
console.log(result.rahuKalam);                // { start: Date, end: Date }

// Choghadiya — 8 daytime slots
result.choghadiya.day.forEach(slot => {
  console.log(slot.name, slot.quality);       // "Amrit", "auspicious"
});

// Panchaka
console.log(result.panchaka);                 // true | false

Reading Output Times

All Date objects in the result are offset-adjusted to the requested timezone. Always read time components via getUTC* methods:

const sunrise = result.sunrise;
const h = sunrise.getUTCHours();    // 7
const m = sunrise.getUTCMinutes();  // 4
// → Sunrise at 07:04 local time

// Format helper:
function fmt(d: Date) {
  const h = d.getUTCHours(), m = d.getUTCMinutes();
  return `${h}:${String(m).padStart(2, '0')}`;
}
fmt(result.rahuKalam.start); // "09:04"

Do not use .getHours() — it uses your system timezone, which may differ.

moonrise and moonset can be null — the Moon occasionally does not rise or set on a given calendar day, which is normal.


API Reference

getDailyPanchang(date, location, options)

Returns the full Hindu day from sunrise to next sunrise, with all element transitions.

import { getDailyPanchang } from 'panchang-ts';

const result = getDailyPanchang(
  date,      // Date — any moment within the local calendar day
  location,  // GeoLocation — { latitude, longitude, elevation? }
  options,   // PanchangOptions — { timezone, ayanamsa?, language?, ... }
);

Returns: DailyPanchangResult

| Field | Type | Description | |-------|------|-------------| | date | Date | Input date | | location | GeoLocation | Input location | | timezone | number | Resolved UTC offset in minutes | | sunrise | Date | Sunrise (offset-adjusted) | | sunset | Date | Sunset (offset-adjusted) | | nextSunrise | Date | Following day's sunrise (offset-adjusted) | | dayDurationMinutes | number | Length of daytime in minutes | | nightDurationMinutes | number | Length of night in minutes | | tithis | DailyTithiInfo[] | Tithis active during the day (usually 1–2) | | nakshatras | DailyNakshatraInfo[] | Nakshatras active during the day | | yogas | DailyYogaInfo[] | Yogas active during the day | | karanas | DailyKaranaInfo[] | Karanas active during the day (usually 2–4) | | vara | VaraInfo | Weekday (Vara) | | rahuKalam | TimePeriod | Rahu Kalam start/end | | gulikaKalam | TimePeriod | Gulika Kalam start/end | | yamaganda | TimePeriod | Yamaganda start/end | | abhijitMuhurta | TimePeriod | Abhijit Muhurta start/end | | brahmaMuhurta | TimePeriod | Brahma Muhurta (96–48 min before sunrise) | | masa | MasaInfo | Solar month (Saura Masa) | | chandramasa | ChandraMasaInfo | Lunar month + Adhika (leap) flag | | samvat | SamvatInfo | Vikram Samvat and Shaka Samvat year numbers | | chandraRashi | RashiInfo | Moon's zodiac sign (changes every ~2.5 days) | | suryaNakshatra | RashiInfo | Sun's nakshatra (changes every ~13–14 days) | | choghadiya | ChoghadiyaInfo | 8 day slots + 8 night slots, each named and rated | | hora | HoraInfo | 12 day horas + 12 night horas, each with ruling planet | | moonrise | Date \| null | Moonrise (offset-adjusted); null if none that day | | moonset | Date \| null | Moonset (offset-adjusted); null if none that day | | panchaka | boolean | true when Moon is in last 5 nakshatras | | ayanamsa | number | Ayanamsa in degrees at sunrise | | siderealSunAtSunrise | number | Sun sidereal longitude at sunrise (°) | | siderealMoonAtSunrise | number | Moon sidereal longitude at sunrise (°) |


getInstantPanchang(date, location, options?)

Returns the single Panchang element active at an exact UTC moment.

import { getInstantPanchang } from 'panchang-ts';

const result = getInstantPanchang(
  new Date('2025-01-14T03:00:00Z'),           // UTC moment
  { latitude: 18.5204, longitude: 73.8567 },
  { language: 'sa' },                          // Sanskrit names
);

console.log(result.tithi.name);              // "कृष्ण चतुर्दशी"
console.log(result.nakshatra.name);          // "मृगशिरा"
console.log(result.chandramasa.name);        // "पौष"
console.log(result.chandraRashi.name);       // "मिथुन"
console.log(result.samvat.vikramSamvat);     // 2081
console.log(result.panchaka);               // false

Returns: InstantPanchangResult

| Field | Type | Description | |-------|------|-------------| | timestamp | Date | Input UTC moment | | location | GeoLocation | Input location | | tithi | TithiInfo | Active Tithi with paksha, number, completion % | | nakshatra | NakshatraInfo | Active Nakshatra with pada, degrees | | yoga | YogaInfo | Active Yoga | | karana | KaranaInfo | Active Karana (movable or fixed) | | vara | VaraInfo | Active Vara (weekday) | | chandramasa | ChandraMasaInfo | Lunar month + Adhika flag | | samvat | SamvatInfo | Vikram Samvat and Shaka Samvat year numbers | | chandraRashi | RashiInfo | Moon's zodiac sign | | suryaNakshatra | RashiInfo | Sun's nakshatra | | panchaka | boolean | true when Moon is in last 5 nakshatras | | ayanamsa | number | Ayanamsa in degrees | | siderealSun | number | Sun sidereal longitude (°) | | siderealMoon | number | Moon sidereal longitude (°) |


Options

PanchangOptions (required for getDailyPanchang):

| Option | Type | Default | Description | |--------|------|---------|-------------| | timezone | number \| string | required | UTC offset in minutes (330 for IST). Use a number on Hermes — IANA strings require Intl. | | ayanamsa | 'lahiri' \| 'raman' \| 'krishnamurti' | 'lahiri' | Ayanamsa system | | language | 'en' \| 'sa' \| 'hi' | 'en' | Language for element names | | computeEndTimes | boolean | true | Set false for ~5× faster, names-only output | | precision | 'standard' \| 'high' | 'standard' | Binary-search iterations (15 vs 25). High precision is rarely needed. |

InstantPanchangOptions (optional for getInstantPanchang): same as above but without timezone.


Low-level Utilities

These are exported for advanced use cases (building your own tools, visualisations, or debugging).

import {
  getSunrise, getSunset,
  getMoonrise, getMoonset,
  getSiderealSunLongitude, getSiderealMoonLongitude,
  getAyanamsa,
  computeRahuKalam, computeGulikaKalam, computeYamaganda,
  computeAbhijitMuhurta, computeBrahmaMuhurta,
} from 'panchang-ts';

// Sunrise/sunset
const sunrise = getSunrise(localMidnightUtc, { latitude: 28.6, longitude: 77.2 });
const sunset  = getSunset(sunrise, { latitude: 28.6, longitude: 77.2 });

// Moonrise/moonset — return null when the Moon doesn't rise/set that day
const moonrise = getMoonrise(localMidnightUtc, { latitude: 28.6, longitude: 77.2 });
const moonset  = getMoonset(localMidnightUtc, { latitude: 28.6, longitude: 77.2 });

// Sidereal longitudes
const moonLon = getSiderealMoonLongitude(new Date(), 'lahiri'); // degrees [0, 360)
const sunLon  = getSiderealSunLongitude(new Date(), 'lahiri');

// Ayanamsa
const ayan = getAyanamsa(new Date(), 'lahiri');  // e.g. 24.10

// Inauspicious periods (varaIndex: 0=Sun … 6=Sat)
const rahu  = computeRahuKalam(sunrise, sunset, varaIndex);   // { start, end }
const gulika = computeGulikaKalam(sunrise, sunset, varaIndex);
const yama  = computeYamaganda(sunrise, sunset, varaIndex);

// Muhurta
const abhijit = computeAbhijitMuhurta(sunrise, sunset);       // { start, end }
const brahma  = computeBrahmaMuhurta(sunrise, sunset);        // { start, end }

Types

interface GeoLocation {
  latitude: number;    // -90 to 90
  longitude: number;   // -180 to 180
  elevation?: number;  // metres, default 0
}

interface TimePeriod {
  start: Date;
  end: Date;
}

// ── Pancha Anga ──────────────────────────────────────────────────────────────

interface TithiInfo {
  index: number;               // 0–29
  name: string;                // e.g. "Shukla Pratipada"
  paksha: 'Shukla' | 'Krishna';
  number: number;              // 1–15 within the paksha
  completionPercentage: number;
  endTime: Date | null;
}

interface NakshatraInfo {
  index: number;               // 0–26
  name: string;
  pada: number;                // 1–4
  degreesInNakshatra: number;
  completionPercentage: number;
  endTime: Date | null;
}

interface DailyTithiInfo extends TithiInfo {
  startTime: Date | null;      // null if active at sunrise
  isActiveAtSunrise: boolean;
}

// DailyNakshatraInfo, DailyYogaInfo, DailyKaranaInfo follow the same pattern

// ── Lunar calendar ───────────────────────────────────────────────────────────

interface ChandraMasaInfo {
  index: number;       // 0 = Chaitra … 11 = Phalguna
  name: string;        // e.g. "Pausha"
  isAdhika: boolean;   // true = leap/intercalary month
}

interface SamvatInfo {
  vikramSamvat: number;  // e.g. 2081
  shakaSamvat: number;   // e.g. 1946
}

// ── Zodiac & asterism ────────────────────────────────────────────────────────

interface RashiInfo {
  index: number;  // 0 = Mesha … 11 = Meena (for rashi); 0–26 for nakshatra
  name: string;
}

// chandraRashi and suryaNakshatra both use RashiInfo

// ── Choghadiya ───────────────────────────────────────────────────────────────

type ChoghadiyaQuality = 'auspicious' | 'inauspicious' | 'neutral';

interface ChoghadiyaSlot extends TimePeriod {
  index: number;
  name: string;           // e.g. "Amrit", "Kaal", "Shubh"
  quality: ChoghadiyaQuality;
}

interface ChoghadiyaInfo {
  day: ChoghadiyaSlot[];    // 8 slots (sunrise → sunset)
  night: ChoghadiyaSlot[];  // 8 slots (sunset → next sunrise)
}

// ── Hora ─────────────────────────────────────────────────────────────────────

interface HoraSlot extends TimePeriod {
  planet: string;       // "Sun", "Moon", "Mars", "Mercury", "Jupiter", "Venus", "Saturn"
  planetIndex: number;  // 0–6 in Chaldean order
}

interface HoraInfo {
  day: HoraSlot[];    // 12 slots (sunrise → sunset)
  night: HoraSlot[];  // 12 slots (sunset → next sunrise)
}

React Native / Hermes Usage

Works with Expo and bare React Native (Hermes engine). Pass timezone as a number — IANA timezone strings ('Asia/Kolkata') require Intl, which older Hermes versions don't fully support.

Two-pass rendering for smooth UI:

import { getDailyPanchang } from 'panchang-ts';
import { InteractionManager } from 'react-native';

// Pass 1 — instant, names only (~0.1 ms on Node, <100 ms on Hermes)
const fast = getDailyPanchang(date, location, {
  timezone: 330,
  computeEndTimes: false,
});
setState(fast); // show names immediately

// Pass 2 — background, full with end-times (~0.5 ms on Node, <500 ms on Hermes)
InteractionManager.runAfterInteractions(() => {
  const full = getDailyPanchang(date, location, { timezone: 330 });
  setState(full); // update with transition times
});

Performance

| Mode | Node.js | Hermes (budget Android) | |------|---------|------------------------| | Names-only (computeEndTimes: false) | ~0.1 ms | <100 ms | | Full with end-times | ~0.5 ms | <500 ms |

Measured with Vitest benchmarks on Node 22 and on a physical budget Android device via the dharmSetu React Native app.


Accuracy

Validated against DrikPanchang.com for 15+ date/city combinations.

| Element | Accuracy | |---------|----------| | Sunrise / Sunset | ±2 minutes | | Moonrise / Moonset | ±2 minutes | | Tithi, Nakshatra, Yoga, Karana names | Exact match | | Element end-times | ±5 minutes | | Ayanamsa | ±0.005° vs Swiss Ephemeris | | Choghadiya / Hora slots | Derived from sunrise/sunset — inherits ±2 min |


Compatibility

| Environment | Support | |-------------|---------| | Node.js 18+ | ✅ | | Node.js 20+ | ✅ | | Node.js 22+ | ✅ | | React Native (Hermes) | ✅ (pass timezone as number) | | Expo (managed + bare) | ✅ | | Browser (modern) | ✅ (ESM build) | | Browser (legacy / IE) | ✗ |


Error Handling

import { PanchangError } from 'panchang-ts';

try {
  getDailyPanchang(date, location, options);
} catch (e) {
  if (e instanceof PanchangError) {
    console.error(e.code);    // e.g. 'INVALID_LATITUDE', 'NO_SUNRISE'
    console.error(e.message);
  }
}

PanchangErrorCode values: INVALID_DATE, INVALID_LATITUDE, INVALID_LONGITUDE, INVALID_TIMEZONE, INVALID_AYANAMSA, NO_SUNRISE, NO_SUNSET.

Note: getMoonrise / getMoonset never throw — they return null when no rise/set occurs within the search window (this is normal for the Moon).


License

MIT