完成1.0版
parent
4564fb60b8
commit
0d35f290b7
|
@ -7,3 +7,4 @@ useTabs: false
|
|||
tabWidth: 2
|
||||
trailingComma: none
|
||||
bracketSpacing: true
|
||||
arrowParens: avoid
|
24
Readme.md
24
Readme.md
|
@ -6,25 +6,43 @@
|
|||
\____\__,_|_|\___|_| |_|\__,_|\__,_|_| 终端版万年历
|
||||
|
||||
```
|
||||
农历的计算, 只支持 1901-2100 范围内的。
|
||||
|
||||
|
||||
![demo1.png](./img/demo1.png)
|
||||
![demo1.png](./img/demo.png)
|
||||
|
||||
|
||||
## 安装
|
||||
```bash
|
||||
npm i -g bash-calendar
|
||||
# 安装完之后, 可以使用 calendar命令
|
||||
# 也可以使用 简写的 cal命令
|
||||
```
|
||||
|
||||
## 用法
|
||||
> 用法: `cal [command] args...`
|
||||
|
||||
+ Commands:
|
||||
- Commands:
|
||||
* -y {year} - 打印指定年份的日历
|
||||
* -m - 打印指定月份的日历
|
||||
* -h - 查看帮助文档
|
||||
* -v - 查看工具的版本
|
||||
* -v - 查看程序的版本
|
||||
|
||||
示例:
|
||||
|
||||
```bash
|
||||
cal # 不带参数打印当前年月
|
||||
cal -y # -y不接参数, 打印当前年的所有月份
|
||||
cal -y 2000 # 打印指定年份的所有月份
|
||||
cal -y 2021 5 # 打印指定年份, 指定月份
|
||||
cal -y 2000 -m 3 # 同上
|
||||
cal -m 5 # 打印当前年份的 指定月份
|
||||
```
|
||||
|
||||
## 更新日志
|
||||
|
||||
### v1.0.0
|
||||
* 完成农历显示、公历节日及农历节日的显示
|
||||
|
||||
### v0.0.1
|
||||
* 初始化项目
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
const esbuild = require('esbuild')
|
||||
const { version } = require('./package.json')
|
||||
|
||||
esbuild.build({
|
||||
entryPoints: ['src/index.js'],
|
||||
sourcemap: false,
|
||||
bundle: true,
|
||||
define: { 'process.env.APP_VERSION': `'${version}'` },
|
||||
platform: 'node',
|
||||
target: 'node10',
|
||||
minify: true,
|
||||
// external: ['chalk'],
|
||||
outfile: 'index.js'
|
||||
})
|
Binary file not shown.
After Width: | Height: | Size: 50 KiB |
BIN
img/demo1.png
BIN
img/demo1.png
Binary file not shown.
Before Width: | Height: | Size: 94 KiB |
File diff suppressed because one or more lines are too long
359
lunar.js
359
lunar.js
|
@ -1,359 +0,0 @@
|
|||
/* 公历转农历代码思路:
|
||||
1、建立农历年份查询表
|
||||
2、计算输入公历日期与公历基准的相差天数
|
||||
3、从农历基准开始遍历农历查询表,计算自农历基准之后每一年的天数,并用相差天数依次相减,确定农历年份
|
||||
4、利用剩余相差天数以及农历每个月的天数确定农历月份
|
||||
5、利用剩余相差天数确定农历哪一天 */
|
||||
|
||||
// 农历1949-2100年查询表
|
||||
const LUNAR_YEARS = [
|
||||
0x0b557, //1949
|
||||
0x06ca0,
|
||||
0x0b550,
|
||||
0x15355,
|
||||
0x04da0,
|
||||
0x0a5b0,
|
||||
0x14573,
|
||||
0x052b0,
|
||||
0x0a9a8,
|
||||
0x0e950,
|
||||
0x06aa0, //1950-1959
|
||||
0x0aea6,
|
||||
0x0ab50,
|
||||
0x04b60,
|
||||
0x0aae4,
|
||||
0x0a570,
|
||||
0x05260,
|
||||
0x0f263,
|
||||
0x0d950,
|
||||
0x05b57,
|
||||
0x056a0, //1960-1969
|
||||
0x096d0,
|
||||
0x04dd5,
|
||||
0x04ad0,
|
||||
0x0a4d0,
|
||||
0x0d4d4,
|
||||
0x0d250,
|
||||
0x0d558,
|
||||
0x0b540,
|
||||
0x0b6a0,
|
||||
0x195a6, //1970-1979
|
||||
0x095b0,
|
||||
0x049b0,
|
||||
0x0a974,
|
||||
0x0a4b0,
|
||||
0x0b27a,
|
||||
0x06a50,
|
||||
0x06d40,
|
||||
0x0af46,
|
||||
0x0ab60,
|
||||
0x09570, //1980-1989
|
||||
0x04af5,
|
||||
0x04970,
|
||||
0x064b0,
|
||||
0x074a3,
|
||||
0x0ea50,
|
||||
0x06b58,
|
||||
0x055c0,
|
||||
0x0ab60,
|
||||
0x096d5,
|
||||
0x092e0, //1990-1999
|
||||
0x0c960,
|
||||
0x0d954,
|
||||
0x0d4a0,
|
||||
0x0da50,
|
||||
0x07552,
|
||||
0x056a0,
|
||||
0x0abb7,
|
||||
0x025d0,
|
||||
0x092d0,
|
||||
0x0cab5, //2000-2009
|
||||
0x0a950,
|
||||
0x0b4a0,
|
||||
0x0baa4,
|
||||
0x0ad50,
|
||||
0x055d9,
|
||||
0x04ba0,
|
||||
0x0a5b0,
|
||||
0x15176,
|
||||
0x052b0,
|
||||
0x0a930, //2010-2019
|
||||
0x07954,
|
||||
0x06aa0,
|
||||
0x0ad50,
|
||||
0x05b52,
|
||||
0x04b60,
|
||||
0x0a6e6,
|
||||
0x0a4e0,
|
||||
0x0d260,
|
||||
0x0ea65,
|
||||
0x0d530, //2020-2029
|
||||
0x05aa0,
|
||||
0x076a3,
|
||||
0x096d0,
|
||||
0x04afb,
|
||||
0x04ad0,
|
||||
0x0a4d0,
|
||||
0x1d0b6,
|
||||
0x0d250,
|
||||
0x0d520,
|
||||
0x0dd45, //2030-2039
|
||||
0x0b5a0,
|
||||
0x056d0,
|
||||
0x055b2,
|
||||
0x049b0,
|
||||
0x0a577,
|
||||
0x0a4b0,
|
||||
0x0aa50,
|
||||
0x1b255,
|
||||
0x06d20,
|
||||
0x0ada0, //2040-2049
|
||||
0x14b63,
|
||||
0x09370,
|
||||
0x049f8,
|
||||
0x04970,
|
||||
0x064b0,
|
||||
0x168a6,
|
||||
0x0ea50,
|
||||
0x06b20,
|
||||
0x1a6c4,
|
||||
0x0aae0, //2050-2059
|
||||
0x0a2e0,
|
||||
0x0d2e3,
|
||||
0x0c960,
|
||||
0x0d557,
|
||||
0x0d4a0,
|
||||
0x0da50,
|
||||
0x05d55,
|
||||
0x056a0,
|
||||
0x0a6d0,
|
||||
0x055d4, //2060-2069
|
||||
0x052d0,
|
||||
0x0a9b8,
|
||||
0x0a950,
|
||||
0x0b4a0,
|
||||
0x0b6a6,
|
||||
0x0ad50,
|
||||
0x055a0,
|
||||
0x0aba4,
|
||||
0x0a5b0,
|
||||
0x052b0, //2070-2079
|
||||
0x0b273,
|
||||
0x06930,
|
||||
0x07337,
|
||||
0x06aa0,
|
||||
0x0ad50,
|
||||
0x14b55,
|
||||
0x04b60,
|
||||
0x0a570,
|
||||
0x054e4,
|
||||
0x0d160, //2080-2089
|
||||
0x0e968,
|
||||
0x0d520,
|
||||
0x0daa0,
|
||||
0x16aa6,
|
||||
0x056d0,
|
||||
0x04ae0,
|
||||
0x0a9d4,
|
||||
0x0a2d0,
|
||||
0x0d150,
|
||||
0x0f252, //2090-2099
|
||||
0x0d520 //2100
|
||||
]
|
||||
|
||||
const LUNAR_MONTH = ['正', '二', '三', '四', '五', '六', '七', '八', '九', '十', '冬', '腊']
|
||||
const LUNAR_DAY = {
|
||||
0: '初',
|
||||
1: '一',
|
||||
2: '二',
|
||||
3: '三',
|
||||
4: '四',
|
||||
5: '五',
|
||||
6: '六',
|
||||
7: '七',
|
||||
8: '八',
|
||||
9: '九',
|
||||
10: '十',
|
||||
20: '廿'
|
||||
}
|
||||
// 生肖、天干、地支, 节气
|
||||
const ZODIAC = ['鼠', '牛', '虎', '兔', '龙', '蛇', '马', '羊', '猴', '鸡', '狗', '猪']
|
||||
const HEAVENLY_STEMS = ['甲', '乙', '丙', '丁', '戊', '己', '庚', '辛', '壬', '癸']
|
||||
const EARTHLY_BRANCHES = ['子', '丑', '寅', '卯', '辰', '巳', '午', '未', '申', '酉', '戌', '亥']
|
||||
const SOLAR_TERMS = [
|
||||
'立春',
|
||||
'雨水',
|
||||
'惊蛰',
|
||||
'春分',
|
||||
'清明',
|
||||
'谷雨',
|
||||
'立夏',
|
||||
'小满',
|
||||
'芒种',
|
||||
'夏至',
|
||||
'小暑',
|
||||
'大暑',
|
||||
'立秋',
|
||||
'处暑',
|
||||
'白露',
|
||||
'秋分',
|
||||
'寒露',
|
||||
'霜降',
|
||||
'立冬',
|
||||
'小雪',
|
||||
'大雪',
|
||||
'冬至',
|
||||
'小寒',
|
||||
'大寒'
|
||||
]
|
||||
|
||||
// 公历转农历函数
|
||||
export function sloar2lunar(sy, sm, sd) {
|
||||
// 计算与公历基准的相差天数
|
||||
let daySpan = (Date.UTC(sy, sm, sd) - Date.UTC(1949, 0, 29)) / (24 * 60 * 60 * 1000) + 1
|
||||
let ly, lm, ld
|
||||
// 确定输出的农历年份
|
||||
for (let j = 0; j < LUNAR_YEARS.length; j++) {
|
||||
daySpan -= lunarYearDays(LUNAR_YEARS[j])
|
||||
if (daySpan <= 0) {
|
||||
ly = 1949 + j
|
||||
// 获取农历年份确定后的剩余天数
|
||||
daySpan += lunarYearDays(LUNAR_YEARS[j])
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// 确定输出的农历月份
|
||||
for (let k = 0; k < lunarYearMonths(LUNAR_YEARS[ly - 1949]).length; k++) {
|
||||
daySpan -= lunarYearMonths(LUNAR_YEARS[ly - 1949])[k]
|
||||
if (daySpan <= 0) {
|
||||
// 有闰月时,月份的数组长度会变成13,因此,当闰月月份小于等于k时,lm不需要加1
|
||||
if (hasLeapMonth(LUNAR_YEARS[ly - 1949]) && hasLeapMonth(LUNAR_YEARS[ly - 1949]) <= k) {
|
||||
if (hasLeapMonth(LUNAR_YEARS[ly - 1949]) < k) {
|
||||
lm = k
|
||||
} else if (hasLeapMonth(LUNAR_YEARS[ly - 1949]) === k) {
|
||||
lm = '闰' + k
|
||||
} else {
|
||||
lm = k + 1
|
||||
}
|
||||
} else {
|
||||
lm = k + 1
|
||||
}
|
||||
// 获取农历月份确定后的剩余天数
|
||||
daySpan += lunarYearMonths(LUNAR_YEARS[ly - 1949])[k]
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// 确定输出农历哪一天
|
||||
ld = daySpan
|
||||
|
||||
// console.log(sm, sd, ly, lm, ld)
|
||||
// 将计算出来的农历月份转换成汉字月份,闰月需要在前面加上闰字
|
||||
if (hasLeapMonth(LUNAR_YEARS[ly - 1949]) && (typeof lm === 'string' && lm.indexOf('闰') > -1)) {
|
||||
lm = `闰${LUNAR_MONTH[/\d/.exec(lm) - 1]}`
|
||||
} else {
|
||||
lm = LUNAR_MONTH[lm - 1]
|
||||
}
|
||||
|
||||
// 将计算出来的农历年份转换为天干地支年
|
||||
ly = getTianGan(ly) + getDiZhi(ly)
|
||||
|
||||
if (ld < 1) {
|
||||
return ' '.repeat(4)
|
||||
}
|
||||
|
||||
if (ld === 1) {
|
||||
return lm + '月'
|
||||
}
|
||||
if (ld < 11) {
|
||||
return LUNAR_DAY[0] + LUNAR_DAY[ld]
|
||||
}
|
||||
|
||||
if (ld < 20) {
|
||||
return LUNAR_DAY[10] + LUNAR_DAY[ld - 10]
|
||||
}
|
||||
|
||||
if (ld === 20) {
|
||||
return LUNAR_DAY[2] + LUNAR_DAY[10]
|
||||
}
|
||||
|
||||
if (ld === 30) {
|
||||
return LUNAR_DAY[3] + LUNAR_DAY[10]
|
||||
}
|
||||
|
||||
return LUNAR_DAY[20] + LUNAR_DAY[ld - 20]
|
||||
}
|
||||
|
||||
// 计算农历年是否有闰月,参数为存储农历年的16进制
|
||||
// 农历年份信息用16进制存储,其中16进制的最后1位可以用于判断是否有闰月
|
||||
function hasLeapMonth(ly) {
|
||||
// 获取16进制的最后1位,需要用到&与运算符
|
||||
if (ly & 0xf) {
|
||||
return ly & 0xf
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// 如果有闰月,计算农历闰月天数,参数为存储农历年的16进制
|
||||
// 农历年份信息用16进制存储,其中16进制的第1位(0x除外)可以用于表示闰月是大月还是小月
|
||||
function leapMonthDays(ly) {
|
||||
if (hasLeapMonth(ly)) {
|
||||
// 获取16进制的第1位(0x除外)
|
||||
return ly & 0xf0000 ? 30 : 29
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
// 计算农历一年的总天数,参数为存储农历年的16进制
|
||||
// 农历年份信息用16进制存储,其中16进制的第2-4位(0x除外)可以用于表示正常月是大月还是小月
|
||||
function lunarYearDays(ly) {
|
||||
let totalDays = 0
|
||||
|
||||
// 获取正常月的天数,并累加
|
||||
// 获取16进制的第2-4位,需要用到>>移位运算符
|
||||
for (let i = 0x8000; i > 0x8; i >>= 1) {
|
||||
let monthDays = ly & i ? 30 : 29
|
||||
totalDays += monthDays
|
||||
}
|
||||
// 如果有闰月,需要把闰月的天数加上
|
||||
if (hasLeapMonth(ly)) {
|
||||
totalDays += leapMonthDays(ly)
|
||||
}
|
||||
|
||||
return totalDays
|
||||
}
|
||||
|
||||
// 获取农历每个月的天数
|
||||
// 参数需传入16进制数值
|
||||
function lunarYearMonths(ly) {
|
||||
let monthArr = []
|
||||
|
||||
// 获取正常月的天数,并添加到monthArr数组中
|
||||
// 获取16进制的第2-4位,需要用到>>移位运算符
|
||||
for (let i = 0x8000; i > 0x8; i >>= 1) {
|
||||
monthArr.push(ly & i ? 30 : 29)
|
||||
}
|
||||
// 如果有闰月,需要把闰月的天数加上
|
||||
if (hasLeapMonth(ly)) {
|
||||
monthArr.splice(hasLeapMonth(ly), 0, leapMonthDays(ly))
|
||||
}
|
||||
|
||||
return monthArr
|
||||
}
|
||||
|
||||
// 将农历年转换为天干,参数为农历年
|
||||
function getTianGan(ly) {
|
||||
let tianGanKey = (ly - 3) % 10
|
||||
if (tianGanKey === 0) tianGanKey = 10
|
||||
return HEAVENLY_STEMS[tianGanKey - 1]
|
||||
}
|
||||
|
||||
// 将农历年转换为地支,参数为农历年
|
||||
function getDiZhi(ly) {
|
||||
let diZhiKey = (ly - 3) % 12
|
||||
if (diZhiKey === 0) diZhiKey = 12
|
||||
return EARTHLY_BRANCHES[diZhiKey - 1]
|
||||
}
|
|
@ -1,15 +1,14 @@
|
|||
{
|
||||
"name": "bash-calendar",
|
||||
"description": "终端版万年历",
|
||||
"version": "0.0.1",
|
||||
"type": "module",
|
||||
"version": "1.0.0",
|
||||
"author": "yutent <yutent.io@gmail.com>",
|
||||
"bin": {
|
||||
"calendar": "index.js",
|
||||
"cal": "index.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"chalk": "^4.0.0"
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
*/
|
||||
|
||||
import chalk from 'chalk'
|
||||
import { sloar2lunar } from './lunar.js'
|
||||
import { solar2lunar, getHSEBYear } from './lunar/index.js'
|
||||
|
||||
const CAL_HEAD = ['日', '一', '二', '三', '四', '五', '六'].map((s, i) => {
|
||||
s = '星期' + s
|
||||
|
@ -63,13 +63,15 @@ export function getCalendarTable(year, month) {
|
|||
}
|
||||
if (i > 0) {
|
||||
let week = getFirstDay(year, month, i)
|
||||
let lunar = solar2lunar(year, month, i)
|
||||
tmp.weekend = week === 0 || week === 6
|
||||
tmp.picked = !!isPicked({ year, month, day: i }, today)
|
||||
tmp.lunar = sloar2lunar(year, month, i)
|
||||
tmp.lunar = lunar.short
|
||||
tmp.highlight = !!lunar.festival
|
||||
} else {
|
||||
// 从上个月中补齐第1周
|
||||
tmp.grey = 1
|
||||
tmp.lunar = sloar2lunar(year, month - 1, lnums - -i)
|
||||
tmp.lunar = solar2lunar(year, month - 1, lnums + i).short
|
||||
}
|
||||
list.push(tmp)
|
||||
}
|
||||
|
@ -81,7 +83,7 @@ export function getCalendarTable(year, month) {
|
|||
for (let day = 1; day <= nd; day++) {
|
||||
list.push({
|
||||
day: (day + '').padStart(2, '0'),
|
||||
lunar: sloar2lunar(year, month + 1, day),
|
||||
lunar: solar2lunar(year, month + 1, day).short,
|
||||
grey: 1
|
||||
})
|
||||
}
|
||||
|
@ -90,7 +92,7 @@ export function getCalendarTable(year, month) {
|
|||
|
||||
// 画表头
|
||||
function drawThead(year, month) {
|
||||
var dateStr = `${year}年${month + 1}月`
|
||||
var dateStr = `${year}年${month + 1}月${' '.repeat(10)}${getHSEBYear(year, month)}`
|
||||
|
||||
dateStr =
|
||||
chalk.grey('| ') + chalk.cyan(dateStr) + ' '.repeat(75 - dateStr.length - 2) + chalk.grey('|')
|
||||
|
@ -155,9 +157,12 @@ function drawTbody(year, month) {
|
|||
if (tmp.picked) {
|
||||
tr += chalk.bgRed.white.bold(' '.repeat(3) + tmp.lunar + ' '.repeat(3)) + VLINE
|
||||
} else {
|
||||
tmp.lunar = chalk.grey(tmp.lunar)
|
||||
|
||||
tr += ' '.repeat(3) + tmp.lunar + ' '.repeat(3) + VLINE
|
||||
let pad = 5
|
||||
if (tmp.lunar) {
|
||||
pad = (10 - tmp.lunar.length * 2) / 2
|
||||
tmp.lunar = tmp.highlight ? chalk.cyan.dim(tmp.lunar) : chalk.grey(tmp.lunar)
|
||||
}
|
||||
tr += ' '.repeat(pad) + tmp.lunar + ' '.repeat(pad) + VLINE
|
||||
}
|
||||
break
|
||||
}
|
|
@ -0,0 +1,129 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* {终端版万年历}
|
||||
* @author yutent<yutent.io@gmail.com>
|
||||
* @date 2021/11/26 17:20:02
|
||||
*/
|
||||
|
||||
import chalk from 'chalk'
|
||||
import { getThisYearMonth, drawCalendar } from './calendar.js'
|
||||
|
||||
var version = process.env.APP_VERSION
|
||||
var argvs = process.argv.slice(2)
|
||||
var action = argvs.shift()
|
||||
var [year, month] = getThisYearMonth()
|
||||
|
||||
function drawOneYear(y) {
|
||||
for (let i = 0; i < 12; i++) {
|
||||
drawCalendar(y, i)
|
||||
}
|
||||
}
|
||||
|
||||
function print(...args) {
|
||||
args[0] = args[0].padEnd(20, ' ')
|
||||
if (args.length > 1) {
|
||||
args.splice(1, 0, ' - ')
|
||||
}
|
||||
console.log.apply(null, args)
|
||||
}
|
||||
|
||||
function print_help() {
|
||||
print('='.repeat(64))
|
||||
print(`终端版万年历 v${version}, 作者: 宇天`)
|
||||
print('='.repeat(64))
|
||||
print('用法: cal [command] args...')
|
||||
print('Commands:')
|
||||
print(' -y {year}', '打印指定年份的日历')
|
||||
print(' -m', '打印指定月份的日历')
|
||||
print(' -h', '查看帮助文档')
|
||||
print(' -v', '查看程序的版本\n')
|
||||
print('示例: ')
|
||||
print(' cal ' + chalk.grey('# 不带参数打印当前年月'))
|
||||
print(' cal -y ' + chalk.grey('# -y 不接参数, 打印当前年的所有月份'))
|
||||
print(' cal -y 2000 ' + chalk.grey('# 打印指定年份的所有月份'))
|
||||
print(' cal -y 2021 5 ' + chalk.grey('# 打印指定年份, 指定月份'))
|
||||
print(' cal -y 2000 -m 3 ' + chalk.grey('# 同上'))
|
||||
print(' cal -m 5 ' + chalk.grey('# 打印当前年份的 指定月份'))
|
||||
process.exit()
|
||||
}
|
||||
|
||||
switch (action) {
|
||||
case '-y':
|
||||
switch (argvs.length) {
|
||||
// 再无其他参数, 由打印当前年份所有的日历
|
||||
case 0:
|
||||
drawOneYear(year)
|
||||
break
|
||||
|
||||
// 有1~2个参数, cal -y 2020 2, cal -y 2020 5
|
||||
case 1:
|
||||
case 2:
|
||||
year = +argvs.shift()
|
||||
month = +argvs.shift()
|
||||
|
||||
if (year === year) {
|
||||
if (month < 13 && month > 0) {
|
||||
drawCalendar(year, month - 1)
|
||||
} else {
|
||||
drawOneYear(year)
|
||||
}
|
||||
} else {
|
||||
console.log('-y 参数异常')
|
||||
}
|
||||
break
|
||||
|
||||
// 3个参数 cal -y 2020 -m 1
|
||||
case 3:
|
||||
action = argvs.shift()
|
||||
month = +argvs.shift()
|
||||
if (action === '-m' && month < 13 && month > 0) {
|
||||
drawCalendar(year, month - 1)
|
||||
} else {
|
||||
console.log('-m 参数异常')
|
||||
}
|
||||
break
|
||||
default:
|
||||
console.log('-y 参数异常')
|
||||
break
|
||||
}
|
||||
|
||||
break
|
||||
|
||||
case '-m':
|
||||
month = +argvs.shift()
|
||||
if (month < 13 && month > 0) {
|
||||
drawCalendar(year, month - 1)
|
||||
} else {
|
||||
console.log('-m 参数异常')
|
||||
}
|
||||
break
|
||||
|
||||
case '-v':
|
||||
print(version)
|
||||
break
|
||||
|
||||
case '-h':
|
||||
print_help()
|
||||
break
|
||||
|
||||
default:
|
||||
if (action) {
|
||||
year = +action
|
||||
month = +argvs.shift()
|
||||
if (year === year) {
|
||||
if (month < 13 && month > 0) {
|
||||
drawCalendar(year, month - 1)
|
||||
} else {
|
||||
drawOneYear(year)
|
||||
}
|
||||
} else {
|
||||
console.log('参数异常')
|
||||
}
|
||||
} else {
|
||||
drawCalendar(year, month)
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
process.exit()
|
|
@ -0,0 +1,303 @@
|
|||
// 农历1900-2100年查询表
|
||||
export const LUNAR_YEARS = [
|
||||
0x04bd8, // 1900
|
||||
0x04ae0,
|
||||
0x0a570,
|
||||
0x054d5,
|
||||
0x0d260,
|
||||
0x0d950,
|
||||
0x16554,
|
||||
0x056a0,
|
||||
0x09ad0,
|
||||
0x055d2, //1909
|
||||
0x04ae0,
|
||||
0x0a5b6,
|
||||
0x0a4d0,
|
||||
0x0d250,
|
||||
0x1d255,
|
||||
0x0b540,
|
||||
0x0d6a0,
|
||||
0x0ada2,
|
||||
0x095b0,
|
||||
0x14977, //1919
|
||||
0x04970,
|
||||
0x0a4b0,
|
||||
0x0b4b5,
|
||||
0x06a50,
|
||||
0x06d40,
|
||||
0x1ab54,
|
||||
0x02b60,
|
||||
0x09570,
|
||||
0x052f2,
|
||||
0x04970, //1929
|
||||
0x06566,
|
||||
0x0d4a0,
|
||||
0x0ea50,
|
||||
0x16a95,
|
||||
0x05ad0,
|
||||
0x02b60,
|
||||
0x186e3,
|
||||
0x092e0,
|
||||
0x1c8d7,
|
||||
0x0c950, //1939
|
||||
0x0d4a0,
|
||||
0x1d8a6,
|
||||
0x0b550,
|
||||
0x056a0,
|
||||
0x1a5b4,
|
||||
0x025d0,
|
||||
0x092d0,
|
||||
0x0d2b2,
|
||||
0x0a950,
|
||||
0x0b557, //1949
|
||||
0x06ca0,
|
||||
0x0b550,
|
||||
0x15355,
|
||||
0x04da0,
|
||||
0x0a5b0,
|
||||
0x14573,
|
||||
0x052b0,
|
||||
0x0a9a8,
|
||||
0x0e950,
|
||||
0x06aa0, //1959
|
||||
0x0aea6,
|
||||
0x0ab50,
|
||||
0x04b60,
|
||||
0x0aae4,
|
||||
0x0a570,
|
||||
0x05260,
|
||||
0x0f263,
|
||||
0x0d950,
|
||||
0x05b57,
|
||||
0x056a0, //1969
|
||||
0x096d0,
|
||||
0x04dd5,
|
||||
0x04ad0,
|
||||
0x0a4d0,
|
||||
0x0d4d4,
|
||||
0x0d250,
|
||||
0x0d558,
|
||||
0x0b540,
|
||||
0x0b6a0,
|
||||
0x195a6, //1979
|
||||
0x095b0,
|
||||
0x049b0,
|
||||
0x0a974,
|
||||
0x0a4b0,
|
||||
0x0b27a,
|
||||
0x06a50,
|
||||
0x06d40,
|
||||
0x0af46,
|
||||
0x0ab60,
|
||||
0x09570, //1989
|
||||
0x04af5,
|
||||
0x04970,
|
||||
0x064b0,
|
||||
0x074a3,
|
||||
0x0ea50,
|
||||
0x06b58,
|
||||
0x05ac0,
|
||||
0x0ab60,
|
||||
0x096d5,
|
||||
0x092e0, //1999
|
||||
0x0c960,
|
||||
0x0d954,
|
||||
0x0d4a0,
|
||||
0x0da50,
|
||||
0x07552,
|
||||
0x056a0,
|
||||
0x0abb7,
|
||||
0x025d0,
|
||||
0x092d0,
|
||||
0x0cab5, //2009
|
||||
0x0a950,
|
||||
0x0b4a0,
|
||||
0x0baa4,
|
||||
0x0ad50,
|
||||
0x055d9,
|
||||
0x04ba0,
|
||||
0x0a5b0,
|
||||
0x15176,
|
||||
0x052b0,
|
||||
0x0a930, //2019
|
||||
0x07954,
|
||||
0x06aa0,
|
||||
0x0ad50,
|
||||
0x05b52,
|
||||
0x04b60,
|
||||
0x0a6e6,
|
||||
0x0a4e0,
|
||||
0x0d260,
|
||||
0x0ea65,
|
||||
0x0d530, //2029
|
||||
0x05aa0,
|
||||
0x076a3,
|
||||
0x096d0,
|
||||
0x04afb,
|
||||
0x04ad0,
|
||||
0x0a4d0,
|
||||
0x1d0b6,
|
||||
0x0d250,
|
||||
0x0d520,
|
||||
0x0dd45, //2039
|
||||
0x0b5a0,
|
||||
0x056d0,
|
||||
0x055b2,
|
||||
0x049b0,
|
||||
0x0a577,
|
||||
0x0a4b0,
|
||||
0x0aa50,
|
||||
0x1b255,
|
||||
0x06d20,
|
||||
0x0ada0, //2049
|
||||
0x14b63,
|
||||
0x09370,
|
||||
0x049f8,
|
||||
0x04970,
|
||||
0x064b0,
|
||||
0x168a6,
|
||||
0x0ea50,
|
||||
0x06b20,
|
||||
0x1a6c4,
|
||||
0x0aae0, //2059
|
||||
0x092e0,
|
||||
0x0d2e3,
|
||||
0x0c960,
|
||||
0x0d557,
|
||||
0x0d4a0,
|
||||
0x0da50,
|
||||
0x05d55,
|
||||
0x056a0,
|
||||
0x0a6d0,
|
||||
0x055d4, //2069
|
||||
0x052d0,
|
||||
0x0a9b8,
|
||||
0x0a950,
|
||||
0x0b4a0,
|
||||
0x0b6a6,
|
||||
0x0ad50,
|
||||
0x055a0,
|
||||
0x0aba4,
|
||||
0x0a5b0,
|
||||
0x052b0, //2079
|
||||
0x0b273,
|
||||
0x06930,
|
||||
0x07337,
|
||||
0x06aa0,
|
||||
0x0ad50,
|
||||
0x14b55,
|
||||
0x04b60,
|
||||
0x0a570,
|
||||
0x054e4,
|
||||
0x0d160, //2089
|
||||
0x0e968,
|
||||
0x0d520,
|
||||
0x0daa0,
|
||||
0x16aa6,
|
||||
0x056d0,
|
||||
0x04ae0,
|
||||
0x0a9d4,
|
||||
0x0a2d0,
|
||||
0x0d150,
|
||||
0x0f252, //2099
|
||||
0x0d520 // 2100
|
||||
]
|
||||
|
||||
export const LUNAR_MONTH = ['正', '二', '三', '四', '五', '六', '七', '八', '九', '十', '冬', '腊']
|
||||
export const LUNAR_DAY = {
|
||||
0: '初',
|
||||
1: '一',
|
||||
2: '二',
|
||||
3: '三',
|
||||
4: '四',
|
||||
5: '五',
|
||||
6: '六',
|
||||
7: '七',
|
||||
8: '八',
|
||||
9: '九',
|
||||
10: '十',
|
||||
20: '廿'
|
||||
}
|
||||
// 生肖、天干、地支, 节气
|
||||
export const ZODIAC = ['鼠', '牛', '虎', '兔', '龙', '蛇', '马', '羊', '猴', '鸡', '狗', '猪']
|
||||
export const HEAVENLY_STEMS = ['甲', '乙', '丙', '丁', '戊', '己', '庚', '辛', '壬', '癸']
|
||||
export const EARTHLY_BRANCHES = [
|
||||
'子',
|
||||
'丑',
|
||||
'寅',
|
||||
'卯',
|
||||
'辰',
|
||||
'巳',
|
||||
'午',
|
||||
'未',
|
||||
'申',
|
||||
'酉',
|
||||
'戌',
|
||||
'亥'
|
||||
]
|
||||
|
||||
// 24节气表和C值
|
||||
export const SOLAR_TERMS = [
|
||||
'小寒',
|
||||
'大寒',
|
||||
'立春',
|
||||
'雨水',
|
||||
'惊蛰',
|
||||
'春分',
|
||||
'清明',
|
||||
'谷雨',
|
||||
'立夏',
|
||||
'小满',
|
||||
'芒种',
|
||||
'夏至',
|
||||
'小暑',
|
||||
'大暑',
|
||||
'立秋',
|
||||
'处暑',
|
||||
'白露',
|
||||
'秋分',
|
||||
'寒露',
|
||||
'霜降',
|
||||
'立冬',
|
||||
'小雪',
|
||||
'大雪',
|
||||
'冬至'
|
||||
]
|
||||
|
||||
// 农历节日(仅为常规节日, 地方节日、教派节日未收录)
|
||||
export const FESTIVALS = {
|
||||
'1.1': '春节',
|
||||
'1.15': '元宵节',
|
||||
'2.2': '龙抬头',
|
||||
'3.3': '上巳节',
|
||||
'5.5': '端午节',
|
||||
'7.7': '七夕节',
|
||||
'7.15': '中元节',
|
||||
'8.15': '中秋节',
|
||||
'9.9': '重阳节',
|
||||
'10.1': '寒衣节',
|
||||
'10.15': '下元节',
|
||||
'12.8': '腊八节',
|
||||
'12.23': '北方小年',
|
||||
'12.24': '南方小年',
|
||||
'12.30': '除夕' // 不一定有年三十, 计算时会修正
|
||||
}
|
||||
|
||||
// 公历节日(不全, 仅国内常用的)
|
||||
export const SOLAR_FESTIVALS = {
|
||||
'1.1': '元旦节',
|
||||
'2.14': '情人节',
|
||||
'3.8': '妇女节',
|
||||
'3.12': '植树节',
|
||||
'4.1': '愚人节',
|
||||
'5.1': '劳动节',
|
||||
'5.4': '青年节',
|
||||
'5.12': '护士节',
|
||||
'6.1': '儿童节',
|
||||
'7.1': '建党节',
|
||||
'8.1': '建军节',
|
||||
'9.10': '教师节',
|
||||
'10.1': '国庆节',
|
||||
'12.24': '平安夜',
|
||||
'12.25': '圣诞节'
|
||||
}
|
|
@ -0,0 +1,175 @@
|
|||
/**
|
||||
* {农历转换算法}
|
||||
* @author yutent<yutent.io@gmail.com>
|
||||
* @date 2021/11/30 13:31:34
|
||||
*/
|
||||
|
||||
import {
|
||||
LUNAR_YEARS,
|
||||
LUNAR_MONTH,
|
||||
LUNAR_DAY,
|
||||
HEAVENLY_STEMS,
|
||||
EARTHLY_BRANCHES,
|
||||
ZODIAC,
|
||||
FESTIVALS,
|
||||
SOLAR_FESTIVALS
|
||||
} from './config.js'
|
||||
|
||||
/**
|
||||
* 公历转农历函数
|
||||
* 传入公历{年月日}, 返回农历信息, 范围支持 1901/01/01 ~ 2100/12/31
|
||||
*/
|
||||
export function solar2lunar(year = 1901, month = 0, day = 1) {
|
||||
var baseDate = Date.UTC(1900, 0, 31) // 公历基准(1900年春节)
|
||||
var timestamp = Date.UTC(year, month, day) // 传入日期的时间戳
|
||||
var offset = (timestamp - baseDate) / (24 * 60 * 60 * 1000) + 1 // 计算与的相差天数, 有1天的修正
|
||||
var months, leap
|
||||
var result = { short: '' }
|
||||
|
||||
if (year < 1901 || year > 2100) {
|
||||
return result
|
||||
}
|
||||
|
||||
// 计算给出的公历对应的农历年份
|
||||
for (let y = 1900; y <= 2100; y++) {
|
||||
let days = getLunarYearDays(y)
|
||||
offset -= days
|
||||
|
||||
// 确定之后, 得出农历天数(距离正月初一)
|
||||
if (offset <= 0) {
|
||||
result.year = y
|
||||
offset += days
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// 获取当年的农历月份天数
|
||||
months = getLunarMonthsDays(result.year)
|
||||
leap = getLeapMonth(result.year)
|
||||
|
||||
// 计算农历月份
|
||||
for (let m = 0; m < months.length; m++) {
|
||||
offset -= months[m] // 一个一个月的天数相减,直到小于0
|
||||
if (offset <= 0) {
|
||||
result.month = m
|
||||
result.day = offset + months[m] // 补回天数
|
||||
|
||||
// 有闰月, 且当前月份大于等于闰月, 那得到的月份要减1
|
||||
if (leap > 0 && m >= leap) {
|
||||
result.leap = m === leap
|
||||
result.month -= 1
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// 公历节日
|
||||
result.festival = SOLAR_FESTIVALS[`${month + 1}.${day}`]
|
||||
|
||||
// 非闰月才有农历节日
|
||||
if (!result.leap) {
|
||||
// 修正没有年三十的除夕
|
||||
if (result.month === 11 && result.day === months.pop()) {
|
||||
result.festival = FESTIVALS['12.30']
|
||||
} else {
|
||||
result.festival = FESTIVALS[`${result.month + 1}.${result.day}`] || result.festival
|
||||
}
|
||||
}
|
||||
|
||||
result.yearCN = getHSEBYear(result.year)
|
||||
result.monthCN = (result.leap > 0 ? '闰' : '') + LUNAR_MONTH[result.month] + '月'
|
||||
|
||||
if (result.day < 11) {
|
||||
result.dayCN = LUNAR_DAY[0] + LUNAR_DAY[result.day]
|
||||
} else if (result.day < 20) {
|
||||
result.dayCN = LUNAR_DAY[10] + LUNAR_DAY[result.day - 10]
|
||||
} else if (result.day === 20) {
|
||||
result.dayCN = LUNAR_DAY[2] + LUNAR_DAY[10]
|
||||
} else if (result.day < 30) {
|
||||
result.dayCN = LUNAR_DAY[20] + LUNAR_DAY[result.day - 20]
|
||||
} else if (result.day === 30) {
|
||||
result.dayCN = LUNAR_DAY[3] + LUNAR_DAY[10]
|
||||
}
|
||||
|
||||
result.short = result.festival
|
||||
? result.festival
|
||||
: result.day === 1
|
||||
? result.monthCN
|
||||
: result.dayCN
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定年份的农历天数
|
||||
* @param year {Number} 1901 ~ 2100
|
||||
* @return {Number}
|
||||
*/
|
||||
function getLunarYearDays(year) {
|
||||
var months = getLunarMonthsDays(year)
|
||||
return months.reduce((sum, n) => (sum += n), 0)
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断指定年份是否有闰月
|
||||
* 16进制最后一位表示闰月的月份 (0-12), 0表示无闰月
|
||||
* @param year {Number} 1901 - 2100
|
||||
* @return {Number} 0-12
|
||||
*/
|
||||
function getLeapMonth(year) {
|
||||
var hexYear = LUNAR_YEARS[year - 1900] // 转16进制年份
|
||||
return hexYear & 0xf
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取闰月的天数
|
||||
* 16进制年份的第1位表示闰月是大小月
|
||||
* @param year {Number} 1901 - 2100
|
||||
* @return {Number}
|
||||
*/
|
||||
function getLeapMonthDays(year) {
|
||||
var hexYear = LUNAR_YEARS[year - 1900] // 转16进制年份
|
||||
var month = getLeapMonth(year)
|
||||
if (month > 0) {
|
||||
return hexYear & 0xf0000 ? 30 : 29
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定年份的所有月份天数
|
||||
* @param year {Number} 1901 - 2100
|
||||
* @return {Array}
|
||||
*/
|
||||
function getLunarMonthsDays(year) {
|
||||
var hexYear = LUNAR_YEARS[year - 1900] // 转16进制年份
|
||||
var leap = getLeapMonth(year)
|
||||
var leapDays = getLeapMonthDays(year)
|
||||
var months = []
|
||||
|
||||
// 16进制年份的2-4位用于表示大小月
|
||||
for (let i = 0x8000; i > 0x8; i >>= 1) {
|
||||
months.push(hexYear & i ? 30 : 29)
|
||||
}
|
||||
|
||||
if (leap > 0) {
|
||||
months.splice(leap, 0, leapDays)
|
||||
}
|
||||
|
||||
return months
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定年份的天干地支生肖
|
||||
* @param year {Number} 1901 - 2100
|
||||
* @return {String}
|
||||
*/
|
||||
export function getHSEBYear(year) {
|
||||
var hy = (year - 3) % 10
|
||||
var eb = (year - 3) % 12
|
||||
|
||||
hy = hy === 0 ? 10 : hy
|
||||
eb = eb === 0 ? 12 : eb
|
||||
|
||||
return HEAVENLY_STEMS[hy - 1] + EARTHLY_BRANCHES[eb - 1] + ZODIAC[(year - 4) % 12] + '年'
|
||||
}
|
Loading…
Reference in New Issue