Calculate days between dates with unique days in months in python - python

from datetime import datetime
x = input("first date: ")
y = input("second date: ")
a = datetime.strptime(x, "%Y/%m/%d")
b = datetime.strptime(y, "%Y/%m/%d")
result = (a-b).days
print("days: ",result)
# my first date is = 2021/2/8
# my second date is = 2021/1/24
# output = days : 15
So as you see everything is fine in this code But my teacher make a challenge for me . He said can you write a code with unusual days in months . For ex : January have 31 days but I want it to be 41 days and etc .
What should I do now ? (Please don't say : sum the output with 10 because the user inputs could be changeable and I should change all of the days in months so this will not work)
I am amatuar in coding so simple explanation would be better.
So I am looking for something like this :
# if January have 41 days instead of 31 days
# my first date is = 2021/2/8
# my second date is = 2021/1/24
# output will be = days : 15 + 10 = 25

You can make dictionary consisting of months and their custom days (For example, '1': 41 means first month consisting of 41 days). Then all you need to do is to add input date of the first month with the subtraction of total days of current month and days of input date. (Assuming first date is always greater than the second).
months = {
'1': 41,
'2': 38,
'3': 24,
...
...
'12': 45,
}
x = input("first date: ")
y = input("second date: ")
a = list(x.split('/'))
b = list(y.split('/'))
# 2021/2/8
# ['2021', '2', '8']
result = int(a[2]) + (months[b[1]] - int(b[2]))
print(result)

I think you're close the answer.
you don't want to 'sum the output with 10', but why not?
the answer to the problem is 'result + extra_days' (so sum of output + offset).
So instead of the '10' you want the offset, the offset is maxDayOfMonth +/- requestedDate
Here is a related post which gives a function to get the last day of any month:
def last_day_of_month(any_day):
# this will never fail
# get close to the end of the month for any day, and add 4 days 'over'
next_month = any_day.replace(day=28) + datetime.timedelta(days=4)
# subtract the number of remaining 'overage' days to get last day of current month, or said programattically said, the previous day of the first of next month
return next_month - datetime.timedelta(days=next_month.day)
It always helps to find a scenario for your problem, for example:
Your teacher discoverd an alternate universe where the days in a month are variable, and he wants to use the datetime library to work. :)

Related

Datetime usage in Python for finance related task

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
'''

Python: How do you scrape daily data from dynamic web using Python?

The following code works but stops after 29th of Feb. The website returns "you have entered an invalid date. Please re-enter your search", which necessitate clicking on "OK". How do I get around this?
country_search("United States")
time.sleep(2)
date_select = Select(driver.find_element_by_name("dr"))
date_select.select_by_visible_text("Enter date range...") #All Dates
select_economic_news()
#btnModifySearch
for month in range(1,9):
for day in range(1,32):
try:
set_from_month(month)
set_from_date(day)
set_from_year("2020")
set_to_month(month)
set_to_date(day)
set_to_year("2020")
time.sleep(5)
#select_economic_news()
time.sleep(5)
search_now()
time.sleep(8)
export_csv()
modify_search()
time.sleep(5)
#country_remove()
except ElementClickInterceptedException:
break
logout()
If you can only use the methods featured in the initial post then I would try something like:
set_from_year('2020')
set_to_year('2020')
for month in range(1, 9):
# 1 to 9 for Jan to Aug
month_str = '0' + str(month)
set_from_month(month_str)
set_to_month(month_str)
for day in range(1, 32):
# Assuming an error is thrown for invalid days
try:
# Store data as needed
except Exception as e:
# print(e) to learn from error if needed
pass
There is a lot more that goes into this if it turns out that you're writing these methods yourself and need to loop through HTML and find a pattern for daily data.
I believe you want to dynamically obtain the number of days in a month, so that you can loop over that number to get data for each date. You can do this as follows:
from datetime import datetime
currentDay = datetime.today()
# You can set the currentDay using this if you want the data till the current date or
# whenever your scheduler runs the job.
# Now you need to get the number of days in each month from the chosen date, you can
# have the corresponding function like getStartMonth() in your program which will
# return the starting month.
from calendar import monthrange
daysPerMonth = {}
year = currentDay.year #TODO : change this to getStartYear()
startMonth = 3 # TODO : Implement getStartMonth() in your code.
for month in range(startMonth, currentDay.month+1):
# monthrange returns (weekday,number of days in that month)
daysPerMonth[month] = monthrange(year, month)[1]
for month in daysPerMonth.items():
print(month[0], '-',month[1])
This will output something like this(Number of days in a month from - March 2020 till August 2020):
3 - 31
4 - 30
5 - 31
6 - 30
7 - 31
8 - 31
And then you can run a loop for number of days while referring the range from the dict that you've obtained.
NOTE : In the function where you're running the loop to get data for each date add one if condition to check if it's the last day of the year and modify the year accordingly.
Maybe You can use these function to get count days of month:
import datetime
def get_month_days_count(year: int, month: int) -> int:
date = datetime.datetime(year, month, 1)
while (date + datetime.timedelta(days=1)).month == month:
date = date + datetime.timedelta(days=1)
return date.day

Finding Month from Day, Week and Year Python

I can not figure out how to take the year, day and week to return the month. Right now I am just trying to develop a Python Script that will do this. The goal after finishing this script is to use it for a Spark SQL Query to find the month since in my data I am given a day, year and week in each row.
As of now my python code looks like so. This code only works for the statement I have into the print(getmonth(2, 30 ,2018) returning 7. I have tried other dates and the output is only "None". I have tried variables also, but no success there.
import datetime
def month(day, week, year):
for month in range(1,13):
try:
date = datetime.datetime(year, month, day)
except ValueError:
iso_year, iso_weeknum, iso_weekday = date.isocalendar()
if iso_weeknum == week:
return date.month
print(getmonth(2, 30, 2018))
#iso_(year,weeknum,weekday) are the classes for ISO. Year is 1-9999, weeknum is 0-52 or 53, and weekday is 0-6
#isocaldenar is a tuple (year, week#, weekday)
I don't really understand your questions, but i think datetime will work... sorce: Get date from ISO week number in Python:
>>> from datetime import datetime
>>> day = 28
>>> week = 30
>>> year = 2018
>>> t = datetime.strptime('{}_{}_{}{}'.format(day,week,year,-0), '%d_%W_%Y%w')
>>> t.strftime('%W')
'30'
>>> t.strftime('%m')
'07'
>>>
A simpler solution can be created using the pendulum library. As in your code, loop through month numbers, create dates, compare the weeks for these dates against the desired date. If found halt the loop; if the date is not seen then exit the loop with, say, a -1.
>>> import pendulum
>>> for month in range(1,13):
... date = pendulum.create(2018, month, 28)
... if date.week_of_year == 30:
... break
... else:
... month = -1
...
>>> month
7
>>> date
<Pendulum [2018-07-28T00:00:00+00:00]>
Here is a brute force method that loops through the days of the year (It expects the day as Monday being 0 and Sunday being 6, it also returns the Month 0 indexed, January being 0 and December being 11):
import datetime
def month(day, week, year):
#Generate list of No of days of the month
months = [31,28,31,30,31,30,31,31,30,31,30,31]
if((year % 4 == 0 and year % 100 != 0) or year % 400 == 0): months[1] += 1
#ISO wk1 of the yr is the first wk with a thursday, otherwise it's wk53 of the previous yr
currentWeek = 1 if day < 4 else 0
#The day that the chosen year started on
currentDay = datetime.datetime(year, 1, 1).weekday()
#Loop over every day of the year
for i in range(sum(months)):
#If the week is correct and day is correct you're done
if day == currentDay and week == currentWeek:
return months.index(next(filter(lambda x: x!=0, months)))
#Otherwise, go to next day of wk/next wk of yr
currentDay = (currentDay + 1) % 7
if currentDay == 0:
currentWeek += 1
#And decrement counter for current month
months[months.index(next(filter(lambda x: x!=0, months)))]-=1
print(month(2, 30, 2018)) # 6 i.e. July
months.index(next(filter(lambda x: x!=0, months))) is used to get the first month of that we haven't used all of the days of, i.e. the month you're currently in.

Algorithm for getting current week number after changing the starting day of the week in python?

I want to design an algorithm which will calculate the week number according to the start week day set. for eg : - If I set the start day as WEDNESDAY and currently its 40 week and its TUESDAY, it should print 40 as the week number. If it is WEDNESDAY or THURSDAY, I should get 41.
Think of it like a cycle. From Wednesday till tuesday, it should be assigned a week no + 1, then when next wednesday comes, week should be incremented again.
I tried using calendar.setfirstweekday(calendar.WEDNESDAY) and then altering my system machine time, all I get is 40 as the week number everytime.
How do I design such as algorithm in python?
I have a similar problem for month, but I have designed a solution for it. Here is it.
current_date = datetime.datetime.now()
if current_date.day < gv.month_start_date:
month = current_date.month -1
if month == 0:
month = 12
else:
month = current_date.month
How can I design it for week?
I finally designed a solution for this.
if current_day >= set_week_day:
week = current_week
else:
week = current_week - 1
Works for all cases.
datetime in python has a function called isocalender to get the ISO week number (starts on Monday)
import datetime
datetime.date(2013, 9, 30).isocalendar()[1]
You can use this with a little bit of logic (this script should have the week begin on Wednesdays)
import datetime
day = 30
month = 9
year = 2013
weekcount = datetime.date(year, month, day).isocalendar()[1]
if datetime.date(year, month, day).isocalendar()[2] <= 3: # start on wednesday
weekcount -= 1
print weekcount

How to calculate number of days between two given dates

If I have two dates (ex. '8/18/2008' and '9/26/2008'), what is the best way to get the number of days between these two dates?
If you have two date objects, you can just subtract them, which computes a timedelta object.
from datetime import date
d0 = date(2008, 8, 18)
d1 = date(2008, 9, 26)
delta = d1 - d0
print(delta.days)
The relevant section of the docs:
https://docs.python.org/library/datetime.html.
See this answer for another example.
Using the power of datetime:
from datetime import datetime
date_format = "%m/%d/%Y"
a = datetime.strptime('8/18/2008', date_format)
b = datetime.strptime('9/26/2008', date_format)
delta = b - a
print delta.days # that's it
Days until Christmas:
>>> import datetime
>>> today = datetime.date.today()
>>> someday = datetime.date(2008, 12, 25)
>>> diff = someday - today
>>> diff.days
86
More arithmetic here.
everyone has answered excellently using the date,
let me try to answer it using pandas
dt = pd.to_datetime('2008/08/18', format='%Y/%m/%d')
dt1 = pd.to_datetime('2008/09/26', format='%Y/%m/%d')
(dt1-dt).days
This will give the answer.
In case one of the input is dataframe column. simply use dt.days in place of days
(dt1-dt).dt.days
You want the datetime module.
>>> from datetime import datetime
>>> datetime(2008,08,18) - datetime(2008,09,26)
datetime.timedelta(4)
Another example:
>>> import datetime
>>> today = datetime.date.today()
>>> print(today)
2008-09-01
>>> last_year = datetime.date(2007, 9, 1)
>>> print(today - last_year)
366 days, 0:00:00
As pointed out here
from datetime import datetime
start_date = datetime.strptime('8/18/2008', "%m/%d/%Y")
end_date = datetime.strptime('9/26/2008', "%m/%d/%Y")
print abs((end_date-start_date).days)
It also can be easily done with arrow:
import arrow
a = arrow.get('2017-05-09')
b = arrow.get('2017-05-11')
delta = (b-a)
print delta.days
For reference: http://arrow.readthedocs.io/en/latest/
without using Lib just pure code:
#Calculate the Days between Two Date
daysOfMonths = [ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
def isLeapYear(year):
# Pseudo code for this algorithm is found at
# http://en.wikipedia.org/wiki/Leap_year#Algorithm
## if (year is not divisible by 4) then (it is a common Year)
#else if (year is not divisable by 100) then (ut us a leap year)
#else if (year is not disible by 400) then (it is a common year)
#else(it is aleap year)
return (year % 4 == 0 and year % 100 != 0) or year % 400 == 0
def Count_Days(year1, month1, day1):
if month1 ==2:
if isLeapYear(year1):
if day1 < daysOfMonths[month1-1]+1:
return year1, month1, day1+1
else:
if month1 ==12:
return year1+1,1,1
else:
return year1, month1 +1 , 1
else:
if day1 < daysOfMonths[month1-1]:
return year1, month1, day1+1
else:
if month1 ==12:
return year1+1,1,1
else:
return year1, month1 +1 , 1
else:
if day1 < daysOfMonths[month1-1]:
return year1, month1, day1+1
else:
if month1 ==12:
return year1+1,1,1
else:
return year1, month1 +1 , 1
def daysBetweenDates(y1, m1, d1, y2, m2, d2,end_day):
if y1 > y2:
m1,m2 = m2,m1
y1,y2 = y2,y1
d1,d2 = d2,d1
days=0
while(not(m1==m2 and y1==y2 and d1==d2)):
y1,m1,d1 = Count_Days(y1,m1,d1)
days+=1
if end_day:
days+=1
return days
# Test Case
def test():
test_cases = [((2012,1,1,2012,2,28,False), 58),
((2012,1,1,2012,3,1,False), 60),
((2011,6,30,2012,6,30,False), 366),
((2011,1,1,2012,8,8,False), 585 ),
((1994,5,15,2019,8,31,False), 9239),
((1999,3,24,2018,2,4,False), 6892),
((1999,6,24,2018,8,4,False),6981),
((1995,5,24,2018,12,15,False),8606),
((1994,8,24,2019,12,15,True),9245),
((2019,12,15,1994,8,24,True),9245),
((2019,5,15,1994,10,24,True),8970),
((1994,11,24,2019,8,15,True),9031)]
for (args, answer) in test_cases:
result = daysBetweenDates(*args)
if result != answer:
print "Test with data:", args, "failed"
else:
print "Test case passed!"
test()
For calculating dates and times, there are several options but I will write the simple way:
from datetime import timedelta, datetime, date
import dateutil.relativedelta
# current time
date_and_time = datetime.now()
date_only = date.today()
time_only = datetime.now().time()
# calculate date and time
result = date_and_time - timedelta(hours=26, minutes=25, seconds=10)
# calculate dates: years (-/+)
result = date_only - dateutil.relativedelta.relativedelta(years=10)
# months
result = date_only - dateutil.relativedelta.relativedelta(months=10)
# week
results = date_only - dateutil.relativedelta.relativedelta(weeks=1)
# days
result = date_only - dateutil.relativedelta.relativedelta(days=10)
# calculate time
result = date_and_time - timedelta(hours=26, minutes=25, seconds=10)
result.time()
Hope it helps
There is also a datetime.toordinal() method that was not mentioned yet:
import datetime
print(datetime.date(2008,9,26).toordinal() - datetime.date(2008,8,18).toordinal()) # 39
https://docs.python.org/3/library/datetime.html#datetime.date.toordinal
date.toordinal()
Return the proleptic Gregorian ordinal of the date, where January 1 of year 1 has ordinal 1. For any date object d,
date.fromordinal(d.toordinal()) == d.
Seems well suited for calculating days difference, though not as readable as timedelta.days.
from datetime import date
def d(s):
[month, day, year] = map(int, s.split('/'))
return date(year, month, day)
def days(start, end):
return (d(end) - d(start)).days
print days('8/18/2008', '9/26/2008')
This assumes, of course, that you've already verified that your dates are in the format r'\d+/\d+/\d+'.
Here are three ways to go with this problem :
from datetime import datetime
Now = datetime.now()
StartDate = datetime.strptime(str(Now.year) +'-01-01', '%Y-%m-%d')
NumberOfDays = (Now - StartDate)
print(NumberOfDays.days) # Starts at 0
print(datetime.now().timetuple().tm_yday) # Starts at 1
print(Now.strftime('%j')) # Starts at 1
If you want to code the calculation yourself, then here is a function that will return the ordinal for a given year, month and day:
def ordinal(year, month, day):
return ((year-1)*365 + (year-1)//4 - (year-1)//100 + (year-1)//400
+ [ 0,31,59,90,120,151,181,212,243,273,304,334][month - 1]
+ day
+ int(((year%4==0 and year%100!=0) or year%400==0) and month > 2))
This function is compatible with the date.toordinal method in the datetime module.
You can get the number of days of difference between two dates as follows:
print(ordinal(2021, 5, 10) - ordinal(2001, 9, 11))
Without using datetime object in python.
# A date has day 'd', month 'm' and year 'y'
class Date:
def __init__(self, d, m, y):
self.d = d
self.m = m
self.y = y
# To store number of days in all months from
# January to Dec.
monthDays = [31, 28, 31, 30, 31, 30,
31, 31, 30, 31, 30, 31 ]
# This function counts number of leap years
# before the given date
def countLeapYears(d):
years = d.y
# Check if the current year needs to be considered
# for the count of leap years or not
if (d.m <= 2) :
years-= 1
# An year is a leap year if it is a multiple of 4,
# multiple of 400 and not a multiple of 100.
return int(years / 4 - years / 100 + years / 400 )
# This function returns number of days between two
# given dates
def getDifference(dt1, dt2) :
# COUNT TOTAL NUMBER OF DAYS BEFORE FIRST DATE 'dt1'
# initialize count using years and day
n1 = dt1.y * 365 + dt1.d
# Add days for months in given date
for i in range(0, dt1.m - 1) :
n1 += monthDays[i]
# Since every leap year is of 366 days,
# Add a day for every leap year
n1 += countLeapYears(dt1)
# SIMILARLY, COUNT TOTAL NUMBER OF DAYS BEFORE 'dt2'
n2 = dt2.y * 365 + dt2.d
for i in range(0, dt2.m - 1) :
n2 += monthDays[i]
n2 += countLeapYears(dt2)
# return difference between two counts
return (n2 - n1)
# Driver program
dt1 = Date(31, 12, 2018 )
dt2 = Date(1, 1, 2019 )
print(getDifference(dt1, dt2), "days")
If you don't have a date handling library (or you suspect it has bugs in it), here's an abstract algorithm that should be easily translatable into most languages.
Perform the following calculation on each date, and then simply subtract the two results. All quotients and remainders are positive integers.
Step A. Start by identifying the parts of the date as Y (year), M (month) and D (day). These are variables that will change as we go along.
Step B. Subtract 3 from M
(so that January is -2 and December is 9).
Step C. If M is negative, add 12 to M and subtract 1 from the year Y.
(This changes the "start of the year" to 1 March, with months numbered 0 (March) through 11 (February). The reason to do this is so that the "day number within a year" doesn't change between leap years and ordinary years, and so that the "short" month is at the end of the year, so there's no following month needing special treatment.)
Step D.
Divide M by 5 to get a quotient Q₁ and remainder R₁. Add Q₁ × 153 to D. Use R₁ in the next step.
(There are 153 days in every 5 months starting from 1 March.)
Step E. Divide R₁ by 2 to get a quotient Q₂ and ignore the remainder. Add R₁ × 31 - Q₂ to D.
(Within each group of 5 months, there are 61 days in every 2 months, and within that the first of each pair of months is 31 days. It's safe to ignore the fact that Feb is shorter than 30 days because at this point you only care about the day number of 1-Feb, not of 1-Mar the following year.)
Steps D & E combined - alternative method
Before the first use, set L=[0,31,61,92,122,153,184,214,245,275,306,337]
(This is a tabulation of the cumulative number of days in the (adjusted) year before the first day of each month.)
Add L[M] to D.
Step F
Skip this step if you use Julian calendar dates rather than Gregorian calendar dates; the change-over varies between countries, but is taken as 3 Sep 1752 in most English-speaking countries, and 4 Oct 1582 in most of Europe.
You can also skip this step if you're certain that you'll never have to deal with dates outside the range 1-Mar-1900 to 28-Feb-2100, but then you must make the same choice for all dates that you process.
Divide Y by 100 to get a quotient Q₃ and remainder R₃. Divide Q₃ by 4 to get another quotient Q₄ and ignore the remainder. Add Q₄ + 36524 × Q₃ to D.
Assign R₃ to Y.
Step G.
Divide the Y by 4 to get a quotient Q₅ and ignore the remainder. Add Q₅ + 365 × Y to D.
Step H. (Optional)
You can add a constant of your choosing to D, to force a particular date to have a particular day-number.
Do the steps A~G for each date, getting D₁ and D₂.
Step I.
Subtract D₁ from D₂ to get the number of days by which D₂ is after D₁.
Lastly, a comment: exercise extreme caution dealing with dates prior to about 1760, as there was not agreement on which month was the start of the year; many places counted 1 March as the new year.

Categories

Resources