Convert a time span in seconds to formatted time in shell
Asked Answered
I

6

44

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?

Infralapsarian answered 16/11, 2012 at 18:59 Comment(0)
B
97

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 tells date to accept the time information from string instead of using now
    • The @${i} part is how you tell date that $i is in seconds
  • The +"%T" is for formatting your output. From the man date page: %T time; same as %H:%M:%S. Since we only care about the HH:MM:SS part, this fits!
Barbed answered 16/11, 2012 at 19:17 Comment(10)
Look at Alan Tam's answer below for how this works in a Mac/Unix : https://mcmap.net/q/95479/-convert-a-time-span-in-seconds-to-formatted-time-in-shellKarim
I 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:00Tilford
In Ubuntu 12.04 I get "invalid date «@»" .Tishtisha
@TulainsCórdova then use date -u -d @"$i" +"%T"Dnepropetrovsk
Don't use the "u" switch if you want the times to be in your local time zone.Dnepropetrovsk
On macOS this should be date -u -r "$i" +"%T"Skitter
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=61Diabolic
Why quote "%T" and not "+%T" or just no quotes, there's no shell substitution happeningBastardize
to make it work for even more than 86400 seconds: date -u +"$(( ${i} / 86400 ))d %T" -d "@${i}"Schuh
@Diabolic this is to be expected, because date does not display time spans but actual dates (technically it is counted from 1970-01-01T00:00:00+00:00). and quoting from the man page: "%d day of month (e.g., 01)" - so in your case date displays the 1970-01-01T00:01:01+00:00 but just the selected parts of it and %-d results in 1 because there is not a day 0 of a month. || for an even more hacky way to make it work for time spans >=1 day, have a look a my previous comment.Schuh
H
22

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

Heracliteanism answered 16/11, 2012 at 23:16 Comment(1)
may not have been what OP was after, but was exactly what I needed. Thank you.Ullman
S
16

The -d argument applies to date from coreutils (Linux) only.

In BSD/OS X, use

date -u -r $i +%T
Sepulcher answered 17/2, 2014 at 6:48 Comment(0)
B
2

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.

Bugbane answered 16/11, 2012 at 19:17 Comment(2)
Same (duplicate) as @Barbed with the +%T.Dnepropetrovsk
And answered at the same time ;-) (to the minute, likely not to the second).Hubert
C
1

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
Cerebral answered 7/1, 2015 at 13:43 Comment(0)
A
0

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)"
Aikens answered 24/11, 2016 at 9:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.