humane-ruby
Getting human-readable file sizes with 1000-based math
(as the Mac Finder displays) and relative times worded the way Swift's
RelativeDateTimeFormatter does turned out to be a real challenge to get
both right and simple. The humane library exists so a Ruby application can share
consistent size and time formatting with a Swift application, instead of
reaching for a library whose output doesn't match Swift's or that's
complicated to drop in.
require "humane"
Humane::SizeFormatter.new.string(from_byte_count: 225_935) # "226 KB"
time_formatter = Humane::TimeFormatter.new
time_formatter.string(at: Time.now - 180, relative_to: Time.now) # "3 minutes ago"
Corresponding functions in Swift will have consistent output.
import Foundation
ByteCountFormatter.string(fromByteCount: Int64(225935), countStyle: .file) // "226 KB"
let formatter = RelativeDateTimeFormatter(); formatter.unitsStyle = .full
formatter.localizedString(for: time, relativeTo: now) // "3 minutes ago"
If you're writing Swift directly rather than calling Foundation by hand,
humane-swift wraps these same two
formatters with the identical API shape -- including the
includeSeconds/approximate options below.
Install
gem install humane
or in a Gemfile:
gem "humane"
Beyond Foundation's defaults
Two options on Humane::TimeFormatter, both off by default so it matches
RelativeDateTimeFormatter exactly out of the box:
include_seconds(defaultfalse): under 30 seconds, collapses to "less than a minute ago"/"in less than a minute" instead of an exact second count. Named after ActionView'sinclude_seconds, which defaults the same way.approximate(defaultfalse): prefixes "about"/"in about" on the hour-scale buckets (1 hour, and 2..24 hours), the way ActionView'sdistance_of_time_in_wordsdoes for those same buckets -- for a render that can't refresh itself and shouldn't overstate its own precision. Matches ActionView's own table exactly (down to its 44:30/89:30 rounding cutoffs), through the "1 day" bucket; week/month/year buckets are out of scope. See issue #1.
Humane::TimeFormatter.new(approximate: true).string(at: t - 15 * 3600, relative_to: t)
# => "about 15 hours ago"
Scope
Finder's .file byte-count style, and a numeric (non-calendar-aware)
relative time style -- that's the whole surface area today.
allowed_units/alternate count_styles and a :named style
("yesterday", calendar-boundary-aware) aren't implemented -- contributions
welcome.