/* Copyright © 2026 Thomas von Dein This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package es import ( "fmt" "math" "regexp" "strconv" "time" ) var ( matchDuration = regexp.MustCompile(`(\d+)([dhms])`) ) type esDuration struct { days, hours, minutes, seconds int } /* We could use time.ParseDuration(), but this doesn't support days. We could also use github.com/xhit/go-str2duration/v2, which does the job, but it's just another dependency, just for this little gem. And we don't need a time.Time value. And int is good enough for duration comparison. Convert a duration into an integer. Valid time units are "s", "m", "h" and "d". via https://codeberg.org/scip/tablizer/src/branch/main/lib/sort.go#L113 */ func parseDuration(duration string) time.Duration { seconds := 0 for _, match := range matchDuration.FindAllStringSubmatch(duration, -1) { if len(match) == 3 { durationvalue, _ := strconv.Atoi(match[1]) switch match[2][0] { case 'd': seconds += durationvalue * 86400 case 'h': seconds += durationvalue * 3600 case 'm': seconds += durationvalue * 60 case 's': seconds += durationvalue } } } return time.Duration(seconds) * time.Second } // pretty much the same as above, but return a struct filled with int duration values func extractDuration(duration string) esDuration { esd := esDuration{} 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 } // convert a duration 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 fmt.Sprintf("%dd", int64(days)) } return fmt.Sprintf("%dd:%dh:%dm", int64(days), int64(hoursLeft), esd.minutes, ) } }