Limitations of Hugo's Date Format Templating

As I’ve mentioned, I use Hugo to generate the bulk of the content on this site. Its templating system is built on that found in the Go programming language. The time and date formatting routines Hugo inherits from Go are idiosyncratic, to say the least.

Basic Hugo Date Formatting

The front matter for a Hugo blog post includes a date, e.g.,

title: BIND for the Small LAN
date: 2007-10-04T00:00:00Z
author: Paul Heinlein

A template formats that date in your preferred textual represention. Given the date stamp above, then

  • {{ .Date.Format "Jan 2, 2006" }} becomes “Oct 4, 2007”
  • {{ .Date.Format "Jan 02, 2006" }} becomes “Oct 04, 2007”
  • {{ .Date.Format "January 02, 2006" }} becomes “October 04, 2007”
  • {{ .Date.Format "Mon, Jan 2, 2006" }} becomes “Thu, Oct 4, 2007”

and so forth. You can use the dateFormat template function in similar fashion:

  • {{ dateFormat "Jan 2, 2006" "2007-10-04" }} becomes “Oct 4, 2007”

Going Astray

I was piecing together an internal documentation site at work and decided to use a prebuilt Hugo template rather than conconcting one of my own. I altered the date formatting string just slightly:

{{ .Date.Format "Jan 1, 2006" }}

It’s a trivial change: “Jan 2” in the examples above becomes “Jan 1.”

All of a sudden, however, articles on the site had wacky dates. The day of the month was always the same as the month of the year. For instance, any article with a date in July 2016 was published as “Jul 7, 2016.” Any with a date in August was published as “Aug 8, 2016.”

In fact, it was trivially easy to wreak havoc on date formatting by straying just the slightest from the formats I showed in the first examples above.

The Format String Trick

The tricky and obscure bit is that Go parses date format strings using a very specific numerology. A comment by spf13 on the Hugo issue tracker pointed me in the right direction.

Here are the comments in an example Go time-parsing routine:

// The layout string used by the Parse function and Format method
// shows by example how the reference time should be represented.
// We stress that one must show how the reference time is formatted,
// not a time of the user's choosing. Thus each layout string is a
// representation of the time stamp,
//    Jan 2 15:04:05 2006 MST
// An easy way to remember this value is that it holds, when presented
// in this order, the values (lined up with the elements above):
//      1 2  3  4  5    6  -7
// There are some wrinkles illustrated below.

Format strings absolutely must adhere to the 1-2-3-4-5-6-7 order:

  • Month must be Jan, January, 01, or 1
  • Date must be 02 or 2
  • Hour must be 03, 3, or 15
  • Minute must 04
  • Second must be 05
  • Year must be 2006
  • Timezone must be MST or -7

Wacky, eh?