Date Format Problem

I have written a code in Linux environment which compares two dates and print "correct" if 1st date is less than 2nd date. But when I'm running the same code in SunOS environment, "date -d is an illegal format" is the error it is throwing. How different should my code be so that it executes well in SunOS environment.

#!/usr/bin/bash
clear
export NLS_LANG=AMERICAN_AMERICA.AL32UTF8



if [ $# -lt 2 ]  ; then
        echo " Incorrect Number of Arguments";
        echo " Usage : Main_Script <FROM_DATE> <TO_DATE>";
        echo " Example : Main_Script 21-JUL-2015 30-JUL-2015";
        exit;

fi;

if [ $# == 2 ]; then
      if [[ $1 == [0-3][0-9]-[A-Z][A-Z][A-Z]-[0-9][0-9][0-9][0-9] ]]; then
              if  [[ $2 == [0-3][0-9]-[A-Z][A-Z][A-Z]-[0-9][0-9][0-9][0-9] ]];
                  then
                  d1=`date -d $1 +%s`
                  d2=`date -d $2 +%s`
                echo $d1;
                echo $d2;
        
                                        if [[ $d2 -gt $d1 ]];
                                        then
                                        echo "correct";

                      else
                                                 echo "Start date is more than end date";

                         exit;

 fi;
                   else
                   echo "Incorrect date format";
                   echo  $2;
                                  echo "Usage : DD-MMM-YYYY";
                  echo " Example :  Main_Script 21-JUL-2015 30-JUL-2015";
                  exit;
       fi;
           else
            echo "Incorrect date format";
                echo  $1;

It would be of great help if someone can help me.
Thank you

Install the gnu utilities on the Sun machine.

How would i do that??
Can I get the details

https://www.opencsw.org/package/coreutils/

This is not helping. Can anyone help by making some changes in this code so that it runs well for Solaris

Hello chandan_Bose,

I think this thread is pretty much similar too following thread, where me and other forum members tried our best to answer your question.
http://www.unix.com/shell-programming-and-scripting/265838-scripting-issue-2.html\#post302972639
Could you please let me know where are we on that, as we have tried our best to answer and solve your problem.

Thanks,
R. Singh

Well, the problem seems to be that in your "SunOS environment" date doesn't behave like (GNU) date in linux. You've been given two alternatives (in your other thread ) that don't depend on GNU date. Wouldn't one of those do what you need?

when you say this is not helping what do you mean ?
You installed the package and it did not help?
Or
Thats not what I am looking for..
If second solution, you have to do the work as you have noticed yourself :
There are differences between the date command under linux and under solaris..
So show us in this particular case what you tried and give us the output so we can help

IF first option - Are you sure you have all? You should have the gnu date utility to be able to run the script the way its written here , if so are you sure its that one beeing used?
Post the output

Hi VBE,

   Problem is the environment in which I'm working is provided by our client. So we cannot request for an additional install package. We have to rewrite this code in another way so that we can fit it into the Solaris environment. Please try and run my code in Linux environment with a the following format 

<filename> <DD-MMM-YYYY> <DD-MMM-YYYY>

#!/usr/bin/bash                                
date=$1                                        
#day=${date:0:2}                               
#mo=${date:3:3}                                
#yr=${date:7:4}                                
day=`echo $date|cut -f1 -d"-"`                 
mo=`echo $date|cut -f2 -d"-"`                  
yr=`echo $date|cut -f3 -d"-"`                  
echo $day $mo $yr                              
months="JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC"  
i=0                                            
m=0                                            
while [ $i -lt 34 ]                            
do                                             
        if [ "${months:$i:3}" = "$mo" ]        
        then                                   
                m=`expr 1 + $i / 3`            
                i=`expr $i + 35`               
        else                                   
                i=`expr $i + 3`                
        fi                                     
done                                           
if [ $m  -eq 0 ]                               
then                                           
        echo invalid month                     
        exit                                   
fi                                             
numdate=`expr $yr \* 10000 + $m \* 100 + $day` 
echo $numdate                                  

You can decide whether to use cut or substrings to extract the components of the date. Do you always expect 01-MAY-2016, or is 1-MAY-2016 also valid?
There is no check to see if 29-FEB is valid, or whether 31-APR is valid.

1 Like

Thanks a lot JGT. But fact is i need to compare two dates and return "correct" if start date is less than end date. I have written down the code and it runs well, fact is I need the code to run well in Solaris environment, where "date -d" is showing as an illegal format. I need modifications to some part of my code instead of breaking down the entire code so that Solaris doesn't throw such error

So change the following two lines in your script.

d1=`date -d $1 +%s` 
d2=`date -d $2 +%s`

with

d1=`jgt_date $1`
d2=`jgt_date $2`

Where 'jgt_date' is the script that I posted. You may need to change the last line of my script to

echo "$numdate\c"
or 
echo -e "$numdate\c"

and also change the exit for invalid month to exit 1.

Thank you everyone for helping me so much. JGT, I have rewritten your code in a slightly different format and it did quiet well. here is the code.

#!/usr/bin/bash
if [ $# = 2 ]; then

st_date=$1
st_day=`echo $st_date|cut -f1 -d"-"`
st_mo=`echo $st_date|cut -f2 -d"-"`
st_yr=`echo $st_date|cut -f3 -d"-"`
echo $st_day $st_mo $st_yr
months="JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC"
i=0
st_m=0
while [ $i -lt 34 ]
do
        if [ "${months:$i:3}" = "$st_mo" ]
        then
                st_m=`expr 1 + $i / 3`
                i=`expr $i + 35`
        else
                i=`expr $i + 3`
        fi
done
if [ $st_m  -eq 0 ]
then
        echo invalid month
        exit
fi
start_date=`expr $st_yr \* 10000 + $st_m \* 100 + $st_day`
echo $start_date

ed_date=$2
ed_day=`echo $ed_date|cut -f1 -d"-"`
ed_mo=`echo $ed_date|cut -f2 -d"-"`
ed_yr=`echo $ed_date|cut -f3 -d"-"`
echo $ed_day $ed_mo $ed_yr
months="JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC"
i=0
m=0
while [ $i -lt 34 ]
do
        if [ "${months:$i:3}" = "$ed_mo" ]
        then
                ed_m=`expr 1 + $i / 3`
                i=`expr $i + 35`
        else
                i=`expr $i + 3`
        fi
done
if [ $ed_m  -eq 0 ]
then
        echo invalid month
        exit
fi
end_date=`expr $ed_yr \* 10000 + $ed_m \* 100 + $ed_day`
echo $end_date

if [ $start_date -le $end_date ]
echo "Success at last";
 exit;
 fi;
 
 else 
 echo "Start date is greater than end date";
exit;
fi;

This code runs in both Linux as well as Solaris and performs every functionality very well.

When I tried you code, it failed with a syntax error due to the missing then on the last if statement.

After fixing that, I also thought it was strange that when the script was invoked with no operands, it responded with Success at last . (The inconsistent indentation in your code probably contributed to this oversight.)

And, there are a lot of calls to the external utilities expr and cut that can be handled much more efficiently and faster using shell built-ins available in bash , ksh93 , and a few other shells (although some of them are extensions to the features required to appear in a POSIX-conforming shell).

Maybe something like the following would also work for you:

#!/usr/bin/bash
#set -xv
IAm=${0##*/}
months="JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC"

dateconv='
	    #[0-9][0-9]-[ADFJMNOS][ACEOPU][BCGLNPRTVY]-[0-9][0-9][0-9][0-9] ]]
	if [[ "$in" != \
	    [0-9][0-9]-[[:upper:]][[:upper:]][[:upper:]]-[0-9][0-9][0-9][0-9] ]]
	then	printf "%s: Bad %s date format: \"%s\"\n" "$IAm" "$s_e" \
		    "$in" >&2
		usage 2
	fi
	day=${in%%-*}
	day=${day#0}
	abb_month=${in:3:3}
	year=${in##*-}
	year=${year#0}
	year=${year#0}
	year=${year#0}
	month=0
	echo "$day $abb_month $year"
		for((i = 0; i < 36; i += 3))
	do	if [ "${months:$i:3}" = "$abb_month" ]
		then	month=$(((i + 3) / 3))
			break
		fi
	done
	if [ $month  -eq 0 ]
	then	printf "%s: Invalid abbreviated %s month: \"%s\"\n" "$IAm" \
		    "$s_e" "$abb_month" >&2
		usage 3
	fi
	dt=$(($year * 10000 + $month * 100 + $day))
'

usage() {
	printf 'Usage: %s start_date end_date\n\t%s\n\t%s\n' "$IAm" \
	    'start_date & end_date format: DD-MMM-YYYY' \
	    '(where MMM is a 3 uppercase-letter abbreviation for the month)' >&2
	exit ${1:-1}
}
	
if [ $# -ne 2 ]
then	printf '%s: Incorrect number of operands (%d found, 2 required).\n' \
	    "$IAm" $# >&2
	usage
fi
in=$1
s_e=start
eval "$dateconv"
start_date=$dt
echo $start_date

in=$2
s_e=end
eval "$dateconv"
end_date=$dt
echo $end_date

if [ $start_date -le $end_date ]
then	echo "Success at last"
else 	printf '%s: start date "%s" is greater than end date "%s"\n' "$IAm" \
	    "$1" "$2"
	exit 4
fi

(Note that this uses /usr/bin/bash as it appeared in your code. On my system, there is a /bin/bash but not a /usr/bin/bash .)

Hi.

To improve portability with the use of env in such situations, see link below.

Best wishes ... cheers, drl

Post #6 at Environment Variables in Shebangs

Nothing bits knowing the targets you are coding for. env can have the same problem that you are trying to solve, the binary could be in different location in different OSes. Also, it increases the risk of selecting the wrong interpreter, since it looks in each directory in the path, choosing the first one that it finds.

Hi, Aia.

Thanks for your interesting reply. It's always good to have a different perspective on issues.

Are you saying that the env binary may be in a directory different from /usr/bin ? If so, do you have an example?

Our experiences seem to differ. I use AIX, RHEL (CentOS), Antergos, AntiX, {Open,Free,Net}BSD, Haiku, HP-UX, Crux, Fedora, NixOS, Elementary, FreeNAS, Ubuntu, Debian, OSX, MiNT, PCBSD, Slackware, Solaris, SuSE, and Cygwin.

In the posts here and on other forums, I often present an entire script with results. If you look at them, I try to be in the same environment as the questioner. In every case that I can think of, the env approach has worked successfully.

It may have failed on an infrequently used OS, I just don't recall it.

For my purposes, the ease of portability beats the likelihood that I find something wrong. I have more than 1000 scripts, and to use a number of those on different platforms that might require changes would be irritating. However, that's why I also suggested fixin , but that would not solve the problem of same-named codes in different places.

As for interpreters of the same name being in different directories, that seems to me like a bad configuration idea, and an accident waiting to happen. If I encountered a situation like that, I'd try to improve the situation, to remove the risk, and, if not, try to remove myself.

I have had different versions of things, but I named them differently, e.g bash vs bash2 vs bash3 vs bash4, etc. And that was only a stop-gap until the old ones were removed after sufficient time of notice.

Best wishes ... cheers, drl

Hi drl,

Older systems are more likely to be affected by where env might live if at all.

A casual perusing of the wikipidia entry for Shebang (Unix) shows a couple examples of systems that do not have an /usr/bin/env , under the portability subtitle.

Hi.

I think we're beyond the scope of this topic, so for more on the topic of env , please see new thread http://www.unix.com/shell-programming-and-scripting/266000-discussion-use-usr-bin-env-not.html\#post302973156

Best wishes ... cheers, drl