如何找到datetime.isocalendar()的逆函数?

2024-05-19 10:28:00 发布

您现在位置:Python中文网/ 问答频道 /正文

Python^{}方法返回给定datetime对象的元组(ISO_year, ISO_week_number, ISO_weekday)。有对应的反函数吗?如果没有,有没有一种简单的方法来计算一年中给定的日期、周数和一周中的某一天?


Tags: 对象方法numberdatetimeisoyear元组week
3条回答
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日。正如解释所说,选择哪一天作为参考点并不重要,但选择1月4日让这个选择变得不那么“神奇”。

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

%G
ISO 8601 year with century representing the year that contains the greater part of the ISO week (%V).

%u
ISO 8601 weekday as a decimal number where 1 is Monday.

%V
ISO 8601 week as a decimal number with Monday as the first day of the week. Week 01 is the week containing Jan 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()

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

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)

相关问题 更多 >

    热门问题