我正在尝试计算给定日期的第n个工作日。例如,我应该能够在给定日期计算当月的第3个星期三。
我已经写了两个版本的函数应该这样做:
from datetime import datetime, timedelta
### version 1
def nth_weekday(the_date, nth_week, week_day):
temp = the_date.replace(day=1)
adj = (nth_week-1)*7 + temp.weekday()-week_day
return temp + timedelta(days=adj)
### version 2
def nth_weekday(the_date, nth_week, week_day):
temp = the_date.replace(day=1)
adj = temp.weekday()-week_day
temp += timedelta(days=adj)
temp += timedelta(weeks=nth_week)
return temp
控制台输出
# Calculate the 3rd Friday for the date 2011-08-09
x=nth_weekday(datetime(year=2011,month=8,day=9),3,4)
print 'output:',x.strftime('%d%b%y')
# output: 11Aug11 (Expected: '19Aug11')
这两个函数中的逻辑显然是错误的,但我似乎无法找到错误 - 任何人都可以发现代码有什么问题 - 我如何修复它以返回正确的值?
答案 0 :(得分:10)
<强>单行强>
您可以使用标准库中的日历找到第n个工作日。
import calendar
calendar.Calendar(x).monthdatescalendar(year, month)[n][0]
其中:的
x:表示工作日的整数(0表示星期一)
n:问题的“第n”部分
年,月:整数年和月
这将返回datetime.date对象。
细分
可以这样分解:
calendar.Calendar(x)
创建一个日历对象,其工作日从您所需的工作日开始。
.monthdatescalendar(year, month)
返回该月的所有日历日。
[n][0]
返回第n周的0索引值(该周的第一天,从第x天开始)。
工作原理
在您所需的工作日开始一周的原因是默认情况下0(星期一)将用作一周的第一天,如果月份从星期三开始,则日历将考虑开始的第一周第一次出现在星期一(即第2周),你将落后一周。
示例强>
如果您需要2013年9月的第三个星期六(当月的美国股票期权到期日),您将使用以下内容:
calendar.Calendar(5).monthdatescalendar(2013,9)[3][0]
答案 1 :(得分:7)
你的问题在这里:
adj = temp.weekday()-week_day
首先,你正在以错误的方式减去事物:你需要从所需的那一天减去实际的一天,而不是相反。
其次,您需要确保减法的结果不是负数 - 应使用% 7
将其置于0-6范围内。
结果:
adj = (week_day - temp.weekday()) % 7
此外,在您的第二个版本中,您需要像在第一个版本中那样添加nth_week-1
周。
完整示例:
def nth_weekday(the_date, nth_week, week_day):
temp = the_date.replace(day=1)
adj = (week_day - temp.weekday()) % 7
temp += timedelta(days=adj)
temp += timedelta(weeks=nth_week-1)
return temp
>>> nth_weekday(datetime(2011,8,9), 3, 4)
datetime.datetime(2011, 8, 19, 0, 0)
答案 2 :(得分:1)
单票投票最多的问题是它不起作用。
但是它可以用作完善的基础:
您看到的是您得到的:
c = calendar.Calendar(calendar.SUNDAY).monthdatescalendar(2018, 7)
for c2 in c:
print(c2[0])
2018-07-01
2018-07-08
2018-07-15
2018-07-22
2018-07-29
c = calendar.Calendar(calendar.SUNDAY).monthdatescalendar(2018, 8)
for c2 in c:
print(c2[0])
2018-07-29
2018-08-05
2018-08-12
2018-08-19
2018-08-26
如果考虑到这一点,它正在尝试将日历组织到嵌套列表中,一次打印一周的日期。因此,其他月份的流浪者开始发挥作用。通过使用该月有效日期的新列表,可以达到目的。
带有附加列表的答案
import calendar
import datetime
def get_nth_DOW_for_YY_MM(dow, yy, mm, nth) -> datetime.date:
#dow - Python Cal - 6 Sun 0 Mon ... 5 Sat
#nth is 1 based... -1. is ok for last.
i = -1 if nth == -1 or nth == 5 else nth -1
valid_days = []
for d in calendar.Calendar(dow).monthdatescalendar(yy, mm):
if d[0].month == mm:
valid_days.append(d[0])
return valid_days[i]
所以这是怎么称呼的:
firstSundayInJuly2018 = get_nth_DOW_for_YY_MM(calendar.SUNDAY, 2018, 7, 1)
firstSundayInAugust2018 = get_nth_DOW_for_YY_MM(calendar.SUNDAY, 2018, 8, 1)
print(firstSundayInJuly2018)
print(firstSundayInAugust2018)
这是输出:
2018-07-01
2018-08-05
可以使用如下lambda表达式重构 get_nth_DOW_for_YY_MM()
:
具有lambda表达式重构的答案
import calendar
import datetime
def get_nth_DOW_for_YY_MM(dow, yy, mm, nth) -> datetime.date:
#dow - Python Cal - 6 Sun 0 Mon ... 5 Sat
#nth is 1 based... -1. is ok for last.
i = -1 if nth == -1 or nth == 5 else nth -1
return list(filter(lambda x: x.month == mm, \
list(map(lambda x: x[0], \
calendar.Calendar(dow).monthdatescalendar(yy, mm) \
)) \
))[i]
答案 3 :(得分:0)
如果目标日落在该月的第一天,那么单行答案似乎不起作用。例如,如果你想要每个月的第二个星期五,那么单线方法
calendar.Calendar(4).monthdatescalendar(year, month)[2][0]
2013年3月将于2013年3月15日返回时应该是2013年3月8日。也许可以添加支票
if date(year, month, 1).weekday() == x:
delivery_date.append(calendar.Calendar(x).monthdatescalendar(year, month)[n-1][0])
else:
delivery_date.append(calendar.Calendar(x).monthdatescalendar(year, month)[n][0])
答案 4 :(得分:0)
或者这适用于Python 2,返回上述月份的工作日,即2018年6月16日是输入,然后返回2018年6月16日当天的出现
您可以将月份/年份/日期整数替换为您可能需要的任何内容 - 现在它通过datetime
省略打印报表或使用pass
不需要的地方
import calendar
import datetime
import pprint
month_number = int(datetime.datetime.now().strftime('%m'))
year_number = int(datetime.datetime.now().strftime('%Y'))
date_number = int(datetime.datetime.now().strftime('%d'))
day_ofweek = str(datetime.datetime.now().strftime('%A'))
def weekday_occurance():
print "\nFinding current date here\n"
for week in xrange(5):
try:
calendar.monthcalendar(year_number, month_number)[week].index(date_number)
occurance = week + 1
print "Date %s of month %s and year %s is %s #%s in this month." % (date_number,month_number,year_number,day_ofweek,occurance)
return occurance
break
except ValueError as e:
print "The date specified is %s which is week %s" % (e,week)
myocc = weekday_occurance()
print myocc
答案 5 :(得分:0)
稍微调整一下就可以使单行正常工作:
import calendar
calendar.Calendar((weekday+1)%7).monthdatescalendar(year, month)[n_th][-1]
这里的 n_th
应该被解释为 c-style,例如0 是第一个索引。
示例:要查找 2018 年 7 月的第一个星期日,可以输入:
>>> calendar.Calendar(0).monthdatescalendar(2018, 7)[0][-1]
datetime.date(2018, 7, 1)
答案 6 :(得分:0)
这里的人似乎喜欢单线,我会在下面推荐。
import calendar
[cal[0] for cal in calendar.Calendar(x).monthdatescalendar(year, month) if cal[0].month == month][n]