查找datetime.isocalendar()的反转的最佳方法是什么?

时间:2008-11-20 03:38:52

标签: python datetime

Python datetime.isocalendar()方法为给定的(ISO_year, ISO_week_number, ISO_weekday)对象返回元组datetime。是否有相应的反函数?如果没有,是否有一种简单的方法来计算给定年份,周数和星期几的日期?

8 个答案:

答案 0 :(得分:64)

我最近不得不自己解决这个问题,并提出了这个解决方案:

import datetime

def iso_year_start(iso_year):
    "The gregorian calendar date of the first day of the given ISO year"
    fourth_jan = datetime.date(iso_year, 1, 4)
    delta = datetime.timedelta(fourth_jan.isoweekday()-1)
    return fourth_jan - delta 

def iso_to_gregorian(iso_year, iso_week, iso_day):
    "Gregorian calendar date for the given ISO year, week and day"
    year_start = iso_year_start(iso_year)
    return year_start + datetime.timedelta(days=iso_day-1, weeks=iso_week-1)

一些测试用例:

>>> iso = datetime.date(2005, 1, 1).isocalendar()
>>> iso
(2004, 53, 6)
>>> iso_to_gregorian(*iso)
datetime.date(2005, 1, 1)

>>> iso = datetime.date(2010, 1, 4).isocalendar()    
>>> iso
(2010, 1, 1)
>>> iso_to_gregorian(*iso)
datetime.date(2010, 1, 4)

>>> iso = datetime.date(2010, 1, 3).isocalendar()
>>> iso
(2009, 53, 7)
>>> iso_to_gregorian(*iso)
datetime.date(2010, 1, 3)

答案 1 :(得分:10)

import datetime

def iso_to_gregorian(iso_year, iso_week, iso_day):
    "Gregorian calendar date for the given ISO year, week and day"
    fourth_jan = datetime.date(iso_year, 1, 4)
    _, fourth_jan_week, fourth_jan_day = fourth_jan.isocalendar()
    return fourth_jan + datetime.timedelta(days=iso_day-fourth_jan_day, weeks=iso_week-fourth_jan_week)

这是改编自@ BenJames的非常好的答案。你不必知道一年的第一天。您只需要知道一个日期的例子,该日期肯定在同一个ISO年份,以及该日期的ISO日历周和日期。

1月4日只是一个例子,因为正如本指出的那样,1月4日总是属于同一个ISO年和格里高利年,并且是一年中的第一天。

由于周长度相同,您可以简单地减去所需日期的ISO与两种表格中您知道的日期的ISO之间的天数和周数,并添加该天数和周数。 (这些数字是正数还是负数并不重要,所以你可以选择其他一些'固定日',例如12月28日。)

修改

我纠正了这一点,因为正如@JoSo所指出的那样,格里高利年的第一天也属于ISO年份,是1月4日而不是1月5日。正如解释所说,选择哪个日期作为参考点并不重要,但选择Jan 4会使这个选择变得不那么“神奇”。

答案 2 :(得分:9)

从Python 3.6开始,您可以使用新的%G%u%V指令。请参阅issue 12006updated documentation

  

%G
  ISO 8601年,世纪代表包含ISO周的大部分时间的年份(%V)。

     

%u
  工作日的ISO 8601为十进制数,其中1为星期一。

     

%V
  ISO 8601周作为十进制数,星期一作为一周的第一天。第01周是包含1月4日的一周。

给定一个包含年份,周数和工作日数字的字符串,可以很容易地将这些字符串解析为以下日期:

from datetime import datetime

datetime.strptime('2002 01 1', '%G %V %u').date()

或作为具有整数输入的函数:

from datetime import datetime

def date_from_isoweek(iso_year, iso_weeknumber, iso_weekday):
    return datetime.strptime(
        '{:04d} {:02d} {:d}'.format(iso_year, iso_weeknumber, iso_weekday),
        '%G %V %u').date()

答案 3 :(得分:3)

从Python 3.6开始,datetime.strptime()将支持%G%V%u指令,因此您只需执行datetime.strptime('2015 1 2', '%G %V %u').date()即可。请参阅:https://hg.python.org/cpython/rev/acdebfbfbdcf

答案 4 :(得分:3)

对于来到这里的下一个人来说,这是Ben的优秀解决方案的简短单一版本:

def iso_to_gregorian(iso_year, iso_week, iso_day):
    jan4 = datetime.date(iso_year, 1, 4)
    start = jan4 - datetime.timedelta(days=jan4.isoweekday()-1)
    return start + datetime.timedelta(weeks=iso_week-1, days=iso_day-1)

答案 5 :(得分:0)

请注意,%W是周#(0-53),与ISO周(1-53)不同。会有边缘情况,%W将无效。

答案 6 :(得分:0)

我想出了一种与本·詹姆斯(Ben James)发布的解决方案类似的解决方案,但是使用了一个功能:

import datetime
def getDateFromWeek(year,week,day):
    """Method to retrieve the date from the specified week, year and weekday"""

    year_start = datetime.date(year,1,1)
    ys_weekday =  year_start.weekday()
    delta = (week*7)+(day-ys_weekday)
    if ys_weekday<4:
        delta -= 7

    return  year_start  + datetime.timedelta(days=delta)

我用2020年最后一周和2021年第一周之类的边界值进行了测试,效果很好。

答案 7 :(得分:-1)

编辑:忽略这一点,边缘情况很痛苦。选择Ben的解决方案。

好的,经过仔细检查,我发现strptime%W%w个参数,因此以下工作原理:

def fromisocalendar(y,w,d):
   return datetime.strptime( "%04dW%02d-%d"%(y,w-1,d), "%YW%W-%w")

一些问题:ISO周号从1开始,而%W0开始。 ISO周工作日从1(星期一)开始,与%w相同,因此星期日可能必须是0,而不是7 ...