I'm working on a script that calculates my salary, for each of my work days, since we don't get the plan send out electronic.
We do earn extra withing some time periods.
every hour i earn 61.86 DKK, but at within some time periods i earn extra money, as seen below.
(For simplicity i have calculated the time in 24h cycle, since that what i am used to)
Weekdays (18:00 - 06:00) 12.20 DKK
Saturday (15:00 - 24:00) 21.65 DKK
Sunday (whole day) 24.50 DKK
So fare i have worked out, how to calculate the extra money and the hourly rate fine. Although my problem is, if i have a work guard that starts 20:00 and ends next day 4:00 then it will give me and error. I have an IF statement that activates if the hour is above 18(which is when i get extra in the weekdays) then i subtract the hour count with 18 to get, how many hours that's i need to earn extra.
if d2.isoweekday() <= 5: #If its a weekday
if d2.hour >= 18:
extra += ((d2.hour - 18) * weekdaySalary) + ((d2.minute / 60) * weekdaySalary)
How do i detect, exact how many hours that's between a specific period?
like if i have to dates
26-12-2014 17:00
27-12-2014 08:00
i need a way to see how many of those work hours is within the time period(18:00-06:00).
how can this be done?
it's like having 2 diffrent date ranges.
1st - for when i get extra.
2rd - for when i actually work.
26-12-2014 17:00
18:00 - extra money period start here
|
|how do i get the time between these to points?
|
06:00 - extra money period ends here
27-12-2014 08:00
it could also be like this
26-12-2014 17:00
18:00 - extra money period start here
|
|how do i get the time between these to points?
|
27-12-2014 04:00
06:00 - extra money period ends here
Every answer is highly appreciated, spent so much time trying to figure out with no really result.
Based on the two ranges you provided, presuming they are when your shift starts and ends, the following will calculate pay from start of shift to end, increasing by basic rate or basic rate plus extra pay based on the time of day:
def calculate_ot(t1,t2):
t1 = datetime.strptime(t1, "%d-%m-%Y %H:%M")
t2 = datetime.strptime(t2, "%d-%m-%Y %H:%M")
days = ((t2 - t1).days * 86400)
hours, rem = divmod((t2 - t1).seconds + days, 3600)
start_ot = datetime.strptime("18:00 {}".format(t1.date()), "%H:%M %Y-%m-%d")
end_ot = datetime.strptime("06:00 {}".format(t2.date()), "%H:%M %Y-%m-%d")
total_pay = 0
for x in range(hours): # loop in total hour time difference
# if we are within the range of extras pay increase by normal rate plus ot
if start_ot <= t1 < end_ot and t1 < t2:
total_pay += 62 # or 62.20 you have conflicting examples
else:
# else just add basic pay rate
total_pay == 50
t1 += timedelta(hours=1) # keep adding another hour
return total_pay
Related
I'd like to write a small function that can calculate the number of hours in any given day, for any time zone. The obvious approach was to count the hours between the first instant of the day and the next day. Unfortunately, whatever day I choose, this approach always says that a day is 24 hours long.
In the UK, the clocks are advanced at 1am in March by 1 hour. That means the 28th March 2021 should have 23 hours. The time-range from 1am to 2am will not have existed that day.
Likewise, on the 31st October 2021 the clock is pushed back at 1am, so that day will have 25 hours. The time-range midnight to 1am will have occurred twice in that day.
import datetime
import pytz
# When do the clocks change?
# https://www.gov.uk/when-do-the-clocks-change
day0=datetime.datetime(2021,3,28, tzinfo=pytz.timezone("Europe/London"))
day1=datetime.datetime(2021,3,29, tzinfo=pytz.timezone("Europe/London"))
delta = day1-day0
print(delta)
hours = delta / datetime.timedelta(hours=1)
print(hours)
This script gives output that seems incorrect:
1 day, 0:00:00
24.0
Is there a simpler way to get the number of hours in a particular day, that gives the right answer?
Ideally this should be able to account for daylight savings, leap-years and even leap seconds.
Part of the issue is "using the tzinfo argument of the standard datetime constructors ‘’does not work’’ with pytz for many timezones."
So we can work around that by using timezone.localize() with a local naive time (no tz):
London = pytz.timezone("Europe/London")
day0 = London.localize(datetime.datetime(2021,3,28))
day1 = London.localize(datetime.datetime(2021,3,29))
(day1 - day0).total_seconds() / 60 / 60 # in hours
# 23.0
And for 31st October:
day0 = London.localize(datetime.datetime(2021, 10, 31))
day1 = London.localize(datetime.datetime(2021, 11, 1))
(day1 - day0).total_seconds() / 60 / 60
# 25.0
I am a complete beginner in Python and it is my first question on Stackoverflow. I have tried numerous tutorials on youtube + some additional google searching, but havent been really able to completely solve my task. Briefly putting it below asf:
We have a dataset of futures prices (values) for next 12-36 months. Each value corresponds to one month in future. The idea for the code is to have an input of following:
starting date in days (like 2nd of Feb 2021 or any other)
duration of given days (say 95 or 150 days or 425 days)
The code has to calculate the number of days from each given month between starting and ending date (which is starting + duration) and then to use appropriate values from corresponding month to calculate an average price for this particular duration in time.
Example:
Starting date is 2nd of Feb 2021 and duration is 95 days (end date 8th of May). Values are Feb - 7750, Mar - 9200, April - 9500, May is 10100.
I have managed to do same in Excel (which was very clumsy and too complicated to use on the daily basis) and average stands for around 8949 taking in mind all above. But I cant figure out how to code same "interval" with days per month in Python. All of the articles just simply point out to "monthrange" function, but how is that possible to apply same for this task?
Appreciate your understanding of a newbie question and sorry for the lack of knowledge to express/explain my thoughts more clear.
Looking forward to any help relative to above.
You can use dataframe.todatetime() to constuct your code. If you need further help, just click ctrl + tab within your code to see the inputs and their usage.
You can try the following code.
The input_start_date() function will input the start date, and return it when called.
After we have the start date we input the duration of days.
Then we simply add them using timedelta
For the Distribution of days in the month : SO - #wwii
import datetime
from datetime import timedelta
def input_start_date():
YEAR = int(input('Enter the year : '))
MONTH = int(input('Enter the month : '))
DAY = int(input('Enter the day : '))
DATE = datetime.date(YEAR, MONTH, DAY)
return DATE
# get the start date:
Start_date = input_start_date()
# get the Duration
Duration = int(input('Enter the duration : '))
print('Start Date : ', Start_date)
print('Duration :', Duration)
# final date.
Final_date = Start_date + timedelta(days=Duration)
print(Final_date)
# credit goes to #wwii -----------------------
one_day = datetime.timedelta(1)
start_dates = [Start_date]
end_dates = []
today = Start_date
while today <= Final_date:
tomorrow = today + one_day
if tomorrow.month != today.month:
start_dates.append(tomorrow)
end_dates.append(today)
today = tomorrow
end_dates.append(Final_date)
# -----------------------------------------------
print("Distribution : ")
for i in range(len(start_dates)):
days = int(str(end_dates[i]-start_dates[i]).split()[0]) + 1
print(start_dates[i], ' to ', end_dates[i], ' = ', days)
print(str(end_dates[0]-start_dates[0]))
'''
Distribution :
2021-02-02 to 2021-02-28 = 27
2021-03-01 to 2021-03-31 = 31
2021-04-01 to 2021-04-30 = 30
2021-05-01 to 2021-05-08 = 8
'''
I want to calculate hours of work during a day, and subtract lunchtime from that time. So somebody clocks in at 8:00, takes a lunch from 12:00 to 12:30, and finish at 16:00.
Lunchtime is configured in a settings table, with start-time and end-time.
So in a nutshell I want to calculate this:
endtime minus starttime = n hours:minutes of work, minus lunchtime (= 12:30 - 12:00 = 30 minutes)
How can I calculate this in Python without making this a hardcoded thing?
Help would be much appreciated
cheers
You can do it with Python datetime:
import datetime as dt
def work_time(start, end, lunch=[], format_='%H:%M'):
""" Calculate the hours worked in a day.
"""
start_dt = dt.datetime.strptime(start, format_)
end_dt = dt.datetime.strptime(end, format_)
if lunch:
lunch_start_dt = dt.datetime.strptime(lunch[0], format_)
lunch_end_dt = dt.datetime.strptime(lunch[1], format_)
lunch_duration = lunch_end_dt - lunch_start_dt
else:
lunch_duration = dt.timedelta(0)
elapsed = end_dt - start_dt - lunch_duration
hours = elapsed.seconds / 3600
return hours
>>> work_time('8:00', '16:00', lunch=['12:00', '12:30'])
7.5
The documentation for datetime provides more information on specific formatting and how to use timedeltas to perform operations on datetime and time objects.
I would like to create a running dataframe of trading data for the next four hours from the current time while skipping non-trading hours (5-6pm weekdays, Saturday-6pm Sunday). For example, at 4pm on Friday, I'd like a dataframe that runs from 4pm to 5pm on Friday and then 6pm-9pm on Sunday.
Currently, I am using the following:
time_parameter = pd.Timedelta(hours=4) #Set time difference to four hours
df = df.set_index(['Time'])
for current_time, row in df.iterrows(): #df is the entire trading data df
future_time = current_time + time_parameter
temp_df = df.loc[current_time : future_time]
This obviously doesn't skip non-trading hours so I am trying to find an efficient way to do that.
One method I can use is creating a set of non-trading hours, checking if the current time bounds (current_time:future_time) include any, and adding an additional hour for each.
However, since the dataset has about 3.5million rows and would need this check for each row, I want to ask if anyone may know of a faster approach?
In short, looking for a method to add 4 business hours (Sun-Fri 6pm-5pm) to current time. Thanks!
Input Data: This shows the first 19 rows of the trading data
Expected Output Data: This shows the first and last 3 rows from a four hour period starting at 18:00:30 on January 8th, 2017
Solution
Based on the answer by Code Different below, I used the following:
def last_trading_hour(start_time, time_parameter, periods_parameter):
start_series = pd.date_range(start_time, freq='H', periods = periods_parameter)
mask = (((start_series.dayofweek == 6) & (time_2(18) <= start_series.time)) #Sunday: After 6pm
| ((start_series.dayofweek == 4) & (start_series.time < time_2(17))) #Friday before 5pm
| ((start_series.dayofweek < 4) & (start_series.time < time_2(17))) #Mon-Thur before 5pm
| ((start_series.dayofweek < 4) & (time_2(18) <= start_series.time)) #Mon-Thur after 6pm
)
return start_series[mask][time_parameter]
start_time = pd.Timestamp('2019-08-16 13:00:10')
time_parameter = 4 #Adding 4 hours to time
periods_parameter = 49 + time_parameter #Max 49 straight hours of no-trades (Fri 5pm-Sun 6pm)
last_trading_hour(start_time, time_parameter, periods_parameter)
Results:
Timestamp('2019-08-18 18:00:10')
If you need the entire series, follow Code Different's method for indexing.
Generate a sufficiently long series of hours then filter for the first 4 that are trading hours:
from datetime import time
start_time = pd.Timestamp('2019-08-16 16:00')
s = pd.date_range(start_time, freq='H', periods=72)
is_trading_hour = (
((s.weekday == 6) & (time(18) <= s.time))
| ((s.weekday == 4) & (s.time < time(17)))
| (s.weekday < 4)
)
s[is_trading_hour][:4]
Result:
DatetimeIndex(['2019-08-16 16:00:00', '2019-08-18 18:00:00',
'2019-08-18 19:00:00', '2019-08-18 20:00:00'],
dtype='datetime64[ns]', freq=None)
It's hard to tell from so little information. However, it seems that you're working on hour boundaries. If so, it should be straightforward to set up a look-up table (dict) keyed by each day and hour, perhaps: (0,0) for midnight Sun/Mon, (2, 13) for 1pm Wed, and so on. Then provide simple entries for the end of the 4-hour period
(0, 0): Timedelta(hours= 4), # 0:00 Mon, normal span; regular trading hours
(0,16): Timedelta(hours= 5), # 16:00 Sun; 1 hour of down-time
(4,16): Timedelta(hours=53), # 16:00 Fri; 1 hour trade, 49 hrs down, 3 hrs trade
(5,16): Timedelta(hours=26), # 16:00 Sat; 26 hours down, 4 hours trade
Add the indicated Timedelta to your start time; that gives you the end time of the period. You can write a few loops and if statements to compute these times for you, or just hard-code all 168; they're rather repetitive.
Checking your data base lines remains up to you, since you didn't specify their format or semantics in your posting.
I have to save the time in AM PM format.
But i am having trouble in deciding how to enter midnight time.
Suppose the time is 9PM to 6AM next morning. I have to divide it into day to day basis . Like this
t1 = datetime.datetime.strptime('09:00PM', '%I:%M%p').time()
t2 = datetime.datetime.strptime('12:00AM', '%I:%M%p').time()
t3 = datetime.datetime.strptime('06:00AM', '%I:%M%p').time()
Now i want to know whether the t2 should be
12:00 AM or 11.59PM
If i do 12:00AM then i can't compare if 9pm > 12am but 11.59 looks odd or may be it is right way
You should always use 00:00 (or 12:00 AM) to represent midnight.
Using 23:59 (or 11:59 PM) is problematic for a couple of reasons:
Precision matters in the comparison. Is 23:59:01 not before midnight? What about 23:59:59.9999?
Duration calculation will be thrown off by whatever precision you chose. Consider that 10:00 pm to midnight is 2 hours, not 1 hour and 59 minutes.
To avoid these problems, you should always treat time intervals as half-open intervals. That is, the range has an inclusive start, and an exclusive end. In interval notation: [start, end)
Now with regard to crossing the midnight boundary:
When you are comparing times that are associated with a date, you can just compare directly:
[2015-01-01T21:00, 2015-01-02T06:00) = 9 hours
2015-01-01T21:00 < 2015-01-02T06:00
When you do not have a date, you can determine duration, but you cannot determine order!
[21:00, 06:00) = 9 hours
21:00 < 06:00 OR 21:00 > 06:00
The best you can do is determine whether a time is between the points covered by the range.
Both 23:00 and 01:00 are in the range [21:00, 06:00)
21:00 is also in that range, but 06:00 is NOT.
Think about a clock. It's modeled as a circle, not as a straight line.
To calculate duration of a time-only interval that can cross midnight, use the following pseudocode:
if (start <= end)
duration = end - start
else
duration = end - start + 24_hours
Or more simply:
duration = (end - start + 24_hours) % 24_hours
To determine whether a time-only value falls within a time-only interval that can cross midnight, use this pseudocode:
if (start <= end)
is_between = start <= value AND end > value
else
is_between = start <= value OR end > value
Note that in the above pseudocode, I am referring to the magnitude of the values, as compared numerically - not the logical time values which, as said earlier, cannot be compared independently without a reference date.
Also, much of this is covered in my Date and Time Fundamentals course on Pluralsight (towards the very end, in "Working With Ranges").
How about making t1 = 09:00PM, t2 = 11.59PM, t3 = 12:00AM and t4 = 06:00AM. Then you have definite time ranges per day. Of course, adding the date would make time differences evident as well.