:::note
**TL;DR**
- Two BaZi calculators disagree because the Four Pillars have three unsettled conventions, not because one of them is broken.
- A birth at 23:30 on 1990-06-15 in Shanghai returns 辛亥 day and 庚子 hour, 辛亥 day and 戊子 hour, or 壬子 day and 庚子 hour, depending on the day boundary school alone.
- Two of those readings hand you a different Day Master, which is the value every other judgement in the chart is measured against.
- RoxyAPI types all three switches as request parameters and echoes the applied set back in a `conventions` object, so a chart is reproducible instead of a black box.
:::

Somebody sends you a BaZi chart their teacher drew, you run the same birth data through your own code, and the day pillar comes back different. Nothing is broken. The Four Pillars of Destiny are a calendar system with three genuinely open conventions inside it, and a calculator that does not tell you which one it applied is asking you to guess. This post walks the one that moves the most, the day boundary, using a birth moment where all three schools separate cleanly, then shows how far a single convention travels into the finished reading, and finishes on how to pin every convention so a chart can be reproduced by anyone holding the same birth data.

## Why do two BaZi calculators disagree about the same birth data?

Because casting the pillars is not one algorithm, it is one algorithm plus three unsettled choices, and different lineages resolve them differently. The three are: which instant starts the sexagenary day, which instant starts the sexagenary year, and which clock the hour branch is read from. Each is a real practice question with real schools behind it. None of them is a rounding error, and none of them has a settled answer.

:::stat 1 hour
Births between 23:00 and 23:59 are the only ones where the three day boundary schools return different pillars. A 14:30 birth and a 00:30 birth on the same dates return identical pillars under all three. Method notes: [RoxyAPI methodology](/methodology "how RoxyAPI verifies calculations against authoritative references").
:::

The day boundary is the sharpest of the three because its blast radius is disproportionate to its window. It touches one hour in twenty four, and inside that hour it can move the day pillar, and the day pillar stem is the Day Master, which is the reference point the whole reading is built on. A calculator that resolves that choice for you without saying so is the reason the two charts on your desk do not match.

Ready to build this? [Chinese Astrology API](/products/chinese-astrology-api "production-ready BaZi and Four Pillars API with typed school conventions") gives you the Four Pillars with every convention typed, defaulted and echoed back on the response. [See pricing](/pricing "RoxyAPI pricing tiers").

## What does the day boundary switch actually move?

It moves the day pillar, the hour pillar, or both, for a birth in the late zi hour. Take 15 June 1990 at 23:30 in Shanghai. The year pillar is 庚午 and the month pillar is 壬午 under every school, because those turn on solar term instants and no boundary convention touches them. The bottom half of the chart is where the three answers appear:

| `dayBoundary` | Day pillar | Hour pillar | What the school says |
|---|---|---|---|
| `split-zi` (the default here) | 辛亥 xin-hai | 庚子 geng-zi | The day turns at 00:00, but the hour stem is taken from the day that is about to begin |
| `midnight` | 辛亥 xin-hai | 戊子 wu-zi | The day turns at 00:00 and 23:00 to 23:59 is the late zi hour of the day that is ending, so the hour stem comes from that day |
| `early-zi` | 壬子 ren-zi | 庚子 geng-zi | The whole day turns at 23:00, so the birth already belongs to the sixteenth |

The hour stem is not chosen independently. It is derived from the governing day stem by the Five Rats rule, under which the ten day stems fold into five starting points: the pairs 甲/己, 乙/庚, 丙/辛, 丁/壬 and 戊/癸 each begin their zi hour on the same stem. A 辛 day starts on 戊子, a 壬 day starts on 庚子. That is why `midnight` returns 戊子 while both other schools return 庚子, and it is arithmetic you can check by hand.

## How far does one convention travel into the reading?

All the way to the verdict. Because the day pillar stem is the Day Master, `split-zi` and `early-zi` do not just print two different characters, they hand a practitioner two different subjects. Everything downstream is measured against that subject, so the element balance, the strength verdict and the branch interactions all move with it.

Same birth moment, one parameter changed, taken from live responses:

| Reading | `split-zi` | `midnight` | `early-zi` |
|---|---|---|---|
| Day Master | 辛 Metal, yin | 辛 Metal, yin | 壬 Water, yang |
| Strength verdict | `balanced`, score -0.6 | `balanced`, score -0.6 | `very-strong`, score 4.1 |
| `favorableElements` | empty | empty | Wood, Fire, Earth |
| Wood / Fire / Earth / Metal / Water | 0 / 2 / 0 / 3 / 3 | 0 / 2 / 1 / 2 / 3 | 0 / 2 / 0 / 2 / 4 |
| Branch interactions found | 3 | 3 | 5 |

Read the Metal row across. Metal is `excess` at three under the first school, `balanced` at two under the other two, and the elements a reading would recommend flip from an empty list to Wood, Fire and Earth. Two extra clashes appear under `early-zi` because the day branch becomes 子, which clashes the 午 sitting in both the year and the month. One switch, a different chart, a different prescription.

:::warning
This is the reason a support ticket that says "your chart is wrong" is usually a convention mismatch rather than a defect. Before debugging arithmetic, compare the conventions the two systems applied. If the other system does not publish them, that comparison is not available and the disagreement cannot be resolved.
:::

## Which clock does the hour branch read from?

Civil time by default, and that is a convention too. The hour branch covers two clock hours, so it depends on which clock you read. `clock` takes the time exactly as a birth certificate records it. `local-mean` shifts to the mean sun over the birth longitude, worth up to 59 minutes at the edge of a wide time zone. `solar` adds the equation of time on top, worth up to a further 16 minutes.

The gap is largest where a birth place sits a long way west of the meridian its civil time zone is centred on. Send longitude 87.6 east on a UTC plus 8 clock and the same 23:30 birth moves two branches:

| `hourClock` | Hour pillar | Branch |
|---|---|---|
| `clock` | 庚子 geng-zi | 子, the rat hour |
| `local-mean` | 戊戌 wu-xu | 戌, the dog hour |
| `solar` | 戊戌 wu-xu | 戌, the dog hour |

Note what that does to the previous section: once the hour branch is no longer 子, the birth is no longer in the late zi hour at all, so the day boundary question stops applying. The three switches are not independent, which is the argument for stating all three rather than the one you happen to care about.

:::warning
`local-mean` and `solar` both need `longitude` in the request and return a 400 without it. The error names the field and the fix rather than failing silently, which matters because a silent fallback to civil time is indistinguishable from a correct answer.
:::

## How to reproduce a BaZi chart you did not cast

Send the conventions, then read them back off the response. Every birth-data call starts with a place lookup, because the timezone that resolves the birth moment has to be the historically correct one for that date rather than the offset in force today.

```bash
curl -s "https://roxyapi.com/api/v2/location/search?q=Shanghai&limit=1" \
  -H "X-API-Key: YOUR_KEY"
# {"total":97,"limit":1,"offset":0,"cities":[{"city":"Shanghai","province":"Shanghai",
#  "country":"China","iso2":"CN","latitude":31.2222,"longitude":121.4581,
#  "timezone":"Asia/Shanghai","utcOffset":8,"population":24874500}]}
```

Feed `timezone` straight into [`POST /chinese-astrology/bazi/chart`](/api-reference#tag/chinese-astrology/POST/chinese-astrology/bazi/chart "BaZi Four Pillars chart endpoint with typed day boundary, year boundary and hour clock parameters") and name the conventions you want:

:::tabs
### curl
```bash
curl -s -X POST https://roxyapi.com/api/v2/chinese-astrology/bazi/chart \
  -H "X-API-Key: YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "date": "1990-06-15",
    "time": "23:30:00",
    "timezone": "Asia/Shanghai",
    "dayBoundary": "midnight"
  }'
```

### TypeScript
```typescript
import { createRoxy } from '@roxyapi/sdk';

const roxy = createRoxy(process.env.ROXY_API_KEY!);

const { data } = await roxy.chineseAstrology.generateBaziChart({
  body: {
    date: '1990-06-15',
    time: '23:30:00',
    timezone: 'Asia/Shanghai',
    dayBoundary: 'midnight',
  },
});

console.log(data.conventions.dayBoundary); // "midnight"
```

### Python
```python
from roxy_sdk import create_roxy

roxy = create_roxy("your-api-key")

chart = roxy.chinese_astrology.generate_bazi_chart(
    date="1990-06-15",
    time="23:30:00",
    timezone="Asia/Shanghai",
    day_boundary="midnight",
)

print(chart["conventions"]["dayBoundary"])  # "midnight"
```
:::

Every response carries the set that was actually applied, including the defaults you did not send:

```json
{
  "conventions": {
    "dayBoundary": "midnight",
    "yearBoundary": "li-chun",
    "hourClock": "clock"
  }
}
```

The third field is the year boundary, the switch that decides whether a late-January or early-February birth belongs to the outgoing animal or the incoming one. It is typed and echoed exactly like the other two, and it deserves its own walkthrough rather than a footnote here.

### The identifier fields stay English in every language

`conventions.dayBoundary` returns `split-zi` under `?lang=zh-Hans` exactly as it does under `?lang=en`, and so does every identifier in the payload. Machine values are canonical English; the reader-facing copy arrives as a sibling field beside it. On the day pillar of the chart above:

| Field | `?lang=en` | `?lang=es` | `?lang=zh-Hans` |
|---|---|---|---|
| `branch.id` | `hai` | `hai` | `hai` |
| `branch.animal` | `pig` | `pig` | `pig` |
| `branch.animalLocalized` | absent | `Cerdo` | `猪` |
| `branch.elementLocalized` | absent | `Agua` | `水` |

Switch your code on `animal`, render `animalLocalized`. The sibling is absent in English on purpose, so an English caller gets the same payload it always did, and `animalLocalized ?? animal` is the whole rendering rule. Chinese astrology and feng shui are the two domains carrying Simplified and Traditional Chinese today, which is worth saying plainly rather than implying the whole catalogue is translated into both scripts. The same reproducibility problem in a different tradition is worked through in [why two kundlis disagree](/blogs/why-two-kundlis-disagree-vedic-api-debugging "debugging identical birth data that produces different Vedic charts across APIs").

## FAQ

**Why do BaZi calculators give different results for the same birth time?**

Because the Four Pillars carry three unsettled conventions: the day boundary, the year boundary and the hour clock. Two calculators applying different conventions produce different pillars from identical input, and neither is doing the arithmetic wrong. RoxyAPI types all three as request parameters and returns the applied set in a `conventions` object on every BaZi response.

**Which BaZi day boundary is correct, 23:00 or midnight?**

Both are practised, and the choice belongs to the lineage a reading sits in rather than to the software. Turning the whole day at 23:00 is standard across Hong Kong, Taiwan and much of South East Asia, while turning it at 00:00 is the position recorded in the Ming compendium San Ming Tong Hui (三命通會). RoxyAPI defaults to the split reading that most software implements and lets you send `dayBoundary` explicitly to get either of the others.

**Does the day boundary change my Day Master?**

It can, for a birth between 23:00 and 23:59. In the worked example above, one convention returns a 辛 Metal Day Master and another returns a 壬 Water Day Master from the same birth moment, which changes the strength verdict and the favourable elements that follow from it. Outside that hour all three conventions return the same day pillar.

**Is there a BaZi API that returns the Four Pillars as JSON?**

Yes. `POST /chinese-astrology/bazi/chart` returns the four pillars with every Heavenly Stem and Earthly Branch, the hidden stems, the Ten God relations, the Na Yin element, the five-element balance and the branch interactions in one call, with the applied conventions echoed back. It is part of 209+ endpoints across 14+ insight domains on one RoxyAPI key.

**How do I make a BaZi chart reproducible across two systems?**

Record the conventions alongside the birth data, and pass them explicitly on every call rather than relying on a default. A chart that stores `date`, `time`, `timezone`, `dayBoundary`, `yearBoundary` and `hourClock` can be recast identically by anyone holding those six values. A chart that stores only the birth moment cannot, because the missing three are exactly the fields the two systems disagree on.

## Conclusion

A BaZi chart is only reproducible if the conventions travel with it. The three switches are real practice questions with real lineages behind them, so the honest engineering answer is not to pick a winner but to make the choice explicit, defaulted and visible on the response. Build it on the [Chinese Astrology API](/products/chinese-astrology-api "BaZi Four Pillars API with typed day boundary, year boundary and hour clock conventions") and every chart you ship can be recast, argued with, and reconciled against the one a practitioner drew by hand.