|
|
package humanize
import ( "fmt" "math" "sort" "time" )
// Seconds-based time units
const ( Day = 24 * time.Hour Week = 7 * Day Month = 30 * Day Year = 12 * Month LongTime = 37 * Year )
// Time formats a time into a relative string.
//
// Time(someT) -> "3 weeks ago"
func Time(then time.Time) string { return RelTime(then, time.Now(), "ago", "from now") }
// A RelTimeMagnitude struct contains a relative time point at which
// the relative format of time will switch to a new format string. A
// slice of these in ascending order by their "D" field is passed to
// CustomRelTime to format durations.
//
// The Format field is a string that may contain a "%s" which will be
// replaced with the appropriate signed label (e.g. "ago" or "from
// now") and a "%d" that will be replaced by the quantity.
//
// The DivBy field is the amount of time the time difference must be
// divided by in order to display correctly.
//
// e.g. if D is 2*time.Minute and you want to display "%d minutes %s"
// DivBy should be time.Minute so whatever the duration is will be
// expressed in minutes.
type RelTimeMagnitude struct { D time.Duration Format string DivBy time.Duration }
var defaultMagnitudes = []RelTimeMagnitude{ {time.Second, "now", time.Second}, {2 * time.Second, "1 second %s", 1}, {time.Minute, "%d seconds %s", time.Second}, {2 * time.Minute, "1 minute %s", 1}, {time.Hour, "%d minutes %s", time.Minute}, {2 * time.Hour, "1 hour %s", 1}, {Day, "%d hours %s", time.Hour}, {2 * Day, "1 day %s", 1}, {Week, "%d days %s", Day}, {2 * Week, "1 week %s", 1}, {Month, "%d weeks %s", Week}, {2 * Month, "1 month %s", 1}, {Year, "%d months %s", Month}, {18 * Month, "1 year %s", 1}, {2 * Year, "2 years %s", 1}, {LongTime, "%d years %s", Year}, {math.MaxInt64, "a long while %s", 1}, }
// RelTime formats a time into a relative string.
//
// It takes two times and two labels. In addition to the generic time
// delta string (e.g. 5 minutes), the labels are used applied so that
// the label corresponding to the smaller time is applied.
//
// RelTime(timeInPast, timeInFuture, "earlier", "later") -> "3 weeks earlier"
func RelTime(a, b time.Time, albl, blbl string) string { return CustomRelTime(a, b, albl, blbl, defaultMagnitudes) }
// CustomRelTime formats a time into a relative string.
//
// It takes two times two labels and a table of relative time formats.
// In addition to the generic time delta string (e.g. 5 minutes), the
// labels are used applied so that the label corresponding to the
// smaller time is applied.
func CustomRelTime(a, b time.Time, albl, blbl string, magnitudes []RelTimeMagnitude) string { lbl := albl diff := b.Sub(a)
if a.After(b) { lbl = blbl diff = a.Sub(b) }
n := sort.Search(len(magnitudes), func(i int) bool { return magnitudes[i].D > diff })
if n >= len(magnitudes) { n = len(magnitudes) - 1 } mag := magnitudes[n] args := []interface{}{} escaped := false for _, ch := range mag.Format { if escaped { switch ch { case 's': args = append(args, lbl) case 'd': args = append(args, diff/mag.DivBy) } escaped = false } else { escaped = ch == '%' } } return fmt.Sprintf(mag.Format, args...) }
|