Human-readable time difference ("3 years ago...")

Heya folks, I have a conceptual task I’m not grokking. Basically, I have a bunch of data with created_at timestamps. I’d like to turn that into “3 years ago”, or similar.

I was looking for a function that might do the thing I wanted, but now I think I need to do some math.

One approach I’ve thought: turn values into Unix epoch seconds, find difference, convert answer back to human readable time statement.

I’d appreciate alternatives or prior art. Is there a programming pattern that could assist me? :slight_smile:

Interesting timing (no pun intended). I currently have a need for this as well.

A few years ago, on an AMP project, we used:
https://amp.dev/documentation/components/amp-timeago/

This seems to work well, and is locale-aware:
https://www.npmjs.com/package/javascript-time-ago

git clone --single-branch -b hugo-forum-topic-37496 https://github.com/jmooring/hugo-testing hugo-forum-topic-37496
cd hugo-forum-topic-37496
npm install
hugo server

It would be convenient if we could do:

{{ .Date | time.Format ":fuzzy" }}

to produce a locale-aware string, but only if you intend to frequently rebuild the site. If it says “1 hour ago” and you last updated the site a year ago…

1 Like

This seems to be more popular, locale-aware, and a little easier to use:
https://www.npmjs.com/package/timeago.js

I’ve updated the example site referenced in my previous response. Give it a try.

2 Likes

Yes, I was looking for that. :slight_smile:

Thanks for putting the example repo together, I am so used to working on projects alone I forget to mention I was looking for a go template solution, in case there was a much easier way to do it.

el.innerHTML = timeAgo({{ .PublishDate.UnixMilli }}, {{ $locale }});

That’s good to know.

Looks like I’m gonna do some go template math! Whee!

The only problem with the template (static) solution is that “1 minute ago” won’t be true 1 minute from now.

EDIT

The AMP implementation that I referenced above has a cutoff argument:
https://amp.dev/documentation/examples/components/amp-timeago/

If you set cutoff to 604800 (the number of seconds in a week), a fuzzy date will appear during the first week following the specified date. After one week, the actual date will appear.

A Hugo implementation of fuzzy dates would be much more useful if we had a cutoff value, but invert its meaning. For example, if the specified date is less than a month ago, display the actual date, otherwise display a fuzzy date. This would provide more accurate results for sites that are built once per week, month, etc.

I’m not sure how to parameterize a cutoff value with this:

{{ .Date | time.Format ":fuzzy" }}

Perhaps another site configuration setting. Food for thought…

2 Likes

Yep, I was planning on conditionally only showing the “ago” value if it was over a certain time ago; I’ll check the AMP docs for inspiration. :slight_smile:

Say, AMP called it “timeago”. What is this pattern called, if there is a common reference name?

Most of the packages in various langs have the word “timeago” in the name, but I’ve seen the concept referred to as “fuzzy date” or “fuzzy time.”

There’s a ruby thing called distance_of_time_in_words.
https://api.rubyonrails.org/v7.0.1/classes/ActionView/Helpers/DateHelper.html#method-i-distance_of_time_in_words

And there are at least a couple of golang modules, including:
https://pkg.go.dev/github.com/sersh88/timeago

The problem with “timeago” is that it connotes a past event, but fuzzy times are also used for future events:

  • “5 days from now”
  • “in 3 months”
  • etc.
2 Likes

I am using js from this example to show age of the tour guides on a client website. the only thing I set in Hugo is the date of birth and let the js calculate the time ago.

is it usable/helpful to you?

thanks

1 Like

I suspect the pragmatic approach with :fuzzy in a static context would be to have a fairly long default cutoff. A config option may be nice-to-have, but the main use case is to get a distinct marker for “old content”, I suspect …

2 Likes
{{ with $profile.created_at }}
  {{ $born := time . }}
    <p>{{ sub now.Year $born.Year }} years old</p>
  {{ end }}
{{ end }}

time.Time just (partially) clicked in my head.

I’m listing documents, so in this case I’m fine with it potentially saying “0 years old”. :slight_smile:

This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.