Django: Use of DATE_FORMAT, DATETIME_FORMAT, TIME_FORMAT in settings.py? - django

I would like to globally (through my entire site, admin and front-end) adjust the way dates and time are displayed to my likings, but I cannot figure out what is going on with the DATE_FORMAT, DATETIME_FORMAT and TIME_FORMAT variables in settings.py.
In this question it says that the settings are ignored. The question is over a year old though. In the Django documentation it says they can be used when you have USE_L10N = True and apparently something changed in Django 1.2. According to this however there might be a bug.
I am currently using Django 1.2 and when I have USE_L10N = True it just ignores the date(time) format in settings.py. When I have USE_L10N = False it also seems to ignore them.
Is there a way to globally customize the date and time display? Or should I create my own custom formats file as Karen suggests in the Django Users Google Group post?

Had same problem, solution is simple and documented. Whenever you render a date, you need to specify you want the template to render it as a date/time/short_date/datetime (e.g., {{ some_date_var | date }} and then it will render it as specified with DATE_FORMAT in your settings.py
Example:
>>> from django.conf import settings # imported to show my variables in settings.py
>>> settings.DATE_FORMAT # - showing my values; I modified this value
'm/d/Y'
>>> settings.TIME_FORMAT
'P'
>>> settings.DATETIME_FORMAT
'N j, Y, P'
>>> from django.template import Template, Context
>>> from datetime import datetime
>>> c = Context(dict(moon = datetime(1969, 7, 20, 20, 17, 39))) # Create context with datetime to render in a template
>>> print c['moon'] # This is the default format of a printing datetime object
1969-07-20 20:17:39
>>> print Template("default formatting : {{ moon }}\n"
"use DATE_FORMAT : {{ moon|date }}\n"
"use TIME_FORMAT : {{ moon|time }}\n"
"use DATETIME_FORMAT: {{ moon|date:'DATETIME_FORMAT' }}\n"
"use SHORT_DATETIME_FORMAT: {{ moon|date:'SHORT_DATETIME_FORMAT' }}"
).render(c)
default formatting : 1969-07-20 20:17:39
use DATE_FORMAT : 07/20/1969
use TIME_FORMAT : 8:17 p.m.
use DATETIME_FORMAT: July 20, 1969, 8:17 p.m.
use SHORT_DATETIME_FORMAT: 07/20/1969 8:17 p.m.
This makes sense; e.g., the template needs to know whether it should use the DATE_FORMAT or the SHORT_DATE_FORMAT or whatever.

Searching through the source shows that DATETIME_FORMAT, etc., are only used when django.utils.formats.localize() is called, and that only seems to be called when django.template.VariableNodes are rendered.
I'm not sure when exactly VariableNodes are used in template rendering, but I would guess that if you have settings.USE_L10N turned on and you have a VariableNode, it will be localized.
localize looks like this:
def localize(value):
"""
Checks if value is a localizable type (date, number...) and returns it
formatted as a string using current locale format
"""
if settings.USE_L10N:
if isinstance(value, (decimal.Decimal, float, int)):
return number_format(value)
elif isinstance(value, datetime.datetime):
return date_format(value, 'DATETIME_FORMAT')
elif isinstance(value, datetime.date):
return date_format(value)
elif isinstance(value, datetime.time):
return time_format(value, 'TIME_FORMAT')
return value
To answer your question, I'd probably write a quick context processor that called localize() on everything in the context.

You can override DATE_FORMAT, DATETIME_FORMAT, TIME_FORMAT and other date/time formats when USE_L10N = True by creating custom format files as described in Django documentation.
In summary:
Set FORMAT_MODULE_PATH = 'yourproject.formats' in settings.py
Create directory structure yourproject/formats/en (replacing en with the corresponding ISO 639-1 locale code if you are using other locale than English) and add __init__.py files to all directories to make it a valid Python module
Add formats.py to the leaf directory, containing the format definitions you want to override, e.g. DATE_FORMAT = 'j. F Y'.
Example from an actual project here.

A late response, but hopefully this will help anyone else searching for this.
By setting USE_L10N = True in your settings, Django looks for locale specific formats, giving them precedence over non-locale related settings.
The solution: (to display 30/12/2017 on a DateField)
from django.conf.locale.en import formats as en_formats
en_formats.DATE_FORMAT = "%d/%m/%Y"
and for inputs (to accept 30/12/2017 or 30-12-2017)
en_formats.DATE_INPUT_FORMATS = ['%d/%m/%Y', '%d-%m-%Y']
Reference: https://mounirmesselmeni.github.io/2014/11/06/date-format-in-django-admin/
*tested on Django==1.10.7

Related

Django: Trying to add 'SHORT_TIME_FORMAT' somehow changes time zone to Chicargo

I required some extra date/time formats in addition to ones Django ships with, sI created these new formats:
SHORT_TIME_FORMAT
FILE_DATETIME_FORMAT
ISO8601_DATETIME_FORMAT.
So that I could use them in templates like this:
{{ value|date:"SHORT_DATE_FORMAT" }}
And In code like this:
from django.utils import formats
formats.date_format(value, `SHORT_TIME_FORMAT`)
I created the following code in utils/time/formats.py:
from collections import ChainMap
from django.utils import formats
DJANGO_DATETIME_FORMATS = {
'DATETIME_FORMAT': 'd M Y, H:i',
'DATE_FORMAT': 'j M Y',
'TIME_FORMAT': 'H:i:s',
'SHORT_DATETIME_FORMAT': 'Y-m-d H:i:s',
'SHORT_DATE_FORMAT': 'Y-m-d',
'MONTH_DAY_FORMAT': 'd M',
'YEAR_MONTH_FORMAT': 'Y M',
}
EXTRA_DATETIME_FORMATS = {
'SHORT_TIME_FORMAT': 'H:i',
'FILE_DATETIME_FORMAT': 'Y-m-d H.i.s',
'ISO8601_DATETIME_FORMAT': 'c', # Compatible with Javascript passing
}
def set_formats(globals_dict):
"""Returns a set of datetime formats for use across the whole project
Contains a union of the default formats along with the additional ones.
To add a new format, one has to perform the following two actions:
1. Add the name of the format to formats.FORMAT_SETTINGS
2. Add a variable with the same name as the variable to the settings.py
file with the value assigned to the required format.
globals_dict is the globals from the settings.py file
"""
formats.FORMAT_SETTINGS = frozenset(formats.FORMAT_SETTINGS | EXTRA_DATETIME_FORMATS.keys())
all_formats = ChainMap(DJANGO_DATETIME_FORMATS, EXTRA_DATETIME_FORMATS)
for setting, value in all_formats.items():
globals_dict[setting] = value
However when I add it to my settings.py file as so:
# settings.py
from utils.time.formats import set_formats
set_formats(globals())
My timezone changes to Chicargo, even though in settings.py I have:
TIME_ZONE = 'Africa/Johannesburg'
After research I found out that Django's default timezone is Chicargo, which is 7 Hrs behind me (I am UTC+02).
I can test it like this:
$ python manage.py shell
> from django.utils import timezone
> from django.conf import settings
> print(f"The settings.py TIME_ZONE value is: {settings.TIME_ZONE=}")
The settings.py TIME_ZONE value is: settings.TIME_ZONE='Africa/Johannesburg'
> print("Using Django local time, now is:")
Using Django local time, now is:
> print(timezone.localtime())
2022-07-27 20:54:35.293958+02:00
If I don't use set_formats, the datetime is correctly in my local time, if I add my set_formats function, then datetime is 7 Hrs off, and in the admin interface and other date/times on my website are all 7 hours off, even though settings.TIME_ZONE reports Africa/Johannesburg.
this code used to work, but at some point recently stopped working. I did change from pytz to zoneinfo, so that might be the reason, but I was a little bit sure it worked after the change.
Why is the timezone changing? How can I add a date/time format so it can be used in templates and in code with the django.utils.formats.date_format function?

How to prevent Django from auto converting datetime

Datetime value such as, day = "2017-9-2 00:00:00" ,
when used in template,
index.html
...
{{day}}
...
it is auto converted by Django to Sept. 2, 2017, midnight.
How can I disable this behavior?
I want it to display in its original format, "2017-9-2 00:00:00".
You should override settings.DATETIME_FORMAT in your settings in order to override the default format.
settings.py:
# ...
USE_L10N = False # At first, disable USE_L10N, because it overrides the format
DATETIME_FORMAT = 'Y-m-d H:i:s' # Set your own datetime format
Now every datetime in your project should be present in this format.
EDIT: If you don't want to globally format all the dates in this format, you can specifically format this date in your template, like this:
{{ day|date:'Y-m-d H:i:s' }}

Where does django read request language code and sneak it into DecimalField output?

I'm a little confused why my site is occasionally rendering commas as decimal separators.
I've disabled USE_L10N now which should take care of the issue, but I'm still curious where this per request language code to DecimalField magic is happening. There are no instances of localize=True anywhere in my codebase.
My only thought is that the browser requests a language code other than en-us and django automatically responds by converting decimal fields, but I can't seem to find where this happens in the django 1.4 source.
Example here: click through products and watch price deicmal separator.
http://www.grovemade.com/product/iphone-5-case/#amongshadows-bamboo-iphone-5-case
The output is cached per URL w/o regard to language code which is why you're seeing some prices with decimal separators as , vs .. The ones with 0,00 must have been cached from a non en-us accept request.
To answer your question as to where this is happening, its in the template system:
def _render_value_in_context(value, context):
"""
Converts any value to a string to become part of a rendered template. This
means escaping, if required, and conversion to a unicode object. If value
is a string, it is expected to have already been translated.
"""
value = localtime(value, use_tz=context.use_tz)
value = localize(value, use_l10n=context.use_l10n)
value = force_unicode(value)
if ((context.autoescape and not isinstance(value, SafeData)) or
isinstance(value, EscapeData)):
return escape(value)
else:
return value
localize from django.utils.formats:
def localize(value, use_l10n=None):
"""
Checks if value is a localizable type (date, number...) and returns it
formatted as a string using current locale format.
If use_l10n is provided and is not None, that will force the value to
be localized (or not), overriding the value of settings.USE_L10N.
"""
if isinstance(value, bool):
return mark_safe(six.text_type(value))
elif isinstance(value, (decimal.Decimal, float) + six.integer_types):
return number_format(value, use_l10n=use_l10n)
elif isinstance(value, datetime.datetime):
return date_format(value, 'DATETIME_FORMAT', use_l10n=use_l10n)
elif isinstance(value, datetime.date):
return date_format(value, use_l10n=use_l10n)
elif isinstance(value, datetime.time):
return time_format(value, 'TIME_FORMAT', use_l10n=use_l10n)
else:
return value
I think what's happening is that your template is setting localize somewhere to true, which is overriding your settings USE_L10N setting.
Or you may have some stale settings files that are still in use. Try clearing out .pyc and your cache and try again.

TimeField format in Django template

I'm writing an application in Django and using several TimeFields in a model. I only want to work with the time format hh:mm (not hh:mm:ss or hh p.m./a.m. or other things).
I have set the django setting TIME_FORMAT = 'H:i' and USE_L10N = False according to the documentation,
USE_L10N overrides TIME_FORMAT if set to True
In my template I'm using input boxes automatically created by Django like:
{{formName.timeField}}
The problem is that as long as I introduce something like "10:00" and do a POST, when the POST is done Django (or whatever) turns it into "10:00:00" (so it adds the seconds).
Is there a way to specify the format in which datetime fields display saved dates? If I could just use something like |date:"H:i" in the value of the input box that would do the trick.
On the other side I know I could do the input box manually (not directly using {{formName.timeField}}), but I've had some problems in the past with that so I would like to avoid that (at least for the moment).
There is also this similar question in Django TimeField Model without seconds, but the solution does not work (it gives me 'NoneType' object has no attribute 'strptime')
I had exactly this problem in my app, and solved it by passing a format parameter to Django's TimeInput widget:
from django import forms
class SettingsForm(forms.Form):
delivery_time = forms.TimeField(widget=forms.TimeInput(format='%H:%M'))
Assuming you have a format you want all TimeFields to use, you can add the TIME_INPUT_FORMATS to your settings file. For example, TIME_INPUT_FORMATS = ('%I:%M %p',) will format your times as "5:30 PM".
The docs: https://docs.djangoproject.com/en/dev/ref/settings/#std:setting-TIME_INPUT_FORMATS

Django's USE_L10N does not work

I already set USE_L10N = True in settings.py
But in following view:
from django.contrib.humanize.templatetags.humanize import intcomma
dev view_name(request):
output = intcomma(123456)
Output is always "123,456" for all locales.
Intcomma only respects the localization settings in Django 1.4 and higher.
In the meantime, remove intcomma and enable USE_THOUSAND_SEPARATOR.
Note that this enables thousand separators on all integers.
I think intcomma() does the same for all locales:
def intcomma(value):
"""
Converts an integer to a string containing commas every three digits.
For example, 3000 becomes '3,000' and 45000 becomes '45,000'.
"""
orig = force_unicode(value)
new = re.sub("^(-?\d+)(\d{3})", '\g<1>,\g<2>', orig)
if orig == new:
return new
else:
return intcomma(new)
intcomma.is_safe = True
register.filter(intcomma)
You can modify this function and pass the separator as an argument.
If you are printing that in a template, you can set in settings.py:
USE_THOUSAND_SEPARATOR=True
THOUSAND_SEPARATOR='.'
NUMBER_GROUPING=3
making the 3 changes above, DECIMAL_SEPARATOR will automaticaly become ','. But you can also set it:
DECIMAL_SEPARATOR=','
this way you dont need humanize, but i guess this will affect all your applications under this settings.py file.
import locale
locale.format("%d", 123456, True)