forked from mergestat/timediff
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtimediff.go
104 lines (85 loc) · 2.72 KB
/
timediff.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
package timediff
import (
"sort"
"time"
"github.com/hatchet-dev/timediff/locale"
)
// TimeDiffOption is an option used to customize a call to TimeDiff
type TimeDiffOption func(*timeDiffOptions)
type timeDiffOptions struct {
// Start is the time to calculate the time from.
Start time.Time
// Locale is the locale string used by TimeDiff function.
Locale locale.Locale
// CustomFormatters allows the caller to override the formatters used with their own
CustomFormatters locale.Formatters
}
// WithStartTime changes the start time from which time diff calculations are made.
// Defaults to time.Now().
func WithStartTime(t time.Time) TimeDiffOption {
return func(opt *timeDiffOptions) {
opt.Start = t
}
}
// WithLocale changes the locale used for the diff operation
func WithLocale(locale locale.Locale) TimeDiffOption {
return func(opt *timeDiffOptions) {
opt.Locale = locale
}
}
// WithCustomFormatters overrides the formatters supplied by any registered and used locale
func WithCustomFormatters(f locale.Formatters) TimeDiffOption {
return func(opt *timeDiffOptions) {
opt.CustomFormatters = f
}
}
// TimeDiff prints a human-readable string representing the difference between two `time.Time`s.
// By default, the "start" time is time.Now(), but can be overridden with the WithStartTime(t time.Time) option.
func TimeDiff(t time.Time, options ...TimeDiffOption) string {
// set some default options
opt := &timeDiffOptions{Start: time.Now(), Locale: "en-US"}
// apply the option functions
for _, optionFn := range options {
optionFn(opt)
}
var rf locale.Formatters
if opt.CustomFormatters == nil {
if rf = locale.Lookup(opt.Locale); rf == nil {
return "" // TODO: find out a way to return an error in case locale is not found
}
} else {
rf = opt.CustomFormatters
}
// break up the range into slices of keys (durations) and values (formatters)
durations := make([]time.Duration, 0, len(rf))
formatters := make([]func(time.Duration) string, len(rf))
// create a slice of durations
for d := range rf {
durations = append(durations, d)
}
// sort it ASC
sort.SliceStable(durations, func(i, j int) bool {
return durations[i] < durations[j]
})
// populate the slice of formatters, corresponding to their sorted durations
for i, d := range durations {
formatters[i] = rf[d]
}
// take the diff between the supplied time and the start time
diff := opt.Start.Sub(t).Round(time.Second)
for i := range durations {
if diff >= 0 {
dur := durations[i]
if diff <= dur {
return formatters[i](diff)
}
} else {
reverseIdx := len(durations) - 1 - i
dur := durations[reverseIdx]
if diff >= dur {
return formatters[reverseIdx](diff)
}
}
}
return formatters[len(formatters)-1](diff)
}