Calculation of business working hour in python - python

I would like to write a function that calculate working business hours in python, to do that I don't like to define a class and use python ready function to calculate.
I tried with following code but the code is not working well. I need to modify the code and change it for the hour instead of minutes too.
Do you have any suggestion?
def getminutes(datetime1,datetime2,worktiming=[9, 17]):
day_hours = (worktiming[1]-worktiming[0])
day_minutes = day_hours * 60 # minutes in a work day
weekends=[6, 7]
# Set initial default variables
dt_start = datetime1.datetime # datetime of start
dt_end = datetime2.datetime # datetime of end
worktime_in_seconds = 0
if dt_start.date() == dt_end.date():
# starts and ends on same workday
full_days = 0
if dt_start in [6, 7]:
return 0
else:
if dt_start.hour < worktiming[0]:
# set start time to opening hour
dt_start = datetime.datetime(
year=dt_start.year,
month=dt_start.month,
day=dt_start.day,
hour=worktiming[0],
minute=0)
if dt_start.hour >= worktiming[1] or \
dt_end.hour < worktiming[0]:
return 0
if dt_end.hour >= worktiming[1]:
dt_end = datetime.datetime(
year=dt_end.year,
month=dt_end.month,
day=dt_end.day,
hour=worktiming[1],
minute=0)
worktime_in_seconds = (dt_end-dt_start).total_seconds()
elif (dt_end-dt_start).days < 0:
# ends before start
return 0
else:
# start and ends on different days
current_day = dt_start # marker for counting workdays
while not current_day.date() == dt_end.date():
if not is_weekend(current_day):
if current_day == dt_start:
# increment hours of first day
if current_day.hour < worktiming[0]:
# starts before the work day
worktime_in_seconds += day_minutes*60 # add 1 full work day
elif current_day.hour >= worktiming[1]:
pass # no time on first day
else:
# starts during the working day
dt_currentday_close = datetime.datetime(
year=dt_start.year,
month=dt_start.month,
day=dt_start.day,
hour= worktiming[1],
minute=0)
worktime_in_seconds += (dt_currentday_close
- dt_start).total_seconds()
else:
# increment one full day
worktime_in_seconds += day_minutes*60
current_day += datetime.timedelta(days=1) # next day
# Time on the last day
if not is_weekend(dt_end):
if dt_end.hour >= worktiming[1]: # finish after close
# Add a full day
worktime_in_seconds += day_minutes*60
elif dt_end.hour < worktiming[0]: # close before opening
pass # no time added
else:
# Add time since opening
dt_end_open = datetime.datetime(
year=dt_end.year,
month=dt_end.month,
day=dt_end.day,
hour=worktiming[0],
minute=0)
worktime_in_seconds += (dt_end-dt_end_open).total_seconds()
return int(worktime_in_seconds / 60)
How can I modify the code that works with the following input ?
getminutes(2019-12-02 09:30:00,2019-12-07 12:15:00,worktiming=[9, 17])

You can use pd.bdate_range(datetime1, datetime2) to compute the number of working days. When converting worktiming to a pandas datetime, it is easy to compute the difference (in seconds) between the two datetimes:
import pandas as pd
datetime1 = "2019-12-02 09:30:00"
datetime2 = "2019-12-07 12:15:00"
def getminutes(datetime1, datetime2, worktiming=[9, 17]):
d1 = pd.to_datetime(datetime1)
d2 = pd.to_datetime(datetime2)
wd = pd.bdate_range(d1, d2) # working days
day_hours = (worktiming[1] - worktiming[0])
day_minutes = day_hours * 60 # minutes in a work day
day_seconds = day_minutes * 60 # seconds in a work day
full_days = len(wd)
day1 = datetime1[:10]
day2 = datetime2[:10]
dt1 = pd.to_datetime(day1 + " " + str(worktiming[0]) + ":00")
dt2 = pd.to_datetime(day2 + " " + str(worktiming[1]) + ":00")
ex1, ex2 = 0, 0
if day1 in wd:
ex1 = max(pd.Timedelta(d1 - dt1).seconds, 0)
if day2 in wd:
ex2 = max(pd.Timedelta(dt2 - d2).seconds, 0)
total_seconds = full_days * day_seconds - ex1 - ex2
total_minutes = total_seconds / 60
total_hours = total_minutes / 60
return int(total_minutes)
print(getminutes(datetime1, datetime2))
Output: 2370

Related

Python Timer Cooldown Example

I'm looking for a cooldown timer for python, basically just to print days,hours,minutes,seconds left from a certain date.
Thanks very much!
You can get the counter with the help of time delta function.
import datetime
import time
future_date = datetime.datetime.now()+ datetime.timedelta(seconds=3)
while True:
curr_date = datetime.datetime.now()
rem_time = future_date - curr_date
total_seconds = int(rem_time.total_seconds())
if total_seconds > 0:
days, h_remainder = divmod(total_seconds, 86400)
hours, remainder = divmod(h_remainder, 3600)
minutes, seconds = divmod(remainder, 60)
print("Time Left: {} days, {} hours, {} minutes, {} seconds".format(days, hours, minutes, seconds))
time.sleep(1)
else:
break
sample output will be:
Time Left: 0 days, 0 hours, 0 minutes, 2 seconds
Time Left: 0 days, 0 hours, 0 minutes, 1 seconds
Try this. The module datetime is preinstalled on Python, I believe.
import datetime
while True:
print("\033[H\033[J")
present = datetime.datetime.now()
future = datetime.datetime(2022, 3, 31, 8, 0, 0)
difference = future - present
print(difference)
The format for datetime's future is: year, month, day, hour, minute, second.
Or, if you'd like to have user input:
import datetime
year = int(input('Enter the year of the end date: '))
month = int(input('Enter the month of the end date: '))
day = int(input('Enter the day of the end date: '))
hour = int(input('Enter the hour of the end date: '))
minute = int(input('Enter the minute of the end date: '))
second = int(input('Enter the second of the end date (a little tricky): '))
future = datetime.datetime(year, month, day, hour, minute, second)
while True:
print("\033[H\033[J")
present = datetime.datetime.now()
difference = future - present
if present >= future:
break
print(difference)
print('Time reached!')
You can use the seconds from a timedelta from subtracting two dates to calculate the days, hours, minutes and seconds like this:
from datetime import datetime
import time
totalSecs = 1 #So the while loop doesn't stop immidiately
while totalSecs > 0:
startDate = datetime.now() #Can be any date
endDate = datetime(2021, 12, 25)
delta = endDate - startDate
totalSecs = delta.total_seconds()
days = divmod(totalSecs, 86400)
hrs = divmod(days[1], 3600)
mins = divmod(hrs[1], 60)
seconds = divmod(mins[1], 1)
print("{:02d}:{:02d}:{:02d}:{:02d}".format(int(days[0]), int(hrs[0]), int(mins[0]), int(seconds[0]))) #Zero pad all the numbers
time.sleep(1) #Print every second.
Thank you all for your replies, i've done a mistake when i made the post. Is not from a date. Is a countdown in day,hours,minutes,seconds from a certain amount of seconds. Let's say i've got 31104000 seconds and i want to print how many days,hours,minutes,seconds left from that amount of seconds.
The code i've got now is a bit trivial and i can't print seconds in realtime.
def SecondToDHM(time):
if time < 60:
return "%.2f %s" % (time, SECOND)
second = int(time % 60)
minute = int((time / 60) % 60)
hour = int((time / 60) / 60) % 24
day = int(int((time / 60) / 60) / 24)
text = ""
if day > 0:
text += str(day) + DAY
text += " "
if hour > 0:
text += str(hour) + HOUR
text += " "
if minute > 0:
text += str(minute) + MINUTE
text += " "
if second > 0:
text += str(second) + SECOND
return text
import datetime
a = datetime.datetime.now()
"%s:%s.%s" % (a.minute, a.second, str(a.microsecond))

Execute function X amount of times between two dates, how would I do it?

If I was able to execute a function a (user-specified) amount of time between two dates, how would I do it?
Am I on the right track?
from datetime import date, datetime
from upload import *
current_time = datetime.utcnow()
start_time = datetime.time.hour(17)
end_time = datetime.time.hour(20)
imageposts = []
post_limit = 0
for imagepost in imageposts:
if start_time <= current_time & current.time <= end_time & post_limit <= 3:
try:
upload()
postlimit += 1
except:
print('Current time is not between times')
Try this:
from datetime import datetime
from upload import *
current_time = datetime.utcnow()
year, month, day = current_time.year, current_time.month, current_time.day
start_time = datetime(year, month, day, 17)
end_time = datetime(year, month, day, 20, 59, 59)
imageposts = []
post_limit = 0
for imagepost in imageposts:
if start_time <= current.time <= end_time and post_limit <= 3:
try:
upload()
post_limit += 1
except:
print('Current time is not between times')

I am trying to sample at 100hz instead of just as quick as the program will run. How would I do that?

I have a program in which I am just printing to a csv and I want exactly 100 sample points every second but I have no clue where to start with this or how to do it!!! Please help!
from datetime import datetime
import pandas as pd
i = 0
data = []
filename = 'Data.csv'
hz = 0
count = 0
while True:
#start = process_time()
if i == 0:
Emptydf = pd.DataFrame([], columns = ['COUNT', 'TIME'])
(Emptydf).to_csv('Data.csv', index = False)
curr_time = datetime.now()
str_milli = curr_time.strftime("%f")[:2]
milliseconds = int(str_milli)
timestamp = curr_time.strftime("%H:%M:%S.%f")
datarow = {'Count': i, 'TIME' : timestamp}
#diff = curr_time - past time of 0.01 milli seconds
#if diff >= 0.01:
data.append(datarow)
#time.sleep(.006)
if i%10 == 0:
dataframe = pd.DataFrame(data)
(dataframe).to_csv('Data.csv', mode = 'a', header = False, index = False)
#print(dataframe)
data.clear()
i += 1
Here is an example that increments a counter 100 times per second:
import time
FREQ_HZ = 100.
count = 0
start_time = time.time()
try:
while True:
count += 1
time.sleep(count / FREQ_HZ - (time.time() - start_time))
except:
print("%.2f iter/second\n" % (count / (time.time() - start_time)))
To test, let it run for a bit and then hit ^C.
Basically, what you do is the following;
import time
cycletime = 0.01 # seconds
while True:
start = time.monotonic()
# << Do whatever you need to do here. >>
delta = time.monotonic() - start
if delta < cycletime: # Did we finish in time?
time.sleep(cycletime - delta) # Sleep the rest of the time.
else:
print('WARNING: cycle too long!')
Note that for such applications time.monotonic is preferred over time.time because the latter can decrease when the system clock is changed.

Get the last thursday of the current month using python

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

Python Time Math

I want to write a program that allows the user to enter in a start time hour, end time hour, and number of divisions.
So they might enter 9, 10, and 4 which should mean a start time of 9:00AM, end of 10:00AM and to split the range 4 times, resulting in an output of 9:00, 9:15, 9:30, 9:45.
I've tried using the time module and datetime, but cannot get the addition of time to work. I do not care about date.
I can calculate the time split, but the actual addition to the start time is evading me.
I have a hodge-podge of code, and the following is mostly me experimenting trying to figure out how to make this work. I've tried adding the minutes, tried converting to seconds, delved into datetime, tried the time module, but can't seem to get it to work. There are plenty of examples of how to "add 15 minutes to now" but the issue is I don't want to start at the "now", but rather let the user decide start time.
Thank you.
time_start = "9"
time_end = "10"
time_split = "4"
if len(time_start) == 1:
time_start = "0" + str(time_start) + ":00"
else:
time_start = str(time_start) + ":00"
if len(time_end) == 1:
time_end = "0" + str(time_end) + ":00"
else:
time_end = str(time_end) + ":00"
print time_start
print time_end
s1 = time_start + ':00'
s2 = time_end + ':00'
FMT = '%H:%M:%S'
tdelta = datetime.strptime(s2, FMT) - datetime.strptime(s1, FMT)
divided = tdelta / int(time_split)
print tdelta
print divided
s3 = str(divided)
print "s1 time start: " + str(s1)
print "s2 time end: " + str(s2)
print "s3 time divided: " + str(s3)
ftr = [3600,60,1]
add_seconds = sum([a*b for a,b in zip(ftr, map(int,s3.split(':')))])
print "s3 time divided seconds: " + str(add_seconds)
print "time delta: " + str(tdelta)
EDIT: I did a small bit of research and found a much better solution that elegantly handles resolution to the millisecond. Please implement this code instead (though I will save the old code for posterity)
import datetime
start_time = 9 # per user input
end_time = 10 # per user input
divisions = 7 # per user input
total_time = end_time - start_time
start_time = datetime.datetime.combine(datetime.date.today(),datetime.time(start_time))
end_time = start_time + datetime.timedelta(hours=total_time)
increment = total_time*3600000//divisions # resolution in ms
times = [(start_time+datetime.timedelta(milliseconds=increment*i)).time()
for i in range(divisions)]
from pprint import pprint
pprint(list(map(str,times)))
# ['09:00:00',
# '09:08:34.285000',
# '09:17:08.570000',
# '09:25:42.855000',
# '09:34:17.140000',
# '09:42:51.425000',
# '09:51:25.710000']
If I were you, I'd do my math as raw minutes and use datetime.time only to save the results as something more portable.
Try this:
import datetime
start_time = 9 # per user input
end_time = 10 # per user input
divisions = 4 # per user input
total_minutes = (end_time-start_time)*60
increment = total_minutes // divisions
minutes = [start_time*60]
while minutes[-1] < end_time*60:
# < end_time*60 - increment to exclude end_time from result
minutes.append(minutes[-1] + increment)
times = [datetime.time(c//60,c%60) for c in minutes]
# [09:00:00,
# 09:15:00,
# 09:30:00,
# 09:45:00,
# 10:00:00]

Categories

Resources