I have a variable of $i which is seconds in a shell script, and I am trying to convert it to 24 HOUR HH:MM:SS. Is this possible in shell?
7 Answers
Here's a fun hacky way to do exactly what you are looking for =)
date -u -d @${i} +"%T"
Explanation:
- The
date
utility allows you to specify a time, from string, in seconds since 1970-01-01 00:00:00 UTC, and output it in whatever format you specify. - The
-u
option is to display UTC time, so it doesn't factor in timezone offsets (since start time from 1970 is in UTC) - The following parts are GNU
date
-specific (Linux):- The
-d
part tellsdate
to accept the time information from string instead of usingnow
- The
@${i}
part is how you telldate
that$i
is in seconds
- The
- The
+"%T"
is for formatting your output. From theman date
page:%T time; same as %H:%M:%S
. Since we only care about theHH:MM:SS
part, this fits!

- 382,024
- 64
- 607
- 775

- 45,805
- 12
- 84
- 81
-
3Quick and impressive! – Sébastien Clément Dec 19 '14 at 15:09
-
1Look at Alan Tam's answer below for how this works in a Mac/Unix : http://stackoverflow.com/a/21822510/243709 – Aman Alam Jun 12 '15 at 16:50
-
8I think it is worth mentioning this only works for `i` lower than 86400s: `i=86400; date -u -d @${i} +"%T"` will give you `00:00:00` – galaux Apr 02 '16 at 16:28
-
1In Ubuntu 12.04 I get `"invalid date «@»"` . – Tulains Córdova Oct 26 '16 at 20:02
-
2@TulainsCórdova then use `date -u -d @"$i" +"%T"` – Shai Alon Feb 13 '18 at 14:58
-
Don't use the "u" switch if you want the times to be in your local time zone. – Shai Alon Feb 13 '18 at 15:04
-
On macOS this should be `date -u -r "$i" +"%T"` – ryancey Nov 12 '18 at 19:43
-
I'm trying this `$(date -d @${diff} '+%d days %T')` This however returns '1 days 0:01:01' instead of '0 days 0:01:01' when diff=61 – oneindelijk Jun 24 '19 at 14:24
-
date: invalid date ‘@’ – Maveňツ Jul 15 '21 at 14:12
-
Why quote `"%T"` and not `"+%T"` or just no quotes, there's no shell substitution happening – CervEd May 15 '23 at 09:13
Another approach: arithmetic
i=6789
((sec=i%60, i/=60, min=i%60, hrs=i/60))
timestamp=$(printf "%d:%02d:%02d" $hrs $min $sec)
echo $timestamp
produces 1:53:09

- 238,783
- 38
- 220
- 352
-
1may not have been what OP was after, but was exactly what I needed. Thank you. – Tim Kennedy Dec 31 '12 at 17:01
The -d
argument applies to date from coreutils
(Linux) only.
In BSD/OS X, use
date -u -r $i +%T

- 2,027
- 1
- 20
- 33
If $i
represents some date in second since the Epoch, you could display it with
date -u -d @$i +%H:%M:%S
but you seems to suppose that $i
is an interval (e.g. some duration) not a date, and then I don't understand what you want.

- 223,805
- 18
- 296
- 547
-
-
And answered at the same time ;-) (to the minute, likely not to the second). – Jesse Chisholm Feb 27 '20 at 17:02
Here is my algo/script helpers on my site: http://ram.kossboss.com/seconds-to-split-time-convert/ I used this elogant algo from here: Convert seconds to hours, minutes, seconds
convertsecs() {
((h=${1}/3600))
((m=(${1}%3600)/60))
((s=${1}%60))
printf "%02d:%02d:%02d\n" $h $m $s
}
TIME1="36"
TIME2="1036"
TIME3="91925"
echo $(convertsecs $TIME1)
echo $(convertsecs $TIME2)
echo $(convertsecs $TIME3)
Example of my second to day, hour, minute, second converter:
# convert seconds to day-hour:min:sec
convertsecs2dhms() {
((d=${1}/(60*60*24)))
((h=(${1}%(60*60*24))/(60*60)))
((m=(${1}%(60*60))/60))
((s=${1}%60))
printf "%02d-%02d:%02d:%02d\n" $d $h $m $s
# PRETTY OUTPUT: uncomment below printf and comment out above printf if you want prettier output
# printf "%02dd %02dh %02dm %02ds\n" $d $h $m $s
}
# setting test variables: testing some constant variables & evaluated variables
TIME1="36"
TIME2="1036"
TIME3="91925"
# one way to output results
((TIME4=$TIME3*2)) # 183850
((TIME5=$TIME3*$TIME1)) # 3309300
((TIME6=100*86400+3*3600+40*60+31)) # 8653231 s = 100 days + 3 hours + 40 min + 31 sec
# outputting results: another way to show results (via echo & command substitution with backticks)
echo $TIME1 - `convertsecs2dhms $TIME1`
echo $TIME2 - `convertsecs2dhms $TIME2`
echo $TIME3 - `convertsecs2dhms $TIME3`
echo $TIME4 - `convertsecs2dhms $TIME4`
echo $TIME5 - `convertsecs2dhms $TIME5`
echo $TIME6 - `convertsecs2dhms $TIME6`
# OUTPUT WOULD BE LIKE THIS (If none pretty printf used):
# 36 - 00-00:00:36
# 1036 - 00-00:17:16
# 91925 - 01-01:32:05
# 183850 - 02-03:04:10
# 3309300 - 38-07:15:00
# 8653231 - 100-03:40:31
# OUTPUT WOULD BE LIKE THIS (If pretty printf used):
# 36 - 00d 00h 00m 36s
# 1036 - 00d 00h 17m 16s
# 91925 - 01d 01h 32m 05s
# 183850 - 02d 03h 04m 10s
# 3309300 - 38d 07h 15m 00s
# 1000000000 - 11574d 01h 46m 40s
I use C shell, like this:
#! /bin/csh -f
set begDate_r = `date +%s`
set endDate_r = `date +%s`
set secs = `echo "$endDate_r - $begDate_r" | bc`
set h = `echo $secs/3600 | bc`
set m = `echo "$secs/60 - 60*$h" | bc`
set s = `echo $secs%60 | bc`
echo "Formatted Time: $h HOUR(s) - $m MIN(s) - $s SEC(s)"

- 9
- 2
Continuing @Daren`s answer, just to be clear:
If you want to use the conversion to your time zone, don't use the "u" switch, as in: date -d @$i +%T
or in some cases date -d @"$i" +%T
.

- 969
- 13
- 21