繁体   English   中英

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

[英]How to calculate number of leap years between two dates in Oracle?

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

年包括366天。 我假设两个日期之间的“ le年”由一年的1月1日至12月31日(即2月29日)的所有日期组成。

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

  • 计算雇用日期后一年的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

计算leap日数有点棘手,但这不是问题要问的。

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

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;
/

在这种情况下,您可以选择1到2999之间的数字。

    Select Rownum year
    From dual
    Connect By Rownum <= 2999

这样的事情将允许您检查特定年份是否为a年

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

现在,您只需要添加过滤和the年的总和。

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

就性能而言,这确实可以得到改善,但是像这样,我认为它更容易理解每​​个步骤在做什么,然后您可以将其分解为您真正想要和期望的东西。

尝试这个:

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 <sysdate)。

然后,您可以将其用作:

SELECT LEAP_YEARS(E.EMPLOYEE_ID) FROM EMPLOYEE E;

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM