Date functions: valid_date

valid_date()
{
    order=ymd
    case $1 in
        -dmy) order=dmy; shift ;;
        -mdy) order=mdy; shift ;;
        -ymd) order=ymd; shift ;; ## default
    esac

    ofs=$IFS
    IFS="$IFS-./"
    set -- $*
    IFS=$ofs
    case $order in
        dmy) v_day=$1
            v_month=$2
            v_year=$3
            ;;
        mdy) v_month=$1
            v_day=$2
            v_year=$3
            ;;
        ymd) v_month=$2
            v_day=$3
            v_year=$1
            ;;
    esac

    case $v_year in
        "") v_year=`date +%Y` ;;
        *[!0-9]*) echo "Year $v_year contains a non-numeric character" >&2
                  return 1 ;;
    esac

    case $v_month in
        ## allow non-padded months
        [1-9]|\
        0[1-9]|\
        1[012]) ;;
        *) echo "Invalid month: $v_month" >&2
            return 1
            ;;
    esac

    case $v_day in
        ## allow non-padded days
        [1-9]|\
        0[1-9]|\
        1[0-9]|\
        2[0-8]) ;; ## if 28 or less, day is OK
        [23][0-9]) SILENT_FUNCS=1 days_in_month $v_month $v_year
		   [ $v_day -le $_DAYS_IN_MONTH ] || {
		       echo "Invalid day: $v_day" >&2
		       return 1
		   }
		   ;;
        *) echo "Invalid day: $v_day" >&2
            return 1
            ;;
    esac
}