【问题标题】:Datetime Python - Next Business Day日期时间 Python - 下一个工作日
【发布时间】:2012-02-08 02:52:40
【问题描述】:

两个相关问题:(1) 我使用的所有数据都附有工作日日期。在不同的时候,我需要知道下一个工作日是什么。我已经编写了类似下面的代码来做出这个决定,但我确信有更好的方法。任何人? (2) 理想情况下,我不仅需要知道下一个工作日,还需要知道下一个美国工作日——即下一个不是美国市场假期的工作日。对此的任何帮助也会很棒。

import datetime as dt

day = dt.datetime.strptime('2012-02-03','%Y-%m-%d').date()
print day#day=2012-03-02 (Friday)

if day.weekday()==4:
    day = day+dt.timedelta(days=3)
else:
    day = day+dt.timedelta(days=1)

print day#day=2012-02-06 (Monday)
day = day+dt.timedelta(days=1)
print day#day=2012-02-07 (Tuesday)

【问题讨论】:

标签: python datetime


【解决方案1】:

我会使用dateutil.rrule:

import datetime
from dateutil import rrule


holidays = [
    datetime.date(2012, 5, 1,),
    datetime.date(2012, 6, 1,),
    # ...
]

# Create a rule to recur every weekday starting today
r = rrule.rrule(rrule.DAILY,
                byweekday=[rrule.MO, rrule.TU, rrule.WE, rrule.TH, rrule.FR],
                dtstart=datetime.date.today())

# Create a rruleset
rs = rrule.rruleset()

# Attach our rrule to it
rs.rrule(r)

# Add holidays as exclusion days
for exdate in holidays:
    rs.exdate(exdate)


print rs[0]

【讨论】:

    【解决方案2】:

    我使用了holidays 包。

    $ pip install holidays
    

    这是我用来确定今天之后的下一个工作日的函数。

    import datetime
    import holidays
    
    ONE_DAY = datetime.timedelta(days=1)
    HOLIDAYS_US = holidays.US()
    
    def next_business_day():
        next_day = datetime.date.today() + ONE_DAY
        while next_day.weekday() in holidays.WEEKEND or next_day in HOLIDAYS_US:
            next_day += ONE_DAY
        return next_day
    

    如果明天不是周末也不是假期,它将返回明天的日期。否则它会发现下一个* 天不是这些东西中的任何一个。 2017 年 3 月 15 日星期三运行的示例:

    >>> next_business_day()
    datetime.date(2017, 3, 16)
    

    * 注意,如果President Camacho 宣布每天为假期,这可能会无限循环。

    【讨论】:

      【解决方案3】:

      这个问题很常见,有不同层次的解决方案:

      最简单:使用类似于查看工作日的方法。一种常见的惯用语类似于

      d = datetime.date(2012,2,7)
      next = d + datetime.timedelta(days= 7-d.weekday() if d.weekday()>3 else 1)
      

      一旦你想要假期,你可以滚动你自己的日期时间“TradingDateChecker”,它必须扫描“可预测的”假期,如 1 月 1 日、7 月 4 日、12 月 25 日的周五之前或之后的周一,如果他们是周末, 5 月的最后一个星期一、9 月的第一个星期一等。

      我什至不会费心在此处发布该代码,因为对于交易假期,它仍然是不够的。

      • 耶稣受难日纽约证券交易所休市,期货和债券市场开市
      • 哥伦布日和退伍军人节,银行关门,股市开市。

      股票和期货市场有不同的假期。如果您想要 NYSE 假期(常见请求),请参见下文。由于截止日期通常只在未来几年内公布,因此您无法真正保留自己的日历。

      # For a longer list of NYSE closed dates see: http://www.chronos-st.org/NYSE_Observed_Holidays-1885-Present.html
      holidays = [datetime.date(2000, 1, 17),
       datetime.date(2000, 2, 21),
       datetime.date(2000, 4, 21),
       datetime.date(2000, 5, 29),
       datetime.date(2000, 7, 4),
       datetime.date(2000, 9, 4),
       datetime.date(2000, 11, 23),
       datetime.date(2000, 12, 25),
       datetime.date(2001, 1, 1),
       datetime.date(2001, 1, 15),
       datetime.date(2001, 2, 19),
       datetime.date(2001, 5, 28),
       datetime.date(2001, 7, 4),
       datetime.date(2001, 9, 3),
       datetime.date(2001, 9, 11),
       datetime.date(2001, 9, 12),
       datetime.date(2001, 9, 13),
       datetime.date(2001, 9, 14),
       datetime.date(2001, 11, 22),
       datetime.date(2001, 12, 25),
       datetime.date(2002, 1, 1),
       datetime.date(2002, 1, 21),
       datetime.date(2002, 2, 18),
       datetime.date(2002, 3, 29),
       datetime.date(2002, 5, 27),
       datetime.date(2002, 7, 4),
       datetime.date(2002, 9, 2),
       datetime.date(2002, 11, 28),
       datetime.date(2002, 12, 25),
       datetime.date(2003, 1, 1),
       datetime.date(2003, 1, 20),
       datetime.date(2003, 2, 17),
       datetime.date(2003, 4, 18),
       datetime.date(2003, 5, 26),
       datetime.date(2003, 7, 4),
       datetime.date(2003, 9, 1),
       datetime.date(2003, 11, 27),
       datetime.date(2003, 12, 25),
       datetime.date(2004, 1, 1),
       datetime.date(2004, 1, 19),
       datetime.date(2004, 2, 16),
       datetime.date(2004, 4, 9),
       datetime.date(2004, 5, 31),
       datetime.date(2004, 6, 11),
       datetime.date(2004, 7, 5),
       datetime.date(2004, 9, 6),
       datetime.date(2004, 11, 25),
       datetime.date(2004, 12, 24),
       datetime.date(2005, 1, 17),
       datetime.date(2005, 2, 21),
       datetime.date(2005, 3, 25),
       datetime.date(2005, 5, 30),
       datetime.date(2005, 7, 4),
       datetime.date(2005, 9, 5),
       datetime.date(2005, 11, 24),
       datetime.date(2005, 12, 26),
       datetime.date(2006, 1, 2),
       datetime.date(2006, 1, 16),
       datetime.date(2006, 2, 20),
       datetime.date(2006, 4, 14),
       datetime.date(2006, 5, 29),
       datetime.date(2006, 7, 4),
       datetime.date(2006, 9, 4),
       datetime.date(2006, 11, 23),
       datetime.date(2006, 12, 25),
       datetime.date(2007, 1, 1),
       datetime.date(2007, 1, 2),
       datetime.date(2007, 1, 15),
       datetime.date(2007, 2, 19),
       datetime.date(2007, 4, 6),
       datetime.date(2007, 5, 28),
       datetime.date(2007, 7, 4),
       datetime.date(2007, 9, 3),
       datetime.date(2007, 11, 22),
       datetime.date(2007, 12, 25),
       datetime.date(2008, 1, 1),
       datetime.date(2008, 1, 21),
       datetime.date(2008, 2, 18),
       datetime.date(2008, 3, 21),
       datetime.date(2008, 5, 26),
       datetime.date(2008, 7, 4),
       datetime.date(2008, 9, 1),
       datetime.date(2008, 11, 27),
       datetime.date(2008, 12, 25),
       datetime.date(2009, 1, 1),
       datetime.date(2009, 1, 19),
       datetime.date(2009, 2, 16),
       datetime.date(2009, 4, 10),
       datetime.date(2009, 5, 25),
       datetime.date(2009, 7, 3),
       datetime.date(2009, 9, 7),
       datetime.date(2009, 11, 26),
       datetime.date(2009, 12, 25),
       datetime.date(2010, 1, 1),
       datetime.date(2010, 1, 18),
       datetime.date(2010, 2, 15),
       datetime.date(2010, 4, 2),
       datetime.date(2010, 5, 31),
       datetime.date(2010, 7, 5),
       datetime.date(2010, 9, 6),
       datetime.date(2010, 11, 25),
       datetime.date(2010, 12, 24),
       datetime.date(2011, 1, 17),
       datetime.date(2011, 2, 21),
       datetime.date(2011, 4, 22),
       datetime.date(2011, 5, 30),
       datetime.date(2011, 7, 4),
       datetime.date(2011, 9, 5),
       datetime.date(2011, 11, 24),
       datetime.date(2011, 12, 26),
       datetime.date(2012, 1, 2),
       datetime.date(2012, 1, 16),
       datetime.date(2012, 2, 20),
       datetime.date(2012, 4, 6),
       datetime.date(2012, 5, 28),
       datetime.date(2012, 7, 4),
       datetime.date(2012, 9, 3),
       datetime.date(2012, 11, 22),
       datetime.date(2012, 12, 25),
       datetime.date(2013, 1, 1),
       datetime.date(2013, 1, 21),
       datetime.date(2013, 2, 18),
       datetime.date(2013, 3, 29),
       datetime.date(2013, 5, 27),
       datetime.date(2013, 7, 4),
       datetime.date(2013, 9, 2),
       datetime.date(2013, 11, 28),
       datetime.date(2013, 12, 25)]
      

      【讨论】:

        【解决方案4】:

        超过一个工作日

        def next_business_day(start_day, business_days, HOLIDAYS):
            ONE_DAY = datetime.timedelta(days=1)
            temp_day = start_day
            for i in range(0, business_days):
                next_day = temp_day + ONE_DAY
                while next_day.weekday() in [5,6] or next_day in HOLIDAYS:
                    next_day += ONE_DAY
                temp_day = next_day
            return temp_day
        

        【讨论】:

          【解决方案5】:

          另一种没有 if 的方法是:

          def next_wk_day():
              date_today = datetime.datetime.today()
              shift = 1 + ((date_today.weekday()//4)*(6-date_today.weekday()))
              return(date_today+shift)
          

          如果您在星期六或星期日这样做,这也可以。

          【讨论】:

          • 或更简单:return date_today + [1, 1, 1, 1, 3, 2, 1][date_today.weekday()] 虽然这些公式忽略了假期。
          猜你喜欢
          • 1970-01-01
          • 2023-03-09
          • 2022-01-12
          • 2014-03-07
          • 1970-01-01
          • 1970-01-01
          • 2011-07-28
          • 1970-01-01
          相关资源
          最近更新 更多