UNPKG

lunar-typescript

Version:

lunar是一款无第三方依赖的公历(阳历)、农历(阴历、老黄历)、佛历和道历工具,支持星座、儒略日、干支、生肖、节气、节日、彭祖百忌、每日宜忌、吉神宜趋、凶煞宜忌、吉神(喜神/福神/财神/阳贵神/阴贵神)方位、胎神方位、冲煞、纳音、星宿、八字、五行、十神、建除十二值星、青龙名堂等十二神、黄道日及吉凶等。lunar is a calendar library for Solar and Chinese Lunar.

522 lines (521 loc) 14 kB
import { SolarUtil } from "./SolarUtil.mjs"; import { SolarWeek } from "./SolarWeek.mjs"; import { LunarUtil } from "./LunarUtil.mjs"; import { HolidayUtil } from "./HolidayUtil.mjs"; import { Lunar } from "./Lunar.mjs"; import { SolarMonth } from "./SolarMonth.mjs"; const _Solar = class { static fromYmd(year, month, day) { return _Solar.fromYmdHms(year, month, day, 0, 0, 0); } static fromYmdHms(year, month, day, hour, minute, second) { return new _Solar(year, month, day, hour, minute, second); } static fromDate(date) { return _Solar.fromYmdHms(date.getFullYear(), date.getMonth() + 1, date.getDate(), date.getHours(), date.getMinutes(), date.getSeconds()); } static fromJulianDay(julianDay) { let d = Math.floor(julianDay + 0.5); let f = julianDay + 0.5 - d; let c; if (d >= 2299161) { c = Math.floor((d - 186721625e-2) / 36524.25); d += 1 + c - Math.floor(c / 4); } d += 1524; let year = Math.floor((d - 122.1) / 365.25); d -= Math.floor(365.25 * year); let month = Math.floor(d / 30.601); d -= Math.floor(30.601 * month); let day = d; if (month > 13) { month -= 13; year -= 4715; } else { month -= 1; year -= 4716; } f *= 24; let hour = Math.floor(f); f -= hour; f *= 60; let minute = Math.floor(f); f -= minute; f *= 60; let second = Math.round(f); if (second > 59) { second -= 60; minute++; } if (minute > 59) { minute -= 60; hour++; } if (hour > 23) { hour -= 24; day += 1; } return _Solar.fromYmdHms(year, month, day, hour, minute, second); } static fromBaZi(yearGanZhi, monthGanZhi, dayGanZhi, timeGanZhi, sect = 2, baseYear = 1900) { sect = 1 == sect ? 1 : 2; const l = []; let m = LunarUtil.index(monthGanZhi.substring(1), LunarUtil.ZHI, -1) - 2; if (m < 0) { m += 12; } if (((LunarUtil.index(yearGanZhi.substring(0, 1), LunarUtil.GAN, -1) + 1) * 2 + m) % 10 !== LunarUtil.index(monthGanZhi.substring(0, 1), LunarUtil.GAN, -1)) { return l; } let y = LunarUtil.getJiaZiIndex(yearGanZhi) - 57; if (y < 0) { y += 60; } y++; m *= 2; let h = LunarUtil.index(timeGanZhi.substring(1), LunarUtil.ZHI, -1) * 2; let hours = [h]; if (0 == h && 2 == sect) { hours = [0, 23]; } const startYear = baseYear - 1; const endYear = (/* @__PURE__ */ new Date()).getFullYear(); while (y <= endYear) { if (y >= startYear) { const jieQiLunar = Lunar.fromYmd(y, 1, 1); const jieQiList = jieQiLunar.getJieQiList(); const jieQiTable = jieQiLunar.getJieQiTable(); let solarTime = jieQiTable[jieQiList[4 + m]]; if (solarTime.getYear() >= baseYear) { let d = LunarUtil.getJiaZiIndex(dayGanZhi) - LunarUtil.getJiaZiIndex(solarTime.getLunar().getDayInGanZhiExact2()); if (d < 0) { d += 60; } if (d > 0) { solarTime = solarTime.next(d); } hours.forEach((hour) => { let mi = 0; let s = 0; if (d == 0 && hour === solarTime.getHour()) { mi = solarTime.getMinute(); s = solarTime.getSecond(); } const solar = _Solar.fromYmdHms(solarTime.getYear(), solarTime.getMonth(), solarTime.getDay(), hour, mi, s); let lunar = solar.getLunar(); let dgz = 2 === sect ? lunar.getDayInGanZhiExact2() : lunar.getDayInGanZhiExact(); if (lunar.getYearInGanZhiExact() === yearGanZhi && lunar.getMonthInGanZhiExact() === monthGanZhi && dgz === dayGanZhi && lunar.getTimeInGanZhi() === timeGanZhi) { l.push(solar); } }); } } y += 60; } return l; } constructor(year, month, day, hour, minute, second) { if (1582 === year && 10 === month) { if (day > 4 && day < 15) { throw new Error(`wrong solar year ${year} month ${month} day ${day}`); } } if (month < 1 || month > 12) { throw new Error(`wrong month ${month}`); } if (day < 1 || day > 31) { throw new Error(`wrong day ${day}`); } if (hour < 0 || hour > 23) { throw new Error(`wrong hour ${hour}`); } if (minute < 0 || minute > 59) { throw new Error(`wrong minute ${minute}`); } if (second < 0 || second > 59) { throw new Error(`wrong second ${second}`); } this._year = year; this._month = month; this._day = day; this._hour = hour; this._minute = minute; this._second = second; } getYear() { return this._year; } getMonth() { return this._month; } getDay() { return this._day; } getHour() { return this._hour; } getMinute() { return this._minute; } getSecond() { return this._second; } getWeek() { return (Math.floor(this.getJulianDay() + 0.5) + 7000001) % 7; } getWeekInChinese() { return SolarUtil.WEEK[this.getWeek()]; } getSolarWeek(start) { return SolarWeek.fromYmd(this._year, this._month, this._day, start); } isLeapYear() { return SolarUtil.isLeapYear(this._year); } getFestivals() { const l = []; let f = SolarUtil.FESTIVAL[this._month + "-" + this._day]; if (f) { l.push(f); } const weeks = Math.ceil(this._day / 7); const week = this.getWeek(); f = SolarUtil.WEEK_FESTIVAL[this._month + "-" + weeks + "-" + week]; if (f) { l.push(f); } if (this._day + 7 > SolarUtil.getDaysOfMonth(this._year, this._month)) { f = SolarUtil.WEEK_FESTIVAL[this._month + "-0-" + week]; if (f) { l.push(f); } } return l; } getOtherFestivals() { const l = []; const fs = SolarUtil.OTHER_FESTIVAL[this._month + "-" + this._day]; if (fs) { fs.forEach((f) => { l.push(f); }); } return l; } getXingzuo() { return this.getXingZuo(); } getXingZuo() { let index = 11; const y = this._month * 100 + this._day; if (y >= 321 && y <= 419) { index = 0; } else if (y >= 420 && y <= 520) { index = 1; } else if (y >= 521 && y <= 621) { index = 2; } else if (y >= 622 && y <= 722) { index = 3; } else if (y >= 723 && y <= 822) { index = 4; } else if (y >= 823 && y <= 922) { index = 5; } else if (y >= 923 && y <= 1023) { index = 6; } else if (y >= 1024 && y <= 1122) { index = 7; } else if (y >= 1123 && y <= 1221) { index = 8; } else if (y >= 1222 || y <= 119) { index = 9; } else if (y <= 218) { index = 10; } return SolarUtil.XINGZUO[index]; } /** * 获取薪资比例(感谢 https://gitee.com/smr1987) * @returns 1 | 2 | 3 薪资比例 */ getSalaryRate() { if (this._month === 1 && this._day === 1) { return 3; } if (this._month === 5 && this._day === 1) { return 3; } if (this._month === 10 && this._day >= 1 && this._day <= 3) { return 3; } const lunar = this.getLunar(); if (lunar.getMonth() === 1 && lunar.getDay() >= 1 && lunar.getDay() <= 3) { return 3; } if (lunar.getMonth() === 5 && lunar.getDay() === 5) { return 3; } if (lunar.getMonth() === 8 && lunar.getDay() === 15) { return 3; } if ("\u6E05\u660E" === lunar.getJieQi()) { return 3; } const holiday = HolidayUtil.getHoliday(this._year, this._month, this._day); if (holiday) { if (!holiday.isWork()) { return 2; } } else { const week = this.getWeek(); if (week === 6 || week === 0) { return 2; } } return 1; } toYmd() { let y = this._year + ""; while (y.length < 4) { y = "0" + y; } return [y, (this._month < 10 ? "0" : "") + this._month, (this._day < 10 ? "0" : "") + this._day].join("-"); } toYmdHms() { return this.toYmd() + " " + [(this._hour < 10 ? "0" : "") + this._hour, (this._minute < 10 ? "0" : "") + this._minute, (this._second < 10 ? "0" : "") + this._second].join(":"); } toString() { return this.toYmd(); } toFullString() { let s = this.toYmdHms(); if (this.isLeapYear()) { s += " \u95F0\u5E74"; } s += " \u661F\u671F" + this.getWeekInChinese(); const festivals = this.getFestivals(); festivals.forEach((f) => { s += " (" + f + ")"; }); s += " " + this.getXingZuo() + "\u5EA7"; return s; } nextYear(years) { const y = this._year + years; let m = this._month; let d = this._day; if (1582 === y && 10 === m) { if (d > 4 && d < 15) { d += 10; } } else if (2 === m) { if (d > 28) { if (!SolarUtil.isLeapYear(y)) { d = 28; } } } return _Solar.fromYmdHms(y, m, d, this._hour, this._minute, this._second); } nextMonth(months) { const month = SolarMonth.fromYm(this._year, this._month).next(months); const y = month.getYear(); const m = month.getMonth(); let d = this._day; if (1582 === y && 10 === m) { if (d > 4 && d < 15) { d += 10; } } else { const maxDay = SolarUtil.getDaysOfMonth(y, m); if (d > maxDay) { d = maxDay; } } return _Solar.fromYmdHms(y, m, d, this._hour, this._minute, this._second); } nextDay(days) { let y = this._year; let m = this._month; let d = this._day; if (1582 === y && 10 === m) { if (d > 4) { d -= 10; } } if (days > 0) { d += days; let daysInMonth = SolarUtil.getDaysOfMonth(y, m); while (d > daysInMonth) { d -= daysInMonth; m++; if (m > 12) { m = 1; y++; } daysInMonth = SolarUtil.getDaysOfMonth(y, m); } } else if (days < 0) { while (d + days <= 0) { m--; if (m < 1) { m = 12; y--; } d += SolarUtil.getDaysOfMonth(y, m); } d += days; } if (1582 === y && 10 === m) { if (d > 4) { d += 10; } } return _Solar.fromYmdHms(y, m, d, this._hour, this._minute, this._second); } next(days, onlyWorkday = false) { if (onlyWorkday) { let solar = _Solar.fromYmdHms(this._year, this._month, this._day, this._hour, this._minute, this._second); if (days !== 0) { let rest = Math.abs(days); const add = days < 1 ? -1 : 1; while (rest > 0) { solar = solar.next(add); let work = true; const holiday = HolidayUtil.getHoliday(solar.getYear(), solar.getMonth(), solar.getDay()); if (!holiday) { const week = solar.getWeek(); if (0 === week || 6 === week) { work = false; } } else { work = holiday.isWork(); } if (work) { rest -= 1; } } } return solar; } else { return this.nextDay(days); } } nextHour(hours) { const h = this._hour + hours; const n = h < 0 ? -1 : 1; let hour = Math.abs(h); let days = Math.floor(hour / 24) * n; hour = hour % 24 * n; if (hour < 0) { hour += 24; days--; } const solar = this.next(days); return _Solar.fromYmdHms(solar.getYear(), solar.getMonth(), solar.getDay(), hour, solar.getMinute(), solar.getSecond()); } getLunar() { return Lunar.fromSolar(this); } getJulianDay() { let y = this._year; let m = this._month; let d = this._day + ((this._second / 60 + this._minute) / 60 + this._hour) / 24; let n = 0; let g = false; if (y * 372 + m * 31 + Math.floor(d) >= 588829) { g = true; } if (m <= 2) { m += 12; y--; } if (g) { n = Math.floor(y / 100); n = 2 - n + Math.floor(n / 4); } return Math.floor(365.25 * (y + 4716)) + Math.floor(30.6001 * (m + 1)) + d + n - 1524.5; } isBefore(solar) { if (this._year > solar.getYear()) { return false; } if (this._year < solar.getYear()) { return true; } if (this._month > solar.getMonth()) { return false; } if (this._month < solar.getMonth()) { return true; } if (this._day > solar.getDay()) { return false; } if (this._day < solar.getDay()) { return true; } if (this._hour > solar.getHour()) { return false; } if (this._hour < solar.getHour()) { return true; } if (this._minute > solar.getMinute()) { return false; } if (this._minute < solar.getMinute()) { return true; } return this._second < solar.getSecond(); } isAfter(solar) { if (this._year > solar.getYear()) { return true; } if (this._year < solar.getYear()) { return false; } if (this._month > solar.getMonth()) { return true; } if (this._month < solar.getMonth()) { return false; } if (this._day > solar.getDay()) { return true; } if (this._day < solar.getDay()) { return false; } if (this._hour > solar.getHour()) { return true; } if (this._hour < solar.getHour()) { return false; } if (this._minute > solar.getMinute()) { return true; } if (this._minute < solar.getMinute()) { return false; } return this._second > solar.getSecond(); } subtract(solar) { return SolarUtil.getDaysBetween(solar.getYear(), solar.getMonth(), solar.getDay(), this._year, this._month, this._day); } subtractMinute(solar) { let days = this.subtract(solar); const cm = this._hour * 60 + this._minute; const sm = solar.getHour() * 60 + solar.getMinute(); let m = cm - sm; if (m < 0) { m += 1440; days--; } m += days * 1440; return m; } }; export let Solar = _Solar; Solar.J2000 = 2451545;