Django datetime localization - django

I want to output a datetime object (with timezone info set to UTC) in a Django template. I have I18N, L10N, and TZ support all on in the settings. I've also added the LocaleMiddleware and set the language settings. Settings also contains my local timezone as the default. If I simply do {{ mydatetime }} in the template than it properly gives the information in the local timezone. However {{ mydatetime|localize }} seems to always output the datetime in UTC.
Now, I know you're supposed to call django.utils.timezone.activate() to report the current user's timezone (which I'm not doing), but the docs seem to indicate that if you don't use that to report the user's timezone that it uses the default.
Also, does the localize filter get used on datetimes automatically? Is the only purpose of having an explicit call is for when you use {% localize off %} and you want a one-off localization made?

Related

How to Convert UTC Time To User's Local Time in Django

I undrestand that this question is repeated, but unfortunately I cannot find any answer.
My impression is that Django already takes care of converting server time to local user as long as I have
TIME_ZONE = 'UTC'
USE_TZ = True
in my settings.
Even more if the db is postgresql that setting also doesn't matter and every thing will be still converted.
however I tried all the followings:
{% load tz %}
{{ obj.date }}
{{ obj.date|localtime }}
{{ obj.date | timezone:"Canada/Mountain" }}
and only last one works and the rest gives me UTC time. Last one also is not useful as the time would be only correct for users in that zone.
I was wondering if I am missing anything here.
I have a very simple test model:
class TimeObject(models.Model):
date = models.DateTimeField(auto_now=True)
My impression is that Django already takes care of converting server time to local
Unfortunately that is incorrect.
As discussed here, there's no automatic way of knowing what the user's timezone is. You need to figure that out in some other way (it could be saved as a user setting, for example). Then you need to activate() that timezone. Once you do, Django will perform the conversion.

Getting the current date in a particular timezone django

I want to get the current date for a specific timezone in my Django app, irrespective of the server's timezone. I save the user's timezone in the database. I'll then use that in the following function:
def current_date(zone):
utc = timezone.now()
tz = pytz.timezone(zone)
return utc.astimezone(tz).date()
print(current_date('Pacific/Auckland')) #prints 2016-05-30
print(current_date('Africa/Accra')) #prints 2016-05-29
It seems to work, but working with timezones seems complex and I'm wondering if something can go wrong with this approach?
It looks fine as long as getting to the value in view itself is what you want. Since the date/time print is an aspect of presentation you probably may not want to do it in the view code rather in the template using something like below:
{% load tz %}
{{ object.datetime_field|timezone:request.user.timezone }}
assuming you are storing the user's timezone selection in the user model.

django format date on user supplied locale

I'm trying to set up the formatting of dates in templates based on a locale supplied by the user. As the rest of the page will remain in the original local ('en'), I only want my users'
supplied data to be formatted.
for example, dates.
users in the uk should be able to use l10n on the dates on their pages, but I don't want to set the whole site to be en_GB.
is there a way to set the locale in a template within a block, eg. something like
{% locale|'en_GB' %}
{{ my_date|localize }}
{% endlocale %}
You don't need to do anything explicit in the template.
Inside your settings.py define the FORMAT_MODULE_PATH setting.
Like:
FORMAT_MODULE_PATH = 'myproject.myapp.formats'
under the formats directory create one python package per supported language(other
than your default) of your project. Inside each of these you should have a formats.py
which should have any localized formatting options.
In my case the default language for my project is en, but I also support el(greek).
So I have this in my settings.py:
FORMAT_MODULE_PATH = 'myproject.websiteapp.formats'
Inside the myproject/websiteapp/formats directory I have a el package with a formats.py file, like:
el/
__init__.py
formats.py
Inside the formats.py I have this:
DATETIME_FORMAT="l j M Y, g:i a"
which is the greek specific representation of a date.
So when I use a datetime field inside my templates:
{{ mymodel.pub_date }}
It prints the default en representation when locale is set to the default:
Published on: Feb. 22, 2013, 1:47 p.m.
and my custom greek one when the locale is set to el.
Δημοσιεύτηκε: Τετάρτη 6 Φεβ 2013, 5:39 μμ.
More info here
Edit
Hmm, I just realized that you asked for specific template blocks or values.
Maybe the localize template filter or the localize template tag
are more relevant to your specific case?

Handling per-object timezone settings in Django

I have a Django application in which a user can create an Activity, and then for an Activity create a number of Log entries. An Activity has a created datetime, and a Log entry also has a created datetime.
The Activity should be created with the timezone of the creating user at the time at which they create it. Specifically, a given user may have two Activities in separate timezones; the timezone setting is not per-user, but per-activity. I can derive a user's current offset from UTC in JavaScript in the browser (and I'm happy to rely on that).
What I do not know is: how do I save these times to the database, and then display them correctly on rendering?
I have USE_TZ turned on. Here in the UK, everything works: when creating an Activity, I save the created datetime as django.utils.timezone.now(), and I save the user's current offset (from JavaScript) as timezoneHoursOffset in the Activity. Then, when I display the Activity and its Log entries on a page, I wrap this in {% timezone "Etc/GMT+(timezoneHoursOffset)" %} ... {% endtimezone %}.
However, this approach doesn't work if the server's not in the UK. The time is saved in the database as UTC (I've verified this by checking in the database itself, not using the ORM), that time is then "changed" by the ORM to be eight hours behind UTC (because the server's timezone is UTC-8) (and that gives the correct time!) and then the {% timezone %} tag subtracts another eight hours off the time, meaning that the displayed time is eight hours behind what it should be.
I'm not sure whether I should be saving the times differently; changing them on output; using the timezone template tag; or something else. This stuff is very confusing. How would you advise that I handle this situation?
Ref the answer, "Etc/GMT" timezones have their sign reversed. For example, I'm in +0800, it should be 'Etc/GMT-8' instead of 'Etc/GMT+8' (and I suspect that your UTC-8 actually should be "Etc/GMT+8" ):
>>> from django.template import Template, Context
>>> from django.utils.timezone import now
>>> print(Template("""{% load tz %}
localtime: {{ t }}
Etc/GMT-8: {{ t|timezone:"Etc/GMT-8" }}
Etc/GMT+8: {{ t|timezone:"Etc/GMT+8" }}
""").render(Context({'t':now()})))
localtime: Jan. 29, 2013, 11:48 p.m.
Etc/GMT-8: Jan. 29, 2013, 11:48 p.m.
Etc/GMT+8: Jan. 29, 2013, 7:48 a.m.
So, you have to reverse your timezoneHoursOffset...
For DB storing, according to the doc, it's better to store data in UTC.
Also, you need to make sure your javascript generates correct hour offset because of DST. If you can, it's better to store timezone name and use it accordingly.
from datetime import datetime
from dateutil import zoneinfo
from_zone = zoneinfo.gettz('UTC')
to_zone = zoneinfo.gettz('UK/UK')
utc = created # your datetime object from the db
# Tell the datetime object that it's in UTC time zone since
# datetime objects are 'naive' by default
utc = utc.replace(tzinfo=from_zone)
# Convert time zone
eastern_time = utc.aztimezone(to_zone)

Django - Pre render signal?

I have a 'live settings' app which I use to store certain global site settings. Certain pages of my site reference these settings, although generally they only use 2-3 at a time. I access these settings using a custom template tag like so:
{% settings site_name %}
Each time I use this tag, the model will retrieve the setting from the database, so if I had something like:
{% settings site_name %} {% settings num_articles %}
the database would get queried twice.
What I'd like to do is not hit the database more than once per page for the settings values, if I could get all the settings used on a page and then hit the database to retrieve them all, that would be much better.
I had a look through the documentation and it seems Django has no pre render signal which I could use to update any references to the settings, so does anyone have any suggestions how I could optimise this system? And yes obviously caching is the obvious answer but I'd still like to improve on this for when the page isn't cached.
Agreeing with Daniel that process_template_response is the hook you're looking for. I don't know how many settings you have, but it could also make sense to retrieve all settings once, and store them in some dictionary like structure, so you can access them anytime without hitting the database. You could retrieve them once either per request, or - even if your settings do barely change - when django initializes. You could additionally use django's signals to update your cached settings on delete or update.
If you have a look at django-dbsettings you will see it does a similar thing!
Django 1.3 includes the new TemplateResponse class, which allows you to modify the response later in the rendering process - eg in middleware. This looks like it might do what you want.
If you wish to stick to a scheme similar to what you already have, I'd implement a filter that takes in a list of keys and returns a dict with all the relevant values.
Example filter:
def get_settings(key_list):
# take values from conf.settings. In practice, can be from any source
return dict((k, getattr(settings, k, None)) for k in key_list.split(","))
register.filter("get_settings", get_settings)
Usage:
{# load multiple values with a single call #}
{% with "KEY1,KEY2"|get_settings as settings %}
setting values {{ settings.KEY1 }} and {{ settings.KEY2 }}
{% endwith %}
Note that I used a filter instead of a tag because the with builtin expects a single value before as.