92 lines
1.9 KiB
Go
92 lines
1.9 KiB
Go
|
package humanize
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"math"
|
||
|
"sort"
|
||
|
"time"
|
||
|
)
|
||
|
|
||
|
// Seconds-based time units
|
||
|
const (
|
||
|
Minute = 60
|
||
|
Hour = 60 * Minute
|
||
|
Day = 24 * 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")
|
||
|
}
|
||
|
|
||
|
var magnitudes = []struct {
|
||
|
d int64
|
||
|
format string
|
||
|
divby int64
|
||
|
}{
|
||
|
{1, "now", 1},
|
||
|
{2, "1 second %s", 1},
|
||
|
{Minute, "%d seconds %s", 1},
|
||
|
{2 * Minute, "1 minute %s", 1},
|
||
|
{Hour, "%d minutes %s", Minute},
|
||
|
{2 * Hour, "1 hour %s", 1},
|
||
|
{Day, "%d hours %s", 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 {
|
||
|
lbl := albl
|
||
|
diff := b.Unix() - a.Unix()
|
||
|
|
||
|
after := a.After(b)
|
||
|
if after {
|
||
|
lbl = blbl
|
||
|
diff = a.Unix() - b.Unix()
|
||
|
}
|
||
|
|
||
|
n := sort.Search(len(magnitudes), func(i int) bool {
|
||
|
return magnitudes[i].d > diff
|
||
|
})
|
||
|
|
||
|
mag := magnitudes[n]
|
||
|
args := []interface{}{}
|
||
|
escaped := false
|
||
|
for _, ch := range mag.format {
|
||
|
if escaped {
|
||
|
switch ch {
|
||
|
case '%':
|
||
|
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...)
|
||
|
}
|