1

I am trying a script to get the no. of days between now and a future date. I intend to run this script on AIX and linux from a common location. Now, I am using modules DateTime for linux and Date::Calc for AIX. For some reason, each doesn't work in the other OS. So, I am writing an if statement and checking for OS. If it's AIX, I am using Date::Calc or I am using DateTime. Here's my code

#!/usr/bin/perl
use strict;
use warnings;
my $OS = `uname`;
if ( $OS=~/AIX/i ) {
use Date::Calc qw(Delta_Days);
my @today = (localtime)[5,4,3];
$today[0] += 1900;
$today[1]++;
my @end = (2015, 11, 12);
my $expiry = Delta_Days(@today, @end);
print "$expiry\n";
} else {
require DateTime;
my $exp = DateTime->new( year => 2015, month => 11, day => 12 );
my $now = DateTime->now;
my $diff = $now->delta_days($exp);
my $expiry = $diff->delta_days;
print $expiry,"\n";}

This scripts appears to be working fine in AIX when i use use Date::Calc in the if loop. But when i run this script in linux, it gives me an error saying can't locate Date/Calc pm in @INC. When i change it to require Date::Calc in the if loop, it gives me an error can't locate Date::Calc pm in @INC on the AIX server. And it's vice versa with the else loop for Linux OS too.

How can i achieve common ground? For some reason, i can't install these modules in one server or the other.

user3164754
  • 205
  • 2
  • 9
  • I checked this out. But for some reason, my management doesn't want me to install the modules. They feel like there's no reason to fix what ain't broker. They have given this as a challenge to me. – user3164754 Feb 06 '14 at 15:16
  • Tell them that it _is_ broken, and needs to be fixed. – Ilmari Karonen Feb 06 '14 at 15:17
  • Also, are you sure about those error messages? Clearly you retyped them instead of copy-pasting them (since the capitalization is wrong), but I suspect the second one is wrong in other ways too. – Ilmari Karonen Feb 06 '14 at 15:19
  • The first error happens on Linux when i use `use` in the if loop. The sceond error happens on AIX when i use `require` in the if loop. the script works on Linux server when i use `require` in the if loop. – user3164754 Feb 06 '14 at 15:23
  • OK, it's just that I'm pretty sure it _doesn't_ say that, unless you actually wrote `require "Date::Calc";`with the quotes. – Ilmari Karonen Feb 06 '14 at 15:24

2 Answers2

4

Executing a script is done is multiple passes. The "use module" statement are executed in the same phase as the BEGIN blocks, while the "normal" code is executed later. This means, that you cannot wrap a use statement simply inside an if-block. What you can do is the following:

BEGIN {
   if ( $^O =~ m/aix/i ) { 
      require Date::Calc;
      *day_diff = sub { ... use Date::Calc::Delta_Days... }
   } else {
      require DateTime;
      *day_diff = sub { ... use DateTime here ... }
   }
}

day_diff( ... ); # will call either the DateTime or Delta_Days variant with a common interface

This way you define a function inside the BEGIN block. The implementation depends in this case on the platform (better use $^O not uname), but you could also simply check if a module is available and thus have the code more flexible:

BEGIN {
    if ( eval { require Date::Calc } ) {
        *day_diff = sub { ... use Date::Calc::Delta_Days... }
    } elsif ( eval { require DateTime }) {
        *day_diff = sub { ... use DateTime here ... }
    } else {
         die "cannot neither load Date::Calc not DateTime"
    }
}
Steffen Ullrich
  • 114,247
  • 10
  • 131
  • 172
4

In Perl programs, use statements always happen at compile time. That means that they happen anyway, even if they are in a block of code that shouldn't be executed. So your use Date::Calc always gets executed and (because it's not installed on your non-AIX boxes) fails.

The simplest way to fix this is probably to convert each use to a require/import pair.

if ( $OS=~/AIX/i ) {
  require Date::Calc;
  Date::Calc->import(qw(Delta_Days));
  ...;
} else {
  require DateTime;
  ...;
}

But, to avoid further pain in your future, I'd definitely investigate getting DateTime installed on all of your boxes so that you can get rid of Date::Calc.

Dave Cross
  • 68,119
  • 3
  • 51
  • 97