添加月份至今:PostgreSQL 与 Oracle
Adding months to date: PostgreSQL vs. Oracle
PostgreSQL 和 Oracle 在 adding/subtracting 个月 to/from 日期的行为不同。
基本上,如果我们将 1 个月加到某一天,这 不是该月的最后一个 ,它们都会 return 中的同一天数结果月份(如果我们添加的天数更大,则结果月份的最后一个月份,例如添加到 1 月 31 日时的 2 月 28 日)。
PostgreSQL:
# select '2015-01-12'::timestamptz + '1 month'::interval;
date
------------------------
2015-02-12 00:00:00+03
甲骨文:
> select add_months('12-JAN-2015',1) from dual;
ADD_MONTH
---------
12-FEB-15
但是
如果我们要添加的日期是该月的最后一天,Oracle 将 return 结果月份的最后一天,即使它更大,而 PostgreSQL 仍将 return同一天数(如果结果月份较短,则为较低的那一天)。这可能会导致一些不一致(甚至很有趣!),尤其是 adding/subtracting 多次甚至分组操作时 - 在 PostgreSQL 中结果不同:
甲骨文:
> select add_months('28-FEB-2015',1) from dual;
ADD_MONTH
---------
31-MAR-15
> select add_months('31-JAN-2015',4) from dual;
ADD_MONTH
---------
31-MAY-15
> select add_months(add_months(add_months(add_months('31-JAN-2015',1),1),1),1) from dual;
ADD_MONTH
---------
31-MAY-15
PostgreSQL:
-- Adding 4 months at once:
# select '2015-01-31'::timestamptz + '4
months'::interval;
date
-------------------------------
2015-05-31 00:00:00+03
-- Adding 4 months by one:
# select '2015-01-31'::timestamptz + '1
months'::interval + '1 months'::interval + '1 months'::interval +'1
months'::interval;
date
-------------------------------
2015-05-28 00:00:00+03
-- Adding 4 months by one with grouping operations:
# select '2015-01-31'::timestamptz + ('1
months'::interval + '1 months'::interval) + '1 months'::interval +'1
months'::interval;
date
-------------------------------
2015-05-30 00:00:00+03
-- And even adding 4 months and then subtracting them does not return the initial date!
# select '2015-01-31'::timestamptz + '1 months'::interval + '1
months'::interval + '1 months'::interval +'1 months'::interval - '4 months'::interval;
date
------------------------
2015-01-28 00:00:00+03
我知道我总是可以使用像
这样的东西
SELECT (date_trunc('MONTH', now())+'1 month'::interval - '1 day'::interval);
获取月份的最后一天并在 PostgreSQL 中添加月份时使用它,但是
问题是:为什么他们都选择实施不同的标准,哪个是 better/worse 以及为什么。
Oracle 指定
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.
PostgreSQL 指定
Note there can be ambiguity in the months returned by age because
different months have a different number of days. PostgreSQL's
approach uses the month from the earlier of the two dates when
calculating partial months. For example, age('2004-06-01',
'2004-04-30') uses April to yield 1 mon 1 day, while using May would
yield 1 mon 2 days because May has 31 days, while April has only 30.
您可能想看看 PostgreSQL 提供的 justify_days(interval)
函数。
why both of them chose to implement different standards, which one is
better/worse and why ?
None 其中一个比另一个更好(主要是基于意见),只是不同而已。至于为什么他们决定实施不同的标准,老实说我不认为真的有原因,可能只是事实。
PostgreSQL 和 Oracle 在 adding/subtracting 个月 to/from 日期的行为不同。
基本上,如果我们将 1 个月加到某一天,这 不是该月的最后一个 ,它们都会 return 中的同一天数结果月份(如果我们添加的天数更大,则结果月份的最后一个月份,例如添加到 1 月 31 日时的 2 月 28 日)。
PostgreSQL:
# select '2015-01-12'::timestamptz + '1 month'::interval;
date
------------------------
2015-02-12 00:00:00+03
甲骨文:
> select add_months('12-JAN-2015',1) from dual;
ADD_MONTH
---------
12-FEB-15
但是
如果我们要添加的日期是该月的最后一天,Oracle 将 return 结果月份的最后一天,即使它更大,而 PostgreSQL 仍将 return同一天数(如果结果月份较短,则为较低的那一天)。这可能会导致一些不一致(甚至很有趣!),尤其是 adding/subtracting 多次甚至分组操作时 - 在 PostgreSQL 中结果不同:
甲骨文:
> select add_months('28-FEB-2015',1) from dual;
ADD_MONTH
---------
31-MAR-15
> select add_months('31-JAN-2015',4) from dual;
ADD_MONTH
---------
31-MAY-15
> select add_months(add_months(add_months(add_months('31-JAN-2015',1),1),1),1) from dual;
ADD_MONTH
---------
31-MAY-15
PostgreSQL:
-- Adding 4 months at once:
# select '2015-01-31'::timestamptz + '4
months'::interval;
date
-------------------------------
2015-05-31 00:00:00+03
-- Adding 4 months by one:
# select '2015-01-31'::timestamptz + '1
months'::interval + '1 months'::interval + '1 months'::interval +'1
months'::interval;
date
-------------------------------
2015-05-28 00:00:00+03
-- Adding 4 months by one with grouping operations:
# select '2015-01-31'::timestamptz + ('1
months'::interval + '1 months'::interval) + '1 months'::interval +'1
months'::interval;
date
-------------------------------
2015-05-30 00:00:00+03
-- And even adding 4 months and then subtracting them does not return the initial date!
# select '2015-01-31'::timestamptz + '1 months'::interval + '1
months'::interval + '1 months'::interval +'1 months'::interval - '4 months'::interval;
date
------------------------
2015-01-28 00:00:00+03
我知道我总是可以使用像
这样的东西SELECT (date_trunc('MONTH', now())+'1 month'::interval - '1 day'::interval);
获取月份的最后一天并在 PostgreSQL 中添加月份时使用它,但是
问题是:为什么他们都选择实施不同的标准,哪个是 better/worse 以及为什么。
Oracle 指定
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.
PostgreSQL 指定
Note there can be ambiguity in the months returned by age because different months have a different number of days. PostgreSQL's approach uses the month from the earlier of the two dates when calculating partial months. For example, age('2004-06-01', '2004-04-30') uses April to yield 1 mon 1 day, while using May would yield 1 mon 2 days because May has 31 days, while April has only 30.
您可能想看看 PostgreSQL 提供的 justify_days(interval)
函数。
why both of them chose to implement different standards, which one is better/worse and why ?
None 其中一个比另一个更好(主要是基于意见),只是不同而已。至于为什么他们决定实施不同的标准,老实说我不认为真的有原因,可能只是事实。