command to Substract two timestamps in unix - unix

I am writing a script and which requires to calculate the difference between the two timestamps . I have done some search but didn't get a clue so far.
For Example say:
time1 = 20160314 10:16:27
time2 = 20160313 15:17:28
From the above I need to get result like below: difference is: "1 day 5 hours 1 minute 1 second"
Please help me in resolving this.

datediff() {
t1=$(date -d "$1" +%s)
t2=$(date -d "$2" +%s)
diff=$(( $t1 - $t2 ))
echo "Duration: $(( $diff / 86400 )) days $(($diff / 3600 )) hours $((( $diff % 3600) / 60)) minutes $(( $diff % 60 )) seconds"
}
date -d "$1" +%s converts given date to time stamp(counted from 1970).
More details on date conversion
http://www.gnu.org/software/coreutils/manual/html_node/Date-input-formats.html#Date-input-formats
example:
$ date -d 2013-07-05 +%m/%d/%Y
07/05/2013
$ date -d 07/05/2013 +%F
2013-07-05

The command you likely want to use is date, but its usage depends on your operating system. You've specified unix in the tags on your question, which isn't really specific enough for a single answer.
In general though, you'll calculate differences between dates by counting the seconds between them. So your method should be to figure out the unix epoch second for each of your dates, subtract to find the difference, and then print the results in whatever format suits you.
In Linux, GNU date (from "coreutils") has a -d option that can understand a number of date references.
$ time1="20160314 10:16:27"
$ date -d "$time1" '+%s'
1457964987
And you can calculate the difference in seconds between two dates like this:
echo "$(( $(date -d "$time1" '+%s') - $(date -d "$time2" '+%s') ))"
Converting that to your output format is a simple matter of division and remainders:
s=$(( $(date -d "$time1" '+%s') - $(date -d "$time2" '+%s') ))
printf "%d day(s) %d hours %d minute %d second\n" \
$(( s / 86400 )) \
$(( s % 86400 / 3600 )) \
$(( s % 3600 / 60 )) \
$(( s % 60 ))
In FreeBSD, on the other hand, the -d option does something completely different, and you'd use -f and -v to parse and adjust a date. For example:
$ time1="20160314 10:16:27"
$ date -j -f '%Y%m%d %T' "$time1" '+%s'
1457964987
Figuring out the difference looks similar to the Linux method then:
s=$(( $(date -j -f '%Y%m%d %T' "$time1" '+%s') - $(date -j -f '%Y%m%d %T' "$time2" '+%s') ))
You can then use the same printf command I've shown above to format your output.
I don't have details on how the date command works in Solaris or other operating systems, but you can man date from a shell to see if either of these strategies appears to be compatible with whatever operating system you're running.

Related

File pulling with yesterday's date in UNIX based on file name [duplicate]

I've got a shell script which does the following to store the current day's date in a variable 'dt':
date "+%a %d/%m/%Y" | read dt
echo ${dt}
How would i go about getting yesterdays date into a variable?
Basically what i'm trying to achieve is to use grep to pull all of yesterday's lines from a log file, since each line in the log contains the date in "Mon 01/02/2010" format.
Thanks a lot
dt=$(date --date yesterday "+%a %d/%m/%Y")
echo $dt
On Linux, you can use
date -d "-1 days" +"%a %d/%m/%Y"
You can use GNU date command as shown below
Getting Date In the Past
To get yesterday and earlier day in the past use string day ago:
date --date='yesterday'
date --date='1 day ago'
date --date='10 day ago'
date --date='10 week ago'
date --date='10 month ago'
date --date='10 year ago'
Getting Date In the Future
To get tomorrow and day after tomorrow (tomorrow+N) use day word to get date in the future as follows:
date --date='tomorrow'
date --date='1 day'
date --date='10 day'
date --date='10 week'
date --date='10 month'
date --date='10 year'
If you have Perl available (and your date doesn't have nice features like yesterday), you can use:
pax> date
Thu Aug 18 19:29:49 XYZ 2010
pax> dt=$(perl -e 'use POSIX;print strftime "%d/%m/%Y%",localtime time-86400;')
pax> echo $dt
17/08/2010
If you are on a Mac or BSD or something else without the --date option, you can use:
date -r `expr \`date +%s\` - 86400` '+%a %d/%m/%Y'
Update: or perhaps...
date -r $((`date +%s` - 86400)) '+%a %d/%m/%Y'
I have shell script in Linux and following code worked for me:
#!/bin/bash
yesterday=`TZ=EST+24 date +%Y%m%d` # Yesterday is a variable
mkdir $yesterday # creates a directory with YYYYMMDD format
You have atleast 2 options
Use perl:
perl -e '#T=localtime(time-86400);printf("%02d/%02d/%02d",$T[4]+1,$T[3],$T[5]+1900)'
Install GNU date (it's in the sh_utils package if I remember correctly)
date --date yesterday "+%a %d/%m/%Y" | read dt
echo ${dt}
Not sure if this works, but you might be able to use a negative timezone. If you use a timezone that's 24 hours before your current timezone than you can simply use date.
Try the following method:
dt=`case "$OSTYPE" in darwin*) date -v-1d "+%s"; ;; *) date -d "1 days ago" "+%s"; esac`
echo $dt
It works on both Linux and OSX.
Here is a ksh script to calculate the previous date of the first argument, tested on Solaris 10.
#!/bin/ksh
sep=""
today=$(date '+%Y%m%d')
today=${1:-today}
ty=`echo $today|cut -b1-4` # today year
tm=`echo $today|cut -b5-6` # today month
td=`echo $today|cut -b7-8` # today day
yy=0 # yesterday year
ym=0 # yesterday month
yd=0 # yesterday day
if [ td -gt 1 ];
then
# today is not first of month
let yy=ty # same year
let ym=tm # same month
let yd=td-1 # previous day
else
# today is first of month
if [ tm -gt 1 ];
then
# today is not first of year
let yy=ty # same year
let ym=tm-1 # previous month
if [ ym -eq 1 -o ym -eq 3 -o ym -eq 5 -o ym -eq 7 -o ym -eq 8 -o ym - eq 10 -o ym -eq 12 ];
then
let yd=31
fi
if [ ym -eq 4 -o ym -eq 6 -o ym -eq 9 -o ym -eq 11 ];
then
let yd=30
fi
if [ ym -eq 2 ];
then
# shit... :)
if [ ty%4 -eq 0 ];
then
if [ ty%100 -eq 0 ];
then
if [ ty%400 -eq 0 ];
then
#echo divisible by 4, by 100, by 400
leap=1
else
#echo divisible by 4, by 100, not by 400
leap=0
fi
else
#echo divisible by 4, not by 100
leap=1
fi
else
#echo not divisible by 4
leap=0 # not divisible by four
fi
let yd=28+leap
fi
else
# today is first of year
# yesterday was 31-12-yy
let yy=ty-1 # previous year
let ym=12
let yd=31
fi
fi
printf "%4d${sep}%02d${sep}%02d\n" $yy $ym $yd
Tests
bin$ for date in 20110902 20110901 20110812 20110801 20110301 20100301 20080301 21000301 20000301 20000101 ; do yesterday $date; done
20110901
20110831
20110811
20110731
20110228
20100228
20080229
21000228
20000229
19991231
Thanks for the help everyone, but since i'm on HP-UX (after all: the more you pay, the less features you get...) i've had to resort to perl:
perl -e '#T=localtime(time-86400);printf("%02d/%02d/%04d",$T[3],$T[4]+1,$T[5]+1900)' | read dt
If your HP-UX installation has Tcl installed, you might find it's date arithmetic very readable (unfortunately the Tcl shell does not have a nice "-e" option like perl):
dt=$(echo 'puts [clock format [clock scan yesterday] -format "%a %d/%m/%Y"]' | tclsh)
echo "yesterday was $dt"
This will handle all the daylight savings bother.
If you don't have a version of date that supports --yesterday and you don't want to use perl, you can use this handy ksh script of mine. By default, it returns yesterday's date, but you can feed it a number and it tells you the date that many days in the past. It starts to slow down a bit if you're looking far in the past. 100,000 days ago it was 1/30/1738, though my system took 28 seconds to figure that out.
#! /bin/ksh -p
t=`date +%j`
ago=$1
ago=${ago:=1} # in days
y=`date +%Y`
function build_year {
set -A j X $( for m in 01 02 03 04 05 06 07 08 09 10 11 12
{
cal $m $y | sed -e '1,2d' -e 's/^/ /' -e "s/ \([0-9]\)/ $m\/\1/g"
} )
yeardays=$(( ${#j[*]} - 1 ))
}
build_year
until [ $ago -lt $t ]
do
(( y=y-1 ))
build_year
(( ago = ago - t ))
t=$yeardays
done
print ${j[$(( t - ago ))]}/$y
ksh93:
dt=${ printf "%(%a %d/%m/%Y)T" yesterday; }
or:
dt=$(printf "%(%a %d/%m/%Y)T" yesterday)
The first one runs in the same process, the second one in a subshell.
For Hp-UX only below command worked for me:
TZ=aaa24 date +%Y%m%d
you can use it as :
ydate=`TZ=aaa24 date +%Y%m%d`
echo $ydate
If you have access to python, this is a helper that will get the yyyy-mm-dd date value for any arbitrary n days ago:
function get_n_days_ago {
local days=$1
python -c "import datetime; print (datetime.date.today() - datetime.timedelta(${days})).isoformat()"
}
# today is 2014-08-24
$ get_n_days_ago 1
2014-08-23
$ get_n_days_ago 2
2014-08-22
$var=$TZ;
TZ=$TZ+24;
date;
TZ=$var;
Will get you yesterday in AIX and set back the TZ variable back to original
Though all good answers, unfortunately none of them worked for me. So I had to write something old school. ( I was on a bare minimal Linux OS )
$ date -d #$( echo $(( $(date +%s)-$((60*60*24)) )) )
You can combine this with date's usual formatting. Eg.
$ date -d #$( echo $(( $(date +%s)-$((60*60*24)) )) ) +%Y-%m-%d
Explanation :
Take date input in terms of epoc seconds ( the -d option ), from which you would have subtracted one day equivalent seconds. This will give the date precisely one day back.

awk convert quoted date time format to unixtimestamp [duplicate]

I am converting timestamps to EPOCH seconds in awk, getting incorrect output for repeated timestamps
Input:
20180614 00:00:00
20180614 00:00:23
20180614 22:45:00
20180614 22:45:21
20180614 00:00:00
20180614 00:00:23
Expected Output :
1528930800
1528930823
1528930800
1529012721
1528930800
1528930823
I did
awk '{ ts="\""$0"\""; ("date +%s -d "ts)| getline epochsec; print epochsec}'
output after running above command:
1528930800
1528930823
1529012700
1529012721
1529012721
1529012721
With GNU xargs:
xargs -I {} date +%s -d {} < file
Output:
1528927200
1528927223
1529009100
1529009121
1528927200
1528927223
A bit a shorter GNU awk version is using FIELDWIDTHS which is available from gawk-2.13 onwards:
awk 'BEGIN{FIELDWIDTHS="4 2 3 2 1 2 1 2"}{print mktime($1" "$2" "$3$4" "$6" "$8)}'
Since gawk-4.2 you can skip intervening fields:
awk 'BEGIN{FIELDWIDTHS="4 2 2 1:2 1:2 1:2"}{print mktime($1" "$2" "$3" "$4" "$5" "$6)}'
Or even shorter using FPAT
awk 'BEGIN{FPAT="[0-9][0-9]"}{print mktime($1$2" "$3" "$4" "$5" "$6" "$7)}
note: the usage of a single awk-mktime combination will be faster than anything which makes system calls to date as you do not constantly have to call a binary. With the awk mktime solution you call a single binary. Nonetheless, the xargs solution given by Cyrus is by far the most comfortable one.
You could use system function
$ awk '{system("date +%s -d \""$0"\"")}' ip.txt
1528914600
1528914623
1528996500
1528996521
1528914600
1528914623
Or use sed
$ sed 's/.*/date +%s -d "&"/e' ip.txt
1528914600
1528914623
1528996500
1528996521
1528914600
1528914623
As per AllAboutGetline article, you'll need
$ awk '{ ts="date +%s -d \""$0"\""; while ((ts|getline ep)>0) print ep; close(ts) }' ip.txt
1528914600
1528914623
1528996500
1528996521
1528914600
1528914623
However getline is not needed at all for this case and avoid using it unless you really need it and know how to use it
Using GNU awk mktime function:
awk '{gsub(":"," ",$2); print mktime(substr($1,1,4) " " substr($1,5,2) " " substr($1,7,2) " " $2)}' file
To add to Cyrus's answer, the following works on Mac OSX. Strangely, MAC has a different way of handling date-time format to epoch conversion.
xargs -I {} date -j -u -f "%a %b %d %T %Z %Y" {} +%s < file

How can I find the current date minus seven days in Unix?

I am trying to find the date that was seven days before today.
CURRENT_DT=`date +"%F %T"`
diff=$CURRENT_DT-7
echo $diff
I am trying stuff like the above to find the 7 days less than from current date. Could anyone help me out please?
GNU date will to the math for you:
date --date "7 days ago"
Other version will require you to covert the current date into seconds since the UNIX epoch first, manually subtract 7 days' worth of seconds, and convert that back into the desired form. Consult the documentation for your version of date for details on how to convert to and from Unix timestamps. Here's an example using GNU date again:
x=$(date +%s)
x=$((x - 7 * 24 * 60 * 60))
date --date #$x
Here is a simple Perl script which (unlike the other examples) works with Unix:
perl -e 'use POSIX qw(ctime); printf "%s", ctime(time - (7 * 24 * 60 * 60));'
(Tested with Solaris 10, and a token Linux system, of course - with the caveat that Perl is not necessarily part of one's configuration, merely very likely).
Adding this one for shells on OSX:
date -v-7d
> Tue Apr 3 15:16:31 EDT 2018
date
> Tue Apr 10 15:16:33 EDT 2018
Need that formated?
date -v-7d +%Y-%m-%d
> 2018-04-03
Ksh's printf can do time calculation:
$ printf '%(%Y-%m-%d)T\n'
2015-04-07
$ printf '%(%Y-%m-%d)T\n' '7 days ago'
2015-03-31
$
I haven't used unix in a while but I found this in one of my scripts
echo `date +%s`-604800 | bc
DATE=$(date --date "7 days ago" | awk '{print$1,$2,$3}')
echo "$DATE"
if [ -z "$(grep -i "$DATE" test.log)" ]; then
exit 1
fi
sed -i "1,/$DATE/d" test.log

Time difference of 14 digit date YYYYmmDDHHMMSS

I need a Unix script which i can find the time difference between 2 times look like YYYYmmDDHHMMSS
Example
T1=20120624192555
T2=20120624204006
So the time difference will be =1:14:11
Any clue?
I'm not sure if you can get around specifying the date format, but here is a rather lengthy date solution:
# Get seconds since epoch
D1=$(date --date "${T1:0:4}-${T1:4:2}-${T1:6:2} ${T1:8:2}:${T1:10:2}: ${T1:12:2}" +%s)
D2=$(date --date "${T2:0:4}-${T2:4:2}-${T2:6:2} ${T2:8:2}:${T2:10:2}: ${T2:12:2}" +%s)
date --date "0 + $(( D2 - D1 )) seconds" +%T
See here for the ${VAR:OFF:LEN} reference.
Note: as mentioned by jrouquie below, this fails when exceeding 24 hours. This is a limitation of the date command, $(( D2 - D1 )) still gives the correct result in seconds though.
time1=`echo $1 | sed -r 's/([0-9]{4})([0-9]{2})([0-9]{2})([0-9]{2})([0-9]{2})([0-9]{2})/\1-\2-\3 \4:\5:\6/'`
time2=`echo $2 | sed -r 's/([0-9]{4})([0-9]{2})([0-9]{2})([0-9]{2})([0-9]{2})([0-9]{2})/\1-\2-\3 \4:\5:\6/'`
seconds1=`date --utc -d "$time1" +%s`
seconds2=`date --utc -d "$time2" +%s`
difference=`expr $seconds2 - $seconds1`
echo `expr $difference / 3600`:`expr "(" $difference / 60 ")" % 60`:`expr $difference % 60`
Note the use of --utc which prevents a bug with daylight saving time.
Caveats:
This script does not check input.
It assumes $2 > $1.
It could be rewritten to factor repeated code
EDIT: regarding the first comment, here is a version without the "-r" option to sed (-r means --regexp-extended, which here allowed to dispense with all the backslashes).
time1=`echo $1 | sed 's/\([0-9]\{4\}\)\([0-9]\{2\}\)\([0-9]\{2\}\)\([0-9]\{2\}\)\([0-9]\{2\}\)\([0-9]\{2\}\)/\1-\2-\3 \4:\5:\6/'`
time2=`echo $2 | sed 's/\([0-9]\{4\}\)\([0-9]\{2\}\)\([0-9]\{2\}\)\([0-9]\{2\}\)\([0-9]\{2\}\)\([0-9]\{2\}\)/\1-\2-\3 \4:\5:\6/'`
seconds1=`date --utc -d "$time1" +%s`
seconds2=`date --utc -d "$time2" +%s`
difference=`expr $seconds2 - $seconds1`
echo `expr $difference / 3600`:`expr "(" $difference / 60 ")" % 60`:`expr $difference % 60`
Here is a solution taking the best of the one by Thor/kjp and mine:
#!/bin/bash
function seconds_since_epoch() {
echo $(date --utc --date "${1:0:4}-${1:4:2}-${1:6:2}
${1:8:2}:${1:10:2}:${1:12:2}" +%s)
}
difference=$(( `seconds_since_epoch $2` - `seconds_since_epoch $1` ))
echo \
`expr $difference / 3600`:\
`expr "(" $difference / 60 ")" % 60`:\
`expr $difference % 60`

In a unix shell, how to get yesterday's date into a variable?

I've got a shell script which does the following to store the current day's date in a variable 'dt':
date "+%a %d/%m/%Y" | read dt
echo ${dt}
How would i go about getting yesterdays date into a variable?
Basically what i'm trying to achieve is to use grep to pull all of yesterday's lines from a log file, since each line in the log contains the date in "Mon 01/02/2010" format.
Thanks a lot
dt=$(date --date yesterday "+%a %d/%m/%Y")
echo $dt
On Linux, you can use
date -d "-1 days" +"%a %d/%m/%Y"
You can use GNU date command as shown below
Getting Date In the Past
To get yesterday and earlier day in the past use string day ago:
date --date='yesterday'
date --date='1 day ago'
date --date='10 day ago'
date --date='10 week ago'
date --date='10 month ago'
date --date='10 year ago'
Getting Date In the Future
To get tomorrow and day after tomorrow (tomorrow+N) use day word to get date in the future as follows:
date --date='tomorrow'
date --date='1 day'
date --date='10 day'
date --date='10 week'
date --date='10 month'
date --date='10 year'
If you have Perl available (and your date doesn't have nice features like yesterday), you can use:
pax> date
Thu Aug 18 19:29:49 XYZ 2010
pax> dt=$(perl -e 'use POSIX;print strftime "%d/%m/%Y%",localtime time-86400;')
pax> echo $dt
17/08/2010
If you are on a Mac or BSD or something else without the --date option, you can use:
date -r `expr \`date +%s\` - 86400` '+%a %d/%m/%Y'
Update: or perhaps...
date -r $((`date +%s` - 86400)) '+%a %d/%m/%Y'
I have shell script in Linux and following code worked for me:
#!/bin/bash
yesterday=`TZ=EST+24 date +%Y%m%d` # Yesterday is a variable
mkdir $yesterday # creates a directory with YYYYMMDD format
You have atleast 2 options
Use perl:
perl -e '#T=localtime(time-86400);printf("%02d/%02d/%02d",$T[4]+1,$T[3],$T[5]+1900)'
Install GNU date (it's in the sh_utils package if I remember correctly)
date --date yesterday "+%a %d/%m/%Y" | read dt
echo ${dt}
Not sure if this works, but you might be able to use a negative timezone. If you use a timezone that's 24 hours before your current timezone than you can simply use date.
Try the following method:
dt=`case "$OSTYPE" in darwin*) date -v-1d "+%s"; ;; *) date -d "1 days ago" "+%s"; esac`
echo $dt
It works on both Linux and OSX.
Here is a ksh script to calculate the previous date of the first argument, tested on Solaris 10.
#!/bin/ksh
sep=""
today=$(date '+%Y%m%d')
today=${1:-today}
ty=`echo $today|cut -b1-4` # today year
tm=`echo $today|cut -b5-6` # today month
td=`echo $today|cut -b7-8` # today day
yy=0 # yesterday year
ym=0 # yesterday month
yd=0 # yesterday day
if [ td -gt 1 ];
then
# today is not first of month
let yy=ty # same year
let ym=tm # same month
let yd=td-1 # previous day
else
# today is first of month
if [ tm -gt 1 ];
then
# today is not first of year
let yy=ty # same year
let ym=tm-1 # previous month
if [ ym -eq 1 -o ym -eq 3 -o ym -eq 5 -o ym -eq 7 -o ym -eq 8 -o ym - eq 10 -o ym -eq 12 ];
then
let yd=31
fi
if [ ym -eq 4 -o ym -eq 6 -o ym -eq 9 -o ym -eq 11 ];
then
let yd=30
fi
if [ ym -eq 2 ];
then
# shit... :)
if [ ty%4 -eq 0 ];
then
if [ ty%100 -eq 0 ];
then
if [ ty%400 -eq 0 ];
then
#echo divisible by 4, by 100, by 400
leap=1
else
#echo divisible by 4, by 100, not by 400
leap=0
fi
else
#echo divisible by 4, not by 100
leap=1
fi
else
#echo not divisible by 4
leap=0 # not divisible by four
fi
let yd=28+leap
fi
else
# today is first of year
# yesterday was 31-12-yy
let yy=ty-1 # previous year
let ym=12
let yd=31
fi
fi
printf "%4d${sep}%02d${sep}%02d\n" $yy $ym $yd
Tests
bin$ for date in 20110902 20110901 20110812 20110801 20110301 20100301 20080301 21000301 20000301 20000101 ; do yesterday $date; done
20110901
20110831
20110811
20110731
20110228
20100228
20080229
21000228
20000229
19991231
Thanks for the help everyone, but since i'm on HP-UX (after all: the more you pay, the less features you get...) i've had to resort to perl:
perl -e '#T=localtime(time-86400);printf("%02d/%02d/%04d",$T[3],$T[4]+1,$T[5]+1900)' | read dt
If your HP-UX installation has Tcl installed, you might find it's date arithmetic very readable (unfortunately the Tcl shell does not have a nice "-e" option like perl):
dt=$(echo 'puts [clock format [clock scan yesterday] -format "%a %d/%m/%Y"]' | tclsh)
echo "yesterday was $dt"
This will handle all the daylight savings bother.
If you don't have a version of date that supports --yesterday and you don't want to use perl, you can use this handy ksh script of mine. By default, it returns yesterday's date, but you can feed it a number and it tells you the date that many days in the past. It starts to slow down a bit if you're looking far in the past. 100,000 days ago it was 1/30/1738, though my system took 28 seconds to figure that out.
#! /bin/ksh -p
t=`date +%j`
ago=$1
ago=${ago:=1} # in days
y=`date +%Y`
function build_year {
set -A j X $( for m in 01 02 03 04 05 06 07 08 09 10 11 12
{
cal $m $y | sed -e '1,2d' -e 's/^/ /' -e "s/ \([0-9]\)/ $m\/\1/g"
} )
yeardays=$(( ${#j[*]} - 1 ))
}
build_year
until [ $ago -lt $t ]
do
(( y=y-1 ))
build_year
(( ago = ago - t ))
t=$yeardays
done
print ${j[$(( t - ago ))]}/$y
ksh93:
dt=${ printf "%(%a %d/%m/%Y)T" yesterday; }
or:
dt=$(printf "%(%a %d/%m/%Y)T" yesterday)
The first one runs in the same process, the second one in a subshell.
For Hp-UX only below command worked for me:
TZ=aaa24 date +%Y%m%d
you can use it as :
ydate=`TZ=aaa24 date +%Y%m%d`
echo $ydate
If you have access to python, this is a helper that will get the yyyy-mm-dd date value for any arbitrary n days ago:
function get_n_days_ago {
local days=$1
python -c "import datetime; print (datetime.date.today() - datetime.timedelta(${days})).isoformat()"
}
# today is 2014-08-24
$ get_n_days_ago 1
2014-08-23
$ get_n_days_ago 2
2014-08-22
$var=$TZ;
TZ=$TZ+24;
date;
TZ=$var;
Will get you yesterday in AIX and set back the TZ variable back to original
Though all good answers, unfortunately none of them worked for me. So I had to write something old school. ( I was on a bare minimal Linux OS )
$ date -d #$( echo $(( $(date +%s)-$((60*60*24)) )) )
You can combine this with date's usual formatting. Eg.
$ date -d #$( echo $(( $(date +%s)-$((60*60*24)) )) ) +%Y-%m-%d
Explanation :
Take date input in terms of epoc seconds ( the -d option ), from which you would have subtracted one day equivalent seconds. This will give the date precisely one day back.

Resources