版本: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>
// 所有 API 挂载在全局 ChineseDate 对象上
const date = ChineseDate.ChineseDate.fromGregorian(2024, 6, 21)
console.log(date.formatFull()) // "甲辰龙年 五月初六"
// 低级 API
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 }
// 即:甲辰年 五月初六
参数为公历年、月(1-12)、日。
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 })
支持三种公历日期格式:
// ISO 格式
const d1 = ChineseDate.fromISO('2024-06-21')
// 斜杠格式
const d2 = ChineseDate.fromISO('2024/06/21')
// 中文格式
const d3 = ChineseDate.fromISO('2024年6月21日')
// 解析失败返回 null
const d4 = ChineseDate.fromISO('invalid') // null
// parse 是 fromISO 的别名
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 // "🐉" — 生肖 Emoji
date.zodiacIndex // 4 — 生肖索引(0=鼠, 1=牛, ..., 11=猪)
date.getZodiac('zh-TW') // "龍"
date.getZodiac('ja-JP') // "辰"
date.getZodiac('ko-KR') // "용"
date.getZodiac('vi-VN') // "Thìn"
date.weekday // 5 — 星期几(0=周日, 1=周一, ..., 6=周六)
date.weekdayName // "星期五" — 星期全称(简体中文)
date.weekdayShort // "五" — 星期简称(简体中文)
date.getWeekdayName('ja-JP') // "金曜日"
date.getWeekdayShort('ja-JP') // "金"
date.getWeekdayName('ko-KR') // "금요일"
date.getWeekdayShort('vi-VN') // "T6"
date.gregorianYearCn // "二〇二四" — 公历年中文数字(〇版)
date.gregorianYearCnLower // "二零二四" — 公历年中文数字(零版)
const date = ChineseDate.fromGregorian(2024, 6, 21)
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 nextWeek = date.addDays(7)
// 加减月数(基于公历计算,自动处理月末 clamp)
const nextMonth = date.addMonths(1)
const lastMonth = date.addMonths(-1)
// 加减年数(基于公历计算,自动处理闰年 clamp)
const nextYear = date.addYears(1)
const lastYear = date.addYears(-1)
注意:
addMonths和addYears在公历上运算。如果结果日期无效(如 2 月 30 日),会自动 clamp 到该月最后一天。
使用 with() 修改部分字段,返回新实例:
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
a.equals(a) // true
注意:
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(农历月只有大月30天和小月29天)
const date = ChineseDate.fromGregorian(2024, 6, 21)
// 完整格式
date.formatFull() // "甲辰龙年 五月初六"
date.formatFull('zh-TW') // "甲辰龍年 五月初六"
date.formatFull('zh-HK') // "甲辰龍年 五月初六"
date.formatFull('ja-JP') // "甲辰辰年 五月初六"
// 干支格式
date.formatGanZhi() // "甲辰年 庚午月 甲寅日"
date.formatGanZhi('ko-KR') // "甲辰年 庚午月 甲寅日"
// 紧凑格式(适合存储和传输)
date.formatCompact() // "78/34/5/0/6"
// ISO 格式
date.formatISO() // "78-34-5-0-6"
// 默认字符串(等同 formatFull)
date.toString() // "甲辰龙年 五月初六"
紧凑格式说明:cycle/year/month/leap/day,其中 leap 编码为 0(非闰月)或 1(闰月)。
const date = ChineseDate.fromGregorian(2024, 6, 21)
// 农历模式
date.format('{Ygz}{Z}年 {Mname}{Dname}', 'zh-CN') // "甲辰龙年 五月初六"
date.format('{Ygz}{Z}年 {Mname}{Dname}', 'zh-TW') // "甲辰龍年 五月初六"
// 公历模式(需要公历数据,值对象的 format 方法自动提供)
date.format('{GY}年{GM}月{GD}日', 'zh-CN') // "2024年6月21日"
date.format('{GYcn}年{GMcn}月{GDcn}日', 'zh-CN') // "二〇二四年六月二十一日"
date.format('{GY}-{GM0}-{GD0}', 'zh-CN') // "2024-06-21"
// 混合模式
date.format('{Ygz}年 {Mname}{Dname} {GY}年{GM}月{GD}日', 'zh-CN')
// "甲辰年 五月初六 2024年6月21日"
// 带星期
date.format('{GYcn}年{GMcn}月{GDcn}日 {Wname}', 'zh-CN')
// "二〇二四年六月二十一日 星期五"
import { PATTERNS } from 'chinese-lunar-date'
const date = ChineseDate.fromGregorian(2025, 10, 11)
date.format(PATTERNS.GREGORIAN_CN_FULL) // "二〇二五年十月十一日"
date.format(PATTERNS.GREGORIAN_CN_FULL_LOWER) // "二零二五年十月十一日"
date.format(PATTERNS.GREGORIAN_CN_NUMERIC) // "2025年10月11日"
date.format(PATTERNS.GREGORIAN_ISO) // "2025-10-11"
date.format(PATTERNS.GREGORIAN_SLASH) // "2025/10/11"
date.format(PATTERNS.LUNAR_FULL) // "甲辰龙年 九月初九"
date.format(PATTERNS.LUNAR_GANZHI) // "甲辰年 九月初九"
date.format(PATTERNS.FULL_WITH_WEEKDAY) // "二〇二五年十月十一日 星期六"
date.format(PATTERNS.NUMERIC_WITH_WEEKDAY) // "2025年10月11日 星期六"
date.format(PATTERNS.LUNAR_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} |
星期简称 | 五 / 金 |
注意:公历和星期相关 Token 需要公历日期数据。使用值对象的
format()方法时自动提供;使用独立format()函数时需手动传入公历日期。
import { parseCompact, parseISO } from 'chinese-lunar-date'
parseCompact('78/34/5/0/6') // { cycle: 78, year: 34, month: 5, leap: false, day: 6 }
parseCompact('78/34/2/1/15') // { cycle: 78, year: 34, month: 2, leap: true, day: 15 }
parseCompact('invalid') // null
parseISO('78-34-5-0-6') // { cycle: 78, year: 34, month: 5, leap: false, day: 6 }
parseISO('78-34-2-1-15') // { cycle: 78, year: 34, month: 2, leap: true, day: 15 }
parseISO('invalid') // null
import { parseGregorian } from 'chinese-lunar-date'
parseGregorian('2025-10-11') // { year: 2025, month: 10, day: 11 }
parseGregorian('2025/10/11') // { year: 2025, month: 10, day: 11 }
parseGregorian('2025年10月11日') // { year: 2025, month: 10, day: 11 }
parseGregorian('invalid') // null
const date = ChineseDate.fromGregorian(2024, 6, 21)
// 字符串形式
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} }
import {
yearGanZhi, monthGanZhi, dayGanZhi,
getGanZhiInfo, formatGanZhi, parseGanZhi,
ganZhiToCycleIndex, allGanZhi,
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 } → 丁酉
monthGanZhi(value) // { gan: ..., zhi: ... }
dayGanZhi(2460482) // { gan: ..., zhi: ... } — 注意:日干支需要 JDE
// 格式化
formatGanZhi({ gan: 3, zhi: 9 }) // "丁酉"
// 解析
parseGanZhi('甲子') // { gan: 0, zhi: 0 }
parseGanZhi('癸亥') // { gan: 9, zhi: 11 }
// 六十甲子序号
ganZhiToCycleIndex({ gan: 0, zhi: 0 }) // 1 — 甲子是第1个
ganZhiToCycleIndex({ gan: 9, zhi: 11 }) // 60 — 癸亥是第60个
// 天干/地支字符
ganChar(0) // "甲"
zhiChar(0) // "子"
// 天干/地支数组
GAN // ["甲", "乙", "丙", "丁", "戊", "己", "庚", "辛", "壬", "癸"]
ZHI // ["子", "丑", "寅", "卯", "辰", "巳", "午", "未", "申", "酉", "戌", "亥"]
allGanZhi()
// ["甲子", "乙丑", "丙寅", "丁卯", "戊辰", "己巳", "庚午", "辛未", "壬申", "癸酉",
// "甲戌", "乙亥", "丙子", ..., "壬戌", "癸亥"]
// 共 60 项
const date = ChineseDate.fromGregorian(2024, 6, 21)
date.zodiac // "龙"
date.zodiacEmoji // "🐉"
date.zodiacIndex // 4
date.getZodiac('zh-CN') // "龙"
date.getZodiac('zh-TW') // "龍"
date.getZodiac('zh-HK') // "龍"
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-CN') // "鸡"
zodiac(value, 'zh-TW') // "雞"
zodiac(value, 'ja-JP') // "鶏"
zodiac(value, 'ko-KR') // "닭"
zodiac(value, 'vi-VN') // "Dậu"
// Emoji
zodiacEmoji(value) // "🐔"
// 生肖索引
zodiacIndex(value) // 9(鸡)
// 从公历年快速获取
zodiacFromGregorianYear(2024, 'zh-CN') // "龙"
zodiacFromGregorianYear(2024, 'ja-JP') // "辰"
// 生肖列表
zodiacList('zh-CN') // ["鼠", "牛", "虎", "兔", "龙", "蛇", "马", "羊", "猴", "鸡", "狗", "猪"]
zodiacList('zh-TW') // ["鼠", "牛", "虎", "兔", "龍", "蛇", "馬", "羊", "猴", "雞", "狗", "豬"]
zodiacList('ko-KR') // ["쥐", "소", "호랑이", "토끼", "용", "뱀", "말", "양", "원숭이", "닭", "개", "돼지"]
import { ChineseDate } from 'chinese-lunar-date'
// 获取指定节气的公历日期(节气编号 1-24)
ChineseDate.solarTerm(1, 2024) // { year: 2024, month: 2, day: 4 } — 立春
ChineseDate.solarTerm(5, 2024) // { year: 2024, month: 4, day: 4 } — 清明
ChineseDate.solarTerm(24, 2024) // { year: 2024, month: 1, day: 20 } — 大寒
// 清明快捷方法
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-CN') // "惊蛰"
solarTermName(3, 'zh-TW') // "驚蟄"
solarTermName(3, 'zh-HK') // "驚蟄"
solarTermName(3, 'ja-JP') // "啓蟄"
solarTermName(3, 'ko-KR') // "경칩"
solarTermName(3, 'vi-VN') // "Kinh trập"
// 全部节气名称
solarTermNames('zh-CN') // ["立春", "雨水", "惊蛰", ..., "小寒", "大寒"]
solarTermNames('ja-JP') // ["立春", "雨水", "啓蟄", ..., "小寒", "大寒"]
const date = ChineseDate.fromGregorian(2024, 4, 4)
date.getSolarTermName('zh-CN') // "清明"
const date2 = ChineseDate.fromGregorian(2024, 6, 21)
date2.getSolarTermName('zh-CN') // null — 这天不是节气
const terms = ChineseDate.solarTermsInYear(2024, 'zh-CN')
// [
// { index: 1, name: "立春", date: { year: 2024, month: 2, day: 4 }, jde: 2460344.2... },
// { index: 2, name: "雨水", date: { year: 2024, month: 2, day: 19 }, jde: 2460359.2... },
// ...
// { index: 24, name: "大寒", date: { year: 2025, month: 1, day: 20 }, jde: 2460694.2... }
// ]
ChineseDate.festivalDate('spring', 2024) // { year: 2024, month: 2, day: 10 }
ChineseDate.festivalDate('mid-autumn', 2024) // { year: 2024, month: 9, day: 17 }
ChineseDate.festivalDate('dragon-boat', 2024) // { year: 2024, month: 6, day: 10 }
ChineseDate.festivalDate('new-year-eve', 2024) // { year: 2025, month: 1, day: 28 }
const date = ChineseDate.fromGregorian(2024, 2, 10)
date.getFestivals('zh-CN') // [{ name: "春节", key: "spring", month: 1, day: 1, leap: false }]
date.getFestivals('zh-HK') // [{ name: "農曆新年", key: "spring", month: 1, day: 1, leap: false }]
date.festivals // 同 getFestivals('zh-CN')
ChineseDate.festivalsInYear(2024, 'zh-CN')
// [
// { name: "春节", key: "spring", date: { year: 2024, month: 2, day: 10 }, ... },
// { name: "元宵节", key: "lantern", date: { year: 2024, month: 2, day: 24 }, ... },
// ...
// ]
ChineseDate.festivalsInYear(2024, 'zh-HK')
// [
// { name: "農曆新年", key: "spring", date: { year: 2024, month: 2, day: 10 }, ... },
// ...
// ]
| Key | 农历日期 | zh-CN | zh-TW | zh-HK |
|---|---|---|---|---|
spring |
正月初一 | 春节 | 春節 | 農曆新年 |
lantern |
正月十五 | 元宵节 | 元宵節 | 元宵節 |
dragon-head |
二月初二 | 龙抬头 | 龍抬頭 | 龍抬頭 |
shangsi |
三月初三 | 上巳节 | 上巳節 | 上巳節 |
dragon-boat |
五月初五 | 端午节 | 端午節 | 端午節 |
qixi |
七月初七 | 七夕节 | 七夕 | 七夕 |
ghost |
七月十五 | 中元节 | 中元節 | 中元節 |
mid-autumn |
八月十五 | 中秋节 | 中秋節 | 中秋節 |
double-ninth |
九月初九 | 重阳节 | 重陽節 | 重陽節 |
laba |
腊月初八 | 腊八节 | 臘八節 | 臘八節 |
little-new-year-north |
腊月廿三 | 小年(北方) | — | — |
little-new-year-south |
腊月廿四 | 小年(南方) | 小年 | 小年 |
new-year-eve |
腊月三十 | 除夕 | 除夕 | 除夕 |
"—" 表示该地区不庆祝此节日,
festivalsInYear会自动排除。
import { ChineseDate, JapaneseDate, KoreanDate, VietnameseDate } from 'chinese-lunar-date'
// 中国农历 (UTC+8)
const cn = ChineseDate.fromGregorian(2024, 6, 21)
// 日本旧历 (UTC+9)
const jp = JapaneseDate.fromGregorian(2024, 6, 21)
// 韩国农历 (UTC+8:30/9,檀君纪元)
const kr = KoreanDate.fromGregorian(2024, 6, 21)
// 越南农历 (UTC+7/8)
const vn = VietnameseDate.fromGregorian(2024, 6, 21)
所有子类都支持与 ChineseDate 相同的构造方法和实例方法:
// 构造方法
JapaneseDate.fromGregorian(2024, 6, 21)
JapaneseDate.fromDate(new Date())
JapaneseDate.fromValue({ cycle: 78, year: 34, month: 5, leap: false, day: 6 })
JapaneseDate.fromISO('2024-06-21')
JapaneseDate.fromTimestamp(Date.now())
JapaneseDate.today()
// 实例方法
jp.yearGanZhi // "甲辰"
jp.formatFull() // "甲辰年 五月初六"
jp.toGregorian() // { year: 2024, month: 6, day: 21 }
由于时区不同,同一公历日期在不同历法中可能对应不同的农历日期:
// 假设新月发生在 UTC+8 的午夜附近
const cn = ChineseDate.fromGregorian(2024, 1, 12) // 可能是腊月初二
const jp = JapaneseDate.fromGregorian(2024, 1, 12) // 可能是腊月初三(UTC+9 已过午夜)
韩国历法使用檀君纪元(公元前 2333 年),因此 cycle 和 year 与中国历法不同:
const cn = ChineseDate.fromGregorian(2024, 6, 21)
cn.cycle // 78
cn.year // 34
const kr = KoreanDate.fromGregorian(2024, 6, 21)
kr.cycle // 83(檀君纪元更早,周期序号更大)
kr.year // 不同值
// 但公历年相同
cn.gregorianYear // 2024
kr.gregorianYear // 2024
import { availableLocales, isLocaleSupported } from 'chinese-lunar-date'
availableLocales() // ["zh-CN", "zh-TW", "zh-HK", "ja-JP", "ko-KR", "vi-VN"]
isLocaleSupported('zh-CN') // true
isLocaleSupported('zh-MO') // false
import { getLocale } from 'chinese-lunar-date'
const loc = getLocale('ja-JP')
loc.gan // ["甲", "乙", "丙", "丁", "戊", "己", "庚", "辛", "壬", "癸"]
loc.zhi // ["子", "丑", "寅", "卯", "辰", "巳", "午", "未", "申", "酉", "戌", "亥"]
loc.zodiac // ["鼠", "牛", "虎", "兔", "竜", "蛇", "馬", "羊", "猿", "鶏", "犬", "猪"]
loc.monthNames(12, false) // "師走"
loc.monthNames(6, false) // "水無月"
loc.dayNames(15) // "十五"
loc.solarTerms // ["立春", "雨水", "啓蟄", ...]
loc.yearFormat('甲辰', '辰') // "甲辰辰年"
| 项目 | 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)
// { cycle: 78, year: 34, month: 5, leap: false, day: 6 }
// 农历 → 公历
const greg = lunarToGregorian(CHINESE_CONFIG, lunar)
// { year: 2024, month: 6, day: 21 }
// 农历 → JDE
const jde = lunarToJDE(CHINESE_CONFIG, lunar)
// JDE → 农历
const lunar2 = fromJDE(CHINESE_CONFIG, jde)
// 春节 JDE
const nyJDE = newYear(CHINESE_CONFIG, 2024)
// 周期/年序 → 公历年
yearFromEpochCycle(CHINESE_CONFIG, 78, 34) // 2024
// 判断是否中气月
inMajorSolarTerm(CHINESE_CONFIG, lunar) // true/false
// 判断是否闰月
isLeapMonth(CHINESE_CONFIG, 2024, 5) // false(2024年五月不是闰月)
import {
solarTermJDE, majorSolarTermJDE, minorSolarTermJDE,
nextNewMoon, previousNewMoon, midnight
} from 'chinese-lunar-date'
// 节气 JDE
solarTermJDE(CHINESE_CONFIG, 5, 2024) // 清明的 JDE
majorSolarTermJDE(CHINESE_CONFIG, 3, 2024) // 第3个中气的 JDE
minorSolarTermJDE(CHINESE_CONFIG, 3, 2024) // 第3个节气的 JDE
// 新月 JDE
nextNewMoon(2460482) // 下一个新月的 JDE
previousNewMoon(2460482) // 上一个新月的 JDE
// 午夜 JDE
midnight(2024, 6, 21) // 2024-06-21 午夜的 JDE
import { CHINESE_CONFIG, JAPANESE_CONFIG, KOREAN_CONFIG, VIETNAMESE_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') // "二〇二五"(〇版,日期常用)
toChineseYear(2025, 'lower') // "二零二五"(零版,口语常用)
toChineseYear(1900, 'upper') // "一九〇〇"
// 数字转换(1-99)
toChineseNumber(1, 'upper') // "一"
toChineseNumber(10, 'upper') // "十"
toChineseNumber(11, 'upper') // "十一"
toChineseNumber(21, 'upper') // "二十一"
toChineseNumber(30, 'upper') // "三十"
toChineseNumber(99, 'upper') // "九十九"
// 星期名称
getWeekdayName(0, 'zh-CN') // "星期日"
getWeekdayName(6, 'zh-CN') // "星期六"
getWeekdayName(6, 'ja-JP') // "土曜日"
getWeekdayName(6, 'ko-KR') // "토요일"
getWeekdayName(6, 'vi-VN') // "Thứ Bảy"
// 星期简称
getWeekdayShort(6, 'zh-CN') // "六"
getWeekdayShort(6, 'ja-JP') // "土"
getWeekdayShort(6, 'ko-KR') // "토"
getWeekdayShort(6, 'vi-VN') // "T7"
/** 农历日期值 */
interface LunarDateValue {
cycle: number // 六十甲子周期序号(1 起始)
year: number // 周期内年序(1-60)
month: number // 月(1-12)
leap: boolean // 是否闰月
day: number // 日(1-30)
}
/** 公历日期值 */
interface GregorianDate {
year: number
month: number
day: number
}
/** 历法类型 */
type CalendarType = 'chinese' | 'korean' | 'japanese' | 'vietnamese'
/** 历法配置 */
interface CalendarConfig {
type: CalendarType
epochYear: number
epochJDE: number
timeshiftUTC(year: number, month: number, day: number): number
}
/** 干支索引对 */
interface GanZhiPair {
gan: number // 天干索引(0-9)
zhi: number // 地支索引(0-11)
}
/** 年月日干支完整信息 */
interface GanZhiInfo {
year: GanZhiPair
month: GanZhiPair
day: GanZhiPair
}
/** 节气信息 */
interface SolarTermInfo {
index: number // 节气序号(1-24)
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
}
/** 格式化 Token 类型 */
type FormatToken =
| 'CY' | 'Y' | 'Ygz' | 'Z' | 'M' | 'Mname' | 'L' | 'D' | 'Dname'
| 'GY' | 'GYcn' | 'GYcn2' | 'GM' | 'GM0' | 'GMcn' | 'GD' | 'GD0' | 'GDcn'
| 'W' | 'Wname' | 'Wshort'
中国农历使用六十甲子周期系统。cycle 标识第几个 60 年周期,year 标识周期内的第几年(1-60)。这种设计:
year=1 → 甲子)date.gregorianYear 即可这是因为时区差异。当新月发生在 UTC+8 的午夜附近时,日本(UTC+9)可能已经进入下一天,导致农历月份或日期不同。
韩国历法使用檀君纪元(公元前 2333 年),比中国纪元(公元前 2636 年)晚 297 年,因此周期序号不同。但 gregorianYear 属性返回的公历年份是相同的。
// 方法1:通过低级 API
import { isLeapMonth, CHINESE_CONFIG } from 'chinese-lunar-date'
// 检查 2023 年八月是否为闰月
isLeapMonth(CHINESE_CONFIG, 2023, 8) // false
// 方法2:通过值对象遍历
// 创建该年任意一天的实例,然后遍历月份
const date = ChineseDate.fromGregorian(2024, 6, 21)
date.daysInMonth() // 29 或 30
使用值对象的 format() 方法时,公历数据会自动提供。但如果使用独立的 format() 函数,需要手动传入公历日期:
// 值对象方法 — 自动提供公历数据
date.format('{GY}年{GM}月{GD}日') // "2024年6月21日" ✓
// 独立函数 — 需要手动传入公历日期
format(value, jde, greg, '{GY}年{GM}月{GD}日') // ✓
format(value, jde, '{GY}年{GM}月{GD}日') // "" — 公历 Token 为空 ✗
<script src="dist/chinese-lunar-date.iife.js"></script>
<script>
// 类名需要写两遍:ChineseDate.ChineseDate
const date = ChineseDate.ChineseDate.fromGregorian(2024, 6, 21)
// 函数直接在 ChineseDate 对象上
const lunar = ChineseDate.gregorianToLunar(ChineseDate.CHINESE_CONFIG, 2024, 6, 21)
</script>
本库基于 VSOP87 行星理论的天文算法,与天文台发布的历表精度一致(误差在秒级)。自研轻量天文模块通过截断 VSOP87 数据(阈值 1e-7,保留 220/2564 项),在保持足够精度的同时大幅减小体积。
如果您在使用过程中遇到问题,或有功能建议、商务合作等需求,欢迎通过邮件联系我们:
src/
├── types.ts # 核心类型定义
├── core/
│ ├── astronomy-lite.ts # 自研轻量天文模块(VSOP87 截断数据)
│ ├── vsop87Bearth-truncated.ts # 截断版 VSOP87 地球数据
│ ├── 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 # 主入口
设计原则:
with() / addDays() 返回新实例CalendarConfig 区分(纪元年、时区历史规则)