How to format a duration
For example, to provide a custom format for a duration,
package main
import (
"fmt"
"time"
)
func fmtDuration(d time.Duration) string {
d = d.Round(time.Minute)
h := d / time.Hour
d -= h * time.Hour
m := d / time.Minute
return fmt.Sprintf("%02d:%02d", h, m)
}
func main() {
modTime := time.Now().Round(0).Add(-(3600 + 60 + 45) * time.Second)
since := time.Since(modTime)
fmt.Println(since)
durStr := fmtDuration(since)
fmt.Println(durStr)
}
Playground: https://play.golang.org/p/HT4bFfoA5r
Output:
1h1m45s
01:02
If you want to sort on a duration then use the Go sort
package. I would sort on ModTime
to defer the calculation of the duration, Since(ModTime)
, to be accurate at the time it is printed. For example,
package main
import (
"fmt"
"os"
"path/filepath"
"sort"
"strings"
"time"
)
func isVideo(path string) bool {
videos := []string{".mp4", ".m4v", ".h264"}
ext := strings.ToLower(filepath.Ext(path))
for _, video := range videos {
if ext == video {
return true
}
}
return false
}
type modTimeInfo struct {
path string
modTime time.Time
}
func walkModTime(root string) ([]modTimeInfo, error) {
var infos []modTimeInfo
err := filepath.Walk(
root,
func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if info.Mode().IsRegular() {
path = filepath.Clean(path)
if !isVideo(path) {
return nil
}
sep := string(filepath.Separator)
dir := sep + `Videos` + sep
path = strings.Replace(path, dir, sep, 1)
infos = append(infos, modTimeInfo{
path: path,
modTime: info.ModTime()},
)
}
return nil
},
)
if err != nil {
return nil, err
}
return infos, nil
}
func sortModTime(infos []modTimeInfo) {
sort.SliceStable(
infos,
func(i, j int) bool {
return infos[i].modTime.Before(infos[j].modTime)
},
)
}
func fmtAge(d time.Duration) string {
d = d.Round(time.Minute)
h := d / time.Hour
d -= h * time.Hour
m := d / time.Minute
return fmt.Sprintf("%02d:%02d", h, m)
}
func main() {
root := `/home/peter/Videos` // Testing ...
infos, err := walkModTime(root)
if err != nil {
fmt.Println(err)
return
}
sortModTime(infos)
now := time.Now()
for _, info := range infos {
age := fmtAge(now.Sub(info.modTime))
fmt.Println("Age (H:M):", age, "File:", info.path)
}
}
Playground: https://play.golang.org/p/j2TUmJdAi4
FYI, if you just want to quickly display a duration, the built-in formatting works well:
fmt.Sprintf("duration: %s", d)
will display something like this:
duration: 7h3m45s
Another way to format the duration if you don't care about the day, month or year
package main
import (
"fmt"
"time"
)
type Timespan time.Duration
func (t Timespan) Format(format string) string {
z := time.Unix(0, 0).UTC()
return z.Add(time.Duration(t)).Format(format)
}
func main() {
dur := 7777 * time.Second
fmt.Println(Timespan(dur).Format("15:04:05")) // 02:09:37
}
https://play.golang.org/p/XM-884oYMvE