查找给定日期后的第一个星期一的日期

给定一个特定的日期,比如2011-07-02,我怎样才能找到该日期之后的下一个星期一(或任何一个工作日)的日期?

91055 次浏览
import datetime
def next_weekday(d, weekday):
days_ahead = weekday - d.weekday()
if days_ahead <= 0: # Target day already happened this week
days_ahead += 7
return d + datetime.timedelta(days_ahead)


d = datetime.date(2011, 7, 2)
next_monday = next_weekday(d, 0) # 0 = Monday, 1=Tuesday, 2=Wednesday...
print(next_monday)

Try

>>> dt = datetime(2011, 7, 2)
>>> dt + timedelta(days=(7 - dt.weekday()))
datetime.datetime(2011, 7, 4, 0, 0)

using, that the next monday is 7 days after the a monday, 6 days after a tuesday, and so on, and also using, that Python's datetime type reports monday as 0, ..., sunday as 6.

You can start adding one day to date object and stop when it's monday.

>>> d = datetime.date(2011, 7, 2)
>>> while d.weekday() != 0: #0 for monday
...     d += datetime.timedelta(days=1)
...
>>> d
datetime.date(2011, 7, 4)

This will give the first next Monday after given date:

import datetime


def get_next_monday(year, month, day):
date0 = datetime.date(year, month, day)
next_monday = date0 + datetime.timedelta(7 - date0.weekday() or 7)
return next_monday


print get_next_monday(2011, 7, 2)
print get_next_monday(2015, 8, 31)
print get_next_monday(2015, 9, 1)

2011-07-04
2015-09-07
2015-09-07

via list comprehension?

from datetime import *
[datetime.today()+timedelta(days=x) for x in range(0,7) if (datetime.today()+timedelta(days=x)).weekday() % 7 == 0]


(0 at the end is for next monday, returns current date when run on monday)
weekday = 0 ## Monday
dt = datetime.datetime.now().replace(hour=0, minute=0, second=0) ## or any specific date
days_remaining = (weekday - dt.weekday() - 1) % 7 + 1
next_dt = dt + datetime.timedelta(days_remaining)

Here's a succinct and generic alternative to the slightly weighty answers above.

def onDay(date, day):
"""
Returns the date of the next given weekday after
the given date. For example, the date of next Monday.


NB: if it IS the day we're looking for, this returns 0.
consider then doing onDay(foo, day + 1).
"""
days = (day - date.weekday() + 7) % 7
return date + datetime.timedelta(days=days)

Another simple elegant solution is to use pandas offsets.

I find it very helpful and robust when playing with dates.

  • If you want the first Sunday just modify the frequency to freq='W-SUN'.
  • If you want a couple of next Sundays, change the offsets.Day(days).
  • Using pandas offsets allow you to ignore holidays, work only with Business Days and more.

You can also apply this method easily on a whole DataFrame using the apply method.

import pandas as pd
import datetime


# 1. Getting the closest monday from a given date
date = datetime.date(2011, 7, 2)
closest_monday = pd.date_range(start=date, end=date + pd.offsets.Day(6), freq="W-MON")[
0
]


# 2. Adding a 'ClosestMonday' column with the closest monday for each row in
# a pandas df using apply. Requires you to have a 'Date' column in your df
def get_closest_monday(row):
return pd.date_range(
start=row.Date, end=row.Date + pd.offsets.Day(6), freq="W-MON"
)[0]




df = pd.DataFrame([datetime.date(2011, 7, 2)], columns=["Date"])
df["ClosestMonday"] = df.apply(lambda row: get_closest_monday(row), axis=1)
print(df)
import datetime


d = datetime.date(2011, 7, 2)
while d.weekday() != 0:
d += datetime.timedelta(1)

This is example of calculations within ring mod 7.

import datetime




def next_day(given_date, weekday):
day_shift = (weekday - given_date.weekday()) % 7
return given_date + datetime.timedelta(days=day_shift)


now = datetime.date(2018, 4, 15) # sunday
names = ['monday', 'tuesday', 'wednesday', 'thursday', 'friday',
'saturday', 'sunday']
for weekday in range(7):
print(names[weekday], next_day(now, weekday))

will print:

monday 2018-04-16
tuesday 2018-04-17
wednesday 2018-04-18
thursday 2018-04-19
friday 2018-04-20
saturday 2018-04-21
sunday 2018-04-15

As you see it's correctly give you next monday, tuesday, wednesday, thursday friday and saturday. And it also understood that 2018-04-15 is a sunday and returned current sunday instead of next one.

I'm sure you'll find this answer extremely helpful after 7 years ;-)

Another alternative uses rrule

from dateutil.rrule import rrule, WEEKLY, MO
from datetime import date


next_monday = rrule(freq=WEEKLY, dtstart=date.today(), byweekday=MO, count=1)[0]

rrule docs: https://dateutil.readthedocs.io/en/stable/rrule.html

Generally to find any date from day of week from today:


def getDateFromDayOfWeek(dayOfWeek):
week_days = ["monday", "tuesday", "wednesday",
"thursday", "friday", "saturday", "sunday"]
today = datetime.datetime.today().weekday()
requiredDay = week_days.index(dayOfWeek)
if today>requiredDay:
noOfDays=7-(today-requiredDay)
print("noDays",noOfDays)
else:
noOfDays = requiredDay-today
print("noDays",noOfDays)
requiredDate = datetime.datetime.today()+datetime.timedelta(days=noOfDays)
return requiredDate


print(getDateFromDayOfWeek('sunday').strftime("%d/%m/%y"))

Gives output in format of Day/Month/Year

dateutil has a special feature for this kind of operation and it's the most elegant way I have ever seen yet.

from datetime import datetime
from dateutil.relativedelta import relativedelta, MO


first_monday_date = (datetime(2011,7,2) + relativedelta(weekday=MO(0))).date()

if you want datetime just

first_monday_date = datetime(2011,7,2) + relativedelta(weekday=MO(0))