0

I want to print all Thursdays between these date ranges

from datetime import date, timedelta
sdate = date(2015, 1, 7)   # start date
edate = date(2015, 12, 31)   # end date

What is the best pythonic way to do that?

sam
  • 18,509
  • 24
  • 83
  • 116
  • This is a duplicated question. It's answered here. https://stackoverflow.com/questions/42949449/using-pandas-date-range-to-generate-multiple-datetimes-two-dates-per-week – ERIC Aug 11 '21 at 11:45

6 Answers6

2

using your sdate.weekday() # returns int between 0 (mon) and 6 (sun):

sdate = ...
while sdate < edate:
    if sdate.weekday() != 3:  # not thursday
        sdate += timedelta(days=1)
        continue
    # It is thursday
    print(sdate)
    sdate += timedelta(days=7)  #  next week
2

Compute the number of days till thursday from the start date :

days_to_thursday = (3 - sdate.weekday()) % 7

Compute the number of thursdays inbetween both dates:

week_diff = ((edate - sdate).days - days_to_thursday ) // 7

Get all thursdays in the date range:

thursdays = [sdate + timedelta(days=days_to_thursday + 7 * more_weeks) \
    for more_weeks in range(week_diff + 1) ]

Print them if you need:

for t in thursdays:
    print(t)
Whole Brain
  • 2,097
  • 2
  • 8
  • 18
  • 1
    Thank you for pointing out the trick of the remainder of dividing a negative number by a positive number. I didn't know it before, very useful property. – Алексей Р Jun 08 '21 at 09:50
1
import datetime
import calendar

def weekday_count(start, end, day):
    start_date  = datetime.datetime.strptime(start, '%d/%m/%Y')
    end_date    = datetime.datetime.strptime(end, '%d/%m/%Y')
    day_count = []
    
    for i in range((end_date - start_date).days):
        if calendar.day_name[(start_date + datetime.timedelta(days=i+1)).weekday()] == day:
            print(str(start_date + datetime.timedelta(days=i+1)).split()[0])

weekday_count("01/01/2017", "31/01/2017", "Thursday")

# prints result
# 2017-01-05
# 2017-01-12
# 2017-01-19
# 2017-01-26

1

Simple solution:

from datetime import date, timedelta

sdate = date(2015, 1, 7)   # start date
edate = date(2015, 12, 31)   # end date

delta = edate - sdate

for day in range(delta.days + 1):
    day_obj = sdate + timedelta(days=day)
    if day_obj.weekday() == 3:  # Thursday
        print(day_obj)

# 2015-01-08
# 2015-01-15
# ...
# 2015-12-24
# 2015-12-31

The most efficient solution:

from datetime import date, timedelta

sdate = date(2015, 1, 7)   # start date
edate = date(2015, 12, 31)   # end date

day_index = 3  # Thursday
delta = (day_index - sdate.weekday()) % 7
match = sdate + timedelta(days=delta)

while match <= edate:  # Change this to `<` to ignore the last one
    print(match) # Can be easily converted to a generator with `yield`
    match += timedelta(days=7)

# 2015-01-08
# 2015-01-15
# ...
# 2015-12-24
# 2015-12-31

Docs:

sobolevn
  • 16,714
  • 6
  • 62
  • 60
  • 1
    The `abs` function makes this solution incorrect **for any sdate with a weekday greater than 3**. It gives a delta of `1, 2 or 3` instead of `6, 5 or 4` respectively. – Whole Brain Jun 08 '21 at 09:14
  • It doesn't print proper Thursdays for 2016 – sam Jun 08 '21 at 17:09
  • @sam looks like it does print all Thursdays for 2016: https://replit.com/@sobolevn/CarefulConcreteListener#main.py – sobolevn Jun 08 '21 at 20:40
1

You could try a list comprehension to get the Thursdays between the 2 dates.

This code actually outputs the dates as formatted strings but you can get actual dates by dropping the strftime.

from datetime import date, timedelta
sdate = date(2015, 1, 7)   # start date
edate = date(2015, 12, 31)   # end date

thursdays = [(sdate+timedelta(days=d)).strftime('%A %Y-%m-%d') for d in range(0, (edate-sdate).days+1) 
             if (sdate+timedelta(days=d)).weekday() ==3]

print('\n'.join(thursdays))

""" Example output
Thursday 2015-01-08
Thursday 2015-01-15
Thursday 2015-01-22
Thursday 2015-01-29
Thursday 2015-02-05
Thursday 2015-02-12
""""
norie
  • 9,609
  • 2
  • 11
  • 18
1

Most people are iterating through every day which is a waste. Also might be helpful to delay calculating the thursdays until you actually need them. For this you could use a generator.

def get_days(start, day_index, end=None):
    # set the start as the next valid day
    start += timedelta(days=(day_index - start.weekday()) % 7)
    week = timedelta(days=7)
    while end and start < end or not end:
        yield start
        start += week

This delays getting the next day until you need it, and allows infinite days if you don't specify and end date.

thursday_generator = get_days(date(2015, 1, 7), 3, date(2015, 12, 31))
print(list(thursday_generator))

"""
[datetime.date(2015, 1, 8), datetime.date(2015, 1, 15), datetime.date(2015, 1, 22), ...]
"""

You can easily dump as strings:

print("\n".join(map(str, thursday_generator)))

"""
2015-01-08
2015-01-15
2015-01-22
...
"""

You can also use f-strings for custom string formatting:

print("\n".join(f"{day:%A %x}" for day in thursday_generator))

"""
Thursday 01/08/15
Thursday 01/15/15
Thursday 01/22/15
...
"""

If you don't specify an end date, it goes on forever.

In [28]: thursday_generator = get_days(date(2015, 1, 7), 3)
    ...: print(len(list(thursday_generator)))
---------------------------------------------------------------------------
OverflowError                             Traceback (most recent call last)
<ipython-input-28-b161cdcccc75> in <module>
      1 thursday_generator = get_days(date(2015, 1, 7), 3)
----> 2 print(len(list(thursday_generator)))

<ipython-input-16-0691db329606> in get_days(start, day_index, end)
      5     while end and start < end or not end:
      6         yield start
----> 7         start += week
      8

OverflowError: date value out of range
blueteeth
  • 3,330
  • 1
  • 13
  • 23