- Checking date format in bash
- 3 Answers 3
- check if date argument is in yyyy-mm-dd format [closed]
- 4 Answers 4
- check if argument is a valid date in bash shell
- 8 Answers 8
- A valid date in the correct format is OK
- An invalid date in the correct format is NOT OK
- A valid date in the incorrect format is NOT OK
- Alternate simpler method: use BASH variable string replace hyphens to slashes
Checking date format in bash
This works fine as long as the input are 8 numbers (e.g. it accepts «20210901» and rejects «20213131»). However, when the input is totally off (e.g. «a» or «nonsense»), it simply takes today’s date. How could the code be modified for a stricter check of the format? The modified code reads:
valid=0 while true; do DATE=date FORMAT="%Y%m%d" read -p "Enter start date (YYYYMMDD) " initialdate if date=$(date -d "$initialdate" +'+%Y%m%d'); then start_date=`$DATE +$FORMAT -d $initialdate` if [[ "$start_date" =~ ^[[0123456789]]$ ]] then valid=1 echo "valid"; echo $start_date break else echo "Invalid format" fi fi echo "Please use right format (YYYYMMDD) " done
Please don’t edit the solution to your question. If you want to share what ultimately worked for you, you can add your own answer instead.
3 Answers 3
A common way to do input validation is to use an infinite loop that you break out of as soon as the input has been validated.
In this case, «validated» means that the input string contains only eight digits and that GNU date is able to use that date as an option argument to its -d option.
With bash , we could write this as
while true; do read -r -p 'Input date: ' if [[ $REPLY =~ ^[[:digit:]]$ ]] && date -d "$REPLY" >/dev/null 2>&1 then break fi echo 'Invalid format, try again' >&2 done thedate=$REPLY
This reads the date at the start of our loop, then tests it with a regular expression that will match if the string contains only eight digits. If that test passes, the string is also tested with GNU date . If that goes well, the loop is exited via a break statement.
In sh , we need to replace the regular expression match with a shell pattern match:
while true; do printf 'Input date: ' >&2 read -r REPLY case $REPLY in *[![:digit:]]*) ;; . ) date -d "$REPLY" >/dev/null 2>&1 && break esac echo 'Invalid format, try again' >&2 done thedate=$REPLY
The test here first tests whether the string contains any other character than a digit. If that test fails, the next test is for exactly eight characters. If that test succeeds we have a string of eight digits and we test with GNU date and exit the loop if the date is ok.
check if date argument is in yyyy-mm-dd format [closed]
Is there a way to check if a date argument is in the correct format (YYYY-MM-DD)? I got this from the web but it doesn’t work for me:
date "+%Y-%m-%d" -d "2015-10-11" > /dev/null 2>&1 echo $?
Oh ok, now I start to see : did you read the comments of this post? I think this peace of code validate only if it is a possible date for (only) the format mm/dd/yyyy which is not your format
Your command looks fine. When I try it, it behaves just as expected: 0 for valid dates and 1 for invalid ones.
4 Answers 4
This will check for the correct format (YYYY-MM-DD) in bash (with built-in regex match):
if [[ $1 =~ ^8-4-5$ ]] then echo "Date $1 is in valid format (YYYY-MM-DD)" else echo "Date $1 is in an invalid format (not YYYY-MM-DD)" fi
Date 2015-12-10 is in valid format (YYYY-MM-DD)
It doesn’t check if the date itself is valid, only the format (as stated in the question, «Check if a date argument is in the correct format (YYYY-MM-DD»))
If you need to check the date format and validate the date value, try something like:
if [[ $1 =~ ^4-2-8$ ]] && date -d "$1" >/dev/null then echo "Date $1 is valid and matches the format (YYYY-MM-DD)" fi
This will discard invalid dates like 0000-88-77 that pass the regex matching.
(Credit goes to @glenn jackman for this suggestion.)
I would also use if [[ . ]] && date -d «$1» >/dev/null to validate both the format and the actual value — discard invalid dates like 9999-99-99 that pass the regex matching.
@DmitryGrigoryev Using date is not required to check the format. The format is checked with bash regex matching. Using date additionally validates the value, not format.
date is not required to check the format, but it can be used check it, so why write a custom regex for something which is already there?
You have not tagged an OS, and because you’re using ksh I’m guessing you’re probably not using Linux, and you might be using Solaris. The date command you give will work, but it’s for GNU date where -d (or —date ) is a GNU enhancement.
So the simple option is to use GNU date , you may need to install the GNU coreutils package, or you may already have it (check in /usr/sfw/bin on Solaris) it may already be available possibly as gdate or gnudate . This will properly validate the date in the YYYY-MM-DD format (unlike the regex examples elsewhere which will accept 2015-31-01)
You may instead be able to use the touch command in a similar and more portable (POSIX) way
touch -c -d 2015-12-12T00:00:00 /tmp/does-not-exist
- use -c so that a file is not created
- append T00:00:00 to the date to make a valid time stamp
(However, if you are using Solaris not only do some versions lack -d , I have found some versions at least have a bug/misfeature where they do not validate and instead try to be smart, so «2015-02-29» becomes «2015-03-01» with no error, so you cannot use these versions for date validation.)
I prefer this way, it’s robust and portable assuming you have gawk (or mawk instead, but traditional nawk lacks these time functions).
- takes the first argument and splits in on the «-» character.
- mktime() to determine an epoch time stamp for the indicated YYYY-MM-DD
- sprintf() to normalise the YYYY-MM-DD (leading 0)
- strftime() to convert epoch time back to YYYY-MM-DD, and compare as a string
The reason for the extra convert and compare is to catch the case where questionable dates are reinterpreted by the C library mktime() , as is the case with glibc on linux (the same problem as with Solaris touch above).
Caring about the correct format of YYYY-MM-DD may or may not mean caring about the validity of the date (something date will do), and might even mean being able to eliminate YYYY-DD-MM format dates. If you only wish to confirm the format is «date like», then a regular expression will suffice:
grep -qE "^6-[01]?9-[0123]?8$" grep -qE "^[12]4-(0?3|10|11|12)-(0?4|[12]7|3[01])$"
(On Solaris use /usr/xpg4/bin/grep not the default grep ) The first one will reject most bogus dates, the second one will reject almost all bogus dates. With -q there will be no output and you can use the return code as expected. Take care to anchor ( ^. $ ) or otherwise restrict the regular expression so that it does not simply match valid substring, e.g. 2015-12-12345
check if argument is a valid date in bash shell
I am writing a bash shell script in Linux, this program will accept a date (mm-dd-yyyy) as a parameter. I am wondering if there is a simply way to check if the date is valid? is there an operator and I can just use test to check?
8 Answers 8
You can check with date -d «datestring»
So date -d «12/31/2012» is valid, but using hyphens, e.g. date -d «12-31-2012» , is not valid for date .
You can also use words: date -d ‘yesterday’ or date -d ‘1 week ago’ are both valid.
I just tried with slashes and backward slashes (bash .4.2.2, date gnu coreutils 8,4) and it happily accepts both without hyphens.
You can extract the day, month, and year values from the input date value MM-DD-YYYY and validate it as the unambiguous (ISO) format YYYY-MM-DD instead (you can validate a DD-MM-YYY formatted date as «correct» using date, e.g. 25-12-2010, but it is not a valid MM-DD-YYY date, hence the need to change the date format first)
A valid date in the correct format is OK
30th November 2005 is valid:
$ DATE=11-30-2005; d=$; m=$; Y=$; echo "year=$Y, month=$m, day=$d"; if date -d "$Y-$m-$d" &> /dev/null; then echo VALID; else echo INVALID; fi year=2005, month=11, day=30 VALID $ DATE=11-30-2005; if date -d "$-$-$" &> /dev/null; then echo VALID; else echo INVALID; fi VALID
An invalid date in the correct format is NOT OK
31st November 2005 does not validate:
$ DATE=11-31-2005; d=$; m=$; Y=$; echo "year=$Y, month=$m, day=$d"; if date -d "$Y-$m-$d" &> /dev/null; then echo VALID; else echo INVALID; fi year=2005, month=11, day=31 INVALID $ DATE=11-31-2005; if date -d "$-$-$" &> /dev/null; then echo VALID; else echo INVALID; fi INVALID
A valid date in the incorrect format is NOT OK
20th April 1979 in DD-MM-YYYY format does not validate as a MM-DD-YYYY date:
$ DATE=20-04-1979; d=$; m=$; Y=$; echo "year=$Y, month=$m, day=$d"; if date -d "$Y-$m-$d" &> /dev/null; then echo VALID; else echo INVALID; fi year=1979, month=20, day=04 INVALID $ DATE=20-04-1979; if date -d "$-$-$" &> /dev/null; then echo VALID; else echo INVALID; fi INVALID
Alternate simpler method: use BASH variable string replace hyphens to slashes
$ DATE="04-30-2005"; [[ $(date -d "$" 2> /dev/null) ]] && echo VALID || echo INVALID VALID $ DATE="04-31-2005"; [[ $(date -d "$" 2> /dev/null) ]] && echo VALID || echo INVALID INVALID
I know it’s been long time since you posted this answer but how do I modified your condition so that it checks «if not valid» instead of «if valid»
Like many other languages, you use the «!» as a NOT operator, and then change your then and else to suit, e.g. DATE=20-04-1979; d=$
For script use, I kept it as simple as I could. Testing the date value with the date function then checking the exit code of the process.
This will redirect the standard in and standard error to null : and using echo to return the exit code with $? allows me to check for 0=good date and 1=bad date.
I would not output date to create a file called «:». I’d clean it up bit. date -d «11/31/2018» > /dev/null 2>&1, which will return 1 (false). change the 31 for 30 and the return is 0 (true).
For validation of YYYY-MM-DD (ISO 8601) dates on OSX in the BASH shell, the following approach validates both the format and the date.
isYYYYMMDDdate() < [[ "$1" =~ ^2-4-3$ ]] && [[ "$1" == $(date -r $(date -j -f "%Y-%m-%d" "$1" "+%s") '+%Y-%m-%d') ]] &> /dev/null; echo "$?" >
- It first uses a regular expression match to check the format.
- Then, it converts the date to epoch time and then back to a date.
- If the original and twice-converted dates match, then it is valid.
Test a valid date: 2005-11-30
$ isYYYYMMDDdate 2005-11-30 0
Test an invalid date: 2005-11-31
$ isYYYYMMDDdate 2005-11-31 1
Test a valid date formatted incorrectly: 1979-20-04
$ isYYYYMMDDdate 1979-20-04 1
The following worked well for me. Many thanks to my co-worker, Tyler Chamberlain, for the OSX solution.
# Validate a given date/time in Bash on either Linux or Mac (OSX). # Expected date/time format (in quotes from the command line): YYYY-MM-DD HH:MM:SS # Example(s): ./this_script "2012-02-29 13:00:00" # IS valid # ./this_script "2013-02-29 13:00:00" # Is NOT valid START_DATETIME=$1 function report_error_and_exit < local MSG=$1 echo "$MSG" >&2 exit 1 > # We can use OSTYPE to determine what OS we're running on. # From http://stackoverflow.com/questions/394230/detect-the-os-from-a-bash-script # Determine whether the given START_DATETIME is valid. if [[ "$OSTYPE" == "linux-gnu" ]] then # Validate the date on a Linux machine (Redhat or Debian). On Linux, this is # as easy as adding one minute and checking the return code. If one minute # cannot be added, then the starting value is not a valid date/time. date -d "$START_DATETIME UTC + 1 min" +"%F %T" &> /dev/null test $? -eq 0 || report_error_and_exit "'$START_DATETIME' is not a valid date/time value. $OSTYPE" elif [[ "$OSTYPE" == "darwin"* ]] then # Validate the date on a Mac (OSX). This is done by adding and subtracting # one minute from the given date/time. If the resulting date/time string is identical # to the given date/time string, then the given date/time is valid. If not, then the # given date/time is invalid. TEST_DATETIME=$(date -v+1M -v-1M -jf "%F %T" "$START_DATETIME" +"%F %T" 2> /dev/null) if [[ "$TEST_DATETIME" != "$START_DATETIME" ]] then report_error_and_exit "'$START_DATETIME' is not a valid date/time value. $OSTYPE" fi fi echo "The date/time is valid."
I tested this script on a Red Hat-based system, a Debian-based system and OSX, and it worked as expected on all three platforms. I did not have time to test on Windows (Cygwin).