Получение числа определенных дней недели (выходных) из интервала в PostgreSQL - PullRequest
3 голосов
/ 14 апреля 2009

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

OR

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

Ответы [ 8 ]

5 голосов
/ 15 апреля 2009

Следующая функция возвращает количество полных выходных дней между двумя датами. Поскольку вам нужны полные дни, вы можете привести временные метки к датам перед вызовом функции. Возвращает 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');
2 голосов
/ 09 декабря 2015

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

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;
1 голос
/ 14 апреля 2009

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

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

1 голос
/ 14 апреля 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.

1 голос
/ 14 апреля 2009

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

0 голосов
/ 29 сентября 2015

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

Этот код выше создаст функцию 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
0 голосов
/ 02 апреля 2014

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

-- 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
0 голосов
/ 14 апреля 2009

Этот пост может оказаться полезным: http://www.depesz.com/index.php/2007/12/27/how-many-1sts-of-any-month-were-sundays-since-1901-01-01/

...