如何计算Postgres中两个日期之间除星期天以外的天数?

Man*_*ani 2 postgresql date-arithmetic postgresql-9.3

要查找两个日期之间的天数,我们可以使用如下代码:

SELECT date_part('day',age('2017-01-31','2017-01-01')) as total_days;
Run Code Online (Sandbox Code Playgroud)

在上面的查询中,我们得到30作为输出,而不是31。为什么?
我还想找到星期日的天数。间隔的预期输出('2017-01-01', '2017-01-31')

Total Days = 31
Total Days except Sundays = 26
Run Code Online (Sandbox Code Playgroud)

Erw*_*ter 5

您需要更紧密地定义“两个日期之间”。下限和上限是否包括在内?一个常见的定义是包括一个区间的下限,而排除一个区间的上限。另外,当上下限相同时,将结果定义为0。这个定义恰好与日期减法相吻合

SELECT date '2017-01-31' - date '2017-01-01' AS days_between
Run Code Online (Sandbox Code Playgroud)

这个确切的定义对于排除星期日非常重要。对于给定的定义,从星期日到星期日(1周后)的时间间隔不包括上限,因此只能减去1个星期日。

interval in days  | sundays
0                 | 0
1-6               | 0 or 1
7                 | 1
8-13              | 1 or 2
14                | 2
...
Run Code Online (Sandbox Code Playgroud)

7天的间隔始终包括一个星期日。

我们可以用一个简单的整数除法(days / 7)得到最小结果,该结果将被截断。

剩余的1-6天的额外星期日取决于间隔的第一天。如果是星期天,宾果游戏;如果是星期一,那太糟了。等等,我们可以从中得出一个简单的公式:

SELECT days, sundays, days - sundays AS days_without_sundays
FROM  (
   SELECT z - a AS days
      , ((z - a) + EXTRACT(isodow FROM a)::int - 1 ) / 7 AS sundays
   FROM  (SELECT date '2017-01-02' AS a       -- your interval here
               , date '2017-01-30' AS z) tbl
   ) sub;
Run Code Online (Sandbox Code Playgroud)

适用于任何给定的时间间隔。
注意:isodow,不适dow用于EXTRACT()

包含上限,只需将替换z - a(z - a) + 1。(由于运算符的优先级,本来可以没有括号地工作,但是最好弄清楚。)

性能特征是O(1)(常数),与O(N)生成的集合上的条件集合相反。

有关: