codemonkey

extends Human with Blog

Formatted Localized Dates in Playframework 2

A question I see popup every now and then on the play mailing list is how to format dates in play framework templates. A lot of people seem to find it hard to understand why their dates are not formatted according to the locale they expect, sometimes they expect their native language to be automagically selected, some times the browser locale.

So, to ease the confusion, a small guide to formatting dates in play framework.

The built in Java date class

The java.util.Date API has a separate set of interfaces and classes for formatting, living in java.text. The most commonly used is the SimpleDateFormat, which can be created with either just a date format pattern or a pattern and a locale. (javadoc here)

The locale is important. If you do not provide one the “default” one will be used, what the default is will depend on the locale of the system you run your application on. So if you develop on a computer which you have set to your home language it will show month names in your language, but when you deploy to your server where the locale most probably is en_us you will get english month names.

So, to cut to the chase, this has got nothing special to do with play framework it is a property of the java date formatting API:s - you must provide a locale for the date format to be sure to get consistently formatted dates.

An additional problematic thing about the SimpleDateFormats is that instances are not thread safe, so using them in a server context, you must make sure you do not share instances accross requests or you will get unexpected results.

A good way to do this is to provide a helper template like this, for hardcoding locale to always be swedish, regardless of browser and server locales:

Harcoded locale

formatDate.scala.html

1
2
3
4
@(date: java.util.Date)
@import java.text.SimpleDateFormat
@import java.util.Locale
@(new SimpleDateFormat("yyyy-MMM-dd", new Locale("sv", "SE")).format(date))

Locale from request

Often you actually want the format to follow the locale of the visiting browser, and you probably do not know every date format on earth, luckily this is built into the java date formatting api. The locale of the visiting browser can be accessed from the request

formatDate2.scala.html

1
2
3
@(date: java.util.Date)(implicit lang: play.api.i18n.Lang)
@import java.text.DateFormat
@DateFormat.getDateInstance(DateFormat.SHORT, lang.toLocale).format(date)

Joda Time

I you are using joda time for dates you have a whole set of formatting options, a separate date format API that you can find under org.joda.time.format._ (javadoc here)

You also have a shortcut living on the actual date and time representations so that you can call .format("pattern", locale) on a date. Using that you could create a helper much like the examples above.

Hardcoded locale

formatjodaDate.scala.html

1
2
3
@(date: org.joda.DateTime)
@import java.util.Locale
@date.format("yyyy-MMM-dd", new Locale("sv", "SE"))

Locale from request

Again we need the implicit import to get the requested locale.

formatjodaDate2.scala.html

1
2
@(date: org.joda.DateTime)(implicit lang: play.api.i18n.Lang)
@date.format("yyyy-MMM-dd", lang.toLocale)

Using the templates above in a regular template would then look like this, note the implicit request that is needed for the two date formats that uses the Lang from the request to get its hands on it:

myBigDateTemplate.scala.html

1
2
3
4
5
6
@(date: java.util.Date, jodate: org.joda.DateTime)(implicit request: Request)

@formatDate(date)
@formatDate2(date)
@formatjodaDate(jodate)
@formatjodaDate2(jodate)