由于end_date
没有小数秒,或者实际上没有任何时间组件,您可以使用add_months
并将其转换为timestamp
:
select cast(add_months(end_date, 2) as timestamp) from ...
但add_months
也有自己的怪癖。如果原始日期是该月的最后一天,您将获得调整后月份的最后一天 - 在这种情况下,如果您打算缩短月份,这就是您想要的,但如果您要去,则可能不是另一种方法:
with t as (
select to_timestamp('2013-07-31', 'YYYY-MM-DD') as end_date from dual
union all select to_timestamp('2013-06-30', 'YYYY-MM-DD') from dual
union all select to_timestamp('2013-02-28', 'YYYY-MM-DD') from dual
union all select to_timestamp('2012-02-29', 'YYYY-MM-DD') from dual
)
select end_date, cast(add_months(end_date, 2) as timestamp)
from t;
END_DATE CAST(ADD_MONTHS(END_DATE,2)AST
------------------------------ ------------------------------
2013-07-31 00:00:00.000000 2013-09-30 00:00:00.000000
2013-06-30 00:00:00.000000 2013-08-31 00:00:00.000000
2013-02-28 00:00:00.000000 2013-04-30 00:00:00.000000
2012-02-29 00:00:00.000000 2012-04-30 00:00:00.000000
或者您可以创建自己的函数来处理错误日期,然后向后调整直到找到有效日期:
create or replace function adjust_timestamp(orig_ts in timestamp,
months in number)
return timestamp is
new_ts timestamp;
offset number := 0;
bad_adjustment exception;
pragma exception_init(bad_adjustment, -01839);
begin
while new_ts is null loop
begin
new_ts := orig_ts - numtodsinterval(offset, 'DAY')
+ numtoyminterval(months, 'MONTH');
exception
when bad_adjustment then
offset := offset + 1;
continue;
end;
end loop;
return new_ts;
end;
/
这使用为 ORA-01839 错误代码定义的异常来捕获错误日期,并在循环中执行此操作,因此它可以向后(通过offset
)工作,直到找到没有错误的日期。
with t as (
select to_timestamp('2013-07-31', 'YYYY-MM-DD') as end_date from dual
union all select to_timestamp('2013-06-30', 'YYYY-MM-DD') from dual
union all select to_timestamp('2013-02-28', 'YYYY-MM-DD') from dual
union all select to_timestamp('2012-02-29', 'YYYY-MM-DD') from dual
)
select end_date, adjust_timestamp(end_date, 2)
from t;
END_DATE ADJUST_TIMESTAMP(END_DATE,2)
------------------------------ ------------------------------
2013-07-31 00:00:00.000000 2013-09-30 00:00:00.000000
2013-06-30 00:00:00.000000 2013-08-30 00:00:00.000000
2013-02-28 00:00:00.000000 2013-04-28 00:00:00.000000
2012-02-29 00:00:00.000000 2012-04-29 00:00:00.000000
这给add_months
版本带来了不同的结果。你需要确定你得到了什么,以及你希望数据如何表现。