Reputation: 17366
I saw couple of posts (some depends upon date -d $xyz
to verify) but I'm trying to create an until
loop where the user should be re-prompted to enter the value of a date format until it matches the custom date format.
My date format (what I need for Splunk) is m/d/yyyy:h:m:s
or mm/dd/yyyy:hh:mm:ss
which means, if m
(month number) is a single digit lets say 1 for January
, then both 1
or 01
values are possible for date format but 0
or 00
is NOT a valid value. Value range is 01-to->12
or 1-to->12
but not greater than 12.
Similarly, the same rule applies to d
(day number), it can be 01-to->10-to->31
or 1-to->31
but not 00
or more than 31
and all other yyyy
(year), h
(hour), m
(minute), s
(second) part.
What could be a minimal code (obfuscated is fine) to do this verification in BASH? It seems like date -d ???
doesn't provides this custom kind of verification for date/times!
OK, I can write one verifyDateFormatfunc() to do this, but I know there are people who have already written a one-liner / minimal snippet to verify this for sure. grep -f ..
(where bunch of regex are listed line by line for all possible combinations, again the main code will look very minimal if I follow this? as the patterns sitting in -f file
for grep
will be transparent to a user) -or creating a map funcation (based on delimiters) for value ranges?
Possible values:
1/03/2017:23:0:15
02/4/2017:0:1:2
09/05/2017:10:10:0
10/6/2017:12:14:16
Upvotes: 3
Views: 140
Reputation: 2045
I do not know whether using BSD date is an option for you, but it has what you are looking for.
There the date checker function can look like this
is_datetime_valid() {
date -j -f "%m/%d/%Y:%T" $1 1> /dev/null 2>&1
return $?
}
Upvotes: 1
Reputation: 18697
Here's an unholy extended regular expression (POSIX ERE):
^([1-9]|1[0-2]|0[1-9])/([1-9]|0[1-9]|[12][0-9]|3[01])/[0-9]{4}:([0-9]|0[0-9]|1[0-9]|2[0-3]):([0-9]|[0-5][0-9]):([0-9]|[0-5][0-9])$
that will test for the date/time patterns you specified (m/d/yyyy:h:m:s
and mm/dd/yyyy:hh:mm:ss
), with:
1-12
, 01-12
1-31
, 01-31
0000-9999
0-23
, 00-23
0-59
, 00-59
0-59
, 00-59
You can use in an awk
program that will exit with success (exit code 0) if the (first) line is a valid date/time (wrapped in a shell function that tests the first argument, for convenience):
#!/bin/bash
is_datetime_valid() {
awk '{exit $0!~"^([1-9]|1[0-2]|0[1-9])/([1-9]|0[1-9]|[12][0-9]|3[01])/[0-9]{4}:([0-9]|0[0-9]|1[0-9]|2[0-3]):([0-9]|[0-5][0-9]):([0-9]|[0-5][0-9])$"}' <<<"$1"
}
Or, if you prefer a pure bash
solution (with ERE support in bash
v3.0+):
#!/bin/bash
is_datetime_valid() {
local pat='^([1-9]|1[0-2]|0[1-9])/([1-9]|0[1-9]|[12][0-9]|3[01])/[0-9]{4}:([0-9]|0[0-9]|1[0-9]|2[0-3]):([0-9]|[0-5][0-9]):([0-9]|[0-5][0-9])$'
[[ $1 =~ $pat ]]
}
You can use it like:
if is_datetime_valid "1/03/2017:23:0:15"; then
# yup, it's valid
else
# ney, it's invalid
fi
Tested on a few examples:
#!/bin/bash
samples=(
"1/03/2017:23:0:15" "02/4/2017:0:1:2" "09/05/2017:10:10:0" "10/6/2017:12:14:16"
"00/03/2017:23:0:15" "1/33/2017:23:0:15"
)
for dt in "${samples[@]}"; do
if is_datetime_valid "$dt"; then
echo "$dt is valid"
else
echo "$dt is invalid"
fi
done
Gives:
1/03/2017:23:0:15 is valid
02/4/2017:0:1:2 is valid
09/05/2017:10:10:0 is valid
10/6/2017:12:14:16 is valid
00/03/2017:23:0:15 is invalid
1/33/2017:23:0:15 is invalid
Upvotes: 3