如何计算Oracle中两个日期之间的闰年数?

时间:2018-06-08 16:41:52

标签: sql oracle date

我想计算雇员的雇用日期和当前日期之间的闰年数(在Oracle SQL Developer的hr.employees表中)。怎么做?

4 个答案:

答案 0 :(得分:4)

闰年包括366天。我假设有一个闰年"两个日期之间包括2月29日1月1日至12月31日的所有日期。

基于这种理解,有一个非常简单的解决方案。

  • 计算租用日期后1月1日至结束日期1月1日之间的天数。
  • 计算这两个日期之间的年数。
  • 减去天数和年数* 365
  • 之间的差异

令人高兴的是,内置函数完成了大部分工作。

这导致:

   (trunc(sysdate, 'YYYY') -
    trunc(hiredate + interval '1' year, 'YYYY') -
    365 * (extract(year from sysdate) - extract(year from hiredate) - 1)
   ) as num_years

计算闰日有点棘手,但这不是问题所在。

答案 1 :(得分:2)

您可以重用Oracle已编写的代码:只检查创建闰日是否会引发异常:

SELECT TO_DATE('2016-02-29','YYYY-MM-DD') FROM DUAL;
29.02.2016 

SELECT TO_DATE('2018-02-29','YYYY-MM-DD') FROM DUAL;
ORA-01839: date not valid for month specified

所以你只需计算例外:

CREATE OR REPLACE FUNCTION count_leap_years (p_from DATE, p_to DATE) RETURN NUMBER 
IS
  number_of_leap_days NUMBER := 0;
  date_not_valid EXCEPTION;
  PRAGMA EXCEPTION_INIT(date_not_valid, -1839);
BEGIN
  FOR y IN EXTRACT(YEAR FROM p_from) .. EXTRACT(YEAR FROM p_to) LOOP
    DECLARE
      d DATE;
    BEGIN
      d := TO_DATE(to_char(y,'fm0000')||'-02-29', 'YYYY-MM-DD');
      IF p_from < d AND d < p_to THEN
        number_of_leap_days := number_of_leap_days + 1;
      END IF;
    EXCEPTION WHEN date_not_valid THEN 
      NULL;
    END;
  END LOOP;
  RETURN number_of_leap_days;
END count_leap_years;
/

答案 2 :(得分:0)

这样的东西可以让你选择数字,在这种情况下,从1到2999.

    Select Rownum year
    From dual
    Connect By Rownum <= 2999

这样的事情可以让你检查特定年份是否是闰年

CASE WHEN ((MOD(YEAR, 4) = 0 AND (MOD(YEAR, 100) <> 0)) OR MOD(year, 400) = 0) THEN 1 ELSE 0 END as isLeapYear

现在你只需要添加过滤和闰年的总和。

Select sum(isLeapYear)
from (
    Select year, CASE WHEN ((MOD(YEAR, 4) = 0 AND (MOD(YEAR, 100) <> 0)) OR MOD(year, 400) = 0) THEN 1 ELSE 0 END as isLeapYear
FROM (
    Select Rownum year
    From dual
    Connect By Rownum <= 2999
    ) a
    Where a.year >= EXTRACT(YEAR FROM DATE %DateStart%) and a.year <= EXTRACT(YEAR FROM DATE %DateEnd%)
) b

在性能方面可以真正改善,但是我认为更容易理解每​​个步骤的作用,然后你可以将它分解成你真正想要和期望的东西。

答案 3 :(得分:0)

试试这个:

CREATE OR REPLACE FUNCTION LEAP_YEARS(EMP_ID IN NUMBER)
RETURN NUMBER
IS 

HIRE_YEAR NUMBER:=0;
SYS_YEAR  NUMBER:=0;
NUMBER_LEAP_YEARS NUMBER:=0;

BEGIN
 SELECT EXTRACT(YEAR FROM HIRE_DATE) INTO HIRE_YEAR
 FROM EMPLOYEE
 WHERE EMPLOYEE_ID = EMP_ID;

 SELECT EXTRACT(YEAR FROM SYSDATE()) INTO SYS_YEAR
 FROM DUAL;

 FOR IDX IN HIRE_YEAR..SYS_YEAR LOOP
    IF MOD(IDX,4)=0 THEN
        NUMBER_LEAP_YEARS := NUMBER_LEAP_YEARS  + 1;
    END IF;
 END LOOP;

RETURN NUMBER_LEAP_YEARS;
END;

我在一个玩具示例上进行了测试,但它确实有效。也许你需要改进它(提示:也许它需要一些例外,它假设为hire_date&lt; sysdate)。

然后您可以将其用作:

SELECT LEAP_YEARS(E.EMPLOYEE_ID) FROM EMPLOYEE E;