This question already has answers here:
Best way to find the months between two dates
(41 answers)
Closed 8 years ago.
In my django app, I have some date.
I need to count how many months left to this date, using full (rounded) months.
eg: today is 19/02/2015 (february), my "search" date is 04/08/2015. Difference should be 6.
How can I get a proper value?
from datetime import datetime,timedelta
from calendar import monthrange
today = datetime.today()
dt = "04/08/2015"
fut = datetime.strptime(dt, "%d/%m/%Y")
diff = 0
while today <= fut:
today += timedelta(days=monthrange(today.day,today.month)[1])
diff += 1
print(diff)
6
Without importing calender we can increment a count everytime we see a new month:
from datetime import datetime,timedelta
today = datetime.today()
dt = "09/08/2015"
fut = datetime.strptime(dt, "%d/%m/%Y")
diff = 0
while today <= fut:
mon = today.month
today += timedelta(days=1)
if today.month != mon:
diff += 1
print(diff)
6
If you want to make the future day the last day of the month:
from datetime import datetime, timedelta
from calendar import monthrange
today = datetime.today()
dt = "02/08/2015"
fut = datetime.strptime(dt, "%d/%m/%Y")
fut = fut + timedelta(days=monthrange(fut.day,fut.month)[1]-fut.day)
diff = 0
while today < fut:
mon = today.month
today += timedelta(days=1)
if today.month != mon:
diff += 1
print(diff)
This is purposely inaccurate to allow for rounding as required, all we care about are the amount of different months we encounter.
I like the arrow library: http://crsmithdev.com/arrow/
eg.
d1 = arrow.get("19/02/2015", "DD/MM/YYYY")
d2 = arrow.get("04/08/2015", "DD/MM/YYYY")
(d2-d1).days
You are going to have decide how to do your calculation. Divide by 30 or extract the months and subtract those.
d2.month - d1.month
To handle it going over a year:
((d2.year * 100) + d2.month) - ((d1.year * 100) + d1.month)
To calculate the month difference (rounded) I would go this direction:
Get the date objects for the different dates (see datetime package). This is rather easy, since the constructor takes year, month, day
Calculate the difference between the dates "date2 - date1" this automatically gives a timedelta object
Get the difference seconds between the two dates by calling "total_seconds()" on the timedelta object
Dividing the number of seconds by 24*60*60 will give the number of days
Dividing the number of days by 30 or (as you like) 31 will give the number of months. You can round the value as you like.
This should suffice:
d,m,y = date1.split('/')
d1 = datetime.date(y, m, d)
d,m,y = date1.split('/')
d2 = datetime.date(y, m, d)
delta = d2 - d1
days = delta.total_seconds() // (24*60*60)
result = int(days/30.0+0.5)
The nice thing: No additional packages needed, all is in the standard packages.
Related
As an example I want to see what the date would be if it was today - 6 days. However, I only want to count days that are weekdays. So given 8/22 the output should be 8/12 as that is 6 business days only.
Tried using the weekday function to return if it is a 5 or 6 for saturday and sunday and skipping those days but I am not having luck so far
Current code:
from datetime import datetime, timedelta
age = 6
counter = 0
difference = datetime.today() - timedelta(counter)
while counter <= age:
difference = datetime.today() - timedelta(counter)
counter = counter + 1
this code only returns the day with the weekends included as I haven't been able to figure out how to exclude the weekend. I set up the code to loop to check if it is a 5 or 6 using the weekday() function but I keep getting bad results when attempting that
from datetime import date, timedelta
def weekdays_between(startdate,stopdate):
day = startdate
daycount = 0
while day < stopdate :
if day.weekday() < 5 :
daycount += 1
day = day + timedelta(days=1)
return daycount
if __name__ == "__main__" :
day=date.today()
dayn=day + timedelta(days=45)
print(weekdays_between(day,dayn))
You can calculate the actual days difference by calculating the number of weekends past, and subtracting the date by the days difference and the days in weekend to get the result.
from datetime import datetime,timedelta
from math import ceil
def subtract_weekdays (from_date, diff):
no_of_weekends = ceil((diff - from_date.weekday())/5)
result_date = from_date - timedelta(days=diff + no_of_weekends * 2)
return result_date
print(subtract_weekdays(datetime.today(), 6))
I am trying to find the difference between two times and see what it is as a percentage of the year. I am subtracting a future date from today's date. For example, if the future date is two days from now, I would subtract the two dates and compute that the difference is 2. Then I would like to divide it by 365 and obtain the percentage 0.5%
So far, I managed to find the difference between two dates, however when I try to divide I just get a time as the output. Here is my code below and the outputs:
import time
import datetime
from datetime import datetime, timedelta
#Time to Expiration:
expTime = input("What is the date of expiry (yyyy-mm-dd)?: ")
expTime = datetime.strptime(expTime, "%Y-%m-%d")
today = datetime.today()
duration = expTime - today
duration_in_s = duration.total_seconds()
daysRemaining = duration.days
daysRemaining = divmod(duration_in_s, 86400)[0]
daysRemaining = (expTime - today)
#Days remaining as a percentage of the year
t = daysRemaining/365.0
print(t)
Output:
What is the date of expiry (yyyy-mm-dd)?: 2021-09-21
print(t)
6:21:03.861188
print(daysRemaining)
96 days, 14:08:29.333438
Also, if I would just like days remaining, how would I get rid of the timestamp?
Thank you!
ANSWER:
I modified my code based on the comments and answers given to:
#Time to Expiration:
expTime = input("What is the date of expiry (yyyy-mm-dd)?: ")
expTime = datetime.strptime(expTime, "%Y-%m-%d")
today = datetime.today()
daysRemaining = (expTime - today)
print("There are", daysRemaining,"days until expiration.")
#Days remaining as a percentage of the year
daysRemaining = round(((daysRemaining.total_seconds()/86400/365.24)*100),3)
print("This is", daysRemaining, "% of the year.")
this is not the best way but you can make something like this :
import datetime
today = datetime.date.today()
future = datetime.date(2021,6,20)
diff = future - today
diff = diff.days
percentage = diff/365
If I want to add a loop to constrain days as well, what is the easiest way to do it, considering different length of month, leap years etc.
This is the script with years and months:
yearStart = 2010
yearEnd = 2017
monthStart = 1
monthEnd = 12
for year in list(range(yearStart, yearEnd + 1)):
for month in list(range(monthStart, monthEnd + 1)):
startDate = '%04d%02d%02d' % (year, month, 1)
numberOfDays = calendar.monthrange(year, month)[1]
lastDate = '%04d%02d%02d' % (year, month, numberOfDays)
If you want only the days then this code, using the pendulum library, is probably the easiest.
>>> import pendulum
>>> first_date = pendulum.Pendulum(2010, 1, 1)
>>> end_date = pendulum.Pendulum(2018, 1, 1)
>>> for day in pendulum.period(first_date, end_date).range('days'):
... print (day)
... break
...
2010-01-01T00:00:00+00:00
pendulum has many other nice features. For one thing, it's a drop-in replacement for datetime. Therefore, many of the properties and methods that you are familiar with using for that class will also be available to you.
You may want to use datetime in addition to calendar library. I am exactly not sure on requirements. But it appears you want the first date and last date of a given month and year. And, then loop through those dates. The following function will give you the first day and last day of each month. Then, you can loop between those two dates in whichever way you want.
import datetime
import calendar
def get_first_last_day(month, year):
date = datetime.datetime(year=year, month=month, day=1)
first_day = date.replace(day = 1)
last_day = date.replace(day = calendar.monthrange(date.year, date.month)[1])
return first_day, last_day
Adding the logic for looping through 2 dates as well.
d = first_day
delta = datetime.timedelta(days=1)
while d <= last_day:
print d.strftime("%Y-%m-%d")
d += delta
If 17:00:00 today is already passed, then it should be today's date, otherwise - yesterday's.
Today's time I get with:
test = datetime.datetime.now().replace(hour=17,minute=0,second=0,microsecond=0)
But I don't want to have future time. How can I fix it?
You could check if the current time is less than 17:00, if so, substract one day from the generated time object:
test = datetime.datetime.now().replace(hour=17,minute=0,second=0,microsecond=0)
if datetime.datetime.now() < test:
test = test - datetime.timedelta(days=1)
Better use the datetime.time of today directly for comparing the times. Then use datetime.timedelta to do the math:
if datetime.datetime.now().time() > datetime.time(17,0):
# today, as it's after 17 o'clock
test = datetime.date.today()
else:
# yesterday, as it's before 17 o'clock
test = datetime.date.today() - datetime.timedelta(days=1)
set test as today or yesterday depending on the time of day:
from datetime import datetime, date, timedelta
if datetime.now().strftime('%H:%M') > '17:00':
test = date.today()
else:
test = date.today() - timedelta(days=1)
Pythons datetime functions are indeed quite unhandy sometimes. While you can use datetime.timedelta objects for your case, to substract times in days, e.g. upcounting month or years becomes annoying. So in case you sooner or later not only want to add one day, maybe give this function a try:
import datetime
import calendar
def upcount(dt, years=0, months=0, **kwargs):
"""
Python provides no consistent function to add time intervals
with years, months, days, minutes and seconds. Usage example:
upcount(dt, years=1, months=2, days=3, hours=4)
"""
if months:
total_months = dt.month + months
month_years, months = divmod(total_months, 12)
if months == 0:
month_years -= 1
months = 12
years += month_years
else:
months = dt.month
years = dt.year + years
try:
dt = dt.replace(year=years, month=months)
except ValueError:
# 31st march -> 31st april gives this error
max_day = calendar.monthrange(years, months)[1]
dt = dt.replace(year=years, month=months, day=max_day)
if kwargs:
dt += datetime.timedelta(**kwargs)
return dt
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Best way to find the months between two dates (in python)
I would like to know how I can have the exact number of months for this difference:
date1 = datetime.strptime(str('2011-08-15 12:00:00'), '%Y-%m-%d %H:%M:%S')
date2 = datetime.strptime(str('2012-02-15'), '%Y-%m-%d')
date2-date1 results in
datetime.timedelta(183, 43200)
I would like to know the exact number of months, in this case it should return 5 and not 6 (because of the hour)
You could use python-dateutil.
In [4]: from datetime import datetime
In [5]: date1 = datetime.strptime(str('2011-08-15 12:00:00'), '%Y-%m-%d %H:%M:%S')
In [6]: date2 = datetime.strptime(str('2012-02-15'), '%Y-%m-%d')
In [7]: from dateutil import relativedelta
In [8]: r = relativedelta.relativedelta(date1, date2)
In [9]: r
Out[9]: relativedelta(months=-5, days=-30, hours=-12)
Only you know the requirements you must meet, but the fact that there are 183 days and 43200 SI seconds between these two dates highlights an inherent subjectivity in determining how many months that "really" is.
Is a month 30 days, or (365 / 12) days, or ((365 * 4 + 1) / 48) days, or ...?
Is a day always 86400 seconds, or do you count historical leap seconds, or do you predict leap seconds for future dates?
These decisions affect the answer the algorithm you appear to desire will give you for certain input dates that are close to these boundaries.
In my opinion, it is more intuitive to consider months as atomic units of time for this purpose and use this formula: (date2.year - date1.year) * 12 + (date2.month - date1.month)
Using calendar module to find out how many days each month has, you can simply count the months.
from calendar import monthrange
from datetime import datetime, timedelta
def monthdelta(d1, d2):
delta = 0
while True:
mdays = monthrange(d1.year, d1.month)[1]
d1 += timedelta(days=mdays)
if d1 <= d2:
delta += 1
else:
break
return delta
The advantage of doing it this way is that there are few module dependencies and no looping -- the months can be found by straight calculation.
import datetime as dt
def months_between(date1,date2):
if date1>date2:
date1,date2=date2,date1
m1=date1.year*12+date1.month
m2=date2.year*12+date2.month
months=m2-m1
if date1.day>date2.day:
months-=1
elif date1.day==date2.day:
seconds1=date1.hour*3600+date1.minute+date1.second
seconds2=date2.hour*3600+date2.minute+date2.second
if seconds1>seconds2:
months-=1
return months
date1 = dt.datetime.strptime('2011-08-15 12:00:00', '%Y-%m-%d %H:%M:%S')
date2 = dt.datetime.strptime('2012-02-15', '%Y-%m-%d')
print(months_between(date1,date2))
# 5
date1 = dt.datetime.strptime('2011-08-15 12:00:00', '%Y-%m-%d %H:%M:%S')
date2 = dt.datetime.strptime('2012-02-15 11:59:00', '%Y-%m-%d %X')
print(months_between(date1,date2))
# 5
date2 = dt.datetime.strptime('2012-02-15 12:00:00', '%Y-%m-%d %X')
print(months_between(date1,date2))
# 6
date2 = dt.datetime.strptime('2012-02-15 12:00:01', '%Y-%m-%d %X')
print(months_between(date1,date2))
# 6