【问题标题】:How to get week number in Python?如何在 Python 中获取周数?
【发布时间】:2011-02-05 17:52:40
【问题描述】:

如何使用 Python 找出今年 6 月 16 日(wk24)的周数?

【问题讨论】:

  • @Donal:一个在 6 月 16 日,另一个在 6 月 26 日。
  • 定义第一周。isocalendar() 不是唯一的方法。
  • 请注意strftime("%U", d) 的输出可能与isocalendar() 不同。例如,如果您将年份更改为 2004 年,您将使用 strftime() 获得第 24 周,使用 isocalendar() 获得第 25 周。

标签: python


【解决方案1】:

datetime.date 有一个isocalendar() 方法,它返回一个包含日历周的元组:

>>> import datetime
>>> datetime.date(2010, 6, 16).isocalendar()[1]
24

datetime.date.isocalendar() 是一个实例方法,返回一个元组,其中包含给定日期实例的相应顺序的年、周数和工作日。

在 Python 3.9+ 中,isocalendar() 返回一个带有 yearweekweekday 字段的 namedtuple,这意味着您可以使用命名属性显式访问星期:

>>> import datetime
>>> datetime.date(2010, 6, 16).isocalendar().week
24

【讨论】:

  • 如果您解释了“[1]”,或者提供了查找信息的指针,将会有所帮助。
  • 我想最简单的方法是使用strftime提取周数,最好 import datetime today = datetime.now() week = today.strftime("%W")
  • 这有点晚了。但在我的机器上,date(2010, 1, 1).isocalendar()[1] 返回53。来自文档:“例如,2004 年从星期四开始,因此 ISO 2004 年的第一周从 2003 年 12 月 29 日星期一开始,到 2004 年 1 月 4 日星期日结束,因此 date(2003, 12, 29).isocalendar() == (2004, 1, 1)date(2004, 1, 4).isocalendar() == (2004, 1, 7)。”
  • isocalendar() 很棒,但请确保它是您想要的。今天就是一个完美的例子。 2016 年 1 月 1 日等于 (2015, 53, 5)now.strftime("%W")now.strftime("%U") 等于 00,这通常是我们想要的。 STRFTIME examples
  • datetime.utcnow().isocalendar().week
【解决方案2】:

您可以直接从日期时间获取周数作为字符串。

>>> import datetime
>>> datetime.date(2010, 6, 16).strftime("%V")
'24'

您还可以通过更改strftime 参数来获得一年中不同“类型”的周数:

%U - 一年中的周数(星期天为一周的第一天) 零填充十进制数。新年中第一个星期日之前的所有日子都被认为是在第 0 周。示例:00、01、...、53

%W - 以十进制数表示的一年中的周数(星期一 为一周的第一天)。新年中第一个星期一之前的所有日子都被认为是在第 0 周。示例:00、01、...、53

[...]

在 Python 3.6 中添加,向后移植到某些发行版的 Python 2.7)为方便起见,包含了 C89 标准不需要的几个附加指令。这些参数都对应于 ISO 8601 日期值。 strftime() 方法一起使用时,这些可能并非在所有平台上都可用。

[...]

%V - ISO 8601 周 十进制数字,星期一是一周的第一天。第 01 周是包含 1 月 4 日的那一周。示例:01、02、...、53

来自:datetime — Basic date and time types — Python 3.7.3 documentation

我是从here 了解到的。它在 Python 2.7.6 中对我有用

【讨论】:

  • 你在引用什么,一些 Linux 手册? Python 2.7.5 和 3.3.2 对这种模式说 Invalid format string。他们的文档也没有提到%V
  • 对不起,我没有提到它,我来自here。它在 Python 2.7.6 中对我有用。
  • 很好的答案!我想补充一点,如果您对日期的“-”表示感兴趣,请使用%G-%V 而不是%Y-%V%G%Y 的 ISO 年等值
  • 我必须这样写才能让它工作:datetime.datetime(2010, 6, 16).strftime("%V"),或者像这样 datetime.datetime(2010, 6, 16).date().strftime("%V")
  • 如何将此解决方案应用于整个数据框列?
【解决方案3】:

我相信date.isocalendar() 会是答案。 This article 解释了 ISO 8601 日历背后的数学原理。查看 Python 文档的 datetime page 的 date.isocalendar() 部分。

>>> dt = datetime.date(2010, 6, 16) 
>>> wk = dt.isocalendar()[1]
24

.isocalendar() 返回一个 3 元组 (year, wk num, wk day)。 dt.isocalendar()[0] 返回年份,dt.isocalendar()[1] 返回星期数,dt.isocalendar()[2] 返回星期几。尽可能简单。

【讨论】:

  • +1 链接解释了 ISO 周的非直观性质。
【解决方案4】:

这是另一个选择:

import time
from time import gmtime, strftime
d = time.strptime("16 Jun 2010", "%d %b %Y")
print(strftime(d, '%U'))

打印24

见:http://docs.python.org/library/datetime.html#strftime-and-strptime-behavior

【讨论】:

  • 或 %W 如果您的周从星期一开始。
  • 这种方法在您不想拆分或转换以字符串形式出现的日期的情况下更好...只需按原样以字符串格式传递 strptime 中的字符串并指定格式在第二个论点。很好的解决方案。请记住:如果一周从星期一开始,则为 %W。
  • 这对我有用!我在使用上述答案时遇到了日期时间问题datetime.datetime(2019, 12, 30),这给了我1,但这给出了正确的星期。
  • TypeError: strftime() 参数 1 必须是 str,而不是 time.struct_time
  • 我只需添加int(),因此:print(int(strftime(d, '%U'))) 以避免前导零。
【解决方案5】:

许多用于周编号的系统。以下是最常见的系统,简单地用代码示例说明:

  • ISO:第一周从星期一开始,并且必须包含 1 月 4 日。 ISO 日历已经在 Python 中实现:

    >>> from datetime import date
    >>> date(2014, 12, 29).isocalendar()[:2]
    (2015, 1)
    
  • 北美:第一周从星期日开始,并且必须包含 1 月 1 日。以下代码是我对北美系统的 Python 的 ISO 日历实现的修改版本:

    from datetime import date
    
    def week_from_date(date_object):
        date_ordinal = date_object.toordinal()
        year = date_object.year
        week = ((date_ordinal - _week1_start_ordinal(year)) // 7) + 1
        if week >= 52:
            if date_ordinal >= _week1_start_ordinal(year + 1):
                year += 1
                week = 1
        return year, week
    
    def _week1_start_ordinal(year):
        jan1 = date(year, 1, 1)
        jan1_ordinal = jan1.toordinal()
        jan1_weekday = jan1.weekday()
        week1_start_ordinal = jan1_ordinal - ((jan1_weekday + 1) % 7)
        return week1_start_ordinal
    
    >>> from datetime import date
    >>> week_from_date(date(2014, 12, 29))
    (2015, 1)
    
  • MMWR (CDC):第一周从星期日开始,并且必须包含 1 月 4 日。我专门为这个编号系统创建了epiweeks 包(也支持 ISO 系统)。这是一个例子:
    >>> from datetime import date
    >>> from epiweeks import Week
    >>> Week.fromdate(date(2014, 12, 29))
    (2014, 53)
    

【讨论】:

  • 这是该问题的最佳答案,因为它考虑了年份编号和不同的周编号标准。
【解决方案6】:

其他人建议的 ISO 周不错,但可能不符合您的需求。它假设每周都从星期一开始,这会导致年初和年末出现一些有趣的异常情况。

如果您更愿意使用这样的定义,即第 1 周始终是 1 月 1 日到 1 月 7 日,而不管一周中的哪一天,请使用如下推导:

>>> testdate=datetime.datetime(2010,6,16)
>>> print(((testdate - datetime.datetime(testdate.year,1,1)).days // 7) + 1)
24

【讨论】:

  • 说 isocalendar 在年初和年末有“一些有趣的异常”似乎有点轻描淡写。对于某些日期时间值,例如 2014 年 12 月 29 日 00:00:00,isocalendar 的结果非常具有误导性(即使在 ISO 规范下实际上并不正确),根据 isocalendar 的年份值为 2015 年和周数为 1(请参阅我在下面的条目)。
  • @Kevin,没有错,只是他们的定义与你的不符。 ISO 决定了两件事:第一,从周一到周日的整个星期都在同一年,第二,包含大部分日子的那一年将是指定的那一年。这会导致一年中年初和年末的一周中的几天进入下一年。
  • 同意。但按照大多数人的定义,2014 年 12 月 29 日绝对不是 2015 年的第一周。我只是想提请注意这个潜在的混乱来源。
  • 这正是我想要的。不是关于如何做到这一点,而是关于 ISO 和从星期一开始的信息。
【解决方案7】:

一般获取当前周数(从周日开始):

from datetime import *
today = datetime.today()
print today.strftime("%U")

【讨论】:

  • 来自 strftime('%U') 的文档:“一年中的周数(星期日为一周的第一天)为十进制数 [00,53]。第一个星期日之前的新年被认为是在第 0 周。”
【解决方案8】:

对于一年中的瞬时周的整数值,请尝试:

import datetime
datetime.datetime.utcnow().isocalendar()[1]

【讨论】:

    【解决方案9】:

    如果您只使用等日历周数,则以下内容就足够了:

    import datetime
    week = date(year=2014, month=1, day=1).isocalendar()[1]
    

    这将检索 isocalendar 返回的元组的第二个成员,用于我们的周数。

    但是,如果您要使用处理公历的日期函数,则单独使用 isocalendar 是行不通的!举个例子:

    import datetime
    date = datetime.datetime.strptime("2014-1-1", "%Y-%W-%w")
    week = date.isocalendar()[1]
    

    这里的字符串表示返回 2014 年第一周的星期一作为我们的日期。当我们在这里使用 isocalendar 检索周数时,我们希望得到相同的周数,但我们没有。相反,我们得到的周数是 2。为什么?

    公历中的第 1 周是包含星期一的第一周。等历中的第 1 周是包含星期四的第一周。 2014 年初的部分周包含一个星期四,所以这是等日历的第 1 周,因此 date 第 2 周。

    如果我们想要获得公历周,我们需要将等历转换为公历。这是一个可以解决问题的简单函数。

    import datetime
    
    def gregorian_week(date):
        # The isocalendar week for this date
        iso_week = date.isocalendar()[1]
    
        # The baseline Gregorian date for the beginning of our date's year
        base_greg = datetime.datetime.strptime('%d-1-1' % date.year, "%Y-%W-%w")
    
        # If the isocalendar week for this date is not 1, we need to 
        # decrement the iso_week by 1 to get the Gregorian week number
        return iso_week if base_greg.isocalendar()[1] == 1 else iso_week - 1
    

    【讨论】:

      【解决方案10】:

      我将讨论总结为两个步骤:

      1. 将原始格式转换为datetime 对象。
      2. 使用datetime对象或date对象的函数计算周数。

      热身

      from datetime import datetime, date, time
      d = date(2005, 7, 14)
      t = time(12, 30)
      dt = datetime.combine(d, t)
      print(dt)
      

      第一步

      要手动生成datetime对象,我们可以使用datetime.datetime(2017,5,3)datetime.datetime.now()

      但实际上,我们通常需要解析一个现有的字符串。我们可以使用strptime 函数,例如datetime.strptime('2017-5-3','%Y-%m-%d'),您必须在其中指定格式。不同格式代码的详细信息可以在official documentation中找到。

      另外,更方便的方法是使用dateparse 模块。例如dateparser.parse('16 Jun 2010')dateparser.parse('12/2/12')dateparser.parse('2017-5-3')

      以上两种方法都会返回一个datetime对象。

      第二步

      使用获取到的datetime对象调用strptime(format)。例如,

      蟒蛇

      dt = datetime.strptime('2017-01-1','%Y-%m-%d') # return a datetime object. This day is Sunday
      print(dt.strftime("%W")) # '00' Monday as the 1st day of the week. All days in a new year preceding the 1st Monday are considered to be in week 0.
      print(dt.strftime("%U")) # '01' Sunday as the 1st day of the week. All days in a new year preceding the 1st Sunday are considered to be in week 0.
      print(dt.strftime("%V")) # '52' Monday as the 1st day of the week. Week 01 is the week containing Jan 4.
      

      决定使用哪种格式非常棘手。更好的方法是获取一个date 对象来调用isocalendar()。例如,

      蟒蛇

      dt = datetime.strptime('2017-01-1','%Y-%m-%d') # return a datetime object
      d = dt.date() # convert to a date object. equivalent to d = date(2017,1,1), but date.strptime() don't have the parse function
      year, week, weekday = d.isocalendar() 
      print(year, week, weekday) # (2016,52,7) in the ISO standard
      

      实际上,您更有可能使用date.isocalendar() 来准备每周报告,尤其是在Christmas-New Year 购物旺季。

      【讨论】:

        【解决方案11】:

        你可以试试下面的 %W 指令:

        d = datetime.datetime.strptime('2016-06-16','%Y-%m-%d')
        print(datetime.datetime.strftime(d,'%W'))
        

        '%W':以十进制数表示的一年中的周数(星期一为一周的第一天)。新年中第一个星期一之前的所有日子都被认为是在第 0 周。(00, 01, ..., 53)

        【讨论】:

          【解决方案12】:

          我发现这些是获取周数的最快方法;所有的变种。

          from datetime import datetime
          
          
          dt = datetime(2021, 1, 3)  # Date is January 3rd (sunday), 2021, year starts with Friday
          
          dt.strftime("%W")  # '00'; Monday is considered first day of week, Sunday is the last day of the week which started in the previous year
          dt.strftime("%U")  # '01'; Sunday is considered first day of week
          dt.strftime("%V")  # '53'; ISO week number; result is '53' since there is no Thursday in this year's part of the week
          

          可以在 Python 文档中找到对 %V 的进一步说明:

          ISO 年由 52 或 53 个整周组成,其中一周从星期一开始,到星期日结束。 ISO 年的第一周是包含星期四的一年中的第一个(公历)日历周。这称为第 1 周,该星期四的 ISO 年与其公历年相同。

          https://docs.python.org/3/library/datetime.html#datetime.date.isocalendar

          注意:请记住返回值是一个字符串,因此如果您需要一个数字,请将结果传递给int 构造函数。

          【讨论】:

            【解决方案13】:

            isocalendar() 对某些日期返回不正确的年份和周数值:

            Python 2.7.3 (default, Feb 27 2014, 19:58:35) 
            [GCC 4.6.3] on linux2
            Type "help", "copyright", "credits" or "license" for more information.
            >>> import datetime as dt
            >>> myDateTime = dt.datetime.strptime("20141229T000000.000Z",'%Y%m%dT%H%M%S.%fZ')
            >>> yr,weekNumber,weekDay = myDateTime.isocalendar()
            >>> print "Year is " + str(yr) + ", weekNumber is " + str(weekNumber)
            Year is 2015, weekNumber is 1
            

            与 Mark Ransom 的方法比较:

            >>> yr = myDateTime.year
            >>> weekNumber = ((myDateTime - dt.datetime(yr,1,1)).days/7) + 1
            >>> print "Year is " + str(yr) + ", weekNumber is " + str(weekNumber)
            Year is 2014, weekNumber is 52
            

            【讨论】:

            • 查看有关 iso8601 日历的一些链接(例如,staff.science.uu.nl/~gent0113/calendar/isocalendar.htm),我发现 isocalendar() 返回的年份和周数值并非“不正确”。例如,在 ISO8601 下,2004 年从 2003 年 12 月 29 日开始。所以 isocalendar() 可能在 2014 年 12 月 29 日返回 2015 年是正确的,但对于很多人来说,这将是相当误导.
            【解决方案14】:

            假设您需要将一周与当天的年份组合为一个字符串。

            import datetime
            year,week = datetime.date.today().isocalendar()[:2]
            week_of_the_year = f"{year}-{week}"
            print(week_of_the_year)
            

            你可能会得到类似 2021-28

            【讨论】:

              【解决方案15】:

              对于 pandas 用户,如果你想得到一列周数:

              df['weekofyear'] = df['Date'].dt.week
              

              【讨论】:

                【解决方案16】:

                如果您想更改一周的第一天,可以使用calendar module

                import calendar
                import datetime
                
                calendar.setfirstweekday(calendar.WEDNESDAY)
                isodate = datetime.datetime.strptime(sweek,"%Y-%m-%d").isocalendar()
                week_of_year = isodate[1]
                

                例如,计算从星期三开始的一周的冲刺次数:

                def calculate_sprint(sweek):
                    calendar.setfirstweekday(calendar.WEDNESDAY)
                    isodate=datetime.datetime.strptime(sweek,"%Y-%m-%d").isocalendar()
                    return "{year}-{month}".format(year=isodate[0], month=isodate[1])
                
                calculate_sprint('2021-01-01')
                >>>'2020-53'
                

                【讨论】:

                  【解决方案17】:

                  我们有一个类似的问题,我们想出了这个逻辑 我已经测试了 1 年的测试用例并且全部通过了

                  import datetime
                  
                  
                  def week_of_month(dt):
                  
                      first_day = dt.replace(day=1)
                      dom = dt.day
                      if first_day.weekday() == 6:
                          adjusted_dom = dom
                      else:
                          adjusted_dom = dom + first_day.weekday()
                      if adjusted_dom % 7 == 0 and first_day.weekday() != 6:
                         value = adjusted_dom / 7.0 + 1
                      elif first_day.weekday() == 6 and adjusted_dom % 7 == 0 and adjusted_dom == 7:
                          value = 1
                      else:
                          value = int(ceil(adjusted_dom / 7.0))
                  
                      return int(value)
                  
                  
                  year = 2020
                  month = 01
                  date = 01
                  
                  date_value = datetime.datetime(year, month, date).date()
                  no = week_of_month(date_value)
                  

                  【讨论】:

                    【解决方案18】:
                    userInput = input ("Please enter project deadline date (dd/mm/yyyy/): ")
                    
                    import datetime
                    
                    currentDate = datetime.datetime.today()
                    
                    testVar = datetime.datetime.strptime(userInput ,"%d/%b/%Y").date()
                    
                    remainDays = testVar - currentDate.date()
                    
                    remainWeeks = (remainDays.days / 7.0) + 1
                    
                    
                    print ("Please pay attention for deadline of project X in days and weeks are  : " ,(remainDays) , "and" ,(remainWeeks) , "Weeks ,\nSo  hurryup.............!!!") 
                    

                    【讨论】:

                      【解决方案19】:

                      已经给出了很多答案,但我想补充一下。

                      如果您需要将周显示为年/周样式(例如 1953 年 - 2019 年第 53 周、2001 年 - 2020 年第 1 周等),您可以这样做:

                      import datetime
                      
                      year = datetime.datetime.now()
                      week_num = datetime.date(year.year, year.month, year.day).strftime("%V")
                      long_week_num = str(year.year)[0:2] + str(week_num)
                      

                      它将采用当前年份和周数,并且在撰写本文的当天 long_week_num 将是:

                      >>> 2006
                      

                      【讨论】:

                      • 为什么要从头开始创建date()datetime.datetime() 实例具有用于该作业的 .date() 方法。
                      • 然而,更令人担忧的是,您的答案选择的是世纪,而不是当年。如果您打算对周数使用字符串格式,那么为什么不也使用它来包含年份呢?
                      猜你喜欢
                      • 2020-10-30
                      • 2014-02-04
                      • 1970-01-01
                      • 2010-09-13
                      • 1970-01-01
                      • 1970-01-01
                      • 2020-07-14
                      • 2021-04-17
                      相关资源
                      最近更新 更多