版本:1.0.0 | 最後更新:2025-06 Copyright (c) 2025 北京鋒通科技有限公司 (郭玉峰, 吳瓊). MIT License.
chinese-lunar-date 是一個基於天文算法的高精度農曆曆法庫,提供以下核心能力:
| 能力 | 說明 |
|---|---|
| 公曆 ↔ 農曆轉換 | 基於 VSOP87 行星理論的天文級精度 |
| 天干地支 | 年柱、月柱、日柱,六十甲子序號與字串互轉 |
| 生肖 | 12 生肖多語言名稱 + Emoji |
| 24 節氣 | 精確到天的節氣計算,6 種語言 |
| 傳統節日 | 13 個內建節日,按地區自動篩選 |
| 格式化 | 5 種內建格式 + 自訂模式字串(17 種 Token) |
| 多曆法 | 中國 / 日本 / 韓國 / 越南四種農曆變體 |
| 多語言 | 簡體中文 / 繁體中文(臺灣/香港)/ 日本語 / 한국어 / Tiếng Việt |
輸出格式: ESM / CJS / IIFE,IIFE 壓縮後僅 ~47 KB(gzip ~16 KB)。
npm install chinese-lunar-date
import { ChineseDate, formatGanZhi, PATTERNS } from 'chinese-lunar-date'
const { ChineseDate, formatGanZhi, PATTERNS } = require('chinese-lunar-date')
<script src="dist/chinese-lunar-date.iife.js"></script>
<script>
const date = ChineseDate.ChineseDate.fromGregorian(2024, 6, 21)
console.log(date.formatFull('zh-TW')) // "甲辰龍年 五月初六"
const lunar = ChineseDate.gregorianToLunar(ChineseDate.CHINESE_CONFIG, 2024, 6, 21)
console.log(lunar) // { cycle: 78, year: 34, month: 5, leap: false, day: 6 }
</script>
本函式庫使用原生 TypeScript 編寫,自帶完整型別定義,無需額外安裝 @types 套件。
import type { LunarDateValue, GanZhiPair, LocaleCode } from 'chinese-lunar-date'
中國農曆使用連續的六十甲子週期(六十甲子)來標記年份:
cycle — 週期序號(1 起始),表示當前是第幾個 60 年週期year — 週期內年序(1-60),直接對應干支year=1 → 甲子年,year=34 → 丁酉年,year=60 → 癸亥年公曆年份換算公式:
gregorianYear = epochYear + (cycle - 1) * 60 + (year - 1)
// 例:中國曆法 epoch = -2636,cycle=78, year=34 → 2024
提示:大多數場景下,直接使用
date.gregorianYear屬性即可取得公曆年份,無需手動計算。
所有日期實例(ChineseDate、JapaneseDate 等)都是不可變的。任何修改操作都會回傳新實例,原實例保持不變:
const date = ChineseDate.fromGregorian(2024, 6, 21)
const tomorrow = date.addDays(1) // 回傳新實例
date === tomorrow // false
date.day // 6(原實例未變)
tomorrow.day // 7
四種曆法變體使用不同的時區歷史和紀元:
| 曆法 | 時區 | 紀元 | 配置常量 |
|---|---|---|---|
| 中國 | UTC+8 | 公元前 2636 年 | CHINESE_CONFIG |
| 日本 | UTC+9 | 公元前 2636 年 | JAPANESE_CONFIG |
| 韓國 | UTC+8:30 / UTC+9 | 公元前 2333 年(檀君) | KOREAN_CONFIG |
| 越南 | UTC+7 / UTC+8 | 公元前 2636 年 | VIETNAMESE_CONFIG |
| 代碼 | 語言 | 說明 |
|---|---|---|
zh-CN |
簡體中文 | 中國大陸 |
zh-TW |
繁體中文 | 臺灣 |
zh-HK |
繁體中文 | 香港 |
ja-JP |
日本語 | 日本 |
ko-KR |
한국어 | 韓國 |
vi-VN |
Tiếng Việt | 越南 |
const date = ChineseDate.fromGregorian(2024, 6, 21)
// { cycle: 78, year: 34, month: 5, leap: false, day: 6 }
// 即:甲辰年 五月初六
const jsDate = new Date(2024, 5, 21) // 注意:JS Date 月份從 0 開始
const date = ChineseDate.fromDate(jsDate)
注意:
fromDate使用本地時區提取日期分量。
const date = ChineseDate.fromValue({ cycle: 78, year: 34, month: 5, leap: false, day: 6 })
const d1 = ChineseDate.fromISO('2024-06-21')
const d2 = ChineseDate.fromISO('2024/06/21')
const d3 = ChineseDate.fromISO('2024年6月21日')
const d4 = ChineseDate.fromISO('invalid') // null
const d5 = ChineseDate.parse('2024-06-21')
const date = ChineseDate.fromTimestamp(Date.now())
const date = ChineseDate.fromJDE(2460482.5)
const today = ChineseDate.today()
const date = ChineseDate.fromGregorian(2024, 6, 21)
date.cycle // 78 — 六十甲子週期序號
date.year // 34 — 週期內年序(34 → 甲辰)
date.month // 5 — 五月
date.leap // false — 非閏月
date.day // 6 — 初六
date.calendarType // 'chinese'
date.gregorianYear // 2024
date.yearGanZhi // "甲辰"
date.monthGanZhi // "庚午"
date.dayGanZhi // "甲寅"
date.yearGanZhiPair // { gan: 0, zhi: 4 }
date.monthGanZhiPair // { gan: 6, zhi: 6 }
date.dayGanZhiPair // { gan: 0, zhi: 2 }
date.ganZhiInfo // { year: {gan:0,zhi:4}, month: {gan:6,zhi:6}, day: {gan:0,zhi:2} }
干支索引說明:
gan(天干):0=甲, 1=乙, 2=丙, 3=丁, 4=戊, 5=己, 6=庚, 7=辛, 8=壬, 9=癸zhi(地支):0=子, 1=丑, 2=寅, 3=卯, 4=辰, 5=巳, 6=午, 7=未, 8=申, 9=酉, 10=戌, 11=亥date.zodiac // "龍"
date.zodiacEmoji // "🐉"
date.zodiacIndex // 4
date.getZodiac('zh-TW') // "龍"
date.getZodiac('ja-JP') // "辰"
date.getZodiac('ko-KR') // "용"
date.getZodiac('vi-VN') // "Thìn"
date.weekday // 5
date.weekdayName // "星期五"
date.weekdayShort // "五"
date.getWeekdayName('ja-JP') // "金曜日"
date.getWeekdayShort('ja-JP') // "金"
date.getWeekdayName('ko-KR') // "금요일"
date.gregorianYearCn // "二〇二四"
date.gregorianYearCnLower // "二零二四"
date.toGregorian() // { year: 2024, month: 6, day: 21 }
date.toDate() // Date object(使用本地時區)
const json = date.toJSON()
// { cycle: 78, year: 34, month: 5, leap: false, day: 6 }
const str = JSON.stringify(date)
// '{"cycle":78,"year":34,"month":5,"leap":false,"day":6}'
const restored = ChineseDate.fromValue(JSON.parse(str))
所有日期運算方法都回傳新實例,原實例不變:
const date = ChineseDate.fromGregorian(2024, 6, 21)
const tomorrow = date.addDays(1)
const yesterday = date.addDays(-1)
const nextMonth = date.addMonths(1)
const lastYear = date.addYears(-1)
注意:
addMonths和addYears在公曆上運算。如果結果日期無效,會自動 clamp 到該月最後一天。
const date = ChineseDate.fromGregorian(2024, 6, 21)
const firstDay = date.with({ day: 1 }) // 五月初一
const prevMonth = date.with({ month: 4 }) // 四月初六
const leapMonth = date.with({ month: 4, leap: true }) // 閏四月初六
const a = ChineseDate.fromGregorian(2024, 6, 21)
const b = ChineseDate.fromGregorian(2024, 6, 20)
a.equals(b) // false
a.isAfter(b) // true
a.isBefore(b) // false
注意:
equals同時比較calendarType,不同曆法的實例即使日期相同也不相等。
const a = ChineseDate.fromGregorian(2024, 6, 21)
const b = ChineseDate.fromGregorian(2024, 6, 18)
a.diffDays(b) // 3
b.diffDays(a) // -3
const date = ChineseDate.fromGregorian(2024, 6, 21)
date.daysInMonth() // 29 或 30
const date = ChineseDate.fromGregorian(2024, 6, 21)
date.formatFull('zh-TW') // "甲辰龍年 五月初六"
date.formatGanZhi() // "甲辰年 庚午月 甲寅日"
date.formatCompact() // "78/34/5/0/6"
date.formatISO() // "78-34-5-0-6"
date.toString() // "甲辰龍年 五月初六"
緊湊格式說明:cycle/year/month/leap/day,其中 leap 編碼為 0(非閏月)或 1(閏月)。
const date = ChineseDate.fromGregorian(2024, 6, 21)
date.format('{Ygz}{Z}年 {Mname}{Dname}', 'zh-TW') // "甲辰龍年 五月初六"
date.format('{GY}年{GM}月{GD}日', 'zh-TW') // "2024年6月21日"
date.format('{GYcn}年{GMcn}月{GDcn}日', 'zh-TW') // "二〇二四年六月二十一日"
date.format('{Ygz}年 {Mname}{Dname} {GY}年{GM}月{GD}日', 'zh-TW')
// "甲辰年 五月初六 2024年6月21日"
import { PATTERNS } from 'chinese-lunar-date'
const date = ChineseDate.fromGregorian(2025, 10, 11)
date.format(PATTERNS.LUNAR_FULL) // "甲辰龍年 九月初九"
date.format(PATTERNS.GREGORIAN_CN_FULL) // "二〇二五年十月十一日"
date.format(PATTERNS.FULL_WITH_WEEKDAY) // "二〇二五年十月十一日 星期六"
| 常量 | 格式模式 | 輸出範例 |
|---|---|---|
GREGORIAN_CN_FULL |
{GYcn}年{GMcn}月{GDcn}日 |
二〇二五年十月十一日 |
GREGORIAN_CN_FULL_LOWER |
{GYcn2}年{GMcn}月{GDcn}日 |
二零二五年十月十一日 |
GREGORIAN_CN_NUMERIC |
{GY}年{GM}月{GD}日 |
2025年10月11日 |
GREGORIAN_ISO |
{GY}-{GM0}-{GD0} |
2025-10-11 |
GREGORIAN_SLASH |
{GY}/{GM}/{GD} |
2025/10/11 |
LUNAR_FULL |
{Ygz}{Z}年 {Mname}{Dname} |
甲辰龍年 九月初九 |
LUNAR_GANZHI |
{Ygz}年 {Mname}{Dname} |
甲辰年 九月初九 |
FULL_WITH_WEEKDAY |
{GYcn}年{GMcn}月{GDcn}日 {Wname} |
二〇二五年十月十一日 星期六 |
NUMERIC_WITH_WEEKDAY |
{GY}年{GM}月{GD}日 {Wname} |
2025年10月11日 星期六 |
LUNAR_WITH_WEEKDAY |
{Ygz}{Z}年 {Mname}{Dname} {Wname} |
甲辰龍年 九月初九 星期六 |
| Token | 輸出 | 範例 |
|---|---|---|
{CY} |
週期序號 | 78 |
{Y} |
週期內年序 | 34 |
{Ygz} |
年干支 | 甲辰 |
{Z} |
生肖 | 龍 |
{M} |
月份數字 | 5 |
{Mname} |
月份名稱 | 五月 / 閏四月 |
{L} |
閏月標記 | 閏(非閏月時為空) |
{D} |
日期數字 | 6 |
{Dname} |
日期名稱 | 初六 / 廿一 / 三十 |
| Token | 輸出 | 範例 |
|---|---|---|
{GY} |
公曆年 | 2024 |
{GYcn} |
公曆年中文(〇版) | 二〇二四 |
{GYcn2} |
公曆年中文(零版) | 二零二四 |
{GM} |
公曆月 | 6 |
{GM0} |
公曆月補零 | 06 |
{GMcn} |
公曆月中文 | 六 |
{GD} |
公曆日 | 21 |
{GD0} |
公曆日補零 | 21 |
{GDcn} |
公曆日中文 | 二十一 |
| Token | 輸出 | 範例 |
|---|---|---|
{W} |
星期幾數字 (0-6) | 5 |
{Wname} |
星期全稱 | 星期五 / 金曜日 |
{Wshort} |
星期簡稱 | 五 / 金 |
import { parseCompact, parseISO, parseGregorian } from 'chinese-lunar-date'
parseCompact('78/34/5/0/6') // { cycle: 78, year: 34, month: 5, leap: false, day: 6 }
parseISO('78-34-5-0-6') // { cycle: 78, year: 34, month: 5, leap: false, day: 6 }
parseGregorian('2025-10-11') // { year: 2025, month: 10, day: 11 }
const date = ChineseDate.fromGregorian(2024, 6, 21)
date.yearGanZhi // "甲辰"
date.monthGanZhi // "庚午"
date.dayGanZhi // "甲寅"
date.ganZhiInfo
// { year: {gan:0,zhi:4}, month: {gan:6,zhi:6}, day: {gan:0,zhi:2} }
import {
yearGanZhi, monthGanZhi, dayGanZhi,
formatGanZhi, parseGanZhi, allGanZhi,
ganZhiToCycleIndex, ganChar, zhiChar, GAN, ZHI
} from 'chinese-lunar-date'
const value = { cycle: 78, year: 34, month: 7, leap: false, day: 28 }
yearGanZhi(value) // { gan: 3, zhi: 9 } → 丁酉
formatGanZhi({ gan: 3, zhi: 9 }) // "丁酉"
parseGanZhi('甲子') // { gan: 0, zhi: 0 }
ganZhiToCycleIndex({ gan: 0, zhi: 0 }) // 1
ganZhiToCycleIndex({ gan: 9, zhi: 11 }) // 60
allGanZhi() // ["甲子", "乙丑", ..., "癸亥"]
allGanZhi()
// ["甲子", "乙丑", "丙寅", ..., "壬戌", "癸亥"] — 共 60 項
const date = ChineseDate.fromGregorian(2024, 6, 21)
date.zodiac // "龍"
date.zodiacEmoji // "🐉"
date.zodiacIndex // 4
date.getZodiac('zh-TW') // "龍"
date.getZodiac('ja-JP') // "辰"
date.getZodiac('ko-KR') // "용"
date.getZodiac('vi-VN') // "Thìn"
import { zodiac, zodiacEmoji, zodiacFromGregorianYear, zodiacList, zodiacIndex } from 'chinese-lunar-date'
const value = { cycle: 78, year: 34, month: 7, leap: false, day: 28 }
zodiac(value, 'zh-TW') // "雞"
zodiacEmoji(value) // "🐔"
zodiacFromGregorianYear(2024, 'zh-TW') // "龍"
zodiacList('zh-TW') // ["鼠", "牛", "虎", "兔", "龍", "蛇", "馬", "羊", "猴", "雞", "狗", "豬"]
ChineseDate.solarTerm(1, 2024) // { year: 2024, month: 2, day: 4 } — 立春
ChineseDate.solarTerm(5, 2024) // { year: 2024, month: 4, day: 4 } — 清明
ChineseDate.qingming(2024) // { year: 2024, month: 4, day: 4 }
節氣編號對照表:
| 編號 | 名稱 | 編號 | 名稱 | 編號 | 名稱 | 編號 | 名稱 |
|---|---|---|---|---|---|---|---|
| 1 | 立春 | 7 | 立夏 | 13 | 立秋 | 19 | 立冬 |
| 2 | 雨水 | 8 | 小滿 | 14 | 處暑 | 20 | 小雪 |
| 3 | 驚蟄 | 9 | 芒種 | 15 | 白露 | 21 | 大雪 |
| 4 | 春分 | 10 | 夏至 | 16 | 秋分 | 22 | 冬至 |
| 5 | 清明 | 11 | 小暑 | 17 | 寒露 | 23 | 小寒 |
| 6 | 穀雨 | 12 | 大暑 | 18 | 霜降 | 24 | 大寒 |
奇數編號為節氣(節),偶數編號為中氣(氣)。
import { solarTermName, solarTermNames } from 'chinese-lunar-date'
solarTermName(3, 'zh-TW') // "驚蟄"
solarTermName(3, 'ja-JP') // "啓蟄"
solarTermName(3, 'ko-KR') // "경칩"
solarTermNames('zh-TW') // ["立春", "雨水", "驚蟄", ..., "小寒", "大寒"]
const date = ChineseDate.fromGregorian(2024, 4, 4)
date.getSolarTermName('zh-TW') // "清明"
const terms = ChineseDate.solarTermsInYear(2024, 'zh-TW')
// [{ index: 1, name: "立春", date: {...}, jde: ... }, ...]
ChineseDate.festivalDate('spring', 2024) // { year: 2024, month: 2, day: 10 }
ChineseDate.festivalDate('mid-autumn', 2024) // { year: 2024, month: 9, day: 17 }
const date = ChineseDate.fromGregorian(2024, 2, 10)
date.getFestivals('zh-TW') // [{ name: "春節", key: "spring", ... }]
date.getFestivals('zh-HK') // [{ name: "農曆新年", key: "spring", ... }]
ChineseDate.festivalsInYear(2024, 'zh-TW')
// [{ name: "春節", key: "spring", date: {...} }, ...]
| Key | 農曆日期 | zh-TW | zh-HK |
|---|---|---|---|
spring |
正月初一 | 春節 | 農曆新年 |
lantern |
正月十五 | 元宵節 | 元宵節 |
dragon-head |
二月初二 | 龍抬頭 | 龍抬頭 |
shangsi |
三月初三 | 上巳節 | 上巳節 |
dragon-boat |
五月初五 | 端午節 | 端午節 |
qixi |
七月初七 | 七夕 | 七夕 |
ghost |
七月十五 | 中元節 | 中元節 |
mid-autumn |
八月十五 | 中秋節 | 中秋節 |
double-ninth |
九月初九 | 重陽節 | 重陽節 |
laba |
臘月初八 | 臘八節 | 臘八節 |
little-new-year-south |
臘月廿四 | 小年 | 小年 |
new-year-eve |
臘月三十 | 除夕 | 除夕 |
import { ChineseDate, JapaneseDate, KoreanDate, VietnameseDate } from 'chinese-lunar-date'
const cn = ChineseDate.fromGregorian(2024, 6, 21) // UTC+8
const jp = JapaneseDate.fromGregorian(2024, 6, 21) // UTC+9
const kr = KoreanDate.fromGregorian(2024, 6, 21) // UTC+8:30/9
const vn = VietnameseDate.fromGregorian(2024, 6, 21) // UTC+7/8
由於時區不同,同一公曆日期在不同曆法中可能對應不同的農曆日期。
韓國曆法使用檀君紀元(公元前 2333 年),因此 cycle 和 year 與中國曆法不同,但 gregorianYear 相同。
import { availableLocales, isLocaleSupported } from 'chinese-lunar-date'
availableLocales() // ["zh-CN", "zh-TW", "zh-HK", "ja-JP", "ko-KR", "vi-VN"]
import { getLocale } from 'chinese-lunar-date'
const loc = getLocale('zh-TW')
loc.gan // ["甲", "乙", "丙", ...]
loc.zodiac // ["鼠", "牛", "虎", "兔", "龍", "蛇", "馬", "羊", "猴", "雞", "狗", "豬"]
loc.monthNames(12, false) // "十二月"
loc.solarTerms // ["立春", "雨水", "驚蟄", ...]
| 項目 | zh-CN | zh-TW | zh-HK |
|---|---|---|---|
| 生肖 | 龙 马 鸡 猪 | 龍 馬 雞 豬 | 龍 馬 雞 豬 |
| 閏月標記 | 闰 | 閏 | 閏 |
| 臘月 | 腊月 | 臘月 | 臘月 |
| 春節名稱 | 春节 | 春節 | 農曆新年 |
| 節氣用字 | 惊蛰 谷雨 处暑 小满 芒种 | 驚蟄 穀雨 處暑 小滿 芒種 | 驚蟄 穀雨 處暑 小滿 芒種 |
| 小年 | 分南北方 | 統一(廿四) | 統一(廿四) |
import {
gregorianToLunar, lunarToGregorian, lunarToJDE, fromJDE,
newYear, yearFromEpochCycle,
inMajorSolarTerm, isLeapMonth,
CHINESE_CONFIG, JAPANESE_CONFIG, KOREAN_CONFIG, VIETNAMESE_CONFIG
} from 'chinese-lunar-date'
const lunar = gregorianToLunar(CHINESE_CONFIG, 2024, 6, 21)
const greg = lunarToGregorian(CHINESE_CONFIG, lunar)
import {
solarTermJDE, majorSolarTermJDE, minorSolarTermJDE,
nextNewMoon, previousNewMoon, midnight
} from 'chinese-lunar-date'
solarTermJDE(CHINESE_CONFIG, 5, 2024) // 清明的 JDE
nextNewMoon(2460482) // 下一個新月的 JDE
midnight(2024, 6, 21) // 午夜的 JDE
import { CHINESE_CONFIG, getConfig } from 'chinese-lunar-date'
CHINESE_CONFIG.type // 'chinese'
CHINESE_CONFIG.epochYear // -2636
getConfig('korean') // KOREAN_CONFIG
import { toChineseYear, toChineseNumber, getWeekdayName, getWeekdayShort } from 'chinese-lunar-date'
toChineseYear(2025, 'upper') // "二〇二五"
toChineseNumber(21, 'upper') // "二十一"
getWeekdayName(6, 'zh-TW') // "星期六"
getWeekdayShort(6, 'ja-JP') // "土"
interface LunarDateValue {
cycle: number
year: number
month: number
leap: boolean
day: number
}
interface GregorianDate {
year: number
month: number
day: number
}
type CalendarType = 'chinese' | 'korean' | 'japanese' | 'vietnamese'
interface GanZhiPair {
gan: number
zhi: number
}
interface GanZhiInfo {
year: GanZhiPair
month: GanZhiPair
day: GanZhiPair
}
interface SolarTermInfo {
index: number
name: string
date: GregorianDate
jde: number
}
interface FestivalInfo {
name: string
key: string
month: number
day: number
leap: boolean
}
type LocaleCode = 'zh-CN' | 'zh-TW' | 'zh-HK' | 'ja-JP' | 'ko-KR' | 'vi-VN'
interface LocaleData {
code: LocaleCode
gan: string[]
zhi: string[]
zodiac: string[]
solarTerms: string[]
monthNames(month: number, leap: boolean): string
dayNames(day: number): string
yearFormat(ganzhi: string, zodiac: string): string
}
中國農曆使用六十甲子週期系統。cycle 標識第幾個 60 年週期,year 標識週期內的第幾年(1-60)。大多數場景下,直接使用 date.gregorianYear 即可。
這是因為時區差異。當新月發生在 UTC+8 的午夜附近時,日本(UTC+9)可能已經進入下一天。
韓國曆法使用檀君紀元(公元前 2333 年),比中國紀元晚 297 年,因此週期序號不同。但 gregorianYear 相同。
import { isLeapMonth, CHINESE_CONFIG } from 'chinese-lunar-date'
isLeapMonth(CHINESE_CONFIG, 2023, 8) // false
const date = ChineseDate.fromGregorian(2024, 6, 21)
date.daysInMonth() // 29 或 30
<script src="dist/chinese-lunar-date.iife.js"></script>
<script>
const date = ChineseDate.ChineseDate.fromGregorian(2024, 6, 21)
const lunar = ChineseDate.gregorianToLunar(ChineseDate.CHINESE_CONFIG, 2024, 6, 21)
</script>
本函式庫基於 VSOP87 行星理論的天文算法,與天文臺發布的曆表精度一致(誤差在秒級)。
如果您在使用過程中遇到問題,或有功能建議、商務合作等需求,歡迎透過電子郵件聯繫我們:
src/
├── types.ts # 核心型別定義
├── core/
│ ├── astronomy-lite.ts # 自研輕量天文模組
│ ├── config.ts # 四種曆法配置
│ └── algorithm.ts # 核心算法
├── ganzhi.ts # 天干地支
├── zodiac.ts # 生肖
├── solar-term.ts # 24 節氣
├── festival.ts # 傳統節日
├── locale.ts # 多語言 / 多地區
├── format.ts # 格式化 + 解析
├── chinese-numerals.ts # 中文數字
├── lunar-date.ts # 不可變值物件 API
└── index.ts # 主入口
設計原則:
CalendarConfig 區分