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
Related
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
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.
I want to know how many years, months, days, hours, minutes and seconds in between '2014-05-06 12:00:56' and '2012-03-06 16:08:22'. The result shall looked like: “the difference is xxx year xxx month xxx days xxx hours xxx minutes”
For example:
import datetime
a = '2014-05-06 12:00:56'
b = '2013-03-06 16:08:22'
start = datetime.datetime.strptime(a, '%Y-%m-%d %H:%M:%S')
ends = datetime.datetime.strptime(b, '%Y-%m-%d %H:%M:%S')
diff = start – ends
if I do:
diff.days
It gives the difference in days.
What else I can do? And how can I achieve the wanted result?
Use a relativedelta from the dateutil package. This will take into account leap years and other quirks.
import datetime
from dateutil.relativedelta import relativedelta
a = '2014-05-06 12:00:56'
b = '2013-03-06 16:08:22'
start = datetime.datetime.strptime(a, '%Y-%m-%d %H:%M:%S')
ends = datetime.datetime.strptime(b, '%Y-%m-%d %H:%M:%S')
diff = relativedelta(start, ends)
>>> print "The difference is %d year %d month %d days %d hours %d minutes" % (diff.years, diff.months, diff.days, diff.hours, diff.minutes)
The difference is 1 year 1 month 29 days 19 hours 52 minutes
You might want to add some logic to print for e.g. "2 years" instead of "2 year".
diff is a timedelta instance.
for python2, see:
https://docs.python.org/2/library/datetime.html#timedelta-objects
for python 3, see:
https://docs.python.org/3/library/datetime.html#timedelta-objects
from docs:
timdelta instance attributes (read-only):
days
seconds
microseconds
timdelta instance methods:
total_seconds()
timdelta class attributes are:
min
max
resolution
You can use the days and seconds instance attributes to calculate what you need.
for example:
import datetime
a = '2014-05-06 12:00:56'
b = '2013-03-06 16:08:22'
start = datetime.datetime.strptime(a, '%Y-%m-%d %H:%M:%S')
ends = datetime.datetime.strptime(b, '%Y-%m-%d %H:%M:%S')
diff = start - ends
hours = int(diff.seconds // (60 * 60))
mins = int((diff.seconds // 60) % 60)
This question already has answers here:
How do I get the day of week given a date?
(30 answers)
Closed 9 years ago.
I'm using "datetime" and am having trouble figuring out how to grab the date in the format "%Y-%M-%d" by day of the week. For example:
Since today is 2013-04-01 (a Monday), what code would grab the following Tuesday or Thursday? (output should be 2013-04-02 - Tuesday)
Or if the date is 2013-04-02, a Tuesday, what code would grab the next Mon, Wed, or Fri? (output should be 2013-04-03 - Next day or Wednesday)
Thanks,
This works:
import datetime as dt
dow={d:i for i,d in
enumerate('Mon,Tue,Wed,Thu,Fri,Sat,Sun'.split(','))}
def next_dow(d,day):
while d.weekday()!=day:
d+=dt.timedelta(1)
return d
d1=min(next_dow(dt.datetime(2013,4,1),day)
for day in (dow['Tue'],dow['Thu']))
d2=min(next_dow(dt.datetime(2013,4,2),day)
for day in (dow['Mon'],dow['Wed'],dow['Fri']))
for d in d1,d2:
print d.strftime('%Y-%m-%d')
Or (perhaps better but less general):
def next_dow(d,days):
while d.weekday() not in days:
d+=dt.timedelta(1)
return d
d1=next_dow(dt.datetime(2013,4,1),(dow['Tue'],dow['Thu']))
d2=next_dow(dt.datetime(2013,4,2),(dow['Mon'],dow['Wed'],dow['Fri']))
for d in d1,d2:
print d.strftime('%Y-%m-%d')
Prints:
2013-04-02
2013-04-03
You could try something like this:
from datetime import datetime
from datetime import timedelta
def return_next_tues_thur(dt):
while True:
dt += timedelta(days=1)
dow = dt.strftime(%w)
if dow == 2 || dow == 4:
return dt
dt = datetime.now() # Or you set it: dt = datetime(2013, 4, 1)
next_tues_thur = return_next_tues_thur(dt)
print next_tues_thur.strftime("%Y-%m-%d")
This uses the strftime method and the %w modifier to get the day-of-week from a datetime object. (%w will return an int in the range 0 to 6 where zero is Sunday.)
This idea should be easily extensible to Monday/Wednesday/Friday.
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