MySQL:根據陽曆獲取農曆日期函式
阿新 • • 發佈:2019-01-04
begin DECLARE v_OffSet INT; DECLARE v_Lunar INT; # 農曆年是否含閏月,幾月是閏月,閏月天數,其它月天數 DECLARE v_YearDays INT; # 農曆年所含天數 DECLARE v_MonthDays INT; # 農曆月所含天數 DECLARE v_LeapMonthDays INT; # 農曆閏月所含天數 DECLARE v_LeapMonth INT; # 農曆年閏哪個月 1-12 , 沒閏傳回 0 DECLARE v_LeapFlag INT; # 某農曆月是否為閏月 1:是 0:不是 DECLARE v_MonthNo INT; # 某農曆月所對應的2進位制數 如農曆3月: 001000000000 DECLARE i INT; DECLARE j INT; DECLARE k INT; DECLARE v_Year INT; # i_SolarDay 對應的農曆年 DECLARE v_Month INT; # i_SolarDay 對應的農曆月 DECLARE v_Day INT; # i_SolarDay 對應的農曆日 DECLARE o_OutputDate VARCHAR(25); # 返回值 格式:農曆 ****年 **(閏)月 **日 DECLARE e_ErrMsg VARCHAR(200); declare v_j int; declare v_temp_m varchar(100); declare v_temp_d varchar(100); # -e_ErrDate EXCEPTION; #輸入引數判斷 /* IF i_SolarDay<TO_DATE('1900-01-31','YYYY-MM-DD') OR i_SolarDay>=TO_DATE('2050-01-23','YYYY-MM-DD') THEN RAISE e_ErrDate; END IF ; */ # i_SolarDay 到 1900-01-30(即農曆1900-01-01的前一天) 的天數 # v_OffSet := TRUNC(i_SolarDay, 'DD') - TO_DATE('1900-01-30', 'YYYY-MM-DD'); DECLARE exit HANDLER FOR SQLEXCEPTION,SQLWARNING,NOT FOUND begin set o_OutputDate ='獲取農曆失敗'; return o_OutputDate; end; set v_OffSet = DATEDIFF(i_SolarDay,str_to_date('1900-01-30', '%Y-%c-%d')); # 確定農曆年開始 set i = 1900; WHILE i < 2050 AND v_OffSet > 0 DO set v_YearDays = 348; # 29*12 以每年12個農曆月,每個農曆月含29個農曆日為基數 set v_LeapMonthDays = 0; # 取出農曆年是否含閏月,幾月是閏月,閏月天數,其它月天數 # 如農曆2001年: 0x0d954(16進位制) -> 55636(10進位制) -> 0 110110010101 0100(2進位制) # 1,2,4,5,8,10,12月大, 3,6,7,9,11月小, 4月為閏月,閏月小 SELECT DataInt INTO v_Lunar FROM SolarData WHERE YearId = i; # 傳回農曆年的總天數 set j = 32768; # 100000000000 0000 -> 32768 # 0 110110010101 0100 -> 55636(農曆2001年) # 依次判斷v_Lunar年個月是否為大月,是則加一天 WHILE j > 8 Do # 閏月另行判斷 8 -> 0 000000000000 1000 set v_j = v_Lunar&j; #IF BITAND(v_Lunar, j) + 0 > 0 then if v_j+0 >0 then set v_YearDays = v_YearDays + 1; #v_YearDays := v_YearDays + 1; END IF; set j = j/2; # 判斷下一個月是否為大 END WHILE; # 傳回農曆年閏哪個月 1-12 , 沒閏傳回 0 15 -> 1 0000 # v_LeapMonth := BITAND(v_Lunar, 15) + 0; set v_LeapMonth = v_Lunar&15 + 0; # 傳回農曆年閏月的天數 ,加在年的總天數上 IF v_LeapMonth > 0 THEN # 判斷閏月大小 65536 -> 1 000000000000 0000 #IF BITAND(v_Lunar, 65536)+0 > 0 THEN if v_Lunar&65536 + 0 > 0 then set v_LeapMonthDays = 30; ELSE set v_LeapMonthDays = 29; END IF; set v_YearDays = v_YearDays + v_LeapMonthDays; END IF; set v_OffSet = v_OffSet - v_YearDays; set i = i + 1; END WHILE; IF v_OffSet <= 0 THEN # i_SolarDay 在所屬農曆年(即i年)中的第 v_OffSet 天 set v_OffSet = v_OffSet + v_YearDays; set i = i - 1; END IF; # 確定農曆年結束 set v_Year = i; # 確定農曆月開始 set i = 1; SELECT DataInt INTO v_Lunar FROM SolarData WHERE YearId = v_Year; # 判斷那個月是潤月 # 如農曆2001年 (55636,15 -> 0 1101100101010100, 1111 -> 4) 即潤4月,且閏月小 set v_LeapMonth = v_Lunar&15 + 0; set v_LeapFlag = 0; WHILE i < 13 AND v_OffSet > 0 DO # 判斷是否為閏月 set v_MonthDays = 0; IF (v_LeapMonth > 0 AND i = (v_LeapMonth + 1) AND v_LeapFlag = 0) THEN # 是閏月 set i = i - 1; set k = i; # 儲存是閏月的時i的值 set v_LeapFlag = 1; # 傳回農曆年閏月的天數 #IF BITAND(v_Lunar, 65536)+0 > 0 THEN if v_Lunar&65536+0 > 0 then set v_MonthDays = 30; ELSE set v_MonthDays = 29; END IF; ELSE # 不是閏月 set j = 1; set v_MonthNo = 65536; # 計算 i 月對應的2進位制數 如農曆3月: 001000000000 WHILE j<= i DO set v_MonthNo = v_MonthNo/2; set j = j + 1; END WHILE; # 計算農曆 v_Year 年 i 月的天數 #IF BITAND(v_Lunar, v_MonthNo)+0 > 0 THEN if v_Lunar&v_MonthNo + 0 > 0 then set v_MonthDays = 30; ELSE set v_MonthDays = 29; END IF; END IF; # 解除閏月 IF v_LeapFlag = 1 AND i = v_LeapMonth +1 THEN set v_LeapFlag = 0; END IF; set v_OffSet = v_OffSet - v_MonthDays; set i = i + 1; END while; IF v_OffSet <= 0 THEN # i_SolarDay 在所屬農曆月(即i月)中的第 v_OffSet 天 set v_OffSet = v_OffSet + v_MonthDays; set i = i - 1; END IF; # 確定農曆月結束 set v_Month = i; # 確定農曆日結束 set v_Day = v_OffSet; # 格式化返回值 set o_OutputDate =CONCAT(getNumYear(v_Year),'年'); IF k = i THEN #set o_OutputDate := o_OutputDate || LPAD(TO_CHAR(v_Month), 2, '0')||'(潤)月 '; set v_temp_m = concat(getNumMonth(v_Month),'(潤)月 '); ELSE # o_OutputDate := o_OutputDate || LPAD(TO_CHAR(v_Month), 2, '0')||'月 '; set v_temp_m = concat(getNumMonth(v_Month),'月'); END IF; # o_OutputDate := o_OutputDate || LPAD(TO_CHAR(v_Day), 2, '0')||'日'; set v_temp_d = getNumDay(v_Day); set o_OutputDate = CONCAT(CONCAT(o_OutputDate,v_temp_m),v_temp_d); RETURN o_OutputDate; END