summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJesse Duffield <jessedduffield@gmail.com>2023-06-01 18:53:55 +1000
committerGitHub <noreply@github.com>2023-06-01 18:53:55 +1000
commit860fd23b421f3091f1b63ee50d1b77936b45d9c1 (patch)
tree69c510464ef9a243671d6c0cc338b18a62f8e9b2
parent33e5f8f776f30792ec539560f8d3f7ed9d09711a (diff)
parent61f00e6dd41ddc9736c448b3b38186a525995e97 (diff)
Merge pull request #2695 from jesseduffield/fix-time-ago-function
-rw-r--r--pkg/utils/date.go55
-rw-r--r--pkg/utils/date_test.go97
2 files changed, 143 insertions, 9 deletions
diff --git a/pkg/utils/date.go b/pkg/utils/date.go
index 0ced26172..2b9dcaf0f 100644
--- a/pkg/utils/date.go
+++ b/pkg/utils/date.go
@@ -7,17 +7,54 @@ import (
func UnixToTimeAgo(timestamp int64) string {
now := time.Now().Unix()
- delta := float64(now - timestamp)
- // we go seconds, minutes, hours, days, weeks, months, years
- conversions := []float64{60, 60, 24, 7, 4.34524, 12}
- labels := []string{"s", "m", "h", "d", "w", "m", "y"}
- for i, conversion := range conversions {
- if delta < conversion {
- return fmt.Sprintf("%d%s", int(delta), labels[i])
+ return formatSecondsAgo(now - timestamp)
+}
+
+const (
+ SECONDS_IN_SECOND = 1
+ SECONDS_IN_MINUTE = 60
+ SECONDS_IN_HOUR = 3600
+ SECONDS_IN_DAY = 86400
+ SECONDS_IN_WEEK = 604800
+ SECONDS_IN_YEAR = 31536000
+ SECONDS_IN_MONTH = SECONDS_IN_YEAR / 12
+)
+
+type period struct {
+ label string
+ secondsInPeriod int64
+}
+
+var periods = []period{
+ {"s", SECONDS_IN_SECOND},
+ {"m", SECONDS_IN_MINUTE},
+ {"h", SECONDS_IN_HOUR},
+ {"d", SECONDS_IN_DAY},
+ {"w", SECONDS_IN_WEEK},
+ // we're using 'm' for both minutes and months which is ambiguous but
+ // disambiguating with another character feels like overkill.
+ {"m", SECONDS_IN_MONTH},
+ {"y", SECONDS_IN_YEAR},
+}
+
+func formatSecondsAgo(secondsAgo int64) string {
+ for i, period := range periods {
+ if i == 0 {
+ continue
+ }
+
+ if secondsAgo < period.secondsInPeriod {
+ return fmt.Sprintf("%d%s",
+ secondsAgo/periods[i-1].secondsInPeriod,
+ periods[i-1].label,
+ )
}
- delta /= conversion
}
- return fmt.Sprintf("%dy", int(delta))
+
+ return fmt.Sprintf("%d%s",
+ secondsAgo/periods[len(periods)-1].secondsInPeriod,
+ periods[len(periods)-1].label,
+ )
}
// formats the date in a smart way, if the date is today, it will show the time, otherwise it will show the date
diff --git a/pkg/utils/date_test.go b/pkg/utils/date_test.go
new file mode 100644
index 000000000..17deeed94
--- /dev/null
+++ b/pkg/utils/date_test.go
@@ -0,0 +1,97 @@
+package utils
+
+import (
+ "testing"
+)
+
+func TestFormatSecondsAgo(t *testing.T) {
+ tests := []struct {
+ name string
+ args int64
+ want string
+ }{
+ {
+ name: "zero",
+ args: 0,
+ want: "0s",
+ },
+ {
+ name: "one second",
+ args: 1,
+ want: "1s",
+ },
+ {
+ name: "almost a minute",
+ args: 59,
+ want: "59s",
+ },
+ {
+ name: "one minute",
+ args: 60,
+ want: "1m",
+ },
+ {
+ name: "one minute and one second",
+ args: 61,
+ want: "1m",
+ },
+ {
+ name: "almost one hour",
+ args: 3599,
+ want: "59m",
+ },
+ {
+ name: "one hour",
+ args: 3600,
+ want: "1h",
+ },
+ {
+ name: "almost one day",
+ args: 86399,
+ want: "23h",
+ },
+ {
+ name: "one day",
+ args: 86400,
+ want: "1d",
+ },
+ {
+ name: "almost a week",
+ args: 604799,
+ want: "6d",
+ },
+ {
+ name: "one week",
+ args: 604800,
+ want: "1w",
+ },
+ {
+ name: "six months",
+ args: SECONDS_IN_YEAR / 2,
+ want: "6m",
+ },
+ {
+ name: "almost one year",
+ args: 31535999,
+ want: "11m",
+ },
+ {
+ name: "one year",
+ args: SECONDS_IN_YEAR,
+ want: "1y",
+ },
+ {
+ name: "50 years",
+ args: SECONDS_IN_YEAR * 50,
+ want: "50y",
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ if got := formatSecondsAgo(tt.args); got != tt.want {
+ t.Errorf("formatSecondsAgo(%d) = %v, want %v", tt.args, got, tt.want)
+ }
+ })
+ }
+}