I'm trying to find the midpoint of a video, in other words divide the total length by 2
. ffmpeg
gives time in format HOURS:MM:SS.MICROSECONDS
, so ignoring microseconds, how could I get the half way point? I've tried dividing each number (hours/minutes/seconds
) by 2
but this fails in the case of 0:01:00
, for example.

- 514
- 2
- 5
- 23
-
4Can you show some code? What have you tried? – mkopriva Aug 30 '19 at 07:08
-
@mkopriva you caught me before I could properly format my answer :) – Kelly Flet Aug 30 '19 at 07:18
-
1@KellyFlet: You should properly format your question before posting it. – Jonathan Hall Aug 30 '19 at 10:21
-
What's with the downvotes? My question was clear enough for @icza to provide a clear and concise answer without any further clarification. I provided an answer to my own question, so it's not as if I didn't try anything (as is often the complaint) and thought I would not clutter the question with all the different things I tried; instead, keeping it simple. Of course, my answer was not the most succinct, which is why the community is here to provide better answers. – Kelly Flet Aug 30 '19 at 15:39
4 Answers
This can be much simpler (and maybe even faster) if we use the parsing and formatting logic provided by the time
package.
func getDividedTime(times string, n int) (string, error) {
t, err := time.Parse("15:04:05.000000", times)
if err != nil {
return "", err
}
d := t.Sub(time.Time{}) / time.Duration(n)
return time.Time{}.Add(d).Format("15:04:05"), nil
}
Try it on the Go Playground. The weakness of this solution is that it "rejects" inputs having hours > 23
.

- 389,944
- 63
- 907
- 827
-
1I also thought of this first but I wouldn't like to have this upper bound of 24 hours in a timer implementation. Check [this](https://play.golang.org/p/JhoAAc49X1f) one out! – ifnotak Aug 30 '19 at 09:11
Avoid parsing the stderr output of ffmpeg
to get duration (that's what I'm assuming you're doing): it's not meant for machine parsing and is prone to breakage. That's what ffprobe
is for and you won't have to perform additional processing to isolate the duration.
You can use ffprobe
to get duration in seconds which is much easier to divide:
ffprobe -v error -show_entries format=duration -of csv=p=0 input.mp4
Example result:
48.012000
Then use your favorite function or tool to divide by 2. (Example using bc
in a Bash script.)
If you require HOURS:MM:SS.MICROSECONDS
then add the -sexagesimal
option.

- 121,796
- 28
- 232
- 243
An even simpler solution that uses Duration
and not Time
. It allows parsing of hours > 24
. This is usually desired when dealing with timers or in your case, video duration!
func getDividedTime(st string, div int) string {
var h, m, s int
fmt.Sscanf(st, "%d:%d:%d", &h, &m, &s)
seconds := (h*60*60 + m*60 + s) / div
d := time.Duration(int64(seconds) * int64(1e9))
hh, mm, ss := int(d.Hours()), int(d.Minutes()), int(d.Seconds())
return fmt.Sprintf("%d:%02d:%02d", hh, mm-(hh*60), ss-(mm*60))
}
Try it in Go Playground! Feel free to check for invalid input errors returned by fmt.Sscanf()
!

- 4,147
- 3
- 22
- 36
Essentially, you want to:
- Convert everything to seconds
- Divide by 2
- Convert back to hours:minutes:seconds
(and do some formatting for ffmpeg
).
Also note that this answer can be generalized to dividing by n
, instead of just halving.
import (
"fmt"
"strconv"
"strings"
)
// ffmpeg uses the format HOURS:MM:SS.MICROSECONDS
func getDividedTime(time string, n int) string {
times := strings.Split(time, ":")
// get rid of microseconds
times[2] = strings.Split(times[2], ".")[0]
// conversions
minutesToSeconds := 60
hoursToSeconds := 60 * minutesToSeconds
// convert everything to seconds
seconds, _ := strconv.Atoi(times[2])
minutes, _ := strconv.Atoi(times[1])
hours, _ := strconv.Atoi(times[0])
secMinutes := minutes * minutesToSeconds
secHours := hours * hoursToSeconds
totalSeconds := seconds + secHours + secMinutes
totalSeconds /= n
// update time and grab seconds
newSeconds := totalSeconds % 60
totalSeconds /= 60
// update time and grab minutes
newMinutes := totalSeconds % 60
totalSeconds /= 60
newHours := totalSeconds % 3600
times[0] = strconv.Itoa(newHours)
times[1] = strconv.Itoa(newMinutes)
times[2] = strconv.Itoa(newSeconds)
// zero padding for seconds and minutes (not hours)
if newMinutes < 10 {
times[1] = "0" + times[1]
}
if newSeconds < 10 {
times[2] = "0" + times[2]
}
dividedTime := strings.Join(times[:], ":")
return dividedTime
}
func main() {
// create some tests
tables := []struct {
inputTime string
correctTime string
}{
{"0:11:28.956000", "0:05:44"},
{"1:00:00.111999", "0:30:00"},
{"1:15:00.111999", "0:37:30"},
{"1:45:00.111999", "0:52:30"},
{"0:59:00.000000", "0:29:30"},
{"2:04:22.123151", "1:02:11"},
{"0:00:00.000000", "0:00:00"},
{"0:00:03.000000", "0:00:01"},
{"0:00:04.000000", "0:00:02"},
{"0:20:00.000000", "0:10:00"},
{"0:02:00.000000", "0:01:00"},
{"99:00:00.000000", "49:30:00"},
}
// ensure output matches truth values
for _, table := range tables {
output := getDividedTime(table.inputTime, 2) // cut time in half
if output != table.correctTime {
fmt.Printf("failure: expected: %s, got: %s\n", table.correctTime, output)
}
}
}

- 514
- 2
- 5
- 23
-
*ffmpeg uses the format HOURS:MM:SS.MICROSECONDS* --> only in certain display fields. It will accept decimal seconds in almost every function. – Gyan Aug 30 '19 at 07:52