dongnong7524 2017-11-17 00:12
浏览 120
已采纳

如何在Golang中格式化持续时间

I have the following code which I can't run on play because I use the gin framework and filewalk.

package main

import (
    "fmt"
    "os"
    "path/filepath"
    "time"
    "regexp"
    "github.com/gin-gonic/gin"
    "sort"
    "strings"
    "github.com/davidscholberg/go-durationfmt"
)

var filext = regexp.MustCompile(`\.[mM][pP]4|\.[mM]4[vV]|\.jpg|\.[hH]264|\.go`)
var m map[int]string
var keys []int

func main() {

    if gin.IsDebugging() {
        fmt.Print("This progamm shows only the path and the age of a file in 'STARTDIR'
")
        fmt.Print("only the following files will be handled '.[mM][pP]4|.[mM]4[vV$|.[hH]264|.go'
")
        fmt.Print("The git repository: https://gitlab.com/aleks001/show-files-age 
")
    }

    if len(os.Getenv("LISTEN_IP_PORT")) == 0 {
        fmt.Print("I need a ip and port on which I should listen.
")
        os.Exit(1)
    }
    router := gin.Default()

    gin.DisableConsoleColor()

    router.GET("/videoinfo",getInfo)

    router.Run(os.Getenv("LISTEN_IP_PORT"))
}

func getInfo(c *gin.Context)  {

    loc, _ := time.LoadLocation("Europe/Vienna")
    var startdir = ""

    if os.Getenv("STARTDIR") != "" {
        startdir = os.Getenv("STARTDIR")
    } else if c.GetHeader("STARTDIR") != "" {
        startdir = c.GetHeader("STARTDIR")
    } else {
        c.String(404,"Startdir not found <br>
")
        return
    }

    m = make(map[int]string)
    keys = nil

    filepath.Walk(startdir,walkpath)

    for k := range m {
        keys = append(keys, k)
    }
    sort.Ints(keys)

    for _, k := range keys {
        t := time.Date(time.Now().Year(),time.Now().Month(),time.Now().Day(),time.Now().Hour(),k,time.Now().Second(),time.Now().Nanosecond(),loc)
        durStr, err := durationfmt.Format(time.Since(t), "%h:%m")

        if err != nil {
            fmt.Println(err)
        } else {
            //fmt.Println(durStr)
            fmt.Printf("Key: %s Value: %s
", durStr , m[k])
            c.String(200,"Minutes: %s File: %s
", durStr, m[k])
        }
    }
}

func walkpath(path string, f os.FileInfo, err error) error {

  if err != nil {
        fmt.Println(err)
    } else {
        if filext.MatchString(path) {
            age := time.Now().Sub(f.ModTime())
            path_new := strings.Replace(path,"/videos/","",1)
            // path_new := strings.Replace(path,"..\\","",1)
            /*
            fmt.Printf("Path: %s, ModTime: %s, Age: %s <br>
", walker.Path(), walker.Stat().ModTime(), age)
            c.String(200,"Path: %s, ModTime: %s, Age: %s <br>
", walker.Path(), walker.Stat().ModTime(), age)
            */
            fmt.Printf("Path: %s, Age: %d age minutes %0.2f  <br>
", path_new, age, age.Minutes())
            m[int(age.Minutes())]=path_new
            //c.String(200,"Path: %s, Age: %0.2f <br>
", path, age.Minutes())
        }
    //fmt.Printf("%s with %d bytes at motime %s
", path,f.Size(), f.ModTime())
}
    return nil
}

What I want to do is a sorted output of files based on filext als filter and the modtime as sort criteria.

I was able to fulfil the most part of the request but the output looks ugly as you can see below.

I have used https://github.com/davidscholberg/go-durationfmt to format the duration but the output looks ugly or I missus the library.

Minutes: 0:6 File: upload/dir003/file1.m4v
Minutes: 0:5 File: transfer/dir5/file2.jpg
Minutes: -5:-48 File: transfer/dir001/file.mp4
Minutes: -6:-21 File: transfer/03.jpg
Minutes: -6:-22 File: transfer/02.mp4

As I'm very new to go I'm sure that there are better way to solve this issue. Thanks for help.

  • 写回答

1条回答 默认 最新

  • douxiezha9319 2017-11-17 02:16
    关注

    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

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥20 有关区间dp的问题求解
  • ¥15 多电路系统共用电源的串扰问题
  • ¥15 slam rangenet++配置
  • ¥15 有没有研究水声通信方面的帮我改俩matlab代码
  • ¥15 对于相关问题的求解与代码
  • ¥15 ubuntu子系统密码忘记
  • ¥15 信号傅里叶变换在matlab上遇到的小问题请求帮助
  • ¥15 保护模式-系统加载-段寄存器
  • ¥15 电脑桌面设定一个区域禁止鼠标操作
  • ¥15 求NPF226060磁芯的详细资料