我需要从当前日期减去营业日。
我目前有一些代码需要始终在最近的工作日运行。所以今天可能是今天,如果我们是星期一到星期五,但如果是星期六或星期日,那么我需要把它设置回周末前的星期五。我目前有一些漂亮的笨重的代码来执行此操作:
lastBusDay = datetime.datetime.today()
if datetime.date.weekday(lastBusDay) == 5: #if it's Saturday
lastBusDay = lastBusDay - datetime.timedelta(days = 1) #then make it Friday
elif datetime.date.weekday(lastBusDay) == 6: #if it's Sunday
lastBusDay = lastBusDay - datetime.timedelta(days = 2); #then make it Friday
有更好的方法吗?
我可以告诉timedelta在工作日而不是日历日工作吗?
答案 0 :(得分:104)
使用熊猫!
import pandas as pd
# BDay is business day, not birthday...
from pandas.tseries.offsets import BDay
# pd.datetime is an alias for datetime.datetime
today = pd.datetime.today()
print today - BDay(4)
从今天是9月26日星期四,这将给你输出:
datetime.datetime(2013, 9, 20, 14, 8, 4, 89761)
答案 1 :(得分:13)
如果您愿意安装额外的库,似乎有几种选择。
本文介绍了使用dateutil定义工作日的方法。
http://coding.derkeiler.com/Archive/Python/comp.lang.python/2004-09/3758.html
BusinessHours允许您自定义假期列表等,以定义您的工作时间(以及延长工作日)。
答案 2 :(得分:9)
DISCLAMER:我是作者......
我写了一个包,它完成了这个,业务日期计算。您可以使用自定义周规格和假期。
我在使用财务数据时遇到了这个问题,并且没有找到任何可用的解决方案特别容易,所以我写了一个。
希望这对其他人有用。
答案 3 :(得分:6)
也许这段代码可以提供帮助:
lastBusDay = datetime.datetime.today()
shift = datetime.timedelta(max(1,(lastBusDay.weekday() + 6) % 7 - 3))
lastBusDay = lastBusDay - shift
这个想法是,星期一,你必须在3天,第2天和第1天再回来。
声明(lastBusDay.weekday() + 6) % 7
只是将星期一从0重新定为6。
真的不知道这在性能方面是否会更好。
答案 4 :(得分:4)
timeboard
包就是这样做的。
假设您的日期是2017年9月4日。尽管是星期一,但这是美国的假期(劳动节)。因此,最近的工作日是9月1日星期五。
>>> import timeboard.calendars.US as US
>>> clnd = US.Weekly8x5()
>>> clnd('04 Sep 2017').rollback().to_timestamp().date()
datetime.date(2017, 9, 1)
在英国,2017年9月4日是正常工作日,因此最近的工作日本身就是。
>>> import timeboard.calendars.UK as UK
>>> clnd = UK.Weekly8x5()
>>> clnd('04 Sep 2017').rollback().to_timestamp().date()
datetime.date(2017, 9, 4)
免责声明:我是时间表的作者。
答案 5 :(得分:3)
如果您想跳过美国假期以及周末,这对我很有用(使用熊猫0.23.3):
import pandas as pd
from pandas.tseries.holiday import USFederalHolidayCalendar
from pandas.tseries.offsets import CustomBusinessDay
US_BUSINESS_DAY = CustomBusinessDay(calendar=USFederalHolidayCalendar())
july_5 = pd.datetime(2018, 7, 5)
result = july_5 - 2 * US_BUSINESS_DAY # 2018-7-2
要转换为python日期对象,我这样做:
result.to_pydatetime().date()
答案 6 :(得分:2)
这将给出一个工作日的生成器,当然没有假期,stop是datetime.datetime对象。如果您需要假期,只需在假期列表中添加其他参数,并查看“IFology”; - )
def workingdays(stop, start=datetime.date.today()):
while start != stop:
if start.weekday() < 5:
yield start
start += datetime.timedelta(1)
稍后您可以将它们视为
workdays = workingdays(datetime.datetime(2015, 8, 8))
len(list(workdays))
答案 7 :(得分:2)
如果有人正在寻找有关假期的解决方案(没有像熊猫这样的大型图书馆),请尝试使用其功能:
import holidays
import datetime
def previous_working_day(check_day_, holidays=holidays.US()):
offset = max(1, (check_day_.weekday() + 6) % 7 - 3)
most_recent = check_day_ - datetime.timedelta(offset)
if most_recent not in holidays:
return most_recent
else:
return previous_working_day(most_recent, holidays)
check_day = datetime.date(2020, 12, 28)
previous_working_day(check_day)
产生:
datetime.date(2020, 12, 24)
答案 8 :(得分:0)
你为什么不尝试这样的事情:
lastBusDay = datetime.datetime.today()
if datetime.date.weekday(lastBusDay) not in range(0,5):
lastBusDay = 5
答案 9 :(得分:0)
def getNthBusinessDay(startDate, businessDaysInBetween):
currentDate = startDate
daysToAdd = businessDaysInBetween
while daysToAdd > 0:
currentDate += relativedelta(days=1)
day = currentDate.weekday()
if day < 5:
daysToAdd -= 1
return currentDate
答案 10 :(得分:0)
另一个简化版本
lastBusDay = datetime.datetime.today()
wk_day = datetime.date.weekday(lastBusDay)
if wk_day > 4: #if it's Saturday or Sunday
lastBusDay = lastBusDay - datetime.timedelta(days = wk_day-4) #then make it Friday
答案 11 :(得分:0)
解决方案,无论不同的司法管辖区有不同的假期:
如果您需要在表格中找到正确的ID,则可以使用此代码段。 Table模型是sqlalchemy模型,要搜索的日期在字段日期。
def last_relevant_date(db: Session, given_date: date) -> int:
available_days = (db.query(Table.id, Table.day)
.order_by(desc(Table.day))
.limit(100).all())
close_dates = pd.DataFrame(available_days)
close_dates['delta'] = close_dates['day'] - given_date
past_dates = (close_dates
.loc[close_dates['delta'] < pd.Timedelta(0, unit='d')])
table_id = int(past_dates.loc[past_dates['delta'].idxmax()]['id'])
return table_id
当您必须批量转换时,这不是我建议的解决方案。由于您不使用联接,因此它相当通用且昂贵。此外,它假设您有一个相关的天,它是模型表中最近100天中的某一天。因此,它可以处理日期可能不同的数据输入。