ADD_MONTHS函数不会在Oracle中返回正确的日期

Moh*_*igh 8 sql oracle date-arithmetic

查看以下查询的结果:

>> SELECT ADD_MONTHS(TO_DATE('30-MAR-11','DD-MON-RR'),-4) FROM DUAL;
30-NOV-10


>> SELECT ADD_MONTHS(TO_DATE('30-NOV-10','DD-MON-RR'),4) FROM DUAL;
31-MAR-11
Run Code Online (Sandbox Code Playgroud)

如果在某个日期增加4个月,我如何获得'30 -MAR-11'?

请帮忙.

M'v*_*'vy 8

这里还有另一个关于Oracle和Java的问题

它说明了这一点

来自add_months上的Oracle参考资料http://download-west.oracle.com/docs/cd/B19306_01/server.102/b14200/functions004.htm

如果日期是该月的最后一天,或者结果月份的日期少于日期的日期组成部分,则结果是结果月份的最后一天.否则,结果与日期具有相同的日期组件.

所以我猜你必须手动检查说明日和结束日来改变功能的行为.或者通过添加天而不是几个月.(但我没有add_day在裁判中找到一个函数)

  • 您找不到任何"add_days"函数可能是因为它们认为它是多余的,因为能够使用`+`和`-`进行更简单的数学运算. (2认同)
  • @Mohammed Saligh:请定义这种通用方式.到目前为止,我可以假设你想要在"30-NOV-11"中添加4个月时保留day组件.但是如果你不得不从31-MAR-11减去4个月呢?那一天应该是什么? (2认同)

And*_*y M 5

作为一种解决方法,我可能会使用此算法:

  1. 计算目标日期TargetDate1使用ADD_MONTHS.
  2. 或者TargetDate2像这样计算目标日期:

    1)申请ADD_MONTHS来源日期的第一个月;
    2)添加源日期和同月开头之间的天数差异.

  3. 选择LEAST之间TargetDate1TargetDate2.

因此,如果源日期的日期组件大于目标月份中的天数,则最终目标日期将包含不同的日期组件.在这种情况下,目标日期将是相应月份的最后一天.

我不太确定我对Oracle SQL语法的了解,但基本上实现可能如下所示:

SELECT
  LEAST(
    ADD_MONTHS(SourceDate, Months),
    ADD_MONTHS(TRUNC(SourceDate, 'MONTH'), Months)
      + (SourceDate - TRUNC(SourceDate, 'MONTH'))
  ) AS TargetDate
FROM (
  SELECT
    TO_DATE('30-NOV-10', 'DD-MON-RR') AS SourceDate,
    4 AS Months
  FROM DUAL
)
Run Code Online (Sandbox Code Playgroud)

以下是该方法的工作原理的详细说明:

SourceDate = '30-NOV-10'
Months     = 4

TargetDate1 = ADD_MONTHS('30-NOV-10', 4) = '31-MAR-11'  /* unacceptable */
TargetDate2 = ADD_MONTHS('01-NOV-10', 4) + (30 - 1)
            = '01-MAR-11' + 29 = '30-MAR-11'            /* acceptable */
TargetDate  = LEAST('31-MAR-11', '30-MAR-11') = '30-MAR-11'
Run Code Online (Sandbox Code Playgroud)

以下是一些显示不同情况的示例:

SourceDate | Months | TargetDate1 | TargetDate2 | TargetDate
-----------+--------+-------------+-------------+-----------
 29-NOV-10 |    4   |   29-MAR-11 |   29-MAR-11 |  29-MAR-11
 30-MAR-11 |   -4   |   30-NOV-10 |   30-NOV-10 |  30-NOV-10
 31-MAR-11 |   -4   |   30-NOV-10 |   01-DEC-10 |  30-NOV-10
 30-NOV-10 |    3   |   28-FEB-11 |   02-MAR-11 |  28-FEB-11
Run Code Online (Sandbox Code Playgroud)