python 找到 datetime.isocalendar() 倒数的最佳方法是什么?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/304256/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What's the best way to find the inverse of datetime.isocalendar()?
提问by Tom
The Python datetime.isocalendar()
method returns a tuple (ISO_year, ISO_week_number, ISO_weekday)
for the given datetime
object. Is there a corresponding inverse function? If not, is there an easy way to compute a date given a year, week number and day of the week?
Pythondatetime.isocalendar()
方法返回(ISO_year, ISO_week_number, ISO_weekday)
给定datetime
对象的元组。有对应的反函数吗?如果没有,是否有一种简单的方法来计算给定年份、周数和星期几的日期?
回答by Ben James
I recently had to solve this problem myself, and came up with this solution:
我最近不得不自己解决这个问题,并想出了这个解决方案:
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)
A few test cases:
几个测试用例:
>>> 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)
回答by Martijn Pieters
As of Python 3.6, you can use the new %G
, %u
and %V
directives. See issue 12006and the updated documentation:
从 Python 3.6 开始,您可以使用新的%G
,%u
和%V
指令。请参阅问题 12006和更新的文档:
%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.
%G
ISO 8601 年,世纪代表包含 ISO 周大部分时间的年份 (%V
)。
%u
ISO 8601 工作日为十进制数,其中 1 是星期一。
%V
ISO 8601 周为十进制数,星期一为一周的第一天。第 1 周是包含 1 月 4 日的那一周。
Given a string with year, weeknumber and weekday number, it is easy to parse those out to a date with:
给定一个包含年、周数和工作日数的字符串,很容易将它们解析为日期:
from datetime import datetime
datetime.strptime('2002 01 1', '%G %V %u').date()
or as a function with integer inputs:
或作为具有整数输入的函数:
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()
回答by jwg
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)
This was adapted from @BenJames's very good answer. You don't have to know the first day of the year. You just have to know an example of a date which is certainly in the same ISO year, and the ISO calendar week and day of that date.
这是改编自@BenJames 的非常好的答案。你不必知道一年的第一天。您只需要知道肯定在同一 ISO 年份中的日期示例,以及该日期的 ISO 日历周和日。
The 4th of Jan is simply one example, because, as Ben pointed out, the 4th of Jan always belongs to the same ISO year and Gregorian year, and is the first day of the year to do so.
1 月 4 日只是一个例子,因为正如 Ben 指出的那样,1 月 4 日始终属于同一个 ISO 年和公历年,并且是一年中的第一天。
Since weeks are all the same length, you can simply subtract the days and weeks between the ISO of the date you want, and the ISO of the date which you know in both forms, and add on that number of days and weeks. (It doesn't matter whether these numbers are positive or negative, so you could choose some other 'fixed day' such as Dec 28th.)
由于周的长度都相同,您可以简单地减去所需日期的 ISO 与您在两种形式中都知道的日期的 ISO 之间的天数和周数,然后加上该天数和周数。(这些数字是正数还是负数都没有关系,因此您可以选择其他一些“固定日期”,例如 12 月 28 日。)
Edit
编辑
I corrected this because, as was helpfully pointed by @JoSo, the first day of the Gregorian year which also belongs to the ISO year is Jan 4th not Jan 5th. As the explanation says, it doesn't matter which date is chosen as a reference point, but choosing the Jan 4th makes this choice less 'magic'.
我更正了这一点,因为正如@JoSo 所帮助指出的那样,同样属于 ISO 年的公历年的第一天是 1 月 4 日而不是 1 月 5 日。正如解释所说,选择哪个日期作为参考点并不重要,但选择 1 月 4 日会使这个选择不那么“神奇”。
回答by Jo So
For the next people coming here, a shorter, single-def, version of Ben's good solution:
对于接下来来到这里的人,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)
回答by Erik Cederstrand
Starting in Python 3.6, datetime.strptime()
will support the %G
, %V
and %u
directives, so you can simply do datetime.strptime('2015 1 2', '%G %V %u').date()
. See: https://hg.python.org/cpython/rev/acdebfbfbdcf
从 Python 3.6 开始,datetime.strptime()
将支持%G
,%V
和%u
指令,因此您可以简单地执行datetime.strptime('2015 1 2', '%G %V %u').date()
. 见:https: //hg.python.org/cpython/rev/acdebfbfbdcf
回答by oviedodaniel
I came up with a solution similar to the one posted by Ben James, but using a single function:
我想出了一个类似于 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)
I tested it out with boundary values such as the last week of 2020 and first week of 2021, and it worked out pretty well.
我用边界值(例如 2020 年的最后一周和 2021 年的第一周)对其进行了测试,结果非常好。
回答by oviedodaniel
Note that %W is the week # (0-53) which is NOT THE SAME as the ISO week (1-53). There will be edge cases where %W will not work.
请注意,%W 是第 # (0-53) 周,它与 ISO 周 (1-53) 不同。会有 %W 不起作用的边缘情况。
回答by Tom
EDIT: ignore this, the edge cases are a pain. Go with Ben's solution.
编辑:忽略这一点,边缘情况很痛苦。使用 Ben 的解决方案。
Ok, on closer inspection I noticed that strptime
has %W
and %w
parameters, so the following works:
好的,经过仔细检查,我注意到strptime
has%W
和%w
parameters,因此以下有效:
def fromisocalendar(y,w,d):
return datetime.strptime( "%04dW%02d-%d"%(y,w-1,d), "%YW%W-%w")
A couple of gotchas: The ISO week number starts at 1
, while %W
starts at 0
. The ISO week day starts at 1
(Monday), which is the same as %w
, so Sunday would probably have to be 0
, not 7
...
几个问题:ISO 周数从 开始1
,而%W
从0
. ISO 工作日从1
(Monday)开始,这与 相同%w
,因此周日可能必须是0
,而不是7
...