sql—在oracle中准确计算经过的年数,计算闰年

axzmvihb  于 2021-07-29  发布在  Java
关注(0)|答案(2)|浏览(335)

在oracle中,我需要计算一个基于1的值,即从给定日期起经过的年数,即闰年。
最初的计算没有考虑闰年。是的

CEIL ((SYSDATE- prog_start_dt) / 365))

然后我决定用 MONTHS_BETWEEN ,但我的新计算中有一个错误:

CEIL(MONTHS_BETWEEN(SYSDATE, prog_start_dt) / 12)

问题是如果我在 prog_start_date 无论时间长短,该值都小于1。前任。:

sysdate = 2020-07-01 15:30:00
prog_start_dt = 2019-07-01 00:00:00
--> 1. CEIL ((SYSDATE- prog_start_dt) / 365)) --> Result: 2
--> 2. CEIL(MONTHS_BETWEEN(SYSDATE, prog_start_dt) / 12) --> Result 1

正确的结果是 2 . 所以我需要顶级公式的行为,但是考虑闰年,这显然是不可能的 365 . 有什么好办法吗?

mxg2im7a

mxg2im7a1#

这是一种记录在案的行为:
如果 date1 以及 date2 如果是一个月的同一天,或者是两个月的最后几天,则结果总是整数。
如果您真的想解决这个问题,那么一个选项是添加一些逻辑来处理这个特定的情况:当比较的日期属于同一个月和同一天时,检查时间部分以查看年份是否已经过去:

ceil(months_between(sysdate, prog_start_dt) / 12)
+ case when to_char(sysdate, 'mm-dd') = to_char(prog_start_dt, 'mm-dd') 
       and to_char(sysdate, 'hh24:mi') > to_char(prog_start_dt, 'hh24:mi')
    then 1
    else 0
end

db小提琴演示:

with t as (
    select 
        to_date('2020-07-01 15:30:00', 'yyyy-mm-dd hh24:mi:ss') date1, 
        to_date('2019-07-01 00:00:00' , 'yyyy-mm-dd hh24:mi:ss') date2
    from dual
)
select 
    ceil(months_between(date1, date2) / 12)
    + case when to_char(date1, 'mm-dd') = to_char(date2, 'mm-dd') 
           and to_char(date1, 'hh24:mi') > to_char(date2, 'hh24:mi')
        then 1
        else 0
    end year_diff
from t
| YEAR_DIFF |
| --------: |
|         2 |
htzpubme

htzpubme2#

从上的文档 MONTHS_BETWEEN : MONTHS_BETWEEN 返回日期之间的月数 date1 以及 date2 . 如果 date1 晚于 date2 ,则结果为正。如果 date1 早于 date2 ,则结果为负。如果 date1 以及 date2 如果是一个月的同一天,或者是两个月的最后几天,则结果总是整数。否则,oracle数据库将根据31天的月份计算结果的小数部分,并考虑时间组件的差异 date1 以及 date2 .
你可以“修复” MONTHS_BETWEEN 因此,当一个月的某一天相同(或者如果它们都是一个月的最后几天)时,它并不总是使用整数值,使用:

MONTHS_BETWEEN( end_date, start_date )
+
CASE
WHEN EXTRACT( DAY FROM start_date ) = EXTRACT( DAY FROM end_date )
OR   ( start_date = LAST_DAY( start_date ) AND end_date = LAST_DAY( end_date ) )
THEN ( end_date
     - ADD_MONTHS( start_date, MONTHS_BETWEEN( end_date, start_date ) )
     ) / 31
ELSE 0
END

所以,你的问题是:

SELECT start_date,
       end_date,
       CEIL(
         (
         MONTHS_BETWEEN( end_date, start_date )
         +
         CASE
         WHEN EXTRACT( DAY FROM start_date ) = EXTRACT( DAY FROM end_date )
         OR   ( start_date = LAST_DAY( start_date ) AND end_date = LAST_DAY( end_date ) )
         THEN ( end_date
                - ADD_MONTHS( start_date, MONTHS_BETWEEN( end_date, start_date ) )
              ) / 31
         ELSE 0
         END
         )
         / 12
       ) AS years
FROM   test_data;

对于一些测试数据:

CREATE TABLE test_data ( start_date, end_date ) AS
  SELECT DATE '2019-07-01',
         DATE '2020-07-01' + INTERVAL '15:30:00' HOUR TO SECOND
  FROM   DUAL
UNION ALL
  SELECT DATE '2019-07-31',
         DATE '2020-02-29' + INTERVAL '15:30:00' HOUR TO SECOND
  FROM   DUAL
UNION ALL
  SELECT DATE '2019-02-28',
         DATE '2020-02-29' + INTERVAL '15:30:00' HOUR TO SECOND
  FROM   DUAL;

这将输出:

START_DATE          | END_DATE            | YEARS
:------------------ | :------------------ | ----:
2019-07-01 00:00:00 | 2020-07-01 15:30:00 |     2
2019-07-31 00:00:00 | 2020-02-29 15:30:00 |     1
2019-02-28 00:00:00 | 2020-02-29 15:30:00 |     2

db<>在这里摆弄

相关问题