从 PostgreSQL 中的时间间隔获取一周中的某些天数(周末)

发布于 2024-07-16 17:22:15 字数 92 浏览 3 评论 0原文

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

或者

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

Given 2 timestamps in postgres, how do you calculate the time difference without counting whole Saturdays and Sundays?

OR

How do you count the number of Saturdays and Sundays in a given time interval?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

静待花开 2024-07-23 17:22:15

以下函数返回两个日期之间的完整周末天数。 由于您需要一整天,您可以在调用该函数之前将时间戳转换为日期。 如果第一个日期不严格早于第二个日期,则返回 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');

The following function is returning the number of full weekend days between two dates. As you need full days, you can cast the timestamps to dates before calling the function. It returns 0 in case the first date is not strictly before the second.

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;

Examples:

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

To obtain the number of days except full weekend days, simply subtract the number of days from the function above:

SELECT
  '2009-04-20'::date
    -
  '2009-04-13'::date
    -
   COUNT_FULL_WEEKEND_DAYS('2009-04-13', '2009-04-20');
等你爱我 2024-07-23 17:22:15

您可能会发现这确实很有帮助:

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;

You might find this really helpful:

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;
黄昏下泛黄的笔记 2024-07-23 17:22:15

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

(days/7)*2 + number of sat/sun in the last (days%7) days.

弥繁 2024-07-23 17:22:15

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

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 就很简单了。

This should answer the second part of your question:

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
$;

Making a corresponding count_non_weekend_days is simple after that.

日久见人心 2024-07-23 17:22:15

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

该表通常是提前填充的 - 比如说 20 年,并适当标记了众所周知的假期的日期。 如果假期发生变化,您可以偶尔维护该表以将这些日子标记为假期。
更多信息请参见此处在这里。 它使用 MS SQL Server,但也很容易移植。

The best solution to this will be to use a calendar table. This is incredibly useful and you can do all sort of interesting things - including counting the number of working days between two dates or counting the number of holidays between two dates.

This table is usually populated in advance - say for 20 years with the date for well known holidays appropriately tagged. If holidays shift, you maintain the table once in a while to mark the days as holidays.
More info here and here. This uses MS SQL Server, but is easily ported as well.

以酷 2024-07-23 17:22:15

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

-- 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

This will count the number of a certain day between two dates:

-- 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
请远离我 2024-07-23 17:22:15

我建议你创建一个函数,想什么时候用就什么时候用,少写一些; )

上面的代码将创建一个 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

I suggest you to create a function for use whenever you want and write less ; )

This code above will create a sql function that count and return the amount of weekend days (Sat, Sun) .
Just the way you will have more flexibility to use this function.

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;

After that, you can use the function to return only the number of weekend days in a interval.
Here's the example to use:

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

This select must return four because the first and the second day are Monday, and we have 2 Saturdays and 2 Sundays between them.

Now, to return only business days (without weekends), as you want, just make a subtraction, like the example below:

SELECT (date '2017-09-25' - date '2017-09-11' ) - <YourSchemaName>.count_full_weekend_days('2017-09-11', '2017-09-25'); --> RES: 14 - 4 = 10
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文