Monday, May 4, 2015

Re: How to represent a calendar month as a field in django models

> Den 04/05/2015 kl. 13.26 skrev Matthys Kroon <matthysk@gmail.com>:
>
> I'm specifically looking at only situations where the year and month alone are significant.
>
> The downside I see with using a DateField and forcing the day to the first of the month, with custom widget etc. is that somebody looking at the database may not realize that something unusual is going on and I'm not sure how I would go about finding the month x months before or after after a given month ... solutions like
> where 12 * year(t1.month_field) + month(t1.month_field) = 12 * year(t2.month_field) + month(t2.month_field) + x
> come to mind for sql but not sure how this would translate into django. Not that I'm saying it is not the correct solution, all of the options I considered have some downside.

Python stdlib doesn't support operating on months the way I think you expect. If you want to truly only operate on years and month values, then I think the most Pythonic/Djangoic way is to create your own Month model/class (unless you want to marry ourself to PostgreSQL and its' tuple type). The math to add/subtract months is very simple:


class Month(models.Model):
year = models.IntegerField()
month = models.PositiveSmallIntegerField()

def add_months(self, n):
assert n >= 0
dy, dm = divmod(self.month + n, 12)
self.year += dy
self.month += dm

# Expand as needed with __add__, __sub__, remove_months() etc.


> The logic for adding and subtracting these "months" requires something like timedelta(month=2), which doesn't exist in the standard library as far as I know - though I'm not an expert.
>
> There are recipes on stackoverflow for incrementing months though not very elegant.

That's because incrementing months is ambiguous when operating on actual datetimes. timedelta(months=2) is nonsense because months have different lengths. Adding 1 month to March 2 would mean April 2 to most people, but what about January 31 (let's ignore for a moment that both PHP and MySQL accept February 31 as a valid date)? Do you want February 28 (or possibly 29), or March 2 (or 3), or possibly 4 weeks ahead?

Erik

--
You received this message because you are subscribed to the Google Groups "Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-users+unsubscribe@googlegroups.com.
To post to this group, send email to django-users@googlegroups.com.
Visit this group at http://groups.google.com/group/django-users.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-users/7399E8A3-DC57-4709-B280-65BA11465439%40cederstrand.dk.
For more options, visit https://groups.google.com/d/optout.

No comments:

Post a Comment