Convert between the Korean lunar calendar (음력) and the Gregorian solar calendar (양력) — entirely offline, following the KARI (Korea Astronomy and Space Science Institute) standard.
▶ Try the live demo — convert dates in your browser.
The Korean and Chinese lunar calendars share the same astronomical basis but can fall on different dates. This library uses the Korean (KARI) standard.
- Two-way conversion — solar → lunar and lunar → solar, in one small class.
- Offline — the conversion table is bundled; no network calls, no external services.
- GapJa (간지) strings — get the sexagenary year/month/day in both Korean (정유년 병오월) and Chinese (丁酉年 丙午月), plus raw cheongan/ganji indices.
- Leap-month aware — handles intercalation months (윤달) and the 1582 Gregorian reform gap.
- Input validation — every setter returns a
boolean; out-of-range, non-integer, and impossible-leap-month dates are rejected. - Typed & dual-format — ships TypeScript types, ESM + CommonJS, plus a minified browser build.
- Zero runtime dependencies.
| Calendar | From | To |
|---|---|---|
| Lunar (음력) | 1000-01-01 |
2050-11-18 |
| Solar (양력) | 1000-02-13 |
2050-12-31 |
Dates outside this range cause the corresponding setter to return false.
npm install korean-lunar-calendar// ES Modules
import KoreanLunarCalendar from "korean-lunar-calendar";
// CommonJS
const KoreanLunarCalendar = require("korean-lunar-calendar");<!-- Browser (CDN) -->
<script src="https://cdn.jsdelivr.net/npm/korean-lunar-calendar/dist/korean-lunar-calendar.min.js"></script>const calendar = new KoreanLunarCalendar();
// setSolarDate(year, month, day) → boolean (false if invalid/out of range)
calendar.setSolarDate(2017, 6, 24);
calendar.getLunarCalendar();
// { year: 2017, month: 5, day: 1, intercalation: true }
calendar.getKoreanGapja();
// { year: "정유년", month: "병오월", day: "임오일", intercalation: "윤월" }
calendar.getChineseGapja();
// { year: "丁酉年", month: "丙午月", day: "壬午日", intercalation: "閏月" }const calendar = new KoreanLunarCalendar();
// setLunarDate(year, month, day, intercalation) → boolean
calendar.setLunarDate(1956, 1, 21, false);
calendar.getSolarCalendar();
// { year: 1956, month: 3, day: 3 }
calendar.getKoreanGapja();
// { year: "병신년", month: "경인월", day: "기사일", intercalation: "" }Always check the return value of
setSolarDate/setLunarDatebefore reading the result — the getters reflect the last successful set call.
new KoreanLunarCalendar() creates a stateful converter. Set a date, then read it back in the
other calendar.
| Method | Returns | Description |
|---|---|---|
setSolarDate(year, month, day) |
boolean |
Set a Gregorian date. Returns false for out-of-range, non-integer, or nonexistent dates. |
setLunarDate(year, month, day, intercalation) |
boolean |
Set a lunar date. intercalation requests the leap month; returns false if that month has no leap month. |
getSolarCalendar() |
CalendarData |
The solar date for the last successful set. |
getLunarCalendar() |
CalendarData |
The lunar date (includes intercalation). |
getKoreanGapja() |
GapJaData |
Sexagenary cycle in Korean (e.g. 정유년). |
getChineseGapja() |
GapJaData |
Sexagenary cycle in Chinese characters (e.g. 丁酉年). |
getGapja(isChinese?) |
GapJaData |
GapJa in Korean by default, Chinese when isChinese is true. |
getGapJaIndex() |
{ cheongan, ganji } |
Raw 0-based cheongan (천간) and ganji (지지) indices for year/month/day. |
interface CalendarData {
year: number;
month: number;
day: number;
intercalation?: boolean; // present on lunar results
}
interface GapJaData {
year: string;
month: string;
day: string;
intercalation?: string; // "윤월" / "閏月" when the lunar month is a leap month, else ""
}
getSolarCalendar()andgetLunarCalendar()return a copy — mutating the returned object does not affect the converter's internal state.
Every setter validates its input and returns a boolean, so you can branch on the result:
const calendar = new KoreanLunarCalendar();
// Rejected → return false
calendar.setLunarDate(99, 1, 1, false); // before supported range
calendar.setSolarDate(2051, 1, 1); // after supported range
calendar.setSolarDate(2017, 6, 24.5); // non-integer day
calendar.setSolarDate(1582, 10, 8); // skipped by the 1582 Gregorian reform
calendar.setLunarDate(2017, 3, 1, true); // month 3 of 2017 has no leap month
// Accepted → return true
calendar.setLunarDate(1000, 1, 1, false);
calendar.setSolarDate(2050, 12, 31);The same library is available for other ecosystems:
- Java — usingsky/KoreanLunarCalendar
- Python — usingsky/korean_lunar_calendar_py
- JavaScript — usingsky/korean_lunar_calendar_js
Conversion data follows the KARI (Korea Astronomy and Space Science Institute) Korean lunar–solar standard. Many thanks to KARI for publishing the reference tables.
MIT © Jinil Lee