lunisolar
Version:
专业农历库,支持公历阴历互转,支持各类黄历数据查询,如八字四柱、阴历、神煞宜忌、时辰吉凶、建除十二神、胎神占方、五行纳音等。支持自定义插件。
267 lines (229 loc) • 7.31 kB
text/typescript
import { LUNAR_UNITS_SET } from '../constants'
import {
parseDate,
prettyUnit,
computeSBMonthValueByTerm,
getTranslation,
computeUtcOffset,
getDateData
} from '../utils'
import { dateDiff, lunarDateDiff } from '../utils/dateDiff'
import { dateAdd } from '../utils/dateAdd'
import { format } from '../utils/format'
import { Lunar } from './lunar'
import { SolarTerm } from './solarTerm'
import { Char8 } from './char8'
import { FIRST_YEAR, LAST_YEAR } from '../constants/lunarData'
import { _GlobalConfig } from '../config'
import { SB } from './stemBranch'
import lunisolarFac from '../index'
import { cache } from '../utils/decorators'
import { CacheClass } from './CacheClass'
import { Markers } from './markers'
export class Lunisolar extends CacheClass {
readonly _config: LunisolarConfigData
readonly _date: Date
readonly _offset: number
constructor(date?: DateParamType, config?: lunisolar.ConfigType) {
super()
this._config = Object.assign({ extra: {} }, _GlobalConfig, config)
const { isUTC, offset } = this._config
const _date = parseDate(date, isUTC)
if (offset !== 0) {
_date.setMinutes(_date.getMinutes() + offset)
}
const localTimezoneOffset = -1 * parseDate(date).getTimezoneOffset()
this._config.extra.localTimezoneOffset = localTimezoneOffset
this._date = _date
this._offset = offset
}
get lunisolar(): typeof lunisolar {
return lunisolarFac
}
get year(): number {
return getDateData(this._date, 'FullYear', this.isUTC())
}
get month(): number {
return getDateData(this._date, 'Month', this.isUTC()) + 1
}
get day(): number {
return getDateData(this._date, 'Date', this.isUTC())
}
get dayOfWeek(): number {
return getDateData(this._date, 'Day', this.isUTC())
}
get hour(): number {
return getDateData(this._date, 'Hours', this.isUTC())
}
get minute(): number {
return getDateData(this._date, 'Minutes', this.isUTC())
}
get second(): number {
return getDateData(this._date, 'Seconds', this.isUTC())
}
get millis(): number {
return getDateData(this._date, 'Milliseconds', this.isUTC())
}
get lunar(): Lunar {
return new Lunar(this._date, { lang: this._config.lang, isUTC: this.isUTC() })
}
// 八字
get char8(): Char8 {
const config = {
lang: this._config.lang,
changeAgeTerm: this._config.changeAgeTerm,
isUTC: this.isUTC(),
offset: this._offset
}
return new Char8(this._date, config)
}
// markers
get markers(): Markers {
return new Markers(this)
}
// 节气
get solarTerm(): SolarTerm | null {
const year = this.year
if (year < FIRST_YEAR || year > LAST_YEAR) {
throw new Error(`${year} is not in the allowed time range.`)
}
const month = this.month
const date = this.day
const [term1, term2] = SolarTerm.getMonthTerms(year, month)
const config = {
lang: this._config.lang
}
if (date === term1) return new SolarTerm((month - 1) * 2, config)
else if (date === term2) return new SolarTerm((month - 1) * 2 + 1, config)
else return null
}
/**
* 取得当前日期之前的最近的节气点
* @param nodeFlag 取的节气点,0: 取节, 1: 取气, 2: 节或气都取
*/
recentSolarTerm(nodeFlag: 0 | 1 | 2): [SolarTerm, Date] {
return SolarTerm.findNode<false>(this._date, {
lang: this._config.lang,
nodeFlag,
returnValue: false
})
}
/**
* 取得當前日期所在的月建或月將地支,
月建:子月從0開始,月將:子月月將日到丑月月將日為0,類推
* @param flag 為0時取月建,為1時取月將
*/
getMonthBuilder(flag: 0 | 1 = 0): [SB, lunisolar.SolarTerm, Date] {
const sbConfig = {
lang: this.getConfig('lang') as string
}
const [term, termDate] = this.recentSolarTerm(flag)
const sbValue = computeSBMonthValueByTerm(this.toDate(), term.value, termDate)
const sb = new SB(sbValue, undefined, sbConfig)
return [sb, term, termDate]
}
getSeasonIndex(): number {
const rst = this.recentSolarTerm(0)
const termVal = rst[0].value
if (2 <= termVal && termVal < 8) return 0
if (8 <= termVal && termVal < 14) return 1
if (14 <= termVal && termVal < 20) return 2
return 3
}
getSeason(isShortName: boolean = false): string {
const ssv = this.getSeasonIndex()
const locale = this.getLocale()
return isShortName && locale.seasonShortName
? locale.seasonShortName[ssv]
: locale.seasonName[ssv]
}
getLocale(lang?: string): LocaleData {
return _GlobalConfig.locales[lang ?? this._config.lang]
}
L(key: keyof LocaleData): LocaleData[typeof key]
L<T = any>(key: string): T | string {
const locale = this.getLocale()
return getTranslation<T, LocaleData>(locale, key)
}
getConfig(): LunisolarConfigData
getConfig(key: keyof LunisolarConfigData): LunisolarConfigData[typeof key]
getConfig(key?: keyof LunisolarConfigData): any {
if (typeof key === 'undefined') return this._config
if (typeof this._config[key]) return this._config[key]
return undefined
}
toDate(): Date {
return new Date(this.valueOf())
}
clone() {
return new Lunisolar(this.valueOf(), this._config)
}
unix() {
return Math.floor(this.valueOf() / 1000)
}
valueOf() {
return this._date.valueOf() - this._offset * 60 * 1000
}
local() {
const config = Object.assign({}, this._config, {
isUTC: false,
offset: 0
})
return new Lunisolar(this.toDate(), config)
}
utc(): Lunisolar {
return this.utcOffset(-this._offset)
}
isUTC() {
return this._config.isUTC
}
utcOffset(): number
utcOffset(utcOffset: number): Lunisolar
utcOffset(utcOffset?: number): number | Lunisolar {
if (utcOffset === void 0) {
if (this.isUTC()) return this._offset
return computeUtcOffset(this._date)
}
const config = Object.assign({}, this._config, {
isUTC: true,
offset: Math.abs(utcOffset) <= 16 ? utcOffset * 60 : utcOffset
})
return new Lunisolar(this._date, config)
}
toISOString() {
return this._date.toISOString()
}
toUTCString() {
return this._date.toUTCString()
}
toString() {
return this._date.toUTCString() + ` (${this.lunar})` + ` utcOffset: ${this.utcOffset()}`
}
format(formatStr: string): string {
return format(formatStr, this)
}
diff(date: DateParamType, unit?: Unit, float: boolean = false): number {
unit = (unit ? prettyUnit(unit) : 'millisecond') as UnitFullNameLower
if (LUNAR_UNITS_SET.has(unit)) {
// 如果是农历查询
return lunarDateDiff(
this,
date instanceof Lunisolar ? date : new Lunisolar(date, this._config),
unit as LunarUnit,
float
)
}
return dateDiff(this._date, date, unit as GreUnit, float)
}
add(value: number, unit?: DateAddUnit): Lunisolar {
const date = this.toDate()
const newDate = dateAdd(date, value, unit)
return new Lunisolar(newDate, this.getConfig())
}
}