Get remaining seconds from input HH:mm in bash (OSX) - bash

I want write a simple bash script. Input is "HH:mm" string and the output is remaining seconds to that time, for example
$ getsec.sh 12:55 # now it's 12:30. so 25 minutes left.
1500
I thought using date command would probably the solution of this. But it seems like it doesn't exist the simple way that I can use.
(Added after checking some answers)
It looks like the date command depends on OS and version.
I use OSX, and the result of the suggested answer is as follows.
$ date -d '12:55' '+%s'
usage: date [-jnu] [-d dst] [-r seconds] [-t west] [-v[+|-]val[ymwdHMS]] ...
[-f fmt date | [[[mm]dd]HH]MM[[cc]yy][.ss]] [+format]

The *BSD (and thus OSX) date command has a different option syntax than GNU date, which is ubiquitous on Linux and available on many other platforms (including OSX, with Homebrew, Fink, etc).
now=$(date -j +%s)
then=$(date -j -f '%H:%M' 12:55 +%s)
echo "$((then-now)) seconds left"
For a portable solution, maybe use a portable scripting language instead.

You can do:
ts=$(date -d '12:55' '+%s')
now=$(date '+%s')
diff=$((ts-now))

This script accepts the target time as a command line argument (accessed in the script as the parameter $1
#!/bin/bash
current_time=$(date +%s)
target_time=$(date +%s --date="$1")
# evaluate the difference using an arithmetic expression
echo "seconds remaining to target time: "$(( target_time - current_time ))
usage:
% ./get_sec.sh "22:00"
output:
seconds remaining to target time: 16151

Related

Bash: Calculate the time differences in hours from input like "YYYYMMDDHH"

I have two dates in forms like: YYYYMMDDHH and want to calculate the differences (in hours) between these two dates. For example
start_date=1996010100
end_date=1996010122
which stands for two dates: 1996-01-01 00:00:00 and 1996-01-01 22:00:00. I want to use date to calculate the difference in hours, the result shall be 22 hours. I tried with
START=$(date -d "$start_date" +"%s")
END=$(date -d "$end_date" +"%s")
HOURS=$(bc -l <<< "($END - $START) / 3600")
but it failed...
So how can I do this? Thanks!
For performance reasons we want to limit the number of sub-process calls we need to invoke:
use bash substring functionality to convert inputs into usable date/time strings
use bash math to replace bc call
bash substring functionality to break the inputs into a usable date/time format, eg:
# convert to usable date/time format:
$ start_date=1996010100
$ echo "${start_date:0:4}-${start_date:4:2}-${start_date:6:2} ${start_date:8:2}:00:00"
1996-01-01 00:00:00
# convert to epoch/seconds:
$ start=$(date -d "${start_date:0:4}-${start_date:4:2}-${start_date:6:2} ${start_date:8:2}:00:00" +"%s")
$ echo $start
820476000
Applying to ${end_date} and using bash math:
$ end_date=1996010122
$ end=$(date -d "${end_date:0:4}-${end_date:4:2}-${end_date:6:2} ${end_date:8:2}:00:00" +"%s")
$ echo $end
820555200
$ hours=$(( (end - start) / 3600))
$ echo $hours
22
This leaves us with 2 sub-process calls ($(date ...)). While other languages/tools (awk, perl, etc) can likely speed this up a bit, if you need to store the result in a bash variable then you're looking at needing at least 1 sub-process call (ie, hours=$(awk/perl/??? ...)).
If performance is really important (eg, needing to perform this 1000's of times) take a look at this SO answer that uses a fifo, background date process and io redirection ... yeah, a bit more coding and a bit more convoluted but also a bit faster for large volumes of operations.
busybox date can do the trick
start_date=1996010100
end_date=1996010122
START=$(busybox date -D "%Y%m%d%H" -d "$start_date" +"%s")
END=$(busybox date -D "%Y%m%d%H" -d "$end_date" +"%s")
HOURS=$(bc -l <<< "scale=0;($END - $START) / 3600")
echo $HOURS
If it's possible for you to use a more fully-featured scripting language like Python, it'll provide a much more pleasant and understandable date parsing experience, and is probably installed by default (datetime is also a standard Python library)
Structured with shell vars
start_date=1996010100
end_date=1996010122
python -c "import datetime ; td = datetime.datetime.strptime('${end_date}', '%Y%m%d%H') - datetime.datetime.strptime('${start_date}', '%Y%m%d%H') ; print(int(td.total_seconds() / 3600))"
Structured to read dates and format code from stdin
echo '%Y%m%d%H' 1996010100 1996010122 | python -c "import datetime,sys ; fmt, date_start, date_end = sys.stdin.read().strip().split() ; td = datetime.datetime.strptime(date_end, fmt) - datetime.datetime.strptime(date_start, fmt) ; print(int(td.total_seconds() / 3600))"
Should work with both Python 3 and Python 2.7
format codes available here (1989 C standard)
https://docs.python.org/3/library/datetime.html#strftime-and-strptime-format-codes
which stands for two dates: 1996-01-01 00:00:00
So convert it to that form if it stands for it.
start_date=1996010100
start_date=$(sed -E 's/(....)(..)(..)(..)/\1-\2-\3 \4:00:00/' <<<"$start_date")
start=$(date -d "$start_date" +"%s")
and the same with end.
the most simple way is to install "dateutils" using this command
sudo apt-get install dateutils
Run these commands to get the difference in seconds:
dateutils.ddiff -i '%Y%m%d%H%M%S' 20200817040001 20210817040101
output:
31536060s
next step: Simply divide by 86400 to get the number of days or similarly for hours and minutes :)

How to subtract 60 minutes from current time in unix

I'm currently creating a shell script that will run a python code once an hour that collects, processes, and displays data from a radar for the previous hour.
The python code I am using requires a UTC begin time and end time in format "YYYYMMDDHHmm". So far, I have found using the unix command date -u +"%Y%m%d%H%M" will retrieve my current time in the correct format, but I have not been able to find a way to subtract 60 minutes from this first time and have it output the "start" time/
code I have tried:
date +"%Y%m%d%H%M-60" >> out: 201908201833-60
now= date -u +"%Y%m%d%H%M" >> out:201908201834
echo "$now - 60" >> out: - 60
I'm just starting to self teach/learn shell coding and I am more comfortable with python coding which is why my attempts are set up more like how you would write with python. I'm sure there is a way to store the variable and have it subtract 60 from the end time, but I have not been able to find a good online source for this (both on here and via Google).
You can use -d option in date:
date -u +"%Y%m%d%H%M" -d '-60 minutes'
or else subtract 1 hour instead of 60 minutes:
date -u +"%Y%m%d%H%M" -d '-1 hour'
To be able to capture this value in a variable, use command substitution:
now=$(date -u +"%Y%m%d%H%M" -d '-1 hour')
On OSX (BSD) use this date command as -d is not supported:
now=$(date -u -v-1H +"%Y%m%d%H%M")
Your current attempt has some simple shell script errors.
now= date -u +"%Y%m%d%H%M" >> out:201908201834
This assigns an empty string to the variable now and then runs the date command as previously. If the plan is to capture the output to the variable now, the syntax for that is
now=$(date -u +"%Y%m%d%H%M")
Next up, you try to
echo "$now - 60"
which of course will output the literal string
201908201834 - 60
rather than perform arithmetic evaluation. You can say
echo "$((now - 60))"
to subtract 60 from the value and echo that -- but of course, date arithmetic isn't that simple; subtracting 60 from 201908210012 will not produce 201908202312 like you would hope.
If you have GNU date (that's a big if if you really want to target any Unix) you could simply have done
date -u -d "60 minutes ago" +%F%H%M
but if you are doing this from Python anyway, performing the date extraction and manipulation in Python too will be a lot more efficient as well as more portable.
from datetime import datetime, timedelta
dt = datetime.strptime(when,'%Y%m%d%H%M')
print(dt - timedelta(minutes=60))
The shell command substitution $(command) and arithmetic evaluation $((expression)) syntaxes look vaguely similar, but are really unrelated. Both of them have been introduced after the fundamental shell syntax was already stable, so they had to find a way to introduce new syntax which didn't already have a well-established meaning in the original Bourne shell.

Time difference between two dates in the log files

I am trying to get the time difference between two dates as given below in Bash script. However I am not successful
head_info: 05-31-2017:04:27:37
tail_info: 05-31-2017:04:30:57
the problem is that after Reformation above time and while trying to calculate in seconds due to space, it is ignoring time.
This is my script:
fm_head_info=(${head_info:6:4}"-"${head_info:0:2}"-"${head_info:3:2}" \
"${head_info:11:8})
fm_tail_info=(${tail_info:6:4}"-"${tail_info:0:2}"-"${tail_info:3:2}" \
"${tail_info:11:8})
$ fm_head_info
-bash: 2017-05-31: command not found
Thank you
Let's define your shell variables:
$ tail_info=05-31-2017:04:30:57
$ head_info=05-31-2017:04:27:37
Now, let's create a function to convert those dates to seconds-since-epoch:
$ date2sec() { date -d "$(sed 's|-|/|g; s|:| |' <<<"$*")" +%s; }
To find the time difference between those two date in seconds:
$ echo $(( $(date2sec "$tail_info") - $(date2sec "$head_info") ))
200
As written above, this requires bash (or similar advanced shell) and GNU date. In other words, this should work on any standard Linux. To make this work on OSX, some changes to the date command will likely be necessary.
How it works
Starting with the innermost command inside the function date2sec, we have:
sed 's|-|/|g; s|:| |' <<<"$*"
In the argumnet to the function, this replaces all - with / and it replaces the first : with a space. This converts the the dates from the format in your input to one that the GNU date function will understand. For example:
$ sed 's|-|/|g; s|:| |' <<<"05-31-2017:04:30:57"
05/31/2017 04:30:57
With this form, we can use date to find seconds-since-epoch:
$ date -d "05/31/2017 04:30:57" +%s
1496230257
And, for the head_info:
$ date -d "05/31/2017 04:27:37" +%s
1496230057
Now that we have that, all that is left is to subtract the times:
$ echo $(( 1496230257 - 1496230057 ))
200
Your immediate issue is the inclusion of erroneous (...) surrounding your string indexed assignment and your questionable quoting. It looks like you intended:
fm_head_info="${head_info:6:4}-${head_info:0:2}-${head_info:3:2} ${head_info:11:8}"
fm_tail_info="${tail_info:6:4}-${tail_info:0:2}-${tail_info:3:2} ${tail_info:11:8}"
Your use of string indexes is correct, e.g.
#!/bin/bash
head_info=05-31-2017:04:27:37
tail_info=05-31-2017:04:30:57
fm_head_info="${head_info:6:4}-${head_info:0:2}-${head_info:3:2} ${head_info:11:8}"
fm_tail_info="${tail_info:6:4}-${tail_info:0:2}-${tail_info:3:2} ${tail_info:11:8}"
echo "fm_head_info: $fm_head_info"
echo "fm_tail_info: $fm_tail_info"
Example Use/Output
$ bash headinfo.sh
fm_head_info: 2017-05-31 04:27:37
fm_tail_info: 2017-05-31 04:30:57
You can then do something similar with the differences in date -d "$var" +%s as John shows in his answer to arrive at the time difference. Note, string indexes are limited to bash, while a sed solution (absent the herestring) would be portable on all POSIX shells.

Using date to get tomorrows date in Bash

I want to write a bash script that will run on a given but process data with next days date, My current approach is to get the unix time stamp and add a days worth of seconds to it, but I cant get it working, and haven't yet found what I'm looking for online.
Here's what I've tried, I feel like the problem is that its a string an not a number, but I dont know enough about bash to be sure, is this correct? and how do I resolve this?
today="$(date +'%s')"
tomorrow="$($today + 86400)"
echo "$today"
echo "$tomorrow"
If you have gnu-date then to get next day you can just do:
date -d '+1 day'
Some of the answers for this question depend on having GNU date installed. If you don't have GNU date, you can use the built-in date command with the -v option.
The command
$ date -v+1d
returns tomorrow's date.
You can use it with all the standard date formatting options, so
$ date -v+1d +%Y-%m-%d
returns tomorrow's date in the format YYYY-MM-DD.
$(...) is command substitution. You're trying to run $today + 86400 as a command.
$((...)) is arithmetic expansion. This is what you want to use.
tomorrow=$(( today + 86400 ))
Also see http://mywiki.wooledge.org/ArithmeticExpression for more on doing arithmetics in the shell.
I hope that this will solve your problem here.
date --date 'next day'
Set your timezone, then run date.
E.g.
TZ=UTC-24 date
Alternatively, I'd use perl:
perl -e 'print localtime(time+84600)."\n"'
echo $(date --date="next day" +%Y%m%d)
This will output
20170623
I like
input_date=$(date '+%Y-%m-%d')
tomorrow_date=$(date '+%Y-%m-%d' -d "$input_date + 1 day")
echo "$tomorrow_date"
It returns the date of the day after $input_date, in format YYYY-MM-DD
You can try below
#!/bin/bash
today=`date`
tomorrow=`date --date="next day"`
echo "$today"
echo "$tomorrow"

Comparing dates of two files in shell

I have two files created at different times.
In my shell scripting program, I want to initialize a variable with the date of the file which was created earlier.
For eg. if file1 was created on 22 April and file2 was created on April 19. my variable should be initialized to 19th April.
How can I do this in bash shell?
Assuming existence of GNU stat (part of GNU coreutils):
if [[ $(stat -c%W <file1>) -lt $(stat -c%W <file2>) ]]
then
EARLIER="$(stat -c%w <file1>)"
else
EARLIER="$(stat -c%w <file1>)"
fi
Note the case of %W (integer) vs. %w (human-readable) is significant.
%W / %w is birth time, since you asked for "creation time". Usually %Y / %y (last modification) or %Z / %z (last change) are more meaningful.
If you need a different format for your date, you could feed the stat output to date, e.g.:
date -d "$(stat -c%w <earlier_file>)" +"%Y-%m-%d")
PS: While you are at the subject of time stamps, please consider RFC 3339 for your formatting, i.e. YYYY-MM-DD HH:MM:DD-TZ, which is non-ambiguous, portable, and sortable.
/bin/date can convert to timestamps, using the %s format, after which date comparison is a straight numeric compare, so the solution to your problem, modulo syntax errors, is:
DATE1=`date -j '22 April' +"%d %B"`
DATE2=`date -j '19 April' +"%d %B"`
if [[ $DATE2 < $DATE1 ]]; then
export VAR=`date -j $DATE1 +"%s"`
else
export VAR=`date -j $DATE2 +"%s"`
fi

Resources