3

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 
4
  • So, would you say 2/31/2017:0:0:0 is a valid date? Commented Oct 16, 2017 at 19:35
  • You can use your arithmetic operators to validate date/time components with leading zeros, e.g. echo $((01)) is 1. Commented Oct 16, 2017 at 19:37
  • @randomir :) nice catch. As splunk accepts both 01 or 1 as valid, Im now thinking just go with no leading zero format. Still Feb is a special case. Commented Oct 16, 2017 at 20:22
  • Doing this will give remove leading 0's from a given number: a="9/09/2019:00:00:00"; echo "$a" | grep -o "[0-9]\{1,2\}/[0-9]\{1,2\}/[1-9][0-9]\{3\}:[0-9]\{1,2\}:[0-9]\{1,2\}:[0-9]\{1,2\}" | sed "s/\([\/:]\)0/\1/g" ; echo $? 9/9/2019:0:0:0 0(success) and will give me the date time format which Splunk can read, next I can put some checks around individual values (delimited by / or :)... or wrap it in a minimal code for a verifyDateTime function. I'll share what I can get but would be great if there's any other minimal one-liner/code to do the same. Commented Oct 16, 2017 at 20:39

2 Answers 2

3

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:

  • month: 1-12, 01-12
  • day: 1-31, 01-31
  • year: 0000-9999
  • hour: 0-23, 00-23
  • minute: 0-59, 00-59
  • second: 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 
Sign up to request clarification or add additional context in comments.

6 Comments

Awesome, except it'll catch 0000 for yyyy so first number for year can't be 0.
What's the valid range for year, in your case?
I would say, more precisely anytime after Splunk was born (2003 onwards), but i'll do it. Thanks.
You can then use [2-9][0-9]{3} for the year field (if 2000-9999 is ok).
This is great! I think the only thing I have to nail down now is checking for February for day# 28/29 thingy based on a given leap year. I'll try that later but initial verification looks perfect. This is indeed very simple one-liner solution. Thanks. is_splunkdatetime_valid 2/30/2017:23:0:15; echo $? 0 . Lol: refinery29.com/2017/02/142002/why-does-february-have-28-days
|
1

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 $? } 

2 Comments

nice! That's good to know and very clean one liner. Most probably the slave server used by Jenkins is based on an Ubuntu image so I'll prefer the grep awk way but this one is definitely one of the answer for a BSD based system
@ArunSangal : try date --date="13/3/2017 23:00:15" "+%m/%d/%Y:%T", this will produce date: invalid date `13/3/2017 23:00:15', running on a debian type linux (and any others with a modern date (If you're lucky ;-) ). Good luck to all.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.