### Run example scripts Source: https://github.com/urstory/manseryeok-js/blob/main/README.md Execute the provided example files after building the project. ```bash # 예제 실행 (빌드 후) node examples/01-solar-to-lunar.mjs node examples/06-saju-calculation.mjs ``` -------------------------------- ### Install the library Source: https://github.com/urstory/manseryeok-js/blob/main/README.md Use npm to install the package in your project. ```bash npm install @fullstackfamily/manseryeok ``` -------------------------------- ### Install Dependencies Source: https://github.com/urstory/manseryeok-js/blob/main/CONTRIBUTING.md Command to install project dependencies. ```bash npm install ``` -------------------------------- ### Unit Test Example Source: https://github.com/urstory/manseryeok-js/blob/main/CONTRIBUTING.md Example test case using Jest to verify solar to lunar conversion. ```ts import { solarToLunar } from '../core/solar-lunar-converter'; describe('solarToLunar', () => { test('2024년 설날 변환', () => { const result = solarToLunar(2024, 2, 10); expect(result.lunar.month).toBe(1); expect(result.lunar.day).toBe(1); }); }); ``` -------------------------------- ### JSDoc Function Example Source: https://github.com/urstory/manseryeok-js/blob/main/CONTRIBUTING.md Example of the required JSDoc documentation style for exported functions. ```ts /** * 양력을 음력으로 변환합니다. * @param solarYear 양력 년 (1900~2050) * @param solarMonth 양력 월 (1~12) * @param solarDay 양력 일 (1~31) * @returns 음력 날짜와 갑자 정보 */ export function solarToLunar( solarYear: number, solarMonth: number, solarDay: number ): SolarToLunarResult { // 구현 } ``` -------------------------------- ### getAllSolarTerms - Get All 24 Solar Terms Source: https://context7.com/urstory/manseryeok-js/llms.txt Retrieves an array containing the basic information for all 24 Solar Terms (Jieqi and Zhongqi). ```APIDOC ## getAllSolarTerms - Get All 24 Solar Terms ### Description Retrieves an array containing the basic information for all 24 Solar Terms (Jieqi and Zhongqi). The terms alternate between Jieqi (節氣) and Zhongqi (中氣). ### Method `getAllSolarTerms` ### Parameters None ### Request Example ```javascript import { getAllSolarTerms } from '@fullstackfamily/manseryeok'; const allTerms = getAllSolarTerms(); console.log('Number of Solar Terms:', allTerms.length); // 24 // Display first 6 terms (Spring terms) allTerms.slice(0, 6).forEach((term, i) => { console.log(`${i + 1}. ${term.name} (${term.hanja}) - Longitude ${term.longitude}°, Saju Month ${term.sajuMonth}, Type ${term.type}`); }); ``` ### Response An array of objects, where each object represents a Solar Term and contains: - `name` (string) - The Korean name of the Solar Term (e.g., '입춘'). - `hanja` (string) - The Hanja (Chinese characters) name of the Solar Term (e.g., '立春'). - `longitude` (number) - The ecliptic longitude at which the Solar Term occurs (0-360). - `sajuMonth` (number) - The corresponding Saju month (1-12). - `type` (string) - The type of the term ('jeolgi' for Jieqi, 'junggi' for Zhongqi). ### Response Example ```json [ { "name": "입춘", "hanja": "立春", "longitude": 315, "sajuMonth": 1, "type": "jeolgi" }, { "name": "우수", "hanja": "雨水", "longitude": 330, "sajuMonth": 1, "type": "junggi" } // ... other solar terms ] ``` ``` -------------------------------- ### GET /solar-terms Source: https://github.com/urstory/manseryeok-js/blob/main/README.md Endpoints for retrieving information about the 24 solar terms, including specific dates, names, and seasonal data. ```APIDOC ## GET /solar-terms ### Description Retrieves information about the 24 solar terms. ### Methods - `getAllSolarTerms()`: Returns an array of all 24 solar terms. - `getSolarTermByName(name)`: Retrieves a specific solar term by its name (e.g., '입춘'). - `getSolarTermsByYear(year)`: Retrieves all solar terms for a specific year. - `getSolarTermForDate(year, month, day)`: Retrieves the solar term for a specific date. - `getSolarTermsByMonth(year, month)`: Retrieves solar terms occurring in a specific month. - `getSolarTermsBySajuMonth(month)`: Retrieves solar terms associated with a specific Saju month. - `getSupportedSolarTermYears()`: Returns an array of years for which solar term data is supported. ``` -------------------------------- ### Verify Year-Based Month Pillar Calculation (오호둔법) Source: https://github.com/urstory/manseryeok-js/blob/main/docs/issue-5-month-pillar-bug-analysis.md Tests the `getGapja` function using the 'Year-Based Month Pillar Calculation' (年上起月法) method for different years (2024 and 2025) to ensure correct starting month pillars. ```typescript // 갑자년(2024): 갑/기 → 병인(丙寅) 시작 expect(getGapja(2024, 2, 4).monthPillarHanja).toBe('丙寅'); // 인월 // 을축년(2025): 을/경 → 무인(戊寅) 시작 expect(getGapja(2025, 2, 4).monthPillarHanja).toBe('戊寅'); // 인월 ``` -------------------------------- ### Get Supported Solar Term Years Source: https://github.com/urstory/manseryeok-js/blob/main/README.md Retrieves a list of years for which solar term data is currently supported by the library. Future expansions are noted. ```typescript import { getSupportedSolarTermYears } from '@fullstackfamily/manseryeok'; const supportedYears = getSupportedSolarTermYears(); console.log('절기 데이터 지원 연도:', supportedYears.join(', ')); // 절기 데이터 지원 연도: 2020, 2021, 2022, 2023, 2024, 2025, 2026, 2027, 2028, 2029, 2030 // 참고: 향후 1900~2050년 전체 데이터로 확장 예정 ``` -------------------------------- ### Get Solar Term Info by Name Source: https://context7.com/urstory/manseryeok-js/llms.txt Retrieves metadata for a specific solar term by its Korean name. Returns undefined if no match is found. ```typescript import { getSolarTermInfoByName } from '@fullstackfamily/manseryeok'; const ipchun = getSolarTermInfoByName('입춘'); if (ipchun) { console.log('절기명:', ipchun.name); // 입춘 console.log('한자:', ipchun.hanja); // 立春 console.log('황경:', ipchun.longitude); // 315 console.log('유형:', ipchun.type); // jeolgi console.log('사주월:', ipchun.sajuMonth); // 1 } const dongji = getSolarTermInfoByName('동지'); console.log(`동지 (${dongji?.hanja}): 황경 ${dongji?.longitude}°`); // 동지 (冬至): 황경 270° const notFound = getSolarTermInfoByName('없는절기'); console.log('검색 결과:', notFound); // undefined ``` -------------------------------- ### getSupportedSolarTermYears - Get List of Supported Solar Term Years Source: https://context7.com/urstory/manseryeok-js/llms.txt Returns a list of years for which solar term timing data is available. Currently supports years from 2020 to 2030. ```APIDOC ## getSupportedSolarTermYears - 지원되는 절기 연도 목록 절기 시각 데이터가 제공되는 연도 목록을 반환합니다. 현재 2020~2030년을 지원합니다. ### Method GET (conceptual, function call in JS) ### Endpoint N/A (JavaScript function) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```javascript import { getSupportedSolarTermYears } from '@fullstackfamily/manseryeok'; const supportedYears = getSupportedSolarTermYears(); console.log('절기 데이터 지원 연도:', supportedYears.join(', ')); // 절기 데이터 지원 연도: 2020, 2021, 2022, 2023, 2024, 2025, 2026, 2027, 2028, 2029, 2030 console.log('지원 연도 수:', supportedYears.length); // 11 console.log('최소 연도:', Math.min(...supportedYears)); // 2020 console.log('최대 연도:', Math.max(...supportedYears)); // 2030 // 특정 연도 지원 여부 확인 function isSolarTermYearSupported(year) { return getSupportedSolarTermYears().includes(year); } console.log('2024년 지원:', isSolarTermYearSupported(2024)); // true console.log('2000년 지원:', isSolarTermYearSupported(2000)); // false ``` ### Response #### Success Response (Array of Numbers) - Returns an array of numbers, where each number represents a year for which solar term data is supported. #### Response Example ```json [2020, 2021, 2022, 2023, 2024, 2025, 2026, 2027, 2028, 2029, 2030] ``` ``` -------------------------------- ### Get Solar Term Info by Index Source: https://context7.com/urstory/manseryeok-js/llms.txt Retrieves solar term information using an index from 0 (Ipchun) to 23 (Daehan). ```typescript import { getSolarTermInfoByIndex } from '@fullstackfamily/manseryeok'; // 입춘 (0번) const ipchun = getSolarTermInfoByIndex(0); console.log(ipchun.name, ipchun.hanja); // 입춘 立春 // 동지 (21번) const dongji = getSolarTermInfoByIndex(21); console.log(dongji.name, dongji.hanja); // 동지 冬至 // 24절기 전체 출력 for (let i = 0; i < 24; i++) { const term = getSolarTermInfoByIndex(i); console.log(`${i}: ${term.name} (${term.type === 'jeolgi' ? '절기' : '중기'})`); } // 범위 초과 시 예외 try { getSolarTermInfoByIndex(25); } catch (error) { console.log(error.message); // Solar term index must be 0~23, got 25 } ``` -------------------------------- ### Get Supported Solar Term Years Source: https://context7.com/urstory/manseryeok-js/llms.txt Returns a list of years for which solar term timing data is available. Currently supports years from 2020 to 2030. ```typescript import { getSupportedSolarTermYears } from '@fullstackfamily/manseryeok'; const supportedYears = getSupportedSolarTermYears(); console.log('절기 데이터 지원 연도:', supportedYears.join(', ')); // 절기 데이터 지원 연도: 2020, 2021, 2022, 2023, 2024, 2025, 2026, 2027, 2028, 2029, 2030 console.log('지원 연도 수:', supportedYears.length); // 11 console.log('최소 연도:', Math.min(...supportedYears)); // 2020 console.log('최대 연도:', Math.max(...supportedYears)); // 2030 // 특정 연도 지원 여부 확인 function isSolarTermYearSupported(year: number): boolean { return getSupportedSolarTermYears().includes(year); } console.log('2024년 지원:', isSolarTermYearSupported(2024)); // true console.log('2000년 지원:', isSolarTermYearSupported(2000)); // false ``` -------------------------------- ### Check if Before Lichun (Start of Spring) Source: https://context7.com/urstory/manseryeok-js/llms.txt Determines if a Gregorian month and day occur before Lichun (around February 4th). This is used for determining the year pillar, applying the previous year's pillar if before Lichun. ```typescript import { isBeforeLichun } from '@fullstackfamily/manseryeok'; // 입춘(2월 4일) 기준 확인 console.log('1월 1일:', isBeforeLichun(1, 1)); // true console.log('1월 31일:', isBeforeLichun(1, 31)); // true console.log('2월 3일:', isBeforeLichun(2, 3)); // true console.log('2월 4일:', isBeforeLichun(2, 4)); // false (입춘 당일) console.log('2월 5일:', isBeforeLichun(2, 5)); // false console.log('12월 31일:', isBeforeLichun(12, 31)); // false // 년주 결정 로직 예시 function getYearPillarYear(year: number, month: number, day: number): number { // 입춘 이전이면 전년도 년주 적용 if (isBeforeLichun(month, day)) { return year - 1; } return year; } console.log('2024년 1월 15일 년주 연도:', getYearPillarYear(2024, 1, 15)); // 2023 console.log('2024년 2월 5일 년주 연도:', getYearPillarYear(2024, 2, 5)); // 2024 ``` -------------------------------- ### isBeforeLichun - Check if Before Lichun (Start of Spring) Source: https://context7.com/urstory/manseryeok-js/llms.txt Determines if a given Gregorian month and day occur before Lichun (around February 4th). This is used in determining the year pillar for Saju, applying the previous year's pillar if it's before Lichun. ```APIDOC ## isBeforeLichun - 입춘 이전 여부 확인 양력 월/일이 입춘(2월 4일경) 이전인지 확인합니다. 년주 결정에 사용되며, 입춘 이전이면 전년도 년주를 적용합니다. ### Method GET (conceptual, function call in JS) ### Endpoint N/A (JavaScript function) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```javascript import { isBeforeLichun } from '@fullstackfamily/manseryeok'; // 입춘(2월 4일) 기준 확인 console.log('1월 1일:', isBeforeLichun(1, 1)); // true console.log('1월 31일:', isBeforeLichun(1, 31)); // true console.log('2월 3일:', isBeforeLichun(2, 3)); // true console.log('2월 4일:', isBeforeLichun(2, 4)); // false (입춘 당일) console.log('2월 5일:', isBeforeLichun(2, 5)); // false console.log('12월 31일:', isBeforeLichun(12, 31)); // false // 년주 결정 로직 예시 function getYearPillarYear(year, month, day) { // 입춘 이전이면 전년도 년주 적용 if (isBeforeLichun(month, day)) { return year - 1; } return year; } console.log('2024년 1월 15일 년주 연도:', getYearPillarYear(2024, 1, 15)); // 2023 console.log('2024년 2월 5일 년주 연도:', getYearPillarYear(2024, 2, 5)); // 2024 ``` ### Response #### Success Response (Boolean) - Returns `true` if the date is before Lichun. - Returns `false` if the date is on or after Lichun. #### Response Example ```json true ``` ``` -------------------------------- ### Calculate 60-Year Cycle (Gapja) Source: https://context7.com/urstory/manseryeok-js/llms.txt Calculates the year, month, and day pillars of the 60-year cycle for a given solar date. The year pillar changes based on the start of the solar term 'Ipsun' (around February 4th). ```typescript import { getGapja } from '@fullstackfamily/manseryeok'; // 1984년 입춘 이후 (갑자년) const gapja1 = getGapja(1984, 2, 5); console.log('1984년 2월 5일 (입춘 이후)'); console.log('년주:', gapja1.yearPillar, '/', gapja1.yearPillarHanja); // 년주: 갑자 / 甲子 // 1984년 입춘 이전 (아직 계해년) const gapja2 = getGapja(1984, 2, 2); console.log('1984년 2월 2일 (입춘 전)'); console.log('년주:', gapja2.yearPillar, '/', gapja2.yearPillarHanja); // 년주: 계해 / 癸亥 // 완전한 갑자 정보 조회 const gapja3 = getGapja(1990, 5, 15); console.log('=== 1990년 5월 15일 갑자 ==='); console.log(`년주: ${gapja3.yearPillar} (${gapja3.yearPillarHanja})`); console.log(`월주: ${gapja3.monthPillar} (${gapja3.monthPillarHanja})`); console.log(`일주: ${gapja3.dayPillar} (${gapja3.dayPillarHanja})`); // 년주: 경오 (庚午) // 월주: 신사 (辛巳) // 일주: 경진 (庚辰) ``` -------------------------------- ### Get Solar Terms for a Specific Month and Year Source: https://github.com/urstory/manseryeok-js/blob/main/README.md Fetches all solar terms that occur within a specific month of a given year. Provides details like date, time, and name. ```typescript import { getSolarTermsByMonth } from '@fullstackfamily/manseryeok'; // 2024년 2월의 절기 const februaryTerms = getSolarTermsByMonth(2024, 2); februaryTerms.forEach(term => { console.log(`${term.month}/${term.day} ${term.hour}:${String(term.minute).padStart(2, '0')} - ${term.name} (${term.nameHanja})`); }); // 2/4 5:02 - 입춘 (立春) // 2/19 1:23 - 우수 (雨水) ``` -------------------------------- ### Clone Repository Source: https://github.com/urstory/manseryeok-js/blob/main/CONTRIBUTING.md Initial steps to clone the project and navigate to the directory. ```bash git clone https://github.com/urstory/manseryeok-js.git cd manseryeok-js ``` -------------------------------- ### Type Checking and Building Source: https://github.com/urstory/manseryeok-js/blob/main/docs/issue-5-development-plan.md Commands for verifying types and building the project. ```bash npm run typecheck ``` ```bash npm run build ``` -------------------------------- ### Run Project Tests Source: https://github.com/urstory/manseryeok-js/blob/main/docs/issue-5-development-plan.md Execute the test suite for the project. ```bash cd /Users/toto/devel/myprojects/saju/manseryeok-js npm test ``` -------------------------------- ### getSolarTermInfoByIndex - Get Solar Term Info by Index Source: https://context7.com/urstory/manseryeok-js/llms.txt Retrieves Solar Term information using its index (0-23). ```APIDOC ## getSolarTermInfoByIndex - Get Solar Term Info by Index ### Description Retrieves Solar Term information using its index (0-23). Index 0 corresponds to '입춘' (Start of Spring), and index 23 corresponds to '대한' (Great Cold). ### Method `getSolarTermInfoByIndex` ### Parameters - `index` (number) - Required - The index of the Solar Term (0-23). ### Request Example ```javascript import { getSolarTermInfoByIndex } from '@fullstackfamily/manseryeok'; // Get information for the first Solar Term (index 0) const ipchun = getSolarTermInfoByIndex(0); console.log(ipchun.name, ipchun.hanja); // 입춘 立春 // Get information for the 22nd Solar Term (index 21) const dongji = getSolarTermInfoByIndex(21); console.log(dongji.name, dongji.hanja); // 동지 冬至 // Iterate through all Solar Terms for (let i = 0; i < 24; i++) { const term = getSolarTermInfoByIndex(i); console.log(`${i}: ${term.name} (${term.type === 'jeolgi' ? 'Jeolgi' : 'Junggi'})`); } // Example of handling out-of-bounds index try { getSolarTermInfoByIndex(25); } catch (error) { console.error(error.message); // Solar term index must be 0~23, got 25 } ``` ### Response An object containing the Solar Term's information: - `name` (string) - The Korean name of the Solar Term. - `hanja` (string) - The Hanja name of the Solar Term. - `longitude` (number) - The ecliptic longitude. - `type` (string) - The type of the term ('jeolgi' or 'junggi'). - `sajuMonth` (number) - The corresponding Saju month. ### Response Example ```json { "name": "입춘", "hanja": "立春", "longitude": 315, "type": "jeolgi", "sajuMonth": 1 } ``` ### Error Handling - Throws an error if the `index` is outside the range of 0-23. ``` -------------------------------- ### Execute Data Compression Source: https://github.com/urstory/manseryeok-js/blob/main/docs/issue-5-development-plan.md Command to regenerate the compressed data index file. ```bash cd /Users/toto/devel/myprojects/saju/manseryeok-js npm run compress-data ``` -------------------------------- ### Get Solar Term by Name Source: https://github.com/urstory/manseryeok-js/blob/main/README.md Fetches a specific solar term by its Korean name. Returns undefined if the name is not found. ```typescript // 절기 이름으로 조회 const ipchun = getSolarTermByName('입춘'); console.log('입춘:', ipchun?.nameHanja, '황경', ipchun?.longitude, '°'); // 입춘: 立春 황경 315 ° ``` -------------------------------- ### getSolarTermsBySajuMonth - Get Solar Terms by Saju Month Source: https://context7.com/urstory/manseryeok-js/llms.txt Retrieves a list of Solar Terms corresponding to a specific Saju month (1-12). ```APIDOC ## getSolarTermsBySajuMonth - Get Solar Terms by Saju Month ### Description Retrieves a list of Solar Terms corresponding to a specific Saju month (1-12). Each Saju month contains two terms: one Jieqi (節氣) and one Zhongqi (中氣). ### Method `getSolarTermsBySajuMonth` ### Parameters - `sajuMonth` (number) - Required - The Saju month to query (1-12). ### Request Example ```javascript import { getSolarTermsBySajuMonth } from '@fullstackfamily/manseryeok'; // Get terms for Saju Month 1 (寅月) const month1Terms = getSolarTermsBySajuMonth(1); console.log('Saju Month 1 Terms:'); month1Terms.forEach(term => { console.log(` ${term.name} (${term.hanja}) - ${term.type === 'jeolgi' ? 'Jieqi' : 'Zhongqi'}`); }); // Get terms for Saju Month 5 (午月) const month5Terms = getSolarTermsBySajuMonth(5); console.log('Saju Month 5 Terms:', month5Terms.map(t => t.name).join(', ')); // Get terms for all Saju months for (let m = 1; m <= 12; m++) { const terms = getSolarTermsBySajuMonth(m); console.log(`${m} Month: ${terms.map(t => t.name).join(', ')}`); } ``` ### Response An array of two objects, each representing a Solar Term within the specified Saju month: - `name` (string) - The Korean name of the Solar Term. - `hanja` (string) - The Hanja name of the Solar Term. - `longitude` (number) - The ecliptic longitude. - `type` (string) - The type of the term ('jeolgi' or 'junggi'). - `sajuMonth` (number) - The corresponding Saju month. ### Response Example ```json [ { "name": "입춘", "hanja": "立春", "longitude": 315, "type": "jeolgi", "sajuMonth": 1 }, { "name": "우수", "hanja": "雨水", "longitude": 330, "type": "junggi", "sajuMonth": 1 } ] ``` ``` -------------------------------- ### getSolarTermInfoByName - Get Solar Term Info by Name Source: https://context7.com/urstory/manseryeok-js/llms.txt Retrieves the basic information for a specific Solar Term using its Korean name. ```APIDOC ## getSolarTermInfoByName - Get Solar Term Info by Name ### Description Retrieves the basic information for a specific Solar Term using its Korean name. Returns `undefined` if no matching term is found. ### Method `getSolarTermInfoByName` ### Parameters - `name` (string) - Required - The Korean name of the Solar Term to search for (e.g., '입춘'). ### Request Example ```javascript import { getSolarTermInfoByName } from '@fullstackfamily/manseryeok'; const ipchun = getSolarTermInfoByName('입춘'); if (ipchun) { console.log('Name:', ipchun.name); console.log('Hanja:', ipchun.hanja); console.log('Longitude:', ipchun.longitude); console.log('Type:', ipchun.type); console.log('Saju Month:', ipchun.sajuMonth); } const dongji = getSolarTermInfoByName('동지'); console.log(`Dongji (${dongji?.hanja}): Longitude ${dongji?.longitude}°`); const notFound = getSolarTermInfoByName('없는절기'); console.log('Search Result:', notFound); // undefined ``` ### Response An object containing the Solar Term's information if found, otherwise `undefined`. - `name` (string) - The Korean name of the Solar Term. - `hanja` (string) - The Hanja name of the Solar Term. - `longitude` (number) - The ecliptic longitude. - `type` (string) - The type of the term ('jeolgi' or 'junggi'). - `sajuMonth` (number) - The corresponding Saju month. ### Response Example ```json { "name": "입춘", "hanja": "立春", "longitude": 315, "type": "jeolgi", "sajuMonth": 1 } ``` ``` -------------------------------- ### Development Scripts Source: https://github.com/urstory/manseryeok-js/blob/main/CONTRIBUTING.md Commonly used npm scripts for building, testing, and type checking. ```bash # 빌드 npm run build # 테스트 실행 npm test # 타입 체크 npm run typecheck # 테스트 감시 모드 npm run test:watch # 테스트 커버리지 확인 npm run test:coverage ``` -------------------------------- ### Update Version and Commit Source: https://github.com/urstory/manseryeok-js/blob/main/docs/issue-5-development-plan.md Update the version in package.json and commit changes with a tag. ```json "version": "1.0.7" ``` ```bash git add -A git commit -m "fix: 월주(monthPillarId) 절기 기준 재계산 (Issue #5) - getSajuMonth() 기본값 버그 수정 (축월→자월) - compress-date-index.ts에 오호둔법 재계산 로직 추가 - date-index-compressed.ts 데이터 재생성 - 월주 절기 기준 검증 테스트 추가" git tag v1.0.7 ``` -------------------------------- ### Get Solar Terms by Saju Month Source: https://context7.com/urstory/manseryeok-js/llms.txt Returns the two solar terms (Jeolgi and Junggi) associated with a specific Saju month. ```typescript import { getSolarTermsBySajuMonth } from '@fullstackfamily/manseryeok'; // 인월(寅月, 사주 1월)의 절기 const month1Terms = getSolarTermsBySajuMonth(1); console.log('인월(1월) 절기:'); month1Terms.forEach(term => { console.log(` ${term.name} (${term.hanja}) - ${term.type === 'jeolgi' ? '절기' : '중기'}`); }); // 인월(1월) 절기: // 입춘 (立春) - 절기 // 우수 (雨水) - 중기 // 오월(午月, 사주 5월)의 절기 const month5Terms = getSolarTermsBySajuMonth(5); console.log('오월(5월) 절기:', month5Terms.map(t => t.name).join(', ')); // 오월(5월) 절기: 망종, 하지 // 전체 사주 월별 절기 매핑 for (let m = 1; m <= 12; m++) { const terms = getSolarTermsBySajuMonth(m); console.log(`${m}월: ${terms.map(t => t.name).join(', ')}`); } ``` -------------------------------- ### Add Month Pillar Verification Tests Source: https://github.com/urstory/manseryeok-js/blob/main/docs/issue-5-development-plan.md Unit tests for validating month pillar calculations based on solar terms and the Five Tiger Method. ```typescript describe('월주 절기 기준 검증 (Issue #5)', () => { describe('1996년(丙子年) 전체 월 순환', () => { const cases = [ { date: [1996, 2, 4], expected: '庚寅', desc: '인월 (입춘)' }, { date: [1996, 3, 6], expected: '辛卯', desc: '묘월 (경칩)' }, { date: [1996, 4, 5], expected: '壬辰', desc: '진월 (청명)' }, { date: [1996, 5, 6], expected: '癸巳', desc: '사월 (입하)' }, { date: [1996, 6, 6], expected: '甲午', desc: '오월 (망종)' }, { date: [1996, 7, 7], expected: '乙未', desc: '미월 (소서)' }, { date: [1996, 8, 8], expected: '丙申', desc: '신월 (입추)' }, { date: [1996, 9, 8], expected: '丁酉', desc: '유월 (백로)' }, { date: [1996, 10, 8], expected: '戊戌', desc: '술월 (한로)' }, { date: [1996, 11, 8], expected: '己亥', desc: '해월 (입동)' }, { date: [1996, 12, 7], expected: '庚子', desc: '자월 (대설)' }, ]; cases.forEach(({ date, expected, desc }) => { test(`${date.join('-')} → ${expected} (${desc})`, () => { const gapja = getGapja(date[0], date[1], date[2]); expect(gapja.monthPillarHanja).toBe(expected); }); }); }); describe('절기 경계 검증', () => { test('소한 전 (1996-01-01) → 자월 戊子', () => { expect(getGapja(1996, 1, 1).monthPillarHanja).toBe('戊子'); }); test('소한 후 (1996-01-06) → 축월 己丑', () => { expect(getGapja(1996, 1, 6).monthPillarHanja).toBe('己丑'); }); test('입춘 전 (1996-02-03) → 축월 己丑', () => { expect(getGapja(1996, 2, 3).monthPillarHanja).toBe('己丑'); }); test('입춘 당일 (1996-02-04) → 인월 庚寅', () => { expect(getGapja(1996, 2, 4).monthPillarHanja).toBe('庚寅'); }); test('청명 전 (1996-04-04) → 묘월 辛卯', () => { expect(getGapja(1996, 4, 4).monthPillarHanja).toBe('辛卯'); }); test('청명 당일 (1996-04-05) → 진월 壬辰', () => { expect(getGapja(1996, 4, 5).monthPillarHanja).toBe('壬辰'); }); }); describe('오호둔법 연간별 검증', () => { // 갑/기년 → 병인(丙寅) 시작 test('2024 갑진년 인월 → 丙寅', () => { expect(getGapja(2024, 2, 4).monthPillarHanja).toBe('丙寅'); }); // 을/경년 → 무인(戊寅) 시작 test('2025 을사년 인월 → 戊寅', () => { expect(getGapja(2025, 2, 4).monthPillarHanja).toBe('戊寅'); }); // 병/신년 → 경인(庚寅) 시작 test('1996 병자년 인월 → 庚寅', () => { expect(getGapja(1996, 2, 4).monthPillarHanja).toBe('庚寅'); }); // 정/임년 → 임인(壬寅) 시작 test('1997 정축년 인월 → 壬寅', () => { expect(getGapja(1997, 2, 4).monthPillarHanja).toBe('壬寅'); }); // 무/계년 → 갑인(甲寅) 시작 test('1998 무인년 인월 → 甲寅', () => { expect(getGapja(1998, 2, 4).monthPillarHanja).toBe('甲寅'); }); }); describe('경계 연도 검증', () => { // 데이터 범위 시작 연도 (1900 庚子年) test('1900-02-05 경자년 인월 → 戊寅', () => { expect(getGapja(1900, 2, 5).monthPillarHanja).toBe('戊寅'); }); test('1900-01-01 기해년 자월 → 丙子', () => { expect(getGapja(1900, 1, 1).monthPillarHanja).toBe('丙子'); }); // 데이터 범위 끝 연도 (2050 庚午年) test('2050-02-04 경오년 인월 → 戊寅', () => { expect(getGapja(2050, 2, 4).monthPillarHanja).toBe('戊寅'); }); test('2050-12-07 경오년 자월 → 戊子', () => { expect(getGapja(2050, 12, 7).monthPillarHanja).toBe('戊子'); }); }); }); ``` -------------------------------- ### Data Pipeline Trace for Month Pillar Calculation Source: https://github.com/urstory/manseryeok-js/blob/main/docs/issue-5-month-pillar-bug-analysis.md This diagram illustrates the data flow from the KASI API to the compressed date index, highlighting where the incorrect lunar-based month pillar data originates. ```text KASI API (astro.kasi.re.kr) └─ LUNC_WLGN 필드 = "음력 월 갑자" (음력 1일 기준으로 변경됨) └─ populate-from-kasi-solc.ts:119 └─ gapjaToId(response.LUNC_WLGN) → month_pillar_id └─ MySQL DB (manseryeok_dates 테이블) └─ dump-mysql-data.ts → manseryeok-dates.json └─ convert-to-js-data.ts → date-index.ts (11.4MB) └─ compress-date-index.ts → date-index-compressed.ts (227KB) ``` -------------------------------- ### Get All Solar Terms Source: https://github.com/urstory/manseryeok-js/blob/main/README.md Retrieves a list of all 24 solar terms. Useful for displaying a full calendar or performing general lookups. ```typescript import { getAllSolarTerms } from '@fullstackfamily/manseryeok'; // 전체 24절기 목록 const allTerms = getAllSolarTerms(); console.log('24절기 개수:', allTerms.length); // 24절기 개수: 24 ``` -------------------------------- ### Import getSajuMonth in compression script Source: https://github.com/urstory/manseryeok-js/blob/main/docs/issue-5-development-plan.md Adds the necessary import for the recalculation logic in the compression script. ```typescript import { getSajuMonth } from '../src/core/solar-term'; ``` -------------------------------- ### Verify Boundary Cases for Solar Terms Source: https://github.com/urstory/manseryeok-js/blob/main/docs/issue-5-month-pillar-bug-analysis.md Tests the `getGapja` function around critical solar term dates (Sohan, Lichun, Qingming) to ensure correct month pillar assignment before and after the term. ```typescript // 소한 경계 (1996년) expect(getGapja(1996, 1, 1).monthPillarHanja).toBe('戊子'); // 자월 (소한 전) expect(getGapja(1996, 1, 6).monthPillarHanja).toBe('己丑'); // 축월 (소한 후) // 입춘 경계 expect(getGapja(1996, 2, 3).monthPillarHanja).toBe('己丑'); // 축월 (입춘 전) expect(getGapja(1996, 2, 4).monthPillarHanja).toBe('庚寅'); // 인월 (입춘 당일) // 청명 경계 (이슈 리포트의 핵심 케이스) expect(getGapja(1996, 4, 4).monthPillarHanja).toBe('辛卯'); // 묘월 (청명 전) expect(getGapja(1996, 4, 5).monthPillarHanja).toBe('壬辰'); // 진월 (청명 당일) ``` -------------------------------- ### Applying Runtime Correction in solarToLunar Source: https://github.com/urstory/manseryeok-js/blob/main/docs/issue-5-month-pillar-bug-analysis.md This code shows how to integrate the `computeMonthPillarId` function into `solarToLunar` to recalculate and use the correct month pillar ID before formatting the Gapja. ```typescript // solar-lunar-converter.ts (수정) export function solarToLunar(solarYear, solarMonth, solarDay) { // ... 기존 코드 ... // 월주 보정: 저장된 monthPillarId 대신 절기 기반 재계산 const correctedMonthPillarId = computeMonthPillarId( solarYear, solarMonth, solarDay, entry.gapja.yearPillarId ); const gapja = formatGapjaByIds( entry.gapja.yearPillarId, correctedMonthPillarId, // ← 보정된 값 사용 entry.gapja.dayPillarId ); // ... 기존 코드 ... } ``` -------------------------------- ### Generate Monthly Calendar (Solar to Lunar) Source: https://github.com/urstory/manseryeok-js/blob/main/README.md Creates a monthly calendar by converting solar dates to lunar dates and displaying the corresponding 60갑자. This function is useful for displaying traditional calendars. ```typescript import { solarToLunar } from '@fullstackfamily/manseryeok'; function printCalendar(year: number, month: number) { console.log(`\n=== ${year}년 ${month}월 ===`); console.log('양력\t음력\t\t갑자'); console.log(''.padEnd(40, '-')); const daysInMonth = new Date(year, month, 0).getDate(); for (let day = 1; day <= daysInMonth; day++) { const result = solarToLunar(year, month, day); const lunarStr = `${result.lunar.month}/${result.lunar.day}${result.lunar.isLeapMonth ? ' 윤' : ''}`; const gapjaStr = `${result.gapja.yearPillar} ${result.gapja.dayPillar}`; console.log(`${month}/${day}\t${lunarStr}\t\t${gapjaStr}`); } } // 2024년 2월 달력 printCalendar(2024, 2); ``` -------------------------------- ### Get Solar Term for a Specific Date Source: https://context7.com/urstory/manseryeok-js/llms.txt Retrieves the solar term for a given date. Returns null if the date is not within one day of a solar term. ```typescript import { getSolarTermForDate } from '@fullstackfamily/manseryeok'; // 2024년 입춘 (2월 4일) const term = getSolarTermForDate(2024, 2, 4); if (term) { console.log('2024년 2월 4일은', term.name, '입니다'); console.log(`정확한 시각: ${term.month}월 ${term.day}일 ${term.hour}시 ${term.minute}분`); console.log(`황경: ${term.longitude}°`); } // 2024년 2월 4일은 입춘 입니다 // 정확한 시각: 2월 4일 5시 2분 // 황경: 315° // 절기가 아닌 날 const noTerm = getSolarTermForDate(2024, 2, 15); console.log('2024년 2월 15일 절기:', noTerm); // null // 동지 확인 const dongji = getSolarTermForDate(2024, 12, 21); console.log('2024년 12월 21일:', dongji?.name); // 동지 ```