@senspond
>
대한민국 표준시 동경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 를 구성해봐야 합니다.
안녕하세요. Red, Green, Blue 가 만나 새로운 세상을 만들어 나가겠다는 이상을 가진 개발자의 개인공간입니다.
현재글에서 작성자가 발행한 같은 카테고리내 이전, 다음 글들을 보여줍니다
@senspond
>