for a new feature I would need to query objects (which have
created attribute) where the date is 1 year ago, or 2 years ago etc… The use case is displaying “anniversaries”.
What is the correct approach to take into account leap years and other calendar weirdness? I have used
timedelta for shorter timespans, but I don’t think that is correct usage, since I can init it with days value max.
Btw my database is Postgres.
See the month and day comparison operators.
relativedelta(years=1) may be what you want: relativedelta — dateutil 2.8.2 documentation
Thanks both! The relativedelta looks especially nice, since I can specify entire years.
Will try this out and report how it went
So finally got around to it, but somehow I cant seem to get it quite right, although it seems somewhat trivial.
I initially tried the
relativedelta approach to generate anniversary dates for given years and then query apps.
But then I realized I can use the
__month filter options on the
datetime field to get all records which are precisely X years ago…
I am using the
timezone.now() to get these numbers.
This kind of seems to work, but it keeps showing same record the next day as anniversaries, which is wrong.
I have a few tests where I am injecting mock datetime and all pass sucessfully. Even the one which tests the day right after the anniversary day.
I am using the
app_released field also on detail page, to know if there is anniversary and this logic (also based on checking day and month) works correctly. Meaning first day it shows the anniversary info but not the next day.
Any ideas what to test?
PS: All these times should be in UTC.
If you’re using
timezone.now() to get the current day and month, check to verify if that’s local time. See: Time zones | Django documentation | Django
I have the project template, which uses
UTC for the
TIME_ZONE settings and
USE_TZ is set to
Since month and day are just integers, I find it curious why are same records filtered on two separate days.
If it were a timezone issue (not saying it is) your local time days don’t necessarily correspond to UTC days. (Nov 17 EST spans in part both UTC Nov 17 and Nov 18.)
Without seeing the actual code in the view, it’s tough to say what might be wrong. I’d be looking to verify that the right values are being used at all points in the process - but anything specific would all be conjecture.
Here is the entire “logic” that I have. Nothing fancy I would say.
day, month = now.day, now.month
possible_anniversaries = AppRecord.objects.filter(app_released__month=month, app_released__day=day)
anniversaries = 
year = now.year
for app in possible_anniversaries:
if app.app_released.year == year:
In my understanding timezones shouldn’t even play a part here?
For example some app was released Nov 17 2016.
timezone.now(), that gets me
month=11 as long as it is this day in UTC time… But the current behavior is for some reason that I would get the same result for my query tomorrow Now 18, although day should be 18 and therefore this part of the filter:
app_released__day=day should rule it out?
This problem must be something rather dumb but I cannot find it
Please try moving the assignment of now to a line within the function. I’ve got a feeling that the value is being bound once, and not new for every call.
No way. That would explain it, as it would set this to always be the day I deployed the changes.
I think I briefly considered it but thought it must surely be wrong since this is function that shouldn’t be in any global scope and is always called from the view…
That line is interpreted at the time the function is compiled - the timezone.now() statement returns an object, bound to the variable at that time. It’s effectively the same issue encountered as using a mutable object as a default parameter.