15

I want to validate the below date format in shell script

2015-Jul-13

I'm using date -d "2015-Jul-13" +"%Y-%b-%d" but its giving error as

date: invalid date '2015-Jul-13'
Thushi
  • 9,498
  • @Pandya: OP is clear about his/her question. OP wants to validate(check the entered date is valid or not) the mentioned date format but it is saying the entered date is invalid. – Thushi Jul 13 '15 at 11:20
  • GNU date doesn't recognise YYYY-MMM-DD. Could you use YYYY-MM-DD or DD MMM YYYY instead? – Chris Davies Jul 13 '15 at 12:29
  • I'm pretty sure at does, and - I think - touch does as well. I wrote a date validation shell funvtion based on touch once... nope, not touch - it only handles numerals, but at does some pretty deep parsing... – mikeserv Jul 13 '15 at 12:30
  • @Thushi let's clear redundant comment by us – Pandya Jul 13 '15 at 13:10
  • 7
    Misread the title: Date validation is hell – Adam Davis Jul 13 '15 at 18:43

3 Answers3

13

GNU date does not support YYYY-MMM-DD. However, it does understand DD-MMM-YYYY. So if you really have to handle dates of this format you can do it with something like this, which simply swaps the arguments around to a format that date expects:

ymd='2015-Jul-13'

dmy=$(echo "$ymd" | awk -F- '{ OFS=FS; print $3,$2,$1 }')
if date --date "$dmy" >/dev/null 2>&1
then
    echo OK
fi

Here's an all shell solution. Breaking it down, the IFS=- instructions tells the shell to split a forthcoming command line by hyphen - instead of whitespace. The set $ymd parses the $ymd variable as for a command line, but now splits by hyphen, assigning values to the parameters $1, $2 et seq. The echo "$3-$2-$1" trivially outputs the three captured values in reversed order.

ymd='2015-Jul-13'

dmy=$(IFS=-; set $ymd; echo "$3-$2-$1")
if date --date "$dmy" >/dev/null 2>&1
then
    echo OK
fi
mikeserv
  • 58,310
Chris Davies
  • 116,213
  • 16
  • 160
  • 287
  • 1
    @mikeserv: Coolness! It worked with:
    ``ymd=$(IFS=-;set $ymd; echo "$3-$2-$1")``
    
    

    Could you maybe reveal the magic behind the set command?

    – joepd Jul 13 '15 at 13:17
11

From manpage:-

DATE STRING
       The --date=STRING is a mostly free format human readable date string such as "Sun, 29 Feb 2004 16:21:42 -0800"
       or  "2004-02-29  16:21:42" or even "next Thursday".  A date string may contain items indicating calendar date,
       time of day, time zone, day of week, relative time, relative date, and numbers.  An empty string indicates the
       beginning  of  the  day.   The  date string format is more complex than is easily documented here but is fully
       described in the info documentation.

But it seems not recognize YYYY-MMM-DD format. So, you can use either from below or similar like:

$ date -d "2015-07-13" +"%Y-%b-%d"
2015-Jul-13
$ date -d "Jul 13 2015" +"%Y-%b-%d"
2015-Jul-13
$ date -d "13 Jul 2015" +"%Y-%b-%d"
2015-Jul-13

OR you've to convert/re-formate it before sending to date!

Also see How do you specify a format for the input to date?


I recommend to Visit: Date input formats.

Here are the rules.

For numeric months, the ISO 8601 format 'year-month-day' is allowed, where year is any positive number, month is a number between 01 and 12, and day is a number between 01 and 31. A leading zero must be present if a number is less than ten. If year is 68 or smaller, then 2000 is added to it; otherwise, if year is less than 100, then 1900 is added to it. The construct 'month/day/year', popular in the United States, is accepted. Also 'month/day', omitting the year.

Literal months may be spelled out in full: 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November' or 'December'. Literal months may be abbreviated to their first three letters, possibly followed by an abbreviating dot. It is also permitted to write 'Sept' instead of 'September'.

When months are written literally, the calendar date may be given as any of the following:

 day month year
 day month
 month day year
 day-month-year

emphasized by me

Here you can see that there is no format like year-month-day! (for months are written literally)

Pandya
  • 24,618
7

With zsh you could use the strftime builtin (available via zsh/datetime) with -r (reverse):

strftime -r format timestring

which uses format to parse the timestring and output the number of seconds since epoch:

zmodload zsh/datetime
strftime -r %Y-%b-%d 2015-Jul-13
1436734800

This errors out if the date is invalid:

strftime -r %Y-%b-%d 2015-Jul-33
zsh:strftime:5: format not matched

You can also convert the seconds since epoch to any other standard/custom date format e.g.

strftime '%A, %B %d, %Y' 1447970400
Friday, November 20, 2015
don_crissti
  • 82,805