Skip to content
Documentation · all sections

Dashas & Transits

panchang · v5.4.0 · MIT

Vimshottari (3-level), Ashtottari, Yogini, Chara, and Narayan dashas, plus the daily transits — Chandra Balam, Tarabala, and Sade Sati.

Five classical dasha systems

All five run off a birth moment. computeVimshottariDashaFromBirth works out the Moon's longitude for you. computeVimshottariDasha, computeAshtottariDasha and computeYoginiDasha take a sidereal Moon longitude you already have, from getSiderealMoonLongitude or from a chart. The two Jaimini systems take a location instead, because they start from the lagna.

A Moon longitude outside [0, 360) is wrapped into it first, so 360 reads as 0 and -0.5 as 359.5. NaN or an infinity throws a PanchangError with code INVALID_INPUT. Both are new in 5.4. For such values TypeScript used to return periods with no lord or the wrong one, or fail with a raw TypeError. In Go, ComputeAshtottariDasha and ComputeYoginiDasha returned ErrInvalidInput for anything outside the range, and ComputeVimshottariDasha panicked, except that on some processors a NaN got a wrong dasha back with no error.

import {
  getSiderealMoonLongitude, computeVimshottariDashaFromBirth, computeVimshottariPratyantarIn,
  computeAshtottariDasha, computeYoginiDasha, computeCharaDasha, computeNarayanDasha,
} from 'panchang-ts';

const birth = new Date('1995-08-15T05:30:00Z');
const loc   = { latitude: 28.6139, longitude: 77.2090 };
const asOf  = new Date('2011-05-03T00:00:00Z');
const moonLon = getSiderealMoonLongitude(birth, 'lahiri');

// 1. Vimshottari — 120-year, 9-lord, Maha -> Antar -> Pratyantar.
const vim = computeVimshottariDashaFromBirth(birth, 'lahiri', asOf);
console.log(vim.currentMahaDashaLord, vim.currentIndex);      // Venus 2
const maha  = vim.mahaDashas[0]!;
const antar = maha.antarDashas[0]!;                           // running at birth
const pra = computeVimshottariPratyantarIn(maha, antar);
console.log(antar.lord, pra.length, pra[0]!.lord);            // Rahu 6 Mercury

// 2. Ashtottari — 108-year, 8-lord cycle (no Ketu).
const ash = computeAshtottariDasha(birth, moonLon, asOf);
console.log(ash.mahaDashas[0]!.lord, ash.mahaDashas.length);  // Rahu 8

// 3. Yogini — 36-year, 8 yoginis.
const yog = computeYoginiDasha(birth, moonLon, asOf);
console.log(yog.mahaDashas[0]!.yogini, yog.mahaDashas[0]!.lord); // Ulka Saturn

// 4. Chara (Jaimini) — sign-based, 9-8-7 years, forward only.
const cha = computeCharaDasha(birth, loc, 'lahiri', asOf);
console.log(cha.mahaDashas[0]!.rashi, cha.mahaDashas[0]!.years); // 6 9

// 5. Narayan (Jaimini) — direction from lagna parity.
const nar = computeNarayanDasha(birth, loc, 'lahiri', { asOfDate: asOf });
console.log(nar.direction, nar.startingRashi);                   // forward 6

// Narayan variable-duration variant (Sanjay Rath).
const narV = computeNarayanDasha(birth, loc, 'lahiri', { duration: 'variable', asOfDate: asOf });
console.log(narV.mahaDashas[0]!.years, narV.mahaDashas[1]!.years); // 9 5
SystemCycleResult type
Vimshottari120 years, 9 lords, Maha → Antar → PratyantarVimshottariDashaResult
Ashtottari108 years, 8 lords (no Ketu)VimshottariDashaResult
Yogini36 years, 8 yoginis with planet lordsYoginiDashaResult
Chara (Jaimini)sign-based, 9-8-7 years per modalityCharaDashaResult
Narayan (Jaimini)sign-based, direction by lagna parity; fixed or variable yearsNarayanDashaResult

Narayan runs forward for a vishama-pada lagna (Aries, Taurus, Gemini, Libra, Scorpio, Sagittarius) and backward for a sama-pada one (Cancer, Leo, Virgo, Capricorn, Aquarius, Pisces). Read the direction off nar.direction. In the variable-duration variant each maha dasha runs 0 to 12 years, counted from the sign to its lord, plus one year if the lord is exalted and minus one if it is debilitated. From 5.2 a sign no longer aspects its immediate neighbours under rasi drishti, which moved some of those durations.

A sign whose lord sits in it gets the full 12 years, counting round the whole zodiac. Before 5.4 it got 0, a period of no length (1 for Mercury in Kanya, where it is also exalted), and every later period started that many years early. For a birth at Pune on 15 May 1990 at 06:30 UTC, Makara holds Saturn and now runs 12 years, from 2037 to 2049.

Chara, by contrast, is a fixed scheme: movable signs run 9 years, fixed 8 and dual 7, always forward, and the chart only picks the starting sign. It is not the Chara dasha of K. N. Rao or P. V. R. Narasimha Rao, whose years come from each sign's lord and whose direction depends on the chart. The variable Narayan dasha is the one that counts to the lord.

The order and year constants (ASHTOTTARI_ORDER, ASHTOTTARI_YEARS, YOGINI_ORDER, CHARA_RASHI_YEARS, …) are exported so you can build your own UI from them. See the export list.

Antardashas and pratyantars

Every mahadasha carries its antardashas in antarDashas. The first mahadasha starts at birth with only the balance of its years left, and its antardashas are those of the full mahadasha: the ones already over at birth are dropped, and the one running at birth is clipped to start there. Vimshottari already worked this way, and since 5.4 Ashtottari and Yogini do too. Before, they squeezed all eight antardashas into the balance, starting with the mahadasha's own lord.

Every list of sub-periods ends exactly at its parent's end, to the millisecond. Before 5.4 the last one could end up to 8 ms before or after it.

import {
  getSiderealMoonLongitude, computeVimshottariDashaFromBirth, computeYoginiDasha,
  computeVimshottariPratyantar, computeVimshottariPratyantarIn,
} from 'panchang-ts';

const birth = new Date('1995-08-15T05:30:00Z');
const asOf  = new Date('2011-05-03T00:00:00Z');
const moonLon = getSiderealMoonLongitude(birth, 'lahiri');

// Yogini: four of Ulka's eight antardashas are left at birth.
const yog = computeYoginiDasha(birth, moonLon, asOf);
console.log(yog.mahaDashas[0]!.antarDashas.map(a => a.yogini).join(' '));
// Pingala Dhanya Bhramari Bhadrika

// Vimshottari: the birth antardasha is Rahu, clipped to start at birth.
const vim   = computeVimshottariDashaFromBirth(birth, 'lahiri', asOf);
const maha  = vim.mahaDashas[0]!;
const antar = maha.antarDashas[0]!;

// The pratyantars of the whole Rahu antardasha, from the one running at birth.
const pra = computeVimshottariPratyantarIn(maha, antar);
console.log(pra.map(p => p.lord).join(' '));     // Mercury Ketu Venus Sun Moon Mars
console.log(pra[0]!.endDate.toISOString());      // 1995-09-25T00:15:07.079Z

// The plain call spreads all nine over the clipped span, from Rahu.
const squeezed = computeVimshottariPratyantar(antar);
console.log(squeezed.length, squeezed[0]!.lord); // 9 Rahu

// Any later antardasha is whole, and the two calls agree.
const next = maha.antarDashas[1]!;
console.log(JSON.stringify(computeVimshottariPratyantar(next)) ===
  JSON.stringify(computeVimshottariPratyantarIn(maha, next)));   // true

computeVimshottariPratyantar splits whatever span it is given as if it were a whole antardasha, starting with the antardasha's own lord. That is right for every antardasha except the one running at birth, which is clipped. computeVimshottariPratyantarIn, new in 5.4, takes the mahadasha as well and reads only its lord. It rebuilds the antardasha's full length from the two lords, ending where the antardasha ends, and drops the pratyantars over before it starts. So the birth antardasha's list begins with the pratyantar running at birth and can hold fewer than nine. For an antardasha that was not clipped it returns the same list as the plain call, so when you have the mahadasha to hand it is the one to use.

Both throw a PanchangError with code INVALID_INPUT for an unknown lord (the plain call threw a bare Error before 5.4) and INVALID_DATE for an Invalid Date. In Go both are package functions, panchang.ComputeVimshottariPratyantar and panchang.ComputeVimshottariPratyantarIn, and an unknown lord is ErrInvalidInput.

Pinning the evaluation date

Which dasha is running depends on when you ask. Six entry points take an asOfDate, added in 5.2, so you can ask what was running on 3 May 2011 and get the same answer every time. Five take it as a trailing argument; Narayan takes it in the options bag.

import {
  getSiderealMoonLongitude, computeVimshottariDasha, computeVimshottariDashaFromBirth,
  computeAshtottariDasha, computeYoginiDasha, computeCharaDasha, computeNarayanDasha,
  computeSadeSati,
} from 'panchang-ts';

const birth = new Date('1995-08-15T05:30:00Z');
const loc   = { latitude: 28.6139, longitude: 77.2090 };
const asOf  = new Date('2011-05-03T00:00:00Z');
const moonLon = getSiderealMoonLongitude(birth, 'lahiri');

// Five take it as a trailing positional argument.
console.log(computeVimshottariDasha(birth, moonLon, asOf).currentMahaDashaLord);          // Venus
console.log(computeVimshottariDashaFromBirth(birth, 'lahiri', asOf).currentMahaDashaLord); // Venus
console.log(computeAshtottariDasha(birth, moonLon, asOf).currentMahaDashaLord);            // Venus
console.log(computeYoginiDasha(birth, moonLon, asOf).currentYogini);                       // Sankata
console.log(computeCharaDasha(birth, loc, 'lahiri', asOf).currentRashi);                   // 7

// Narayan takes it in the options bag — both overloads.
console.log(computeNarayanDasha(birth, loc, 'lahiri', { asOfDate: asOf }).currentRashi);   // 7
console.log(computeNarayanDasha(birth, loc, 'lahiri',
  { duration: 'variable', asOfDate: asOf }).currentRashi);                                 // 8

// Sade Sati already had it in 5.1.1.
console.log(computeSadeSati(0, asOf).active);                                              // false

// A different pin gives a different answer.
console.log(computeVimshottariDashaFromBirth(birth, 'lahiri',
  new Date('2000-01-01T00:00:00Z')).currentMahaDashaLord);                                 // Mercury

// Omit it and the call resolves to new Date(). For this birth that
// prints Venus until 1 October 2028, then Sun.
console.log(computeVimshottariDashaFromBirth(birth, 'lahiri').currentMahaDashaLord);

In TypeScript, omit it and the call uses new Date(), so code written before 5.2 behaves as it did. Pass a non-Date or an invalid Date and you get a PanchangError with code INVALID_DATE and the message Invalid asOfDate: …. See Errors & Compatibility.

Go has no optional arguments, so you always pass the date and the zero time.Time is what means now. A time.Time cannot be invalid, so the Invalid asOfDate error has no Go counterpart. A date outside 1900 to 2100 still reports INVALID_DATE, as in TypeScript: a birth, or the asOf of ComputeSadeSati, which is the date it computes Saturn for. The variable-duration Narayan dasha is a separate method, ComputeNarayanDashaVariable, and ComputeSadeSati takes the ayanamsa as a required third argument.

computeVimshottariPratyantar and computeVimshottariPratyantarIn are the exception in both languages. They subdivide an AntarDasha you already have, so they take no date. See Antardashas and pratyantars.

Daily transits — Chandra Balam and Tarabala

Pass janmaRashi and janmaNakshatra to a daily call and the result carries Chandra Balam and Tarabala for that day (see Daily Panchang). Leave them out and both fields are empty. computeChandraBalam and computeTarabala do the same job from a natal index and a transit index.

import { getDailyPanchang, computeChandraBalam, computeTarabala } from 'panchang-ts';

const date = new Date('2026-09-02T00:00:00Z');
const loc  = { latitude: 18.5204, longitude: 73.8567 };

const r = getDailyPanchang(date, loc, {
  timezone: 330,
  janmaRashi: 3,        // 0 = Mesha … 11 = Meena
  janmaNakshatra: 0,    // 0 = Ashwini … 26 = Revati
})!;

// Both fields are null unless the janma indices were supplied.
console.log(r.chandraBalam!.house, r.chandraBalam!.quality, r.chandraBalam!.name); // 10 strong Shubha
console.log(r.tarabala!.taraIndex, r.tarabala!.name, r.tarabala!.quality);         // 1 Sampat auspicious

// Or compute them standalone from transit indices.
const cb = computeChandraBalam(3, r.moon.rashi.index);
const tb = computeTarabala(0, r.angas.nakshatras[0].index);
console.log(cb.house, cb.quality);   // 10 strong
console.log(tb.taraIndex, tb.name);  // 1 Sampat

Chandra Balam counts the transit Moon's house from the janma rashi, where 1 is the janma rashi itself. Houses 1, 3, 6, 7, 10 and 11 are Shubha. Tarabala is the nine-tara cycle from the janma nakshatra: Janma, Sampat, Vipat, Kshema, Pratyari, Sadhaka, Vadha, Mitra, Ati-Mitra.

Sade Sati

computeSadeSati tells you where Saturn is in its seven-and-a-half-year arc over the natal Moon sign. Phase 1 is Saturn in the 12th from the Moon, phase 2 on the Moon, phase 3 in the 2nd.

import { computeSadeSati } from 'panchang-ts';

const asOf = new Date('2026-09-02T00:00:00Z');

// natalMoonRashi 0 = Mesha. Phase and the arc dates are null when inactive.
const ss = computeSadeSati(0, asOf);
console.log(ss.active, ss.phase);                // true 1
console.log(ss.currentArcStart!.toISOString());  // 2025-03-30T00:00:00.000Z
console.log(ss.currentArcEnd!.toISOString());    // 2032-05-31T00:00:00.000Z
console.log(ss.nextArcStart);                    // null

const off = computeSadeSati(3, asOf);
console.log(off.active, off.phase === null, off.nextArcStart!.toISOString());
// false true 2032-05-31T06:00:00.000Z

// A retrograde return into the arc counts as an entry.
const kumbha = computeSadeSati(10, new Date('2027-08-01T00:00:00Z'));
console.log(kumbha.active, kumbha.nextArcStart!.toISOString());
// false 2027-10-20T12:00:00.000Z

When no arc is running, phase, currentArcStart and currentArcEnd are empty and nextArcStart gives you the next start: Saturn's next entry into any of the three signs, found to within a day, or empty when there is none within 30 years. A retrograde return counts as an entry. On 1 August 2027 Saturn has moved on into Mesha, out of a Kumbha Moon's arc, and it retrogrades back into Meena on 20 October. Before 5.4 the search skipped a return like that and could land about 21 years late: here it gave 7 March 2049.

nextArcStart comes from a search of its own, so it can differ by hours from the currentArcStart a query made inside the arc reports. Asked on 22 October 2027, the same Kumbha arc starts at 2027-10-21T00:00:00.000Z. Arc boundaries land within one or two days of authoritative ephemerides; see Accuracy.