3

给定 postgres 中的 2 个时间戳,如何在不计算整个周六和周日的情况下计算时差?

或者

您如何计算给定时间间隔内的星期六和星期日的数量?

4

8 回答 8

5

以下函数返回两个日期之间的完整周末天数。由于您需要一整天,您可以在调用函数之前将时间戳转换为日期。如果第一个日期不是严格在第二个日期之前,它会返回 0。

CREATE FUNCTION count_full_weekend_days(date, date)
  RETURNS int AS
$BODY$
  SELECT
    ($1 < $2)::int
      *
    (
      (($2 - $1) / 7) * 2
        + 
      (EXTRACT(dow FROM $1)<6 AND EXTRACT(dow FROM $2)>0 AND EXTRACT(dow FROM $1)>EXTRACT(dow FROM $2))::int * 2
        +
      (EXTRACT(dow FROM $1)=6 AND EXTRACT(dow FROM $2)>0)::int
        +
      (EXTRACT(dow FROM $2)=0 AND EXTRACT(dow FROM $1)<6)::int
    );
$BODY$
  LANGUAGE 'SQL' IMMUTABLE STRICT;

例子:

SELECT COUNT_FULL_WEEKEND_DAYS('2009-04-10', '2009-04-20');
# returns 4

SELECT COUNT_FULL_WEEKEND_DAYS('2009-04-11', '2009-04-20');
# returns 3 (11th is Saturday, so it shouldn't be counted as full day)

SELECT COUNT_FULL_WEEKEND_DAYS('2009-04-12', '2009-04-20');
# returns 2 (12th is Sunday, so it shouldn't be counted as full day)

SELECT COUNT_FULL_WEEKEND_DAYS('2009-04-13', '2009-04-20');
# returns 2

要获得除周末全天以外的天数,只需从上面的函数中减去天数:

SELECT
  '2009-04-20'::date
    -
  '2009-04-13'::date
    -
   COUNT_FULL_WEEKEND_DAYS('2009-04-13', '2009-04-20');
于 2009-04-15T12:37:39.737 回答
2

你可能会发现这真的很有帮助:

CREATE OR REPLACE FUNCTION working_days(date, date) RETURNS INT AS
$$
SELECT COUNT(days)::INT
    FROM generate_series($1, $2, '1 day') AS days
    WHERE EXTRACT(DOW FROM days) NOT IN(0, 6);
$$
LANGUAGE 'sql' IMMUTABLE STRICT;
于 2015-12-08T22:16:02.737 回答
1

(days/7)*2 + 最近 (days%7) 天的周六/周日数。

于 2009-04-14T10:29:19.290 回答
1

这应该回答您问题的第二部分:

create or replace function is_weekend_day(date) returns boolean
 strict immutable language 'sql'
 as $$ select case extract(dow from $1) when 0 then true when 6 then true else false end $$;

create or replace function count_weekend_days(start_date date, end_date date) returns int
 strict immutable language 'sql'
 as $$
select cast(sum(case when is_weekend_day($1 + ofs) then 1 else 0 end) as int)
from generate_series(0, $2 - $1) ofs
$$;

之后进行对应就很count_non_weekend_days简单了。

于 2009-04-14T11:05:03.433 回答
1

最好的解决方案是使用日历表。这非常有用,您可以做各种有趣的事情——包括计算两个日期之间的工作日数或计算两个日期之间的假期数。

该表通常是提前填充的——比如 20 年,并适当标记了众所周知的假期的日期。如果假期发生变化,您会不时维护表格以将日期标记为假期。 更多信息在这里这里。这使用 MS SQL Server,但也很容易移植。

于 2009-04-14T11:19:09.000 回答
0

您可能会发现这篇博文很有帮助: http: //www.depesz.com/index.php/2007/12/27/how-many-1sts-of-any-month-were-sundays-since-1901-01-01 /

于 2009-04-14T11:34:38.853 回答
0

这将计算两个日期之间某一天的数量:

-- 0 Sunday
-- 1 Monday
-- 2 Tuesday
-- 3 Wednesday
-- 4 Thursday
-- 5 Friday
-- 6 Saturday

WITH rng AS (
  SELECT
      'march 3 2013'::date AS start,
      'march 3 2014'::date AS end,
      0                    AS day -- Sunday
)

SELECT count(1)
FROM rng, generate_series(0, (extract(epoch from age(rng.end, rng.start)) / (60*60*24))::int) AS n
WHERE extract(dow from rng.start + (n * '1 day'::interval)) = rng.day
于 2014-04-02T19:26:29.103 回答
0

我建议您创建一个随时使用的函数,并且少写一些;)

上面的代码将创建一个计算并返回周末天数 (Sat, Sun) 的 sql 函数。就像您可以更灵活地使用此功能一样。

CREATE OR REPLACE FUNCTION <YourSchemaNameOptional>.count_full_weekend_days(date, date)
RETURNS bigint AS
$BODY$
        select  COUNT(MySerie.*) as Qtde
        from    (select  CURRENT_DATE + i as Date, EXTRACT(DOW FROM CURRENT_DATE + i) as DiaDate
                 from    generate_series(date ($1) - CURRENT_DATE,  date ($2) - CURRENT_DATE ) i) as MySerie
        WHERE   MySerie.DiaDate in (6,0);
$BODY$
LANGUAGE 'SQL' IMMUTABLE STRICT;

之后,您可以使用该函数仅返回间隔中的周末天数。这是要使用的示例:

SELECT <YourSchemaNameOptional>.count_full_weekend_days('2017-09-11', '2017-09-25') as days; --> RES: 4

此选择必须返回 4,因为第一天和第二天是星期一,并且它们之间有 2 个星期六和 2 个星期日。

现在,根据需要仅返回工作日(不包括周末),只需进行减法,如下例所示:

SELECT (date '2017-09-25' - date '2017-09-11' ) - <YourSchemaName>.count_full_weekend_days('2017-09-11', '2017-09-25'); --> RES: 14 - 4 = 10
于 2015-09-29T17:47:56.473 回答