249

Using Jinja2, how do I format a date field? I know in Python I can simply do this:

print(car.date_of_manufacture.strftime('%Y-%m-%d'))

But how do I format the date in Jinja2?

Martin Thoma
  • 124,992
  • 159
  • 614
  • 958
Ambrosio
  • 3,789
  • 6
  • 22
  • 13

10 Answers10

435

There are two ways to do it. The direct approach would be to simply call (and print) the strftime() method in your template, for example

{{ car.date_of_manufacture.strftime('%Y-%m-%d') }}

Another, sightly better approach would be to define your own filter, e.g.:

from flask import Flask
import babel

app = Flask(__name__)

@app.template_filter()
def format_datetime(value, format='medium'):
    if format == 'full':
        format="EEEE, d. MMMM y 'at' HH:mm"
    elif format == 'medium':
        format="EE dd.MM.y HH:mm"
    return babel.dates.format_datetime(value, format)
    

(This filter is based on babel for reasons regarding i18n, but you can use strftime too). The advantage of the filter is, that you can write

{{ car.date_of_manufacture|format_datetime }}
{{ car.date_of_manufacture|format_datetime('full') }}

which looks nicer and is more maintainable. Another common filter is also the "timedelta" filter, which evaluates to something like "written 8 minutes ago". You can use babel.dates.format_timedelta for that, and register it as filter similar to the datetime example given here.

Tom Burrows
  • 2,225
  • 2
  • 29
  • 46
tux21b
  • 90,183
  • 16
  • 117
  • 101
  • 4
    did you actually try that? calling it directly results in: 'time.struct_time object' has no attribute 'strftime' – Karl P Apr 13 '11 at 13:15
  • 7
    According to your question, you are talking about something different. Initial, this thread were about formatting a `datetime` object from the python module `datetime`, but you are trying to format a `struct_time` object from the low level `time` module. `struct_time` objects do not have a `strftime()` method, although there might be a global `strftime()` method in the time package. But I recommend you to use the high level (platform independent) `datetime` package instead. – tux21b Apr 13 '11 at 13:37
  • Correct, I have been using time.time(), and should now consider whether I really want that, or datetime.datetime.today() Thanks – Karl P Apr 13 '11 at 18:07
  • 2
    I think you mean `babel.dates.format_datetime(value, format)` – johnboiles Apr 01 '14 at 19:59
  • 3
    defining a new filter, is not better in any way. More code to write = more code to be maintained = more code to be parsed, bit-cached (if used) and interpreted. One of the big advantages of using Jinja2 is the ability of writing small python code inside the template. Some of the performance gains, compared to Django's template system, comes from that. – StefanNch Dec 11 '14 at 10:02
  • 7
    @StefanNch "defining a new filter, is not better in any way". It can be: if the filter is called many times in the templates, this avoids repeating the format string, and can result into writting less code. And even more important, less *repeated* code, by adding an abstration. – jacquev6 Jun 04 '18 at 08:59
  • Is it not possible to create a default rule so that I don't have to add |date to all my dates? – Kritz Feb 17 '19 at 14:42
  • `{{ car.date_of_manufacture.strftime('%Y-%m-%d') }}` in the template directly is works perfetctly, thanks Man :) – Tri Sep 09 '19 at 00:47
  • 1
    I had to add ```app.jinja_env.filters['datetime'] = format_datetime``` . – Rivers Cuomo Oct 11 '20 at 13:45
  • "defining a new filter, is not better in any way" To add to @jacquev6 comment, sometimes you don’t have a choice. If the object you have access to from your template features the required method, you’re lucky. The answer did a good job showing how to add a filter for something that is not built-in (i18n using Babel). – Maëlan Apr 25 '21 at 14:11
  • @KarlP [`time.strftime`](https://docs.python.org/2/library/time.html#time.strftime) is the answer, e.g. `time.strftime('%c', time.localtime())` – Cristian Ciupitu Feb 23 '23 at 14:16
32

Here's the filter that I ended up using for strftime in Jinja2 and Flask

@app.template_filter('strftime')
def _jinja2_filter_datetime(date, fmt=None):
    date = dateutil.parser.parse(date)
    native = date.replace(tzinfo=None)
    format='%b %d, %Y'
    return native.strftime(format) 

And then you use the filter like so:

{{car.date_of_manufacture|strftime}}
Raj
  • 3,791
  • 5
  • 43
  • 56
22

You can use it like this in template without any filters

{{ car.date_of_manufacture.strftime('%Y-%m-%d') }}
Logovskii Dmitrii
  • 2,629
  • 4
  • 27
  • 44
19

If you are dealing with a lower level time object (I often just use integers), and don't want to write a custom filter for whatever reason, an approach I use is to pass the strftime function into the template as a variable, where it can be called where you need it.

For example:

import time
context={
    'now':int(time.time()),
    'strftime':time.strftime }  # Note there are no brackets () after strftime
                                # This means we are passing in a function, 
                                # not the result of a function.

self.response.write(jinja2.render_template('sometemplate.html', **context))

Which can then be used within sometemplate.html:

<html>
    <body>
        <p>The time is {{ strftime('%H:%M%:%S',now) }}, and 5 seconds ago it was {{ strftime('%H:%M%:%S',now-5) }}.
    </body>
</html>
Oliver Fawcett
  • 583
  • 1
  • 6
  • 18
19

I think you have to write your own filter for that. It's actually the example for custom filters in the documentation.

bignose
  • 30,281
  • 14
  • 77
  • 110
Brian Goldman
  • 716
  • 3
  • 11
5

Google App Engine users : If you're moving from Django to Jinja2, and looking to replace the date filter, note that the % formatting codes are different.

The strftime % codes are here: http://docs.python.org/2/library/datetime.html#strftime-and-strptime-behavior

Andrew Murphy
  • 1,336
  • 1
  • 11
  • 10
4

You can use it like this in jinja template {{ row.session_start_date_time.strftime('%d-%m-%Y %H:%M:%S')}}

In this code the field name is row.session_start_date_time.

Exelian
  • 5,749
  • 1
  • 30
  • 49
1

in flask, with babel, I like to do this :

@app.template_filter('dt')
def _jinja2_filter_datetime(date, fmt=None):
    if fmt:
        return date.strftime(fmt)
    else:
        return date.strftime(gettext('%%m/%%d/%%Y'))

used in the template with {{mydatetimeobject|dt}}

so no with babel you can specify your various format in messages.po like this for instance :

#: app/views.py:36
#, python-format
msgid "%%m/%%d/%%Y"
msgstr "%%d/%%m/%%Y"
euri10
  • 2,446
  • 3
  • 24
  • 46
0

I use this filter, it's in Spanish but you may change the names as you need.

@app.template_filter('datetime')
def date_format(value):
    months = ('Enero','Febrero',"Marzo","Abril","Mayo","Junio","Julio","Agosto","Septiembre","Octubre","Noviembre","Diciembre")
    month = months[value.month-1]
    hora = str(value.hour).zfill(2)
    minutos = str(value.minute).zfill(2)
    return "{} de {} del {} a las {}:{}hs".format(value.day, month, value.year, hora, minutos)
chelodegli
  • 21
  • 2
  • you also could use this library: https://pypi.org/project/timeago/ it formats with "2 minutes ago" and similar in many languages – chelodegli Aug 11 '21 at 03:41
-3

There is a jinja2 extension you can use just need pip install (https://github.com/hackebrot/jinja2-time)

mumubin
  • 87
  • 7