Bash convert two Epoch times to remaining time - bash

I'm trying to convert two Epoch (Unix timestamp) dates to human readable date (time left)
AT=$(echo $RES | jq '.results[0].unixtime' | tr -d '"') # Returns unix time in JST.
NOW=$(TZ=":Asia/Tokyo" date +%s) # Returns current time in JST
DIFF=$(echo $AT-$NOW | bc)
As an example;
AT=1470038400
NOW=1470032871
DIFF=5529
How do I get the remaining time between the two in the following format: DAYd HOURh MINm SECs?

You can try the following
printf "%dd %dh %dm %ds\n" $(( DIFF / (3600 * 24) )) $(( (DIFF / 3600 ) % 24)) $(( (DIFF / 60) % 60)) $((DIFF % 60))

Related

Bash: Display Nano Seconds With Date

With date it is possible to generate formatted time strings like
date +"%Y-%m-%d-%H:%M:%S.%N"
With date it is also possible to create unix timestamps in nano seconds. Using
NANO_TIMESTAMP=$(date +%s%N)
Is it possible to use date to read in a nano second timestamp to create a formatted date string?
How can I pass a nano second timestamp to date?
I tried:
date -d$NANO_TIMESTAMP +%H:%M:%S.%N
date: invalid date ‘1550736813798767689’
date -d#$NANO_TIMESTAMP +"%Y-%m-%d-%H:%M:%S.%N"
date: time 1550736813798767689 is out of range
You can do that by first by converting the nanosecond value in EPOCH to seconds value in EPOCH and then use that for conversion to human readable strings
nano=1550736813798767689
date -d#"$(( $nano / 1000000000 ))" +"%Y-%m-%d-%H:%M:%S.%N"
For even more accurate representation back, take the modulo of the nano second value
withNano="$(( $nano % 1000000000 ))"
withoutNano="$(date -d#"$(( $nano / 1000000000 ))" +"%Y-%m-%d-%H:%M:%S")"
echo "$withoutNano.$withNano"
So putting this together in a wrapper function
from_nano_to_readable() {
(( $# )) || { printf '%s\n' 'provide atleast one argument' >&2 ; }
input="$1"
withNano="$(( $input % 1000000000 ))"
withoutNano="$(date -d#"$(( $input / 1000000000 ))" +"%Y-%m-%d-%H:%M:%S")"
printf '%s\n' "$withoutNano.$withNano"
}
and call it as
from_nano_to_readable 1550736813798767690
2019-02-21-03:13:33.798767690
Yes, but you have to do the math (division and modulo) yourself.
> set -x
> NANO_TIMESTAMP=$(date +%s%N)
++ date +%s%N
+ NANO_TIMESTAMP=1550740150623261543
> date -d#$((NANO_TIMESTAMP/(1000*1000*1000))).$((NANO_TIMESTAMP%(1000*1000*1000))) +%Y-%m-%d-%H:%M:%S.%N
+ date -d#1550740150.623261543 +%Y-%m-%d-%H:%M:%S.%N
2019-02-21-10:09:10.623261543
Like this but without math.
NANO_TIMESTAMP=$(date +%s%N)
secs=$(printf "%1d\n" ${NANO_TIMESTAMP: 0 : -9})
nanos=${NANO_TIMESTAMP: -9 : 9 }
printf '\r%s' $(TZ=UTC date -d#$secs.$nanos +"%Y-%m-%d-%H:%M:%S.%N")
With printf "%1d" I want to make sure, that there is at least one zero in the secs variable.

Subtraction in bash

printf "$(( $(date '+%H * 60 + %M') ))\n"
date '+%H * 60 + %M' | bc
date '+%H 60 * %M + p' | dc
The above will give the minutes that have passed in the day.
Using any of the above time outputs, how do I subtract it from the total minutes in the day (i.e., 1440) to display the minutes left in the day?
Given your three exemplars, what about:
printf "$(( 1440 - ( $(date '+%H * 60 + %M') ) ))\n"
date '+1440 - ( %H * 60 + %M )' | bc
date '+1440 %H 60 * %M + - p' | dc
You don't quite need all the spaces added, but you do need the added parentheses.
The following computes the difference of timestamps in minutes:
printf '%d\n' $(( ( $(date -d 'tomorrow 00:00' '+%s') - $(date '+%s') ) / 60 ))
Note the use of format string %d\n. You shouldn't pass your data in the first argument for printf, as the first argument is the format string, and printf may interpret some sequences as the format specifiers (%d as integer specifier, %s as string specifier, etc.).
You could use something like this:
minutesElapsed="$(date '+%H * 60 + %M' | bc)"
minutesDay="1440"
minutesLeft="$(($minutesDay-$minutesElapsed))"
Output:
echo "$minutesLeft"
332
Short version:
echo "$((1440-$(date '+%H * 60 + %M' | bc)))"

How can I echo minutes since midnight in any timezone using the date command on OS X?

Here's what isn't working:
> echo $(( ($(date +%s) - $(date +%s -d$(date +%Y-%m-%d))) / 60 ))
date: illegal time format
usage: date [-jnu] [-d dst] [-r seconds] [-t west] [-v[+|-]val[ymwdHMS]] ...
[-f fmt date | [[[mm]dd]HH]MM[[cc]yy][.ss]] [+format]
I've also tried:
> echo $(date +%s -f%Y-%m-%d $(date +%Y-%m-%d))
The following works, but only with a fixed UTC offset that will break during standard time:
> echo $[ ( ( $(date "+%s") - 28800 ) % 86400 ) / 60 ]
Reference: OS X date manual
The number of minutes (or seconds) since midnight can be computed directly from a time alone.
echo $(( $(date "+10#%H * 60 + 10#%M") )) # Minutes since midnight
echo $(( $(date "+(10#%H * 60 + 10#%M) * 60 + 10#%S") )) # Seconds since midnight
Note that this requires only minimal support from date, so will work with either GNU or BSD date.
This works by having date output a string which can be passed directly to the shell's arithmetic expression construct.
Thanks to Petesh for pointing out the need to force numbers with leading zeros to be treated as decimal.
The problem with your first attempt is that you're trying to apply a gnu date option to the BSD date that's on OSX. This has caught me out a lot as I've tried to make scripts compatible between both platforms.
One way is:
seconds_now=$(date +%s)
seconds_midnight=$(date -j -f'%Y-%m-%d %H:%M:%S' "$(date +%Y-%m-%d) 00:00:00" +%s)
minutes_now=$(((seconds_now - seconds_midnight) / 60))
You have to use the full format for the time, otherwise date takes the actual hours, minutes and seconds of the current time, which is not what you want.
Another way is:
Use date +%z to get the offset from UTC, and apply it to the number of minutes past midnight on the day.
offset=$(date +%z) # get TZ offset as [+-]<HH><MM> - for *now*
sign=${offset:0:1} # get sign
hours=${offset:1:2} # get hours
mins=${offset:3:2} # get minutes
minoff=$((10#$hours * 60 + 10#$mins)) # offset in minutes from UTC
from_midnight_utc_mins=$((($(date +%s) % 86400) / 60))
from_midnight_local=$(($from_midnight_utc_mins $sign $minoff))
It's seriously gack, though.
I use 10# for all the numbers in the minoff calculation to prevent the case where two digit numbers with a leading 0 are interpreted as octal, which can yield miscalculations/errors.

shell script: time difference

This is my script to count the time difference between now and my date.
Is there any other way to do the same operation more efficiently?
#!/bin/bash
mydate=20141224 # yyyymmdd
mytime=00:00:00 #hh:mm:ss
current=$(date +%s)
target=$(date -d "$mydate $mytime" +%s)
diff=$((target-current))
day=$((diff / 86400))
left=$((diff - (day*86400)))
diff=$((left))
hour=$((diff / 3600))
left=$((diff - (hour * 3600)))
diff=$((left))
min=$((diff / 60))
left=$((diff -(min * 60)))
diff=$((left))
sec=$((diff))
echo $day"d" $hour"h" $min"min" $sec"sec"

shell scripting time difference in variables

How can i get the time difference in 2 variables in shell
say i have 4 variables-
t1=07:50:19:612
t2=07:52:14:697
t3=10:20:54:201
t4=11:02:09:716
and i want to find difference in times
result=(t2-t1)+(t4-t3)
If milliseconds can't be ignored, I suggest you to define own shell functions :
function getMillis()
{
val=($(echo $1|grep -Eo "(00|[1-9][0-9]*)"))
mil=$(( ${val[0]} * 3600000 ))
mil=$(($mil + ${val[1]}*60000))
mil=$(($mil + ${val[2]}*1000))
mil=$(($mil + ${val[3]}))
echo $mil
}
function format()
{
hr=$(( $1 / 3600000 ))
mn=$(( $1 % 3600000 / 60000 ))
sc=$(( $1 % 60000 / 1000 ))
ms=$(( $1 % 1000 ))
echo "$hr hours, $mn mins, $sc secs, $ms millisecs"
}
Then you can obtain the desired result as :
res=$(( $(getMillis $t2) - $(getMillis $t1) + $(getMillis $t4) - $(getMillis $t3) ))
format $res
The code above is just to show how this can be done. There may be other elegant solutions present.
As far as I know, shell do not support date format for millisecond. The command date can handle time format, of which the precision is rounded up to second.
The following is an example for time format with second as mininum time unit:
t1=07:50:19
t2=07:52:14
t3=10:20:54
t4=11:02:09
t10=$(date -d $t1 +%s)
t20=$(date -d $t2 +%s)
t30=$(date -d $t3 +%s)
t40=$(date -d $t4 +%s)
result=$(expr $t20 - $t10 + $t40 - $t30)
echo $result
hour=$(expr $result / 3600)
min=$(expr $result % 3600 / 60)
sec=$(expr $result % 60)
echo $hour:$min:$sec

Resources