Rubab
Rubab

Reputation: 27

validate date in unix for DD-MM-YYYY format

How to validate the date in Unix.
Where the date format is DD-MM-YYYY.
For example if i run one script ./ValidateDate.sh DD-MM-YYYY then it should check that the date is in this format and also that the date exists.
If date is valid and in above format then proceed for next else print message 'Invalid date'

Thanks.

Upvotes: 0

Views: 15238

Answers (4)

David W.
David W.

Reputation: 107040

Well... This is a fine can o' worms.

Any shell script that you create may not work on all of the various flavors of Unix/Linux.

The BSD date command (found on OS X and Solaris) does a great job at taking in the date and verifying the format. It requires you to specify your date format, but once you do, it has no problems:

if date -j -f "%d-%m-%Y" "$DATE" 2>&1 > /dev/null # No output
then
    echo "ERROR: Date '$DATE' is not a valid format."
    exit 2
else
    echo "Date is '$DATE'."
fi

Linux and other systems that use GNU's date can also validate the date, but use a different syntax:

date -d "$DATE" 2>&1 /dev/null   # With a bit of luck this will work...
if $? -ne 0
then
    echo "ERROR: Date '$DATE' is not a valid format."
else
    echo "Date is '$DATE'."
fi

I say With a bit of luck because it's up to the date command to figure out your date's format. This normally works, and will work with your YYYY-MM-DD format, but it can be confusing:

Imagine this:

$ DATE="15/6/2014"              # It's June 15, 2014
$ date -d "$DATE"
date: invalid date `15/6/2014'  # Invalid?

That's because in my timezone, the dd/mm/yyyy format isn't a valid format. In my timezone, the date should be mm/dd/yyyy. To get around this you can use Wintermute's suggestion and format the date into ISO format before using GNU's date format.

A more universal possibility is to use Perl or Python to figure out if the date is correct:

if perl -mTime::Piece -e "Time::Piece->strptime(\"$DATE\", \"%Y-%m-%d\")" 2> /dev/null
then
    echo "ERROR: Date '$DATE' is not a valid format."
else
    echo "Date is '$DATE'."
fi

This Perl oneliner will return a non-zero error status if $DATE isn't a valid date in %Y-%m-%d format.

Upvotes: 3

chepner
chepner

Reputation: 531165

You can do this fairly easily if you are willing to break the validation into two steps. First, check that the string is in the right format:

date=$1
[[ $date =~ ([0-9][0-9])-([0-9][0-9])-([0-9]+) ]] || { printf "Invalid date format\n"; exit 1; }

If that test passes, you can extract the day, month, and year fields, then verify that each falls in the correct range.

day=${BASH_REMATCH[1]}
month=${BASH_REMATCH[2]}
year=${BASH_REMATCH[3]}

thirty_one_days='0[1-9]|[12][0--9]|3[01]'
thirty_days='0[1-9]|[12][0--9]|30'
twenty_eight_days='0[1-9]|1[0-9]|2[0-8]'
case $month in
    01|03|05|07|08|10|12)
        [[ $day =~ $thirty_one_days ]] ;;
    04|06|09|11)
        [[ $day =~ $thirty_days ]] ;;
    02)
        # 1-28, but 29 OK in a leap year.
        [[ $day =~ $twenty_eight_days ]] ||
            (( year % 4 == 0 && $year % 400 == 0 && day == 29 ))
    *)
         false
 esac || { print "Invalid date\n"; exit 1; }

Upvotes: 0

user3442743
user3442743

Reputation:

awk way

awk 'split($0,a,"-"){print strftime("%d-%m-%Y",mktime(a[3]" "a[2]" "a[1]" 00 00 00"))==$0?"valid":"not valid"}' <<< "31-12-1992"

It Converts the string to epoch,converts epoch back then checks against the original.

Edit:

Thought i would add after testing this works for dates
FROM 01-01-0
TO 31-12-2147483647

Although a drawback is after you go below the year 1000 you have to remove leading zeros from the year.

Upvotes: 0

Wintermute
Wintermute

Reputation: 44043

You can validate the date with the date utility, but you first have to transform the input into something it can understand. I suggest ISO representation (always). It could, for example, look like this:

 #!/bin/sh

 PATTERN='\([0-9]\{1,2\}\)-\([0-9]\{1,2\}\)-\([0-9]\+\)'

 # if the pattern doesn't match, this will give date an empty string, so it will fail as expected.
 if date -d $(echo "$1" | sed -n "/$PATTERN/ { s/$PATTERN/\3-\2-\1/; p }") > /dev/null 2>&1 ; then
     echo valid
 else
     echo invalid
 fi

Upvotes: 0

Related Questions