工具 : PLSQL Developer
要求:
给定一个时间(date 类型, yyyy-MM-dd HH:mm:ss),求过了n个星期后,此时间的下一个月的时间.
CREATE OR REPLACE FUNCTION FN_RECURSIVE_DATE(EXEC_TIME IN DATE, -- 执行时间 V_CYCLE IN NUMBER, -- n周 OUT_DATE OUT DATE) -- 执行时间执行n周后的下一个月时间 RETURN DATE AS /*按周期赠送,按周的递归函数,找到配置的执行时间的下一个月*/ V_EXEC_DAY NUMBER(2); -- 执行时间EXEC_TIME中的天 V_EXEC_MONTH NUMBER(2); -- 执行时间EXEC_TIME中的月份 V_EXEC_YEAR VARCHAR2(4); -- 执行时间EXEC_TIME中的年份 V_DAYS NUMBER(4); -- 总天数 V_STR_EXEC_TIME VARCHAR2(20); -- 执行时间EXEC_TIME的字符串表示方式 V_SPACE_INDEX NUMBER(2); -- 执行时间EXEC_TIME中空格所在索引 V_OTHERS_TIME VARCHAR2(20); -- EXEC_TIME的格式' HH:mm:ss' V_MAX_DAY NUMBER(2); -- 某个月的最大天数 V_CUR_YEAR VARCHAR2(4); -- 当前年份 V_CUR_MONTH NUMBER(2); -- 当前月份 V_N_EXEC_YEAR NUMBER(4); -- V_EXEC_YEAR 的number格式 V_NEXT_MONTH NUMBER(2); -- 下一月 V_N_CUR_YEAR NUMBER(4); -- v_cur_year 的number格式 BEGIN -- 取出execTime的day V_EXEC_DAY := FN_GET_DAY_OF_DATE(EXEC_TIME, V_EXEC_DAY); -- 取出执行时间execTime中的月份 V_EXEC_MONTH := F_GET_MONTH(EXEC_TIME, V_EXEC_MONTH); -- execTime 的年份 V_EXEC_YEAR := FN_GET_YEAR_OF_DATE(EXEC_TIME, V_EXEC_YEAR); -- n周的天数+执行时间中的day V_DAYS := V_EXEC_DAY + V_CYCLE * 7; -- 将exec_time转成string格式 V_STR_EXEC_TIME := TO_CHAR(EXEC_TIME, 'yyyy-mm-dd hh24:mi:ss'); -- 找出exec_time中空格的位置 V_SPACE_INDEX := INSTR(V_STR_EXEC_TIME, ' ', 1, 1); -- ' HH:mm:ss' V_OTHERS_TIME := SUBSTR(V_STR_EXEC_TIME, V_SPACE_INDEX); -- 某个月的最大天数 V_MAX_DAY := FN_MAXDAYOFMONTH(V_EXEC_MONTH, V_EXEC_YEAR, V_MAX_DAY); IF V_DAYS > V_MAX_DAY THEN /* 如果总天数大于该月的最大天数 */ V_EXEC_MONTH := V_EXEC_MONTH + 1; IF V_EXEC_MONTH > 12 THEN V_EXEC_MONTH := 1; V_EXEC_YEAR := TO_CHAR(TO_NUMBER(V_EXEC_YEAR) + 1); END IF; -- end of IF V_EXEC_MONTH > 12 V_EXEC_DAY := V_DAYS - V_MAX_DAY; -- 获取当前月份 V_CUR_MONTH := F_GET_MONTH(SYSDATE, V_CUR_MONTH); -- 执行年份的number格式 V_N_EXEC_YEAR := TO_NUMBER(V_EXEC_YEAR); V_NEXT_MONTH := V_CUR_MONTH + 1; IF V_NEXT_MONTH > 12 THEN V_NEXT_MONTH := 1; V_N_EXEC_YEAR := V_N_EXEC_YEAR + 1; END IF; -- end of IF v_next_month > 12 -- 获取当前年份 V_CUR_YEAR := FN_GET_YEAR_OF_DATE(SYSDATE, V_CUR_YEAR); V_N_CUR_YEAR := TO_NUMBER(V_CUR_YEAR); IF (V_N_CUR_YEAR = V_N_EXEC_YEAR OR V_N_CUR_YEAR + 1 = V_N_EXEC_YEAR) AND V_NEXT_MONTH = V_EXEC_MONTH THEN /* 是下一个月 */ V_STR_EXEC_TIME := V_EXEC_YEAR || '-' || V_EXEC_MONTH || '-' || V_EXEC_DAY || V_OTHERS_TIME; OUT_DATE := TO_DATE(V_STR_EXEC_TIME, 'yyyy-mm-dd hh24:mi:ss'); RETURN OUT_DATE; END IF; ELSE /* 没到下一个月 */ -- 这里的day写的是 V_DAYS (相加后的总天数) , 不然会出现死循环 V_STR_EXEC_TIME := V_EXEC_YEAR || '-' || V_EXEC_MONTH || '-' || V_DAYS || V_OTHERS_TIME; OUT_DATE := TO_DATE(V_STR_EXEC_TIME, 'yyyy-mm-dd hh24:mi:ss'); -- 递归调用 RETURN FN_RECURSIVE_DATE(OUT_DATE, V_CYCLE, OUT_DATE); END IF; -- end of if V_DAYS > V_MAX_DAY EXCEPTION WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('execute FN_RECURSIVE_DATE fail!' || SQLERRM); END; /
执行:
在工具 PLSQL Developer 的Command Window 中输入以下的代码:
VAR v_date DATE; EXEC :v_date := FN_RECURSIVE_DATE(SYSDATE,2,:v_date);
执行结果如下所示: