Postgres:计算期间的开始日期,以使间隔保持不变

时间:2018-09-25 08:54:13

标签: sql postgresql date intervals

在一段时间内,使用PostgresQL 9.6,我有三个输入值:

  • “ endDate”:任意日期,即结束日期
  • “月”:介于0到ca之间的月份数。 30
  • “天”:0到29之间的天数

任务是:查找该期间的开始日期。要求是:age("end","start")(*)的结果必须始终与输入间隔(月+天)相同。换句话说:在不显式保存给定间隔的情况下,仅通过开始和结束即可存储该周期,但要确保该间隔保持完全相同。

我的第一个简单尝试是

SELECT "endDate" - ("months" || ' mons ' || "days" ' days')::interval

但是,这不适用于输入

  • “ endDate”:2017-06-29
  • “月”:4
  • “天”:19

通过这种方法计算的开始日期将为2017-02-09。并且age('2017-06-29','2017-02-10')将返回4 mons 20 days,这是一天太多了。

可能的原因是减号运算符很可能会首先减去月份,然后如果它降落在“不可能的日期”(如2017-02-29),请转到上一个“可能的”日期(此处为:2017-02) -28),然后减去天数,降落在2017-02-09上-这是错误的。

所以,我想到了这个主意:

WITH prep AS 
( SELECT ("months"||' mons')::interval AS moninterval, 
         ("days" || ' days')::interval AS dayinterval )

SELECT 
 CASE WHEN date_part('day',"endDate") > "days" 
   THEN (("endDate" - dayinterval) - moninterval)::date 
   ELSE ("endDate" - (  moninterval + dayinterval) )::date
END AS simstart
FROM prep

基本上,这个想法是:如果结束日期的天数大于间隔中的天数,则先减去天,再减去月。否则,请像以前一样进行操作。

在许多情况下都可以使用。但是,我仍然找到了一个没有的极端情况:

  • “ endDate”:2018-03-02
  • “月”:0
  • “天”:28

无论使用哪种方法:开始日期将始终以2018-02-02计算。而且,如果您执行SELECT age_forward('2018-03-02','2018-02-02'),则将始终以1 mon结尾-从技术上讲这是正确的。但是,这是错误的,因为原始输入是28 days

(*)更准确地说:age_forward。在这里https://stackoverflow.com/a/51173709/2710714中查看我对自己问题的回答。但是,我认为与上述边缘案例问题无关。

0 个答案:

没有答案