Bash: Date/Time math problems

Brian

The following script takes two inputs, sourceFile="${1}" and trimFile="${2}". The $sourceFile is a video file that is to be trimmed into multiple new files based on data in the $trimFile. The $trimFile is a text file of the following structure (actual file related to this problem):

00:49:30,00:53:00 DescriptionA
03:33:30,03:38:40 DescriptionB
04:54:32,04:55:37 DescriptionC

The $trimFile uses both commas and spaces as delimiters in the script below. While rather obvious, each line represents a clip to be created from the $sourceFile. Further, the first field is the starting time of the clip to be trimmed, the second field is the ending time of the clip to be trimmed and the last field is a description of the clip.

My problem isn't with the trimming of the $sourceFile. I am trying to rename the new clips with a date and time relative to the original video files date. Each $sourceFile and $trimFile is named like the following example (which are the actual file names I am presently using): 2017-05-15_14-17-22 (2017-05-16 00-45-41.151674100 -0400) (HEVC27).mp4 and 2017-05-15_14-17-22 (2017-05-16 00-45-41.151674100 -0400) (HEVC27).txt, respectively. Again, while rather obvious, the date components are Year: 2017, Month: 05, Day: 16, Hour: 14, Minute: 17, and Second:22 (ignore the date is the parenthesis as it is an old reference with the wrong UTC adjusted date).

It should be evident in the script below how the date/time in the file is extracted as well as how the date/time within the $trimFile are extracted. To illustrate the problem, I need to show it both with and without certain lines commented out. Here it is with certain lines commented out (it will make sense as I discuss it next).

01: sourceFile="${1}"
02: trimFile="${2}"
03: 
04: IFS=$'\n'
05: 
06: dos2unix "$trimFile"
07: numberOfSegments=`cat "$trimFile" | wc -l`
08: numberOfSegments=$((numberOfSegments + 1))
09: extension=`echo "$sourceFile" | awk -F'.' '{print $NF}'`
10: 
11: base=`echo "$sourceFile" | sed -e "s|.$extension||g"`
12: 
13: #~/bin/ffmpeg -i "${sourceFile}" -c:v copy "/dev/shm/$base.${extension}"
14: #sourceFile="/dev/shm/$base.${extension}"
15: 
16: # File date/time information
17: origYear="${sourceFile:0:4}"
18: origMonth="${sourceFile:5:2}"
19: origDay="${sourceFile:8:2}"
20: origHour="${sourceFile:11:2}"
21: origMinute="${sourceFile:14:2}"
22: origSecond="${sourceFile:17:2}"
23: 
24: origDate="${origYear}-${origMonth}-${origDay} ${origHour}:${origMinute}:${origSecond}"
25: 
26: for (( i=1;i<="$numberOfSegments";i++ ))
27:     do
28: 
29:         lineEntry=`cat "$trimFile" | head -"$i" | tail -1`
30: 
31:         startHour=`echo "$lineEntry" | awk -F'[:,]' '{print $1}'`
32:         startMinute=`echo "$lineEntry" | awk -F'[:,]' '{print $2}'`
33:         startSecond=`echo "$lineEntry" | awk -F'[:,]' '{print $3}'`
34: 
35:         endHour=`echo "$lineEntry" | awk -F'[:,]' '{print $4}'`
36:         endMinute=`echo "$lineEntry" | awk -F'[:,]' '{print $5}'`
37:         endSecond=`echo "$lineEntry" | awk -F'[:,]' '{print $6}'`
38: 
39:         description=`echo "$lineEntry" | awk -F'[:, ]' '{print $7}'`
40: 
41:         beginSeconds=`awk "BEGIN {print ($startHour*3600+$startMinute*60+$startSecond)}"`
42:         stopSeconds=`awk "BEGIN {print ($endHour*3600+$endMinute*60+$endSecond)}"`
43:         duration=`awk "BEGIN {print $stopSeconds-$beginSeconds}"`
44: 
45:         newDate=$(date -d "@$(( $(date -d "${origDate}" +%s) + ${beginSeconds}))" +'%Y-%m-%d_%H-%M-%S')
46: 
47:         new="${newDate}_${description}"
48:         echo "${lineEntry}"
49:         echo "${origDate}"
50:         echo "${beginSeconds}"
51:         echo "${new}"
52:         echo ""
53:         
54:         #~/bin/ffmpeg -n -vsync drop -fflags +genpts -i "$sourceFile" -ss "$beginSeconds" -t "$duration" -c:v libx265 -crf 27 -preset slow "$new.mkv"
55: 
56: 
57:     done
58:     
59: #rm "/dev/shm/${base}.${extension}"

When I execute the script in this form, I get the following output corresponding to lines 48-52 in the script:

01: 00:49:30,00:53:00 DescriptionA
02: 2017-05-15 14:17:22
03: 2970
04: 2017-05-15_15-06-52_DescriptionA
05: 
06: 03:33:30,03:38:40 DescriptionB
07: 2017-05-15 14:17:22
08: 12810
09: 2017-05-15_17-50-52_DescriptionB
10: 
11: 04:54:32,04:55:37 DescriptionC
12: 2017-05-15 14:17:22
13: 17672
14: 2017-05-15_19-11-54_DescriptionC
15: 
16: 04:54:32,04:55:37 DescriptionC
17: 2017-05-15 14:17:22
18: 17672
19: 2017-05-15_19-11-54_DescriptionC

As you can see, the expected new date/time is output correctly in lines 4,9,14 (I am unsure why the last line of the $trimFile is output twice but that isn't my concern at the moment).

The problem lies is the actual renaming of the file when I remove the commented lines (lines 13, 14, 54, 59) from the script so that the script now looks like this:

01: sourceFile="${1}"
02: trimFile="${2}"
03: 
04: IFS=$'\n'
05: 
06: dos2unix "$trimFile"
07: numberOfSegments=`cat "$trimFile" | wc -l`
08: numberOfSegments=$((numberOfSegments + 1))
09: extension=`echo "$sourceFile" | awk -F'.' '{print $NF}'`
10: 
11: base=`echo "$sourceFile" | sed -e "s|.$extension||g"`
12: 
13: ~/bin/ffmpeg -i "${sourceFile}" -c:v copy "/dev/shm/$base.${extension}"
14: sourceFile="/dev/shm/$base.${extension}"
15: 
16: # File date/time information
17: origYear="${sourceFile:0:4}"
18: origMonth="${sourceFile:5:2}"
19: origDay="${sourceFile:8:2}"
20: origHour="${sourceFile:11:2}"
21: origMinute="${sourceFile:14:2}"
22: origSecond="${sourceFile:17:2}"
23: 
24: origDate="${origYear}-${origMonth}-${origDay} ${origHour}:${origMinute}:${origSecond}"
25: 
26: for (( i=1;i<="$numberOfSegments";i++ ))
27:     do
28: 
29:         lineEntry=`cat "$trimFile" | head -"$i" | tail -1`
30: 
31:         startHour=`echo "$lineEntry" | awk -F'[:,]' '{print $1}'`
32:         startMinute=`echo "$lineEntry" | awk -F'[:,]' '{print $2}'`
33:         startSecond=`echo "$lineEntry" | awk -F'[:,]' '{print $3}'`
34: 
35:         endHour=`echo "$lineEntry" | awk -F'[:,]' '{print $4}'`
36:         endMinute=`echo "$lineEntry" | awk -F'[:,]' '{print $5}'`
37:         endSecond=`echo "$lineEntry" | awk -F'[:,]' '{print $6}'`
38: 
39:         description=`echo "$lineEntry" | awk -F'[:, ]' '{print $7}'`
40: 
41:         beginSeconds=`awk "BEGIN {print ($startHour*3600+$startMinute*60+$startSecond)}"`
42:         stopSeconds=`awk "BEGIN {print ($endHour*3600+$endMinute*60+$endSecond)}"`
43:         duration=`awk "BEGIN {print $stopSeconds-$beginSeconds}"`
44: 
45:         newDate=$(date -d "@$(( $(date -d "${origDate}" +%s) + ${beginSeconds}))" +'%Y-%m-%d_%H-%M-%S')
46: 
47:         new="${newDate}_${description}"
48:         echo "${lineEntry}"
49:         echo "${origDate}"
50:         echo "${beginSeconds}"
51:         echo "${new}"
52:         echo ""
53:         
54:         ~/bin/ffmpeg -n -vsync drop -fflags +genpts -i "$sourceFile" -ss "$beginSeconds" -t "$duration" -c:v libx265 -crf 27 -preset slow "$new.mkv"
55: 
56: 
57:     done
58:     
59: rm "/dev/shm/${base}.${extension}"
60: 
61: 

The files created by the script are named as follows:

1969-12-31_19-49-30_DescriptionA.mkv
1969-12-31_22-33-30_DescriptionB.mkv
1969-12-31_23-54-32_DescriptionC.mkv

Obviously, the dates used to name the file isn't anything like the output to stout created when I didn't re-encode the video but rather just tested that the new date variables were being calculated correctly.

So, my question boils down to this, why is, after doing some date/time math, the date/time correct when echoed to stout but grossly wrong when used to name the files once encoded.

Thanks!

Kamil Maciorowski

why is, after doing some date/time math, the date/time correct when echoed to stout but grossly wrong when used to name the files once encoded?

By uncommenting

sourceFile="/dev/shm/$base.${extension}"

you made the lines that follow extract wrong fragments.

origYear="${sourceFile:0:4}"
origMonth="${sourceFile:5:2}"
…

E.g. now $origYear expands to /dev.

I would expect date -d to throw errors similar to date: invalid date '/dev-sh-/2 17:05:15'. Maybe your date -d doesn't validate its input (or did you ignore the errors?).

You can fix this particular problem by assigning substrings to origYear, origMonth etc. before you change the value of sourceFile.

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related