如何在Go中解析视频时间戳?

gr8qqesn  于 2023-03-27  发布在  Go
关注(0)|答案(2)|浏览(171)

我正在做一个有YAML的项目

- title: Toshiki Kadomatsu - Airport Lady                                                                                                          
         time: 35:46                                                                                                                                      
       - title: Yellow Magic Orchestra - Technopolis                                                                                                      
         time: 39:58

具体来说,它是一个控制MPD(音乐播放器守护程序)的Go程序,这样它就可以播放长音频文件中的特定歌曲。
然而,我希望能够在我的程序中显示当前正在播放的歌曲。我计划通过从MPD接收经过的时间(以秒数表示)来实现这一点[例如:1239.324 ]。我可以从这个创建一个持续时间,只需在末尾加上一个“s”。然后我计划将这个持续时间与yaml文件中歌曲的其他持续时间进行比较。
我似乎无法使用time.ParseDuration35:46解析为持续时间。我可以将:替换为m,并在末尾添加s,但有些歌曲文件的时间戳超过了一个小时,如下所示:01:04:20 .
如何用Go语言解析这些时间戳?

5cg8jx4n

5cg8jx4n1#

您可以使用strings.Split方法,将字符串按照分隔符进行分隔,然后创建一个[3]float64数组,并按照从后到前的顺序填充数据,这样可以避免由于缺少小时或分钟而导致的数据短缺。

arr := strings.Split(timeStr, ":")
var d [3]float64 // d[0]: hour, [1]: min, 0: sec
for i := 2; i >= 0; i-- {
    if len(arr) == 0 {
        break
    }
    val, err := strconv.Atoi(arr[len(arr)-1])
    if err != nil {
        return t, err
    }
    d[i] = float64(val)
    arr = arr[:len(arr)-1] // update arr
}

另外,可以考虑用时间来处理一些特殊情况,比如71秒00:01:11。例如:

func ParseTime(timeStr string) (time.Time, error) {
    t := time.Date(1, 0, 0, 0, 0, 0, 0, time.UTC)

    arr := strings.Split(timeStr, ":")
    var d [3]float64 // d[0]: hour, [1]: min, 0: sec
    for i := 2; i >= 0; i-- {
        if len(arr) == 0 {
            break
        }
        val, err := strconv.Atoi(arr[len(arr)-1])
        if err != nil {
            return t, err
        }
        d[i] = float64(val)
        arr = arr[:len(arr)-1] // update arr
    }

    var hours, minutes, seconds float64
    hours, minutes, seconds = d[0], d[1], d[2]
    if v := hours + minutes/60 + seconds/3600; v >= 24 {
        return t, fmt.Errorf("[invalid hour] %s | %.4f", timeStr, v)
    }

    return t.Add(time.Duration(hours)*time.Hour + time.Duration(minutes)*time.Minute + time.Duration(seconds)*time.Second), nil
}

测试

for _, timeStr := range []string{
        // ↓ general case
        "39",       // 0 0 39
        "2:7",      // 0 2 7
        "12:2:7",   // 12 2 7
        "23:59:59", // 23 59 59
        // ↓ advance
        "72",    //       1min 12sec
        "72:5",  // 1hour 12min 5sec
        "72:75", // 1hour 13min 15sec
        // ↓ error
        "24:00:00",
        "24:00:01",
        "23:61:00",
    } {
        myT, err := parseTime(timeStr)
        if err == nil {
            fmt.Println(myT.Hour(), myT.Minute(), myT.Second())
        } else {
            fmt.Println(err)
        }
    }

ffdz8vbo

ffdz8vbo2#

如果你想做一些特别的事情,写一个函数。
比如说

package main

import (
    "fmt"
    "strings"
    "time"
)

// Timestamp (h:m:s, m:s, or s) to Duration
func TimestampToDuration(s string) (time.Duration, error) {
    s = strings.TrimSpace(s)
    var lo string
    switch strings.Count(s, ":") {
    case 0:
        lo = "5"
    case 1:
        lo = "4:5"
    default:
        lo = "15:4:5"
    }
    t, err := time.Parse(lo, s)
    if err != nil {
        return 0, err
    }
    return t.Sub(time.Date(0, 1, 1, 0, 0, 0, 0, time.UTC)), nil
}

func main() {
    tests := []struct {
        timestamp string
    }{
        {timestamp: "35:46"},
        {timestamp: "39:58"},
        {timestamp: "01:04:20"},
    }
    for _, tt := range tests {
        d, err := TimestampToDuration(tt.timestamp)
        s := d.Seconds()
        fmt.Printf("%q:  %v  %v  %v\n", tt.timestamp, d, s, err)
    }
}

https://go.dev/play/p/JvHYPEnk-Gy

"35:46":  35m46s  2146  <nil>
"39:58":  39m58s  2398  <nil>
"01:04:20":  1h4m20s  3860  <nil>

相关问题