@senspond

>

개발기>App 개발기

사주 만세력 JAVA 백엔드 개발 - 4 - 시주 계산로직 만들기

등록일시 : 2024-01-28 (일) 11:55
업데이트 : 2024-01-28 (일) 04:19
오늘 조회수 : 341
총 조회수 : 3184

    대한민국 표준시 동경135도, 명리학에서 시주를 세우는 법에 대한 내용을 정리해보고 JAVA 프로그램을 통해 시주를 계산해본 내용입니다.

    안녕하세요. 이번에는 시주를 계산하는 로직을 만들어 볼 것입니다. 먼저 알아야만 하는 사전 지식들이 있습니다.


    대한민국 표준시

    현재 우리나라는 동경 135도에 맞춘 UTC+9를 표준시로 사용하고 있습니다. 그러나 역사적으로 우리나라의 표준시는 계속 바뀌어 왔습니다. 시기에 따라 우리나라에서 사용된 표준시를 적어보면 아래와 같습니다.


    표준 자오선

    사용 기간

    관련 법령

    동경 127도 30분

    1908년 4월 1일 ~ 1911년 12월 31일

    관보 제 3994호(칙령 제5호)

    동경 135도

    1912년 1월 1일 ~ 1954년 3월 20일

    조선총독부 관보 제367호(고시 제338호)

    동경 127도 30분

    1954년 3월 21일 ~ 1961년 8월 9일

    대통령령 제876호(1954년 3월 17일)

    동경 135도

    1961년 8월 10일 ~ 현재

    법률 제676호(1961년 8월 7일) 법률 제3919호(1986년 12월 31일)


    정확하게 한국 국토 중심부를 지나는 127도 30분 자오선을 기준으로 하는것이 정확한 시간인데... 일본이 조선총독부를 세우며 멋대로 한국 표준시를 일본 도쿄를 지나고 있는 동경135도를 기준으로 변경한 이후로 현재에 이르기까지 이 시간을 한국 표준시로 쓰고 있기 때문입니다. 한때 일본의 잔재를 벗어나야 한다는 이유로 한때 다시 동격 127도 30분으로 변경하게 되었지만.. 군사정권이 이어지며 연합훈련 등등 여러 이유로 인해서 다시 동경135로 변경 되었고 아직까지 쓰고 있습니다.


    현재 대부분의 만세력은 한국천문연구원에서 발표한 24절기 절입시각을 표기하고 있습니다. 그런데 이 시각은 동경 135도 기준시각입니다. 법적인 표준시간이 동경135도 이기때문에 어쩔 수 없겠지만... 4차례나 30분씩 표준시간이 바뀐 전적도 있고...전통학문을 하는 사람들 입장에서는 혼란스러운 일입니다.


    명리학에서 시주를 계산하는 방법

    십이지지를 이용한 동양의 전통적 시간 표기법과 현재 사용하는 시간 표기법의 대응표는 다음과 같습니다.


    십이지지 시간표

    시간

    시지(시주의 지지)

    23시 - 1시

    子時(자시)

    1시 - 3시

    丑時(축시)

    3시 - 5시

    寅時(인시)

    5시 - 7시

    卯時(묘시)

    7시 - 9시

    辰時(진시)

    9시 - 11시

    巳時(사시)

    11시 - 13시

    午時(오시)

    13시 - 15시

    未時(미시)

    15시 - 17시

    申時(신시)

    17시 - 19시

    酉時(유시)

    19시 - 21시

    戌時(술시)

    21시 - 23시

    亥時(해시)


    전통 명리학에서 자시는 23:00 시부터 01:00 까지 입니다.

    하지만, 한국에는 사주팔자를 뽑을 때는 다른 시간을 적용하는데요. 그 이유는 다음과 같습니다.


    앞서 설명했듯이 정확하게 한국 국토 중심부를 지나는 127도 30분 자오선인데... 동경 135도를 기준인 표준시로 계산하게 되면 시간이 맞지 않게 되어 잘못된 사주를 뽑게 됩니다. 한국과 일본의 시간차이는 약 30분 정도가 나는데요. 만약, 우리나라가 실제 경도에 딱 맞는 표준시를 썼다면 아침 7시는 사실 아침 6시 30분이 되게 됩니다. 그러니까 실제 우리가 알고 있는 시간보다 30분 일찍 살고 있는 아침의 나라라는 것입니다.


    아무튼 그래서 이 한국의 역사적 배경과 현실에 맞게 30분을 조정해서 다음과 같은 조견표를 가지고 시주를 세웁니다.


    한국 출생시간 기준 시주 조견표


    甲己日

    乙庚日

    丙辛日

    丁壬日

    戊癸日

    23:30 ~ 01:30(자시)

    甲子

    丙子

    戊子

    庚子

    壬子

    01:30 ~ 03:30(축시)

    乙丑

    丁丑

    己丑

    辛丑

    癸丑

    03:30 ~ 05:30(인시)

    丙寅

    戊寅

    庚寅

    壬寅

    甲寅

    05:30 ~ 07:30(묘시)

    丁卯

    己卯

    辛卯

    癸卯

    乙卯

    07:30 ~ 09:30(진시)

    戊辰

    庚辰

    壬辰

    甲辰

    丙辰

    09:30 ~ 11:30(사시)

    己巳

    辛巳

    癸巳

    乙巳

    丁巳

    11:30 ~ 13:30(오시)

    庚午

    壬午

    甲午

    丙午

    戊午

    13:30 ~ 15:30(미시)

    辛未

    癸未

    乙未

    丁未

    己未

    15:30 ~ 17:30(신시)

    壬申

    甲申

    丙申

    戊申

    庚申

    17:30 ~ 19:30(유시)

    癸酉

    乙酉

    丁酉

    己酉

    辛酉

    19:30 ~ 21:30(술시)

    甲戌

    丙戌

    戊戌

    庚戌

    壬戌

    21:30 ~ 23:30(해시)

    乙亥

    丁亥

    己亥

    辛亥

    癸亥


    아무튼 저 조건표를 기준으로 예시를 들어보겠습니다.

    만약 갑기일에 해당하는 일주가 묘시에 태어났다면 시주는 정묘(丁卯)가 됩니다.


    어떻게 프로그래밍을 할 것인가?

    지금까지 개발에 필요한 사전 지식들에 대해서 설명을 했습니다. 그냥 저 조건표에서 해당하는 것을 그냥 선택하면 되는 간단한 것이 아니냐고 반문하실 수 있겠지만... 코딩을 해보신 분들은 공감하실 수 있겠지만 컴퓨터는 사람같은 인지능력을 가지고 있지 않은 0과 1밖에 모르는 바보 중의 바보입니다.


    그래서 바보에게 일을 시키는 가장 간단한 방법은 저 조견표에 해당하는 모든케이스들을 하드코딩으로 집어넣고 찾을 수 있도록 만드는 것입니다. 그런데 가로 세로를 곱해보면 12 X 5 = 60 개의 케이스가 됩니다. 그만큼 사람이 노가다를 해야한다는 뜻입니다. 상당히 귀찮은 작업입니다. 그래서 일련의 규칙성을 찾아봅니다.


    시주 조견표의 수학적 패턴찾기


    甲(1) 또는 己(6)

    乙(2) 또는 庚 (7)

    丙(3) 또는 辛(8)

    丁(4) 또는 壬(9)

    戊(5) 또는 癸(10)

    자(1)

    甲(1) 子(1)

    丙(3) 子(1)

    戊(5) 子(1)

    庚(7) 子(1)

    壬(9) 子(1)

    축(2)

    乙(2) 丑 (2)

    丁(4) 丑(2)

    己(6) 丑(2)

    辛(8) 丑(2)

    癸(10) 丑(2)

    인(3)

    丙(3) 寅 (3)

    戊(5) 寅(3)

    庚(7) 寅(3)

    壬(9) 寅(3)

    甲(1) 寅(3)

    묘(4)

    丁(4) 卯 (4)

    己(6) 卯(4)

    辛(8) 卯(4)

    癸(10) 卯(4)

    乙(2) 卯(4)

    진(5)

    戊(5) 辰(5)

    庚(7) 辰(5)

    壬(9) 辰(5)

    甲(1) 辰(5)

    丙(3) 辰(5)

    사(6)

    己(6) 巳(6)

    辛(8) 巳(6)

    癸巳

    乙巳

    丁巳

    오(7)

    庚(7) 午(7)

    壬(9) 午(7)

    甲午

    丙午

    戊午

    미(8)

    辛(8) 未(8)

    癸(10) 未(8)

    乙未

    丁未

    己未

    신(9)

    壬(9) 申(9)

    甲(1) 申(9)

    丙申

    戊申

    庚申

    유(10)

    癸(10) 酉(10)

    乙(2) 酉(10)

    丁酉

    己酉

    辛酉

    술(11)

    甲(1) 戌(11)

    丙戌

    戊戌

    庚戌

    壬戌

    해(12)

    乙(2) 亥(12)

    丁亥

    己亥

    辛亥

    癸亥


    여기서 일련의 규칙성이 있음을 발견 할 수가 있습니다. ( 쓰다가 귀찮아서 나머지는 그냥 두었습니다..)

    일간은 5가 넘어가면 -5 를 해서 넣은 값과 동일하고요.

    아래로 내려갈때 시간은 1씩 이동하고 오른쪽으로 갈때 2씩 이동하네요. 그러다가 10을 초과하면 다시 1이 됩니다.


    프로그램화


    필요한 입력값

    • x : 일간 숫자 (입력 범위 1 ~ 12)

    • y : 시지 숫자 (입력 범위 1 ~ 10)


    예를들어 x : 庚 (7) 일간이 y : 유(10)시에 태어났다면 乙(2) 酉(10) 시 라는 결과가 도출되어야 합니다.

        private void calculatorTime(int x, int y, int ox, int oy){
            
    			  int dx = x > 5 ? x - 5 : x;
            int oX = (y + ((dx-1) *2 )); // 시간숫자
           		  oX = oX > 10 ? oX -10 : oX;
            int oY = y; // 시지숫자
    			   
            System.out.println(oX + ":" + oY);
            assertEquals(oX , ox);  // oX 의 값이 ox와 같은지 검증
            assertEquals(oY , oy);
        }
    
        @Test
        public void test(){
            calculatorTime(7,10, 2, 10); // 庚 (7) 일간이 유(10)시에 태어났다면 乙(2) 酉(10)
            calculatorTime(3,3, 7, 3);   // 丙(3) 일간이 寅(3)시에 태어났다면 庚(7) 寅(3)
            calculatorTime(9,5, 1, 5);  // 壬(9) 일간이 辰(5)시에 태어났다면  甲(1) 辰(5)
        }

    로직을 만들었고 몇가지 경우의 수를 입력해서 테스트를 해봤습니다.


    그럼 실제 사용중인 코드에 맞게 적용을 해보겠습니다.


    프로젝트에 적용

    이 개발기 1편을 보면 처음 만들었을때 아래처럼 천간과 지지에 대한 정보를 상수화 해서 만들어 줬습니다.

    @AllArgsConstructor
    @Getter
    @ToString
    @JsonFormat(shape = JsonFormat.Shape.OBJECT)
    public enum Sky implements GanJi {(1,"갑", "甲", WuXing., YinYang.),(2,"을", "乙", WuXing., YinYang.),(3,"병", "丙", WuXing., YinYang.),(4,"정", "丁", WuXing., YinYang.),(5,"무", "戊", WuXing., YinYang.),(6,"기", "己", WuXing., YinYang.),(7,"경", "庚", WuXing., YinYang.),(8,"신", "辛", WuXing., YinYang.),(9,"임", "壬", WuXing., YinYang.),(10,"계", "癸", WuXing.,YinYang.);
    
        private final int idx;
        private final String korean;
        private final String chinese;
        //@JsonFormat(shape = JsonFormat.Shape.STRING)
        private final WuXing wuXing;
        //@JsonFormat(shape = JsonFormat.Shape.STRING)
        private final YinYang yinYang;
    
        public static final Map<Integer, Sky> indexMap =
                Stream.of(values()).collect(toMap(Sky::getIdx, v -> v));
    }


    아까 만들어 확인해본 로직을 그대로 옮겨서 현재 개발중인 코드에 옮겼습니다.

        /**
         * 일간과 시지를 입력받아 시간(천간)을 리턴한다.
         * @param daySky        일간(천간)
         * @param groundTime    시지(지지)
         * @return 시간
         */
        public Sky calculateTimeSky(Sky daySky, Ground groundTime){
            int daySkyIndex = daySky.getIdx();
            int groundTimeIndex = groundTime.getIdx();
    
            int dx = daySkyIndex <= 5 ? daySkyIndex : daySkyIndex - 5;
            int idx = (groundTimeIndex + ((dx-1) *2 ));
                idx = idx > 10 ? idx -10 : idx;
    
           return Sky.indexMap.get(oX);
        }


    시간 입력정보로부터 시지 변환

    다음으로 필요한 것은 사용자에게 입력받은 07:30 ~ 09:30 와 같은 시간 정보를 Ground 객체로 변환하는 것입니다.

    이것도 일련의 규칙성을 찾아 로직을 만들었습니다.

        /**
         * 입력시간 문자열로부터 명리학 몇시에 해당하는지 시지 응답
         * @param  timeStr hh:mm 형식의 시간
         * @return Ground  시지
         * @throws NumberFormatException
         */
        public Ground findGround(String timeStr) throws NumberFormatException{
            String[] timDiv = timeStr.split(":");
            LocalTime time = LocalTime.of(Integer.parseInt(timDiv[0]), Integer.parseInt(timDiv[1]));
            // 기준의 되는 시간 자시 (23:29 < x < 01:30)
            LocalTime start = LocalTime.of(23, 29);
            LocalTime end = LocalTime.of(01, 30);
            Ground timeGround = Ground.;
    
            // 지지 갯수만큼 반복
            for(int i = 0; i < 12; i++){
                if(time.isAfter(start) && time.isBefore(end)){
                    timeGround = Ground.indexMap.get(i+1);
                    break; // 찾으면 반복문 중지
                }
                // next time
                start = start.plusHours(2);
                end = end.plusHours(2);
            }
            return timeGround;
        }
    


    테스트 코드로 검증해봅니다.

        @Test
        public void findGroundTest() {
            assertEquals(mansesService.findGround("23:30"), Ground.); // 23:30 자시
            assertEquals(mansesService.findGround("01:29"), Ground.); // 01:29 자시
            assertEquals(mansesService.findGround("01:30"), Ground.); // 01:30 축시
            assertEquals(mansesService.findGround("03:28"), Ground.); 
            assertEquals(mansesService.findGround("03:30"), Ground.);
            assertEquals(mansesService.findGround("05:28"), Ground.);
            assertEquals(mansesService.findGround("05:30"), Ground.);
            assertEquals(mansesService.findGround("08:30"), Ground.);
            assertEquals(mansesService.findGround("19:30"), Ground.);
            assertEquals(mansesService.findGround("21:30"), Ground.);
            assertEquals(mansesService.findGround("23:29"), Ground.);
        }
    
    



    만세력 조회 데이터에 시주 세팅

        /**
         * 만세력 조회 응답 DTO 에서 시주를 세팅
         * @param responseDto
         */
        public void setTimeSkyAndGround(ManseResponseDto responseDto){
            String inputTime = responseDto.getTime();
            Sky daySky = Sky.from(responseDto.getDaySky());
            Ground dayGround = findGround(inputTime);
            Sky timeSky = calculateTimeSky(daySky, dayGround);
            responseDto.setTimeSky(timeSky.getChinese());
            responseDto.setTimeGround(dayGround.getChinese());
        }


    최종 결과 확인


    양력 1988년 1월 28일 23:40분 야자시/조자시 미적용. 출력결과 정묘년 계축월 계미일 임자시 로 나왔네요.

    실제 서비스되고 있는 만세력하고 비교해보며 검증해보고 있습니다. 다음은 대운과 세운을 계산하는 로직을 만들고 웹으로 구성할 프론트엔드 UI 를 구성해봐야 합니다.


    senspond

    안녕하세요. Red, Green, Blue 가 만나 새로운 세상을 만들어 나가겠다는 이상을 가진 개발자의 개인공간입니다.

    댓글 ( 0 )

    카테고리내 관련 게시글

    현재글에서 작성자가 발행한 같은 카테고리내 이전, 다음 글들을 보여줍니다

    @senspond

    >

    개발기>App 개발기

    • 앱개발 애드몹 광고송출 안되는 오류 Ad failed to load : 3.. 광고실패 처리 필요성

      앱개발 애드몹 광고송출 안되는 오류 Ad failed to load : 3를 겪어보면서 써본 글입니다.
        2024-09-15 (일) 10:37
      1. 사주 만세력 JAVA 백엔드 개발 - 2 - 오행의 상생/상극 관계를 표현, 천간지지 상극관계, 육친관계 분석

        JAVA 프로그래밍으로 사주명리학의 오행의 상생/상극 관계를 표현하고 천간과 지지 간의 상극 관계, 육친관계를 분석할 수 있도록 구현해 본 글입니다.
          2023-09-06 (수) 01:10
        1. 사주 만세력 JAVA 백엔드 개발 - 3 - 만세력 DB 구축하기, 24절기, 절입조정, 서머타임, 야자시/조자시 개념

          프로그램 개발을 위한 만세력 DB 구축하기, 24절기, 절입조정, 서머타임, 야자시/조자시 개념을 정리해본 글입니다.
            2024-01-28 (일) 10:22
          1. [현재글] 사주 만세력 JAVA 백엔드 개발 - 4 - 시주 계산로직 만들기

            대한민국 표준시 동경135도, 명리학에서 시주를 세우는 법에 대한 내용을 정리해보고 JAVA 프로그램을 통해 시주를 계산해본 내용입니다.
              2024-01-28 (일) 11:55
            1. 모바일 앱 구글 플레이 스토어 심사 거절후기. 거절 사유가?

              구글 플레이스토어 앱출시 거절된 이야기를 담아봤습니다.
                2024-09-23 (월) 06:29