Anyone can assert a planetary position. Stating how it was arrived at is what makes it checkable, so these are the conventions this site uses, held constant across every chart and every reading. Where one is weaker than you might expect, it is written that way on purpose: a settings list that flatters the engine is worth nothing to someone trying to reproduce a chart. The page has been corrected several times; each correction is dated in the history at the bottom.
The settings at a glance
| setting | what we use |
|---|---|
| Ephemeris | Swiss Ephemeris 2.10.03 on the compressed JPL DE441 data files, covering 1800 to 2399; their names and digests are under "Run it yourself" |
| Python binding | pyswisseph==2.10.3.2, the package that carries that Swiss Ephemeris version |
| Python | 3.13, in the python:3.13-slim server image; the patch release is not recorded on this page |
| Calculation flags | Planets: FLG_SWIEPH, FLG_SPEED and FLG_SIDEREAL; ascendant: FLG_SWIEPH and FLG_SIDEREAL. Apparent, geocentric positions, with the library's own conversion from UT to ephemeris time |
| Zodiac | Sidereal, Lahiri (Chitrapaksha) ayanamsha: SIDM_LAHIRI, 23°15′00.658″ at 21 March 1956, 0:00 TDT, a true value that includes nutation |
| Houses | Whole sign |
| Lunar nodes | Mean node for Rahu, Ketu exactly 180 degrees from it |
| Timezone | The birth place's IANA zone, looked up from the coordinates with timezonefinder 9.0.0; if the chart has no usable coordinates, the timezone on your account, then Asia/Kolkata |
| Timezone data | Python's zoneinfo, which applies the IANA rules in force on the birth date, from the copy of the database the server supplies; its release is not recorded on this page |
| Coordinates | A place search against Photon, restricted to features carrying OpenStreetMap's place tag, with no filter on the type of place: the single point Photon returns for the place you choose; the date of Photon's data is not recorded on this page |
| Rounding | None: full double precision, rounded only where a number is shown |
Positions
Planetary positions come from the Swiss Ephemeris running the compressed data files derived from NASA JPL's DE441. The version and the years they cover are in the settings table.
Swiss Ephemeris can also run from an analytical ephemeris built into the library, originally by Steve Moshier, and it falls back to it silently when the data files are absent. We ran that way without knowing until 13 September 2026. The two agree closely, and here is how closely, measured rather than assumed:
| planet | worst disagreement |
|---|---|
| Moon | 2.73 arcseconds |
| Mars | 0.99 |
| Jupiter | 0.78 |
| Saturn | 0.64 |
| Venus | 0.50 |
| Mercury | 0.15 |
| Sun | 0.10 |
A pada, the smallest division this site works in, is 12,000 arcseconds wide, so the worst case is about one part in four thousand of a pada.
That does not prove no chart was affected, so we tested the thing itself: which division each ephemeris placed each body in, across 48,000 sampled positions.
| division | disagreements |
|---|---|
| sign | 0 of 48,000 |
| nakshatra | 0 of 48,000 |
| pada | 1 of 48,000 |
So it is not never: one sampled position in 48,000 sat close enough to a pada boundary for the two to disagree. One event is too few to give a rate with any confidence. What it does not tell you is whether it happened in a chart we served: a rate in a sample is not an event in a population, and we have not audited the charts we actually served. We will not quote a number for them we have not measured, in either direction.
Reproducing those two tables
Both runs use swe.set_sid_mode(swe.SIDM_LAHIRI) and compare
FLG_SWIEPH | FLG_SIDEREAL against FLG_MOSEPH | FLG_SIDEREAL, on the
pyswisseph version named in the settings table.
- The arcsecond table: start at Julian Day for 1 January 1900, 12:00 UT, step 36.7 days, 2,000 dates, seven bodies from Sun to Saturn.
- The division table: same start, step 12.2 days, 6,000 dates, eight bodies, the same seven plus the mean node. 6,000 times 8 is the 48,000.
Run those and you should get these numbers. If you do not, we would like to know.
Calculation flags
Planet longitudes come from swe.calc_ut with FLG_SWIEPH, FLG_SPEED and
FLG_SIDEREAL, and the ascendant from swe.houses_ex with FLG_SWIEPH and
FLG_SIDEREAL, with the sidereal mode set to SIDM_LAHIRI. FLG_SPEED only
adds the daily speed, which is used for the retrograde marker; the longitude is
the same number with or without it, which is why the script in "Run it
yourself" leaves it out.
None of the flags that change the default kind of position is set: not
FLG_TRUEPOS, FLG_NOABERR, FLG_NOGDEFL, FLG_TOPOCTR or FLG_HELCTR. The
Swiss Ephemeris programming documentation
says the default is an apparent position in geocentric ecliptic coordinates,
relative to the true equinox of the date (section 3.3.1). Apparent
means corrected for the light-time from the body to the Earth, and geocentric
means seen from the centre of the Earth rather than from the birth place
(section 3.3.5, "True or apparent positions"). FLG_SIDEREAL then refers the
longitude to the Lahiri zero point instead of the equinox of the date. For the
mean node, a mathematical point, the manual says there is no apparent position
and that its true position is returned (section 3.3.1); this is the mean node
still, not the true node.
calc_ut takes the Julian day in UT, and the library converts it to ephemeris
time itself (section 3.1). Our chart code calls no delta-T function and sets no delta-T
value of its own.
Sidereal frame
Calculations are sidereal, using the Lahiri (Chitrapaksha) ayanamsha,
SIDM_LAHIRI in Swiss Ephemeris terms: the modern realization, with its value
at 21 March 1956 in the settings table, not the
23°15′00″ the Calendar Reform Committee fixed for 21 March 1956, which Swiss
Ephemeris keeps separately as SIDM_LAHIRI_ICRC. The
Swiss Ephemeris documentation,
section 2.8.5 and Appendix E, attributes the settings-table value to
the Indian Astronomical Ephemeris from 1985 and says it is a true ayanamsha,
one that includes nutation. The library holds the mean value, 23°14′44″ at
21 March 1956, and adds nutation when it converts to sidereal longitudes; "Run it yourself"
prints both values.
In the Report of the Calendar Reform Committee
(Council of Scientific and Industrial Research, New Delhi, 1955; chairman M. N. Saha),
the recommendations for the religious calendar say the moments of the moon's
exit from a nakshatra, or the sun's entry into one, are to be calculated with
a variable ayanamsha that is 23°15′0″ on 21 March 1956 and then grows by about
50″ a year (item 7), while solar months start a fixed 23°15′ ahead of the vernal
equinoctial point (item 5). The civil calendar it
proposed is a unified solar calendar based on the tropical year. How many
practising astrologers use Lahiri we do not know and will not estimate. If you
compare our output against a source using another ayanamsha, expect it to
shift every longitude by the difference: on the check case's date, Swiss
Ephemeris's SIDM_KRISHNAMURTI is about 6 arcminutes less than Lahiri and
SIDM_RAMAN about 1 degree 27 arcminutes less. Against a tropical Western
chart, expect roughly 24 degrees at present.
Houses
Whole sign houses. The rising sign becomes the first house in its entirety, the next sign the second, and so on. A planet's house is its sign's distance from the rising sign, and nothing else enters the calculation.
This is our deliberate choice and not a settled historical fact, and this page does not claim that any text requires it. The classical text we consult, Brihat Parashara Hora Shastra, is read in the Ranjan edition, published by Ranjan Publications, New Delhi, translated by R. Santhanam (volume 1) and G.S. Kapoor (volume 2); the translator's preface to volume 1 is dated 1984. We cite no verse for the house rule because we are not saying the text settles it, and we have no survey of practice to cite, so we make no claim about practice. It is certainly not the only basis. Sripati and bhava chalit divide houses by cusp rather than by sign, and a chart cast that way puts some planets in different houses from ours. We do not use Placidus or Koch for interpretation either.
The ascendant degree itself is the same number under every house system, so this choice changes which house a planet falls in, not where the ascendant is.
Lunar nodes
Mean node for Rahu and Ketu, not the true node. Ketu is taken as exactly 180 degrees from Rahu. Both are reported retrograde, which for the mean node is a description rather than a convention: it moves backwards along the ecliptic at a steady rate. The true node is the one that occasionally turns direct, and it is not what we use.
The two differ by up to about 2 degrees: measured against our own engine across 1900 to 2100, the largest gap is 1.98 degrees, on 10 October 1905 (about 21:45 UT; among the daily 00:00 UT samples described under "Reproducing the node figures", the largest is the one on 11 October). On 92.8% of the 73,414 days from 1 January 1900 to 31 December 2100, sampled at 00:00 UT, the two nodes fall in the same nakshatra, and on 96.8% in the same sign. On the other days they do not, and anything read from the node's nakshatra changes with it. It does not change your Vimshottari dasha sequence: that is set by the Moon's nakshatra and nothing else. So if our Rahu disagrees with another chart's by a degree or so, this is why, and the other chart is not necessarily wrong.
Reproducing the node figures
One date a day at 00:00 UT, from 1 January 1900 to 31 December 2100 (73,414
dates), swe.MEAN_NODE against swe.TRUE_NODE with FLG_SWIEPH | FLG_SIDEREAL,
on the pyswisseph version named in the settings table. A node's nakshatra is its sidereal
longitude divided by 13°20′, rounded down. The chart of the gap is the 730 days
from 1 January 2026, every second day (365 values). The 21:45 UT peak on
10 October 1905 comes from the same nodes scanned at 15-minute steps from 9 to
13 October 1905.
Run that and you should get these numbers. If you do not, we would like to know.
Time and place
The timezone
Birth time is interpreted in the timezone of the place of birth, looked up
from the birth coordinates using timezonefinder,
which maps a coordinate to an IANA zone from its own boundary polygons.
The lookup has nothing to work with in one case: a chart saved without usable
coordinates, or an error in the lookup itself. Then we fall back to the
timezone on your account, and if there is none, to Asia/Kolkata. Both
fallbacks are guesses, and the first of them is the behaviour this page was
corrected for in the correction history. The fallback does not run for coordinates over water.
The lookup we call, timezone_at, returns a whole-hour nautical zone there
instead of nothing: with the timezonefinder version in the settings table, 0° N 30° W
returns Etc/GMT+2. A birth at sea is therefore read in the nautical zone for
its longitude, not in the account's timezone. A birth place found through our
search is a single point, and we have not tested the lookup for every point on
land, so we would rather write down the branches than claim more than we have
tested.
Within that zone we apply the historical offset recorded for that date in the IANA timezone database, including any daylight saving of the period.
The timezone database
That database is good but it is not a complete record of civil time. IANA's
own theory notes say it is not
designed for applications that need accurate handling of all past times
everywhere, and Indian history is a good example of why. Asia/Kolkata
follows railway time, and the comments in the database itself
note that some municipalities kept their former time and that the time in
Calcutta depended on whether you were at the railway station or at government
offices. Bombay Time, set 4 hours 51 minutes ahead of Greenwich, was
maintained until 1955, about nine
minutes short of five hours ahead. A clock time written on an Indian
certificate from the 1940s may not be the time Asia/Kolkata would
reconstruct.
So: we apply the recorded history where it exists, and if your birth is early enough for this to matter, tell us and we will set the offset by hand rather than let the database guess.
Coordinates
Coordinates come from a place search against Photon,
restricted to features that carry OpenStreetMap's place tag. That tag covers
cities, towns and villages and also larger areas such as states and districts,
and we do not filter on the type of place. What comes back is the single point
Photon gives for the place you choose, which for a state or district is one point
representing a large area and can be far from any town. It is not a street address.
The displacement table is measured at the New Delhi case in "Check us".
Kilometres become degrees of longitude by km / (111.32 * cos(latitude)), which at 28.6139 N is about
97.72 km per degree; the cosine matters: leaving it out gives about
7.7 arcminutes at 10 km rather than 8.72.
| displacement | ascendant moves |
|---|---|
| 1 km east or west | 0.87 arcminutes |
| 3 km | 2.62 arcminutes |
| 5 km | 4.36 arcminutes |
| 10 km | 8.72 arcminutes |
The last digit depends on which earth model you convert with, so treat these as good to about a hundredth of an arcminute. North to south barely matters: 10 km gives 0.53 arcminutes. Even 10 km east is under a sixth of a degree, so a point a few kilometres from your street will not move your rising sign unless your ascendant was already within a few arcminutes of a boundary. If it was, your birth time matters far more than your street did.
Rounding
None. Longitudes are carried as full double-precision degrees through every stage, and rounding happens only where a number is displayed. Nothing is snapped to a boundary.
Check us
One fixed case, computed by the same function that serves the API.
| Quantity | Expected result |
|---|---|
| Ayanamsha removed (nutation included) | 23.720706 degrees (23.717417 without nutation) |
| Ascendant | Pisces 13 degrees 55' 22" (343.922640 decimal degrees) |
| Sun | Sagittarius 16 degrees 51' 36", Purva Ashadha pada 2 (256.859923 decimal degrees) |
| Moon | Aquarius 6 degrees 27' 55", Dhanishtha pada 4 (306.465258 decimal degrees) |
| Rahu (mean) | Capricorn 24 degrees 43' 35", Dhanishtha pada 1 (294.726414 decimal degrees) |
Enter that case into any properly configured sidereal engine with Lahiri (nutation included) and the mean node and you should get the same signs, nakshatras and padas, with degrees agreeing to within a few arcseconds. If you get a materially different answer, one of us has a setting wrong, and this page tells you all of ours.
One honest limit on this vector: printed to whole arcseconds it does not by itself prove which ephemeris is loaded, because Moshier and DE441 differ by less than that here. It proves the ayanamsha, the node setting and the house rule. The ephemeris is proved by the flag the library returns, which is how we found we had it wrong.
Run it yourself
Install the pyswisseph version named in the
settings table, which this page does not repeat,
so there is one place to update it, and put the two data
files in a folder called ephe beside this file. These two files, for the
ephemeris named in that same settings-table row, have the following SHA-256
digests today; a version or data-file change on that row means these digests
are stale and must be regenerated, not assumed to still match:
sepl_18.se1 ca1393ceab3a44fbc895887cf789c68819ae6a1cbc9b22225872dbe4ccd99a66
semo_18.se1 1ca07bd67c24374d77226180c20a4f9996cba013697894810518e7eb582ca4f7
Then run this:
import swisseph as swe
# ephe/ holds the two .se1 files
swe.set_ephe_path("ephe")
swe.set_sid_mode(swe.SIDM_LAHIRI)
flags = swe.FLG_SWIEPH | swe.FLG_SIDEREAL
# 12:00 at +05:30 is 06:30 UT
jd = swe.julday(1990, 1, 1, 6.5)
print(swe.get_ayanamsa_ex_ut(jd, swe.FLG_SWIEPH)[1])
print(swe.get_ayanamsa_ut(jd))
for body in (swe.SUN, swe.MOON, swe.MEAN_NODE):
print(swe.calc_ut(jd, body, flags)[0][0])
print(swe.houses_ex(jd, 28.6139, 77.2090, b"W", swe.FLG_SIDEREAL)[1][0])
It prints, to six decimals, the ayanamsha the library removes (nutation
included, then the value swe.get_ayanamsa_ut gives without nutation), then
the sidereal longitudes of the Sun, the Moon and the mean node, then the
ascendant: the same six figures already given in decimal degrees, in
parentheses, in the Check us table, which is the one
place on this page these numbers are written. Pisces begins at 330 degrees,
which is why Pisces 13 degrees 55' 22" and its decimal-degree figure in that
table agree to the whole arcsecond.
Where else this engine is used
The Choghadiya calculator, also in Hindi, takes its sunrise and sunset from the same Swiss Ephemeris. It does not use the place search or the timezone lookup described in "Time and place": it works from a fixed list of cities, each with its coordinates and its IANA timezone written down, and shows the times in that city's timezone. Choghadiya asks only the weekday and the sunrise and sunset, so the tool uses none of the sidereal settings in the settings table: not the ayanamsha, the house system or the nodes. Sunrise there means the upper limb of the sun with standard refraction, which that page states as one of its own limits.
What this page does not cover
Chart casting, which is everything on this page so far, is not the whole engine. Dasha derivation has its own conventions and is worked through step by step on the nakshatras page instead, including how the birth Moon's position sets the first period and how much of it remains. If you want to reproduce a dasha rather than a chart, start there.
Three things this page does not record: the release of the timezone database the server used, the date of the Photon data behind a place search, and the patch release of Python.
What we do not do
We do not adjust, round or "correct" a stated birth time to produce a tidier chart. If a birth time is uncertain, the honest response is to say which conclusions depend on it, and we say so rather than quietly picking one.
Correction history
Rows that begin with a date were found and fixed on that day. The others were found and fixed on 13 or 14 September 2026, and some of them were later reworded or given a source; the row says what it now claims.
| what we said | what was true | who it affected |
|---|---|---|
| Positions come from the JPL data files | The files were not installed and the library had silently fallen back to Moshier | Unknown for the charts we served, because we have not audited them. In 48,000 sampled positions the two ephemerides put one in a different pada |
| The data derive from DE431 | The installed files say DE441 in their own header, and Astrodienst's own page says the Swiss Ephemeris moved to DE441 in May 2026 | Nobody: a wrong label on the right files |
| The true node is used for Rahu and Ketu | The mean node is used, everywhere | Anyone comparing our Rahu against a true-node chart and assuming we agreed |
| No chart we produced was ever affected by the ephemeris | A sampled benchmark cannot support a claim about every chart, and testing it found one pada disagreement in 48,000 | Stated honestly now: we have not audited the charts we served |
| Birth time is read in the account's timezone | It was, and it should have been the birth place's. A London birth was read five and a half hours out, or four and a half during British Summer Time | Anyone for whom the two zones disagreed at their own birth moment. Not everyone born abroad, and not decidable from a country: Sri Lanka matches India today, but the tz database has it at UTC+06:30 from 25 May 1996, UTC+06:00 from 26 October 1996 and back to UTC+05:30 from 15 April 2006, the same three exact days the timeline diagram and this table's own 27 September row give, not the month-level version once written here, so a Colombo birth in that decade moved and one either side of it did not. If a reading from before 13 September 2026 could be affected, ask us and we will run it again |
| A few kilometres moves the ascendant well under a minute of arc | About fivefold wrong: 3 km east moves it 2.62 arcminutes | Nobody: the effect is still small, the number was not |
| Birth time is read in the timezone of the birth place | It is, and when the chart has no usable coordinates it falls back to the account timezone and then to Asia/Kolkata. The rule was stated without its fallback | Unknown: the fallback runs only for a chart without usable coordinates, and we have not counted how often that has happened. The undisclosed branch is the defect |
| SIDM_LAHIRI is the ayanamsha the Calendar Reform Committee adopted for the national calendar | The Committee's civil calendar is a solar calendar based on the tropical year, and the 23°15′00″ reference it fixed for 21 March 1956 is for the religious calendar's nakshatra and solar-month calculations, in its 1955 Report, items 5 and 7 of the religious-calendar recommendations. Swiss Ephemeris's SIDM_LAHIRI (23°15′00.658″) is a later, distinct realization of that reference | A reader checking why our Lahiri differs from another engine's SIDM_LAHIRI_ICRC output, or assuming India's civil calendar is itself sidereal |
| 27 September: the check case's ayanamsha is 23.717417 degrees | That is the value without nutation. The library removes 23.720706 degrees at that date, which is the difference between the tropical and sidereal Sun in the same run; the table and the script now show the value it removes | A reader who subtracted 23.717417 from a tropical longitude and compared the result with the table: they were about 12 arcseconds apart |
| 27 September: our place search returns "populated-place centroids" | It is restricted to OpenStreetMap's place tag and nothing else, and that tag also covers larger areas such as states, so the point returned can be one point standing for a whole area. The page now says this | Anyone who chose a state or district as a birth place instead of a town; we have not counted how many did |
| 27 September: the summary at the top said birth times are read in the timezone of the birth place | It left out the fallback to the account's timezone and then to Asia/Kolkata, already corrected in the body; the summary, the figure and its text now state it | The same readers as the earlier timezone row: anyone for whom the fallback ran |
27 September: when no zone can be found for the coordinates, the account's timezone and then Asia/Kolkata are used | That is only for a chart without usable coordinates, or when the lookup itself errors. Coordinates over water, whether open ocean or the English Channel, get an Etc/GMT zone such as Etc/GMT+2 from the lookup, not the fallback | Anyone born at sea, or whose saved coordinates were over water; we have not counted them |
| 27 September: six conversions lie between your birth certificate and your chart, each documented in its own section | There are six stages, which is five conversions, and two of them, the step to UTC and the nakshatra and pada step, have no section of their own. The caption now says six stages and that the sections record the settings | Nobody: a miscount in a caption |
| 27 September: about once in fifty thousand a sampled position sits close enough to a pada boundary for the ephemerides to disagree | It was one disagreement in 48,000 sampled positions, and one event is too few to give a rate. The page now states the count | Nobody: the same paragraph already said the sample says nothing about the charts we served |
| 27 September: Sri Lanka ran UTC+06:30 and then UTC+06:00 from May 1996 until April 2006 | The tz database has +06:30 from 25 May 1996, +06:00 from 26 October 1996 and +05:30 from 15 April 2006. The sentence put +06:00 in May 1996 | A reader working out whether a Colombo birth in the summer of 1996 was affected by a timezone error |