Printing working dates between two dates but excluding every weekends - python

I am trying to print the working days between two dates, but excluding the latter one and the weekends, holding in there. I've tried the following code:
from datetime import timedelta, date, datetime
def print_working_dates(date1, date2):
excluded = (6,7)
for n in range(int((date2 - date1).days)+1):
if date1.isoweekday == excluded:
continue
else:
yield date1 + timedelta(n)
start_dt = datetime.now()
end_dt = datetime(2022, 4, 28)
for dt in print_working_dates(start_dt, end_dt):
print(dt.strftime("%Y-%m-%d"))
which prints every day before the last one, but it holds all weekends. Could anyone please anyone could give a piece of advice to define better this function? To my mind, the excluded object should be better detailed, but I cannot know how.

Firstly, you can check if a value is in an iterable (such as a tuple or list) using the in keyword. isoweekday is a function, so you need to call it with isoweekday(). Finally, you need to work out the new date, then check it's weekday, otherwise it just checks if the start date is a weekend for every date.
def print_working_dates(date1, date2):
excluded = (6,7)
for n in range(int((date2 - date1).days)+1):
new = date1 + timedelta(n)
if new.isoweekday() not in excluded:
yield new
I've negated the if statement with not to make it a bit more compact.

First off, you are not checking the correct time to be a weekday or not you have to check if (date1 + timedelta(n)) is a weekday, not date1
And secondly you have to you have to check if isoweekday's return value is in the excluded
Here's my solution to your code:
from datetime import timedelta, datetime
def print_working_dates(date1, date2):
excluded = (6,7)
for n in range(int((date2 - date1).days)+1):
if (date1 + timedelta(n)).isoweekday() in excluded:
continue
else:
yield date1 + timedelta(n)
start_dt = datetime.now()
end_dt = datetime(2022, 4, 28)
for dt in print_working_dates(start_dt, end_dt):
print(dt.strftime("%Y-%m-%d"))

Related

Python: iterate per year between two dates

I'm not a Python developer but have to fix an existing code.
In this code, a method (extract) is called providing an interval of dates:
extract(start_date, end_date)
The parameters can have for exemple the values:
start_date : 2020-10-01
end_date : 2022-01-03
The problem
The issue with this call is that the extract method only support a 1 year max interval of dates. If greater, the interval must be split, for exemple as follow:
extract('2020-10-01', '2020-12-31')
extract('2021-01-01', '2021-12-31')
extract('2022-01-01', '2022-01-03')
So I'm trying to create loop where the start_date and end_date are computed dynamically. But being new to Python, I have no ideas for now how this can be done. Any help would be greatly appreciated.
EDIT
Answer to some comments here
Tried so far finding a solution starting from code like this so far:
from datetime import datetime
from dateutil import relativedelta
from datetime import datetime
from_date = datetime.strptime('2020-10-01', "%Y-%m-%d")
end_date = datetime.strptime('2022-01-03', "%Y-%m-%d")
# Get the interval between the two dates
diff = relativedelta.relativedelta(end_date, from_date)
Then I thought iterating accross the years using diff.years and adding some logic to build the start_date and end_date from there, but I thought there might be a much simplier approach.
Also saw others possibilities like here but still no final simple result found at the moment.
from_str = '2020-10-01'
end_str = '2022-01-03'
from_year = int(from_str[:4])
end_year = int(end_str[:4])
if from_year != end_year:
# from_date to end of first year
extract(from_str, f"{from_year}-12-31")
# full years
for y in range(from_year + 1, end_year):
extract(f"{y}-01-01", f"{y}-12-31")
# rest
extract(f"{end_year}-01-01", end_str)
else:
extract(from_str, end_str)
As mentioned in the comments, you can either use the datetime library or you can also use pandas if you want. The pandas version is the following (admittively not the most pretty, but it does the job):
import pandas as pd
import datetime
start = datetime.datetime(2020,10,1)
end = datetime.datetime(2022,1,3)
def extract(from_dt, to_dt):
print(f'Extracting from {from_dt} to {to_dt}')
prev_end = pd.to_datetime(start)
for next_end in pd.date_range(datetime.datetime(start.year, 12, 31), end, freq='y'):
if next_end < end:
extract(prev_end.strftime('%Y-%m-%d'), next_end.strftime('%Y-%m-%d'))
else:
extract(prev_end.strftime('%Y-%m-%d'), end.strftime('%Y-%m-%d'))
prev_end = next_end + datetime.timedelta(days=1)
if prev_end < end:
extract(prev_end.strftime('%Y-%m-%d'), end.strftime('%Y-%m-%d'))
If you need to parse the original dates from strings, check out datetime.strptime
This kind of problems are nice ones to resolve by recursion:
from datetime import datetime
start_date = '2020-10-01'
end_date = '2022-01-03'
def intervalcalc(datestart,dateend):
newdate=dateend[:4] + '-01-01'
startd = datetime.strptime(datestart, "%Y-%m-%d")
endd = datetime.strptime(newdate, "%Y-%m-%d")
if endd < startd:
print(datestart, dateend)
return True
else:
print(newdate, dateend)
previousyear=str(int(newdate[:4])-1) + '-12-31'
intervalcalc(datestart,previousyear)
intervalcalc(start_date, end_date)
output:
2022-01-01 2022-01-03
2021-01-01 2021-12-31
2020-10-01 2020-12-31
You just need to change the prints by calls to extract function.
As mentioned by #Wups the conversion to date is not really necessary, it could be an string compare as they are YYYYMMDD dates.
Also, this can be done the other way around and calculate from the start date year + '-12-31' and then compare dateend>end_date to determine the anchor for the recursion.

Check if given date is between two days

For a private project I want to check in Python if one day is in a range of two dates. The tricky part is that I have to check it without the year.
The project is meant to calculate what star sign a specific person has and the year is not needed.
Example:
Aquarius 01-21 - 02-19 (21.01. - 19.02.)
All the tutorials I've seen are with the specific year but it seems too complicated for me to calculate that too.
I don't need the whole code, but a hint would be very much appreciated.
I would add a reference year to the dates, just for sake of comparing it. The only tricky part would then be the range December - January. In those cases you would have to change the year to the next year.
start_date = datetime.datetime(2000, 1, 21)
end_date = datetime.datetime(2000, 2, 19)
check_date = datetime.datetime(2000, 2, 1)
if start_date < check_date and check_date < end_date:
print('success!')
Use the datetime module of Python, it will handle the year part as well. Refer to the example code below. If anyone finds any mistake or has a better approach, please comment also.
import datetime
def datetime_format(date):
date_list = date.split('-')
date_list = list(map(int, date_list))
date = datetime.date(date_list[0], date_list[1], date_list[2])
return date
def compare_dates(first, last, date_):
first = datetime_format(first)
last = datetime_format(last)
date_ = datetime_format(date_)
if date_ <= last and date_ >= first:
return("Within range")
return("Out of range")
first = '2020-01-01'
last = '2022-12-31'
date_ = '2021-05-05'
print(compare_dates(first, last, date_))

create a list of dates with a while loop python

I want tot create a list of dates starting from 10/09/2020 with increments of 182 days until reaching 05/03/2020.
my code is this :
start_date="10/09/2020"
last_date="05/03/2020"
start_date=datetimedatetime.strptime(date,"%d/%m/%Y").date()
last_date=datetimedatetime.strptime(date,"%d/%m/%Y").date()
dates=[]
while dates[-1] != last_date:
i=star_date+timedelta(days=182)
dates.append(i)
dates[i]=i+timedelta(days=pago_cupon)
I don't know what's your problem.
You can try this code
from datetime import date, timedelta
start_day = date(year=2020, month=9, day=10)
end_day = date(year=2021, month=3, day=5)
one_data_delta = timedelta(days=1)
res = []
while end_day != start_day:
start_day += one_data_delta
res.append(start_day)
print(res)
A few problems:
You had a spelling mistake in your for loop star_date instead of start_date.
Also, you may want to change the comparison from != to less than equals or more than equals.
I am checking against (last_date - timedelta(days=182)) so that we won't exceed the last_date.
Your original start date is after your original end date.
As an example, I have adjusted the end day to be a couple years in the future.
I'm appending the dates as text.
from datetime import datetime, timedelta
start="10/09/2020"
last="05/03/2022"
start_date=datetime.strptime(start,"%d/%m/%Y")
last_date=datetime.strptime(last,"%d/%m/%Y")
dates=[]
while start_date <= (last_date - timedelta(days=182)):
start_date += timedelta(days=182)
dates.append(start_date.strftime("%d/%m/%Y"))
# not quite sure what you are trying to do here:
#dates[i]=i+timedelta(days=pago_cupon)
print(dates)
Output:
['11/03/2021', '09/09/2021']

Comparing datetime to a time range

I have a datetime object representing when a user logged, from this object I want to check whether the datetime object expresses a date in the range today -7, so if today is 2018-06-21 I would like to return ever date between today and 2018-06-14. I attach an example of my code (terribly wrong).
def joined_today(self, query):
filtered = []
today = datetime.today().date()
for x in query:
if x[1].date() = today -7:
filtered.append(x)
return filtered
A couple of things here. Firstly, you can do date calculations using datetime.timedelta. And secondly, you don't want to check that the date is equal to "today - 7", you want to check it is greater than that and less than or equal to today. So:
seven_days_ago = today - timedelta(days=7)
for x in query:
if seven_days_ago < x[1].date() <= today:
...

date_range not accepting the variable I want to use?

When I input a value like '2015-08', my date_range works as intended. If I use the startdate variable, then it no longer works? I cannot figure out why this would be.
The error I get is "Cannot convert input to Timestamp"
Not for points. I'm a bit confused, isn't what you're doing just basically the following?
Code:
from datetime import datetime, timedelta
now = datetime.now()
print now.strftime("%Y-%m")
month_ago = now.replace(day=1) - timedelta(days = 1)
print month_ago.strftime("%Y-%m")
months_ago = month_ago.replace(day=1) - timedelta(days = 1)
print months_ago.strftime("%Y-%m")
Output:
2015-11
2015-10
2015-09
The above might not be the perfect answer, but you can substitute any datetime for now and it will give you basically the current and last two months. Adjust as needed, of course.
EDIT:
You can even take it a step further and just create a function that allows you to specify the numbers of months back or use a custom date.
from datetime import datetime, timedelta
def last_n_months(num_of_months, start_date=datetime.now(), include_curr=True):
f = "%Y-%m"
curr = start_date
if include_curr:
yield curr.strftime(f)
for num in range(num_of_months):
curr = curr.replace(day=1) - timedelta(days=1)
yield curr.strftime(f)
# This month and last 12 months.
print [m for m in last_n_months(12)]
# ['2015-11', '2015-10', '2015-09', '2015-08', '2015-07', '2015-06', '2015-05', '2015-04', '2015-03', '2015-02', '2015-01', '2014-12', '2014-11']
# Last 12 months only.
print [m for m in last_n_months(12, include_curr=False)]
# ['2015-10', '2015-09', '2015-08', '2015-07', '2015-06', '2015-05', '2015-04', '2015-03', '2015-02', '2015-01', '2014-12', '2014-11']
# Last 12 months from custom date, exclude custom date.
d = datetime(2012, 6, 1)
print [m for m in last_n_months(12, d, False)]
# ['2012-05', '2012-04', '2012-03', '2012-02', '2012-01', '2011-12', '2011-11', '2011-10', '2011-09', '2011-08', '2011-07', '2011-06']

Categories

Resources