为给定月份生成一系列周间隔

Posted

技术标签:

【中文标题】为给定月份生成一系列周间隔【英文标题】:Generate series of week intervals for given month 【发布时间】:2013-03-04 11:51:42 【问题描述】:

在 Postgres 9.1 数据库中,我试图为给定月份生成一系列周,但有一些限制。我需要所有的星期都从星期一开始,然后在它们开始或在另一个月结束时被削减。

例子:

对于 2013 年 2 月,我想生成一个这样的系列:

         start
------------------------
2013-02-01 00:00:00+00
2013-02-04 00:00:00+00
2013-02-11 00:00:00+00
2013-02-18 00:00:00+00
2013-02-25 00:00:00+00

我现在的查询如下所示:

SELECT GREATEST(date_trunc('week', dates.d),
                date_trunc('month',dates.d)) as start
FROM generate_series(to_timestamp(1359676800),to_timestamp(1362095999), '1 week') as dates(d)

这个查询让我获得了前 4 周的信息,但它缺少从 25 日开始的那一周。最后一周能拿到吗?

【问题讨论】:

【参考方案1】:
select
    greatest(date_trunc('week', dates.d), date_trunc('month',dates.d)) as start
from generate_series('2013-02-01'::date, '2013-02-28', '1 day') as dates(d)
group by 1
order by 1

【讨论】:

【参考方案2】:
SELECT generate_series(date_trunc('week', date '2013-02-01' + interval '6 days')
                     , date_trunc('week', date '2013-02-01' + interval '1 month - 1 day')
                     , interval '1 week')::date AS day
UNION  SELECT date '2013-02-01'
ORDER  BY 1;

此变体不需要子选择GREATESTGROUP BY,只生成所需的行。更简单,更快。 UNION一排更便宜。

date_trunc('week', ...) 之前的每月的第一天加上 6 天,以计算出每月的第一个星期一

date_trunc('week', ...) 之前加上 1 个月并减去 1 天,得到当月的最后一个星期一。 这可以方便地填充到单个 interval 表达式中:'1 month - 1 day'

UNION不是UNION ALL)在每月的第一天添加它,除非它已经包含在星期一。

请注意,date + interval 的结果是 timestamp,这是此处的最佳值。详细解释:

Generating time series between two dates in PostgreSQL

自动化

您可以在 CTE 中提供日期系列的开始:

WITH t(d) AS (SELECT date '2013-02-01')  -- enter 1st of month once
SELECT generate_series(date_trunc('week', d + interval '6 days')
                     , date_trunc('week', d + interval '1 month - 1 day')
                     , interval '1 week')::date AS day
FROM   t
UNION  SELECT d FROM t
ORDER  BY 1;

为了方便重复调用,或者将其包装成一个简单的 SQL 函数:

CREATE OR REPLACE FUNCTION f_week_starts_this_month(date)
  RETURNS SETOF date AS
$func$
SELECT generate_series(date_trunc('week', $1 + interval '6 days')
                     , date_trunc('week', $1 + interval '1 month - 1 day')
                     , interval '1 week')::date AS day
UNION
SELECT $1
ORDER  BY 1
$func$  LANGUAGE sql IMMUTABLE;

呼叫:

SELECT * FROM f_week_starts_this_month('2013-02-01');

您可以传递当月第一天的日期,但它适用于任何日期。您的第一天和下个月的所有星期一。

【讨论】:

以上是关于为给定月份生成一系列周间隔的主要内容,如果未能解决你的问题,请参考以下文章

如何检查给定间隔的哪个星期和月份日由?

Quartz.Net系列:Trigger之CalendarIntervalScheduleBuilder详解

SQL 日期相减(间隔)datediff函数

在 UILocalNotification 中创建周间隔以及周期

extjs计算两个DateField所间隔的月份(天数)

java实现日期月份的间隔数