Получение количества определенных дней недели (выходных) из интервала в PostgreSQL

Учитывая 2 отметки времени в postgres, как вычислить разницу во времени, не считая целые субботы и воскресенья?

OR

Как подсчитать количество суббот и воскресений в заданном временном интервале?


person Ole    schedule 14.04.2009    source источник


Ответы (8)


Следующая функция возвращает количество полных выходных дней между двумя датами. Поскольку вам нужны полные дни, вы можете преобразовать метки времени в даты перед вызовом функции. Он возвращает 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');
person Kouber Saparev    schedule 15.04.2009

Вы можете найти это действительно полезным:

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;
person Florin Asăvoaie    schedule 08.12.2015

(дней / 7) * 2 + количество сб / вс за последние (дней% 7) дней.

person vartec    schedule 14.04.2009

Это должно ответить на вторую часть вашего вопроса:

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 просто.

person araqnid    schedule 14.04.2009

Лучшим решением этого будет использование календарного стола. Это невероятно полезно, и вы можете делать всевозможные интересные вещи, включая подсчет количества рабочих дней между двумя датами или подсчет количества праздников между двумя датами.

Эта таблица обычно заполняется заранее - скажем, за 20 лет с соответствующей пометкой даты хорошо известных праздников. Если праздничные дни меняются, вы время от времени ведете таблицу, чтобы отмечать дни как праздничные. Подробнее здесь и здесь. Это использует MS SQL Server, но также легко переносится.

person no_one    schedule 14.04.2009

Вы можете найти этот пост в блоге полезным: http://www.depesz.com/index.php/2007/12/27/how-many-1sts-of-any-month-were-sundays-since-1901-01-01/

person Community    schedule 14.04.2009

Это будет подсчитывать количество определенного дня между двумя датами:

-- 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
person Ilia Choly    schedule 02.04.2014

Я предлагаю вам создать функцию для использования в любое время и писать меньше; )

Этот код выше создаст функцию 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

Этот выбор должен вернуть четыре, потому что первый и второй день - понедельник, а между ними 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
person Wagner Cipriano    schedule 29.09.2015