Files
ts/pkg/runexpr/duration.go

143 lines
2.9 KiB
Go

package runexpr
import (
"fmt"
"log"
"math"
"strconv"
"time"
)
const maxDuration time.Duration = 1<<63 - 1
// humanDuration represents a ES duration with day support
type humanDuration struct {
days, hours, minutes, seconds int
}
func parseDuration(duration string) time.Duration {
var seconds int64
for _, match := range matchDuration.FindAllStringSubmatch(duration, -1) {
if len(match) == 3 {
durationvalue, err := strconv.ParseInt(match[1], 10, 64)
if err != nil {
log.Fatal(err)
}
switch match[2][0] {
case 'y':
seconds += durationvalue * 31536000
case 'd':
seconds += durationvalue * 86400
case 'h':
seconds += durationvalue * 3600
case 'm':
seconds += durationvalue * 60
case 's':
seconds += durationvalue
}
}
}
if seconds >= int64(maxDuration.Seconds()) {
log.Fatal("duration overflow, choose a smaller duration")
}
dur := time.Duration(seconds) * time.Second
return dur
}
// extractDuration parses a ES duration and returns an esDuration
func extractDuration(duration string) humanDuration {
esd := humanDuration{}
for _, match := range matchDuration.FindAllStringSubmatch(duration, -1) {
if len(match) == 3 {
durationvalue, _ := strconv.Atoi(match[1])
switch match[2][0] {
case 'd':
esd.days = durationvalue
case 'h':
esd.hours = durationvalue
case 'm':
esd.minutes = durationvalue
case 's':
esd.seconds = durationvalue
}
}
}
return esd
}
// formatDays returns days string, unless days is larger than 365,
// then it returns years and days, e.g. 3y/34d
func formatDays(days float64) string {
if days > 365 {
years := days / 365
days := math.Remainder(days, 365)
return fmt.Sprintf("%dy/%dd", int64(years), int64(days))
}
return fmt.Sprintf("%dd", int64(days))
}
// formatDuration converts a time.Duration to a prettier human
// readable form, like 156h6m15.095s-6d/12h/6m => 6d/12h/6m
func formatDuration(val time.Duration) string {
esd := extractDuration(val.String())
daysF := float64(esd.hours) / 24.0
days := math.Floor(daysF)
hoursLeft := (daysF - days) * 24
switch {
case val.Minutes() < 1:
return fmt.Sprintf("%ds", int64(esd.seconds))
case val.Hours() < 1:
return fmt.Sprintf("%dm", int64(esd.minutes))
case val.Hours() < 24:
if esd.minutes == 0 {
return fmt.Sprintf("%dh", esd.hours)
}
return fmt.Sprintf("%dh/%dm", esd.hours, int64(esd.minutes))
default:
if esd.minutes == 0 && hoursLeft == 0 {
return formatDays(days)
}
return fmt.Sprintf("%s/%dh/%dm",
formatDays(days),
int64(hoursLeft),
esd.minutes,
)
}
}
func toYears(d time.Duration) float64 {
return d.Hours() / 24 / 365
}
func toDays(d time.Duration) float64 {
return d.Hours() / 24
}
func toHours(d time.Duration) float64 {
return d.Hours()
}
func toMinutes(d time.Duration) float64 {
return d.Minutes()
}
func toSeconds(d time.Duration) float64 {
return d.Seconds()
}