Ask a Korean friend their birth year and you will often get their tti (띠), the zodiac animal, instead. When we built the birth-chart engine for our Korean saju app, the animal turned out to be the first thing that broke: plenty of people born in January or early February got the wrong one.
The reason is that the zodiac year does not start on January 1. In saju it starts at Ipchun (입춘, 立春), the "start of spring" solar term. Here is how we compute it, and where the method stops being exact.
Why "Feb 4" is not enough
Most tables say Ipchun is "around February 4". That is true, but it is a moment, not a date. It is the instant the Sun reaches ecliptic longitude 315°, and it drifts by about six hours a year until a leap year pulls it back.
From the table above: in 2021, 2025 and 2029 it lands late on February 3 in Korea time. In 2020 and 2024 it lands in the evening of February 4. So a baby born on the afternoon of Feb 4, 2024 still belongs to the previous year's animal (Rabbit), while one born a few hours later is a Dragon.
Two more traps:
- Seollal is a different rule. In everyday life many Koreans switch the animal at the Lunar New Year (late January to mid-February). Saju uses Ipchun. The two rules disagree for birthdays that fall between them.
- Time zone history matters. Korea used UTC+8:30 from 1954-03-21 to 1961-08-09, and had daylight saving time in the summers of 1987 and 1988. If you convert a birth time with a flat UTC+9, edge cases move.
The calculation
We do not ship an almanac table. We compute the solar terms with the low-precision solar position from Jean Meeus, Astronomical Algorithms (chapter 25), then solve for the moment the longitude hits the target with a few Newton-style steps.
/// Apparent ecliptic longitude of the Sun (degrees, 0-360)
double sunLongitude(double jd) {
final t = (jd - 2451545.0) / 36525;
final l0 = 280.46646 + 36000.76983 * t + 0.0003032 * t * t;
final m = _rad(357.52911 + 35999.05029 * t - 0.0001537 * t * t);
final c = (1.914602 - 0.004817 * t - 0.000014 * t * t) * math.sin(m)
+ (0.019993 - 0.000101 * t) * math.sin(2 * m)
+ 0.000289 * math.sin(3 * m);
final omega = _rad(125.04 - 1934.136 * t);
return _norm(l0 + c - 0.00569 - 0.00478 * math.sin(omega));
}
/// Moment (UTC) when the Sun reaches [deg], searched near [approx]
DateTime termMoment(double deg, DateTime approx) {
var jd = _jd(approx);
for (var i = 0; i < 8; i++) {
var diff = deg - sunLongitude(jd);
diff = ((diff + 540) % 360) - 180; // wrap to -180..180
jd += diff / 360 * 365.2422; // ~1 degree per day
if (diff.abs() < 1e-6) break;
}
return _fromJd(jd);
}
DateTime ipchun(int year) => termMoment(315, DateTime.utc(year, 2, 4, 3));
/// Saju year: before the Ipchun instant, it is still last year.
int sajuYearAt(DateTime utc) =>
utc.isBefore(ipchun(utc.year)) ? utc.year - 1 : utc.year;
After that, the animal is just an index: (sajuYear - 4) % 12 gives 0 for Rat (1984 was a Rat year). The same function with longitudes 285°, 345°, 15° and so on gives the 12 month boundaries, which saju needs for the month pillar.
Where it stops being exact
Be honest about the error bar. This formula is good to roughly 0.01° of solar longitude, which is about 15 minutes of time. Checked against published almanac times, our results land a few minutes off: for 2024 we get 17:21 KST, the commonly published Ipchun time is 17:27. We ignore ΔT (about a minute these days), which is smaller than that error.
For an entertainment app that is fine for almost everyone. It is not fine for someone born within ~15 minutes of the boundary, so for those births the honest answer is "check a full ephemeris". If you need that precision, use the full VSOP87 theory or a JPL ephemeris instead of the short series.
Try it
If you want to see the result on your own birthday, our app Starlit Alley: Saju & Tarot does the full four-pillar chart with this engine (Android, free to try): Google Play.
For the plain birth-year table from 1948 to 2031 and the Seollal vs Ipchun rule in non-code form, see our guide Korean Zodiac Animals by Birth Year.
Saju and zodiac readings are cultural entertainment, not predictions.

Top comments (0)