Python gets days / weeks / months in advance

I searched through stackoverflow for an answer, but I was not able to find what I am looking for in Python and Pythonic.

I am trying to get the number of days, weeks or months in advance depending on two dates. Here is a little script that I created that does what I want to do, but it bothers me.

import datetime from dateutil.relativedelta import relativedelta now = datetime.datetime.now() days_ahead = datetime.datetime.now() + relativedelta(days=3) weeks_ahead = datetime.datetime.now() + relativedelta(weeks=2) month_ahead = datetime.datetime.now() + relativedelta(months=1) months_ahead = datetime.datetime.now() + relativedelta(months=3) def get_relative_date(dt): ahead = (dt - now).days if ahead < 7: return "Due in " + str(ahead) + " days" elif ahead < 31: return "Due in " + str(ahead/7) + " weeks" else: return "Due in " + str(ahead/30) + " months" print get_relative_date(days_ahead) print get_relative_date(weeks_ahead) print get_relative_date(month_ahead) print get_relative_date(months_ahead) 

The result is the following:

 Due in 3 days Due in 2 weeks Due in 1 months Due in 3 months 

Despite the fact that I was a good answer, my problems are related to:

  • I use ahead < 30 , but what about months with 31 days? Won't this cause some kind of overhead and make no mistakes at some point?
  • Is there a better way to get this information? Some library or built-in function for datetime or dateutil that returns this information to you?

Thanks in advance. If you answered the question, write me a message, and I will carefully read it. I would like to provide additional information if required.

Edit

I am including my full updated code here for those who also need this feature in Python. He also takes care of the negative values โ€‹โ€‹of the day today.

 def relative_date(dt): if dt is not None and len(dt) > 0: now = datetime.now() then = arrow.get(dt).naive rd = relativedelta(then, now) if rd.years or rd.months: months = 12 * rd.years + rd.months if months < 0: if months == -1: return "Due 1 month ago" return "Due %i months ago" % -months if months == 1: return "Due in 1 month" return "Due in %d months" % months elif rd.days > 7 or rd.days < -7: weeks = rd.days / 7 if weeks < 0: if weeks == -1: return "Due 1 week ago" return "Due %i weeks ago" % -weeks if weeks == 1: return "Due in 1 week" return "Due in %d weeks" % weeks else: if rd.days == 0: return "Due Today" elif rd.days < 0: if rd.days == -1: return "Due 1 day ago" return "Due %i days ago" % -rd.days elif rd.days == 1: return "Due in 1 day" return "Due in %d days" % rd.days else: return "" 
+4
source share
1 answer

Yes, your current code is a problem because not all months have 31 days. In practice, you can decide that it is not too important if he says "Debt for 2 months", when he really should be within 1 month and 28 days. In the end, rounding means that you show "Debt for 2 months" when it should be after 2 months and 28 days.

Since you are already using the dateutil module, note that you can also use relativedelta other way around (see the examples page ).

If you create a relativedelta instance with two date objects, it returns a relativedelta object with the attributes year , month and day .

 >>> relativedelta(date(2015, 7, 20), date(2014, 6, 10)) relativedelta(years=+1, months=+1, days=+10) 

You can use this in your method as follows:

 from dateutil.relativedelta import relativedelta def get_relative_date(dt): rd = relativedelta(dt, now) if rd.years or rd.months: months = 12 * rd.years + rd.months: return "Due in %d months" % months elif rd.days > 7: weeks = rd.days / 7 return "Due in %d weeks" % weeks else: return "Due in %d days" % rd.days 
+4
source

All Articles