Link to home
Start Free TrialLog in
Avatar of tindavid
tindavid

asked on

Need perl command line program to test if 2 string variable is of date value and compare them

I have 2 lines of text as below:

#!/usr/bin/ksh
record1="Tue Mar 29 00:48:05 2016"
record2="Tue Mar 29 00:48:05 2016"

record1_is_time_record=`perl -n    ......     ${record1}     .....`
record2_is_time_record=`perl -n    ......     ${record2}     .....`

if [ $record1_is_time -eq 1 ] and [ $record2_is_time -eq 1 ]; then
   record1_is_eailer_than_record2=`perl -n .......   ${record1}  compare with $reocrd2}  return 1 is yes else 0..
fi
Avatar of wilcoxon
wilcoxon
Flag of United States of America image

Will the dates always be in the format you show in your question?  If not, do you know what other formats are possible?
Hmm.  Do you want the script in perl or do you want two perl one-liners to check the date format?  If just two one-liners, why not do the whole thing in perl?  It would actually be simpler.

If all you want is one-liners, I think this should work (I hardly ever call perl from a shell script so the variable syntax may be off or the return may not be correct)...
# these check the format but don't actually check for valid dates
record1_is_time_record=`perl -e "print '${record1}' =~ m{^\w+\s+\w+\d+\s+\d\d:\d\d:\d\d\s+\d{4}$}) ? 1 : 0"`
record2_is_time_record=`perl -e "print '${record2}' =~ m{^\w+\s+\w+\d+\s+\d\d:\d\d:\d\d\s+\d{4}$}) ? 1 : 0"`
if [ $record1_is_time -eq 1 ] and [ $record2_is_time -eq 1 ]; then
   # this will be standard cmp comparison output (-1 is record1 is earlier, 0 if equal, 1 if record2 is earlier)
   record_compare=`perl -e "use Data::Manip; print Date_Cmp('${record1}', '${record2}')"`
fi

Open in new window

Avatar of tindavid
tindavid

ASKER

record1 and 2 has to be a valid date valid, therefore

record1_is_time_record=`perl -e   ...`  shall return 1 or 0 if it is valid date value

also, our system does not have the Date Library. as below:
Can't locate Data/Manip.pm in @INC (@INC contains: /opt/perl_32/lib/5.8.8/IA64.ARCHREV_0-thread-multi /opt/perl_32/lib/5.8.8 /opt/perl_32/lib/site_perl/5.8.8/IA64.ARCHREV_0-thread-multi /opt/perl_32/lib/site_perl/5.8.8 /opt/perl_32/lib/site_perl /opt/perl_32/lib/vendor_perl/5.8.8/IA64.ARCHREV_0-thread-multi /opt/perl_32/lib/vendor_perl/5.8.8 /opt/perl_32/lib/vendor_perl .) at -e line 1.
BEGIN failed--compilation aborted at -e line 1.


Can we use some other method to do the comparison ?   my shell script will be like this:

#!/usr/bin/ksh

# the information in record can be following type of Date format or other non date string
#
record1="Thu Apr 28 09:53:55 2016"    # can be some other rubbish string
record2="Thu Apr 29 10:53:55 2016"    # can be some other rubbish string

# these check the format but don't actually check for valid dates
record1_is_time_record=`perl -e   ....`
record2_is_time_record=`perl -e  .... `

if [ $record1_is_time -eq 1 ] and [ $record2_is_time -eq 1 ]; then
   # this will be standard cmp comparison output (-1 is record1 is earlier, 0 if equal, 1 if record2 is earlier)
   record_compare=`perl -e "use Data::Manip; print Date_Cmp('${record1}', '${record2}')"`
fi
Is it enough the validate the format of the date or does it need to be validated as a valid date (eg the current regex I suggested would accept "ABC DEF 99 66:77:88 9999" as valid).

Oops.  It should have been Date::Manip (not Data::Manip).  Can you try the following and let me know if any of them succeed?  If any of them work, you can stop (the first 3 would definitely work - the others, I'm just guessing based on the module name).
perl -e 'use Date::Manip'
perl -e 'use Date::Calc'
perl -e 'use DateTime'
perl -e 'use Time::Date'
perl -e 'use Date::Parser'
perl -e 'use Date::Parse'
Hi Wil,

Very unfortunately, all your suggested test of the library do not work . see the outcome below:

rxngna02[nGens_wk][/home/dba/oracle/dtin] >perl -e 'use Date::Manip'
Can't locate Date/Manip.pm in @INC (@INC contains: /opt/perl_32/lib/5.8.8/IA64.ARCHREV_0-thread-multi /opt/perl_32/lib/5.8.8 /opt/perl_32/lib/site_perl/5.8.8/IA64.ARCHREV_0-thread-multi /opt/perl_32/lib/site_perl/5.8.8 /opt/perl_32/lib/site_perl /opt/perl_32/lib/vendor_perl/5.8.8/IA64.ARCHREV_0-thread-multi /opt/perl_32/lib/vendor_perl/5.8.8 /opt/perl_32/lib/vendor_perl .) at -e line 1.
BEGIN failed--compilation aborted at -e line 1.
rxngna02[nGens_wk][/home/dba/oracle/dtin] >perl -e 'use Date::Calc'
Can't locate Date/Calc.pm in @INC (@INC contains: /opt/perl_32/lib/5.8.8/IA64.ARCHREV_0-thread-multi /opt/perl_32/lib/5.8.8 /opt/perl_32/lib/site_perl/5.8.8/IA64.ARCHREV_0-thread-multi /opt/perl_32/lib/site_perl/5.8.8 /opt/perl_32/lib/site_perl /opt/perl_32/lib/vendor_perl/5.8.8/IA64.ARCHREV_0-thread-multi /opt/perl_32/lib/vendor_perl/5.8.8 /opt/perl_32/lib/vendor_perl .) at -e line 1.
BEGIN failed--compilation aborted at -e line 1.
rxngna02[nGens_wk][/home/dba/oracle/dtin] >perl -e 'use DateTime'
Can't locate DateTime.pm in @INC (@INC contains: /opt/perl_32/lib/5.8.8/IA64.ARCHREV_0-thread-multi /opt/perl_32/lib/5.8.8 /opt/perl_32/lib/site_perl/5.8.8/IA64.ARCHREV_0-thread-multi /opt/perl_32/lib/site_perl/5.8.8 /opt/perl_32/lib/site_perl /opt/perl_32/lib/vendor_perl/5.8.8/IA64.ARCHREV_0-thread-multi /opt/perl_32/lib/vendor_perl/5.8.8 /opt/perl_32/lib/vendor_perl .) at -e line 1.
BEGIN failed--compilation aborted at -e line 1.
rxngna02[nGens_wk][/home/dba/oracle/dtin] >perl -e 'use Time::Date'
Can't locate Time/Date.pm in @INC (@INC contains: /opt/perl_32/lib/5.8.8/IA64.ARCHREV_0-thread-multi /opt/perl_32/lib/5.8.8 /opt/perl_32/lib/site_perl/5.8.8/IA64.ARCHREV_0-thread-multi /opt/perl_32/lib/site_perl/5.8.8 /opt/perl_32/lib/site_perl /opt/perl_32/lib/vendor_perl/5.8.8/IA64.ARCHREV_0-thread-multi /opt/perl_32/lib/vendor_perl/5.8.8 /opt/perl_32/lib/vendor_perl .) at -e line 1.
BEGIN failed--compilation aborted at -e line 1.
rxngna02[nGens_wk][/home/dba/oracle/dtin] >perl -e 'use Date::Parser'
Can't locate Date/Parser.pm in @INC (@INC contains: /opt/perl_32/lib/5.8.8/IA64.ARCHREV_0-thread-multi /opt/perl_32/lib/5.8.8 /opt/perl_32/lib/site_perl/5.8.8/IA64.ARCHREV_0-thread-multi /opt/perl_32/lib/site_perl/5.8.8 /opt/perl_32/lib/site_perl /opt/perl_32/lib/vendor_perl/5.8.8/IA64.ARCHREV_0-thread-multi /opt/perl_32/lib/vendor_perl/5.8.8 /opt/perl_32/lib/vendor_perl .) at -e line 1.
BEGIN failed--compilation aborted at -e line 1.
rxngna02[nGens_wk][/home/dba/oracle/dtin] >perl -e 'use Date::Parse'
Can't locate Date/Parse.pm in @INC (@INC contains: /opt/perl_32/lib/5.8.8/IA64.ARCHREV_0-thread-multi /opt/perl_32/lib/5.8.8 /opt/perl_32/lib/site_perl/5.8.8/IA64.ARCHREV_0-thread-multi /opt/perl_32/lib/site_perl/5.8.8 /opt/perl_32/lib/site_perl /opt/perl_32/lib/vendor_perl/5.8.8/IA64.ARCHREV_0-thread-multi /opt/perl_32/lib/vendor_perl/5.8.8 /opt/perl_32/lib/vendor_perl .) at -e line 1.
BEGIN failed--compilation aborted at -e line 1.
Would it work to do the whole script in perl instead of in ksh and calling perl one-liners?

You didn't answer the question at the top of the previous post...  Is it enough the validate the format of the date or does it need to be validated as a valid date (eg the current regex I suggested would accept "ABC DEF 99 66:77:88 9999" as valid).
it is ok to have it in a perl and then call it from shell with argument.

i would like to have IN 2 arguments and one return value of 1 or 0 when comparing 2 in args. 

it is possible that arg1 might not be the date value at all.

however if they were date value, they will have the above date format.
If the perl script takes two date arguments, verifies them, and compares them (if both are dates), what should the output be in each case?
Date1 is not a date
Date2 is not a date
Date1 is less than Date2
Date1 is equal to Date2
Date1 is greater than Date2

I assume you can not install any more Perl modules from CPAN on your system?
let say    sub_time_compare(arg1,arg2) return integer if

0 if unable to compare due to either one of the value is non-date value
-X  if arg1 is < arg2                 X is the number of days
+X if arg1 is > arg2

I will handle if arg1 = arg2 (by assuming they should have the same pattern or string )
Without the use of any date modules, it will require quite a bit of code.  I wasn't able to test this but I think it's correct.  It could potentially return an answer that is off by 1 day (per leap year) if the dates are far enough apart and fall "right".  If the dates can be before 2000, this will also need some modification.
#!/usr/local/bin/perl
use strict;
use warnings;

my %mm = (Jan => 1, Feb => 2, Mar => 3, Apr => 4, May => 5, Jun => 6,
          Jul => 7, Aug => 8, Sep => 9, Oct => 10, Nov => 11, Dec => 12);
my $mon = join '|', keys %mm;
my $dom = (Jan => 31, Feb => 28, Mar => 31, Apr => 30, May => 31, Jun => 30,
           Jul => 31, Aug => 31, Sep => 30, Oct => 31, Nov => 30, Dec => 31);
my $dow = 'Mon|Tue|Wed|Thu|Fri|Sat|Sun';

my $dt1 = shift or die "Usage: $0 date1 date2\n";
my $dt2 = shift or die "Usage: $0 date1 date2\n";
my (@pt1, @pt2);

if ($dt1 =~ m{^(?:$dow)\s+($mon)\s+(\d+)\s+(\d\d):(\d\d):(\d\d)\s+(\d{4})$}) {
    my @pt1 = ($6, $mm{$1}, $2, $3, $4, $5);
    if ($pt1[1] <> 2 and $pt1[2] > $dom{$pt1[1]}) {
        ret(0);
    } elsif ($pt1[1] == 2 and $pt1[2] > 28 + leap($pt1[0])) {
        ret(0);
    }
} else {
    ret(0);
}

if ($dt2 =~ m{^(?:$dow)\s+($mon)\s+(\d+)\s+(\d\d):(\d\d):(\d\d)\s+(\d{4})$}) {
    my @pt2 = ($6, $mm{$1}, $2, $3, $4, $5);
    if ($pt2[1] <> 2 and $pt2[2] > $dom{$pt2[1]}) {
        ret(0);
    } elsif ($pt2[1] == 2 and $pt2[2] > 28 + leap($pt2[0])) {
        ret(0);
    }
} else {
    ret(0);
}

my $days1 = ($pt1[0]-2000) * 365 + sum_mon($pt1[1], $pt1[0]) + $pt1[2];
my $days2 = ($pt2[0]-2000) * 365 + sum_mon($pt2[1], $pt2[0]) + $pt2[2];
ret($days2 - $days1);

sub ret {
    print $_[0], "\n";
    exit;
}

sub leap {
    my ($yr) = @_;
    if ($yr % 4 == 0 and ($yr % 100 <> 0 or $yr % 400 == 0)) {
        return 1;
    }
    return 0;
}

sub sum_mon {
    my ($mon, $yr) = @_;
    my $sum = 0;
    for my $i (1..$mon) {
        $sum += $dom{$mon};
        $sum++ if ($mon == 2 and leap($yr) > 0);
    }
}

Open in new window


You would call it from ksh by:
ksh_var=`perl_script_name`

Open in new window

[/code]
Tried:

say: compare.pl will contains all your code

my.sh has these lines:

date1="Tue Mar 29 00:48:05 2016"
date2="Tue May 03 00:48:05 2016"

the_result=`perl comparedate.pl ${date1} ${date2}`

when execute:

...
...
Useless use of a constant in void context at comparedate.pl line 9.
Useless use of a constant in void context at comparedate.pl line 9.
Useless use of a constant in void context at comparedate.pl line 9.
Useless use of a constant in void context at comparedate.pl line 9.
syntax error at comparedate.pl line 18, near "<>"
Global symbol "%dom" requires explicit package name at comparedate.pl line 18.
Execution of comparedate.pl aborted due to compilation errors.
ASKER CERTIFIED SOLUTION
Avatar of wilcoxon
wilcoxon
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Excellent solution. That is what I needed!