Human-friendly time formatting and parsing for Ruby. Convert timestamps to readable strings like "3 hours ago" and parse duration strings like "2h 30m" into seconds.
- timeago - Convert timestamps to relative time ("3 hours ago", "in 2 days")
- duration - Format seconds to human-readable duration ("2 hours, 30 minutes")
- parse_duration - Parse duration strings to seconds ("2h30m" → 9000)
- human_date - Contextual dates ("Yesterday", "Last Friday", "March 15")
- date_range - Smart date range formatting ("January 15–22, 2024")
Add this line to your application's Gemfile:
gem 'whenwords'And then execute:
bundle installOr install it yourself as:
gem install whenwordsrequire 'whenwords' # Not needed in Rails (Bundler auto-requires)
# Relative time
Whenwords.timeago(Time.now - 3600, reference: Time.now)
# => "1 hour ago"
# Format duration
Whenwords.duration(9000)
# => "2 hours, 30 minutes"
# Parse duration
Whenwords.parse_duration("2h 30m")
# => 9000
# Human-readable date
Whenwords.human_date(Date.today - 1, reference: Date.today)
# => "Yesterday"
# Date range
Whenwords.date_range(Date.new(2024, 1, 15), Date.new(2024, 1, 22))
# => "January 15–22, 2024"After installing the gem:
# Relative time
whenwords timeago 1704067110 --reference 1704067200
# => 2 minutes ago
# Duration formatting
whenwords duration 9000 --compact
# => 2h 30m
# Parse duration string
whenwords parse "2 hours 30 minutes"
# => 9000
# Human-readable date
whenwords human_date 1705190400 --reference 1705276800
# => Yesterday
# Date range
whenwords date_range 1705276800 1705881600
# => January 15–22, 2024Returns a human-readable relative time string.
Whenwords.timeago(1704067110, reference: 1704067200)
# => "2 minutes ago"
Whenwords.timeago(Time.now + 3600, reference: Time.now)
# => "in 1 hour"Parameters:
timestamp- Unix timestamp (Integer/Float), Time, DateTime, Date, or ISO 8601 Stringreference:- Optional reference timestamp (defaults to same as timestamp)
Thresholds:
| Condition | Output |
|---|---|
| 0–44 seconds | "just now" |
| 45–89 seconds | "1 minute ago" |
| 90 seconds – 44 minutes | "{n} minutes ago" |
| 45–89 minutes | "1 hour ago" |
| 90 minutes – 21 hours | "{n} hours ago" |
| 22–35 hours | "1 day ago" |
| 36 hours – 25 days | "{n} days ago" |
| 26–45 days | "1 month ago" |
| 46–319 days | "{n} months ago" |
| 320–547 days | "1 year ago" |
| 548+ days | "{n} years ago" |
Future times use "in {n} {units}" format.
Formats a duration in seconds to a human-readable string.
Whenwords.duration(3661)
# => "1 hour, 1 minute"
Whenwords.duration(3661, compact: true)
# => "1h 1m"
Whenwords.duration(93661, max_units: 3)
# => "1 day, 2 hours, 1 minute"Parameters:
seconds- Non-negative number of secondscompact:- Use compact format ("2h 30m" vs "2 hours, 30 minutes")max_units:- Maximum number of units to display (default: 2)
Parses a human-written duration string into seconds.
Whenwords.parse_duration("2h30m") # => 9000
Whenwords.parse_duration("2 hours 30 minutes") # => 9000
Whenwords.parse_duration("2.5 hours") # => 9000
Whenwords.parse_duration("2:30") # => 9000 (h:mm)
Whenwords.parse_duration("1 week") # => 604800Accepted formats:
- Compact: "2h30m", "2h 30m", "2h, 30m"
- Verbose: "2 hours 30 minutes", "2 hours and 30 minutes"
- Decimal: "2.5 hours", "1.5h"
- Colon: "2:30" (h:mm), "2:30:00" (h:mm:ss)
Unit aliases:
- seconds: s, sec, secs, second, seconds
- minutes: m, min, mins, minute, minutes
- hours: h, hr, hrs, hour, hours
- days: d, day, days
- weeks: w, wk, wks, week, weeks
Returns a contextual date string.
Whenwords.human_date(Date.today, reference: Date.today)
# => "Today"
Whenwords.human_date(Date.today - 3, reference: Date.today)
# => "Last Friday" (if today is Monday)Outputs:
- Same day → "Today"
- Previous day → "Yesterday"
- Next day → "Tomorrow"
- Within past 7 days → "Last {weekday}"
- Within next 7 days → "This {weekday}"
- Same year → "Month Day"
- Different year → "Month Day, Year"
Formats a date range with smart abbreviation.
Whenwords.date_range(1705276800, 1705363200)
# => "January 15–16, 2024"
Whenwords.date_range(1705276800, 1707955200)
# => "January 15 – February 15, 2024"Behavior:
- Same day: "March 5, 2024"
- Same month: "March 5–7, 2024"
- Same year: "March 5 – April 7, 2024"
- Different years: "December 28, 2024 – January 3, 2025"
- Swapped inputs are auto-corrected
After adding gem 'whenwords' to your Gemfile and running bundle install, Whenwords is automatically available throughout your Rails app.
# app/helpers/application_helper.rb
module ApplicationHelper
def time_ago_in_words(time)
Whenwords.timeago(time, reference: Time.now)
end
def format_duration(seconds, compact: false)
Whenwords.duration(seconds, compact: compact)
end
endclass Video < ApplicationRecord
def duration_formatted(compact: false)
Whenwords.duration(duration_seconds, compact: compact)
end
def duration_seconds=(value)
if value.is_a?(String) && value.match?(/[a-z]/i)
super(Whenwords.parse_duration(value))
else
super
end
end
endbegin
Whenwords.parse_duration("invalid string")
rescue Whenwords::ParseError => e
puts "Parse error: #{e.message}"
end
begin
Whenwords.duration(-100)
rescue Whenwords::Error => e
puts "Error: #{e.message}"
endAll timestamp parameters accept:
Integer/Float- Unix timestamp (seconds)Time- Ruby Time objectDateTime- Ruby DateTime objectDate- Ruby Date objectString- ISO 8601 formatted string
After checking out the repo, run bundle install to install dependencies. Then, run rake spec to run the tests.
To install this gem onto your local machine, run bundle exec rake install.
Bug reports and pull requests are welcome on GitHub at https://github.com/ZPVIP/whenwords.
This Ruby gem is an implementation of the whenwords specification by Drew Breunig — "An Open Source Library Without Code".
The gem is available as open source under the terms of the MIT License.