EngineeringBug FixedJune 2026

The UTC Timezone Bug in Vimshottari Dasha Calculation — And How to Fix It

There is a one-line bug that causes every Vimshottari dasha start and end date to be off by approximately one day on any server not running in Indian Standard Time. It shows up on AWS, GCP, Vercel, Railway — any cloud server defaulting to UTC. The bug is using new Date() to parse the birth date instead of Date.UTC().

Why Dasha Dates Are Sensitive to Timezone

Vimshottari dasha start dates are calculated from the Moon's position at birth — specifically, from the portion of the birth nakshatra already elapsed. A Moon at 5° of Ashwini means the person has already lived through 5/13.333 of their Ketu dasha balance. The birth moment must be in UTC for the Julian Day Number calculation to be correct. Parse it in local timezone and you introduce a systematic offset — up to 5.5 hours for IST, 8+ hours for US timezones — which shifts every single dasha date.

The Exact Bug

Here is the pattern that causes the problem. It appears in a function that converts the birth date + time string into a JavaScript Date for Julian Day Number computation:

❌ Broken — uses server local timezone
// dob = "01/01/1990", tob = "12:00", tz = 5.5
function getBirthDate(dob, tob, tz) {
const [d, m, y] = dob.split('/')
const [h, min] = tob.split(':')
// BUG: new Date() parses in server local timezone
const birthLocal = new Date(y, m-1, d, h, min)
const utcMs = birthLocal.getTime() - (tz * 3600000)
return new Date(utcMs)
}

The problem: new Date(y, m-1, d, h, min) interprets the date components in the server's local timezone. On a UTC server, this is fine. On a server set to IST (+5:30), this adds 5.5 hours implicitly before the explicit timezone subtraction — causing a double-application of IST offset.

The fix is one word:

✓ Fixed — timezone-independent
function getBirthDate(dob, tob, tz) {
const [d, m, y] = dob.split('/')
const [h, min] = tob.split(':')
// Date.UTC() always interprets as UTC — server timezone irrelevant
const utcMs = Date.UTC(+y, +m-1, +d, +h, +min) - (tz * 3600000)
return new Date(utcMs)
}

Date.UTC() always interprets its arguments as UTC components — it ignores the server's local timezone entirely. The birth local time is then explicitly shifted by the tz parameter (e.g. 5.5 for IST) to get the true UTC moment of birth. This is the only correct implementation.

How to Detect This Bug in Your API

Run the same birth chart on your API and on Jagannatha Hora. Compare the Jupiter Mahadasha start date for this reference chart:

dob: 01/01/1990 tob: 12:00 lat: 28.6139 lon: 77.2090 tz: 5.5
Correct Jupiter MD start: 2014-05-14 (±2 days)
Buggy result on UTC server: 2014-05-13 or 2014-05-15

A ~1-day drift in Jupiter Mahadasha start means every subsequent dasha date — Saturn, Mercury, Ketu, Venus, Sun, Moon, Mars, Rahu — is also off by approximately the same amount. The drift accumulates as a fixed offset across all 27 dashas.

Is Your Dasha API Affected?

If your Vedic astrology API is deployed on any cloud platform defaulting to UTC (AWS Lambda, GCP Cloud Functions, Vercel, Railway, Render, Fly.io), and your birth date parsing uses new Date(year, month, day, hour, minute), you have this bug.

The easiest test: run the reference chart above, compare the Jupiter Mahadasha start date to Jagannatha Hora. If it differs by more than 2 days, apply the Date.UTC() fix everywhere you parse birth date components into a JavaScript Date.

VedIntel™ AstroAPI: This Bug Is Fixed

We found and fixed this bug during our accuracy overhaul. Our dasha dates are verified against Jagannatha Hora within 2 days across the full 120-year cycle. See the full 71-check golden record test suite.

Try the API Free →View Docs
Related articles
How we verified 71 calculations against Jagannatha Hora →Rahu true node vs mean node — the 1.29° difference →Why Swiss Ephemeris matters for accuracy →