From: Hermann Peifer on
On 23/04/2010 05:46, Ed Morton wrote:
>
> Yes, but that wouldn't solve the logic problem. You could instead use
> GNU date's --date= argument or GNU awks' "mktime()" function to check if
> the specified date is a real one by trying to use it as a date.
>

How would you do the test with GNU awks' "mktime()" function:

gawk 'BEGIN{ print mktime("2010 03 32 0 0 0")
print mktime("2010 04 01 0 0 0")
}'
1270072800
1270072800


?

Hermann
From: Ed Morton on
On 4/23/2010 6:45 AM, Hermann Peifer wrote:
> On 23/04/2010 05:46, Ed Morton wrote:
>>
>> Yes, but that wouldn't solve the logic problem. You could instead use
>> GNU date's --date= argument or GNU awks' "mktime()" function to check if
>> the specified date is a real one by trying to use it as a date.
>>
>
> How would you do the test with GNU awks' "mktime()" function:
>
> gawk 'BEGIN{ print mktime("2010 03 32 0 0 0")
> print mktime("2010 04 01 0 0 0")
> }'
> 1270072800
> 1270072800
>

I expected mktime() to return -1 for that like it does for other invalid date
specs so I'm surprised by that result. I guess you'd have to do something like
compare the returned value for your given date to the values returned for the
next day.

Ed.


From: Ed Morton on
On 4/23/2010 7:14 AM, Ed Morton wrote:
> On 4/23/2010 6:45 AM, Hermann Peifer wrote:
>> On 23/04/2010 05:46, Ed Morton wrote:
>>>
>>> Yes, but that wouldn't solve the logic problem. You could instead use
>>> GNU date's --date= argument or GNU awks' "mktime()" function to check if
>>> the specified date is a real one by trying to use it as a date.
>>>
>>
>> How would you do the test with GNU awks' "mktime()" function:
>>
>> gawk 'BEGIN{ print mktime("2010 03 32 0 0 0")
>> print mktime("2010 04 01 0 0 0")
>> }'
>> 1270072800
>> 1270072800
>>
>
> I expected mktime() to return -1 for that like it does for other invalid
> date specs so I'm surprised by that result. I guess you'd have to do
> something like compare the returned value for your given date to the
> values returned for the next day.
>

Here's what I mean by that:

$ gawk 'BEGIN{
print mktime("2010 02 28 0 0 0")
print mktime("2010 02 29 0 0 0")
print mktime("2010 02 30 0 0 0")
print mktime("2010 03 01 0 0 0")
print ""
print mktime("2012 02 28 0 0 0")
print mktime("2012 02 29 0 0 0")
print mktime("2012 02 30 0 0 0")
print mktime("2012 03 01 0 0 0")
}'
1267336800 <- less than first day of next month so valid
1267423200 <- equal to first day of next month so invalid
1267509600 <- greater than first day of next month so invalid
1267423200

1330408800 <- less than first day of next month so valid
1330495200 <- less than first day of next month so valid
1330581600 <- equal to first day of next month so invalid
1330581600

So, assuming you can range-check the months and years, if you find that
mktime(current date) returns a value greater than or equal to mktime(1st day of
next month) then you have an invalid date.

Regards,

Ed.
From: Bill Marcum on
On 2010-04-23, Scott Bass <sas_l_739(a)yahoo.com.au> wrote:

>
> Or perhaps another alternative is to do the entire error checking in
> awk. In pseudocode:
>
> * get date parameter from arguments
> * in awk:
> * split on ":" character
> * check length of array - if not 2 - 4 then print error msg and exit
> the script
> * if two fields check hour/minute are valid else print error msg and
> exit
> * if three fields check day/hour/minute are valid else print error msg
> and exit
> * if four fields check month/day/hour/minute are valid else print
> error msg and exit
>
> 1) Is the above pseudocode possible in awk?
Yes. split is an awk function. The return value is the number of elements
in the array.

> 2) And would you recommend it as a good approach?
Yes.
> 3) If not, is there a way I can get awk to return the date parameter
> split as shell variables month/day/hour/minute?
>
You could do it without awk.
IFS=":" set $date
case $# in
2) hour=$1; minute=$2 ;;
3) day=$1; hour=$2; minute=$3 ;;
4) month=$1; day=$2; hour=$3; minute=$4 ;;
*) echo "error" ;;
esac

> Thanks for the help and advice...
>
> Scott
From: Ed Morton on
On 4/22/2010 7:30 PM, Scott Bass wrote:
> Hi,
>
> I'm writing a script (ksh) where the user enters a date parameter as
> follows:
>
> -a "begin time"
>
> Job will not start until after begin time
> begin time is in the form of month:day:hour:minute where
> month 1-12, day is 1-31, hour is 0-23 and minute is 0-59.
> At least 2 fields must be given hour:minute, if 3 fields
> are given they are assumed to be day:hour:minute.
>
> I would like to add error checking in the script, rather than having
> the called utility choke on bad dates.
>
> I'd like to split the user parameter into fields, then check the
> fields in my script.
>
> In Perl, the code would be something like:
>
> ($month, $day, $hour, $minute) = split(/:/, $foo);
>
> I've also found this awk example:
>
> foo="12:34:56"
> echo $foo | awk '{split ($0, a, ":"); print a[1]}'
>
> But I can't see how to get the array "a" into variables available to
> the script.
>
> Or perhaps another alternative is to do the entire error checking in
> awk. In pseudocode:
>
> * get date parameter from arguments
> * in awk:
> * split on ":" character
> * check length of array - if not 2 - 4 then print error msg and exit
> the script
> * if two fields check hour/minute are valid else print error msg and
> exit
> * if three fields check day/hour/minute are valid else print error msg
> and exit
> * if four fields check month/day/hour/minute are valid else print
> error msg and exit
>
> 1) Is the above pseudocode possible in awk?
> 2) And would you recommend it as a good approach?
> 3) If not, is there a way I can get awk to return the date parameter
> split as shell variables month/day/hour/minute?
>
> Thanks for the help and advice...
>
> Scott

All things considered and now that I know mktime() wouldn't be as simple a
solution as I thought, here's how I'd really approach this to pass in the target
date/time plus the current date/time to an awk script and let it do all the
checks. Below is a start, you'd have to add the leap year logic (divide the year
by 4) and use the currently unused "nowA" array to figure out if the target date
is in the future (as desired) or not. Note that you need the month (30-day
month?) and the year (leap year?) to do some validation on the day and specific
target date (already past?).

So, there's still a fair bit to do, but this should show you approach and the
syntax of how to do it.

Ed.

$ cat tst.awk
BEGIN {
mths30["04"]; mths30["06"]; mths30["09"]; mths30["11"]

numNowFlds = split(now,nowA,/:/)

numTgtFlds = split(tgt,tgtA,/:/)

validInput = 1

for (i=1; i<=numTgtFlds; i++) {
if (tgtA[i] !~ /^[[:digit:]]+$/) {
printf "Input field %d (%s) has non-digits.\n",i,tgtA[i] | "cat>&2"
validInput = 0
}
}

if (numTgtFlds >= 2) {
min = tgtA[numTgtFlds]
hour = tgtA[numTgtFlds-1]
if (numTgtFlds >= 3) {
day = tgtA[numTgtFlds-2]
if (numTgtFlds >= 4) {
mth = tgtA[numTgtFlds-3]
if (numTgtFlds >= 5) {
print "Too many input fields" | "cat>&2"
validInput = 0
}
}
}
}
else {
print "Too few input fields" | "cat>&2"
validInput = 0
}

if ((min < 0) || (min > 59)) {
printf "Minutes field (%s) out of range\n",min | "cat>&2"
validInput = 0
}

if ((hour < 0) || (hour > 23)) {
printf "Hours field (%s) out of range\n",hour | "cat>&2"
validInput = 0
}

if (mth != "") {
if ((mth >= 1) && (mth <= 12)) {
gotMonth = 1
}
else {
printf "Months field (%s) out of range\n",mth | "cat>&2"
validInput = 0
}
}

if (day != "") {
if ((day >= 1) && (day <= 31)) {
gotDay = 1
if (gotMth) {
if ((mth == 2) && (day > 28)) {
printf "Days field (%s) too big for month %s\n",day,mth | "cat>&2"
validInput = 0
gotDay = 0
}
if ((mth in mths30) && (day == 31)) {
printf "Days field (%s) too big for month %s\n",day,mth | "cat>&2"
validInput = 0
gotDay = 0
}
}
}
else {
printf "Days field (%s) out of range\n",day | "cat>&2"
validInput = 0
}
}

print min, hour, day, mth | "cat>&2"
if (! validInput) {
print "Errors found, exiting." | "cat>&2"
exit 1
}
}

$ awk -v now="$(date +%Y:%m:%d:%H:%M)" -v tgt="10:20" -f tst.awk
20 10
$ awk -v now="$(date +%Y:%m:%d:%H:%M)" -v tgt="07:02:28:10:20" -f tst.awk
Too many input fields
20 10 28 02
Errors found, exiting.
$ awk -v now="$(date +%Y:%m:%d:%H:%M)" -v tgt="02:28:10:20" -f tst.awk
20 10 28 02
$ awk -v now="$(date +%Y:%m:%d:%H:%M)" -v tgt="02:29:10:20" -f tst.awk
Days field (29) too big for month 02
20 10 29 02
Errors found, exiting.
$ awk -v now="$(date +%Y:%m:%d:%H:%M)" -v tgt="05:31:10:20" -f tst.awk
20 10 31 05
$ awk -v now="$(date +%Y:%m:%d:%H:%M)" -v tgt="06:31:10:20" -f tst.awk
Days field (31) too big for month 06
20 10 31 06
Errors found, exiting.