panchang-ts 5.1.1 → 5.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +225 -107
- package/dist/calendar/eclipsesTable.d.cts +5 -36
- package/dist/calendar/eclipsesTable.d.ts +5 -36
- package/dist/calendar/festivalsTable.cjs +0 -2
- package/dist/calendar/festivalsTable.d.cts +5 -35
- package/dist/calendar/festivalsTable.d.ts +5 -35
- package/dist/calendar/festivalsTable.js +0 -2
- package/dist/calendar/moonPhasesTable.cjs +0 -2
- package/dist/calendar/moonPhasesTable.d.cts +5 -35
- package/dist/calendar/moonPhasesTable.d.ts +5 -35
- package/dist/calendar/moonPhasesTable.js +0 -2
- package/dist/eclipsesTableTypes-NXQJdqX5.d.cts +72 -0
- package/dist/eclipsesTableTypes-NXQJdqX5.d.ts +72 -0
- package/dist/{festivalsTableTypes-CzDgY4zS.d.cts → festivalsTableTypes-DrGZtRjB.d.cts} +2 -39
- package/dist/{festivalsTableTypes-CzDgY4zS.d.ts → festivalsTableTypes-DrGZtRjB.d.ts} +2 -39
- package/dist/index.cjs +411 -645
- package/dist/index.d.cts +402 -4627
- package/dist/index.d.ts +402 -4627
- package/dist/index.js +406 -646
- package/dist/moonPhasesTableTypes-DQcbizmB.d.cts +64 -0
- package/dist/moonPhasesTableTypes-DQcbizmB.d.ts +64 -0
- package/dist/muhurta/muhurtaTable.cjs +0 -2
- package/dist/muhurta/muhurtaTable.d.cts +5 -36
- package/dist/muhurta/muhurtaTable.d.ts +5 -36
- package/dist/muhurta/muhurtaTable.js +0 -2
- package/dist/muhurtaTableTypes-D8iSFzSI.d.cts +52 -0
- package/dist/muhurtaTableTypes-D8iSFzSI.d.ts +52 -0
- package/package.json +10 -9
- package/dist/eclipsesTableTypes-BFYWRA44.d.cts +0 -108
- package/dist/eclipsesTableTypes-BFYWRA44.d.ts +0 -108
- package/dist/moonPhasesTableTypes-9XLibNCZ.d.cts +0 -103
- package/dist/moonPhasesTableTypes-9XLibNCZ.d.ts +0 -103
- package/dist/muhurtaTableTypes-CgBom297.d.cts +0 -81
- package/dist/muhurtaTableTypes-CgBom297.d.ts +0 -81
package/README.md
CHANGED
|
@@ -6,12 +6,16 @@
|
|
|
6
6
|
Pure TypeScript Hindu Panchang (almanac), Jyotish, and Birth Chart calculations.
|
|
7
7
|
Zero runtime dependencies. Works offline in React Native (Hermes), Node.js, and browsers.
|
|
8
8
|
|
|
9
|
-
**Fast** (~0.25 ms trimmed, ~0.41 ms full) · **Typed** (full TypeScript) · **Offline** (pure JS math) · **8,
|
|
9
|
+
**Fast** (~0.25 ms trimmed, ~0.41 ms full) · **Typed** (full TypeScript) · **Offline** (pure JS math) · **8,805 tests across 138 files**
|
|
10
10
|
|
|
11
11
|
> 📖 **Full documentation: [dharmagya.app/docs/panchang-ts](https://dharmagya.app/docs/panchang-ts)**
|
|
12
|
-
> This README covers install, quick start, and the 5.0 → 5.1 and 4.x → 5 migrations
|
|
13
|
-
> plus a per-feature quick reference. The complete reference
|
|
14
|
-
> table format, accuracy bound and performance note
|
|
12
|
+
> This README covers install, quick start, and the 5.1 → 5.2, 5.0 → 5.1 and 4.x → 5 migrations
|
|
13
|
+
> in full, plus a per-feature quick reference. The complete reference (every option, result field,
|
|
14
|
+
> table format, accuracy bound and performance note) lives on the docs site.
|
|
15
|
+
|
|
16
|
+
A Go port of the same engine ships from the same repository, held to this package's
|
|
17
|
+
exact arithmetic by a parity harness. See
|
|
18
|
+
[the repository](https://github.com/ishankgupta95/panchang-ts) if you need it.
|
|
15
19
|
|
|
16
20
|
---
|
|
17
21
|
|
|
@@ -46,12 +50,12 @@ console.log(result!.calendar.samvat.vikramSamvat); // 2081
|
|
|
46
50
|
|
|
47
51
|
### Reading Output Times
|
|
48
52
|
|
|
49
|
-
Every `Date` in a result is a **real instant
|
|
53
|
+
Every `Date` in a result is a **real instant**: `.getTime()` is the correct
|
|
50
54
|
epoch millisecond. Every instant has a `*Local` companion: an offset-carrying
|
|
51
55
|
ISO 8601 string, which is what you want for display.
|
|
52
56
|
|
|
53
57
|
```typescript
|
|
54
|
-
result!.sun.rise; // Date
|
|
58
|
+
result!.sun.rise; // Date: 2025-01-14T01:39:44.172Z (the actual moment)
|
|
55
59
|
result!.sun.riseLocal; // "2025-01-14T07:09:44.172+05:30"
|
|
56
60
|
result!.inauspicious.rahuKalam.start; // Date
|
|
57
61
|
result!.inauspicious.rahuKalam.startLocal;
|
|
@@ -73,7 +77,7 @@ const noon = new Date((result!.sun.rise.getTime() + result!.sun.set.getTime()) /
|
|
|
73
77
|
formatInZone(noon, result!.timezone.offsetMinutes); // "2025-01-14T12:27:31.086+05:30"
|
|
74
78
|
```
|
|
75
79
|
|
|
76
|
-
> **Changed in v5
|
|
80
|
+
> **Changed in v5. This is the breaking change most likely to affect you.**
|
|
77
81
|
> Through 4.x every published `Date` was the true instant *shifted* by the UTC
|
|
78
82
|
> offset, and the README told you to read it back with `getUTC*`. That worked
|
|
79
83
|
> only as long as you did nothing else with the value: `JSON.stringify` emitted
|
|
@@ -84,7 +88,7 @@ formatInZone(noon, result!.timezone.offsetMinutes); // "2025-01-14T12:27:31.086
|
|
|
84
88
|
> Migration is mechanical: `x.getUTCHours()` → read `xLocal`, or format the
|
|
85
89
|
> instant. See [Upgrading from 4.x](#upgrading-from-4x).
|
|
86
90
|
|
|
87
|
-
`moon.rise` / `moon.set` can be `null
|
|
91
|
+
`moon.rise` / `moon.set` can be `null`: the Moon occasionally does not rise or
|
|
88
92
|
set on a given calendar day, which is normal. `moon.riseLocal` / `moon.setLocal`
|
|
89
93
|
are `null` exactly when they are.
|
|
90
94
|
|
|
@@ -97,7 +101,7 @@ Through 4.x it was ~50 flat fields; the groups are what tell you where to look.
|
|
|
97
101
|
|---|---|
|
|
98
102
|
| `sun` | `rise` / `set` / `nextRise` (+ `*Local`), day and night lengths, the Sun's `siderealLongitude` and `nakshatra` |
|
|
99
103
|
| `moon` | `rise` / `set` (+ `*Local`), the Moon's `siderealLongitude` and `rashi` |
|
|
100
|
-
| `angas` | the five limbs
|
|
104
|
+
| `angas` | the five limbs: `tithis`, `nakshatras`, `yogas`, `karanas`, `vara` |
|
|
101
105
|
| `calendar` | `masa` (solar), `chandramasa` (lunar), `samvat` |
|
|
102
106
|
| `muhurtas` | `abhijit`, `brahma`, `vijaya`, `godhuli`, `nishita`, `amritKala`, `madhyahna`, `pratahSandhya`, `sayahnaSandhya`, `doGhati` |
|
|
103
107
|
| `inauspicious` | `rahuKalam`, `gulikaKalam`, `yamaganda`, `durMuhurta`, `varjyam`, `bhadra`, `gandaMula`, `panchaka`, `panchakaInfo`, `panchakaRahita` |
|
|
@@ -109,7 +113,7 @@ Top level: `date`, `location`, `timezone`, `ayanamsa`, `specialYogas`,
|
|
|
109
113
|
**Nothing is optional.** Every field is always present. A value that does not
|
|
110
114
|
apply is `null`; a collection that does not apply is `[]`. That holds whether
|
|
111
115
|
the reason is the domain (no Bhadra window today) or your options (you did not
|
|
112
|
-
pass `janmaRashi`, so `chandraBalam` is `null`)
|
|
116
|
+
pass `janmaRashi`, so `chandraBalam` is `null`). The result *shape* never
|
|
113
117
|
depends on what you passed.
|
|
114
118
|
|
|
115
119
|
`getInstantPanchang` uses the same group names for the subset an instant can
|
|
@@ -124,32 +128,148 @@ answer: `sun`, `moon`, `angas`, `calendar`, `inauspicious`. There is no
|
|
|
124
128
|
| Single-moment snapshot ("what's active right now?") or birth-chart casting | `getInstantPanchang` |
|
|
125
129
|
|
|
126
130
|
`getInstantPanchang` emits a `festivals` field but only checks rule predicates
|
|
127
|
-
at the given instant
|
|
131
|
+
at the given instant: it skips canonical-time refinements (madhyahna /
|
|
128
132
|
pradosha / nishita / chandrodaya), transit-based Sankranti, and Smarta/Vaishnava
|
|
129
133
|
Ekadashi split. For reliable festival dating, use `getDailyPanchang`.
|
|
130
134
|
|
|
135
|
+
### If you have no location
|
|
136
|
+
|
|
137
|
+
`location` is required and stays required. Nothing here silently guesses where you are, because a
|
|
138
|
+
panchang computed for the wrong place does not look wrong: it returns a complete, plausible result
|
|
139
|
+
with some dates off by one.
|
|
140
|
+
|
|
141
|
+
There are three reference frames, and a result is always in one of them:
|
|
142
|
+
|
|
143
|
+
| frame | point | when |
|
|
144
|
+
|---|---|---|
|
|
145
|
+
| `practical` | the location you passed | you have real coordinates. The only frame correct for a real user |
|
|
146
|
+
| `traditional` | **Ujjain** 23.1765N, 75.7885E | the classical madhya rekha of the Surya Siddhanta. The default |
|
|
147
|
+
| `modern` | **Central Station** 23.1833N, 82.5E | the 1955 Calendar Reform Committee reference for the Rashtriya Panchang |
|
|
148
|
+
|
|
149
|
+
Why the frame matters at all: a tithi, nakshatra, yoga or karana **ends at one instant worldwide**.
|
|
150
|
+
Only the civil day it gets labelled with depends on your sunrise, along with everything else
|
|
151
|
+
rise/set derived (rahu kalam, choghadiya, pradosha, nishita, moonrise anchors).
|
|
152
|
+
|
|
153
|
+
```typescript
|
|
154
|
+
import { getDailyPanchang, resolveLocation, IST_OFFSET_MINUTES } from 'panchang-ts';
|
|
155
|
+
|
|
156
|
+
// maybeLocation may be undefined; traditional (Ujjain) is the default frame
|
|
157
|
+
const { location, reference } = resolveLocation(maybeLocation);
|
|
158
|
+
const day = getDailyPanchang(date, location, { timezone: IST_OFFSET_MINUTES });
|
|
159
|
+
|
|
160
|
+
if (reference !== 'practical') {
|
|
161
|
+
// say so, the way a printed panchang names the city it was computed for
|
|
162
|
+
console.info(`Computed for the ${reference} reference, not your location.`);
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Pass `'modern'` as the second argument to fall back to the Central Station instead, or use
|
|
167
|
+
`referenceLocation('traditional' | 'modern')` if you only want the point. `'practical'` is
|
|
168
|
+
reported, never selected: passing a location is what makes a result practical.
|
|
169
|
+
|
|
170
|
+
**Price the fallbacks before you rely on them.** Measured over 730 days against 48 Indian cities,
|
|
171
|
+
the tithi at the reference's sunrise differs from the city's own on up to **5.9% of days** for
|
|
172
|
+
Ujjain and **4.0%** for the Central Station. Ujjain is the better of the two for most users
|
|
173
|
+
(population-weighted 1.18% against 1.80%, since India's metros lie west of the IST meridian) and
|
|
174
|
+
the worse in the tail. Outside India both degrade without limit.
|
|
175
|
+
|
|
176
|
+
`IST_OFFSET_MINUTES` (330) is exact for the Central Station, whose longitude is the IST meridian.
|
|
177
|
+
For Ujjain it is the civil clock rather than its local mean time, which is 303.2 minutes; the
|
|
178
|
+
26.8-minute gap is what the classical deshantara correction exists to close.
|
|
179
|
+
|
|
180
|
+
A half-filled location throws rather than being completed from a reference point, and
|
|
181
|
+
`{ latitude: 0, longitude: 0 }` is treated as the real place it is, not as missing.
|
|
182
|
+
|
|
183
|
+
Note that the shipped static tables (`panchang-ts/festivals`, `/eclipses`, `/muhurta`) are
|
|
184
|
+
pre-computed for Varanasi, which is a fourth point again.
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
## Upgrading to 5.2
|
|
189
|
+
|
|
190
|
+
No type breaks and no removed exports. What changes is output: a set of dates that
|
|
191
|
+
were wrong, or missing entirely, are now right. If you cache festival dates, diff
|
|
192
|
+
them against a rebuild before you ship, and key on `festivals[].key` rather than on
|
|
193
|
+
the label, because 27 user-visible strings changed punctuation in both `en` and `hi`.
|
|
194
|
+
|
|
195
|
+
### Festivals that used to vanish for a whole year now appear
|
|
196
|
+
|
|
197
|
+
A tithi that begins and ends between two consecutive sunrises is current at no
|
|
198
|
+
sunrise. A rule keyed on the sunrise tithi matched it on no day of the year, so the
|
|
199
|
+
festival disappeared from that year entirely. Ugadi and Gudi Padwa were absent from
|
|
200
|
+
2026 at every location; Navaratri 2027, Gangaur 2025, both Teejes, Govardhan Puja,
|
|
201
|
+
Bhai Dooj, Anant Chaturdashi, Kartika Purnima and Chhath Kharna were missing at some
|
|
202
|
+
cities and present at others. The Hindu day that wholly contains the tithi now claims it, which
|
|
203
|
+
is what the reference almanac publishes.
|
|
204
|
+
|
|
205
|
+
Measured over eight Indian cities across 2020 to 2030: **87 dates added, and no
|
|
206
|
+
existing date moves.** Every addition belongs to a city and year where the festival
|
|
207
|
+
previously had no date at all, so nothing is rescheduled.
|
|
208
|
+
|
|
209
|
+
Four festivals are deliberately left out, because the reference does not put them on
|
|
210
|
+
the containing day: Narak Chaturdashi and Chhath Usha Arghya, which it publishes on
|
|
211
|
+
the day the tithi ends, and Holi and Phagli, which are anchored to pradosha.
|
|
212
|
+
|
|
213
|
+
### Three festivals move to a different date
|
|
214
|
+
|
|
215
|
+
These are the ones to diff for. They are corrections, not additions.
|
|
216
|
+
|
|
217
|
+
| festival | was | now |
|
|
218
|
+
|---|---|---|
|
|
219
|
+
| Vat Savitri Amavasya | roughly 30 days late, every year | 7 of 7 checked years match the reference |
|
|
220
|
+
| Rig Upakarma | 9 of 13 checked years right | 13 of 13 |
|
|
221
|
+
| Sama Upakarma | 4 of 13 checked years right | 13 of 13 |
|
|
222
|
+
|
|
223
|
+
Vat Savitri Amavasya was filed under the wrong lunar month. The vrat falls on
|
|
224
|
+
purnimanta Jyeshtha Amavasya, and an amavasya ends its amanta month, so the two
|
|
225
|
+
namings sit a month apart; the rule had been selecting the following new moon since
|
|
226
|
+
the festival was added. It is now also anchored to aparahna rather than sunrise, with
|
|
227
|
+
the later day taking a span that reaches aparahna twice. `vat_savitri_purnima` is
|
|
228
|
+
unaffected and still correct, because a purnima sits inside the amanta month it names.
|
|
229
|
+
|
|
230
|
+
Both Upakarma rules matched on the nakshatra at sunrise and nothing else. Sama
|
|
231
|
+
Upakarma fired a **second** time in six of thirteen years, on the Bhadrapada Krishna
|
|
232
|
+
Amavasya that carries Hasta again, and was a day late in five more. Rig Upakarma
|
|
233
|
+
emitted two dates when its nakshatra spanned two sunrises (2019, 2029), a date in the
|
|
234
|
+
wrong paksha when the nakshatra slipped into Krishna (2020), and nothing at all in
|
|
235
|
+
the one year it fell outside Shukla paksha entirely (2022). Both now emit exactly one date in all 88
|
|
236
|
+
city-years of the eight-city sweep. Sama Upakarma is anchored to aparahna and is
|
|
237
|
+
therefore longitude sensitive: in 2026 it is the 13th of September at Kolkata and the
|
|
238
|
+
12th elsewhere, which is what the reference publishes.
|
|
239
|
+
|
|
240
|
+
### Numbers that changed
|
|
241
|
+
|
|
242
|
+
`getUpcomingSolarEclipse` did not check that an eclipse ended after the instant it
|
|
243
|
+
was asked to search from, so range walkers could return the same eclipse repeatedly
|
|
244
|
+
and drop others. `computeEclipsesInRange(2000 to 2011, Varanasi)` returned 277
|
|
245
|
+
entries of which 249 were one 2007 partial; it now returns 32 distinct entries.
|
|
246
|
+
Shadbala Kala Bala is now anchored to the preceding sunrise rather than the following
|
|
247
|
+
one, moving 1009 of 2016 sampled births. Narayan dasha durations exclude adjacent
|
|
248
|
+
signs from rasi drishti. Gulika and Mandi use a day/night test that matches their own
|
|
249
|
+
definition.
|
|
250
|
+
|
|
131
251
|
---
|
|
132
252
|
|
|
133
|
-
## Upgrading to 5.1
|
|
253
|
+
## Upgrading to 5.1, part 2
|
|
134
254
|
|
|
135
255
|
Two deliberate type breaks, both correcting fields that did not match
|
|
136
|
-
|
|
256
|
+
the reference almanac (the project's parity oracle), in the same style as part 1's
|
|
137
257
|
`varjyam` break.
|
|
138
258
|
|
|
139
259
|
### `inauspicious.durMuhurta` is now `DurMuhurtaPeriod[]`
|
|
140
260
|
|
|
141
261
|
```diff
|
|
142
262
|
- const [dm1, dm2] = r.inauspicious.durMuhurta;
|
|
143
|
-
+ r.inauspicious.durMuhurta.forEach((dm) => show(dm)); // 1
|
|
263
|
+
+ r.inauspicious.durMuhurta.forEach((dm) => show(dm)); // 1-2 windows
|
|
144
264
|
+ // dm.segment is 'day' or 'night' (only Tuesday carries a night window)
|
|
145
265
|
```
|
|
146
266
|
|
|
147
|
-
The old table emitted two day windows every day and matched
|
|
267
|
+
The old table emitted two day windows every day and matched the almanac on none of
|
|
148
268
|
the seven weekdays. The corrected classical Muhurta-Chintamani table gives
|
|
149
|
-
one window on Sunday and Wednesday, two elsewhere
|
|
269
|
+
one window on Sunday and Wednesday, two elsewhere, and Tuesday's second
|
|
150
270
|
window falls at **night** (the 7th of the 15 sunset→sunrise muhurtas), so
|
|
151
271
|
the exactly-two-day-windows tuple could not survive. Verified against 58
|
|
152
|
-
consecutive
|
|
272
|
+
consecutive almanac day-pages across two cities; a full almanac week is pinned.
|
|
153
273
|
|
|
154
274
|
### `muhurtas.amritKala` is now `TimePeriod[]`
|
|
155
275
|
|
|
@@ -158,18 +278,18 @@ consecutive drik day-pages across two cities; a full drik week is pinned.
|
|
|
158
278
|
+ r.muhurtas.amritKala.forEach(show); // [] when the day has none
|
|
159
279
|
```
|
|
160
280
|
|
|
161
|
-
Amrit Kala shares Varjyam's architecture (
|
|
281
|
+
Amrit Kala shares Varjyam's architecture (the almanac prints them from the same
|
|
162
282
|
frame): each window anchors at its nakshatra's own start, offset by a
|
|
163
283
|
per-nakshatra count of nakshatra-elastic ghatikas, spans exactly 4 such
|
|
164
|
-
ghatikas, and belongs to the Hindu day its **start** falls in
|
|
165
|
-
per day. The old sunrise-anchored single window disagreed with
|
|
284
|
+
ghatikas, and belongs to the Hindu day its **start** falls in (0-2 windows
|
|
285
|
+
per day). The old sunrise-anchored single window disagreed with the almanac by up
|
|
166
286
|
to ~16 h. `computeAmritKala` is replaced by
|
|
167
287
|
`computeAmritKalaWindows(sunriseUtc, nextSunriseUtc, getMoon)`.
|
|
168
288
|
|
|
169
289
|
### Ekadashi splits: Smarta first, Vaishnava second
|
|
170
290
|
|
|
171
|
-
On the days
|
|
172
|
-
fast and the **later** one the Vaishnava fast
|
|
291
|
+
On the days the almanac prints an Ekadashi twice, the **earlier** day is the Smarta
|
|
292
|
+
fast and the **later** one the Vaishnava fast. The almanac says so in prose on every
|
|
173
293
|
Ekadashi date-time page. Two corrections bring the library in line:
|
|
174
294
|
|
|
175
295
|
```diff
|
|
@@ -183,11 +303,10 @@ Ekadashi date-time page. Two corrections bring the library in line:
|
|
|
183
303
|
```
|
|
184
304
|
|
|
185
305
|
Both the Dashami-viddha and the vriddha-Dwadashi (Pakshavardhini) splits now
|
|
186
|
-
match
|
|
306
|
+
match the almanac across every pair it publishes in 2024-2028. `getDailyPanchang`
|
|
187
307
|
callers that keyed off `smarta_ekadashi` / `vaishnava_ekadashi` on split days
|
|
188
308
|
will see the two swap places; `computeEkadashiDatesForYear` is unchanged.
|
|
189
|
-
Custom locale packs need the renamed viddha description keys
|
|
190
|
-
CHANGELOG.
|
|
309
|
+
Custom locale packs need the renamed viddha description keys.
|
|
191
310
|
|
|
192
311
|
### Regional solar new years land on their own days
|
|
193
312
|
|
|
@@ -203,12 +322,11 @@ keyed, with a piecewise `vasa` segment list on `BhadraInfo`), night-transit
|
|
|
203
322
|
Sankranti dates (+ a new `moment` field on `SankrantiEvent`), kshaya-Dwadashi
|
|
204
323
|
Ekadashi advance, Vijayadashami/Karva Chauth/Janmashtami kala rules, the
|
|
205
324
|
Kali Yuga year boundary, `scoreMuhurta` special-yoga parity, eastern-
|
|
206
|
-
longitude Gulika/Mandi, and the opt-in Ashtakavarga reductions.
|
|
207
|
-
CHANGELOG for each rule and its drik evidence.
|
|
325
|
+
longitude Gulika/Mandi, and the opt-in Ashtakavarga reductions.
|
|
208
326
|
|
|
209
327
|
---
|
|
210
328
|
|
|
211
|
-
## Upgrading to 5.1
|
|
329
|
+
## Upgrading to 5.1, part 1 (from 5.0)
|
|
212
330
|
|
|
213
331
|
One deliberate type break, two corrected dasha tables, and one opt-in flag.
|
|
214
332
|
|
|
@@ -221,24 +339,24 @@ One deliberate type break, two corrected dasha tables, and one opt-in flag.
|
|
|
221
339
|
|
|
222
340
|
5.0 evaluated only the nakshatra active at sunrise and dropped the second
|
|
223
341
|
Varjyam window printed panchangs show on transition days. 5.1 publishes every
|
|
224
|
-
window, in start order, under
|
|
342
|
+
window, in start order, under the almanac's attribution rule: a window belongs
|
|
225
343
|
to the Hindu day its **start** falls in (one that begins before sunrise and
|
|
226
|
-
runs past it is yesterday's), and window instants are unclamped
|
|
344
|
+
runs past it is yesterday's), and window instants are unclamped, so an end can
|
|
227
345
|
land after next sunrise. Validated window-for-window against a 61-day
|
|
228
|
-
|
|
346
|
+
reference-almanac sweep (Aug-Sep 2026, two full nakshatra cycles): 62/62 match.
|
|
229
347
|
|
|
230
348
|
Two value-level corrections ride along: **Mula carries a second tyajya spell**
|
|
231
|
-
(elapsed ghatikas 20 *and* 56
|
|
349
|
+
(elapsed ghatikas 20 *and* 56; the reference almanac, ProKerala and B.V. Raman's
|
|
232
350
|
*Muhurta* concur), so Mula days now emit the window 5.0 missed; and the
|
|
233
351
|
standalone `computeVarjyam` primitive returns the *earliest* of a nakshatra's
|
|
234
352
|
spells overlapping the day. New export: `computeVarjyamWindows(sunriseUtc,
|
|
235
353
|
nextSunriseUtc, getMoon)`.
|
|
236
354
|
|
|
237
|
-
### Yogini and Ashtottari starting lords were wrong
|
|
355
|
+
### Yogini and Ashtottari starting lords were wrong, now classical
|
|
238
356
|
|
|
239
357
|
- **Yogini** used `nakshatraIndex % 8`, off by three Yoginis for every birth.
|
|
240
|
-
Now the classical Devi-Bhagavata formula
|
|
241
|
-
8
|
|
358
|
+
Now the classical Devi-Bhagavata formula: (1-based janma nakshatra + 3) mod
|
|
359
|
+
8, remainder 1 = Mangala … 0 = Sankata, so Ashwini → Bhramari, Pushya →
|
|
242
360
|
Dhanya. Verified against published worked examples and PyJHora.
|
|
243
361
|
- **Ashtottari** used a years-proportional split of the zodiac from a Krittika
|
|
244
362
|
anchor, matching no source. Now the classical Ardradi **group table**
|
|
@@ -256,11 +374,11 @@ and should be discarded.
|
|
|
256
374
|
computeAshtakoot(boy, girl, { ganaCancellation: true });
|
|
257
375
|
```
|
|
258
376
|
|
|
259
|
-
Default output is byte-identical to 5.0 (
|
|
260
|
-
table applies no Gana cancellation, and
|
|
377
|
+
Default output is byte-identical to 5.0 (the reference almanac's published 36-guna
|
|
378
|
+
table applies no Gana cancellation, and reference-almanac parity stays the default
|
|
261
379
|
standard). With the flag raised, a doshic Gana score (≤ 1) is restored to the
|
|
262
380
|
full 6 when the two Moons' sign lords are the same graha or mutual naisargika
|
|
263
|
-
friends, recorded in `cancellations
|
|
381
|
+
friends, recorded in `cancellations`: the condition set attested across
|
|
264
382
|
independent pandit corpora; weaker ones are documented on `AshtakootOptions`
|
|
265
383
|
and deliberately not encoded.
|
|
266
384
|
|
|
@@ -272,10 +390,10 @@ Three changes move numbers that 4.x produced, and one option is gone.
|
|
|
272
390
|
|
|
273
391
|
### Lahiri ayanamsa corrected by +38″
|
|
274
392
|
|
|
275
|
-
The library's Lahiri constant sat 38 arcseconds behind
|
|
276
|
-
`23.853211°` at J2000 (the widely-repeated 23° 51′ 11.6″ figure) where
|
|
277
|
-
computes `23.863801°`. The replacement was solved from
|
|
278
|
-
values across 1950
|
|
393
|
+
The library's Lahiri constant sat 38 arcseconds behind the reference almanac's: it
|
|
394
|
+
used `23.853211°` at J2000 (the widely-repeated 23° 51′ 11.6″ figure) where the
|
|
395
|
+
almanac computes `23.863801°`. The replacement was solved from the almanac's own published
|
|
396
|
+
values across 1950-2050, which agree on it to within 0.01″, a century-wide
|
|
279
397
|
baseline, so the precession polynomial is pinned too, not just the epoch
|
|
280
398
|
constant. Every sidereal output moves with it:
|
|
281
399
|
|
|
@@ -284,32 +402,32 @@ constant. Every sidereal output moves with it:
|
|
|
284
402
|
| Nakshatra end-times | ~69 s later than 4.x (carries the ayanamsa once) |
|
|
285
403
|
| Yoga end-times | ~129 s later than 4.x (carries it twice) |
|
|
286
404
|
| Planetary longitudes, rashi, pada, lagna, divisionals, dashas | shifted +0.0106° |
|
|
287
|
-
| Tithi / karana end-times | unchanged
|
|
405
|
+
| Tithi / karana end-times | unchanged: Moon − Sun cancels the ayanamsa |
|
|
288
406
|
| Raman / KP / True Chitra / Thirukanitham | moved by the same +38″; their offsets from Lahiri are preserved |
|
|
289
407
|
|
|
290
|
-
Worst-case end-time drift vs
|
|
291
|
-
by ayanamsa exposure
|
|
408
|
+
Worst-case end-time drift vs the almanac dropped from 131 s to 60 s, and the sign split
|
|
409
|
+
by ayanamsa exposure (nakshatra and yoga early, tithi and karana late) is gone.
|
|
292
410
|
If you have snapshot tests or cached charts from 4.x, expect them to need
|
|
293
411
|
re-pinning.
|
|
294
412
|
|
|
295
413
|
### ΔT now uses measurement, so every published time moves ~6 s
|
|
296
414
|
|
|
297
|
-
4.x took ΔT (TT − UT) entirely from Espenak
|
|
298
|
-
extrapolation published in 2006, and Earth's rotation did not follow it
|
|
415
|
+
4.x took ΔT (TT − UT) entirely from Espenak-Meeus. Its post-2005 branches are an
|
|
416
|
+
extrapolation published in 2006, and Earth's rotation did not follow it. By
|
|
299
417
|
2026 the model reads about **5.9 s high**, drifting a further ~0.6 s each year.
|
|
300
418
|
Because this library reports *times*, that lands directly on published values.
|
|
301
419
|
|
|
302
420
|
v5 takes ΔT from the leap-second chain (`32.184 + (TAI − UTC)`, exact, and
|
|
303
421
|
within the 0.9 s band leap seconds maintain) wherever ΔT has actually been
|
|
304
|
-
measured, and resumes Espenak
|
|
422
|
+
measured, and resumes Espenak-Meeus beyond it carrying the offset it had
|
|
305
423
|
accrued. Against JPL Horizons the measured era now agrees to **0.005 s** at
|
|
306
424
|
every decade from 1980, where 4.x was seconds out.
|
|
307
425
|
|
|
308
426
|
| Output | Effect |
|
|
309
427
|
|---|---|
|
|
310
428
|
| Tithi / nakshatra / yoga / karana end-times | ~5.7 s later for 2025 dates, growing with the model's drift |
|
|
311
|
-
| Sankranti and other transit instants | same shift
|
|
312
|
-
| Sunrise / sunset / moonrise / moonset | barely moved
|
|
429
|
+
| Sankranti and other transit instants | same shift: it is one uniform correction, not per-element |
|
|
430
|
+
| Sunrise / sunset / moonrise / moonset | barely moved: the error scales against the 15°/hr sky rotation |
|
|
313
431
|
| Dates a panchang element is *filed under* | unchanged except where a transit sits within seconds of sunrise |
|
|
314
432
|
|
|
315
433
|
That last row is the one to know about. `computeSankrantisForYear` publishes a
|
|
@@ -323,7 +441,7 @@ near sunrise are where a day could flip.
|
|
|
323
441
|
`getInstantPanchang` located sunrise by searching forward from `date − 12 h`.
|
|
324
442
|
For an evening instant that start point is already past the morning's sunrise,
|
|
325
443
|
so it found *tomorrow's* and rolled the weekday back a day. Any query after
|
|
326
|
-
roughly 7 pm returned the previous vara
|
|
444
|
+
roughly 7 pm returned the previous vara, and with it the wrong Rahu Kalam,
|
|
327
445
|
Gulika Kalam, Yamaganda, Choghadiya, Hora, Anandadi yoga and special yogas.
|
|
328
446
|
`getDailyPanchang` was never affected. If you cached instant-mode results from
|
|
329
447
|
4.x for evening timestamps, discard them.
|
|
@@ -333,7 +451,7 @@ Gulika Kalam, Yamaganda, Choghadiya, Hora, Anandadi yoga and special yogas.
|
|
|
333
451
|
`precision: 'standard' | 'high'` and the `Precision` type no longer exist.
|
|
334
452
|
Element transitions are now solved by secant iteration, which converges to the
|
|
335
453
|
root rather than stopping at a fixed tolerance, so there is nothing left for the
|
|
336
|
-
option to select
|
|
454
|
+
option to select, and the tighter setting no longer buys anything. Removing it
|
|
337
455
|
from your options object is the whole migration; leaving it in is a type error,
|
|
338
456
|
not a silent no-op.
|
|
339
457
|
|
|
@@ -343,7 +461,7 @@ Solar rise/set is computed from a canonical anchor and cached per location-day,
|
|
|
343
461
|
so it no longer depends on which instant the caller happened to start searching
|
|
344
462
|
from. Values shift by ≤108 ms vs 4.x, and two calls for the same day now agree
|
|
345
463
|
exactly instead of differing by up to 109 ms. Windows derived proportionally
|
|
346
|
-
from the day length
|
|
464
|
+
from the day length (Varjyam, Bhadra, the slot systems) move by a little more
|
|
347
465
|
than that. This removes an inconsistency rather than introducing an
|
|
348
466
|
approximation: 4.x returned a different sunrise depending on which caller asked.
|
|
349
467
|
|
|
@@ -353,7 +471,7 @@ The same treatment sunrise received, now applied to the Moon. `getMoonrise` /
|
|
|
353
471
|
`getMoonset` resolve through a canonical per-UTC-day cache, so an event has one
|
|
354
472
|
timestamp no matter which caller asks or from which instant they searched.
|
|
355
473
|
Published `moon.rise` / `moon.set` shift by **≤182 ms** vs 4.x. Nothing else in the
|
|
356
|
-
result moves
|
|
474
|
+
result moves, verified over 11,520 daily results across six locations and three
|
|
357
475
|
centuries: zero changes to any index, name, boolean, festival date or other
|
|
358
476
|
timestamp.
|
|
359
477
|
|
|
@@ -361,8 +479,8 @@ timestamp.
|
|
|
361
479
|
|
|
362
480
|
`getFestivalsForYear` read a pre-built table; `getFestivalsInRange` ran the
|
|
363
481
|
engine. Two near-identical names, completely different inputs and semantics. v5
|
|
364
|
-
settles one convention across all four families
|
|
365
|
-
phases and muhurta:
|
|
482
|
+
settles one convention across all four families (festivals, eclipses, moon
|
|
483
|
+
phases and muhurta):
|
|
366
484
|
|
|
367
485
|
| 4.x | v5 | what it does |
|
|
368
486
|
|---|---|---|
|
|
@@ -371,8 +489,8 @@ phases and muhurta:
|
|
|
371
489
|
| `getFestivalsYearRange` | `readFestivalsYearRange` | reads a table |
|
|
372
490
|
| `getEclipsesForYear` / `ForDate` / `YearRange` | `readEclipsesForYear` / … | reads a table |
|
|
373
491
|
| `getMoonPhasesForYear` / `ForDate` / `YearRange` | `readMoonPhasesForYear` / … | reads a table |
|
|
374
|
-
|
|
|
375
|
-
|
|
|
492
|
+
| n/a | `readMuhurtaForYear` / `ForDate` / `YearRange` | **new**: reads a table |
|
|
493
|
+
| n/a | `readBestMuhurtaDays` | **new**: top-scoring days |
|
|
376
494
|
| `getFestivalsInRange` | `computeFestivalsInRange` | runs the engine |
|
|
377
495
|
| `getEclipsesInRange` | `computeEclipsesInRange` | runs the engine |
|
|
378
496
|
| `getMoonPhasesInRange` | `computeMoonPhasesInRange` | runs the engine |
|
|
@@ -380,7 +498,7 @@ phases and muhurta:
|
|
|
380
498
|
| `getEkadashiDatesForYear` | `computeEkadashiDatesForYear` | runs the engine |
|
|
381
499
|
| `getSankrantisForYear` | `computeSankrantisForYear` | runs the engine |
|
|
382
500
|
|
|
383
|
-
**Every 4.x name still works
|
|
501
|
+
**Every 4.x name still works**: they are deprecated aliases pointing at the same
|
|
384
502
|
functions, kept through v5. Nothing breaks today; the old names will go in v6.
|
|
385
503
|
|
|
386
504
|
New single-year entry points, the shape most callers reach for first:
|
|
@@ -419,7 +537,7 @@ Only days that pass the rule are stored unless you pass `includeFailures: true`.
|
|
|
419
537
|
indices, rather than repeating every localized string at every occurrence. A
|
|
420
538
|
10-year festival table goes from 315 KB to **89.9 KB (28.5%)**; a 10-year
|
|
421
539
|
moon-phase table from 106 KB to **29.7 KB (28.0%)**. Resolved output is
|
|
422
|
-
identical
|
|
540
|
+
identical, verified across every year and both locales.
|
|
423
541
|
|
|
424
542
|
Gzip already hid most of this on the wire, so the win is **parse time and
|
|
425
543
|
resident memory**, which is the constraint that actually bites on Hermes.
|
|
@@ -432,7 +550,7 @@ engine output.
|
|
|
432
550
|
table built with 4.x keeps working; only `key` is unavailable from it, and comes
|
|
433
551
|
back as `''`.
|
|
434
552
|
|
|
435
|
-
### Published `Date`s are real instants
|
|
553
|
+
### Published `Date`s are real instants: the flagship change
|
|
436
554
|
|
|
437
555
|
```diff
|
|
438
556
|
- result.sunrise.getTime() // NOT when sunrise happened (off by the UTC offset)
|
|
@@ -441,7 +559,7 @@ back as `''`.
|
|
|
441
559
|
+ result.sun.riseLocal // "2025-01-14T07:09:44.172+05:30"
|
|
442
560
|
```
|
|
443
561
|
|
|
444
|
-
Applies to **every** `Date` in `DailyPanchangResult` and to every `TimePeriod
|
|
562
|
+
Applies to **every** `Date` in `DailyPanchangResult` and to every `TimePeriod`:
|
|
445
563
|
`sun.rise`, `sun.set`, `sun.nextRise`, `moon.rise`, `moon.set`, all the muhurtas
|
|
446
564
|
and inauspicious periods, all four slot systems, the element
|
|
447
565
|
`startTime`/`endTime` arrays, the eclipse contacts and sutak window. Each gains
|
|
@@ -459,7 +577,7 @@ a `*Local` companion: `sun.riseLocal`, `inauspicious.rahuKalam.startLocal`,
|
|
|
459
577
|
`getInstantPanchang` results carry **no** `*Local` fields: that call takes no
|
|
460
578
|
timezone, so there is no zone to render a wall clock in.
|
|
461
579
|
|
|
462
|
-
**Cost:** rendering the strings adds ~0.04 ms per daily panchang
|
|
580
|
+
**Cost:** rendering the strings adds ~0.04 ms per daily panchang, invisible on
|
|
463
581
|
a cold call and ~20% of a fully cached warm one. The release warms to
|
|
464
582
|
**0.17 ms**, against published 4.3.1's **6.20 ms**.
|
|
465
583
|
|
|
@@ -472,7 +590,7 @@ a cold call and ~20% of a fully cached warm one. The release warms to
|
|
|
472
590
|
```
|
|
473
591
|
|
|
474
592
|
`options.timezone` has always accepted `number | string`, but the result carried
|
|
475
|
-
only a number
|
|
593
|
+
only a number, so passing `'America/New_York'` produced a result that could not
|
|
476
594
|
say which zone produced it. `zone` is present only when you passed a zone name.
|
|
477
595
|
|
|
478
596
|
**The DST limit, now stated explicitly.** The offset is resolved **once per
|
|
@@ -485,7 +603,7 @@ whole truth.
|
|
|
485
603
|
### The result object is grouped
|
|
486
604
|
|
|
487
605
|
`DailyPanchangResult` had ~50 flat top-level fields mixing five categories.
|
|
488
|
-
v5 sorts them into seven groups
|
|
606
|
+
v5 sorts them into seven groups. See [The result is grouped](#the-result-is-grouped)
|
|
489
607
|
for the full table. This is a large break, and it lands in the same release as
|
|
490
608
|
the `Date` change on purpose: migrating both at once is one pass over your read
|
|
491
609
|
sites, not two.
|
|
@@ -514,7 +632,7 @@ Every rename, in full:
|
|
|
514
632
|
| `varjyam` / `bhadra` / `gandaMula` / `panchaka` / `panchakaRahita` | `inauspicious.*` (same names) |
|
|
515
633
|
| `choghadiya` / `hora` | `periods.choghadiya` / `periods.hora` |
|
|
516
634
|
| `gowriPanchangam` | `periods.gowri` |
|
|
517
|
-
| `eclipse.magnitude` (disc *area*) | `eclipse.obscuration
|
|
635
|
+
| `eclipse.magnitude` (disc *area*) | `eclipse.obscuration`: same value; the new `eclipse.magnitude` is the *diameter* fraction catalogues publish, and is negative for a penumbral lunar eclipse |
|
|
518
636
|
|
|
519
637
|
Unmoved: `date`, `location`, `timezone`, `ayanamsa`, `specialYogas`,
|
|
520
638
|
`anandadiYoga`, `festivals`, `eclipse`, `chandraBalam`, `tarabala`.
|
|
@@ -527,12 +645,12 @@ For `getInstantPanchang`: `tithi` / `nakshatra` / `yoga` / `karana` / `vara` →
|
|
|
527
645
|
|
|
528
646
|
### One rule for "not applicable": always present, `null` or `[]`
|
|
529
647
|
|
|
530
|
-
4.x used three conventions and you could not predict which you would get
|
|
648
|
+
4.x used three conventions and you could not predict which you would get:
|
|
531
649
|
`| null` for `bhadra` / `varjyam` / `eclipse`, `?`-optional for `chandraBalam` /
|
|
532
650
|
`tarabala`, and an empty array for `panchakaRahita` / `festivals`. v5 has one
|
|
533
651
|
rule: **every field is always present**, a value that does not apply is `null`,
|
|
534
652
|
and a collection that does not apply is `[]`. (Since 5.1, `varjyam` is a
|
|
535
|
-
collection and follows the `[]` arm
|
|
653
|
+
collection and follows the `[]` arm; see [Upgrading from 5.0](#upgrading-from-50).)
|
|
536
654
|
|
|
537
655
|
```diff
|
|
538
656
|
- if ('chandraBalam' in r) … // 4.x: field absent without janmaRashi
|
|
@@ -563,7 +681,7 @@ always `undefined`.
|
|
|
563
681
|
|
|
564
682
|
`sun.dinamanaMinutes` / `sun.dayDurationMinutes` and `sun.ratrimanaMinutes` /
|
|
565
683
|
`sun.nightDurationMinutes` are the same numbers under classical and English
|
|
566
|
-
names. Both pairs stay
|
|
684
|
+
names. Both pairs stay (consumers use both vocabularies) and the types now say
|
|
567
685
|
plainly that they are aliases, never independently computed.
|
|
568
686
|
|
|
569
687
|
`calendar.chandramasa` keeps its casing beside `moon.rashi` and `sun.nakshatra`.
|
|
@@ -575,15 +693,15 @@ the **lunar** one, which was previously left to guesswork.
|
|
|
575
693
|
|
|
576
694
|
- `EclipseInfo` / `EclipseSubtype` are now exported. 4.x shipped
|
|
577
695
|
`getUpcomingLunarEclipse` and friends without the type they return.
|
|
578
|
-
- `festivals[].key
|
|
696
|
+
- `festivals[].key`: stable, language-independent festival id. Match on this,
|
|
579
697
|
never on `name`.
|
|
580
|
-
- `bhadra.locationName
|
|
698
|
+
- `bhadra.locationName`: localized display name; `bhadra.location` stays the
|
|
581
699
|
machine-readable key.
|
|
582
|
-
- `MuhurtaScore.factors
|
|
583
|
-
- `BirthChart.byPlanet
|
|
700
|
+
- `MuhurtaScore.factors`: structured scoring inputs alongside English `reasons`.
|
|
701
|
+
- `BirthChart.byPlanet`: the nine placements keyed by graha.
|
|
584
702
|
- `eclipse.description` is now localized. Under `language: 'hi'` it was
|
|
585
703
|
previously emitted in English, including inside `festivals[].description`.
|
|
586
|
-
- `sections` on `getDailyPanchang
|
|
704
|
+
- `sections` on `getDailyPanchang`: opt into a narrower, cheaper call. See
|
|
587
705
|
[Performance](#performance).
|
|
588
706
|
|
|
589
707
|
---
|
|
@@ -592,7 +710,7 @@ the **lunar** one, which was previously left to guesswork.
|
|
|
592
710
|
|
|
593
711
|
| Category | Features |
|
|
594
712
|
|---|---|
|
|
595
|
-
| **Pancha Anga** | Tithi, Nakshatra, Yoga, Karana, Vara
|
|
713
|
+
| **Pancha Anga** | Tithi, Nakshatra, Yoga, Karana, Vara, with all intra-day transitions |
|
|
596
714
|
| **Lunar Calendar** | Chandra Masa (Purnimanta + Amanta), Adhika (leap) detection, Vikram + Shaka Samvat |
|
|
597
715
|
| **Solar Calendar** | Saura Masa, Surya Nakshatra, Sankranti (transit-based) |
|
|
598
716
|
| **Sun & Moon** | Sunrise, Sunset, Moonrise, Moonset (Meeus apparent-upper-limb), Chandra Rashi |
|
|
@@ -602,7 +720,7 @@ the **lunar** one, which was previously left to guesswork.
|
|
|
602
720
|
| **Special Yogas** | Anandadi (28-cycle), Amrit Siddhi, Sarvartha Siddhi, Ravi/Guru Pushya, Dwi-/Tripushkar, Jwalamukhi, Aadal, Vidaal, Ravi |
|
|
603
721
|
| **Festivals (80+)** | Ekadashi (Smarta/Vaishnava split), Pradosha, Sankranti, classical (Diwali/Holi/Shivaratri…), regional across 21 states + Nepal |
|
|
604
722
|
| **Eclipses** | Solar/lunar detection, subtype, magnitude, horizon visibility, sutak window |
|
|
605
|
-
| **Planetary Positions** | All 9 grahas (sidereal) with rashi, nakshatra, pada, retrograde
|
|
723
|
+
| **Planetary Positions** | All 9 grahas (sidereal) with rashi, nakshatra, pada, retrograde; mean or true Rahu/Ketu |
|
|
606
724
|
| **Dashas** | Vimshottari (3-level), Ashtottari, Yogini, Chara, Narayan |
|
|
607
725
|
| **Personal Transits** | Chandra Balam, Tarabala (9-cycle), Sade Sati |
|
|
608
726
|
| **Birth Chart** | Lagna, Bhava under 3 house systems, D1/D2/D3/D7/D9/D10/D12/D30, Planetary Dignity |
|
|
@@ -620,14 +738,14 @@ the **lunar** one, which was previously left to guesswork.
|
|
|
620
738
|
|
|
621
739
|
## Used By
|
|
622
740
|
|
|
623
|
-
- [dharmagya.app](https://dharmagya.app)
|
|
741
|
+
- [dharmagya.app](https://dharmagya.app): Daily Panchang and Hindu calendar ([Play Store](https://play.google.com/store/apps/details?id=com.ishank1995.dharmagya))
|
|
624
742
|
|
|
625
743
|
---
|
|
626
744
|
|
|
627
745
|
# Feature Reference
|
|
628
746
|
|
|
629
747
|
A quick tour with runnable snippets. **Each section links to its full page on
|
|
630
|
-
the docs site
|
|
748
|
+
the docs site**: every option, field, and caveat lives there.
|
|
631
749
|
|
|
632
750
|
## Pancha Anga & the daily result
|
|
633
751
|
|
|
@@ -639,8 +757,8 @@ const r = getDailyPanchang(date, location, { timezone: 330 })!;
|
|
|
639
757
|
r.angas.tithis.forEach(t => console.log(t.name, t.paksha, t.endTime));
|
|
640
758
|
r.angas.vara.name; // "Mangalawara"
|
|
641
759
|
r.calendar.chandramasa.isAdhika; // true during leap months
|
|
642
|
-
r.muhurtas.brahma; // TimePeriod | null
|
|
643
|
-
r.inauspicious.rahuKalam; // { start, end }
|
|
760
|
+
r.muhurtas.brahma; // TimePeriod | null, and 9 more muhurtas
|
|
761
|
+
r.inauspicious.rahuKalam; // { start, end }, and 9 more windows
|
|
644
762
|
r.periods.choghadiya.day[0].name; // 16 Choghadiya + Gowri + 24 Hora slots
|
|
645
763
|
r.anandadiYoga.name; r.specialYogas; // Anandadi + Amrit/Sarvartha Siddhi, …
|
|
646
764
|
|
|
@@ -656,7 +774,7 @@ console.log(i.angas.tithi.name, i.angas.nakshatra.name);
|
|
|
656
774
|
|
|
657
775
|
```typescript
|
|
658
776
|
r.festivals.forEach(f => console.log(f.key, f.name, f.type, f.deferralDate));
|
|
659
|
-
// `name` is localized, so match on `key
|
|
777
|
+
// `name` is localized, so match on `key`, never on `name`:
|
|
660
778
|
const hasDiwali = r.festivals.some(f => f.key === 'diwali');
|
|
661
779
|
|
|
662
780
|
// Scope regional variants: 21 state slugs + 'nepal' + 'all' (default)
|
|
@@ -667,7 +785,7 @@ import { buildFestivalsTable } from 'panchang-ts';
|
|
|
667
785
|
import { readFestivalsForYear, readFestivalsForDate } from 'panchang-ts/festivals';
|
|
668
786
|
```
|
|
669
787
|
|
|
670
|
-
No table ships with the package
|
|
788
|
+
No table ships with the package: festival dates are observer-dependent, so you
|
|
671
789
|
build one for your users' location and years (`npm run festivals:gen` is a
|
|
672
790
|
worked example).
|
|
673
791
|
|
|
@@ -699,7 +817,7 @@ import { scoreMuhurta, computeAuspiciousDatesInRange, vivahRule } from 'panchang
|
|
|
699
817
|
|
|
700
818
|
const s = scoreMuhurta(new Date('2026-05-12'), DELHI, vivahRule, { timezone: 330 });
|
|
701
819
|
s.score; // 0..100; passes when ≥ 50
|
|
702
|
-
s.factors; // structured, stable codes
|
|
820
|
+
s.factors; // structured, stable codes: localize/filter on these
|
|
703
821
|
s.reasons; // diagnostic English
|
|
704
822
|
|
|
705
823
|
computeAuspiciousDatesInRange(vivahRule, start, end, DELHI, { timezone: 330 });
|
|
@@ -774,7 +892,7 @@ import {
|
|
|
774
892
|
|
|
775
893
|
computeAshtakoot({ rashi: 4, nakshatra: 9 }, { rashi: 0, nakshatra: 1 });
|
|
776
894
|
// → { totalScore: 0..36, koots: KootScore[8], cancellations: string[] }
|
|
777
|
-
// Opt-in Gana-dosha cancellation (default off
|
|
895
|
+
// Opt-in Gana-dosha cancellation (default off, preserves almanac 36-guna parity):
|
|
778
896
|
computeAshtakoot(boy, girl, { ganaCancellation: true });
|
|
779
897
|
|
|
780
898
|
computeMangalCompatibility(boyChart, girlChart); // Manglik is a PAIRWISE verdict
|
|
@@ -826,7 +944,7 @@ getHinduNewYear(2026, 'tamil-nadu', DELHI, { timezone: 330 }); // region-aware
|
|
|
826
944
|
```typescript
|
|
827
945
|
const hi = getDailyPanchang(date, loc, { timezone: 330, language: 'hi' })!;
|
|
828
946
|
hi.angas.tithis[0].name; // "कृष्ण चतुर्दशी"
|
|
829
|
-
hi.angas.vara.englishName; // "Tuesday"
|
|
947
|
+
hi.angas.vara.englishName; // "Tuesday", englishName always English
|
|
830
948
|
|
|
831
949
|
// All options: timezone (number | IANA string), ayanamsa (5), language (en|hi),
|
|
832
950
|
// masaSystem (purnimanta|amanta), region, computeEndTimes, sections,
|
|
@@ -834,12 +952,12 @@ hi.angas.vara.englishName; // "Tuesday" — englishName always English
|
|
|
834
952
|
```
|
|
835
953
|
|
|
836
954
|
Machine-readable keys never change with language: match on `festival.key`,
|
|
837
|
-
`bhadra.location`, `eclipse.kind`, `factors[].code
|
|
955
|
+
`bhadra.location`, `eclipse.kind`, `factors[].code`; render `name` /
|
|
838
956
|
`locationName` / `description` / `reasons`.
|
|
839
957
|
|
|
840
958
|
## Types & Exports
|
|
841
959
|
|
|
842
|
-
📖 [Types & Exports →](https://dharmagya.app/docs/panchang-ts/types)
|
|
960
|
+
📖 [Types & Exports →](https://dharmagya.app/docs/panchang-ts/types): the key
|
|
843
961
|
interfaces (`TithiInfo`, `FestivalInfo`, `EclipseInfo`, `GrahaPosition`, …) and
|
|
844
962
|
the complete export list of the main entry and the four engine-free subpaths
|
|
845
963
|
(`panchang-ts/festivals`, `/eclipses`, `/moon-phases`, `/muhurta`).
|
|
@@ -849,7 +967,7 @@ the complete export list of the main entry and the four engine-free subpaths
|
|
|
849
967
|
## React Native / Hermes
|
|
850
968
|
|
|
851
969
|
Works with Expo and bare React Native (Hermes engine). Pass `timezone` as a
|
|
852
|
-
**number
|
|
970
|
+
**number**: IANA strings need `Intl`, which older Hermes versions lack.
|
|
853
971
|
|
|
854
972
|
Two-pass rendering pattern for smooth UI:
|
|
855
973
|
|
|
@@ -857,7 +975,7 @@ Two-pass rendering pattern for smooth UI:
|
|
|
857
975
|
import { getDailyPanchang } from 'panchang-ts';
|
|
858
976
|
import { InteractionManager } from 'react-native';
|
|
859
977
|
|
|
860
|
-
// Pass 1
|
|
978
|
+
// Pass 1 (cheapest useful result): elements, slots, muhurtas (~0.25 ms).
|
|
861
979
|
const fast = getDailyPanchang(date, location, {
|
|
862
980
|
timezone: 330,
|
|
863
981
|
sections: [],
|
|
@@ -865,7 +983,7 @@ const fast = getDailyPanchang(date, location, {
|
|
|
865
983
|
});
|
|
866
984
|
setState(fast);
|
|
867
985
|
|
|
868
|
-
// Pass 2
|
|
986
|
+
// Pass 2 (background): everything (~0.41 ms).
|
|
869
987
|
InteractionManager.runAfterInteractions(() => {
|
|
870
988
|
setState(getDailyPanchang(date, location, { timezone: 330 }));
|
|
871
989
|
});
|
|
@@ -877,35 +995,35 @@ InteractionManager.runAfterInteractions(() => {
|
|
|
877
995
|
|
|
878
996
|
📖 [Full accuracy notes →](https://dharmagya.app/docs/panchang-ts/accuracy)
|
|
879
997
|
|
|
880
|
-
8,
|
|
881
|
-
panchang calculations spanning 2025
|
|
998
|
+
8,805 tests across 138 files, including fixtures cross-verified against reference
|
|
999
|
+
panchang calculations spanning 2025-2026 across 10 Indian cities plus New York,
|
|
882
1000
|
London, Sydney, Dubai, Singapore (diaspora fixtures cover DST on
|
|
883
1001
|
`America/New_York`).
|
|
884
1002
|
|
|
885
1003
|
| Element | Accuracy |
|
|
886
1004
|
|---|---|
|
|
887
1005
|
| Sunrise / Sunset | ≤29 s observed vs reference minute-midpoint (±45 s tolerance) |
|
|
888
|
-
| Moonrise / Moonset | Meeus apparent-upper-limb (refraction + parallax); ~3
|
|
1006
|
+
| Moonrise / Moonset | Meeus apparent-upper-limb (refraction + parallax); ~3-5 min vs simpler-horizon authorities is expected |
|
|
889
1007
|
| Tithi / Nakshatra / Yoga / Karana names | Exact match vs reference |
|
|
890
|
-
| Tithi / Nakshatra / Yoga / Karana end-times | ≤60 s vs
|
|
891
|
-
| Ayanamsa (Lahiri) | Reproduces
|
|
892
|
-
| Planetary positions (Sun
|
|
1008
|
+
| Tithi / Nakshatra / Yoga / Karana end-times | ≤60 s vs the reference almanac across all 20 audited comparisons |
|
|
1009
|
+
| Ayanamsa (Lahiri) | Reproduces the reference almanac's published value to ~0.01″ across 1950-2050 |
|
|
1010
|
+
| Planetary positions (Sun-Saturn) | ±0.02° sidereal |
|
|
893
1011
|
| Planetary positions (Rahu/Ketu) | ≤0.5° mean node, ≤0.6° true node (typical) |
|
|
894
1012
|
| Lagna sidereal longitude | Cross-checked against Jagannath Hora reference charts |
|
|
895
1013
|
| D1 / D9 house placement | Exact match vs reference for 9-graha placement |
|
|
896
1014
|
| Ashtakoot total | ±1 point per pair across 30+ matched pairs |
|
|
897
|
-
| Varjyam windows | count + position vs
|
|
898
|
-
| Sade Sati arc start/end | ±1
|
|
1015
|
+
| Varjyam windows | count + position vs the reference almanac over a 61-day / two-nakshatra-cycle sweep, ≤2 min (62/62 windows) |
|
|
1016
|
+
| Sade Sati arc start/end | ±1-2 days vs authoritative ephemerides |
|
|
899
1017
|
|
|
900
1018
|
**Festival dating** uses tithi-at-sunrise; a few festivals have authorities on
|
|
901
1019
|
other rules (tithi-at-midnight for Janmashtami / Shivaratri / Diwali,
|
|
902
1020
|
madhyahna-vyapini for Ganesh Chaturthi edge years) where output can drift
|
|
903
|
-
±1 day
|
|
1021
|
+
±1 day. The exact list is
|
|
904
1022
|
[documented](https://dharmagya.app/docs/panchang-ts/accuracy#festival-tradeoff).
|
|
905
1023
|
|
|
906
1024
|
**Detection conventions:** Aadal / Vidaal follow the classical Moon-from-Sun
|
|
907
1025
|
nakshatra-distance rule, not the Tamil-Vakya weekday rule. Varjyam lists every
|
|
908
|
-
window whose start falls in the Hindu day (
|
|
1026
|
+
window whose start falls in the Hindu day (the almanac's attribution; Mula carries two
|
|
909
1027
|
tyajya spells). Do Ghati does not rotate by weekday.
|
|
910
1028
|
|
|
911
1029
|
---
|
|
@@ -914,7 +1032,7 @@ tyajya spells). Do Ghati does not rotate by weekday.
|
|
|
914
1032
|
|
|
915
1033
|
📖 [Full performance notes →](https://dharmagya.app/docs/panchang-ts/performance)
|
|
916
1034
|
|
|
917
|
-
Measured at Pune, Apple M-series, Node
|
|
1035
|
+
Measured at Pune, Apple M-series, Node (median of 11 processes). **Distinct
|
|
918
1036
|
days** is the calendar-scan cost; **same day repeated** is what a UI
|
|
919
1037
|
re-rendering one date sees. Last column is published 4.3.1, benchmarked beside
|
|
920
1038
|
this release.
|
|
@@ -927,12 +1045,12 @@ this release.
|
|
|
927
1045
|
|
|
928
1046
|
**A default day is ~15× cheaper than 4.3.1**, a repeated day ~37×. The levers:
|
|
929
1047
|
|
|
930
|
-
- **`sections`**
|
|
1048
|
+
- **`sections`** skips the optional ephemeris-backed blocks (`'festivals'`,
|
|
931
1049
|
`'eclipse'`, `'moonTimes'`, `'lunarWindows'`). Narrowing is exactly
|
|
932
1050
|
output-neutral: every field a narrowed call computes is identical to the full
|
|
933
1051
|
call's; omitted sections sit at their documented `null` / `[]`.
|
|
934
|
-
- **`computeEndTimes: false`**
|
|
935
|
-
~5
|
|
1052
|
+
- **`computeEndTimes: false`** drops the `endTime` transition searches;
|
|
1053
|
+
~5-10%. Use it to drop fields you don't want, not to go faster.
|
|
936
1054
|
|
|
937
1055
|
Range helpers narrow internally: `computeEkadashiDatesForYear` **~18 ms/year**
|
|
938
1056
|
(4.3.1: ~2,360), `computeFestivalsInRange` **~131 ms/year** (~2,180),
|
|
@@ -941,7 +1059,7 @@ cached process-wide (bounded, 20k entries), which also makes them
|
|
|
941
1059
|
single-valued.
|
|
942
1060
|
|
|
943
1061
|
One deliberate regression: raw chart primitives (`computeRashiChart`,
|
|
944
|
-
`computeNavamsa`) cost ~0.32 ms vs ~0.10 in 4.3.1
|
|
1062
|
+
`computeNavamsa`) cost ~0.32 ms vs ~0.10 in 4.3.1, the price of an
|
|
945
1063
|
order-of-magnitude accuracy gain against JPL DE441. `computeShadbala` /
|
|
946
1064
|
`computeBhavaBala` went the other way, ~2× faster.
|
|
947
1065
|
|
|
@@ -970,7 +1088,7 @@ Error codes: `INVALID_DATE`, `INVALID_LATITUDE`, `INVALID_LONGITUDE`,
|
|
|
970
1088
|
`CIRCUMPOLAR` (Placidus-KP houses above ±66.5°).
|
|
971
1089
|
|
|
972
1090
|
**Polar locations.** `getDailyPanchang` and `getInstantPanchang` return `null`
|
|
973
|
-
rather than throwing
|
|
1091
|
+
rather than throwing: the Hindu day is undefined when sunrise can't be
|
|
974
1092
|
computed. The low-level `getSunrise` / `getSunset` primitives still throw
|
|
975
1093
|
`PanchangError(NO_SUNRISE)` / `PanchangError(NO_SUNSET)` for direct callers
|
|
976
1094
|
who need the precise reason. `getMoonrise` / `getMoonset` return `null` (normal
|
|
@@ -995,7 +1113,7 @@ dependencies**, and is `sideEffects: false`.
|
|
|
995
1113
|
|
|
996
1114
|
## Acknowledgements
|
|
997
1115
|
|
|
998
|
-
As of v5 the package has **no runtime dependencies
|
|
1116
|
+
As of v5 the package has **no runtime dependencies**: the ephemeris, ΔT model
|
|
999
1117
|
and event searches are the library's own. Two projects still deserve credit:
|
|
1000
1118
|
[astronomy-engine](https://github.com/cosinekitty/astronomy) by Don Cross (MIT),
|
|
1001
1119
|
the runtime engine through 4.x and now the dev-time baseline the own ephemeris
|