您最好只在日历上查找它并将结果存储在您的代码以后可以查找的表中。
首先请注意,如果考虑部分周,则 OP 不是要求“一个月有多少周”,而是“一个月有多少周”。虽然有细微的差别,但还是有差别的。
结果是所有月份都在 5 或 6 周内,除了 2 月有 4 或 5 周。
虽然@Laurenz Albe 和@VBoke 的尝试令人钦佩,但他们都注定要遭受同样的致命弱点; ISO-8601 标准与公历的差异。该标准定义明确且一致,不幸的是日历不符合标准。
该标准定义每周从星期一开始,整整 7 天,日历月不那么规则。此外,该标准仅承认一个重要日期 - 1 月 4 日。该日期总是在一年的第 1 周。因此,1 月 1 日至 1 月的那一周可能是上一年的第 52/53 周,而 12 月的最后几天可能会落入下一年的第 1 周。这可能导致负周计算。最后,至少现在,从 Sun 开始的任何一个月,这个算法都会产生额外的一周。哦,然后是二月。
以 Laurenz's 作为基线示例:
-- expanded to show Month Year, start and end week number and the number of weeks
set timezone to 'UTC';
with date_list (a_date) as (select generate_series('2019-12-01'::timestamptz,'2030-02-01'::timestamptz,interval '1 month'))
select to_char(a_date, 'Mon yyyy')
, date_part('week', date_trunc('month', a_date) + INTERVAL '1 month' - INTERVAL '1 day') end_of_month_week
, date_part('week', date_trunc('month', a_date)) start_of_month_week
-- L actual
, date_part('week', date_trunc('month', a_date) + INTERVAL '1 month' - INTERVAL '1 day')
- date_part('week', date_trunc('month',a_date)) + 1 number_of_weeks_month_in
from date_list
;
在大多数情况下似乎是正确的,但显然不是全部。考虑到以上我修改了Laurenz的维护基本除了调整。结果:
set timezone to 'UTC';
with date_list (a_date) as (select generate_series('2019-12-01'::timestamptz,'2030-02-01'::timestamptz,interval '1 month'))
select a_date, start_of_month_week, end_of_month_week
, case when start_of_month_week > end_of_month_week
then case when date_part('month', a_date) = 1
-- adjustment for Jan
then case when date_part('dow', a_date) = 0
then 5 else 6 end
-- adjustment for Dec
else case when date_part('dow',a_date) = 6
then 6 else 5 end
end
when date_part('month',a_date) = 2
-- and then there is Feb
then case when date_part('day', a_date+interval '1 month - 1 day') = 29
then 5
when date_part('dow', a_date) = 0
then 4 else 5
end
when date_part('dow', a_date) = 0
-- month beging on Sun
then end_of_month_week - start_of_month_week
-- No adjustment needed Mar - Nov And Not 1st on Mon
else end_of_month_week - start_of_month_week + 1
end::integer number_of_weeks_month_in
, date_part('day', a_date+interval '1 month - 1 day')
from (
SELECT a_date::date
, date_part('week', date_trunc('month', a_date) + INTERVAL '1 month' - INTERVAL '1 day') end_of_month_week
, date_part('week', date_trunc('month', a_date)) start_of_month_week
from date_list
) dts
;
免责声明:虽然我相信调整后的查询是正确的,但我没有每月调查并验证每个月或一周中可能需要自己调整基本算法的其他日子。重复查找这些值并将它们存储在表中可能会更容易。