Subtraction in bash - 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)))"

Related

Bash convert two Epoch times to remaining time

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))

How can I pass the result of a command to another command in one line?

How can I pass minutes since midnight to a cli in one line?
This works:
echo $[ ( ( `date "+%s"` - 28800 ) % 86400 ) / 60 ]
// Correctly returns minutes since midnight in PST
But how can I pass the same into another command?
This doesn't work:
my_cli --json '{"minutes" : ' $[ ( ( `date \"+%s\"` - 28800 ) % 86400 ) / 60 ] '}'
Returns:
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]
ERROR: "my_cli json" was called with arguments ["-300", "}"]
Usage: "my_cli json"
I also tried:
my_cli --json "{\"minutes\" : \$[ ( ( $(date "+%s") - 28800 ) % 86400 ) / 60 ] }"
And I received the following error:
...unexpected token at '{"connection" : $[ ( ( 1432139956 - 28800 ) % 86400 ) / 60 ] }' (JSON::ParserError)`
Assuming that the number of minutes should be an integer rather than a string:
my_cli --json '{"minutes" : '"$(( ( ( $(date +%s) - 18000 ) % 86400 ) / 60 ))"' }'
The following provides minutes since midnight for any timezone, with the proviso that "midnight" and "now" might have different time zone offsets:
$(( ($(date +%s) - $(date +%s -d$(date +%Y-%m-%d))) / 60 ))
(I've used the forms $((...)) and $(...) instead of the obsolete and deprecated $[...] and `...`.)
You probably need to provide a single argument to your CLI, so you need to be careful with quoting. For example:
my_cli --json "{\"minutes\" : $(( ($(date +%s) - $(date +%s -d$(date +%Y-%m-%d))) / 60 ))}"

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