最近的Python工作日

时间:2010-02-08 20:47:33

标签: python datetime

我需要从当前日期减去营业日

我目前有一些代码需要始终在最近的工作日运行。所以今天可能是今天,如果我们是星期一到星期五,但如果是星期六或星期日,那么我需要把它设置回周末前的星期五。我目前有一些漂亮的笨重的代码来执行此操作:

 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在工作日而不是日历日工作吗?

12 个答案:

答案 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允许您自定义假期列表等,以定义您的工作时间(以及延长工作日)。

http://pypi.python.org/pypi/BusinessHours/

答案 2 :(得分:9)

DISCLAMER:我是作者......

我写了一个包,它完成了这个,业务日期计算。您可以使用自定义周规格和假期。

我在使用财务数据时遇到了这个问题,并且没有找到任何可用的解决方案特别容易,所以我写了一个。

希望这对其他人有用。

https://pypi.python.org/pypi/business_calendar/

答案 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天中的某一天。因此,它可以处理日期可能不同的数据输入。