UNPKG

kor-lunar

Version:

한국 음력 변환 유틸 / Korean lunar calendar converter

474 lines (464 loc) 16.8 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var toInt = function (num) { if (typeof num === "string" || typeof num === "number") return ~~num; return num; }; /** * 음력 테이블 * * 9b (17-25): 해당 해의 총 음력 일 수 (예: 384) * * 1b ( 16): 윤달의 크기 (0: 29일, 1: 30일) * * 4b (12-15): 윤달 위치 (1-12, 윤달이 없으면 0) * * 12b ( 0-11): 각 월의 크기 (0: 29일, 1: 30일) */ var LUN_TABLE = [ /* 0 1 2 3 4 5 6 7 8 9 */ /*1890*/ 0x3002ab6, 0x2c60daa, 0x3006ee4, 0x2c40ea4, 0x2c40d4a, 0x2fe5555, 0x2c60a97, 0x2c40556, 0x300355d, 0x2c60ad5, /*1900*/ 0x3008bd2, 0x2c40752, 0x2c60ea5, 0x2fe5b2a, 0x2c4064b, 0x2c60a9b, 0x3014aa6, 0x2c4056a, 0x2c60b59, 0x3002baa, /*1910*/ 0x2c40752, 0x3006da5, 0x2c40b25, 0x2c40a4b, 0x300595b, 0x2c60aad, 0x2c4056a, 0x30025b5, 0x2c60ba9, 0x3007dd2, /*1920*/ 0x2c40d92, 0x2c40d25, 0x3005d2d, 0x2c40956, 0x2c402b5, 0x3024add, 0x2c406d4, 0x2c60da9, 0x3002eca, 0x2c40e92, /*1930*/ 0x2fe66a6, 0x2c40527, 0x2c60a57, 0x3015956, 0x2c60ada, 0x2c406d4, 0x3013751, 0x2c40749, 0x3017b13, 0x2c40a93, /*1940*/ 0x2c4052b, 0x301651b, 0x2c6096d, 0x2c60b6a, 0x3014da4, 0x2c40ba4, 0x2c40b49, 0x3002d4b, 0x2c40a95, 0x3007aab, /*1950*/ 0x2c4052d, 0x2c60aad, 0x3015aaa, 0x2c60db2, 0x2c40da4, 0x3013ea1, 0x2c40d4a, 0x3008d95, 0x2c40a96, 0x2c40556, /*1960*/ 0x3006575, 0x2c60ad5, 0x2c406d2, 0x3004755, 0x2c60ea5, 0x2c40e4a, 0x2fe364e, 0x2c60a9b, 0x3007ad6, 0x2c4056a, /*1970*/ 0x2c60b59, 0x3005bb2, 0x2c40752, 0x2c40725, 0x3004b2b, 0x2c40a4b, 0x30089ab, 0x2c402ad, 0x2c6056b, 0x30165a9, /*1980*/ 0x2c60da9, 0x2c40d92, 0x3004d95, 0x2c40d25, 0x300ae4d, 0x2c40a56, 0x2c402b6, 0x3026aed, 0x2c406d4, 0x2c60da9, /*1990*/ 0x3005ed2, 0x2c40e92, 0x2c40d26, 0x2fe352e, 0x2c60a57, 0x30089b6, 0x2c60b5a, 0x2c406d4, 0x3005769, 0x2c40749, /*2000*/ 0x2c40693, 0x3004a97, 0x2c4052b, 0x2c60a5b, 0x3002aae, 0x2c4036a, 0x3027dd5, 0x2c40ba4, 0x2c40b49, 0x3005d53, /*2010*/ 0x2c40a95, 0x2c4052d, 0x301352d, 0x2c60aad, 0x3009baa, 0x2c405d2, 0x2c60da5, 0x3005eaa, 0x2c40d4a, 0x2c40a95, /*2020*/ 0x3004a9d, 0x2c40556, 0x2c60ab5, 0x3002ad6, 0x2c406d2, 0x3006765, 0x2c60ea5, 0x2c40e4a, 0x2fe5656, 0x2c60c9b, /*2030*/ 0x2c4055a, 0x300356d, 0x2c60b69, 0x300bf52, 0x2c40752, 0x2c40b25, 0x3016b0b, 0x2c40a4b, 0x2c404ab, 0x30052bb, /*2040*/ 0x2c6056d, 0x2c60b69, 0x3002daa, 0x2c40d92, 0x3007ea5, 0x2c40d25, 0x2c40a4d, 0x3015a4d, 0x2c402b6, 0x2c605b5, /*2050*/ 0x00136d1 /* 11월 18일 까지라 데이터 부족 */, ]; var gan = ["갑", "을", "병", "정", "무", "기", "경", "신", "임", "계"]; var ji = ["자", "축", "인", "묘", "진", "사", "오", "미", "신", "유", "술", "해"]; var BASE_YEAR$1 = 1890; var BASE_MONTH$1 = 1; var BASE_DAY$1 = 1; var BASE_VALUE$1 = BASE_YEAR$1 * 10000 + BASE_MONTH$1 * 100 + BASE_DAY$1; var MAX_YEAR$1 = 2050; var MAX_MONTH$1 = 11; var MAX_DAY$1 = 18; var MAX_VALUE$1 = MAX_YEAR$1 * 10000 + MAX_MONTH$1 * 100 + MAX_DAY$1; var SMALL_MONTH_DAY = 29; var BIG_MONTH_DAY = 30; var totalDaysBeforeYear$1 = {}; var getYearData = function (year) { year = toInt(year); return LUN_TABLE[year - BASE_YEAR$1]; }; /** * 해당 월 (평달)의 일 수를 반환합니다. * @param year 1890년 ~ 2050년 * @param month 1월 ~ 12월 * @returns 월의 일 수 (29 또는 30) */ var getMonthDays$1 = function (year, month) { month = toInt(month); var monthType = (getYearData(year) >> (month - 1)) & 0x1; return monthType === 0 ? SMALL_MONTH_DAY : BIG_MONTH_DAY; }; /** * 해당 연도의 윤달을 반환합니다. * @param year 1890년 ~ 2050년 * @returns 윤달 월 (1월 ~ 12월), 없으면 0 */ var getLeapMonth = function (year) { return (getYearData(year) >> 12) & 0xf; }; /** * 해당 연도에 윤달이 있는지를 반환합니다. * @param year 1890년 ~ 2050년 * @return 윤달이 있으면 true */ var hasLeapMonth = function (year) { return getLeapMonth(year) !== 0; }; /** * 해당 월이 윤달인지를 반환합니다. * @param year 1890년 ~ 2050년 * @param month 1월 ~ 12월 * @returns 윤달이면 true */ var isLeapMonth = function (year, month) { month = toInt(month); return month === getLeapMonth(year); }; /** * 해당 월 (윤달)의 일 수를 반환합니다. * @param year 1890년 ~ 2050년 * @param month 1월 ~ 12월 * @returns 윤달의 일 수 (29 또는 30), 윤달이 아니면 0 */ var getLeapMonthDays = function (year, month) { if (!isLeapMonth(year, month)) return 0; var monthType = (getYearData(year) >> 16) & 0x1; return monthType === 0 ? SMALL_MONTH_DAY : BIG_MONTH_DAY; }; /** * 해당 연도의 총 일 수를 반환합니다. * @param year 1890년 ~ 2050년 * @return 해당 연도의 총 일 수 */ var getYearDays$1 = function (year) { return (getYearData(year) >> 17) & 0x1ff; }; /** * 연도별 누적 일 수를 초기에 룩업 테이블로 생성하여 * O(1)으로 누적 일 수를 가져오게 변환함 */ totalDaysBeforeYear$1[BASE_YEAR$1] = 0; for (var y$1 = BASE_YEAR$1 + 1; y$1 <= MAX_YEAR$1; y$1++) { totalDaysBeforeYear$1[y$1] = totalDaysBeforeYear$1[y$1 - 1] + getYearDays$1(y$1 - 1); } /** * 1890년부터 해당 연도 전까지의 누적 일 수를 반환합니다. * @param year 1890년 ~ 2050년 * @return 해당 연도 전까지의 누적 일 수 */ var getTotalDaysBeforeYear$1 = function (year) { year = toInt(year); var days = totalDaysBeforeYear$1[year]; return days; }; /** * 해당 연도 내에서 해당 월 (및 윤달 포함) 전까지의 누적 일 수를 반환합니다. * @param year 1890년 ~ 2050년 * @param month 1월 ~ 12월 * @param isLeapMonth 대상이 윤달이면 true * @returns 해당 연도 내, 해당 월 전까지의 누적 일 수 */ var getTotalDaysBeforeMonth$1 = function (year, month, isLeapMonth) { month = toInt(month); var days = 0; // 해당 월 전까지 윤달을 포함하여 누적 for (var m = 1; m < month; m++) { days += getMonthDays$1(year, m); if (m === getLeapMonth(year)) { days += getLeapMonthDays(year, m); } } // 대상이 윤달이면, 앞에 있는 평달을 누적 var leapMonth = getLeapMonth(year); if (isLeapMonth && leapMonth === month) { days += getMonthDays$1(year, month); } return days; }; /** * 1890년부터 해당 연도, 월, 일 (및 윤달 포함) 까지의 누적 일 수를 반환합니다. * @param year 1890년 ~ 2050년 * @param month 1월 ~ 12월 * @param day 일자 * @param isLeapMonth 대상이 윤달이면 true * @returns 총 누적 일 수 */ var getTotalDays$1 = function (year, month, day, isLeapMonth) { day = toInt(day); var days = getTotalDaysBeforeYear$1(year) + getTotalDaysBeforeMonth$1(year, month, isLeapMonth) + day; return days; }; var getSecha = function (year) { year = toInt(year); var g = gan[(year + 6) % gan.length]; var j = ji[(year + 8) % ji.length]; return g + j; }; var getWolgeon = function (year, month) { year = toInt(year); month = toInt(month); var g = gan[(year * 2 + month + 3) % gan.length]; var j = ji[(month + 1) % ji.length]; return g + j; }; var getIljinByJulianDay = function (julianDay) { julianDay = toInt(julianDay); var g = gan[(julianDay - 1) % gan.length]; var j = ji[(julianDay + 1) % ji.length]; return g + j; }; var getIljin = function (year, month, day, isLeapMonth) { var days = getTotalDays$1(year, month, day, isLeapMonth); return getIljinByJulianDay(days - 1); }; /** * 날짜가 지원하는 범위 내에 있는지를 반환합니다. * 날짜의 유효성 (존재 여부)은 검사하지 않습니다. * @returns 날짜가 범위 내에 있으면 true */ var isDateInRange$1 = function (year, month, day) { year = toInt(year); month = toInt(month); day = toInt(day); var value = year * 10000 + month * 100 + day; return value >= BASE_VALUE$1 && value <= MAX_VALUE$1; }; /** * 실제로 존재하는 유효한 날짜인지를 반환합니다. * @returns 유효한 날짜이면 true */ var isValidDate$1 = function (year, month, day, isLeapMonth) { year = toInt(year); month = toInt(month); day = toInt(day); if (year < BASE_YEAR$1 || year > MAX_YEAR$1) return false; if (year === BASE_YEAR$1) { if (month < BASE_MONTH$1) return false; if (month === BASE_MONTH$1 && day < BASE_DAY$1) return false; } if (year === MAX_YEAR$1) { if (month > MAX_MONTH$1) return false; if (month === MAX_MONTH$1 && day > MAX_DAY$1) return false; } if (month < 1 || month > 12) return false; if (day < 1) return false; var endDay = isLeapMonth ? getLeapMonthDays(year, month) : getMonthDays$1(year, month); return day <= endDay; }; var LunarData = /*#__PURE__*/Object.freeze({ __proto__: null, BASE_YEAR: BASE_YEAR$1, BASE_MONTH: BASE_MONTH$1, BASE_DAY: BASE_DAY$1, BASE_VALUE: BASE_VALUE$1, MAX_YEAR: MAX_YEAR$1, MAX_MONTH: MAX_MONTH$1, MAX_DAY: MAX_DAY$1, MAX_VALUE: MAX_VALUE$1, getMonthDays: getMonthDays$1, getLeapMonth: getLeapMonth, hasLeapMonth: hasLeapMonth, isLeapMonth: isLeapMonth, getLeapMonthDays: getLeapMonthDays, getYearDays: getYearDays$1, getTotalDaysBeforeYear: getTotalDaysBeforeYear$1, getTotalDaysBeforeMonth: getTotalDaysBeforeMonth$1, getTotalDays: getTotalDays$1, getSecha: getSecha, getWolgeon: getWolgeon, getIljinByJulianDay: getIljinByJulianDay, getIljin: getIljin, isDateInRange: isDateInRange$1, isValidDate: isValidDate$1 }); var MONTH_DAYS = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; var LEAP_FEBRUARY_DAY = 29; var YEAR_DAY = 365; var LEAP_YEAR_DAY = 366; var BASE_YEAR = 1890; var BASE_MONTH = 1; var BASE_DAY = 21; var BASE_VALUE = BASE_YEAR * 10000 + BASE_MONTH * 100 + BASE_DAY; var MAX_YEAR = 2050; var MAX_MONTH = 12; var MAX_DAY = 31; var MAX_VALUE = MAX_YEAR * 10000 + MAX_MONTH * 100 + MAX_DAY; var totalDaysBeforeYear = {}; var isLeapYear = function (year) { year = toInt(year); return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0; }; var getMonthDays = function (year, month) { month = toInt(month); var day = month === 2 && isLeapYear(year) ? LEAP_FEBRUARY_DAY : MONTH_DAYS[month - 1]; return day; }; var getYearDays = function (year) { var day = isLeapYear(year) ? LEAP_YEAR_DAY : YEAR_DAY; return day; }; /** * 연도별 누적 일 수를 초기에 룩업 테이블로 생성하여 * O(1)으로 누적 일 수를 가져오게 변환함 */ totalDaysBeforeYear[BASE_YEAR] = 0; for (var y = BASE_YEAR + 1; y <= MAX_YEAR; y++) { totalDaysBeforeYear[y] = totalDaysBeforeYear[y - 1] + getYearDays(y - 1); } var getTotalDaysBeforeYear = function (year) { year = toInt(year); var day = totalDaysBeforeYear[year]; return day; }; var getTotalDaysBeforeMonth = function (year, month) { var day = 0; for (var m = 1; m < month; m++) { day += getMonthDays(year, m); } return day; }; var getTotalDays = function (year, month, day) { var days = getTotalDaysBeforeYear(year) + getTotalDaysBeforeMonth(year, month) + day; return days; }; /** * 날짜가 지원하는 범위 내에 있는지를 반환합니다. * 날짜의 유효성 (존재 여부)은 검사하지 않습니다. * @returns 날짜가 범위 내에 있으면 true */ var isDateInRange = function (year, month, day) { year = toInt(year); month = toInt(month); day = toInt(day); var value = year * 10000 + month * 100 + day; return value >= BASE_VALUE && value <= MAX_VALUE; }; /** * 실제로 존재하는 유효한 날짜인지를 반환합니다. * @returns 유효한 날짜이면 true */ var isValidDate = function (year, month, day) { year = toInt(year); month = toInt(month); day = toInt(day); if (year < BASE_YEAR || year > MAX_YEAR) return false; if (year === BASE_YEAR) { if (month < BASE_MONTH) return false; if (month === BASE_MONTH && day < BASE_DAY) return false; } if (year === MAX_YEAR) { if (month > MAX_MONTH) return false; if (month === MAX_MONTH && day > MAX_DAY) return false; } if (month < 1 || month > 12) return false; if (day < 1) return false; var endDay = getMonthDays(year, month); return day <= endDay; }; var SolarData = /*#__PURE__*/Object.freeze({ __proto__: null, BASE_YEAR: BASE_YEAR, BASE_MONTH: BASE_MONTH, BASE_DAY: BASE_DAY, BASE_VALUE: BASE_VALUE, MAX_YEAR: MAX_YEAR, MAX_MONTH: MAX_MONTH, MAX_DAY: MAX_DAY, MAX_VALUE: MAX_VALUE, isLeapYear: isLeapYear, getMonthDays: getMonthDays, getYearDays: getYearDays, getTotalDaysBeforeYear: getTotalDaysBeforeYear, getTotalDaysBeforeMonth: getTotalDaysBeforeMonth, getTotalDays: getTotalDays, isDateInRange: isDateInRange, isValidDate: isValidDate }); var SOLAR_LUNAR_DAY_DIFF = 20; var JULIAN_DAY_DIFF = 2411389; /** * 양력을 음력으로 변환합니다. * 양력 지원 날짜 범위: 1890년 1월 21일 ~ 2050년 12월 31일 * @param solYear 양력 연도 * @param solMonth 양력 월 * @param solDay 양력 일 * @returns 음력 날짜 */ var toLunar = function (solYear, solMonth, solDay) { solYear = toInt(solYear); solMonth = toInt(solMonth); solDay = toInt(solDay); if (!isDateInRange(solYear, solMonth, solDay)) { throw new RangeError("\uC9C0\uC6D0\uB418\uC9C0 \uC54A\uB294 \uB0A0\uC9DC\uC785\uB2C8\uB2E4. \uC785\uB825\uD55C \uB0A0\uC9DC: ".concat(solYear, "-").concat(solMonth, "-").concat(solDay)); } var year = Math.min(solYear, MAX_YEAR$1); var month = solYear > MAX_YEAR$1 ? MAX_MONTH$1 : solMonth; var day = 1; var lunTotalDays = getTotalDays$1(year, month, day, true); var solTotalDays = getTotalDays(solYear, solMonth, solDay); var diffDays = solTotalDays - SOLAR_LUNAR_DAY_DIFF - lunTotalDays; day += diffDays; var day2 = solTotalDays - SOLAR_LUNAR_DAY_DIFF; var julianDay = JULIAN_DAY_DIFF + day2 - 1; var dayOfWeek = (day2 + 1) % 7; var isLeapMonth = month === getLeapMonth(year); var monthDays; while (day < 1) { if (isLeapMonth) { isLeapMonth = false; } else { month--; if (month === 0) { month = 12; year--; } isLeapMonth = month === getLeapMonth(year); } monthDays = isLeapMonth ? getLeapMonthDays(year, month) : getMonthDays$1(year, month); day += monthDays; } return { year: year, month: month, day: day, isLeapMonth: isLeapMonth, secha: getSecha(year), wolgeon: isLeapMonth ? "" : getWolgeon(year, month), iljin: getIljinByJulianDay(julianDay), julianDay: julianDay, dayOfWeek: dayOfWeek, }; }; /** * 음력을 양력으로 변환합니다. * 음력 지원 날짜 범위: 1890년 1월 1일 ~ 2050년 11월 18일 * @param lunYear 음력 연도 * @param lunMonth 음력 월 * @param lunDay 음력 일 * @param isLeapMonth 음력 윤달 여부, 윤달이면 true * @returns 양력 날짜 */ var toSolar = function (lunYear, lunMonth, lunDay, isLeapMonth) { lunYear = toInt(lunYear); lunMonth = toInt(lunMonth); lunDay = toInt(lunDay); if (!isDateInRange$1(lunYear, lunMonth, lunDay)) { throw new RangeError("\uC9C0\uC6D0\uB418\uC9C0 \uC54A\uB294 \uB0A0\uC9DC\uC785\uB2C8\uB2E4. \uC785\uB825\uD55C \uB0A0\uC9DC: ".concat(lunYear, "-").concat(lunMonth, "-").concat(lunDay)); } var lunTotalDays = getTotalDays$1(lunYear, lunMonth, lunDay, isLeapMonth); var solTotalDays = getTotalDays(lunYear, lunMonth, lunDay); var diffDays = lunTotalDays - (solTotalDays - SOLAR_LUNAR_DAY_DIFF); var year = lunYear; var month = lunMonth; var day = lunDay + diffDays; var monthDays = getMonthDays(year, month); while (day > monthDays) { day -= monthDays; month++; if (month > 12) { month = 1; year++; } monthDays = getMonthDays(year, month); } return { year: year, month: month, day: day }; }; var korLunar = { toLunar: toLunar, toSolar: toSolar, LunarData: LunarData, SolarData: SolarData }; exports.LunarData = LunarData; exports.SolarData = SolarData; exports["default"] = korLunar; exports.toLunar = toLunar; exports.toSolar = toSolar; //# sourceMappingURL=kor-lunar.js.map