Calculate amount between a range of dates - python

So i have this problem, I want to calculate an amount of money between the first and last day of the month.
Example:
I am going to receive a payment of $1000 for a job that is going to take 3 months but i want to subtract the amount I'm going to receive each month lets say I work 8 a day 5 days a week.
def get_montly_adjustments(self, start_date, end_date, project_id):
# calculating the month first day and last day
month_range = monthrange(year, month)
first_day_month_str = "%s-%s-01" % (year, month)
last_day_month_str = "%s-%s-01" % (year, month, month_range[1])
month_first_day = datetime.strptime(first_day_month_str, "%Y-%m-%d")
month_last_day = datetime.strptime(last_day_month_str, "%Y-%m-%d")
I have created a function to calculate the first and last day of the month but im looking for an idea on how to calculate the amount?
Thanks!.

First, let's not convert a date to string and parse it back. We can do better:
def get_montly_adjustments(self, start_date, end_date, project_id):
first_of_month = date(start_date.year, start_date.month, 1)
last_of_month = date(start_date.year, start_date.month + 1, 1) + timedelta(-1)
Assuming that workdays are Monday through Friday, I get
day = first_of_month
workdays = 0
while day <= last_of_month:
if day.weekday() not in [5, 6]: # Saturday, Sunday
workdays += 1
day += timedelta(1)
print(f"workdays: {workdays}")
It's not clear to me how you expect to be paid. This probably depends on country and law regulations. One approach would be as follows
Starting on 2021-06-09, work until 2021-09-08 (3 months) gives 4 payments:
9 to 30 in June = 22 days (= x workdays)
1 to 31 in July = 31 days (= x workdays)
1 to 31 in August = 31 days (= x workdays)
1 to 8 in September = 8 days (= x workdays)
Code for that:
def get_montly_adjustments(self, start_date, end_date, project_id):
# Calculate all workdays in project range
day = start_date
last_of_month = date(day.year, day.month + 1, 1) + timedelta(-1)
workdays = 0
workdayspermonth = []
while day <= end_date:
if day.weekday() not in [5, 6]:
workdays += 1
if day == last_of_month or day == end_date:
workdayspermonth.append(workdays)
workdays = 0
last_of_month = date(day.year, day.month + 2, 1) + timedelta(-1) # next last of month
day += timedelta(1)
# Get to the money
monthnames = {1: "Jan", 2: "Feb", 3: "Mar", 4: "Apr", 5: "May", 6: "Jun", 7: "Jul", 8: "Aug", 9: "Sep", 10: "Oct",
11: "Nov", 12: "Dec"}
totalworkdays = sum(workdayspermonth)
print(f"Total workdays: {totalworkdays}")
moneyperday = 1000 / totalworkdays
print(f"That's an awesome {moneyperday:.2f} USD per day")
for month in range(len(workdayspermonth)):
workdays = workdayspermonth[month]
print(f"Get paid! {workdays * moneyperday:.2f} USD for {workdays} workdays in {monthnames[start_date.month + month]}")
Output for
get_montly_adjustments(None, date(2021, 6, 9), date(2021, 9, 9), 815)
is
Total workdays: 67
That's an awesome 14.93 USD per day
Get paid! 238.81 USD for 16 workdays in Jun
Get paid! 328.36 USD for 22 workdays in Jul
Get paid! 328.36 USD for 22 workdays in Aug
Get paid! 104.48 USD for 7 workdays in Sep

I'm going to use pandas date range but perhaps someone can modify it for datetime.
create the days in the month range:
days = pd.date_range("01/01/2021", "03/01/2021", freq="D")
state what days you work:
working_days = ["Mon", "Tue", "Wed", "Thu", "Fri"]
Find the days in the month you would work in that time:
worked_days = days[days.strftime('%a').isin(days_worked)]
multiply the number of days worked by your price per day:
cost = len(worked_days)*8*price_per_hour
You may need to take into account bank holidays, days off etc.

Related

How can i find all 'friday the 13th' due year 2000 to 2020 by python

How can i find all 'friday the 13th' due year 2000 to 2020 by python and have it print as below using a nested for loop:
print(i,k,13,"is friday the 13th!")
ex)
2000 10 13 is friday the 13th!
2001 4 13 is friday the 13th!
...
2020 11 13 is friday the 13th!
Based on your code in the comments, this should work for you:
from datetime import date, timedelta
def friday_13_in_year(y):
day = date(y, 1, 1)
end = date(y, 12, 31)
one_day = timedelta(days=1)
while day < end:
if day.weekday() == 4 and day.day == 13:
return str(day)+" is friday the 13th!"
day += one_day
print([friday_13_in_year(y) for y in range(2000, 2022+1)])
l=[i for i in ((datetime.datetime.strptime('20000101','%Y%m%d')+datetime.timedelta(days=i)) for i in range(7306)) if i.day == 13 and i.weekday() == 4]
l lists all Fridays 13th from 2000 to 2020. 20 years in days is 20*365.25+1 = 7306

Get last friday of each month in python

I want last friday of each month for upcoming three months.
Friday_date = datetime.date.today()
while Friday_date.weekday() != 4:
Friday_date += datetime.timedelta(1)
This gives me the nearest friday. I want to make sure this is the last friday of this month so that i can add 28 days to get next friday.
The easiest way to do this is to use the module dateutil:
>>> from dateutil.relativedelta import FR, relativedelta
>>> datetime.date.today()+relativedelta(day=31, weekday=FR(-1))
datetime.date(2021, 6, 25)
Don't assume you can get the last Friday of subsequent months just by adding 28 days. It won't always work. Adding 28 days to the last Friday of February 2024 gives you this:
>>> datetime.date(2024,2,1)+relativedelta(day=31, weekday=FR(-1), days=28)
datetime.date(2024, 3, 22)
but the last Friday of that month is 29 March. Let dateutil do that correctly for you:
>>> datetime.date(2024,2,1)+relativedelta(day=31, weekday=FR(-1), months=1)
datetime.date(2024, 3, 29)
If needed with standard library only, here is with calendar and datetime:
import calendar
from datetime import date
today = date.today()
year, month = today.year, today.month
n_months = 4
friday = calendar.FRIDAY
for _ in range(n_months):
# get last friday
c = calendar.monthcalendar(year, month)
day_number = c[-1][friday] or c[-2][friday]
# display the found date
print(date(year, month, day_number))
# refine year and month
if month < 12:
month += 1
else:
month = 1
year += 1
where the line c[-1][friday] or c[-2][friday] first checks the last week of the month: is Friday nonzero there? if so take it, else look at the week before where there must be a Friday.
This prints
2021-06-25
2021-07-30
2021-08-27
2021-09-24
This formula gets you the day of the last Friday of any given month:
import calendar
year = 2021
month = 6
last_day = calendar.monthrange(year, month)[1]
last_weekday = calendar.weekday(year, month, last_day)
last_friday = last_day - ((7 - (4 - last_weekday)) % 7)
# ^ ^
# | Friday
# days in a week
This is my first coffee, so this can probably be condensed a bit, but it illustrates the logic. last_day is the last calendar day (30 for June), last_weekday is what weekday it is (2 for Wednesday), and based on that we simply calculate how many days to subtract to land on the last Friday (25).
If you want to know the last friday you can do this :
from datetime import date
from datetime import timedelta
today = date.today()
offset = (today.weekday() - 4) % 7
last_wednesday = today - timedelta(days=offset)

python nested while loops and datetime

I'm teaching myself python to ATBS. Instead of spending 45 minutes typing out a bunch of repetitive data in excel I've spent the past 90 failing to write a simple calendar script.
Starting with the values "2012-09-01" and "2012-09-30" I want to each line to increase the month value by 1 it hits 12 and at which point the year value advances by 1, until the date 2018-12-31.
e.g.
"2012-09-01 2012-09-30
2012-10-01 2012-10-31
2012-11-01 2012-11-30
2012-12-01 2012-12-31"
Here's my code, which stops at 2012-12-31.
import datetime
year = 2012
month = 9
day_start = 1
day_end = 31
while year <= 2018:
while month <= 12:
if month == 4 or month == 6 or month == 9 or month == 11:
day_end = 30
else:
day_end = 31
print(datetime.date(year, month, day_start), " ", datetime.date(year, month, day_end))
month = month + 1
year = year + 1
Any help is much appreciated!
Check this out. Using the calendar library to detect leap years.
import datetime
import calendar
year = 2012
month = 9
day_start = 1
day_end = 31
while year <= 2018:
while month <= 12:
if month == 4 or month == 6 or month == 9 or month == 11:
day_end = 30
elif month == 2:
day_end = 29 if calendar.isleap(year) else 28
else:
day_end = 31
print(datetime.date(year, month, day_start), " ", datetime.date(year, month, day_end))
month = month + 1
year = year + 1
month = 1
Line
if month == 4 or month == 6 or month == 9 or month == 11:
can be abbreviated to:
if month in (4, 6, 9, 11):

Print specific date in python

I want to create a function that will return a date depending on each month. More specific I want it to return to me the 23d day of each month in the example format (YYYY, MM, DD):
2018, 1, 23 .
except for the occasion that this date coincides with a weekend, in which I want it to return the exact previous working day. For example for December 2017 the 23d was Saturday, so in this case I want my function to return to me
2017, 12, 22.
Right now I use:
import datetime
someday = datetime.date(2018, 1, 23)
print(someday)
with which in the someday variable I define the desired date manually for each month.
In short for the next seven months of 2018 (January, February, March, April, May, June, July), I want my function to return to me :
2018, 1, 23
2018, 2, 23
2018, 3, 23
2018, 4, 23
2018, 5, 23
2018, 6, 22
2018, 7, 23
and so on and so forth for the next months.
You can achieve this with weekday(), timedelta() and while loop:
from datetime import date, timedelta
def last_workday(somedate):
while somedate.weekday() > 4: #weekday returns values 0-6 (Mon-Sun)
somedate -= timedelta(days=1) #timedelta returns 1 day which you subtract from your date
return somedate
y = 2018
d = 23
for m in range(1,13):
print(last_workday(date(y, m, d)))
I wrote a small python script on how you could do it.
Use toordinal to check for the day of the week and if it's Saturday or Sunday, subtract 1 or 2 by using timedelta
import datetime
# Yes, from 1,13 because 13 is exclusive (Goes only to 12)
days_month = datetime.monthrange(2018,x)
for x in range(days_month[0],days_month[1]+1):
for x in range(1, monthrange):
someday = datetime.date(2018, x, 23) # Loop over every month
weekday = someday.weekday() # 0 = Monday, 6 = Sunday
if(weekday > 5 ): # If it's "more" than Friday
jumpback_days = weekday - 4; # Subtract 4 from the current weekday to get 1 for Saturday and 2 for Sunday
print(someday - datetime.timedelta(days=jumpback_days)) # Subtract days and print
else:
# Print without subtracting anything
print(someday)
Note: If you are using Python2, please replace range with xrange for it to work.
EDIT: If you want to print only and all workdays in a specific year, you can do it this way:
import datetime
from calendar import monthrange
year = 2018
for month in range(1, 13): # Yes, from 1,13 because 13 is exclusive (Goes only to 12)
days_month = monthrange(year, month) # Request the amount of days in that month
for day in range(1, days_month[1] + 1): # Iterate through all days of that month (+1 because it's exclusive)
someday = datetime.date(year, month, day) # Loop over every month
weekday = someday.weekday() # 0 = Monday, 6 = Sunday
if(weekday < 5 ): # If it's "less" than Saturday
# Print because if it's "less" than Saturday, then it's a workday
print(someday)

How to Calculate the number of days in the year(s) between 2 dates in python

For example:
date 1 : 1 january 2000
date 2 : 17 november 2006
I want to know how many days there are between date 1 and date 2 in the year 2000, 2001, ..., 2006
so I need something that returns something like this (doesn't matter if it's in a list or something):
2000: 365, 2001: 365, ..., 2006: 320
I've looked for something like this on the internet but that only turned up ways to calculate the number of days/months/years between 2 dates
hm, try something like this:
import datetime, calendar
date1 = datetime.date(year1, month1, day1) # month and day are 1-base
date2 = datetime.date(year2, month2, day2)
days_in_first_year = (datetime.date(year1,12,31)-date1).days
days_in_last_year = (date2 - datetime.date(year2, 1, 1)).days
if year1 != year2:
n_days_list = [days_in_first_year]
for year in range(year1+1, year2): n_days_list.append(365 + (1*calendar.isleap(year)))
n_days_list.append(days_in_last_year)
else: n_days_list = [days_in_first_year + days_in_last_year]
haven't tested this, might be some off-by-one errors; make sure it does what you expect.
edit: correct the boundaries of the range() call, correctly handle year1 == year2
>>> start_date = datetime.datetime(2006, 7, 3)
>>> end_date = datetime.datetime(2012, 12, 21)
>>> years = range(start_date.year, end_date.year + 1)
>>> start, end = start_date, end_date + datetime.timedelta(1)
>>> for year in years:
... year_start = datetime.datetime(year, 1, 1, 0, 0)
... year_end = datetime.datetime(year + 1, 1, 1, 0, 0)
... print(year, min(end, year_end) - max(start, year_start))
...
2006 182 days, 0:00:00
2007 365 days, 0:00:00
2008 366 days, 0:00:00
2009 365 days, 0:00:00
2010 365 days, 0:00:00
2011 365 days, 0:00:00
2012 356 days, 0:00:00
UPDATE: You should probably add a datetime.timedelta(1) to the end date, because otherwise you'd be off with one day at the end. Fixed. But that depends on whether you want to include it or exclude it.
from datetime import date
DATE_END = date(2006, 11, 17)
def get_days(date_start):
return (DATE_END - date_start).days
starting_dates = [
date(2000, 1, 1),
date(2001, 1, 1),
date(2002, 1, 1),
]
print map(get_days, starting_dates)
Use this pseudocode to see if a year is a leap-year or not
if year modulo 400 is 0
then is_leap_year
else if year modulo 100 is 0
then not_leap_year
else if year modulo 4 is 0
then is_leap_year
else
not_leap_year
to create a list of all leap-years and the years that's not.
You can have something simply by doing this:
>>> from datetime import datetime
>>> d1 = datetime.strptime("30 Nov 00", "%d %b %y")
>>> (datetime.now() - d1).days
3907
two parts: build the date ranges as tuples with a start and end date, build a dictionary whose key is the year and the values are the days. I don't need to account for leap year in the calculation because that is automatic in the range calculation
date_ranges=[]
def buildDateRanges(start_year,start_month,start_day, end_year,end_month,end_day):
start_date=datetime.datetime(start_year,start_month,start_day)
end_date=datetime.datetime(end_year,end_month,end_day)
start_year=start_date.year
end_year=end_date.year
date_ranges=[]
if start_year != end_year:
for year in range(start_year,end_year+1):
if year==start_year:
date_ranges.append((start_date,datetime.datetime(start_date.year,12,31)))
elif year==end_year:
date_ranges.append((datetime.datetime(start_year+1,1,1),end_date))
else:
date_ranges.append((start_date,end_date))
return date_ranges
date_ranges=buildDateRanges(2006, 7, 3,2012,12,21)
def years_days(days):
years = days // 365
days = days % 365
return years, days
results={}
for i in range(len(date_ranges)):
start_date=date_ranges[i][0]
end_date=date_ranges[i][1]
days=(end_date-start_date).days
years,days=years_days(days)
year=start_date.year
print(years,days)
while True:
if year==end_date.year:
results[year]=days
else:
results[year]=365
year+=1
if year>end_date.year:
break
print(results)
output:
{2006: 181, 2007: 365.0, 2008: 365.0, 2009: 365.0, 2010: 365.0, 2011: 365.0, 2012: 356.0}
Convert both days into seconds since the epoch (ie. 1 Jan 1970 Midnight)
Subtract.
The do the division to convert seconds into days for the difference.

Categories

Resources