Playing with Time
Jul 14, 2025
When generating my site's RSS feed
and post index, I prefer to sort
posts by their <pubDate>
sub-element so newer posts always
appear on top. While it's an entirely optional field, as specified in the
RSS 2.0 spec, most
other feed generators I've used sort items by the <pubDate>
sub-element, so I would feel a bit left out if my bespoke build script
couldn't sort posts too.
For some context, my build script creates a struct called Rss
to represent the RSS feed, with a Posts
field containing a slice
of Post
structs, which (as the name implies) represent
individual posts:
type Rss struct {
LastBuildDate string
Posts *[]Post
XmlHeader html.HTML
}
type Post struct {
name string
Title string
Author string
Link string
Body string
RawDate string
PubDate string
}
Prior to generating the feed, the Posts
field is sorted based on
each post's PubDate
field. The script then generates the XML
file by iterating over the Posts
field, creating an entry for
each post using some templating magic.
The publish date values in the PubDate
field look like this:
Sat, 05 Jul 2025 23:46:02 -0400
Sorting those dates can be frustrating. My original attempt naively used
cmp.Compare
to compare the two PubDate
fields:
slices.SortFunc(posts, func(a, b Post) int {
return cmp.Compare(b.PubDate, a.PubDate)
}
One can imagine this didn't work out well, since PubDate
(a
string) doesn't fit under the Ordered
constraint that permits any ordered type.
To my relief, Go includes a time package in its standard library that makes measuring time a heck of lot easier.
Digging through the docs, I found the method Time.Compare
, which
is used to compare two time.Time
structs. Unlike the methods
Time.Before
and Time.After
, Time.Compare
returns an int, which satisfies the cmp function's prototype in
slices.SortFunc
.
slices.SortFunc(posts, func(a, b Post) int {
aTime, _ := time.Parse(time.RFC1123Z, a.PubDate)
bTime, _ := time.Parse(time.RFC1123Z, b.PubDate)
return bTime.Compare(aTime)
})
The PubDate
fields for each struct are already formatted as
RFC 1123Z compliant strings, so parsing them into time.Time
structs before the comparison is a breeze and only adds a couple lines of
code.