음력 ==> 양력변환 5 10 13,420

by 문대훈 [2010.04.30 17:04:44]


어떤분이 작업 해 놓은 자료 입니다...
필요할것 같아서 올려 놓아요...
펑션입니다.


CREATE OR REPLACE FUNCTION Lunar_To_Solar( as_lunar IN CHAR )
    RETURN VARCHAR2
    IS
   Out_Of_Range exception;
   ls_return VARCHAR2(100);
   LunerY  NUMBER(5) := 0 ;
   LunerM  NUMBER(5) := 0 ;
   LunerD  NUMBER(5) := 0 ;
   i  NUMBER(5) := 0 ;
   j NUMBER(5) := 0 ;

    -- 1921년부터 해당년까지의 년수
   ll_FromYear   NUMBER(10) := 0 ;
   ls_YunMon    VARCHAR2(500); --윤달
   ls_YunLen VARCHAR2(500);    --윤달의 길이(29 OR 30)

 --매년 정상적인 달의 길이의 합
    --( 12 byte의 자리값 * (30일인 경우만 1 ) 의 합)
   ls_MonLen VARCHAR2(500)  ;
   ls_lYearDay    VARCHAR2(500);   --음력으로 윤달의 길이(29 OR 30)
   ls_SolarMon    VARCHAR2(39) ;
  
    --0000-00-00부터 해당일자까지의 누적일수
   ll_DaySum     NUMBER(10);

   li_M NUMBER(5) := 0 ;
   MM NUMBER(5) := 0 ;
   MK NUMBER(5):=0 ;

   v_loop NUMBER(5) :=0;

   li_PrevYear NUMBER(5):=0;
   li_OneYearDay  NUMBER(5):=0;
   NA NUMBER(5):=0;
   YD NUMBER(5):=0;
   KA NUMBER(5):=0;
   SolarY NUMBER(5):=0 ;
   SolarM NUMBER(5):=0 ;
   SolarD NUMBER(5):=0;
BEGIN
    LunerY := TO_NUMBER(SUBSTR( as_lunar,1,4)) + 2333;
    LunerM := TO_NUMBER(SUBSTR( as_lunar,5,2));
    LunerD := TO_NUMBER(SUBSTR( as_lunar,7,2));

    -- 1921-2030년 범위, 1-12월 범위, 1-31일 범위를 벗어날 경우 에러처리.
    IF (SUBSTR(as_lunar,1,4) < '1921' OR SUBSTR(as_lunar,1,4) > '2030')
   OR
   (SUBSTR(as_lunar,5,2) < '01' OR SUBSTR(as_lunar,5,2) > '12')
   OR
   (SUBSTR(as_lunar,7,2) < '01' OR SUBSTR(as_lunar,7,2) > '31')
   THEN
   raise Out_Of_Range;
    END IF ;

   --1921 - 2030
   ls_YunMon := ' 0 5 0 0 4 0 0 2 0 6'||
  ' 0 0 5 0 0 3 0 7 0 0'||
  ' 6 0 0 4 0 0 2 0 7 0'||
  ' 0 5 0 0 3 0 8 0 0 6'||
  ' 0 0 4 0 0 3 0 7 0 0'||
  ' 5 0 0 4 0 8 0 0 6 0'||
  ' 0 4 010 0 0 6 0 0 5'||
  ' 0 0 3 0 8 0 0 5 0 0'||
  ' 4 0 0 2 0 7 0 0 5 0'||
  ' 0 3 0 9 0 0 5 0 0 4'||
  ' 0 0 2 0 6 0 0 5 0 0';
   --1921 - 2030
   ls_YunLen := ' 029 0 029 0 029 029'||
  ' 0 030 0 030 030 0 0'||
  '30 0 030 0 029 029 0'||
  ' 030 0 030 029 0 029'||
  ' 0 029 0 029 029 0 0'||
  '29 0 029 029 0 030 0'||
   ' 029 029 0 029 0 029'||
  ' 0 029 029 0 029 0 0'||
  '29 0 029 029 0 029 0'||
  ' 030 029 0 029 0 029'||
  ' 0 029 029 0 029 0 0';

   --1921 - 2030
   ls_lYearDay :=
  ' 354 384 354 354 385 354 355 384 354 383'||
  ' 354 355 384 355 354 384 354 384 354 354'||
    ' 384 355 355 384 354 354 384 354 384 354'||
  ' 355 384 355 354 384 354 384 354 354 384'||
    ' 355 354 384 355 353 384 355 384 354 355'||
  ' 384 354 354 384 354 384 354 355 384 355'||
    ' 354 384 354 384 354 354 385 354 355 384'||
  ' 354 354 383 355 384 355 354 384 354 354'||
  ' 384 354 355 384 355 384 354 354 384 354'||
  ' 354 384 355 384 355 354 384 354 354 384'||
  ' 354 355 384 354 384 355 354 383 355 354';

 --1921 - 2030
   ls_MonLen :=
  '26352891170527722997 6942395133511751622'||
  '3658374917051461 69422222350321332213402'||
    '346629211389 603 60523493371270934132890'||
  '290113651243 603213513232715168517062794'||
   '2741120627342647131838783477171713862477'||
  '1245119826383405336534132900343423942395'||
   '1179271526352855170117482901 69423951207'||
  '117516111866374917531453 694241423503222'||
  '37333402349318771389 699 605234932432709'||
  '28902890290113731211 6032391132327092965'||
  '1706277317171206267026471319170234751450';
   ll_DaySum := 701303  ; --1920년까지의 누적일수

   --1921년무터 해당일자 직전 년도 까지의 년수 계산
   ll_FromYear := LunerY - 4254  ;
   FOR  i IN 1..ll_FromYear LOOP
    ll_DaySum := ll_DaySum + TO_NUMBER( SubStr( ls_lYearDay, i*4-3, 4 ) );
   END LOOP;

   --해당년도의 월 계산
   IF LunerM <> 1  THEN --1월이 아닐 경우에만 월->일로 환산
li_M := 2048;
ll_FromYear := ll_FromYear + 1;

MM := TO_NUMBER( SUBSTR( ls_MonLen, ll_FromYear*4-3,4 ) );

FOR  j IN 1..LunerM - 1 LOOP
    --해당월의 일수를 누적시켜나간다.
    ll_DaySum := ll_DaySum + 29 + TRUNC(MM / li_M);

    MM := MM - TRUNC(MM / li_M) * li_M;
    li_M := TRUNC(li_M / 2);

    IF  j = TO_NUMBER( SUBSTR( ls_YunMon,ll_FromYear*2-1,2 ) )  THEN 
    --윤달일 경우
    ll_DaySum := ll_DaySum +
  TO_NUMBER( SUBSTR( ls_YunLen, ll_FromYear*2-1,2 ) );
    END IF;
END LOOP ;
   END IF;

   -- 해당월의 일 누적
   ll_DaySum := ll_DaySum + LunerD;

   ------------------------------------------------------
   --1921년부터 해당일 까지의 누적일수를 계산하여 더한다.
   ------------------------------------------------------
   li_PrevYear := TRUNC(ll_DaySum/365) - 1    ;
   NA := TRUNC(ll_DaySum - li_PrevYear*365)    ;
   YD := TRUNC(li_PrevYear/4)
- TRUNC(li_PrevYear/100)
+ TRUNC(li_PrevYear/400) ;
   KA := NA - YD  ;

   IF KA < 0 THEN
    li_PrevYear := li_PrevYear - 1;
    NA := ll_DaySum - TRUNC(li_PrevYear*365);
    YD := TRUNC(li_PrevYear/4) - TRUNC(li_PrevYear/100 )
  + TRUNC(li_PrevYear/400);
    NA := NA - YD;
   ELSE
    NA := KA;
   END IF;

   --양력으로 해당년도의 일수를 계산한다.
   SolarY := li_PrevYear + 1;
   IF   SolarY = TRUNC(SolarY/4)*4  AND  SolarY<>TRUNC(SolarY/100)*100 THEN
    ls_SolarMon := '  0 31 29 31 30 31 30 31 31 30 31 30 31';
    li_OneYearDay := 366;

   ELSIF  SolarY = TRUNC(SolarY/400)*400 THEN
    ls_SolarMon := '  0 31 29 31 30 31 30 31 31 30 31 30 31';
    li_OneYearDay := 366;

   ELSE
 ls_SolarMon := '  0 31 28 31 30 31 30 31 31 30 31 30 31';
    li_OneYearDay := 365;

   END IF;

   IF NA = 0 THEN
NA := li_OneYearDay;
SolarY := SolarY - 1;
   END IF;

   FOR  I IN 1..13 LOOP
    v_loop := I;
    IF  NA > TO_NUMBER( SUBSTR( ls_SolarMon,I*3-2,3 ) ) THEN
    NA := NA - TO_NUMBER( SUBSTR( ls_SolarMon,I*3-2,3 ) );
    ELSE
    EXIT;
    END IF;
   END LOOP;
  
   SolarM := v_loop - 1;
   SolarD := NA;
   ls_return := LPAD(SolarY,4,'0') ||
    LPAD(SolarM,2,'0') ||
    LPAD(SolarD,2,'0');
   Return ls_return;

   exception
WHEN DUP_VAL_ON_INDEX then
  ls_return := 'DUP_VAL_ON_INDEX 입니다.';
  Return ls_return;
WHEN INVALID_NUMBER then
  ls_return := 'INVALID_NUMBER 입니다.';
  Return ls_return;
WHEN LOGIN_DENIED then
  ls_return := 'Login Denied.';
  Return ls_return;
WHEN NOT_LOGGED_ON then
  ls_return := 'Not Logged On.';
  Return ls_return;
WHEN PROGRAM_ERROR then
  ls_return := 'Program Error입니다.';
  Return ls_return;
WHEN STORAGE_ERROR then
  ls_return := 'Storage Error입니다.';
  Return ls_return;
WHEN TIMEOUT_ON_RESOURCE then
  ls_return := 'Timeout on resource.';
  Return ls_return;
WHEN VALUE_ERROR then
  ls_return := 'VALUE_ERROR 입니다. ';
  Return ls_return;
WHEN ZERO_DIVIDE then
  ls_return := 'Zero Divide .';
  Return ls_return;
WHEN Out_Of_Range then
  ls_return := '범위(1921.01.01-2030.11.28)를 벗어났습니다.';
  Return ls_return;
WHEN others then
  ls_return := SUBSTR(SQLERRM, 1, 100 );
  Return ls_return;
END;




 

by 그리움 [2011.01.27 11:03:05]
이거...되게 좋은건데 왜 사람들 반응이 없지요? ㅎㅎ

by 임동국 [2011.02.09 11:12:19]
대단하시단 말밖에 안나오네요... 지금은 아니지만 다음에 꼭 써먹겠습니다.
감사합니다.

by 조은사람 [2011.02.10 13:41:09]
와... 정말 대단합니다.
잘 사용할께요...

by 궁금증 [2011.02.21 11:08:37]
1월달 음력을 양력으로 바꾸는 부분이 문제 있는듯 싶은데요..

by 나그네 [2011.05.27 10:57:01]
자료 감사합니다.

by 불장작 [2012.06.05 14:43:03]

자료 너무 감사합니다.

by 오라클하수 [2013.02.12 18:06:38]

곡 필요한 자료였는데 감사합니다

by 손님 [2013.02.28 15:24:50]

필요하던 건데 감사합니다.

by 박민철 [2014.08.28 10:36:38]

즐겨찾기 등록했어요

좋은 자료 감사해요^^


by 전종현 [2016.01.20 09:34:14]

대단하시네요. 잘 사용하겠습니다.

댓글등록
SQL문을 포맷에 맞게(깔끔하게) 등록하려면 code() 버튼을 클릭하여 작성 하시면 됩니다.
로그인 사용자만 댓글을 작성 할 수 있습니다. 로그인, 회원가입