- Dharmagya
- panchang docs
- Upgrading 5.1 → 5.2
Upgrading 5.1 → 5.2
panchang · v5.4.0 · MIT
No type breaks and no removed exports — the festivals that used to vanish for a whole year, the three that move date, the de-duplicated eclipse ranges, and the new reference frames and asOfDate parameter.
This page covers the npm package. The Go module is versioned alongside it.
Nothing breaks. 5.2.0 removes, renames and retypes no exports. Every result shape, option shape, field name and field type is what it was in 5.1.1, and nine exports are added. What changes is output. Festivals that used to disappear for a whole year now appear, three festivals move to a different date, eclipse ranges stop repeating one eclipse and dropping the rest, and four numbers in the Jyotish layer come out of a corrected frame.
So there is no type diff to walk. The compiler will flag none of this, and your tests will not either unless they pin values. Everything below is a stored-value problem. Re-run anything you cached, and re-pin anything you snapshotted.
Festivals stop vanishing when their tithi is kshaya
A kshaya tithi begins and ends between two consecutive sunrises, so it is current at no sunrise at all. A rule keyed on the sunrise tithi therefore matched it on no day of the year, and the festival did not exist that year at that location. There was no exception and no empty entry, so nothing signalled the omission. Ugadi and Gudi Padwa were absent from 2026 across almost all of India — everywhere the Chaitra Shukla Pratipada of 19 March fell between two sunrises, which is everything east of about 70.5° E.
The Hindu day that wholly contains the tithi now claims it, which is what the reference almanac publishes. The change only adds dates. Every new date belongs to a city and year where the festival had no date at all before, so nothing is rescheduled and no city gains a second date for a festival it already had. Across eight Indian cities over 2020–2030 that is 86 dates added, none moved, and none doubled — setting aside the three festivals below, which 5.2 re-anchors on purpose.
The 86 span eleven festivals. Ugadi and Gudi Padwa 2026, Bhai Dooj 2020, Hariyali Teej 2027, Hartalika Teej 2028 and Govardhan Puja 2028 were missing at all eight cities. Navaratri 2027, Gangaur 2025 and Chhath Kharna 2022 were missing everywhere but Kolkata, and Govardhan Puja 2029, Hartalika Teej 2029, Kartika Purnima 2024, Anant Chaturdashi 2021 and Bhai Dooj 2029 at some cities and not others.
Where the reference splits a date by city, so does this. Hartalika Teej 2029 is 10 September at Ahmedabad, Jaipur, Mumbai and Ujjain, and 11 September at Delhi, Varanasi, Chennai and Kolkata.
Four rules opt out of containment, because the reference does not date them that way. narak_chaturdashi and chhath_usha_arghya are published on the day the tithi ends, since their observances sit in its pre-dawn tail and Chhath is anchored as a four-day sequence. holi and phagli are observed at pradosha. Those four still key on sunrise and await anchors of their own. dhanteras is unaffected, because it already keys on pradosha.
5.4 gave three of the four their own anchors: holi moved to the day after the new holika_dahan, narak_chaturdashi takes arunodaya, and chhath_usha_arghya falls one day after the Shashthi sunrise day. Only phagli still opts out. See Upgrading 5.3 → 5.4.
Three festivals move to a different date
These three are the only dates that move rather than appear, so they are what you diff a cached table for.
| Festival | Was | Now |
|---|---|---|
vat_savitri_amavasya | Filed under amanta Jyeshtha and keyed on sunrise, which picked the wrong new moon in every year: roughly 30 days late. | Amanta Vaishakha, dated by aparahna, with the last of two qualifying days taking it. Agrees with the reference in all seven checked years. |
rig_upakarma | Matched on the sunrise nakshatra and nothing else. That gave two dates in years the Shravana nakshatra spans two sunrises (2019 everywhere but Kolkata, 2029 at Varanasi and Kolkata), the wrong paksha when it slipped into Krishna (2020), and nothing at all in 2022, so 4 of the 13 checked years are wrong at one city or more. | Now constrained to the Shukla paksha, with a Hasta fallback. Exactly one date in every year 2018–2030. |
sama_upakarma | Same sunrise-only match. At Delhi that gave a spurious second date in 6 of 13 checked years and a date a day late in 5, overlapping in two, so 9 of the 13 are wrong one way or the other. In 2018, 2021, 2023, 2026 and 2027 the second date was the amanta Bhadrapada Amavasya about a month later, which carries Hasta again. Samavedi Upakarma kala is aparahna. | Now constrained to the Shukla paksha, and dated by aparahna against the nakshatra. Exactly one date in every year 2018–2030. |
The first one was a calendar-system mismatch, not arithmetic. The vrat is observed on purnimanta Jyeshtha Amavasya, but the rule was filed under amanta Jyeshtha. An amavasya ends its amanta month, so amanta Jyeshtha's amavasya is what the purnimanta system calls Ashadha Amavasya. vat_savitri_purnima is untouched and still keys on amanta Jyeshtha, which is right there, because a purnima sits inside the amanta month whose name it carries. yajur_upakarma is untouched too. It keys on Shravana Purnima, a tithi, and was already correct.
2025 shows what the aparahna anchor buys. The Amavasya begins at 12:12 IST on 26 May and reaches sunrise only on the 27th. The reference publishes the 26th, and aparahna on the 26th falls wholly inside the Amavasya while the 27th's falls long after it ends. Sama Upakarma is aparahna-anchored, so it is longitude-sensitive, and so is the published date. Sama Upakarma 2026 is 13 September at Kolkata and 12 September everywhere else.
Eclipse ranges no longer repeat one eclipse
getUpcomingSolarEclipse and its lunar twin never checked that the eclipse they found actually ended after the instant they were asked to search from. For an observer east of the shadow axis the local contacts can fall entirely before the geocentric conjunction. A range walker advancing its cursor to eclipse.end + 1s then re-found the same eclipse until it ran out of steps, and never reached any eclipse after it.
computeEclipsesInRange(new Date('2000-01-01'), new Date('2011-01-01'), varanasi);
// 5.1.1: 277 entries, 249 of them the same 2007-03-19 partial.
// The 2008-08-01, 2009-07-22 and 2010-01-15 solar eclipses were
// dropped entirely — the 2009 total was visible over India.
// 5.2.0: 32 distinct entries, with all three present.Every range caller inherited it: getUpcomingEclipses, computeEclipsesInRange, computeEclipsesForYear, buildEclipsesTable and the deprecated getEclipsesInRange alias. getDailyPanchang was never affected, because it asks about one day, not a range. Over 1900–2100 the bug touched 33 of 80 locally visible solar eclipses at Varanasi, 31 of 77 at Delhi and 18 of 74 at New York.
Numbers that changed in the Jyotish layer
| What | Why | How much |
|---|---|---|
| Shadbala Kala Bala | The day frame came from getSunrise(birth − 12h), which for evening and night births resolves to the sunrise after birth, so it used the wrong Hindu day. It now uses the sunrise at or before birth, and Nathonatha can no longer fall outside its 0–60 virupa range. | 1,009 of 2,016 sampled births change, by up to 482 virupas. This is the largest numeric change in the release. |
| Narayan dasha durations | Rasi drishti implemented Jaimini rashi aspects by modality alone, so a sign aspected its immediate neighbours. Classical rasi drishti excludes adjacent signs, and that guard feeds the co-lord tie-break that picks variable-duration years. | 160 of 3,660 sampled charts change their maha-dasha lengths. |
| Gulika and Mandi | The day/night decision used a topocentric horizon test including refraction and semi-diameter, which disagrees with the sunrise and sunset instants the eighth-part arithmetic is built from. It now tests the birth instant against the sunset of its own anchoring sunrise. | A window of roughly four minutes a day, but those births move by up to 101°, which is a different rashi. |
| Nakshatra pada | A sidereal longitude landing one ULP below a nakshatra boundary made the offset slightly negative, so the floor produced pada 0 with negative-zero degreesInNakshatra. | Latent. Pada is now genuinely always 1–4; at 5.1.1 it had a one-double hole. |
| Chandra masa | A reference instant sitting within a millisecond of a lunation boundary could be resolved to the wrong side of it. Instants that close to a boundary are now resolved exactly. | Latent, but a full month wrong when it fired. |
The Gulika and Mandi fix is the second correction to that pair. 5.1 already corrected them for eastern longitudes. If you carried charts through both releases, re-pin them rather than working out which fix moved what.
New: three named reference frames
Nine new exports, for callers that have no coordinates of their own. Nothing starts defaulting on its own. location is still a required positional parameter on getDailyPanchang, getInstantPanchang and every jyotish entry point, and nothing inside the library calls these helpers. They exist so that a caller who would otherwise invent a place picks a defensible one and labels the result honestly, the way a printed panchang names the city it was computed for.
import { resolveLocation, TRADITIONAL_REFERENCE, IST_OFFSET_MINUTES } from 'panchang-ts';
resolveLocation({ latitude: 18.52, longitude: 73.86 });
// → { location: { …unchanged… }, reference: 'practical' }
resolveLocation(null); // → TRADITIONAL_REFERENCE, reference: 'traditional'
resolveLocation(null, 'modern'); // → MODERN_REFERENCE, reference: 'modern'
resolveLocation({ latitude: 0, longitude: 0 }); // Null Island is a real place:
// 'practical', not "absent"
// @ts-expect-error — TypeScript rejects a half-filled location outright.
resolveLocation({ latitude: 18.5 }); // JS callers get INVALID_LONGITUDE:
// half-filled is not completedTRADITIONAL_REFERENCE— Ujjain (23.1765° N, 75.7885° E), the classical madhya rekha of the Surya Siddhanta. This is the default fallback.MODERN_REFERENCE— the Central Station (23.1833° N, 82.5° E), the 1955 Calendar Reform Committee reference for the Rashtriya Panchang.IST_TIMEZONEandIST_OFFSET_MINUTES—'Asia/Kolkata'and330.referenceLocation(mode)andresolveLocation(location?, mode?), plus the typesPanchangReference(which frame a result is in, including'practical', which is reported but never selected),ReferenceMode(which fallback you may ask for) andResolvedLocation.
The cost of using a reference frame is measured. Over 730 days against 48 Indian cities, the tithi at the reference's sunrise differs from the city's own on up to 5.9% of days for Ujjain and 4.0% for the Central Station. Weighted by population it is 1.18% versus 1.80%, because India's metros lie west of the IST meridian, so Ujjain is better weighted and worse in the tail. Outside India both degrade without limit.
IST_OFFSET_MINUTES is exact for the Central Station, whose longitude is the IST meridian. For Ujjain it is the civil clock only, since Ujjain's local mean time is 303.2 minutes. The 26.8-minute gap is what the classical deshantara correction closes.
New: asOfDate on six dasha entry points
This is additive. Existing calls compile and behave the same. Before 5.2 each of these called bare new Date() inside, which made them non-deterministic and left “which dasha was running on date X?” unanswerable.
@@ asOfDate is optional on all six @@
computeVimshottariDasha(birth, moonLon)
+ computeVimshottariDasha(birth, moonLon, asOf)
computeVimshottariDashaFromBirth(birth, 'lahiri')
+ computeVimshottariDashaFromBirth(birth, 'lahiri', asOf)
computeAshtottariDasha(birth, moonLon) + asOf
computeYoginiDasha(birth, moonLon) + asOf
computeCharaDasha(birth, loc, 'lahiri') + asOf
- computeNarayanDasha(birth, loc, 'lahiri', { duration: 'variable' })
+ computeNarayanDasha(birth, loc, 'lahiri', { duration: 'variable', asOfDate: asOf })Omit it and the call resolves to new Date() exactly as before. Pass a non-Date or an invalid Date and it throws PanchangError with code INVALID_DATE and message Invalid asOfDate: …. computeSadeSati already took one in 5.1.1, so 5.2 finishes an existing convention rather than inventing one. computeVimshottariPratyantar takes none, because it subdivides an AntarDasha you already computed. See Dashas & Transits.
43 display strings were repunctuated
Em dashes inside user-visible strings became colons or commas, in both locales. That covers every Chhath and Bathukamma festival name, the eclipse description template, the built eclipse and moon-phase table notes with their phase and obscuration descriptions, the two polar no-sunrise messages, and the Manglik, Ashtakoot and Porutham reason text. One of the 43 also changes a word: the eclipse table's default note now reads (reference almanac / pandit consensus).
No key and no error code moved. festivals[].key is unchanged, and the PanchangErrorCode union is identical to 5.1.1. Code that branches on either is unaffected. Code that matched on name or on message text breaks.
What to rebuild and re-pin
- Rebuild every eclipses table generated on 5.1.1 or earlier. The format is unchanged, so nothing will warn you.
- Rebuild festival tables and diff them. Expect additions everywhere, and moves on exactly three keys:
vat_savitri_amavasya,rig_upakarmaandsama_upakarma. - Recompute stored Shadbala and Bhava Bala totals. Half the sampled births change.
- Re-pin Narayan variable durations and any Gulika/Mandi placement carried from 5.1.
- Match festivals on
key, never onname, and match errors oncode, never on message text.
