lunisolar
Version:
专业农历库,支持公历阴历互转,支持各类黄历数据查询,如八字四柱、阴历、神煞宜忌、时辰吉凶、建除十二神、胎神占方、五行纳音等。支持自定义插件。
185 lines (176 loc) • 5.52 kB
text/typescript
import { UNITS } from '../constants'
import { LUNAR_MONTH_DATAS, FIRST_YEAR } from '../constants/lunarData'
import { parseDate, prettyUnit } from './index'
/**
* 計算兩日期的時間差
* @param date1 起始日期
* @param date2 結束日期
* @param unit 單位
* @param float 是否返回小數
* @returns {nnumber}
*/
export function dateDiff(
date1: DateParamType,
date2: DateParamType,
unit?: GreUnit,
float?: boolean
): number {
;[date1, date2] = [parseDate(date1), parseDate(date2)]
const diffValue = date2.valueOf() - date1.valueOf()
unit = (unit ? prettyUnit(unit) : 'millisecond') as GreUnitFullName
let res = diffValue
if (UNITS.s === unit) {
res = diffValue / 1000
} else if (UNITS.m === unit) {
res = diffValue / (1000 * 60)
} else if (UNITS.h === unit) {
res = diffValue / (1000 * 60 * 60)
} else if (UNITS.d === unit) {
res = diffValue / (1000 * 60 * 60 * 24)
} else if (UNITS.w === unit) {
res = diffValue / (1000 * 60 * 60 * 24 * 7)
} else if (UNITS.M === unit) {
res = monthDiff(date1, date2)
} else if (UNITS.y === unit) {
res = monthDiff(date1, date2) / 12
} else if (UNITS.q === unit) {
res = monthDiff(date1, date2) / 3
}
return float ? res : parseInt(String(res))
}
/**
* 月差
* @param date1 日期1
* @param date2 日期2
* @returns {number}
*/
export const monthDiff = (date1: DateParamType, date2: DateParamType): number => {
;[date1, date2] = [parseDate(date1), parseDate(date2)]
const yearDiff = date2.getFullYear() - date1.getFullYear()
const monthDiff = date2.getMonth() - date1.getMonth()
const diffValue = yearDiff * 12 + monthDiff // 取得月差
// 下边计算小数部分
const anchor = new Date(date1).setMonth(date1.getMonth() + diffValue)
const c = anchor.valueOf() > date2.valueOf()
const anchor2 = new Date(date1).setMonth(date1.getMonth() + diffValue + (c ? -1 : 1))
return (
diffValue + (date2.valueOf() - anchor.valueOf()) / (c ? anchor - anchor2 : anchor2 - anchor) ||
0
)
}
/**
* 計算陰歷的時間差
* @param lsr1 起始日
* @param lsr2 結束日
* @returns {number}
*/
export const lunarDateDiff = (
lsr1: lunisolar.Lunisolar,
lsr2: lunisolar.Lunisolar,
unit?: LunarUnit,
float?: boolean
): number => {
const [lunar1, lunar2] = [lsr1.lunar, lsr2.lunar]
const [year1, year2] = [lunar1.year, lunar2.year]
let diff = lsr2.valueOf() - lsr1.valueOf()
unit = prettyUnit(unit) as LunarUnitFullNameLower
if (unit === UNITS.ly) {
const diff = year2 - year1
return float ? diff - 1 + getYearDecimals(lsr1, true) + getYearDecimals(lsr2, false) : diff
} else if (unit === UNITS.lM) {
return lunarMonthDiff(lsr1, lsr2, float)
} else if (unit === UNITS.ld) {
diff = diff / (1000 * 60 * 60 * 24)
} else if (unit === UNITS.lh) {
diff = diff / (1000 * 60 * 60 * 2)
}
return float ? diff : Math.ceil(diff)
}
/**
* 計算陰歷的月差
* @param lsr1 起始日
* @param lsr2 結束日
* @returns {number}
*/
export const lunarMonthDiff = (
lsr1: lunisolar.Lunisolar,
lsr2: lunisolar.Lunisolar,
float?: boolean
): number => {
if (lsr1 > lsr2) return -lunarMonthDiff(lsr2, lsr1)
const [lunar1, lunar2] = [lsr1.lunar, lsr2.lunar]
const [year1, year2] = [lunar1.year, lunar2.year]
const [month1, month2] = [lunar1.month, lunar2.month]
let currYear = year1
let cnt = 0
while (currYear <= year2) {
let [start, end] = [1, 12]
if (currYear === year1) start = month1
if (currYear === year2) end = month2
cnt += countLunarMonthInYear(currYear, start, end)
currYear++
}
if (!float) return cnt - 1
// 計算小數部分
if (cnt > 0) {
cnt += getMonthDecimals(lsr1, true) + getMonthDecimals(lsr2, false) - 2
} else {
const monthLen = lunar1.isBigMonth ? 30 : 29
cnt = (lsr2.valueOf() - lsr1.valueOf()) / (1000 * 60 * 60 * 24 * monthLen)
}
return cnt
}
/**
* 計算該年有多少個月
*/
export const countLunarMonthInYear = (year: number, start?: number, end?: number): number => {
const monthData = LUNAR_MONTH_DATAS[year - FIRST_YEAR]
LUNAR_MONTH_DATAS
start = start || 1
end = end || 12
let addLeap = false
if (start > 100) {
start -= 100
addLeap = true
}
if (end > 100) {
end -= 100
addLeap = true
}
const leapMonth = monthData >> 13
if (start <= leapMonth && leapMonth <= end) addLeap = true
return end - start + 1 + (addLeap ? 1 : 0)
}
/**
* 用于計算陰歷月差的小數部分
* @param lsr 日期
* @param isAfterPath 是否后半部分
* @returns {number}
*/
export const getMonthDecimals = (
lsr: lunisolar.Lunisolar,
isAfterPath: boolean = false
): number => {
const monthDayLen = lsr.lunar.isBigMonth ? 30 : 29
const day = lsr.lunar.day
return isAfterPath ? 1 - day / monthDayLen : day / monthDayLen
}
/**
* 用于計算陰歷年差的小數部分
* @param lsr 日期
* @param isAfterPath 是否后半部分
* @returns {number}
*/
export const getYearDecimals = (lsr: lunisolar.Lunisolar, isAfterPath: boolean = false): number => {
const leapMonth = lsr.lunar.leapMonth
const yearMonthLen = leapMonth > 0 ? 13 : 12
let isLeapMonth = false
let month = lsr.lunar.month
if (month > 100) {
month -= 100
isLeapMonth = true
}
if (leapMonth > 0 && (month > leapMonth || (month === leapMonth && isLeapMonth))) month++
const md = getMonthDecimals(lsr, isAfterPath)
return isAfterPath ? 1 - (month - md) / yearMonthLen : (month + md - 1) / yearMonthLen
}