有没有办法在增加间隔的同时保留每月的最后一天?

问题描述

虽然会计用户我们发出帐单31.03,下一个帐单我们将在30.04发行,下一个31.05等(对于月初发行的帐单:05.03,下一份帐单的日期为05.0405.05等)

在postgresql上执行此操作会导致结果稍有不同:

tucha=> select '2020-03-31'::timestamptz +interval '1mon';
        ?column?        
------------------------
 2020-04-30 00:00:00+03
(1 row)

tucha=> select '2020-03-31'::timestamptz +interval '1mon' +interval '1mon';
        ?column?        
------------------------
 2020-05-30 00:00:00+03
(1 row)

tucha=> select '2020-03-31'::timestamptz +interval '2mon';
        ?column?        
------------------------
 2020-05-31 00:00:00+03
(1 row)

您还可以注意到,根据您添加相同间隔的方式,您将获得不同的结果。

一些用于日期数学的库甚至提供了特殊的参数。例如,优秀的 perl DateTime实现了preserve参数:

wrap模式下,添加会导致新月结束后的天数增加的月份或年份,将延续到下个月。例如,将2月29日加一年将导致3月1日。

如果您将“ end_of_month”模式指定为limit,则月末永远不会越过。因此,将2000年2月29日增加一年,将在2001年2月28日产生。如果再加上3年,则将导致2004年2月28日。

如果将“ end_of_month”模式指定为preserve ,则与limit的计算相同,不同之处在于,如果原始日期位于月底,新日期也将是。例如,将2000年2月29日增加一个月,则将导致2000年3月31日。

注意:此标志仅在每月的最后几天生效,而其他人完好无损

postgresql是否具有类似的标志或可能是特殊的日期构造函数,如显示的preserve选项? (可能链接到有关实施欢迎的讨论)

解决方法

您可以简单地将日期截断到一个月初,添加两个月并减去一天:

select date_trunc('month','2020-03-31'::timestamptz) +interval '2 month -1 day'

好处是,无论您给哪个月的开始日期,它总是返回下个月的月底:也就是说,它将返回相同的结果,即3月7日,25日或31日。

这是怎么回事:

  • 通过截断日期,您可以获得月份的第一个日期。在我们的例子中是2020-03-01
  • 然后我们添加一个月以退还被截断的月份。
  • 第二个月是我们的下个月。在我们的例子中是2020-05-01
  • 最后我们减去一天,这就是预期月份的最后一天。在我们的例子中是2020-04-01
,

也许此功能可以使您高兴:

CREATE OR REPLACE FUNCTION add_months_preserve_end(d date,i interval)
   RETURNS date
   LANGUAGE sql IMMUTABLE STRICT AS
$$SELECT
   CASE WHEN date_trunc('month',d) + INTERVAL '1 month' = d + INTERVAL '1 day'
             AND i = date_trunc('month',i)
        THEN (date_trunc('month',d) + i + INTERVAL '1 month -1 day')::date
        ELSE (d + i)::date
   END$$;

它对待月底的日子的方式有所不同。

,

只需创建一些功能:


DROP function first_day_in_month(deet DATE) ;
CREATE function first_day_in_month(deet DATE) RETURNS date
AS
$func$
        SELECT date_trunc('mon',$1)::date;
$func$
        LANGUAGE sql
        ;


DROP function last_day_in_month(deet DATE) ;
CREATE function last_day_in_month(deet DATE) RETURNS date
AS
$func$
        SELECT (first_day_in_month($1) +interval '1 mon' -interval '1day' )::date;
$func$
        LANGUAGE sql
        ;

SELECT first_day_in_month( CURRENT_DATE );
SELECT last_day_in_month( CURRENT_DATE );
SELECT first_day_in_month( '2020-11-03' );
SELECT last_day_in_month( '2020-11-03' );

输出:


DROP FUNCTION
CREATE FUNCTION
DROP FUNCTION
CREATE FUNCTION
 first_day_in_month 
--------------------
 2020-10-01
(1 row)

 last_day_in_month 
-------------------
 2020-10-31
(1 row)

 first_day_in_month 
--------------------
 2020-11-01
(1 row)

 last_day_in_month 
-------------------
 2020-11-30
(1 row)

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...