Whenwords
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.
Features
- 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")
Installation
Add this line to your application's Gemfile:
gem 'whenwords'And then execute:
bundle installOr install it yourself as:
gem install whenwordsQuick Start
require '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"Command Line Usage
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, 2024API Reference
timeago(timestamp, reference: nil) → String
Returns 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 String -
reference:- 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.
duration(seconds, compact: false, max_units: 2) → String
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 seconds -
compact:- Use compact format ("2h 30m" vs "2 hours, 30 minutes") -
max_units:- Maximum number of units to display (default: 2)
parse_duration(string) → Integer
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
human_date(timestamp, reference: nil) → String
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"
date_range(start, end) → String
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
Rails Integration
After adding gem 'whenwords' to your Gemfile and running bundle install, Whenwords is automatically available throughout your Rails app.
View Helper
# 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
endModel
class 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
endError Handling
begin
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}"
endAccepted Input Types
All timestamp parameters accept:
-
Integer/Float- Unix timestamp (seconds) -
Time- Ruby Time object -
DateTime- Ruby DateTime object -
Date- Ruby Date object -
String- ISO 8601 formatted string
Development
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.
Contributing
Bug reports and pull requests are welcome on GitHub at https://github.com/ZPVIP/whenwords.
Credits
This Ruby gem is an implementation of the whenwords specification by Drew Breunig — "An Open Source Library Without Code".
License
The gem is available as open source under the terms of the MIT License.