15.6 Date Functions: now, dateFormat, time, duration
Right, let’s talk about dates and times. You’d think this would be straightforward, but it’s a surprisingly fertile ground for frustration. Hugo, thankfully, gives us a solid toolkit to wrestle this chaos into submission. We’re going to cover the core functions that let you get the current moment, format it beautifully, and calculate durations. Forget everything you know about JavaScript’s Date object; Hugo’s way is both simpler and, dare I say, more sensible.
The now Function: Your Temporal Anchor
This one is your starting pistol. now returns the current date and time, but crucially, it’s not evaluated at site build time and then frozen. It’s evaluated when the page is rendered. This is a critical distinction. If you’re using hugo server with live reload, a page showing now will actually update as you sit there. It’s a live wire.
<!-- This will reflect the precise moment Hugo rendered this page -->
<p>This site was built right at: {{ now }}</p>
By default, this will spit out something like 2023-10-27 14:35:12.123456789 +0000 UTC. Not exactly human-friendly. That’s where our next function comes in.
The dateFormat Function: Making Time Presentable
Here’s where you impose order. The dateFormat function is your strftime-inspired workhorse. You feed it a layout string and a time, and it gives you back a nicely formatted string. The most common gotcha? The order of arguments. It’s dateFormat layout input, not the other way around. I’ve lost hours of my life to this. Don’t be me.
{{ $now := now }}
<!-- Format the current time -->
<p>A nicely formatted date: {{ $now | dateFormat "Monday, January 2, 2006" }}</p>
<!-- You can also use it directly on a string from your front matter -->
{{ $myDate := "2023-12-07T15:04:05Z" | time }}
<p>My event is on: {{ $myDate | dateFormat "2006-01-02" }}</p>
“Why does the layout use ‘2006-01-02’?” I hear you cry. It’s Hugo’s one truly weird quirk. It uses Go’s reference time: Mon Jan 2 15:04:05 MST 2006. Remember it as 1-2-3-4-5-6-7 (for values of 7). Month (01), Day (02), Hour (15), Minute (04), Second (05), Year (2006), Timezone (MST). It’s bizarre until it isn’t, and then it’s actually kind of brilliant because your layout is its own example.
The time Function: Converting Your Strings
Your content isn’t all now; you have dates in front matter. By default, those are strings. The time function converts a string into a proper time.Time object that Hugo can understand and you can perform operations on. This is non-negotiable if you want to do anything more advanced than just print a date.
{{ $stringFromFrontMatter := "2023-04-01" }} <!-- This is a string -->
{{ $realDate := $stringFromFrontMatter | time }} <!-- This is a time.Time object -->
<!-- Now we can format it properly -->
<p>The converted date: {{ $realDate | dateFormat "Jan 2" }}</p>
<!-- And more importantly, we can use it in comparisons and math -->
{{ if gt $realDate (now.AddDate -1 0 0) }}
<p>This post is from the last year!</p>
{{ end }}
The pitfall here is assuming your string is in a format Hugo can parse. Stick to ISO 8601 (2006-01-02T15:04:05Z07:00) or RFC 3339 for guaranteed results. If you feed it April 1, 2023 without telling it the format, it’ll throw its hands up and give you a zero value.
The duration Function: Measuring the Chunks
Need to add 90 minutes to a time? Subtract 36 hours? The duration function is your friend. It parses a string representing a length of time into a time.Duration object, which you can then use with Hugo’s add and mod functions.
The format is intuitive: a number followed by a unit. Valid units are ns, us (or µs), ms, s, m, h.
{{ $startTime := now }}
{{ $duration := "90m" | duration }} <!-- 90 minutes -->
{{ $endTime := $startTime.Add $duration }}
<p>The meeting started at {{ $startTime | dateFormat "3:04 PM" }} and will end at {{ $endTime | dateFormat "3:04 PM" }}.</p>
<!-- You can also use it for negative durations -->
{{ $lastWeek := now.Add (duration "-168h") }}
<p>This time last week was: {{ $lastWeek | dateFormat "Monday" }}</p>
The absolute best practice here is to always use the most precise unit possible. Want to add a day? Don’t use "24h". Use "24h". No, seriously, use "24h". Daylight Saving Time exists. Adding 24 hours is always 24 hours. Adding a “day” can be 23, 24, or 25 hours depending on the whims of your local government. Hugo’s AddDate is for calendar math (add one calendar day), while Add with a duration is for precise time math. Know which one you need. This distinction has caused more production bugs than I care to admit.