0

I'm trying to write a basic reminder app where users can enter important dates (birthdays, anniversaries, etc.) and see how much time is left until the next anniversary of that date. For example, a user can have a birthday as something like Jan 1st 1990, and I want to display for them the time until their next birthday (2 months 14 days).

I've been using the django timeuntil built in template tag, but it only works for dates in the future (it won't display anything if the date is before the current date). I'm not sure how to to go about "normalizing" the entered date to be a time in the future.

Current code:

def events(request):
    relationships = Relationship.objects.filter(user=request.user)
     events = Event.objects.filter(user=request.user).order_by('date')[:8]
    event_date = events[0].date

    if datetime.now() >= event_date:
        difference = datetime.now() - event_date
        event_date_new = event_date + difference
        event_date = event_date_new
     context = {
         'relationships': relationships,
         'events': events
      }
     return render(request, 'app/events.html', context)     

Template

<td class="column-right"><h4>{{event.date|timeuntil}}</h4></td>

(It also throws an error on datetime.now() module has no attribute "now", is that an old way to find the current date?)

Thanks in advance!

berserkia
  • 277
  • 1
  • 2
  • 9

2 Answers2

0

now is a method of the datetime.datetime class, not the datetime module:

difference = datetime.datetime.now() - event_date

That said, your correction logic is off. If you write out the calculation in one line, it should be clear why:

difference = datetime.now() - event_date
event_date_new = event_date + difference

So by substitution:

event_date_new = event_date + (datetime.now() - event_date)

Which simplifies to:

event_date_new = datetime.now()

I would try it this way:

now = datetime.datetime.now()
event_date = event_date.replace(year=now.year)
if event_date < now:
    event_date.replace(year=now.year + 1)

As Christian Ternus points out, that won't work if event_date is a leap day. You could disallow leap days as event_date values, requiring the user to enter either February 28th or March 1st. Or you could catch the ValueError exception raised by replace and make the correction, adding or subtracting a one-day timedelta. Or use calendar.isleap to figure out the next leap year, if you want to show the true time interval.

Peter DeGlopper
  • 36,326
  • 7
  • 90
  • 83
  • What happens on February 29? – Christian Ternus Oct 18 '13 at 01:28
  • @ChristianTernus - a fair point, but one I think the OP has to decide about. `replace` is only called on `event_date`, not the current date, so that special case could be checked for either at entry or in the calculation. I'm not sure what the time until next anniversary for February 29, 2012 should be. – Peter DeGlopper Oct 18 '13 at 01:32
  • When dealing with date offsets it's best to use something like `dateutil.relativedelta` that handles cases like Feb 29th. – Tim Edgar Oct 18 '13 at 01:33
  • Thanks so much, it's now throwing the error that it can't compare dateime.dateime to dateime.now, which I know is related to this SO question: http://stackoverflow.com/questions/7239315/cant-compare-datetime-datetime-to-datetime-date/7239341#7239341. But I still don't get the difference there... EDIT spelling – berserkia Oct 18 '13 at 01:52
  • If `event_date` is a `DateField` rather than a `DateTimeField`, use `datetime.date.today()` instead of `datetime.datetime.now()`. `datetime.date` is a different class than `datetime.datetime` - the former does not track time of day, just the calendar date. – Peter DeGlopper Oct 18 '13 at 01:55
  • Awesome, it works! I obviously need to read up a bit more thoroughly on how dates work – berserkia Oct 18 '13 at 01:59
0

datetime is a standard Python module , there's is a object has the same name under this module. now is a class method of the datetime object. So if you want to use datetime.now() you should from datetime import datetime or call datetime.datetime.now()

Leonardo.Z
  • 9,425
  • 3
  • 35
  • 38