5

I have aware datetime instances (where tzinfo = "America/Los_Angeles") that I would like to save to a model.

Should I convert it to UTC somehow before saving? Or can I just save it as is, since it's aware of its own timezone? Do I need to convert it to users' timezones later with activate(), or will Django do that for me, since the instance is aware?

I'm most curious what the conventions are in regards to this. Thanks in advance.

user193130
  • 8,009
  • 4
  • 36
  • 64
sgarza62
  • 5,998
  • 8
  • 49
  • 69
  • 1
    By "post" do you mean calling the `.save()` on a model instance or an **HTTP POST**? Hopefully you mean the former because an **HTTP POST** has no business in a model... – user193130 Mar 04 '14 at 22:22
  • Yes, sorry for being unclear there. I'm referring to calling the `save()` method on model instance. I'll be storing the values as `DateTimeField`s. – sgarza62 Mar 04 '14 at 22:25

2 Answers2

8

If it is timezone aware and you have USE_TZ set to True in your settings.py django will automatically convert it to UTC when you save it.

When you retrieve it from the DB later it will be timezone aware but set to UTC: django will not save the timezone it used to be.

When you display the datetime in a template it will be converted to the timezone set by TIME_ZONE in your settings.py, unless you utilize django's timezone utilities to activate a different timezone.

dgel
  • 16,352
  • 8
  • 58
  • 75
  • Great, thank you, that's exactly what I was wondering. Would you mind expanding on how to "utilize the correct timezone utilities to convert it to the current timezone when you want to display it"? – sgarza62 Mar 04 '14 at 22:30
  • Clarified that a bit. Django's [timezone documentation](https://docs.djangoproject.com/en/1.6/topics/i18n/timezones/) shows how to activate a timezone and how to convert datetime's for display. – dgel Mar 04 '14 at 22:34
  • Is there a way for me to *always* display the datetime value in the end-user's local timezone? Without having to riddle my templates and views with `activate()`s and `{% localtime on %}`s? Is there a setting or something that always displays the time in the user's timezone? – sgarza62 Mar 04 '14 at 22:39
  • 1
    You would need to store the user's timezone in the DB then you could automatically activate it using a custom middleware- django's timezone documentation [includes an example](https://docs.djangoproject.com/en/1.6/topics/i18n/timezones/#selecting-the-current-time-zone). – dgel Mar 04 '14 at 22:41
  • Ah, really? That's a bit of a pain. I feel like if the datetime instance is aware, it should display in the user's timezone by default. – sgarza62 Mar 04 '14 at 22:42
3

You do not have to convert it to UTC before saving it as Django will automatically do that for you. When you retrieve it, it will be retrieved as the timezone that was defined in the TIMEZONE setting.

You can override that with activate() and to see the current timezone, use django.utils.timezone.get_current_timezone().

This means that the time you retrieve from the database may be different than the timezone of the datetime object you used to save the object originally. However, it will still be the same moment in time.

If you have a timezone for each user, you should save this with the user's profile and call activate() with the user's timezone BEFORE retrieving the model instance that contains the DateTimeField. The retrieved object will be in the appropriate timezone.

Alternatively you can use the override() context manager.

If you are sure you always want the datetime objects in the user's timezone instead of the server's timezone, write a custom middleware to call activate() on request.user. You will need to store/retrieve the timezone yourself as Django has no way of knowing what the user's timezone is and does not store it in the User model by default.

user193130
  • 8,009
  • 4
  • 36
  • 64
  • Is there a way for me to always display the datetime value in the end-user's local timezone? Without having to riddle my templates and views with activate()s and {% localtime on %}s? Is there a setting or something that always displays the time in the user's timezone? – sgarza62 Mar 04 '14 at 22:39
  • 1
    @sgarza62 Yes, you can write a middleware to call activate early on based on `request.user`. You can also wrap a view in a `override()` context manager – user193130 Mar 04 '14 at 22:43