我们经常使用ADD_MONTHS()函数来获取一个日期的几个月之后的日期,例如,我们希望得到两个月之后的日期(2013年04月05日):
ChenZw> alter session set nls_date_format = 'yyyy-mm-dd';
会话已更改。
已用时间: 00: 00: 00.00
ChenZw> select add_months(to_date('20130405','yyyymmdd'),2) from dual;
ADD_MONTHS
----------
2013-06-05
已选择 1 行。
已用时间: 00: 00: 00.00
上面的例子中,我们得到了2013年04月05日后面第二个月的该日期,也就是2013年06月05日,这个是符合我们期望的日期。
但是这里有一个问题,如果我想得到,该日期(2013年04月05日)之后的1.2个月的日期呢?让我们看一下:
ChenZw> select add_months(to_date('20130405','yyyymmdd'),1.2) from dual;
ADD_MONTHS
----------
2013-05-05
已选择 1 行。
已用时间: 00: 00: 00.00
咦? 这个答案好像不是我想要的,我希望的应该是1.2个月之后的啊!能不能不要这么不严谨!你应该是给我四舍五入了吧?那就告诉我1.9999999999999个月的今天是几号吧!
ChenZw> select add_months(to_date('20130405','yyyymmdd'),1.9999999999999) from dual;
ADD_MONTHS
----------
2013-05-05
已选择 1 行。
已用时间: 00: 00: 00.00
看到这个答案,我有点无语哽咽了,幸亏没有在工作中使用啊,否则我就悲剧了,日期很有可能就算错了。Oracle,你能不能不这么坑爹。
带着疑惑的心情,去请教Oracle的官方文档:
ADD_MONTHS
ADD_MONTHS
returns the date date
plus integer
months. A month is defined by the session parameter NLS_CALENDAR
. The date argument can be a datetime value or any value that can be implicitly converted to DATE
. The integer
argument can be an integer or any value that can be implicitly converted to an integer. The return type is always DATE
, regardless of the data type of date
. If date
is the last day of the month or if the resulting month has fewer days than the day component of date
, then the result is the last day of the resulting month. Otherwise, the result has the same day component as date
.
The following example returns the month after the hire_date
in the sample table employees
:
SELECT TO_CHAR(ADD_MONTHS(hire_date, 1), 'DD-MON-YYYY') "Next month" FROM employees WHERE last_name = 'Baer'; Next Month ----------- 07-JUL-2002
现在明白了,原来1.9999999999999是被直接截取成1了,Oracle所谓的implicitly convert是截掉小数点之后的部分。