Bi-monthly salary between interval of two dates - python

I'm trying to program a salary calculator that tells you what your salary is during sick leave. In Costa Rica, where I live, salaries are paid bi-monthly (the 15th and 30th of each month), and each sick day you get paid 80% of your salary. So, the program asks you what your monthly salary is and then asks you what was the start date and finish date of your sick leave. Finally, it's meant to print out what you got paid each payday between your sick leave. This is what I have so far:
import datetime
salario = float(input("What is your monthly salary? "))
fecha1 = datetime.strptime(input('Start date of sick leave m/d/y: '), '%m/%d/%Y')
fecha2 = datetime.strptime(input('End date of sick leave m/d/y: '), '%m/%d/%Y')
diasinc = ((fecha2 - fecha1).days)
print ("Number of days in sick leave: ")
print (diasinc)
def daterange(fecha1, fecha2):
for n in range(int ((fecha2 - fecha1).days)):
yield fecha1 + timedelta(n)
for single_date in daterange(fecha1, fecha2):
print (single_date.strftime("%Y-%m-%d")) #This prints out each individual day between those dates.
I know for the salary I just multiply it by .8 to get 80% but how do I get the program to print it out for each pay day?
Thank you in advance.

Here's an old answer to a similar question from about eight years ago: python count days ignoring weekends ...
... read up on the Python: datetime module and adjust Dave Webb's generator expression to count each time the date is on the 15th or the 30th. Here's another example for counting the number of occurrences of Friday on the 13th of any month.
There are fancier ways to shortcut this calculation using modulo arithmetic. But they won't matter unless you're processing millions of these at a time on lower powered hardware and for date ranges spanning months at a time. There may even be a module somewhere that does this sort of thing, more efficiently, for you. But it might be hard for you to validate (test for correctness) as well as being hard to find.
Note that one approach which might be better in the long run would be to use Python: SQLite3 which should be included with the standard libraries of your Python distribution. Use that to generate a reference table of all dates over a broad range (from the founding of your organization until a century from now). You can add a column to that table to note all paydays and use SQL to query that table and select the dates WHERE payday==True AND date BETWEEN .... etc.
There's an example of how to SQLite: Get all dates between dates.
That approach invests some minor coding effort and some storage space into a reference table which can be used efficiently for the foreseeable future.

Related

Planning a method for working out maximum hours in a set period

I am playing with python code for looking at my work rota.
I have made a nice script which reads the rota document sent to me and extracts all of my shifts into datetimes for shift start and end, it can also reformat them into google calendar events which is great for automating my calendar.
I now want to look at my rota and compare it against the contractual rules for my rota pattern.
The rule I am looking at presently is:
"no more than 72 hours of work in any 7 day period"
Now, this is very easy to look at each week and calculate how many hours are worked. I have made this work as below:
def hours_per_week(df):
df["Week Start"] = pd.to_datetime(df["Start Date"]) - pd.to_timedelta(7, unit="d")
df = (
df.groupby([pd.Grouper(key="Week Start", freq="W-MON")])["Shift Length"]
.sum()
.reset_index()
.sort_values("Week Start")
)
df = df.rename(columns={"Shift Length": "Hours"})
df["Hours"] = df["Hours"] / np.timedelta64(1, "h")
return df
However, this method calculates the hours in the 7 day period from 0000 every Monday. The rule applies to ANY 7 day period so from 0500 on a Wednesday would be equally relevant as from 0000 on Monday.
The only way I can think of doing this is by iterating through EVERY possible hour working out the hours worked in the 7 day period from that hour. This would be easy enough but seems hugely inefficient. Before I go about writing this ugly piece of code, does anyone have an idea of a better approach to this problem?

How to get a year-week text in Python?

I have a table which contains information on the number of changes done on a particular day. I want to add a text field to it in the format YYYY-WW (e. g. 2022-01) which indicates the week number of the day. I need this information to determine in what week the total number of changes was the highest.
How can I determine the week number in Python?
Below is the code based on this answer:
week_nr = day.isocalendar().week
year = day.isocalendar().year
week_nr_txt = "{:4d}-{:02d}".format(year, week_nr)
At a first glance it seems to work, but I am not sure that week_nr_txt will contain year-week tuple according to the ISO 8601 standard.
Will it?
If not how do I need to change my code in order to avoid any week-related errors (example see below)?
Example of a week-related error: In year y1 there are 53 weeks and the last week spills over into the year y1+1.
The correct year-week tuple is y1-53. But I am afraid that my code above will result in y2-53 (y2=y1+1) which is wrong.
Thanks. I try to give my answer. You can easily use datetime python module like this:
from datetime import datetime
date = datetime(year, month, day)
# And formating the date time object like :
date.strftime('%Y-%U')
Then you will have the year and wich week the total information changes

Python - Calendar / Date Library for Arithmetic Date Operations

This is for Python:
I need a library that is able to do arithmetic operations on dates while taking into account the duration of a month and or year.
For example, say I add a value of "1 day" to 3/31/2020, the result of should return:
1 + 3/31/2020 = 4/1/2020.
I also would need to be able to convert this to datetime format, and extract day, year and month.
Does a library like this exist?
import datetime
tday = datetime.date.today() # create today
print("Today:", tday)
""" create one week time duration """
oneWeek = datetime.timedelta(days=7)
""" create 1 day and 1440 minutes of time duraiton """
eightDays = datetime.timedelta(days=7, minutes=1440)
print("A week later than today:", tday + oneWeek) # print today +7 days
And the output to this code snippet is:
Today: 2020-03-25
A week later than today: 2020-04-01
>>>
As you see, it takes month overflows into account and turns March to April. datetime module has lots of things, I don't know all its attributes well and haven't used for a long time. However, I believe you can find nice documentation or tutorials on the web.
You definitely can create any specific date(there should be some constraints though) instead of today by supplying day, month and year info. I just don't remember how to do it.

Why does W-DAY behave confusingly in Pandas?

The behaviour of freq = "W-SUN" etc. seems confusing and inconsistent. For example, d.date_range(pd.Timestamp('2019-07-09'), pd.Timestamp('2019-11-11'), freq='W-SUN') produces a sequence of Sundays, but pd.Index([pd.Timestamp('2019-07-09')]).to_period('W-SUN').to_timestamp() produces a Monday. What is going on here?
This has come up because I have an index of dates that I want to round to some frequency, while also generating a date_range with the same frequency and phase. It seems like index.to_period(freq).to_timestamp() and pd.date_range(start, end, freq=freq) should work for this, but it doesn't when freq is "W-DAY".
This is a little counter-intuitive, but here's the logic. When you use .to_period(), Pandas calculates the period of time within which the date you supplied falls. The way Pandas calculates this period is to find the next day that matches your specified frequency and extending the period backwards to include your chosen day. In other words, the period is end-inclusive, not start-inclusive.
To find the Sunday-anchored week for a given Tuesday, it finds the next Sunday after that Tuesday and adds the previous six days. When you convert to timestamp, however, it selects the first day of that period, which in this case will be a Monday. If you asked for the Sunday-anchored period of a Sunday, it would give you that day plus the previous six days, not the following six days.
If you want your period to start rather than end on a particular day of the week, just set the frequency string to the day prior. In your case, pd.Index([pd.Timestamp('2019-07-09')]).to_period('W-SAT').to_timestamp() should do the trick.
Some hopefully helpful demonstrations:
pd.Index([pd.Timestamp('2019-07-09')]).to_period('W-SUN') gives:
PeriodIndex(['2019-07-08/2019-07-14'], dtype='period[W-SUN]', freq='W-SUN
Note that this period ends on a Sunday. When you run pd.Index([pd.Timestamp('2019-07-09')]).to_period('W-SUN').to_timestamp() it gives you the first day of this period:
DatetimeIndex(['2019-07-08'], dtype='datetime64[ns]', freq=None)
You can observe how the days are chosen by running:
for f in ['W-SUN', 'W-MON', 'W-TUE', 'W-WED', 'W-THU', 'W-FRI', 'W-SAT']:
print(f, pd.Index([pd.Timestamp('2019-07-09')]).to_period(f))
Which gives:
PeriodIndex(['2019-07-08/2019-07-14'], dtype='period[W-SUN]', freq='W-SUN')
PeriodIndex(['2019-07-09/2019-07-15'], dtype='period[W-MON]', freq='W-MON')
PeriodIndex(['2019-07-03/2019-07-09'], dtype='period[W-TUE]', freq='W-TUE')
PeriodIndex(['2019-07-04/2019-07-10'], dtype='period[W-WED]', freq='W-WED')
PeriodIndex(['2019-07-05/2019-07-11'], dtype='period[W-THU]', freq='W-THU')
PeriodIndex(['2019-07-06/2019-07-12'], dtype='period[W-FRI]', freq='W-FRI')
PeriodIndex(['2019-07-07/2019-07-13'], dtype='period[W-SAT]', freq='W-SAT')
Note that the start of the chosen period jumps in the middle, but the logic remains consistent.

Pandas: convert datetime timestamp to whether it's day or night?

I am trying to determine if its a day or night based on list of timestamps. Will it be correct if I just check the hour between 7:00AM to 6:00PM to classify it as "day", otherwise "night"? Like I have done in below code. I am not sure of this because sometimes its day even after 6pm so whats the accurate way to differentiate between day or night using python?
sample data: (timezone= utc/zulutime)
timestamps = ['2015-03-25 21:15:00', '2015-06-27 18:24:00', '2015-06-27 18:22:00', '2015-06-27 18:21:00', '2015-07-07 07:53:00']
Code:
for timestamp in timestamps:
time = datetime.datetime.strptime(timestamp, "%Y-%m-%d %H:%M:%S")
hr, mi = (time.hour, time.minute)
if hr>=7 and hr<18: print ("daylight")
else: print ("evening or night")
sample output:
evening or night
evening or night
evening or night
evening or night
daylight
You could use pyephem for this task. It's a
Python package for performing high-precision astronomy computations.
You could set the desired location and get the sun altitude. There are multiple definitions for night, depending if it's for civil (-6°), nautical (-12°) or astronomical (-18°) purposes. Just pick a treshold : if the sun is below, it's nighttime!
#encoding: utf8
import ephem
import math
import datetime
sun = ephem.Sun()
observer = ephem.Observer()
# ↓ Define your coordinates here ↓
observer.lat, observer.lon, observer.elevation = '48.730302', '9.149483', 400
# ↓ Set the time (UTC) here ↓
observer.date = datetime.datetime.utcnow()
sun.compute(observer)
current_sun_alt = sun.alt
print(current_sun_alt*180/math.pi)
# -16.8798870431°
As a workaround, there is a free api for adhan times for muslims. It includes sunset and sunrise times exactly. However you still need location coordinates to obtain the data. It is free at the moment.
Unfortunately python's timestamp cannot determine whether it's day or night. This is also because it depends on where you are located and how exactly you define day and night. I'm afraid you will have to get auxiliary data for that.
You need to know both latitude and longitude. In fact, if a place is in a deep valley the sunrise there will be later and the sunset earlier. You can pay for this service if you need to obtain it many times per day or simply scrape pages like the one at https://www.timeanddate.com/worldclock/uk/london.

Categories