【问题标题】:Week number of the month?一个月的周数?
【发布时间】:2011-04-17 21:57:00
【问题描述】:

python 是否提供了一种轻松获取当前本月的一周 (1:4) 的方法?

【问题讨论】:

  • 到了29号,其实已经是第五周了,对吧?
  • 一周是从每月的第一天开始还是总是从星期一开始?还是总是在星期天?还是……?
  • “一周中的一周”并不是一个常用的概念。您需要告诉我们您对“月份中的一周”的定义是什么,并举例说明......特别是哪个月份的一周,例如周从星期一开始,假设今天既是星期日又是该月的第一天:您想要(上个月,第 5 周)还是(当前月,第 -1 周或第 0 周)或其他?
  • Mark Byers 的回答直截了当。我正在使用 cx_Oracle 访问一个 Oracle 数据库,并尝试优化计算时间,通过该月和某周的查询(该表按月分区并按月的周子分区,John Machin 链接的定义为: "WEEK_OF_MONTH 字段范围从 .. 1 到 .. 5")

标签: python time week-number


【解决方案1】:

为了使用直除,您正在查看的日期的月份日期需要根据该月第一天的位置(一周内)进行调整。因此,如果您的月份恰好从星期一(一周的第一天)开始,您可以按照上面的建议进行除法。但是,如果月份从星期三开始,您将需要加 2,然后进行除法。这一切都封装在下面的函数中。

from math import ceil

def week_of_month(dt):
    """ Returns the week of the month for the specified date.
    """

    first_day = dt.replace(day=1)

    dom = dt.day
    adjusted_dom = dom + first_day.weekday()

    return int(ceil(adjusted_dom/7.0))

【讨论】:

  • adjusted_dom = (1 + first_day.weekday()) % 7 从星期日开始的一周
  • 效果很好。谢谢。
  • 如果我想搜索每个月的第二个星期六,它将在 2019 年 9 月 7 日失败。
  • 对于 2020 年 3 月 4 日,返回 2,这是不正确的。切换到下面的另一个解决方案:stackoverflow.com/a/26662038/6072151
  • @JustinPoehnelt 我认为你犯了一个错误。应该是adjusted_dom = dom + (1 + first_day.weekday()) % 7
【解决方案2】:

我知道这已经有好几年了,但我花了很多时间试图找到这个答案。我做了自己的方法,并认为我应该分享。

日历模块有一个monthcalendar 方法,该方法返回一个二维数组,其中每一行代表一周。例如:

import calendar
calendar.monthcalendar(2015,9)

结果:

[[0,0,1,2,3,4,5],
 [6,7,8,9,10,11,12],
 [13,14,15,16,17,18,19],
 [20,21,22,23,24,25,26],
 [27,28,29,30,0,0,0]]

所以 numpy 你的朋友在哪里。我在美国,所以我希望一周从星期日开始,第一周标记为 1:

import calendar
import numpy as np
calendar.setfirstweekday(6)

def get_week_of_month(year, month, day):
    x = np.array(calendar.monthcalendar(year, month))
    week_of_month = np.where(x==day)[0][0] + 1
    return(week_of_month)

get_week_of_month(2015,9,14)

返回

3

【讨论】:

  • 对不起,我是新手。如何使用此函数获取当前日期的周数,而不是插入确切的年月日?
  • @RSM - 只需使用datetime.today().year/month/day :-)
  • 在我看来,使用 numpy 来完成这一功能太过分了。
【解决方案3】:

如果您的第一周从每月的第一天开始,您可以使用整数除法:

导入日期时间 day_of_month = datetime.datetime.now().day week_number = (day_of_month - 1) // 7 + 1

【讨论】:

  • 也许 datetime.datetime.now().day 会给出该月的今天
  • 谢谢。事实证明这毕竟不是关于 Python,而是关于算术:)
  • 我不清楚这是否有效。假设您的一周从星期一开始,感兴趣月份的第一天是星期日,您希望将第 1 个月的一天映射到第 1 个月的一周。在这种情况下,上面的算法将返回正确的答案。但是,如果您移动到第二天,即 2 号星期一,您会希望算法返回 2。在这种情况下,算法会返回错误的答案。请在下面查看我的答案,它通过考虑偏移量在两种情况下都返回正确的结果。
  • 它在 2020 年 2 月 10 日的案例和大多数其他案例中都失败了。它不是通用的
【解决方案4】:

查看包裹Pendulum

>>> dt = pendulum.parse('2018-09-30')
>>> dt.week_of_month
5

【讨论】:

  • 我一直在使用该解决方案,直到 2021-01-10、2021-01-17、2021-01-24、2021-01-31 日期分别返回负值:-51 , -50, -49, -48 .. 所以这有点麻烦。
【解决方案5】:

这个版本可以改进,但作为python模块(日期时间和日历)的第一个外观,我提出了这个解决方案,希望对你有用:

from datetime import datetime
n = datetime.now()
#from django.utils.timezone import now
#n = now() #if you use django with timezone

from calendar import Calendar
cal = Calendar() # week starts Monday
#cal = Calendar(6) # week stars Sunday

weeks = cal.monthdayscalendar(n.year, n.month)
for x in range(len(weeks)):
    if n.day in weeks[x]:
        print x+1

【讨论】:

  • now 变量是什么?
【解决方案6】:

查看 python calendar 模块

【讨论】:

  • 谢谢。我知道 calendar 和 dateutil,但两者都没有帮助我。
  • vito 有正确的答案。我用过:st, end = calendar.monthrange(2012, 6)days = range(st, end+1)week_days = [days[i : i+7] for i in range(0, len(days), 7)]
  • 提供链接并不能回答问题。
【解决方案7】:

乔希的答案必须稍微调整以适应星期天的第一天。

def get_week_of_month(date):
   first_day = date.replace(day=1)

   day_of_month = date.day

   if(first_day.weekday() == 6):
       adjusted_dom = (1 + first_day.weekday()) / 7
   else:
       adjusted_dom = day_of_month + first_day.weekday()

   return int(ceil(adjusted_dom/7.0))

【讨论】:

    【解决方案8】:

    我找到了一个很简单的方法:

    import datetime
    def week(year, month, day):
        first_week_month = datetime.datetime(year, month, 1).isocalendar()[1]
        if month == 1 and first_week_month > 10:
            first_week_month = 0
        user_date = datetime.datetime(year, month, day).isocalendar()[1]
        if month == 1 and user_date > 10:
            user_date = 0
        return user_date - first_week_month
    

    如果是第一周则返回 0

    【讨论】:

    • isocalendar() 可以为 1 月 1 日返回 53。您的实现为 weekOfMonth(2010, 1, 8) 返回 -52。
    • 我修复了代码并检查了该错误,但代码并没有变得那么大,它完美地完成了这项工作。
    • 返回 -47 日期:2012-12-31、2013-12-30、2013-12-31
    • 返回 -48 日期:2014-12-29、2014-12-30、2014-12-31
    【解决方案9】:

    乔希的回答似乎是最好的,但我认为我们应该考虑一个事实,即只有当周四属于该月时,一周才属于一个月。至少那是what the iso says

    根据该标准,一个月最多可以有 5 周。一天可能属于一个月,但它所属的星期可能不属于。

    我已经考虑到了,只需添加一个简单的

    if (first_day.weekday()>3) :
            return ret_val-1
        else:
            return ret_val
    

    其中 ret_val 正是 Josh 的计算值。在 2017 年 6 月(有 5 周)和 2017 年 9 月测试。通过“2017-09-01”返回 0,因为那一天属于不属于 9 月的一周。

    最正确的方法是让方法返回输入日期所属的周数和月份名称

    【讨论】:

      【解决方案10】:
      def week_of_month(date_value):
       return (date_value.isocalendar()[1] - date_value.replace(day=1).isocalendar()[1] + 1)
      

      date_value 应该是时间戳格式 这将在所有情况下给出完美的答案

      【讨论】:

        【解决方案11】:

        @Manuel Solorzano's answer 的变体:

        from calendar import monthcalendar
        def get_week_of_month(year, month, day):
            return next(
                (
                    week_number
                    for week_number, days_of_week in enumerate(monthcalendar(year, month), start=1)
                    if day in days_of_week
                ),
                None,
            )
        

        例如:

        >>> get_week_of_month(2020, 9, 1)
        1
        >>> get_week_of_month(2020, 9, 30)
        5
        >>> get_week_of_month(2020, 5, 35)
        None
        

        【讨论】:

          【解决方案12】:

          假设我们有如下月份的日历:

          Mon Tue Wed Thur Fri Sat Sun
                           1   2   3 
          4   5   6   7    8   9   10
          

          我们说第 1 ~ 3 天属于第 1 周,第 4 ~ 10 天属于第 2 周等等。

          在这种情况下,我认为特定日期的 week_of_month 应按如下方式计算:

          import datetime
          def week_of_month(year, month, day):
              weekday_of_day_one = datetime.date(year, month, 1).weekday()
              weekday_of_day = datetime.date(year, month, day)
              return (day - 1)//7 + 1 + (weekday_of_day < weekday_of_day_one)
          

          但是,如果我们想要获取该日期所在的第 n 个工作日,例如第 1 天是 1st 星期五,第 8 天是 2nd 星期五,而第 6 天是 1st 星期三,那么我们可以简单地返回 (day - 1)//7 + 1

          【讨论】:

          • 效果很好,但我们需要:weekday_of_day = datetime.date(year, month, day).weekday()
          【解决方案13】:

          您要查找的答案是(dm-dw+(dw-dm)%7)/7+1,其中dm 是月份中的某天,dw 是星期几,% 是正余数。

          这来自将月份偏移量 (mo) 和月份的周数 (wm) 关联起来,其中月份偏移量是第一天开始到一周的距离。如果我们考虑所有这些变量都从 0 开始,我们有

          wm*7+dw = dm+mo
          

          您可以解决 mo 的模 7,因为这会导致 wm 变量丢失,因为它只显示为 7 的倍数

          dw = dm+mo   (%7)
          mo = dw-dm   (%7)
          mo = (dw-dm)%7  (since the month offset is 0-6)
          

          然后你只需将月份偏移量代入原始方程并求解wm

          wm*7+dw = dm+mo
          wm*7 = dm-dw + mo
          wm*7 = dm-dw + (dw-dm)%7
          wm = (dm-dw + (dw-dm)%7) / 7
          

          由于dmdw 总是成对的,它们可以任意偏移,因此,将所有内容切换为以1 开头只会将等式更改为(dm-dw + (dw-dm)%7)/7 + 1

          当然,python datetime 库在 1 处开始 dm,在 0 处开始 dw。因此,假设 datedatatime.date 对象,您可以使用

          (date.day-1-date.dayofweek() + (date.dayofweek()-date.day+1)%7) / 7 + 1
          

          由于内部位始终是 7 的倍数(字面意思是 dw*7),您可以看到第一个 -date.dayofweek() 只是将值向后调整到最接近 7 的倍数。整数除法也是如此,所以它可以进一步简化为

          (date.day-1 + (date.dayofweek()-date.day+1)%7) // 7 + 1
          

          请注意,dayofweek() 将星期日放在周末。

          【讨论】:

          • 感谢您的回答。这是 100% 正确的。我已经通过使用 calendar.monthcalendar 作为事实来源并从 datetime.date.min 到 datetime.date.max 进行了测试,结果是相同的。我只需要更改 daysofweek() -> weekday() 并在最后删除 +1。请查看此要点以获取更多详细信息。 gist.github.com/klement97/0912e56a8023741e87201fac0da261cd
          【解决方案14】:

          应该这样做。

          #! /usr/bin/env python2
          
          import calendar, datetime
          
          #FUNCTIONS
          def week_of_month(date):
              """Determines the week (number) of the month"""
          
              #Calendar object. 6 = Start on Sunday, 0 = Start on Monday
              cal_object = calendar.Calendar(6)
              month_calendar_dates = cal_object.itermonthdates(date.year,date.month)
          
              day_of_week = 1
              week_number = 1
          
              for day in month_calendar_dates:
                  #add a week and reset day of week
                  if day_of_week > 7:
                      week_number += 1
                      day_of_week = 1
          
                  if date == day:
                      break
                  else:
                      day_of_week += 1
          
              return week_number
          
          
          #MAIN
          example_date = datetime.date(2015,9,21)
          
          print "Week",str(week_of_month(example_date))
          #Returns 'Week 4'
          

          【讨论】:

            【解决方案15】:

            移动到一个月的最后一天并除以 7

            from math import ceil
            
            def week_of_month(dt):
                """ Returns the week of the month for the specified date.
                """
                # weekday from monday == 0 ---> sunday == 6
                last_day_of_week_of_month = dt.day + (7 - (1 + dt.weekday()))
                return int(ceil(last_day_of_week_of_month/7.0))
            

            【讨论】:

              【解决方案16】:
                import datetime
                  
                def week_number_of_month(date_value):
                          week_number = (date_value.isocalendar()[1] - date_value.replace(day=1).isocalendar()[1] + 1)
                          if week_number == -46:
                              week_number = 6
                         return week_number
                              
               date_given = datetime.datetime(year=2018, month=12, day=31).date()
                              
               week_number_of_month(date_given)
              

              【讨论】:

                【解决方案17】:

                您可以简单地执行以下操作:

                1. 先提取年份数字的月份和星期
                df['month'] = df['Date'].dt.month
                df['week'] = df['Date'].dt.week 
                
                1. 然后按月分组并排列周数
                df['weekOfMonth'] = df.groupby('month')["week"].rank("dense", ascending=False)
                

                【讨论】:

                  猜你喜欢
                  • 2010-12-20
                  • 1970-01-01
                  • 1970-01-01
                  • 2015-04-20
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多