Why every BaZi calculator disagrees with the almanac

javascript dev.to

Every Four Pillars calculator — saju in Korea, BaZi in China — agrees on the easy 95% of the job. Feed it a birth date and it maps that instant onto a traditional calendar: four pillars, each a heavenly stem paired with an earthly branch.

The remaining 5% is boundaries. And at the boundaries, nearly all of them quietly disagree with the printed almanac they claim to reproduce.

I maintain a saju reading service, and getting these four cases right was most of the actual engineering. Here they are, with the failing inputs.

1. A solar term is an instant, not a date

The year pillar does not turn on January 1, and not on lunar new year either. It turns at 입춘 (ipchun, "start of spring") — one of the 24 solar terms, defined by the sun's apparent longitude. In 2024 that moment was February 4, 16:27 KST.

A calculator that applies solar terms at day granularity says "February 4 → new year pillar" and hands the wrong year to everyone born that morning.

npx k-saju 2024-02-04 04:00
# year 癸卯 — still the old year pillar, because 04:00 < 16:27
Enter fullscreen mode Exit fullscreen mode

The fix is unglamorous: store term boundaries as instants and compare instants. The subtlety is that this correction applies to the year and month pillars only — the day pillar runs on its own sexagenary count and must not be touched.

2. The 23:00 hour belongs to two days at once

Traditional practice starts the day at 23:00, not midnight — the hour of the Rat (자시). So for a birth at 23:31, there are two defensible answers about which day's stem the hour pillar derives from, and schools split on it.

The convention this engine declares: the day pillar keeps clock midnight, while the hour stem takes the next day's stem (the 야자시 rule).

npx k-saju 2000-05-15 23:31
# day 癸酉, hour 甲子
Enter fullscreen mode Exit fullscreen mode

I am not claiming this is the One True Rule. I am claiming it should be written down. Most tools pick a side in silence, which is how two calculators give one person two charts and neither can explain why.

3. The clock is not the sun

Korea keeps time on the 135°E meridian. Seoul sits near 127°E. That is about 32 minutes of difference between civil noon and solar noon — before you add the equation of time, which swings solar noon by up to ~16 minutes across the year.

Hour pillars are two-hour buckets. A half-hour error puts a birth in the wrong bucket often enough to matter.

npx k-saju 2000-05-05 09:30 --lon 124.7   # hour 丙辰
npx k-saju 2000-05-05 09:30               # hour 丁巳  (Seoul default)
Enter fullscreen mode Exit fullscreen mode

Same wall clock, different hour pillar, purely from longitude.

4. Foreign births need absolute time

This one bites hardest. A solar term is an astronomical instant, global. If someone is born in New York on February 3 at 16:00, that is already February 4 in Korea — and possibly already past the term.

npx k-saju 2024-02-03 16:00 --place new-york
# year 甲辰 — the new year pillar, on a local date of "Feb 3"
Enter fullscreen mode Exit fullscreen mode

Compare local dates against KST term dates and you get this backwards. Convert both to absolute time and compare instants, and it falls out correctly.

Testing claims instead of asserting them

All four examples above are golden tests. The README table's example commands are the test inputs, so a claim that drifts from the code fails CI rather than sitting there being wrong.

That matters more than usual in this domain, because "accuracy" claims here normally hide two things: which school's conventions were chosen, and where the dataset runs out. Mine, stated openly: minute-exact term instants cover 2020–2030 (dataset range) and degrade to day granularity outside it; luck-pillar start ages use day-granular boundaries and can differ from a paper almanac by ±1 year.

What is deliberately missing

Interpretation. The library turns a birth instant into symbolic coordinates and stops.

I think that split is the honest one. The calendar math is verifiable — you can check it against an almanac and I can hand you a test suite. What those eight characters mean is not verifiable, and blending the two is how this whole genre earned its reputation. (My commercial product does write readings, with an LLM that is structurally forbidden from touching a number.)

The engine is MIT: https://github.com/bunhine0452/k-saju

npx k-saju 1995-03-16 07:30
Enter fullscreen mode Exit fullscreen mode

If you have ever tried to reconcile two calculators at 2 a.m., issue #1 — extending minute-exact solar terms to 1900–2050 astronomically — is open and genuinely fun.

Source: dev.to

arrow_back Back to Tutorials