I have a method which returns the number of days within a specified range and excluding some specific days like Friday. here is an example if you take out friday and thursday, from 2016-8-6 to 2016-9-6 the result will be 8 days holiday and 24 working day. in case i want to do the reverse operation how do i find the end date (2016-9-6) if i have only working days and start date.
from datetime import datetime, timedelta
def measure_workingdays(start_date, end_date, off_days):
format = "%Y-%m-%d"
if not isinstance(start_date, datetime):
start_date = datetime.strptime(start_date, format)
if not isinstance(end_date, datetime):
end_date = datetime.strptime(end_date, format)
total_days = (end_date - start_date).days + 1 # + 1 Because it count one day less
holiday = 0
start = start_date
for rec in range(total_days):
day = start.strftime("%a")
if day in off_days:
holiday += 1
start += timedelta(days=1)
print(holiday) # 8
working_days = total_days - holiday
print(working_days) # 24
start_date = "2016-8-6"
start_date = datetime.strptime(start_date, "%Y-%m-%d")
end_date = "2016-9-6"
end_date = datetime.strptime(end_date, "%Y-%m-%d")
off_day = ['Fri','Thu']
working_days = measure_weekdays(start_date, end_date, off_day)
Example of Reverse operation
def measure_weekdays_reverse(start_date, paid, off_days):
format = "%Y-%m-%d"
if not isinstance(start_date, datetime):
start_date = datetime.strptime(start_date, format)
holiday = 0
start = start_date
for rec in range(paid):
day = start.strftime("%a")
if day in off_days:
holiday += 1
start += timedelta(days=1)
print(holiday) # Output 6 instead of 8
last_paid_date = start + timedelta(days=holiday)
print(last_paid_date) # output 2016-09-05 insteaad of 2016-09-06
total_days = measure_weekdays_reverse(start_date, 24, ["Fri","Thu"])
The error is that you only loop a fix number of times (the number of paid days), so if you encounter holidays, you will in fact not iterate enough to find all the true paid days, which may still hide some holidays.
You can fix this by adding an inner loop on the holidays. Change this:
for rec in range(paid):
day = start.strftime("%a")
if day in off_days:
holiday += 1
start += timedelta(days=1)
print(holiday) # Output 6 instead of 8
last_paid_date = start + timedelta(days=holiday)
to this:
for rec in range(paid):
day = start.strftime("%a")
while day in off_days:
holiday += 1
start += timedelta(days=1)
day = start.strftime("%a")
last_paid_date = start
start += timedelta(days=1)
print(holiday)
Related
How to remove 0:00:00 from the output of datetime.date() function? For example:
import datetime
now = datetime.datetime.now()
year1 = now.strftime("%Y")
month2 = now.strftime("%m")
day3 = now.strftime("%d")
year = int(year1)
month = int(month2)
day = int(day3)
first_day = datetime.date(2021,8,1)
second_day = datetime.date(year,month,day)
daysleft = first_day - second_day
print(daysleft)
I get the output:
9 days, 0:00:00
If you didn't understand the question title, My main goal is to remove the 0:00:00 before the period (.). I've seen many other questions like this (in stack overflow/exchange and other websites), but it was nothing in python coding language.
You can get just the days by asking for the .days attribute of a datetime.timedelta object. E.g.:
print('{} days'.format(daysleft.days))
If your only goal is printing the output and you don't care about maintaining daysleft as a datetime object, you can always convert it to a string and .split() it like this:
print(str(daysleft).split(",")[0])
datetime has many useful functions and values
To get only days you can daysleft.days
print(f'{daysleft.days} days')
but you can also reduce other code to
now = datetime.datetime.now()
daysleft = first_day - now.date()
or
today = datetime.date.today()
daysleft = first_day - today
BTW:
If you need year, month, day as numbers then you can get it as
year = now.year
month = now.month
day = now.day
hour = now.hour
minute = now.minute
second = now.second
ms = now.microsecond
weekday = now.weekday() # 0 = monday, ..., 6 = sunday
weekday = now.isoweekday() # 1 = monday, ..., 7 = sunday
Other useful function timedelta
one_day = datetime.timedelta(days=1)
today = datetime.date.today()
yesterday = today - one_day
tomorrow = today + one_day
day_after_tomorrow = today + 2*one_day
Minimal working code with tkinter
import datetime
first_day = datetime.date(2021, 8, 1)
now = datetime.datetime.now()
daysleft = first_day - now.date()
today = datetime.date.today()
daysleft = first_day - today
print(f'{daysleft.days} days')
# ---
import tkinter as tk
root = tk.Tk()
lbl = tk.Label(root, text=f'{daysleft.days} days till {first_day}')
lbl.pack()
root.mainloop()
I need pandas to drop some rows based on 2 factors:
If it's monday drop all rows created before friday
If it's not monday, drop all rows created before yesterday
Tried saving a variable containing today's date and comparing it with an IFELSE
Daycheck = pd.to_datetime('today', format="%Y/%m/%d").dt.date
df.insert(1, "Today", Daycheck)
df['Date'] = pd.to_datetime(df['Application Date'], format="%Y/%m/%d").dt.date
Yesterday = df['Today'] - timedelta(days=1)
Friday = df['Today'] - timedelta(days=3)
if Daycheck.weekday() == 0:
df = df.drop(df[df['Date'] < Friday ].index)
else:
df = df.drop(df[df['Date'] < Yesterday].index)
It's having issues comparing the data types coming from the timestamps to the ones in the dataframe, even though I formatted the same. So far no luck making it work.
Have you considered something like
import pandas as pd
# Only for test
import datetime as dt
dates = pd.date_range(start='2019-09-15', end='2019-09-24')
df = pd.DataFrame({"created_on": dates})
today = pd.datetime.today()
## Test Monday
# today = dt.datetime(2019, 9, 23)
## Test Not Monday
# today = dt.datetime(2019, 9, 24)
if today.weekday() == 0:
do = pd.DateOffset(days=3)
else:
do = pd.DateOffset(days=1)
date_lmt = today - do
df = df[df["created_on"] > date_lmt]
You don't need to create your friday and yesterday variables using your dataframe. Just using datetime should suffice.
import pandas as pd
import datetime as dt
today = dt.date.today()
weekday = today.weekday()
mon = dt.date.today() - dt.timedelta(days=1)
sun = dt.date.today() - dt.timedelta(days=2)
sat = dt.date.today() - dt.timedelta(days=3)
fri = dt.date.today() - dt.timedelta(days=4)
thur = dt.date.today() - dt.timedelta(days=5)
wed = dt.date.today() - dt.timedelta(days=6)
data = {'date':[sun,sat,fri,thur,wed],
'greeting':['good morning!', 'up n attem!', 'wakey wakey', 'rise and
shine', 'zzzzz']
}
date_df = pd.DataFrame(data)
fri_if_mon = dt.date.today() - dt.timedelta(days=3)
yesterday = dt.date.today() - dt.timedelta(days=1)
print(weekday)
print(date_df)
if(weekday == 0):
date_df.drop(date_df[date_df['date'] < fri_if_mon].index, inplace = True)
else:
date_df.drop(date_df[date_df['date'] < yesterday].index, inplace = True)
print(date_df)
Give you this output when it is Monday.
date greeting
0 2019-09-22 good morning!
1 2019-09-21 up n attem!
2 2019-09-20 wakey wakey
So I'm trying to print the total hours in intervals between a start date and an end date in python as follows:
#app.route('/test/')
def test():
date_format = "%Y-%m-%d %H:%M:%S"
start_date_time = datetime.strptime("2018-10-16 07:00:00", date_format)
end_date_time = datetime.strptime("2018-10-18 22:00:00", date_format)
def daterange(start_date_time, end_date_time):
for n in range(int ((end_date_time - start_date_time).days)):
yield start_date_time + timedelta(n)
for single_date in daterange(start_date_time, end_date_time):
def get_delta(start_date_time, end_date_time):
delta = end_date_time - start_date_time
return delta
# Split time in hours
delta = get_delta(start_date_time,end_date_time)
for i in range(delta.days * 24 + 1): # THIS IS ONLY CALCULATING 24HRS FROM TIME GIVEN START TIME NOT TILL THE SELECTED END TIME SO I'M ONLY GETTING AN EXACT 24 HOUR RANGE
currtime = start_date_time + timedelta(hours=i)
print (currtime)
return ("done")
By This i'm only managing to get the first 24 Hours from the selected date, but I wish to keep on counting and get all hours till the selected end date.
You might be overthinking it.
from datetime import datetime, timedelta
date_format = "%Y-%m-%d %H:%M:%S"
start_date_time = datetime.strptime("2018-10-16 07:00:00", date_format)
end_date_time = datetime.strptime("2018-10-18 22:00:00", date_format)
def get_delta(l, r):
return abs(int((l-r).total_seconds())) / 3600
for h in range(int(get_delta(start_date_time, end_date_time))):
print((start_date_time + timedelta(0, h*3600)).strftime(date_format))
What I am trying to do is see if date is in 1 week from currdate
from datetime import datetime, timedelta
import yagmail
year = datetime.now().year
month = datetime.now().month
day = datetime.now().day
currdate = '{}-{}-{}'.format(year, month, day)
currdate = datetime.strptime(currdate, '%Y-%m-%d')
date = '2018-04-01'
days = currdate - timedelta(int(date[-2:]))
days = str(days)
print(days)
if days[8:11] == '07':
yag = yagmail.SMTP("##########gmail.com", "######")
content = ['One Of Your Homework\'s Is Due In 1 Week!']
yag.send('###########gmail.com', 'Homework Due Soon!', content)
else:
print('It Isn\'t')
But it prints:
2018-04-07 00:00:00
It Isnt't
And I'm not sure why. Because days[8:11] is 07.
It is not 07. It's 07 (note the trailing space).
The following change will work:
if int(days[8:11]) == 7:
I'd create a function that you pass the date as a string. Something like this:
import datetime
def check_if_less_than_seven_days(x):
d = datetime.datetime.strptime(x, "%Y-%m-%d") # Add .date() if hour doesn't matter
now = datetime.datetime.now() # Add .date() if hour doesn't matter
return (d - now).days < 7
if check_if_less_than_seven_days("2018-04-18"):
print('Do something') # This will not print
if check_if_less_than_seven_days("2018-04-14"):
print('Do something') # This will print
Will print:
'Do something'
I suppose your first line when you initiate datetime.now() three times is just for testing purposes but dont do this as it could end up over different days (if you run this exactly at the milliseconds around midnight..) this will work better in that regard.
now = datetime.datetime.now()
year = now.year
month = now.month
day = now.day
Anyway, read up on datetime timedelta. Just make you logic around that.
https://docs.python.org/3/library/datetime.html#timedelta-objects
import datetime
test_date_string = "2018-04-10"
d = datetime.datetime.strptime(test_date_string, "%Y-%m-%d")
now = datetime.datetime.now()
delta = d - now
elif delta.days < 7:
print("You have less then 7 days to go")
For days[8:11] you get the following output
>>> days[8:11]
'08 '
So you should use days[8:10]=='07' in case you want to use the same method,as it wont have extra space at the end.
>>> days[8:10]
'08'
so you should use
if days[8:10] == '07':
Following this answer I tried to get the date for last Thursday of the current month. But my code doesn't get out of loop.
from datetime import datetime
from dateutil.relativedelta import relativedelta, TH
todayte = datetime.today()
cmon = todayte.month
nthu = todayte
while nthu.month == cmon:
nthu += relativedelta(weekday=TH(1))
#print nthu.strftime('%d%b%Y').upper()
Looking at the documentation of relativedelta
Notice that if the calculated date is already Monday, for example, using (0, 1) or (0, -1) won’t change the day.
If nthu is already Thursday then adding TH(1) or TH(-1) won't have any effect but result in the same date and that's why your loop is running infinitely.
I will assume maximum 5 weeks in a month and do it like following:
todayte = datetime.today()
cmon = todayte.month
for i in range(1, 6):
t = todayte + relativedelta(weekday=TH(i))
if t.month != cmon:
# since t is exceeded we need last one which we can get by subtracting -2 since it is already a Thursday.
t = t + relativedelta(weekday=TH(-2))
break
Based on Adam Smith's answer on How can I get the 3rd Friday of a month in Python?, you can get the date of the last Thursday of the current month as follows:
import calendar
import datetime
def get_thursday(cal,year,month,thursday_number):
'''
For example, get_thursday(cal, 2017,8,0) returns (2017,8,3)
because the first thursday of August 2017 is 2017-08-03
'''
monthcal = cal.monthdatescalendar(year, month)
selected_thursday = [day for week in monthcal for day in week if \
day.weekday() == calendar.THURSDAY and \
day.month == month][thursday_number]
return selected_thursday
def main():
'''
Show the use of get_thursday()
'''
cal = calendar.Calendar(firstweekday=calendar.MONDAY)
today = datetime.datetime.today()
year = today.year
month = today.month
date = get_thursday(cal,year,month,-1) # -1 because we want the last Thursday
print('date: {0}'.format(date)) # date: 2017-08-31
if __name__ == "__main__":
main()
You should pass 2 to TH instead of 1, as 1 doesn't change anything. Modify your code to:
while (nthu + relativedelta(weekday=TH(2))).month == cmon:
nthu += relativedelta(weekday=TH(2))
print nthu.strftime('%d-%b-%Y').upper()
# prints 26-MAY-2016
Note that I modified the loop's condition in order to break in the last occurrence of the day on the month, otherwise it'll break in the next month (in this case, June).
from datetime import datetime , timedelta
todayte = datetime.today()
cmon = todayte.month
nthu = todayte
while todayte.month == cmon:
todayte += timedelta(days=1)
if todayte.weekday()==3: #this is Thursday
nthu = todayte
print nthu
You can also use calendar package.
Access the calendar in the form of monthcalendar. and notice that, the Friday is the last day of a week.
import calendar
import datetime
now = datetime.datetime.now()
last_sunday = max(week[-1] for week in calendar.monthcalendar(now.year,
now.month))
print('{}-{}-{:2}'.format(now.year, calendar.month_abbr[now.month],
last_sunday))
I think this will be fastest perhaps:
end_of_month = datetime.datetime.today() + relativedelta(day=31)
last_thursday = end_of_month + relativedelta(weekday=TH(-1))
This code can be used in python 3.x for finding last Thursday of current month.
import datetime
dt = datetime.datetime.today()
def lastThurs(dt):
currDate, currMth, currYr = dt, dt.month, dt.year
for i in range(31):
if currDate.month == currMth and currDate.year == currYr and currDate.weekday() == 3:
#print('dt:'+ str(currDate))
lastThuDate = currDate
currDate += datetime.timedelta(1)
return lastThuDate
You can do something like this:
import pandas as pd
from dateutil.relativedelta import relativedelta, TH
expiry_type = 0
today = pd.datetime.today()
expiry_dates = []
if expiry_type == 0:
# Weekly expiry
for i in range(1,13):
expiry_dates.append((today + relativedelta(weekday=TH(i))).date())
else:
# Monthly expiry
for i in range(1,13):
x = (today + relativedelta(weekday=TH(i))).date()
y = (today + relativedelta(weekday=TH(i+1))).date()
if x.month != y.month :
if x.day > y.day :
expiry_dates.append(x)
print(expiry_dates)
import datetime
def get_thursday(_month,_year):
for _i in range(1,32):
if _i > 9:
_dateStr = str(_i)
else:
_dateStr = '0' + str(_i)
_date = str(_year) + '-' + str(_month) + '-' + _dateStr
try:
a = datetime.datetime.strptime(_date, "%Y-%m-%d").strftime('%a')
except:
continue
if a == 'Thu':
_lastThurs = _date
return _lastThurs
x = get_thursday('05','2017')
print(x)
It is straightforward fast and easy to understand, we take the first of every month and then subtract it by 3 coz 3 is Thursday weekday number and then multiply it by either 4 and check if it is in the same month if it is then that is last Thursday otherwise we multiply it with 3 and we get our last Thursday
import datetime as dt
from datetime import timedelta
#start is the first of every month
start = dt.datetime.fromisoformat('2022-08-01')
if start.month == (start + timedelta((3 - start.weekday()) + 4*7)).month:
exp = start + timedelta((3 - start.weekday()) + 4*7)
else:
exp = start + timedelta((3 - start.weekday()) + 3*7)
You can use Calendar to achieve your result. I find it simple.
import calendar
import datetime
testdate= datetime.datetime.now()
weekly_thursday=[]
for week in calendar.monthcalendar(testdate.year,testdate.month):
if week[3] != 0:
weekly_thursday.append(week[3])
weekly_thursday
The list weekly_thursday will have all the Thursdays from the month.
weekly_thursday[-1] will give you the last Thursday of the month.
testdate : datetime.datetime(2022, 9, 9, 6, 35, 16, 752465)
weekly_thursday : [1, 8, 15, 22, 29]
weekly_thursday [-1]:29