Calculate given date - 1 day

Hi Team,

We have a requirement as follows.

If a date 20141220 as parameter to the script, then the script has to return the output as 20141219.
i.e given date - 1.

The requirement is simple. But it should satisfy leap year, the months having 31 and 30 days, the date in which day light savings changes happens, etc,.

The date has to be calculated based on the server date and time.

Can anyone help me out?

try this

date -d '20141220 1 day ago'  '+%Y%m%d'

That depends on what your system - which you fail to mention - provides. Above is an example of GNU date, which is not avaiable on every system. (Free)BSD provides

date -v-1d -jf "%Y%m%d" 20141220 +"%Y%m%d"
20141219

Recent bash has the printf "%(datefmt)T" builtin, but that needs epoch seconds, which may be difficult to get at.

Hello kmanivan82,

Pravin's code will work if you have GNU date in your system. Following code may help you to get the previous date of any input date passed by you to script as follows.

cat date_check.ksh
echo $1 | awk -vs1="01" -vs2="03" -vs3="12" '{if(length($0)>8){print "Wrong Input!!";exit};YEAR=substr($0,1,4);YEAR+0;MONTH=substr($0,5,2);MONTH+0;DATE=substr($0,7,2);DATE+0;split("31 29 31 30 31 30 31 31 30 31 30 31", W," ");if(DATE==s1 && MONTH==s1){YEAR=YEAR-1; MONTH=12; DATE=31; print YEAR MONTH DATE}  else if(DATE==s1 && MONTH >= s1 && MONTH <= s3){MONTH=MONTH-1;W[2]=(YEAR%4!=0)?28:29;print YEAR MONTH W[MONTH]} else {DATE=DATE-1;print YEAR MONTH DATE}}'

Followings are some examples while running the script:
i- simply get previous day

./date_check.ksh 20201212
20201211   ####### Output

ii- To check about leap year:

./date_check.ksh 20200301
2020229     ####### Output

iii- To check date of previous month.

./date_check.ksh 20200401
2020331    ####### Output

This has been made to get the previous date only, kindly check it and let me know if this helps and you have any queries.

EDIT: Adding a non one liner form of code.

echo $1 | awk -vs1="01" -vs2="03" -vs3="12" '{
                                                if(length($0)>8){
                                                                        print "Wrong Input!!";
                                                                        exit
                                                                }
                                                YEAR=substr($0,1,4);
                                                YEAR+0;
                                                MONTH=substr($0,5,2);
                                                MONTH+0;
                                                DATE=substr($0,7,2);
                                                DATE+0;
                                                split("31 29 31 30 31 30 31 31 30 31 30 31", W," ");
                                                if(DATE==s1 && MONTH==s1){
                                                                                YEAR=YEAR-1;
                                                                                MONTH=12;
                                                                                DATE=31;
                                                                                print YEAR MONTH DATE
                                                                         }
                                                else if(DATE==s1 && MONTH >= s1 && MONTH <= s3){
                                                                                MONTH=MONTH-1;
                                                                                W[2]=(YEAR%4!=0)?28:29;
                                                                                print YEAR MONTH W[MONTH]
                                                                                                }
                                                else {
                                                                                DATE=DATE-1;
                                                                                print YEAR MONTH DATE
                                                     }
                                              }'

Thanks,
R. Singh

Try this

date -d'yesterday' +%Y%m%d

If you don't have GNU date, then another alternative is perl if you have that. From your input date, we need to split it up the values and feed them in:-

#!/bin/ksh

input_date=$1

in_yyyy="${input_date%????}"     # Remove last four characters
in_dd="${input_date#??????}"     # Remove lead four characters
in_mm="${input_date#????}"       # Remove lead four characters
in_mm="${in_mm%??}"              # Remove last two characters from previously split value

((temp_mm=$in_mm-1))             # Reduce month by one as epoch counts from 1/1/1970 as zero

# Get time in seconds since epoch
perl -e "use Time::Local; print timelocal(0,0,0,$in_dd,$temp_mm,$in_yyyy), ;" | read in_seconds

# Go back one day in seconds
((out_seconds=$in_seconds-86400))

# Display answer in required format
perl -e 'use POSIX qw(strftime);print scalar(strftime "%Y%m%d", localtime $ARGV[0]), "\n";' $out_seconds

I hope that this meets the brief you have given us. There may be smarter ways to read & split the input date, so I'm open to suggestions.

Obviously some validity checking on the input would be wise else you will get various horrible messages from the perl

I've put it in a script called 254222 (thread number) and tested it as shown:-

$ 254222 20141220
20141219

$ 254222 20140301
20140228

$ 254222 20160301
20160229

$

I hope that this helps. I had fun with the challenge and I'm pretty sure I'm going to need it soon myself too, so thanks for the query :b:

Robin

1 Like

Thank you All.

The code does not work in our system. We are using AIX 6.1

date -d '20141220 1 day ago'  '+%Y%m%d'

Right now, I am using the code given by RavinderSingh13. Yet to try out the code given by rbatte1.

Is there anyway this funciton can be implemented simply using perl, Since Perl has the date datatype?

Perl

#!/usr/bin/perl
use Date::Calc qw (Add_Delta_DHMS);
$dateParam=shift;
@date1=unpack("A4 A2 A2", $dateParam);
@date2 = Add_Delta_DHMS(@date1,0,0,0,-1,0,0,0);
print "@date2 \n";

Invocation

perl dateCalc.pl 20141220
1 Like

Hi RavinderSingh13,

Need a modification in the output.

I have parameterized the code that you have given as follows.

	GetDate=$1
	echo $GetDate | awk -vs1="01" -vs2="03" -vs3="12" '{if(length($0)>8){print "Wrong Input!!";exit};YEAR=substr($0,1,4);YEAR+0;MONTH=substr($0,5,2);MONTH+0;DATE=substr($0,7,2);DATE+0;split("31 29 31 30 31 30 31 31 30 31 30 31", W," ");if(DATE==s1 && MONTH==s1){YEAR=YEAR-1; MONTH=12; DATE=31; print YEAR MONTH DATE}  else if(DATE==s1 && MONTH >= s1 && MONTH <= s3){MONTH=MONTH-1;W[2]=(YEAR%4!=0)?28:29;print YEAR MONTH W[MONTH]} else {DATE=DATE-1;print YEAR MONTH DATE}}'

if i exec the script by passing the date, the script will return previous date as output.

ksh date_check.ksh 20150106
2015015

The output is displayed correct. But I need the output day should be displayed in 2 digits. I am expecting the same output to be displayed as 20150105

Output should always be
year 4 digits
month 2 digits
day 2 digits

Can you help me out?

Hello kmanivan82,

Kindly use code tags always for codes/commands/Inputs you are providing in your posts as per forum rules. Following may help you in same.

cat date_check1.ksh
echo $1 | awk -vs1="01" -vs2="03" -vs3="12" '{
                                                if(length($0)>8){
                                                                        print "Wrong Input!!";
                                                                        exit
                                                                }
                                                YEAR=substr($0,1,4);
                                                YEAR+0;
                                                MONTH=substr($0,5,2);
                                                MONTH+0;
                                                DATE=substr($0,7,2);
                                                DATE+0;
                                                split("31 29 31 30 31 30 31 31 30 31 30 31", W," ");
                                                if(DATE==s1 && MONTH==s1){
                                                                                YEAR=YEAR-1;
                                                                                MONTH=12;
                                                                                DATE=31;
                                                                                print YEAR MONTH DATE
                                                                         }
                                                else if(DATE==s1 && MONTH >= s1 && MONTH <= s3){
                                                                                MONTH=MONTH-1;
                                                                                W[2]=(YEAR%4!=0)?28:29;
                                                                                print YEAR MONTH W[MONTH]
                                                                                                }
                                                else {
                                                                                DATE=DATE-1;
                                                                                printf("%04d%02d%02d\n", YEAR, MONTH, DATE);
                                                     }
                                              }'

When we run code it will show output as follows.

./date_check1.ksh 20150106
20150105

EDIT: Adding one liner form for same.

cat date_check.ksh
echo $1 | awk -vs1="01" -vs2="03" -vs3="12" '{if(length($0)>8){print "Wrong Input!!";exit};YEAR=substr($0,1,4);YEAR+0;MONTH=substr($0,5,2);MONTH+0;DATE=substr($0,7,2);DATE+0;split("31 29 31 30 31 30 31 31 30 31 30 31", W," ");if(DATE==s1 && MONTH==s1){YEAR=YEAR-1; MONTH=12; DATE=31; print YEAR MONTH DATE}  else if(DATE==s1 && MONTH >= s1 && MONTH <= s3){MONTH=MONTH-1;W[2]=(YEAR%4!=0)?28:29;print YEAR MONTH W[MONTH]} else {DATE=DATE-1;printf("%04d%02d%02d\n", YEAR, MONTH, DATE)}}'

Thanks,
R. Singh

1 Like