UNPKG

viet-lunar-calendar

Version:

Helper tool to convert Gregorian date to Vietnamese Lunar Date (default timezone is GMT+7)

241 lines (240 loc) 11.7 kB
import { SOLAR_TERM, STEMS, ZODIAC_BRANCHES } from "./model"; export default class CalendarCalculator { parseGregorianDate(date) { return { day: date.getDate(), month: date.getMonth() + 1, year: date.getFullYear(), }; } floorNumber(number) { return Math.floor(number); } getDayNumber(date) { const gregorianDate = this.parseGregorianDate(date); const a = this.floorNumber((14 - gregorianDate.month) / 12); let y = gregorianDate.year + 4800 - a; let m = gregorianDate.month + 12 * a - 3; let dayNumber; dayNumber = gregorianDate.day + this.floorNumber((153 * m + 2) / 5) + 365 * y + this.floorNumber(y / 4) - this.floorNumber(y / 100) + this.floorNumber(y / 400) - 32045; if (dayNumber < 2299161) { dayNumber = gregorianDate.day + this.floorNumber((153 * m + 2) / 5) + 365 * y + this.floorNumber(y / 4) - 32083; } return dayNumber; } getKNumber(dayNumber) { return this.floorNumber((dayNumber - 2415021.076998695) / 29.530588853); } newMoon(k) { const t = k / 1236.85; const t2 = t * t; const t3 = t2 * t; const dr = Math.PI / 180; let jd1 = 2415020.75933 + 29.53058868 * k + 0.0001178 * t2 - 0.000000155 * t3; jd1 = jd1 + 0.00033 * Math.sin((166.56 + 132.87 * t - 0.009173 * t2) * dr); const m = 359.2242 + 29.10535608 * k - 0.0000333 * t2 - 0.00000347 * t3; const mpr = 306.0253 + 385.81691806 * k + 0.0107306 * t2 + 0.00001236 * t3; const F = 21.2964 + 390.67050646 * k - 0.0016528 * t2 - 0.00000239 * t3; let c1 = (0.1734 - 0.000393 * t) * Math.sin(m * dr) + 0.0021 * Math.sin(2 * dr * m); c1 = c1 - 0.4068 * Math.sin(mpr * dr) + 0.0161 * Math.sin(dr * 2 * mpr); c1 = c1 - 0.0004 * Math.sin(dr * 3 * mpr); c1 = c1 + 0.0104 * Math.sin(dr * 2 * F) - 0.0051 * Math.sin(dr * (m + mpr)); c1 = c1 - 0.0074 * Math.sin(dr * (m - mpr)) + 0.0004 * Math.sin(dr * (2 * F + m)); c1 = c1 - 0.0004 * Math.sin(dr * (2 * F - m)) - 0.0006 * Math.sin(dr * (2 * F + mpr)); c1 = c1 + 0.0010 * Math.sin(dr * (2 * F - mpr)) + 0.0005 * Math.sin(dr * (2 * mpr + m)); let deltat; if (t < -11) { deltat = 0.001 + 0.000839 * t + 0.0002261 * t2 - 0.00000845 * t3 - 0.000000081 * t * t3; } else { deltat = -0.000278 + 0.000265 * t + 0.000262 * t2; } const jdNew = jd1 + c1 - deltat; return jdNew; } getNewMoonDay(k, timeZone) { return this.floorNumber(this.newMoon(k) + 0.5 + timeZone / 24); } sunLongitude(jdn) { const t = (jdn - 2451545.0) / 36525; const t2 = t * t; const dr = Math.PI / 180; const m = 357.52910 + 35999.05030 * t - 0.0001559 * t2 - 0.00000048 * t * t2; const l0 = 280.46645 + 36000.76983 * t + 0.0003032 * t2; let dl = (1.914600 - 0.004817 * t - 0.000014 * t2) * Math.sin(dr * m); dl = dl + (0.019993 - 0.000101 * t) * Math.sin(dr * 2 * m) + 0.000290 * Math.sin(dr * 3 * m); let l = l0 + dl; l = l * dr; l = l - Math.PI * 2 * ((this.floorNumber(l / (Math.PI * 2)))); return l; } getSunLongitude(dayNumber, timeZone) { const jdn = dayNumber - 0.5 - timeZone / 24; return this.floorNumber(this.sunLongitude(jdn) / Math.PI * 6); } getLunarMonth11(year, timeZone) { const lastDayOfYear = new Date(year, 11, 31); ; const off = this.getDayNumber(lastDayOfYear) - 2415021; const k = this.floorNumber(off / 29.530588853); let nm = this.getNewMoonDay(k, timeZone); const sunLong = this.getSunLongitude(nm, timeZone); if (sunLong >= 9) { nm = this.getNewMoonDay(k - 1, timeZone); } return nm; } getSolarTermId(dayNumber, timeZone) { return this.floorNumber(this.sunLongitude(dayNumber - 0.5 - timeZone / 24.0) / Math.PI * 12); } getLunarDayStemBranch(dayNumber) { var _a, _b, _c, _d, _e; const stemIndex = (dayNumber + 3) % 10; const branchIndex = (dayNumber + 2) % 12 == 0 ? 12 : (dayNumber + 2) % 12; return { stemIndex: stemIndex, branchIndex: branchIndex, branchEmoji: `${(_b = (_a = ZODIAC_BRANCHES === null || ZODIAC_BRANCHES === void 0 ? void 0 : ZODIAC_BRANCHES[branchIndex]) === null || _a === void 0 ? void 0 : _a["emoji"]) !== null && _b !== void 0 ? _b : ''}`, say: `${(_c = STEMS === null || STEMS === void 0 ? void 0 : STEMS[stemIndex]) !== null && _c !== void 0 ? _c : ''} ${(_e = (_d = ZODIAC_BRANCHES === null || ZODIAC_BRANCHES === void 0 ? void 0 : ZODIAC_BRANCHES[branchIndex]) === null || _d === void 0 ? void 0 : _d["han_viet"]) !== null && _e !== void 0 ? _e : ''}` }; } getLunarMonthStemBranch(year, month) { var _a, _b, _c, _d, _e; const stemIndex = (year * 12 + month + 7) % 10; const branchIndex = (month + 2) % 12 == 0 ? 12 : (month + 2) % 12; return { stemIndex: stemIndex, branchIndex: branchIndex, branchEmoji: `${(_b = (_a = ZODIAC_BRANCHES === null || ZODIAC_BRANCHES === void 0 ? void 0 : ZODIAC_BRANCHES[branchIndex]) === null || _a === void 0 ? void 0 : _a["emoji"]) !== null && _b !== void 0 ? _b : ''}`, say: `${(_c = STEMS === null || STEMS === void 0 ? void 0 : STEMS[stemIndex]) !== null && _c !== void 0 ? _c : ''} ${(_e = (_d = ZODIAC_BRANCHES === null || ZODIAC_BRANCHES === void 0 ? void 0 : ZODIAC_BRANCHES[branchIndex]) === null || _d === void 0 ? void 0 : _d["han_viet"]) !== null && _e !== void 0 ? _e : ''}` }; } getLunarYearStemBranch(year) { var _a, _b, _c, _d, _e; const stemIndex = (year + 10) % 10; const branchIndex = (year + 9) % 12 == 0 ? 12 : (year + 9) % 12; return { stemIndex: stemIndex, branchIndex: branchIndex, branchEmoji: `${(_b = (_a = ZODIAC_BRANCHES === null || ZODIAC_BRANCHES === void 0 ? void 0 : ZODIAC_BRANCHES[branchIndex]) === null || _a === void 0 ? void 0 : _a["emoji"]) !== null && _b !== void 0 ? _b : ''}`, say: `${(_c = STEMS === null || STEMS === void 0 ? void 0 : STEMS[stemIndex]) !== null && _c !== void 0 ? _c : ''} ${(_e = (_d = ZODIAC_BRANCHES === null || ZODIAC_BRANCHES === void 0 ? void 0 : ZODIAC_BRANCHES[branchIndex]) === null || _d === void 0 ? void 0 : _d["han_viet"]) !== null && _e !== void 0 ? _e : ''}` }; } getLeapMonthOffset(a11, timeZone) { const k = this.floorNumber((a11 - 2415021.076998695) / 29.530588853 + 0.5); let last = 0; let i = 1; let arc = this.getSunLongitude(this.getNewMoonDay(k + i, timeZone), timeZone); while (arc != last && i < 14) { last = arc; i += 1; arc = this.getSunLongitude(this.getNewMoonDay(k + i, timeZone), timeZone); } return i - 1; } getZodiacHours(date) { var _a, _b, _c, _d, _e, _f, _g; const zodiacHourMap = [ "110100101100", "001101001011", "110011010010", "101100110100", "001011001101", "010010110011" ]; const dayNumber = this.getDayNumber(date); const startStem = (((dayNumber - 1) * 2) % 10) + 4; const dayBranchIndex = (dayNumber + 2) % 12 == 0 ? 12 : (dayNumber + 2) % 12; let zodiacHourStr = zodiacHourMap[(dayBranchIndex - 1) % 6]; let zodiacHours = []; for (let i = 0; i < zodiacHourStr.length; i++) { const stemIndex = (startStem + i) % 10; const branchIndex = i + 1; zodiacHours.push({ presentFrom: (_b = (_a = ZODIAC_BRANCHES === null || ZODIAC_BRANCHES === void 0 ? void 0 : ZODIAC_BRANCHES[branchIndex]) === null || _a === void 0 ? void 0 : _a["hour_from"]) !== null && _b !== void 0 ? _b : 0, presentTo: (_d = (_c = ZODIAC_BRANCHES === null || ZODIAC_BRANCHES === void 0 ? void 0 : ZODIAC_BRANCHES[branchIndex]) === null || _c === void 0 ? void 0 : _c["hour_to"]) !== null && _d !== void 0 ? _d : 0, stemIndex: stemIndex, branchIndex: branchIndex, say: `${(_e = STEMS === null || STEMS === void 0 ? void 0 : STEMS[stemIndex]) !== null && _e !== void 0 ? _e : ''} ${(_g = (_f = ZODIAC_BRANCHES === null || ZODIAC_BRANCHES === void 0 ? void 0 : ZODIAC_BRANCHES[branchIndex]) === null || _f === void 0 ? void 0 : _f["han_viet"]) !== null && _g !== void 0 ? _g : ''}`, goldenHour: zodiacHourStr[i] == "1" }); } return zodiacHours; } getLunarDate(date, timeZone = 7.0) { var _a, _b, _c, _d, _e, _f; const gregorianDate = this.parseGregorianDate(date); const dayNumber = this.getDayNumber(date); const k = this.getKNumber(dayNumber); let newMoonDayNumber = this.getNewMoonDay(k + 1, timeZone); if (newMoonDayNumber > dayNumber) { newMoonDayNumber = this.getNewMoonDay(k, timeZone); } let a11 = this.getLunarMonth11(gregorianDate.year, timeZone); let b11 = a11; let lunarYear; if (a11 >= newMoonDayNumber) { lunarYear = gregorianDate.year; a11 = this.getLunarMonth11(gregorianDate.year - 1, timeZone); } else { lunarYear = gregorianDate.year + 1; b11 = this.getLunarMonth11(gregorianDate.year + 1, timeZone); } const lunarDay = dayNumber - newMoonDayNumber + 1; const diff = this.floorNumber((newMoonDayNumber - a11) / 29); let lunarLeap = 0; let lunarMonth = diff + 11; if (b11 - a11 > 365) { const leapMonthDiff = this.getLeapMonthOffset(a11, timeZone); if (diff >= leapMonthDiff) { lunarMonth = diff + 10; if (diff == leapMonthDiff) { lunarLeap = 1; } } } if (lunarMonth > 12) { lunarMonth = lunarMonth - 12; } if (lunarMonth >= 11 && diff < 4) { lunarYear -= 1; } const solarTermId = this.getSolarTermId(dayNumber + 1, timeZone); return { day: lunarDay, month: lunarMonth, monthSay: (_b = (_a = ZODIAC_BRANCHES === null || ZODIAC_BRANCHES === void 0 ? void 0 : ZODIAC_BRANCHES[lunarMonth]) === null || _a === void 0 ? void 0 : _a["month_say"]) !== null && _b !== void 0 ? _b : '', year: lunarYear, leap: lunarLeap, dayStemBranch: this.getLunarDayStemBranch(dayNumber), monthStemBranch: this.getLunarMonthStemBranch(lunarYear, lunarMonth), yearStemBranch: this.getLunarYearStemBranch(lunarYear), solarTermHanViet: (_d = (_c = SOLAR_TERM === null || SOLAR_TERM === void 0 ? void 0 : SOLAR_TERM[solarTermId]) === null || _c === void 0 ? void 0 : _c['han_viet']) !== null && _d !== void 0 ? _d : '', solarTermViet: (_f = (_e = SOLAR_TERM === null || SOLAR_TERM === void 0 ? void 0 : SOLAR_TERM[solarTermId]) === null || _e === void 0 ? void 0 : _e['viet']) !== null && _f !== void 0 ? _f : '', }; } }