Skip to content

Commit

Permalink
feat: add time template helpers
Browse files Browse the repository at this point in the history
Signed-off-by: Sergey <freak12techno@gmail.com>
  • Loading branch information
freak12techno committed Apr 29, 2024
1 parent 5c108f8 commit cf6a4f0
Show file tree
Hide file tree
Showing 4 changed files with 188 additions and 1 deletion.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
vendor/
vendor/
.idea
41 changes: 41 additions & 0 deletions helpers/templates/convert_to_float.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Copyright 2015 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package templates

import (
"fmt"
"strconv"
"time"
)

func convertToFloat(i interface{}) (float64, error) {
switch v := i.(type) {
case float64:
return v, nil
case string:
return strconv.ParseFloat(v, 64)
case int:
return float64(v), nil
case uint:
return float64(v), nil
case int64:
return float64(v), nil
case uint64:
return float64(v), nil
case time.Duration:
return v.Seconds(), nil
default:
return 0, fmt.Errorf("can't convert %T to float", v)
}
}
79 changes: 79 additions & 0 deletions helpers/templates/humamize_duration_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// Copyright 2015 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package templates

import (
"testing"

)

func TestHumanizeDurationSecondsFloat64(t *testing.T) {
input := []float64{0, 1, 60, 3600, 86400, 86400 + 3600, -(86400*2 + 3600*3 + 60*4 + 5), 899.99}
expected := []string{"0s", "1s", "1m 0s", "1h 0m 0s", "1d 0h 0m 0s", "1d 1h 0m 0s", "-2d 3h 4m 5s", "14m 59s"}

for index, value := range input {
result, err := HumanizeDuration(value)
require.NoError(t, err)
require.Equal(t, expected[index], result)
}
}

func TestHumanizeDurationSubsecondAndFractionalSecondsFloat64(t *testing.T) {
input := []float64{.1, .0001, .12345, 60.1, 60.5, 1.2345, 12.345}
expected := []string{"100ms", "100us", "123.5ms", "1m 0s", "1m 0s", "1.234s", "12.35s"}

for index, value := range input {
result, err := HumanizeDuration(value)
require.NoError(t, err)
require.Equal(t, expected[index], result)
}
}

func TestHumanizeDurationErrorString(t *testing.T) {
_, err := HumanizeDuration("one")
require.Error(t, err)
}

func TestHumanizeDurationSecondsString(t *testing.T) {
input := []string{"0", "1", "60", "3600", "86400"}
expected := []string{"0s", "1s", "1m 0s", "1h 0m 0s", "1d 0h 0m 0s"}

for index, value := range input {
result, err := HumanizeDuration(value)
require.NoError(t, err)
require.Equal(t, expected[index], result)
}
}

func TestHumanizeDurationSubsecondAndFractionalSecondsString(t *testing.T) {
input := []string{".1", ".0001", ".12345", "60.1", "60.5", "1.2345", "12.345"}
expected := []string{"100ms", "100us", "123.5ms", "1m 0s", "1m 0s", "1.234s", "12.35s"}

for index, value := range input {
result, err := HumanizeDuration(value)
require.NoError(t, err)
require.Equal(t, expected[index], result)
}
}

func TestHumanizeDurationSecondsInt(t *testing.T) {
input := []int{0, -1, 1, 1234567}
expected := []string{"0s", "-1s", "1s", "14d 6h 56m 7s"}

for index, value := range input {
result, err := HumanizeDuration(value)
require.NoError(t, err)
require.Equal(t, expected[index], result)
}
}
66 changes: 66 additions & 0 deletions helpers/templates/humanize_duration.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// Copyright 2015 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package templates

import (
"fmt"
"math"
)

func HumanizeDuration(i interface{}) (string, error) {
v, err := convertToFloat(i)
if err != nil {
return "", err
}

if math.IsNaN(v) || math.IsInf(v, 0) {
return fmt.Sprintf("%.4g", v), nil
}
if v == 0 {
return fmt.Sprintf("%.4gs", v), nil
}
if math.Abs(v) >= 1 {
sign := ""
if v < 0 {
sign = "-"
v = -v
}
duration := int64(v)
seconds := duration % 60
minutes := (duration / 60) % 60
hours := (duration / 60 / 60) % 24
days := duration / 60 / 60 / 24
// For days to minutes, we display seconds as an integer.
if days != 0 {
return fmt.Sprintf("%s%dd %dh %dm %ds", sign, days, hours, minutes, seconds), nil
}
if hours != 0 {
return fmt.Sprintf("%s%dh %dm %ds", sign, hours, minutes, seconds), nil
}
if minutes != 0 {
return fmt.Sprintf("%s%dm %ds", sign, minutes, seconds), nil
}
// For seconds, we display 4 significant digits.
return fmt.Sprintf("%s%.4gs", sign, v), nil
}
prefix := ""
for _, p := range []string{"m", "u", "n", "p", "f", "a", "z", "y"} {
if math.Abs(v) >= 1 {
break
}
prefix = p
v *= 1000
}
return fmt.Sprintf("%.4g%ss", v, prefix), nil
}

0 comments on commit cf6a4f0

Please sign in to comment.