【问题标题】:How can we get the count of number of weeks in a month in postgresql我们如何在postgresql中获得一个月的周数
【发布时间】:2020-01-21 16:02:11
【问题描述】:

使用下面的查询我可以得到当前的星期。

select extract(week from current_timestamp)

我想知道给定月份有多少周。

【问题讨论】:

  • 一个给定的月份总是有 4 个完整的星期。你还想知道什么?没有特定的日子?比如有多少个周六或周日?
  • @AnkitBajpai 不仅是整周,即使下个月的一两天属于当月周,我们也想计算
  • 那么你的预期输出是什么?
  • 使用部分数据,每年最多可能有 6 周(参见 2022 年 1 月)。但是做出这个决定,你需要定义一个星期。你还没有这样做,所以你认为一周是多少。

标签: sql postgresql date


【解决方案1】:

要了解与一个月重叠的周数,请尝试

SELECT date_part('week', date_trunc('month', current_timestamp) + INTERVAL '1 month' - INTERVAL '1 day')
     - date_part('week', date_trunc('month', current_timestamp))
     +1;

这会计算一个月中最后一天的周与第一天的周之间的差,然后相加。一个。

current_timestamp 替换为您感兴趣的月份的时间戳。

【讨论】:

    【解决方案2】:

    我不相信这将是您的最终解决方案,但它可能会有所帮助。

    使用TO_NUMBER函数,所以我们可以在外部选择中添加数字,而to_char函数的结果不是数字:)

    使用TO_CHAR 函数,因此我们可以从使用 date_trunc 函数“计算”的日期获取月份数。 TO_CHAR 函数的结果将是第一个月的 05。

    DATE_TRUNC 函数结合+ interval '1 month - 1 day' 用于获取当月的第一天,然后使用这部分+ interval '1 month - 1 day',我们以这种格式获得该月的最后一个日期:2020-01-31 00:00:00+00。从那天起,我们将使用 to_char 函数获得值05(周数)。

    我在这里为你计算了第 1 和第 12:

    SELECT one "1st"
           , "12th" 
    from (
    select 
    (to_number(to_char((date_trunc('month', CURRENT_DATE) + interval '1 month - 1 day'), 'IW'), '99')  
    - to_number(to_char((date_trunc('month', CURRENT_DATE)), 'IW'), '99') +1) "one",
    (to_number(to_char((date_trunc('month', CURRENT_DATE) + interval '12 month - 1 day'), 'IW'), '99')
    - to_number(to_char((date_trunc('month', CURRENT_DATE) + interval '11 month'), 'IW'), '99') +1) "12th") table_alias
    

    这是DEMO

    【讨论】:

    • 嗨@user8545255,非常感谢您的反馈。谢谢!
    【解决方案3】:

    您最好只在日历上查找它并将结果存储在您的代码以后可以查找的表中。 首先请注意,如果考虑部分周,则 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  
          ;
    

    免责声明:虽然我相信调整后的查询是正确的,但我没有每月调查并验证每个月或一周中可能需要自己调整基本算法的其他日子。重复查找这些值并将它们存储在表中可能会更容易。

    【讨论】:

      【解决方案4】:
      SELECT 
          mnth
          , DATE(DATE_TRUNC('week', mnth)) AS week_start
          , DATE(DATE_TRUNC('week', mnth + INTERVAL '1 month' - INTERVAL '1 day')) AS week_end
          , (DATE(DATE_TRUNC('week', mnth + INTERVAL '1 month' - INTERVAL '1 day')) - DATE(DATE_TRUNC('week', mnth))) / 7 + 1 AS week_cnt
      FROM
          (VALUES ('2022-01-01'::date)) AS a (mnth)
      ;
      

      结果:

          mnth    | week_start |  week_end  | week_cnt
      ------------+------------+------------+----------
       2022-01-01 | 2021-12-27 | 2022-01-31 |        6
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2015-11-14
        • 1970-01-01
        • 2022-06-21
        • 2022-11-13
        • 2011-03-20
        • 2022-01-08
        • 1970-01-01
        相关资源
        最近更新 更多